Summary
The janitor sidecar in files/fleetlock.yaml (added in e952c15, deployed 2026-03-08) is supposed to delete the fleetlock-default lease when its holderIdentity no longer matches any current node's machine ID. It does not work.
Impact
On 2026-06-06 the cluster's OS auto-updates were found to be fully stalled. The fleetlock-default lease (namespace default) had been held for ~112 days by machine ID 010bf3597d08415bad40906d032083a8, which matches no current node — it is a ghost from an original node destroyed in a prior make deploy (deploys recreate cloud instances).
Because the ghost holder never releases the lock, every node loops forever in upgrade-os.sh on POST /v1/pre-reboot getting a non-200, so staged rpm-ostree upgrades never reboot. Agent nodes were stuck on FCOS 43.20260202 for ~4 months.
The janitor was added specifically to prevent this, but failed to do its job.
Evidence the janitor is broken
- Pod running 90 days, janitor container: 0 restarts.
- Janitor logs are completely empty (it should log "Lease holder ... not found among current nodes, deleting lease").
kubectl invoked inside the janitor container hangs (in-pod kubectl exec into control-plane pods also hangs).
- The lease survived the entire 90 days and had to be deleted manually.
Likely contributing factors in the script
- No
--request-timeout on the kubectl calls → a hung get-lease wedges the while loop forever on the first iteration.
2>/dev/null on the get-lease swallows any error, so failures are invisible in logs.
- 1800s sleep makes iteration slow to observe.
Proposed fix (not yet applied)
- Add
--request-timeout=30s to all kubectl calls.
- Drop
2>/dev/null so failures surface in logs.
- Possibly shorten the sleep / add explicit logging per iteration.
- Investigate why in-pod kubectl hangs on the control-plane node (API reachability from pod network, kubelet exec stream) — the fleetlock Go client on the same pod works fine, so this is specific to the kubectl path.
Workaround
kubectl --kubeconfig elsa.yaml delete lease fleetlock-default -n default
Safe and self-healing — fleetlock recreates the lease on the next real reboot request. After deletion a waiting node acquired the lock within 15s and proceeded to reboot.
Summary
The
janitorsidecar infiles/fleetlock.yaml(added in e952c15, deployed 2026-03-08) is supposed to delete thefleetlock-defaultlease when itsholderIdentityno longer matches any current node's machine ID. It does not work.Impact
On 2026-06-06 the cluster's OS auto-updates were found to be fully stalled. The
fleetlock-defaultlease (namespacedefault) had been held for ~112 days by machine ID010bf3597d08415bad40906d032083a8, which matches no current node — it is a ghost from an original node destroyed in a priormake deploy(deploys recreate cloud instances).Because the ghost holder never releases the lock, every node loops forever in
upgrade-os.shonPOST /v1/pre-rebootgetting a non-200, so stagedrpm-ostreeupgrades never reboot. Agent nodes were stuck on FCOS43.20260202for ~4 months.The janitor was added specifically to prevent this, but failed to do its job.
Evidence the janitor is broken
kubectlinvoked inside the janitor container hangs (in-podkubectl execinto control-plane pods also hangs).Likely contributing factors in the script
--request-timeouton thekubectlcalls → a hung get-lease wedges thewhileloop forever on the first iteration.2>/dev/nullon the get-lease swallows any error, so failures are invisible in logs.Proposed fix (not yet applied)
--request-timeout=30sto allkubectlcalls.2>/dev/nullso failures surface in logs.Workaround
Safe and self-healing — fleetlock recreates the lease on the next real reboot request. After deletion a waiting node acquired the lock within 15s and proceeded to reboot.