virt-install: Split out --wait handling into a helper class

And add much more clitest coverage
This commit is contained in:
Cole Robinson 2019-06-13 16:02:58 -04:00
parent 8234b55fe8
commit 3b396e8321
3 changed files with 88 additions and 66 deletions

View File

@ -1648,9 +1648,8 @@ Amount of time to wait (in minutes) for a VM to complete its install.
Without this option, virt-install will wait for the console to close (not
necessarily indicating the guest has shutdown), or in the case of
--noautoconsole, simply kick off the install and exit. Any negative
value will make virt-install wait indefinitely, a value of 0 triggers the
same results as noautoconsole. If the time limit is exceeded, virt-install
simply exits, leaving the virtual machine in its current state.
value will make virt-install wait indefinitely, If the time limit is exceeded,
virt-install simply exits, leaving the virtual machine in its current state.
=item B<--dry-run>

View File

@ -795,7 +795,7 @@ c.add_invalid("--features smm=on --machine pc") # smm=on doesn't work for machi
c = vinst.add_category("nodisk-install", "--nographics --noautoconsole --nodisks")
c.add_valid("--hvm --cdrom %(EXISTIMG1)s") # Simple cdrom install
c.add_valid("--wait 0 --os-variant winxp --cdrom %(EXISTIMG1)s") # Windows (2 stage) install
c.add_valid("--os-variant winxp --cdrom %(EXISTIMG1)s") # Windows (2 stage) install
c.add_valid("--pxe --virt-type test") # Explicit virt-type
c.add_valid("--arch i686 --pxe") # Explicitly fullvirt + arch
c.add_valid("--location location=%(TREEDIR)s") # Directory tree URL install
@ -804,8 +804,8 @@ c.add_valid("--hvm --location %(TREEDIR)s --extra-args console=ttyS0") # Direct
c.add_valid("--paravirt --location %(TREEDIR)s") # Paravirt location
c.add_valid("--paravirt --location %(TREEDIR)s --os-variant none") # Paravirt location with --os-variant none
c.add_valid("--location %(TREEDIR)s --os-variant fedora12") # URL install with manual os-variant
c.add_valid("--cdrom %(EXISTIMG2)s --os-variant win2k3 --wait 0") # HVM windows install with disk
c.add_valid("--cdrom %(EXISTIMG2)s --os-variant win2k3 --wait 0 --print-step 2") # HVM windows install, print 3rd stage XML
c.add_valid("--cdrom %(EXISTIMG2)s --os-variant win2k3") # HVM windows install with disk
c.add_valid("--cdrom %(EXISTIMG2)s --os-variant win2k3 --print-step 2") # HVM windows install, print 3rd stage XML
c.add_valid("--pxe --autostart") # --autostart flag
c.add_compare("--cdrom http://example.com/path/to/some.iso", "cdrom-url")
c.add_compare("--pxe --print-step all", "simple-pxe") # Diskless PXE install
@ -831,7 +831,11 @@ c.add_valid("--hvm --import") # FV Import install
c.add_valid("--hvm --import --prompt --force") # Working scenario w/ prompt shouldn't ask anything
c.add_valid("--paravirt --import") # PV Import install
c.add_valid("--paravirt --print-xml 1") # print single XML, implied import install
c.add_compare("-c %(EXISTIMG2)s --os-variant win2k3 --wait 0 --vcpus cores=4 --controller usb,model=none", "w2k3-cdrom") # HVM windows install with disk
c.add_compare("-c %(EXISTIMG2)s --os-variant win2k3 --vcpus cores=4 --controller usb,model=none", "w2k3-cdrom") # HVM windows install with disk
c.add_invalid("--hvm --import --wait 2", grep="exceeded specified time limit") # --wait positive number, but test suite hack
c.add_invalid("--hvm --import --wait 0", grep="exceeded specified time limit") # --wait 0, but test suite hack
c.add_invalid("--hvm --import --wait -1", grep="exceeded specified time limit") # --wait -1, but test suite hack
c.add_invalid("--connect test:///default --name foo --ram 64 --disk none --sdl --hvm --import", use_default_args=False, grep="exceeded specified time limit") # --sdl doesn't have a console callback, triggers implicit --wait -1
c.add_invalid("--paravirt --import --print-xml 2") # PV Import install, no second XML step
c.add_invalid("--paravirt --import --print-xml 7") # Invalid --print-xml arg
c.add_invalid("--location kernel=foo,initrd=bar") # location kernel/initrd without any url
@ -894,7 +898,7 @@ c = vinst.add_category("kvm-generic", "--connect %(URI-KVM)s --noautoconsole")
c.add_compare("--os-variant fedora-unknown --file %(EXISTIMG1)s --location %(TREEDIR)s --extra-args console=ttyS0 --cpu host --channel none --console none --sound none --redirdev none --boot cmdline='foo bar baz'", "kvm-fedoralatest-url", prerun_check=has_old_osinfo) # Fedora Directory tree URL install with extra-args
c.add_compare("--test-media-detection %(TREEDIR)s --arch x86_64 --hvm", "test-url-detection") # --test-media-detection
c.add_compare("--os-variant full_id=http://fedoraproject.org/fedora/20 --disk %(EXISTIMG1)s,device=floppy --disk %(NEWIMG1)s,size=.01,format=vmdk --location %(TREEDIR)s --extra-args console=ttyS0 --quiet", "quiet-url", prerun_check=has_old_osinfo) # Quiet URL install should make no noise
c.add_compare("--cdrom %(EXISTIMG2)s --file %(EXISTIMG1)s --os-variant win2k3 --wait 0 --sound --controller usb", "kvm-win2k3-cdrom") # HVM windows install with disk
c.add_compare("--cdrom %(EXISTIMG2)s --file %(EXISTIMG1)s --os-variant win2k3 --sound --controller usb", "kvm-win2k3-cdrom") # HVM windows install with disk
c.add_compare("--os-variant ubuntusaucy --nodisks --boot cdrom --virt-type qemu --cpu Penryn --input tablet", "qemu-plain") # plain qemu
c.add_compare("--os-variant fedora20 --nodisks --boot network --nographics --arch i686", "qemu-32-on-64", prerun_check=has_old_osinfo) # 32 on 64
@ -1061,7 +1065,6 @@ c.add_valid("--nographics --cdrom %(EXISTIMG1)s") # console warning about cdrom
c.add_valid("--nographics --console none --location %(TREEDIR)s") # console warning about nographics + --console none
c.add_valid("--nographics --console none --location %(TREEDIR)s") # console warning about nographics + --console none
c.add_valid("--nographics --location %(TREEDIR)s") # console warning about nographics + missing extra args
c.add_invalid("--pxe --noautoconsole --wait 1", grep="Installation has exceeded specified time limit") # --wait 1 is converted to 1 second if we are in the test suite, so this should actually touch the wait machinery. however in this case it exits with failure
c.add_valid("--pxe --nographics --transient", grep="testsuite console command: ['virsh'") # --transient handling

View File

@ -562,38 +562,74 @@ def build_guest_instance(conn, options):
# Install process helpers #
###########################
def _sleep(secs):
if not cli.in_testsuite():
time.sleep(secs) # pragma: no cover
class WaitHandler:
"""
Helper class for handling the --wait option sleeping and time tracking
"""
def __init__(self, wait):
self.wait_is_requested = False
self._wait_mins = 0
self._start_time = 0
if wait is not None:
self.wait_is_requested = True
self._wait_mins = wait
@property
def wait_for_console_to_exit(self):
# If --wait specified, we don't want the default behavior of waiting
# for virt-viewer to exit, we want to launch it, then manually count
# down time for ourselves
return not self.wait_is_requested
@property
def _wait_forever(self):
return self._wait_mins < 0
@property
def _wait_secs(self):
return self._wait_mins * 60
def start(self):
self._start_time = time.time()
def get_time_string(self):
timestr = _(" %d minutes") % self._wait_secs
if self._wait_forever:
timestr = ""
ret = _("Waiting%(time_string)s for installation to complete.") % {
"time_string": timestr}
return ret
def wait(self):
"""
sleep 1 second, then teturn True if wait time has expired
"""
_sleep(1)
if self._wait_forever:
if cli.in_testsuite():
return True
return False # pragma: no cover
time_elapsed = (time.time() - self._start_time)
return (time_elapsed >= self._wait_secs) or cli.in_testsuite()
def start_install(guest, installer, options):
if options.wait is not None:
wait_on_install = True
wait_time = options.wait * 60
else:
wait_on_install = False
wait_time = -1
# If --wait specified, we don't want the default behavior of waiting
# for virt-viewer to exit, since then we can't exit the app when time
# expires
wait_on_console = not wait_on_install
if wait_time == 0:
# --wait 0 implies --noautoconsole
autoconsole = False
else:
autoconsole = options.autoconsole
conscb = None
if autoconsole:
if options.autoconsole:
conscb = cli.get_console_cb(guest)
if not conscb:
if not conscb and options.wait is None:
# If there isn't any console to actually connect up,
# default to --wait -1 to get similarish behavior
autoconsole = False
if options.wait is None:
logging.warning(_("No console to launch for the guest, "
"defaulting to --wait -1"))
wait_on_install = True
wait_time = -1
logging.warning(_("No console to launch for the guest, "
"defaulting to --wait -1"))
options.wait = -1
waithandler = WaitHandler(options.wait)
meter = cli.get_meter()
logging.debug("Guest.has_install_phase: %s",
installer.has_install_phase())
@ -603,7 +639,7 @@ def start_install(guest, installer, options):
domain = None
try:
start_time = time.time()
waithandler.start()
domain = installer.start_install(guest, meter=meter,
doboot=not options.noreboot,
@ -612,10 +648,10 @@ def start_install(guest, installer, options):
if options.destroy_on_exit:
atexit.register(_destroy_on_exit, domain)
cli.connect_console(guest, domain, conscb, wait_on_console,
cli.connect_console(guest, domain, conscb,
waithandler.wait_for_console_to_exit,
options.destroy_on_exit)
check_domain(installer, domain, conscb, options.transient,
wait_on_install, wait_time, start_time)
check_domain(installer, domain, conscb, options.transient, waithandler)
print_stdout(_("Domain creation completed."))
if not options.transient and not domain.isActive():
@ -644,8 +680,7 @@ def start_install(guest, installer, options):
_destroy_on_exit(domain)
def check_domain(installer, domain, conscb, transient,
wait_for_install, wait_time, start_time):
def check_domain(installer, domain, conscb, transient, waithandler):
"""
Make sure domain ends up in expected state, and wait if for install
to complete if requested
@ -674,16 +709,14 @@ def check_domain(installer, domain, conscb, transient,
# just closed the console and the VM is still running. In the
# the former case, libvirt may not have caught up yet with the
# VM having exited, so wait a bit and check again
if not cli.in_testsuite():
time.sleep(2) # pragma: no cover
_sleep(2)
if check_domain_inactive():
return # pragma: no cover
# If we reach here, the VM still appears to be running.
if not wait_for_install or wait_time == 0:
if not waithandler.wait_is_requested:
# User either:
# used --noautoconsole
# used --wait 0
# killed console and guest is still running
if not installer.has_install_phase():
return
@ -693,13 +726,8 @@ def check_domain(installer, domain, conscb, transient,
" to \nthe console to complete the installation process."))
sys.exit(0)
wait_forever = (wait_time < 0)
timestr = (not wait_forever and
_(" %d minutes") % (int(wait_time) / 60) or "")
print_stdout(
_("Domain installation still in progress. Waiting"
"%(time_string)s for installation to complete.") %
{"time_string": timestr})
print_stdout(_("Domain installation still in progress."))
print_stdout(waithandler.get_time_string())
# Wait loop
while True:
@ -707,20 +735,12 @@ def check_domain(installer, domain, conscb, transient,
print_stdout(_("Domain has shutdown. Continuing."))
break
if not cli.in_testsuite(): # pragma: no cover
time.sleep(1)
time_elapsed = (time.time() - start_time)
if not cli.in_testsuite(): # pragma: no cover
if wait_forever:
continue
if time_elapsed < wait_time:
continue
print_stdout(
_("Installation has exceeded specified time limit. "
"Exiting application."))
sys.exit(1)
done = waithandler.wait()
if done:
print_stdout(
_("Installation has exceeded specified time limit. "
"Exiting application."))
sys.exit(1)
########################