Skip to content

Commit f8a9468

Browse files
committed
test: Add a boot test for bootc pxe-tar-xz
This uses QEMU from vmtest, provided by the osbuild/images repository. It grabs the ostree= kernel cmdline from the grub.cfg in the tarball, boots qemu with the artifacts and tests that ssh login is successful. NOTE: Running bootc status from the booted system currently does not work so that has been disabled until it has been fixed. The tests include a cmdline option, --keep-tmpdir, that will keep the pxe-tar-xz tmpdir around after the test runs in order to help with debugging problems.
1 parent d46634a commit f8a9468

File tree

2 files changed

+94
-2
lines changed

2 files changed

+94
-2
lines changed

test/bib/conftest.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@ def pytest_addoption(parser):
1010
help=("Force AWS upload when building AMI, failing if credentials are not set. "
1111
"If not set, the upload will be performed only when credentials are available."))
1212

13+
parser.addoption("--keep-tmpdir", action="store_true", default=False,
14+
help="Keep the pxe tar tmpdir.")
15+
1316

1417
@pytest.fixture(name="force_aws_upload", scope="session")
1518
def force_aws_upload_fixture(request):
1619
return request.config.getoption("--force-aws-upload")
1720

1821

22+
@pytest.fixture(name="keep_tmpdir", scope="session")
23+
def keep_tmpdir_fixture(request):
24+
return request.config.getoption("--keep-tmpdir")
25+
26+
1927
# see https://hackebrot.github.io/pytest-tricks/param_id_func/ and
2028
# https://docs.pytest.org/en/7.1.x/reference/reference.html#pytest.hookspec.pytest_make_parametrize_id
2129
def pytest_make_parametrize_id(config, val): # pylint: disable=W0613

test/bib/test_build_pxe.py

Lines changed: 86 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
import string
77
import subprocess
88
import textwrap
9+
import threading
10+
911
from contextlib import ExitStack
12+
from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler
13+
from tempfile import TemporaryDirectory
1014

1115
import pytest
1216
# local test utils
@@ -24,6 +28,83 @@
2428
shared_tmpdir_fixture,
2529
)
2630
from vmtest.vm import QEMU
31+
from vmtest.util import get_free_port
32+
33+
34+
def get_ostree_path(grub_path):
35+
"""Get the ostree= boot path from a grub.cfg file"""
36+
with open(grub_path, encoding="utf-8") as f:
37+
for line in f.readlines():
38+
if "ostree=" not in line:
39+
continue
40+
args=line.split()
41+
for a in args:
42+
if a.startswith("ostree="):
43+
return a
44+
return ""
45+
46+
47+
class DirServer(ThreadingHTTPServer):
48+
def __init__(self, address, directory):
49+
super().__init__(address, SimpleHTTPRequestHandler)
50+
self.directory = directory
51+
52+
def finish_request(self, request, client_address):
53+
SimpleHTTPRequestHandler(request, client_address, self, directory=self.directory)
54+
55+
56+
def boot_qemu_pxe(arch, pxe_tar_path, container_ref, username, password, ssh_key_path, keep=False):
57+
with ExitStack() as cm:
58+
# unpack the tar and create a combined image
59+
tmpdir = cm.enter_context(TemporaryDirectory(dir="/var/tmp", prefix="qemu-pxe-", delete=keep))
60+
subprocess.check_call(
61+
["tar", "-C", tmpdir, "-x", "-f", pxe_tar_path])
62+
subprocess.check_call(
63+
"echo rootfs.img | cpio -c --quiet -L -o > rootfs.cpio", shell=True, cwd=tmpdir)
64+
subprocess.check_call(
65+
"cat initrd.img rootfs.cpio > combined.img", shell=True, cwd=tmpdir)
66+
67+
# Get the ostree= kernel cmdline argument from grub.cfg
68+
ostree_path = get_ostree_path(pathlib.Path(tmpdir) / "grub.cfg")
69+
assert ostree_path.startswith("ostree=")
70+
71+
# Setup http server thread for the rootfs.img
72+
http_server = DirServer(('127.0.0.1', 0), tmpdir)
73+
http_port = http_server.server_port
74+
threading.Thread(target=http_server.serve_forever).start()
75+
try:
76+
# test disk is unused for live OS
77+
test_disk_path = pathlib.Path(tmpdir) / "disk.img"
78+
with open(test_disk_path, "w", encoding="utf-8") as fp:
79+
fp.truncate(0)
80+
81+
# test both the combined and HTTP rootfs variants
82+
for use_ovmf in [False, True]:
83+
for root_arg, initrd_file in [
84+
("live:/rootfs.img", "combined.img"),
85+
(f"live:http://10.0.2.2:{http_port}/rootfs.img", "initrd.img")
86+
]:
87+
append_arg = (
88+
f"rd.live.image root={root_arg} rw console=ttyS0 "
89+
f"systemd.debug-shell=ttyS0 "
90+
f"{ostree_path}"
91+
)
92+
extra_args = [
93+
"-kernel", str(pathlib.Path(tmpdir) / "vmlinuz"),
94+
"-initrd", str(pathlib.Path(tmpdir) / initrd_file),
95+
"-append", append_arg
96+
]
97+
98+
with QEMU(test_disk_path, memory="4096", arch=arch, extra_args=extra_args) as vm:
99+
vm.start(use_ovmf=use_ovmf)
100+
vm.run("true", user=username, password=password)
101+
ret = vm.run("mount", user="root", keyfile=ssh_key_path)
102+
## ret = vm.run(["bootc", "status"], user="root", keyfile=ssh_key_path)
103+
## assert f"image: {container_ref}" in ret.stdout
104+
finally:
105+
http_server.shutdown()
106+
107+
return True
27108

28109

29110
@pytest.mark.skipif(platform.system() != "Linux", reason="boot test only runs on linux right now")
@@ -33,7 +114,7 @@
33114
"quay.io/centos-bootc/centos-bootc:stream9",
34115
])
35116
# pylint: disable=too-many-locals
36-
def test_bootc_pxe_tar_xz(tmp_path, build_container, container_ref):
117+
def test_bootc_pxe_tar_xz(keep_tmpdir, tmp_path, build_container, container_ref):
37118
# XXX: duplicated from test_build_disk.py
38119
username = "test"
39120
password = "".join(
@@ -101,4 +182,7 @@ def test_bootc_pxe_tar_xz(tmp_path, build_container, container_ref):
101182
]
102183
subprocess.check_call(cmd)
103184
assert os.path.exists(output_path / "xz" / "pxe.tar.xz")
104-
# TODO use lzap's pxe boot code from images to boot the result
185+
boot_qemu_pxe(platform.machine(), output_path / "xz" / "pxe.tar.xz",
186+
container_ref,
187+
username, password,
188+
ssh_keyfile_private_path)

0 commit comments

Comments
 (0)