Split test_s390x_secure_ipl() into two subtests. Each tests with a different boot device: virtio-blk-ccw or virtio-blk-pci. Use class-level variables and a temporary shared workdir such that the time-consuming setup is not run multiple times.
Signed-off-by: Joshua Daley <[email protected]> --- tests/functional/s390x/test_secure_ipl.py | 131 ++++++++++++++-------- 1 file changed, 87 insertions(+), 44 deletions(-) diff --git a/tests/functional/s390x/test_secure_ipl.py b/tests/functional/s390x/test_secure_ipl.py index 5af36b91d8..cc9bff5737 100755 --- a/tests/functional/s390x/test_secure_ipl.py +++ b/tests/functional/s390x/test_secure_ipl.py @@ -8,6 +8,9 @@ secure-boot enabled, and verifying cryptographic validation results. """ +import os +import shutil +import tempfile from subprocess import check_call, DEVNULL from qemu_test import QemuSystemTest, Asset, get_qemu_img @@ -22,12 +25,24 @@ class S390xSecureIpl(QemuSystemTest): 'Fedora-Server-KVM-40-1.14.s390x.qcow2'), '091c232a7301be14e19c76ce9a0c1cbd2be2c4157884a731e1fc4f89e7455a5f') - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.root_password = None - self.qcow2_path = None - self.cert_path = None - self.prompt = None + _shared_workdir = None + _root_password = None + _qcow2_path = None + _cert_path = None + _prompt = None + _setup_done = None + + @classmethod + def setUpClass(cls): + super().setUpClass() + cls._shared_workdir = tempfile.mkdtemp(prefix='qemu_sipl_') + + @classmethod + def tearDownClass(cls): + if cls._shared_workdir is not None: + shutil.rmtree(cls._shared_workdir, ignore_errors=True) + cls._shared_workdir = None + super().tearDownClass() def _require_host_secure_ipl_support(self, vm): """ @@ -62,7 +77,7 @@ def _sign_binaries(self, vm): exec_command_and_wait_for_pattern(self, 'sudo dnf install kernel-devel-$(uname -r) -y', 'Complete!', vm=vm) - wait_for_console_pattern(self, self.prompt, vm=vm) + wait_for_console_pattern(self, S390xSecureIpl._prompt, vm=vm) exec_command_and_wait_for_pattern(self, 'ls /usr/src/kernels/$(uname -r)/scripts/', 'sign-file', vm=vm) @@ -71,11 +86,11 @@ def _sign_binaries(self, vm): exec_command(self, '/usr/src/kernels/$(uname -r)/scripts/sign-file ' 'sha256 mykey.pem mycert.pem /lib/s390-tools/stage3.bin', vm=vm) - wait_for_console_pattern(self, self.prompt, vm=vm) + wait_for_console_pattern(self, S390xSecureIpl._prompt, vm=vm) exec_command(self, '/usr/src/kernels/$(uname -r)/scripts/sign-file ' 'sha256 mykey.pem mycert.pem /boot/vmlinuz-$(uname -r)', vm=vm) - wait_for_console_pattern(self, self.prompt, vm=vm) + wait_for_console_pattern(self, S390xSecureIpl._prompt, vm=vm) def _run_zipl_secure(self, vm): """Run zipl to prepare for secure boot""" @@ -91,10 +106,11 @@ def _extract_certificate(self, vm): cert = "\n".join(out.decode("utf-8").splitlines()[1:]) self.log.info("%s", cert) - self.cert_path = self.scratch_file("mycert.pem") + cert_path = os.path.join(S390xSecureIpl._shared_workdir, "mycert.pem") - with open(self.cert_path, 'w', encoding="utf-8") as file_object: + with open(cert_path, 'w', encoding="utf-8") as file_object: file_object.write(cert) + S390xSecureIpl._cert_path = cert_path def setup_s390x_secure_ipl(self): """ @@ -109,39 +125,42 @@ def setup_s390x_secure_ipl(self): temp_vm.set_machine('s390-ccw-virtio') asset_path = self.ASSET_F40_QCOW2.fetch() - self.qcow2_path = self.scratch_file('f40.qcow2') + qcow2_path = os.path.join(S390xSecureIpl._shared_workdir, 'f40.qcow2') qemu_img = get_qemu_img(self) check_call([qemu_img, 'create', '-f', 'qcow2', '-b', asset_path, - '-F', 'qcow2', self.qcow2_path], stdout=DEVNULL, stderr=DEVNULL) + '-F', 'qcow2', qcow2_path], stdout=DEVNULL, stderr=DEVNULL) + S390xSecureIpl._qcow2_path = qcow2_path temp_vm.set_console() temp_vm.add_args('-nographic', '-accel', 'kvm', '-m', '1024', '-drive', - f'id=drive0,if=none,format=qcow2,file={self.qcow2_path}', + f'id=drive0,if=none,format=qcow2,file={qcow2_path}', '-device', 'virtio-blk-ccw,drive=drive0,bootindex=1') temp_vm.launch() self._require_host_secure_ipl_support(temp_vm) # Initial root account setup (Fedora first boot screen) - self.root_password = 'fedora40password' + S390xSecureIpl._root_password = 'fedora40password' wait_for_console_pattern(self, 'Please make a selection from the above', vm=temp_vm) exec_command_and_wait_for_pattern(self, '4', 'Password:', vm=temp_vm) - exec_command_and_wait_for_pattern(self, self.root_password, + exec_command_and_wait_for_pattern(self, S390xSecureIpl._root_password, 'Password (confirm):', vm=temp_vm) - exec_command_and_wait_for_pattern(self, self.root_password, + exec_command_and_wait_for_pattern(self, S390xSecureIpl._root_password, 'Please make a selection from the above', vm=temp_vm) # Login as root - self.prompt = '[root@localhost ~]#' - exec_command_and_wait_for_pattern(self, 'c', 'localhost login:', vm=temp_vm) - exec_command_and_wait_for_pattern(self, 'root', 'Password:', vm=temp_vm) - exec_command_and_wait_for_pattern(self, self.root_password, self.prompt, + S390xSecureIpl._prompt = '[root@localhost ~]#' + exec_command_and_wait_for_pattern(self, 'c', 'localhost login:', vm=temp_vm) + exec_command_and_wait_for_pattern(self, 'root', 'Password:', + vm=temp_vm) + exec_command_and_wait_for_pattern(self, S390xSecureIpl._root_password, + S390xSecureIpl._prompt, vm=temp_vm) self._create_certificate(temp_vm) self._sign_binaries(temp_vm) @@ -150,41 +169,65 @@ def setup_s390x_secure_ipl(self): # Shutdown temp vm temp_vm.shutdown() + S390xSecureIpl._setup_done = True - @skipBigDataTest() - def test_s390x_secure_ipl(self): + def verify_s390x_secure_ipl(self, boot_dev_bus: str): """ Verify secure boot validation during s390x guest boot. Expects two "Verified component" messages and confirms /sys/firmware/ipl/secure reports secure boot is active. """ - self.require_accelerator('kvm') - self.setup_s390x_secure_ipl() - - self.set_machine('s390-ccw-virtio') - - self.vm.set_console() - self.vm.add_args('-nographic', - '-machine', 's390-ccw-virtio,secure-boot=on,' - f'boot-certs.0.path={self.cert_path}', - '-accel', 'kvm', - '-m', '1024', - '-drive', - f'id=drive1,if=none,format=qcow2,file={self.qcow2_path}', - '-device', 'virtio-blk-ccw,drive=drive1,bootindex=1') - self.vm.launch() + if boot_dev_bus not in ['ccw', 'pci']: + raise ValueError( + f"boot_dev_bus must be 'ccw' or 'pci', got {boot_dev_bus}") + + vm = self.get_vm(name=f'sipl_test_vblk_{boot_dev_bus}') + vm.set_machine('s390-ccw-virtio') + + vm.set_console() + vm.add_args('-nographic', + '-machine', 's390-ccw-virtio,secure-boot=on,' + f'boot-certs.0.path={S390xSecureIpl._cert_path}', + '-accel', 'kvm', + '-m', '1024', + '-drive', + f'id=drive1,if=none,format=qcow2,' + f'file={S390xSecureIpl._qcow2_path}', + '-device', + f'virtio-blk-{boot_dev_bus},drive=drive1,bootindex=1') + vm.launch() # Expect two verified components verified_output = "Verified component" - wait_for_console_pattern(self, verified_output) - wait_for_console_pattern(self, verified_output) + wait_for_console_pattern(self, verified_output, vm=vm) + wait_for_console_pattern(self, verified_output, vm=vm) # Login and verify the vm is booted using secure boot - wait_for_console_pattern(self, 'localhost login:') - exec_command_and_wait_for_pattern(self, 'root', 'Password:') - exec_command_and_wait_for_pattern(self, self.root_password, self.prompt) - exec_command_and_wait_for_pattern(self, 'cat /sys/firmware/ipl/secure', '1') + wait_for_console_pattern(self, 'localhost login:', vm=vm) + exec_command_and_wait_for_pattern(self, 'root', 'Password:', vm=vm) + exec_command_and_wait_for_pattern( + self, S390xSecureIpl._root_password, S390xSecureIpl._prompt, vm=vm) + exec_command_and_wait_for_pattern( + self, 'cat /sys/firmware/ipl/secure', '1', vm=vm) + + vm.shutdown() + + @skipBigDataTest() + def test_s390x_secure_ipl_ccw(self): + """Test secure IPL with a virtio-blk-ccw boot device.""" + self.require_accelerator('kvm') + if not S390xSecureIpl._setup_done: + self.setup_s390x_secure_ipl() + self.verify_s390x_secure_ipl('ccw') + + @skipBigDataTest() + def test_s390x_secure_ipl_pci(self): + """Test secure IPL with a virtio-blk-pci boot device.""" + self.require_accelerator('kvm') + if not S390xSecureIpl._setup_done: + self.setup_s390x_secure_ipl() + self.verify_s390x_secure_ipl('pci') if __name__ == '__main__': QemuSystemTest.main() -- 2.34.1
