ci: Build and test OpenVMM runtime-rs on AKS

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 <abombo@microsoft.com>
Generated-By: GitHub Copilot
This commit is contained in:
Aurélien Bombo
2026-07-10 11:26:20 -05:00
parent f838c90df5
commit 8e67f77c84
17 changed files with 237 additions and 2 deletions

View File

@@ -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<String> {
// 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);

View File

@@ -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",

View File

@@ -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")

View File

@@ -658,6 +658,14 @@ shims:
httpsProxy: ""
noProxy: ""
openvmm-azure-runtime-rs:
enabled: ~
supportedArches:
- amd64
allowedHypervisorAnnotations: []
containerd:
snapshotter: ""
# Default shim per architecture
defaultShim:
amd64: qemu

View File

@@ -194,6 +194,9 @@ coco-guest-components-tarball:
cloud-hypervisor-tarball:
${MAKE} $@-build
openvmm-tarball:
${MAKE} $@-build
firecracker-tarball:
${MAKE} $@-build

View File

@@ -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 ;;

View File

@@ -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"]

View File

@@ -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

View File

@@ -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}

View File

@@ -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

View File

@@ -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}"