settings: an operator can check before the agent runs - #43
Merged
github-actions[bot] merged 1 commit intoSep 12, 2026
Merged
Conversation
ADR 0016 slice 2. There are five per-cluster settings now, and the only way to check one was to restart the agent and read its startup lines. `config check` calls configure -- the function run calls -- prints what each setting resolved to, and exits non-zero if any is broken. It is not a parallel validator. A second reader of the settings list is this design's own defect one level up: the one nobody ran would drift from the one that decides. The startup lines are the same states run prints, and the summary line is formatted in one place so a check and the run it predicts cannot describe one registry differently. Absent is not broken. Every setting but the action level is optional, and a cluster that has not opted in is in a state rather than a mistake, so an unconfigured directory exits zero. A broken setting exits 6 rather than 1: correcting a file and reporting a bug want different actions, and an installer that can only see non-zero has to parse messages to tell them apart. A passing check says what it did not check. The line ADR 0016 drew is syntactic at load, semantic at use -- whether a flavour id exists needs the credential and a network call, and a checker that sometimes talks to a cluster is one an operator learns to ignore the first time it fails because the cloud was busy. main's switch moves into dispatch so the tests reach the subcommand the way an operator does. A subcommand tested only through its own function can be deleted from the switch and still pass; removing the case here fails four tests. Signed-off-by: Travis Wu <travis.wu@bigstack.co>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
advisor-agent config check— ADR 0016 slice 2. Prints what each of the fiveper-cluster settings resolved to and exits non-zero if any is broken, without
starting anything.
Why
There are five settings now — action level, consent, cube-cos-api access,
instance profile, OpenStack credential — and the only way to check one was to
restart the agent and read its startup lines. Some settings only fail at use:
a transposed flavour id is syntactically fine and invisible until a person has
approved a VM that then fails.
Reviewer notes
It calls
configure, the functionruncalls. Not a parallel validator —a second reader of the settings list is this design's own defect one level up,
and the one nobody ran would drift from the one that decides. The per-setting
lines are the same
settingState.linevaluesrunprints;summaryLineis nowformatted in one place and used by both, so a check and the run it predicts
cannot describe one registry differently.
Absent is not broken. Every setting but the action level is optional, and a
cluster that has not opted in is in a state rather than a mistake. An
unconfigured directory exits 0 and says "not configured" per setting.
A broken setting exits 6, not 1. Correcting a file and reporting a bug want
different actions, and
main.go's own comment says an installer that can onlysee non-zero has to parse messages, "and then the messages become an interface
nobody meant to define".
exitFailedstays for a check that could not run.No semantic validation, deliberately. ADR 0016 drew the line at syntactic at
load, semantic at use. Checking that a flavour id exists needs the credential
and a network call, and a checker that sometimes talks to a cloud is a different
tool with different failure modes — one an operator learns to ignore the first
time it fails because the cloud was busy, and one that is useless during an
air-gapped bring-up before the cloud answers. A passing check therefore says
what it did not check, because "every setting is fine" reads as a stronger claim
than it is.
-probesis accepted so the tool count answers for the agent the operatorwill actually start: with it the same directory reports 8 tools rather than 6.
Building a
ProbeRunnervalidates the probe list and touches nothing else; thesweeper that does touch scratch is started by
run, separately, never here.-dirdefaults to the production directory, and pointing it at a stagingcopy is how an operator checks before promoting one.
Output goes to stdout, failures to stderr. In
runthese lines are logcontext; here they are the answer, and an operator may pipe them.
main's switch moved intodispatchso the tests reach the subcommand theway an operator does. This matters: a subcommand tested only through its own
function can be deleted from the switch and still pass its own tests. Removing
case "config"fails four tests.Breaks proved, each watched to fail a named test then restored:
exitOKTestConfigCheckReportsABrokenSettingAndExitsNonZero—exit = 0, want 6case "config"removed fromdispatchexit = 2config.goreachesinternal/agentTestConfigCheckStartsNothing— "a check that can dial or serve is no longer a check"None failed to fail.
TestConfigCheckStartsNothingis enforcement, not a guarantee: it readsthis file's imports, so a helper in another file could still reach the tunnel.
It catches the change that would actually be written, and the behavioural half —
a directory with settings but no identity exits 0, where
runwould refuse — isasserted beside it.
discardAuditor()insettings_test.gonow callscheckAuditor(), the oneconfig checkuses, so the tests and that command do not disagree about how tobuild a registry with no audit log.
Docs
kb/cube-ai-advisor/architecture/read-only-plane-end-to-end.md, with the otherslices.