fix: ConfigMap volumes don't force Recreate strategy + resilient hooks

Two fixes for multi-deployment:

1. _pod_has_pvcs now excludes ConfigMap volumes from PVC detection.
   Pods with only ConfigMap volumes (like maintenance) correctly get
   RollingUpdate strategy instead of Recreate.

2. call_stack_deploy_start catches SystemExit when stack path doesn't
   resolve from cwd (common during restart). Most stacks don't have
   deploy hooks, so this is non-fatal.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
A. F. Dudley 2026-03-20 15:51:58 +00:00
parent 6923e1c23b
commit 32f6e57b70
2 changed files with 21 additions and 3 deletions

View File

@ -272,7 +272,19 @@ def call_stack_deploy_start(deployment_context):
create additional k8s resources (Services, etc.) in the deployment namespace.
The namespace can be derived as f"laconic-{deployment_context.id}".
"""
python_file_paths = _commands_plugin_paths(deployment_context.stack.name)
try:
python_file_paths = _commands_plugin_paths(deployment_context.stack.name)
except SystemExit:
# Stack path may not resolve from current cwd (e.g. during restart
# when cwd isn't the repo root). get_parsed_stack_config calls
# error_exit (sys.exit) when the stack directory doesn't exist.
# Most stacks don't have deploy hooks, so this is non-fatal.
if opts.o.debug:
print(
f"Could not resolve plugin paths for stack"
f" {deployment_context.stack.name}, skipping hooks"
)
return
for python_file_path in python_file_paths:
if python_file_path.exists():
spec = util.spec_from_file_location("commands", python_file_path)

View File

@ -696,9 +696,15 @@ class ClusterInfo:
return name
def _pod_has_pvcs(self, parsed_pod_file: Any) -> bool:
"""Check if a parsed compose file declares named volumes (PVCs)."""
"""Check if a parsed compose file declares volumes that become PVCs.
Excludes volumes that are ConfigMaps (declared in spec.configmaps),
since those don't require Recreate strategy.
"""
volumes = parsed_pod_file.get("volumes", {})
return len(volumes) > 0
configmaps = set(self.spec.get_configmaps().keys())
pvc_volumes = [v for v in volumes if v not in configmaps]
return len(pvc_volumes) > 0
def _build_common_pod_metadata(self, services: dict) -> tuple:
"""Build shared annotations, labels, affinity, tolerations for pods.