diff --git a/.github/workflows/verify-split-files.yml b/.github/workflows/verify-split-files.yml index 644866f..d5bb1eb 100644 --- a/.github/workflows/verify-split-files.yml +++ b/.github/workflows/verify-split-files.yml @@ -39,6 +39,7 @@ on: - "tests/incus-target.sh" - "tests/incus-storage-space.sh" - "tests/release-stamp-pending.sh" + - "tests/pct-start-reason.sh" - ".github/workflows/verify-split-files.yml" push: branches: [main] @@ -69,6 +70,7 @@ on: - "tests/incus-target.sh" - "tests/incus-storage-space.sh" - "tests/release-stamp-pending.sh" + - "tests/pct-start-reason.sh" - ".github/workflows/verify-split-files.yml" workflow_dispatch: @@ -139,6 +141,8 @@ jobs: run: bash tests/incus-storage-space.sh - name: Release stamp pending marker tests run: bash tests/release-stamp-pending.sh + - name: pct start reason tests + run: bash tests/pct-start-reason.sh - name: Prefetch lists cover every engine file run: | diff --git a/pve/backend.func b/pve/backend.func index c6bd081..097a7d4 100644 --- a/pve/backend.func +++ b/pve/backend.func @@ -158,7 +158,7 @@ _pct_start_failed() { reason="$(journalctl -u "pve-container@${ctid}" -n 80 --no-pager -o cat 2>/dev/null | awk '/^Starting pve-container@/ { n = 0; next } { l[++n] = $0 } END { for (i = 1; i <= n; i++) print l[i] }' | grep -vE '^pve-container@[0-9]+\.service: |^Failed to start pve-container@|To get more details, run the container in foreground mode' | - tail -n 10)" + tail -n 10 || true)" { echo "--- pct start ${ctid} ---" [[ -n "$out" ]] && echo "$out" @@ -3591,7 +3591,8 @@ create_lxc_container() { # - Posts final "done" status to API telemetry # ------------------------------------------------------------------------------ description() { - IP=$(pct exec "$CTID" ip a s dev eth0 | awk '/inet / {print $2}' | cut -d/ -f1) + IP=$(pct exec "$CTID" -- ip -4 addr show dev eth0 2>/dev/null | awk '/inet / {print $2}' | cut -d/ -f1 | head -n1 || true) + [[ -n "$IP" ]] || IP=$(pct exec "$CTID" -- ip -6 addr show dev eth0 scope global 2>/dev/null | awk '/inet6 / {print $2}' | cut -d/ -f1 | head -n1 || true) # Links follow the repository the script actually came from, which # detect_repo_source() has already established. Hardcoding DevScripts sent diff --git a/tests/pct-start-reason.sh b/tests/pct-start-reason.sh new file mode 100644 index 0000000..3bdf765 --- /dev/null +++ b/tests/pct-start-reason.sh @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# _pct_start_failed runs under the host's errexit and ERR trap. Its journal +# filter ends in grep -v, which exits 1 when nothing survives, so the helper +# that explains a failed start was itself reported as the failure. +set -uo pipefail + +CORE_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." && pwd)" +eval "$(awk '/^_pct_start_failed[(][)] [{]/,/^}/' "$CORE_DIR/pve/backend.func")" + +TEST_DIR="$(mktemp -d)" +trap 'rm -rf -- "$TEST_DIR"' EXIT +export TAB=" " YW="" CL="" +BUILD_LOG="$TEST_DIR/build.log" +JOURNAL="$TEST_DIR/journal" +: >"$JOURNAL" +passed=0 failed=0 + +journalctl() { cat "$JOURNAL"; } +msg_custom() { :; } + +expect() { + if [[ "$2" == "$3" ]]; then + echo "PASS $1" + passed=$((passed + 1)) + else + echo "FAIL $1: expected <$2>, got <$3>" >&2 + failed=$((failed + 1)) + fi +} + +# The helper as the host runs it: errexit, errtrace, pipefail and an ERR trap. +run_helper() { + ( + set -Eeo pipefail + trap 'echo TRAPPED; exit 99' ERR + _pct_start_failed 100 "$1" + echo "rc=$?" + ) 2>&1 +} + +out="$(run_helper "startup for container '100' failed")" +expect "an empty journal does not trip the ERR trap" 0 "$(grep -c TRAPPED <<<"$out")" +expect "the helper returns 0" 1 "$(grep -c '^rc=0$' <<<"$out")" +expect "the pct output is shown instead" 1 "$(grep -c "startup for container" <<<"$out")" +expect "the build log gets the pct output" 1 "$(grep -c "startup for container" "$BUILD_LOG")" + +: >"$BUILD_LOG" +printf '%s\n' 'Starting pve-container@100.service - PVE LXC Container: 100...' \ + 'lxc-start: 100: conf.c: mount_entry: No such file or directory' \ + 'pve-container@100.service: Control process exited, code=exited, status=1/FAILURE' \ + 'Failed to start pve-container@100.service - PVE LXC Container: 100.' >"$JOURNAL" +out="$(run_helper "pct out")" +expect "the journal reason survives the filter" 1 "$(grep -c 'conf.c: mount_entry' <<<"$out")" +expect "systemd bookkeeping is dropped" 0 "$(grep -c 'Control process exited' <<<"$out")" +expect "a journal with lines does not trip the trap either" 0 "$(grep -c TRAPPED <<<"$out")" +expect "the reason lands in the build log" 1 "$(grep -c 'conf.c: mount_entry' "$BUILD_LOG")" + +echo "$passed passed, $failed failed" +((failed == 0))