From b6d6ad81455d91479884f2ffd05af41c8dc1d339 Mon Sep 17 00:00:00 2001 From: "A. F. Dudley" Date: Wed, 4 Mar 2026 16:41:16 +0000 Subject: [PATCH] feat(k8s): 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 are skipped for individual extraMounts and their PV paths resolve to /mnt/{relative_path}. Volumes outside the root keep individual extraMounts as before. Co-Authored-By: Claude Opus 4.6 --- stack_orchestrator/constants.py | 1 + stack_orchestrator/deploy/k8s/cluster_info.py | 6 +++++- stack_orchestrator/deploy/k8s/helpers.py | 21 ++++++++++++++++++- stack_orchestrator/deploy/spec.py | 3 +++ 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/stack_orchestrator/constants.py b/stack_orchestrator/constants.py index 75bd0ebc..2c0c8de0 100644 --- a/stack_orchestrator/constants.py +++ b/stack_orchestrator/constants.py @@ -45,3 +45,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" diff --git a/stack_orchestrator/deploy/k8s/cluster_info.py b/stack_orchestrator/deploy/k8s/cluster_info.py index 2ebf96f2..818ffa25 100644 --- a/stack_orchestrator/deploy/k8s/cluster_info.py +++ b/stack_orchestrator/deploy/k8s/cluster_info.py @@ -371,7 +371,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) diff --git a/stack_orchestrator/deploy/k8s/helpers.py b/stack_orchestrator/deploy/k8s/helpers.py index 8b367f86..95e53d73 100644 --- a/stack_orchestrator/deploy/k8s/helpers.py +++ b/stack_orchestrator/deploy/k8s/helpers.py @@ -440,7 +440,11 @@ 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): + 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}" @@ -563,6 +567,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 @@ -583,6 +588,17 @@ 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. @@ -642,6 +658,9 @@ 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 mount root + if mount_root_emitted and str(host_path).startswith(kind_mount_root): + continue container_path = get_kind_pv_bind_mount_path( volume_name ) diff --git a/stack_orchestrator/deploy/spec.py b/stack_orchestrator/deploy/spec.py index bd62779e..c4cde6f8 100644 --- a/stack_orchestrator/deploy/spec.py +++ b/stack_orchestrator/deploy/spec.py @@ -223,5 +223,8 @@ class Spec: def is_kind_deployment(self): return self.get_deployment_type() in [constants.k8s_kind_deploy_type] + def get_kind_mount_root(self): + return self.obj.get(constants.kind_mount_root_key) + def is_docker_deployment(self): return self.get_deployment_type() in [constants.compose_deploy_type]