|
13 | 13 | # token minted with repo-admin creds, which live here on the bridge, not |
14 | 14 | # on the Mac node. This watchdog closes that gap. |
15 | 15 | # |
| 16 | +# Sibling of runner-watchdog-mac-arm.sh (PR #923). This is the backport of |
| 17 | +# that PR's three drop-test-proven fixes onto the Intel node. |
| 18 | +# |
16 | 19 | # WHAT IT DOES (idempotent, non-destructive): |
17 | 20 | # 1. Polls the repo's runners API for macpro-intel-204. |
18 | 21 | # 2. If the runner is absent or "offline" for >= THRESHOLD consecutive |
19 | 22 | # checks, mints a fresh registration token and re-registers the runner |
20 | | -# over SSH using `config.sh --replace` (no delete; --replace reuses the |
21 | | -# same name), then reloads the launchd service. |
| 23 | +# over SSH (see the launchd/config sequence below), then reloads the |
| 24 | +# launchd service into the GUI domain. |
22 | 25 | # 3. Resets the failure counter as soon as the runner is seen online. |
23 | 26 | # |
24 | 27 | # REVERT: delete this file + remove its launchd/cron entry on the bridge. |
25 | | -# It never deletes the runner; --replace is the only mutation it makes. |
| 28 | +# It never deletes the runner; it re-registers under the same name. |
26 | 29 | # |
27 | 30 | set -euo pipefail |
28 | 31 |
|
@@ -62,20 +65,61 @@ log "status=${status} consecutive_fails=${fails}/${THRESHOLD}" |
62 | 65 | [ "$fails" -lt "$THRESHOLD" ] && exit 0 |
63 | 66 |
|
64 | 67 | log "threshold reached -> re-registering" |
65 | | -TOKEN=$(gh api --method POST "repos/${REPO}/actions/runners/registration-token" --jq .token) |
66 | | -[ -z "$TOKEN" ] && { log "ERROR: empty registration token"; exit 1; } |
| 68 | +REG_TOKEN=$(gh api --method POST "repos/${REPO}/actions/runners/registration-token" --jq .token) |
| 69 | +[ -z "$REG_TOKEN" ] && { log "ERROR: empty registration token"; exit 1; } |
| 70 | +# Removal token deregisters the stale server-side registration + wipes local |
| 71 | +# config so a clean re-register succeeds. Best-effort: if GitHub already |
| 72 | +# dropped the runner ("absent"), remove is a no-op and we fall back to |
| 73 | +# wiping the local config files directly. |
| 74 | +RM_TOKEN=$(gh api --method POST "repos/${REPO}/actions/runners/remove-token" --jq .token 2>/dev/null || true) |
67 | 75 |
|
68 | | -ssh -i "$NODE_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no "$NODE_SSH" bash -s <<EOF |
| 76 | +# The original Intel 5-liner (svc.sh stop -> config.sh --replace -> svc.sh |
| 77 | +# start) was never drop-tested and is non-functional for a *deregistered* |
| 78 | +# runner, for two reasons proven by the .227 arm64 drop test 2026-07-27 |
| 79 | +# (PR #923) and expected to hold identically on this Intel node: |
| 80 | +# (a) The runner's launchd LaunchAgent lives in the user's *GUI* (Aqua) |
| 81 | +# domain. Over a non-GUI SSH session `svc.sh install/uninstall` |
| 82 | +# (plain `launchctl load/unload`) fail with "Unload failed: 5: |
| 83 | +# Input/output error". The agent must be managed with an explicit |
| 84 | +# `launchctl bootout|bootstrap gui/$UID ...` target. |
| 85 | +# (b) `config.sh --replace` does NOT bypass the local "already configured" |
| 86 | +# guard; a real `config.sh remove` (or wiping .runner/.credentials) |
| 87 | +# must precede a fresh `config.sh` configure. |
| 88 | +# Sequence: bootout+uninstall service -> unconfigure -> fresh configure -> |
| 89 | +# install + bootstrap+kickstart into the GUI domain. Non-destructive: no |
| 90 | +# runner is deleted beyond its own re-registration under the same name. |
| 91 | +ssh -i "$NODE_KEY" -o IdentitiesOnly=yes -o StrictHostKeyChecking=no "$NODE_SSH" \ |
| 92 | + REG_TOKEN="$REG_TOKEN" RM_TOKEN="$RM_TOKEN" REPO="$REPO" \ |
| 93 | + RUNNER_NAME="$RUNNER_NAME" RUNNER_LABELS="$RUNNER_LABELS" RUNNER_DIR="$RUNNER_DIR" \ |
| 94 | + bash -s <<'EOF' |
69 | 95 | set -e |
70 | | -cd "${RUNNER_DIR}" |
71 | | -./svc.sh stop || true |
72 | | -./config.sh remove --token "${TOKEN}" || true |
73 | | -./config.sh --unattended --replace \ |
| 96 | +cd "$RUNNER_DIR" |
| 97 | +U=$(id -u) |
| 98 | +LABEL="actions.runner.$(echo "$REPO" | tr '/' '-').${RUNNER_NAME}" |
| 99 | +PLIST="$HOME/Library/LaunchAgents/${LABEL}.plist" |
| 100 | +
|
| 101 | +# 1) stop + uninstall the LaunchAgent from the GUI domain |
| 102 | +launchctl bootout "gui/${U}/${LABEL}" 2>/dev/null || true |
| 103 | +./svc.sh uninstall 2>/dev/null || true |
| 104 | +
|
| 105 | +# 2) unconfigure (deregister + wipe local config); fall back to wiping files |
| 106 | +if [ -n "$RM_TOKEN" ]; then |
| 107 | + ./config.sh remove --token "$RM_TOKEN" || rm -f .runner .credentials .credentials_rsaparams |
| 108 | +else |
| 109 | + rm -f .runner .credentials .credentials_rsaparams |
| 110 | +fi |
| 111 | +
|
| 112 | +# 3) fresh register under the same name + labels |
| 113 | +./config.sh --unattended \ |
74 | 114 | --url "https://github.com/${REPO}" \ |
75 | | - --token "${TOKEN}" \ |
76 | | - --name "${RUNNER_NAME}" \ |
77 | | - --labels "${RUNNER_LABELS}" |
78 | | -./svc.sh start |
| 115 | + --token "$REG_TOKEN" \ |
| 116 | + --name "$RUNNER_NAME" \ |
| 117 | + --labels "$RUNNER_LABELS" |
| 118 | +
|
| 119 | +# 4) (re)install + load the service into the GUI domain |
| 120 | +./svc.sh install |
| 121 | +launchctl bootstrap "gui/${U}" "$PLIST" 2>/dev/null || true |
| 122 | +launchctl kickstart -k "gui/${U}/${LABEL}" |
79 | 123 | EOF |
80 | 124 |
|
81 | 125 | log "re-registration issued; clearing fail counter" |
|
0 commit comments