diff options
author | Cole Robinson <crobinso@redhat.com> | 2020-01-26 17:12:09 -0500 |
---|---|---|
committer | Cole Robinson <crobinso@redhat.com> | 2020-01-26 18:27:20 -0500 |
commit | 8fe0a208dbfa074e56a29397f7b461104baaba41 (patch) | |
tree | 8694501ecef37d6bd7d422014c41d480f404a573 /virt-install | |
parent | 3538a8df793c6b3652162d5202b49104236444fd (diff) | |
download | virt-manager-8fe0a208dbfa074e56a29397f7b461104baaba41.tar.gz |
Move virt-* code into their modules
This layout is closer to what most python modules have nowadays.
It also simplifies testing and static analysis setup.
Keep virt-* wrappers locally, for ease of running these commands
from a git checkout.
Adjust the wrapper binaries we install on via packaging to be
pure python, which makes things like running gdb easier.
Signed-off-by: Cole Robinson <crobinso@redhat.com>
Diffstat (limited to 'virt-install')
-rwxr-xr-x | virt-install | 1049 |
1 files changed, 6 insertions, 1043 deletions
diff --git a/virt-install b/virt-install index 09f01441..17702dc3 100755 --- a/virt-install +++ b/virt-install @@ -1,1046 +1,9 @@ -#!/usr/bin/env python3 -# -# Copyright 2005-2014 Red Hat, Inc. -# -# This work is licensed under the GNU GPLv2 or later. -# See the COPYING file in the top-level directory. +#!/usr/bin/python3 +# Convenience wrapper for easily running virt-install from the git tree -import argparse -import atexit +import os import sys -import time -import select +sys.path.insert(0, os.path.dirname(__file__)) -import libvirt - -import virtinst -from virtinst import cli -from virtinst import log -from virtinst.cli import fail, print_stdout, print_stderr - - -############################## -# Validation utility helpers # -############################## - -INSTALL_METHODS = "--location URL, --cdrom CD/ISO, --pxe, --import, --boot hd|cdrom|..." - - -def supports_pxe(guest): - """ - Return False if we are pretty sure the config doesn't support PXE - """ - for nic in guest.devices.interface: - if nic.type == nic.TYPE_USER: - continue - if nic.type != nic.TYPE_VIRTUAL: - return True - - try: - netobj = nic.conn.networkLookupByName(nic.source) - xmlobj = virtinst.Network(nic.conn, parsexml=netobj.XMLDesc(0)) - return xmlobj.can_pxe() - except Exception: # pragma: no cover - log.debug("Error checking if PXE supported", exc_info=True) - return True - - return False - - -def check_cdrom_option_error(options): - if options.cdrom_short and options.cdrom: - fail("Cannot specify both -c and --cdrom") - - if options.cdrom_short: - if "://" in options.cdrom_short: - fail("-c specified with what looks like a libvirt URI. " - "Did you mean to use --connect? If not, use --cdrom instead") - options.cdrom = options.cdrom_short - - -################################# -# Back compat option conversion # -################################# - -def convert_old_printxml(options): - if options.xmlstep: - options.xmlonly = options.xmlstep - del(options.xmlstep) - - -def convert_old_sound(options): - if not options.sound: - return - for idx in range(len(options.sound)): - if options.sound[idx] is None: - options.sound[idx] = "default" - - -def convert_old_init(options): - if not options.init: - return - if not options.boot: - options.boot = [""] - options.boot[-1] += ",init=%s" % options.init - log.debug("Converted old --init to --boot %s", options.boot[-1]) - - -def _do_convert_old_disks(options): - paths = virtinst.xmlutil.listify(options.file_paths) - sizes = virtinst.xmlutil.listify(options.disksize) - - def padlist(l, padsize): - l = virtinst.xmlutil.listify(l) - l.extend((padsize - len(l)) * [None]) - return l - - disklist = padlist(paths, max(0, len(sizes))) - sizelist = padlist(sizes, len(disklist)) - - opts = [] - for idx, path in enumerate(disklist): - optstr = "" - if path: - optstr += "path=%s" % path - if sizelist[idx]: - if optstr: - optstr += "," - optstr += "size=%s" % sizelist[idx] - if options.sparse is False: - if optstr: - optstr += "," - optstr += "sparse=no" - log.debug("Converted to new style: --disk %s", optstr) - opts.append(optstr) - - options.disk = opts - - -def convert_old_disks(options): - if options.nodisks and (options.file_paths or - options.disk or - options.disksize): - fail(_("Cannot specify storage and use --nodisks")) - - if ((options.file_paths or options.disksize or not options.sparse) and - options.disk): - fail(_("Cannot mix --file, --nonsparse, or --file-size with --disk " - "options. Use --disk PATH[,size=SIZE][,sparse=yes|no]")) - - if not options.disk: - if options.nodisks: - options.disk = ["none"] - else: - _do_convert_old_disks(options) - - del(options.file_paths) - del(options.disksize) - del(options.sparse) - del(options.nodisks) - log.debug("Distilled --disk options: %s", options.disk) - - -def convert_old_os_options(options): - if not options.os_variant and options.old_os_type: - options.os_variant = options.old_os_type - del(options.old_os_type) - - -def convert_old_memory(options): - if options.memory: - return - if not options.oldmemory: - return - options.memory = str(options.oldmemory) - - -def convert_old_cpuset(options): - if not options.cpuset: - return - - newvcpus = options.vcpus or [] - newvcpus.append(",cpuset=%s" % options.cpuset) - options.vcpus = newvcpus - log.debug("Generated compat cpuset: --vcpus %s", options.vcpus[-1]) - - -def convert_old_networks(options): - if options.nonetworks: - options.network = ["none"] - - macs = virtinst.xmlutil.listify(options.mac) - networks = virtinst.xmlutil.listify(options.network) - bridges = virtinst.xmlutil.listify(options.bridge) - - if bridges and networks: - fail(_("Cannot mix both --bridge and --network arguments")) - - if bridges: - # Convert old --bridges to --networks - networks = ["bridge:" + b for b in bridges] - - def padlist(l, padsize): - l = virtinst.xmlutil.listify(l) - l.extend((padsize - len(l)) * [None]) - return l - - # If a plain mac is specified, have it imply a default network - networks = padlist(networks, max(len(macs), 1)) - macs = padlist(macs, len(networks)) - - for idx, ignore in enumerate(networks): - if networks[idx] is None: - networks[idx] = "default" - if macs[idx]: - networks[idx] += ",mac=%s" % macs[idx] - - # Handle old format of bridge:foo instead of bridge=foo - for prefix in ["network", "bridge"]: - if networks[idx].startswith(prefix + ":"): - networks[idx] = networks[idx].replace(prefix + ":", - prefix + "=") - - del(options.mac) - del(options.bridge) - del(options.nonetworks) - - options.network = networks - log.debug("Distilled --network options: %s", options.network) - - -def convert_old_graphics(options): - vnc = options.vnc - vncport = options.vncport - vnclisten = options.vnclisten - nographics = options.nographics - sdl = options.sdl - keymap = options.keymap - graphics = options.graphics - - if graphics and (vnc or sdl or keymap or vncport or vnclisten): - fail(_("Cannot mix --graphics and old style graphical options")) - - optnum = sum([bool(g) for g in [vnc, nographics, sdl, graphics]]) - if optnum > 1: - raise ValueError(_("Can't specify more than one of VNC, SDL, " - "--graphics or --nographics")) - - if options.graphics: - return - - if optnum == 0: - return - - # Build a --graphics command line from old style opts - optstr = ((vnc and "vnc") or - (sdl and "sdl") or - (nographics and ("none"))) - if vnclisten: - optstr += ",listen=%s" % vnclisten - if vncport: - optstr += ",port=%s" % vncport - if keymap: - optstr += ",keymap=%s" % keymap - - log.debug("--graphics compat generated: %s", optstr) - options.graphics = [optstr] - - -def convert_old_features(options): - if options.features: - return - - opts = [] - if options.noacpi: - opts.append("acpi=off") - if options.noapic: - opts.append("apic=off") - if opts: - options.features = [",".join(opts)] - - -def convert_wait_zero(options): - # Historical back compat, --wait 0 is identical to --noautoconsole - if options.wait == 0: - log.warning("Treating --wait 0 as --noautoconsole") - options.autoconsole = "none" - options.wait = None - - -################################## -# Install media setup/validation # -################################## - -def do_test_media_detection(conn, options): - url = options.test_media_detection - guest = virtinst.Guest(conn) - if options.arch: - guest.os.arch = options.arch - if options.os_type: - guest.os.os_type = options.os_type - guest.set_capabilities_defaults() - - installer = virtinst.Installer(conn, location=url) - print_stdout(installer.detect_distro(guest), do_force=True) - - -############################# -# General option validation # -############################# - -def storage_specified(options, guest): - if guest.os.is_container(): - return True - return options.disk or options.filesystem - - -def memory_specified(guest): - return guest.memory or guest.currentMemory or guest.cpu.cells - - -def validate_required_options(options, guest, installer): - # Required config. Don't error right away if nothing is specified, - # aggregate the errors to help first time users get it right - msg = "" - - if not memory_specified(guest): - msg += "\n" + _("--memory amount in MiB is required") - - if not storage_specified(options, guest): - msg += "\n" + ( - _("--disk storage must be specified (override with --disk none)")) - - if not guest.os.is_container() and not installer.options_specified(): - msg += "\n" + ( - _("An install method must be specified\n(%(methods)s)") % - {"methods": INSTALL_METHODS}) - - if msg: - fail(msg) - - -def show_console_warnings(installer, autoconsole): - if not installer.cdrom: - return - if not autoconsole.is_text(): - return - log.warning(_("CDROM media does not print to the text console " - "by default, so you likely will not see text install output. " - "You might want to use --location.") + " " + - _("See the man page for examples of " - "using --location with CDROM media")) - - -def _show_memory_warnings(guest): - if not guest.currentMemory: - return - - res = guest.osinfo.get_recommended_resources() - rammb = guest.currentMemory // 1024 - minram = (res.get_minimum_ram(guest.os.arch) or 0) - if minram: - if (minram // 1024) > guest.currentMemory: - log.warning(_("Requested memory %s MiB is less than the " - "recommended %s MiB for OS %s"), rammb, - minram // (1024 * 1024), guest.osinfo.name) - elif rammb < 17: - log.warning(_("Requested memory %s MiB is abnormally low. " - "Were you trying to specify GiB?"), rammb) - - -def show_guest_warnings(options, guest, osdata): - if options.pxe and not supports_pxe(guest): - log.warning( - _("The guest's network configuration may not support PXE")) - - # Limit it to hvm x86 guests which presently our defaults - # only really matter for - if (guest.osinfo.name == "generic" and - not osdata.is_none and - not osdata.name == "generic" and - guest.os.is_x86() and guest.os.is_hvm()): - log.warning(_("No operating system detected, VM performance may " - "suffer. Specify an OS with --os-variant for optimal results.")) - - _show_memory_warnings(guest) - - -########################## -# Guest building helpers # -########################## - -def get_location_for_os(guest, osname, profile=None): - osinfo = virtinst.OSDB.lookup_os(osname, raise_error=True) - location = osinfo.get_location(guest.os.arch, profile) - print_stdout(_("Using {osname} --location {url}").format( - osname=osname, url=location)) - return location - - -def build_installer(options, guest, installdata): - cdrom = None - location = None - location_kernel = None - location_initrd = None - unattended_data = None - extra_args = options.extra_args - - install_bootdev = installdata.bootdev - install_kernel = installdata.kernel - install_initrd = installdata.initrd - install_kernel_args = installdata.kernel_args - install_os = installdata.os - no_install = installdata.no_install - if installdata.kernel_args: - if installdata.kernel_args_overwrite: - install_kernel_args = installdata.kernel_args - else: - extra_args = [installdata.kernel_args] - - if options.unattended: - unattended_data = cli.parse_unattended(options.unattended) - - if install_os: - profile = unattended_data.profile if unattended_data else None - location = get_location_for_os(guest, install_os, profile) - elif options.location: - (location, - location_kernel, - location_initrd) = cli.parse_location(options.location) - elif options.cdrom: - cdrom = options.cdrom - if options.livecd: - no_install = True - elif options.pxe: - install_bootdev = "network" - elif installdata.is_set: - pass - elif (options.import_install or - options.xmlonly or - options.boot): - no_install = True - - installer = virtinst.Installer(guest.conn, - cdrom=cdrom, - location=location, - location_kernel=location_kernel, - location_initrd=location_initrd, - install_bootdev=install_bootdev, - install_kernel=install_kernel, - install_initrd=install_initrd, - install_kernel_args=install_kernel_args, - no_install=no_install) - - if unattended_data: - installer.set_unattended_data(unattended_data) - if extra_args: - installer.set_extra_args(extra_args) - if options.initrd_inject: - installer.set_initrd_injections(options.initrd_inject) - if options.autostart: - installer.autostart = True - if options.cloud_init: - cloudinit_data = cli.parse_cloud_init(options.cloud_init) - installer.set_cloudinit_data(cloudinit_data) - - return installer - - -def set_cli_defaults(options, guest): - if not guest.name: - default_name = virtinst.Guest.generate_name(guest) - cli.print_stdout(_("Using default --name {vm_name}").format( - vm_name=default_name)) - guest.name = default_name - - if guest.os.is_container(): - if not memory_specified(guest): - mbram = 1024 - # LXC doesn't even do anything with memory settings, but libvirt - # XML requires it anyways. Fill in 64 MiB - cli.print_stdout( - _("Using container default --memory {megabytes}").format( - megabytes=mbram)) - guest.currentMemory = mbram * 1024 - return - - if (options.unattended and - guest.osinfo.is_windows() and - guest.osinfo.supports_unattended_drivers(guest.os.arch)): - guest.add_extra_drivers( - guest.osinfo.get_pre_installable_devices(guest.os.arch)) - - res = guest.osinfo.get_recommended_resources() - storage = res.get_recommended_storage(guest.os.arch) - ram = res.get_recommended_ram(guest.os.arch) - ncpus = res.get_recommended_ncpus(guest.os.arch) - - if ram and not memory_specified(guest): - mbram = str(ram / (1024 * 1024)).rstrip("0").rstrip(".") - cli.print_stdout( - _("Using {os_name} default --memory {megabytes}").format( - os_name=guest.osinfo.name, megabytes=mbram)) - guest.currentMemory = ram // 1024 - - if ncpus: - # We need to do this upfront, so we don't incorrectly set guest.vcpus - guest.sync_vcpus_topology() - if not guest.vcpus: - # I don't think we need to print anything here as this was never - # a required value. - guest.vcpus = ncpus - - if storage and not storage_specified(options, guest): - diskstr = 'size=%d' % (storage // (1024 ** 3)) - cli.print_stdout( - _("Using {os_name} default --disk {disk_options}".format( - os_name=guest.osinfo.name, disk_options=diskstr))) - options.disk = [diskstr] - cli.ParserDisk(diskstr, guest=guest).parse(None) - - -def set_explicit_guest_options(options, guest): - if options.name: - guest.name = options.name - options.name = None - if options.uuid: - guest.uuid = options.uuid - options.uuid = None - if options.description: - guest.description = options.description - options.description = None - if options.os_type: - guest.os.os_type = options.os_type - options.os_type = None - if options.virt_type: - guest.type = options.virt_type - options.virt_type = None - if options.arch: - guest.os.arch = options.arch - options.arch = None - if options.machine: - guest.os.machine = options.machine - options.machine = None - - -def installer_detect_distro(guest, installer, osdata): - try: - # OS name has to be set firstly whenever --os-variant is passed, - # otherwise it won't be respected when the installer creates the - # Distro Store. - if osdata.name: - guest.set_os_name(osdata.name) - - # This also validates the install location - autodistro = installer.detect_distro(guest) - if osdata.is_auto and autodistro: - guest.set_os_name(autodistro) - except ValueError as e: - fail(_("Error validating install location: %s") % str(e)) - - -def build_guest_instance(conn, options): - guest = virtinst.Guest(conn) - guest.skip_default_osinfo = True - - # Fill in guest from the command line content - set_explicit_guest_options(options, guest) - cli.parse_option_strings(options, guest, None) - - # Call set_capabilities_defaults explicitly here rather than depend - # on set_defaults calling it. Installer setup needs filled in values. - # However we want to do it after parse_option_strings to ensure - # we are operating on any arch/os/type values passed in with --boot - guest.set_capabilities_defaults() - - installdata = cli.parse_install(options.install) - installer = build_installer(options, guest, installdata) - - # Set guest osname, from commandline or detected from media - osdata = cli.parse_os_variant(options.os_variant) - if installdata.os: - osdata.set_installdata_name(installdata.os) - guest.set_default_os_name() - installer_detect_distro(guest, installer, osdata) - - set_cli_defaults(options, guest) - installer.set_install_defaults(guest) - for path in installer.get_search_paths(guest): - cli.check_path_search(guest.conn, path) - - # cli specific disk validation - for disk in guest.devices.disk: - cli.validate_disk(disk) - - validate_required_options(options, guest, installer) - show_guest_warnings(options, guest, osdata) - - return guest, installer - - -########################### -# 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_mins - 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 _print_cloudinit_passwd(installer): - passwd = installer.get_generated_password() - if not passwd: - return - - print_stdout(_("Password for first root login is: %s") % passwd, - do_force=True, do_log=False) - - stdins = [sys.stdin] - timeout = 10 - if sys.stdin.closed or not sys.stdin.isatty(): - if not cli.in_testsuite(): # pragma: no cover - return - stdins = [] - timeout = .0001 - - sys.stdout.write( - _("Installation will continue in 10 seconds " - "(press Enter to skip)...")) - sys.stdout.flush() - - select.select(stdins, [], [], timeout) - - -def start_install(guest, installer, options): - autoconsole = cli.parse_autoconsole(options, guest, installer) - show_console_warnings(installer, autoconsole) - - conscb = autoconsole.get_console_cb() - if autoconsole.is_default() and 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 - log.warning(_("No console to launch for the guest, " - "defaulting to --wait -1")) - options.wait = -1 - - waithandler = WaitHandler(options.wait) - meter = cli.get_meter() - log.debug("Guest.has_install_phase: %s", installer.has_install_phase()) - - # we've got everything -- try to start the install - print_stdout(_("\nStarting install...")) - - domain = None - try: - _print_cloudinit_passwd(installer) - - waithandler.start() - - domain = installer.start_install(guest, meter=meter, - doboot=not options.noreboot, - transient=options.transient) - - if options.destroy_on_exit: - atexit.register(_destroy_on_exit, domain) - - cli.connect_console(guest, domain, conscb, - waithandler.wait_for_console_to_exit, - options.destroy_on_exit) - check_domain(installer, domain, conscb, options.transient, waithandler) - - print_stdout(_("Domain creation completed.")) - if not options.transient and not domain.isActive(): - if options.noreboot or not installer.has_install_phase(): - print_stdout( # pragma: no cover - _("You can restart your domain by running:\n %s") % - cli.virsh_start_cmd(guest)) - else: - print_stdout(_("Restarting guest.")) - domain.create() - cli.connect_console(guest, domain, conscb, True, - options.destroy_on_exit) - - except KeyboardInterrupt: # pragma: no cover - log.debug("", exc_info=True) - print_stderr(_("Domain install interrupted.")) - raise - except Exception as e: - fail(e, do_exit=False) - if domain is None: - installer.cleanup_created_disks(guest, meter) - cli.install_fail(guest) - - if cli.in_testsuite() and options.destroy_on_exit: - # Helps with unit testing - _destroy_on_exit(domain) - - -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 - """ - def check_domain_inactive(): - try: - dominfo = domain.info() - state = dominfo[0] - - if state == libvirt.VIR_DOMAIN_CRASHED: - fail(_("Domain has crashed.")) # pragma: no cover - - return not domain.isActive() - except libvirt.libvirtError as e: - if transient and e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN: - log.debug("transient VM shutdown and disappeared.") - return True - raise # pragma: no cover - - if check_domain_inactive(): - return - - if bool(conscb): - # We are trying to detect if the VM shutdown, or the user - # 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 - _sleep(2) - if check_domain_inactive(): - return # pragma: no cover - - # If we reach here, the VM still appears to be running. - if not waithandler.wait_is_requested: - # User either: - # used --noautoconsole - # killed console and guest is still running - if not installer.has_install_phase(): - return - - print_stdout( - _("Domain installation still in progress. You can reconnect" - " to \nthe console to complete the installation process.")) - sys.exit(0) - - print_stdout(_("Domain installation still in progress.")) - print_stdout(waithandler.get_time_string()) - - # Wait loop - while True: - if check_domain_inactive(): # pragma: no cover - print_stdout(_("Domain has shutdown. Continuing.")) - break - - done = waithandler.wait() - if done: - print_stdout( - _("Installation has exceeded specified time limit. " - "Exiting application.")) - sys.exit(1) - - -######################## -# XML printing helpers # -######################## - -def xml_to_print(guest, installer, xmlonly, dry): - start_xml, final_xml = installer.start_install( - guest, dry=dry, return_xml=True) - if not start_xml: - start_xml = final_xml - final_xml = None - - if dry and not xmlonly: - print_stdout(_("Dry run completed successfully")) - return - - if xmlonly not in [False, "1", "2", "all"]: - fail(_("Unknown XML step request '%s', must be 1, 2, or all") % - xmlonly) - - if xmlonly == "1": - return start_xml - if xmlonly == "2": - if not final_xml: - fail(_("Requested installation does not have XML step 2")) - return final_xml - - # "all" case - xml = start_xml - if final_xml: - xml += final_xml - return xml - - -####################### -# CLI option handling # -####################### - -def parse_args(): - parser = cli.setupParser( - "%(prog)s --name NAME --memory MB STORAGE INSTALL [options]", - _("Create a new virtual machine from specified install media."), - introspection_epilog=True) - cli.add_connect_option(parser) - - geng = parser.add_argument_group(_("General Options")) - geng.add_argument("-n", "--name", - help=_("Name of the guest instance")) - cli.add_memory_option(geng, backcompat=True) - cli.vcpu_cli_options(geng) - cli.add_metadata_option(geng) - geng.add_argument("-u", "--uuid", help=argparse.SUPPRESS) - geng.add_argument("--description", help=argparse.SUPPRESS) - - insg = parser.add_argument_group(_("Installation Method Options")) - insg.add_argument("-c", dest="cdrom_short", help=argparse.SUPPRESS) - insg.add_argument("--cdrom", help=_("CD-ROM installation media")) - insg.add_argument("-l", "--location", - help=_("Distro install URL, eg. https://host/path. See man " - "page for specific distro examples.")) - insg.add_argument("--pxe", action="store_true", - help=_("Boot from the network using the PXE protocol")) - insg.add_argument("--import", action="store_true", dest="import_install", - help=_("Build guest around an existing disk image")) - insg.add_argument("--livecd", action="store_true", help=argparse.SUPPRESS) - insg.add_argument("-x", "--extra-args", action="append", - help=_("Additional arguments to pass to the install kernel " - "booted from --location")) - insg.add_argument("--initrd-inject", action="append", - help=_("Add given file to root of initrd from --location")) - insg.add_argument("--unattended", nargs="?", const=1, - help=_("Perform an unattended installation")) - insg.add_argument("--install", - help=_("Specify fine grained install options")) - insg.add_argument("--cloud-init", nargs="?", const=1, - help=_("Perform a cloud image installation, configuring cloud-init")) - - # Takes a URL and just prints to stdout the detected distro name - insg.add_argument("--test-media-detection", help=argparse.SUPPRESS) - # Helper for cli testing, fills in standard stub options - insg.add_argument("--test-stub-command", action="store_true", - help=argparse.SUPPRESS) - - cli.add_boot_options(insg) - insg.add_argument("--init", help=argparse.SUPPRESS) - - osg = cli.add_os_variant_option(parser, virtinstall=True) - osg.add_argument("--os-type", dest="old_os_type", help=argparse.SUPPRESS) - - devg = parser.add_argument_group(_("Device Options")) - cli.add_disk_option(devg) - cli.add_net_option(devg) - cli.add_gfx_option(devg) - cli.add_device_options(devg, sound_back_compat=True) - - # Deprecated device options - devg.add_argument("-f", "--file", dest="file_paths", action="append", - help=argparse.SUPPRESS) - devg.add_argument("-s", "--file-size", type=float, - action="append", dest="disksize", - help=argparse.SUPPRESS) - devg.add_argument("--nonsparse", action="store_false", - default=True, dest="sparse", - help=argparse.SUPPRESS) - devg.add_argument("--nodisks", action="store_true", help=argparse.SUPPRESS) - devg.add_argument("--nonetworks", action="store_true", - help=argparse.SUPPRESS) - devg.add_argument("-b", "--bridge", action="append", - help=argparse.SUPPRESS) - devg.add_argument("-m", "--mac", action="append", help=argparse.SUPPRESS) - devg.add_argument("--vnc", action="store_true", help=argparse.SUPPRESS) - devg.add_argument("--vncport", type=int, help=argparse.SUPPRESS) - devg.add_argument("--vnclisten", help=argparse.SUPPRESS) - devg.add_argument("-k", "--keymap", help=argparse.SUPPRESS) - devg.add_argument("--sdl", action="store_true", help=argparse.SUPPRESS) - devg.add_argument("--nographics", action="store_true", - help=argparse.SUPPRESS) - - - gxmlg = parser.add_argument_group(_("Guest Configuration Options")) - cli.add_guest_xml_options(gxmlg) - - - virg = parser.add_argument_group(_("Virtualization Platform Options")) - ostypeg = virg.add_mutually_exclusive_group() - ostypeg.add_argument("-v", "--hvm", - action="store_const", const="hvm", dest="os_type", - help=_("This guest should be a fully virtualized guest")) - ostypeg.add_argument("-p", "--paravirt", - action="store_const", const="xen", dest="os_type", - help=_("This guest should be a paravirtualized guest")) - ostypeg.add_argument("--container", - action="store_const", const="exe", dest="os_type", - help=_("This guest should be a container guest")) - virg.add_argument("--virt-type", - help=_("Hypervisor name to use (kvm, qemu, xen, ...)")) - virg.add_argument("--arch", help=_("The CPU architecture to simulate")) - virg.add_argument("--machine", help=_("The machine type to emulate")) - virg.add_argument("--accelerate", action="store_true", - help=argparse.SUPPRESS) - virg.add_argument("--noapic", action="store_true", - default=False, help=argparse.SUPPRESS) - virg.add_argument("--noacpi", action="store_true", - default=False, help=argparse.SUPPRESS) - - - misc = parser.add_argument_group(_("Miscellaneous Options")) - misc.add_argument("--autostart", action="store_true", default=False, - help=_("Have domain autostart on host boot up.")) - misc.add_argument("--transient", action="store_true", default=False, - help=_("Create a transient domain.")) - misc.add_argument("--destroy-on-exit", action="store_true", default=False, - help=_("Force power off the domain when the console " - "viewer is closed.")) - misc.add_argument("--wait", type=int, const=-1, nargs="?", - help=_("Minutes to wait for install to complete.")) - - cli.add_misc_options(misc, prompt=True, printxml=True, printstep=True, - noreboot=True, dryrun=True, noautoconsole=True) - - cli.autocomplete(parser) - - return parser.parse_args() - - -################### -# main() handling # -################### - -# Catchall for destroying the VM on ex. ctrl-c -def _destroy_on_exit(domain): - try: - isactive = bool(domain and domain.isActive()) - if isactive: - domain.destroy() # pragma: no cover - except libvirt.libvirtError as e: # pragma: no cover - if e.get_error_code() != libvirt.VIR_ERR_NO_DOMAIN: - log.debug("Error invoking atexit destroy_on_exit", - exc_info=True) - - -def set_test_stub_options(options): # pragma: no cover - # Set some basic options that will let virt-install succeed. Helps - # save boiler plate typing when testing new command line additions - if not options.test_stub_command: - return - - options.import_install = True - if not options.connect: - options.connect = "test:///default" - if not options.name: - options.name = "test-stub-command" - if not options.memory: - options.memory = "256" - if not options.disk: - options.disk = "none" - if not options.graphics: - options.graphics = "none" - if not options.os_variant: - options.os_variant = "fedora27" - - -def main(conn=None): - cli.earlyLogging() - options = parse_args() - - # Default setup options - convert_old_printxml(options) - options.quiet = (options.xmlonly or - options.test_media_detection or options.quiet) - cli.setupLogging("virt-install", options.debug, options.quiet) - - if cli.check_option_introspection(options): - return 0 - - check_cdrom_option_error(options) - cli.convert_old_force(options) - cli.parse_check(options.check) - cli.set_prompt(options.prompt) - convert_old_memory(options) - convert_old_sound(options) - convert_old_networks(options) - convert_old_graphics(options) - convert_old_disks(options) - convert_old_features(options) - convert_old_cpuset(options) - convert_old_init(options) - convert_wait_zero(options) - set_test_stub_options(options) - convert_old_os_options(options) - - conn = cli.getConnection(options.connect, conn=conn) - - if options.test_media_detection: - do_test_media_detection(conn, options) - return 0 - - guest, installer = build_guest_instance(conn, options) - if options.xmlonly or options.dry: - xml = xml_to_print(guest, installer, options.xmlonly, options.dry) - if xml: - print_stdout(xml, do_force=True) - else: - start_install(guest, installer, options) - - return 0 - -if __name__ == "__main__": # pragma: no cover - try: - sys.exit(main()) - except SystemExit as sys_e: - sys.exit(sys_e.code) - except KeyboardInterrupt: - log.debug("", exc_info=True) - print_stderr(_("Installation aborted at user request")) - except Exception as main_e: - fail(main_e) +from virtinst import virtinstall +virtinstall.runcli() |