From 69743729a332ea45a112dc5653cd523bc5322ba3 Mon Sep 17 00:00:00 2001 From: Andrew Lavery Date: Tue, 14 Apr 2026 18:30:26 +0400 Subject: [PATCH] smoke test all linux target architectures (#2016) * smoke test all linux target architectures * go mod update * use 'real' target cluster * better logging * newer alpine --- .github/workflows/build-test.yaml | 132 +++++++++++++++++- go.mod | 4 +- go.sum | 8 +- .../linuxArchSmokeLocalHostCollectors.yaml | 23 +++ 4 files changed, 160 insertions(+), 7 deletions(-) create mode 100644 test/e2e/support-bundle/spec/linuxArchSmokeLocalHostCollectors.yaml diff --git a/.github/workflows/build-test.yaml b/.github/workflows/build-test.yaml index 5091e44a..4617a468 100644 --- a/.github/workflows/build-test.yaml +++ b/.github/workflows/build-test.yaml @@ -104,6 +104,134 @@ jobs: path: bin/ retention-days: 1 + # Minimal linux architecture smoke tests + linux-arch-smoke: + if: needs.changes.outputs.go-files == 'true' + needs: [changes, lint] + runs-on: ubuntu-latest + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + include: + - goarch: amd64 + docker_platform: linux/amd64 + expected_machine: x86_64 + - goarch: arm64 + docker_platform: linux/arm64 + expected_machine: aarch64 + - goarch: arm + goarm: "7" + docker_platform: linux/arm/v7 + expected_machine: armv7l + - goarch: riscv64 + docker_platform: linux/riscv64 + expected_machine: riscv64 + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-go@v6 + with: + go-version-file: 'go.mod' + - name: Setup K3s + uses: replicatedhq/action-k3s@main + with: + version: v1.31.2-k3s1 + - uses: docker/setup-qemu-action@v3 + with: + platforms: arm64,arm,riscv64 + + - name: Build linux/${{ matrix.goarch }} binaries + env: + CGO_ENABLED: "0" + GOOS: linux + GOARCH: ${{ matrix.goarch }} + GOARM: ${{ matrix.goarm }} + run: | + if [ -n "${GOARM}" ]; then + echo "Building for GOARCH=${GOARCH} GOARM=${GOARM}" + else + echo "Building for GOARCH=${GOARCH}" + fi + make build + + - name: Collect a minimal support bundle on ${{ matrix.docker_platform }} + env: + PREFLIGHT_AUTO_UPDATE: "false" + TROUBLESHOOT_AUTO_UPDATE: "false" + run: | + set -euo pipefail + tmpdir="$(mktemp -d)" + trap 'rm -rf "$tmpdir"' EXIT + kubeconfig_path="${KUBECONFIG:-$HOME/.kube/config}" + + assert_tar_member() { + local pattern="$1" + local label="$2" + local member + member="$(grep -m1 "$pattern" "$tmpdir/archive-members.txt" || true)" + if [ -z "$member" ]; then + echo "Expected ${label} was not found in ${archive}" + exit 1 + fi + echo "Found ${label}: ${member}" + } + + echo "Using kubeconfig at ${kubeconfig_path}" + test -f "${kubeconfig_path}" + cp "${kubeconfig_path}" "$tmpdir/kubeconfig" + + echo "Verifying K3s cluster is reachable on the host" + kubectl --kubeconfig "$tmpdir/kubeconfig" get nodes -o wide + + docker run --rm \ + --platform ${{ matrix.docker_platform }} \ + --network host \ + -v "$PWD:/src" \ + -v "$tmpdir:/tmp/linux-arch-smoke" \ + -w /src \ + alpine:3.23 \ + sh -ec ' + export PREFLIGHT_AUTO_UPDATE=false + export TROUBLESHOOT_AUTO_UPDATE=false + /src/bin/support-bundle \ + --kubeconfig /tmp/linux-arch-smoke/kubeconfig \ + --interactive=false \ + /src/test/e2e/support-bundle/spec/linuxArchSmokeLocalHostCollectors.yaml \ + --output /tmp/linux-arch-smoke/linux-arch-support-bundle.tar.gz + ' + + archive="$tmpdir/linux-arch-support-bundle.tar.gz" + test -f "$archive" + echo "Generated support bundle archive: $archive" + tar -tf "$archive" > "$tmpdir/archive-members.txt" + + assert_tar_member '/host-collectors/system/cpu.json$' 'cpu.json' + assert_tar_member '/host-collectors/system/memory.json$' 'memory.json' + assert_tar_member '/host-collectors/run-host/uname.txt$' 'uname.txt' + assert_tar_member '/cluster-resources/nodes.json$' 'cluster-resources nodes.json' + assert_tar_member '/cluster-resources/resources.json$' 'cluster-resources resources.json' + assert_tar_member '/analysis.json$' 'analysis.json' + + echo "Checking uname -m output" + uname_path="$(grep -m1 '/host-collectors/run-host/uname.txt$' "$tmpdir/archive-members.txt")" + uname_machine="$(tar -xOf "$archive" "$uname_path" | tr -d '\r\n')" + if [ "$uname_machine" != '${{ matrix.expected_machine }}' ]; then + echo "Unexpected uname -m output: ${uname_machine}" + exit 1 + fi + echo "Analyzer input check passed: uname -m reported ${uname_machine}" + + echo "Checking analysis.json" + analysis_path="$(grep -m1 '/analysis.json$' "$tmpdir/archive-members.txt")" + tar -xOf "$archive" "$analysis_path" > "$tmpdir/analysis.json" + jq -e ' + .[] + | select(.insight.primary == "Linux arch smoke node count") + | select(.insight.detail == "This cluster has exactly 1 node") + | select(.severity == "debug") + ' "$tmpdir/analysis.json" >/dev/null + echo "Found expected analyzer result: Linux arch smoke node count -> This cluster has exactly 1 node" + # E2E tests e2e: if: needs.changes.outputs.go-files == 'true' || github.event_name == 'push' @@ -143,7 +271,7 @@ jobs: # Success summary success: if: always() - needs: [lint, test, build, e2e] + needs: [lint, test, build, linux-arch-smoke, e2e] runs-on: ubuntu-latest steps: - name: Check results @@ -152,6 +280,7 @@ jobs: if [[ "${{ needs.lint.result }}" == "failure" ]] || \ [[ "${{ needs.test.result }}" == "failure" ]] || \ [[ "${{ needs.build.result }}" == "failure" ]] || \ + [[ "${{ needs.linux-arch-smoke.result }}" == "failure" ]] || \ [[ "${{ needs.e2e.result }}" == "failure" ]]; then echo "::error::Some jobs failed or were cancelled" exit 1 @@ -161,6 +290,7 @@ jobs: if [[ "${{ needs.lint.result }}" == "cancelled" ]] || \ [[ "${{ needs.test.result }}" == "cancelled" ]] || \ [[ "${{ needs.build.result }}" == "cancelled" ]] || \ + [[ "${{ needs.linux-arch-smoke.result }}" == "cancelled" ]] || \ [[ "${{ needs.e2e.result }}" == "cancelled" ]]; then echo "::error::Some jobs failed or were cancelled" exit 1 diff --git a/go.mod b/go.mod index 053bed7e..911e991c 100644 --- a/go.mod +++ b/go.mod @@ -47,7 +47,7 @@ require ( go.opentelemetry.io/otel v1.43.0 go.opentelemetry.io/otel/sdk v1.43.0 go.podman.io/image/v5 v5.39.2 - golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 + golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f golang.org/x/mod v0.35.0 golang.org/x/sync v0.20.0 gopkg.in/yaml.v2 v2.4.0 @@ -166,7 +166,7 @@ require ( go.opentelemetry.io/otel/trace v1.43.0 // indirect go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect - golang.org/x/tools v0.43.0 // indirect + golang.org/x/tools v0.44.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20260226221140-a57be14db171 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20260226221140-a57be14db171 // indirect gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect diff --git a/go.sum b/go.sum index 932dfbf4..0b2762e6 100644 --- a/go.sum +++ b/go.sum @@ -650,8 +650,8 @@ golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.50.0 h1:zO47/JPrL6vsNkINmLoo/PH1gcxpls50DNogFvB5ZGI= golang.org/x/crypto v0.50.0/go.mod h1:3muZ7vA7PBCE6xgPX7nkzzjiUq87kRItoJQM1Yo8S+Q= -golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= -golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM= +golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80= golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM= golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -686,8 +686,8 @@ golang.org/x/text v0.36.0/go.mod h1:NIdBknypM8iqVmPiuco0Dh6P5Jcdk8lJL0CUebqK164= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.43.0 h1:12BdW9CeB3Z+J/I/wj34VMl8X+fEXBxVR90JeMX5E7s= -golang.org/x/tools v0.43.0/go.mod h1:uHkMso649BX2cZK6+RpuIPXS3ho2hZo4FVwfoy1vIk0= +golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c= +golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk= gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E= diff --git a/test/e2e/support-bundle/spec/linuxArchSmokeLocalHostCollectors.yaml b/test/e2e/support-bundle/spec/linuxArchSmokeLocalHostCollectors.yaml new file mode 100644 index 00000000..62ba9420 --- /dev/null +++ b/test/e2e/support-bundle/spec/linuxArchSmokeLocalHostCollectors.yaml @@ -0,0 +1,23 @@ +apiVersion: troubleshoot.sh/v1beta2 +kind: SupportBundle +metadata: + name: linux-arch-smoke-local-host-collectors +spec: + collectors: + - clusterResources: {} + hostCollectors: + - cpu: {} + - memory: {} + - run: + collectorName: uname + command: uname + args: ["-m"] + analyzers: + - nodeResources: + checkName: Linux arch smoke node count + outcomes: + - pass: + when: "= 1" + message: This cluster has exactly 1 node + - fail: + message: Expected exactly 1 node in the cluster