diff --git a/.kiro/specs/controller-peers-env-fallback/tasks.md b/.kiro/specs/controller-peers-env-fallback/tasks.md index 805ee20f..3ded7878 100644 --- a/.kiro/specs/controller-peers-env-fallback/tasks.md +++ b/.kiro/specs/controller-peers-env-fallback/tasks.md @@ -50,7 +50,7 @@ - _Requirements: 1.6_ - [ ] 3. Scheduler, worker and harness -- [ ] 3.1 Fall back to the environment variable in the scheduler +- [x] 3.1 Fall back to the environment variable in the scheduler - Add the scheduler cases to the regression script first and see them fail: env list used ("HA cluster config: N candidate(s)" in the log); `--peers` winning; neither set (extended no-peers line); parse error and port-0 validation error from each source naming that source on stderr; `--help` naming the variable and the opt-out; simulation mode with a missing replay file and the variable set showing the simulation start-up failure on stderr and no peers-related log line - Use the variable only when no `--peers` is given; leave the simulation path, which returns earlier, untouched - Name the source in the parse-error and cluster-config-validation messages; extend the no-peers line; update the help text @@ -135,3 +135,5 @@ - (2.2) The tlog early-exit race did not reproduce on this machine (0/20 before the fix, 0/200 ad hoc); `case_controller_log_flushed_on_early_exit` is kept as a regression guard, not proof of the fix. - (2.2 → 2.3) That case matches the text "No --peers flag; running as single-node primary"; when 2.3 extends the line (1.8), keep that text intact or update the case's pattern. - (2.3) The 1.8 wording cannot contain the old "No --peers flag; running ..." substring, so the 2.2 flush case now matches the full new line. Env-sourced "HA mode" lines end " (from XCE_CONTROLLER_PEERS)"; explicit-`--peers` lines and error texts are unchanged apart from naming the source. Reword the script header's "while the case list is empty" comment in 3.x when the shellcheck disable is dropped. +- (3.1 → 3.2) The scheduler's validation message now quotes the value, names the source and hints "(empty host or port 0?)" (the old "missing identity?" was wrong: identity is always set there, and `xce_parse_peers` caps the candidate count itself). Use the same shape for the worker's `xce_cluster_config_validate()` message. +- (3.1 → 5.2) On this machine `test-version-startup-consistency.sh` and `test-dirty-fingerprint-startup-log-unchanged.sh` exit 1 for an environmental reason: their apiserver `go build` fails with "module lookup disabled by GOPROXY=off" (no Go module cache). Their scheduler checks pass. Task 5.2's "both scripts pass" needs a machine with the Go module cache, or the result must be reported as environment-limited with the scheduler checks shown passing. diff --git a/src/scheduler/src/main.c b/src/scheduler/src/main.c index 0051eadf..cfab0e97 100644 --- a/src/scheduler/src/main.c +++ b/src/scheduler/src/main.c @@ -85,7 +85,12 @@ struct arguments { static struct argp_option options[] = { { "logfile", 'l', "FILE", 0, "The full path of log file" }, { "verbose", 'v', 0, 0, "Produce verbose log" }, - { "peers", 'P', "LIST", 0, "HA candidate list: [name=]host:port,..." }, + { "peers", 'P', "LIST", 0, + "HA candidate list: [name=]host:port,... When omitted, the " + "XCE_CONTROLLER_PEERS environment variable (same format) is used " + "instead; with that variable unset or empty the scheduler takes the " + "single-controller path, so unset or empty it for one invocation to " + "opt out (e.g. XCE_CONTROLLER_PEERS= xce_scheduler ...)." }, /* Req 5 AC 9 "Mode selection" / Req 5 AC 13 "Simulation mode startup" * (scheduler-core spec, tasks 5.2/11.1): --sim FILE selects the * simulation driver; the flags below configure it. */ @@ -407,32 +412,52 @@ int main(int argc, char* argv[]) return 0; } - /* P2.5-6: populate and validate xce_cluster_config_t when --peers given */ - if (arguments.peers) { - if (xce_parse_peers(arguments.peers, &cluster_cfg) != 0) { + /* P2.5-6: populate and validate xce_cluster_config_t when a candidate + * list is given. controller-peers-env-fallback Req 1.1-1.3, 1.7: an + * explicit --peers wins; otherwise a non-empty XCE_CONTROLLER_PEERS + * supplies the list (unset or empty = single-controller path). + * peers_src names where the list came from in every message about it + * (Req 1.4). */ + const char* peers_str = arguments.peers; + int peers_from_env = 0; + if (peers_str == NULL) { + peers_str = xce_controller_peers_env(); + peers_from_env = (peers_str != NULL); + } + const char* peers_src = peers_from_env ? "XCE_CONTROLLER_PEERS" : "--peers"; + + if (peers_str) { + if (xce_parse_peers(peers_str, &cluster_cfg) != 0) { fprintf(stderr, - "xce_scheduler: --peers parse error: expected " + "xce_scheduler: %s parse error: expected " "\"[name=]host:port,...\" got \"%s\"\n", - arguments.peers); + peers_src, peers_str); return 1; } strncpy(cluster_cfg.identity, "xce_scheduler", sizeof(cluster_cfg.identity) - 1); if (xce_cluster_config_validate(&cluster_cfg) != 0) { - fprintf(stderr, "xce_scheduler: invalid cluster config (missing " - "identity?).\n"); + fprintf(stderr, + "xce_scheduler: %s: invalid cluster config (empty host " + "or port 0?) in \"%s\"\n", + peers_src, peers_str); return 1; } if (cluster_cfg.candidates_count > N_MAX_MASTERS) { - WARN("xce_scheduler: --peers has %d candidates; " + WARN("xce_scheduler: %s has %d candidates; " "only <=%d validated for HA", - cluster_cfg.candidates_count, N_MAX_MASTERS); + peers_src, cluster_cfg.candidates_count, N_MAX_MASTERS); } - INFO("HA cluster config: %d candidate(s), identity=%s, version %s", - cluster_cfg.candidates_count, cluster_cfg.identity, version_buf); + /* The version stays last on the line: the version-consistency + * scripts read everything after its prefix as the build time. */ + INFO("HA cluster config: %d candidate(s), identity=%s%s, version %s", + cluster_cfg.candidates_count, cluster_cfg.identity, + peers_from_env ? " (from XCE_CONTROLLER_PEERS)" : "", + version_buf); cluster_cfg_ptr = &cluster_cfg; } else { - INFO("No --peers flag; using single-controller path, version %s", + INFO("No --peers flag and XCE_CONTROLLER_PEERS unset or empty; " + "using single-controller path, version %s", version_buf); } diff --git a/src/tools/verify-controller-peers-env.sh b/src/tools/verify-controller-peers-env.sh index 0b10eced..9c437832 100755 --- a/src/tools/verify-controller-peers-env.sh +++ b/src/tools/verify-controller-peers-env.sh @@ -504,6 +504,152 @@ case_controller_flag_own_name_unchecked() { add_case case_controller_flag_own_name_unchecked \ "controller: explicit --peers without the own name is not checked at startup (1.6)" +# ── Task 3.1 (Req 1.1-1.5, 1.7, 1.8): the scheduler resolves its candidate +# list from --peers, else XCE_CONTROLLER_PEERS, else the single-controller +# path. A valid list keeps the scheduler running (it retries its controller), +# so those runs are started in the background, stopped once the startup line +# is in the log, and only then asserted on. Argument errors exit on their own. + +# Either startup line; every successful scheduler start logs exactly one. +SCHED_ANCHOR_RE='HA cluster config|No --peers flag' +SCHED_STANDALONE_RE='No --peers flag and XCE_CONTROLLER_PEERS unset or empty; using single-controller path, version ' + +# start_scheduler