From cf2269ebdc7ec6259b99f6db16bf00e00f30b98b Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Thu, 16 Apr 2026 04:21:40 +0000 Subject: [PATCH] so-l2l: add --delete-namespace flag to stop/down for full teardown Plumb --delete-namespace through the CLI (stop, down), the down_operation, the Deployer abstract method, and both k8s / compose implementations. When set, k8s down() calls the existing _delete_namespace() + _wait_for_namespace_gone() after label- based resource deletion, restoring the old behavior for the teardown case. Compose mode ignores the flag. Default remains False, so normal stop/restart still keep the namespace Active (Part B behavior). Co-Authored-By: Claude Opus 4.6 (1M context) --- .../deploy/compose/deploy_docker.py | 3 ++- stack_orchestrator/deploy/deploy.py | 9 ++++++- stack_orchestrator/deploy/deployer.py | 2 +- stack_orchestrator/deploy/deployment.py | 24 +++++++++++++++---- stack_orchestrator/deploy/k8s/deploy_k8s.py | 8 ++++++- 5 files changed, 38 insertions(+), 8 deletions(-) diff --git a/stack_orchestrator/deploy/compose/deploy_docker.py b/stack_orchestrator/deploy/compose/deploy_docker.py index 2804c4ea..0efaa10f 100644 --- a/stack_orchestrator/deploy/compose/deploy_docker.py +++ b/stack_orchestrator/deploy/compose/deploy_docker.py @@ -55,7 +55,8 @@ class DockerDeployer(Deployer): except DockerException as e: raise DeployerException(e) - def down(self, timeout, volumes, skip_cluster_management): + def down(self, timeout, volumes, skip_cluster_management, delete_namespace=False): + # delete_namespace is k8s-only; ignored in compose mode. if not opts.o.dry_run: try: return self.docker.compose.down(timeout=timeout, volumes=volumes) diff --git a/stack_orchestrator/deploy/deploy.py b/stack_orchestrator/deploy/deploy.py index 8ede3e72..fb32f91c 100644 --- a/stack_orchestrator/deploy/deploy.py +++ b/stack_orchestrator/deploy/deploy.py @@ -172,7 +172,13 @@ def up_operation( ) -def down_operation(ctx, delete_volumes, extra_args_list, skip_cluster_management=False): +def down_operation( + ctx, + delete_volumes, + extra_args_list, + skip_cluster_management=False, + delete_namespace=False, +): timeout_arg = None if extra_args_list: timeout_arg = extra_args_list[0] @@ -182,6 +188,7 @@ def down_operation(ctx, delete_volumes, extra_args_list, skip_cluster_management timeout=timeout_arg, volumes=delete_volumes, skip_cluster_management=skip_cluster_management, + delete_namespace=delete_namespace, ) diff --git a/stack_orchestrator/deploy/deployer.py b/stack_orchestrator/deploy/deployer.py index 57e45f34..107658ce 100644 --- a/stack_orchestrator/deploy/deployer.py +++ b/stack_orchestrator/deploy/deployer.py @@ -24,7 +24,7 @@ class Deployer(ABC): pass @abstractmethod - def down(self, timeout, volumes, skip_cluster_management): + def down(self, timeout, volumes, skip_cluster_management, delete_namespace=False): pass @abstractmethod diff --git a/stack_orchestrator/deploy/deployment.py b/stack_orchestrator/deploy/deployment.py index 4edf8c52..e0031561 100644 --- a/stack_orchestrator/deploy/deployment.py +++ b/stack_orchestrator/deploy/deployment.py @@ -157,13 +157,21 @@ def prepare(ctx, skip_cluster_management): default=True, help="Skip cluster initialization/tear-down (only for kind-k8s deployments)", ) +@click.option( + "--delete-namespace", + is_flag=True, + default=False, + help="Also delete the k8s namespace (full teardown)", +) @click.argument("extra_args", nargs=-1) # help: command: down @click.pass_context -def down(ctx, delete_volumes, skip_cluster_management, extra_args): +def down(ctx, delete_volumes, skip_cluster_management, delete_namespace, extra_args): # Get the stack config file name # TODO: add cluster name and env file here ctx.obj = make_deploy_context(ctx) - down_operation(ctx, delete_volumes, extra_args, skip_cluster_management) + down_operation( + ctx, delete_volumes, extra_args, skip_cluster_management, delete_namespace + ) # stop is the preferred alias for down @@ -176,12 +184,20 @@ def down(ctx, delete_volumes, skip_cluster_management, extra_args): default=True, help="Skip cluster initialization/tear-down (only for kind-k8s deployments)", ) +@click.option( + "--delete-namespace", + is_flag=True, + default=False, + help="Also delete the k8s namespace (full teardown)", +) @click.argument("extra_args", nargs=-1) # help: command: down @click.pass_context -def stop(ctx, delete_volumes, skip_cluster_management, extra_args): +def stop(ctx, delete_volumes, skip_cluster_management, delete_namespace, extra_args): # TODO: add cluster name and env file here ctx.obj = make_deploy_context(ctx) - down_operation(ctx, delete_volumes, extra_args, skip_cluster_management) + down_operation( + ctx, delete_volumes, extra_args, skip_cluster_management, delete_namespace + ) @command.command() diff --git a/stack_orchestrator/deploy/k8s/deploy_k8s.py b/stack_orchestrator/deploy/k8s/deploy_k8s.py index 4c57b38c..a29e767d 100644 --- a/stack_orchestrator/deploy/k8s/deploy_k8s.py +++ b/stack_orchestrator/deploy/k8s/deploy_k8s.py @@ -912,7 +912,7 @@ class K8sDeployer(Deployer): call_stack_deploy_start(self.deployment_context) - def down(self, timeout, volumes, skip_cluster_management): + def down(self, timeout, volumes, skip_cluster_management, delete_namespace=False): self.skip_cluster_management = skip_cluster_management self.connect_api() @@ -940,6 +940,12 @@ class K8sDeployer(Deployer): self._delete_labeled_resources(ns, label_selector, delete_volumes=volumes) + # Full teardown: nuke the namespace and wait for termination so that a + # subsequent up() can recreate it cleanly. + if delete_namespace: + self._delete_namespace() + self._wait_for_namespace_gone() + if self.is_kind() and not self.skip_cluster_management: destroy_cluster(self.kind_cluster_name)