Skip to content

Instantly share code, notes, and snippets.

@bgulla
Created February 21, 2026 13:46
Show Gist options
  • Select an option

  • Save bgulla/4d577ec8bae900a445d8c28f31d2352f to your computer and use it in GitHub Desktop.

Select an option

Save bgulla/4d577ec8bae900a445d8c28f31d2352f to your computer and use it in GitHub Desktop.
Elemental Force Removal Script
#!/usr/bin/env bash
# Force delete stuck Elemental machines from Rancher
# Assumes machines are powered off / unreachable
set -euo pipefail
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
error() { echo -e "${RED}[ERROR]${NC} $*"; }
NAMESPACES=("fleet-default" "cattle-elemental-system" "cattle-system" "fleet-system")
RESOURCE_TYPES=(
"machineinventories.elemental.cattle.io"
"machines.elemental.cattle.io"
"machineregistrations.elemental.cattle.io"
"elementalmachines.elemental.cattle.io"
)
kubectl cluster-info &>/dev/null || { error "kubectl can't reach the cluster"; exit 1; }
# ── Find all stuck Elemental resources ──────────────────────────────────────
declare -A FOUND # "resource/namespace/name" => 1
find_stuck() {
info "Scanning for stuck Elemental resources..."
for rt in "${RESOURCE_TYPES[@]}"; do
# Skip unknown CRDs silently
kubectl get crd "$rt" &>/dev/null || continue
for ns in "${NAMESPACES[@]}"; do
kubectl get namespace "$ns" &>/dev/null || continue
while IFS= read -r name; do
[[ -z "$name" ]] && continue
key="${rt}|${ns}|${name}"
FOUND["$key"]=1
echo " STUCK: $rt/$name (ns: $ns)"
done < <(kubectl get "$rt" -n "$ns" \
-o jsonpath='{range .items[?(@.metadata.deletionTimestamp)]}{.metadata.name}{"\n"}{end}' 2>/dev/null || true)
done
done
}
# ── Force-delete one resource ────────────────────────────────────────────────
force_delete() {
local rt="$1" ns="$2" name="$3"
info "Processing $rt/$name in $ns..."
# 1. Strip finalizers
kubectl patch "$rt" "$name" -n "$ns" \
--type json \
-p '[{"op":"replace","path":"/metadata/finalizers","value":[]}]' \
&>/dev/null && info " Finalizers cleared" || warn " Patch failed (may already be gone)"
# 2. Force delete
kubectl delete "$rt" "$name" -n "$ns" \
--force --grace-period=0 \
--ignore-not-found=true \
&>/dev/null && info " Deleted" || warn " Delete failed (may already be gone)"
}
# ── Main ─────────────────────────────────────────────────────────────────────
main() {
find_stuck
if [[ ${#FOUND[@]} -eq 0 ]]; then
info "No stuck Elemental machines found — you're already clean!"
exit 0
fi
echo ""
warn "Found ${#FOUND[@]} stuck resource(s). This will force-remove them."
read -rp "Continue? (yes/no): " confirm
[[ "$confirm" == "yes" ]] || { info "Aborted."; exit 0; }
echo ""
for key in "${!FOUND[@]}"; do
IFS='|' read -r rt ns name <<< "$key"
force_delete "$rt" "$ns" "$name"
done
echo ""
info "Done. Verifying..."
sleep 2
find_stuck
if [[ ${#FOUND[@]} -eq 0 ]]; then
info "All clear! No stuck resources remain."
else
warn "${#FOUND[@]} resource(s) still stuck. You may need to check the Elemental operator logs:"
echo " kubectl logs -n cattle-elemental-system deploy/elemental-operator"
fi
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment