Fix raw USB live boot and verify both installation media paths
This commit is contained in:
+44
-3
@@ -635,7 +635,12 @@ def qemu_path(path):
|
||||
return str(path)
|
||||
|
||||
|
||||
def qemu_argv(qemu, scratch, disk, code, variables, iso, memory, *, keep_cdrom_drive=False):
|
||||
def qemu_argv(qemu, scratch, disk, code, variables, iso, memory, *, keep_cdrom_drive=False,
|
||||
live_media='cdrom'):
|
||||
if live_media not in {'cdrom', 'usb'}:
|
||||
raise SmokeError('Unknown live media; choose cdrom or usb')
|
||||
if keep_cdrom_drive and live_media == 'usb':
|
||||
raise SmokeError('keep_cdrom_drive cannot be combined with usb live media')
|
||||
scratch = Path(scratch)
|
||||
owned_file(disk, scratch)
|
||||
owned_file(variables, scratch)
|
||||
@@ -658,10 +663,14 @@ def qemu_argv(qemu, scratch, disk, code, variables, iso, memory, *, keep_cdrom_d
|
||||
if iso is not None:
|
||||
optical += ',format=raw,file=' + qemu_path(iso)
|
||||
argv += ['-drive', optical]
|
||||
elif iso is not None and live_media == 'usb':
|
||||
argv += ['-drive', f'if=none,id=acceptance-usb,format=raw,readonly=on,file={qemu_path(iso)}',
|
||||
'-device', 'qemu-xhci,id=acceptance-xhci',
|
||||
'-device', 'usb-storage,bus=acceptance-xhci.0,drive=acceptance-usb,bootindex=1']
|
||||
elif iso is not None:
|
||||
argv += ['-drive', f'file={qemu_path(iso)},media=cdrom,format=raw,readonly=on']
|
||||
if iso is not None:
|
||||
argv += ['-boot', 'order=d,strict=on']
|
||||
argv += ['-boot', 'strict=on' if live_media == 'usb' else 'order=d,strict=on']
|
||||
else:
|
||||
argv += ['-boot', 'order=c,strict=on']
|
||||
return argv
|
||||
@@ -827,7 +836,8 @@ class VM:
|
||||
self.stderr = open(scratch / f'{phase}-qemu.log', 'ab', buffering=0)
|
||||
self.process = subprocess.Popen(qemu_argv(args.qemu, scratch, disk,
|
||||
args.ovmf_code, scratch / 'OVMF_VARS.fd', iso, args.memory,
|
||||
keep_cdrom_drive=getattr(args, 'keep_cdrom_drive', False)),
|
||||
keep_cdrom_drive=getattr(args, 'keep_cdrom_drive', False),
|
||||
live_media=getattr(args, 'live_media', 'cdrom')),
|
||||
stdin=subprocess.DEVNULL, stdout=self.stderr, stderr=self.stderr)
|
||||
self.console = None
|
||||
self.qmp = None
|
||||
@@ -910,6 +920,25 @@ for tool in hydra hydra-install qemu-system-x86_64 qemu-img remote-viewer foot l
|
||||
for service in NetworkManager hydra-network hydra-dnsmasq; do systemctl is-active "$service"; done
|
||||
'''
|
||||
|
||||
LIVE_GRAPHICAL_CHECK = r'''set -eu
|
||||
systemctl is-active greetd
|
||||
pgrep -u hydra-live -x labwc
|
||||
pgrep -u hydra-live -x foot
|
||||
'''
|
||||
|
||||
|
||||
def live_graphical_probe(console, timeout=30):
|
||||
# Serial login can become ready before greetd has launched the live shell.
|
||||
deadline = time.monotonic() + timeout
|
||||
while True:
|
||||
try:
|
||||
return console.command(LIVE_GRAPHICAL_CHECK, min(10, max(0, deadline - time.monotonic())))
|
||||
except SmokeError:
|
||||
if time.monotonic() >= deadline:
|
||||
raise
|
||||
time.sleep(min(1, max(0, deadline - time.monotonic())))
|
||||
|
||||
|
||||
INSTALLED_CHECK = r'''set -eu
|
||||
assert_no_match() {
|
||||
if grep "$@"; then
|
||||
@@ -1069,6 +1098,10 @@ def digest(path):
|
||||
def main(argv=None):
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('--iso', required=True, type=Path)
|
||||
parser.add_argument('--live-media', choices=('cdrom', 'usb'), default='cdrom',
|
||||
help='Attach ISO as optical media or a read-only raw USB disk')
|
||||
parser.add_argument('--live-only', action='store_true',
|
||||
help='Check live boot and graphical session, then power off without installing')
|
||||
parser.add_argument('--ovmf-code', required=True, type=Path)
|
||||
parser.add_argument('--ovmf-vars', required=True, type=Path)
|
||||
parser.add_argument('--qemu', default='qemu-system-x86_64')
|
||||
@@ -1092,6 +1125,7 @@ def main(argv=None):
|
||||
print(f'Acceptance artifacts: {scratch}', flush=True)
|
||||
report = {'schema': 1, 'status': 'running', 'scratch': str(scratch),
|
||||
'iso': str(args.iso), 'iso_sha256': digest(args.iso),
|
||||
'live_media': args.live_media, 'scope': 'live-only' if args.live_only else 'install-reboot',
|
||||
'checks': {}, 'physical_hardware': 'pending',
|
||||
'nested_scope': 'Normal-user KVM VM launch, bridge helper and QMP; no nested guest OS boot',
|
||||
'ovmf_code_sha256': digest(args.ovmf_code),
|
||||
@@ -1115,6 +1149,13 @@ def main(argv=None):
|
||||
console = vm.console
|
||||
console.expect(rb'hydra-live[^\r\n]*[#$] ', args.boot_timeout)
|
||||
checkpoint('live_boot', console.command(LIVE_CHECK, 90))
|
||||
if args.live_only:
|
||||
checkpoint('live_graphical_session', live_graphical_probe(console))
|
||||
console.send('sudo -n poweroff\n')
|
||||
vm.wait_poweroff(90)
|
||||
checkpoint('live_poweroff', b'Live-only check completed without invoking the installer')
|
||||
report['status'] = 'passed'
|
||||
return 0
|
||||
console.buffer = b''
|
||||
installer_token = secrets.token_hex(12)
|
||||
console.send(installer_command(installer_token) + '\n')
|
||||
|
||||
Reference in New Issue
Block a user