@@ -476,10 +476,12 @@ def local_registry_image(image: str) -> str:
476476 return f"localhost:{ LOCAL_REGISTRY_HOST_PORT } /{ image } "
477477
478478
479- def pods_in_deployment (core_api : client .CoreV1Api , deployment_name : str ):
479+ def pods_in_deployment (
480+ core_api : client .CoreV1Api , deployment_name : str , namespace : str = "default"
481+ ):
480482 pods = []
481483 pod_response = core_api .list_namespaced_pod (
482- namespace = "default" , label_selector = f"app={ deployment_name } "
484+ namespace = namespace , label_selector = f"app={ deployment_name } "
483485 )
484486 if opts .o .debug :
485487 print (f"pod_response: { pod_response } " )
@@ -489,9 +491,14 @@ def pods_in_deployment(core_api: client.CoreV1Api, deployment_name: str):
489491 return pods
490492
491493
492- def containers_in_pod (core_api : client .CoreV1Api , pod_name : str ) -> list [str ]:
494+ def containers_in_pod (
495+ core_api : client .CoreV1Api , pod_name : str , namespace : str = "default"
496+ ) -> list [str ]:
493497 containers : list [str ] = []
494- pod_response = cast (client .V1Pod , core_api .read_namespaced_pod (pod_name , namespace = "default" ))
498+ pod_response = cast (
499+ client .V1Pod ,
500+ core_api .read_namespaced_pod (pod_name , namespace = namespace ),
501+ )
495502 if opts .o .debug :
496503 print (f"pod_response: { pod_response } " )
497504 if not pod_response .spec or not pod_response .spec .containers :
@@ -521,7 +528,14 @@ def named_volumes_from_pod_files(parsed_pod_files):
521528 return named_volumes
522529
523530
524- def get_kind_pv_bind_mount_path (volume_name : str ):
531+ def get_kind_pv_bind_mount_path (
532+ volume_name : str ,
533+ kind_mount_root : str | None = None ,
534+ host_path : str | None = None ,
535+ ):
536+ if kind_mount_root and host_path and host_path .startswith (kind_mount_root ):
537+ rel = os .path .relpath (host_path , kind_mount_root )
538+ return f"/mnt/{ rel } "
525539 return f"/mnt/{ volume_name } "
526540
527541
@@ -634,6 +648,7 @@ def _generate_kind_mounts(parsed_pod_files, deployment_dir, deployment_context):
634648 volume_definitions = []
635649 volume_host_path_map = _get_host_paths_for_volumes (deployment_context )
636650 seen_host_path_mounts = set () # Track to avoid duplicate mounts
651+ kind_mount_root = deployment_context .spec .get_kind_mount_root ()
637652
638653 # Cluster state backup for offline data recovery (unique per deployment)
639654 # etcd contains all k8s state; PKI certs needed to decrypt etcd offline
@@ -654,6 +669,14 @@ def _generate_kind_mounts(parsed_pod_files, deployment_dir, deployment_context):
654669 f" propagation: HostToContainer\n "
655670 )
656671
672+ # When kind-mount-root is set, emit a single extraMount for the root.
673+ # Individual volumes whose host path starts with the root are covered
674+ # by this single mount and don't need their own extraMount entries.
675+ mount_root_emitted = False
676+ if kind_mount_root :
677+ volume_definitions .append (f" - hostPath: { kind_mount_root } \n " f" containerPath: /mnt\n " )
678+ mount_root_emitted = True
679+
657680 # Note these paths are relative to the location of the pod files (at present)
658681 # So we need to fix up to make them correct and absolute because kind assumes
659682 # relative to the cwd.
@@ -705,6 +728,11 @@ def _generate_kind_mounts(parsed_pod_files, deployment_dir, deployment_context):
705728 volume_host_path_map [volume_name ],
706729 deployment_dir ,
707730 )
731+ # Skip if covered by mount root
732+ if mount_root_emitted and str (host_path ).startswith (
733+ kind_mount_root
734+ ):
735+ continue
708736 container_path = get_kind_pv_bind_mount_path (volume_name )
709737 volume_definitions .append (
710738 f" - hostPath: { host_path } \n "
@@ -744,9 +772,35 @@ def _generate_kind_port_mappings_from_services(parsed_pod_files):
744772
745773def _generate_kind_port_mappings (parsed_pod_files ):
746774 port_definitions = []
775+ seen = set ()
747776 # Map port 80 and 443 for the Caddy ingress controller (HTTPS support)
748777 for port_string in ["80" , "443" ]:
749- port_definitions .append (f" - containerPort: { port_string } \n hostPort: { port_string } \n " )
778+ port_definitions .append (
779+ f" - containerPort: { port_string } \n " f" hostPort: { port_string } \n "
780+ )
781+ seen .add ((port_string , "TCP" ))
782+ # Map ports declared in compose services
783+ for pod in parsed_pod_files :
784+ parsed_pod_file = parsed_pod_files [pod ]
785+ if "services" in parsed_pod_file :
786+ for service_name in parsed_pod_file ["services" ]:
787+ service_obj = parsed_pod_file ["services" ][service_name ]
788+ for port_entry in service_obj .get ("ports" , []):
789+ port_str = str (port_entry )
790+ protocol = "TCP"
791+ if "/" in port_str :
792+ port_str , proto = port_str .split ("/" , 1 )
793+ protocol = proto .upper ()
794+ if ":" in port_str :
795+ port_str = port_str .split (":" )[- 1 ]
796+ port_num = port_str .strip ("'\" " )
797+ if (port_num , protocol ) not in seen :
798+ seen .add ((port_num , protocol ))
799+ port_definitions .append (
800+ f" - containerPort: { port_num } \n "
801+ f" hostPort: { port_num } \n "
802+ f" protocol: { protocol } \n "
803+ )
750804 return (
751805 ""
752806 if len (port_definitions ) == 0
@@ -950,7 +1004,8 @@ def _generate_containerd_config_patches(deployment_dir: Path, has_high_memlock:
9501004 patches = []
9511005
9521006 # Always configure the local registry mirror so kind nodes pull from it
953- registry_plugin = f'plugins."io.containerd.grpc.v1.cri".registry.mirrors."localhost:{ LOCAL_REGISTRY_HOST_PORT } "'
1007+ mirror = f"localhost:{ LOCAL_REGISTRY_HOST_PORT } "
1008+ registry_plugin = 'plugins."io.containerd.grpc.v1.cri"' f'.registry.mirrors."{ mirror } "'
9541009 endpoint = f"http://{ LOCAL_REGISTRY_NAME } :{ LOCAL_REGISTRY_CONTAINER_PORT } "
9551010 patches .append (f" [{ registry_plugin } ]\n " f' endpoint = ["{ endpoint } "]' )
9561011
0 commit comments