infra: FLY_FEED_VIA is validated at deploy and read case-blind by the watchdog; flyedge gets the page's CPUs
Review round 1. flysim reads FLY_FEED_VIA case-insensitively, so check 2 must too: with Bus in fly.env it read flysim's zeroed counters and would have escalated to restarting flystage and flycast every pass. It now lowercases. 05-deploy.sh runs the value through feed_via_normalize (lib/common.sh) and dies on anything but direct|bus, writing the lowercased word, so a typo is a deploy refusal instead of a flysim boot loop. lint's fly.target check read only the first physical Wants=/Requires= line; target_pulls joins backslash continuations and drops comments, with a fixture that names a unit only on a continuation line. The cpuset loop writes a flyedge drop-in on the page CPUs, and lint holds it.
This commit is contained in:
parent
1ba5c80053
commit
2da7f688a8
4 changed files with 87 additions and 8 deletions
|
|
@ -413,6 +413,10 @@ log "05-deploy: non-secret env files"
|
||||||
# never drift apart (see cpuset_partition's own header comment). They are
|
# never drift apart (see cpuset_partition's own header comment). They are
|
||||||
# assigned in section 0b, which needs them earlier than this for the
|
# assigned in section 0b, which needs them earlier than this for the
|
||||||
# deploy-time cpu pinning; nothing between here and there changes them.
|
# deploy-time cpu pinning; nothing between here and there changes them.
|
||||||
|
# Who serves the feed (docs/design/flybus.md): refused here rather than at flysim's boot.
|
||||||
|
FLY_FEED_VIA_EFFECTIVE="$(feed_via_normalize "${FLY_FEED_VIA:-}")" \
|
||||||
|
|| die "05-deploy: FLY_FEED_VIA must be 'direct' or 'bus', got '${FLY_FEED_VIA}'"
|
||||||
|
|
||||||
tmp_fly_env="$(mktemp)"
|
tmp_fly_env="$(mktemp)"
|
||||||
tmp_flypush_env="$(mktemp)"
|
tmp_flypush_env="$(mktemp)"
|
||||||
trap 'rm -f "$tmp_fly_env" "$tmp_flypush_env"' EXIT
|
trap 'rm -f "$tmp_fly_env" "$tmp_flypush_env"' EXIT
|
||||||
|
|
@ -507,7 +511,8 @@ trap 'rm -f "$tmp_fly_env" "$tmp_flypush_env"' EXIT
|
||||||
# unconditionally, like FLY_MACRO_MODE, so one grep says which a box runs.
|
# unconditionally, like FLY_MACRO_MODE, so one grep says which a box runs.
|
||||||
# Watchdog check 2 reads this line to know whose /metrics carries the
|
# Watchdog check 2 reads this line to know whose /metrics carries the
|
||||||
# feed counters (flysim's :9101, or flyedge's loopback :9102).
|
# feed counters (flysim's :9101, or flyedge's loopback :9102).
|
||||||
echo "FLY_FEED_VIA=${FLY_FEED_VIA:-direct}"
|
# Validated and lowercased above (feed_via_normalize).
|
||||||
|
echo "FLY_FEED_VIA=${FLY_FEED_VIA_EFFECTIVE}"
|
||||||
# How long a macro leaves a target alone after a walk to it aborted
|
# How long a macro leaves a target alone after a walk to it aborted
|
||||||
# (macros.md section 12.1, the Viridian stall). Only written when it is set,
|
# (macros.md section 12.1, the Viridian stall). Only written when it is set,
|
||||||
# because the default lives in the crate and a box that has not tuned it
|
# because the default lives in the crate and a box that has not tuned it
|
||||||
|
|
@ -642,9 +647,11 @@ if [ -n "${CPUSET:-}" ]; then
|
||||||
"leaves cpuset.cpus.effective empty and the unit unstartable."
|
"leaves cpuset.cpus.effective empty and the unit unstartable."
|
||||||
else
|
else
|
||||||
read -r sim_cpus page_cpus encoder_cpus <<< "$(cpuset_partition "$CPUSET" "$RAYON_THREADS_EFFECTIVE" "$ENCODER_CORES_EFFECTIVE")"
|
read -r sim_cpus page_cpus encoder_cpus <<< "$(cpuset_partition "$CPUSET" "$RAYON_THREADS_EFFECTIVE" "$ENCODER_CORES_EFFECTIVE")"
|
||||||
log "05-deploy: cpuset partition — flysim=$sim_cpus, xvfb/flystage/flystage-web/pulse/mediamtx=$page_cpus, flycast=$encoder_cpus"
|
log "05-deploy: cpuset partition — flysim=$sim_cpus, xvfb/flystage/flystage-web/pulse/mediamtx/flyedge=$page_cpus, flycast=$encoder_cpus"
|
||||||
tmp_dropin="$(mktemp)"
|
tmp_dropin="$(mktemp)"
|
||||||
for u in flysim xvfb flystage flystage-web flycast pulse mediamtx; do
|
# flyedge is off by default, but its drop-in is written with the rest so that the day
|
||||||
|
# it is enabled it serves the page from the page's CPUs, never from flysim's.
|
||||||
|
for u in flysim xvfb flystage flystage-web flycast pulse mediamtx flyedge; do
|
||||||
case "$u" in
|
case "$u" in
|
||||||
flysim) cpus="$sim_cpus" ;;
|
flysim) cpus="$sim_cpus" ;;
|
||||||
flycast) cpus="$encoder_cpus" ;;
|
flycast) cpus="$encoder_cpus" ;;
|
||||||
|
|
|
||||||
|
|
@ -351,7 +351,8 @@ feed_metrics_url() {
|
||||||
fi
|
fi
|
||||||
local via=""
|
local via=""
|
||||||
if [ -f "$FLY_ENV_FILE" ]; then
|
if [ -f "$FLY_ENV_FILE" ]; then
|
||||||
via="$(awk -F= '/^FLY_FEED_VIA=/ { print $2; exit }' "$FLY_ENV_FILE" 2>/dev/null | tr -d ' \r' || true)"
|
# Lowercased: flysim reads the value case-insensitively, so `Bus` is bus mode.
|
||||||
|
via="$(awk -F= '/^FLY_FEED_VIA=/ { print $2; exit }' "$FLY_ENV_FILE" 2>/dev/null | tr -d ' \r"' | tr '[:upper:]' '[:lower:]' || true)"
|
||||||
fi
|
fi
|
||||||
if [ "$via" = "bus" ]; then
|
if [ "$via" = "bus" ]; then
|
||||||
echo "$FLY_EDGE_METRICS_URL"
|
echo "$FLY_EDGE_METRICS_URL"
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,20 @@ require_release_tag() {
|
||||||
# (An earlier, eight-cpu version of this same live hotfix — CPUSET=
|
# (An earlier, eight-cpu version of this same live hotfix — CPUSET=
|
||||||
# 1,3,5,7,9,11,13,15, ENCODER_CORES=2 (the default) — gave flysim=1,3,5,7,
|
# 1,3,5,7,9,11,13,15, ENCODER_CORES=2 (the default) — gave flysim=1,3,5,7,
|
||||||
# page=9,11, flycast=13,15; infra/tests/lint.sh checks both shapes.)
|
# page=9,11, flycast=13,15; infra/tests/lint.sh checks both shapes.)
|
||||||
|
# feed_via_normalize VALUE — print FLY_FEED_VIA lowercased (empty means "direct"), or
|
||||||
|
# return 1 for anything but direct|bus. flysim itself reads the value case-insensitively
|
||||||
|
# and refuses anything else at boot, which on a container is a restart loop; 05-deploy.sh
|
||||||
|
# refuses it at deploy instead and writes the lowercased word, so watchdog check 2 and
|
||||||
|
# flysim can never read the same line two ways (docs/design/flybus.md).
|
||||||
|
feed_via_normalize() {
|
||||||
|
local via
|
||||||
|
via="$(printf '%s' "${1:-direct}" | tr '[:upper:]' '[:lower:]')"
|
||||||
|
case "$via" in
|
||||||
|
direct|bus) printf '%s\n' "$via" ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
cpuset_partition() {
|
cpuset_partition() {
|
||||||
local cpuset="$1" rayon_threads="$2" encoder_cores="${3:-2}"
|
local cpuset="$1" rayon_threads="$2" encoder_cores="${3:-2}"
|
||||||
local sim_cpus remainder remainder_count page_count page_cpus encoder_cpus
|
local sim_cpus remainder remainder_count page_count page_cpus encoder_cpus
|
||||||
|
|
|
||||||
|
|
@ -460,19 +460,73 @@ else
|
||||||
&& pass "flyedge.service keeps its metrics on loopback" \
|
&& pass "flyedge.service keeps its metrics on loopback" \
|
||||||
|| fail "flyedge.service FLY_EDGE_METRICS_ADDR must be a 127.0.0.1 address"
|
|| fail "flyedge.service FLY_EDGE_METRICS_ADDR must be a 127.0.0.1 address"
|
||||||
fi
|
fi
|
||||||
if grep -E '^(Wants|Requires)=' "$INFRA_DIR/units/fly.target" | grep -q 'flyedge'; then
|
# Every unit a target's Wants=/Requires= names, with backslash continuations joined and
|
||||||
|
# comments dropped: fly.target spreads both lists over several physical lines, and the
|
||||||
|
# continuation line is exactly where a new unit would be added.
|
||||||
|
target_pulls() {
|
||||||
|
awk '
|
||||||
|
/^[[:space:]]*[#;]/ { next }
|
||||||
|
{
|
||||||
|
line = $0
|
||||||
|
cont = sub(/\\[[:space:]]*$/, "", line)
|
||||||
|
buf = buf line
|
||||||
|
if (cont) next
|
||||||
|
if (buf ~ /^[[:space:]]*(Wants|Requires)=/) { sub(/^[^=]*=/, "", buf); print buf }
|
||||||
|
buf = ""
|
||||||
|
}
|
||||||
|
' "$1" | tr -s ' \t' '\n' | grep -v '^$' || true
|
||||||
|
}
|
||||||
|
if target_pulls "$INFRA_DIR/units/fly.target" | grep -qx 'flyedge.service'; then
|
||||||
fail "fly.target pulls flyedge.service in; it must stay off until the operator enables it"
|
fail "fly.target pulls flyedge.service in; it must stay off until the operator enables it"
|
||||||
else
|
else
|
||||||
pass "fly.target does not pull flyedge.service in"
|
pass "fly.target does not pull flyedge.service in"
|
||||||
fi
|
fi
|
||||||
|
# The parser itself: a unit named only on a continuation line must be found, a commented one
|
||||||
|
# must not, and the real fly.target must still yield flysim.service.
|
||||||
|
tp_fixture="$(mktemp "${TMPDIR:-/tmp}/fly-lint-target.XXXXXX")"
|
||||||
|
cat > "$tp_fixture" <<'TPTARGET'
|
||||||
|
[Unit]
|
||||||
|
Wants=network-online.target xvfb.service \
|
||||||
|
flysim.service flyedge.service
|
||||||
|
# Requires=commented.service
|
||||||
|
Requires=xvfb.service \
|
||||||
|
pulse.service
|
||||||
|
TPTARGET
|
||||||
|
tp_units="$(target_pulls "$tp_fixture")"
|
||||||
|
if printf '%s\n' "$tp_units" | grep -qx 'flyedge.service' \
|
||||||
|
&& printf '%s\n' "$tp_units" | grep -qx 'pulse.service' \
|
||||||
|
&& ! printf '%s\n' "$tp_units" | grep -qx 'commented.service' \
|
||||||
|
&& target_pulls "$INFRA_DIR/units/fly.target" | grep -qx 'flysim.service'; then
|
||||||
|
pass "target_pulls reads continuation lines and skips comments (fixture + fly.target)"
|
||||||
|
else
|
||||||
|
fail "target_pulls missed a continuation line or read a comment: $(echo "$tp_units" | tr '\n' ' ')"
|
||||||
|
fi
|
||||||
|
rm -f "$tp_fixture"
|
||||||
if grep -E '^(ALWAYS_ON_UNITS|APP_UNITS)=' "$INFRA_DIR/07-enable.sh" "$INFRA_DIR/verify.sh" | grep -q 'flyedge'; then
|
if grep -E '^(ALWAYS_ON_UNITS|APP_UNITS)=' "$INFRA_DIR/07-enable.sh" "$INFRA_DIR/verify.sh" | grep -q 'flyedge'; then
|
||||||
fail "07-enable.sh or verify.sh lists flyedge.service as always-on"
|
fail "07-enable.sh or verify.sh lists flyedge.service as always-on"
|
||||||
else
|
else
|
||||||
pass "07-enable.sh and verify.sh leave flyedge.service alone"
|
pass "07-enable.sh and verify.sh leave flyedge.service alone"
|
||||||
fi
|
fi
|
||||||
grep -qF 'echo "FLY_FEED_VIA=${FLY_FEED_VIA:-direct}"' "$INFRA_DIR/05-deploy.sh" \
|
if grep -qF 'FLY_FEED_VIA_EFFECTIVE="$(feed_via_normalize "${FLY_FEED_VIA:-}")"' "$INFRA_DIR/05-deploy.sh" \
|
||||||
&& pass "05-deploy.sh writes FLY_FEED_VIA with direct as the default" \
|
&& grep -qF 'echo "FLY_FEED_VIA=${FLY_FEED_VIA_EFFECTIVE}"' "$INFRA_DIR/05-deploy.sh"; then
|
||||||
|| fail "05-deploy.sh must write FLY_FEED_VIA=\${FLY_FEED_VIA:-direct} into fly.env"
|
pass "05-deploy.sh validates FLY_FEED_VIA and writes the normalized value"
|
||||||
|
else
|
||||||
|
fail "05-deploy.sh must run FLY_FEED_VIA through feed_via_normalize and write FLY_FEED_VIA_EFFECTIVE"
|
||||||
|
fi
|
||||||
|
# shellcheck source=../lib/common.sh
|
||||||
|
fv_out="$(bash -c '. "$1/lib/common.sh"
|
||||||
|
for v in "" direct DIRECT bus Bus BUS; do printf "%s=%s " "${v:-empty}" "$(feed_via_normalize "$v")"; done
|
||||||
|
for v in buss "bus " direct,bus; do feed_via_normalize "$v" >/dev/null && printf "ACCEPTED:%s " "$v"; done; true' _ "$INFRA_DIR" 2>&1)"
|
||||||
|
if [ "$fv_out" = "empty=direct direct=direct DIRECT=direct bus=bus Bus=bus BUS=bus " ]; then
|
||||||
|
pass "feed_via_normalize: direct|bus in any case, empty is direct, anything else refused"
|
||||||
|
else
|
||||||
|
fail "feed_via_normalize: got '$fv_out'"
|
||||||
|
fi
|
||||||
|
if grep -qE '^[[:space:]]*for u in flysim .*\bflyedge\b.*; do$' "$INFRA_DIR/05-deploy.sh"; then
|
||||||
|
pass "05-deploy.sh writes a cpuset drop-in for flyedge.service"
|
||||||
|
else
|
||||||
|
fail "05-deploy.sh cpuset loop must include flyedge (the page's CPUs, never flysim's)"
|
||||||
|
fi
|
||||||
if grep -qE '^Environment=FLY_FEED_VIA' "$INFRA_DIR/units/flysim.service"; then
|
if grep -qE '^Environment=FLY_FEED_VIA' "$INFRA_DIR/units/flysim.service"; then
|
||||||
fail "flysim.service pins FLY_FEED_VIA; it belongs to fly.env so a box can be switched by deploy"
|
fail "flysim.service pins FLY_FEED_VIA; it belongs to fly.env so a box can be switched by deploy"
|
||||||
else
|
else
|
||||||
|
|
@ -502,6 +556,9 @@ else
|
||||||
feed_url_case "direct" "FLY_FEED_VIA=direct" "" "http://sim"
|
feed_url_case "direct" "FLY_FEED_VIA=direct" "" "http://sim"
|
||||||
feed_url_case "no FLY_FEED_VIA line (a fly.env before it)" "FLY_GAME=pokemon-red" "" "http://sim"
|
feed_url_case "no FLY_FEED_VIA line (a fly.env before it)" "FLY_GAME=pokemon-red" "" "http://sim"
|
||||||
feed_url_case "bus" "FLY_FEED_VIA=bus" "" "http://edge"
|
feed_url_case "bus" "FLY_FEED_VIA=bus" "" "http://edge"
|
||||||
|
feed_url_case "Bus (flysim lowercases)" "FLY_FEED_VIA=Bus" "" "http://edge"
|
||||||
|
feed_url_case "BUS" "FLY_FEED_VIA=BUS" "" "http://edge"
|
||||||
|
feed_url_case "quoted bus" 'FLY_FEED_VIA="bus"' "" "http://edge"
|
||||||
feed_url_case "explicit override wins" "FLY_FEED_VIA=bus" "http://other" "http://other"
|
feed_url_case "explicit override wins" "FLY_FEED_VIA=bus" "http://other" "http://other"
|
||||||
rm -rf "$fe_fixture"
|
rm -rf "$fe_fixture"
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue