Skip to content
Merged
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
1 change: 1 addition & 0 deletions .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ test:qemu-integration --config=x86_64-qnx
test:qemu-integration --run_under=//scripts:run_under_qemu
test:qemu-integration --build_tests_only

build:qemu-integration-linux --extra_toolchains=@score_linux_x86_64_ext4_toolchain//:ext4-x86_64-linux
test:qemu-integration-linux --run_under=//scripts:run_under_qemu
test:qemu-integration-linux --build_tests_only

Expand Down
10 changes: 8 additions & 2 deletions MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ use_repo(
"score_qcc_x86_64_toolchain_pkg",
)

bazel_dep(name = "score_rules_imagefs", version = "0.0.3", dev_dependency = True)
bazel_dep(name = "score_rules_imagefs", version = "0.1.0", dev_dependency = True)

imagefs = use_extension("@score_rules_imagefs//extensions:imagefs.bzl", "imagefs", dev_dependency = True)
imagefs.toolchain(
Expand All @@ -219,7 +219,13 @@ imagefs.toolchain(
target_os = "qnx",
type = "ifs",
)
use_repo(imagefs, "score_qnx_x86_64_ifs_toolchain")
imagefs.toolchain(
name = "score_linux_x86_64_ext4_toolchain",
target_cpu = "x86_64",
target_os = "linux",
type = "ext4",
)
use_repo(imagefs, "score_linux_x86_64_ext4_toolchain", "score_qnx_x86_64_ifs_toolchain")

###############################################################################
#
Expand Down
89 changes: 81 additions & 8 deletions MODULE.bazel.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,10 +285,13 @@ py_itf_test(
args = [
"--qemu-rootfs=$(location @os_images//ubuntu_x86_64:image)",
"--qemu-config=$(location @os_images//ubuntu_x86_64:qemu_config)",
# optional disk image with test data
"--qemu-disk=$(location @os_images//ubuntu_x86_64:qemu_disk_image)",
],
data = [
"@os_images//ubuntu_x86_64:image",
"@os_images//ubuntu_x86_64:qemu_config",
"@os_images//ubuntu_x86_64:qemu_disk_image",
],
plugins = ["@score_itf//score/itf/plugins:qemu_plugin"],
)
Expand All @@ -304,11 +307,14 @@ py_itf_test(
"--qemu-rootfs=$(location @os_images//ebclfsa_aarch64:image)",
"--qemu-kernel=$(location @os_images//ebclfsa_aarch64:kernel)",
"--qemu-config=$(location @os_images//ebclfsa_aarch64:qemu_config)",
# optional disk image with test data
"--qemu-disk=$(location @os_images//ebclfsa_aarch64:qemu_disk_image)",
],
data = [
"@os_images//ebclfsa_aarch64:image",
"@os_images//ebclfsa_aarch64:kernel",
"@os_images//ebclfsa_aarch64:qemu_config",
"@os_images//ebclfsa_aarch64:qemu_disk_image",
],
plugins = ["@score_itf//score/itf/plugins:qemu_plugin"],
)
Expand Down
19 changes: 17 additions & 2 deletions score/itf/plugins/qemu/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,13 @@ def pytest_addoption(parser):
help="Path to a QEMU disk image (qcow2, wic, or img). "
"An ephemeral overlay is created so the original image is not modified.",
)
parser.addoption(
"--qemu-disk",
action="store",
default=None,
help="Path to an additional disk image to attach to the target as a second block device. "
"A qcow2 overlay is created so the original image is not modified.",
)


@pytest.fixture(scope="session")
Expand All @@ -96,6 +103,7 @@ def config(request):
qemu_kernel = request.config.getoption("qemu_kernel")
qemu_image = request.config.getoption("qemu_image")
rootfs = request.config.getoption("qemu_rootfs")
disk = request.config.getoption("qemu_disk")

if qemu_image:
logger.warning(
Expand All @@ -108,25 +116,32 @@ def config(request):
qemu_config=load_configuration(qemu_config),
qemu_kernel=qemu_kernel,
qemu_rootfs=rootfs,
qemu_disk=disk,
)


@pytest.fixture(scope="session")
def target_init(config, request, dlt):
logger.info(f"Starting tests on host: {socket.gethostname()}")
overlay_path = None
if config.qemu_rootfs:
overlay_path = _create_overlay(os.path.abspath(config.qemu_rootfs))
disk_overlay_path = None
try:
if config.qemu_rootfs:
overlay_path = _create_overlay(os.path.abspath(config.qemu_rootfs))
if config.qemu_disk:
disk_overlay_path = _create_overlay(os.path.abspath(config.qemu_disk))
with qemu_target(
Bunch(
qemu_config=config.qemu_config,
qemu_kernel=config.qemu_kernel,
qemu_rootfs=overlay_path,
qemu_disk=disk_overlay_path,
)
) as qemu:
pre_tests_phase(qemu)
yield qemu
finally:
if overlay_path and os.path.exists(overlay_path):
os.unlink(overlay_path)
if disk_overlay_path and os.path.exists(disk_overlay_path):
os.unlink(disk_overlay_path)
32 changes: 26 additions & 6 deletions score/itf/plugins/qemu/qemu.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,19 @@
"network_device": "virtio-net-pci",
"machine": "pc",
"block_device": "virtio-blk-pci",
# virtio-blk-pci is probed by the guest in the same order the devices are
# specified on the command line.
"block_device_order": "ascending",
},
"virt-aarch64": {
"architecture": "aarch64",
"cpu": "cortex-a53",
"network_device": "virtio-net-device",
"machine": "virt,virtualization=true,gic-version=3",
"block_device": "virtio-blk-device",
# virtio-blk-device (virtio-mmio) is probed by the guest in the reverse order
# the devices are specified on the command line.
"block_device_order": "descending",
},
}

Expand All @@ -55,6 +61,7 @@ def __init__(
port_forwarding,
rootfs,
kernel_cmdline,
disk,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is optional at the interface of __init__.py, where the default is None. IMHO carrying this into each and every function call with default parameters, makes the code more complicated.

):
"""Create a QEMU instance with the specified parameters.

Expand All @@ -67,6 +74,7 @@ def __init__(
:param list port_forwarding: List of port forwarding configurations.
:param str rootfs: Optional path to a qcow2 disk image.
:param str kernel_cmdline: Optional kernel command line string.
:param str disk: Optional path to an additional qcow2 disk image.
"""
if machine not in _SUPPORTED_MACHINES:
raise ValueError("machine must be one of: " + ", ".join(sorted(_SUPPORTED_MACHINES)))
Expand All @@ -78,6 +86,7 @@ def __init__(
self.__port_forwarding = port_forwarding
self.__rootfs = rootfs
self.__kernel_cmdline = kernel_cmdline
self.__disk = disk

self.__check_qemu_is_installed()

Expand Down Expand Up @@ -147,25 +156,36 @@ def __build_qemu_command(self):
+ self.__network_devices_args()
+ self.__port_forwarding_args()
+ self.__kernel_args()
+ self.__rootfs_args()
+ self.__disks_args()
)

def __kernel_args(self):
def __kernel_args(self) -> list[str]:
if not self.__path_to_kernel_image:
return []
args = ["-kernel", self.__path_to_kernel_image]
if self.__kernel_cmdline:
args.extend(["-append", self.__kernel_cmdline])
return args

def __rootfs_args(self):
if not self.__rootfs:
def __disks_args(self) -> list[str]:
# Order the disks so that, regardless of the guest's probing order, the rootfs
# always ends up as the first block device (/dev/vda) in the guest.
disks = [self.__rootfs, self.__disk]
if self.__arch_config["block_device_order"] == "descending":
disks = list(reversed(disks))
args = []
for id, disk in enumerate(disks):
args += self.__disk_args(disk, id)
return args

def __disk_args(self, disk: str, id: int) -> list[str]:
if not disk:
return []
return [
"-device",
f"{self.__arch_config['block_device']},drive=vd0",
f"{self.__arch_config['block_device']},drive=vd{id}",
"-drive",
f"if=none,format=qcow2,file={self.__rootfs},id=vd0",
f"if=none,format=qcow2,file={disk},id=vd{id}",
]

def __network_devices_args(self):
Expand Down
5 changes: 5 additions & 0 deletions score/itf/plugins/qemu/qemu_process.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def __init__(
machine,
rootfs,
kernel_cmdline,
disk,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is optional at the interface of __init__.py, where the default is None. IMHO carrying this into each and every function call with default parameters, makes the code more complicated.

):
self._path_to_qemu_kernel_image = path_to_qemu_kernel_image
self._available_ram = available_ram
Expand All @@ -39,6 +40,7 @@ def __init__(
self._machine = machine
self._rootfs = rootfs
self._kernel_cmdline = kernel_cmdline
self._disk = disk
self._qemu = Qemu(
self._path_to_qemu_kernel_image,
self._available_ram,
Expand All @@ -48,6 +50,7 @@ def __init__(
machine=self._machine,
rootfs=self._rootfs,
kernel_cmdline=self._kernel_cmdline,
disk=self._disk,
)
self._console = None

Expand All @@ -65,6 +68,8 @@ def start(self):
logger.info(f"Using QEMU kernel command line: {self._kernel_cmdline}")
if self._rootfs is not None:
logger.info(f"Using QEMU root filesystem image: {self._rootfs}")
if self._disk is not None:
logger.info(f"Using QEMU additional disk image: {self._disk}")
subprocess_params = {
"stdin": subprocess.PIPE,
"stdout": subprocess.PIPE,
Expand Down
1 change: 1 addition & 0 deletions score/itf/plugins/qemu/qemu_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,7 @@ def qemu_target(test_config):
machine=test_config.qemu_config.qemu_machine,
rootfs=test_config.qemu_rootfs,
kernel_cmdline=test_config.qemu_config.qemu_kernel_cmdline,
disk=test_config.qemu_disk,

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is optional at the interface of __init__.py, where the default is None. IMHO carrying this into each and every function call with default parameters, makes the code more complicated.

)
else:
process_ctx = nullcontext()
Expand Down
Loading
Loading