Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions config/runtime/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Runtime templates

## QEMU container image for LAVA

The `boot/qemu.jinja2` template uses `kernelci/qemu` by default. To use a
mirror or another compatible QEMU image, set `qemu_docker_image` in a
platform's `params`:

```yaml
platforms:
qemu-arm64:
arch: arm64
boot_method: qemu
context:
arch: arm64
params:
qemu_docker_image: registry.example.com:5000/kernelci/qemu:stable
```

A job can also set the parameter. Job parameters take precedence over
platform parameters:

```yaml
jobs:
baseline:
template: base/lava.jinja2
params:
boot_commands: ramdisk
test_method: baseline
ramdiskroot: https://example.com/rootfs
qemu_docker_image: registry.example.com/kernelci/qemu:stable
```

Use a complete container image reference, including an optional registry,
port, tag or digest. An omitted, null or empty value uses `kernelci/qemu`.
The selected image must provide the platform's `qemu-system-<arch>` binary
and be accessible to the LAVA worker. This parameter selects the boot
action's container image; it is separate from the job's top-level `image`
setting for its runtime environment.
1 change: 0 additions & 1 deletion config/runtime/base/lava.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
# * kernel image name
# * UEFI binaries for QEMU etc.
# * rootfs URL
# * Docker image for QEMU

job_name: "[{{ instanceid|default('KernelCI AKS')}}] {{ node.id }} {{ node.name }} {{ node.data.kernel_revision.describe }}"

Expand Down
2 changes: 1 addition & 1 deletion config/runtime/boot/qemu.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
- boot:
docker:
binary: qemu-system-{{ platform_config.arch }}
image: kernelci/qemu
image: '{{ qemu_docker_image | default("kernelci/qemu", true) }}'
media: tmpfs
method: qemu
failure_retry: 3
Expand Down
103 changes: 103 additions & 0 deletions tests/test_runtime_qemu.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# SPDX-License-Identifier: LGPL-2.1-or-later
#
# Copyright (C) 2026 Jiakai Xu

"""QEMU container image configuration in generated LAVA jobs."""

import pytest
import yaml

from kernelci.config.job import Job as JobConfig
from kernelci.config.platform import Platform
from kernelci.config.runtime import RuntimeLAVA
from kernelci.runtime import Job
from kernelci.runtime.lava import LAVA


@pytest.mark.parametrize("arch", ["arm64", "x86_64"])
@pytest.mark.parametrize("boot_commands", ["ramdisk", "rootfs"])
@pytest.mark.parametrize(
"platform_params,job_params,expected_image",
[
pytest.param({}, {}, "kernelci/qemu", id="default"),
pytest.param(
{"qemu_docker_image": "registry.example.com:5000/qemu:stable"},
{},
"registry.example.com:5000/qemu:stable",
id="platform",
),
pytest.param(
{},
{"qemu_docker_image": "registry.example.com/qemu:latest"},
"registry.example.com/qemu:latest",
id="job",
),
pytest.param(
{"qemu_docker_image": "registry.example.com/qemu:platform"},
{"qemu_docker_image": "registry.example.com/qemu:job"},
"registry.example.com/qemu:job",
id="job-overrides-platform",
),
pytest.param(
{}, {"qemu_docker_image": None}, "kernelci/qemu", id="null"
),
pytest.param(
{}, {"qemu_docker_image": ""}, "kernelci/qemu", id="empty"
),
pytest.param(
{},
{
"qemu_docker_image": "registry.example.com/qemu@sha256:"
+ "a" * 64
},
"registry.example.com/qemu@sha256:" + "a" * 64,
id="digest",
),
],
)
def test_qemu_docker_image(
arch, boot_commands, platform_params, job_params, expected_image, mocker
):
"""Render platform/job overrides through the real LAVA runtime offline."""
mocker.patch(
"requests.sessions.Session.request",
side_effect=AssertionError("Job generation must not contact a service"),
)
config = JobConfig(
name="baseline",
template="base/lava.jinja2",
params={
"boot_commands": boot_commands,
"test_method": "baseline",
"ramdiskroot": "https://example.com/rootfs",
"ramdisk": "https://example.com/rootfs.cpio.gz",
**job_params,
},
)
job = Job(
{
"id": "qemu-test",
"name": "baseline",
"data": {"kernel_revision": {"describe": "v6.12"}},
"artifacts": {
"kernel": "https://example.com/Image",
"modules": "https://example.com/modules.tar.xz",
},
},
config,
)
job.platform_config = Platform(
name=f"qemu-{arch}",
arch=arch,
boot_method="qemu",
context={"arch": arch},
params=platform_params,
)
runtime = LAVA(RuntimeLAVA(name="test-lab", lab_type="lava"))

definition = yaml.safe_load(runtime.generate(job, runtime.get_params(job)))

assert definition["actions"][1]["boot"]["docker"] == {
"binary": f"qemu-system-{arch}",
"image": expected_image,
}