mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-15 09:01:31 +00:00
fix(ci): scope e2e telemetry per cell/job and define suite topology eligibility once (#573)
* feat(ci): extend per-cell telemetry scoping to every e2e workflow ci.cell only reached e2e-nightly and e2e-suites, so a run of e2e, e2e-ddil or gpu-e2e still landed in the sink as one undifferentiated bucket. Stamp it on the remaining workflows: single/multi on e2e's two provisioning jobs, ddil and gpu on their single-job workflows. The best-effort numeric job id lookup moves out of e2e-nightly into a shared composite action, so the four other provisioning jobs get ci.job_id without copying the gh/jq incantation. The lookup now matches on env.JOB_NAME rather than interpolating the name into the jq filter, which broke on names carrying quotes or non-ASCII separators, and no-ops when telemetry is disabled. gpu-e2e gets ci.cell but deliberately no job id lookup: nothing in that job bakes the attrs into a daemon, so the API call would be paid for an env var no exporter reads. * fix(ci): define e2e suite topology eligibility once Three workflows carried three different answers to which suites a topology can run. e2e-suites and e2e-nightly ran lb on their single-node leg, where every internet-facing subtest skips for want of a peer, so a fraction of the suite reported as a green lb run. e2e-suites' multi leg ran multinode alone, dropping the lb and cert coverage that only a multi-node env can complete — so full lb coverage never ran there at all. .github/scripts/suite-sets.sh is now the single definition, sourced by all three. e2e.yml's two allow-list regexes derive from it, e2e-suites derives both matrices from it (multi_provision gains the suite-matrix step single_provision already had), and e2e-nightly's deliberately narrower per-cell lists are declared there too, guarded by an assert that fails the cell if a subset ever names a suite its topology cannot fully exercise. The nightly stays narrow on purpose: its cells have a 35-minute budget and exist to prove each install/network/host-OS permutation boots and serves. Suite breadth is the PR gate's job and already runs on every push. That is now stated in one place rather than implied by a third divergent list.
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
name: Resolve OTEL job id
|
||||
description: >-
|
||||
Append ci.job_id to SPINIFEX_OTEL_ATTRS so telemetry emitted by this job can
|
||||
be pivoted straight back to its GitHub job log. Must run before the step that
|
||||
bakes SPINIFEX_OTEL_ATTRS into a VM's telemetry.env, and requires
|
||||
`actions: read` on the calling job.
|
||||
|
||||
inputs:
|
||||
job-name:
|
||||
description: >-
|
||||
Rendered name of the calling job, exactly as it appears in the Actions UI.
|
||||
github.job is only the YAML key and no context exposes the numeric id, so
|
||||
the id has to be looked up by name.
|
||||
required: true
|
||||
token:
|
||||
description: Token used for the Actions jobs API lookup.
|
||||
required: false
|
||||
default: ${{ github.token }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Resolve CI job id (best-effort)
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ inputs.token }}
|
||||
JOB_NAME: ${{ inputs.job-name }}
|
||||
REPO: ${{ github.repository }}
|
||||
RUN_ID: ${{ github.run_id }}
|
||||
run: |
|
||||
# Never fail the caller: on any lookup error or name mismatch ci.job_id
|
||||
# is simply omitted and the run proceeds with the labels it already has.
|
||||
set +e
|
||||
|
||||
if [ -z "${SPINIFEX_OTEL_ATTRS:-}" ]; then
|
||||
echo "SPINIFEX_OTEL_ATTRS is unset or empty — telemetry is disabled, nothing to label"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# env.JOB_NAME rather than shell interpolation into the jq filter: job
|
||||
# names carry quotes, slashes and non-ASCII separators that would
|
||||
# otherwise break the expression.
|
||||
JOB_ID=$(gh api "repos/${REPO}/actions/runs/${RUN_ID}/jobs" --paginate \
|
||||
--jq '.jobs[] | select(.name == env.JOB_NAME) | .id' 2>/dev/null | head -n1)
|
||||
|
||||
if [ -n "$JOB_ID" ]; then
|
||||
echo "SPINIFEX_OTEL_ATTRS=${SPINIFEX_OTEL_ATTRS},ci.job_id=${JOB_ID}" >> "$GITHUB_ENV"
|
||||
echo "resolved ci.job_id=${JOB_ID} for job '${JOB_NAME}'"
|
||||
else
|
||||
echo "::warning::could not resolve numeric job id for '${JOB_NAME}' — continuing without ci.job_id"
|
||||
fi
|
||||
exit 0
|
||||
@@ -0,0 +1,58 @@
|
||||
# shellcheck shell=bash
|
||||
# shellcheck disable=SC2034 # every variable here is consumed by the sourcing workflow
|
||||
# Source from a workflow `run:` block:
|
||||
# . "${GITHUB_WORKSPACE}/spinifex/.github/scripts/suite-sets.sh"
|
||||
#
|
||||
# Which e2e suites each topology can run. Sourced by every workflow that drives
|
||||
# suites (e2e.yml, e2e-suites.yml, e2e-nightly.yml) so the lists cannot drift
|
||||
# apart — they previously disagreed three ways.
|
||||
#
|
||||
# Eligibility is a property of the suite, not of the workflow: a suite belongs
|
||||
# to a topology when all of its assertions are reachable there. lb is
|
||||
# multi-only for exactly that reason — on a single node every internet-facing
|
||||
# subtest skips for want of a peer, so a single-node lb run reports green
|
||||
# having exercised a fraction of the suite.
|
||||
|
||||
# Suites runnable against a one-node environment.
|
||||
#
|
||||
# partialblock gates merges because it earned it, not because it is new: on one
|
||||
# node, same binary and workload, it fails against the pre-fix engine (1758 of
|
||||
# 8192 halves reverted a generation) and passes against the fixed one (0 of
|
||||
# 8192). A suite that has never been shown to go red for the reason it claims
|
||||
# does not belong here.
|
||||
E2E_SUITES_SINGLE="single iam cert eks ecs storagegrowth partialblock"
|
||||
|
||||
# Suites runnable against a multi-node environment.
|
||||
E2E_SUITES_MULTI="multinode lb cert"
|
||||
|
||||
# grep -xE alternation form, for narrowing a requested set to the eligible one.
|
||||
E2E_SUITES_SINGLE_RE="$(printf '%s' "${E2E_SUITES_SINGLE}" | tr ' ' '|')"
|
||||
E2E_SUITES_MULTI_RE="$(printf '%s' "${E2E_SUITES_MULTI}" | tr ' ' '|')"
|
||||
|
||||
# e2e-nightly runs a narrower set than the two sets above, deliberately: its
|
||||
# ~19 cells each have a 35-minute budget and exist to prove that every
|
||||
# install / network / host-OS permutation boots and serves. Suite breadth is
|
||||
# the PR gate's job, and it already runs on every push. These are subsets, and
|
||||
# e2e_suites_assert_subset below enforces that.
|
||||
E2E_SUITES_NIGHTLY_SINGLE="single cert"
|
||||
E2E_SUITES_NIGHTLY_MULTI="multinode cert lb"
|
||||
|
||||
# Fail loudly when a narrowed list names a suite its topology cannot run. This
|
||||
# is the guard that stops the lists drifting again: a suite added to a nightly
|
||||
# subset without also being declared eligible above stops the job here rather
|
||||
# than silently skipping half its assertions in CI.
|
||||
# e2e_suites_assert_subset <label> <subset> <eligible-set>
|
||||
e2e_suites_assert_subset() {
|
||||
local label="$1" subset="$2" eligible="$3" suite found eligible_suite
|
||||
for suite in ${subset}; do
|
||||
found=0
|
||||
for eligible_suite in ${eligible}; do
|
||||
if [ "${suite}" = "${eligible_suite}" ]; then found=1; break; fi
|
||||
done
|
||||
if [ "${found}" -ne 1 ]; then
|
||||
echo "::error::${label} names suite '${suite}', which is not eligible for that topology (eligible: ${eligible}). Fix the list in .github/scripts/suite-sets.sh." >&2
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
}
|
||||
@@ -13,6 +13,9 @@ on:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
# actions: read lets the otel-job-id action look up this job's numeric id via
|
||||
# the Actions API — github.job is only the YAML key, no context exposes it.
|
||||
actions: read
|
||||
|
||||
env:
|
||||
GIT_BRANCH: ${{ github.ref_name }}
|
||||
@@ -28,6 +31,10 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
TOFU_LOG: /tmp/e2e-tofu-ddil-${{ github.run_id }}.log
|
||||
# Job-level env wins over the workflow-level default. ci.cell=ddil marks
|
||||
# this workflow's telemetry so a DDIL run's partition-induced errors are
|
||||
# never mistaken for a healthy multi-node run's in the sink.
|
||||
SPINIFEX_OTEL_ATTRS: ci.run_id=${{ github.run_id }},ci.workflow=${{ github.workflow }},ci.cell=ddil
|
||||
steps:
|
||||
- name: Clean Workspace
|
||||
run: sudo rm -rf "$GITHUB_WORKSPACE"/*
|
||||
@@ -72,6 +79,13 @@ jobs:
|
||||
echo "${BIN_DIR}" >> "${GITHUB_PATH}"
|
||||
"${BIN_DIR}/gotestsum" --version
|
||||
|
||||
# Adds ci.job_id alongside ci.cell, before Bootstrap bakes the attrs into
|
||||
# the VMs, so a telemetry doc points back at this job's log directly.
|
||||
- name: Resolve CI job id
|
||||
uses: ./spinifex/.github/actions/otel-job-id
|
||||
with:
|
||||
job-name: DDIL Real Multi-Node
|
||||
|
||||
- name: Build Install Artifacts
|
||||
working-directory: mulga/scripts/tofu-cluster
|
||||
run: |
|
||||
|
||||
@@ -73,29 +73,6 @@ jobs:
|
||||
echo "cell ${CELL} not in '${CELLS}' — subsequent steps will skip"
|
||||
fi
|
||||
|
||||
# Best-effort: github.job is this job's YAML key ("matrix"), not its
|
||||
# numeric id, and no context exposes the id directly, so look it up by
|
||||
# rendered job name via the Actions API before Bootstrap bakes
|
||||
# SPINIFEX_OTEL_ATTRS into the VM's telemetry.env. Must never fail the
|
||||
# job — on any lookup error or name mismatch, ci.job_id is simply
|
||||
# omitted and the run proceeds with ci.cell alone.
|
||||
- name: Resolve CI job id (best-effort)
|
||||
if: steps.gate.outputs.selected == 'true'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
JOB_NAME: "cell-${{ matrix.cell }} (${{ matrix.topo }}/${{ matrix.net }}/${{ matrix.host }}${{ matrix.extra && format('/{0}', matrix.extra) || '' }})"
|
||||
run: |
|
||||
set +e
|
||||
JOB_ID=$(gh api "repos/${{ github.repository }}/actions/runs/${{ github.run_id }}/jobs" --paginate \
|
||||
--jq ".jobs[] | select(.name == \"${JOB_NAME}\") | .id" 2>/dev/null | head -n1)
|
||||
if [ -n "$JOB_ID" ]; then
|
||||
echo "SPINIFEX_OTEL_ATTRS=${SPINIFEX_OTEL_ATTRS},ci.job_id=${JOB_ID}" >> "$GITHUB_ENV"
|
||||
echo "resolved ci.job_id=${JOB_ID} for job '${JOB_NAME}'"
|
||||
else
|
||||
echo "::warning::could not resolve numeric job id for '${JOB_NAME}' — continuing without ci.job_id"
|
||||
fi
|
||||
exit 0
|
||||
|
||||
- name: Clean Workspace
|
||||
if: steps.gate.outputs.selected == 'true'
|
||||
run: |
|
||||
@@ -124,6 +101,16 @@ jobs:
|
||||
with:
|
||||
path: spinifex
|
||||
|
||||
# Nine cells share one run id and every cell names its hosts
|
||||
# node1/node2/node3, so ci.cell above separates them and ci.job_id here
|
||||
# links each cell's telemetry to the job log that produced it. Runs
|
||||
# before Bootstrap bakes SPINIFEX_OTEL_ATTRS into the VM's telemetry.env.
|
||||
- name: Resolve CI job id
|
||||
if: steps.gate.outputs.selected == 'true'
|
||||
uses: ./spinifex/.github/actions/otel-job-id
|
||||
with:
|
||||
job-name: "cell-${{ matrix.cell }} (${{ matrix.topo }}/${{ matrix.net }}/${{ matrix.host }}${{ matrix.extra && format('/{0}', matrix.extra) || '' }})"
|
||||
|
||||
- name: Build Install Artifacts
|
||||
if: steps.gate.outputs.selected == 'true'
|
||||
working-directory: mulga/scripts/tofu-cluster
|
||||
@@ -179,13 +166,20 @@ jobs:
|
||||
if: steps.gate.outputs.selected == 'true' && matrix.topo == 'single' && matrix.extra == ''
|
||||
working-directory: mulga/scripts/tofu-cluster
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# Nightly runs a documented subset of the single-node set; the assert
|
||||
# fails the cell if that subset ever names a suite this topology
|
||||
# cannot fully exercise.
|
||||
. "${GITHUB_WORKSPACE}/spinifex/.github/scripts/suite-sets.sh"
|
||||
e2e_suites_assert_subset "e2e-nightly single" "${E2E_SUITES_NIGHTLY_SINGLE}" "${E2E_SUITES_SINGLE}"
|
||||
|
||||
INVENTORY=$(tofu output -json inventory)
|
||||
WAN_IP=$(echo "$INVENTORY" | jq -r '.nodes[0].wan_ip')
|
||||
SSH_KEY=$(echo "$INVENTORY" | jq -r '.ssh_key_path')
|
||||
SSH_KEY="${SSH_KEY/#\~/$HOME}"
|
||||
ssh -tt -o StrictHostKeyChecking=no -i "$SSH_KEY" tf-user@${WAN_IP} \
|
||||
"set -u; mkdir -p '${ARTIFACT_DIR}'; cd \$HOME/e2e-tests/_bin; FAIL=0; \
|
||||
for SUITE in single cert lb; do \
|
||||
for SUITE in ${E2E_SUITES_NIGHTLY_SINGLE}; do \
|
||||
echo \"::group::suite \$SUITE\"; \
|
||||
date -u +%Y-%m-%dT%H:%M:%SZ > '${ARTIFACT_DIR}/test-'\$SUITE'.start'; \
|
||||
GITHUB_ACTIONS=true FORCE_COLOR=1 SPINIFEX_E2E=1 SPINIFEX_MODE=single \
|
||||
@@ -222,6 +216,11 @@ jobs:
|
||||
if: steps.gate.outputs.selected == 'true' && matrix.topo == 'real-multi'
|
||||
working-directory: mulga/scripts/tofu-cluster
|
||||
run: |
|
||||
set -euo pipefail
|
||||
# See the single-node step: same subset guard, multi-node set.
|
||||
. "${GITHUB_WORKSPACE}/spinifex/.github/scripts/suite-sets.sh"
|
||||
e2e_suites_assert_subset "e2e-nightly multi" "${E2E_SUITES_NIGHTLY_MULTI}" "${E2E_SUITES_MULTI}"
|
||||
|
||||
INVENTORY=$(tofu output -json inventory)
|
||||
NODE1_IP=$(echo "$INVENTORY" | jq -r '.nodes[0].wan_ip')
|
||||
SSH_KEY=$(echo "$INVENTORY" | jq -r '.ssh_key_path')
|
||||
@@ -236,7 +235,7 @@ jobs:
|
||||
|
||||
ssh -tt -o StrictHostKeyChecking=no -i "$SSH_KEY" tf-user@${NODE1_IP} \
|
||||
"set -u; mkdir -p '${ARTIFACT_DIR}'; cd \$HOME/e2e-tests/_bin; FAIL=0; \
|
||||
for SUITE in multinode cert lb; do \
|
||||
for SUITE in ${E2E_SUITES_NIGHTLY_MULTI}; do \
|
||||
echo \"::group::suite \$SUITE\"; \
|
||||
date -u +%Y-%m-%dT%H:%M:%SZ > '${ARTIFACT_DIR}/test-'\$SUITE'.start'; \
|
||||
GITHUB_ACTIONS=true FORCE_COLOR=1 SPINIFEX_E2E=1 SPINIFEX_MODE=multinode \
|
||||
|
||||
@@ -3,11 +3,14 @@
|
||||
# Restructures the looped e2e.yml into env-grouped job blocks so each suite
|
||||
# surfaces as its own node in the Actions graph (mulga-siv-283):
|
||||
#
|
||||
# single_provision ─┬─ single_suite (matrix: single, cert, lb, eks, iam)
|
||||
# single_provision ─┬─ single_suite (matrix: the single-node-eligible suites)
|
||||
# └─ single_teardown (if: always)
|
||||
# multi_provision ─┬─ multi_suite (matrix: multinode)
|
||||
# multi_provision ─┬─ multi_suite (matrix: the multi-node-eligible suites)
|
||||
# └─ multi_teardown (if: always)
|
||||
#
|
||||
# Both matrices come from .github/scripts/suite-sets.sh, the one definition of
|
||||
# which suites a topology can run, shared with e2e.yml and e2e-nightly.yml.
|
||||
#
|
||||
# Constraint: tofu state is runner-filesystem-local, so *_provision and
|
||||
# *_teardown must execute on the same self-hosted runner (one runner per label
|
||||
# today). Teardown reuses the persisted mulga/ tofu-cluster workspace and does
|
||||
@@ -25,9 +28,13 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
single_suites:
|
||||
description: "Single-node suites to run as matrix legs"
|
||||
description: "Single-node suites to run as matrix legs (empty = every single-node-eligible suite, per .github/scripts/suite-sets.sh)"
|
||||
required: false
|
||||
default: "single cert lb eks iam"
|
||||
default: ""
|
||||
multi_suites:
|
||||
description: "Multi-node suites to run as matrix legs (empty = every multi-node-eligible suite, per .github/scripts/suite-sets.sh)"
|
||||
required: false
|
||||
default: ""
|
||||
run_multinode:
|
||||
description: "Also run the multinode env block"
|
||||
type: boolean
|
||||
@@ -40,6 +47,10 @@ on:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
# actions: read lets the otel-job-id action look up a provision job's numeric
|
||||
# id via the Actions API — github.job is only the YAML key, no context
|
||||
# exposes it.
|
||||
actions: read
|
||||
|
||||
env:
|
||||
GIT_BRANCH: ${{ github.ref_name }}
|
||||
@@ -122,12 +133,22 @@ jobs:
|
||||
- name: Re-enable Go toolchain auto-download
|
||||
run: echo "GOTOOLCHAIN=auto" >> "$GITHUB_ENV"
|
||||
|
||||
# Default and allow-list both come from the shared definition, so this
|
||||
# workflow cannot drift from e2e.yml about what a single node can run.
|
||||
- name: Compute suite matrix
|
||||
id: suites
|
||||
env:
|
||||
REQUESTED: ${{ inputs.single_suites }}
|
||||
run: |
|
||||
LIST="${{ inputs.single_suites || 'single cert lb eks iam' }}"
|
||||
set -euo pipefail
|
||||
. "${GITHUB_WORKSPACE}/spinifex/.github/scripts/suite-sets.sh"
|
||||
LIST="${REQUESTED:-${E2E_SUITES_SINGLE}}"
|
||||
e2e_suites_assert_subset "single_suites" "${LIST}" "${E2E_SUITES_SINGLE}"
|
||||
echo "list=${LIST}" >> "$GITHUB_OUTPUT"
|
||||
JSON=$(printf '%s\n' $LIST | jq -R . | jq -cs .)
|
||||
# Unquoted on purpose: the space-separated list must word-split into
|
||||
# one JSON element per suite.
|
||||
# shellcheck disable=SC2086
|
||||
JSON=$(printf '%s\n' ${LIST} | jq -R . | jq -cs .)
|
||||
echo "matrix=${JSON}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Reclaim docker build cache
|
||||
@@ -137,6 +158,14 @@ jobs:
|
||||
docker buildx prune -af --filter "until=24h" || true
|
||||
docker system df || true
|
||||
|
||||
# ci.job_id names the provision job, not the suite job that later drives
|
||||
# the env: the suite legs share this env and its baked telemetry.env, so
|
||||
# the provisioner is the only job the daemon telemetry can belong to.
|
||||
- name: Resolve CI job id
|
||||
uses: ./spinifex/.github/actions/otel-job-id
|
||||
with:
|
||||
job-name: Single env · provision
|
||||
|
||||
- name: Build Install Artifacts
|
||||
working-directory: mulga/scripts/tofu-cluster
|
||||
run: |
|
||||
@@ -504,6 +533,8 @@ jobs:
|
||||
node1_ip: ${{ steps.cluster.outputs.node1_ip }}
|
||||
ssh_key: ${{ steps.cluster.outputs.ssh_key }}
|
||||
nodes_csv: ${{ steps.cluster.outputs.nodes_csv }}
|
||||
suites: ${{ steps.suites.outputs.list }}
|
||||
matrix: ${{ steps.suites.outputs.matrix }}
|
||||
env:
|
||||
TOFU_LOG: /tmp/e2e-tofu-multi-${{ github.run_id }}.log
|
||||
# See single_provision above — daemon telemetry is baked in here, at
|
||||
@@ -564,6 +595,12 @@ jobs:
|
||||
docker buildx prune -af --filter "until=24h" || true
|
||||
docker system df || true
|
||||
|
||||
# See the matching note on single_provision.
|
||||
- name: Resolve CI job id
|
||||
uses: ./spinifex/.github/actions/otel-job-id
|
||||
with:
|
||||
job-name: Multi env · provision
|
||||
|
||||
- name: Build Install Artifacts
|
||||
working-directory: mulga/scripts/tofu-cluster
|
||||
run: |
|
||||
@@ -611,14 +648,36 @@ jobs:
|
||||
echo "ssh_key=${SSH_KEY}" >> "$GITHUB_OUTPUT"
|
||||
echo "nodes_csv=${NODES_CSV}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build multinode binary on runner
|
||||
# Mirrors single_provision's step: the multi leg previously ran multinode
|
||||
# alone, silently dropping the lb and cert coverage that only a
|
||||
# multi-node env can complete.
|
||||
- name: Compute suite matrix
|
||||
id: suites
|
||||
env:
|
||||
REQUESTED: ${{ inputs.multi_suites }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
. "${GITHUB_WORKSPACE}/spinifex/.github/scripts/suite-sets.sh"
|
||||
LIST="${REQUESTED:-${E2E_SUITES_MULTI}}"
|
||||
e2e_suites_assert_subset "multi_suites" "${LIST}" "${E2E_SUITES_MULTI}"
|
||||
echo "list=${LIST}" >> "$GITHUB_OUTPUT"
|
||||
# Unquoted on purpose: the space-separated list must word-split into
|
||||
# one JSON element per suite.
|
||||
# shellcheck disable=SC2086
|
||||
JSON=$(printf '%s\n' ${LIST} | jq -R . | jq -cs .)
|
||||
echo "matrix=${JSON}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build multinode binaries on runner
|
||||
working-directory: spinifex/tests/e2e
|
||||
run: |
|
||||
set -euo pipefail
|
||||
source "${GITHUB_WORKSPACE}/spinifex/.github/scripts/ci-fmt.sh"
|
||||
banner "build multinode, teardown"
|
||||
# teardown always builds: the run-scoped sweep binary runs in the
|
||||
# teardown job, it is never a selectable suite leg.
|
||||
SUITES_BUILD="${{ steps.suites.outputs.list }} teardown"
|
||||
banner "build ${SUITES_BUILD// /, }"
|
||||
group_open "go test -c"
|
||||
make e2e-build SUITES_BUILD="multinode teardown"
|
||||
make e2e-build SUITES_BUILD="${SUITES_BUILD}"
|
||||
group_close
|
||||
ok "$(basename _bin/multinode.test) $(stat -c '%s' _bin/multinode.test | numfmt --to=iec)"
|
||||
|
||||
@@ -662,7 +721,7 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
suite: [multinode]
|
||||
suite: ${{ fromJSON(needs.multi_provision.outputs.matrix) }}
|
||||
env:
|
||||
NODE1_IP: ${{ needs.multi_provision.outputs.node1_ip }}
|
||||
SSH_KEY: ${{ needs.multi_provision.outputs.ssh_key }}
|
||||
|
||||
+38
-13
@@ -26,6 +26,9 @@ on:
|
||||
permissions:
|
||||
contents: read
|
||||
statuses: write
|
||||
# actions: read lets the otel-job-id action look up a job's numeric id via
|
||||
# the Actions API — github.job is only the YAML key, no context exposes it.
|
||||
actions: read
|
||||
|
||||
env:
|
||||
GIT_BRANCH: ${{ github.ref_name }}
|
||||
@@ -78,10 +81,12 @@ jobs:
|
||||
# here, before this job provisions a tofu env or pays the Spinifex install.
|
||||
#
|
||||
# The dispatch check gates on exactly the suites this job's Run step
|
||||
# allow-lists (single|iam|cert|eks|ecs|storagegrowth|partialblock). Gating
|
||||
# on a suite the job won't run — lb, which only executes in the multinode
|
||||
# job — would provision a tofu VM and pay the Spinifex install only to run
|
||||
# nothing and tear down. Push triggers keep running via the null-check on
|
||||
# allow-lists, i.e. E2E_SUITES_SINGLE in .github/scripts/suite-sets.sh —
|
||||
# an `if:` expression cannot source that file, so this one list is
|
||||
# hand-mirrored and must be updated with it. Gating on a suite the job
|
||||
# won't run — lb, which only executes in the multinode job — would
|
||||
# provision a tofu VM and pay the Spinifex install only to run nothing and
|
||||
# tear down. Push triggers keep running via the null-check on
|
||||
# inputs.suites.
|
||||
if: needs.integration.result == 'success' && (github.event_name != 'workflow_dispatch' || contains(github.event.inputs.suites, 'e2e-single') || contains(github.event.inputs.suites, 'e2e-iam') || contains(github.event.inputs.suites, 'e2e-cert') || contains(github.event.inputs.suites, 'e2e-eks') || contains(github.event.inputs.suites, 'e2e-ecs') || contains(github.event.inputs.suites, 'e2e-storagegrowth') || contains(github.event.inputs.suites, 'e2e-partialblock'))
|
||||
runs-on: [self-hosted, ci-single]
|
||||
@@ -89,6 +94,12 @@ jobs:
|
||||
env:
|
||||
TOFU_LOG: /tmp/e2e-tofu-single-${{ github.run_id }}.log
|
||||
ARTIFACT_DIR: /tmp/spinifex-e2e-artifacts-${{ github.run_id }}
|
||||
# Job-level env wins over the workflow-level default. This job and
|
||||
# e2e_multi share one run id and both name their hosts node1/node2/node3,
|
||||
# so without ci.cell their telemetry collapses into one bucket. This job
|
||||
# is where "Bootstrap via Binary Install" bakes SPINIFEX_OTEL_ATTRS into
|
||||
# the VM's telemetry.env, so the label has to be set here.
|
||||
SPINIFEX_OTEL_ATTRS: ci.run_id=${{ github.run_id }},ci.workflow=${{ github.workflow }},ci.cell=single
|
||||
steps:
|
||||
- name: Reap Orphan Procs
|
||||
run: |
|
||||
@@ -153,6 +164,13 @@ jobs:
|
||||
docker buildx prune -af --filter "until=24h" || true
|
||||
docker system df || true
|
||||
|
||||
# Adds ci.job_id alongside ci.cell, before Bootstrap bakes the attrs into
|
||||
# the VM, so a telemetry doc points back at this job's log directly.
|
||||
- name: Resolve CI job id
|
||||
uses: ./spinifex/.github/actions/otel-job-id
|
||||
with:
|
||||
job-name: Single-Node E2E
|
||||
|
||||
- name: Build Install Artifacts
|
||||
working-directory: mulga/scripts/tofu-cluster
|
||||
run: |
|
||||
@@ -318,14 +336,11 @@ jobs:
|
||||
set +e
|
||||
# Allow-list, not a deny-list: a suite runs here only if named. Deny-lists
|
||||
# silently fan a newly added suite out to every job, which is how lb ended up
|
||||
# running twice per e2e run.
|
||||
#
|
||||
# partialblock gates merges because it earned it, not because it is
|
||||
# new: on one node, same binary and workload, it fails against the
|
||||
# pre-fix engine (1758 of 8192 halves reverted a generation) and
|
||||
# passes against the fixed one (0 of 8192). A suite that has never
|
||||
# been shown to go red for the reason it claims does not belong here.
|
||||
SUITES_RUN=$(echo "${SUITES}" | sed 's/e2e-//g' | tr ' ' '\n' | grep -xE 'single|iam|cert|eks|ecs|storagegrowth|partialblock' | tr '\n' ' ')
|
||||
# running twice per e2e run. The allow-list itself is shared with the other
|
||||
# e2e workflows so the three cannot disagree about what a topology can run;
|
||||
# suite-sets.sh also carries the per-suite rationale.
|
||||
. "${GITHUB_WORKSPACE}/spinifex/.github/scripts/suite-sets.sh"
|
||||
SUITES_RUN=$(echo "${SUITES}" | sed 's/e2e-//g' | tr ' ' '\n' | grep -xE "${E2E_SUITES_SINGLE_RE}" | tr '\n' ' ')
|
||||
if [ -z "$(echo "${SUITES_RUN}" | tr -d ' ')" ]; then
|
||||
echo "no in-VM suites requested (SUITES=${SUITES}); skipping"
|
||||
echo "rc=0" >> "$GITHUB_OUTPUT"
|
||||
@@ -515,6 +530,9 @@ jobs:
|
||||
env:
|
||||
TOFU_LOG: /tmp/e2e-tofu-multi-${{ github.run_id }}.log
|
||||
ARTIFACT_DIR: /tmp/spinifex-e2e-multi-artifacts-${{ github.run_id }}
|
||||
# See the matching note on e2e_single: ci.cell is what separates this
|
||||
# job's 3-node telemetry from the single-node job's under one run id.
|
||||
SPINIFEX_OTEL_ATTRS: ci.run_id=${{ github.run_id }},ci.workflow=${{ github.workflow }},ci.cell=multi
|
||||
steps:
|
||||
- name: Reap Orphan Procs
|
||||
run: |
|
||||
@@ -579,6 +597,12 @@ jobs:
|
||||
docker buildx prune -af --filter "until=24h" || true
|
||||
docker system df || true
|
||||
|
||||
# See the matching note on e2e_single.
|
||||
- name: Resolve CI job id
|
||||
uses: ./spinifex/.github/actions/otel-job-id
|
||||
with:
|
||||
job-name: Multi-Node E2E
|
||||
|
||||
- name: Build Install Artifacts
|
||||
working-directory: mulga/scripts/tofu-cluster
|
||||
run: |
|
||||
@@ -721,7 +745,8 @@ jobs:
|
||||
run: |
|
||||
set +e
|
||||
# Allow-list, not a deny-list — see the single-node job for why.
|
||||
SUITES_RUN=$(echo "${SUITES}" | sed 's/e2e-//g' | tr ' ' '\n' | grep -xE 'multinode|lb|cert' | tr '\n' ' ')
|
||||
. "${GITHUB_WORKSPACE}/spinifex/.github/scripts/suite-sets.sh"
|
||||
SUITES_RUN=$(echo "${SUITES}" | sed 's/e2e-//g' | tr ' ' '\n' | grep -xE "${E2E_SUITES_MULTI_RE}" | tr '\n' ' ')
|
||||
if [ -z "$(echo "${SUITES_RUN}" | tr -d ' ')" ]; then
|
||||
echo "no multinode-eligible suites requested (SUITES=${SUITES}); skipping"
|
||||
echo "rc=0" >> "$GITHUB_OUTPUT"
|
||||
|
||||
@@ -88,7 +88,11 @@ env:
|
||||
# the GPU suite's own daemon-side spans are emitted by wattle's already-
|
||||
# configured obs-agent, not by this job.
|
||||
SPINIFEX_OTLP_ENDPOINT: ${{ vars.SPINIFEX_OTLP_ENDPOINT || 'http://192.168.1.13:8200' }}
|
||||
SPINIFEX_OTEL_ATTRS: ci.run_id=${{ github.run_id }},ci.workflow=${{ github.workflow }}
|
||||
# ci.cell=gpu keeps this workflow's telemetry separable from the tofu-env
|
||||
# workflows'. Nothing in this job bakes these attrs into a daemon (see the
|
||||
# note above), so the label only takes effect once wattle's obs-agent is
|
||||
# given them; there is deliberately no ci.job_id lookup for the same reason.
|
||||
SPINIFEX_OTEL_ATTRS: ci.run_id=${{ github.run_id }},ci.workflow=${{ github.workflow }},ci.cell=gpu
|
||||
WATTLE_SSH_HOST: ${{ vars.WATTLE_SSH_HOST || '192.168.1.13' }}
|
||||
WATTLE_SSH_USER: ${{ vars.WATTLE_SSH_USER || 'tf-user' }}
|
||||
TEST_RUN: ${{ inputs.test_run || '' }}
|
||||
|
||||
Reference in New Issue
Block a user