Architecture
The source is four packages and about 2,400 lines.
Where it lives
main.go calls into cmd. Packages: cmd, config, hosts, host.
The packages
- cmd
- The
fiskcommand line, flag parsing, and process startup. Loads both configuration files, builds the Choria framework, starts the Prometheus listener and the signal handler, then callshosts.Process. One file,cmd/provisioner.go. - config
- The YAML configuration, its defaults, and its validation. Also holds the pause flag that
rpcWrapperandrunHelpercheck before every outbound action. Files:config.go,pausable.go,stats.go. - hosts
- Fleet-level scheduling. Broadcast discovery, the lifecycle listener, a work queue, the worker pool, the finisher, and leader election. Files:
hosts.go,event.go,provisioner.go,election.go,stats.go. - host
- Everything that happens to one server. The provisioning sequence, the RPC wrappers, the helper invocation, and RPM version comparison. Files:
host.go,rpc.go,helper.go,version.go,stats.go.
cmd imports hosts, hosts imports host, and all three import config, which imports none of
them. host does not import hosts, so host/host_test.go builds a Host from a config.Config
and a logger with no scheduler involved.
cmd imports hosts, hosts imports host, and nothing imports upward, so host compiles and tests on its own.The boundaries
The helper, the pause flag, and the generated RPC clients each change without touching the other two.
- The helper Provisioner marshals a
Hostto JSON, writes it to a child process on standard input, and unmarshals the reply intohost.ConfigResponse(host/helper.go:38). The helper reaches certificate authorities, CMDBs, and naming services, in any language. - The pause flag
config.ConfigdeclaresPause,Resume,Flip, andPaused(config/pausable.go). Leader election callsPauseandResume, and bothrpcWrapperandrunHelpercheck the flag before sending an RPC request or starting the helper process. - Generated RPC clients
host/rpc.gouses two clients generated in go-choria,provclient.ChoriaProvisionClientfor thechoria_provisionagent andrpcutilclient.RpcutilClientforrpcutil. Every call to either goes throughrpcWrapper, which holds the retries, timing, and pause check for both.
Package-level state in hosts
The hosts package declares its state as package variables rather than struct fields
(hosts/hosts.go:24-33): the hosts map of identity to *host.Host, the buffered work and done
channels, a mutex, and the logger, the Choria framework, and the configuration.
One instance per process
hosts.Process writes these package variables on entry, so exactly one instance can run per process.
That matches the deployment model, where a process runs one Provisioner against one site, and the
scheduler functions take no receiver. Running two Provisioners in one binary requires moving this
state into a struct.
Configuration and startup
cmd.run loads the Provisioner YAML from --config through config.Load, and the Choria client
configuration from --choria-config, defaulting to choria.UserConfig(). cmd.run then overrides
the Choria client configuration in code (cmd/provisioner.go:61-79): log level and log file come from
the Provisioner configuration, and the collective is forced to provisioning for both Collectives
and MainCollective.
Setting choria_insecure disables TLS, sets protocol.Secure to false, and forces the file
security provider. Setting broker_provisioning_password switches the NATS credentials to user
provisioner with that password. The broker’s dedicated provisioning account accepts that user.
config.Load fills defaults and rejects configurations that cannot work
(config/config.go:64-142):
| Rule | Behavior |
|---|---|
workers unset | Defaults to runtime.NumCPU(). |
lifecycle_component unset | Defaults to provision_mode_server. |
lifecycle_component contains ., >, or * | Rejected, since the value is interpolated into a NATS subject. |
cert_deny_list empty | Defaults to four patterns that block privileged Choria certificate names. |
features.pki and features.ed25519 both set | Rejected. The two enrollment models are exclusive. |
features.ed25519 set | Implies features.jwt. |
server_jwt_validity unset | Defaults to one year. |
interval below one minute | Rejected. |
Observability
config/stats.go, hosts/stats.go, and host/stats.go each register their metrics in an init
function: the pause gauge, the fleet-level counters, and per-server timing and errors. Every metric
carries a site label taken from the site configuration key, so a query across installations can
sum or group by site. cmd.setupPrometheus serves them on /metrics when monitor_port is set.
Next
Continue to Discovery and the work queue to see how a server reaches a worker.