'How to pass kubernetes namespaces dynamically to k8s cronjob

I have a cronjob that cleans some job since my kubernetes is on older version so cannot use ttlafterfinished. How can I fetch the namespaces that have this job deployed and pass the namespaces name dynamically instead of repeating the same command several times?

This is my cronjob:

kind: CronJob
metadata:
  name: jobs-cleanup
spec:
  schedule: "*/30 * * * *"
  successfulJobsHistoryLimit: 1
  failedJobsHistoryLimit: 1
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: cleanup-operator
          containers:
          - name: jobs-cleanup
            image: google.io/test/job:1.0
            args:
            - -c
            - |
              for i in $(seq 9);do 
              kubectl get jobs --sort-by=.metadata.creationTimestamp -n dev$i | grep "job-init" | cut -d' ' -f1 | tac | tail -n +2 | xargs -I % kubectl delete jobs % -n dev$i;done
              kubectl get jobs --sort-by=.metadata.creationTimestamp -n stg1 | grep "fusionauth-job" | cut -d' ' -f1 | tac | tail -n +2 | xargs -I % kubectl delete jobs % -n stg1
              kubectl get jobs --sort-by=.metadata.creationTimestamp -n pt1 | grep "fusionauth-job" | cut -d' ' -f1 | tac | tail -n +2 | xargs -I % kubectl delete jobs % -n pt1
              kubectl get jobs --sort-by=.metadata.creationTimestamp -n sit1 | grep "fusionauth-job" | cut -d' ' -f1 | tac | tail -n +2 | xargs -I % kubectl delete jobs % -n sit1
            command:
            - /bin/sh
          restartPolicy: Never
          imagePullSecrets:
            - name: secret


Solution 1:[1]

A more flexible alternative to what you're doing now would be to store the list of job names you want to delete in a list/array. Then, you can iterate through the list of job names and execute the command.

Below is a simpler (IMO) version of your command that uses the -o=jsonpath support instead in kubectl to specify a search criteria.

# The list of jobs you want to delete from any/all namespaces.
jobs_list="job-init fusionauth-job"

for job_name in ${jobs_list}; do
    kubectl get jobs -A --sort-by=.metadata.creationTimestamp \
        -o=jsonpath="{range .items[?(@.metadata.name == '${job_name}')]}{.metadata.namespace} {.metadata.name}{'\n'}{end}" \
          | while read namespace job;do kubectl delete job ${job} -n ${namespace};done;
done

The following was added as a result of the comments/conversation below.

If the job names in your cluster have incrementing suffixes, such as fusionauth-job-01, fusionauth-job-02, etc, and you want to keep only the latest instance of that job in a particular namespace, then you will need to leverage something like jq so you can do some regular expression matching. kubectl's jsonpath feature doesn't support regular expressions.

As an example, let's assume your cluster has the jobs shown below.

NAMESPACE   NAME
default     fusionauth-job-01
team1       fusionauth-job-01
team1       fusionauth-job-02
team1       job-init-01
team1       job-init-02 
team2       fusionauth-job-01
team2       fusionauth-job-02
team2       fusionauth-job-03

Furthermore, the jobs are listed in timestamp order, meaning fusionauth-job-03 is the newest job (whose name matches fusionauth-job*) in namespace team2, job-init-02 is the newest job (whose name matches job-init*) in namespace team1, fusionauth-job-02 is the newest job (of that name pattern) in namespace team1, and fusionauth-job-01 is the only job running in namespace default.

After running your jobs-cleanup job, the expectation is that the following jobs would be left:

NAMESPACE   NAME
default     fusionauth-job-01
team1       fusionauth-job-02
team1       job-init-02 
team2       fusionauth-job-03

A script to produce these results is shown here:

# The list of job name prefixes you want to delete from any/all namespaces.
jobs_list="job-init fusionauth-job"

for job_name in ${jobs_list}; do
    ns_observed=""
    echo "Searching for ${job_name}*"
    kubectl get jobs -A --sort-by=.metadata.creationTimestamp -o json \
        | jq -r '.items[] | select(.metadata.name | test('\"${job_name}\"')) | .metadata.namespace + " " + .metadata.name' \
        | tac \
        | while read namespace job;do
            if test "${ns_observed#*$namespace}" != "$ns_observed";then
                # If we've seen this namespace already for this job, then delete the
                # job, since the one we found previously is the newest.
                kubectl delete job ${job} -n ${namespace};
            else
                # Otherwise, if this is the first time observing this namespace, then
                # this is the newest job that starts with this job name in this namespace.
                ns_observed="$ns_observed $namespace";
            fi;
        done;
done

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1