Compare commits
4 Commits
main
...
caddy-pvc-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1473c5ec4d | ||
|
|
d31f76eb5a | ||
|
|
21d0975e71 | ||
|
|
411e777980 |
@ -301,7 +301,8 @@ class K8sDeployer(Deployer):
|
|||||||
self.connect_api()
|
self.connect_api()
|
||||||
if self.is_kind() and not self.skip_cluster_management:
|
if self.is_kind() and not self.skip_cluster_management:
|
||||||
# Configure ingress controller (not installed by default in kind)
|
# Configure ingress controller (not installed by default in kind)
|
||||||
install_ingress_for_kind()
|
acme_email = self.cluster_info.spec.get_acme_email()
|
||||||
|
install_ingress_for_kind(acme_email=acme_email)
|
||||||
# Wait for ingress to start
|
# Wait for ingress to start
|
||||||
# (deployment provisioning will fail unless this is done)
|
# (deployment provisioning will fail unless this is done)
|
||||||
wait_for_ingress_in_kind()
|
wait_for_ingress_in_kind()
|
||||||
|
|||||||
@ -27,48 +27,6 @@ from stack_orchestrator.deploy.deployer import DeployerException
|
|||||||
from stack_orchestrator import constants
|
from stack_orchestrator import constants
|
||||||
|
|
||||||
|
|
||||||
def is_host_path_mount(volume_name: str) -> bool:
|
|
||||||
"""Check if a volume name is a host path mount (starts with /, ., or ~)."""
|
|
||||||
return volume_name.startswith(("/", ".", "~"))
|
|
||||||
|
|
||||||
|
|
||||||
def sanitize_host_path_to_volume_name(host_path: str) -> str:
|
|
||||||
"""Convert a host path to a valid k8s volume name.
|
|
||||||
|
|
||||||
K8s volume names must be lowercase, alphanumeric, with - allowed.
|
|
||||||
E.g., '../config/test/script.sh' -> 'host-path-config-test-script-sh'
|
|
||||||
"""
|
|
||||||
# Remove leading ./ or ../
|
|
||||||
clean_path = re.sub(r"^\.+/", "", host_path)
|
|
||||||
# Replace path separators and dots with hyphens
|
|
||||||
name = re.sub(r"[/.]", "-", clean_path)
|
|
||||||
# Remove any non-alphanumeric characters except hyphens
|
|
||||||
name = re.sub(r"[^a-zA-Z0-9-]", "", name)
|
|
||||||
# Convert to lowercase
|
|
||||||
name = name.lower()
|
|
||||||
# Remove leading/trailing hyphens and collapse multiple hyphens
|
|
||||||
name = re.sub(r"-+", "-", name).strip("-")
|
|
||||||
# Prefix with 'host-path-' to distinguish from named volumes
|
|
||||||
return f"host-path-{name}"
|
|
||||||
|
|
||||||
|
|
||||||
def resolve_host_path_for_kind(host_path: str, deployment_dir: Path) -> Path:
|
|
||||||
"""Resolve a host path mount (relative to compose file) to absolute path.
|
|
||||||
|
|
||||||
Compose files are in deployment_dir/compose/, so '../config/foo'
|
|
||||||
resolves to deployment_dir/config/foo.
|
|
||||||
"""
|
|
||||||
# The path is relative to the compose directory
|
|
||||||
compose_dir = deployment_dir.joinpath("compose")
|
|
||||||
resolved = compose_dir.joinpath(host_path).resolve()
|
|
||||||
return resolved
|
|
||||||
|
|
||||||
|
|
||||||
def get_kind_host_path_mount_path(sanitized_name: str) -> str:
|
|
||||||
"""Get the path inside the kind node where a host path mount will be available."""
|
|
||||||
return f"/mnt/{sanitized_name}"
|
|
||||||
|
|
||||||
|
|
||||||
def get_kind_cluster():
|
def get_kind_cluster():
|
||||||
"""Get an existing kind cluster, if any.
|
"""Get an existing kind cluster, if any.
|
||||||
|
|
||||||
@ -219,7 +177,6 @@ def volume_mounts_for_service(parsed_pod_files, service):
|
|||||||
for mount_string in volumes:
|
for mount_string in volumes:
|
||||||
# Looks like: test-data:/data
|
# Looks like: test-data:/data
|
||||||
# or test-data:/data:ro or test-data:/data:rw
|
# or test-data:/data:ro or test-data:/data:rw
|
||||||
# or ../config/file.sh:/opt/file.sh (host path mount)
|
|
||||||
if opts.o.debug:
|
if opts.o.debug:
|
||||||
print(f"mount_string: {mount_string}")
|
print(f"mount_string: {mount_string}")
|
||||||
mount_split = mount_string.split(":")
|
mount_split = mount_string.split(":")
|
||||||
@ -228,21 +185,13 @@ def volume_mounts_for_service(parsed_pod_files, service):
|
|||||||
mount_options = (
|
mount_options = (
|
||||||
mount_split[2] if len(mount_split) == 3 else None
|
mount_split[2] if len(mount_split) == 3 else None
|
||||||
)
|
)
|
||||||
# For host path mounts, use sanitized name
|
|
||||||
if is_host_path_mount(volume_name):
|
|
||||||
k8s_volume_name = sanitize_host_path_to_volume_name(
|
|
||||||
volume_name
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
k8s_volume_name = volume_name
|
|
||||||
if opts.o.debug:
|
if opts.o.debug:
|
||||||
print(f"volume_name: {volume_name}")
|
print(f"volume_name: {volume_name}")
|
||||||
print(f"k8s_volume_name: {k8s_volume_name}")
|
|
||||||
print(f"mount path: {mount_path}")
|
print(f"mount path: {mount_path}")
|
||||||
print(f"mount options: {mount_options}")
|
print(f"mount options: {mount_options}")
|
||||||
volume_device = client.V1VolumeMount(
|
volume_device = client.V1VolumeMount(
|
||||||
mount_path=mount_path,
|
mount_path=mount_path,
|
||||||
name=k8s_volume_name,
|
name=volume_name,
|
||||||
read_only="ro" == mount_options,
|
read_only="ro" == mount_options,
|
||||||
)
|
)
|
||||||
result.append(volume_device)
|
result.append(volume_device)
|
||||||
@ -251,12 +200,8 @@ def volume_mounts_for_service(parsed_pod_files, service):
|
|||||||
|
|
||||||
def volumes_for_pod_files(parsed_pod_files, spec, app_name):
|
def volumes_for_pod_files(parsed_pod_files, spec, app_name):
|
||||||
result = []
|
result = []
|
||||||
seen_host_path_volumes = set() # Track host path volumes to avoid duplicates
|
|
||||||
|
|
||||||
for pod in parsed_pod_files:
|
for pod in parsed_pod_files:
|
||||||
parsed_pod_file = parsed_pod_files[pod]
|
parsed_pod_file = parsed_pod_files[pod]
|
||||||
|
|
||||||
# Handle named volumes from top-level volumes section
|
|
||||||
if "volumes" in parsed_pod_file:
|
if "volumes" in parsed_pod_file:
|
||||||
volumes = parsed_pod_file["volumes"]
|
volumes = parsed_pod_file["volumes"]
|
||||||
for volume_name in volumes.keys():
|
for volume_name in volumes.keys():
|
||||||
@ -275,35 +220,6 @@ def volumes_for_pod_files(parsed_pod_files, spec, app_name):
|
|||||||
name=volume_name, persistent_volume_claim=claim
|
name=volume_name, persistent_volume_claim=claim
|
||||||
)
|
)
|
||||||
result.append(volume)
|
result.append(volume)
|
||||||
|
|
||||||
# Handle host path mounts from service volumes
|
|
||||||
if "services" in parsed_pod_file:
|
|
||||||
services = parsed_pod_file["services"]
|
|
||||||
for service_name in services:
|
|
||||||
service_obj = services[service_name]
|
|
||||||
if "volumes" in service_obj:
|
|
||||||
for mount_string in service_obj["volumes"]:
|
|
||||||
mount_split = mount_string.split(":")
|
|
||||||
volume_source = mount_split[0]
|
|
||||||
if is_host_path_mount(volume_source):
|
|
||||||
sanitized_name = sanitize_host_path_to_volume_name(
|
|
||||||
volume_source
|
|
||||||
)
|
|
||||||
if sanitized_name not in seen_host_path_volumes:
|
|
||||||
seen_host_path_volumes.add(sanitized_name)
|
|
||||||
# Create hostPath volume for mount inside kind node
|
|
||||||
kind_mount_path = get_kind_host_path_mount_path(
|
|
||||||
sanitized_name
|
|
||||||
)
|
|
||||||
host_path_source = client.V1HostPathVolumeSource(
|
|
||||||
path=kind_mount_path, type="FileOrCreate"
|
|
||||||
)
|
|
||||||
volume = client.V1Volume(
|
|
||||||
name=sanitized_name, host_path=host_path_source
|
|
||||||
)
|
|
||||||
result.append(volume)
|
|
||||||
if opts.o.debug:
|
|
||||||
print(f"Created hostPath volume: {sanitized_name}")
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@ -322,8 +238,6 @@ def _make_absolute_host_path(data_mount_path: Path, deployment_dir: Path) -> Pat
|
|||||||
def _generate_kind_mounts(parsed_pod_files, deployment_dir, deployment_context):
|
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
|
|
||||||
|
|
||||||
# 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.
|
||||||
@ -338,58 +252,28 @@ def _generate_kind_mounts(parsed_pod_files, deployment_dir, deployment_context):
|
|||||||
for mount_string in volumes:
|
for mount_string in volumes:
|
||||||
# Looks like: test-data:/data
|
# Looks like: test-data:/data
|
||||||
# or test-data:/data:ro or test-data:/data:rw
|
# or test-data:/data:ro or test-data:/data:rw
|
||||||
# or ../config/file.sh:/opt/file.sh (host path mount)
|
|
||||||
if opts.o.debug:
|
if opts.o.debug:
|
||||||
print(f"mount_string: {mount_string}")
|
print(f"mount_string: {mount_string}")
|
||||||
mount_split = mount_string.split(":")
|
mount_split = mount_string.split(":")
|
||||||
volume_name = mount_split[0]
|
volume_name = mount_split[0]
|
||||||
mount_path = mount_split[1]
|
mount_path = mount_split[1]
|
||||||
|
if opts.o.debug:
|
||||||
if is_host_path_mount(volume_name):
|
print(f"volume_name: {volume_name}")
|
||||||
# Host path mount - add extraMount for kind
|
print(f"map: {volume_host_path_map}")
|
||||||
sanitized_name = sanitize_host_path_to_volume_name(
|
print(f"mount path: {mount_path}")
|
||||||
volume_name
|
if volume_name not in deployment_context.spec.get_configmaps():
|
||||||
)
|
if volume_host_path_map[volume_name]:
|
||||||
if sanitized_name not in seen_host_path_mounts:
|
host_path = _make_absolute_host_path(
|
||||||
seen_host_path_mounts.add(sanitized_name)
|
volume_host_path_map[volume_name],
|
||||||
# Resolve path relative to compose directory
|
deployment_dir,
|
||||||
host_path = resolve_host_path_for_kind(
|
|
||||||
volume_name, deployment_dir
|
|
||||||
)
|
)
|
||||||
container_path = get_kind_host_path_mount_path(
|
container_path = get_kind_pv_bind_mount_path(
|
||||||
sanitized_name
|
volume_name
|
||||||
)
|
)
|
||||||
volume_definitions.append(
|
volume_definitions.append(
|
||||||
f" - hostPath: {host_path}\n"
|
f" - hostPath: {host_path}\n"
|
||||||
f" containerPath: {container_path}\n"
|
f" containerPath: {container_path}\n"
|
||||||
)
|
)
|
||||||
if opts.o.debug:
|
|
||||||
print(f"Added host path mount: {host_path}")
|
|
||||||
else:
|
|
||||||
# Named volume
|
|
||||||
if opts.o.debug:
|
|
||||||
print(f"volume_name: {volume_name}")
|
|
||||||
print(f"map: {volume_host_path_map}")
|
|
||||||
print(f"mount path: {mount_path}")
|
|
||||||
if (
|
|
||||||
volume_name
|
|
||||||
not in deployment_context.spec.get_configmaps()
|
|
||||||
):
|
|
||||||
if (
|
|
||||||
volume_name in volume_host_path_map
|
|
||||||
and volume_host_path_map[volume_name]
|
|
||||||
):
|
|
||||||
host_path = _make_absolute_host_path(
|
|
||||||
volume_host_path_map[volume_name],
|
|
||||||
deployment_dir,
|
|
||||||
)
|
|
||||||
container_path = get_kind_pv_bind_mount_path(
|
|
||||||
volume_name
|
|
||||||
)
|
|
||||||
volume_definitions.append(
|
|
||||||
f" - hostPath: {host_path}\n"
|
|
||||||
f" containerPath: {container_path}\n"
|
|
||||||
)
|
|
||||||
return (
|
return (
|
||||||
""
|
""
|
||||||
if len(volume_definitions) == 0
|
if len(volume_definitions) == 0
|
||||||
|
|||||||
@ -117,6 +117,9 @@ class Spec:
|
|||||||
def get_http_proxy(self):
|
def get_http_proxy(self):
|
||||||
return self.obj.get(constants.network_key, {}).get(constants.http_proxy_key, [])
|
return self.obj.get(constants.network_key, {}).get(constants.http_proxy_key, [])
|
||||||
|
|
||||||
|
def get_acme_email(self):
|
||||||
|
return self.obj.get(constants.network_key, {}).get("acme-email", "")
|
||||||
|
|
||||||
def get_annotations(self):
|
def get_annotations(self):
|
||||||
return self.obj.get(constants.annotations_key, {})
|
return self.obj.get(constants.annotations_key, {})
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user