mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-13 15:51:39 +00:00
218 lines
9.1 KiB
YAML
218 lines
9.1 KiB
YAML
name: Qualify Exact-Candidate Containers
|
|
|
|
on:
|
|
workflow_call:
|
|
inputs:
|
|
version:
|
|
description: 'Version number without the leading v'
|
|
required: true
|
|
type: string
|
|
container_artifact:
|
|
description: 'Exact-candidate container payload artifact from this run'
|
|
required: true
|
|
type: string
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
qualify:
|
|
name: Exact-Candidate Container and Helm Smoke
|
|
# Stable qualification must be independent of persistent runner disk state.
|
|
# Prereleases keep the faster PVE lane, where a later clean rehearsal can
|
|
# expose and repair runner capacity without blocking a stable patch.
|
|
runs-on: ${{ !contains(inputs.version, '-') && 'ubuntu-24.04' || fromJSON('["self-hosted","Linux","X64","pulse-pve-build"]') }}
|
|
timeout-minutes: 15
|
|
env:
|
|
VERSION: ${{ inputs.version }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0
|
|
with:
|
|
# A reusable workflow inherits github.sha from its caller. Do not
|
|
# accept a caller-controlled checkout ref: the caller event commit is
|
|
# the immutable source identity for both code and candidate payload.
|
|
ref: ${{ github.sha }}
|
|
persist-credentials: false
|
|
|
|
- name: Verify exact caller source
|
|
env:
|
|
EXPECTED_SOURCE_SHA: ${{ github.sha }}
|
|
run: test "$(git rev-parse HEAD)" = "${EXPECTED_SOURCE_SHA}"
|
|
|
|
- name: Download exact-candidate container payload
|
|
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
name: ${{ inputs.container_artifact }}
|
|
path: ${{ runner.temp }}/release-container-payload
|
|
|
|
- name: Verify exact-candidate container payload
|
|
run: |
|
|
python3 scripts/release_candidate_manifest.py verify-local \
|
|
--release-dir "$RUNNER_TEMP/release-container-payload/payload" \
|
|
--manifest "$RUNNER_TEMP/release-container-payload/release-container-payload.json" \
|
|
--version "${VERSION}" \
|
|
--source-sha "${{ github.sha }}"
|
|
|
|
- name: Assemble exact-candidate runtime and agent images
|
|
run: |
|
|
set -euo pipefail
|
|
docker buildx build \
|
|
--target runtime_prebuilt \
|
|
--platform linux/amd64 \
|
|
--build-context "release_payload=${RUNNER_TEMP}/release-container-payload/payload/release" \
|
|
--load \
|
|
--tag "pulse-helm-smoke:${VERSION}" \
|
|
.
|
|
docker buildx build \
|
|
--target agent_runtime_prebuilt \
|
|
--platform linux/amd64 \
|
|
--build-context "release_payload=${RUNNER_TEMP}/release-container-payload/payload/release" \
|
|
--load \
|
|
--tag "pulse-agent-candidate:${VERSION}" \
|
|
.
|
|
docker buildx build \
|
|
--file deploy/provider-msp/Dockerfile.control-plane \
|
|
--target control_plane_prebuilt \
|
|
--platform linux/amd64 \
|
|
--build-context "compiled_payload=${RUNNER_TEMP}/release-container-payload/payload/compiled" \
|
|
--load \
|
|
--tag "pulse-control-plane-candidate:${VERSION}" \
|
|
.
|
|
|
|
- name: Verify container binaries match immutable candidate
|
|
run: |
|
|
set -euo pipefail
|
|
expected_server="$(sha256sum "$RUNNER_TEMP/release-container-payload/payload/release/amd64/bin/pulse" | awk '{print $1}')"
|
|
actual_server="$(docker run --rm --entrypoint /bin/sh "pulse-helm-smoke:${VERSION}" -c 'sha256sum /app/pulse' | awk '{print $1}')"
|
|
expected_agent="$(sha256sum "$RUNNER_TEMP/release-container-payload/payload/release/amd64/bin/pulse-agent-linux-amd64" | awk '{print $1}')"
|
|
actual_embedded_agent="$(docker run --rm --entrypoint /bin/sh "pulse-helm-smoke:${VERSION}" -c 'sha256sum /usr/local/bin/pulse-agent' | awk '{print $1}')"
|
|
actual_agent="$(docker run --rm --entrypoint /bin/sh "pulse-agent-candidate:${VERSION}" -c 'sha256sum /usr/local/bin/pulse-agent' | awk '{print $1}')"
|
|
expected_control_plane="$(sha256sum "$RUNNER_TEMP/release-container-payload/payload/compiled/binaries/pulse-control-plane-linux-amd64" | awk '{print $1}')"
|
|
actual_control_plane="$(docker run --rm --entrypoint /bin/sh "pulse-control-plane-candidate:${VERSION}" -c 'sha256sum /usr/local/bin/pulse-control-plane' | awk '{print $1}')"
|
|
test "${actual_server}" = "${expected_server}"
|
|
test "${actual_embedded_agent}" = "${expected_agent}"
|
|
test "${actual_agent}" = "${expected_agent}"
|
|
test "${actual_control_plane}" = "${expected_control_plane}"
|
|
docker run --rm --entrypoint /bin/sh "pulse-helm-smoke:${VERSION}" -c '
|
|
set -euo pipefail
|
|
test "$(readlink /usr/local/bin/pulse-agent)" = "/opt/pulse/bin/pulse-agent-linux-amd64"
|
|
test -x /usr/local/bin/pulse-agent
|
|
for sidecar in /opt/pulse/bin/*.sig /opt/pulse/bin/*.sshsig; do
|
|
test ! -x "$sidecar"
|
|
done
|
|
'
|
|
|
|
- name: Set up Helm
|
|
uses: azure/setup-helm@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0
|
|
with:
|
|
version: v3.15.2
|
|
|
|
- name: Helm smoke test with local release-line image
|
|
env:
|
|
SMOKE_IMAGE_REPOSITORY: pulse-helm-smoke
|
|
SMOKE_IMAGE_TAG: ${{ inputs.version }}
|
|
run: |
|
|
set -euo pipefail
|
|
|
|
cleanup() {
|
|
kind delete cluster --name pulse-test >/dev/null 2>&1 || true
|
|
}
|
|
|
|
diagnose() {
|
|
echo "::group::helm status"
|
|
helm status pulse || true
|
|
echo "::endgroup::"
|
|
|
|
echo "::group::kubectl get all"
|
|
kubectl get all -A || true
|
|
echo "::endgroup::"
|
|
|
|
echo "::group::kubectl describe pods"
|
|
kubectl describe pods -A || true
|
|
echo "::endgroup::"
|
|
|
|
echo "::group::pod logs"
|
|
pods=$(kubectl get pods -A -o name 2>/dev/null || true)
|
|
for pod in $pods; do
|
|
echo "### ${pod}"
|
|
kubectl logs --all-containers=true --tail=200 "$pod" || true
|
|
done
|
|
echo "::endgroup::"
|
|
|
|
echo "::group::events"
|
|
kubectl get events -A --sort-by=.lastTimestamp || kubectl get events -A || true
|
|
echo "::endgroup::"
|
|
|
|
cleanup
|
|
}
|
|
|
|
trap 'diagnose' ERR
|
|
|
|
prepare_cluster_tool() {
|
|
local name="$1"
|
|
local url="$2"
|
|
local expected_sha="$3"
|
|
local destination="$RUNNER_TEMP/$name"
|
|
local download="$destination.download"
|
|
local installed_path=""
|
|
installed_path="$(command -v "$name" 2>/dev/null || true)"
|
|
|
|
if [ -n "$installed_path" ] && printf '%s %s\n' "$expected_sha" "$installed_path" | sha256sum --check --status; then
|
|
install -m 0755 "$installed_path" "$destination"
|
|
else
|
|
rm -f "$download"
|
|
curl -fsSL -o "$download" "$url"
|
|
printf '%s %s\n' "$expected_sha" "$download" | sha256sum --check
|
|
chmod 0755 "$download"
|
|
mv "$download" "$destination"
|
|
fi
|
|
|
|
printf '%s %s\n' "$expected_sha" "$destination" | sha256sum --check
|
|
test -x "$destination"
|
|
}
|
|
|
|
prepare_cluster_tool \
|
|
kind \
|
|
https://kind.sigs.k8s.io/dl/v0.20.0/kind-linux-amd64 \
|
|
513a7213d6d3332dd9ef27c24dab35e5ef10a04fa27274fe1c14d8a246493ded
|
|
prepare_cluster_tool \
|
|
kubectl \
|
|
https://dl.k8s.io/release/v1.27.3/bin/linux/amd64/kubectl \
|
|
fba6c062e754a120bc8105cde1344de200452fe014a8759e06e4eec7ed258a09
|
|
export PATH="$RUNNER_TEMP:$PATH"
|
|
test "$(command -v kind)" = "$RUNNER_TEMP/kind"
|
|
test "$(command -v kubectl)" = "$RUNNER_TEMP/kubectl"
|
|
kind version
|
|
kubectl version --client=true
|
|
|
|
cleanup
|
|
kind create cluster --name pulse-test --wait 5m
|
|
kind load docker-image "${SMOKE_IMAGE_REPOSITORY}:${SMOKE_IMAGE_TAG}" --name pulse-test
|
|
|
|
helm install pulse deploy/helm/pulse \
|
|
--set persistence.enabled=false \
|
|
--set server.secretEnv.create=true \
|
|
--set server.secretEnv.data.API_TOKENS=test-token \
|
|
--set image.repository="${SMOKE_IMAGE_REPOSITORY}" \
|
|
--set image.tag="${SMOKE_IMAGE_TAG}" \
|
|
--set image.pullPolicy=Never \
|
|
--wait --timeout 5m --debug
|
|
|
|
kubectl wait --for=condition=ready pod -l app.kubernetes.io/name=pulse --timeout=180s || (kubectl describe pods -l app.kubernetes.io/name=pulse && exit 1)
|
|
kubectl get pods -l app.kubernetes.io/name=pulse
|
|
|
|
helm upgrade pulse deploy/helm/pulse \
|
|
--set persistence.enabled=false \
|
|
--set server.secretEnv.create=true \
|
|
--set server.secretEnv.data.API_TOKENS=test-token \
|
|
--set image.repository="${SMOKE_IMAGE_REPOSITORY}" \
|
|
--set image.tag="${SMOKE_IMAGE_TAG}" \
|
|
--set image.pullPolicy=Never \
|
|
--wait --timeout 5m --debug
|
|
|
|
trap - ERR
|
|
cleanup
|
|
|
|
echo "✓ Helm smoke test passed"
|