From 8e67f77c843cf31810e0ba3c111e451663e040ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A9lien=20Bombo?= Date: Fri, 10 Jul 2026 11:26:20 -0500 Subject: [PATCH] ci: Build and test OpenVMM runtime-rs on AKS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Build the pinned OpenVMM binary from source and package it in the Kata payload. Wire the openvmm-azure-runtime-rs shim into kata-deploy and Helm. Add OpenVMM to the shared amd64 asset matrix and run small and normal cbl-mariner AKS jobs. Select runtime-rs paths in test helpers and skip the known unsupported BlockModern emptyDir path. Signed-off-by: Aurélien Bombo Generated-By: GitHub Copilot --- .../build-kata-static-tarball-amd64.yaml | 1 + .github/workflows/run-k8s-tests-on-aks.yaml | 6 ++ tests/common.bash | 2 +- tests/hypervisor_helpers.sh | 1 + .../k8s-plain-ephemeral-data-storage.bats | 2 +- .../binary/src/artifacts/install.rs | 4 + .../kata-deploy/binary/src/utils/system.rs | 1 + .../kata-deploy/templates/runtimeclasses.yaml | 1 + .../helm-chart/kata-deploy/values.yaml | 8 ++ .../kata-deploy/local-build/Makefile | 3 + .../local-build/kata-deploy-binaries.sh | 29 +++++++ .../kata-deploy/shim-components.json | 3 + tools/packaging/scripts/lib.sh | 5 ++ .../packaging/static-build/openvmm/Dockerfile | 47 ++++++++++++ .../openvmm/build-static-openvmm.sh | 76 +++++++++++++++++++ tools/packaging/static-build/openvmm/build.sh | 45 +++++++++++ versions.yaml | 5 ++ 17 files changed, 237 insertions(+), 2 deletions(-) create mode 100644 tools/packaging/static-build/openvmm/Dockerfile create mode 100755 tools/packaging/static-build/openvmm/build-static-openvmm.sh create mode 100755 tools/packaging/static-build/openvmm/build.sh diff --git a/.github/workflows/build-kata-static-tarball-amd64.yaml b/.github/workflows/build-kata-static-tarball-amd64.yaml index 956e4eaba3..9c936e5237 100644 --- a/.github/workflows/build-kata-static-tarball-amd64.yaml +++ b/.github/workflows/build-kata-static-tarball-amd64.yaml @@ -54,6 +54,7 @@ jobs: - kernel-dragonball-experimental - kernel-nvidia-gpu - nydus + - openvmm - ovmf - ovmf-sev - ovmf-tdx diff --git a/.github/workflows/run-k8s-tests-on-aks.yaml b/.github/workflows/run-k8s-tests-on-aks.yaml index a58deadca7..f6f0fd4dd4 100644 --- a/.github/workflows/run-k8s-tests-on-aks.yaml +++ b/.github/workflows/run-k8s-tests-on-aks.yaml @@ -63,6 +63,12 @@ jobs: - host_os: cbl-mariner vmm: clh-azure-runtime-rs instance-type: normal + - host_os: cbl-mariner + vmm: openvmm-azure-runtime-rs + instance-type: small + - host_os: cbl-mariner + vmm: openvmm-azure-runtime-rs + instance-type: normal concurrency: group: ${{ github.workflow }}-${{ github.job }}-${{ github.event.pull_request.number || github.ref }}-run-k8s-tests-aks-${{ toJSON(matrix) }} cancel-in-progress: true diff --git a/tests/common.bash b/tests/common.bash index 15c132e72e..ce4948cbdc 100644 --- a/tests/common.bash +++ b/tests/common.bash @@ -789,7 +789,7 @@ function enabling_hypervisor() { declare -r CONTAINERD_SHIM_KATA="/usr/local/bin/containerd-shim-kata-${KATA_HYPERVISOR}-v2" case "${KATA_HYPERVISOR}" in - dragonball|clh-runtime-rs|clh-azure-runtime-rs|qemu-runtime-rs|qemu-se-runtime-rs) + dragonball|clh-runtime-rs|clh-azure-runtime-rs|openvmm-azure-runtime-rs|qemu-runtime-rs|qemu-se-runtime-rs) sudo ln -sf "${KATA_DIR}/runtime-rs/bin/containerd-shim-kata-v2" "${CONTAINERD_SHIM_KATA}" declare -r CONFIG_DIR="${KATA_DIR}/share/defaults/kata-containers/runtime-rs" ;; diff --git a/tests/hypervisor_helpers.sh b/tests/hypervisor_helpers.sh index bdca4a9196..1cadd4827e 100644 --- a/tests/hypervisor_helpers.sh +++ b/tests/hypervisor_helpers.sh @@ -18,6 +18,7 @@ ALL_HYPERVISORS=( "clh-azure" "clh-runtime-rs" "clh-azure-runtime-rs" + "openvmm-azure-runtime-rs" "dragonball" "qemu" "qemu-runtime-rs" diff --git a/tests/integration/kubernetes/k8s-plain-ephemeral-data-storage.bats b/tests/integration/kubernetes/k8s-plain-ephemeral-data-storage.bats index 0a1d47d578..57c1c5a51c 100644 --- a/tests/integration/kubernetes/k8s-plain-ephemeral-data-storage.bats +++ b/tests/integration/kubernetes/k8s-plain-ephemeral-data-storage.bats @@ -18,7 +18,7 @@ skip_unsupported_runtime() { # it never reached clh-runtime-rs or dragonball in CI; this generic # block-plain test would, so skip those unsupported VMM paths explicitly. case "${KATA_HYPERVISOR}" in - clh-runtime-rs|clh-azure-runtime-rs|dragonball) + clh-runtime-rs|clh-azure-runtime-rs|dragonball|openvmm-azure-runtime-rs) skip "block-plain emptyDir uses runtime-rs BlockModern, whose VMM glue is missing for ${KATA_HYPERVISOR}" ;; esac diff --git a/tools/packaging/kata-deploy/binary/src/artifacts/install.rs b/tools/packaging/kata-deploy/binary/src/artifacts/install.rs index 760477427f..4f6d174b9e 100644 --- a/tools/packaging/kata-deploy/binary/src/artifacts/install.rs +++ b/tools/packaging/kata-deploy/binary/src/artifacts/install.rs @@ -27,6 +27,7 @@ const ALL_SHIMS: &[&str] = &[ "dragonball", "fc", "firecracker", + "openvmm-azure-runtime-rs", "remote", // QEMU shims "qemu", @@ -68,6 +69,7 @@ fn get_hypervisor_name(shim: &str) -> Result<&str> { "clh" | "clh-azure" | "clh-runtime-rs" | "clh-azure-runtime-rs" => Ok("clh"), "dragonball" => Ok("dragonball"), "fc" | "firecracker" => Ok("firecracker"), + "openvmm-azure-runtime-rs" => Ok("openvmm"), "remote" => Ok("remote"), _ => anyhow::bail!( "Unknown shim '{}'. Valid shims are: {}", @@ -1089,6 +1091,7 @@ fn get_hypervisor_path(config: &Config, shim: &str) -> Result { // For non-QEMU shims, use the appropriate hypervisor binary let binary = match shim { "clh" | "clh-azure" | "clh-runtime-rs" | "clh-azure-runtime-rs" => "cloud-hypervisor", + "openvmm-azure-runtime-rs" => "openvmm", "fc" | "firecracker" => "firecracker", "dragonball" => "dragonball", "stratovirt" => "stratovirt", @@ -1390,6 +1393,7 @@ mod tests { #[case("dragonball", "dragonball")] #[case("fc", "firecracker")] #[case("firecracker", "firecracker")] + #[case("openvmm-azure-runtime-rs", "openvmm")] #[case("remote", "remote")] fn test_get_hypervisor_name_other_hypervisors(#[case] shim: &str, #[case] expected: &str) { assert_eq!(get_hypervisor_name(shim).unwrap(), expected); diff --git a/tools/packaging/kata-deploy/binary/src/utils/system.rs b/tools/packaging/kata-deploy/binary/src/utils/system.rs index 1ba761c765..29f477a509 100644 --- a/tools/packaging/kata-deploy/binary/src/utils/system.rs +++ b/tools/packaging/kata-deploy/binary/src/utils/system.rs @@ -10,6 +10,7 @@ pub const RUST_SHIMS: &[&str] = &[ "clh-azure-runtime-rs", "clh-runtime-rs", "dragonball", + "openvmm-azure-runtime-rs", "qemu-runtime-rs", "qemu-nvidia-gpu-runtime-rs", "qemu-nvidia-gpu-snp-runtime-rs", diff --git a/tools/packaging/kata-deploy/helm-chart/kata-deploy/templates/runtimeclasses.yaml b/tools/packaging/kata-deploy/helm-chart/kata-deploy/templates/runtimeclasses.yaml index c03e582834..f686415d2e 100644 --- a/tools/packaging/kata-deploy/helm-chart/kata-deploy/templates/runtimeclasses.yaml +++ b/tools/packaging/kata-deploy/helm-chart/kata-deploy/templates/runtimeclasses.yaml @@ -14,6 +14,7 @@ "clh-azure" (dict "memory" "130Mi" "cpu" "250m") "clh-runtime-rs" (dict "memory" "130Mi" "cpu" "250m") "clh-azure-runtime-rs" (dict "memory" "130Mi" "cpu" "250m") + "openvmm-azure-runtime-rs" (dict "memory" "130Mi" "cpu" "250m") "dragonball" (dict "memory" "130Mi" "cpu" "250m") "fc" (dict "memory" "130Mi" "cpu" "250m") "qemu" (dict "memory" "320Mi" "cpu" "250m") diff --git a/tools/packaging/kata-deploy/helm-chart/kata-deploy/values.yaml b/tools/packaging/kata-deploy/helm-chart/kata-deploy/values.yaml index 3a12ae30af..3e712a9211 100644 --- a/tools/packaging/kata-deploy/helm-chart/kata-deploy/values.yaml +++ b/tools/packaging/kata-deploy/helm-chart/kata-deploy/values.yaml @@ -658,6 +658,14 @@ shims: httpsProxy: "" noProxy: "" + openvmm-azure-runtime-rs: + enabled: ~ + supportedArches: + - amd64 + allowedHypervisorAnnotations: [] + containerd: + snapshotter: "" + # Default shim per architecture defaultShim: amd64: qemu diff --git a/tools/packaging/kata-deploy/local-build/Makefile b/tools/packaging/kata-deploy/local-build/Makefile index 4cbe8335c5..1c7b504374 100644 --- a/tools/packaging/kata-deploy/local-build/Makefile +++ b/tools/packaging/kata-deploy/local-build/Makefile @@ -194,6 +194,9 @@ coco-guest-components-tarball: cloud-hypervisor-tarball: ${MAKE} $@-build +openvmm-tarball: + ${MAKE} $@-build + firecracker-tarball: ${MAKE} $@-build diff --git a/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh b/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh index 8747ab8b79..49da8f081a 100755 --- a/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh +++ b/tools/packaging/kata-deploy/local-build/kata-deploy-binaries.sh @@ -31,6 +31,7 @@ readonly busybox_builder="${static_build_dir}/busybox/build.sh" readonly agent_builder="${static_build_dir}/agent/build.sh" readonly coco_guest_components_builder="${static_build_dir}/coco-guest-components/build.sh" readonly clh_builder="${static_build_dir}/cloud-hypervisor/build-static-clh.sh" +readonly openvmm_builder="${static_build_dir}/openvmm/build.sh" readonly firecracker_builder="${static_build_dir}/firecracker/build-static-firecracker.sh" readonly kernel_builder="${static_build_dir}/kernel/build.sh" readonly ovmf_builder="${static_build_dir}/ovmf/build.sh" @@ -117,6 +118,7 @@ options: boot-image-se coco-guest-components cloud-hypervisor + openvmm firecracker genpolicy kata-ctl @@ -1176,6 +1178,31 @@ install_clh() { install_clh_helper "musl" "${features}" } +# Install static openvmm asset. +# +# OpenVMM publishes no released binaries, so it is always built from source +# (see static-build/openvmm/build.sh); there is no pull-released-binary fast +# path like cloud-hypervisor. Repeat builds are still short-circuited by the +# cached-artefact tarball via install_cached_tarball_component. +install_openvmm() { + latest_artefact="$(get_from_kata_deps ".assets.hypervisor.openvmm.version")" + latest_builder_image="$(get_openvmm_image_name)" + + install_cached_tarball_component \ + "openvmm" \ + "${latest_artefact}" \ + "${latest_builder_image}" \ + "${final_tarball_name}" \ + "${final_tarball_path}" \ + && return 0 + + info "build static openvmm" + "${openvmm_builder}" + info "Install static openvmm" + mkdir -p "${destdir}/opt/kata/bin/" + install -D --mode "${default_binary_permissions}" openvmm/openvmm "${destdir}/opt/kata/bin/openvmm" +} + # Install static stratovirt asset install_stratovirt() { local stratovirt_version @@ -1652,6 +1679,8 @@ handle_build() { cloud-hypervisor) install_clh ;; + openvmm) install_openvmm ;; + firecracker) install_firecracker ;; genpolicy) install_genpolicy ;; diff --git a/tools/packaging/kata-deploy/shim-components.json b/tools/packaging/kata-deploy/shim-components.json index 7573cd1557..48eaf802db 100644 --- a/tools/packaging/kata-deploy/shim-components.json +++ b/tools/packaging/kata-deploy/shim-components.json @@ -74,6 +74,9 @@ "clh-azure-runtime-rs": { "x86_64": ["shim-v2-rust", "cloud-hypervisor", "virtiofsd", "kernel", "kernel-debug", "rootfs-image-mariner"] }, + "openvmm-azure-runtime-rs": { + "x86_64": ["shim-v2-rust", "openvmm", "virtiofsd", "kernel", "kernel-debug", "rootfs-image-mariner"] + }, "dragonball": { "x86_64": ["shim-v2-rust", "virtiofsd", "nydus", "kernel-dragonball-experimental", "rootfs-image", "rootfs-initrd"], "aarch64": ["shim-v2-rust", "virtiofsd", "nydus", "kernel-dragonball-experimental", "rootfs-image", "rootfs-initrd"] diff --git a/tools/packaging/scripts/lib.sh b/tools/packaging/scripts/lib.sh index fa519847de..e0118b4565 100644 --- a/tools/packaging/scripts/lib.sh +++ b/tools/packaging/scripts/lib.sh @@ -205,6 +205,11 @@ get_busybox_image_name() { echo "${BUILDER_REGISTRY}:busybox-$(get_last_modification "${busybox_script_dir}")-$(uname -m)" } +get_openvmm_image_name() { + openvmm_script_dir="${repo_root_dir}/tools/packaging/static-build/openvmm" + echo "${BUILDER_REGISTRY}:openvmm-$(get_last_modification "${openvmm_script_dir}")-$(uname -m)" +} + get_virtiofsd_image_name() { ARCH=${ARCH:-$(uname -m)} case ${ARCH} in diff --git a/tools/packaging/static-build/openvmm/Dockerfile b/tools/packaging/static-build/openvmm/Dockerfile new file mode 100644 index 0000000000..bf1c9a95fa --- /dev/null +++ b/tools/packaging/static-build/openvmm/Dockerfile @@ -0,0 +1,47 @@ +# Copyright (c) 2026 Microsoft Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +FROM ubuntu:22.04 +ENV DEBIAN_FRONTEND=noninteractive + +ENV RUSTUP_HOME="/opt/rustup" +ENV CARGO_HOME="/opt/cargo" +ENV PATH="/opt/cargo/bin/:${PATH}" + +SHELL ["/bin/bash", "-o", "pipefail", "-c"] + +RUN mkdir ${RUSTUP_HOME} ${CARGO_HOME} + +# OpenVMM build dependencies (see OpenVMM Guide: getting started on Linux) plus +# the tooling needed to clone the repo and bootstrap rustup. OpenVMM has no +# rust-toolchain.toml, so build-static-openvmm.sh installs and pins OpenVMM's +# declared MSRV (Cargo.toml rust-version) at build time; only a bootstrap +# rustup toolchain is installed here. +# +# `sudo` is needed because OpenVMM's `cargo xflowey restore-packages` installs +# additional build inputs at run time via `sudo apt-get` +# (flowey_lib_common::install_dist_pkg). Other Kata builders run as the invoking +# user and install every dependency here at image-build time; this builder +# instead runs as root (build.sh omits --user) so that the run-time +# `sudo apt-get` works, and build.sh chowns the outputs back to the caller. +# +# restore-packages drives apt with interactive=true (no `-y`), so make apt +# assume "yes" image-wide; otherwise those run-time installs hang on the +# "Do you want to continue? [Y/n]" prompt in CI (no TTY) and abort. +RUN echo 'APT::Get::Assume-Yes "true";' > /etc/apt/apt.conf.d/90kata-assume-yes && \ + apt-get update && \ + apt-get install -y --no-install-recommends \ + binutils \ + build-essential \ + ca-certificates \ + curl \ + gcc-aarch64-linux-gnu \ + git \ + libssl-dev \ + pkg-config \ + sudo \ + unzip && \ + apt-get clean && rm -rf /var/lib/apt/lists/* && \ + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain stable && \ + chmod -R a+rwX ${RUSTUP_HOME} ${CARGO_HOME} diff --git a/tools/packaging/static-build/openvmm/build-static-openvmm.sh b/tools/packaging/static-build/openvmm/build-static-openvmm.sh new file mode 100755 index 0000000000..0a7f308b82 --- /dev/null +++ b/tools/packaging/static-build/openvmm/build-static-openvmm.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2026 Microsoft Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +set -o errexit +set -o nounset +set -o pipefail + +ARCH=${ARCH:-$(uname -m)} + +# OpenVMM currently only supports x86_64 and aarch64. +[[ "${ARCH}" != "aarch64" ]] && [[ "${ARCH}" != "x86_64" ]] && exit + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +# shellcheck source=/dev/null +source "${script_dir}/../../scripts/lib.sh" + +openvmm_repo="${openvmm_repo:-}" +openvmm_version="${openvmm_version:-}" + +[[ -n "${openvmm_repo}" ]] || openvmm_repo=$(get_from_kata_deps ".assets.hypervisor.openvmm.url") +[[ -n "${openvmm_version}" ]] || openvmm_version=$(get_from_kata_deps ".assets.hypervisor.openvmm.version") + +[[ -n "${openvmm_repo}" ]] || die "failed to get openvmm repo" +[[ -n "${openvmm_version}" ]] || die "failed to get openvmm version" + +# Unlike cloud-hypervisor, OpenVMM does not publish pre-built release binaries, +# so it is always built from source at the pinned commit. +build_openvmm_from_source() { + info "build openvmm from source: ${openvmm_repo} @ ${openvmm_version}" + + rm -rf openvmm-src openvmm + git clone "${openvmm_repo}" openvmm-src + pushd openvmm-src + git checkout "${openvmm_version}" + + # OpenVMM has no rust-toolchain.toml and requires a newer Rust than the Kata + # runtime toolchain, so pin explicitly to its declared MSRV (Cargo.toml + # rust-version) instead of relying on the default/stable channel. + # restore-packages fetches build inputs (e.g. protoc) the build needs. + local rust_version + rust_version=$(grep -m1 -E '^[[:space:]]*rust-version[[:space:]]*=' Cargo.toml | sed -E 's/.*"([^"]+)".*/\1/') + [[ -n "${rust_version}" ]] || die "failed to read openvmm rust-version from Cargo.toml" + info "building openvmm with Rust ${rust_version}" + rustup toolchain install "${rust_version}" --profile minimal + + # --no-compat-igvm skips downloading released OpenHCL IGVM files (used only + # for VMM compatibility testing, not for building the openvmm binary). Those + # come from GitHub releases and would trigger an interactive `gh auth login` + # device-code prompt, hanging the non-interactive build. OpenVMM's own CI + # (.github/copilot-setup-steps.yml) uses the same flag for this reason. + cargo "+${rust_version}" xflowey restore-packages --no-compat-igvm + cargo "+${rust_version}" build --release --package openvmm + + local binary="target/release/openvmm" + [[ -f "${binary}" ]] || die "openvmm binary not found at ${binary}" + popd + + # Stage the binary at openvmm/openvmm for the installer to pick up + # (a dedicated directory avoids clashing with the openvmm/ source tree). + mkdir -p openvmm + cp -f "openvmm-src/${binary}" openvmm/openvmm + chmod +x openvmm/openvmm + + # build.sh runs this container as root (so restore-packages can apt-install + # its build inputs); hand the generated files back to the invoking user so + # the unprivileged outer build/packaging steps can read and clean them. + if [[ -n "${HOST_UID:-}" ]]; then + chown -R "${HOST_UID}:${HOST_GID:-${HOST_UID}}" openvmm openvmm-src + fi +} + +build_openvmm_from_source diff --git a/tools/packaging/static-build/openvmm/build.sh b/tools/packaging/static-build/openvmm/build.sh new file mode 100755 index 0000000000..be5bf5ff9f --- /dev/null +++ b/tools/packaging/static-build/openvmm/build.sh @@ -0,0 +1,45 @@ +#!/usr/bin/env bash +# +# Copyright (c) 2026 Microsoft Corporation +# +# SPDX-License-Identifier: Apache-2.0 + +set -o errexit +set -o nounset +set -o pipefail + +script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly openvmm_builder="${script_dir}/build-static-openvmm.sh" + +# shellcheck source=/dev/null +source "${script_dir}/../../scripts/lib.sh" + +ARCH=${ARCH:-$(uname -m)} +openvmm_repo="${openvmm_repo:-}" +openvmm_version="${openvmm_version:-}" + +[[ -n "${openvmm_repo}" ]] || openvmm_repo=$(get_from_kata_deps ".assets.hypervisor.openvmm.url") +[[ -n "${openvmm_version}" ]] || openvmm_version=$(get_from_kata_deps ".assets.hypervisor.openvmm.version") + +[[ -n "${openvmm_repo}" ]] || die "Failed to get openvmm repo" +[[ -n "${openvmm_version}" ]] || die "Failed to get openvmm version" + +container_image="${OPENVMM_CONTAINER_BUILDER:-$(get_openvmm_image_name)}" + +# shellcheck disable=SC2154,SC2086 +docker pull "${container_image}" || \ + (docker ${BUILDX} build ${PLATFORM} \ + -t "${container_image}" "${script_dir}" && \ + # No-op unless PUSH_TO_REGISTRY is exported as "yes" + push_to_registry "${container_image}") + +# shellcheck disable=SC2154 +docker run --rm -i -v "${repo_root_dir}:${repo_root_dir}" \ + -w "${PWD}" \ + --env openvmm_repo="${openvmm_repo}" \ + --env openvmm_version="${openvmm_version}" \ + --env ARCH="${ARCH}" \ + --env HOST_UID="$(id -u)" \ + --env HOST_GID="$(id -g)" \ + "${container_image}" \ + bash -c "${openvmm_builder}" diff --git a/versions.yaml b/versions.yaml index 22af6490a7..6d4a9680fa 100644 --- a/versions.yaml +++ b/versions.yaml @@ -77,6 +77,11 @@ assets: https://github.com/cloud-hypervisor/cloud-hypervisor/tags.*/v?(\d\S+)\.tar\.gz version: "v51.1" + openvmm: + description: "OpenVMM is a modular, cross-platform Virtual Machine Monitor written in Rust" + url: "https://github.com/microsoft/openvmm" + version: "00693a5d2e4db2484c576abd0c3dee95632c9fcc" + firecracker: description: "Firecracker micro-VMM" url: "https://github.com/firecracker-microvm/firecracker"