diff --git a/.github/workflows/stlc-generate.yml b/.github/workflows/stlc-generate.yml index b7fd5b14f..10672eea5 100644 --- a/.github/workflows/stlc-generate.yml +++ b/.github/workflows/stlc-generate.yml @@ -238,7 +238,15 @@ jobs: --targets all \ "${commit_args[@]}" stlc exec --targets "$SDK_TARGETS" -- ./scripts/bootstrap - stlc lint --targets "$SDK_TARGETS" + for attempt in 1 2 3; do + if stlc lint --targets "$SDK_TARGETS"; then + break + fi + if [ "$attempt" -eq 3 ]; then + exit 1 + fi + sleep 5 + done stlc test --targets "$SDK_TARGETS" stlc exec --targets "$SDK_TARGETS" -- sh -c \ 'status=$(git status --porcelain --untracked-files=all) && [ -z "$status" ] || { printf "%s\n" "$status" >&2; exit 1; }' diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 261148f24..0d6908541 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -28,6 +28,17 @@ jobs: runs-on: [self-hosted, linux, x64, kvm] steps: - uses: actions/checkout@v4 + id: checkout + continue-on-error: true + with: + clean: false + repository: ${{ env.TEST_SOURCE_REPO }} + ref: ${{ env.TEST_SOURCE_REF }} + persist-credentials: false + + - name: Retry checkout + if: steps.checkout.outcome == 'failure' + uses: actions/checkout@v4 with: clean: false repository: ${{ env.TEST_SOURCE_REPO }} @@ -97,6 +108,27 @@ jobs: sudo env "PATH=$TEST_PATH" bash -lc "command -v '$bin'" done + - name: Stage Windows test fixtures + run: | + fixture_dir=/mnt/data/ci-fixtures/windows + image_source=$(sudo find /mnt/data/home -path '*/windows-vm-exp/build/*-agent.qcow2' -print -quit) + base_source=$(sudo find /mnt/data/home -path '*/windows-vm-exp/build/*-golden.raw' -print -quit) + sudo mkdir -p "$fixture_dir" /ci/windows + if ! test -r "$fixture_dir/image-agent.qcow2" && test -n "$image_source"; then + sudo cp --reflink=auto --sparse=always "$image_source" "$fixture_dir/image-agent.qcow2" + sudo chmod 0444 "$fixture_dir/image-agent.qcow2" + fi + if ! test -r "$fixture_dir/base.raw" && test -n "$base_source"; then + sudo cp --reflink=auto --sparse=always "$base_source" "$fixture_dir/base.raw" + sudo chmod 0444 "$fixture_dir/base.raw" + fi + if test -r "$fixture_dir/image-agent.qcow2"; then + sudo ln -sfn "$fixture_dir/image-agent.qcow2" /ci/windows/image-agent.qcow2 + fi + if test -r "$fixture_dir/base.raw"; then + sudo ln -sfn "$fixture_dir/base.raw" /ci/windows/base.raw + fi + # Slash-command runs are maintainer-approved and need authenticated pulls # for images that are not covered by the prewarm cache. - name: Login to Docker Hub diff --git a/lib/instances/test_network_config_test.go b/lib/instances/test_network_config_test.go index 0df71cb89..738c281d6 100644 --- a/lib/instances/test_network_config_test.go +++ b/lib/instances/test_network_config_test.go @@ -161,7 +161,10 @@ func allocateTestNetworkLease(testName string, seq uint32) (*testNetworkLease, e return err } - bridgeName = fmt.Sprintf("hm%04x%03x", testNetworkRunSeed&0xffff, seq%0xfff) + bridgeName, err = testBridgeNameForSubnet(subnet) + if err != nil { + return err + } allocatedSubnet = subnet leases[subnet] = subnetLease{ TestName: testName, @@ -443,6 +446,34 @@ func pruneStaleLeases(leases map[string]subnetLease, routes []hostRoute) { } } +func testBridgeNameForSubnet(subnet string) (string, error) { + ip, _, err := net.ParseCIDR(subnet) + if err != nil { + return "", fmt.Errorf("parse test subnet %q: %w", subnet, err) + } + ip = ip.To4() + if ip == nil { + return "", fmt.Errorf("test subnet %q is not IPv4", subnet) + } + return fmt.Sprintf("hm%02x%02x", ip[1], ip[2]), nil +} + +func TestBridgeNameForTestSubnet(t *testing.T) { + t.Parallel() + + first, err := testBridgeNameForSubnet("10.200.1.0/24") + if err != nil { + t.Fatal(err) + } + second, err := testBridgeNameForSubnet("10.200.2.0/24") + if err != nil { + t.Fatal(err) + } + if first != "hmc801" || second != "hmc802" || first == second { + t.Fatalf("unexpected bridge names: %q %q", first, second) + } +} + func bridgeExists(name string) bool { if name == "" { return false