Skip to content

Commit ec852f0

Browse files
switch to job with update to unique names
1 parent edec8c2 commit ec852f0

2 files changed

Lines changed: 93 additions & 61 deletions

File tree

charts/cron-job/templates/tests/helm-test.yaml

Lines changed: 92 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -11,82 +11,114 @@
1111
{{- $activeDeadlineSeconds := $cronjob.activeDeadlineSeconds | default $global.activeDeadlineSeconds }}
1212
{{- $cronjobName := include "charts-cron-job.fullname" (dict "root" $ "cronjob" $cronjob "index" $index) }}
1313
{{- $saName := printf "%s-helm-test" $cronjobName | trunc 63 | trimSuffix "-" }}
14-
{{- $jobName := printf "%s-helm-test" $cronjobName | trunc 63 | trimSuffix "-" }}
14+
{{- $executorName := printf "%s-helm-test-executor" $cronjobName | trunc 63 | trimSuffix "-" }}
15+
{{- /* Spawned test Job name base: truncated to 46 chars so the runtime suffix
16+
"-<10-digit-epoch>-<5-digit-random>" (17 chars max) fits within the
17+
63-char Kubernetes resource name limit. */ -}}
18+
{{- $jobNameBase := printf "%s-test" $cronjobName | trunc 46 | trimSuffix "-" }}
1519
---
16-
apiVersion: v1
17-
kind: Pod
20+
apiVersion: batch/v1
21+
kind: Job
1822
metadata:
19-
name: {{ printf "%s-helm-test" $cronjobName | trunc 63 | trimSuffix "-" }}
23+
name: {{ $executorName }}
2024
namespace: {{ $.Release.Namespace }}
2125
labels:
2226
{{- include "charts-cron-job.labels" (dict "root" $ "cronjob" $cronjob) | nindent 4 }}
2327
annotations:
2428
helm.sh/hook: test
2529
helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded
2630
spec:
27-
serviceAccountName: {{ $saName }}
28-
restartPolicy: Never
29-
containers:
30-
- name: helm-test
31-
image: {{ $.Values.global.helmTest.image }}
32-
command:
33-
- /bin/sh
34-
- -c
35-
- |
36-
set -e
31+
backoffLimit: 1
32+
template:
33+
metadata:
34+
labels:
35+
{{- include "charts-cron-job.labels" (dict "root" $ "cronjob" $cronjob) | nindent 8 }}
36+
spec:
37+
serviceAccountName: {{ $saName }}
38+
restartPolicy: Never
39+
containers:
40+
- name: helm-test
41+
image: {{ $.Values.global.image.repository }}/{{ $.Values.global.helmTest.image }}
42+
command:
43+
- /bin/sh
44+
- -c
45+
- |
46+
set -e
3747
38-
CRONJOB="{{ $cronjobName }}"
39-
NAMESPACE="{{ $.Release.Namespace }}"
40-
POLICY="{{ $concurrencyPolicy }}"
41-
JOB_NAME="{{ $jobName }}"
42-
TIMEOUT="{{ $activeDeadlineSeconds }}"
48+
CRONJOB="{{ $cronjobName }}"
49+
NAMESPACE="{{ $.Release.Namespace }}"
50+
POLICY="{{ $concurrencyPolicy }}"
51+
TIMEOUT="{{ $activeDeadlineSeconds }}"
4352
44-
echo "==> Helm test for CronJob: ${CRONJOB}"
45-
echo " ConcurrencyPolicy : ${POLICY}"
46-
echo " Test Job name : ${JOB_NAME}"
47-
echo " Timeout : ${TIMEOUT}s"
53+
# Unique suffix: epoch seconds + shell $RANDOM (0-32767).
54+
# Base is pre-truncated to 46 chars at render time so the full name
55+
# stays within the 63-char Kubernetes resource name limit.
56+
JOB_NAME="{{ $jobNameBase }}-$(date +%s)-${RANDOM}"
4857
49-
# ── Forbid: wait for any currently-active job to finish ──────────
50-
if [ "$POLICY" = "Forbid" ]; then
51-
echo "==> ConcurrencyPolicy=Forbid: waiting for active jobs to finish before creating test job..."
52-
ELAPSED=0
53-
while true; do
54-
ACTIVE=$(kubectl get jobs -n "${NAMESPACE}" \
55-
--selector="batch.kubernetes.io/controller-uid=$(kubectl get cronjob "${CRONJOB}" -n "${NAMESPACE}" -o jsonpath='{.metadata.uid}')" \
56-
-o jsonpath='{range .items[*]}{.status.active}{"\n"}{end}' 2>/dev/null \
57-
| grep -c '^[1-9]' || true)
58-
if [ "${ACTIVE}" -eq 0 ]; then
59-
echo " No active jobs found. Proceeding."
60-
break
61-
fi
62-
if [ "${ELAPSED}" -ge "${TIMEOUT}" ]; then
63-
echo "ERROR: Timed out after ${TIMEOUT}s waiting for active jobs to finish."
64-
exit 1
65-
fi
66-
echo " ${ACTIVE} active job(s) still running. Waiting 10s... (${ELAPSED}s elapsed)"
67-
sleep 10
68-
ELAPSED=$((ELAPSED + 10))
69-
done
58+
echo "==> Helm test for CronJob: ${CRONJOB}"
59+
echo " ConcurrencyPolicy : ${POLICY}"
60+
echo " Test Job name : ${JOB_NAME}"
61+
echo " Timeout : ${TIMEOUT}s"
62+
63+
# ── Forbid: wait for any currently-active job to finish ──────────
64+
if [ "$POLICY" = "Forbid" ]; then
65+
echo "==> ConcurrencyPolicy=Forbid: waiting for active jobs to finish before creating test job..."
7066
71-
# ── Replace: delete any existing test job first ──────────────────
72-
elif [ "$POLICY" = "Replace" ]; then
73-
echo "==> ConcurrencyPolicy=Replace: deleting existing test job if present..."
74-
kubectl delete job "${JOB_NAME}" -n "${NAMESPACE}" --ignore-not-found
75-
echo " Done."
76-
fi
67+
# Resolve the CronJob UID at runtime. Jobs spawned by this CronJob
68+
# carry an ownerReference pointing to this UID — the authoritative
69+
# way to identify all jobs that belong to a specific CronJob instance
70+
# (as seen in the job's .metadata.ownerReferences[].uid field).
71+
CRONJOB_UID=$(kubectl get cronjob "${CRONJOB}" -n "${NAMESPACE}" \
72+
-o jsonpath="{.metadata.uid}")
73+
echo " CronJob UID: ${CRONJOB_UID}"
74+
75+
ELAPSED=0
76+
while true; do
77+
# Emit "<ownerUID> <activeCount>" for every job, then keep only
78+
# lines where the ownerUID matches this CronJob and activeCount > 0.
79+
ACTIVE=$(kubectl get jobs -n "${NAMESPACE}" \
80+
-o jsonpath="{range .items[*]}{.metadata.ownerReferences[0].uid}{' '}{.status.active}{'\n'}{end}" \
81+
| awk -v uid="${CRONJOB_UID}" \
82+
"NF==2 && \$1==uid && \$2+0>0 {count++} END {print count+0}")
83+
if [ "${ACTIVE}" -eq 0 ]; then
84+
echo " No active jobs found. Proceeding."
85+
break
86+
fi
87+
if [ "${ELAPSED}" -ge "${TIMEOUT}" ]; then
88+
echo "ERROR: Timed out after ${TIMEOUT}s waiting for active jobs to finish."
89+
exit 1
90+
fi
91+
echo " ${ACTIVE} active job(s) still running. Waiting 10s... (${ELAPSED}s elapsed)"
92+
sleep 10
93+
ELAPSED=$((ELAPSED + 10))
94+
done
95+
96+
# ── Replace: delete any active scheduler-spawned jobs first ──────
97+
elif [ "$POLICY" = "Replace" ]; then
98+
echo "==> ConcurrencyPolicy=Replace: deleting active jobs owned by this CronJob..."
99+
CRONJOB_UID=$(kubectl get cronjob "${CRONJOB}" -n "${NAMESPACE}" \
100+
-o jsonpath="{.metadata.uid}")
101+
# Find names of all jobs whose ownerReference points to this CronJob
102+
# and that currently have active pods, then delete them.
103+
kubectl get jobs -n "${NAMESPACE}" \
104+
-o jsonpath="{range .items[*]}{.metadata.ownerReferences[0].uid}{' '}{.status.active}{' '}{.metadata.name}{'\n'}{end}" \
105+
| awk -v uid="${CRONJOB_UID}" "NF==3 && \$1==uid && \$2+0>0 {print \$3}" \
106+
| xargs -r kubectl delete job -n "${NAMESPACE}" --ignore-not-found
107+
echo " Done."
108+
fi
77109
78-
# ── Create the test job from the CronJob ─────────────────────────
79-
echo "==> Creating test job '${JOB_NAME}' from CronJob '${CRONJOB}'..."
80-
kubectl create job "${JOB_NAME}" --from=cronjob/"${CRONJOB}" -n "${NAMESPACE}"
110+
# ── Create the test job from the CronJob ─────────────────────────
111+
echo "==> Creating test job '${JOB_NAME}' from CronJob '${CRONJOB}'..."
112+
kubectl create job "${JOB_NAME}" --from=cronjob/"${CRONJOB}" -n "${NAMESPACE}"
81113
82-
# ── Wait for completion ───────────────────────────────────────────
83-
echo "==> Waiting for job '${JOB_NAME}' to complete (timeout: ${TIMEOUT}s)..."
84-
kubectl wait job/"${JOB_NAME}" \
85-
-n "${NAMESPACE}" \
86-
--for=condition=complete \
87-
--timeout="${TIMEOUT}s"
114+
# ── Wait for completion ───────────────────────────────────────────
115+
echo "==> Waiting for job '${JOB_NAME}' to complete (timeout: ${TIMEOUT}s)..."
116+
kubectl wait job/"${JOB_NAME}" \
117+
-n "${NAMESPACE}" \
118+
--for=condition=complete \
119+
--timeout="${TIMEOUT}s"
88120
89-
echo "==> Test job completed successfully."
121+
echo "==> Test job completed successfully."
90122
{{- end }}
91123

92124
{{- end }}

charts/cron-job/values.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,4 +160,4 @@ global:
160160

161161
helmTest:
162162
enabled: true
163-
image: alpine/k8s:latest # Image used by the helm test pod; must contain kubectl
163+
image: dockerhub/alpine/kubectl:latest # Image used by the helm test pod; must contain kubectl

0 commit comments

Comments
 (0)