feat(controller-peers-env-fallback): fall back to XCE_CONTROLLER_PEERS in the scheduler (task 3.1)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9018980b08
commit
55193fcb4b
3 changed files with 187 additions and 14 deletions
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 <dir> <env-args...> -- [scheduler args...]
|
||||
# Start the scheduler in the background with --logfile <dir>/scheduler.log,
|
||||
# wait for its startup line, then stop it. Fails (with the log tail) when
|
||||
# the line never appears.
|
||||
start_scheduler() {
|
||||
local dir="$1"; shift
|
||||
local envargs=() pid
|
||||
while [ $# -gt 0 ] && [ "$1" != -- ]; do
|
||||
envargs+=("$1"); shift
|
||||
done
|
||||
[ $# -gt 0 ] && shift
|
||||
start_bg "$dir" "${envargs[@]}" "$SCHEDULER_BIN" \
|
||||
--logfile "$dir/scheduler.log" "$@"
|
||||
pid="$LAST_PID"
|
||||
if ! wait_for_line "$dir/scheduler.log" "$SCHED_ANCHOR_RE" 10 "$pid"; then
|
||||
stop_proc "$pid"
|
||||
red " scheduler never logged its startup line"
|
||||
_show_tail "$dir/scheduler.log"
|
||||
_show_tail "$dir/stderr"
|
||||
return 1
|
||||
fi
|
||||
stop_proc "$pid"
|
||||
}
|
||||
|
||||
# run_scheduler <dir> <env-args...> -- [scheduler args...]
|
||||
# Run the scheduler to completion (argument errors, --sim, --help).
|
||||
run_scheduler() {
|
||||
local dir="$1"; shift
|
||||
local envargs=()
|
||||
while [ $# -gt 0 ] && [ "$1" != -- ]; do
|
||||
envargs+=("$1"); shift
|
||||
done
|
||||
[ $# -gt 0 ] && shift
|
||||
run_to_completion "$dir" 10 "${envargs[@]}" "$SCHEDULER_BIN" \
|
||||
--logfile "$dir/scheduler.log" "$@"
|
||||
}
|
||||
|
||||
case_scheduler_env_list() {
|
||||
local d; d="$(new_scratch scheduler-env-list)"
|
||||
start_scheduler "$d" "XCE_CONTROLLER_PEERS=$ENV3" -- || return 1
|
||||
assert_grep "$d/scheduler.log" \
|
||||
'HA cluster config: 3 candidate\(s\), identity=xce_scheduler \(from XCE_CONTROLLER_PEERS\), version ' || return 1
|
||||
assert_no_grep "$d/scheduler.log" 'No --peers flag' || return 1
|
||||
}
|
||||
add_case case_scheduler_env_list \
|
||||
"scheduler: XCE_CONTROLLER_PEERS used when --peers is absent (1.2)"
|
||||
|
||||
case_scheduler_peers_wins() {
|
||||
local d; d="$(new_scratch scheduler-peers-wins)"
|
||||
start_scheduler "$d" "XCE_CONTROLLER_PEERS=$ENV3" -- \
|
||||
--peers solo=localhost:7 || return 1
|
||||
assert_grep "$d/scheduler.log" \
|
||||
'HA cluster config: 1 candidate\(s\), identity=xce_scheduler, version ' || return 1
|
||||
assert_no_grep "$d/scheduler.log" '3 candidate|from XCE_CONTROLLER_PEERS' || return 1
|
||||
}
|
||||
add_case case_scheduler_peers_wins \
|
||||
"scheduler: explicit --peers wins over XCE_CONTROLLER_PEERS (1.1)"
|
||||
|
||||
case_scheduler_neither_set() {
|
||||
local d; d="$(new_scratch scheduler-neither)"
|
||||
start_scheduler "$d" -u XCE_CONTROLLER_PEERS -- || return 1
|
||||
assert_grep "$d/scheduler.log" "$SCHED_STANDALONE_RE" || return 1
|
||||
assert_no_grep "$d/scheduler.log" 'HA cluster config' || return 1
|
||||
}
|
||||
add_case case_scheduler_neither_set \
|
||||
"scheduler: neither --peers nor the variable -> single-controller path, line names the variable (1.3, 1.8)"
|
||||
|
||||
case_scheduler_env_empty() {
|
||||
local d; d="$(new_scratch scheduler-env-empty)"
|
||||
start_scheduler "$d" "XCE_CONTROLLER_PEERS=" -- || return 1
|
||||
assert_grep "$d/scheduler.log" "$SCHED_STANDALONE_RE" || return 1
|
||||
assert_no_grep "$d/scheduler.log" 'HA cluster config' || return 1
|
||||
}
|
||||
add_case case_scheduler_env_empty \
|
||||
"scheduler: empty XCE_CONTROLLER_PEERS behaves as unset (1.7, 1.8)"
|
||||
|
||||
case_scheduler_parse_error_source() {
|
||||
local d
|
||||
d="$(new_scratch scheduler-parse-env)"
|
||||
run_scheduler "$d" "XCE_CONTROLLER_PEERS=a=nocolon" --
|
||||
assert_rc 1 || return 1
|
||||
assert_grep "$d/stderr" 'xce_scheduler: XCE_CONTROLLER_PEERS parse error' "stderr (env value)" || return 1
|
||||
|
||||
d="$(new_scratch scheduler-parse-flag)"
|
||||
run_scheduler "$d" "XCE_CONTROLLER_PEERS=$ENV3" -- --peers a=nocolon
|
||||
assert_rc 1 || return 1
|
||||
assert_grep "$d/stderr" 'xce_scheduler: --peers parse error' "stderr (--peers value)" || return 1
|
||||
assert_no_grep "$d/stderr" 'XCE_CONTROLLER_PEERS' "stderr (--peers value)" || return 1
|
||||
}
|
||||
add_case case_scheduler_parse_error_source \
|
||||
"scheduler: parse error names --peers or XCE_CONTROLLER_PEERS (1.4)"
|
||||
|
||||
case_scheduler_validate_error_source() {
|
||||
local d
|
||||
d="$(new_scratch scheduler-port0-env)"
|
||||
run_scheduler "$d" "XCE_CONTROLLER_PEERS=a=localhost:0" --
|
||||
assert_rc 1 || return 1
|
||||
assert_grep "$d/stderr" 'xce_scheduler: XCE_CONTROLLER_PEERS: invalid cluster config' "stderr (env value)" || return 1
|
||||
|
||||
d="$(new_scratch scheduler-port0-flag)"
|
||||
run_scheduler "$d" "XCE_CONTROLLER_PEERS=$ENV3" -- --peers a=localhost:0
|
||||
assert_rc 1 || return 1
|
||||
assert_grep "$d/stderr" 'xce_scheduler: --peers: invalid cluster config' "stderr (--peers value)" || return 1
|
||||
assert_no_grep "$d/stderr" 'XCE_CONTROLLER_PEERS' "stderr (--peers value)" || return 1
|
||||
}
|
||||
add_case case_scheduler_validate_error_source \
|
||||
"scheduler: cluster-config validation error (port 0) names --peers or XCE_CONTROLLER_PEERS (1.4)"
|
||||
|
||||
case_scheduler_help_names_variable() {
|
||||
local d; d="$(new_scratch scheduler-help)"
|
||||
run_to_completion "$d" 10 -u XCE_CONTROLLER_PEERS "$SCHEDULER_BIN" --help
|
||||
assert_rc 0 || return 1
|
||||
# argp wraps help text, so join the lines before matching.
|
||||
tr '\n' ' ' <"$d/stdout" | tr -s ' ' >"$d/help.txt"
|
||||
assert_grep "$d/help.txt" 'XCE_CONTROLLER_PEERS' "--help output" || return 1
|
||||
assert_grep "$d/help.txt" 'unset or empty' "--help output" || return 1
|
||||
assert_grep "$d/help.txt" 'single-controller' "--help output" || return 1
|
||||
}
|
||||
add_case case_scheduler_help_names_variable \
|
||||
"scheduler: --help documents XCE_CONTROLLER_PEERS and the opt-out (1.5, 1.7)"
|
||||
|
||||
# Guard (passes before and after 3.1): --sim returns before the peers block,
|
||||
# so the variable must not reach simulation mode. The "--sim startup failed"
|
||||
# line, which only the --sim branch prints, proves that branch ran.
|
||||
case_scheduler_sim_ignores_variable() {
|
||||
local d; d="$(new_scratch scheduler-sim)"
|
||||
run_scheduler "$d" "XCE_CONTROLLER_PEERS=$ENV3" -- \
|
||||
--sim "$d/does-not-exist.replay"
|
||||
assert_rc nonzero || return 1
|
||||
assert_grep "$d/stderr" 'xce_scheduler: --sim startup failed' "stderr" || return 1
|
||||
assert_no_grep "$d/scheduler.log" "$SCHED_ANCHOR_RE" || return 1
|
||||
assert_no_grep "$d/stderr" "$SCHED_ANCHOR_RE" "stderr" || return 1
|
||||
}
|
||||
add_case case_scheduler_sim_ignores_variable \
|
||||
"scheduler: --sim never reaches the peers block, even with the variable set"
|
||||
|
||||
|
||||
# ════════════════════════════════════════════════════════════════════════════
|
||||
# main
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue