0107. Reset and add replaces the override reclaim switch
Status: Accepted; built · Date: 2026-10-30 · Design section: Trust, Nodes, Deployment · Amends: 0103 (section 2.2), 0105 · Touches: 0094
Decided: there is no installation-wide switch for resetting a machine that another Talos cluster configured and adding it here; who may do it is decided by RBAC alone, the custom verb reclaim on machinereclaims, checked by the webhook with a SubjectAccessReview as the requesting user (as before); ichor-admin (group ichor:admin) holds that verb by default, ichor-machine-reclaimer stays for granting it to anyone else, editors and viewers do not get it; IchorInstallation.spec.reclaim.enabled and the chart value reclaim.enabled are deprecated and ignored (the CRD field stays, append-only; the admission webhook warns when it is set; ichor settings set reclaim.enabled=... and UpdateSettings refuse it with a pointer to this ADR; status.effective stops reporting it; the SettingsGate no longer has a ichorinstallations/reclaim check); the UI calls the feature "Reset and add" (dialog "Add a machine from another cluster"), offers it on the Add node page next to the AlreadyConfigured message and on the Machines page to users who hold the verb, and drops the reclaim card from Settings; the kind MachineReclaim and the command ichor machine reclaim keep their names.
Context
ADR 0103 section 2.2 made machine reclaim an override feature, off unless reclaim.enabled (chart value, then IchorInstallation.spec.reclaim.enabled with a confirmation annotation, ADR 0105). The user found the name "override reclaim" wrong for what is an ordinary step of adding a machine that already runs Talos, and its on/off switch out of place on the Settings page; it belongs with adding nodes.
Decisions
- No installation switch. The request already needs the foreign cluster's admin talosconfig: whoever holds it can reset the node with
talosctlanyway. On top of that Ichor requires a typed UUID, refuses a reset that would break quorum or remove the last control plane, keeps the credential in a TTL'd single-use Secret, and writes audit Events andstatus.audit. A second, global key adds a forgotten-toggle problem, not safety. The controller reconciler, the MachineReclaim webhook and the UI API (ReclaimService) therefore no longer read a switch; the webhook's SubjectAccessReview and the UI API's own SAR for the verb are the only gates.CanReclaimResponse.enabledstays in the proto, always true. - Roles.
ichor_admin_role(config/rbac) andichor-admin(chartichor-user-roles) listcreate,get,list,updateandreclaimonmachinereclaims, as a plain rule like their other explicit verbs (these roles are not built by aggregation).ichor-machine-reclaimerhas the same rules and is now installed wheneverrbac.helpers.enabledis set (before: only withreclaim.enabled).ichor-operatorandichor-viewerdo not get the verb. - Users off. With Ichor's users off the UI API writes as its own ServiceAccount, like it does for its other writes (the talosoperations verbs, settings). That identity is judged by the same webhook and holds no
reclaimverb by default, so the button is not offered until the operator bindsichor-machine-reclaimertoichor-system:ichor-ichor-ui. This is the behaviour of ADR 0103 C8, unchanged; the ServiceAccount's own Role gains nothing. - Deprecation.
spec.reclaimis kept in the schema because CRD fields are append-only and installed objects may carry it; its doc comment says Deprecated. TheIchorInstallationadmission webhook adds a Warning when it is set. The chart valuereclaim.enabledstays invalues.yamlwith a deprecation note; the manager no longer gets--reclaimand ichor-ui no longer getsICHOR_RECLAIM_ENABLED.status.effective.reclaimEnabledand the proto fieldsreclaim_enabled,can_edit_reclaimandconfirm_reclaimstay (wire compatibility) but are never filled or read. The annotationichor.maesh.dev/confirm-reclaimhas no meaning any more. The RBAC subresourceichorinstallations/reclaimis no longer checked; it is removed from the shipped roles (a role losing a verb that nothing asks for breaks no installed binding, since bindings refer to roles by name). - UI. The Settings page has no reclaim card. On the Add node page an AlreadyConfigured address shows "Reset and add" when the user holds the verb; it opens the dialog prefilled with the address and the target cluster. Without the verb the CLI hint stays. The dialog keeps the stored-credential warning and the typed-UUID step; the "Override" banner wording is gone. The Machines list button has the same name.
Consequences
-
A fresh install lets ichor:admin use Reset and add with no step to take; anyone else needs a RoleBinding to
ichor-machine-reclaimer. -
An installation that had the switch off and relied on it as a guard now has the verb in
ichor-admin; an operator who does not want it there must not grantichor:adminor must edit the role. -
Existing
IchorInstallationobjects withspec.reclaimkeep working; the Warning tells the person writing them. -
The removed flags
--reclaim(manager) and--reclaim-enabled(ichor-ui) stay accepted as deprecated no-ops for one release, as--http-addrin ADR 0105 unit 10, so a hand-edited Deployment that still passes them starts. Delete them in the release after.
Amendment (2026-10-30): findings of the hardware run
- Maintenance deadline. A request in
WaitingForMaintenancefails exactlyreclaimMaintenanceWait(10 minutes) after the reset was sent. The wait was measured from a timestamp taken at the start of each reconcile and every reconcile held one of the controller's single worker, so any slow call (a node call has no timeout of its own) delayed all later checks; the hardware run saw 14.5 minutes. Now each reconcile has a 2 minute timeout, the controller runs four workers, no probe runs past the deadline, and the requeue is the smaller of 10 s and the time left, so the failure comes at the deadline with no more slack than the probe in flight. - TTL.
spec.ttl(default 15 minutes, at most 60) bounds only the part before the reset: the credential Secret, and the request while it waits for the typed UUID. The reset deletes the credential; from then on the TTL is not consulted and the request ends Done, Failed (10 minutes after the reset) or is kept for seven days after its expiry time. - Discovery addresses. The controller still never writes
spec. The UI API, which adds the address as the user, records each address it appended in the annotationichor.maesh.dev/reclaim-added-addresseson the TalosCluster (metadata; an address the user had listed is never recorded).CreateReclaim(before it appends its own address) andConfirmReclaimthen take an address back out, as the caller and best effort, when no Done or running request of that cluster names it and no TalosMachine of the cluster is at it: that covers failed, expired and deleted requests. Reads (GetReclaim,ListReclaims) never write a cluster. There is noDeleteReclaimRPC (it would need a newdeletegrant in the admin roles and a UI path); a request deleted with kubectl leaves its address until the next create or confirm. Rejected: an annotation on the MachineReclaim (a deleted request would take its record along) and a "remove address" button (the user cannot tell which addresses Ichor added). A user who lists the same address by hand after Ichor added it loses it again with the request; they should add it before. - Time to a pending machine. A Done request enqueues its target cluster, so discovery probes the new maintenance address right away (no write; the TalosCluster controller watches MachineReclaim). Before, a cluster whose list already held the address waited for its 5 minute discovery pass. Expected now: a few seconds after Done.
Hardware result 2026-10-30 (build v0.0.1850000002-gc549005e, the tree at c549005e): deadline, address cleanup and wake-up
Setup (prefix ichor-e2e-z, 4 nodes): an ichor init cluster ichor-e2e-z (1 control plane + 1 worker, users off, upgraded twice, see ADR 0105) and a foreign Talos v1.14.3 cluster ichor-e2e-zf (talosctl gen config with a KubeNetworkConfig outside 10.244.0.0/16, control plane bootstrapped, worker joined; Kubernetes flannel). ichor-machine-reclaimer bound to ichor-system:ichor-ichor-ui (reclaimui can: enabled, allowed, clusterAllowed), ichor-ui reached through an inner NodePort 30080. spec.discovery.addresses of ichor-e2e-z held the user's 10.244.1.243 (the Ichor worker) and 10.244.9.9 (added by hand). No Go tests were run.
- (b) A machine that never returns: Failed exactly 10 minutes after the reset. Phase
WaitingForMaintenanceuntilFailedat 03:13:10Z (EventReclaimFailed03:13:10Z): delta 10 min 0 s (the earlier run saw 14.5 min).status.result:10.244.2.191 did not return to maintenance mode with UUID 71c86230-...: It may have taken a new address from DHCP: scan for the machine and add its address to a cluster's spec.discovery.addresses. The credential Secret was deleted at 03:03:10Z (CredentialDeleted). A reading of the cluster afterFailed(viaget) still listed10.244.2.191and the annotationichor.maesh.dev/reclaim-added-addresses: 10.244.2.191: reads write nothing. As in ADR 0103's C7 run, the stop within a second of the reset interrupted the wipe: after the node was started again (new address10.244.2.117) the worker answered an authenticated call with the foreign talosconfig as a member ofichor-e2e-zf. - (c) Address cleanup passed. Creating
reclaim-flbc5for the new address10.244.2.117took10.244.2.191out and put10.244.2.117in:spec.discovery.addresseswent from["10.244.1.243","10.244.9.9","10.244.2.191"]to["10.244.1.243","10.244.9.9","10.244.2.117"], and the annotation to10.244.2.117. The user's two addresses stayed. The confirm path was not separately tested (the create already pruned). - (a) Done to a pending machine: under 1 s.
reclaim-flbc5confirmed 03:14:09Z (reset sent 03:14:09Z), Done seen at 03:14:21.2Z (12 s, node back in maintenance), the pendingTalosMachine71c86230-...(endpoint10.244.2.117:50000) hascreationTimestamp03:14:21Z and was seen by polling at 03:14:22.1Z. The address was already in the list (added at create), so this is the wake-up: before it waited for the 5 minute discovery pass. - Failing tests: none run. Everything with prefix
ichor-e2e-zandichor-e2e-zfwas deleted;kubectl getshows none left and the cached ISO disk is untouched.