| 1 | #!/usr/bin/env python3 |
| 2 | # |
| 3 | # SPDX-License-Identifier: GPL-2.0-or-later |
| 4 | ''' |
| 5 | Functional test that checks the pxelinux.cfg network booting of a s390x VM |
| 6 | (TFTP booting without config file is already tested by the pxe qtest, so |
| 7 | we don't repeat that here). |
| 8 | ''' |
| 9 | |
| 10 | import os |
| 11 | import shutil |
| 12 | |
| 13 | from qemu_test import QemuSystemTest, Asset, wait_for_console_pattern |
| 14 | |
| 15 | |
| 16 | PXELINUX_CFG_CONTENTS='''# pxelinux.cfg style config file |
| 17 | default Debian |
| 18 | label Nonexisting |
| 19 | kernel kernel.notavailable |
| 20 | initrd initrd.notavailable |
| 21 | label Debian |
| 22 | kernel kernel.debian |
| 23 | initrd initrd.debian |
| 24 | append testoption=teststring |
| 25 | label Fedora |
| 26 | kernel kernel.fedora |
| 27 | ''' |
| 28 | |
| 29 | class S390PxeLinux(QemuSystemTest): |
| 30 | ''' |
| 31 | Test various ways of booting via a pxelinux.cfg file, for details see: |
| 32 | https://wiki.syslinux.org/wiki/index.php?title=PXELINUX#Configuration |
| 33 | ''' |
| 34 | |
| 35 | ASSET_DEBIAN_KERNEL = Asset( |
| 36 | ('https://snapshot.debian.org/archive/debian/' |
| 37 | '20201126T092837Z/dists/buster/main/installer-s390x/' |
| 38 | '20190702+deb10u6/images/generic/kernel.debian'), |
| 39 | 'd411d17c39ae7ad38d27534376cbe88b68b403c325739364122c2e6f1537e818') |
| 40 | |
| 41 | ASSET_DEBIAN_INITRD = Asset( |
| 42 | ('https://snapshot.debian.org/archive/debian/' |
| 43 | '20201126T092837Z/dists/buster/main/installer-s390x/' |
| 44 | '20190702+deb10u6/images/generic/initrd.debian'), |
| 45 | '836bbd0fe6a5ca81274c28c2b063ea315ce1868660866e9b60180c575fef9fd5') |
| 46 | |
| 47 | ASSET_FEDORA_KERNEL = Asset( |
| 48 | ('https://archives.fedoraproject.org/pub/archive' |
| 49 | '/fedora-secondary/releases/31/Server/s390x/os' |
| 50 | '/images/kernel.img'), |
| 51 | '480859574f3f44caa6cd35c62d70e1ac0609134e22ce2a954bbed9b110c06e0b') |
| 52 | |
| 53 | def pxelinux_launch(self, pl_name='default', extra_opts=None): |
| 54 | '''Create a pxelinux.cfg file in the right location and launch QEMU''' |
| 55 | self.require_netdev('user') |
| 56 | self.set_machine('s390-ccw-virtio') |
| 57 | |
| 58 | debian_kernel = self.ASSET_DEBIAN_KERNEL.fetch() |
| 59 | debian_initrd = self.ASSET_DEBIAN_INITRD.fetch() |
| 60 | fedora_kernel = self.ASSET_FEDORA_KERNEL.fetch() |
| 61 | |
| 62 | # Prepare a folder for the TFTP "server": |
| 63 | tftpdir = self.scratch_file('tftp') |
| 64 | shutil.rmtree(tftpdir, ignore_errors=True) # Remove stale stuff |
| 65 | os.mkdir(tftpdir) |
| 66 | shutil.copy(debian_kernel, os.path.join(tftpdir, 'kernel.debian')) |
| 67 | shutil.copy(debian_initrd, os.path.join(tftpdir, 'initrd.debian')) |
| 68 | shutil.copy(fedora_kernel, os.path.join(tftpdir, 'kernel.fedora')) |
| 69 | |
| 70 | pxelinuxdir = self.scratch_file('tftp', 'pxelinux.cfg') |
| 71 | os.mkdir(pxelinuxdir) |
| 72 | |
| 73 | cfg_fname = self.scratch_file('tftp', 'pxelinux.cfg', pl_name) |
| 74 | with open(cfg_fname, 'w', encoding='utf-8') as f: |
| 75 | f.write(PXELINUX_CFG_CONTENTS) |
| 76 | |
| 77 | virtio_net_dev = 'virtio-net-ccw,netdev=n1,bootindex=1' |
| 78 | if extra_opts: |
| 79 | virtio_net_dev += ',' + extra_opts |
| 80 | |
| 81 | self.vm.add_args('-m', '384', |
| 82 | '-netdev', f'user,id=n1,tftp={tftpdir}', |
| 83 | '-device', virtio_net_dev) |
| 84 | self.vm.set_console() |
| 85 | self.vm.launch() |
| 86 | |
| 87 | |
| 88 | def test_default(self): |
| 89 | '''Check whether the guest uses the "default" file name''' |
| 90 | self.pxelinux_launch() |
| 91 | # The kernel prints its arguments to the console, so we can use |
| 92 | # this to check whether the kernel parameters are correctly handled: |
| 93 | wait_for_console_pattern(self, 'testoption=teststring') |
| 94 | # Now also check that we've successfully loaded the initrd: |
| 95 | wait_for_console_pattern(self, 'Unpacking initramfs...') |
| 96 | wait_for_console_pattern(self, 'Run /init as init process') |
| 97 | |
| 98 | def test_mac(self): |
| 99 | '''Check whether the guest uses file name based on its MAC address''' |
| 100 | self.pxelinux_launch(pl_name='01-02-ca-fe-ba-be-42', |
| 101 | extra_opts='mac=02:ca:fe:ba:be:42,loadparm=3') |
| 102 | wait_for_console_pattern(self, 'Linux version 5.3.7-301.fc31.s390x') |
| 103 | |
| 104 | def test_uuid(self): |
| 105 | '''Check whether the guest uses file name based on its UUID''' |
| 106 | # Also add a non-bootable disk to check the fallback to network boot: |
| 107 | self.vm.add_args('-blockdev', 'null-co,size=65536,node-name=d1', |
| 108 | '-device', 'virtio-blk,drive=d1,bootindex=0,loadparm=1', |
| 109 | '-uuid', '550e8400-e29b-11d4-a716-446655441234') |
| 110 | self.pxelinux_launch(pl_name='550e8400-e29b-11d4-a716-446655441234') |
| 111 | wait_for_console_pattern(self, 'Debian 4.19.146-1 (2020-09-17)') |
| 112 | |
| 113 | def test_ip(self): |
| 114 | '''Check whether the guest uses file name based on its IP address''' |
| 115 | self.vm.add_args('-M', 'loadparm=3') |
| 116 | self.pxelinux_launch(pl_name='0A00020F') |
| 117 | wait_for_console_pattern(self, 'Linux version 5.3.7-301.fc31.s390x') |
| 118 | |
| 119 | def test_menu(self): |
| 120 | '''Check whether the boot menu works for pxelinux.cfg booting''' |
| 121 | self.vm.add_args('-boot', 'menu=on,splash-time=10') |
| 122 | self.pxelinux_launch(pl_name='0A00') |
| 123 | wait_for_console_pattern(self, '[1] Nonexisting') |
| 124 | wait_for_console_pattern(self, '[2] Debian') |
| 125 | wait_for_console_pattern(self, '[3] Fedora') |
| 126 | wait_for_console_pattern(self, 'Debian 4.19.146-1 (2020-09-17)') |
| 127 | |
| 128 | |
| 129 | if __name__ == '__main__': |
| 130 | QemuSystemTest.main() |