feat: add kind-mount-root for unified Kind extraMount
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>
This commit is contained in:
parent
9109cfb7a1
commit
8d03083d0d
@ -46,3 +46,4 @@ runtime_class_key = "runtime-class"
|
||||
high_memlock_runtime = "high-memlock"
|
||||
high_memlock_spec_filename = "high-memlock-spec.json"
|
||||
acme_email_key = "acme-email"
|
||||
kind_mount_root_key = "kind-mount-root"
|
||||
|
||||
@ -455,7 +455,11 @@ class ClusterInfo:
|
||||
)
|
||||
if self.spec.is_kind_deployment():
|
||||
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:
|
||||
host_path = client.V1HostPathVolumeSource(path=volume_path)
|
||||
|
||||
@ -444,7 +444,20 @@ def named_volumes_from_pod_files(parsed_pod_files):
|
||||
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}"
|
||||
|
||||
|
||||
@ -567,6 +580,7 @@ def _generate_kind_mounts(parsed_pod_files, deployment_dir, deployment_context):
|
||||
volume_definitions = []
|
||||
volume_host_path_map = _get_host_paths_for_volumes(deployment_context)
|
||||
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)
|
||||
# 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"
|
||||
)
|
||||
|
||||
# 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)
|
||||
# So we need to fix up to make them correct and absolute because kind assumes
|
||||
# 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],
|
||||
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(
|
||||
volume_name
|
||||
)
|
||||
@ -982,7 +1012,7 @@ def translate_sidecar_service_names(
|
||||
|
||||
|
||||
def envs_from_environment_variables_map(
|
||||
map: Mapping[str, str]
|
||||
map: Mapping[str, str],
|
||||
) -> List[client.V1EnvVar]:
|
||||
result = []
|
||||
for env_var, env_val in map.items():
|
||||
|
||||
@ -264,6 +264,17 @@ class Spec:
|
||||
def is_kind_deployment(self):
|
||||
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]:
|
||||
"""Return maintenance-service value (e.g. 'dumpster-maintenance:8000') or None.
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user