|
6 | 6 | import string |
7 | 7 | import subprocess |
8 | 8 | import textwrap |
| 9 | +import threading |
| 10 | + |
9 | 11 | from contextlib import ExitStack |
| 12 | +from http.server import ThreadingHTTPServer, SimpleHTTPRequestHandler |
| 13 | +from tempfile import TemporaryDirectory |
10 | 14 |
|
11 | 15 | import pytest |
12 | 16 | # local test utils |
|
24 | 28 | shared_tmpdir_fixture, |
25 | 29 | ) |
26 | 30 | 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 |
27 | 108 |
|
28 | 109 |
|
29 | 110 | @pytest.mark.skipif(platform.system() != "Linux", reason="boot test only runs on linux right now") |
|
33 | 114 | "quay.io/centos-bootc/centos-bootc:stream9", |
34 | 115 | ]) |
35 | 116 | # 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): |
37 | 118 | # XXX: duplicated from test_build_disk.py |
38 | 119 | username = "test" |
39 | 120 | password = "".join( |
@@ -101,4 +182,7 @@ def test_bootc_pxe_tar_xz(tmp_path, build_container, container_ref): |
101 | 182 | ] |
102 | 183 | subprocess.check_call(cmd) |
103 | 184 | 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