`swarm-bao-agent-pki` carried its own copy of the mtime-vs-start compare, with the same `stat -c %.6Y | tr -d .` read: on a comma-locale host the `-le` errored and, under `seal = "pkcs11"`, openbao was restarted on every run of the unit. The compare moves out of `refresh_unit` into `written_after_start` (0 newer, 1 not newer, 2 unreadable and logged at `err`), and both `refresh_unit` and the agent-pki unit call it. The agent-pki unit cannot call `refresh_unit` itself: it restarts with `restart`, not `try-restart`, runs a fail-closed check of the bundle between the compare and the restart, and under shamir prints the step instead of restarting. It acts only on 0, so an unreadable time skips the restart as `refresh_unit` does. `script-test-refresh-consumer` covers the three return codes in the agent-pki call shape; `module-eval-bao-basics` asserts both seal arms decide on that call and that no `%.6Y` read is left in the unit. Refs #5230
153 lines
5.1 KiB
Shell
153 lines
5.1 KiB
Shell
# Cases for ./refresh-consumer.nix. Each case sets the credential file's mtime
|
|
# and the consumer's last start, runs the helper with a stub `systemctl` that
|
|
# records every call it is asked to act on, and compares that record and what
|
|
# the helper wrote to stderr.
|
|
set -uo pipefail
|
|
|
|
failures=0
|
|
count=0
|
|
|
|
fail() {
|
|
echo "FAILED: $case: $*" >&2
|
|
failures=$((failures + 1))
|
|
}
|
|
|
|
dir=$(mktemp -d)
|
|
mkdir "$dir/bin"
|
|
calls=$dir/calls
|
|
path=$dir/token
|
|
: >"$path"
|
|
|
|
# `show` prints $STARTED as systemd's `--timestamp=us+utc` does; `is-active`
|
|
# and `is-failed` answer from $ACTIVE and $FAILED; every other verb is
|
|
# appended to $calls.
|
|
cat >"$dir/bin/systemctl" <<STUB
|
|
#!$BASH
|
|
args=" \$* "
|
|
case "\$args" in
|
|
*" show "*) printf '%s\n' "\$STARTED" ;;
|
|
*" is-active "*) [ "\$ACTIVE" = 1 ] ;;
|
|
*" is-failed "*) [ "\$FAILED" = 1 ] ;;
|
|
*) printf '%s\n' "\$*" >>"$calls" ;;
|
|
esac
|
|
STUB
|
|
chmod +x "$dir/bin/systemctl"
|
|
export PATH="$dir/bin:$PATH" ACTIVE=1 FAILED=0 STARTED=
|
|
|
|
export LC_ALL=de_DE.UTF-8
|
|
|
|
# shellcheck source=/dev/null
|
|
. "$HELPER"
|
|
|
|
# The locale the cases run under has to print the comma the helper must not
|
|
# depend on, or none of them tests it.
|
|
case="setup"
|
|
touch -d @1791232888.193159 "$path"
|
|
got=$(stat -c %.6Y "$path")
|
|
if [ "$got" != "1791232888,193159" ]; then fail "stat under $LC_ALL printed '$got', wanted 1791232888,193159"; fi
|
|
|
|
# systemd's `--timestamp=us+utc` rendering of <epoch seconds>.<micros>.
|
|
systemd_ts() {
|
|
LC_ALL=C date -u -d "@$1" '+%a %Y-%m-%d %H:%M:%S.%6N UTC'
|
|
}
|
|
|
|
# check <description> <want systemctl calls, one per line, or ""> <want stderr, or "">
|
|
# <helper call…>
|
|
check() {
|
|
case=$1
|
|
local want_calls=$2 want_err=$3 got err
|
|
shift 3
|
|
count=$((count + 1))
|
|
: >"$calls"
|
|
# `set -e` as the callers' NixOS `script`s run: a failed read must not end the
|
|
# caller. Not under `||` or `if`, which would switch `set -e` off.
|
|
local rc
|
|
(
|
|
set -e
|
|
"$@" >/dev/null 2>"$dir/err"
|
|
)
|
|
rc=$?
|
|
if [ "$rc" != 0 ]; then fail "exited $rc"; fi
|
|
err=$(cat "$dir/err")
|
|
got=$(cat "$calls")
|
|
if [ "$got" != "$want_calls" ]; then
|
|
fail "systemctl was asked:"$'\n'"$got"$'\n'"wanted:"$'\n'"$want_calls"
|
|
fi
|
|
# A failed read also leaves `date`'s own message ahead of the helper's line.
|
|
if [ -n "$want_err" ]; then err=$(printf '%s\n' "$err" | tail -n 1); fi
|
|
if [ "$err" != "$want_err" ]; then
|
|
fail "stderr:"$'\n'"$err"$'\n'"wanted:"$'\n'"$want_err"
|
|
fi
|
|
}
|
|
|
|
touch -d @1791232888.193159 "$path"
|
|
|
|
STARTED=$(systemd_ts 1791232900.000001)
|
|
check "a file older than the start restarts nothing" "" "" \
|
|
refresh_unit gitea-runner-swarm.service "$path"
|
|
check "nor through a container" "" "" \
|
|
refresh_consumer swarm-ci-runner gitea-runner-swarm.service "$path"
|
|
|
|
STARTED=$(systemd_ts 1791232888.193159)
|
|
check "a file written in the start's microsecond restarts nothing" "" "" \
|
|
refresh_unit gitea-runner-swarm.service "$path"
|
|
|
|
STARTED=$(systemd_ts 1791232888.193158)
|
|
check "a file one microsecond newer than the start restarts the unit" \
|
|
"try-restart --no-block gitea-runner-swarm.service" "" \
|
|
refresh_unit gitea-runner-swarm.service "$path"
|
|
check "through a container, with --machine" \
|
|
"--machine=swarm-ci-runner try-restart --no-block gitea-runner-swarm.service" "" \
|
|
refresh_consumer swarm-ci-runner gitea-runner-swarm.service "$path"
|
|
|
|
FAILED=1
|
|
check "a failed unit is reset and started" \
|
|
"reset-failed gitea-runner-swarm.service"$'\n'"start --no-block gitea-runner-swarm.service" "" \
|
|
refresh_unit gitea-runner-swarm.service "$path"
|
|
FAILED=0
|
|
|
|
STARTED=
|
|
check "a unit never active is restarted" \
|
|
"try-restart --no-block gitea-runner-swarm.service" "" \
|
|
refresh_unit gitea-runner-swarm.service "$path"
|
|
|
|
ACTIVE=0
|
|
check "nothing while the container is down" "" "" \
|
|
refresh_consumer swarm-ci-runner gitea-runner-swarm.service "$path"
|
|
ACTIVE=1
|
|
|
|
STARTED="not a time"
|
|
check "an unreadable start restarts nothing and says so at err" "" \
|
|
"<3>cannot compare the mtime of $path ('1791232888193159') with the last start of gitea-runner-swarm.service ('not a time') — leaving gitea-runner-swarm.service as it is" \
|
|
refresh_unit gitea-runner-swarm.service "$path"
|
|
|
|
STARTED=$(systemd_ts 1791232900.000001)
|
|
check "a missing file restarts nothing and says so at err" "" \
|
|
"<3>cannot compare the mtime of $dir/missing ('') with the last start of gitea-runner-swarm.service ('$STARTED') — leaving gitea-runner-swarm.service as it is" \
|
|
refresh_unit gitea-runner-swarm.service "$dir/missing"
|
|
|
|
# compare <description> <want status> <path>. `written_after_start` as
|
|
# `swarm-bao-agent-pki` calls it, which acts only on 0.
|
|
compare() {
|
|
case=$1
|
|
count=$((count + 1))
|
|
local rc
|
|
(
|
|
set -e
|
|
written_after_start openbao.service "$3" --machine=swarm-bao 2>/dev/null
|
|
)
|
|
rc=$?
|
|
if [ "$rc" != "$2" ]; then fail "returned $rc, wanted $2"; fi
|
|
}
|
|
|
|
STARTED=$(systemd_ts 1791232900.000001)
|
|
compare "the compare is 1 for a file older than the start" 1 "$path"
|
|
STARTED=$(systemd_ts 1791232888.193158)
|
|
compare "the compare is 0 for a file newer than the start" 0 "$path"
|
|
STARTED="not a time"
|
|
compare "the compare is 2 for an unreadable start" 2 "$path"
|
|
STARTED=$(systemd_ts 1791232900.000001)
|
|
compare "the compare is 2 for a missing file" 2 "$dir/missing"
|
|
|
|
echo "$count cases, $failures failed"
|
|
[ "$failures" = 0 ]
|