From 362175e3adee802ae44a39cefa9d5b4b3f5c000e Mon Sep 17 00:00:00 2001 From: Sebastian Mitterle Date: Wed, 30 Oct 2024 11:09:39 -0400 Subject: [PATCH] guest_os_booting: update tests for s390x The following features are not available on s390x: * SMBIOS * ACPI * fw_cfg * USB * * firmware settings * SATA For direct kernel boot, don't use hard coded kernel filename. In our setup we'll use kernel.img, so just use the filename from the download url. Don't use ttyS0, it's the line mode console which is not useful. Using ttysclp0 is the standard on s390x. Cover also s390x-specific parameter @loadparm by allowing generically to run a test command in the booted VM whose output should match an expected regular expression. On s390x, the VM will stop if no bootable medium - such as missing cdrom file - is found. Some tests were written assuming the VM would use the //os/boot element instead of the per-device element by trying to remove only that element. Instead just remove all present boot elements in these cases, no matter where, the test will define the new one that's relevant for the test case. In some boot tests also enable boot for VMs without Secure Boot, where there's no firmware. Add test case that attaches same bootable device twice, this had a bug on s390x recently. s390x currently doesn't have secure boot. Use the first VM and don't set os attributes that relate to secure boot on other archs. Move s390x PXE setup to provider for reuse in boot order tests. Allow for pxelinux.cfg without kickstart, for the boot check we don't need it. Signed-off-by: Sebastian Mitterle --- .../boot_order/boot_from_cdrom_device.cfg | 9 +- .../boot_order/boot_from_disk_device.cfg | 6 ++ .../boot_with_multiple_boot_dev.cfg | 1 + .../boot_with_multiple_boot_order.cfg | 42 +++++++- .../hotplug_device_with_boot_order.cfg | 2 + .../direct_kernel_boot/direct_kernel_boot.cfg | 2 + .../firmware_configuration/os_acpi.cfg | 2 +- .../firmware_configuration/smbios_mode.cfg | 1 + .../firmware_configuration/sysinfo_fwcfg.cfg | 1 + .../migration/migration_boot.cfg | 1 + .../boot_order/boot_from_cdrom_device.py | 4 +- .../boot_order/boot_from_disk_device.py | 23 ++++- .../boot_with_multiple_boot_order.py | 26 ++++- .../direct_kernel_boot/direct_kernel_boot.py | 4 +- .../guest_os_booting/guest_os_booting_base.py | 4 + provider/virtual_network/tftpboot.py | 99 +++++++++++++++++++ .../src/virt_install/pxe_installation.py | 79 +-------------- 17 files changed, 216 insertions(+), 90 deletions(-) create mode 100644 provider/virtual_network/tftpboot.py diff --git a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_cdrom_device.cfg b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_cdrom_device.cfg index 0b820f8dad..0ea5c8705c 100644 --- a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_cdrom_device.cfg +++ b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_cdrom_device.cfg @@ -7,6 +7,7 @@ - without_cdrom: only os_dev - with_cdrom_with_no_src: + no s390-virtio cdrom1_attrs = {'target': {'dev': 'sda', 'bus': 'sata'}, **${cdrom_attrs}} aarch64: cdrom1_attrs = {'target': {'dev': 'sda', 'bus': 'scsi'}, **${cdrom_attrs}} @@ -14,19 +15,20 @@ - with_cdrom: check_bootable_iso = "yes" cdrom1_attrs = {'source': {'attrs': {'file': boot_img_path}}, 'target': {'dev': 'sda', 'bus': 'scsi'}, **${cdrom_attrs}} - bootable_patterns = ["begin the installation process|Install Red Hat Enterprise"] + bootable_patterns = ["begin the installation process|Install Red Hat Enterprise|Starting installer"] - multi_cdroms: cdrom1_attrs = {'target': {'dev': 'sda', 'bus': 'scsi'}, **${cdrom_attrs}} cdrom2_attrs = {'source': {'attrs': {'file': boot_img_path}}, 'target': {'dev': 'sdb', 'bus': 'sata'}, **${cdrom_attrs}} - aarch64: + aarch64, s390-virtio: cdrom2_attrs = {'source': {'attrs': {'file': boot_img_path}}, 'target': {'dev': 'sdb', 'bus': 'scsi'}, **${cdrom_attrs}} cdrom_boot_order: check_bootable_iso = "yes" - bootable_patterns = ["begin the installation process|Install Red Hat Enterprise"] + bootable_patterns = ["begin the installation process|Install Red Hat Enterprise|Starting installer"] os_dev: status_error = "yes" variants: - os_dev: + no s390-virtio os_attrs_boots = ['cdrom'] - cdrom_boot_order: variants firmware_type: @@ -36,3 +38,4 @@ status_error = "yes" - ovmf: only q35, aarch64 + - default: diff --git a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_disk_device.cfg b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_disk_device.cfg index 0f913912b4..97b9b4f158 100644 --- a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_disk_device.cfg +++ b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_from_disk_device.cfg @@ -4,6 +4,7 @@ disk1_attrs_target = {'dev': 'vda', 'bus': 'virtio'} variants: - os_dev: + no s390-virtio os_attrs_boots = ['hd'] disk1_attrs = {'target': ${disk1_attrs_target}} variants: @@ -24,8 +25,13 @@ disk2_attrs = {'target': {'dev': 'sda', 'bus': 'scsi'}} seabios: status_error = "yes" + - multi_disks_bootable: + disk1_img = "copied_original.qcow2" + disk1_attrs = {'target': ${disk1_attrs_target}} + disk2_attrs = {'target': {'dev': 'sda', 'bus': 'scsi'}} variants firmware_type: - seabios: only x86_64 - ovmf: only q35, aarch64 + - default: diff --git a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_with_multiple_boot_dev.cfg b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_with_multiple_boot_dev.cfg index ad60e5d8c9..32a76da370 100644 --- a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_with_multiple_boot_dev.cfg +++ b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_with_multiple_boot_dev.cfg @@ -8,6 +8,7 @@ os_dict = {'boots': ['%s', '%s'], 'bootmenu_enable': 'yes'} cdrom_dict = {'source': {'attrs': {'file': '%s'}}, 'type_name': 'file', 'device': 'cdrom', 'driver': {'name': 'qemu', 'type': 'raw'}, 'target': {'dev': 'sda', 'bus': '${target_bus}'}} check_prompt = ["begin the installation process|Install Red Hat Enterprise"] + no s390-virtio variants first_dev: - hd: variants second_dev: diff --git a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_with_multiple_boot_order.cfg b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_with_multiple_boot_order.cfg index 8821b5f6f6..a38454c35a 100644 --- a/libvirt/tests/cfg/guest_os_booting/boot_order/boot_with_multiple_boot_order.cfg +++ b/libvirt/tests/cfg/guest_os_booting/boot_order/boot_with_multiple_boot_order.cfg @@ -6,8 +6,11 @@ aarch64: os_dict = {'bootmenu_enable': 'yes'} target_bus = 'scsi' + s390-virtio: + os_dict = {'bootmenu_enable': 'no'} + target_bus = 'scsi' cdrom_dict = {'source': {'attrs': {'file': '%s'}}, 'type_name': 'file', 'device': 'cdrom', 'driver': {'name': 'qemu', 'type': 'raw'}, 'target': {'dev': 'sda', 'bus': '${target_bus}'}} - check_prompt = ["begin the installation process|Install Red Hat Enterprise"] + check_prompt = ["begin the installation process|Install Red Hat Enterprise|Starting installer"] variants first_dev: - hd: disk_order = {'boot': '1'} @@ -16,6 +19,13 @@ cdrom_order = {'boot': '2'} variants bootable_device: - hd_bootable: + variants: + - @default: + - with_loadparm: + only s390-virtio + disk_order = {'boot': '1', 'loadparm': '1'} + test_cmd = "lsreipl" + expected_output = Loadparm:\s+"1" - cdrom_bootable: - network: network_order = {'boot': '2'} @@ -23,6 +33,10 @@ - hd_bootable: - network_bootable: check_prompt = ["iPXE initialising devices|Start PXE over IPv4"] + s390-virtio: + set_up_tftp = yes + check_prompt = ["Starting installer"] + install_tree_url = INSTALL_TREE_URL - cdrom: cdrom_order = {'boot': '1'} variants second_dev: @@ -30,6 +44,13 @@ disk_order = {'boot': '2'} variants bootable_device: - hd_bootable: + variants: + - @default: + - with_loadparm: + only s390-virtio + disk_order = {'boot': '2', 'loadparm': '2'} + test_cmd = "lsreipl" + expected_output = Loadparm:\s+"2" - cdrom_bootable: - network: network_order = {'boot': '2'} @@ -37,6 +58,10 @@ - cdrom_bootable: - network_bootable: check_prompt = ["iPXE initialising devices|Start PXE over IPv4"] + s390-virtio: + set_up_tftp = yes + check_prompt = ["Starting installer"] + install_tree_url = INSTALL_TREE_URL - network: network_order = {'boot': '1'} variants second_dev: @@ -44,11 +69,26 @@ disk_order = {'boot': '2'} variants bootable_device: - hd_bootable: + variants: + - @default: + - with_loadparm: + only s390-virtio + disk_order = {'boot': '2', 'loadparm': '2'} + test_cmd = "lsreipl" + expected_output = Loadparm:\s+"2" - network_bootable: check_prompt = ["iPXE initialising devices|Start PXE over IPv4"] + s390-virtio: + set_up_tftp = yes + check_prompt = ["Starting installer"] + install_tree_url = INSTALL_TREE_URL - cdrom: cdrom_order = {'boot': '2'} variants bootable_device: - cdrom_bootable: - network_bootable: check_prompt = ["iPXE initialising devices|Start PXE over IPv4"] + s390-virtio: + set_up_tftp = yes + check_prompt = ["Starting installer"] + install_tree_url = INSTALL_TREE_URL diff --git a/libvirt/tests/cfg/guest_os_booting/boot_order/hotplug_device_with_boot_order.cfg b/libvirt/tests/cfg/guest_os_booting/boot_order/hotplug_device_with_boot_order.cfg index 2722ca402f..9dfa260751 100644 --- a/libvirt/tests/cfg/guest_os_booting/boot_order/hotplug_device_with_boot_order.cfg +++ b/libvirt/tests/cfg/guest_os_booting/boot_order/hotplug_device_with_boot_order.cfg @@ -13,6 +13,8 @@ bus_type = "usb" target_disk = "sda" device_dict = {"type_name":"file", "target":{"dev": "${target_disk}", "bus": "${bus_type}"}, 'boot': '2'} + s390-virtio: + expected_error = unsupported configuration: This QEMU doesn't support - filesystem_device: target_dir = "mount_tag" source_dir = "/tmp" diff --git a/libvirt/tests/cfg/guest_os_booting/direct_kernel_boot/direct_kernel_boot.cfg b/libvirt/tests/cfg/guest_os_booting/direct_kernel_boot/direct_kernel_boot.cfg index 563c252244..4d4a51340c 100644 --- a/libvirt/tests/cfg/guest_os_booting/direct_kernel_boot/direct_kernel_boot.cfg +++ b/libvirt/tests/cfg/guest_os_booting/direct_kernel_boot/direct_kernel_boot.cfg @@ -6,6 +6,8 @@ initrd_url = "${repo_url}/images/pxeboot/initrd.img" vmlinuz_url = "${repo_url}/images/pxeboot/vmlinuz" direct_kernel_dict = {'cmdline': 'console=ttyS0 inst.repo=${repo_url}', 'initrd': '%s', 'kernel': '%s'} + s390-virtio: + direct_kernel_dict = {'cmdline': 'console=ttysclp0 inst.repo=${repo_url}', 'initrd': '%s', 'kernel': '%s'} variants: - start_guest: check_prompt = "Starting installer" diff --git a/libvirt/tests/cfg/guest_os_booting/firmware_configuration/os_acpi.cfg b/libvirt/tests/cfg/guest_os_booting/firmware_configuration/os_acpi.cfg index 20d6384228..8cf656f467 100644 --- a/libvirt/tests/cfg/guest_os_booting/firmware_configuration/os_acpi.cfg +++ b/libvirt/tests/cfg/guest_os_booting/firmware_configuration/os_acpi.cfg @@ -4,7 +4,7 @@ acpi_url = "EXAMPLE_ACPI_URL" acpi_file = "slic.dat" acpi_dict = {'acpi': {'table_type': 'slic', 'table': '%s'}} - no aarch64 + no aarch64, s390-virtio variants: - start_guest: cmd_in_guest = "acpidump" diff --git a/libvirt/tests/cfg/guest_os_booting/firmware_configuration/smbios_mode.cfg b/libvirt/tests/cfg/guest_os_booting/firmware_configuration/smbios_mode.cfg index 88eda2e886..e0a034ed82 100644 --- a/libvirt/tests/cfg/guest_os_booting/firmware_configuration/smbios_mode.cfg +++ b/libvirt/tests/cfg/guest_os_booting/firmware_configuration/smbios_mode.cfg @@ -1,6 +1,7 @@ - guest_os_booting.smbios_mode: type = smbios_mode start_vm = no + no s390-virtio variants: - positive_test: variants smbios_mode: diff --git a/libvirt/tests/cfg/guest_os_booting/firmware_configuration/sysinfo_fwcfg.cfg b/libvirt/tests/cfg/guest_os_booting/firmware_configuration/sysinfo_fwcfg.cfg index a9d57e5fe1..32970c35e2 100644 --- a/libvirt/tests/cfg/guest_os_booting/firmware_configuration/sysinfo_fwcfg.cfg +++ b/libvirt/tests/cfg/guest_os_booting/firmware_configuration/sysinfo_fwcfg.cfg @@ -2,6 +2,7 @@ type = sysinfo_fwcfg start_vm = no entry_value = "example value" + no s390-virtio variants: - positive_test: variants: diff --git a/libvirt/tests/cfg/guest_os_booting/migration/migration_boot.cfg b/libvirt/tests/cfg/guest_os_booting/migration/migration_boot.cfg index 58e0e2895f..7fd79d42f7 100644 --- a/libvirt/tests/cfg/guest_os_booting/migration/migration_boot.cfg +++ b/libvirt/tests/cfg/guest_os_booting/migration/migration_boot.cfg @@ -25,6 +25,7 @@ virsh_migrate_connect_uri = "qemu:///system" variants: - os_dev: + no s390-virtio os_attrs_boots = ['hd', 'cdrom', 'network'] - boot_order: disk_boot_idx = 1 diff --git a/libvirt/tests/src/guest_os_booting/boot_order/boot_from_cdrom_device.py b/libvirt/tests/src/guest_os_booting/boot_order/boot_from_cdrom_device.py index d9f7572f3b..4473f5ac1c 100644 --- a/libvirt/tests/src/guest_os_booting/boot_order/boot_from_cdrom_device.py +++ b/libvirt/tests/src/guest_os_booting/boot_order/boot_from_cdrom_device.py @@ -56,9 +56,7 @@ def update_vm_xml(vm, params, cdrom_attrs_list): os_attrs = {'boots': os_attrs_boots} vmxml.setup_attrs(os=os_attrs) else: - vm_os = vmxml.os - vm_os.del_boots() - vmxml.os = vm_os + vmxml.remove_all_boots() if "yes" == params.get("check_bootable_iso", "no"): os_attrs.update({'bootmenu_enable': 'yes', 'bootmenu_timeout': '3000'}) diff --git a/libvirt/tests/src/guest_os_booting/boot_order/boot_from_disk_device.py b/libvirt/tests/src/guest_os_booting/boot_order/boot_from_disk_device.py index d6fecf2f7a..7ef8e19ddd 100644 --- a/libvirt/tests/src/guest_os_booting/boot_order/boot_from_disk_device.py +++ b/libvirt/tests/src/guest_os_booting/boot_order/boot_from_disk_device.py @@ -6,17 +6,19 @@ from virttest.libvirt_xml import vm_xml from virttest.libvirt_xml.devices import disk +from virttest.utils_misc import cmd_status_output from virttest.utils_libvirt import libvirt_disk from virttest.utils_libvirt import libvirt_vmxml from provider.guest_os_booting import guest_os_booting_base -def parse_disks_attrs(vmxml, params): +def parse_disks_attrs(vmxml, test, params): """ Parse disk devices' attrs :param vmxml: The vmxml object + :param test: The test object :param params: Dictionary with the test parameters :return: (Newly created disk image path, list of disk devices' attrs) """ @@ -28,7 +30,14 @@ def parse_disks_attrs(vmxml, params): if disk1_img: disk1_img_path = os.path.join(data_dir.get_data_dir(), 'images', disk1_img) - libvirt_disk.create_disk('file', disk1_img_path, disk_format='qcow2') + if disk1_img == "copied_original.qcow2": + org_source_file = disk_org_attrs['source']['attrs']['file'] + cmd_status_output("qemu-img convert " + "-f qcow2 -O qcow2 -o lazy_refcounts=on " + f"{org_source_file} {disk1_img_path}") + else: + libvirt_disk.create_disk('file', disk1_img_path, disk_format='qcow2') + disk1_attrs = copy.deepcopy(disk_org_attrs) disk1_attrs['source'] = {'attrs': {'file': disk1_img_path}} disk_attrs_list.append(disk1_attrs) @@ -84,15 +93,19 @@ def run(test, params, env): vm = env.get_vm(vm_name) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) bkxml = vmxml.copy() + session = None try: - disk1_img_path, disk_attrs_list = parse_disks_attrs(vmxml, params) + disk1_img_path, disk_attrs_list = parse_disks_attrs(vmxml, test, params) update_vm_xml(vm, params, disk_attrs_list) test.log.debug(vm_xml.VMXML.new_from_dumpxml(vm.name)) vm.start() try: - vm.wait_for_serial_login().close() + #vm.wait_for_serial_login(timeout=120).close() + session = vm.wait_for_serial_login() + if 'emergency mode' in session.get_output(): + test.fail("Couldn't boot correctly") except remote.LoginTimeoutError as detail: if status_error: test.log.debug("Found the expected error: %s", detail) @@ -100,6 +113,8 @@ def run(test, params, env): test.fail(detail) finally: + if session: + session.close() bkxml.sync() if disk1_img_path and os.path.isfile(disk1_img_path): test.log.debug(f"removing {disk1_img_path}") diff --git a/libvirt/tests/src/guest_os_booting/boot_order/boot_with_multiple_boot_order.py b/libvirt/tests/src/guest_os_booting/boot_order/boot_with_multiple_boot_order.py index b3469f6bdd..255fcd65f5 100644 --- a/libvirt/tests/src/guest_os_booting/boot_order/boot_with_multiple_boot_order.py +++ b/libvirt/tests/src/guest_os_booting/boot_order/boot_with_multiple_boot_order.py @@ -1,8 +1,9 @@ # Copyright Red Hat # SPDX-License-Identifier: GPL-2.0 # Author: Meina Li - +import platform import os +import re from avocado.utils import process @@ -13,6 +14,7 @@ from virttest.utils_test import libvirt from provider.guest_os_booting import guest_os_booting_base as guest_os +from provider.virtual_network import tftpboot # Prepare a list to record the file path which need to be removed file_list = [] @@ -33,6 +35,7 @@ def prepare_device_attrs(test, params, vm_name, bootable_device): disk_order = eval(params.get("disk_order", "{}")) cdrom_order = eval(params.get("cdrom_order", "{}")) network_order = eval(params.get("network_order", "{}")) + set_up_tftp = "yes" == params.get("set_up_tftp", "no") disk_image = os.path.join(data_dir.get_data_dir(), 'images', 'test.img') vmxml = guest_os.prepare_os_xml(vm_name, os_dict) vmxml.remove_all_boots() @@ -51,6 +54,14 @@ def prepare_device_attrs(test, params, vm_name, bootable_device): else: cdrom_path = os.path.join(data_dir.get_data_dir(), 'images', 'test.iso') libvirt.create_local_disk("file", path=cdrom_path, size="500M", disk_format="raw") + if bootable_device == "network_bootable" and set_up_tftp: + install_tree_url = params.get("install_tree_url") + tftpboot.create_tftp_content(install_tree_url, + None, + arch=platform.machine()) + tftpboot.create_tftp_network() + iface_dict = {"type": "network", "source": {'network': tftpboot.net_name},"model": "virtio"} + libvirt_vmxml.modify_vm_device(vmxml, 'interface', iface_dict) file_list.append(cdrom_path) cdrom_dict = eval(params.get("cdrom_dict") % cdrom_path) cdrom_dict.update(cdrom_order) @@ -74,10 +85,13 @@ def run(test, params, env): check_prompt = eval(params.get("check_prompt", "[]")) bootable_device = params.get("bootable_device") os_dict = eval(params.get("os_dict")) + test_cmd = params.get("test_cmd", None) + expected_output = params.get("expected_output", None) vm = env.get_vm(vm_name) vmxml = vm_xml.VMXML.new_from_inactive_dumpxml(vm.name) bkxml = vmxml.copy() + session = None try: test.log.info("TEST_SETUP: prepare a guest with necessary attributes.") @@ -89,12 +103,20 @@ def run(test, params, env): test.log.debug(f"The current guest xml is: {vmxml}") test.log.info("TEST_STEP2: check the guest boot from expected device.") if bootable_device == "hd_bootable": - vm.wait_for_login(timeout=360).close() + session = vm.wait_for_login(timeout=360) test.log.debug("Succeed to boot %s", vm_name) + if test_cmd is not None: + output = session.cmd(test_cmd) + if not re.search(expected_output, output): + test.fail(f"Couldn't get {expected_output}, got instead {output}") + test.log.debug("Succeed to set %s", expected_output) + session.close() else: vm.serial_console.read_until_output_matches(check_prompt, timeout=300, internal_timeout=0.5) finally: + if session: + session.close() bkxml.sync() for file in file_list: if os.path.exists(file): diff --git a/libvirt/tests/src/guest_os_booting/direct_kernel_boot/direct_kernel_boot.py b/libvirt/tests/src/guest_os_booting/direct_kernel_boot/direct_kernel_boot.py index 90124677cd..77a70401e6 100644 --- a/libvirt/tests/src/guest_os_booting/direct_kernel_boot/direct_kernel_boot.py +++ b/libvirt/tests/src/guest_os_booting/direct_kernel_boot/direct_kernel_boot.py @@ -35,8 +35,8 @@ def run(test, params, env): bkxml = vmxml.copy() try: - boot_initrd = os.path.join(data_dir.get_data_dir(), "initrd.img") - boot_vmlinuz = os.path.join(data_dir.get_data_dir(), "vmlinuz") + boot_initrd = os.path.join(data_dir.get_data_dir(), initrd_url.split("/")[-1]) + boot_vmlinuz = os.path.join(data_dir.get_data_dir(), vmlinuz_url.split("/")[-1]) url_download(initrd_url, boot_initrd) url_download(vmlinuz_url, boot_vmlinuz) direct_kernel_dict = eval(params.get("direct_kernel_dict") diff --git a/provider/guest_os_booting/guest_os_booting_base.py b/provider/guest_os_booting/guest_os_booting_base.py index 90c64d6217..9e637c2727 100644 --- a/provider/guest_os_booting/guest_os_booting_base.py +++ b/provider/guest_os_booting/guest_os_booting_base.py @@ -1,4 +1,5 @@ import logging +import platform from avocado.core import exceptions from avocado.utils import distro @@ -25,6 +26,9 @@ def get_vm(params): firmware_type = params.get('firmware_type') detected_distro = distro.detect() os_type_dict = {} + if platform.machine() == "s390x": + return vms[0] + for _vm in vms: if os_type_dict.get("seabios") and os_type_dict.get("ovmf"): break diff --git a/provider/virtual_network/tftpboot.py b/provider/virtual_network/tftpboot.py new file mode 100644 index 0000000000..cd6ee14fcd --- /dev/null +++ b/provider/virtual_network/tftpboot.py @@ -0,0 +1,99 @@ +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# See LICENSE for more details. +# +# Copyright: Red Hat Inc. 2024 +# Author: Sebastian Mitterle +import logging as log +import os + +from avocado.utils import process +from virttest import virsh +from virttest.utils_test import libvirt + +logging = log.getLogger("avocado." + __name__) + +tftp_dir = "/var/lib/tftpboot" +boot_file = "pxelinux.cfg" +net_name = "tftpnet" + +cleanup_actions = [] + + +def create_tftp_content(install_tree_url, kickstart_url, arch): + """ + Creates the folder for the tftp server, + downloads images assuming they are below /images, + and creates the pxe configuration file + + :param install_tree_url: url of the installation tree + :param kickstart_url: url of the kickstart file + :param arch: the architecture + """ + + if arch != "s390x": + raise NotImplementedError(f"No implementation available for '{arch}'.") + + process.run("mkdir " + tftp_dir, ignore_status=False, shell=True, verbose=True) + cleanup_actions.insert(0, lambda: process.run("rm -rf " + tftp_dir, ignore_status=False, shell=True, verbose=True)) + + pxeconfig_content = """# pxelinux +default linux +label linux +kernel kernel.img +initrd initrd.img +""" + kernel_cmdline = ("append ip=dhcp inst.repo=%s inst.noverifyssl" + % install_tree_url) + + if kickstart_url: + kernel_cmdline += " inst.ks=%s" % kickstart_url + pxeconfig_content += kernel_cmdline + else: + logging.debug("Create pxelinux.cfg without kickstart.") + + with open(os.path.join(tftp_dir, boot_file), "w") as f: + f.write(pxeconfig_content) + + cmds = [] + + initrd_img_url = install_tree_url + "/images/initrd.img" + kernel_img_url = install_tree_url + "/images/kernel.img" + + cmds.append("curl %s -o %s/initrd.img" % (initrd_img_url, tftp_dir)) + cmds.append("curl %s -o %s/kernel.img" % (kernel_img_url, tftp_dir)) + + cmds.append("chmod -R a+r " + tftp_dir) + cmds.append("chown -R nobody: " + tftp_dir) + cmds.append("chcon -R --reference /usr/sbin/dnsmasq " + tftp_dir) + cmds.append("chcon -R --reference /usr/libexec/libvirt_leaseshelper " + tftp_dir) + + for cmd in cmds: + process.run(cmd, ignore_status=False, shell=True, verbose=True) + + +def create_tftp_network(): + """ + Creates a libvirt network that will serve + the tftp content + """ + + net_params = { + "net_forward": "{'mode':'nat'}", + "net_ip_address": "192.168.150.1", + "dhcp_start_ipv4": "192.168.150.2", + "dhcp_end_ipv4": "192.168.150.254", + "tftp_root": tftp_dir, + "bootp_file": boot_file + } + + net_xml = libvirt.create_net_xml(net_name, net_params) + virsh.net_create(net_xml.xml, debug=True, ignore_status=False) + cleanup_actions.insert(0, lambda: virsh.net_destroy(net_name)) diff --git a/virttools/tests/src/virt_install/pxe_installation.py b/virttools/tests/src/virt_install/pxe_installation.py index 64f961ddb8..7da0f1e8ca 100644 --- a/virttools/tests/src/virt_install/pxe_installation.py +++ b/virttools/tests/src/virt_install/pxe_installation.py @@ -1,83 +1,13 @@ import logging as log -import os -from avocado.utils import process - -from virttest import virsh from virttest.utils_misc import cmd_status_output -from virttest.utils_test import libvirt +from provider.virtual_network import tftpboot logging = log.getLogger("avocado." + __name__) cleanup_actions = [] -tftp_dir = "/var/lib/tftpboot" -boot_file = "pxelinux.cfg" -net_name = "tftpnet" - - -def create_tftp_content(install_tree_url, kickstart_url): - """ - Creates the folder for the tftp server, - downloads images assuming they are below /images, - and creates the pxe configuration file - - :param install_tree_url: url of the installation tree - :param kickstart_url: url of the kickstart file - """ - - process.run("mkdir " + tftp_dir, ignore_status=False, shell=True, verbose=True) - cleanup_actions.insert(0, lambda: process.run("rm -rf " + tftp_dir, ignore_status=False, shell=True, verbose=True)) - - pxeconfig_content = """# pxelinux -default linux -label linux -kernel kernel.img -initrd initrd.img -append ip=dhcp inst.repo=%s inst.ks=%s inst.noverifyssl -""" % (install_tree_url, kickstart_url) - - with open(os.path.join(tftp_dir, boot_file), "w") as f: - f.write(pxeconfig_content) - - cmds = [] - - initrd_img_url = install_tree_url + "/images/initrd.img" - kernel_img_url = install_tree_url + "/images/kernel.img" - - cmds.append("curl %s -o %s/initrd.img" % (initrd_img_url, tftp_dir)) - cmds.append("curl %s -o %s/kernel.img" % (kernel_img_url, tftp_dir)) - - cmds.append("chmod -R a+r " + tftp_dir) - cmds.append("chown -R nobody: " + tftp_dir) - cmds.append("chcon -R --reference /usr/sbin/dnsmasq " + tftp_dir) - cmds.append("chcon -R --reference /usr/libexec/libvirt_leaseshelper " + tftp_dir) - - for cmd in cmds: - process.run(cmd, ignore_status=False, shell=True, verbose=True) - - -def create_tftp_network(): - """ - Creates a libvirt network that will serve - the tftp content - """ - - net_params = { - "net_forward": "{'mode':'nat'}", - "net_ip_address": "192.168.150.1", - "dhcp_start_ipv4": "192.168.150.2", - "dhcp_end_ipv4": "192.168.150.254", - "tftp_root": tftp_dir, - "bootp_file": boot_file - } - - net_xml = libvirt.create_net_xml(net_name, net_params) - virsh.net_create(net_xml.xml, debug=True, ignore_status=False) - cleanup_actions.insert(0, lambda: virsh.net_destroy(net_name)) - - def run(test, params, env): """ Install VM with s390x specific pxe configuration @@ -89,8 +19,8 @@ def run(test, params, env): try: install_tree_url = params.get("install_tree_url") kickstart_url = params.get("kickstart_url") - create_tftp_content(install_tree_url, kickstart_url) - create_tftp_network() + tftpboot.create_tftp_content(install_tree_url, kickstart_url, arch="s390x") + tftpboot.create_tftp_network() cmd = ("virt-install --pxe --name %s" " --disk size=10" @@ -100,7 +30,7 @@ def run(test, params, env): " --wait 10" " --noreboot" " --network network=%s" % - (vm_name, net_name)) + (vm_name, tftpboot.net_name)) cmd_status_output(cmd, shell=True, timeout=600) logging.debug("Installation finished") @@ -117,6 +47,7 @@ def run(test, params, env): finally: if vm and vm.is_alive(): vm.destroy() + cleanup_actions.extend(tftpboot.cleanup_actions) for action in cleanup_actions: try: action()