diff --git a/.github/workflows/auto-updates.yaml b/.github/workflows/auto-updates.yaml index 2443b633b2..60938057f1 100644 --- a/.github/workflows/auto-updates.yaml +++ b/.github/workflows/auto-updates.yaml @@ -28,7 +28,7 @@ jobs: ubuntu-version: resolute name: Update ${{ matrix.ubuntu-version }} packaging related Rust files - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest container: image: ubuntu:${{ matrix.ubuntu-version }} env: diff --git a/.github/workflows/brokers-qa.yaml b/.github/workflows/brokers-qa.yaml index b2b966bbda..6e1037bf53 100644 --- a/.github/workflows/brokers-qa.yaml +++ b/.github/workflows/brokers-qa.yaml @@ -33,7 +33,7 @@ defaults: jobs: go-sanity: name: "Go: Code sanity" - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest steps: - uses: actions/checkout@v7 with: @@ -53,7 +53,7 @@ jobs: shell-sanity: name: "Shell: Code sanity" - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest steps: - uses: actions/checkout@v7 - name: Run ShellCheck @@ -63,7 +63,7 @@ jobs: go-tests: name: "Go: Tests" - runs-on: ubuntu-24.04 # ubuntu-latest-runner + runs-on: ubuntu-26.04 # ubuntu-latest strategy: fail-fast: false matrix: diff --git a/.github/workflows/build-broker-snap.yaml b/.github/workflows/build-broker-snap.yaml index 49d3809d29..960e909fd2 100644 --- a/.github/workflows/build-broker-snap.yaml +++ b/.github/workflows/build-broker-snap.yaml @@ -11,7 +11,7 @@ on: jobs: build-broker-snap: name: Build broker snap (${{ inputs.broker }}) - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest permissions: # Needed by actions/checkout contents: read diff --git a/.github/workflows/cla-check.yaml b/.github/workflows/cla-check.yaml index 7e3b15294b..66c1cefc2d 100644 --- a/.github/workflows/cla-check.yaml +++ b/.github/workflows/cla-check.yaml @@ -4,7 +4,7 @@ on: [pull_request_target] jobs: cla-check: name: Check if CLA is signed - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest steps: - name: Check if CLA signed uses: canonical/has-signed-canonical-cla@v2 diff --git a/.github/workflows/debian-build-test-and-sync.yaml b/.github/workflows/debian-build-test-and-sync.yaml index 5ead14ae7c..9ea8d274b5 100644 --- a/.github/workflows/debian-build-test-and-sync.yaml +++ b/.github/workflows/debian-build-test-and-sync.yaml @@ -26,7 +26,7 @@ jobs: run-autopkgtests: name: Run autopkgtests - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest needs: build-deb # Run autopkgtests only on: @@ -70,7 +70,7 @@ jobs: synchronize-packaging-branches: name: Update packaging branch - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest needs: build-deb permissions: contents: write diff --git a/.github/workflows/debian-build.yaml b/.github/workflows/debian-build.yaml index 86bcbbf14f..a84729a8c7 100644 --- a/.github/workflows/debian-build.yaml +++ b/.github/workflows/debian-build.yaml @@ -28,7 +28,7 @@ env: jobs: build-deb: name: Build Debian package (${{ inputs.files-hash }}) - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest permissions: # Needed by actions/checkout contents: read diff --git a/.github/workflows/debian.yaml b/.github/workflows/debian.yaml index 37ce1bcf67..8a422565f9 100644 --- a/.github/workflows/debian.yaml +++ b/.github/workflows/debian.yaml @@ -58,7 +58,7 @@ concurrency: jobs: compute-hash: name: Compute hash of build-relevant files - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest outputs: files-hash: ${{ steps.hash.outputs.hash }} steps: @@ -71,7 +71,7 @@ jobs: get-modified-files: name: Get modified files - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest outputs: list: ${{ fromJSON(steps.git-diff.outputs.modified_files) }} diff --git a/.github/workflows/e2e-tests-provision-and-run.yaml b/.github/workflows/e2e-tests-provision-and-run.yaml index 00d3f0f081..2705a09646 100644 --- a/.github/workflows/e2e-tests-provision-and-run.yaml +++ b/.github/workflows/e2e-tests-provision-and-run.yaml @@ -29,13 +29,13 @@ on: env: DEBIAN_FRONTEND: noninteractive VM_NAME_BASE: e2e-runner - ARTIFACTS_DIR: /tmp/e2e-artifacts + ARTIFACTS_DIR: /var/tmp/e2e-artifacts E2E_TESTS_DIR: e2e-tests jobs: provision-vm: name: Provision VM - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest permissions: # Needed by actions/checkout contents: read diff --git a/.github/workflows/e2e-tests-run.yaml b/.github/workflows/e2e-tests-run.yaml index fa8ae23197..398796a340 100644 --- a/.github/workflows/e2e-tests-run.yaml +++ b/.github/workflows/e2e-tests-run.yaml @@ -51,9 +51,9 @@ on: env: DEBIAN_FRONTEND: noninteractive VM_NAME_BASE: e2e-runner - ARTIFACTS_DIR: /tmp/e2e-artifacts + ARTIFACTS_DIR: /var/tmp/e2e-artifacts + OUTPUT_DIR: /var/tmp/e2e-${{ inputs.broker }}-${{ inputs.ubuntu-version }}/output E2E_TESTS_DIR: e2e-tests - OUTPUT_DIR: /tmp/e2e-${{ inputs.broker }}-${{ inputs.ubuntu-version }}/output jobs: build-broker-snap: @@ -67,7 +67,7 @@ jobs: name: Run e2e-tests (${{ inputs.broker }}) needs: build-broker-snap if: ${{ !cancelled() && (needs.build-broker-snap.result == 'success' || needs.build-broker-snap.result == 'skipped') }} - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest permissions: # Needed by actions/checkout contents: read diff --git a/.github/workflows/e2e-tests.yaml b/.github/workflows/e2e-tests.yaml index 831d106aad..e96f0fcce3 100644 --- a/.github/workflows/e2e-tests.yaml +++ b/.github/workflows/e2e-tests.yaml @@ -83,7 +83,7 @@ jobs: github.event_name == 'release' || github.event_name == 'schedule' || github.event_name == 'workflow_dispatch' - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest outputs: files-hash: ${{ steps.hash.outputs.hash }} steps: diff --git a/.github/workflows/git.yaml b/.github/workflows/git.yaml index 8f0fdeb653..356f09adc2 100644 --- a/.github/workflows/git.yaml +++ b/.github/workflows/git.yaml @@ -4,7 +4,7 @@ on: [pull_request] jobs: block-fixup: - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest steps: - uses: actions/checkout@v7 diff --git a/.github/workflows/oci-artifacts-cleanup.yaml b/.github/workflows/oci-artifacts-cleanup.yaml index 726c3ce122..76cb1bdada 100644 --- a/.github/workflows/oci-artifacts-cleanup.yaml +++ b/.github/workflows/oci-artifacts-cleanup.yaml @@ -7,7 +7,7 @@ on: jobs: cleanup-broker-snap: - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest permissions: packages: write strategy: @@ -22,7 +22,7 @@ jobs: min-versions-to-keep: 10 cleanup-deb: - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest permissions: packages: write strategy: @@ -44,7 +44,7 @@ jobs: min-versions-to-keep: 10 cleanup-e2e-test-vm-image: - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest permissions: packages: write steps: diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml index c973a74f2a..b0a89336fd 100644 --- a/.github/workflows/qa.yaml +++ b/.github/workflows/qa.yaml @@ -55,6 +55,7 @@ env: libglib2.0-dev libpam-dev libpwquality-dev + systemd-dev go_test_dependencies: >- bubblewrap @@ -67,7 +68,7 @@ jobs: go-sanity: name: "Go: Code sanity" permissions: {} - runs-on: ubuntu-24.04 # ubuntu-latest-runner + runs-on: ubuntu-26.04 # ubuntu-latest steps: - uses: canonical/desktop-engineering/gh-actions/common/dpkg-install-speedup@main - name: Install dependencies @@ -109,7 +110,7 @@ jobs: shell-sanity: name: "Shell: Code sanity" - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest steps: - uses: actions/checkout@v7 - name: Run ShellCheck @@ -120,7 +121,7 @@ jobs: rust-sanity: name: "Rust: Code sanity" permissions: {} - runs-on: ubuntu-24.04 # ubuntu-latest-runner + runs-on: ubuntu-26.04 # ubuntu-latest steps: - uses: canonical/desktop-engineering/gh-actions/common/dpkg-install-speedup@main - name: Install dependencies @@ -141,7 +142,7 @@ jobs: c-sanity: name: "C Code sanity" - runs-on: ubuntu-24.04 # ubuntu-latest-runner + runs-on: ubuntu-26.04 # ubuntu-latest env: CFLAGS: "-Werror" steps: @@ -184,10 +185,10 @@ jobs: go-tests-coverage: name: "Go Tests with Coverage Collection" - runs-on: ubuntu-24.04 # ubuntu-latest-runner + runs-on: ubuntu-26.04 # ubuntu-latest env: - RAW_COVERAGE_DIR: ${{ github.workspace }}/raw-coverage - COVERAGE_DIR: ${{ github.workspace }}/coverage + RAW_COVERAGE_DIR: /tmp/raw-coverage + COVERAGE_DIR: /tmp/coverage # Also run tests which require a different Ubuntu version, which we run in LXD # containers. AUTHD_TESTS_USE_LXD: true @@ -265,7 +266,7 @@ jobs: name: "Retry Go Tests with Coverage Collection" needs: go-tests-coverage if: always() && needs.go-tests-coverage.result == 'failure' - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 # ubuntu-latest env: RAW_COVERAGE_DIR: ${{ github.workspace }}/raw-coverage COVERAGE_DIR: ${{ github.workspace }}/coverage @@ -343,7 +344,7 @@ jobs: go-tests-race: name: "Go Tests with Race Detector" - runs-on: ubuntu-24.04 # ubuntu-latest-runner + runs-on: ubuntu-26.04 # ubuntu-latest steps: - uses: actions/checkout@v7 - id: setup-go-tests @@ -373,7 +374,7 @@ jobs: go-tests-asan: name: "Go PAM tests with Address Sanitizer" - runs-on: ubuntu-24.04 # ubuntu-latest-runner + runs-on: ubuntu-26.04 # ubuntu-latest steps: - uses: actions/checkout@v7 - uses: ./.github/actions/setup-go-tests diff --git a/.github/workflows/update-broker-variant-branches.yaml b/.github/workflows/update-broker-variant-branches.yaml index ab4e32b830..8eb3074813 100644 --- a/.github/workflows/update-broker-variant-branches.yaml +++ b/.github/workflows/update-broker-variant-branches.yaml @@ -25,7 +25,7 @@ jobs: strategy: matrix: branch_name: ["google-edge", "msentraid-edge", "oidc-edge"] - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest steps: - uses: actions/checkout@v7 with: diff --git a/.github/workflows/validate-dependabot.yaml b/.github/workflows/validate-dependabot.yaml index 62b4b18a69..d398750207 100644 --- a/.github/workflows/validate-dependabot.yaml +++ b/.github/workflows/validate-dependabot.yaml @@ -7,7 +7,7 @@ on: jobs: validate: - runs-on: ubuntu-latest + runs-on: ubuntu-26.04 # ubuntu-latest steps: - uses: actions/checkout@v7 - uses: marocchino/validate-dependabot@v3 diff --git a/e2e-tests/install-deps.sh b/e2e-tests/install-deps.sh index eb42c406d3..ddd42e08d9 100755 --- a/e2e-tests/install-deps.sh +++ b/e2e-tests/install-deps.sh @@ -12,7 +12,7 @@ sudo apt-get update && sudo apt-get -y install \ libvirt-clients-qemu \ libvirt-daemon-system \ libxkbcommon-dev \ - qemu-kvm \ + qemu-system-x86 \ python3-cairo \ python3-gi \ python3-tk \ diff --git a/e2e-tests/resources/Journal.py b/e2e-tests/resources/Journal.py index 4e5cb48114..87dba5f364 100644 --- a/e2e-tests/resources/Journal.py +++ b/e2e-tests/resources/Journal.py @@ -34,11 +34,12 @@ async def start_receiving_journal(self) -> None: os.makedirs(self.output_dir, exist_ok=True) if os.getenv("SYSTEMD_SUPPORTS_VSOCK"): + vm_name = VMUtils.vm_name() self.process = ExecUtils.Popen( [ "/lib/systemd/systemd-journal-remote", f"--listen-raw=vsock:{HOST_CID}:{PORT}", - f"--output={self.output_dir}", + f"--output={self.output_dir}/{vm_name}.journal", ], stderr=subprocess.PIPE, ) diff --git a/e2e-tests/vm/helpers/virsh b/e2e-tests/vm/helpers/virsh index be0c547990..a22ebc01dd 100755 --- a/e2e-tests/vm/helpers/virsh +++ b/e2e-tests/vm/helpers/virsh @@ -1,4 +1,4 @@ #!/usr/bin/env bash set -euo pipefail -exec sudo -E /usr/bin/virsh "$@" +exec sudo /usr/bin/virsh "$@" diff --git a/e2e-tests/vm/install-provision-deps.sh b/e2e-tests/vm/install-provision-deps.sh index 39a5491969..5be858c3c0 100755 --- a/e2e-tests/vm/install-provision-deps.sh +++ b/e2e-tests/vm/install-provision-deps.sh @@ -9,7 +9,7 @@ sudo apt-get update && sudo apt-get -y install \ guestfish \ libvirt-clients-qemu \ libvirt-daemon-system \ - qemu-kvm \ + qemu-system-x86 \ retry \ socat \ xvfb \ diff --git a/e2e-tests/vm/lib/libprovision.sh b/e2e-tests/vm/lib/libprovision.sh index 36618927e2..31926188ff 100755 --- a/e2e-tests/vm/lib/libprovision.sh +++ b/e2e-tests/vm/lib/libprovision.sh @@ -76,7 +76,26 @@ function force_create_snapshot() { function restore_snapshot_and_sync_time() { local snapshot_name="$1" virsh snapshot-revert "${VM_NAME}" --snapshotname "${snapshot_name}" - sync_time + # Reverting a disk-only snapshot leaves the VM shut off because + # there is no saved memory state to resume from. Start it if needed. + if ! virsh domstate "${VM_NAME}" | grep -q '^running'; then + boot_system + fi + # Cloud-init may have run its power_state module and shut the VM down + # after booting (e.g. if this snapshot predates the cloud-init disable). + # Detect this via sync_time: if the VM shuts down mid-sync, wait for it + # to stop fully and reboot — cloud-init does not re-run after completing + # its first run. + if ! sync_time; then + if virsh domstate "${VM_NAME}" | grep -q '^running'; then + # VM is still running; sync_time failed for an unrelated reason. + return 1 + fi + timeout 120 retry --delay 1 -- \ + sh -c "virsh domstate \"${VM_NAME}\" | grep -q '^shut off'" + boot_system + sync_time + fi } function sync_time() { diff --git a/e2e-tests/vm/provision-authd.sh b/e2e-tests/vm/provision-authd.sh index 9fe2cb25bc..804866fddf 100755 --- a/e2e-tests/vm/provision-authd.sh +++ b/e2e-tests/vm/provision-authd.sh @@ -259,8 +259,24 @@ fi if has_snapshot "$PRE_AUTHD_SNAPSHOT"; then restore_snapshot_and_sync_time "$PRE_AUTHD_SNAPSHOT" else + # Disable cloud-init before booting so it does not re-run its final + # stage (which includes power_state: poweroff) during provisioning. + # The base image was snapshotted before cloud-init's final stage + # completed, so without this cloud-init would put the VM into + # "shutting down" state mid-provisioning. + sudo guestfish -a "${IMAGE}" -i touch /etc/cloud/cloud-init.disabled # Ensure the VM is running to perform initial setup boot_system + # If cloud-init still powered off the VM despite the above (e.g. because + # the image's ext4 journal replay undid the guestfish write), detect the + # shutdown and handle it: wait for the VM to fully stop, then disable + # cloud-init again on the now-clean filesystem and reboot. + if ! virsh domstate "${VM_NAME}" | grep -q '^running'; then + timeout 120 retry --delay 1 -- \ + sh -c "virsh domstate \"${VM_NAME}\" | grep -q '^shut off'" + sudo guestfish -a "${IMAGE}" -i touch /etc/cloud/cloud-init.disabled + boot_system + fi # Create a pre-authd setup snapshot force_create_snapshot "$PRE_AUTHD_SNAPSHOT" fi diff --git a/e2e-tests/vm/provision-ubuntu.sh b/e2e-tests/vm/provision-ubuntu.sh index 3a55c4b8f2..5c6cec55ef 100755 --- a/e2e-tests/vm/provision-ubuntu.sh +++ b/e2e-tests/vm/provision-ubuntu.sh @@ -265,6 +265,14 @@ if ! cloud_init_finished "${IMAGE}"; then # Detach the cloud-init ISO virsh detach-disk "${VM_NAME}" vdb --config + # Disable cloud-init so it does not re-run on subsequent boots. + # The initial setup is complete; without this, cloud-init would + # re-execute its final stage (including power_state: poweroff) on + # any subsequent boot from this image, because the snapshot used as + # the base image is taken before cloud-init's final stage writes its + # completion semaphores. + sudo guestfish -a "${IMAGE}" -i touch /etc/cloud/cloud-init.disabled + if [ -z "${NO_SNAPSHOT:-}" ]; then boot_system # Create a snapshot of the initial setup diff --git a/internal/testutils/lxd.go b/internal/testutils/lxd.go index 012d8592b1..d11543aede 100644 --- a/internal/testutils/lxd.go +++ b/internal/testutils/lxd.go @@ -147,6 +147,7 @@ func RunTestInLXD(t *testing.T, ubuntuVersion string) bool { goTestArgs = append(goTestArgs, "-v") } if coverDir := CoverDirForTests(); coverDir != "" { + lxcExec(t, containerName, "mkdir", "-p", coverDir) goTestArgs = append(goTestArgs, "-cover", fmt.Sprintf("-test.gocoverdir=%s", coverDir)) } goTestArgs = append(goTestArgs, ".")