diff --git a/.github/workflows/ops-deploy-runner-fleet.yml b/.github/workflows/ops-deploy-runner-fleet.yml new file mode 100644 index 0000000..c5e929f --- /dev/null +++ b/.github/workflows/ops-deploy-runner-fleet.yml @@ -0,0 +1,197 @@ +name: One-shot runner fleet deployment + +on: + push: + branches: + - ops/deploy-runner-fleet-20260818 + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: one-shot-runner-fleet-deployment + cancel-in-progress: false + +jobs: + deploy: + runs-on: [self-hosted, Linux, X64, co-server] + timeout-minutes: 30 + steps: + - name: Deploy scheduler and provision runners + shell: bash + run: | + set -euo pipefail + umask 077 + + echo "== host preflight ==" + id + hostname + sudo -n true + sudo -n -u nomad -H sudo -n true + sudo -n -u nomad -H gh auth status >/dev/null + + work="$(sudo -n -u nomad -H mktemp -d /tmp/runner-fleet-deploy.XXXXXX)" + cleanup() { + sudo rm -rf -- "$work" + } + trap cleanup EXIT + + scheduler_repo="$work/plugin-scheduler" + light_repo="$work/plugin-light" + fleet_repo="$work/ghrunner" + tarball="$work/actions-runner-linux-x64-2.336.0.tar.gz" + + echo "== fetch approved deployment sources ==" + sudo -n -u nomad -H gh repo clone \ + PRISMA-USER-INTERFACE-FRAMEWORK/PluginEditTool \ + "$scheduler_repo" -- --branch fix/scheduler-managed-worker-filter --single-branch --quiet + sudo -n -u nomad -H gh repo clone \ + PRISMA-USER-INTERFACE-FRAMEWORK/PluginEditTool \ + "$light_repo" -- --branch ci/add-prisma-light-runner-bootstrap --single-branch --quiet + sudo -n -u nomad -H gh repo clone \ + G-A-R-D-E-N/GHRUNNER \ + "$fleet_repo" -- --branch feat/hosted-minute-repo-runners --single-branch --quiet + + sudo -n -u nomad -H bash -c 'cd "$1" && ./scripts/validate-repo.sh' bash "$fleet_repo" + python3 -m py_compile "$scheduler_repo/tools/ci/ghrunnerd.py" + bash -n "$light_repo/tools/ci/install-prisma-runner.sh" + + echo "== deploy PluginEditTool #194 scheduler fix ==" + sudo install -m 0755 \ + "$scheduler_repo/tools/ci/ghrunnerd.py" \ + /usr/local/lib/gh-runner/ghrunnerd.py + sudo systemctl restart gh-runner-webhook.service + sudo systemctl is-active --quiet gh-runner-webhook.service + sudo /usr/local/lib/gh-runner/ghrunnerd.py status + + echo "== fetch and verify pinned Actions runner ==" + sudo -n -u nomad -H curl -fL --retry 3 --retry-delay 2 \ + -o "$tarball" \ + https://github.com/actions/runner/releases/download/v2.336.0/actions-runner-linux-x64-2.336.0.tar.gz + actual="$(sha256sum "$tarball" | awk '{print $1}')" + expected="04cf0be1aff4c3ec3554466c39124ca250e3effd8873bb7e8d68535aa9505d5d" + test "$actual" = "$expected" || { + echo "runner archive digest mismatch" >&2 + echo "expected: $expected" >&2 + echo "actual: $actual" >&2 + exit 1 + } + + org_runner_exists() { + sudo -n -u nomad -H gh api \ + 'orgs/PRISMA-USER-INTERFACE-FRAMEWORK/actions/runners?per_page=100' \ + --jq '.runners[] | select(.name == "prisma-light-1") | .name' \ + | grep -qx 'prisma-light-1' + } + + repo_runner_exists() { + local repo="$1" name="$2" + sudo -n -u nomad -H gh api "repos/$repo/actions/runners?per_page=100" \ + --jq ".runners[] | select(.name == \"$name\") | .name" \ + | grep -qx "$name" + } + + echo "== provision prisma-light-1 ==" + light_dir=/opt/actions-runner-prisma-light-1 + light_unit=actions.runner.PRISMA-USER-INTERFACE-FRAMEWORK.prisma-light-1.service + if org_runner_exists; then + test -d "$light_dir" || { + echo "prisma-light-1 exists on GitHub but $light_dir is missing" >&2 + exit 1 + } + sudo systemctl cat "$light_unit" >/dev/null + sudo systemctl enable --now "$light_unit" + else + test ! -e "$light_dir" || { + echo "$light_dir exists but prisma-light-1 is not registered on GitHub" >&2 + exit 1 + } + token="$(sudo -n -u nomad -H gh api -X POST \ + orgs/PRISMA-USER-INTERFACE-FRAMEWORK/actions/runners/registration-token \ + --jq .token)" + test -n "$token" + printf '%s\n' "$token" \ + | sudo -n -u nomad -H bash \ + "$light_repo/tools/ci/install-prisma-runner.sh" \ + prisma-light-1 "$tarball" + unset token + fi + + verify_light_labels() { + sudo -n -u nomad -H gh api \ + 'orgs/PRISMA-USER-INTERFACE-FRAMEWORK/actions/runners?per_page=100' \ + --jq '.runners[] | select(.name == "prisma-light-1") | [.labels[].name] | sort | join(",")' + } + labels="$(verify_light_labels)" + test "$labels" = "prisma-light" || { + echo "prisma-light-1 has unexpected labels: $labels" >&2 + exit 1 + } + sudo systemctl is-active --quiet "$light_unit" + sudo systemctl show "$light_unit" -p User -p Slice -p MemoryHigh -p MemoryMax -p MemorySwapMax + + install_repo_runner() { + local key="$1" repo="$2" name="$3" dir="$4" unit="$5" + echo "== provision $key ($repo) ==" + if repo_runner_exists "$repo" "$name"; then + test -d "$dir" || { + echo "$name exists on GitHub but $dir is missing" >&2 + exit 1 + } + sudo systemctl cat "$unit" >/dev/null + sudo -n -u nomad -H bash -c \ + 'cd "$1" && ./scripts/apply-host-baseline.sh --runner "$2" --apply' \ + bash "$fleet_repo" "$key" + else + test ! -e "$dir" || { + echo "$dir exists but $name is not registered on GitHub" >&2 + exit 1 + } + token="$(sudo -n -u nomad -H gh api -X POST \ + "repos/$repo/actions/runners/registration-token" --jq .token)" + test -n "$token" + printf '%s\n' "$token" \ + | sudo -n -u nomad -H bash -c \ + 'cd "$1" && exec ./scripts/install-runner.sh "$2" "$3"' \ + bash "$fleet_repo" "$key" "$tarball" + unset token + fi + sudo "$fleet_repo/scripts/audit-host.sh" --runner "$key" + } + + install_repo_runner \ + aimatrix G-A-R-D-E-N/AIMatrix aimatrix-ci \ + /opt/actions-runner-aimatrix \ + actions.runner.G-A-R-D-E-N-AIMatrix.aimatrix-ci.service + + install_repo_runner \ + uirepo G-A-R-D-E-N/UIRepo uirepo-ci \ + /opt/actions-runner-uirepo \ + actions.runner.G-A-R-D-E-N-UIRepo.uirepo-ci.service + + install_repo_runner \ + f4lodgen G-A-R-D-E-N/F4LODGEN f4lodgen-ci \ + /opt/actions-runner-f4lodgen \ + actions.runner.G-A-R-D-E-N-F4LODGEN.f4lodgen-ci.service + + install_repo_runner \ + fcc G-A-R-D-E-N/FCC fcc-ci \ + /opt/actions-runner-fcc \ + actions.runner.G-A-R-D-E-N-FCC.fcc-ci.service + + install_repo_runner \ + aimatrix-local G-A-R-D-E-N/aimatrix-local aimatrix-local-ci \ + /opt/actions-runner-aimatrix-local \ + actions.runner.G-A-R-D-E-N-aimatrix-local.aimatrix-local-ci.service + + install_repo_runner \ + commonwealth-ui-sync G-A-R-D-E-N/CommonwealthOnlineUI commonwealth-ui-sync \ + /opt/actions-runner-commonwealth-ui-sync \ + actions.runner.G-A-R-D-E-N-CommonwealthOnlineUI.commonwealth-ui-sync.service + + echo "== final fleet audit ==" + sudo "$fleet_repo/scripts/audit-host.sh" + sudo /usr/local/lib/gh-runner/ghrunnerd.py status + + echo "deployment complete"