From 258045190cd53354352f95bdc831f2d3be1f3172 Mon Sep 17 00:00:00 2001 From: Prathamesh Musale Date: Wed, 15 Apr 2026 13:18:26 +0000 Subject: [PATCH] so-l2l Part A complete: skip Job create on 409 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Deployments, Services, ConfigMaps, Secrets, Ingresses, and Endpoints already use create-or-replace in up(). Jobs were the only remaining gap — they now skip-if-exists since Jobs are one-shot and re-running on restart is usually unwanted. This completes the in-place restart story alongside Part B: restart (which already avoids down()) and stop+start (now that down() keeps the namespace) both run up() idempotently against a live namespace. Co-Authored-By: Claude Opus 4.6 (1M context) --- stack_orchestrator/deploy/k8s/deploy_k8s.py | 31 ++++++++++++++------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/stack_orchestrator/deploy/k8s/deploy_k8s.py b/stack_orchestrator/deploy/k8s/deploy_k8s.py index c51f93b9..4c57b38c 100644 --- a/stack_orchestrator/deploy/k8s/deploy_k8s.py +++ b/stack_orchestrator/deploy/k8s/deploy_k8s.py @@ -709,16 +709,27 @@ class K8sDeployer(Deployer): if opts.o.debug: print(f"Sending this job: {job}") if not opts.o.dry_run: - job_resp = self.batch_api.create_namespaced_job( - body=job, namespace=self.k8s_namespace - ) - if opts.o.debug: - print("Job created:") - if job_resp.metadata: - print( - f" {job_resp.metadata.namespace} " - f"{job_resp.metadata.name}" - ) + job_name = job.metadata.name + try: + job_resp = self.batch_api.create_namespaced_job( + body=job, namespace=self.k8s_namespace + ) + if opts.o.debug: + print("Job created:") + if job_resp.metadata: + print( + f" {job_resp.metadata.namespace} " + f"{job_resp.metadata.name}" + ) + except ApiException as e: + if e.status == 409: + # Job already exists from a prior run. Jobs are one- + # shot — don't recreate on restart. Delete the Job + # explicitly to re-run (stop --delete-volumes also + # clears them via label-based cleanup). + print(f"Job {job_name} already exists, skipping") + else: + raise def _find_certificate_for_host_name(self, host_name): all_certificates = self.custom_obj_api.list_namespaced_custom_object(