Last active
April 4, 2025 20:09
-
-
Save x95castle1/50b7f12515857730b1fc8de025773a55 to your computer and use it in GitHub Desktop.
CronJob that will cleanup Workloads that are in a ready state and are older than a period of time.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| apiVersion: batch/v1 | |
| kind: CronJob | |
| metadata: | |
| name: ready-workload-checker | |
| namespace: tap-install | |
| spec: | |
| schedule: "*/1 * * * *" # Runs every 5 minutes TODO: Adjust this to what you need. Example to run every day at midnight: 0 0 * * * | |
| concurrencyPolicy: Forbid | |
| successfulJobsHistoryLimit: 3 | |
| failedJobsHistoryLimit: 1 | |
| jobTemplate: | |
| spec: | |
| template: | |
| spec: | |
| serviceAccountName: workload-checker-sa | |
| containers: | |
| - name: kubectl | |
| image: bitnami/kubectl:latest | |
| imagePullPolicy: IfNotPresent | |
| env: | |
| - name: EXCLUDED_NAMESPACES | |
| value: "kube-system" | |
| - name: ALLOWED_DELETION_SECONDS | |
| value: "600" # This is in seconds. 600 = 10 minutes for example. 604800 would be 7 days. | |
| command: | |
| - /bin/bash | |
| - -c | |
| - | | |
| #!/bin/bash | |
| echo "$(date): Searching for ready workloads across all namespaces..." | |
| echo "------------------------------------------------" | |
| # Create array of excluded namespaces | |
| IFS=',' read -ra EXCLUDED <<< "$EXCLUDED_NAMESPACES" | |
| echo "Excluded namespaces: ${EXCLUDED_NAMESPACES}" | |
| echo "------------------------------------------------" | |
| # Get all namespaces | |
| namespaces=$(kubectl get namespaces -o jsonpath='{.items[*].metadata.name}') | |
| # Initialize results file | |
| results_file="/tmp/ready-workloads-$(date +%Y%m%d-%H%M%S).txt" | |
| echo "Ready Workloads Report - $(date)" > $results_file | |
| echo "================================================" >> $results_file | |
| # Current time in seconds since epoch | |
| current_time=$(date +%s) | |
| # Loop through each namespace | |
| for namespace in $namespaces; do | |
| skip=false | |
| for excluded in "${EXCLUDED[@]}"; do | |
| if [[ "$namespace" == "$excluded" ]]; then | |
| echo "Skipping excluded namespace: $namespace" | |
| skip=true | |
| break | |
| fi | |
| done | |
| # Skip to next iteration if namespace is excluded | |
| if $skip; then | |
| continue | |
| fi | |
| echo "" | |
| echo "Checking namespace: $namespace" | |
| echo "Namespace: $namespace" >> $results_file | |
| # Get all workloads in the namespace | |
| workloads=$(kubectl get workload -n $namespace -o jsonpath='{.items[*].metadata.name}' 2>/dev/null) | |
| # If no workloads found, continue to next namespace | |
| if [ -z "$workloads" ]; then | |
| echo " No workloads found in this namespace" | |
| echo " No workloads found in this namespace" >> $results_file | |
| continue | |
| fi | |
| # Loop through each workload | |
| for workload in $workloads; do | |
| # Check if the workload has Ready condition with status True | |
| ready_status=$(kubectl get workload $workload -n $namespace -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null) | |
| if [ "$ready_status" = "True" ]; then | |
| # Get the lastTransitionTime for the Ready condition | |
| last_transition=$(kubectl get workload $workload -n $namespace -o jsonpath='{.status.conditions[?(@.type=="Ready")].lastTransitionTime}' 2>/dev/null) | |
| if [ ! -z "$last_transition" ]; then | |
| # Convert ISO 8601 date to seconds since epoch | |
| transition_time=$(TZ=UTC date -d "$(echo $last_transition | sed 's/Z$//')" +%s 2>/dev/null) | |
| if [ ! -z "$transition_time" ]; then | |
| # Calculate time difference in seconds | |
| time_diff=$((current_time - transition_time)) | |
| if [ $time_diff -gt $ALLOWED_DELETION_SECONDS ]; then | |
| # Format time difference in a human-readable format | |
| minutes=$((time_diff / 60)) | |
| hours=$((minutes / 60)) | |
| days=$((hours / 24)) | |
| if [ $days -gt 0 ]; then | |
| duration="${days}d $((hours % 24))h" | |
| elif [ $hours -gt 0 ]; then | |
| duration="${hours}h $((minutes % 60))m" | |
| else | |
| duration="${minutes}m" | |
| fi | |
| echo " ✅ READY: $workload" | |
| echo " ✅ READY: $workload" >> $results_file | |
| echo " Last Transition: $last_transition" | |
| echo " Last Transition: $last_transition" >> $results_file | |
| echo " ⚠️ Workload '$workload' has maintained Ready state for ${duration} (>10 minutes)" | |
| echo " ⚠️ Workload '$workload' has maintained Ready state for ${duration} (>10 minutes)" >> $results_file | |
| echo " DELETING WORKLOAD $workload " | |
| kubectl delete workload $workload -n $namespace | |
| else | |
| echo " ✅ READY: $workload" | |
| echo " ✅ READY: $workload" >> $results_file | |
| echo " Last Transition: $last_transition" | |
| echo " Last Transition: $last_transition" >> $results_file | |
| fi | |
| else | |
| echo " ✅ READY: $workload" | |
| echo " ✅ READY: $workload" >> $results_file | |
| echo " Last Transition: $last_transition (could not parse date for workload '$workload')" | |
| echo " Last Transition: $last_transition (could not parse date for workload '$workload')" >> $results_file | |
| fi | |
| else | |
| echo " ✅ READY: $workload" | |
| echo " ✅ READY: $workload" >> $results_file | |
| echo " Last Transition: Unknown for workload '$workload'" | |
| echo " Last Transition: Unknown for workload '$workload'" >> $results_file | |
| fi | |
| else | |
| echo " 🛑 NOT READY: $workload in status of $ready_status" | |
| fi | |
| done | |
| echo "" >> $results_file | |
| done | |
| echo "" | |
| echo "Search complete. Results saved to $results_file" | |
| # cat $results_file | |
| restartPolicy: OnFailure | |
| --- | |
| apiVersion: v1 | |
| kind: ServiceAccount | |
| metadata: | |
| name: workload-checker-sa | |
| namespace: tap-install | |
| --- | |
| apiVersion: rbac.authorization.k8s.io/v1 | |
| kind: ClusterRole | |
| metadata: | |
| name: workload-checker-role | |
| rules: | |
| - apiGroups: [""] | |
| resources: ["namespaces"] | |
| verbs: ["get", "list"] | |
| - apiGroups: ["carto.run"] # The API group for your workload CRD | |
| resources: ["workloads"] | |
| verbs: ["get", "list", "delete"] | |
| --- | |
| apiVersion: rbac.authorization.k8s.io/v1 | |
| kind: ClusterRoleBinding | |
| metadata: | |
| name: workload-checker-binding | |
| subjects: | |
| - kind: ServiceAccount | |
| name: workload-checker-sa | |
| namespace: tap-install | |
| roleRef: | |
| kind: ClusterRole | |
| name: workload-checker-role | |
| apiGroup: rbac.authorization.k8s.io |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment