so-l2l Part A complete: skip Job create on 409

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) <noreply@anthropic.com>
pull/743/head
Prathamesh Musale 2026-04-15 13:18:26 +00:00
parent c7d2aaa0d0
commit 258045190c
1 changed files with 21 additions and 10 deletions

View File

@ -709,6 +709,8 @@ class K8sDeployer(Deployer):
if opts.o.debug: if opts.o.debug:
print(f"Sending this job: {job}") print(f"Sending this job: {job}")
if not opts.o.dry_run: if not opts.o.dry_run:
job_name = job.metadata.name
try:
job_resp = self.batch_api.create_namespaced_job( job_resp = self.batch_api.create_namespaced_job(
body=job, namespace=self.k8s_namespace body=job, namespace=self.k8s_namespace
) )
@ -719,6 +721,15 @@ class K8sDeployer(Deployer):
f" {job_resp.metadata.namespace} " f" {job_resp.metadata.namespace} "
f"{job_resp.metadata.name}" 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): def _find_certificate_for_host_name(self, host_name):
all_certificates = self.custom_obj_api.list_namespaced_custom_object( all_certificates = self.custom_obj_api.list_namespaced_custom_object(