diff --git a/.github/workflows/binary-build.yml b/.github/workflows/binary-build.yml index 11f69a39e..a822ba82d 100644 --- a/.github/workflows/binary-build.yml +++ b/.github/workflows/binary-build.yml @@ -205,4 +205,10 @@ jobs: uses: actions/upload-artifact@v4 with: name: imagecreator-binary-${{ inputs.arch }} - path: repo/toolkit/out/imagecreator.tar.gz \ No newline at end of file + path: repo/toolkit/out/imagecreator.tar.gz + + - name: Upload osmodifier artifact + uses: actions/upload-artifact@v4 + with: + name: osmodifier-${{ inputs.arch }} + path: repo/toolkit/out/tools/osmodifier diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a6c1704ea..d33782125 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -143,3 +143,30 @@ jobs: with: hostArch: arm64 hostDistro: ubuntu2404 + + tests-vmtests-osmodifier-azl3-amd64: + name: VMTests suite osmodifier AZL3 AMD64 + if: ${{ inputs.runVMTests }} + needs: binary-build-amd64 + uses: ./.github/workflows/tests-vmtests-osmodifier.yml + with: + hostArch: amd64 + hostDistro: azl3 + + tests-vmtests-osmodifier-ubuntu2404-amd64: + name: VMTests suite osmodifier Ubuntu24.04 AMD64 + if: ${{ inputs.runVMTests }} + needs: binary-build-amd64 + uses: ./.github/workflows/tests-vmtests-osmodifier.yml + with: + hostArch: amd64 + hostDistro: ubuntu2404 + + tests-vmtests-osmodifier-ubuntu2404-arm64: + name: VMTests suite osmodifier Ubuntu24.04 ARM64 + if: ${{ inputs.runVMTests }} + needs: binary-build-arm64 + uses: ./.github/workflows/tests-vmtests-osmodifier.yml + with: + hostArch: arm64 + hostDistro: ubuntu2404 diff --git a/.github/workflows/tests-vmtests-osmodifier.yml b/.github/workflows/tests-vmtests-osmodifier.yml new file mode 100644 index 000000000..6abad181a --- /dev/null +++ b/.github/workflows/tests-vmtests-osmodifier.yml @@ -0,0 +1,186 @@ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. + +name: Tests VMTests suite for OSModifier + +permissions: + contents: read + # Azure login. + id-token: write + +on: + workflow_call: + inputs: + hostArch: + required: true + type: string + hostDistro: + required: true + type: string + +env: + EXPECTED_GO_VERSION: "1.24.1" + +jobs: + tests-osmodifier: + name: Tests VMTests suite + runs-on: + - self-hosted + - 1ES.Pool=${{ inputs.hostDistro == 'azl3' && (inputs.hostArch == 'amd64' && 'maritimus-github-runner-azl3-amd64' || 'maritimus-github-runner-azl3-arm64') || (inputs.hostArch == 'amd64' && 'maritimus-github-runner-ubuntu2404-amd64' || 'maritimus-github-runner-ubuntu2404-arm64') }} + permissions: + contents: read + # Azure login. + id-token: write + environment: public + steps: + - name: Setup Go toolchain + uses: actions/setup-go@v5 + with: + go-version: "${{ env.EXPECTED_GO_VERSION }}" + + - name: Install prerequisites (AZL3) + if: inputs.hostDistro == 'azl3' + run: | + set -eux + + sudo tdnf install -y libvirt libvirt-daemon libvirt-daemon-config-network \ + libvirt-daemon-kvm libvirt-devel qemu-kvm qemu-img python3-libvirt \ + python3-devel edk2-ovmf \ + azure-cli + + sudo tdnf list installed + + sudo systemctl restart libvirtd + sudo systemctl status libvirtd + + - name: Install prerequisites (Ubuntu 24.04) + if: inputs.hostDistro == 'ubuntu2404' + run: | + set -eux + + sudo apt update -y + sudo apt -y install python3-venv python3-pip python3-dev \ + libvirt-dev libvirt-daemon libvirt-daemon-system libvirt-clients \ + qemu-kvm virt-manager + + # Install arm64 specific + if [[ "$HOST_ARCH" == "arm64" ]]; then + sudo apt -y install qemu-system-arm qemu-efi-aarch64 ovmf seabios + fi + + sudo apt list --installed + + curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash + env: + HOST_ARCH: ${{ inputs.hostArch }} + + - name: Azure Login + uses: azure/login@v2 + with: + client-id: ${{ vars.AZURE_CLIENT_ID }} + tenant-id: ${{ vars.AZURE_TENANT_ID }} + subscription-id: ${{ vars.AZURE_SUBSCRIPTION_ID }} + + - name: Checkout + uses: actions/checkout@v4 + with: + path: repo + + - name: Download build artifacts + uses: actions/download-artifact@v4 + with: + path: out + + - name: Import container + id: importContainer + run: | + set -eux + + CONTAINER_TAR_PATH="out/container-${{ inputs.hostArch }}/imagecustomizer.tar.gz" + DOCKER_OUTPUT=$(sudo docker image load -i "$CONTAINER_TAR_PATH" 2>&1) + CONTAINER_TAG=$(echo $DOCKER_OUTPUT | awk '{print $3}') + + echo "containerTag=$CONTAINER_TAG" >> "$GITHUB_OUTPUT" + env: + HOST_ARCH: ${{ inputs.hostArch }} + + - name: Verify osmodifier binary + id: osmodifier_bin + run: | + set -eux + + OSMODIFIER_BIN="$(realpath out/osmodifier-${{ inputs.hostArch }}/osmodifier)" + [[ -f "$OSMODIFIER_BIN" ]] || { echo "osmodifier binary not found at $OSMODIFIER_BIN"; ls -la out/; exit 1; } + chmod +x "$OSMODIFIER_BIN" + echo "path=$OSMODIFIER_BIN" >> "$GITHUB_OUTPUT" + + - name: Download base images + run: | + set -eux + + ./repo/.github/workflows/scripts/download-image.sh "$AZURE_STORAGE" "$AZURE_CONTAINER" "azure-linux/core-efi-vhdx-2.0-$HOST_ARCH" azl-core-efi-2.0 + ./repo/.github/workflows/scripts/download-image.sh "$AZURE_STORAGE" "$AZURE_CONTAINER" "azure-linux/core-efi-vhdx-3.0-$HOST_ARCH" azl-core-efi-3.0 + env: + HOST_ARCH: ${{ inputs.hostArch }} + AZURE_STORAGE: ${{ vars.AZURE_STORAGE }} + AZURE_CONTAINER: ${{ vars.AZURE_CONTAINER }} + + - name: Setup input image + id: setup_image + run: | + set -eux + pushd repo/toolkit/tools + + AZL2_IMAGE="../../../azl-core-efi-2.0/image.vhdx" + AZL3_IMAGE="../../../azl-core-efi-3.0/image.vhdx" + + echo "azl2_path=$AZL2_IMAGE" >> "$GITHUB_OUTPUT" + echo "azl3_path=$AZL3_IMAGE" >> "$GITHUB_OUTPUT" + + - name: Test setup + run: | + set -eux + + pushd ./repo/test/vmtests + + # Ensure an ssh key exists. + ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" + + make create-venv + + - name: Run OSModifier tests - AZL 2.0 + if: ${{ inputs.hostArch == 'amd64' }} # Skip ARM64 + env: + IMAGE_CUSTOMIZER_CONTAINER_TAG: ${{ steps.importContainer.outputs.containerTag }} + OSMODIFIER_BIN: ${{ steps.osmodifier_bin.outputs.path }} + INPUT_IMAGE: ${{ steps.setup_image.outputs.azl2_path }} + run: | + set -eux + pushd ./repo/test/vmtests + + sudo make test-osmodifier \ + IMAGE_CUSTOMIZER_CONTAINER_TAG="${IMAGE_CUSTOMIZER_CONTAINER_TAG}" \ + OSMODIFIER_BIN="${OSMODIFIER_BIN}" \ + INPUT_IMAGE="${INPUT_IMAGE}" \ + SSH_PRIVATE_KEY_FILE=~/.ssh/id_ed25519 + + - name: Run OSModifier tests - AZL 3.0 + env: + IMAGE_CUSTOMIZER_CONTAINER_TAG: ${{ steps.importContainer.outputs.containerTag }} + OSMODIFIER_BIN: ${{ steps.osmodifier_bin.outputs.path }} + INPUT_IMAGE: ${{ steps.setup_image.outputs.azl3_path }} + run: | + set -eux + pushd ./repo/test/vmtests + + sudo make test-osmodifier \ + IMAGE_CUSTOMIZER_CONTAINER_TAG="${IMAGE_CUSTOMIZER_CONTAINER_TAG}" \ + OSMODIFIER_BIN="${OSMODIFIER_BIN}" \ + INPUT_IMAGE="${INPUT_IMAGE}" \ + SSH_PRIVATE_KEY_FILE=~/.ssh/id_ed25519 + + - uses: actions/upload-artifact@v4 + if: ${{ !cancelled() }} + with: + name: tests-results-osmodifier-${{ inputs.hostDistro }}-${{ inputs.hostArch }} + path: repo/test/vmtests/out diff --git a/test/vmtests/vmtests/osmodifier/test_osmodifier.py b/test/vmtests/vmtests/osmodifier/test_osmodifier.py index be4fa53fe..f81441cec 100644 --- a/test/vmtests/vmtests/osmodifier/test_osmodifier.py +++ b/test/vmtests/vmtests/osmodifier/test_osmodifier.py @@ -5,7 +5,6 @@ import os import platform import tempfile -from getpass import getuser from pathlib import Path from typing import List, Tuple @@ -22,6 +21,7 @@ from ..utils.libvirt_utils import VmSpec, create_libvirt_domain_xml from ..utils.libvirt_vm import LibvirtVm from ..utils.ssh_client import SshClient +from ..utils.user_utils import get_username @pytest.fixture(scope="session") @@ -53,7 +53,7 @@ def setup_vm_with_osmodifier( target_boot_type = source_boot_type output_image_path = session_temp_dir.joinpath("image." + output_format) - username = getuser() + username = get_username() run_image_customizer( docker_client, @@ -210,14 +210,14 @@ def test_modify_kernel_modules( module_load_path = "/etc/modules-load.d/modules-load.conf" module_options_path = "/etc/modprobe.d/module-options.conf" - load_content = ssh_client.run(f"cat {module_load_path} || true").stdout + load_content = ssh_client.run(f"sudo cat {module_load_path} || true").stdout assert "vfio" in load_content assert "mlx5_ib" in load_content - disabled_content = ssh_client.run(f"cat {module_disabled_path} || true").stdout + disabled_content = ssh_client.run(f"sudo cat {module_disabled_path} || true").stdout assert "blacklist mousedev" in disabled_content - options_content = ssh_client.run(f"cat {module_options_path} || true").stdout + options_content = ssh_client.run(f"sudo cat {module_options_path} || true").stdout assert "options vfio" in options_content assert "enable_unsafe_noiommu_mode=Y" in options_content assert "disable_vga=Y" in options_content @@ -238,7 +238,7 @@ def test_update_hostname( logs_dir / "test_hostname.log", ) - actual_hostname = ssh_client.run("cat /etc/hostname").stdout.strip() + actual_hostname = ssh_client.run("sudo cat /etc/hostname").stdout.strip() expected_hostname = "testname" assert actual_hostname == expected_hostname, f"Expected hostname '{expected_hostname}', got '{actual_hostname}'"