diff --git a/oz.cfg b/oz.cfg index 5be1cb0..8913f9d 100644 --- a/oz.cfg +++ b/oz.cfg @@ -19,3 +19,9 @@ jeos = no [icicle] safe_generation = no + +[timeouts] +install = 1200 +inactivity = 300 +boot = 300 +shutdown = 90 diff --git a/oz/Guest.py b/oz/Guest.py index 54a0e8c..22c93c4 100644 --- a/oz/Guest.py +++ b/oz/Guest.py @@ -203,6 +203,16 @@ class Guest(object): 'safe_generation', False) + # configuration of 'timeouts' section + self.default_install_timeout = int(oz.ozutil.config_get_key(config, 'timeouts', + 'install', 1200)) + self.inactivity_timeout = int(oz.ozutil.config_get_key(config, 'timeouts', + 'inactivity', 300)) + self.boot_timeout = int(oz.ozutil.config_get_key(config, 'timeouts', + 'boot', 300)) + self.shutdown_timeout = int(oz.ozutil.config_get_key(config, 'timeouts', + 'shutdown', 90)) + # only pull a cached JEOS if it was built with the correct image type jeos_extension = self.image_type if self.image_type == 'raw': @@ -471,6 +481,10 @@ class Guest(object): if self.tdl.arch == "armv7l": cmdline += " console=ttyAMA0" self.lxml_subelement(osNode, "cmdline", cmdline) + if self.tdl.arch == "aarch64": + loader,nvram = oz.ozutil.find_uefi_firmware(self.tdl.arch) + self.lxml_subelement(osNode, "loader", loader, {'readonly': 'yes', 'type': 'pflash'}) + self.lxml_subelement(osNode, "nvram", None, {'template': nvram}) # poweroff, reboot, crash self.lxml_subelement(domain, "on_poweroff", "destroy") self.lxml_subelement(domain, "on_reboot", "destroy") @@ -761,8 +775,7 @@ class Guest(object): # the passed in exception was None, just raise a generic error raise oz.OzException.OzException("Unknown libvirt error") - def _wait_for_install_finish(self, libvirt_dom, count, - inactivity_timeout=300): + def _wait_for_install_finish(self, libvirt_dom, count): """ Method to wait for an installation to finish. This will wait around until either the VM has gone away (at which point it is assumed the @@ -774,7 +787,7 @@ class Guest(object): last_disk_activity = 0 last_network_activity = 0 - inactivity_countdown = inactivity_timeout + inactivity_countdown = self.inactivity_timeout origcount = count saved_exception = None while count > 0 and inactivity_countdown > 0: @@ -809,7 +822,7 @@ class Guest(object): inactivity_countdown -= 1 else: # if we did see some activity, then we can reset the timer - inactivity_countdown = inactivity_timeout + inactivity_countdown = self.inactivity_timeout last_disk_activity = total_disk_req last_network_activity = total_net_bytes @@ -826,18 +839,19 @@ class Guest(object): # if we saw no disk or network activity in the countdown window, # we presume the install has hung. Fail here screenshot_text = self._capture_screenshot(libvirt_dom) - raise oz.OzException.OzException("No disk activity in %d seconds, failing. %s" % (inactivity_timeout, screenshot_text)) + raise oz.OzException.OzException("No disk activity in %d seconds, failing. %s" % (self.inactivity_timeout, screenshot_text)) # We get here only if we got a libvirt exception self._wait_for_clean_shutdown(libvirt_dom, saved_exception) self.log.info("Install of %s succeeded", self.tdl.name) - def _wait_for_guest_shutdown(self, libvirt_dom, count=90): + def _wait_for_guest_shutdown(self, libvirt_dom): """ Method to wait around for orderly shutdown of a running guest. Returns True if the guest shutdown in the specified time, False otherwise. """ + count = self.shutdown_timeout origcount = count saved_exception = None while count > 0: @@ -1235,12 +1249,12 @@ class Guest(object): sock.connect(('127.0.0.1', self.listen_port)) addr = None - count = 300 + count = self.boot_timeout data = '' while count > 0: do_sleep = True if count % 10 == 0: - self.log.debug("Waiting for guest %s to boot, %d/300", self.tdl.name, count) + self.log.debug("Waiting for guest %s to boot, %d/%d", self.tdl.name, count, self.boot_timeout) try: # note that we have to build the data up here, since there # is no guarantee that we will get the whole write in one go diff --git a/oz/RedHat.py b/oz/RedHat.py index aaa102c..896edb7 100644 --- a/oz/RedHat.py +++ b/oz/RedHat.py @@ -334,6 +334,11 @@ label customiso # part 4; make sure the guest announces itself self.log.debug("Step 4: Guest announcement") + if self.tdl.arch in [ 'ppc64', 'ppc64le' ]: + announce_device = '/dev/hvc1' + else: + announce_device = '/dev/ttyS1' + scriptfile = os.path.join(self.icicle_tmp, "script") if g_handle.exists("/etc/NetworkManager/dispatcher.d"): @@ -342,9 +347,9 @@ label customiso #!/bin/bash if [ "$1" = "eth0" -a "$2" = "up" ]; then - echo -n "!$DHCP4_IP_ADDRESS,%s!" > /dev/ttyS1 + echo -n "!$DHCP4_IP_ADDRESS,%s!" > %s fi -""" % (self.uuid)) +""" % (self.uuid, announce_device)) try: g_handle.upload(scriptfile, @@ -364,8 +369,8 @@ DEV=$(/bin/awk '{if ($2 == 0) print $1}' /proc/net/route) && [ -z "$DEV" ] && exit 0 ADDR=$(/sbin/ip -4 -o addr show dev $DEV | /bin/awk '{print $4}' | /bin/cut -d/ -f1) && [ -z "$ADDR" ] && exit 0 -echo -n "!$ADDR,%s!" > /dev/ttyS1 -""" % (self.uuid)) +echo -n "!$ADDR,%s!" > %s +""" % (self.uuid, announce_device)) try: g_handle.upload(scriptfile, '/root/reportip') diff --git a/oz/ozutil.py b/oz/ozutil.py index eb4cd6f..775576b 100644 --- a/oz/ozutil.py +++ b/oz/ozutil.py @@ -970,3 +970,45 @@ def recursively_add_write_bit(inputdir): except OSError as err: if err.errno != errno.ENOENT: raise + +def find_uefi_firmware(arch): + # Yuck. Finding the UEFI firmware to start certain guests (like aarch64) + # is a really nasty process. While slightly out of date, this blog post + # describes the mess: http://blog.wikichoon.com/2016/01/uefi-support-in-virt-install-and-virt.html + # Here, we replicate what libguestfs is doing here, which is to essentially + # hardcode paths where UEFI firmware can be found on popular distributions. + # I verified that these files exist on both Fedora/RHEL and Ubuntu. + # Hopefully there will be a nicer way to do this in the future. + class UEFI(object): + def __init__(self, loader, nvram): + self.loader = loader + self.nvram = nvram + + def exists(self): + if os.path.exists(self.loader) and os.path.exists(self.nvram): + return True + return False + + if arch in ['i386', 'i486', 'i586', 'i686']: + uefi_list = [UEFI('/usr/share/edk2.git/ovmf-ia32/OVMF_CODE-pure-efi.fd', + '/usr/share/edk2.git/ovmf-ia32/OVMF_VARS-pure-efi.fd')] + elif arch in ['x86_64']: + uefi_list = [UEFI('/usr/share/OVMF/OVMF_CODE.fd', + '/usr/share/OVMF/OVMF_VARS.fd'), + UEFI('/usr/share/edk2.git/ovmf-x64/OVMF_CODE-pure-efi.fd', + '/usr/share/edk2.git/ovmf-x64/OVMF_VARS-pure-efi.fd')] + elif arch in ['aarch64']: + uefi_list = [UEFI('/usr/share/AAVMF/AAVMF_CODE.fd', + '/usr/share/AAVMF/AAVMF_VARS.fd'), + UEFI('/usr/share/edk2/aarch64/QEMU_EFI-pflash.raw', + '/usr/share/edk2/aarch64/vars-template-pflash.raw'), + UEFI('/usr/share/edk2.git/aarch64/QEMU_EFI-pflash.raw', + '/usr/share/edk2.git/aarch64/vars-template-pflash.raw')] + else: + raise Exception("Invalid arch for UEFI firmware") + + for uefi in uefi_list: + if uefi.exists(): + return uefi.loader,uefi.nvram + + raise Exception("UEFI firmware is not installed!")