feat: add kind-mount-root for unified Kind extraMount
Publish / Build and publish (push) Failing after 0s
Details
Webapp Test / Run webapp test suite (push) Failing after 0s
Details
Smoke Test / Run basic test suite (push) Failing after 0s
Details
Lint Checks / Run linter (push) Failing after 0s
Details
Deploy Test / Run deploy test suite (push) Failing after 0s
Details
Publish / Build and publish (push) Failing after 0s
Details
Webapp Test / Run webapp test suite (push) Failing after 0s
Details
Smoke Test / Run basic test suite (push) Failing after 0s
Details
Lint Checks / Run linter (push) Failing after 0s
Details
Deploy Test / Run deploy test suite (push) Failing after 0s
Details
When kind-mount-root is set in spec.yml, emit a single extraMount
mapping the root to /mnt instead of per-volume mounts. This allows
adding new volumes without recreating the Kind cluster.
Volumes whose host path is under the root skip individual extraMounts
and their PV paths resolve to /mnt/{relative_path}. Volumes outside
the root keep individual extraMounts as before.
Cherry-picked from branch enya-ac868cc4-kind-mount-propagation-fix
(commits b6d6ad81, 929bdab8) and adapted for current main.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
afd-dumpster-local-testing
parent
9109cfb7a1
commit
8d03083d0d
|
|
@ -46,3 +46,4 @@ runtime_class_key = "runtime-class"
|
||||||
high_memlock_runtime = "high-memlock"
|
high_memlock_runtime = "high-memlock"
|
||||||
high_memlock_spec_filename = "high-memlock-spec.json"
|
high_memlock_spec_filename = "high-memlock-spec.json"
|
||||||
acme_email_key = "acme-email"
|
acme_email_key = "acme-email"
|
||||||
|
kind_mount_root_key = "kind-mount-root"
|
||||||
|
|
|
||||||
|
|
@ -455,7 +455,11 @@ class ClusterInfo:
|
||||||
)
|
)
|
||||||
if self.spec.is_kind_deployment():
|
if self.spec.is_kind_deployment():
|
||||||
host_path = client.V1HostPathVolumeSource(
|
host_path = client.V1HostPathVolumeSource(
|
||||||
path=get_kind_pv_bind_mount_path(volume_name)
|
path=get_kind_pv_bind_mount_path(
|
||||||
|
volume_name,
|
||||||
|
kind_mount_root=self.spec.get_kind_mount_root(),
|
||||||
|
host_path=volume_path,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
host_path = client.V1HostPathVolumeSource(path=volume_path)
|
host_path = client.V1HostPathVolumeSource(path=volume_path)
|
||||||
|
|
|
||||||
|
|
@ -444,7 +444,20 @@ def named_volumes_from_pod_files(parsed_pod_files):
|
||||||
return named_volumes
|
return named_volumes
|
||||||
|
|
||||||
|
|
||||||
def get_kind_pv_bind_mount_path(volume_name: str):
|
def get_kind_pv_bind_mount_path(
|
||||||
|
volume_name: str,
|
||||||
|
kind_mount_root: Optional[str] = None,
|
||||||
|
host_path: Optional[str] = None,
|
||||||
|
):
|
||||||
|
"""Get the path inside the Kind node for a PV.
|
||||||
|
|
||||||
|
When kind-mount-root is set and the volume's host path is under
|
||||||
|
that root, return /mnt/{relative_path} so it resolves through the
|
||||||
|
single root extraMount. Otherwise fall back to /mnt/{volume_name}.
|
||||||
|
"""
|
||||||
|
if kind_mount_root and host_path and host_path.startswith(kind_mount_root):
|
||||||
|
rel = os.path.relpath(host_path, kind_mount_root)
|
||||||
|
return f"/mnt/{rel}"
|
||||||
return f"/mnt/{volume_name}"
|
return f"/mnt/{volume_name}"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -567,6 +580,7 @@ def _generate_kind_mounts(parsed_pod_files, deployment_dir, deployment_context):
|
||||||
volume_definitions = []
|
volume_definitions = []
|
||||||
volume_host_path_map = _get_host_paths_for_volumes(deployment_context)
|
volume_host_path_map = _get_host_paths_for_volumes(deployment_context)
|
||||||
seen_host_path_mounts = set() # Track to avoid duplicate mounts
|
seen_host_path_mounts = set() # Track to avoid duplicate mounts
|
||||||
|
kind_mount_root = deployment_context.spec.get_kind_mount_root()
|
||||||
|
|
||||||
# Cluster state backup for offline data recovery (unique per deployment)
|
# Cluster state backup for offline data recovery (unique per deployment)
|
||||||
# etcd contains all k8s state; PKI certs needed to decrypt etcd offline
|
# etcd contains all k8s state; PKI certs needed to decrypt etcd offline
|
||||||
|
|
@ -587,6 +601,16 @@ def _generate_kind_mounts(parsed_pod_files, deployment_dir, deployment_context):
|
||||||
f" - hostPath: {pki_host_path}\n" f" containerPath: /etc/kubernetes/pki\n"
|
f" - hostPath: {pki_host_path}\n" f" containerPath: /etc/kubernetes/pki\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# When kind-mount-root is set, emit a single extraMount for the root.
|
||||||
|
# Individual volumes whose host path starts with the root are covered
|
||||||
|
# by this single mount and don't need their own extraMount entries.
|
||||||
|
mount_root_emitted = False
|
||||||
|
if kind_mount_root:
|
||||||
|
volume_definitions.append(
|
||||||
|
f" - hostPath: {kind_mount_root}\n" f" containerPath: /mnt\n"
|
||||||
|
)
|
||||||
|
mount_root_emitted = True
|
||||||
|
|
||||||
# Note these paths are relative to the location of the pod files (at present)
|
# Note these paths are relative to the location of the pod files (at present)
|
||||||
# So we need to fix up to make them correct and absolute because kind assumes
|
# So we need to fix up to make them correct and absolute because kind assumes
|
||||||
# relative to the cwd.
|
# relative to the cwd.
|
||||||
|
|
@ -646,6 +670,12 @@ def _generate_kind_mounts(parsed_pod_files, deployment_dir, deployment_context):
|
||||||
volume_host_path_map[volume_name],
|
volume_host_path_map[volume_name],
|
||||||
deployment_dir,
|
deployment_dir,
|
||||||
)
|
)
|
||||||
|
# Skip individual extraMount if covered
|
||||||
|
# by the kind-mount-root single mount
|
||||||
|
if mount_root_emitted and str(host_path).startswith(
|
||||||
|
kind_mount_root
|
||||||
|
):
|
||||||
|
continue
|
||||||
container_path = get_kind_pv_bind_mount_path(
|
container_path = get_kind_pv_bind_mount_path(
|
||||||
volume_name
|
volume_name
|
||||||
)
|
)
|
||||||
|
|
@ -982,7 +1012,7 @@ def translate_sidecar_service_names(
|
||||||
|
|
||||||
|
|
||||||
def envs_from_environment_variables_map(
|
def envs_from_environment_variables_map(
|
||||||
map: Mapping[str, str]
|
map: Mapping[str, str],
|
||||||
) -> List[client.V1EnvVar]:
|
) -> List[client.V1EnvVar]:
|
||||||
result = []
|
result = []
|
||||||
for env_var, env_val in map.items():
|
for env_var, env_val in map.items():
|
||||||
|
|
|
||||||
|
|
@ -264,6 +264,17 @@ class Spec:
|
||||||
def is_kind_deployment(self):
|
def is_kind_deployment(self):
|
||||||
return self.get_deployment_type() in [constants.k8s_kind_deploy_type]
|
return self.get_deployment_type() in [constants.k8s_kind_deploy_type]
|
||||||
|
|
||||||
|
def get_kind_mount_root(self) -> typing.Optional[str]:
|
||||||
|
"""Return kind-mount-root path or None.
|
||||||
|
|
||||||
|
When set, laconic-so emits a single Kind extraMount mapping this
|
||||||
|
host path to /mnt inside the Kind node. Volumes with host paths
|
||||||
|
under this root resolve to /mnt/{relative_path} and don't need
|
||||||
|
individual extraMounts. This allows adding new volumes without
|
||||||
|
recreating the Kind cluster.
|
||||||
|
"""
|
||||||
|
return self.obj.get(constants.kind_mount_root_key)
|
||||||
|
|
||||||
def get_maintenance_service(self) -> typing.Optional[str]:
|
def get_maintenance_service(self) -> typing.Optional[str]:
|
||||||
"""Return maintenance-service value (e.g. 'dumpster-maintenance:8000') or None.
|
"""Return maintenance-service value (e.g. 'dumpster-maintenance:8000') or None.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue