The provisioning cycle
Host.Provision runs on a worker goroutine, holds the host’s mutex for the duration of the call, and
returns a delay flag and an error.
Where it lives
host: everything that happens to one server. Main file: host/host.go, with Provision at
host/host.go:78 and handleHostUpgrade at host/host.go:219.
The sequence
The feature flags gate individual steps. The order never changes.
configure runs.Checks before the first RPC
Provision checks provisioned and discovery age before it issues any RPC.
The provisioned short-circuit returns a delay, so the finisher holds a node that has already been
through the sequence out of the map for a further 60 seconds.
The staleness check is the second half of the duplicate-provision trade-off described in
Discovery and the work queue. Because the queue holds up to 50,000
entries, a host can wait long enough that the facts the helper would see no longer match the node.
Provision refuses a host that has waited longer than two
discovery intervals.
Gathering facts
Each fetch is a single RPC against one target, described in
RPC, retries, and upgrades. fetchJWT, fetchInventory, and
fetchEd25519PubKey each return early when the value they collect is already populated, so a retried
Provision on the same Host does not re-fetch.
fetchInventory always runs. Besides the facts, it records h.version and h.upgradable from the
reply, and the upgrade path requires both.
The helper’s answer
getConfig marshals the whole Host to JSON and runs the helper. Its reply, a
host.ConfigResponse, can end the cycle:
- defer
- Returns an error carrying the helper's message. The node stays unconfigured. The finisher removes it from the map, and a later discovery cycle picks it up again.
- shutdown
- Issues a
shutdownRPC to the node and returns a delay. The node exits with code 0, which systemd does not restart. Whenmsgis empty,Provisionlogs a warning that carries no shutdown reason.
Provision copies the rest of the reply onto the Host: the configuration map, the CA, certificate,
key, and SSL directory, the target upgrade version, and the two policy maps.
The helper contract gives the full shape.
The upgrade interruption
When features.upgrades is on and the helper returned an upgrade version, handleHostUpgrade runs
before configuration. It refuses to proceed if the inventory carried no version or the node reported
upgradable as false, then compares versions with the RPM comparison in host/version.go.
The switch that consumes its result (host/host.go:189-202) handles these outcomes:
| Result | Effect |
|---|---|
No error, skipped true | Versions already match. Falls through and configures the node normally. |
No error, skipped false | An upgrade ran. Returns (false, nil) immediately, ending the cycle before configuration. |
Error, upgrades_optional true | Logs a warning and configures the node on its old version. |
Error, upgrades_optional false | Returns (true, err), so the finisher holds the node out of the map for 60 seconds. |
Upgrade and configure never share a pass
An upgraded node returns a false delay flag so the next discovery cycle picks it up at once (“no delay
so we reprov asap”). The node has already replaced its own binary and restarted into provisioning mode
on the new version. Returning no delay leaves it eligible for the next discovery cycle, where it runs
the full sequence again and this time reaches configure. A node is never both upgraded and
configured in a single pass.
Configure and restart
configure sends the whole payload in one RPC: the configuration map as a JSON string, the token, the
CA, certificate, key, SSL directory, the Provisioner’s ECDH public key, both policy maps, and the
signed server JWT. It refuses to send an empty configuration map. If the CSR reply carried an SSL
directory, that value overrides whatever the helper chose.
restart follows with a one second splay, and the node restarts into its new configuration.
Provision sets h.provisioned to true after the restart returns, then returns (true, nil).
Next
The helper contract covers the JSON exchange. RPC, retries, and upgrades covers what happens inside each call.