From f38eb8a3bfe19fcd60d34e6b326ce2f0332e1f2e Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Sun, 21 Dec 2025 17:59:36 +0100 Subject: Testsuite: T8111: remove duplicate -vga and -cpu argument for QEMU --- scripts/check-qemu-install | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'scripts') diff --git a/scripts/check-qemu-install b/scripts/check-qemu-install index b2ebe750..00487347 100755 --- a/scripts/check-qemu-install +++ b/scripts/check-qemu-install @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2019-2025, VyOS maintainers and contributors +# Copyright VyOS maintainers and contributors # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License version 2 or later as @@ -184,11 +184,9 @@ def get_qemu_cmd(name, enable_uefi, disk_img, raid=None, iso_img=None, tpm=False -machine {machine},accel=kvm \ {uefi} \ -m {args.memory}G \ - -vga none \ -nographic \ {vga} {vnc}\ -uuid {uuid} \ - -cpu host \ {cdrom} \ -enable-kvm \ -monitor unix:/tmp/qemu-monitor-socket-{disk_img},server,nowait \ -- cgit v1.2.3 From 01424d292dae2b6564285f06d0bb8d11b05e1790 Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Sun, 21 Dec 2025 18:01:43 +0100 Subject: Testsuite: T8111: add basic_cli_tests() helper function --- scripts/check-qemu-install | 63 +++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 29 deletions(-) (limited to 'scripts') diff --git a/scripts/check-qemu-install b/scripts/check-qemu-install index 00487347..d0350643 100755 --- a/scripts/check-qemu-install +++ b/scripts/check-qemu-install @@ -361,6 +361,38 @@ def toggleUEFISecureBoot(c): UEFIKeyPress(c, KEY_DOWN) UEFIKeyPress(c, KEY_RETURN) +def basic_cli_tests(c): + # Repeating / shared basic CLI test between installed images and the + # cloud-init test-case + c.sendline('configure') + c.expect(cfg_mode_prompt) + c.sendline('exit') + c.expect(op_mode_prompt) + c.sendline('show version') + c.expect(op_mode_prompt) + c.sendline('show version kernel') + c.expect(f'{vyos_defaults["kernel_version"]}-{vyos_defaults["kernel_flavor"]}') + c.expect(op_mode_prompt) + c.sendline('show version frr') + c.expect(op_mode_prompt) + c.sendline('show interfaces') + c.expect(op_mode_prompt) + c.sendline('systemd-detect-virt') + c.expect('kvm') + c.expect(op_mode_prompt) + c.sendline('show system cpu') + c.expect(op_mode_prompt) + c.sendline('show system memory') + c.expect(op_mode_prompt) + c.sendline('show system memory detail | no-more') + c.expect(op_mode_prompt) + c.sendline('show configuration commands | match kernel') + c.expect(op_mode_prompt) + c.sendline('cat /proc/cmdline') + c.expect(op_mode_prompt) + c.sendline('show version all | grep -e "vpp" -e "vyos-1x"') + c.expect(op_mode_prompt) + if args.qemu_cmd: tmp = get_qemu_cmd(qemu_name, args.uefi, args.disk, raid=diskname_raid, iso_img=args.iso, vnc_enabled=args.vnc, secure_boot=args.sbtest) os.system(tmp) @@ -429,6 +461,7 @@ try: c.expect(cfg_mode_prompt) c.sendline('exit') c.expect(op_mode_prompt) + ################################################# # Installing into VyOS system ################################################# @@ -576,35 +609,7 @@ try: # Basic Configmode/Opmode switch ################################################# log.info('Basic CLI configuration mode test') - - c.sendline('configure') - c.expect(cfg_mode_prompt) - c.sendline('exit') - c.expect(op_mode_prompt) - c.sendline('show version') - c.expect(op_mode_prompt) - c.sendline('show version kernel') - c.expect(f'{vyos_defaults["kernel_version"]}-{vyos_defaults["kernel_flavor"]}') - c.expect(op_mode_prompt) - c.sendline('show version frr') - c.expect(op_mode_prompt) - c.sendline('show interfaces') - c.expect(op_mode_prompt) - c.sendline('systemd-detect-virt') - c.expect('kvm') - c.expect(op_mode_prompt) - c.sendline('show system cpu') - c.expect(op_mode_prompt) - c.sendline('show system memory') - c.expect(op_mode_prompt) - c.sendline('show system memory detail | no-more') - c.expect(op_mode_prompt) - c.sendline('show configuration commands | match kernel') - c.expect(op_mode_prompt) - c.sendline('cat /proc/cmdline') - c.expect(op_mode_prompt) - c.sendline('show version all | grep -e "vpp" -e "vyos-1x"') - c.expect(op_mode_prompt) + basic_cli_tests(c) ################################################# # Verify /etc/os-release via lsb_release -- cgit v1.2.3 From d21ca283b02a8959c8de24411ecb33efb9b79172 Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Sun, 21 Dec 2025 18:03:19 +0100 Subject: Testsuite: T8111: add BOOTLOADERchooseSerialConsole() helper When booting ISO or installed image in QEMU testsuite, always select the serial console as default tty during Linux boot. --- scripts/check-qemu-install | 86 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 8 deletions(-) (limited to 'scripts') diff --git a/scripts/check-qemu-install b/scripts/check-qemu-install index d0350643..7e55a5a7 100755 --- a/scripts/check-qemu-install +++ b/scripts/check-qemu-install @@ -58,6 +58,7 @@ qemu_name = 'VyOS-QEMU' # getch.py KEY_F2 = chr(27) + chr(91) + chr(49) + chr(50) + chr(126) KEY_F10 = chr(27) + chr(91) + chr(50) + chr(49) + chr(126) +KEY_UP = chr(27) + chr(91) + chr(65) KEY_DOWN = chr(27) + chr(91) + chr(66) KEY_SPACE = chr(32) KEY_RETURN = chr(13) @@ -361,6 +362,81 @@ def toggleUEFISecureBoot(c): UEFIKeyPress(c, KEY_DOWN) UEFIKeyPress(c, KEY_RETURN) +def BOOTLOADERchooseSerialConsole(c, live: bool) -> None: + """ Select GRUB boot entry that uses the serial console. This differs + between a LIVE ISO image and an already installed system. """ + BOOTLOADER_TMO = 20 + BOOTLOADER_SLEEP = 0.5 + BOOTLOADER_LOAD_TMO = 5 # let GRUB screen load + + UEFI_STRING = r'BdsDxe.*' + GRUB_STRING = r'GNU GRUB.*' + ISOLINUX_STRING = r'ISOLINUX.*' + + # XXX: UEFI systems directly load GRUB, BIOS systems fallback to ISOLINUX + if live and args.uefi: + # Let UEFI start before GRUB + c.expect(UEFI_STRING, timeout=BOOTLOADER_TMO) + # Wait for GRUB + c.expect(GRUB_STRING, timeout=BOOTLOADER_TMO) + time.sleep(BOOTLOADER_LOAD_TMO) + + # Select GRUB serial console + # Key DOWN -> fail-safe mode + c.send(KEY_DOWN) + time.sleep(BOOTLOADER_SLEEP) + # Key DOWN -> Serial Console boot + c.send(KEY_DOWN) + time.sleep(BOOTLOADER_SLEEP) + # Boot + c.send(KEY_RETURN) + elif live and not args.uefi: + # Wait for ISOLINUX + c.expect(ISOLINUX_STRING, timeout=BOOTLOADER_TMO) + time.sleep(BOOTLOADER_LOAD_TMO) + + # Key UP - always start from top menu entry, selection does not wrap + c.send(KEY_UP) + time.sleep(BOOTLOADER_SLEEP) + c.send(KEY_UP) + time.sleep(BOOTLOADER_SLEEP) + c.send(KEY_UP) + time.sleep(BOOTLOADER_SLEEP) + # Select Serial console - second option + c.send(KEY_DOWN) + time.sleep(BOOTLOADER_SLEEP) + # Boot + c.send(KEY_RETURN) + else: + # Let UEFI start before GRUB + if args.uefi: + c.expect(UEFI_STRING, timeout=BOOTLOADER_TMO) + + # Wait for GRUB + c.expect(GRUB_STRING, timeout=BOOTLOADER_TMO) + time.sleep(BOOTLOADER_LOAD_TMO) + + # Select GRUB serial console + # Boot options + c.send(KEY_DOWN) + time.sleep(BOOTLOADER_SLEEP) + c.send(KEY_RETURN) + time.sleep(BOOTLOADER_SLEEP) + # Select console type + c.send(KEY_DOWN) + time.sleep(BOOTLOADER_SLEEP) + c.send(KEY_RETURN) + time.sleep(BOOTLOADER_SLEEP) + # *ttyS (serial) + c.send(KEY_DOWN) + time.sleep(BOOTLOADER_SLEEP) + c.send(KEY_RETURN) + time.sleep(BOOTLOADER_SLEEP) + # Boot + c.send(KEY_RETURN) + + return None + def basic_cli_tests(c): # Repeating / shared basic CLI test between installed images and the # cloud-init test-case @@ -425,14 +501,7 @@ try: log.info('Disable UEFI Secure Boot for initial installation') toggleUEFISecureBoot(c) - try: - c.expect('Welcome to GRUB', timeout=10) - c.send(KEY_DOWN) - c.send(KEY_DOWN) - c.send(KEY_RETURN) - except pexpect.TIMEOUT: - log.warning('Did not find GRUB countdown window, ignoring') - + BOOTLOADERchooseSerialConsole(c, live=(not args.cloud_init)) loginVM(c, log) ################################################# @@ -566,6 +635,7 @@ try: # Booting installed system ################################################# log.info('Booting installed system') + BOOTLOADERchooseSerialConsole(c, live=False) ################################################# # Logging into VyOS system -- cgit v1.2.3 From 6fa36ec9957501e9e917a345fb93a8d95786199d Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Sun, 21 Dec 2025 18:06:22 +0100 Subject: Testsuite: T8111: make --iso and --disk optional arguments It is now possible to pass in an already existing qcow2 disk image to the Testsuite. This is necessary if we would like to boot wxisting flavor images like KVM or PROXMOX. --- Makefile | 14 +++++++------- scripts/check-qemu-install | 44 ++++++++++++++++++++++++++++---------------- 2 files changed, 35 insertions(+), 23 deletions(-) (limited to 'scripts') diff --git a/Makefile b/Makefile index 348e536d..4b4b5a70 100644 --- a/Makefile +++ b/Makefile @@ -21,37 +21,37 @@ checkiso: .PHONY: test .ONESHELL: test: checkiso - scripts/check-qemu-install --debug --configd --match="$(MATCH)" --smoketest --uefi --cpu 4 --memory 8 build/live-image-amd64.hybrid.iso $(filter-out $@,$(MAKECMDGOALS)) + scripts/check-qemu-install --debug --configd --match="$(MATCH)" --smoketest --uefi --cpu 4 --memory 8 --iso build/live-image-amd64.hybrid.iso $(filter-out $@,$(MAKECMDGOALS)) .PHONY: test-no-interfaces .ONESHELL: test-no-interfaces: checkiso - scripts/check-qemu-install --debug --configd --smoketest --uefi --no-interfaces --cpu 4 --memory 8 --huge-page-size 2M --huge-page-count 1800 build/live-image-amd64.hybrid.iso + scripts/check-qemu-install --debug --configd --smoketest --uefi --no-interfaces --cpu 4 --memory 8 --huge-page-size 2M --huge-page-count 1800 --iso build/live-image-amd64.hybrid.iso .PHONY: test-no-interfaces-no-vpp .ONESHELL: test-no-interfaces-no-vpp: checkiso - scripts/check-qemu-install --debug --configd --smoketest --uefi --no-interfaces --no-vpp build/live-image-amd64.hybrid.iso + scripts/check-qemu-install --debug --configd --smoketest --uefi --no-interfaces --no-vpp --iso build/live-image-amd64.hybrid.iso .PHONY: test-interfaces .ONESHELL: test-interfaces: checkiso - scripts/check-qemu-install --debug --configd --match="interfaces_" --smoketest --uefi build/live-image-amd64.hybrid.iso + scripts/check-qemu-install --debug --configd --match="interfaces_" --smoketest --uefi --iso build/live-image-amd64.hybrid.iso .PHONY: test-vpp .ONESHELL: test-vpp: checkiso - scripts/check-qemu-install --debug --configd --match="vpp" --smoketest --uefi --cpu 4 --memory 8 --huge-page-size 2M --huge-page-count 1800 build/live-image-amd64.hybrid.iso + scripts/check-qemu-install --debug --configd --match="vpp" --smoketest --uefi --cpu 4 --memory 8 --huge-page-size 2M --huge-page-count 1800 --iso build/live-image-amd64.hybrid.iso .PHONY: testc .ONESHELL: testc: checkiso - scripts/check-qemu-install --debug --configd --match="!vpp" --cpu 2 --memory 7 --configtest build/live-image-amd64.hybrid.iso $(filter-out $@,$(MAKECMDGOALS)) + scripts/check-qemu-install --debug --configd --match="!vpp" --cpu 2 --memory 7 --configtest --iso build/live-image-amd64.hybrid.iso $(filter-out $@,$(MAKECMDGOALS)) .PHONY: testcvpp .ONESHELL: testcvpp: checkiso - scripts/check-qemu-install --debug --configd --match="vpp" --cpu 4 --memory 8 --huge-page-size 2M --huge-page-count 1800 --configtest build/live-image-amd64.hybrid.iso $(filter-out $@,$(MAKECMDGOALS)) + scripts/check-qemu-install --debug --configd --match="vpp" --cpu 4 --memory 8 --huge-page-size 2M --huge-page-count 1800 --configtest --iso build/live-image-amd64.hybrid.iso $(filter-out $@,$(MAKECMDGOALS)) .PHONY: testraid .ONESHELL: diff --git a/scripts/check-qemu-install b/scripts/check-qemu-install index 7e55a5a7..07e59fc5 100755 --- a/scripts/check-qemu-install +++ b/scripts/check-qemu-install @@ -51,7 +51,8 @@ import tomli import pexpect EXCEPTION = 0 -now = datetime.now() +DISK_IMAGE_EXTENSION = '.raw' + tpm_folder = '/tmp/vyos_tpm_test' qemu_name = 'VyOS-QEMU' @@ -68,10 +69,8 @@ KEY_Y = chr(121) mok_password = '1234' parser = argparse.ArgumentParser(description='Install and start a test VyOS vm.') -parser.add_argument('iso', help='ISO file to install') -parser.add_argument('disk', help='name of disk image file', nargs='?', - default='testinstall-{}-{}.img'.format(now.strftime('%Y%m%d-%H%M%S'), - "%04x" % random.randint(0,65535))) +parser.add_argument('--iso', help='ISO file to install') +parser.add_argument('--disk', help='name of disk image file', nargs='?') parser.add_argument('--keep', help='Do not remove disk-image after installation', action='store_true', default=False) parser.add_argument('--silent', help='Do not show output on stdout unless an error has occured', @@ -142,10 +141,6 @@ class StreamToLogger(object): def flush(self): pass -OVMF_CODE = '/usr/share/OVMF/OVMF_CODE_4M.secboot.fd' -OVMF_VARS_TMP = args.disk.replace('.img', '.efivars') -if args.sbtest: - shutil.copy('/usr/share/OVMF/OVMF_VARS_4M.ms.fd', OVMF_VARS_TMP) def get_qemu_cmd(name, enable_uefi, disk_img, raid=None, iso_img=None, tpm=False, vnc_enabled=False, secure_boot=False): uefi = "" @@ -178,6 +173,10 @@ def get_qemu_cmd(name, enable_uefi, disk_img, raid=None, iso_img=None, tpm=False # RFC7042 section 2.1.2 MAC addresses used for documentation macbase = '00:00:5E:00:53' + + # Set QEmu disk image format - this differs if VyOS was installed via smoketest + # or we use an already ewxisting image + disk_format = 'qcow2' if args.disk.endswith('.qcow2') else 'raw' cmd = f'qemu-system-x86_64 \ -name "{name}" \ -smp {args.cpu},sockets=1,cores={args.cpu},threads=1 \ @@ -200,11 +199,11 @@ def get_qemu_cmd(name, enable_uefi, disk_img, raid=None, iso_img=None, tpm=False -netdev user,id=n6 -device virtio-net-pci,netdev=n6,mac={macbase}:06,romfile="" \ -netdev user,id=n7 -device virtio-net-pci,netdev=n7,mac={macbase}:07,romfile="" \ -device virtio-scsi-pci,id=scsi0 \ - -drive format=raw,file={disk_img},if=none,media=disk,id=drive-hd1,readonly=off \ + -drive format={disk_format},file={disk_img},if=none,media=disk,id=drive-hd1,readonly=off \ -device scsi-hd,bus=scsi0.0,drive=drive-hd1,id=hd1,bootindex=1' if raid: - cmd += f' -drive format=raw,file={raid},if=none,media=disk,id=drive-hd2,readonly=off' \ + cmd += f' -drive format={disk_format},file={raid},if=none,media=disk,id=drive-hd2,readonly=off' \ f' -device scsi-hd,bus=scsi0.0,drive=drive-hd2,id=hd2,bootindex=2' if tpm: @@ -276,14 +275,27 @@ if args.silent: else: output = sys.stdout.buffer -if not os.path.isfile(args.iso): - log.error('Unable to find iso image to install') - sys.exit(1) - if not os.path.exists('/dev/kvm'): log.error('KVM not enabled on host, proceeding with software emulation') sys.exit(1) +if not args.iso and not args.disk: + log.error('Neither ISO not QCOW2 disk image supplied - error!') + sys.exit(1) + +if not args.disk: + tmp_disk_time = datetime.now().strftime('%Y%m%d-%H%M%S') + tmp_disk_random = "%04x" % random.randint(0,65535) + args.disk = f'testinstall-{tmp_disk_time}-{tmp_disk_random}{DISK_IMAGE_EXTENSION}' + +if not args.iso or not os.path.isfile(args.iso): + log.debug('Unable to find ISO image to install ...') + +OVMF_CODE = '/usr/share/OVMF/OVMF_CODE_4M.secboot.fd' +OVMF_VARS_TMP = args.disk.replace(DISK_IMAGE_EXTENSION, '.efivars') +if args.sbtest: + shutil.copy('/usr/share/OVMF/OVMF_VARS_4M.ms.fd', OVMF_VARS_TMP) + # Creating diskimage!! diskname_raid = None def gen_disk(name): @@ -292,7 +304,7 @@ def gen_disk(name): c = subprocess.check_output(['qemu-img', 'create', name, '2G']) log.debug(c.decode()) else: - log.info(f'Diskimage "{name}" already exists, using the existing one.') + log.info(f'Re-using already existing disk image "{name}".') if args.raid: filename, ext = os.path.splitext(args.disk) -- cgit v1.2.3 From 8e065320b32804bcab1326dff1e27337163e7e85 Mon Sep 17 00:00:00 2001 From: Christian Breunig Date: Sun, 21 Dec 2025 18:37:11 +0100 Subject: Testsuite: T8111: add --cloud-init test target Add support to dynamically assemble cloud-init NoCloud ISO image and attach it to an existing qcow2 image file. The config data injected via NoCloud is later validated if it has been properly configured on the OS level. --- .gitignore | 4 +- Makefile | 14 ++- .../hooks/live/01-live-serial.binary | 6 +- scripts/check-qemu-install | 116 ++++++++++++++++++--- 4 files changed, 121 insertions(+), 19 deletions(-) (limited to 'scripts') diff --git a/.gitignore b/.gitignore index 6ef765d2..de9b67f9 100644 --- a/.gitignore +++ b/.gitignore @@ -7,8 +7,10 @@ packer_cache/* key/* packages/* !packages/*/ -/testinstall*.img +/testinstall*.raw /testinstall*.efivars +/ci_data +/ci_seed.iso /*.qcow2 /*.tar .DS_Store diff --git a/Makefile b/Makefile index 4b4b5a70..197910ae 100644 --- a/Makefile +++ b/Makefile @@ -68,10 +68,20 @@ testsb: checkiso testtpm: checkiso scripts/check-qemu-install --debug --tpmtest build/live-image-amd64.hybrid.iso $(filter-out $@,$(MAKECMDGOALS)) +.PHONY: test-ci-qcow2 +.ONESHELL: +test-ci-qcow2: + if [ ! -f build/*.qcow2 ]; then + echo "Could not find any QCOW2 disk image" + exit 1 + fi + rm -f cloud-init-image-amd64.qcow2 ; cp $$(ls -t build/*.qcow2 | head -n 1) cloud-init-image-amd64.qcow2 + scripts/check-qemu-install --debug --cloud-init --disk cloud-init-image-amd64.qcow2 $(filter-out $@,$(MAKECMDGOALS)) + .PHONY: qemu-live .ONESHELL: qemu-live: checkiso - scripts/check-qemu-install --qemu-cmd --uefi build/live-image-amd64.hybrid.iso $(filter-out $@,$(MAKECMDGOALS)) + scripts/check-qemu-install --qemu-cmd --iso build/live-image-amd64.hybrid.iso $(filter-out $@,$(MAKECMDGOALS)) .PHONY: oci .ONESHELL: @@ -101,4 +111,4 @@ clean: .PHONY: purge purge: - rm -rf build packer_build packer_cache testinstall-*.img + rm -rf build packer_build packer_cache testinstall-*.raw ci_data ci_seed.iso diff --git a/data/live-build-config/hooks/live/01-live-serial.binary b/data/live-build-config/hooks/live/01-live-serial.binary index 05785da7..0e449fc9 100755 --- a/data/live-build-config/hooks/live/01-live-serial.binary +++ b/data/live-build-config/hooks/live/01-live-serial.binary @@ -18,14 +18,16 @@ echo "$GRUB_MENUENTRY" | sed \ -e "s/$KVM_CONSOLE/$SERIAL_CONSOLE/g" >> $GRUB_PATH # Live.cfg Update -ISOLINUX_MENUENTRY=$(sed -e '/label live-\(.*\)-vyos$/,/^\tappend.*/!d' $ISOLINUX_PATH) +ISOLINUX_MENUENTRY=$(sed -e '/label live-vyos$/,/^\tappend.*/!d' $ISOLINUX_PATH) # Update KVM menuentry name sed -i 's/Live system \((.*vyos)\)/Live system \1 - KVM console/' $ISOLINUX_PATH # Insert serial menuentry echo "\n$ISOLINUX_MENUENTRY" | sed \ - -e 's/live-\(.*\)-vyos/live-\1-vyos-serial/' \ + -e 's/live-vyos/live-vyos-serial/' \ + -e 's/^\tmenu label \^/\tmenu label /' \ -e '/^\tmenu default/d' \ -e 's/Live system \((.*vyos)\)/Live system \1 - Serial console/' \ -e "s/$KVM_CONSOLE/$SERIAL_CONSOLE/g" >> $ISOLINUX_PATH + diff --git a/scripts/check-qemu-install b/scripts/check-qemu-install index 07e59fc5..9abd5e85 100755 --- a/scripts/check-qemu-install +++ b/scripts/check-qemu-install @@ -52,10 +52,24 @@ import pexpect EXCEPTION = 0 DISK_IMAGE_EXTENSION = '.raw' +CI_CONFIG_ARGS = { + 'hostname': 'vyos-CLOUD-INIT', + 'eth0_ipv4': '192.0.2.1/25', + 'eth0_ipv6': '2001:db8::1/64', + 'default_nexthop' : '192.0.2.126', + 'default_nexthop6' : '2001:db8::ffff', + } tpm_folder = '/tmp/vyos_tpm_test' qemu_name = 'VyOS-QEMU' +test_timeout = 5 *3600 # 5 hours (in seconds) to complete individual testcases + +op_mode_prompt = r'vyos@vyos:~\$' +cfg_mode_prompt = r'vyos@vyos#' +default_user = 'vyos' +default_password = 'vyos' + # getch.py KEY_F2 = chr(27) + chr(91) + chr(49) + chr(50) + chr(126) KEY_F10 = chr(27) + chr(91) + chr(50) + chr(49) + chr(126) @@ -94,6 +108,8 @@ parser.add_argument('--tpmtest', help='Execute TPM encrypted config tests', action='store_true', default=False) parser.add_argument('--sbtest', help='Execute Secure Boot tests', action='store_true', default=False) +parser.add_argument('--cloud-init', help='Execute cloud-init tests', + action='store_true', default=False) parser.add_argument('--qemu-cmd', help='Only generate QEMU launch command', action='store_true', default=False) parser.add_argument('--cpu', help='Set QEMU CPU', type=int, default=2) @@ -107,6 +123,11 @@ parser.add_argument('--huge-page-count', help='Number of huge pages to allocate' args = parser.parse_args() +if args.cloud_init: + hostname = CI_CONFIG_ARGS['hostname'] + op_mode_prompt = rf'vyos@{hostname}:~\$' + cfg_mode_prompt = rf'vyos@{hostname}#' + # This is what we requested the build to contain with open('data/defaults.toml', 'rb') as f: vyos_defaults = tomli.load(f) @@ -141,6 +162,8 @@ class StreamToLogger(object): def flush(self): pass +class EarlyExit(Exception): + pass def get_qemu_cmd(name, enable_uefi, disk_img, raid=None, iso_img=None, tpm=False, vnc_enabled=False, secure_boot=False): uefi = "" @@ -407,17 +430,13 @@ def BOOTLOADERchooseSerialConsole(c, live: bool) -> None: c.expect(ISOLINUX_STRING, timeout=BOOTLOADER_TMO) time.sleep(BOOTLOADER_LOAD_TMO) - # Key UP - always start from top menu entry, selection does not wrap - c.send(KEY_UP) - time.sleep(BOOTLOADER_SLEEP) - c.send(KEY_UP) - time.sleep(BOOTLOADER_SLEEP) - c.send(KEY_UP) + # Boot Menu starts at Live system (vyos) - KVM console + c.send(KEY_DOWN) time.sleep(BOOTLOADER_SLEEP) - # Select Serial console - second option + # Live system (vyos fail-safe mode) c.send(KEY_DOWN) time.sleep(BOOTLOADER_SLEEP) - # Boot + # Live system (vyos) - Serial console - boot it up c.send(KEY_RETURN) else: # Let UEFI start before GRUB @@ -486,7 +505,49 @@ if args.qemu_cmd: os.system(tmp) exit(0) -test_timeout = 5 *3600 # 3 hours (in seconds) +if args.cloud_init: + # Build cloud-init seed iso + CI_ISO = 'ci_seed.iso' + CI_DATA_DIR = 'ci_data' + # Insert cloud-init ISO into CD-ROM + args.iso = CI_ISO + + if not os.path.exists(CI_DATA_DIR): + os.makedirs(CI_DATA_DIR) + + # create "empty" meta-data file + open(f'{CI_DATA_DIR}/meta-data', mode='w').close() + + network_config = """version: 2 +ethernets: + eth0: + dhcp4: false + dhcp6: false +""" + + user_data = """#cloud-config +vyos_config_commands: + - set system host-name '{hostname}' + - set service ntp server 1.pool.ntp.org + - set service ntp server 2.pool.ntp.org + - delete interfaces ethernet eth0 address 'dhcp' + - set interfaces ethernet eth0 address '{eth0_ipv4}' + - set interfaces ethernet eth0 address '{eth0_ipv6}' + - set protocols static route 0.0.0.0/0 next-hop '{default_nexthop}' + - set protocols static route6 ::/0 next-hop '{default_nexthop6}' +""".format(**CI_CONFIG_ARGS) + + with open(f'{CI_DATA_DIR}/network-config', mode='w') as f: + f.writelines(network_config) + + with open(f'{CI_DATA_DIR}/user-data', mode='w') as f: + f.writelines(user_data) + + # Assemble cloud-init ISO file + if os.path.exists(CI_ISO): + os.unlink(CI_ISO) + os.system(f'mkisofs -joliet -rock -volid "cidata" -output {CI_ISO} {CI_DATA_DIR}') + tpm_process = None try: # Start TPM emulator @@ -504,11 +565,6 @@ try: ################################################# # Logging into VyOS system ################################################# - op_mode_prompt = r'vyos@vyos:~\$' - cfg_mode_prompt = r'vyos@vyos#' - default_user = 'vyos' - default_password = 'vyos' - if args.sbtest: log.info('Disable UEFI Secure Boot for initial installation') toggleUEFISecureBoot(c) @@ -516,6 +572,35 @@ try: BOOTLOADERchooseSerialConsole(c, live=(not args.cloud_init)) loginVM(c, log) + ################################################# + # Cloud-Init comes with a pre-assembled ISO - just boot and test it + ################################################# + if args.cloud_init: + log.info('Perform basic CLI configuration mode tests from cloud-init...') + basic_cli_tests(c) + + # Valida assigned IPv4 and IPv6 addresses + c.sendline('ip --json addr show dev eth0 | jq -r \'.[0].addr_info[] | select(.family=="inet") | "\(.local)/\(.prefixlen)"\'') + c.expect(CI_CONFIG_ARGS['eth0_ipv4']) + c.expect(op_mode_prompt) + + c.sendline('ip --json addr show dev eth0 | jq -r \'.[0].addr_info[] | select(.family=="inet6" and .scope=="global" and (.temporary|not)) | "\(.local)/\(.prefixlen)"\'') + c.expect(CI_CONFIG_ARGS['eth0_ipv6']) + c.expect(op_mode_prompt) + + # Valida default route nexthops + c.sendline('ip -4 --json route show default | jq -r ".[0].gateway"') + c.expect(CI_CONFIG_ARGS['default_nexthop']) + c.expect(op_mode_prompt) + + c.sendline('ip -6 --json route show default | jq -r ".[0].gateway"') + c.expect(CI_CONFIG_ARGS['default_nexthop6']) + c.expect(op_mode_prompt) + + shutdownVM(c, log, 'Powering off system') + c.close() + raise EarlyExit + ################################################# # Check for no private key contents within the image ################################################# @@ -1113,6 +1198,9 @@ try: shutdownVM(c, log, 'Powering off system') c.close() +except EarlyExit: + pass + except pexpect.exceptions.TIMEOUT: log.error('Timeout waiting for VyOS system') log.error(traceback.format_exc()) -- cgit v1.2.3