virt-manager-1.5.1/0000775000175100017510000000000013245574323015604 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/virt-install0000775000175100017510000010220713245573052020162 0ustar crobinsocrobinso00000000000000#!/usr/bin/env python2 # # Copyright 2005-2014 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import argparse import logging import os import re import sys import time import libvirt import virtinst from virtinst import cli 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 install_specified(location, cdpath, pxe, import_install): return bool(pxe or cdpath or location or import_install) def cdrom_specified(guest, disk=None): disks = guest.get_devices("disk") for d in disks: if d.device == virtinst.VirtualDisk.DEVICE_CDROM: return True # Probably haven't set up disks yet if not disks and disk: for opts in disk: if opts.count("device=cdrom"): return True return False def supports_pxe(guest): """ Return False if we are pretty sure the config doesn't support PXE """ for nic in guest.get_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)) if xmlobj.can_pxe(): return True except Exception: logging.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 URI. Did you mean " "to use --connect? If not, use --cdrom instead") options.cdrom = options.cdrom_short if not options.cdrom: return # Catch a strangely common error of users passing -vcpus=2 instead of # --vcpus=2. The single dash happens to map to enough shortened options # that things can fail weirdly if --paravirt is also specified. for vcpu in [o for o in sys.argv if o.startswith("-vcpu")]: if options.cdrom == vcpu[3:]: fail("You specified -vcpus, you want --vcpus") ################################# # 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 += ",init=%s" % options.init logging.debug("Converted old --init to --boot %s", options.boot) def _do_convert_old_disks(options): paths = virtinst.util.listify(options.file_paths) sizes = virtinst.util.listify(options.disksize) def padlist(l, padsize): l = virtinst.util.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" logging.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) logging.debug("Distilled --disk options: %s", options.disk) def convert_old_os_options(options): distro_variant = options.distro_variant distro_type = options.distro_type if not distro_type and not distro_variant: # Default to distro autodetection options.distro_variant = "auto" return distro_variant = distro_variant and str(distro_variant).lower() or None distro_type = distro_type and str(distro_type).lower() or None distkey = distro_variant or distro_type if not distkey or distkey == "none": options.distro_variant = "none" else: options.distro_variant = distkey 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 if not options.vcpus: options.vcpus = "" options.vcpus += ",cpuset=%s" % options.cpuset logging.debug("Generated compat cpuset: --vcpus %s", options.vcpus) def convert_old_networks(options): if options.nonetworks: if options.mac: fail(_("Cannot use --mac with --nonetworks")) if options.bridge: fail(_("Cannot use --bridge with --nonetworks")) if options.network: fail(_("Cannot use --nonetworks with --network")) options.network = ["none"] if options.pxe and options.network and "none" in options.network: fail(_("Can't use --pxe without any network")) macs = virtinst.util.listify(options.mac) networks = virtinst.util.listify(options.network) bridges = virtinst.util.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.util.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 logging.debug("Distilled --network options: %s", options.network) def _determine_default_graphics(guest, default_override): if default_override is True: return elif default_override is False: guest.skip_default_graphics = True return def convert_old_graphics(guest, options, default_override=None): 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: _determine_default_graphics(guest, default_override) 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 logging.debug("--graphics compat generated: %s", optstr) options.graphics = [optstr] def convert_old_features(options): if getattr(options, "features", None): return opts = "" if options.noacpi: opts += "acpi=off" if options.noapic: if opts: opts += "," opts += "apic=off" options.features = opts or None ######################## # Virt type validation # ######################## def get_guest(conn, options): # Set up all virt/hypervisor parameters if sum([bool(f) for f in [options.fullvirt, options.paravirt, options.container]]) > 1: fail(_("Can't do more than one of --hvm, --paravirt, or --container")) req_hv_type = options.hv_type and options.hv_type.lower() or None if options.fullvirt: req_virt_type = "hvm" elif options.paravirt: req_virt_type = "xen" elif options.container: req_virt_type = "exe" else: # This should force capabilities to give us the most sensible default req_virt_type = None logging.debug("Requesting virt method '%s', hv type '%s'.", (req_virt_type and req_virt_type or _("default")), (req_hv_type and req_hv_type or _("default"))) arch = options.arch if re.match("i.86", arch or ""): arch = "i686" try: guest = conn.caps.lookup_virtinst_guest( os_type=req_virt_type, arch=arch, typ=req_hv_type, machine=options.machine) except Exception as e: fail(e) if (not req_virt_type and not req_hv_type and conn.is_qemu() and guest.os.arch in ["i686", "x86_64"] and not guest.type == "kvm"): logging.warning("KVM acceleration not available, using '%s'", guest.type) return guest ################################## # Install media setup/validation # ################################## def set_install_media(guest, location, cdpath, distro_variant): try: cdinstall = bool(not location and (cdpath or cdrom_specified(guest))) if cdinstall or cdpath: guest.installer.cdrom = True if location or cdpath: guest.installer.location = (location or cdpath) if distro_variant not in ["auto", "none"]: guest.os_variant = distro_variant guest.installer.check_location(guest) if distro_variant == "auto": guest.os_variant = guest.installer.detect_distro(guest) except ValueError as e: fail(_("Error validating install location: %s") % str(e)) def do_test_media_detection(conn, url): guest = conn.caps.lookup_virtinst_guest() guest.installer = virtinst.DistroInstaller(conn) guest.installer.location = url print_stdout(guest.installer.detect_distro(guest), do_force=True) ############################# # General option validation # ############################# def validate_required_options(options, guest): # 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 options.name: msg += "\n" + _("--name is required") if not options.memory: msg += "\n" + _("--memory amount in MiB is required") if (not guest.os.is_container() and not (options.disk or options.filesystem)): msg += "\n" + ( _("--disk storage must be specified (override with --disk none)")) if (not guest.os.is_container() and not options.xmlonly and (not install_specified(options.location, options.cdrom, options.pxe, options.import_install)) and (not cdrom_specified(guest, options.disk))): msg += "\n" + ( _("An install method must be specified\n(%(methods)s)") % {"methods": install_methods}) if msg: fail(msg) _cdrom_location_man_page = _("See the man page for examples of " "using --location with CDROM media") def check_option_collisions(options, guest): if options.noreboot and options.transient: fail(_("--noreboot and --transient can not be specified together")) # Install collisions if sum([bool(l) for l in [options.pxe, options.location, options.cdrom, options.import_install]]) > 1: fail(_("Only one install method can be used (%(methods)s)") % {"methods": install_methods}) if (guest.os.is_container() and install_specified(options.location, options.cdrom, options.pxe, options.import_install)): fail(_("Install methods (%s) cannot be specified for " "container guests") % install_methods) if guest.os.is_xenpv(): if options.pxe: fail(_("Network PXE boot is not supported for paravirtualized " "guests")) if options.cdrom or options.livecd: fail(_("Paravirtualized guests cannot install off cdrom media.")) if (options.location and guest.conn.is_remote() and not guest.conn.support_remote_url_install()): fail(_("Libvirt version does not support remote --location installs")) cdrom_err = "" if guest.installer.cdrom: cdrom_err = " " + _cdrom_location_man_page if not options.location and options.extra_args: fail(_("--extra-args only work if specified with --location.") + cdrom_err) if not options.location and options.initrd_inject: fail(_("--initrd-inject only works if specified with --location.") + cdrom_err) def _show_nographics_warnings(options, guest): if guest.get_devices("graphics"): return if not options.autoconsole: return if guest.installer.cdrom: logging.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.") + " " + _cdrom_location_man_page) return if not options.location: return # Trying --location --nographics with console connect. Warn if # they likely won't see any output. if not guest.get_devices("console"): logging.warning(_("No --console device added, you likely will not " "see text install output from the guest.")) return serial_arg = "console=ttyS0" serial_arm_arg = "console=ttyAMA0" hvc_arg = "console=hvc0" console_type = serial_arg if guest.os.is_arm(): console_type = serial_arm_arg if guest.get_devices("console")[0].target_type in ["virtio", "xen"]: console_type = hvc_arg if guest.os.is_ppc64() or guest.os.is_arm_machvirt(): # Later arm/ppc kernels figure out console= automatically, so don't # warn about it. return for args in options.extra_args: if console_type in (args or ""): return logging.warning(_("Did not find '%(console_string)s' in --extra-args, " "which is likely required to see text install output from the " "guest."), {"console_string": console_type}) def show_warnings(options, guest): if options.pxe and not supports_pxe(guest): logging.warning(_("The guest's network configuration does not support " "PXE")) if (guest.os_variant == "generic" and options.distro_variant not in ["none", "generic"]): logging.warning(_("No operating system detected, VM performance may " "suffer. Specify an OS with --os-variant for optimal results.")) _show_nographics_warnings(options, guest) ########################## # Guest building helpers # ########################## def build_installer(options, conn, virt_type): # Build the Installer instance if options.pxe: instclass = virtinst.PXEInstaller elif options.cdrom or options.location or options.livecd: instclass = virtinst.DistroInstaller elif virt_type == "exe": instclass = virtinst.ContainerInstaller elif options.import_install or options.boot: if options.import_install and options.nodisks: fail(_("A disk device must be specified with --import.")) options.import_install = True instclass = virtinst.ImportInstaller elif options.xmlonly: instclass = virtinst.ImportInstaller else: instclass = virtinst.DistroInstaller installer = instclass(conn) if options.livecd: installer.livecd = True return installer def build_guest_instance(conn, options): guest = get_guest(conn, options) logging.debug("Received virt method '%s'", guest.type) logging.debug("Hypervisor name is '%s'", guest.os.os_type) guest.installer = build_installer(options, conn, guest.os.os_type) convert_old_memory(options) convert_old_sound(options) convert_old_networks(options) convert_old_graphics(guest, options) convert_old_disks(options) convert_old_features(options) convert_old_cpuset(options) convert_old_init(options) convert_old_os_options(options) # non-xml install options options.extra_args = options.extra_args or [] guest.installer.extraargs = options.extra_args guest.installer.initrd_injections = options.initrd_inject guest.autostart = options.autostart if options.name: guest.name = options.name if options.uuid: guest.uuid = options.uuid if options.description: guest.description = options.description validate_required_options(options, guest) cli.parse_option_strings(options, guest, None) # Extra disk validation for disk in guest.get_devices("disk"): cli.validate_disk(disk) set_install_media(guest, options.location, options.cdrom, options.distro_variant) guest.add_default_devices() # Default to UEFI for aarch64 if (guest.os.is_arm64() and not guest.os.kernel and not guest.os.loader and guest.os.loader_ro is None and guest.os.nvram is None): try: guest.set_uefi_default() except Exception as e: logging.debug("Error setting UEFI default for aarch64", exc_info=True) logging.warning("Couldn't configure UEFI: %s", e) logging.warning("Your aarch64 VM may not boot successfully.") # Check usability of SMM feature if guest.features.smm: if not guest.os.is_x86(): fail(_("SMM feature is valid only for x86 architecture.")) if guest.os.machine is None: guest.os.machine = "q35" elif not guest.os.is_q35(): fail(_("SMM feature is valid only for q35 machine type")) # Various little validations about option collisions. Need to do # this after setting guest.installer at least check_option_collisions(options, guest) show_warnings(options, guest) return guest ########################### # Install process helpers # ########################### def start_install(guest, options): if options.wait is not None: wait_on_install = True wait_time = options.wait * 60 if "VIRTINST_TEST_SUITE" in os.environ and wait_time: # Convert wait time to 1 second, for the test suite wait_time = 1 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: conscb = cli.get_console_cb(guest) if not conscb: # 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 meter = cli.get_meter() logging.debug("Guest.has_install_phase: %s", guest.installer.has_install_phase()) # we've got everything -- try to start the install print_stdout(_("\nStarting install...")) try: start_time = time.time() # Do first install phase guest.start_install(meter=meter, doboot=not options.noreboot, transient=options.transient) cli.connect_console(guest, conscb, wait_on_console) check_domain(guest, conscb, options.transient, wait_on_install, wait_time, start_time) print_stdout(_("Domain creation completed.")) if not options.transient and not guest.domain.isActive(): if options.noreboot or not guest.installer.has_install_phase(): print_stdout( _("You can restart your domain by running:\n %s") % cli.virsh_start_cmd(guest)) else: print_stdout(_("Restarting guest.")) guest.domain.create() cli.connect_console(guest, conscb, True) except KeyboardInterrupt: logging.debug("", exc_info=True) print_stderr(_("Domain install interrupted.")) raise except Exception as e: fail(e, do_exit=False) if guest.domain is None: guest.cleanup_created_disks(meter) cli.install_fail(guest) def check_domain(guest, conscb, transient, wait_for_install, wait_time, start_time): """ Make sure domain ends up in expected state, and wait if for install to complete if requested """ def check_domain_inactive(): try: dominfo = guest.domain.info() state = dominfo[0] logging.debug("Domain state after install: %s", state) if state == libvirt.VIR_DOMAIN_CRASHED: fail(_("Domain has crashed.")) return not guest.domain.isActive() except libvirt.libvirtError as e: if transient and e.get_error_code() == libvirt.VIR_ERR_NO_DOMAIN: logging.debug("transient VM shutdown and disappeared.") return True raise 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 time.sleep(2) if check_domain_inactive(): return # If we reach here, the VM still appears to be running. if not wait_for_install or wait_time == 0: # User either: # used --noautoconsole # used --wait 0 # killed console and guest is still running if not guest.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) 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}) # Wait loop while True: if not guest.domain.isActive(): print_stdout(_("Domain has shutdown. Continuing.")) break time_elapsed = (time.time() - start_time) if not wait_forever and time_elapsed >= wait_time: print_stdout( _("Installation has exceeded specified time limit. " "Exiting application.")) sys.exit(1) time.sleep(1) if not guest.domain.isActive(): print_stdout(_("Domain has shutdown. Continuing.")) break ######################## # XML printing helpers # ######################## def xml_to_print(guest, xmlonly, dry): start_xml, final_xml = guest.start_install(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=_("Installation source (eg, nfs:host:/path, " "http://host/path, ftp://host/path)")) 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=_("Treat the CD-ROM media as a Live CD")) 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")) # Takes a URL and just prints to stdout the detected distro name insg.add_argument("--test-media-detection", help=argparse.SUPPRESS) insg.add_argument("--os-type", dest="distro_type", help=argparse.SUPPRESS) insg.add_argument("--os-variant", dest="distro_variant", help=_("The OS variant being installed guests, " "e.g. 'fedora18', 'rhel6', 'winxp', etc.")) cli.add_boot_options(insg) insg.add_argument("--init", 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")) virg.add_argument("-v", "--hvm", action="store_true", dest="fullvirt", help=_("This guest should be a fully virtualized guest")) virg.add_argument("-p", "--paravirt", action="store_true", help=_("This guest should be a paravirtualized guest")) virg.add_argument("--container", action="store_true", default=False, help=_("This guest should be a container guest")) virg.add_argument("--virt-type", dest="hv_type", default="", help=_("Hypervisor name to use (kvm, qemu, xen, ...)")) virg.add_argument("--accelerate", action="store_true", default=False, help=argparse.SUPPRESS) virg.add_argument("--arch", help=_("The CPU architecture to simulate")) virg.add_argument("--machine", help=_("The machine type to emulate")) 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", dest="autostart", default=False, help=_("Have domain autostart on host boot up.")) misc.add_argument("--transient", action="store_true", dest="transient", default=False, help=_("Create a transient domain.")) misc.add_argument("--wait", type=int, dest="wait", 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) return parser.parse_args() ################### # main() handling # ################### def main(conn=None): cli.earlyLogging() options = parse_args() convert_old_printxml(options) # Default setup options options.quiet = (options.xmlonly or options.test_media_detection or options.quiet) cli.setupLogging("virt-install", options.debug, options.quiet) check_cdrom_option_error(options) cli.convert_old_force(options) cli.parse_check(options.check) cli.set_prompt(options.prompt) if cli.check_option_introspection(options): return 0 if conn is None: conn = cli.getConnection(options.connect) if options.test_media_detection: do_test_media_detection(conn, options.test_media_detection) return 0 guest = build_guest_instance(conn, options) if options.xmlonly or options.dry: xml = xml_to_print(guest, options.xmlonly, options.dry) if xml: print_stdout(xml, do_force=True) else: start_install(guest, options) return 0 if __name__ == "__main__": try: sys.exit(main()) except SystemExit as sys_e: sys.exit(sys_e.code) except KeyboardInterrupt: logging.debug("", exc_info=True) print_stderr(_("Installation aborted at user request")) except Exception as main_e: fail(main_e) virt-manager-1.5.1/virt-manager.spec.in0000664000175100017510000001367613245573052021474 0ustar crobinsocrobinso00000000000000# -*- rpm-spec -*- %global with_guestfs 0 %global stable_defaults 0 %global askpass_package "openssh-askpass" %global qemu_user "qemu" %global libvirt_packages "libvirt-daemon-kvm,libvirt-daemon-config-network" %global kvm_packages "" %global preferred_distros "fedora,rhel" %global default_hvs "qemu,xen,lxc" %if 0%{?rhel} %global preferred_distros "rhel,fedora" %global stable_defaults 1 %endif # End local config Name: virt-manager Version: @VERSION@ Release: 1%{?dist} %global verrel %{version}-%{release} Summary: Desktop tool for managing virtual machines via libvirt Group: Applications/Emulators License: GPLv2+ BuildArch: noarch URL: http://virt-manager.org/ Source0: http://virt-manager.org/download/sources/%{name}/%{name}-%{version}.tar.gz Requires: virt-manager-common = %{verrel} Requires: pygobject3 Requires: gtk3 Requires: libvirt-glib >= 0.0.9 Requires: dconf Requires: dbus-x11 # The vte291 package is actually the latest vte with API version 2.91, while # the vte3 package is effectively a compat package with API version 2.90. # virt-manager works fine with either, so pull the latest bits so there's # no ambiguity. Requires: vte291 # For console widget Requires: gtk-vnc2 Requires: spice-gtk3 %if 0%{?rhel} == 7 Requires: gnome-icon-theme %endif BuildRequires: intltool BuildRequires: /usr/bin/pod2man # For python, and python2 rpm macros BuildRequires: python2-devel %description Virtual Machine Manager provides a graphical tool for administering virtual machines for KVM, Xen, and LXC. Start, stop, add or remove virtual devices, connect to a graphical or serial console, and see resource usage statistics for existing VMs on local or remote machines. Uses libvirt as the backend management API. %package common Summary: Common files used by the different Virtual Machine Manager interfaces Group: Applications/Emulators # This version not strictly required: virt-manager should work with older, # however varying amounts of functionality will not be enabled. Requires: libvirt-python >= 0.7.0 Requires: libxml2-python Requires: python-requests Requires: python-ipaddr Requires: libosinfo >= 0.2.10 # Required for gobject-introspection infrastructure Requires: pygobject3-base # Required for pulling files from iso media with isoinfo Requires: genisoimage %description common Common files used by the different virt-manager interfaces, as well as virt-install related tools. %package -n virt-install Summary: Utilities for installing virtual machines Requires: virt-manager-common = %{verrel} # For 'virsh console' Requires: libvirt-client Provides: virt-install Provides: virt-clone Provides: virt-convert Provides: virt-xml Obsoletes: python-virtinst %description -n virt-install Package includes several command line utilities, including virt-install (build and install new VMs) and virt-clone (clone an existing virtual machine). %prep %setup -q %build %if %{qemu_user} %global _qemu_user --qemu-user=%{qemu_user} %endif %if %{kvm_packages} %global _kvm_packages --kvm-package-names=%{kvm_packages} %endif %if %{preferred_distros} %global _preferred_distros --preferred-distros=%{preferred_distros} %endif %if %{libvirt_packages} %global _libvirt_packages --libvirt-package-names=%{libvirt_packages} %endif %if %{askpass_package} %global _askpass_package --askpass-package-names=%{askpass_package} %endif %if %{stable_defaults} %global _stable_defaults --stable-defaults %endif %if %{default_hvs} %global _default_hvs --default-hvs %{default_hvs} %endif python setup.py configure \ %{?_qemu_user} \ %{?_kvm_packages} \ %{?_libvirt_packages} \ %{?_askpass_package} \ %{?_preferred_distros} \ %{?_stable_defaults} \ %{?_default_hvs} %install python setup.py \ --no-update-icon-cache --no-compile-schemas \ install -O1 --root=%{buildroot} %find_lang %{name} # Replace '#!/usr/bin/env python2' with '#!/usr/bin/python2' # The format is ideal for upstream, but not a distro. See: # https://fedoraproject.org/wiki/Features/SystemPythonExecutablesUseSystemPython for f in $(find %{buildroot} -type f -executable -print); do sed -i "1 s|^#!/usr/bin/env python2|#!%{__python2}|" $f || : done # The conversion script was only added to virt-manager after several # Fedora cycles of using gsettings. Installing it now could convert old data # and wipe out recent settings. rm %{buildroot}%{_datadir}/GConf/gsettings/org.virt-manager.virt-manager.convert %post /bin/touch --no-create %{_datadir}/icons/hicolor &>/dev/null || : /usr/bin/update-desktop-database &> /dev/null || : %postun if [ $1 -eq 0 ] ; then /bin/touch --no-create %{_datadir}/icons/hicolor &>/dev/null /usr/bin/gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : /usr/bin/glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || : fi /usr/bin/update-desktop-database &> /dev/null || : %posttrans /usr/bin/gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : /usr/bin/glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || : %files %doc README.md COPYING NEWS.md %{_bindir}/%{name} %{_mandir}/man1/%{name}.1* %{_datadir}/%{name}/ui/*.ui %{_datadir}/%{name}/virt-manager %{_datadir}/%{name}/virtManager %{_datadir}/%{name}/icons %{_datadir}/icons/hicolor/*/apps/* %{_datadir}/appdata/%{name}.appdata.xml %{_datadir}/applications/%{name}.desktop %{_datadir}/glib-2.0/schemas/org.virt-manager.virt-manager.gschema.xml %files common -f %{name}.lang %dir %{_datadir}/%{name} %{_datadir}/%{name}/virtcli %{_datadir}/%{name}/virtconv %{_datadir}/%{name}/virtinst %files -n virt-install %{_mandir}/man1/virt-install.1* %{_mandir}/man1/virt-clone.1* %{_mandir}/man1/virt-convert.1* %{_mandir}/man1/virt-xml.1* %{_datadir}/%{name}/virt-install %{_datadir}/%{name}/virt-clone %{_datadir}/%{name}/virt-convert %{_datadir}/%{name}/virt-xml %{_bindir}/virt-install %{_bindir}/virt-clone %{_bindir}/virt-convert %{_bindir}/virt-xml virt-manager-1.5.1/virt-convert0000775000175100017510000001071013245573052020171 0ustar crobinsocrobinso00000000000000#!/usr/bin/env python2 # # Copyright 2008, 2013, 2014 Red Hat, Inc. # Joey Boggs # Cole Robinson # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import sys from virtinst import cli from virtinst.cli import fail, print_stderr, print_stdout from virtconv import VirtConverter # Example appliances: # # OVF/OVA: # http://virtualboxes.org/tag/ova/ # VMX, but they are all multipart which is current unsupported # http://www.thoughtpolice.co.uk/vmware/ # Minix VMX: # http://download.minix3.org/iso/minix3_1_2a_vmware.zip # Simple live test with # ./virt-convert --connect test:///default tests/virtconv-files/vmx_input/test-nodisks.vmx ##################### # Argument handling # ##################### def parse_args(): desc = _( "Convert an OVF or VMX appliance to native libvirt XML, and run " "the guest.\nThe VM contents are not altered. Disk images are " "copied to the hypervisor\ndefault storage location.\n\n" "Examples:\n" " virt-convert fedora18.ova\n" " virt-convert centos6.zip --disk-format qcow2" ) parser = cli.setupParser( "%(prog)s inputconfig [options]", desc) parser.add_argument("input", metavar="inputconfig", nargs=1, help=_("Conversion input. Can be a ovf/vmx file, a directory " "containing a config and disk images, or a zip/ova/7z/etc " "archive.")) cli.add_connect_option(parser) cong = parser.add_argument_group("Conversion Options") cong.add_argument("-i", "--input-format", help=_("Force the input format. 'vmx' or 'ovf'")) cong.add_argument("-D", "--disk-format", default='raw', help=_("Output disk format. default is 'raw'. " "Disable conversion with 'none'")) cong.add_argument("--destination", default=None, help=_("Destination directory the disk images should be " "converted/copied to. Defaults to the default " "libvirt directory.")) misc = parser.add_argument_group("Miscellaneous Options") cli.add_misc_options(misc, dryrun=True, printxml=True, noautoconsole=True) options = parser.parse_args() options.input = options.input[0] return options ####################### # Functional handlers # ####################### def main(conn=None): cli.earlyLogging() options = parse_args() cli.setupLogging("virt-convert", options.debug, options.quiet) if conn is None: conn = cli.getConnection(options.connect) if options.xmlonly: options.dry = True options.quiet = True options.autoconsole = False print_cb = print_stdout if options.quiet: print_cb = None converter = VirtConverter(conn, options.input, input_name=options.input_format, print_cb=print_cb) try: converter.convert_disks(options.disk_format or "none", destdir=options.destination, dry=options.dry) guest = converter.get_guest() conscb = None if options.autoconsole: conscb = cli.get_console_cb(guest) or None if options.xmlonly: print_stdout(guest.start_install(return_xml=True)[1], do_force=True) elif not options.dry: print_stdout(_("Creating guest '%s'.") % guest.name) guest.start_install() cli.connect_console(guest, conscb, True) except Exception: converter.cleanup() raise return 0 if __name__ == "__main__": try: sys.exit(main()) except SystemExit as sys_e: sys.exit(sys_e.code) except KeyboardInterrupt: print_stderr(_("Aborted at user request")) except Exception as main_e: fail(main_e) virt-manager-1.5.1/virt-manager0000775000175100017510000002421113245573052020124 0ustar crobinsocrobinso00000000000000#!/usr/bin/env python2 # # Copyright (C) 2006, 2014 Red Hat, Inc. # Copyright (C) 2006 Daniel P. Berrange # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. # from __future__ import print_function import argparse import logging import os import signal import sys import traceback import gi gi.require_version('LibvirtGLib', '1.0') from gi.repository import LibvirtGLib from virtinst import util as util from virtinst import cli as virtinstcli from virtcli import CLIConfig # This is massively heavy handed, but I can't figure out any way to shut # up the slew of gtk deprecation warnings that clog up our very useful # stdout --debug output. Of course we could drop use of deprecated APIs, # but it's a serious quantity of churn import warnings # pylint: disable=wrong-import-order warnings.simplefilter("ignore") try: gi.check_version("3.14.0") except (ValueError, AttributeError): print("pygobject3 3.14.0 or later is required.") sys.exit(1) def _show_startup_error(msg, details): logging.debug("Error starting virt-manager: %s\n%s", msg, details, exc_info=True) from virtManager.error import vmmErrorDialog err = vmmErrorDialog() title = _("Error starting Virtual Machine Manager") err.show_err(title + ": " + msg, details=details, title=title, modal=True, debug=False) def _import_gtk(leftovers): # The never ending fork+gsettings problems now require us to # import Gtk _after_ the fork. This creates a funny race, since we # need to parse the command line arguments to know if we need to # fork, but need to import Gtk before cli processing so it can # handle --g-fatal-args. We strip out our flags first and pass the # left overs to gtk origargv = sys.argv try: sys.argv = origargv[:1] + leftovers[:] gi.require_version('Gtk', '3.0') from gi.repository import Gtk leftovers = sys.argv[1:] if Gtk.check_version(3, 14, 0): print("gtk3 3.14.0 or later is required.") sys.exit(1) # This will error if Gtk wasn't correctly initialized Gtk.init() globals()["Gtk"] = Gtk import virtManager.config ignore = virtManager.config except Exception as e: # Don't just let the exception raise here. abrt reports bugs # when users mess up su/sudo and DISPLAY isn't set. Printing # it avoids the issue display = os.environ.get("DISPLAY", "") msg = str(e) if display: msg += ": Could not open display: %s" % display logging.debug("".join(traceback.format_exc())) print(msg) sys.exit(1) finally: sys.argv = origargv return leftovers def drop_tty(): # We fork and setsid so that we drop the controlling # tty. This prevents libvirt's SSH tunnels from prompting # for user input if SSH keys/agent aren't configured. if os.fork() != 0: os._exit(0) # pylint: disable=protected-access os.setsid() def drop_stdio(): # This is part of the fork process described in drop_tty() for fd in range(0, 2): try: os.close(fd) except OSError: pass os.open(os.devnull, os.O_RDWR) os.dup2(0, 1) os.dup2(0, 2) def parse_commandline(): epilog = ("Also accepts standard GTK arguments like --g-fatal-warnings") parser = argparse.ArgumentParser(usage="virt-manager [options]", epilog=epilog) parser.add_argument('--version', action='version', version=CLIConfig.version) parser.set_defaults(domain=None) # Trace every libvirt API call to debug output parser.add_argument("--trace-libvirt", help=argparse.SUPPRESS, action="store_true") # Don't load any connections on startup to test first run # PackageKit integration parser.add_argument("--test-first-run", help=argparse.SUPPRESS, action="store_true") # Force use of old style libvirt polling APIs parser.add_argument("--test-old-poll", help=argparse.SUPPRESS, action="store_true") # Force disable use of libvirt object events parser.add_argument("--test-no-events", help=argparse.SUPPRESS, action="store_true") parser.add_argument("-c", "--connect", dest="uri", help="Connect to hypervisor at URI", metavar="URI") parser.add_argument("--debug", action="store_true", help="Print debug output to stdout (implies --no-fork)", default=False) parser.add_argument("--no-fork", action="store_true", help="Don't fork into background on startup") parser.add_argument("--no-conn-autostart", action="store_true", dest="skip_autostart", help="Do not autostart connections") parser.add_argument("--spice-disable-auto-usbredir", action="store_true", dest="usbredir", help="Disable Auto USB redirection support") parser.add_argument("--show-domain-creator", action="store_true", help="Show 'New VM' wizard") parser.add_argument("--show-domain-editor", metavar="NAME|ID|UUID", help="Show domain details window") parser.add_argument("--show-domain-performance", metavar="NAME|ID|UUID", help="Show domain performance window") parser.add_argument("--show-domain-console", metavar="NAME|ID|UUID", help="Show domain graphical console window") parser.add_argument("--show-host-summary", action="store_true", help="Show connection details window") return parser.parse_known_args() def main(): (options, leftovers) = parse_commandline() virtinstcli.setupLogging("virt-manager", options.debug, False, False) import virtManager logging.debug("virt-manager version: %s", CLIConfig.version) logging.debug("virtManager import: %s", str(virtManager)) if options.trace_libvirt: logging.debug("Libvirt tracing requested") import virtManager.module_trace import libvirt virtManager.module_trace.wrap_module(libvirt, regex=None) # Now we've got basic environment up & running we can fork do_drop_stdio = False if not options.no_fork and not options.debug: drop_tty() do_drop_stdio = True # Ignore SIGHUP, otherwise a serial console closing drops the whole app signal.signal(signal.SIGHUP, signal.SIG_IGN) leftovers = _import_gtk(leftovers) Gtk = globals()["Gtk"] # Do this after the Gtk import so the user has a chance of seeing any error if do_drop_stdio: drop_stdio() if leftovers: raise RuntimeError("Unhandled command line options '%s'" % leftovers) logging.debug("PyGObject version: %d.%d.%d", gi.version_info[0], gi.version_info[1], gi.version_info[2]) logging.debug("GTK version: %d.%d.%d", Gtk.get_major_version(), Gtk.get_minor_version(), Gtk.get_micro_version()) config = virtManager.config.vmmConfig( "virt-manager", CLIConfig, options.test_first_run) if not util.local_libvirt_version() >= 6000: # We need this version for threaded virConnect access _show_startup_error( _("virt-manager requires libvirt 0.6.0 or later."), "") return if options.usbredir and config.get_auto_redirection(): config.cli_usbredir = False # Add our icon dir to icon theme icon_theme = Gtk.IconTheme.get_default() icon_theme.prepend_search_path(CLIConfig.icon_dir) from virtManager.engine import vmmEngine Gtk.Window.set_default_icon_name("virt-manager") import virtManager.connection virtManager.connection.FORCE_DISABLE_EVENTS = bool(options.test_no_events) import virtinst.pollhelpers virtinst.pollhelpers.FORCE_OLD_POLL = bool(options.test_old_poll) show_window = None domain = None if options.show_domain_creator: show_window = vmmEngine.CLI_SHOW_DOMAIN_CREATOR elif options.show_host_summary: show_window = vmmEngine.CLI_SHOW_HOST_SUMMARY elif options.show_domain_editor: show_window = vmmEngine.CLI_SHOW_DOMAIN_EDITOR domain = options.show_domain_editor elif options.show_domain_performance: show_window = vmmEngine.CLI_SHOW_DOMAIN_PERFORMANCE domain = options.show_domain_performance elif options.show_domain_console: show_window = vmmEngine.CLI_SHOW_DOMAIN_CONSOLE domain = options.show_domain_console if show_window and options.uri is None: raise RuntimeError("can't use --show-* options without --connect") if show_window: options.skip_autostart = True # Hook libvirt events into glib main loop LibvirtGLib.init(None) LibvirtGLib.event_register() engine = vmmEngine() # Actually exit when we receive ctrl-c from gi.repository import GLib def _sigint_handler(user_data): ignore = user_data logging.debug("Received KeyboardInterrupt. Exiting application.") engine.exit_app(None) GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT, _sigint_handler, None) engine.start(options.uri, show_window, domain, options.skip_autostart) if __name__ == "__main__": try: main() except KeyboardInterrupt: logging.debug("Received KeyboardInterrupt. Exiting application.") except SystemExit: raise except Exception as run_e: if "Gtk" not in globals(): raise _show_startup_error(str(run_e), "".join(traceback.format_exc())) virt-manager-1.5.1/MANIFEST.in0000664000175100017510000000075713245061760017347 0ustar crobinsocrobinso00000000000000# to be included/excluded from the tarball produced by sdist include COPYING HACKING.md INSTALL.md NEWS.md README.md include MANIFEST.in include setup.py include virt-* recursive-include data * exclude data/gschemas.compiled recursive-include man * recursive-include po * recursive-include tests * exclude tests/test_urls_manual.ini recursive-include ui * recursive-include virtManager * recursive-include virtcli * recursive-include virtconv * recursive-include virtinst * global-exclude *.pyc virt-manager-1.5.1/PKG-INFO0000664000175100017510000000034213245574323016700 0ustar crobinsocrobinso00000000000000Metadata-Version: 1.0 Name: virt-manager Version: 1.5.1 Summary: UNKNOWN Home-page: http://virt-manager.org Author: Cole Robinson Author-email: virt-tools-list@redhat.com License: GPLv2+ Description: UNKNOWN Platform: UNKNOWN virt-manager-1.5.1/HACKING.md0000664000175100017510000000446213245573052017176 0ustar crobinsocrobinso00000000000000# HACKING The following commands will be useful for anyone writing patches: ```sh python setup.py test # Run local unit test suite python setup.py pylint # Run a pylint script against the codebase ``` Any patches shouldn't change the output of 'test' or 'pylint'. The 'pylint' requires `pylint` and `pycodestyle` to be installed. Our pylint script uses a blacklist rather than a whitelist approach, so it could throw some false positives or useless messages. If you think your patch exposes one of these, bring it up on the mailing list. 'test*' have a `--debug` option if you are hitting problems. For more options, use `python setup.py test --help`. One useful way to manually test virt-manager's UI is using libvirt's unit test driver. From the source directory, Launch virt-manager like: ```sh virt-manager --connect test://$PWD/tests/testdriver.xml ``` This testdriver has many fake XML definitions that can be used to see each bit of virt-manager's UI. It also enables testing the various wizards without having to alter your host virt config. Also, there's a few standalone specialty tests: ```sh python setup.py test_urls # Test fetching media from distro URLs python setup.py test_initrd_inject # Test --initrd-inject ``` We use [glade-3](https://glade.gnome.org/) for building virt-manager's UI. It is recommended you have a fairly recent version of `glade-3`. If a small UI change seems to rewrite the entire glade file, you likely have a too old (or too new :) glade version. ## Submitting patches Patches should be developed against a git checkout and **not** a source release(see [git repository](https://github.com/virt-manager/virt-manager)). Patches should be sent to the [mailing list](http://www.redhat.com/mailman/listinfo/virt-tools-list). Using git format-patch/send-email is preferred, but an attachment with format-patch output is fine too. Small patches are acceptable via github pull-request, but anything non-trivial should be sent to the mailing list. ## Translations Translations are handled at `fedora.zanata.org`. Please register for a Fedora account and request access to a translation team, as described at [Translate on Zanata](http://fedoraproject.org/wiki/L10N/Translate_on_Zanata). And contribute to [virt-manager at Zanata](https://fedora.zanata.org/project/view/virt-manager/). virt-manager-1.5.1/virtinst/0000775000175100017510000000000013245574323017466 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/virtinst/domainblkiotune.py0000664000175100017510000000225313241024270023211 0ustar crobinsocrobinso00000000000000# # Copyright 2014 Fujitsu Limited. # Chen Hanxiao # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .xmlbuilder import XMLBuilder, XMLProperty class DomainBlkiotune(XMLBuilder): """ Class for generating XML """ _XML_ROOT_NAME = "blkiotune" _XML_PROP_ORDER = ["weight", "device_path", "device_weight"] weight = XMLProperty("./weight", is_int=True) device_path = XMLProperty("./device/path") device_weight = XMLProperty("./device/weight", is_int=True) virt-manager-1.5.1/virtinst/network.py0000664000175100017510000002034613245573052021534 0ustar crobinsocrobinso00000000000000# # Copyright 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. """ Classes for building and installing libvirt XML """ import logging import libvirt from . import util from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty class _NetworkDHCPRange(XMLBuilder): _XML_ROOT_NAME = "range" start = XMLProperty("./@start") end = XMLProperty("./@end") class _NetworkDHCPHost(XMLBuilder): _XML_ROOT_NAME = "host" macaddr = XMLProperty("./@mac") name = XMLProperty("./@name") ip = XMLProperty("./@ip") class _NetworkIP(XMLBuilder): _XML_ROOT_NAME = "ip" family = XMLProperty("./@family") address = XMLProperty("./@address") prefix = XMLProperty("./@prefix", is_int=True) netmask = XMLProperty("./@netmask") tftp = XMLProperty("./tftp/@root") bootp_file = XMLProperty("./dhcp/bootp/@file") bootp_server = XMLProperty("./dhcp/bootp/@server") ranges = XMLChildProperty(_NetworkDHCPRange, relative_xpath="./dhcp") hosts = XMLChildProperty(_NetworkDHCPHost, relative_xpath="./dhcp") def add_range(self): r = _NetworkDHCPRange(self.conn) self.add_child(r) return r class _NetworkRoute(XMLBuilder): _XML_ROOT_NAME = "route" family = XMLProperty("./@family") address = XMLProperty("./@address") prefix = XMLProperty("./@prefix", is_int=True) gateway = XMLProperty("./@gateway") netmask = XMLProperty("./@netmask") class _NetworkForwardPf(XMLBuilder): _XML_ROOT_NAME = "pf" dev = XMLProperty("./@dev") class _NetworkForwardAddress(XMLBuilder): _XML_ROOT_NAME = "address" type = XMLProperty("./@type") domain = XMLProperty("./@domain", is_int=True) bus = XMLProperty("./@bus", is_int=True) slot = XMLProperty("./@slot", is_int=True) function = XMLProperty("./@function", is_int=True) class _NetworkForward(XMLBuilder): _XML_ROOT_NAME = "forward" mode = XMLProperty("./@mode") dev = XMLProperty("./@dev") managed = XMLProperty("./@managed") pf = XMLChildProperty(_NetworkForwardPf) vfs = XMLChildProperty(_NetworkForwardAddress) def add_pf(self): r = _NetworkForwardPf(self.conn) self.add_child(r) return r def pretty_desc(self): return Network.pretty_forward_desc(self.mode, self.dev) class _NetworkBandwidth(XMLBuilder): _XML_ROOT_NAME = "bandwidth" inbound_average = XMLProperty("./inbound/@average") inbound_peak = XMLProperty("./inbound/@peak") inbound_burst = XMLProperty("./inbound/@burst") inbound_floor = XMLProperty("./inbound/@floor") outbound_average = XMLProperty("./outbound/@average") outbound_peak = XMLProperty("./outbound/@peak") outbound_burst = XMLProperty("./outbound/@burst") def is_inbound(self): return bool(self.inbound_average or self.inbound_peak or self.inbound_burst or self.inbound_floor) def is_outbound(self): return bool(self.outbound_average or self.outbound_peak or self.outbound_burst) def pretty_desc(self, inbound=True, outbound=True): items_in = [(self.inbound_average, _("Average"), "KiB/s"), (self.inbound_peak, _("Peak"), "KiB"), (self.inbound_burst, _("Burst"), "KiB/s"), (self.inbound_floor, _("Floor"), "KiB/s")] items_out = [(self.outbound_average, _("Average"), "KiB/s"), (self.outbound_peak, _("Peak"), "KiB"), (self.outbound_burst, _("Burst"), "KiB/s")] def stringify_items(items): return ", ".join(["%s: %s %s" % (desc, val, unit) for val, desc, unit in items if val]) ret = "" show_name = inbound and outbound if inbound: if show_name: ret += _("Inbound: ") ret += stringify_items(items_in) if outbound: if ret: ret += "\n" if show_name: ret += _("Outbound: ") ret += stringify_items(items_out) return ret class _NetworkPortgroup(XMLBuilder): _XML_ROOT_NAME = "portgroup" name = XMLProperty("./@name") default = XMLProperty("./@default", is_yesno=True) class Network(XMLBuilder): """ Top level class for object XML """ @staticmethod def pretty_forward_desc(mode, dev): if mode or dev: if not mode or mode == "nat": if dev: desc = _("NAT to %s") % dev else: desc = _("NAT") elif mode == "route": if dev: desc = _("Route to %s") % dev else: desc = _("Routed network") else: if dev: desc = (_("%(mode)s to %(device)s") % {"mode": mode, "device": dev}) else: desc = _("%s network") % mode.capitalize() else: desc = _("Isolated network, internal and host routing only") return desc ################### # Helper routines # ################### def can_pxe(self): forward = self.forward.mode if forward and forward != "nat": return True for ip in self.ips: if ip.bootp_file: return True return False ###################### # Validation helpers # ###################### def _validate_name(self, name): util.validate_name(_("Network"), name) try: self.conn.networkLookupByName(name) except libvirt.libvirtError: return raise ValueError(_("Name '%s' already in use by another network." % name)) ################## # XML properties # ################## _XML_ROOT_NAME = "network" _XML_PROP_ORDER = ["ipv6", "name", "uuid", "forward", "virtualport_type", "bridge", "stp", "delay", "domain_name", "macaddr", "ips", "routes", "bandwidth"] ipv6 = XMLProperty("./@ipv6", is_yesno=True) name = XMLProperty("./name", validate_cb=_validate_name) uuid = XMLProperty("./uuid") virtualport_type = XMLProperty("./virtualport/@type") # Not entirely correct, there can be multiple routes forward = XMLChildProperty(_NetworkForward, is_single=True) domain_name = XMLProperty("./domain/@name") bridge = XMLProperty("./bridge/@name") stp = XMLProperty("./bridge/@stp", is_onoff=True) delay = XMLProperty("./bridge/@delay", is_int=True) macaddr = XMLProperty("./mac/@address") portgroups = XMLChildProperty(_NetworkPortgroup) ips = XMLChildProperty(_NetworkIP) routes = XMLChildProperty(_NetworkRoute) bandwidth = XMLChildProperty(_NetworkBandwidth, is_single=True) def add_ip(self): ip = _NetworkIP(self.conn) self.add_child(ip) return ip def add_route(self): route = _NetworkRoute(self.conn) self.add_child(route) return route ################## # build routines # ################## def install(self, start=True, autostart=True): xml = self.get_xml_config() logging.debug("Creating virtual network '%s' with xml:\n%s", self.name, xml) net = self.conn.networkDefineXML(xml) try: if start: net.create() if autostart: net.setAutostart(autostart) except Exception: net.undefine() raise return net virt-manager-1.5.1/virtinst/idmap.py0000664000175100017510000000262313241024270021120 0ustar crobinsocrobinso00000000000000# # Copyright 2014 Fujitsu Limited. # Chen Hanxiao # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .xmlbuilder import XMLBuilder, XMLProperty class IdMap(XMLBuilder): """ Class for generating user namespace related XML """ _XML_ROOT_NAME = "idmap" _XML_PROP_ORDER = ["uid_start", "uid_target", "uid_count", "gid_start", "gid_target", "gid_count"] uid_start = XMLProperty("./uid/@start", is_int=True) uid_target = XMLProperty("./uid/@target", is_int=True) uid_count = XMLProperty("./uid/@count", is_int=True) gid_start = XMLProperty("./gid/@start", is_int=True) gid_target = XMLProperty("./gid/@target", is_int=True) gid_count = XMLProperty("./gid/@count", is_int=True) virt-manager-1.5.1/virtinst/seclabel.py0000664000175100017510000000630713241024270021603 0ustar crobinsocrobinso00000000000000# # Copyright 2010, 2012-2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .xmlbuilder import XMLBuilder, XMLProperty class Seclabel(XMLBuilder): """ Class for generating XML """ TYPE_DYNAMIC = "dynamic" TYPE_STATIC = "static" TYPE_DEFAULT = "default" TYPES = [TYPE_DYNAMIC, TYPE_STATIC] MODEL_DEFAULT = "default" MODEL_TEST = "testSecurity" MODEL_SELINUX = "selinux" MODEL_DAC = "dac" MODEL_NONE = "none" MODELS = [MODEL_SELINUX, MODEL_DAC, MODEL_NONE] _XML_ROOT_NAME = "seclabel" _XML_PROP_ORDER = ["type", "model", "relabel", "label", "imagelabel"] def _guess_secmodel(self): # We always want the testSecurity model when running tests if (self.MODEL_TEST in [x.model for x in self.conn.caps.host.secmodels]): return self.MODEL_TEST label = self.label imagelabel = self.imagelabel if not label and not imagelabel: for model in self.MODELS: if model in [x.model for x in self.conn.caps.host.secmodels]: return model raise RuntimeError("No supported model found in capabilities") lab_len = imglab_len = None if label: lab_len = min(3, len(label.split(':'))) if imagelabel: imglab_len = min(3, len(imagelabel.split(':'))) if lab_len and imglab_len and lab_len != imglab_len: raise ValueError(_("Label and Imagelabel are incompatible")) lab_len = lab_len or imglab_len if lab_len == 3: return self.MODEL_SELINUX elif lab_len == 2: return self.MODEL_DAC else: raise ValueError(_("Unknown model type for label '%s'") % self.label) def _get_default_model(self): if self.type is None or self.type == self.TYPE_DEFAULT: return None return self._guess_secmodel() model = XMLProperty("./@model", default_cb=_get_default_model, default_name=MODEL_DEFAULT) def _get_default_type(self): if self.model is None or self.model == self.MODEL_DEFAULT: return None return self.TYPE_DYNAMIC type = XMLProperty("./@type", default_cb=_get_default_type, default_name=TYPE_DEFAULT) label = XMLProperty("./label") imagelabel = XMLProperty("./imagelabel") baselabel = XMLProperty("./baselabel") relabel = XMLProperty("./@relabel", is_yesno=True) virt-manager-1.5.1/virtinst/kernelupload.py0000664000175100017510000001115513245061760022524 0ustar crobinsocrobinso00000000000000# # Copyright 2006-2009, 2013, 2014 Red Hat, Inc. # Daniel P. Berrange # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import logging import os from . import util from .devicedisk import VirtualDisk from .storage import StoragePool, StorageVolume def _build_pool(conn, meter, path): """ Helper function for building a pool on demand. Used for building a scratchdir pool for volume upload """ pool = StoragePool.lookup_pool_by_path(conn, path) if pool: logging.debug("Existing pool '%s' found for %s", pool.name(), path) pool.refresh(0) return pool name = StoragePool.find_free_name(conn, "boot-scratch") logging.debug("Building storage pool: path=%s name=%s", path, name) poolbuild = StoragePool(conn) poolbuild.type = poolbuild.TYPE_DIR poolbuild.name = name poolbuild.target_path = path # Explicitly don't build? since if we are creating this directory # we probably don't have correct perms ret = poolbuild.install(meter=meter, create=True, build=False, autostart=True) return ret def _upload_file(conn, meter, destpool, src): """ Helper for uploading a file to a pool, via libvirt. Used for kernel/initrd upload when we can't access the system scratchdir """ # Build stream object stream = conn.newStream(0) def safe_send(data): while True: ret = stream.send(data) if ret == 0 or ret == len(data): break data = data[ret:] meter = util.ensure_meter(meter) # Build placeholder volume size = os.path.getsize(src) basename = os.path.basename(src) name = StorageVolume.find_free_name(destpool, basename) if name != basename: logging.debug("Generated non-colliding volume name %s", name) vol_install = VirtualDisk.build_vol_install(conn, name, destpool, (float(size) / 1024.0 / 1024.0 / 1024.0), True) disk = VirtualDisk(conn) disk.set_vol_install(vol_install) disk.validate() disk.setup(meter=meter) vol = disk.get_vol_object() if not vol: raise RuntimeError(_("Failed to lookup scratch media volume")) try: # Register upload offset = 0 length = size flags = 0 vol.upload(stream, offset, length, flags) # Open source file fileobj = open(src, "r") # Start transfer total = 0 meter.start(size=size, text=_("Transferring %s") % os.path.basename(src)) while True: # blocksize = (1024 ** 2) blocksize = 1024 data = fileobj.read(blocksize) if not data: break safe_send(data) total += len(data) meter.update(total) # Cleanup stream.finish() meter.end(size) except Exception: if vol: vol.delete(0) raise return vol def upload_kernel_initrd(conn, scratchdir, system_scratchdir, meter, kernel, initrd): """ Upload kernel/initrd media to remote connection if necessary """ tmpvols = [] if (not conn.is_remote() and (conn.is_session_uri() or scratchdir == system_scratchdir)): # We have access to system scratchdir, don't jump through hoops logging.debug("Have access to preferred scratchdir so" " nothing to upload") return kernel, initrd, tmpvols if not conn.support_remote_url_install(): logging.debug("Media upload not supported") return kernel, initrd, tmpvols # Build pool logging.debug("Uploading kernel/initrd media") pool = _build_pool(conn, meter, system_scratchdir) kvol = _upload_file(conn, meter, pool, kernel) newkernel = kvol.path() tmpvols.append(kvol) ivol = _upload_file(conn, meter, pool, initrd) newinitrd = ivol.path() tmpvols.append(ivol) return newkernel, newinitrd, tmpvols virt-manager-1.5.1/virtinst/uri.py0000664000175100017510000001750013245573052020640 0ustar crobinsocrobinso00000000000000# # Copyright 2014 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. # import logging import re import urllib from .cli import parse_optstr_tuples def sanitize_xml_for_test_define(xml): import difflib orig = xml xml = re.sub("arch=\".*\"", "arch=\"i686\"", xml) xml = re.sub("domain type=\".*\"", "domain type=\"test\"", xml) xml = re.sub("machine type=\".*\"", "", xml) xml = re.sub(">exe<", ">hvm<", xml) xml = re.sub(">linux<", ">xen<", xml) diff = "\n".join(difflib.unified_diff(orig.split("\n"), xml.split("\n"))) if diff: logging.debug("virtinst test sanitizing diff\n:%s", diff) return xml class URI(object): """ Parse an arbitrary URI into its individual parts """ def __init__(self, uri): self.uri = uri unquoted_uri = urllib.unquote(uri) (self.scheme, self.username, self.hostname, self.path, self.query, self.fragment) = self._split(unquoted_uri) self.transport = '' if "+" in self.scheme: self.scheme, self.transport = self.scheme.rsplit("+", 1) self.port = '' self.is_ipv6 = False if self.hostname.startswith("[") and "]" in self.hostname: if "]:" in self.hostname: self.hostname, self.port = self.hostname.rsplit(":", 1) self.hostname = "".join(self.hostname[1:].split("]", 1)) self.is_ipv6 = True elif ":" in self.hostname: self.hostname, self.port = self.hostname.split(":", 1) self.host_is_ipv4_string = bool(re.match("^[0-9.]+$", self.hostname)) ################### # Private helpers # ################### def _split(self, uri): def splitnetloc(url, start=0): for c in '/?#': # the order is important! delim = url.find(c, start) if delim >= 0: break else: delim = len(url) return url[start:delim], url[delim:] scheme = username = netloc = query = fragment = '' i = uri.find(":") if i > 0: scheme, uri = uri[:i].lower(), uri[i + 1:] if uri[:2] == '//': netloc, uri = splitnetloc(uri, 2) offset = netloc.find("@") if offset > 0: username = netloc[0:offset] netloc = netloc[offset + 1:] if '#' in uri: uri, fragment = uri.split('#', 1) if '?' in uri: uri, query = uri.split('?', 1) return scheme, username, netloc, uri, query, fragment class MagicURI(object): """ Handle magic virtinst URIs we use for the test suite and UI testing. This allows a special URI to override various features like capabilities XML, reported connection and libvirt versions, that enable testing different code paths. A magic URI has 3 parts: 1) Magic prefix __virtinst_test__ 2) Actual openable URI, usually a test:/// URI 3) Comma separated options The available options are: * 'predictable': Generate predictable UUIDs, MAC addresses, and temporary file names. * 'remote': Have the code consider this as a remote URI * 'session': Have the code consider this as a session URI * 'connver=%d': Override the connection (hv) version * 'libver=%d': Override the libvirt version * 'caps=%s': Points to a file with capabilities XML, that will be returned in conn.getCapabilities. Ex. files in test/capabilities-xml/ * 'domcaps=%s': Points to a file with domain capabilities XML, that will be returned in conn.getDomainCapabilities * qemu, xen, lxc or vz: Fake the specified hypervisor See tests/utils.py for example URLs """ VIRTINST_URI_MAGIC_PREFIX = "__virtinst_test__" @staticmethod def uri_is_magic(uri): return uri.startswith(MagicURI.VIRTINST_URI_MAGIC_PREFIX) def __init__(self, uri): if not self.uri_is_magic(uri): raise RuntimeError("uri=%s is not virtinst magic URI" % uri) uri = uri.replace(self.VIRTINST_URI_MAGIC_PREFIX, "") ret = uri.split(",", 1) self.open_uri = ret[0] opts = dict(parse_optstr_tuples(len(ret) > 1 and ret[1] or "")) def pop_bool(field): ret = field in opts opts.pop(field, None) return ret self.predictable = pop_bool("predictable") self.remote = pop_bool("remote") self.session = pop_bool("session") self.capsfile = opts.pop("caps", None) self.domcapsfile = opts.pop("domcaps", None) self.hv = None if pop_bool("qemu"): self.hv = "qemu" if pop_bool("lxc"): self.hv = "lxc" if pop_bool("xen"): self.hv = "xen" if pop_bool("vz"): self.hv = "vz" self.conn_version = opts.pop("connver", None) if self.conn_version: self.conn_version = int(self.conn_version) elif self.hv: self.conn_version = 10000000000 self.libvirt_version = opts.pop("libver", None) if self.libvirt_version: self.libvirt_version = int(self.libvirt_version) if opts: raise RuntimeError("Unhandled virtinst test uri options %s" % opts) ############## # Public API # ############## def make_fake_uri(self): """ If self.hv is set, we need to make a fake URI so that Connection URI handling bits have something to work with. """ if self.hv: return self.hv + "+abc:///system" return self.open_uri def overwrite_conn_functions(self, conn): """ After the connection is open, we need to stub out various functions depending on what magic bits the user specified in the URI """ # Fake capabilities if self.capsfile: capsxml = open(self.capsfile).read() conn.getCapabilities = lambda: capsxml # Fake domcapabilities. This is insufficient since output should # vary per type/arch/emulator combo, but it can be expanded later # if needed if self.domcapsfile: domcapsxml = open(self.domcapsfile).read() def fake_domcaps(emulator, arch, machine, virttype, flags=0): ignore = emulator ignore = flags ignore = machine ignore = virttype ret = domcapsxml if arch: ret = re.sub("arch>.+%s # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import logging import os import libvirt from virtcli import CLIConfig from . import util from . import support from .osdict import OSDB from .clock import Clock from .cpu import CPU from .cputune import CPUTune from .device import VirtualDevice from .deviceaudio import VirtualAudio from .devicechar import VirtualChannelDevice, VirtualConsoleDevice from .devicecontroller import VirtualController from .devicedisk import VirtualDisk from .devicegraphics import VirtualGraphics from .deviceinput import VirtualInputDevice from .devicepanic import VirtualPanicDevice from .deviceredirdev import VirtualRedirDevice from .devicerng import VirtualRNGDevice from .devicevideo import VirtualVideoDevice from .distroinstaller import DistroInstaller from .domainblkiotune import DomainBlkiotune from .domainfeatures import DomainFeatures from .domainmemorybacking import DomainMemorybacking from .domainmemorytune import DomainMemorytune from .domainnumatune import DomainNumatune from .domainresource import DomainResource from .domcapabilities import DomainCapabilities from .idmap import IdMap from .osxml import OSXML from .pm import PM from .seclabel import Seclabel from .sysinfo import SYSInfo from .xmlbuilder import XMLBuilder, XMLProperty, XMLChildProperty from .xmlnsqemu import XMLNSQemu class Guest(XMLBuilder): @staticmethod def check_vm_collision(conn, name, do_remove): """ Remove the existing VM with the same name if requested, or error if there is a collision. """ vm = None try: vm = conn.lookupByName(name) except libvirt.libvirtError: pass if vm is None: return if not do_remove: raise RuntimeError(_("Domain named %s already exists!") % name) try: logging.debug("Explicitly replacing guest '%s'", name) if vm.ID() != -1: logging.info("Destroying guest '%s'", name) vm.destroy() logging.info("Undefining guest '%s'", name) vm.undefine() except libvirt.libvirtError as e: raise RuntimeError(_("Could not remove old vm '%s': %s") % (str(e))) @staticmethod def validate_name(conn, name, check_collision, validate=True): if validate: util.validate_name(_("Guest"), name) if not check_collision: return try: conn.lookupByName(name) except Exception: return raise ValueError(_("Guest name '%s' is already in use.") % name) _XML_ROOT_NAME = "domain" _XML_PROP_ORDER = ["type", "name", "uuid", "title", "description", "hotplugmemorymax", "hotplugmemoryslots", "maxmemory", "memory", "blkiotune", "memtune", "memoryBacking", "vcpus", "curvcpus", "vcpu_placement", "cpuset", "numatune", "resource", "sysinfo", "bootloader", "os", "idmap", "features", "cpu", "clock", "on_poweroff", "on_reboot", "on_crash", "pm", "emulator", "_devices", "seclabels"] def __init__(self, *args, **kwargs): XMLBuilder.__init__(self, *args, **kwargs) self.autostart = False self.replace = False # Allow virt-manager to override the default graphics type self.default_graphics_type = CLIConfig.default_graphics self.skip_default_console = False self.skip_default_channel = False self.skip_default_sound = False self.skip_default_usbredir = False self.skip_default_graphics = False self.skip_default_rng = False self.x86_cpu_default = self.cpu.SPECIAL_MODE_HOST_MODEL_ONLY self.__os_object = None self._random_uuid = None self._install_cdrom_device = None self._defaults_are_set = False # The libvirt virDomain object we 'Create' self.domain = None # This is set via Capabilities.build_virtinst_guest self.capsinfo = None self.installer = DistroInstaller(self.conn) ###################### # Property accessors # ###################### def _validate_name(self, val): if val == self.name: return self.validate_name(self.conn, val, check_collision=not self.replace) name = XMLProperty("./name", validate_cb=_validate_name) def _set_memory(self, val): if val is None: return None if self.maxmemory is None or self.maxmemory < val: self.maxmemory = val return val memory = XMLProperty("./currentMemory", is_int=True, default_cb=lambda s: 1, set_converter=_set_memory) maxmemory = XMLProperty("./memory", is_int=True) hotplugmemorymax = XMLProperty("./maxMemory", is_int=True) hotplugmemoryslots = XMLProperty("./maxMemory/@slots", is_int=True) def _set_vcpus(self, val): if val is None: return None # Don't force set curvcpus unless already specified if self.curvcpus is not None and self.curvcpus > val: self.curvcpus = val return val vcpus = XMLProperty("./vcpu", is_int=True, set_converter=_set_vcpus, default_cb=lambda s: 1) curvcpus = XMLProperty("./vcpu/@current", is_int=True) vcpu_placement = XMLProperty("./vcpu/@placement") def _validate_cpuset(self, val): DomainNumatune.validate_cpuset(self.conn, val) cpuset = XMLProperty("./vcpu/@cpuset", validate_cb=_validate_cpuset) def _get_default_uuid(self): if self._random_uuid is None: self._random_uuid = util.generate_uuid(self.conn) return self._random_uuid uuid = XMLProperty("./uuid", default_cb=_get_default_uuid) id = XMLProperty("./@id", is_int=True) type = XMLProperty("./@type", default_cb=lambda s: "xen") bootloader = XMLProperty("./bootloader") description = XMLProperty("./description") title = XMLProperty("./title") emulator = XMLProperty("./devices/emulator") on_poweroff = XMLProperty("./on_poweroff") on_reboot = XMLProperty("./on_reboot") on_crash = XMLProperty("./on_crash") on_lockfailure = XMLProperty("./on_lockfailure") seclabels = XMLChildProperty(Seclabel) os = XMLChildProperty(OSXML, is_single=True) features = XMLChildProperty(DomainFeatures, is_single=True) clock = XMLChildProperty(Clock, is_single=True) cpu = XMLChildProperty(CPU, is_single=True) cputune = XMLChildProperty(CPUTune, is_single=True) numatune = XMLChildProperty(DomainNumatune, is_single=True) pm = XMLChildProperty(PM, is_single=True) blkiotune = XMLChildProperty(DomainBlkiotune, is_single=True) memtune = XMLChildProperty(DomainMemorytune, is_single=True) memoryBacking = XMLChildProperty(DomainMemorybacking, is_single=True) idmap = XMLChildProperty(IdMap, is_single=True) resource = XMLChildProperty(DomainResource, is_single=True) sysinfo = XMLChildProperty(SYSInfo, is_single=True) xmlns_qemu = XMLChildProperty(XMLNSQemu, is_single=True) ############################### # Distro detection properties # ############################### def _set_os_object(self, variant): obj = OSDB.lookup_os(variant) if not obj: obj = OSDB.lookup_os("generic") self.__os_object = obj def _get_os_object(self): if not self.__os_object: self._set_os_object(None) return self.__os_object _os_object = property(_get_os_object) def _get_os_variant(self): return self._os_object.name def _set_os_variant(self, val): if val: val = val.lower() if OSDB.lookup_os(val) is None: raise ValueError( _("Distro '%s' does not exist in our dictionary") % val) logging.debug("Setting Guest.os_variant to '%s'", val) self._set_os_object(val) os_variant = property(_get_os_variant, _set_os_variant) ######################################## # Device Add/Remove Public API methods # ######################################## def add_device(self, dev): """ Add the passed device to the guest's device list. @param dev: VirtualDevice instance to attach to guest """ self.add_child(dev) def remove_device(self, dev): """ Remove the passed device from the guest's device list @param dev: VirtualDevice instance """ self.remove_child(dev) def get_devices(self, devtype): """ Return a list of devices of type 'devtype' that will installed on the guest. @param devtype: Device type to search for (one of VirtualDevice.virtual_device_types) """ newlist = [] for i in self._devices: if devtype == "all" or i.virtual_device_type == devtype: newlist.append(i) return newlist _devices = XMLChildProperty( [VirtualDevice.virtual_device_classes[_n] for _n in VirtualDevice.virtual_device_types], relative_xpath="./devices") def get_all_devices(self): """ Return a list of all devices being installed with the guest """ retlist = [] for devtype in VirtualDevice.virtual_device_types: retlist.extend(self.get_devices(devtype)) return retlist ############################ # Install Helper functions # ############################ def _prepare_install(self, meter, dry=False): ignore = dry # Fetch install media, prepare installer devices self.installer.prepare(self, meter) # Initialize install device list if self._install_cdrom_device: self._install_cdrom_device.path = self.installer.cdrom_path() self._install_cdrom_device.validate() def _prepare_get_xml(self): # We do a shallow copy of the OS block here, so that we can # set the install time properties but not permanently overwrite # any config the user explicitly requested. data = (self.os, self.on_reboot) try: self._propstore["os"] = self.os.copy() except Exception: self._finish_get_xml(data) raise return data def _finish_get_xml(self, data): (self._propstore["os"], self.on_reboot) = data def _get_install_xml(self, *args, **kwargs): data = self._prepare_get_xml() try: return self._do_get_install_xml(*args, **kwargs) finally: self._finish_get_xml(data) def _do_get_install_xml(self, install): """ Return the full Guest xml configuration. @install: Whether we want the 'OS install' configuration or the 'post-install' configuration. The difference is mostly whether the install media is attached and set as the boot device. Some installs, like an import or livecd, do not have an 'install' config. """ if install and not self.installer.has_install_phase(): return None self.installer.alter_bootconfig(self, install) if not install: self._remove_cdrom_install_media() if install: self.on_reboot = "destroy" self._set_osxml_defaults() self.bootloader = None if (not install and self.os.is_xenpv() and not self.os.kernel): self.bootloader = "/usr/bin/pygrub" self.os.clear() return self.get_xml_config() ########################### # Private install helpers # ########################### def _build_xml(self): install_xml = self._get_install_xml(install=True) final_xml = self._get_install_xml(install=False) logging.debug("Generated install XML: %s", (install_xml and ("\n" + install_xml) or "None required")) logging.debug("Generated boot XML: \n%s", final_xml) return install_xml, final_xml def _manual_transient_create(self, install_xml, final_xml, needs_boot): """ For hypervisors (like vz) that don't implement createXML, we need to define+start, and undefine on start failure """ domain = self.conn.defineXML(install_xml or final_xml) if not needs_boot: return domain # Handle undefining the VM if the initial startup fails try: domain.create() except Exception: import sys exc_info = sys.exc_info() try: domain.undefine() except Exception: pass raise exc_info[0], exc_info[1], exc_info[2] if install_xml and install_xml != final_xml: domain = self.conn.defineXML(final_xml) return domain def _create_guest(self, meter, install_xml, final_xml, doboot, transient): """ Actually do the XML logging, guest defining/creating @param doboot: Boot guest even if it has no install phase """ meter_label = _("Creating domain...") meter = util.ensure_meter(meter) meter.start(size=None, text=meter_label) needs_boot = doboot or self.installer.has_install_phase() if self.type == "vz": if transient: raise RuntimeError(_("Domain type 'vz' doesn't support " "transient installs.")) domain = self._manual_transient_create( install_xml, final_xml, needs_boot) else: if transient or needs_boot: domain = self.conn.createXML(install_xml or final_xml, 0) if not transient: domain = self.conn.defineXML(final_xml) self.domain = domain try: logging.debug("XML fetched from libvirt object:\n%s", self.domain.XMLDesc(0)) except Exception as e: logging.debug("Error fetching XML from libvirt object: %s", e) def _flag_autostart(self): """ Set the autostart flag for self.domain if the user requested it """ if not self.autostart: return try: self.domain.setAutostart(True) except libvirt.libvirtError as e: if util.is_error_nosupport(e): logging.warning("Could not set autostart flag: libvirt " "connection does not support autostart.") else: raise e ############## # Public API # ############## def start_install(self, meter=None, dry=False, return_xml=False, doboot=True, transient=False): """ Begin the guest install (stage1). @param return_xml: Don't create the guest, just return generated XML """ if self.domain is not None: raise RuntimeError(_("Domain has already been started!")) self.set_install_defaults() self._prepare_install(meter, dry) try: # Create devices if required (disk images, etc.) if not dry: for dev in self.get_all_devices(): dev.setup(meter) install_xml, final_xml = self._build_xml() if return_xml: return (install_xml, final_xml) if dry: return # Remove existing VM if requested self.check_vm_collision(self.conn, self.name, do_remove=self.replace) self._create_guest(meter, install_xml, final_xml, doboot, transient) # Set domain autostart flag if requested self._flag_autostart() finally: self.installer.cleanup() def get_created_disks(self): return [d for d in self.get_devices("disk") if d.storage_was_created] def cleanup_created_disks(self, meter): """ Remove any disks we created as part of the install. Only ever called by clients. """ clean_disks = self.get_created_disks() if not clean_disks: return for disk in clean_disks: logging.debug("Removing created disk path=%s vol_object=%s", disk.path, disk.get_vol_object()) name = os.path.basename(disk.path) try: meter.start(size=None, text=_("Removing disk '%s'") % name) if disk.get_vol_object(): disk.get_vol_object().delete() else: os.unlink(disk.path) meter.end(0) except Exception as e: logging.debug("Failed to remove disk '%s'", name, exc_info=True) logging.error("Failed to remove disk '%s': %s", name, e) ########################### # XML convenience helpers # ########################### def set_uefi_default(self): """ Configure UEFI for the VM, but only if libvirt is advertising a known UEFI binary path. """ domcaps = DomainCapabilities.build_from_guest(self) if not domcaps.supports_uefi_xml(): raise RuntimeError(_("Libvirt version does not support UEFI.")) if not domcaps.arch_can_uefi(): raise RuntimeError( _("Don't know how to setup UEFI for arch '%s'") % self.os.arch) path = domcaps.find_uefi_path_for_arch() if not path: raise RuntimeError(_("Did not find any UEFI binary path for " "arch '%s'") % self.os.arch) self.os.loader_ro = True self.os.loader_type = "pflash" self.os.loader = path self.check_uefi_secure() def check_uefi_secure(self): """ If the firmware name contains "secboot" it is probably build with SMM feature required so we need to enable that feature, otherwise the firmware may fail to load. True secure boot is currently supported only on x86 architecture and with q35 with SMM feature enabled so change the machine to q35 as well. To actually enforce the secure boot for the guest if Secure Boot Mode is configured we need to enable loader secure feature. """ if not self.os.is_x86(): return if "secboot" not in self.os.loader: return if (not self.conn.check_support(self.conn.SUPPORT_DOMAIN_FEATURE_SMM) or not self.conn.check_support(self.conn.SUPPORT_DOMAIN_LOADER_SECURE)): return self.features.smm = True self.os.loader_secure = True self.os.machine = "q35" ################### # Device defaults # ################### def set_install_defaults(self): """ Allow API users to set defaults ahead of time if they want it. Used by vmmDomainVirtinst so the 'Customize before install' dialog shows accurate values. If the user doesn't explicitly call this, it will be called by start_install() """ if self._defaults_are_set: return self._set_defaults() self._defaults_are_set = True def stable_defaults(self, *args, **kwargs): return self.conn.stable_defaults(self.emulator, *args, **kwargs) def _usb_disabled(self): controllers = [c for c in self.get_devices("controller") if c.type == "usb"] if not controllers: return False return all([c.model == "none" for c in controllers]) def add_default_input_device(self): if self.os.is_container(): return if self.get_devices("input"): return if not self.get_devices("graphics"): return if self._usb_disabled(): return usb_tablet = False usb_keyboard = False if self.os.is_x86(): usb_tablet = self._os_object.supports_usbtablet() if self.os.is_arm_machvirt(): usb_tablet = True usb_keyboard = True if usb_tablet: dev = VirtualInputDevice(self.conn) dev.type = "tablet" dev.bus = "usb" self.add_device(dev) if usb_keyboard: dev = VirtualInputDevice(self.conn) dev.type = "keyboard" dev.bus = "usb" self.add_device(dev) def add_default_console_device(self): if self.skip_default_console: return if self.get_devices("console") or self.get_devices("serial"): return dev = VirtualConsoleDevice(self.conn) dev.type = dev.TYPE_PTY if self.os.is_s390x(): dev.target_type = "sclp" self.add_device(dev) def add_default_video_device(self): if self.os.is_container(): return if self.get_devices("video"): return if not self.get_devices("graphics"): return self.add_device(VirtualVideoDevice(self.conn)) def add_default_usb_controller(self): if self.os.is_container(): return if any([d.type == "usb" for d in self.get_devices("controller")]): return usb2 = False usb3 = False if self.os.is_x86(): usb2 = True elif (self.os.is_arm_machvirt() and self.conn.check_support( self.conn.SUPPORT_CONN_MACHVIRT_PCI_DEFAULT)): usb3 = True if not usb2 and not usb3: return if usb2: if not self.conn.check_support( self.conn.SUPPORT_CONN_DEFAULT_USB2): return for dev in VirtualController.get_usb2_controllers(self.conn): self.add_device(dev) if usb3: self.add_device( VirtualController.get_usb3_controller(self.conn, self)) def add_default_channels(self): if self.skip_default_channel: return if self.get_devices("channel"): return if self.os.is_s390x(): # Not wanted for s390 apparently return if (self.conn.is_qemu() and self._os_object.supports_qemu_ga() and self.conn.check_support(self.conn.SUPPORT_CONN_AUTOSOCKET)): dev = VirtualChannelDevice(self.conn) dev.type = "unix" dev.target_type = "virtio" dev.target_name = dev.CHANNEL_NAME_QEMUGA self.add_device(dev) def add_default_graphics(self): if self.skip_default_graphics: return if self.get_devices("graphics"): return if self.os.is_container() and not self.conn.is_vz(): return if self.os.arch not in ["x86_64", "i686", "ppc64", "ppc64le"]: return self.add_device(VirtualGraphics(self.conn)) def add_default_rng(self): if self.skip_default_rng: return if self.get_devices("rng"): return if not (self.os.is_x86() or self.os.is_arm_machvirt() or self.os.is_pseries()): return if (self.conn.is_qemu() and self._os_object.supports_virtiorng() and self.conn.check_support(self.conn.SUPPORT_CONN_RNG_URANDOM)): dev = VirtualRNGDevice(self.conn) dev.type = "random" dev.device = "/dev/urandom" self.add_device(dev) def add_default_devices(self): self.add_default_graphics() self.add_default_video_device() self.add_default_input_device() self.add_default_console_device() self.add_default_usb_controller() self.add_default_channels() self.add_default_rng() def _add_install_cdrom(self): if self._install_cdrom_device: return if not self.installer.needs_cdrom(): return dev = VirtualDisk(self.conn) dev.device = dev.DEVICE_CDROM setattr(dev, "installer_media", not self.installer.livecd) self._install_cdrom_device = dev self.add_device(dev) def _remove_cdrom_install_media(self): for dev in self.get_devices("disk"): # Keep the install cdrom device around, but with no media attached. # But only if we are installing windows which has a multi stage # install. if (dev.is_cdrom() and getattr(dev, "installer_media", False) and not self._os_object.is_windows()): dev.path = None def _set_defaults(self): self._add_install_cdrom() # some options check for has_spice() which is resolved after this: self._set_graphics_defaults() self._set_clock_defaults() self._set_emulator_defaults() self._set_cpu_defaults() self._set_feature_defaults() self._set_pm_defaults() for dev in self.get_all_devices(): dev.set_defaults(self) self._check_address_multi() self._set_disk_defaults() self._add_implied_controllers() self._set_net_defaults() self._set_video_defaults() self._set_sound_defaults() self._set_panic_defaults() def _is_full_os_container(self): if not self.os.is_container(): return False for fs in self.get_devices("filesystem"): if fs.target == "/": return True return False def _set_osxml_defaults(self): if self.os.is_container() and not self.os.init: if self._is_full_os_container(): self.os.init = "/sbin/init" self.os.init = self.os.init or "/bin/sh" if not self.os.loader and self.os.is_hvm() and self.type == "xen": self.os.loader = "/usr/lib/xen/boot/hvmloader" if self.os.kernel or self.os.init: self.os.bootorder = [] def _set_clock_defaults(self): if not self.os.is_hvm(): return if self.clock.offset is None: self.clock.offset = self._os_object.get_clock() if self.clock.timers: return if not self.os.is_x86(): return if not self.conn.check_support( self.conn.SUPPORT_CONN_ADVANCED_CLOCK): return # Set clock policy that maps to qemu options: # -no-hpet -no-kvm-pit-reinjection -rtc driftfix=slew # # hpet: Is unneeded and has a performance penalty # pit: While it has no effect on windows, it doesn't hurt and # is beneficial for linux # # If libvirt/qemu supports it and using a windows VM, also # specify hypervclock. # # This is what has been recommended by the RH qemu guys :) rtc = self.clock.add_timer() rtc.name = "rtc" rtc.tickpolicy = "catchup" pit = self.clock.add_timer() pit.name = "pit" pit.tickpolicy = "delay" hpet = self.clock.add_timer() hpet.name = "hpet" hpet.present = False hv_clock = self.conn.check_support(self.conn.SUPPORT_CONN_HYPERV_CLOCK) hv_clock_rhel = self.conn.check_support(self.conn.SUPPORT_CONN_HYPERV_CLOCK_RHEL) if (self._os_object.is_windows() and self._hyperv_supported() and (hv_clock or (self.stable_defaults() and hv_clock_rhel))): hyperv = self.clock.add_timer() hyperv.name = "hypervclock" hyperv.present = True def _set_emulator_defaults(self): if self.os.is_xenpv() or self.type == "vz": self.emulator = None return if self.emulator: return if self.os.is_hvm() and self.type == "xen": if self.conn.caps.host.cpu.arch == "x86_64": self.emulator = "/usr/lib64/xen/bin/qemu-dm" else: self.emulator = "/usr/lib/xen/bin/qemu-dm" def _set_cpu_defaults(self): self.cpu.set_topology_defaults(self.vcpus) if not self.conn.is_test() and not self.conn.is_qemu(): return if (self.cpu.get_xml_config().strip() or self.cpu.special_mode_was_set): # User already configured CPU return if self.os.is_arm_machvirt() and self.type == "kvm": self.cpu.mode = self.cpu.SPECIAL_MODE_HOST_PASSTHROUGH elif self.os.is_arm64() and self.os.is_arm_machvirt(): # -M virt defaults to a 32bit CPU, even if using aarch64 self.cpu.model = "cortex-a57" elif self.os.is_x86() and self.type == "kvm": if self.os.arch != self.conn.caps.host.cpu.arch: return self.cpu.set_special_mode(self.x86_cpu_default) if self._os_object.broken_x2apic(): self.cpu.add_feature("x2apic", policy="disable") def _hyperv_supported(self): if (self.os.loader_type == "pflash" and self.os_variant in ("win2k8r2", "win7")): return False return True def update_defaults(self): # This is used only by virt-manager to reset any defaults that may have # changed through manual intervention via the customize wizard. # UEFI doesn't work with hyperv bits if not self._hyperv_supported(): self.features.hyperv_relaxed = None self.features.hyperv_vapic = None self.features.hyperv_spinlocks = None self.features.hyperv_spinlocks_retries = None for i in self.clock.timers: if i.name == "hypervclock": self.clock.remove_timer(i) def _set_feature_defaults(self): if self.os.is_container(): self.features.acpi = None self.features.apic = None self.features.pae = None if self._is_full_os_container() and self.type != "vz": self.features.privnet = True return if not self.os.is_hvm(): return default = True if (self._os_object.need_old_xen_disable_acpi() and not self.conn.check_support(support.SUPPORT_CONN_CAN_ACPI)): default = False if self.features.acpi == "default": if default: self.features.acpi = self.capsinfo.guest.supports_acpi() else: self.features.acpi = False if self.features.apic == "default": self.features.apic = self.capsinfo.guest.supports_apic() if self.features.pae == "default": if (self.os.is_hvm() and self.type == "xen" and self.os.arch == "x86_64"): self.features.pae = True else: self.features.pae = self.capsinfo.guest.supports_pae() if (self.features.vmport == "default" and self.os.is_x86() and self.has_spice() and self.conn.check_support(self.conn.SUPPORT_CONN_VMPORT)): self.features.vmport = False if (self._os_object.is_windows() and self._hyperv_supported() and self.conn.check_support(self.conn.SUPPORT_CONN_HYPERV_VAPIC)): if self.features.hyperv_relaxed is None: self.features.hyperv_relaxed = True if self.features.hyperv_vapic is None: self.features.hyperv_vapic = True if self.features.hyperv_spinlocks is None: self.features.hyperv_spinlocks = True if self.features.hyperv_spinlocks_retries is None: self.features.hyperv_spinlocks_retries = 8191 def _set_pm_defaults(self): # When the suspend feature is exposed to VMs, an ACPI shutdown # event triggers a suspend in the guest, which causes a lot of # user confusion (especially compounded with the face that suspend # is often buggy so VMs can get hung, etc). # # We've been disabling this in virt-manager for a while, but lets # do it here too for consistency. if (self.os.is_x86() and self.conn.check_support(self.conn.SUPPORT_CONN_PM_DISABLE)): if self.pm.suspend_to_mem is None: self.pm.suspend_to_mem = False if self.pm.suspend_to_disk is None: self.pm.suspend_to_disk = False def _add_implied_controllers(self): has_spapr_scsi = False has_virtio_scsi = False has_any_scsi = False for dev in self.get_devices("controller"): if dev.type == "scsi": has_any_scsi = True if dev.address.type == "spapr-vio": has_spapr_scsi = True if dev.model == "virtio": has_virtio_scsi = True # Add spapr-vio controller if needed if not has_spapr_scsi: for dev in self.get_devices("disk"): if dev.address.type == "spapr-vio": ctrl = VirtualController(self.conn) ctrl.type = "scsi" ctrl.address.set_addrstr("spapr-vio") self.add_device(ctrl) break # Add virtio-scsi controller if needed if ((self.os.is_arm_machvirt() or self.os.is_pseries()) and not has_any_scsi and not has_virtio_scsi): for dev in self.get_devices("disk"): if dev.bus == "scsi": ctrl = VirtualController(self.conn) ctrl.type = "scsi" ctrl.model = "virtio-scsi" self.add_device(ctrl) break def _check_address_multi(self): addresses = {} for d in self.get_all_devices(): if d.address.type != d.address.ADDRESS_TYPE_PCI: continue if None in [d.address.domain, d.address.bus, d.address.slot]: continue addr = d.address addrstr = "%d%d%d" % (d.address.domain, d.address.bus, d.address.slot) if addrstr not in addresses: addresses[addrstr] = {} if addr.function in addresses[addrstr]: raise ValueError(_("Duplicate address for devices %s and %s") % (str(d), str(addresses[addrstr][addr.function]))) addresses[addrstr][addr.function] = d for devs in addresses.values(): if len(devs) > 1 and 0 in devs: devs[0].address.multifunction = True def _supports_virtio(self, os_support): if not self.conn.is_qemu(): return False # These _only_ support virtio so don't check the OS if (self.os.is_arm_machvirt() or self.os.is_s390x() or self.os.is_pseries()): return True if not os_support: return False if self.os.is_x86(): return True if (self.os.is_arm_vexpress() and self.os.dtb and self._os_object.supports_virtiommio() and self.conn.check_support(support.SUPPORT_CONN_VIRTIO_MMIO)): return True return False def _set_disk_defaults(self): disks = self.get_devices("disk") def set_disk_bus(d): if d.is_floppy(): d.bus = "fdc" return if self.os.is_xenpv(): d.bus = "xen" return if not self.os.is_hvm(): # This likely isn't correct, but it's kind of a catch all # for virt types we don't know how to handle. d.bus = "ide" return if self.os.is_arm_machvirt(): # We prefer virtio-scsi for machvirt, gets us hotplug d.bus = "scsi" elif (d.is_disk() and self._supports_virtio(self._os_object.supports_virtiodisk())): d.bus = "virtio" elif self.os.is_pseries() and d.is_cdrom(): d.bus = "scsi" elif self.os.is_arm(): d.bus = "sd" elif self.os.is_q35(): d.bus = "sata" else: d.bus = "ide" # Generate disk targets used_targets = [] for disk in disks: if not disk.bus: set_disk_bus(disk) for disk in disks: if (disk.target and not getattr(disk, "cli_generated_target", False)): used_targets.append(disk.target) else: disk.cli_generated_target = False used_targets.append(disk.generate_target(used_targets)) def _set_net_defaults(self): net_model = None if not self.os.is_hvm(): net_model = None elif self._supports_virtio(self._os_object.supports_virtionet()): net_model = "virtio" else: net_model = self._os_object.default_netmodel() if net_model: for net in self.get_devices("interface"): if not net.model: net.model = net_model def _set_sound_defaults(self): if self.conn.check_support( support.SUPPORT_CONN_SOUND_ICH6): default = "ich6" elif self.conn.check_support( support.SUPPORT_CONN_SOUND_AC97): default = "ac97" else: default = "es1370" for sound in self.get_devices("sound"): if sound.model == sound.MODEL_DEFAULT: sound.model = default def _set_graphics_defaults(self): def _set_type(gfx): gtype = self.default_graphics_type logging.debug("Using default_graphics=%s", gtype) if (gtype == "spice" and not (self.conn.caps.host.cpu.arch in ["i686", "x86_64"] and self.conn.check_support( self.conn.SUPPORT_CONN_GRAPHICS_SPICE))): logging.debug("spice requested but HV doesn't support it. " "Using vnc.") gtype = "vnc" gfx.type = gtype for dev in self.get_devices("graphics"): if dev.type == "default": _set_type(dev) if (dev.type == "spice" and not self.conn.is_remote() and self.conn.check_support( self.conn.SUPPORT_CONN_SPICE_COMPRESSION)): logging.debug("Local connection, disabling spice image " "compression.") if dev.image_compression is None: dev.image_compression = "off" if dev.type == "spice" and dev.gl: if not self.conn.check_support( self.conn.SUPPORT_CONN_SPICE_GL): raise ValueError(_("Host does not support spice GL")) # If spice GL but rendernode wasn't specified, hardcode # the first one if not dev.rendernode and self.conn.check_support( self.conn.SUPPORT_CONN_SPICE_RENDERNODE): for nodedev in self.conn.fetch_all_nodedevs(): if (nodedev.device_type != 'drm' or nodedev.drm_type != 'render'): continue dev.rendernode = nodedev.get_devnode().path break def _add_spice_channels(self): if self.skip_default_channel: return for chn in self.get_devices("channel"): if chn.type == chn.TYPE_SPICEVMC: return if self.conn.check_support(self.conn.SUPPORT_CONN_CHAR_SPICEVMC): agentdev = VirtualChannelDevice(self.conn) agentdev.type = agentdev.TYPE_SPICEVMC self.add_device(agentdev) def _add_spice_sound(self): if self.skip_default_sound: return if self.get_devices("sound"): return if not self.os.is_hvm(): return if not (self.os.is_x86() or self.os.is_arm_machvirt): return self.add_device(VirtualAudio(self.conn)) def _add_spice_usbredir(self): if self.skip_default_usbredir: return if self.get_devices("redirdev"): return if not self.os.is_x86(): return if not self.conn.check_support(self.conn.SUPPORT_CONN_USBREDIR): return # If we use 4 devices here, we fill up all the emulated USB2 slots, # and directly assigned devices are forced to fall back to USB1 # https://bugzilla.redhat.com/show_bug.cgi?id=1135488 for ignore in range(2): dev = VirtualRedirDevice(self.conn) dev.bus = "usb" dev.type = "spicevmc" self.add_device(dev) def has_spice(self): for gfx in self.get_devices("graphics"): if gfx.type == gfx.TYPE_SPICE: return True def has_gl(self): for gfx in self.get_devices("graphics"): if gfx.gl: return True def has_listen_none(self): for gfx in self.get_devices("graphics"): listen = gfx.get_first_listen_type() if listen and listen == "none": return True return False def _set_video_defaults(self): if self.has_spice(): self._add_spice_channels() self._add_spice_sound() self._add_spice_usbredir() video_model = self._os_object.default_videomodel(self) if self.os.is_arm_machvirt(): video_model = "virtio" for video in self.get_devices("video"): if video.model == video.MODEL_DEFAULT: video.model = video_model if video.model == 'virtio' and self.has_gl(): video.accel3d = True def _set_panic_defaults(self): for panic in self.get_devices("panic"): if panic.model == VirtualPanicDevice.MODEL_DEFAULT: panic.model = VirtualPanicDevice.get_default_model(self.os) virt-manager-1.5.1/virtinst/devicechar.py0000664000175100017510000002565213245573052022145 0ustar crobinsocrobinso00000000000000# # Copyright 2009, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .device import VirtualDevice from .xmlbuilder import XMLProperty class _VirtualCharDevice(VirtualDevice): """ Base class for all character devices. Shouldn't be instantiated directly. """ TYPE_PTY = "pty" TYPE_DEV = "dev" TYPE_STDIO = "stdio" TYPE_PIPE = "pipe" TYPE_FILE = "file" TYPE_VC = "vc" TYPE_NULL = "null" TYPE_TCP = "tcp" TYPE_UDP = "udp" TYPE_UNIX = "unix" TYPE_SPICEVMC = "spicevmc" TYPE_SPICEPORT = "spiceport" TYPE_NMDM = "nmdm" # We don't list the non-UI friendly types here _TYPES_FOR_ALL = [TYPE_PTY, TYPE_DEV, TYPE_FILE, TYPE_TCP, TYPE_UDP, TYPE_UNIX] _TYPES_FOR_CHANNEL = [TYPE_SPICEVMC, TYPE_SPICEPORT] TYPES = _TYPES_FOR_ALL MODE_CONNECT = "connect" MODE_BIND = "bind" MODES = [MODE_CONNECT, MODE_BIND] PROTOCOL_RAW = "raw" PROTOCOL_TELNET = "telnet" PROTOCOLS = [PROTOCOL_RAW, PROTOCOL_TELNET] CHANNEL_TARGET_GUESTFWD = "guestfwd" CHANNEL_TARGET_VIRTIO = "virtio" CHANNEL_TARGETS = [CHANNEL_TARGET_GUESTFWD, CHANNEL_TARGET_VIRTIO] CONSOLE_TARGET_SERIAL = "serial" CONSOLE_TARGET_UML = "uml" CONSOLE_TARGET_XEN = "xen" CONSOLE_TARGET_VIRTIO = "virtio" CONSOLE_TARGETS = [CONSOLE_TARGET_SERIAL, CONSOLE_TARGET_UML, CONSOLE_TARGET_XEN, CONSOLE_TARGET_VIRTIO] CHANNEL_NAME_SPICE = "com.redhat.spice.0" CHANNEL_NAME_QEMUGA = "org.qemu.guest_agent.0" CHANNEL_NAME_LIBGUESTFS = "org.libguestfs.channel.0" CHANNEL_NAME_SPICE_WEBDAV = "org.spice-space.webdav.0" CHANNEL_NAMES = [CHANNEL_NAME_SPICE, CHANNEL_NAME_QEMUGA, CHANNEL_NAME_LIBGUESTFS, CHANNEL_NAME_SPICE_WEBDAV] @staticmethod def pretty_channel_name(val): if val == _VirtualCharDevice.CHANNEL_NAME_SPICE: return "spice" if val == _VirtualCharDevice.CHANNEL_NAME_QEMUGA: return "qemu-ga" if val == _VirtualCharDevice.CHANNEL_NAME_LIBGUESTFS: return "libguestfs" if val == _VirtualCharDevice.CHANNEL_NAME_SPICE_WEBDAV: return "spice-webdav" return None @staticmethod def pretty_type(ctype): """ Return a human readable description of the passed char type """ desc = "" if ctype == _VirtualCharDevice.TYPE_PTY: desc = _("Pseudo TTY") elif ctype == _VirtualCharDevice.TYPE_DEV: desc = _("Physical host character device") elif ctype == _VirtualCharDevice.TYPE_STDIO: desc = _("Standard input/output") elif ctype == _VirtualCharDevice.TYPE_PIPE: desc = _("Named pipe") elif ctype == _VirtualCharDevice.TYPE_FILE: desc = _("Output to a file") elif ctype == _VirtualCharDevice.TYPE_VC: desc = _("Virtual console") elif ctype == _VirtualCharDevice.TYPE_NULL: desc = _("Null device") elif ctype == _VirtualCharDevice.TYPE_TCP: desc = _("TCP net console") elif ctype == _VirtualCharDevice.TYPE_UDP: desc = _("UDP net console") elif ctype == _VirtualCharDevice.TYPE_UNIX: desc = _("Unix socket") elif ctype == _VirtualCharDevice.TYPE_SPICEVMC: desc = _("Spice agent") elif ctype == _VirtualCharDevice.TYPE_SPICEPORT: desc = _("Spice port") return desc @staticmethod def pretty_mode(char_mode): """ Return a human readable description of the passed char type """ desc = "" if char_mode == _VirtualCharDevice.MODE_CONNECT: desc = _("Client mode") elif char_mode == _VirtualCharDevice.MODE_BIND: desc = _("Server mode") return desc def supports_property(self, propname, ro=False): """ Whether the character dev type supports the passed property name """ users = { "source_path": [self.TYPE_FILE, self.TYPE_UNIX, self.TYPE_DEV, self.TYPE_PIPE], "source_mode": [self.TYPE_UNIX, self.TYPE_TCP], "source_host": [self.TYPE_TCP, self.TYPE_UDP], "source_port": [self.TYPE_TCP, self.TYPE_UDP], "source_channel": [self.TYPE_SPICEPORT], "source_master": [self.TYPE_NMDM], "source_slave": [self.TYPE_NMDM], "protocol": [self.TYPE_TCP], "bind_host": [self.TYPE_UDP], "bind_port": [self.TYPE_UDP], } if ro: users["source_path"] += [self.TYPE_PTY] if users.get(propname): return self.type in users[propname] return hasattr(self, propname) def set_defaults(self, guest): ignore = guest if not self.source_mode and self.supports_property("source_mode"): self.source_mode = self.MODE_BIND def _set_host_helper(self, hostparam, portparam, val): def parse_host(val): host, ignore, port = (val or "").partition(":") return host or None, port or None host, port = parse_host(val) if not host: host = "127.0.0.1" if host: setattr(self, hostparam, host) if port: setattr(self, portparam, port) def set_friendly_source(self, val): self._set_host_helper("source_host", "source_port", val) def set_friendly_bind(self, val): self._set_host_helper("bind_host", "bind_port", val) def set_friendly_target(self, val): self._set_host_helper("target_address", "target_port", val) _XML_PROP_ORDER = ["type", "_has_mode_bind", "_has_mode_connect", "bind_host", "bind_port", "source_mode", "source_host", "source_port", "_source_path", "source_channel", "target_type", "target_name"] type = XMLProperty("./@type", doc=_("Method used to expose character device in the host.")) _tty = XMLProperty("./@tty") _source_path = XMLProperty("./source/@path", doc=_("Host input path to attach to the guest.")) def _get_source_path(self): source = self._source_path if source is None and self._tty: return self._tty return source def _set_source_path(self, val): self._source_path = val source_path = property(_get_source_path, _set_source_path) source_channel = XMLProperty("./source/@channel", doc=_("Source channel name.")) source_master = XMLProperty("./source/@master") source_slave = XMLProperty("./source/@slave") ################### # source handling # ################### source_mode = XMLProperty("./source/@mode") _has_mode_connect = XMLProperty("./source[@mode='connect']/@mode") _has_mode_bind = XMLProperty("./source[@mode='bind']/@mode") def _set_source_validate(self, val): if val is None: return None self._has_mode_connect = self.MODE_CONNECT return val source_host = XMLProperty("./source[@mode='connect']/@host", doc=_("Host address to connect to."), set_converter=_set_source_validate) source_port = XMLProperty("./source[@mode='connect']/@service", doc=_("Host port to connect to."), set_converter=_set_source_validate, is_int=True) def _set_bind_validate(self, val): if val is None: return None self._has_mode_bind = self.MODE_BIND return val bind_host = XMLProperty("./source[@mode='bind']/@host", doc=_("Host address to bind to."), set_converter=_set_bind_validate) bind_port = XMLProperty("./source[@mode='bind']/@service", doc=_("Host port to bind to."), set_converter=_set_bind_validate, is_int=True) ####################### # Remaining XML props # ####################### def _get_default_protocol(self): if not self.supports_property("protocol"): return None return self.PROTOCOL_RAW protocol = XMLProperty("./protocol/@type", doc=_("Format used when sending data."), default_cb=_get_default_protocol) def _get_default_target_type(self): if self.virtual_device_type == "channel": return self.CHANNEL_TARGET_VIRTIO return None target_type = XMLProperty("./target/@type", doc=_("Channel type as exposed in the guest."), default_cb=_get_default_target_type) target_address = XMLProperty("./target/@address", doc=_("Guest forward channel address in the guest.")) target_port = XMLProperty("./target/@port", is_int=True, doc=_("Guest forward channel port in the guest.")) def _default_target_name(self): if self.type == self.TYPE_SPICEVMC: return self.CHANNEL_NAME_SPICE return None target_name = XMLProperty("./target/@name", doc=_("Sysfs name of virtio port in the guest"), default_cb=_default_target_name) log_file = XMLProperty("./log/@file") log_append = XMLProperty("./log/@append", is_onoff=True) class VirtualConsoleDevice(_VirtualCharDevice): virtual_device_type = "console" TYPES = [_VirtualCharDevice.TYPE_PTY] class VirtualSerialDevice(_VirtualCharDevice): virtual_device_type = "serial" class VirtualParallelDevice(_VirtualCharDevice): virtual_device_type = "parallel" class VirtualChannelDevice(_VirtualCharDevice): virtual_device_type = "channel" TYPES = (_VirtualCharDevice._TYPES_FOR_CHANNEL + _VirtualCharDevice._TYPES_FOR_ALL) VirtualConsoleDevice.register_type() VirtualSerialDevice.register_type() VirtualParallelDevice.register_type() VirtualChannelDevice.register_type() virt-manager-1.5.1/virtinst/osdict.py0000664000175100017510000004202413245573052021325 0ustar crobinsocrobinso00000000000000# # List of OS Specific data # # Copyright 2006-2008, 2013-2014 Red Hat, Inc. # Jeremy Katz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import datetime import logging import re import gi gi.require_version('Libosinfo', '1.0') from gi.repository import Libosinfo as libosinfo ################### # Sorting helpers # ################### def _remove_older_point_releases(distro_list): ret = distro_list[:] def _get_minor_version(osobj): return int(osobj.name.rsplit(".", 1)[-1]) def _find_latest(prefix): """ Given a prefix like 'rhel4', find the latest 'rhel4.X', and remove the rest from the os list """ latest_os = None first_id = None for osobj in ret[:]: if not re.match("%s\.\d+" % prefix, osobj.name): continue if first_id is None: first_id = ret.index(osobj) ret.remove(osobj) if (latest_os and _get_minor_version(latest_os) > _get_minor_version(osobj)): continue latest_os = osobj if latest_os: ret.insert(first_id, latest_os) _find_latest("rhel4") _find_latest("rhel5") _find_latest("rhel6") _find_latest("rhel7") _find_latest("freebsd9") _find_latest("freebsd10") _find_latest("freebsd11") _find_latest("centos6") _find_latest("centos7") return ret def _sort(tosort, sortpref=None, limit_point_releases=False): sortby_mappings = {} distro_mappings = {} retlist = [] sortpref = sortpref or [] for key, osinfo in tosort.items(): # Libosinfo has some duplicate version numbers here, so append .1 # if there's a collision sortby = osinfo.sortby while sortby_mappings.get(sortby): sortby = sortby + ".1" sortby_mappings[sortby] = key # Group distros by their urldistro value first, so debian is clumped # together, and fedora, etc. distro = osinfo.urldistro or "zzzzzzz" if distro not in distro_mappings: distro_mappings[distro] = [] distro_mappings[distro].append(sortby) # We want returned lists to be sorted descending by 'distro', so we get # debian5, debian4, fedora14, fedora13 # rather than # debian4, debian5, fedora13, fedora14 for distro_list in distro_mappings.values(): distro_list.sort() distro_list.reverse() # Move the sortpref values to the front of the list sorted_distro_list = distro_mappings.keys() sorted_distro_list.sort() sortpref.reverse() for prefer in sortpref: if prefer not in sorted_distro_list: continue sorted_distro_list.remove(prefer) sorted_distro_list.insert(0, prefer) # Build the final list of sorted os objects for distro in sorted_distro_list: distro_list = distro_mappings[distro] for key in distro_list: orig_key = sortby_mappings[key] retlist.append(tosort[orig_key]) # Filter out older point releases if limit_point_releases: retlist = _remove_older_point_releases(retlist) return retlist class _OSDB(object): """ Entry point for the public API """ def __init__(self): self.__os_loader = None self.__all_variants = None # This is only for back compatibility with pre-libosinfo support. # This should never change. _aliases = { "altlinux": "altlinux1.0", "debianetch": "debian4", "debianlenny": "debian5", "debiansqueeze": "debian6", "debianwheezy": "debian7", "freebsd10": "freebsd10.0", "freebsd6": "freebsd6.0", "freebsd7": "freebsd7.0", "freebsd8": "freebsd8.0", "freebsd9": "freebsd9.0", "mandriva2009": "mandriva2009.0", "mandriva2010": "mandriva2010.0", "mbs1": "mbs1.0", "msdos": "msdos6.22", "openbsd4": "openbsd4.2", "opensolaris": "opensolaris2009.06", "opensuse11": "opensuse11.4", "opensuse12": "opensuse12.3", "rhel4": "rhel4.0", "rhel5": "rhel5.0", "rhel6": "rhel6.0", "rhel7": "rhel7.0", "ubuntuhardy": "ubuntu8.04", "ubuntuintrepid": "ubuntu8.10", "ubuntujaunty": "ubuntu9.04", "ubuntukarmic": "ubuntu9.10", "ubuntulucid": "ubuntu10.04", "ubuntumaverick": "ubuntu10.10", "ubuntunatty": "ubuntu11.04", "ubuntuoneiric": "ubuntu11.10", "ubuntuprecise": "ubuntu12.04", "ubuntuquantal": "ubuntu12.10", "ubunturaring": "ubuntu13.04", "ubuntusaucy": "ubuntu13.10", "virtio26": "fedora10", "vista": "winvista", "winxp64": "winxp", # Old --os-type values "linux": "generic", "windows": "winxp", "solaris": "solaris10", "unix": "freebsd9.0", "other": "generic", } ################# # Internal APIs # ################# def _make_default_variants(self): ret = {} # Generic variant v = _OsVariant(None) ret[v.name] = v return ret @property def _os_loader(self): if not self.__os_loader: loader = libosinfo.Loader() loader.process_default_path() self.__os_loader = loader return self.__os_loader @property def _all_variants(self): if not self.__all_variants: loader = self._os_loader allvariants = self._make_default_variants() db = loader.get_db() oslist = db.get_os_list() for os in range(oslist.get_length()): osi = _OsVariant(oslist.get_nth(os)) allvariants[osi.name] = osi self.__all_variants = allvariants return self.__all_variants ############### # Public APIs # ############### def lookup_os(self, key): key = self._aliases.get(key) or key return self._all_variants.get(key) def lookup_os_by_media(self, location): media = libosinfo.Media.create_from_location(location, None) ret = self._os_loader.get_db().guess_os_from_media(media) if not (ret and len(ret) > 0 and ret[0]): return None osname = ret[0].get_short_id() if osname == "fedora-unknown": osname = self.latest_fedora_version() logging.debug("Detected location=%s as os=fedora-unknown. " "Converting that to the latest fedora OS version=%s", location, osname) return osname def list_types(self): approved_types = ["linux", "windows", "bsd", "macos", "solaris", "other", "generic"] return approved_types def list_os(self, typename=None, only_supported=False, sortpref=None): """ List all OSes in the DB :param typename: Only list OSes of this type :param only_supported: Only list OSses where self.supported == True :param sortpref: Sort these OSes at the front of the list """ sortmap = {} for name, osobj in self._all_variants.items(): if typename and typename != osobj.get_typename(): continue if only_supported and not osobj.get_supported(): continue sortmap[name] = osobj return _sort(sortmap, sortpref=sortpref, limit_point_releases=only_supported) def latest_fedora_version(self): for osinfo in self.list_os(): if (osinfo.name.startswith("fedora") and "unknown" not in osinfo.name): # First fedora* occurrence should be the newest return osinfo.name ##################### # OsVariant classes # ##################### class _OsVariant(object): def __init__(self, o): self._os = o self._family = self._os and self._os.get_family() or None self.name = self._os and self._os.get_short_id() or "generic" self.label = self._os and self._os.get_name() or "Generic" self.codename = self._os and self._os.get_codename() or "" self.distro = self._os and self._os.get_distro() or "" self.sortby = self._get_sortby() self.urldistro = self._get_urldistro() self._supported = None ######################## # Internal helper APIs # ######################## def _is_related_to(self, related_os_list, os=None, check_derives=True, check_upgrades=True, check_clones=True): os = os or self._os if not os: return False if os.get_short_id() in related_os_list: return True check_list = [] def _extend(newl): for obj in newl: if obj not in check_list: check_list.append(obj) if check_derives: _extend(os.get_related( libosinfo.ProductRelationship.DERIVES_FROM).get_elements()) if check_clones: _extend(os.get_related( libosinfo.ProductRelationship.CLONES).get_elements()) if check_upgrades: _extend(os.get_related( libosinfo.ProductRelationship.UPGRADES).get_elements()) for checkobj in check_list: if (checkobj.get_short_id() in related_os_list or self._is_related_to(related_os_list, os=checkobj, check_upgrades=check_upgrades, check_derives=check_derives, check_clones=check_clones)): return True return False ############### # Cached APIs # ############### def _get_sortby(self): if not self._os: return "1" version = self._os.get_version() try: t = version.split(".") t = t[:min(4, len(t))] + [0] * (4 - min(4, len(t))) new_version = "" for n in t: new_version = new_version + ("%.4i" % int(n)) version = new_version except Exception: pass return "%s-%s" % (self.distro, version) def _get_supported(self): if not self._os: return True eol_date = self._os.get_eol_date_string() if eol_date: return (datetime.datetime.strptime(eol_date, "%Y-%m-%d") > datetime.datetime.now()) if self.name == "fedora-unknown": return False # As of libosinfo 2.11, many clearly EOL distros don't have an # EOL date. So assume None == EOL, add some manual work arounds. # We should fix this in a new libosinfo version, and then drop # this hack if self._is_related_to(["fedora24", "rhel7.0", "debian6", "ubuntu13.04", "win8", "win2k12", "mageia5", "centos7.0"], check_clones=False, check_derives=False): return True return False def _get_urldistro(self): if not self._os: return None urldistro = self.distro remap = { "opensuse": "suse", "sles": "suse", "mes": "mandriva" } if remap.get(urldistro): return remap[urldistro] return urldistro ############### # Public APIs # ############### def get_supported(self): if self._supported is None: self._supported = self._get_supported() return self._supported def get_typename(self): """ Streamline the family name for use in the virt-manager UI """ if not self._os: return "generic" if self._family in ['linux']: return "linux" if self._family in ['win9x', 'winnt', 'win16']: return "windows" if self._family in ['solaris']: return "solaris" if self._family in ['openbsd', 'freebsd', 'netbsd']: return "bsd" if self._family in ['darwin']: return "macos" return "other" def is_windows(self): return self.get_typename() == "windows" def need_old_xen_disable_acpi(self): return self._is_related_to(["winxp", "win2k"], check_upgrades=False) def broken_x2apic(self): # x2apic breaks networking in solaris10 # https://bugs.launchpad.net/bugs/1395217 return self.name in ('solaris10', 'solaris11') def get_clock(self): if self.is_windows() or self._family in ['solaris']: return "localtime" return "utc" def supports_virtiommio(self): return self._is_related_to(["fedora19"]) def default_netmodel(self): """ Default non-virtio net-model, since we check for that separately """ if not self._os: return None fltr = libosinfo.Filter() fltr.add_constraint("class", "net") devs = self._os.get_all_devices(fltr) for idx in range(devs.get_length()): devname = devs.get_nth(idx).get_name() if devname in ["pcnet", "ne2k_pci", "rtl8139", "e1000"]: return devname return None def supports_usbtablet(self): if not self._os: return False fltr = libosinfo.Filter() fltr.add_constraint("class", "input") fltr.add_constraint("name", "tablet") devs = self._os.get_all_devices(fltr) for idx in range(devs.get_length()): if devs.get_nth(idx).get_bus_type() == "usb": return True return False def supports_virtiodisk(self): if self._os: fltr = libosinfo.Filter() fltr.add_constraint("class", "block") devs = self._os.get_all_devices(fltr) for dev in range(devs.get_length()): d = devs.get_nth(dev) if d.get_name() == "virtio-block": return True return False def supports_virtionet(self): if self._os: fltr = libosinfo.Filter() fltr.add_constraint("class", "net") devs = self._os.get_all_devices(fltr) for dev in range(devs.get_length()): d = devs.get_nth(dev) if d.get_name() == "virtio-net": return True return False def supports_virtiorng(self): if self._os: fltr = libosinfo.Filter() fltr.add_constraint("class", "rng") devs = self._os.get_all_devices(fltr) for dev in range(devs.get_length()): d = devs.get_nth(dev) if d.get_name() == "virtio-rng": return True return False def supports_qemu_ga(self): return self._is_related_to(["debian8", "fedora18", "rhel6.0", "sles11sp4"]) def default_videomodel(self, guest): if guest.os.is_pseries(): return "vga" if guest.has_spice() and guest.os.is_x86(): if guest.has_gl(): return "virtio" else: return "qxl" if self.is_windows(): return "vga" return None def get_recommended_resources(self, guest): ret = {} if not self._os: return ret def read_resource(resources, minimum, arch): # If we are reading the "minimum" block, allocate more # resources. ram_scale = minimum and 2 or 1 n_cpus_scale = minimum and 2 or 1 storage_scale = minimum and 2 or 1 for i in range(resources.get_length()): r = resources.get_nth(i) if r.get_architecture() == arch: ret["ram"] = r.get_ram() * ram_scale ret["cpu"] = r.get_cpu() ret["n-cpus"] = r.get_n_cpus() * n_cpus_scale ret["storage"] = r.get_storage() * storage_scale break # libosinfo may miss the recommended resources block for some OS, # in this case read first the minimum resources (if present) # and use them. read_resource(self._os.get_minimum_resources(), True, "all") read_resource(self._os.get_minimum_resources(), True, guest.os.arch) read_resource(self._os.get_recommended_resources(), False, "all") read_resource(self._os.get_recommended_resources(), False, guest.os.arch) # QEMU TCG doesn't gain anything by having extra VCPUs if guest.type == "qemu": ret["n-cpus"] = 1 return ret OSDB = _OSDB() virt-manager-1.5.1/virtinst/domainresource.py0000664000175100017510000000202513241024270023041 0ustar crobinsocrobinso00000000000000# # Copyright 2014 Fujitsu Limited. # Chen Hanxiao # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .xmlbuilder import XMLBuilder, XMLProperty class DomainResource(XMLBuilder): """ Class for generating XML """ _XML_ROOT_NAME = "resource" _XML_PROP_ORDER = ["partition"] partition = XMLProperty("./partition") virt-manager-1.5.1/virtinst/connection.py0000664000175100017510000003362013245573052022201 0ustar crobinsocrobinso00000000000000# # Copyright 2013, 2014, 2015 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import logging import weakref import libvirt from virtcli import CLIConfig from . import pollhelpers from . import support from . import util from . import Capabilities from .guest import Guest from .nodedev import NodeDevice from .storage import StoragePool, StorageVolume from .uri import URI, MagicURI class VirtualConnection(object): """ Wrapper for libvirt connection that provides various bits like - caching static data - lookup for API feature support - simplified API wrappers that handle new and old ways of doing things """ def __init__(self, uri): _initial_uri = uri or "" if MagicURI.uri_is_magic(_initial_uri): self._magic_uri = MagicURI(_initial_uri) self._open_uri = self._magic_uri.open_uri self._uri = self._magic_uri.make_fake_uri() self._fake_conn_predictable = self._magic_uri.predictable self._fake_conn_remote = self._magic_uri.remote self._fake_conn_session = self._magic_uri.session self._fake_conn_version = self._magic_uri.conn_version self._fake_libvirt_version = self._magic_uri.libvirt_version else: self._magic_uri = None self._open_uri = _initial_uri self._uri = _initial_uri self._fake_conn_predictable = False self._fake_conn_remote = False self._fake_conn_session = False self._fake_libvirt_version = None self._fake_conn_version = None self._daemon_version = None self._conn_version = None self._libvirtconn = None self._uriobj = URI(self._uri) self._caps = None self._support_cache = {} self._fetch_cache = {} # These let virt-manager register a callback which provides its # own cached object lists, rather than doing fresh calls self.cb_fetch_all_guests = None self.cb_fetch_all_pools = None self.cb_fetch_all_vols = None self.cb_fetch_all_nodedevs = None self.cb_cache_new_pool = None ############## # Properties # ############## def __getattr__(self, attr): if attr in self.__dict__: return self.__dict__[attr] # Proxy virConnect API calls libvirtconn = self.__dict__.get("_libvirtconn") return getattr(libvirtconn, attr) def _get_uri(self): return self._uri or self._open_uri uri = property(_get_uri) def _get_caps(self): if not self._caps: self._caps = Capabilities(self, self._libvirtconn.getCapabilities()) return self._caps caps = property(_get_caps) def get_conn_for_api_arg(self): return self._libvirtconn ############## # Public API # ############## def is_closed(self): return not bool(self._libvirtconn) def close(self): self._libvirtconn = None self._uri = None self._fetch_cache = {} def fake_conn_predictable(self): return self._fake_conn_predictable def invalidate_caps(self): self._caps = None def is_open(self): return bool(self._libvirtconn) def open(self, passwordcb): open_flags = 0 valid_auth_options = [libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_PASSPHRASE] authcb = self._auth_cb authcb_data = passwordcb conn = libvirt.openAuth(self._open_uri, [valid_auth_options, authcb, (authcb_data, valid_auth_options)], open_flags) if self._magic_uri: self._magic_uri.overwrite_conn_functions(conn) self._libvirtconn = conn if not self._open_uri: self._uri = self._libvirtconn.getURI() self._uriobj = URI(self._uri) def set_keep_alive(self, interval, count): if hasattr(self._libvirtconn, "setKeepAlive"): self._libvirtconn.setKeepAlive(interval, count) #################### # Polling routines # #################### _FETCH_KEY_GUESTS = "vms" _FETCH_KEY_POOLS = "pools" _FETCH_KEY_VOLS = "vols" _FETCH_KEY_NODEDEVS = "nodedevs" def _fetch_all_guests_raw(self): ignore, ignore, ret = pollhelpers.fetch_vms( self, {}, lambda obj, ignore: obj) return [Guest(weakref.ref(self), parsexml=obj.XMLDesc(0)) for obj in ret] def fetch_all_guests(self): """ Returns a list of Guest() objects """ if self.cb_fetch_all_guests: return self.cb_fetch_all_guests() # pylint: disable=not-callable key = self._FETCH_KEY_GUESTS if key not in self._fetch_cache: self._fetch_cache[key] = self._fetch_all_guests_raw() return self._fetch_cache[key][:] def _build_pool_raw(self, poolobj): return StoragePool(weakref.ref(self), parsexml=poolobj.XMLDesc(0)) def _fetch_all_pools_raw(self): ignore, ignore, ret = pollhelpers.fetch_pools( self, {}, lambda obj, ignore: obj) return [self._build_pool_raw(poolobj) for poolobj in ret] def fetch_all_pools(self): """ Returns a list of StoragePool objects """ if self.cb_fetch_all_pools: return self.cb_fetch_all_pools() # pylint: disable=not-callable key = self._FETCH_KEY_POOLS if key not in self._fetch_cache: self._fetch_cache[key] = self._fetch_all_pools_raw() return self._fetch_cache[key][:] def _fetch_vols_raw(self, poolxmlobj): ret = [] pool = self._libvirtconn.storagePoolLookupByName(poolxmlobj.name) if pool.info()[0] != libvirt.VIR_STORAGE_POOL_RUNNING: return ret ignore, ignore, vols = pollhelpers.fetch_volumes( self, pool, {}, lambda obj, ignore: obj) for vol in vols: try: xml = vol.XMLDesc(0) ret.append(StorageVolume(weakref.ref(self), parsexml=xml)) except Exception as e: logging.debug("Fetching volume XML failed: %s", e) return ret def _fetch_all_vols_raw(self): ret = [] for poolxmlobj in self.fetch_all_pools(): ret.extend(self._fetch_vols_raw(poolxmlobj)) return ret def fetch_all_vols(self): """ Returns a list of StorageVolume objects """ if self.cb_fetch_all_vols: return self.cb_fetch_all_vols() # pylint: disable=not-callable key = self._FETCH_KEY_VOLS if key not in self._fetch_cache: self._fetch_cache[key] = self._fetch_all_vols_raw() return self._fetch_cache[key][:] def _cache_new_pool_raw(self, poolobj): # Make sure cache is primed if self._FETCH_KEY_POOLS not in self._fetch_cache: # Nothing cached yet, so next poll will pull in latest bits, # so there's nothing to do return poollist = self._fetch_cache[self._FETCH_KEY_POOLS] poolxmlobj = self._build_pool_raw(poolobj) poollist.append(poolxmlobj) if self._FETCH_KEY_VOLS not in self._fetch_cache: return vollist = self._fetch_cache[self._FETCH_KEY_VOLS] vollist.extend(self._fetch_vols_raw(poolxmlobj)) def cache_new_pool(self, poolobj): """ Insert the passed poolobj into our cache """ if self.cb_cache_new_pool: # pylint: disable=not-callable return self.cb_cache_new_pool(poolobj) return self._cache_new_pool_raw(poolobj) def _fetch_all_nodedevs_raw(self): ignore, ignore, ret = pollhelpers.fetch_nodedevs( self, {}, lambda obj, ignore: obj) return [NodeDevice.parse(weakref.ref(self), obj.XMLDesc(0)) for obj in ret] def fetch_all_nodedevs(self): """ Returns a list of NodeDevice() objects """ if self.cb_fetch_all_nodedevs: return self.cb_fetch_all_nodedevs() # pylint: disable=not-callable key = self._FETCH_KEY_NODEDEVS if key not in self._fetch_cache: self._fetch_cache[key] = self._fetch_all_nodedevs_raw() return self._fetch_cache[key][:] ######################### # Libvirt API overrides # ######################### def getURI(self): return self._uri ######################### # Public version checks # ######################### def local_libvirt_version(self): if self._fake_libvirt_version is not None: return self._fake_libvirt_version # This handles caching for us return util.local_libvirt_version() def daemon_version(self): if self._fake_libvirt_version is not None: return self._fake_libvirt_version if not self.is_remote(): return self.local_libvirt_version() if not self._daemon_version: if not self.check_support(support.SUPPORT_CONN_LIBVERSION): self._daemon_version = 0 else: self._daemon_version = self._libvirtconn.getLibVersion() return self._daemon_version def conn_version(self): if self._fake_conn_version is not None: return self._fake_conn_version if not self._conn_version: if not self.check_support(support.SUPPORT_CONN_GETVERSION): self._conn_version = 0 else: self._conn_version = self._libvirtconn.getVersion() return self._conn_version def stable_defaults(self, emulator=None, force=False): """ :param force: Just check if we are running on RHEL, regardless of whether stable defaults are requested by the build. This is needed to ensure we don't enable VM devices that are compiled out on RHEL, like vmvga """ if not CLIConfig.stable_defaults and not force: return False if not self.is_qemu(): return False if emulator: return str(emulator).startswith("/usr/libexec") for guest in self.caps.guests: for dom in guest.domains: if dom.emulator.startswith("/usr/libexec"): return True return False ################### # Public URI bits # ################### def is_remote(self): return (self._fake_conn_remote or self._uriobj.hostname) def is_session_uri(self): return (self._fake_conn_session or self.get_uri_path() == "/session") def get_uri_hostname(self): return self._uriobj.hostname def get_uri_port(self): return self._uriobj.port def get_uri_username(self): return self._uriobj.username def get_uri_transport(self): if self.get_uri_hostname() and not self._uriobj.transport: # Libvirt defaults to transport=tls if hostname specified but # no transport is specified return "tls" return self._uriobj.transport def get_uri_path(self): return self._uriobj.path def get_uri_driver(self): return self._uriobj.scheme def is_qemu(self): return self._uriobj.scheme.startswith("qemu") def is_qemu_system(self): return (self.is_qemu() and self._uriobj.path == "/system") def is_qemu_session(self): return (self.is_qemu() and self.is_session_uri()) def is_really_test(self): return URI(self._open_uri).scheme.startswith("test") def is_test(self): return self._uriobj.scheme.startswith("test") def is_xen(self): return (self._uriobj.scheme.startswith("xen") or self._uriobj.scheme.startswith("libxl")) def is_lxc(self): return self._uriobj.scheme.startswith("lxc") def is_openvz(self): return self._uriobj.scheme.startswith("openvz") def is_container(self): return self.is_lxc() or self.is_openvz() def is_vz(self): return (self._uriobj.scheme.startswith("vz") or self._uriobj.scheme.startswith("parallels")) ######################### # Support check helpers # ######################### for _supportname in [_supportname for _supportname in dir(support) if _supportname.startswith("SUPPORT_")]: locals()[_supportname] = getattr(support, _supportname) def check_support(self, feature, data=None): key = feature data = data or self if key not in self._support_cache: self._support_cache[key] = support.check_support( self, feature, data) return self._support_cache[key] def support_remote_url_install(self): if self._magic_uri: return False return (self.check_support(self.SUPPORT_CONN_STREAM) and self.check_support(self.SUPPORT_STREAM_UPLOAD)) ################### # Private helpers # ################### def _auth_cb(self, creds, data): passwordcb, passwordcreds = data for cred in creds: if cred[0] not in passwordcreds: raise RuntimeError("Unknown cred type '%s', expected only " "%s" % (cred[0], passwordcreds)) return passwordcb(creds) virt-manager-1.5.1/virtinst/cloner.py0000664000175100017510000005557113245573052021335 0ustar crobinsocrobinso00000000000000# # Copyright 2013, 2015 Red Hat, Inc. # Copyright(c) FUJITSU Limited 2007. # # Cloning a virtual machine module. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import logging import re import os import libvirt from . import util from .guest import Guest from .deviceinterface import VirtualNetworkInterface from .devicedisk import VirtualDisk from .storage import StorageVolume from .devicechar import VirtualChannelDevice class Cloner(object): # Reasons why we don't default to cloning. CLONE_POLICY_NO_READONLY = 1 CLONE_POLICY_NO_SHAREABLE = 2 CLONE_POLICY_NO_EMPTYMEDIA = 3 def __init__(self, conn): self.conn = conn # original guest name or uuid self._original_guest = None self.original_dom = None self._original_disks = [] self._original_xml = None self._guest = None # clone guest self._clone_name = None self._clone_disks = [] self._clone_macs = [] self._clone_uuid = None self._clone_sparse = True self._clone_xml = None self.clone_nvram = None self._nvram_disk = None self._force_target = [] self._skip_target = [] self._preserve = True self._clone_running = False self._replace = False self._reflink = False # Default clone policy for back compat: don't clone readonly, # shareable, or empty disks self._clone_policy = [self.CLONE_POLICY_NO_READONLY, self.CLONE_POLICY_NO_SHAREABLE, self.CLONE_POLICY_NO_EMPTYMEDIA] # Generate a random UUID at the start self.clone_uuid = util.generate_uuid(conn) # Getter/Setter methods def get_original_guest(self): return self._original_guest def set_original_guest(self, original_guest): if self._lookup_vm(original_guest): self._original_guest = original_guest original_guest = property(get_original_guest, set_original_guest, doc="Original guest name.") def set_original_xml(self, val): if not isinstance(val, str): raise ValueError(_("Original xml must be a string.")) self._original_xml = val self._original_guest = Guest(self.conn, parsexml=self._original_xml).name def get_original_xml(self): return self._original_xml original_xml = property(get_original_xml, set_original_xml, doc="XML of the original guest.") def get_clone_name(self): return self._clone_name def set_clone_name(self, name): try: Guest.validate_name(self.conn, name, check_collision=not self.replace, validate=False) except ValueError as e: raise ValueError(_("Invalid name for new guest: %s") % e) self._clone_name = name clone_name = property(get_clone_name, set_clone_name, doc="Name to use for the new guest clone.") def set_clone_uuid(self, uuid): self._clone_uuid = uuid def get_clone_uuid(self): return self._clone_uuid clone_uuid = property(get_clone_uuid, set_clone_uuid, doc="UUID to use for the new guest clone") def set_clone_paths(self, paths): disklist = [] for path in util.listify(paths): try: device = VirtualDisk.DEVICE_DISK if not path: device = VirtualDisk.DEVICE_CDROM disk = VirtualDisk(self.conn) disk.path = path disk.device = device if (not self.preserve_dest_disks and disk.wants_storage_creation()): vol_install = VirtualDisk.build_vol_install( self.conn, os.path.basename(disk.path), disk.get_parent_pool(), .000001, False) disk.set_vol_install(vol_install) disk.validate() disklist.append(disk) except Exception as e: logging.debug("Error setting clone path.", exc_info=True) raise ValueError(_("Could not use path '%s' for cloning: %s") % (path, str(e))) self._clone_disks = disklist def get_clone_paths(self): return [d.path for d in self.clone_disks] clone_paths = property(get_clone_paths, set_clone_paths, doc="Paths to use for the new disk locations.") def get_clone_disks(self): return self._clone_disks clone_disks = property(get_clone_disks, doc="VirtualDisk instances for the new" " disk paths") def set_clone_macs(self, mac): maclist = util.listify(mac) for m in maclist: msg = VirtualNetworkInterface.is_conflict_net(self.conn, m)[1] if msg: raise RuntimeError(msg) self._clone_macs = maclist def get_clone_macs(self): return self._clone_macs clone_macs = property(get_clone_macs, set_clone_macs, doc="MAC address for the new guest clone.") def get_original_disks(self): return self._original_disks original_disks = property(get_original_disks, doc="VirtualDisk instances of the " "original disks being cloned.") def get_clone_xml(self): return self._clone_xml def set_clone_xml(self, clone_xml): self._clone_xml = clone_xml clone_xml = property(get_clone_xml, set_clone_xml, doc="Generated XML for the guest clone.") def get_clone_sparse(self): return self._clone_sparse def set_clone_sparse(self, flg): self._clone_sparse = flg clone_sparse = property(get_clone_sparse, set_clone_sparse, doc="Whether to attempt sparse allocation during " "cloning.") def get_preserve(self): return self._preserve def set_preserve(self, flg): self._preserve = flg preserve = property(get_preserve, set_preserve, doc="If true, preserve ALL original disk devices.") def get_preserve_dest_disks(self): return not self.preserve preserve_dest_disks = property(get_preserve_dest_disks, doc="If true, preserve ALL disk devices for the " "NEW guest. This means no storage cloning. " "This is a convenience access for " "(not Cloner.preserve)") def set_force_target(self, dev): if isinstance(dev, list): self._force_target = dev[:] else: self._force_target.append(dev) def get_force_target(self): return self._force_target force_target = property(get_force_target, set_force_target, doc="List of disk targets that we force cloning " "despite Cloner's recommendation.") def set_skip_target(self, dev): if isinstance(dev, list): self._skip_target = dev[:] else: self._skip_target.append(dev) def get_skip_target(self): return self._skip_target skip_target = property(get_skip_target, set_skip_target, doc="List of disk targets that we skip cloning " "despite Cloner's recommendation. This " "takes precedence over force_target.") def set_clone_policy(self, policy_list): if not isinstance(policy_list, list): raise ValueError(_("Cloning policy must be a list of rules.")) self._clone_policy = policy_list def get_clone_policy(self): return self._clone_policy clone_policy = property(get_clone_policy, set_clone_policy, doc="List of policy rules for determining which " "vm disks to clone. See CLONE_POLICY_*") def get_clone_running(self): return self._clone_running def set_clone_running(self, val): self._clone_running = bool(val) clone_running = property(get_clone_running, set_clone_running, doc="Allow cloning a running VM. If enabled, " "domain state is not checked before " "cloning.") def _get_replace(self): return self._replace def _set_replace(self, val): self._replace = bool(val) replace = property(_get_replace, _set_replace, doc="If enabled, don't check for clone name collision, " "simply undefine any conflicting guest.") def _get_reflink(self): return self._reflink def _set_reflink(self, reflink): self._reflink = reflink reflink = property(_get_reflink, _set_reflink, doc="If true, use COW lightweight copy") # Functional methods def setup_original(self): """ Validate and setup all parameters needed for the original (cloned) VM """ logging.debug("Validating original guest parameters") if self.original_guest is None and self.original_xml is None: raise RuntimeError(_("Original guest name or xml is required.")) if self.original_guest is not None and not self.original_xml: self.original_dom = self._lookup_vm(self.original_guest) flags = libvirt.VIR_DOMAIN_XML_SECURE self.original_xml = self.original_dom.XMLDesc(flags) logging.debug("Original XML:\n%s", self.original_xml) self._guest = Guest(self.conn, parsexml=self.original_xml) self._guest.id = None self._guest.replace = self.replace # Pull clonable storage info from the original xml self._original_disks = self._get_original_disks_info() logging.debug("Original paths: %s", [d.path for d in self.original_disks]) logging.debug("Original sizes: %s", [d.get_size() for d in self.original_disks]) # If domain has devices to clone, it must be 'off' or 'paused' if (not self.clone_running and (self.original_dom and len(self.original_disks) != 0)): status = self.original_dom.info()[0] if status not in [libvirt.VIR_DOMAIN_SHUTOFF, libvirt.VIR_DOMAIN_PAUSED]: raise RuntimeError(_("Domain with devices to clone must be " "paused or shutoff.")) def _setup_disk_clone_destination(self, orig_disk, clone_disk): """ Helper that validates the new path location """ if self.preserve_dest_disks: return if clone_disk.get_vol_object(): # XXX We could always do this with vol upload? # Special case: non remote cloning of a guest using # managed block devices: fall back to local cloning if # we have permissions to do so. This validation check # caused a few bug reports in a short period of time, # so must be a common case. if (self.conn.is_remote() or clone_disk.type != clone_disk.TYPE_BLOCK or not orig_disk.path or not os.access(orig_disk.path, os.R_OK) or not clone_disk.path or not os.access(clone_disk.path, os.W_OK)): raise RuntimeError( _("Clone onto existing storage volume is not " "currently supported: '%s'") % clone_disk.path) # Setup proper cloning inputs for the new virtual disks if (orig_disk.get_vol_object() and clone_disk.get_vol_install()): clone_vol_install = clone_disk.get_vol_install() # Source and dest are managed. If they share the same pool, # replace vol_install with a CloneVolume instance, otherwise # simply set input_vol on the dest vol_install if (clone_vol_install.pool.name() == orig_disk.get_parent_pool().name()): vol_install = StorageVolume(self.conn) vol_install.input_vol = orig_disk.get_vol_object() vol_install.sync_input_vol() vol_install.name = clone_vol_install.name else: # Cross pool cloning # Sync only the format of the image. clone_vol_install.input_vol = orig_disk.get_vol_object() vol_install = clone_vol_install vol_install.input_vol = orig_disk.get_vol_object() vol_install.sync_input_vol(only_format=True) vol_install.reflink = self.reflink clone_disk.set_vol_install(vol_install) elif orig_disk.path: clone_disk.set_local_disk_to_clone(orig_disk, self.clone_sparse) clone_disk.validate() def _prepare_nvram(self): if self.clone_nvram is None: nvram_dir = os.path.dirname(self._guest.os.nvram) self.clone_nvram = os.path.join(nvram_dir, "%s_VARS.fd" % self._clone_name) nvram = VirtualDisk(self.conn) nvram.path = self.clone_nvram if (not self.preserve_dest_disks and nvram.wants_storage_creation()): old_nvram = VirtualDisk(self.conn) old_nvram.path = self._guest.os.nvram if not old_nvram.get_vol_object(): raise RuntimeError(_("Path does not exist: %s") % old_nvram.path) nvram_install = VirtualDisk.build_vol_install( self.conn, os.path.basename(nvram.path), nvram.get_parent_pool(), nvram.get_size(), False) nvram_install.input_vol = old_nvram.get_vol_object() nvram_install.sync_input_vol(only_format=True) nvram_install.reflink = self.reflink nvram.set_vol_install(nvram_install) nvram.validate() self._nvram_disk = nvram self._guest.os.nvram = nvram.path def setup_clone(self): """ Validate and set up all parameters needed for the new (clone) VM """ logging.debug("Validating clone parameters.") self._clone_xml = self.original_xml if len(self.clone_disks) < len(self.original_disks): raise ValueError(_("More disks to clone than new paths specified. " "(%(passed)d specified, %(need)d needed") % {"passed": len(self.clone_disks), "need": len(self.original_disks)}) logging.debug("Clone paths: %s", [d.path for d in self.clone_disks]) self._guest.name = self._clone_name self._guest.uuid = self._clone_uuid self._clone_macs.reverse() for dev in self._guest.get_devices("graphics"): if dev.port and dev.port != -1: logging.warning(_("Setting the graphics device port to autoport, " "in order to avoid conflicting.")) dev.port = -1 clone_macs = self._clone_macs[:] for iface in self._guest.get_devices("interface"): iface.target_dev = None if clone_macs: mac = clone_macs.pop() else: mac = VirtualNetworkInterface.generate_mac(self.conn) iface.macaddr = mac # Changing storage XML for i, orig_disk in enumerate(self._original_disks): clone_disk = self._clone_disks[i] for disk in self._guest.get_devices("disk"): if disk.target == orig_disk.target: xmldisk = disk self._setup_disk_clone_destination(orig_disk, clone_disk) # Change the XML xmldisk.path = None xmldisk.type = clone_disk.type xmldisk.driver_name = orig_disk.driver_name xmldisk.driver_type = orig_disk.driver_type xmldisk.path = clone_disk.path # For guest agent channel, remove a path to generate a new one with # new guest name for channel in self._guest.get_devices("channel"): if channel.type == VirtualChannelDevice.TYPE_UNIX: channel.source_path = None if self._guest.os.nvram: self._prepare_nvram() # Save altered clone xml self._clone_xml = self._guest.get_xml_config() logging.debug("Clone guest xml is\n%s", self._clone_xml) def start_duplicate(self, meter=None): """ Actually perform the duplication: cloning disks if needed and defining the new clone xml. """ logging.debug("Starting duplicate.") meter = util.ensure_meter(meter) dom = None try: # Replace orig VM if required Guest.check_vm_collision(self.conn, self.clone_name, do_remove=self.replace) # Define domain early to catch any xml errors before duping storage dom = self.conn.defineXML(self.clone_xml) if self.preserve: for dst_dev in self.clone_disks: dst_dev.setup(meter=meter) if self._nvram_disk: self._nvram_disk.setup(meter=meter) except Exception as e: logging.debug("Duplicate failed: %s", str(e)) if dom: dom.undefine() raise logging.debug("Duplicating finished.") def generate_clone_disk_path(self, origpath, newname=None): origname = self.original_guest newname = newname or self.clone_name path = origpath suffix = "" # Try to split the suffix off the existing disk name. Ex. # foobar.img -> foobar-clone.img # # If the suffix is greater than 7 characters, assume it isn't # a file extension and is part of the disk name, at which point # just stick '-clone' on the end. if origpath.count(".") and len(origpath.rsplit(".", 1)[1]) <= 7: path, suffix = origpath.rsplit(".", 1) suffix = "." + suffix dirname = os.path.dirname(path) basename = os.path.basename(path) clonebase = basename + "-clone" if origname and basename == origname: clonebase = newname clonebase = os.path.join(dirname, clonebase) return util.generate_name( clonebase, lambda p: VirtualDisk.path_definitely_exists(self.conn, p), suffix, lib_collision=False) def generate_clone_name(self): # If the orig name is "foo-clone", we don't want the clone to be # "foo-clone-clone", we want "foo-clone1" basename = self.original_guest match = re.search("-clone[1-9]*$", basename) start_num = 1 if match: num_match = re.search("[1-9]+$", match.group()) if num_match: start_num = int(str(num_match.group())) basename = basename.replace(match.group(), "") basename = basename + "-clone" return util.generate_name(basename, self.conn.lookupByName, sep="", start_num=start_num) ############################ # Private helper functions # ############################ # Parse disk paths that need to be cloned from the original guest's xml # Return a list of VirtualDisk instances pointing to the original # storage def _get_original_disks_info(self): clonelist = [] retdisks = [] for disk in self._guest.get_devices("disk"): if self._do_we_clone_device(disk): clonelist.append(disk) continue # Set up virtual disk to encapsulate all relevant path info for disk in clonelist: validate = not self.preserve_dest_disks try: device = VirtualDisk.DEVICE_DISK if not disk.path: # Tell VirtualDisk we are a cdrom to allow empty media device = VirtualDisk.DEVICE_CDROM newd = VirtualDisk(self.conn) newd.path = disk.path newd.device = device newd.driver_name = disk.driver_name newd.driver_type = disk.driver_type newd.target = disk.target if validate: if newd.wants_storage_creation(): raise ValueError(_("Disk path '%s' does not exist.") % newd.path) except Exception as e: logging.debug("Exception creating clone disk objects", exc_info=True) raise ValueError(_("Could not determine original disk " "information: %s" % str(e))) retdisks.append(newd) return retdisks # Pull disk #i from the original guest xml, return it's source path # if it should be cloned # Cloning policy based on 'clone_policy', 'force_target' and 'skip_target' def _do_we_clone_device(self, disk): if not disk.target: raise ValueError(_("XML has no 'dev' attribute in disk target")) if disk.target in self.skip_target: return False if disk.target in self.force_target: return True # No media path if (not disk.path and self.CLONE_POLICY_NO_EMPTYMEDIA in self.clone_policy): return False # Readonly disks if (disk.read_only and self.CLONE_POLICY_NO_READONLY in self.clone_policy): return False # Shareable disks if (disk.shareable and self.CLONE_POLICY_NO_SHAREABLE in self.clone_policy): return False return True # Simple wrapper for checking a vm exists and returning the domain def _lookup_vm(self, name): try: return self.conn.lookupByName(name) except libvirt.libvirtError: raise ValueError(_("Domain '%s' was not found.") % str(name)) virt-manager-1.5.1/virtinst/cli.py0000664000175100017510000027647013245573052020625 0ustar crobinsocrobinso00000000000000# # Utility functions for the command line drivers # # Copyright 2006-2007, 2013, 2014 Red Hat, Inc. # Jeremy Katz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from __future__ import print_function import argparse import collections import logging import logging.handlers import os import re import shlex import subprocess import sys import traceback import libvirt from virtcli import CLIConfig from . import util from .clock import Clock from .cpu import CPU from .cputune import CPUTune from .deviceaudio import VirtualAudio from .devicechar import (VirtualChannelDevice, VirtualConsoleDevice, VirtualSerialDevice, VirtualParallelDevice) from .devicecontroller import VirtualController from .devicedisk import VirtualDisk from .devicefilesystem import VirtualFilesystem from .devicegraphics import VirtualGraphics from .devicehostdev import VirtualHostDevice from .deviceinput import VirtualInputDevice from .deviceinterface import VirtualNetworkInterface from .devicememballoon import VirtualMemballoon from .devicememory import VirtualMemoryDevice from .devicepanic import VirtualPanicDevice from .deviceredirdev import VirtualRedirDevice from .devicerng import VirtualRNGDevice from .devicesmartcard import VirtualSmartCardDevice from .devicetpm import VirtualTPMDevice from .devicevideo import VirtualVideoDevice from .devicewatchdog import VirtualWatchdog from .domainblkiotune import DomainBlkiotune from .domainfeatures import DomainFeatures from .domainmemorybacking import DomainMemorybacking from .domainmemorytune import DomainMemorytune from .domainnumatune import DomainNumatune from .domainresource import DomainResource from .idmap import IdMap from .nodedev import NodeDevice from .osxml import OSXML from .pm import PM from .seclabel import Seclabel from .storage import StoragePool, StorageVolume from .sysinfo import SYSInfo from .xmlnsqemu import XMLNSQemu ########################## # Global option handling # ########################## class _GlobalState(object): def __init__(self): self.quiet = False self.all_checks = None self._validation_checks = {} def set_validation_check(self, checkname, val): self._validation_checks[checkname] = val def get_validation_check(self, checkname): if self.all_checks is not None: return self.all_checks # Default to True for all checks return self._validation_checks.get(checkname, True) _globalstate = None def get_global_state(): return _globalstate def _reset_global_state(): global _globalstate _globalstate = _GlobalState() #################### # CLI init helpers # #################### class VirtStreamHandler(logging.StreamHandler): def emit(self, record): """ Based on the StreamHandler code from python 2.6: ripping out all the unicode handling and just unconditionally logging seems to fix logging backtraces with unicode locales (for me at least). No doubt this is atrocious, but it WORKSFORME! """ try: msg = self.format(record) stream = self.stream fs = "%s\n" stream.write(fs % msg) self.flush() except (KeyboardInterrupt, SystemExit): raise except Exception: self.handleError(record) class VirtHelpFormatter(argparse.RawDescriptionHelpFormatter): ''' Subclass the default help formatter to allow printing newline characters in --help output. The way we do this is a huge hack :( Inspiration: http://groups.google.com/group/comp.lang.python/browse_thread/thread/6df6e6b541a15bc2/09f28e26af0699b1 ''' oldwrap = None # pylint: disable=arguments-differ def _split_lines(self, *args, **kwargs): def return_default(): return argparse.RawDescriptionHelpFormatter._split_lines( self, *args, **kwargs) if len(kwargs) != 0 and len(args) != 2: return return_default() try: text = args[0] if "\n" in text: return text.splitlines() return return_default() except Exception: return return_default() def setupParser(usage, description, introspection_epilog=False): epilog = _("See man page for examples and full option syntax.") if introspection_epilog: epilog = _("Use '--option=?' or '--option help' to see " "available suboptions") + "\n" + epilog parser = argparse.ArgumentParser( usage=usage, description=description, formatter_class=VirtHelpFormatter, epilog=epilog) parser.add_argument('--version', action='version', version=CLIConfig.version) return parser def earlyLogging(): logging.basicConfig(level=logging.DEBUG, format='%(message)s') def setupLogging(appname, debug_stdout, do_quiet, cli_app=True): _reset_global_state() get_global_state().quiet = do_quiet vi_dir = None logfile = None if not _in_testsuite(): vi_dir = util.get_cache_dir() logfile = os.path.join(vi_dir, appname + ".log") try: if vi_dir and not os.access(vi_dir, os.W_OK): if os.path.exists(vi_dir): raise RuntimeError("No write access to directory %s" % vi_dir) try: os.makedirs(vi_dir, 0o751) except IOError as e: raise RuntimeError("Could not create directory %s: %s" % (vi_dir, e)) if (logfile and os.path.exists(logfile) and not os.access(logfile, os.W_OK)): raise RuntimeError("No write access to logfile %s" % logfile) except Exception as e: logging.warning("Error setting up logfile: %s", e) logfile = None dateFormat = "%a, %d %b %Y %H:%M:%S" fileFormat = ("[%(asctime)s " + appname + " %(process)d] " "%(levelname)s (%(module)s:%(lineno)d) %(message)s") streamErrorFormat = "%(levelname)-8s %(message)s" rootLogger = logging.getLogger() # Undo early logging for handler in rootLogger.handlers: rootLogger.removeHandler(handler) rootLogger.setLevel(logging.DEBUG) if logfile: fileHandler = logging.handlers.RotatingFileHandler( logfile, "ae", 1024 * 1024, 5) fileHandler.setFormatter( logging.Formatter(fileFormat, dateFormat)) rootLogger.addHandler(fileHandler) streamHandler = VirtStreamHandler(sys.stderr) if debug_stdout: streamHandler.setLevel(logging.DEBUG) streamHandler.setFormatter(logging.Formatter(fileFormat, dateFormat)) elif cli_app or not logfile: if get_global_state().quiet: level = logging.ERROR else: level = logging.WARN streamHandler.setLevel(level) streamHandler.setFormatter(logging.Formatter(streamErrorFormat)) else: streamHandler = None if streamHandler: rootLogger.addHandler(streamHandler) util.register_libvirt_error_handler() # Log uncaught exceptions def exception_log(typ, val, tb): logging.debug("Uncaught exception:\n%s", "".join(traceback.format_exception(typ, val, tb))) sys.__excepthook__(typ, val, tb) sys.excepthook = exception_log logging.getLogger("requests").setLevel(logging.ERROR) # Log the app command string logging.debug("Launched with command line: %s", " ".join(sys.argv)) def _in_testsuite(): return "VIRTINST_TEST_SUITE" in os.environ ############################## # Libvirt connection helpers # ############################## def getConnection(uri): from .connection import VirtualConnection logging.debug("Requesting libvirt URI %s", (uri or "default")) conn = VirtualConnection(uri) conn.open(_do_creds_authname) logging.debug("Received libvirt URI %s", conn.uri) return conn # SASL username/pass auth def _do_creds_authname(creds): retindex = 4 for cred in creds: credtype, prompt, ignore, ignore, ignore = cred prompt += ": " res = cred[retindex] if credtype == libvirt.VIR_CRED_AUTHNAME: res = raw_input(prompt) elif credtype == libvirt.VIR_CRED_PASSPHRASE: import getpass res = getpass.getpass(prompt) else: raise RuntimeError("Unknown auth type in creds callback: %d" % credtype) cred[retindex] = res return 0 ############################## # Misc CLI utility functions # ############################## def fail(msg, do_exit=True): """ Convenience function when failing in cli app """ logging.debug("".join(traceback.format_stack())) logging.error(msg) if traceback.format_exc().strip() != "None": logging.debug("", exc_info=True) if do_exit: _fail_exit() def print_stdout(msg, do_force=False): if do_force or not get_global_state().quiet: print(msg) def print_stderr(msg): logging.debug(msg) print(msg, file=sys.stderr) def _fail_exit(): sys.exit(1) def nice_exit(): print_stdout(_("Exiting at user request.")) sys.exit(0) def virsh_start_cmd(guest): return ("virsh --connect %s start %s" % (guest.conn.uri, guest.name)) def install_fail(guest): virshcmd = virsh_start_cmd(guest) print_stderr( _("Domain installation does not appear to have been successful.\n" "If it was, you can restart your domain by running:\n" " %s\n" "otherwise, please restart your installation.") % virshcmd) sys.exit(1) def set_prompt(prompt): # Set whether we allow prompts, or fail if a prompt pops up if prompt: logging.warning("--prompt mode is no longer supported.") def validate_disk(dev, warn_overwrite=False): def _optional_fail(msg, checkname, warn_on_skip=True): do_check = get_global_state().get_validation_check(checkname) if do_check: fail(msg + (_(" (Use --check %s=off or " "--check all=off to override)") % checkname)) logging.debug("Skipping --check %s error condition '%s'", checkname, msg) if warn_on_skip: logging.warning(msg) def check_path_exists(dev): """ Prompt if disk file already exists and preserve mode is not used """ if not warn_overwrite: return if not VirtualDisk.path_definitely_exists(dev.conn, dev.path): return _optional_fail( _("This will overwrite the existing path '%s'") % dev.path, "path_exists") def check_inuse_conflict(dev): """ Check if disk is inuse by another guest """ names = dev.is_conflict_disk() if not names: return _optional_fail(_("Disk %s is already in use by other guests %s." % (dev.path, names)), "path_in_use") def check_size_conflict(dev): """ Check if specified size exceeds available storage """ isfatal, errmsg = dev.is_size_conflict() # The isfatal case should have already caused us to fail if not isfatal and errmsg: _optional_fail(errmsg, "disk_size", warn_on_skip=False) def check_path_search(dev): user, broken_paths = dev.check_path_search(dev.conn, dev.path) if not broken_paths: return logging.warning(_("%s may not be accessible by the hypervisor. " "You will need to grant the '%s' user search permissions for " "the following directories: %s"), dev.path, user, broken_paths) check_path_exists(dev) check_inuse_conflict(dev) check_size_conflict(dev) check_path_search(dev) def _run_console(guest, args): logging.debug("Running: %s", " ".join(args)) if _in_testsuite(): # Add this destroy() in here to trigger more virt-install code # for the test suite guest.domain.destroy() return None child = os.fork() if child: return child os.execvp(args[0], args) os._exit(1) # pylint: disable=protected-access def _gfx_console(guest): args = ["virt-viewer", "--connect", guest.conn.uri, "--wait", guest.name] # Currently virt-viewer needs attaching to the local display while # spice gl is enabled or listen type none is used. if guest.has_gl() or guest.has_listen_none(): args.append("--attach") logging.debug("Launching virt-viewer for graphics type '%s'", guest.get_devices("graphics")[0].type) return _run_console(guest, args) def _txt_console(guest): args = ["virsh", "--connect", guest.conn.uri, "console", guest.name] logging.debug("Connecting to text console") return _run_console(guest, args) def connect_console(guest, consolecb, wait): """ Launched the passed console callback for the already defined domain. If domain isn't running, return an error. """ child = None if consolecb: child = consolecb(guest) if not child or not wait: return # If we connected the console, wait for it to finish try: os.waitpid(child, 0) except OSError as e: logging.debug("waitpid error: %s", e) def get_console_cb(guest): gdevs = guest.get_devices("graphics") if not gdevs: return _txt_console gtype = gdevs[0].type if gtype not in ["default", VirtualGraphics.TYPE_VNC, VirtualGraphics.TYPE_SPICE]: logging.debug("No viewer to launch for graphics type '%s'", gtype) return if not _in_testsuite(): try: subprocess.check_output(["virt-viewer", "--version"]) except OSError: logging.warning(_("Unable to connect to graphical console: " "virt-viewer not installed. Please install " "the 'virt-viewer' package.")) return None if not os.environ.get("DISPLAY", ""): logging.warning(_("Graphics requested but DISPLAY is not set. " "Not running virt-viewer.")) return None return _gfx_console def get_meter(): quiet = (get_global_state().quiet or _in_testsuite()) return util.make_meter(quiet=quiet) ########################### # Common CLI option/group # ########################### def add_connect_option(parser, invoker=None): if invoker == "virt-xml": parser.add_argument("-c", "--connect", metavar="URI", help=_("Connect to hypervisor with libvirt URI")) else: parser.add_argument("--connect", metavar="URI", help=_("Connect to hypervisor with libvirt URI")) def add_misc_options(grp, prompt=False, replace=False, printxml=False, printstep=False, noreboot=False, dryrun=False, noautoconsole=False): if prompt: grp.add_argument("--prompt", action="store_true", default=False, help=argparse.SUPPRESS) grp.add_argument("--force", action="store_true", default=False, help=argparse.SUPPRESS) if noautoconsole: grp.add_argument("--noautoconsole", action="store_false", dest="autoconsole", default=True, help=_("Don't automatically try to connect to the guest console")) if noreboot: grp.add_argument("--noreboot", action="store_true", help=_("Don't boot guest after completing install.")) if replace: grp.add_argument("--replace", action="store_true", help=_("Don't check name collision, overwrite any guest " "with the same name.")) if printxml: print_kwargs = { "dest": "xmlonly", "default": False, "help": _("Print the generated domain XML rather than create " "the guest."), } if printstep: print_kwargs["nargs"] = "?" print_kwargs["const"] = "all" else: print_kwargs["action"] = "store_true" grp.add_argument("--print-xml", **print_kwargs) if printstep: # Back compat, argparse allows us to use --print-xml # for everything. grp.add_argument("--print-step", dest="xmlstep", help=argparse.SUPPRESS) if dryrun: grp.add_argument("--dry-run", action="store_true", dest="dry", help=_("Run through install process, but do not " "create devices or define the guest.")) if prompt: grp.add_argument("--check", help=_("Enable or disable validation checks. Example:\n" "--check path_in_use=off\n" "--check all=off")) grp.add_argument("-q", "--quiet", action="store_true", help=_("Suppress non-error output")) grp.add_argument("-d", "--debug", action="store_true", help=_("Print debugging information")) def add_metadata_option(grp): grp.add_argument("--metadata", help=_("Configure guest metadata. Ex:\n" "--metadata name=foo,title=\"My pretty title\",uuid=...\n" "--metadata description=\"My nice long description\"")) def add_memory_option(grp, backcompat=False): grp.add_argument("--memory", help=_("Configure guest memory allocation. Ex:\n" "--memory 1024 (in MiB)\n" "--memory 512,maxmemory=1024\n" "--memory 512,maxmemory=1024,hotplugmemorymax=2048," "hotplugmemoryslots=2")) if backcompat: grp.add_argument("-r", "--ram", type=int, dest="oldmemory", help=argparse.SUPPRESS) def vcpu_cli_options(grp, backcompat=True, editexample=False): grp.add_argument("--vcpus", help=_("Number of vcpus to configure for your guest. Ex:\n" "--vcpus 5\n" "--vcpus 5,maxcpus=10,cpuset=1-4,6,8\n" "--vcpus sockets=2,cores=4,threads=2,")) extramsg = "--cpu host" if editexample: extramsg = "--cpu host-model,clearxml=yes" grp.add_argument("--cpu", help=_("CPU model and features. Ex:\n" "--cpu coreduo,+x2apic\n" "--cpu host-passthrough\n") + extramsg) if backcompat: grp.add_argument("--check-cpu", action="store_true", help=argparse.SUPPRESS) grp.add_argument("--cpuset", help=argparse.SUPPRESS) def add_gfx_option(devg): devg.add_argument("--graphics", action="append", help=_("Configure guest display settings. Ex:\n" "--graphics vnc\n" "--graphics spice,port=5901,tlsport=5902\n" "--graphics none\n" "--graphics vnc,password=foobar,port=5910,keymap=ja")) def add_net_option(devg): devg.add_argument("-w", "--network", action="append", help=_("Configure a guest network interface. Ex:\n" "--network bridge=mybr0\n" "--network network=my_libvirt_virtual_net\n" "--network network=mynet,model=virtio,mac=00:11...\n" "--network none\n" "--network help")) def add_device_options(devg, sound_back_compat=False): devg.add_argument("--controller", action="append", help=_("Configure a guest controller device. Ex:\n" "--controller type=usb,model=ich9-ehci1")) devg.add_argument("--input", action="append", help=_("Configure a guest input device. Ex:\n" "--input tablet\n" "--input keyboard,bus=usb")) devg.add_argument("--serial", action="append", help=_("Configure a guest serial device")) devg.add_argument("--parallel", action="append", help=_("Configure a guest parallel device")) devg.add_argument("--channel", action="append", help=_("Configure a guest communication channel")) devg.add_argument("--console", action="append", help=_("Configure a text console connection between " "the guest and host")) devg.add_argument("--hostdev", action="append", help=_("Configure physical USB/PCI/etc host devices " "to be shared with the guest")) devg.add_argument("--filesystem", action="append", help=_("Pass host directory to the guest. Ex: \n" "--filesystem /my/source/dir,/dir/in/guest\n" "--filesystem template_name,/,type=template")) # Back compat name devg.add_argument("--host-device", action="append", dest="hostdev", help=argparse.SUPPRESS) # --sound used to be a boolean option, hence the nargs handling sound_kwargs = { "action": "append", "help": _("Configure guest sound device emulation"), } if sound_back_compat: sound_kwargs["nargs"] = '?' devg.add_argument("--sound", **sound_kwargs) if sound_back_compat: devg.add_argument("--soundhw", action="append", dest="sound", help=argparse.SUPPRESS) devg.add_argument("--watchdog", action="append", help=_("Configure a guest watchdog device")) devg.add_argument("--video", action="append", help=_("Configure guest video hardware.")) devg.add_argument("--smartcard", action="append", help=_("Configure a guest smartcard device. Ex:\n" "--smartcard mode=passthrough")) devg.add_argument("--redirdev", action="append", help=_("Configure a guest redirection device. Ex:\n" "--redirdev usb,type=tcp,server=192.168.1.1:4000")) devg.add_argument("--memballoon", action="append", help=_("Configure a guest memballoon device. Ex:\n" "--memballoon model=virtio")) devg.add_argument("--tpm", action="append", help=_("Configure a guest TPM device. Ex:\n" "--tpm /dev/tpm")) devg.add_argument("--rng", action="append", help=_("Configure a guest RNG device. Ex:\n" "--rng /dev/urandom")) devg.add_argument("--panic", action="append", help=_("Configure a guest panic device. Ex:\n" "--panic default")) devg.add_argument("--memdev", action="append", help=_("Configure a guest memory device. Ex:\n" "--memdev dimm,target_size=1024")) def add_guest_xml_options(geng): geng.add_argument("--security", action="append", help=_("Set domain security driver configuration.")) geng.add_argument("--cputune", help=_("Tune CPU parameters for the domain process.")) geng.add_argument("--numatune", help=_("Tune NUMA policy for the domain process.")) geng.add_argument("--memtune", action="append", help=_("Tune memory policy for the domain process.")) geng.add_argument("--blkiotune", action="append", help=_("Tune blkio policy for the domain process.")) geng.add_argument("--memorybacking", action="append", help=_("Set memory backing policy for the domain process. Ex:\n" "--memorybacking hugepages=on")) geng.add_argument("--features", help=_("Set domain XML. Ex:\n" "--features acpi=off\n" "--features apic=on,eoi=on")) geng.add_argument("--clock", help=_("Set domain XML. Ex:\n" "--clock offset=localtime,rtc_tickpolicy=catchup")) geng.add_argument("--pm", help=_("Configure VM power management features")) geng.add_argument("--events", help=_("Configure VM lifecycle management policy")) geng.add_argument("--resource", action="append", help=_("Configure VM resource partitioning (cgroups)")) geng.add_argument("--sysinfo", action="append", help=_("Configure SMBIOS System Information. Ex:\n" "--sysinfo emulate\n" "--sysinfo host\n" "--sysinfo bios_vendor=Vendor_Inc.,bios_version=1.2.3-abc,...\n" "--sysinfo system_manufacturer=System_Corp.,system_product=Computer,...\n" "--sysinfo baseBoard_manufacturer=Baseboard_Corp.,baseBoard_product=Motherboard,...\n")) geng.add_argument("--qemu-commandline", action="append", help=_("Pass arguments directly to the qemu emulator. Ex:\n" "--qemu-commandline='-display gtk,gl=on'\n" "--qemu-commandline env=DISPLAY=:0.1")) def add_boot_options(insg): insg.add_argument("--boot", help=_("Configure guest boot settings. Ex:\n" "--boot hd,cdrom,menu=on\n" "--boot init=/sbin/init (for containers)")) insg.add_argument("--idmap", help=_("Enable user namespace for LXC container. Ex:\n" "--idmap uid_start=0,uid_target=1000,uid_count=10")) def add_disk_option(stog, editexample=False): editmsg = "" if editexample: editmsg += "\n--disk cache= (unset cache)" stog.add_argument("--disk", action="append", help=_("Specify storage with various options. Ex.\n" "--disk size=10 (new 10GiB image in default location)\n" "--disk /my/existing/disk,cache=none\n" "--disk device=cdrom,bus=scsi\n" "--disk=?") + editmsg) ############################################# # CLI complex parsing helpers # # (for options like --disk, --network, etc. # ############################################# def _raw_on_off_convert(s): tvalues = ["y", "yes", "1", "true", "t", "on"] fvalues = ["n", "no", "0", "false", "f", "off"] s = (s or "").lower() if s in tvalues: return True elif s in fvalues: return False return None def _on_off_convert(key, val): if val is None: return None val = _raw_on_off_convert(val) if val is not None: return val raise fail(_("%(key)s must be 'yes' or 'no'") % {"key": key}) def _set_attribute(obj, attr, val): # pylint: disable=unused-argument exec("obj." + attr + " = val ") # pylint: disable=exec-used class _VirtCLIArgumentStatic(object): """ Helper class to hold all of the static data we need for knowing how to parse a cli subargument, like --disk path=, or --network mac=. @attrname: The virtinst API attribute name the cliargument maps to. If this is a virtinst object method, it will be called. @cliname: The command line option name, 'path' for path=FOO @cb: Rather than set an attribute directly on the virtinst object, (self, inst, val, virtarg) to this callback to handle it. @ignore_default: If the value passed on the cli is 'default', don't do anything. @can_comma: If True, this option is expected to have embedded commas. After the parser sees this option, it will iterate over the option string until it finds another known argument name: everything prior to that argument name is considered part of the value of this option, '=' included. Should be used sparingly. @aliases: List of cli aliases. Useful if we want to change a property name on the cli but maintain back compat. @is_list: This value should be stored as a list, so multiple instances are appended. @is_onoff: The value expected on the cli is on/off or yes/no, convert it to true/false. @lookup_cb: If specified, use this function for performing match lookups. @is_novalue: If specified, the parameter is not expected in the form FOO=BAR, but just FOO. @find_inst_cb: If specified, this can be used to return a different 'inst' to check and set attributes against. For example, VirtualDisk has multiple seclabel children, this provides a hook to lookup the specified child object. """ def __init__(self, attrname, cliname, cb=None, can_comma=None, ignore_default=False, aliases=None, is_list=False, is_onoff=False, lookup_cb=None, is_novalue=False, find_inst_cb=None): self.attrname = attrname self.cliname = cliname self.cb = cb self.can_comma = can_comma self.ignore_default = ignore_default self.aliases = aliases self.is_list = is_list self.is_onoff = is_onoff self.lookup_cb = lookup_cb self.is_novalue = is_novalue self.find_inst_cb = find_inst_cb def match_name(self, cliname): """ Return True if the passed argument name matches this VirtCLIArgument. So for an option like --foo bar=X, this checks if we are the parser for 'bar' """ for argname in [self.cliname] + util.listify(self.aliases): if re.match("^%s$" % argname, cliname): return True return False class _VirtCLIArgument(object): """ A class that combines the static parsing data _VirtCLIArgumentStatic with actual values passed on the command line. """ def __init__(self, virtarg, key, val): """ Instantiate a VirtCLIArgument with the actual key=val pair from the command line. """ # Sanitize the value if val is None: if not virtarg.is_novalue: raise RuntimeError("Option '%s' had no value set." % key) val = "" if val == "": val = None if virtarg.is_onoff: val = _on_off_convert(key, val) self.val = val self.key = key self._virtarg = virtarg # For convenience self.attrname = virtarg.attrname self.cliname = virtarg.cliname def parse_param(self, parser, inst, support_cb): """ Process the cli param against the pass inst. So if we are VirtCLIArgument for --disk device=, and the user specified --disk device=foo, we were instanciated with key=device val=foo, so set inst.device = foo """ if support_cb: support_cb(inst, self) if self.val == "default" and self._virtarg.ignore_default: return if self._virtarg.find_inst_cb: inst = self._virtarg.find_inst_cb(parser, inst, self.val, self, True) try: if self.attrname: eval("inst." + self.attrname) # pylint: disable=eval-used except AttributeError: raise RuntimeError("programming error: obj=%s does not have " "member=%s" % (inst, self.attrname)) if self._virtarg.cb: self._virtarg.cb(parser, inst, self.val, self) else: _set_attribute(inst, self.attrname, self.val) def lookup_param(self, parser, inst): """ See if the passed value matches our Argument, like via virt-xml So if this Argument is for --disk device=, and the user specified virt-xml --edit device=floppy --disk ..., we were instantiated with key=device val=floppy, so return 'inst.device == floppy' """ if not self.attrname and not self._virtarg.lookup_cb: raise RuntimeError( _("Don't know how to match device type '%(device_type)s' " "property '%(property_name)s'") % {"device_type": getattr(inst, "virtual_device_type", ""), "property_name": self.key}) if self._virtarg.find_inst_cb: inst = self._virtarg.find_inst_cb(parser, inst, self.val, self, False) if not inst: return False if self._virtarg.lookup_cb: return self._virtarg.lookup_cb(parser, inst, self.val, self) else: return eval( # pylint: disable=eval-used "inst." + self.attrname) == self.val def parse_optstr_tuples(optstr): """ Parse the command string into an ordered list of tuples. So a string like --disk path=foo,size=5,path=bar will end up like [("path", "foo"), ("size", "5"), ("path", "bar")] """ argsplitter = shlex.shlex(optstr or "", posix=True) argsplitter.commenters = "" argsplitter.whitespace = "," argsplitter.whitespace_split = True ret = [] for opt in list(argsplitter): if not opt: continue if opt.count("="): cliname, val = opt.split("=", 1) else: cliname = opt val = None ret.append((cliname, val)) return ret def _parse_optstr_to_dict(optstr, virtargs, remove_first): """ Parse the passed argument string into an OrderedDict WRT the passed list of VirtCLIArguments and their special handling. So for --disk path=foo,size=5, optstr is 'path=foo,size=5', and we return {"path": "foo", "size": "5"} """ optdict = collections.OrderedDict() opttuples = parse_optstr_tuples(optstr) def _add_opt(virtarg, cliname, val): if (cliname not in optdict and virtarg.is_list): optdict[cliname] = [] if isinstance(optdict.get(cliname), list): optdict[cliname].append(val) else: optdict[cliname] = val def _lookup_virtarg(cliname): for virtarg in virtargs: if virtarg.match_name(cliname): return virtarg def _consume_comma_arg(commaopt): while opttuples: cliname, val = opttuples[0] if _lookup_virtarg(cliname): # Next tuple is for an actual virtarg break # Next tuple is a continuation of the comma argument, # sum it up opttuples.pop(0) commaopt[1] += "," + cliname if val: commaopt[1] += "=" + val return commaopt # Splice in remove_first names upfront for idx, (cliname, val) in enumerate(opttuples): if val is not None or not remove_first: break opttuples[idx] = (remove_first.pop(0), cliname) while opttuples: cliname, val = opttuples.pop(0) virtarg = _lookup_virtarg(cliname) if not virtarg: optdict[cliname] = val continue if virtarg.can_comma: commaopt = _consume_comma_arg([cliname, val]) _add_opt(virtarg, commaopt[0], commaopt[1]) else: _add_opt(virtarg, cliname, val) return optdict class VirtCLIParser(object): """ Parse a compound arg string like --option foo=bar,baz=12. This is the desired interface to VirtCLIArgument and VirtCLIOptionString. A command line argument like --disk just extends this interface and calls add_arg a bunch to register subarguments like path=, size=, etc. See existing impls examples of how to do all sorts of crazy stuff. Class parameters: @remove_first: List of parameters to peel off the front of the option string, and store in the optdict. So: remove_first=["char_type"] for --serial pty,foo=bar maps to {"char_type", "pty", "foo": "bar"} @stub_none: If the parsed option string is just 'none', make it a no-op. This helps us be backwards compatible: for example, --rng none is a no-op, but one day we decide to add an rng device by default to certain VMs, and --rng none is extended to handle that. --rng none can be added to users command lines and it will give the expected results regardless of the virt-install version. @support_cb: An extra support check function for further validation. Called before the virtinst object is altered. Take arguments (inst, attrname, cliname) @clear_attr: If the user requests to clear the XML (--disk clearxml), this is the property name we grab from inst to actually clear (so 'security' to get guest.security). If it's True, then clear inst (in the case of devices) @cli_arg_name: The command line argument this maps to, so "hostdev" for --hostdev """ objclass = None remove_first = None stub_none = True support_cb = None clear_attr = None cli_arg_name = None _virtargs = [] @classmethod def add_arg(cls, *args, **kwargs): """ Add a VirtCLIArgument for this class. """ if not cls._virtargs: cls._virtargs = [_VirtCLIArgumentStatic( None, "clearxml", cb=cls._clearxml_cb, is_onoff=True)] cls._virtargs.append(_VirtCLIArgumentStatic(*args, **kwargs)) @classmethod def print_introspection(cls): """ Print out all _param names, triggered via ex. --disk help """ print("--%s options:" % cls.cli_arg_name) for arg in sorted(cls._virtargs, key=lambda p: p.cliname): print(" %s" % arg.cliname) print("") def __init__(self, guest, optstr): self.guest = guest self.optstr = optstr self.optdict = _parse_optstr_to_dict(self.optstr, self._virtargs, util.listify(self.remove_first)[:]) def _clearxml_cb(self, inst, val, virtarg): """ Callback that handles virt-xml clearxml=yes|no magic """ if not self.objclass and not self.clear_attr: raise RuntimeError("Don't know how to clearxml --%s" % self.cli_arg_name) if val is not True: return clear_inst = inst if self.clear_attr: clear_inst = getattr(inst, self.clear_attr) # If there's any opts remaining, leave the root stub element # in place with leave_stub=True, so virt-xml updates are done # in place. # # Example: --edit --cpu clearxml=yes should remove the # block. But --edit --cpu clearxml=yes,model=foo should leave # a stub in place, so that it gets model=foo in place, # otherwise the newly created cpu block gets appended to the # end of the domain XML, which gives an ugly diff clear_inst.clear(leave_stub="," in self.optstr) def _make_find_inst_cb(self, cliarg, objpropname, objaddfn): """ Create a callback used for find_inst_cb command line lookup. :param cliarg: The cliarg string that is followed by an index. Example, for --disk seclabel[0-9]* mapping, this is 'seclabel' :param objpropname: The property name on the virtinst object that this parameter maps too. For the seclabel example, we want disk.seclabels, so this value is 'seclabels' :param objaddfn: The function name for adding a new instance of this parameter to the virtinst object. For the seclabel example, we want disk.add_seclabel(), so this value is "add_seclabels" """ def cb(inst, val, virtarg, can_edit): ignore = val num = 0 reg = re.search("%s(\d+)" % cliarg, virtarg.key) if reg: num = int(reg.groups()[0]) if can_edit: while len(getattr(inst, objpropname)) < (num + 1): getattr(inst, objaddfn)() try: return getattr(inst, objpropname)[num] except IndexError: if not can_edit: return None raise return cb def _optdict_to_param_list(self, optdict): """ Convert the passed optdict to a list of instantiated VirtCLIArguments to actually interact with """ ret = [] for virtargstatic in self._virtargs: for key in list(optdict.keys()): if virtargstatic.match_name(key): arginst = _VirtCLIArgument(virtargstatic, key, optdict.pop(key)) ret.append(arginst) return ret def _check_leftover_opts(self, optdict): """ Used to check if there were any unprocessed entries in the optdict after we should have emptied it. Like if the user passed an invalid argument such as --disk idontexist=foo """ if optdict: fail(_("Unknown options %s") % optdict.keys()) def _parse(self, inst): """ Subclasses can hook into this to do any pre/post processing of the inst, or self.optdict """ optdict = self.optdict.copy() for param in self._optdict_to_param_list(optdict): param.parse_param(self, inst, self.support_cb) self._check_leftover_opts(optdict) return inst def parse(self, inst, validate=True): """ Main entry point. Iterate over self._virtargs, and serialize self.optdict into 'inst'. For virt-xml, 'inst' is the virtinst object we are editing, ex. a VirtualDisk from a parsed Guest object. For virt-install, 'inst' is None, and we will create a new inst from self.objclass, or edit a singleton object in place like Guest.features/DomainFeatures """ if not self.optstr: return None if self.stub_none and self.optstr == "none": return None new_object = False if self.objclass and not inst: if self.guest.child_class_is_singleton(self.objclass): inst = self.guest.list_children_for_class(self.objclass)[0] else: new_object = True inst = self.objclass( # pylint: disable=not-callable self.guest.conn) ret = [] try: objs = self._parse(inst or self.guest) for obj in util.listify(objs): if not new_object: break if validate: obj.validate() self.guest.add_child(obj) ret += util.listify(objs) except Exception as e: logging.debug("Exception parsing inst=%s optstr=%s", inst, self.optstr, exc_info=True) fail(_("Error: --%(cli_arg_name)s %(options)s: %(err)s") % {"cli_arg_name": self.cli_arg_name, "options": self.optstr, "err": str(e)}) return ret def lookup_child_from_option_string(self): """ Given a passed option string, search the guests' child list for all objects which match the passed options. Used only by virt-xml --edit lookups """ ret = [] objlist = self.guest.list_children_for_class(self.objclass) try: for inst in objlist: optdict = self.optdict.copy() valid = True for param in self._optdict_to_param_list(optdict): paramret = param.lookup_param(self, inst) if paramret is False: valid = False break if valid: ret.append(inst) self._check_leftover_opts(optdict) except Exception as e: logging.debug("Exception parsing inst=%s optstr=%s", inst, self.optstr, exc_info=True) fail(_("Error: --%(cli_arg_name)s %(options)s: %(err)s") % {"cli_arg_name": self.cli_arg_name, "options": self.optstr, "err": str(e)}) return ret VIRT_PARSERS = [] def _register_virt_parser(parserclass): VIRT_PARSERS.append(parserclass) ################### # --check parsing # ################### def convert_old_force(options): if options.force: if not options.check: options.check = "all=off" del(options.force) class ParseCLICheck(VirtCLIParser): cli_arg_name = "check" def set_cb(self, inst, val, virtarg): # This sets properties on the _GlobalState objects inst.set_validation_check(virtarg.cliname, val) ParseCLICheck.add_arg(None, "path_in_use", is_onoff=True, cb=ParseCLICheck.set_cb) ParseCLICheck.add_arg(None, "disk_size", is_onoff=True, cb=ParseCLICheck.set_cb) ParseCLICheck.add_arg(None, "path_exists", is_onoff=True, cb=ParseCLICheck.set_cb) ParseCLICheck.add_arg("all_checks", "all", is_onoff=True) def parse_check(checkstr): # Overwrite this for each parse parser = ParseCLICheck(None, checkstr) parser.parse(get_global_state()) ###################### # --metadata parsing # ###################### class ParserMetadata(VirtCLIParser): cli_arg_name = "metadata" _register_virt_parser(ParserMetadata) ParserMetadata.add_arg("name", "name", can_comma=True) ParserMetadata.add_arg("title", "title", can_comma=True) ParserMetadata.add_arg("uuid", "uuid") ParserMetadata.add_arg("description", "description", can_comma=True) #################### # --events parsing # #################### class ParserEvents(VirtCLIParser): cli_arg_name = "events" _register_virt_parser(ParserEvents) ParserEvents.add_arg("on_poweroff", "on_poweroff") ParserEvents.add_arg("on_reboot", "on_reboot") ParserEvents.add_arg("on_crash", "on_crash") ParserEvents.add_arg("on_lockfailure", "on_lockfailure") ###################### # --resource parsing # ###################### class ParserResource(VirtCLIParser): cli_arg_name = "resource" objclass = DomainResource remove_first = "partition" _register_virt_parser(ParserResource) ParserResource.add_arg("partition", "partition") ###################### # --numatune parsing # ###################### class ParserNumatune(VirtCLIParser): cli_arg_name = "numatune" objclass = DomainNumatune remove_first = "nodeset" _register_virt_parser(ParserNumatune) ParserNumatune.add_arg("memory_nodeset", "nodeset", can_comma=True) ParserNumatune.add_arg("memory_mode", "mode") #################### # --memory parsing # #################### class ParserMemory(VirtCLIParser): cli_arg_name = "memory" remove_first = "memory" def set_memory_cb(self, inst, val, virtarg): setattr(inst, virtarg.cliname, int(val) * 1024) _register_virt_parser(ParserMemory) ParserMemory.add_arg("memory", "memory", cb=ParserMemory.set_memory_cb) ParserMemory.add_arg("maxmemory", "maxmemory", cb=ParserMemory.set_memory_cb) ParserMemory.add_arg("memoryBacking.hugepages", "hugepages", is_onoff=True) ParserMemory.add_arg("hotplugmemorymax", "hotplugmemorymax", cb=ParserMemory.set_memory_cb) ParserMemory.add_arg("hotplugmemoryslots", "hotplugmemoryslots") ##################### # --memtune parsing # ##################### class ParserMemorytune(VirtCLIParser): cli_arg_name = "memtune" objclass = DomainMemorytune remove_first = "soft_limit" _register_virt_parser(ParserMemorytune) ParserMemorytune.add_arg("hard_limit", "hard_limit") ParserMemorytune.add_arg("soft_limit", "soft_limit") ParserMemorytune.add_arg("swap_hard_limit", "swap_hard_limit") ParserMemorytune.add_arg("min_guarantee", "min_guarantee") ####################### # --blkiotune parsing # ####################### class ParserBlkiotune(VirtCLIParser): cli_arg_name = "blkiotune" objclass = DomainBlkiotune remove_first = "weight" _register_virt_parser(ParserBlkiotune) ParserBlkiotune.add_arg("weight", "weight") ParserBlkiotune.add_arg("device_path", "device_path") ParserBlkiotune.add_arg("device_weight", "device_weight") ########################### # --memorybacking parsing # ########################### class ParserMemorybacking(VirtCLIParser): cli_arg_name = "memorybacking" objclass = DomainMemorybacking _register_virt_parser(ParserMemorybacking) ParserMemorybacking.add_arg("hugepages", "hugepages", is_onoff=True) ParserMemorybacking.add_arg("page_size", "size") ParserMemorybacking.add_arg("page_unit", "unit") ParserMemorybacking.add_arg("page_nodeset", "nodeset", can_comma=True) ParserMemorybacking.add_arg("nosharepages", "nosharepages", is_onoff=True) ParserMemorybacking.add_arg("locked", "locked", is_onoff=True) ################# # --cpu parsing # ################# class ParserCPU(VirtCLIParser): cli_arg_name = "cpu" objclass = CPU remove_first = "model" stub_none = False def cell_find_inst_cb(self, *args, **kwargs): cliarg = "cell" # cell[0-9]* objpropname = "cells" # cpu.cells objaddfn = "add_cell" # cpu.add_cell cb = self._make_find_inst_cb(cliarg, objpropname, objaddfn) return cb(*args, **kwargs) def sibling_find_inst_cb(self, inst, *args, **kwargs): cell = self.cell_find_inst_cb(inst, *args, **kwargs) inst = cell cliarg = "sibling" # cell[0-9]*.distances.sibling[0-9]* objpropname = "siblings" # cell.siblings objaddfn = "add_sibling" # cell.add_sibling cb = self._make_find_inst_cb(cliarg, objpropname, objaddfn) return cb(inst, *args, **kwargs) def set_model_cb(self, inst, val, virtarg): if val == "host": val = inst.SPECIAL_MODE_HOST_MODEL if val == "none": val = inst.SPECIAL_MODE_CLEAR if val in inst.SPECIAL_MODES: inst.set_special_mode(val) else: inst.model = val def set_feature_cb(self, inst, val, virtarg): policy = virtarg.cliname for feature_name in util.listify(val): featureobj = None for f in inst.features: if f.name == feature_name: featureobj = f break if featureobj: featureobj.policy = policy else: inst.add_feature(feature_name, policy) def set_l3_cache_cb(self, inst, val, virtarg, can_edit): cpu = inst if can_edit: cpu.set_l3_cache_mode() try: return cpu.cache[0] except IndexError: if not can_edit: return None raise def _parse(self, inst): # Convert +feature, -feature into expected format for key, value in list(self.optdict.items()): policy = None if value or len(key) == 1: continue if key.startswith("+"): policy = "force" elif key.startswith("-"): policy = "disable" if policy: del(self.optdict[key]) if self.optdict.get(policy) is None: self.optdict[policy] = [] self.optdict[policy].append(key[1:]) return VirtCLIParser._parse(self, inst) _register_virt_parser(ParserCPU) ParserCPU.add_arg(None, "model", cb=ParserCPU.set_model_cb) ParserCPU.add_arg("mode", "mode") ParserCPU.add_arg("match", "match") ParserCPU.add_arg("vendor", "vendor") ParserCPU.add_arg(None, "force", is_list=True, cb=ParserCPU.set_feature_cb) ParserCPU.add_arg(None, "require", is_list=True, cb=ParserCPU.set_feature_cb) ParserCPU.add_arg(None, "optional", is_list=True, cb=ParserCPU.set_feature_cb) ParserCPU.add_arg(None, "disable", is_list=True, cb=ParserCPU.set_feature_cb) ParserCPU.add_arg(None, "forbid", is_list=True, cb=ParserCPU.set_feature_cb) # Options for CPU.cells config ParserCPU.add_arg("id", "cell[0-9]*.id", find_inst_cb=ParserCPU.cell_find_inst_cb) ParserCPU.add_arg("cpus", "cell[0-9]*.cpus", can_comma=True, find_inst_cb=ParserCPU.cell_find_inst_cb) ParserCPU.add_arg("memory", "cell[0-9]*.memory", find_inst_cb=ParserCPU.cell_find_inst_cb) ParserCPU.add_arg("id", "cell[0-9]*.distances.sibling[0-9]*.id", find_inst_cb=ParserCPU.sibling_find_inst_cb) ParserCPU.add_arg("value", "cell[0-9]*.distances.sibling[0-9]*.value", find_inst_cb=ParserCPU.sibling_find_inst_cb) # Options for CPU.cache ParserCPU.add_arg("mode", "cache.mode", find_inst_cb=ParserCPU.set_l3_cache_cb) ParserCPU.add_arg("level", "cache.level", find_inst_cb=ParserCPU.set_l3_cache_cb) ##################### # --cputune parsing # ##################### class ParserCPUTune(VirtCLIParser): cli_arg_name = "cputune" objclass = CPUTune remove_first = "model" stub_none = False def vcpu_find_inst_cb(self, *args, **kwargs): cliarg = "vcpupin" # vcpupin[0-9]* objpropname = "vcpus" objaddfn = "add_vcpu" cb = self._make_find_inst_cb(cliarg, objpropname, objaddfn) return cb(*args, **kwargs) _register_virt_parser(ParserCPUTune) # Options for CPU.vcpus config ParserCPUTune.add_arg("vcpu", "vcpupin[0-9]*.vcpu", find_inst_cb=ParserCPUTune.vcpu_find_inst_cb) ParserCPUTune.add_arg("cpuset", "vcpupin[0-9]*.cpuset", can_comma=True, find_inst_cb=ParserCPUTune.vcpu_find_inst_cb) ################### # --vcpus parsing # ################### class ParserVCPU(VirtCLIParser): cli_arg_name = "vcpus" remove_first = "vcpus" def set_vcpus_cb(self, inst, val, virtarg): attrname = (("maxvcpus" in self.optdict) and "curvcpus" or "vcpus") setattr(inst, attrname, val) def set_cpuset_cb(self, inst, val, virtarg): if not val: return if val != "auto": inst.cpuset = val return # Previously we did our own one-time cpuset placement # based on current NUMA memory availability, but that's # pretty dumb unless the conditions on the host never change. # So instead use newer vcpu placement=, but only if it's # supported. if not inst.conn.check_support( inst.conn.SUPPORT_CONN_VCPU_PLACEMENT): logging.warning("vcpu placement=auto not supported, skipping.") return inst.vcpu_placement = "auto" def _parse(self, inst): set_from_top = ("maxvcpus" not in self.optdict and "vcpus" not in self.optdict) ret = VirtCLIParser._parse(self, inst) if set_from_top: inst.vcpus = inst.cpu.vcpus_from_topology() return ret _register_virt_parser(ParserVCPU) ParserVCPU.add_arg("cpu.sockets", "sockets") ParserVCPU.add_arg("cpu.cores", "cores") ParserVCPU.add_arg("cpu.threads", "threads") ParserVCPU.add_arg(None, "vcpus", cb=ParserVCPU.set_vcpus_cb) ParserVCPU.add_arg("vcpus", "maxvcpus") ParserVCPU.add_arg(None, "cpuset", can_comma=True, cb=ParserVCPU.set_cpuset_cb) ParserVCPU.add_arg("vcpu_placement", "placement") ################## # --boot parsing # ################## class ParserBoot(VirtCLIParser): cli_arg_name = "boot" clear_attr = "os" def set_uefi(self, inst, val, virtarg): ignore = virtarg ignore = val inst.set_uefi_default() def set_initargs_cb(self, inst, val, virtarg): inst.os.set_initargs_string(val) def set_smbios_mode_cb(self, inst, val, virtarg): if not val.startswith("emulate") and not val.startswith("host"): inst.sysinfo.parse(val) val = "sysinfo" inst.os.smbios_mode = val self.optdict["smbios_mode"] = val def set_loader_secure_cb(self, inst, val, virtarg): if not inst.conn.check_support(inst.conn.SUPPORT_DOMAIN_LOADER_SECURE): raise RuntimeError("secure attribute for loader is not supported " "by libvirt.") inst.os.loader_secure = val return val def noset_cb(self, inst, val, virtarg): pass def _parse(self, inst): # Build boot order boot_order = [] for cliname in self.optdict.keys(): if cliname not in inst.os.BOOT_DEVICES: continue del(self.optdict[cliname]) if cliname not in boot_order: boot_order.append(cliname) if boot_order: inst.os.bootorder = boot_order VirtCLIParser._parse(self, inst) _register_virt_parser(ParserBoot) # UEFI depends on these bits, so set them first ParserBoot.add_arg("os.arch", "arch") ParserBoot.add_arg("type", "domain_type") ParserBoot.add_arg("os.os_type", "os_type") ParserBoot.add_arg("emulator", "emulator") ParserBoot.add_arg(None, "uefi", cb=ParserBoot.set_uefi, is_novalue=True) ParserBoot.add_arg("os.useserial", "useserial", is_onoff=True) ParserBoot.add_arg("os.enable_bootmenu", "menu", is_onoff=True) ParserBoot.add_arg("os.kernel", "kernel") ParserBoot.add_arg("os.initrd", "initrd") ParserBoot.add_arg("os.dtb", "dtb") ParserBoot.add_arg("os.loader", "loader") ParserBoot.add_arg("os.loader_ro", "loader_ro", is_onoff=True) ParserBoot.add_arg("os.loader_type", "loader_type") ParserBoot.add_arg("os.loader_secure", "loader_secure", is_onoff=True, cb=ParserBoot.set_loader_secure_cb) ParserBoot.add_arg("os.nvram", "nvram") ParserBoot.add_arg("os.nvram_template", "nvram_template") ParserBoot.add_arg("os.kernel_args", "kernel_args", aliases=["extra_args"], can_comma=True) ParserBoot.add_arg("os.init", "init") ParserBoot.add_arg("os.machine", "machine") ParserBoot.add_arg("os.initargs", "initargs", cb=ParserBoot.set_initargs_cb) ParserBoot.add_arg("os.smbios_mode", "smbios_mode", can_comma=True, cb=ParserBoot.set_smbios_mode_cb) # This is simply so the boot options are advertised with --boot help, # actual processing is handled by _parse for _bootdev in OSXML.BOOT_DEVICES: ParserBoot.add_arg(None, _bootdev, is_novalue=True, cb=ParserBoot.noset_cb) ################### # --idmap parsing # ################### class ParserIdmap(VirtCLIParser): cli_arg_name = "idmap" objclass = IdMap _register_virt_parser(ParserIdmap) ParserIdmap.add_arg("uid_start", "uid_start") ParserIdmap.add_arg("uid_target", "uid_target") ParserIdmap.add_arg("uid_count", "uid_count") ParserIdmap.add_arg("gid_start", "gid_start") ParserIdmap.add_arg("gid_target", "gid_target") ParserIdmap.add_arg("gid_count", "gid_count") ###################### # --security parsing # ###################### class ParserSecurity(VirtCLIParser): cli_arg_name = "security" objclass = Seclabel _register_virt_parser(ParserSecurity) ParserSecurity.add_arg("type", "type") ParserSecurity.add_arg("model", "model") ParserSecurity.add_arg("relabel", "relabel", is_onoff=True) ParserSecurity.add_arg("label", "label", can_comma=True) ParserSecurity.add_arg("baselabel", "label", can_comma=True) ###################### # --features parsing # ###################### class ParserFeatures(VirtCLIParser): cli_arg_name = "features" objclass = DomainFeatures def set_smm_cb(self, inst, val, virtarg): if not inst.conn.check_support(inst.conn.SUPPORT_DOMAIN_FEATURE_SMM): raise RuntimeError("smm is not supported by libvirt") inst.smm = val return val _register_virt_parser(ParserFeatures) ParserFeatures.add_arg("acpi", "acpi", is_onoff=True) ParserFeatures.add_arg("apic", "apic", is_onoff=True) ParserFeatures.add_arg("pae", "pae", is_onoff=True) ParserFeatures.add_arg("privnet", "privnet", is_onoff=True) ParserFeatures.add_arg("hap", "hap", is_onoff=True) ParserFeatures.add_arg("viridian", "viridian", is_onoff=True) ParserFeatures.add_arg("eoi", "eoi", is_onoff=True) ParserFeatures.add_arg("pmu", "pmu", is_onoff=True) ParserFeatures.add_arg("hyperv_reset", "hyperv_reset", is_onoff=True) ParserFeatures.add_arg("hyperv_vapic", "hyperv_vapic", is_onoff=True) ParserFeatures.add_arg("hyperv_relaxed", "hyperv_relaxed", is_onoff=True) ParserFeatures.add_arg("hyperv_spinlocks", "hyperv_spinlocks", is_onoff=True) ParserFeatures.add_arg("hyperv_spinlocks_retries", "hyperv_spinlocks_retries") ParserFeatures.add_arg("hyperv_synic", "hyperv_synic", is_onoff=True) ParserFeatures.add_arg("vmport", "vmport", is_onoff=True) ParserFeatures.add_arg("kvm_hidden", "kvm_hidden", is_onoff=True) ParserFeatures.add_arg("pvspinlock", "pvspinlock", is_onoff=True) ParserFeatures.add_arg("gic_version", "gic_version") ParserFeatures.add_arg("smm", "smm", is_onoff=True, cb=ParserFeatures.set_smm_cb) ################### # --clock parsing # ################### class ParserClock(VirtCLIParser): cli_arg_name = "clock" objclass = Clock def set_timer(self, inst, val, virtarg): tname, attrname = virtarg.cliname.split("_") timerobj = None for t in inst.timers: if t.name == tname: timerobj = t break if not timerobj: timerobj = inst.add_timer() timerobj.name = tname setattr(timerobj, attrname, val) _register_virt_parser(ParserClock) ParserClock.add_arg("offset", "offset") for _tname in Clock.TIMER_NAMES: ParserClock.add_arg(None, _tname + "_present", is_onoff=True, cb=ParserClock.set_timer) ParserClock.add_arg(None, _tname + "_tickpolicy", cb=ParserClock.set_timer) ################ # --pm parsing # ################ class ParserPM(VirtCLIParser): cli_arg_name = "pm" objclass = PM _register_virt_parser(ParserPM) ParserPM.add_arg("suspend_to_mem", "suspend_to_mem", is_onoff=True) ParserPM.add_arg("suspend_to_disk", "suspend_to_disk", is_onoff=True) ##################### # --sysinfo parsing # ##################### class ParserSYSInfo(VirtCLIParser): cli_arg_name = "sysinfo" objclass = SYSInfo remove_first = "type" def set_type_cb(self, inst, val, virtarg): if val == "host" or val == "emulate": self.guest.os.smbios_mode = val elif val == "smbios": self.guest.os.smbios_mode = "sysinfo" inst.type = val else: fail(_("Unknown sysinfo flag '%s'") % val) def set_uuid_cb(self, inst, val, virtarg): # If a uuid is supplied it must match the guest UUID. This would be # impossible to guess if the guest uuid is autogenerated so just # overwrite the guest uuid with what is passed in assuming it passes # the sanity checking below. inst.system_uuid = val self.guest.uuid = val def _parse(self, inst): if self.optstr == "host" or self.optstr == "emulate": self.optdict['type'] = self.optstr elif self.optstr: # If any string specified, default to type=smbios otherwise # libvirt errors. User args can still override this though self.optdict['type'] = 'smbios' return VirtCLIParser._parse(self, inst) _register_virt_parser(ParserSYSInfo) # ParserSYSInfo.add_arg("type", "type", cb=ParserSYSInfo.set_type_cb, can_comma=True) # type 0 BIOS Information ParserSYSInfo.add_arg("bios_vendor", "bios_vendor") ParserSYSInfo.add_arg("bios_version", "bios_version") ParserSYSInfo.add_arg("bios_date", "bios_date") ParserSYSInfo.add_arg("bios_release", "bios_release") # type 1 System Information ParserSYSInfo.add_arg("system_manufacturer", "system_manufacturer") ParserSYSInfo.add_arg("system_product", "system_product") ParserSYSInfo.add_arg("system_version", "system_version") ParserSYSInfo.add_arg("system_serial", "system_serial") ParserSYSInfo.add_arg("system_uuid", "system_uuid", cb=ParserSYSInfo.set_uuid_cb) ParserSYSInfo.add_arg("system_sku", "system_sku") ParserSYSInfo.add_arg("system_family", "system_family") # type 2 Baseboard (or Module) Information ParserSYSInfo.add_arg("baseBoard_manufacturer", "baseBoard_manufacturer") ParserSYSInfo.add_arg("baseBoard_product", "baseBoard_product") ParserSYSInfo.add_arg("baseBoard_version", "baseBoard_version") ParserSYSInfo.add_arg("baseBoard_serial", "baseBoard_serial") ParserSYSInfo.add_arg("baseBoard_asset", "baseBoard_asset") ParserSYSInfo.add_arg("baseBoard_location", "baseBoard_location") ############################## # --qemu-commandline parsing # ############################## class ParserQemuCLI(VirtCLIParser): cli_arg_name = "qemu_commandline" objclass = XMLNSQemu def args_cb(self, inst, val, virtarg): for opt in shlex.split(val): inst.add_arg(opt) def env_cb(self, inst, val, virtarg): name, envval = val.split("=", 1) inst.add_env(name, envval) def _parse(self, inst): self.optdict.clear() if self.optstr.startswith("env="): self.optdict["env"] = self.optstr.split("=", 1)[1] elif self.optstr.startswith("args="): self.optdict["args"] = self.optstr.split("=", 1)[1] elif self.optstr.startswith("clearxml="): self.optdict["clearxml"] = self.optstr.split("=", 1)[1] else: self.optdict["args"] = self.optstr return VirtCLIParser._parse(self, inst) _register_virt_parser(ParserQemuCLI) ParserQemuCLI.add_arg(None, "args", cb=ParserQemuCLI.args_cb, can_comma=True) ParserQemuCLI.add_arg(None, "env", cb=ParserQemuCLI.env_cb, can_comma=True) ########################## # Guest parsing # ########################## def _add_device_address_args(cls): """ Add VirtualDeviceAddress parameters if we are parsing for a device """ cls.add_arg("address.type", "address.type") cls.add_arg("address.domain", "address.domain") cls.add_arg("address.bus", "address.bus") cls.add_arg("address.slot", "address.slot") cls.add_arg("address.multifunction", "address.multifunction", is_onoff=True) cls.add_arg("address.function", "address.function") cls.add_arg("address.controller", "address.controller") cls.add_arg("address.unit", "address.unit") cls.add_arg("address.port", "address.port") cls.add_arg("address.target", "address.target") cls.add_arg("address.reg", "address.reg") cls.add_arg("address.cssid", "address.cssid") cls.add_arg("address.ssid", "address.ssid") cls.add_arg("address.devno", "address.devno") cls.add_arg("address.iobase", "address.iobase") cls.add_arg("address.irq", "address.irq") cls.add_arg("address.base", "address.base") ################## # --disk parsing # ################## def _default_image_file_format(conn): if conn.check_support(conn.SUPPORT_CONN_DEFAULT_QCOW2): return "qcow2" return "raw" def _get_default_image_format(conn, poolobj): tmpvol = StorageVolume(conn) tmpvol.pool = poolobj if tmpvol.file_type != StorageVolume.TYPE_FILE: return None return _default_image_file_format(conn) def _generate_new_volume_name(guest, poolobj, fmt): collidelist = [] for disk in guest.get_devices("disk"): if (disk.get_vol_install() and disk.get_vol_install().pool.name() == poolobj.name()): collidelist.append(os.path.basename(disk.path)) ext = StorageVolume.get_file_extension_for_format(fmt) return StorageVolume.find_free_name( poolobj, guest.name, suffix=ext, collidelist=collidelist) class ParserDisk(VirtCLIParser): cli_arg_name = "disk" objclass = VirtualDisk remove_first = "path" stub_none = False def noset_cb(self, inst, val, virtarg): ignore = self, inst, val, virtarg def seclabel_find_inst_cb(self, *args, **kwargs): cliarg = "seclabel" # seclabel[0-9]* objpropname = "seclabels" # disk.seclabels objaddfn = "add_seclabel" # disk.add_seclabel cb = self._make_find_inst_cb(cliarg, objpropname, objaddfn) return cb(*args, **kwargs) def _parse(self, inst): if self.optstr == "none": return def parse_size(val): if val is None: return None try: return float(val) except Exception as e: fail(_("Improper value for 'size': %s") % str(e)) def convert_perms(val): if val is None: return if val == "ro": self.optdict["readonly"] = "on" elif val == "sh": self.optdict["shareable"] = "on" elif val == "rw": # It's default. Nothing to do. pass else: fail(_("Unknown '%s' value '%s'") % ("perms", val)) has_path = "path" in self.optdict backing_store = self.optdict.pop("backing_store", None) backing_format = self.optdict.pop("backing_format", None) poolname = self.optdict.pop("pool", None) volname = self.optdict.pop("vol", None) size = parse_size(self.optdict.pop("size", None)) fmt = self.optdict.pop("format", None) sparse = _on_off_convert("sparse", self.optdict.pop("sparse", "yes")) convert_perms(self.optdict.pop("perms", None)) has_type_volume = ("source_pool" in self.optdict or "source_volume" in self.optdict) has_type_network = ("source_protocol" in self.optdict) optcount = sum([bool(p) for p in [has_path, poolname, volname, has_type_volume, has_type_network]]) if optcount > 1: fail(_("Cannot specify more than 1 storage path")) if optcount == 0 and size: # Saw something like --disk size=X, have it imply pool=default poolname = "default" if volname: if volname.count("/") != 1: raise ValueError(_("Storage volume must be specified as " "vol=poolname/volname")) poolname, volname = volname.split("/") logging.debug("Parsed --disk volume as: pool=%s vol=%s", poolname, volname) VirtCLIParser._parse(self, inst) # Generate and fill in the disk source info newvolname = None poolobj = None if poolname: if poolname == "default": StoragePool.build_default_pool(self.guest.conn) poolobj = self.guest.conn.storagePoolLookupByName(poolname) if volname: vol_object = poolobj.storageVolLookupByName(volname) inst.set_vol_object(vol_object, poolobj) poolobj = None if ((poolobj or inst.wants_storage_creation()) and (fmt or size or sparse or backing_store)): if not poolobj: poolobj = inst.get_parent_pool() newvolname = os.path.basename(inst.path) if poolobj and not fmt: fmt = _get_default_image_format(self.guest.conn, poolobj) if newvolname is None: newvolname = _generate_new_volume_name(self.guest, poolobj, fmt) vol_install = VirtualDisk.build_vol_install( self.guest.conn, newvolname, poolobj, size, sparse, fmt=fmt, backing_store=backing_store, backing_format=backing_format) inst.set_vol_install(vol_install) if not inst.target: skip_targets = [d.target for d in self.guest.get_devices("disk")] inst.generate_target(skip_targets) inst.cli_generated_target = True return inst _register_virt_parser(ParserDisk) _add_device_address_args(ParserDisk) # These are all handled specially in _parse ParserDisk.add_arg(None, "backing_store", cb=ParserDisk.noset_cb) ParserDisk.add_arg(None, "backing_format", cb=ParserDisk.noset_cb) ParserDisk.add_arg(None, "pool", cb=ParserDisk.noset_cb) ParserDisk.add_arg(None, "vol", cb=ParserDisk.noset_cb) ParserDisk.add_arg(None, "size", cb=ParserDisk.noset_cb) ParserDisk.add_arg(None, "format", cb=ParserDisk.noset_cb) ParserDisk.add_arg(None, "sparse", cb=ParserDisk.noset_cb) ParserDisk.add_arg("source_pool", "source_pool") ParserDisk.add_arg("source_volume", "source_volume") ParserDisk.add_arg("source_name", "source_name") ParserDisk.add_arg("source_protocol", "source_protocol") ParserDisk.add_arg("source_host_name", "source_host_name") ParserDisk.add_arg("source_host_port", "source_host_port") ParserDisk.add_arg("source_host_socket", "source_host_socket") ParserDisk.add_arg("source_host_transport", "source_host_transport") ParserDisk.add_arg("path", "path") ParserDisk.add_arg("device", "device") ParserDisk.add_arg("snapshot_policy", "snapshot_policy") ParserDisk.add_arg("bus", "bus") ParserDisk.add_arg("removable", "removable", is_onoff=True) ParserDisk.add_arg("driver_cache", "cache") ParserDisk.add_arg("driver_discard", "discard") ParserDisk.add_arg("driver_detect_zeroes", "detect_zeroes") ParserDisk.add_arg("driver_name", "driver_name") ParserDisk.add_arg("driver_type", "driver_type") ParserDisk.add_arg("driver_io", "io") ParserDisk.add_arg("error_policy", "error_policy") ParserDisk.add_arg("serial", "serial") ParserDisk.add_arg("target", "target") ParserDisk.add_arg("startup_policy", "startup_policy") ParserDisk.add_arg("read_only", "readonly", is_onoff=True) ParserDisk.add_arg("shareable", "shareable", is_onoff=True) ParserDisk.add_arg("boot.order", "boot_order") ParserDisk.add_arg("iotune_rbs", "read_bytes_sec") ParserDisk.add_arg("iotune_wbs", "write_bytes_sec") ParserDisk.add_arg("iotune_tbs", "total_bytes_sec") ParserDisk.add_arg("iotune_ris", "read_iops_sec") ParserDisk.add_arg("iotune_wis", "write_iops_sec") ParserDisk.add_arg("iotune_tis", "total_iops_sec") ParserDisk.add_arg("sgio", "sgio") ParserDisk.add_arg("logical_block_size", "logical_block_size") ParserDisk.add_arg("physical_block_size", "physical_block_size") # VirtualDisk.seclabels properties ParserDisk.add_arg("model", "seclabel[0-9]*.model", find_inst_cb=ParserDisk.seclabel_find_inst_cb) ParserDisk.add_arg("relabel", "seclabel[0-9]*.relabel", is_onoff=True, find_inst_cb=ParserDisk.seclabel_find_inst_cb) ParserDisk.add_arg("label", "seclabel[0-9]*.label", can_comma=True, find_inst_cb=ParserDisk.seclabel_find_inst_cb) ##################### # --network parsing # ##################### class ParserNetwork(VirtCLIParser): cli_arg_name = "network" objclass = VirtualNetworkInterface remove_first = "type" stub_none = False def set_mac_cb(self, inst, val, virtarg): if val == "RANDOM": return None inst.macaddr = val return val def set_type_cb(self, inst, val, virtarg): if val == "default": inst.set_default_source() else: inst.type = val def set_link_state(self, inst, val, virtarg): ignore = virtarg if val in ["up", "down"]: inst.link_state = val return ret = _raw_on_off_convert(val) if ret is True: val = "up" elif ret is False: val = "down" inst.link_state = val def _parse(self, inst): if self.optstr == "none": return if "type" not in self.optdict: if "network" in self.optdict: self.optdict["type"] = VirtualNetworkInterface.TYPE_VIRTUAL self.optdict["source"] = self.optdict.pop("network") elif "bridge" in self.optdict: self.optdict["type"] = VirtualNetworkInterface.TYPE_BRIDGE self.optdict["source"] = self.optdict.pop("bridge") return VirtCLIParser._parse(self, inst) _register_virt_parser(ParserNetwork) _add_device_address_args(ParserNetwork) ParserNetwork.add_arg("type", "type", cb=ParserNetwork.set_type_cb) ParserNetwork.add_arg("trustGuestRxFilters", "trustGuestRxFilters", is_onoff=True) ParserNetwork.add_arg("source", "source") ParserNetwork.add_arg("source_mode", "source_mode") ParserNetwork.add_arg("source_type", "source_type") ParserNetwork.add_arg("source_path", "source_path") ParserNetwork.add_arg("portgroup", "portgroup") ParserNetwork.add_arg("target_dev", "target") ParserNetwork.add_arg("model", "model") ParserNetwork.add_arg("macaddr", "mac", cb=ParserNetwork.set_mac_cb) ParserNetwork.add_arg("filterref", "filterref") ParserNetwork.add_arg("boot.order", "boot_order") ParserNetwork.add_arg("link_state", "link_state", cb=ParserNetwork.set_link_state) ParserNetwork.add_arg("driver_name", "driver_name") ParserNetwork.add_arg("driver_queues", "driver_queues") ParserNetwork.add_arg("rom_file", "rom_file") ParserNetwork.add_arg("rom_bar", "rom_bar", is_onoff=True) # For 802.1Qbg ParserNetwork.add_arg("virtualport.type", "virtualport_type") ParserNetwork.add_arg("virtualport.managerid", "virtualport_managerid") ParserNetwork.add_arg("virtualport.typeid", "virtualport_typeid") ParserNetwork.add_arg("virtualport.typeidversion", "virtualport_typeidversion") ParserNetwork.add_arg("virtualport.instanceid", "virtualport_instanceid") # For openvswitch & 802.1Qbh ParserNetwork.add_arg("virtualport.profileid", "virtualport_profileid") # For openvswitch & midonet ParserNetwork.add_arg("virtualport.interfaceid", "virtualport_interfaceid") ###################### # --graphics parsing # ###################### class ParserGraphics(VirtCLIParser): cli_arg_name = "graphics" objclass = VirtualGraphics remove_first = "type" stub_none = False def set_keymap_cb(self, inst, val, virtarg): from . import hostkeymap if not val: val = None elif val.lower() == "local": val = VirtualGraphics.KEYMAP_LOCAL elif val.lower() == "none": val = None else: use_keymap = hostkeymap.sanitize_keymap(val) if not use_keymap: raise ValueError( _("Didn't match keymap '%s' in keytable!") % val) val = use_keymap inst.keymap = val def set_type_cb(self, inst, val, virtarg): if val == "default": return inst.type = val def set_listen_cb(self, inst, val, virtarg): if val == "none": inst.set_listen_none() elif val == "socket": inst.remove_all_listens() obj = inst.add_listen() obj.type = "socket" else: inst.listen = val def listens_find_inst_cb(self, *args, **kwargs): cliarg = "listens" # listens[0-9]* objpropname = "listens" # graphics.listens objaddfn = "add_listen" # graphics.add_listen cb = self._make_find_inst_cb(cliarg, objpropname, objaddfn) return cb(*args, **kwargs) def _parse(self, inst): if self.optstr == "none": self.guest.skip_default_graphics = True return ret = VirtCLIParser._parse(self, inst) if inst.conn.is_qemu() and inst.gl: if inst.type != "spice": logging.warning("graphics type=%s does not support GL", inst.type) elif not inst.conn.check_support( inst.conn.SUPPORT_CONN_SPICE_GL): logging.warning("qemu/libvirt version may not support spice GL") if inst.conn.is_qemu() and inst.rendernode: if inst.type != "spice": logging.warning("graphics type=%s does not support rendernode", inst.type) elif not inst.conn.check_support( inst.conn.SUPPORT_CONN_SPICE_RENDERNODE): logging.warning("qemu/libvirt version may not support rendernode") return ret _register_virt_parser(ParserGraphics) _add_device_address_args(ParserGraphics) ParserGraphics.add_arg(None, "type", cb=ParserGraphics.set_type_cb) ParserGraphics.add_arg("port", "port") ParserGraphics.add_arg("tlsPort", "tlsport") ParserGraphics.add_arg("listen", "listen", cb=ParserGraphics.set_listen_cb) ParserGraphics.add_arg("type", "listens[0-9]*.type", find_inst_cb=ParserGraphics.listens_find_inst_cb) ParserGraphics.add_arg("address", "listens[0-9]*.address", find_inst_cb=ParserGraphics.listens_find_inst_cb) ParserGraphics.add_arg("network", "listens[0-9]*.network", find_inst_cb=ParserGraphics.listens_find_inst_cb) ParserGraphics.add_arg("socket", "listens[0-9]*.socket", find_inst_cb=ParserGraphics.listens_find_inst_cb) ParserGraphics.add_arg(None, "keymap", cb=ParserGraphics.set_keymap_cb) ParserGraphics.add_arg("passwd", "password") ParserGraphics.add_arg("passwdValidTo", "passwordvalidto") ParserGraphics.add_arg("connected", "connected") ParserGraphics.add_arg("defaultMode", "defaultMode") ParserGraphics.add_arg("image_compression", "image_compression") ParserGraphics.add_arg("streaming_mode", "streaming_mode") ParserGraphics.add_arg("clipboard_copypaste", "clipboard_copypaste", is_onoff=True) ParserGraphics.add_arg("mouse_mode", "mouse_mode") ParserGraphics.add_arg("filetransfer_enable", "filetransfer_enable", is_onoff=True) ParserGraphics.add_arg("gl", "gl", is_onoff=True) ParserGraphics.add_arg("rendernode", "rendernode") ######################## # --controller parsing # ######################## class ParserController(VirtCLIParser): cli_arg_name = "controller" objclass = VirtualController remove_first = "type" def set_server_cb(self, inst, val, virtarg): inst.address.set_addrstr(val) def _parse(self, inst): if self.optstr == "usb2": return VirtualController.get_usb2_controllers(inst.conn) elif self.optstr == "usb3": inst.type = "usb" inst.model = "nec-xhci" return inst return VirtCLIParser._parse(self, inst) _register_virt_parser(ParserController) _add_device_address_args(ParserController) ParserController.add_arg("type", "type") ParserController.add_arg("model", "model") ParserController.add_arg("index", "index") ParserController.add_arg("master_startport", "master") ParserController.add_arg(None, "address", cb=ParserController.set_server_cb) ################### # --input parsing # ################### class ParserInput(VirtCLIParser): cli_arg_name = "input" objclass = VirtualInputDevice remove_first = "type" _register_virt_parser(ParserInput) _add_device_address_args(ParserInput) ParserInput.add_arg("type", "type") ParserInput.add_arg("bus", "bus") ####################### # --smartcard parsing # ####################### class ParserSmartcard(VirtCLIParser): cli_arg_name = "smartcard" objclass = VirtualSmartCardDevice remove_first = "mode" _register_virt_parser(ParserSmartcard) _add_device_address_args(ParserSmartcard) ParserSmartcard.add_arg("mode", "mode") ParserSmartcard.add_arg("type", "type") ###################### # --redirdev parsing # ###################### class ParserRedir(VirtCLIParser): cli_arg_name = "redirdev" objclass = VirtualRedirDevice remove_first = "bus" stub_none = False def set_server_cb(self, inst, val, virtarg): inst.parse_friendly_server(val) def _parse(self, inst): if self.optstr == "none": self.guest.skip_default_usbredir = True return return VirtCLIParser._parse(self, inst) _register_virt_parser(ParserRedir) _add_device_address_args(ParserRedir) ParserRedir.add_arg("bus", "bus") ParserRedir.add_arg("type", "type") ParserRedir.add_arg("boot.order", "boot_order") ParserRedir.add_arg(None, "server", cb=ParserRedir.set_server_cb) ################# # --tpm parsing # ################# class ParserTPM(VirtCLIParser): cli_arg_name = "tpm" objclass = VirtualTPMDevice remove_first = "type" def _parse(self, inst): if (self.optdict.get("type", "").startswith("/")): self.optdict["path"] = self.optdict.pop("type") return VirtCLIParser._parse(self, inst) _register_virt_parser(ParserTPM) _add_device_address_args(ParserTPM) ParserTPM.add_arg("type", "type") ParserTPM.add_arg("model", "model") ParserTPM.add_arg("device_path", "path") ################# # --rng parsing # ################# class ParserRNG(VirtCLIParser): cli_arg_name = "rng" objclass = VirtualRNGDevice remove_first = "type" stub_none = False def set_hosts_cb(self, inst, val, virtarg): namemap = {} inst.backend_type = inst.cli_backend_type if inst.cli_backend_mode == "connect": namemap["backend_host"] = "connect_host" namemap["backend_service"] = "connect_service" if inst.cli_backend_mode == "bind": namemap["backend_host"] = "bind_host" namemap["backend_service"] = "bind_service" if inst.cli_backend_type == "udp": namemap["backend_connect_host"] = "connect_host" namemap["backend_connect_service"] = "connect_service" if virtarg.cliname in namemap: setattr(inst, namemap[virtarg.cliname], val) def set_backend_cb(self, inst, val, virtarg): if virtarg.cliname == "backend_mode": inst.cli_backend_mode = val elif virtarg.cliname == "backend_type": inst.cli_backend_type = val def _parse(self, inst): if self.optstr == "none": self.guest.skip_default_rng = True return inst.cli_backend_mode = "connect" inst.cli_backend_type = "udp" if self.optdict.get("type", "").startswith("/"): # Allow --rng /dev/random self.optdict["device"] = self.optdict.pop("type") self.optdict["type"] = "random" return VirtCLIParser._parse(self, inst) _register_virt_parser(ParserRNG) _add_device_address_args(ParserRNG) ParserRNG.add_arg("type", "type") ParserRNG.add_arg(None, "backend_mode", cb=ParserRNG.set_backend_cb) ParserRNG.add_arg(None, "backend_type", cb=ParserRNG.set_backend_cb) ParserRNG.add_arg(None, "backend_host", cb=ParserRNG.set_hosts_cb) ParserRNG.add_arg(None, "backend_service", cb=ParserRNG.set_hosts_cb) ParserRNG.add_arg(None, "backend_connect_host", cb=ParserRNG.set_hosts_cb) ParserRNG.add_arg(None, "backend_connect_service", cb=ParserRNG.set_hosts_cb) ParserRNG.add_arg("device", "device") ParserRNG.add_arg("model", "model") ParserRNG.add_arg("rate_bytes", "rate_bytes") ParserRNG.add_arg("rate_period", "rate_period") ###################### # --watchdog parsing # ###################### class ParserWatchdog(VirtCLIParser): cli_arg_name = "watchdog" objclass = VirtualWatchdog remove_first = "model" _register_virt_parser(ParserWatchdog) _add_device_address_args(ParserWatchdog) ParserWatchdog.add_arg("model", "model") ParserWatchdog.add_arg("action", "action") #################### # --memdev parsing # #################### class ParseMemdev(VirtCLIParser): cli_arg_name = "memdev" objclass = VirtualMemoryDevice remove_first = "model" def set_target_size(self, inst, val, virtarg): _set_attribute(inst, virtarg.attrname, int(val) * 1024) _register_virt_parser(ParseMemdev) ParseMemdev.add_arg("model", "model") ParseMemdev.add_arg("access", "access") ParseMemdev.add_arg("target.size", "target_size", cb=ParseMemdev.set_target_size) ParseMemdev.add_arg("target.node", "target_node") ParseMemdev.add_arg("target.label_size", "target_label_size", cb=ParseMemdev.set_target_size) ParseMemdev.add_arg("source.pagesize", "source_pagesize") ParseMemdev.add_arg("source.path", "source_path") ParseMemdev.add_arg("source.nodemask", "source_nodemask", can_comma=True) ######################## # --memballoon parsing # ######################## class ParserMemballoon(VirtCLIParser): cli_arg_name = "memballoon" objclass = VirtualMemballoon remove_first = "model" stub_none = False _register_virt_parser(ParserMemballoon) _add_device_address_args(ParserMemballoon) ParserMemballoon.add_arg("model", "model") ################### # --panic parsing # ################### class ParserPanic(VirtCLIParser): cli_arg_name = "panic" objclass = VirtualPanicDevice remove_first = "model" compat_mode = False def set_model_cb(self, inst, val, virtarg): if self.compat_mode and val.startswith("0x"): inst.model = VirtualPanicDevice.MODEL_ISA inst.iobase = val else: inst.model = val def _parse(self, inst): if (len(self.optstr.split(",")) == 1 and not self.optstr.startswith("model=")): self.compat_mode = True return VirtCLIParser._parse(self, inst) _register_virt_parser(ParserPanic) ParserPanic.add_arg(None, "model", cb=ParserPanic.set_model_cb, ignore_default=True) ParserPanic.add_arg("iobase", "iobase") ###################################################### # --serial, --parallel, --channel, --console parsing # ###################################################### class _ParserChar(VirtCLIParser): remove_first = "char_type" stub_none = False def support_check(self, inst, virtarg): if not isinstance(virtarg.attrname, str): return if not inst.supports_property(virtarg.attrname): raise ValueError(_("%(devtype)s type '%(chartype)s' does not " "support '%(optname)s' option.") % {"devtype": inst.virtual_device_type, "chartype": inst.type, "optname": virtarg.cliname}) support_cb = support_check def set_host_cb(self, inst, val, virtarg): if ("bind_host" not in self.optdict and self.optdict.get("mode", None) == "bind"): inst.set_friendly_bind(val) else: inst.set_friendly_source(val) def set_bind_cb(self, inst, val, virtarg): inst.set_friendly_bind(val) def set_target_cb(self, inst, val, virtarg): inst.set_friendly_target(val) def _parse(self, inst): if self.optstr == "none" and inst.virtual_device_type == "console": self.guest.skip_default_console = True return if self.optstr == "none" and inst.virtual_device_type == "channel": self.guest.skip_default_channel = True return return VirtCLIParser._parse(self, inst) _add_device_address_args(_ParserChar) _ParserChar.add_arg("type", "char_type") _ParserChar.add_arg("source_path", "path") _ParserChar.add_arg("protocol", "protocol") _ParserChar.add_arg("target_type", "target_type") _ParserChar.add_arg("target_name", "name") _ParserChar.add_arg(None, "host", cb=_ParserChar.set_host_cb) _ParserChar.add_arg(None, "bind_host", cb=_ParserChar.set_bind_cb) _ParserChar.add_arg(None, "target_address", cb=_ParserChar.set_target_cb) _ParserChar.add_arg("source_mode", "mode") _ParserChar.add_arg("source_master", "source.master") _ParserChar.add_arg("source_slave", "source.slave") _ParserChar.add_arg("log_file", "log.file") _ParserChar.add_arg("log_append", "log.append", is_onoff=True) class ParserSerial(_ParserChar): cli_arg_name = "serial" objclass = VirtualSerialDevice _register_virt_parser(ParserSerial) class ParserParallel(_ParserChar): cli_arg_name = "parallel" objclass = VirtualParallelDevice _register_virt_parser(ParserParallel) class ParserChannel(_ParserChar): cli_arg_name = "channel" objclass = VirtualChannelDevice _register_virt_parser(ParserChannel) class ParserConsole(_ParserChar): cli_arg_name = "console" objclass = VirtualConsoleDevice _register_virt_parser(ParserConsole) ######################## # --filesystem parsing # ######################## class ParserFilesystem(VirtCLIParser): cli_arg_name = "filesystem" objclass = VirtualFilesystem remove_first = ["source", "target"] _register_virt_parser(ParserFilesystem) _add_device_address_args(ParserFilesystem) ParserFilesystem.add_arg("type", "type") ParserFilesystem.add_arg("accessmode", "accessmode", aliases=["mode"]) ParserFilesystem.add_arg("source", "source") ParserFilesystem.add_arg("target", "target") ################### # --video parsing # ################### class ParserVideo(VirtCLIParser): cli_arg_name = "video" objclass = VirtualVideoDevice remove_first = "model" def _parse(self, inst): ret = VirtCLIParser._parse(self, inst) if inst.conn.is_qemu() and inst.accel3d: if inst.model != "virtio": logging.warning("video model=%s does not support accel3d", inst.model) elif not inst.conn.check_support( inst.conn.SUPPORT_CONN_VIDEO_VIRTIO_ACCEL3D): logging.warning("qemu/libvirt version may not support " "virtio accel3d") return ret _register_virt_parser(ParserVideo) _add_device_address_args(ParserVideo) ParserVideo.add_arg("model", "model", ignore_default=True) ParserVideo.add_arg("accel3d", "accel3d", is_onoff=True) ParserVideo.add_arg("heads", "heads") ParserVideo.add_arg("ram", "ram") ParserVideo.add_arg("vram", "vram") ParserVideo.add_arg("vram64", "vram64") ParserVideo.add_arg("vgamem", "vgamem") ################### # --sound parsing # ################### class ParserSound(VirtCLIParser): cli_arg_name = "sound" objclass = VirtualAudio remove_first = "model" stub_none = False def _parse(self, inst): if self.optstr == "none": self.guest.skip_default_sound = True return return VirtCLIParser._parse(self, inst) _register_virt_parser(ParserSound) _add_device_address_args(ParserSound) ParserSound.add_arg("model", "model", ignore_default=True) ##################### # --hostdev parsing # ##################### class ParserHostdev(VirtCLIParser): cli_arg_name = "hostdev" objclass = VirtualHostDevice remove_first = "name" def set_name_cb(self, inst, val, virtarg): val = NodeDevice.lookupNodedevFromString(inst.conn, val) inst.set_from_nodedev(val) def name_lookup_cb(self, inst, val, virtarg): nodedev = NodeDevice.lookupNodedevFromString(inst.conn, val) return nodedev.compare_to_hostdev(inst) _register_virt_parser(ParserHostdev) _add_device_address_args(ParserHostdev) ParserHostdev.add_arg(None, "name", cb=ParserHostdev.set_name_cb, lookup_cb=ParserHostdev.name_lookup_cb) ParserHostdev.add_arg("driver_name", "driver_name") ParserHostdev.add_arg("boot.order", "boot_order") ParserHostdev.add_arg("rom_bar", "rom_bar", is_onoff=True) ########################### # Public virt parser APIs # ########################### def parse_option_strings(options, guest, instlist, update=False): """ Iterate over VIRT_PARSERS, and launch the associated parser function for every value that was filled in on 'options', which came from argparse/the command line. @update: If we are updating an existing guest, like from virt-xml """ instlist = util.listify(instlist) if not instlist: instlist = [None] ret = [] for parserclass in VIRT_PARSERS: optlist = util.listify(getattr(options, parserclass.cli_arg_name)) if not optlist: continue for inst in instlist: if inst and optlist: # If an object is passed in, we are updating it in place, and # only use the last command line occurrence, eg. from virt-xml optlist = [optlist[-1]] for optstr in optlist: parserobj = parserclass(guest, optstr) parseret = parserobj.parse(inst, validate=not update) ret += util.listify(parseret) return ret def check_option_introspection(options): """ Check if the user requested option introspection with ex: '--disk=?' """ ret = False for parserclass in VIRT_PARSERS: optlist = util.listify(getattr(options, parserclass.cli_arg_name)) if not optlist: continue for optstr in optlist: if optstr == "?" or optstr == "help": parserclass.print_introspection() ret = True return ret virt-manager-1.5.1/virtinst/installer.py0000664000175100017510000002005713245573052022037 0ustar crobinsocrobinso00000000000000# # Common code for all guests # # Copyright 2006-2009, 2013 Red Hat, Inc. # Jeremy Katz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import os import logging from .devicedisk import VirtualDisk from .osxml import OSXML class Installer(object): """ Installer classes attempt to encapsulate all the parameters needed to 'install' a guest: essentially, booting the guest with the correct media for the OS install phase (if there is one), and setting up the guest to boot to the correct media for all subsequent runs. Some of the actual functionality: - Determining what type of install media has been requested, and representing it correctly to the Guest - Fetching install kernel/initrd or boot.iso from a URL - Setting the boot device as appropriate depending on whether we are booting into an OS install, or booting post-install Some of the information that the Installer needs to know to accomplish this: - Install media location (could be a URL, local path, ...) - Virtualization type (parameter 'os_type') ('xen', 'hvm', etc.) - Hypervisor name (parameter 'type') ('qemu', 'kvm', 'xen', etc.) - Guest architecture ('i686', 'x86_64') """ _has_install_phase = True def __init__(self, conn): self.conn = conn self._location = None self.cdrom = False self.livecd = False self.extraargs = [] self.initrd_injections = [] self._install_kernel = None self._install_initrd = None self._tmpfiles = [] self._tmpvols = [] ######################### # Properties properties # ######################### def get_location(self): return self._location def set_location(self, val): self._location = self._validate_location(val) location = property(get_location, set_location) ################### # Private helpers # ################### def _build_boot_order(self, isinstall, guest): bootorder = [self._get_bootdev(isinstall, guest)] # If guest has an attached disk, always have 'hd' in the boot # list, so disks are marked as bootable/installable (needed for # windows virtio installs, and booting local disk from PXE) for disk in guest.get_devices("disk"): if disk.device == disk.DEVICE_DISK: bootdev = "hd" if bootdev not in bootorder: bootorder.append(bootdev) break return bootorder def alter_bootconfig(self, guest, isinstall): """ Generate the portion of the guest xml that determines boot devices and parameters. (typically the block) @param guest: Guest instance we are installing @type guest: L{Guest} @param isinstall: Whether we want xml for the 'install' phase or the 'post-install' phase. @type isinstall: C{bool} """ if isinstall and not self.has_install_phase(): return bootorder = guest.os.bootorder if isinstall or not bootorder: # Per device is not compatible with os/boot. if not any(d.boot.order for d in guest.get_all_devices()): bootorder = self._build_boot_order(isinstall, guest) guest.os.bootorder = bootorder if not isinstall: return if self._install_kernel: guest.os.kernel = self._install_kernel if self._install_initrd: guest.os.initrd = self._install_initrd if self.extraargs: guest.os.kernel_args = " ".join(self.extraargs) ########################## # Internal API overrides # ########################## def _get_bootdev(self, isinstall, guest): raise NotImplementedError("Must be implemented in subclass") def _validate_location(self, val): return val def _prepare(self, guest, meter): ignore = guest ignore = meter ############## # Public API # ############## def scratchdir_required(self): """ Returns true if scratchdir is needed for the passed install parameters. Apps can use this to determine if they should attempt to ensure scratchdir permissions are adequate """ return False def has_install_phase(self): """ Return True if the requested setup is actually installing an OS into the guest. Things like LiveCDs, Import, or a manually specified bootorder do not have an install phase. """ return self._has_install_phase def needs_cdrom(self): """ If this installer uses cdrom media, so it needs a cdrom device attached to the VM """ return False def cdrom_path(self): """ Return the cdrom path needed for needs_cdrom() installs """ return None def cleanup(self): """ Remove any temporary files retrieved during installation """ for f in self._tmpfiles: logging.debug("Removing " + f) os.unlink(f) for vol in self._tmpvols: logging.debug("Removing volume '%s'", vol.name()) vol.delete(0) self._tmpvols = [] self._tmpfiles = [] def prepare(self, guest, meter): self.cleanup() try: self._prepare(guest, meter) except Exception: self.cleanup() raise def check_location(self, guest): """ Validate self.location seems to work. This will might hit the network so we don't want to do it on demand. """ ignore = guest return True def detect_distro(self, guest): """ Attempt to detect the distro for the Installer's 'location'. If an error is encountered in the detection process (or if detection is not relevant for the Installer type), None is returned. @returns: distro variant string, or None """ ignore = guest logging.debug("distro detection not available for this installer.") return None class ContainerInstaller(Installer): _has_install_phase = False def _get_bootdev(self, isinstall, guest): ignore = isinstall ignore = guest return OSXML.BOOT_DEVICE_HARDDISK class PXEInstaller(Installer): def _get_bootdev(self, isinstall, guest): bootdev = OSXML.BOOT_DEVICE_NETWORK if (not isinstall and [d for d in guest.get_devices("disk") if d.device == d.DEVICE_DISK]): # If doing post-install boot and guest has an HD attached bootdev = OSXML.BOOT_DEVICE_HARDDISK return bootdev class ImportInstaller(Installer): _has_install_phase = False # Private methods def _get_bootdev(self, isinstall, guest): disks = guest.get_devices("disk") if not disks: return OSXML.BOOT_DEVICE_HARDDISK return self._disk_to_bootdev(disks[0]) def _disk_to_bootdev(self, disk): if disk.device == VirtualDisk.DEVICE_DISK: return OSXML.BOOT_DEVICE_HARDDISK elif disk.device == VirtualDisk.DEVICE_CDROM: return OSXML.BOOT_DEVICE_CDROM elif disk.device == VirtualDisk.DEVICE_FLOPPY: return OSXML.BOOT_DEVICE_FLOPPY else: return OSXML.BOOT_DEVICE_HARDDISK virt-manager-1.5.1/virtinst/util.py0000664000175100017510000002122213245573052021012 0ustar crobinsocrobinso00000000000000# # Copyright 2006, 2013 Red Hat, Inc. # Jeremy Katz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. # import logging import os import random import re import sys import libvirt def listify(l): if l is None: return [] elif not isinstance(l, list): return [l] else: return l def vm_uuid_collision(conn, uuid): """ Check if passed UUID string is in use by another guest of the connection Returns true/false """ return libvirt_collision(conn.lookupByUUIDString, uuid) def libvirt_collision(collision_cb, val): """ Run the passed collision function with val as the only argument: If libvirtError is raised, return False If no libvirtError raised, return True """ check = False if val is not None: try: if collision_cb(val) is not None: check = True except libvirt.libvirtError: pass return check def validate_uuid(val): if not isinstance(val, str): raise ValueError(_("UUID must be a string.")) form = re.match("[a-fA-F0-9]{8}[-]([a-fA-F0-9]{4}[-]){3}[a-fA-F0-9]{12}$", val) if form is None: form = re.match("[a-fA-F0-9]{32}$", val) if form is None: raise ValueError( _("UUID must be a 32-digit hexadecimal number. It may take " "the form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx or may " "omit hyphens altogether.")) else: # UUID had no dashes, so add them in val = (val[0:8] + "-" + val[8:12] + "-" + val[12:16] + "-" + val[16:20] + "-" + val[20:32]) return val def validate_name(name_type, val): # Rather than try and match libvirt's regex, just forbid things we # know don't work forbid = [" "] if not val: raise ValueError( _("A name must be specified for the %s") % name_type) for c in forbid: if c not in val: continue raise ValueError( _("%s name '%s' can not contain '%s' character.") % (name_type, val, c)) def validate_macaddr(val): if val is None: return if not isinstance(val, str): raise ValueError(_("MAC address must be a string.")) form = re.match("^([0-9a-fA-F]{1,2}:){5}[0-9a-fA-F]{1,2}$", val) if form is None: raise ValueError(_("MAC address must be of the format " "AA:BB:CC:DD:EE:FF, was '%s'") % val) def generate_name(base, collision_cb, suffix="", lib_collision=True, start_num=1, sep="-", force_num=False, collidelist=None): """ Generate a new name from the passed base string, verifying it doesn't collide with the collision callback. This can be used to generate disk path names from the parent VM or pool name. Names generated look like 'base-#suffix', ex: If foobar, and foobar-1.img already exist, and: base = "foobar" suffix = ".img" output = "foobar-2.img" @param base: The base string to use for the name (e.g. "my-orig-vm-clone") @param collision_cb: A callback function to check for collision, receives the generated name as its only arg @param lib_collision: If true, the collision_cb is not a boolean function, and instead throws a libvirt error on failure @param start_num: The number to start at for generating non colliding names @param sep: The seperator to use between the basename and the generated number (default is "-") @param force_num: Force the generated name to always end with a number @param collidelist: An extra list of names to check for collision """ collidelist = collidelist or [] def collide(n): if n in collidelist: return True if lib_collision: return libvirt_collision(collision_cb, tryname) else: return collision_cb(tryname) numrange = range(start_num, start_num + 100000) if not force_num: numrange = [None] + numrange for i in numrange: tryname = base if i is not None: tryname += ("%s%d" % (sep, i)) tryname += suffix if not collide(tryname): return tryname raise ValueError(_("Name generation range exceeded.")) def generate_uuid(conn): for ignore in range(256): uuid = randomUUID(conn) if not vm_uuid_collision(conn, uuid): return uuid logging.error("Failed to generate non-conflicting UUID") def randomUUID(conn): if conn.fake_conn_predictable(): # Testing hack return "00000000-1111-2222-3333-444444444444" u = [random.randint(0, 255) for ignore in range(0, 16)] u[6] = (u[6] & 0x0F) | (4 << 4) u[8] = (u[8] & 0x3F) | (2 << 6) return "-".join(["%02x" * 4, "%02x" * 2, "%02x" * 2, "%02x" * 2, "%02x" * 6]) % tuple(u) def xml_escape(xml): """ Replaces chars ' " < > & with xml safe counterparts """ if xml is None: return None xml = xml.replace("&", "&") xml = xml.replace("'", "'") xml = xml.replace("\"", """) xml = xml.replace("<", "<") xml = xml.replace(">", ">") return xml def is_error_nosupport(err): """ Check if passed exception indicates that the called libvirt command isn't supported @param err: Exception raised from command call @returns: True if command isn't supported, False if we can't determine """ if not isinstance(err, libvirt.libvirtError): return False if (err.get_error_code() == libvirt.VIR_ERR_RPC or err.get_error_code() == libvirt.VIR_ERR_NO_SUPPORT): return True return False def exception_is_libvirt_error(e, error): return (hasattr(libvirt, error) and e.get_error_code() == getattr(libvirt, error)) def local_libvirt_version(): """ Lookup the local libvirt library version, but cache the value since it never changes. """ key = "__virtinst_cached_getVersion" if not hasattr(libvirt, key): setattr(libvirt, key, libvirt.getVersion()) return getattr(libvirt, key) def get_system_scratchdir(hvtype): if "VIRTINST_TEST_SUITE" in os.environ: return os.getcwd() if hvtype == "test": return "/tmp" elif hvtype == "xen": return "/var/lib/xen" else: return "/var/lib/libvirt/boot" def make_scratchdir(conn, hvtype): scratch = None if not conn.is_session_uri(): scratch = get_system_scratchdir(hvtype) if (not scratch or not os.path.exists(scratch) or not os.access(scratch, os.W_OK)): scratch = os.path.join(get_cache_dir(), "boot") if not os.path.exists(scratch): os.makedirs(scratch, 0o751) return scratch def pretty_mem(val): val = int(val) if val > (10 * 1024 * 1024): return "%2.2f GiB" % (val / (1024.0 * 1024.0)) else: return "%2.0f MiB" % (val / 1024.0) def pretty_bytes(val): val = int(val) if val > (1024 * 1024 * 1024): return "%2.2f GiB" % (val / (1024.0 * 1024.0 * 1024.0)) else: return "%2.2f MiB" % (val / (1024.0 * 1024.0)) def get_cache_dir(): ret = "" try: # We don't want to depend on glib for virt-install from gi.repository import GLib ret = GLib.get_user_cache_dir() except ImportError: pass if not ret: ret = os.environ.get("XDG_CACHE_HOME") if not ret: ret = os.path.expanduser("~/.cache") return os.path.join(ret, "virt-manager") def register_libvirt_error_handler(): """ Ignore libvirt error reporting, we just use exceptions """ def libvirt_callback(userdata, err): ignore = userdata ignore = err libvirt.registerErrorHandler(f=libvirt_callback, ctx=None) def ensure_meter(meter): if meter: return meter return make_meter(quiet=True) def make_meter(quiet): from virtinst import progress if quiet: return progress.BaseMeter() return progress.TextMeter(fo=sys.stdout) virt-manager-1.5.1/virtinst/devicepanic.py0000664000175100017510000000513113245061760022306 0ustar crobinsocrobinso00000000000000# # Copyright 2013 Fujitsu Limited. # Chen Hanxiao # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .device import VirtualDevice from .xmlbuilder import XMLProperty class VirtualPanicDevice(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_PANIC MODEL_DEFAULT = "default" MODEL_ISA = "isa" MODEL_PSERIES = "pseries" MODEL_HYPERV = "hyperv" MODEL_S390 = "s390" MODELS = [MODEL_ISA, MODEL_PSERIES, MODEL_HYPERV, MODEL_S390] ISA_ADDRESS_TYPE = "isa" @staticmethod def get_pretty_model(panic_model): if panic_model == VirtualPanicDevice.MODEL_ISA: return _("ISA") elif panic_model == VirtualPanicDevice.MODEL_PSERIES: return _("pSeries") elif panic_model == VirtualPanicDevice.MODEL_HYPERV: return _("Hyper-V") elif panic_model == VirtualPanicDevice.MODEL_S390: return _("s390") return panic_model @staticmethod def get_models(os): if os.is_x86(): return [VirtualPanicDevice.MODEL_ISA, VirtualPanicDevice.MODEL_HYPERV] elif os.is_pseries(): return [VirtualPanicDevice.MODEL_PSERIES] elif os.is_s390x(): return [VirtualPanicDevice.MODEL_S390] return [] @staticmethod def get_default_model(os): models = VirtualPanicDevice.get_models(os) if models: return models[0] return None def _get_default_address_type(self): if self.iobase: return VirtualPanicDevice.ISA_ADDRESS_TYPE return None model = XMLProperty("./@model", default_cb=lambda s: VirtualPanicDevice.MODEL_ISA, default_name=MODEL_DEFAULT) type = XMLProperty("./address/@type", default_cb=_get_default_address_type) iobase = XMLProperty("./address/@iobase") VirtualPanicDevice.register_type() virt-manager-1.5.1/virtinst/initrdinject.py0000664000175100017510000001054413245573052022530 0ustar crobinsocrobinso00000000000000# # Copyright 2006-2009, 2013, 2014 Red Hat, Inc. # Daniel P. Berrange # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import logging import os import shutil import subprocess import tempfile def _rhel4_initrd_inject(initrd, injections): try: file_proc = subprocess.Popen(["file", "-z", initrd], stdout=subprocess.PIPE, stderr=subprocess.PIPE) if "ext2 filesystem" not in file_proc.communicate()[0]: return False except Exception: logging.exception("Failed to file command for rhel4 initrd detection") return False logging.debug("Is RHEL4 initrd") # Uncompress the initrd newinitrd = open(initrd + ".new", "wb") gzip_proc = subprocess.Popen(["gzip", "-d", "-f", "-c", initrd], stdout=newinitrd, stderr=subprocess.PIPE) gzip_proc.wait() newinitrd.close() debugfserr = "" for filename in injections: # We have an ext2 filesystem, use debugfs to inject files cmd = ["debugfs", "-w", "-R", "write %s %s" % (filename, os.path.basename(filename)), newinitrd.name] logging.debug("Copying %s to the initrd with cmd=%s", filename, cmd) debugfs_proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) debugfs_proc.wait() debugfserr += debugfs_proc.stderr.read() or "" gziperr = gzip_proc.stderr.read() if gziperr: logging.debug("gzip stderr=%s", gziperr) if debugfserr: logging.debug("debugfs stderr=%s", debugfserr) # Recompress the initrd gzip_proc = subprocess.Popen(["gzip"], stdin=open(newinitrd.name, "rb"), stdout=open(initrd, "wb"), stderr=subprocess.PIPE) gzip_proc.wait() gziperr = gzip_proc.stderr.read() if gziperr: logging.debug("gzip stderr=%s", gziperr) os.unlink(newinitrd.name) return True def perform_initrd_injections(initrd, injections, scratchdir): """ Insert files into the root directory of the initial ram disk """ if not injections: return if _rhel4_initrd_inject(initrd, injections): return tempdir = tempfile.mkdtemp(dir=scratchdir) os.chmod(tempdir, 0o775) for filename in injections: logging.debug("Copying %s to the initrd.", filename) shutil.copy(filename, tempdir) logging.debug("Appending to the initrd.") find_proc = subprocess.Popen(['find', '.', '-print0'], stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=tempdir) cpio_proc = subprocess.Popen(['cpio', '-o', '--null', '-Hnewc', '--quiet'], stdin=find_proc.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=tempdir) f = open(initrd, 'ab') gzip_proc = subprocess.Popen(['gzip'], stdin=cpio_proc.stdout, stdout=f, stderr=subprocess.PIPE) cpio_proc.wait() find_proc.wait() gzip_proc.wait() f.close() shutil.rmtree(tempdir) finderr = find_proc.stderr.read() cpioerr = cpio_proc.stderr.read() gziperr = gzip_proc.stderr.read() if finderr: logging.debug("find stderr=%s", finderr) if cpioerr: logging.debug("cpio stderr=%s", cpioerr) if gziperr: logging.debug("gzip stderr=%s", gziperr) virt-manager-1.5.1/virtinst/domainmemorytune.py0000664000175100017510000000244113241024270023420 0ustar crobinsocrobinso00000000000000# # Copyright 2014 Fujitsu Limited. # Chen Hanxiao # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .xmlbuilder import XMLBuilder, XMLProperty class DomainMemorytune(XMLBuilder): """ Class for generating XML """ _XML_ROOT_NAME = "memtune" _XML_PROP_ORDER = ["hard_limit", "soft_limit", "swap_hard_limit", "min_guarantee"] hard_limit = XMLProperty("./hard_limit", is_int=True) soft_limit = XMLProperty("./soft_limit", is_int=True) swap_hard_limit = XMLProperty("./swap_hard_limit", is_int=True) min_guarantee = XMLProperty("./min_guarantee", is_int=True) virt-manager-1.5.1/virtinst/devicesmartcard.py0000664000175100017510000000326313241024270023167 0ustar crobinsocrobinso00000000000000# # Copyright 2011, 2013 Red Hat, Inc. # Cole Robinson # Marc-Andre Lureau # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .device import VirtualDevice from .xmlbuilder import XMLProperty class VirtualSmartCardDevice(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_SMARTCARD # Default models list MODE_DEFAULT = "default" MODES = ["passthrough", "host-certificates", "host"] TYPE_DEFAULT = "default" TYPES = ["tcp", "spicevmc", "default"] _XML_PROP_ORDER = ["mode", "type"] mode = XMLProperty("./@mode", default_cb=lambda s: "passthrough", default_name=MODE_DEFAULT) def _default_type(self): if self.mode == self.MODE_DEFAULT or self.mode == "passthrough": return "spicevmc" return "tcp" type = XMLProperty("./@type", default_cb=_default_type, default_name=TYPE_DEFAULT) VirtualSmartCardDevice.register_type() virt-manager-1.5.1/virtinst/devicedisk.py0000664000175100017510000010631113245573052022152 0ustar crobinsocrobinso00000000000000# # Classes for building disk device xml # # Copyright 2006-2008, 2012-2014 Red Hat, Inc. # Jeremy Katz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import os import stat import pwd import subprocess import logging import re from . import diskbackend from . import util from .device import VirtualDevice from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty def _qemu_sanitize_drvtype(phystype, fmt, manual_format=False): """ Sanitize libvirt storage volume format to a valid qemu driver type """ raw_list = ["iso"] if phystype == VirtualDisk.TYPE_BLOCK: if not fmt: return VirtualDisk.DRIVER_TYPE_RAW if fmt and not manual_format: return VirtualDisk.DRIVER_TYPE_RAW if fmt in raw_list: return VirtualDisk.DRIVER_TYPE_RAW return fmt def _is_dir_searchable(uid, username, path): """ Check if passed directory is searchable by uid """ if "VIRTINST_TEST_SUITE" in os.environ: return True try: statinfo = os.stat(path) except OSError: return False if uid == statinfo.st_uid: flag = stat.S_IXUSR elif uid == statinfo.st_gid: flag = stat.S_IXGRP else: flag = stat.S_IXOTH if bool(statinfo.st_mode & flag): return True # Check POSIX ACL (since that is what we use to 'fix' access) cmd = ["getfacl", path] try: proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() except OSError: logging.debug("Didn't find the getfacl command.") return False if proc.returncode != 0: logging.debug("Cmd '%s' failed: %s", cmd, err) return False return bool(re.search("user:%s:..x" % username, out)) class _Host(XMLBuilder): _XML_PROP_ORDER = ["name", "port"] _XML_ROOT_NAME = "host" name = XMLProperty("./@name") port = XMLProperty("./@port", is_int=True) class _DiskSeclabel(XMLBuilder): """ This is for disk source . It's similar to a domain but has fewer options """ _XML_ROOT_NAME = "seclabel" model = XMLProperty("./@model") relabel = XMLProperty("./@relabel", is_yesno=True) label = XMLProperty("./label") class VirtualDisk(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_DISK DRIVER_NAME_PHY = "phy" DRIVER_NAME_QEMU = "qemu" DRIVER_TYPE_RAW = "raw" CACHE_MODE_NONE = "none" CACHE_MODE_WRITETHROUGH = "writethrough" CACHE_MODE_WRITEBACK = "writeback" CACHE_MODE_DIRECTSYNC = "directsync" CACHE_MODE_UNSAFE = "unsafe" cache_types = [CACHE_MODE_NONE, CACHE_MODE_WRITETHROUGH, CACHE_MODE_WRITEBACK, CACHE_MODE_DIRECTSYNC, CACHE_MODE_UNSAFE] DISCARD_MODE_IGNORE = "ignore" DISCARD_MODE_UNMAP = "unmap" discard_types = [DISCARD_MODE_IGNORE, DISCARD_MODE_UNMAP] DEVICE_DISK = "disk" DEVICE_LUN = "lun" DEVICE_CDROM = "cdrom" DEVICE_FLOPPY = "floppy" devices = [DEVICE_DISK, DEVICE_LUN, DEVICE_CDROM, DEVICE_FLOPPY] TYPE_FILE = "file" TYPE_BLOCK = "block" TYPE_DIR = "dir" TYPE_VOLUME = "volume" TYPE_NETWORK = "network" types = [TYPE_FILE, TYPE_BLOCK, TYPE_DIR, TYPE_NETWORK] IO_MODE_NATIVE = "native" IO_MODE_THREADS = "threads" io_modes = [IO_MODE_NATIVE, IO_MODE_THREADS] error_policies = ["ignore", "stop", "enospace", "report"] @staticmethod def disk_type_to_xen_driver_name(disk_type): """ Convert a value of VirtualDisk.type to it's associated Xen property """ if disk_type == VirtualDisk.TYPE_BLOCK: return "phy" elif disk_type == VirtualDisk.TYPE_FILE: return "file" return "file" @staticmethod def pretty_disk_bus(bus): if bus in ["ide", "sata", "scsi", "usb", "sd"]: return bus.upper() if bus in ["xen"]: return bus.capitalize() if bus == "virtio": return "VirtIO" return bus @staticmethod def path_definitely_exists(conn, path): """ Check if path exists. return True if we are certain, False otherwise. Path may in fact exist if we return False, but we can't exhaustively know in all cases. (In fact if cached storage volume data is out of date, the volume may have disappeared behind our back, but that shouldn't have bad effects in practice.) """ if path is None: return False try: (vol, pool) = diskbackend.check_if_path_managed(conn, path) ignore = pool if vol: return True if not conn.is_remote(): return os.path.exists(path) except Exception: pass return False @staticmethod def check_path_search_for_user(conn, path, username): """ Check if the passed user has search permissions for all the directories in the disk path. @return: List of the directories the user cannot search, or empty list @rtype : C{list} """ if path is None: return [] if conn.is_remote(): return [] if username == "root": return [] if diskbackend.path_is_url(path): return [] try: # Get UID for string name uid = pwd.getpwnam(username)[2] except Exception as e: logging.debug("Error looking up username: %s", str(e)) return [] fixlist = [] if os.path.isdir(path): dirname = path base = "-" else: dirname, base = os.path.split(path) while base: if not _is_dir_searchable(uid, username, dirname): fixlist.append(dirname) dirname, base = os.path.split(dirname) return fixlist @staticmethod def check_path_search(conn, path): # Only works for qemu and DAC if conn.is_remote() or not conn.is_qemu_system(): return None, [] from virtcli import CLIConfig user = CLIConfig.default_qemu_user try: for secmodel in conn.caps.host.secmodels: if secmodel.model != "dac": continue label = None for baselabel in secmodel.baselabels: if baselabel.type in ["qemu", "kvm"]: label = baselabel.content break if not label: continue pwuid = pwd.getpwuid( int(label.split(":")[0].replace("+", ""))) if pwuid: user = pwuid[0] except Exception: logging.debug("Exception grabbing qemu DAC user", exc_info=True) return None, [] return user, VirtualDisk.check_path_search_for_user(conn, path, user) @staticmethod def fix_path_search_for_user(conn, path, username): """ Try to fix any permission problems found by check_path_search_for_user @return: Return a dictionary of entries {broken path : error msg} @rtype : C{dict} """ def fix_perms(dirname, useacl=True): if useacl: cmd = ["setfacl", "--modify", "user:%s:x" % username, dirname] proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) out, err = proc.communicate() logging.debug("Ran command '%s'", cmd) if out or err: logging.debug("out=%s\nerr=%s", out, err) if proc.returncode != 0: raise ValueError(err) else: logging.debug("Setting +x on %s", dirname) mode = os.stat(dirname).st_mode newmode = mode | stat.S_IXOTH os.chmod(dirname, newmode) if os.stat(dirname).st_mode != newmode: # Trying to change perms on vfat at least doesn't work # but also doesn't seem to error. Try and detect that raise ValueError(_("Permissions on '%s' did not stick") % dirname) fixlist = VirtualDisk.check_path_search_for_user(conn, path, username) if not fixlist: return [] fixlist.reverse() errdict = {} useacl = True for dirname in fixlist: try: try: fix_perms(dirname, useacl) except Exception: # If acl fails, fall back to chmod and retry if not useacl: raise useacl = False logging.debug("setfacl failed, trying old fashioned way") fix_perms(dirname, useacl) except Exception as e: errdict[dirname] = str(e) return errdict @staticmethod def path_in_use_by(conn, path, shareable=False, read_only=False): """ Return a list of VM names that are using the passed path. @param conn: virConnect to check VMs @param path: Path to check for @param shareable: Path we are checking is marked shareable, so don't warn if it conflicts with another shareable source. @param read_only: Path we are checking is marked read_only, so don't warn if it conflicts with another read_only source. """ if not path: return [] # Find all volumes that have 'path' somewhere in their backing chain vols = [] volmap = dict((vol.backing_store, vol) for vol in conn.fetch_all_vols() if vol.backing_store) backpath = path while backpath in volmap: vol = volmap[backpath] if vol in vols: break backpath = vol.target_path vols.append(backpath) ret = [] vms = conn.fetch_all_guests() for vm in vms: if not read_only: if path in [vm.os.kernel, vm.os.initrd, vm.os.dtb]: ret.append(vm.name) continue for disk in vm.get_devices("disk"): if disk.path in vols and vm.name not in ret: # VM uses the path indirectly via backing store ret.append(vm.name) break if disk.path != path: continue if shareable and disk.shareable: continue if read_only and disk.read_only: continue ret.append(vm.name) break return ret @staticmethod def build_vol_install(conn, volname, poolobj, size, sparse, fmt=None, backing_store=None, backing_format=None): """ Helper for building a StorageVolume instance to pass to VirtualDisk for eventual storage creation. :param volname: name of the volume to be created :param size: size in bytes """ from .storage import StorageVolume if size is None: raise ValueError(_("Size must be specified for non " "existent volume '%s'" % volname)) # This catches --disk /dev/idontexist,size=1 if /dev is unmanaged if not poolobj: raise RuntimeError(_("Don't know how to create storage for " "path '%s'. Use libvirt APIs to manage the parent directory " "as a pool first.") % volname) logging.debug("Creating volume '%s' on pool '%s'", volname, poolobj.name()) cap = (size * 1024 * 1024 * 1024) if sparse: alloc = 0 else: alloc = cap volinst = StorageVolume(conn) volinst.pool = poolobj volinst.name = volname volinst.capacity = cap volinst.allocation = alloc volinst.backing_store = backing_store volinst.backing_format = backing_format if fmt: if not volinst.supports_property("format"): raise ValueError(_("Format attribute not supported for this " "volume type")) volinst.format = fmt return volinst @staticmethod def num_to_target(num): """ Convert an index in range (1, 1024) to a disk /dev number (like hda, hdb, hdaa, etc.) """ digits = [] for factor in range(0, 3): amt = (num % (26 ** (factor + 1))) // (26 ** factor) if amt == 0 and num >= (26 ** (factor + 1)): amt = 26 num -= amt digits.insert(0, amt) seen_valid = False gen_t = "" for digit in digits: if digit == 0: if not seen_valid: continue digit = 1 seen_valid = True gen_t += "%c" % (ord('a') + digit - 1) return gen_t @staticmethod def target_to_num(tgt): """ Convert disk /dev number (like hda, hdb, hdaa, etc.) to an index """ num = 0 k = 0 if tgt[0] == 'x': # This case is here for 'xvda' tgt = tgt[1:] for i, c in enumerate(reversed(tgt[2:])): if i != 0: k = 1 num += (ord(c) - ord('a') + k) * (26 ** i) return num _XML_PROP_ORDER = [ "type", "device", "snapshot_policy", "driver_name", "driver_type", "driver_cache", "driver_discard", "driver_detect_zeroes", "driver_io", "error_policy", "_source_file", "_source_dev", "_source_dir", "auth_username", "auth_secret_type", "auth_secret_uuid", "source_volume", "source_pool", "source_protocol", "source_name", "source_host_name", "source_host_port", "source_host_transport", "source_host_socket", "target", "bus", ] def __init__(self, *args, **kwargs): VirtualDevice.__init__(self, *args, **kwargs) self._source_volume_err = None self._storage_backend = None self.storage_was_created = False ############################# # Public property-esque API # ############################# def _get_path(self): if not self._storage_backend: xmlpath = self._get_xmlpath() if xmlpath: return xmlpath self._set_default_storage_backend() return self._storage_backend.get_path() def _set_path(self, newpath): if (self._storage_backend and self._storage_backend.will_create_storage()): raise ValueError(_("Can't change disk path if storage creation info " "has been set.")) # User explicitly changed 'path', so try to lookup its storage # object since we may need it (vol_object, parent_pool) = diskbackend.manage_path(self.conn, newpath) self._change_backend(newpath, vol_object, parent_pool) self._set_xmlpath(self.path) path = property(_get_path, _set_path) def set_vol_object(self, vol_object, parent_pool): logging.debug("disk.set_vol_object: volxml=\n%s", vol_object.XMLDesc(0)) logging.debug("disk.set_vol_object: poolxml=\n%s", parent_pool.XMLDesc(0)) self._change_backend(None, vol_object, parent_pool) self._set_xmlpath(self.path) def set_vol_install(self, vol_install): logging.debug("disk.set_vol_install: name=%s poolxml=\n%s", vol_install.name, vol_install.pool.XMLDesc(0)) self._storage_backend = diskbackend.ManagedStorageCreator( self.conn, vol_install) self._set_xmlpath(self.path) def get_vol_object(self): return self._storage_backend.get_vol_object() def get_vol_install(self): return self._storage_backend.get_vol_install() def get_parent_pool(self): if self.get_vol_install(): return self.get_vol_install().pool return self._storage_backend.get_parent_pool() def get_size(self): return self._storage_backend.get_size() ############################# # Internal defaults helpers # ############################# def _get_default_driver_name(self): if not self.path: return None # Recommended xen defaults from here: # https://bugzilla.redhat.com/show_bug.cgi?id=1171550#c9 # If type block, use name=phy. Otherwise do the same as qemu if self.conn.is_xen() and self.type == self.TYPE_BLOCK: return self.DRIVER_NAME_PHY if self.conn.check_support( self.conn.SUPPORT_CONN_DISK_DRIVER_NAME_QEMU): return self.DRIVER_NAME_QEMU return None def _get_default_driver_type(self): """ Set driver type from passed parameters Where possible, we want to force /driver/@type = "raw" if installing a QEMU VM. Without telling QEMU to expect a raw file, the emulator is forced to autodetect, which has security implications: http://lists.gnu.org/archive/html/qemu-devel/2008-04/msg00675.html """ if self.driver_name != self.DRIVER_NAME_QEMU: return None drvtype = self._storage_backend.get_driver_type() return _qemu_sanitize_drvtype(self.type, drvtype) ############################# # XML source media handling # ############################# _source_file = XMLProperty("./source/@file") _source_dev = XMLProperty("./source/@dev") _source_dir = XMLProperty("./source/@dir") source_pool = XMLProperty("./source/@pool") source_volume = XMLProperty("./source/@volume") auth_username = XMLProperty("./auth/@username") auth_secret_type = XMLProperty("./auth/secret/@type") auth_secret_uuid = XMLProperty("./auth/secret/@uuid") def add_host(self, name, port): obj = _Host(self.conn) obj.name = name obj.port = port self.add_child(obj) def remove_host(self, obj): self.remove_child(obj) hosts = XMLChildProperty(_Host, relative_xpath="./source") source_name = XMLProperty("./source/@name") source_protocol = XMLProperty("./source/@protocol") # Technically multiple host lines can be listed source_host_name = XMLProperty("./source/host/@name") source_host_port = XMLProperty("./source/host/@port", is_int=True) source_host_transport = XMLProperty("./source/host/@transport") source_host_socket = XMLProperty("./source/host/@socket") def _set_source_network_from_url(self, uri): from .uri import URI uriobj = URI(uri) if uriobj.scheme: self.source_protocol = uriobj.scheme if uriobj.transport: self.source_host_transport = uriobj.transport if uriobj.hostname: self.source_host_name = uriobj.hostname if uriobj.port: self.source_host_port = uriobj.port if uriobj.path: if self.source_host_transport: self.source_host_socket = uriobj.path else: self.source_name = uriobj.path if self.source_name.startswith("/"): self.source_name = self.source_name[1:] def _set_source_network_from_storage(self, volxml, poolxml): self.source_protocol = poolxml.type logging.debug("disk.set_vol_object: poolxml=\n%s", dir(poolxml)) if poolxml.auth_type: self.auth_username = poolxml.auth_username self.auth_secret_type = poolxml.auth_type self.auth_secret_uuid = poolxml.auth_secret_uuid if poolxml.hosts: self.source_host_name = poolxml.hosts[0].name self.source_host_port = poolxml.hosts[0].port for host in poolxml.hosts: self.add_host(host.name, host.port) path = "" if poolxml.source_name: path += poolxml.source_name if poolxml.source_path: path += poolxml.source_path if not path.endswith('/'): path += "/" path += volxml.name self.source_name = path self.type = "network" def _set_network_source_from_backend(self): if (self._storage_backend.get_vol_object() or self._storage_backend.get_vol_install()): volxml = self._storage_backend.get_vol_xml() poolxml = self._storage_backend.get_parent_pool_xml() self._set_source_network_from_storage(volxml, poolxml) elif self._storage_backend.get_path(): self._set_source_network_from_url(self._storage_backend.get_path()) def _build_url_from_network_source(self): ret = self.source_protocol if self.source_host_transport: ret += "+%s" % self.source_host_transport ret += "://" if self.source_host_name: ret += self.source_host_name if self.source_host_port: ret += ":" + str(self.source_host_port) if self.source_name: if not self.source_name.startswith("/"): ret += "/" ret += self.source_name elif self.source_host_socket: if not self.source_host_socket.startswith("/"): ret += "/" ret += self.source_host_socket return ret def _get_default_type(self): if self.source_pool or self.source_volume: return VirtualDisk.TYPE_VOLUME if self._storage_backend: return self._storage_backend.get_dev_type() if self.source_protocol: return VirtualDisk.TYPE_NETWORK return self.TYPE_FILE type = XMLProperty("./@type", default_cb=_get_default_type) def _clear_source_xml(self): """ Unset all XML properties that describe the actual source media """ self._source_file = None self._source_dev = None self._source_dir = None self.source_volume = None self.source_pool = None self.source_name = None self.source_protocol = None self.source_host_name = None self.source_host_port = None self.source_host_transport = None self.source_host_socket = None def _disk_type_to_object_prop_name(self): disk_type = self.type if disk_type == VirtualDisk.TYPE_BLOCK: return "_source_dev" elif disk_type == VirtualDisk.TYPE_DIR: return "_source_dir" elif disk_type == VirtualDisk.TYPE_FILE: return "_source_file" return None # _xmlpath is an abstraction for source file/block/dir paths, since # they don't have any special properties aside from needing to match # 'type' value with the source property used. def _get_xmlpath(self): if self._source_file: return self._source_file if self._source_dev: return self._source_dev if self._source_dir: return self._source_dir return None def _set_xmlpath(self, val): self._clear_source_xml() if self._storage_backend.get_dev_type() == "network": self._set_network_source_from_backend() return propname = self._disk_type_to_object_prop_name() if not propname: return return setattr(self, propname, val) ################## # XML properties # ################## device = XMLProperty("./@device", default_cb=lambda s: s.DEVICE_DISK) snapshot_policy = XMLProperty("./@snapshot") driver_name = XMLProperty("./driver/@name", default_cb=_get_default_driver_name) driver_type = XMLProperty("./driver/@type", default_cb=_get_default_driver_type) sgio = XMLProperty("./@sgio") bus = XMLProperty("./target/@bus") target = XMLProperty("./target/@dev") removable = XMLProperty("./target/@removable", is_onoff=True) read_only = XMLProperty("./readonly", is_bool=True) shareable = XMLProperty("./shareable", is_bool=True) driver_cache = XMLProperty("./driver/@cache") driver_discard = XMLProperty("./driver/@discard") driver_detect_zeroes = XMLProperty("./driver/@detect_zeroes") driver_io = XMLProperty("./driver/@io") error_policy = XMLProperty("./driver/@error_policy") serial = XMLProperty("./serial") startup_policy = XMLProperty("./source/@startupPolicy") logical_block_size = XMLProperty("./blockio/@logical_block_size") physical_block_size = XMLProperty("./blockio/@physical_block_size") iotune_rbs = XMLProperty("./iotune/read_bytes_sec", is_int=True) iotune_ris = XMLProperty("./iotune/read_iops_sec", is_int=True) iotune_tbs = XMLProperty("./iotune/total_bytes_sec", is_int=True) iotune_tis = XMLProperty("./iotune/total_iops_sec", is_int=True) iotune_wbs = XMLProperty("./iotune/write_bytes_sec", is_int=True) iotune_wis = XMLProperty("./iotune/write_iops_sec", is_int=True) seclabels = XMLChildProperty(_DiskSeclabel, relative_xpath="./source") def add_seclabel(self): obj = _DiskSeclabel(self.conn) self.add_child(obj) return obj ################################# # Validation assistance methods # ################################# def _set_default_storage_backend(self): path = None vol_object = None parent_pool = None self._source_volume_err = None typ = self._get_default_type() if self.type == VirtualDisk.TYPE_NETWORK: # Fill in a completed URL for virt-manager UI, path comparison, etc path = self._build_url_from_network_source() if typ == VirtualDisk.TYPE_VOLUME: conn = self.conn if "weakref" in str(type(conn)): conn = conn() try: parent_pool = conn.storagePoolLookupByName(self.source_pool) vol_object = parent_pool.storageVolLookupByName( self.source_volume) except Exception as e: self._source_volume_err = str(e) logging.debug("Error fetching source pool=%s vol=%s", self.source_pool, self.source_volume, exc_info=True) if vol_object is None and path is None: path = self._get_xmlpath() self._change_backend(path, vol_object, parent_pool) def set_local_disk_to_clone(self, disk, sparse): """ Set a path to manually clone (as in, not through libvirt) """ self._storage_backend = diskbackend.CloneStorageCreator(self.conn, self.path, disk.path, disk.get_size(), sparse) def is_cdrom(self): return self.device == self.DEVICE_CDROM def is_floppy(self): return self.device == self.DEVICE_FLOPPY def is_disk(self): return self.device == self.DEVICE_DISK def can_be_empty(self): return self.is_floppy() or self.is_cdrom() def _change_backend(self, path, vol_object, parent_pool): backend = diskbackend.StorageBackend(self.conn, path, vol_object, parent_pool) self._storage_backend = backend def sync_path_props(self): """ Fills in the values of type, driver_type, and driver_name for the associated backing storage. This needs to be manually called if changing an existing disk's media. """ path = self._get_xmlpath() self.type = self._get_default_type() self.driver_name = self._get_default_driver_name() self.driver_type = self._get_default_driver_type() # Need to retrigger this if self.type changed if path: self._set_xmlpath(path) def wants_storage_creation(self): """ If true, this disk needs storage creation parameters or things will error. """ return (self._storage_backend and not self._storage_backend.exists()) def validate(self): if self.path is None: if self._source_volume_err: raise RuntimeError(self._source_volume_err) if not self.can_be_empty(): raise ValueError(_("Device type '%s' requires a path") % self.device) return if (self.type == VirtualDisk.TYPE_DIR and not self.is_floppy()): raise ValueError(_("The path '%s' must be a file or a " "device, not a directory") % self.path) if not self._storage_backend: return if (not self._storage_backend.will_create_storage() and not self._storage_backend.exists()): raise ValueError( _("Must specify storage creation parameters for " "non-existent path '%s'.") % self.path) self._storage_backend.validate(self) def setup(self, meter=None): """ Build storage (if required) If storage doesn't exist (a non-existent file 'path', or 'vol_install' was specified), we create it. """ if not self._storage_backend.will_create_storage(): return meter = util.ensure_meter(meter) vol_object = self._storage_backend.create(meter) self.storage_was_created = True if not vol_object: return parent_pool = self.get_vol_install().pool self._change_backend(None, vol_object, parent_pool) def set_defaults(self, guest): if self.is_cdrom(): self.read_only = True if self.is_cdrom() and guest.os.is_s390x(): self.bus = "scsi" if not self.conn.is_qemu(): return if not self.is_disk(): return if not self.type == self.TYPE_BLOCK: return # Enable cache=none and io=native for block devices. Would # be nice if qemu did this for us but that time has long passed. if not self.driver_cache: self.driver_cache = self.CACHE_MODE_NONE if not self.driver_io: self.driver_io = self.IO_MODE_NATIVE def is_size_conflict(self): """ reports if disk size conflicts with available space returns a two element tuple: 1. first element is True if fatal conflict occurs 2. second element is a string description of the conflict or None Non fatal conflicts (sparse disk exceeds available space) will return (False, "description of collision") """ return self._storage_backend.is_size_conflict() def is_conflict_disk(self, conn=None): """ check if specified storage is in use by any other VMs on passed connection. @return: list of colliding VM names @rtype: C{list} """ if not self.path: return False if not conn: conn = self.conn ret = self.path_in_use_by(conn, self.path, shareable=self.shareable, read_only=self.read_only) return ret def get_target_prefix(self, used_targets=None): """ Returns the suggested disk target prefix (hd, xvd, sd ...) for the disk. @returns: str prefix, or None if no reasonable guess can be made """ # The upper limits here aren't necessarilly 1024, but let the HV # error as appropriate. def _return(prefix): nummap = { "vd": 1024, "xvd": 1024, "fd": 2, "hd": 4, "sd": 1024, } return prefix, nummap[prefix] if self.bus == "virtio": return _return("vd") elif self.bus == "xen": return _return("xvd") elif self.bus == "fdc" or self.is_floppy(): return _return("fd") elif self.bus == "ide": return _return("hd") elif self.bus or not used_targets: # sata, scsi, usb, sd return _return("sd") # If guest already has some disks defined preforder = ["vd", "xvd", "sd", "hd"] for pref in preforder: for target in used_targets: if target.startswith(pref): return _return(pref) return _return("sd") def generate_target(self, skip_targets, pref_ctrl=None): """ Generate target device ('hda', 'sdb', etc..) for disk, excluding any targets in 'skip_targets'. If given the 'pref_ctrl' parameter, it tries to select the target so that the disk is mapped onto that controller. Sets self.target, and returns the generated value. @param skip_targets: list of targets to exclude @type skip_targets: C{list} @param pref_ctrl: preferred controller to connect the disk to @type pref_ctrl: C{int} @raise ValueError: can't determine target type, no targets available @returns generated target @rtype C{str} """ prefix, maxnode = self.get_target_prefix(skip_targets) skip_targets = [t for t in skip_targets if t and t.startswith(prefix)] skip_targets.sort() def get_target(): first_found = None ran = range(maxnode) if pref_ctrl is not None: # We assume narrow SCSI bus and libvirt assigning 7 # (1-7, 8-14, etc.) devices per controller ran = range(pref_ctrl * 7, (pref_ctrl + 1) * 7) for i in ran: gen_t = prefix + self.num_to_target(i + 1) if gen_t in skip_targets: skip_targets.remove(gen_t) continue if not skip_targets: return gen_t elif not first_found: first_found = gen_t if first_found: return first_found ret = get_target() if ret: self.target = ret return ret if pref_ctrl is not None: # This basically means that we either chose full # controller or didn't add any raise ValueError(_("Controller number %d for disk of type %s has " "no empty slot to use" % (pref_ctrl, prefix))) else: raise ValueError(_("Only %s disks for bus '%s' are supported" % (maxnode, self.bus))) VirtualDisk.register_type() virt-manager-1.5.1/virtinst/devicerng.py0000664000175100017510000001042613245061760022005 0ustar crobinsocrobinso00000000000000# # Copyright 2013 Red Hat, Inc. # Giuseppe Scrivano # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .device import VirtualDevice from .xmlbuilder import XMLProperty class VirtualRNGDevice(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_RNG TYPE_RANDOM = "random" TYPE_EGD = "egd" TYPES = [TYPE_RANDOM, TYPE_EGD] BACKEND_TYPE_UDP = "udp" BACKEND_TYPE_TCP = "tcp" BACKEND_TYPES = [BACKEND_TYPE_UDP, BACKEND_TYPE_TCP] BACKEND_MODE_BIND = "bind" BACKEND_MODE_CONNECT = "connect" BACKEND_MODES = [BACKEND_MODE_BIND, BACKEND_MODE_CONNECT] @staticmethod def get_pretty_type(rng_type): if rng_type == VirtualRNGDevice.TYPE_RANDOM: return _("Random") if rng_type == VirtualRNGDevice.TYPE_EGD: return _("Entropy Gathering Daemon") return rng_type @staticmethod def get_pretty_backend_type(backend_type): return {"udp": "UDP", "tcp": "TCP"}.get(backend_type) or backend_type @staticmethod def get_pretty_mode(mode): return {"bind": _("Bind"), "connect": _("Connect")}.get(mode) or mode def supports_property(self, propname): """ Whether the rng dev type supports the passed property name """ users = { "type": [self.TYPE_EGD, self.TYPE_RANDOM], "model": [self.TYPE_EGD, self.TYPE_RANDOM], "bind_host": [self.TYPE_EGD], "bind_service": [self.TYPE_EGD], "connect_host": [self.TYPE_EGD], "connect_service": [self.TYPE_EGD], "backend_type": [self.TYPE_EGD], "device": [self.TYPE_RANDOM], "rate_bytes": [self.TYPE_EGD, self.TYPE_RANDOM], "rate_period": [self.TYPE_EGD, self.TYPE_RANDOM], } if users.get(propname): return self.type in users[propname] return hasattr(self, propname) def backend_mode(self): ret = [] if self._has_mode_bind: ret.append(VirtualRNGDevice.BACKEND_MODE_BIND) if self._has_mode_connect: ret.append(VirtualRNGDevice.BACKEND_MODE_CONNECT) return ret _XML_PROP_ORDER = ["_has_mode_bind", "_has_mode_connect"] _has_mode_connect = XMLProperty("./backend/source[@mode='connect']/@mode") def _set_connect_validate(self, val): if val: self._has_mode_connect = VirtualRNGDevice.BACKEND_MODE_CONNECT return val _has_mode_bind = XMLProperty("./backend/source[@mode='bind']/@mode") def _set_bind_validate(self, val): if val: self._has_mode_bind = VirtualRNGDevice.BACKEND_MODE_BIND return val type = XMLProperty("./backend/@model") model = XMLProperty("./@model", default_cb=lambda s: "virtio") backend_type = XMLProperty("./backend/@type") bind_host = XMLProperty("./backend/source[@mode='bind']/@host", set_converter=_set_bind_validate) bind_service = XMLProperty("./backend/source[@mode='bind']/@service", set_converter=_set_bind_validate) connect_host = XMLProperty("./backend/source[@mode='connect']/@host", set_converter=_set_connect_validate) connect_service = XMLProperty("./backend/source[@mode='connect']/@service", set_converter=_set_connect_validate) rate_bytes = XMLProperty("./rate/@bytes") rate_period = XMLProperty("./rate/@period") device = XMLProperty("./backend[@model='random']") VirtualRNGDevice.register_type() virt-manager-1.5.1/virtinst/urlfetcher.py0000664000175100017510000012672013245573052022211 0ustar crobinsocrobinso00000000000000# # Represents OS distribution specific install data # # Copyright 2006-2007, 2013 Red Hat, Inc. # Daniel P. Berrange # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import ConfigParser import ftplib import io import logging import os import re import subprocess import tempfile import urllib2 import urlparse import requests from .osdict import OSDB ######################################################################### # Backends for the various URL types we support (http, ftp, nfs, local) # ######################################################################### class _URLFetcher(object): """ This is a generic base class for fetching/extracting files from a media source, such as CD ISO, NFS server, or HTTP/FTP server """ _block_size = 16384 def __init__(self, location, scratchdir, meter): self.location = location self.scratchdir = scratchdir self.meter = meter self._srcdir = None logging.debug("Using scratchdir=%s", scratchdir) #################### # Internal helpers # #################### def _make_full_url(self, filename): """ Generate a full fetchable URL from the passed filename, which is relative to the self.location """ ret = self._srcdir or self.location if not filename: return ret if not ret.endswith("/"): ret += "/" return ret + filename def _grabURL(self, filename, fileobj): """ Download the filename from self.location, and write contents to fileobj """ url = self._make_full_url(filename) try: urlobj, size = self._grabber(url) except Exception as e: raise ValueError(_("Couldn't acquire file %s: %s") % (url, str(e))) logging.debug("Fetching URI: %s", url) self.meter.start( text=_("Retrieving file %s...") % os.path.basename(filename), size=size) total = self._write(urlobj, fileobj) self.meter.end(total) def _write(self, urlobj, fileobj): """ Write the contents of urlobj to python file like object fileobj """ total = 0 while 1: buff = urlobj.read(self._block_size) if not buff: break fileobj.write(buff) total += len(buff) self.meter.update(total) return total def _grabber(self, url): """ Returns the urlobj, size for the passed URL. urlobj is whatever data needs to be passed to self._write """ raise NotImplementedError("must be implemented in subclass") ############## # Public API # ############## def prepareLocation(self): """ Perform any necessary setup """ pass def cleanupLocation(self): """ Perform any necessary cleanup """ pass def _hasFile(self, url): raise NotImplementedError("Must be implemented in subclass") def hasFile(self, filename): """ Return True if self.location has the passed filename """ url = self._make_full_url(filename) ret = self._hasFile(url) logging.debug("hasFile(%s) returning %s", url, ret) return ret def acquireFile(self, filename): """ Grab the passed filename from self.location and save it to a temporary file, returning the temp filename """ prefix = "virtinst-" + os.path.basename(filename) + "." # pylint: disable=redefined-variable-type if "VIRTINST_TEST_SUITE" in os.environ: fn = os.path.join("/tmp", prefix) fileobj = open(fn, "wb") else: fileobj = tempfile.NamedTemporaryFile( dir=self.scratchdir, prefix=prefix, delete=False) fn = fileobj.name self._grabURL(filename, fileobj) logging.debug("Saved file to " + fn) return fn def acquireFileContent(self, filename): """ Grab the passed filename from self.location and return it as a string """ fileobj = io.BytesIO() self._grabURL(filename, fileobj) return fileobj.getvalue() class _HTTPURLFetcher(_URLFetcher): def _hasFile(self, url): """ We just do a HEAD request to see if the file exists """ try: response = requests.head(url, allow_redirects=True) response.raise_for_status() except Exception as e: logging.debug("HTTP hasFile request failed: %s", str(e)) return False return True def _grabber(self, url): """ Use requests for this """ response = requests.get(url, stream=True) response.raise_for_status() try: size = int(response.headers.get('content-length')) except Exception: size = None return response, size def _write(self, urlobj, fileobj): """ The requests object doesn't have a file-like read() option, so we need to implemente it ourselves """ total = 0 for data in urlobj.iter_content(chunk_size=self._block_size): fileobj.write(data) total += len(data) self.meter.update(total) return total class _FTPURLFetcher(_URLFetcher): _ftp = None def prepareLocation(self): if self._ftp: return try: parsed = urlparse.urlparse(self.location) self._ftp = ftplib.FTP() self._ftp.connect(parsed.hostname, parsed.port) self._ftp.login() # Force binary mode self._ftp.voidcmd("TYPE I") except Exception as e: raise ValueError(_("Opening URL %s failed: %s.") % (self.location, str(e))) def _grabber(self, url): """ Use urllib2 and ftplib to grab the file """ request = urllib2.Request(url) urlobj = urllib2.urlopen(request) size = self._ftp.size(urlparse.urlparse(url)[2]) return urlobj, size def cleanupLocation(self): if not self._ftp: return try: self._ftp.quit() except Exception: logging.debug("Error quitting ftp connection", exc_info=True) self._ftp = None def _hasFile(self, url): path = urlparse.urlparse(url)[2] try: try: # If it's a file self._ftp.size(path) except ftplib.all_errors: # If it's a dir self._ftp.cwd(path) except ftplib.all_errors as e: logging.debug("FTP hasFile: couldn't access %s: %s", url, str(e)) return False return True class _LocalURLFetcher(_URLFetcher): """ For grabbing files from a local directory """ def _hasFile(self, url): return os.path.exists(url) def _grabber(self, url): urlobj = open(url, "r") size = os.path.getsize(url) return urlobj, size class _MountedURLFetcher(_LocalURLFetcher): """ Fetcher capable of extracting files from a NFS server or loopback mounted file, or local CDROM device """ _in_test_suite = bool("VIRTINST_TEST_SUITE" in os.environ) _mounted = False def prepareLocation(self): if self._mounted: return if self._in_test_suite: self._srcdir = os.environ["VIRTINST_TEST_URL_DIR"] else: self._srcdir = tempfile.mkdtemp(prefix="virtinstmnt.", dir=self.scratchdir) mountcmd = "/bin/mount" logging.debug("Preparing mount at " + self._srcdir) cmd = [mountcmd, "-o", "ro", self.location[4:], self._srcdir] logging.debug("mount cmd: %s", cmd) if not self._in_test_suite: ret = subprocess.call(cmd) if ret != 0: self.cleanupLocation() raise ValueError(_("Mounting location '%s' failed") % (self.location)) self._mounted = True def cleanupLocation(self): if not self._mounted: return logging.debug("Cleaning up mount at " + self._srcdir) try: if not self._in_test_suite: cmd = ["/bin/umount", self._srcdir] subprocess.call(cmd) try: os.rmdir(self._srcdir) except Exception: pass finally: self._mounted = False class _ISOURLFetcher(_URLFetcher): _cache_file_list = None def _make_full_url(self, filename): return "/" + filename def _grabber(self, url): """ Use isoinfo to grab the file """ cmd = ["isoinfo", "-J", "-i", self.location, "-x", url] logging.debug("Running isoinfo: %s", cmd) output = subprocess.check_output(cmd) return io.BytesIO(output), len(output) def _hasFile(self, url): """ Use isoinfo to list and search for the file """ if not self._cache_file_list: cmd = ["isoinfo", "-J", "-i", self.location, "-f"] logging.debug("Running isoinfo: %s", cmd) output = subprocess.check_output(cmd) self._cache_file_list = output.splitlines(False) return url in self._cache_file_list def fetcherForURI(uri, *args, **kwargs): if uri.startswith("http://") or uri.startswith("https://"): fclass = _HTTPURLFetcher elif uri.startswith("ftp://"): fclass = _FTPURLFetcher elif uri.startswith("nfs:"): fclass = _MountedURLFetcher elif os.path.isdir(uri): # Pointing to a local tree fclass = _LocalURLFetcher else: # Pointing to a path (e.g. iso), or a block device (e.g. /dev/cdrom) fclass = _ISOURLFetcher return fclass(uri, *args, **kwargs) ############################################### # Helpers for detecting distro from given URL # ############################################### def _grabTreeinfo(fetcher): """ See if the URL has treeinfo, and if so return it as a ConfigParser object. """ try: tmptreeinfo = fetcher.acquireFile(".treeinfo") except ValueError: return None try: treeinfo = ConfigParser.SafeConfigParser() treeinfo.read(tmptreeinfo) finally: os.unlink(tmptreeinfo) try: treeinfo.get("general", "family") except ConfigParser.NoSectionError: logging.debug("Did not find 'family' section in treeinfo") return None logging.debug("treeinfo family=%s", treeinfo.get("general", "family")) return treeinfo def _distroFromSUSEContent(fetcher, arch, vmtype=None): # Parse content file for the 'LABEL' field containing the distribution name # None if no content, GenericDistro if unknown label type. try: cbuf = fetcher.acquireFileContent("content") except ValueError: return None distribution = None distro_version = None distro_summary = None distro_distro = None distro_arch = None lines = cbuf.splitlines()[1:] for line in lines: if line.startswith("LABEL "): distribution = line.split(' ', 1) elif line.startswith("DISTRO "): distro_distro = line.rsplit(',', 1) elif line.startswith("VERSION "): distro_version = line.split(' ', 1) if len(distro_version) > 1: d_version = distro_version[1].split('-', 1) if len(d_version) > 1: distro_version[1] = d_version[0] elif line.startswith("SUMMARY "): distro_summary = line.split(' ', 1) elif line.startswith("BASEARCHS "): distro_arch = line.split(' ', 1) elif line.startswith("DEFAULTBASE "): distro_arch = line.split(' ', 1) elif line.startswith("REPOID "): distro_arch = line.rsplit('/', 1) if distribution and distro_version and distro_arch: break if not distribution: if distro_summary: distribution = distro_summary elif distro_distro: distribution = distro_distro if distro_arch: arch = distro_arch[1].strip() # Fix for 13.2 official oss repo if arch.find("i586-x86_64") != -1: arch = "x86_64" else: if cbuf.find("x86_64") != -1: arch = "x86_64" elif cbuf.find("i586") != -1: arch = "i586" elif cbuf.find("s390x") != -1: arch = "s390x" def _parse_sle_distribution(d): sle_version = d[1].strip().rsplit(' ')[4] if len(d[1].strip().rsplit(' ')) > 5: sle_version = sle_version + '.' + d[1].strip().rsplit(' ')[5][2] return ['VERSION', sle_version] dclass = GenericDistro if distribution: if re.match(".*SUSE Linux Enterprise Server*", distribution[1]) or \ re.match(".*SUSE SLES*", distribution[1]): dclass = SLESDistro if distro_version is None: distro_version = _parse_sle_distribution(distribution) elif re.match(".*SUSE Linux Enterprise Desktop*", distribution[1]): dclass = SLEDDistro if distro_version is None: distro_version = _parse_sle_distribution(distribution) elif re.match(".*openSUSE.*", distribution[1]): dclass = OpensuseDistro if distro_version is None: distro_version = ['VERSION', distribution[0].strip().rsplit(':')[4]] if distro_version is None: return None ob = dclass(fetcher, arch, vmtype) if dclass != GenericDistro: ob.version_from_content = distro_version # Explictly call this, so we populate os_type/variant info ob.isValidStore() return ob def getDistroStore(guest, fetcher): stores = [] logging.debug("Finding distro store for location=%s", fetcher.location) arch = guest.os.arch _type = guest.os.os_type urldistro = OSDB.lookup_os(guest.os_variant).urldistro treeinfo = _grabTreeinfo(fetcher) if not treeinfo: dist = _distroFromSUSEContent(fetcher, arch, _type) if dist: return dist stores = _allstores[:] # If user manually specified an os_distro, bump it's URL class # to the top of the list if urldistro: logging.debug("variant=%s has distro=%s, looking for matching " "distro store to prioritize", guest.os_variant, urldistro) found_store = None for store in stores: if store.urldistro == urldistro: found_store = store if found_store: logging.debug("Prioritizing distro store=%s", found_store) stores.remove(found_store) stores.insert(0, found_store) else: logging.debug("No matching store found, not prioritizing anything") if treeinfo: stores.sort(key=lambda x: not x.uses_treeinfo) for sclass in stores: store = sclass(fetcher, arch, _type) store.treeinfo = treeinfo if store.isValidStore(): logging.debug("Detected distro name=%s osvariant=%s", store.name, store.os_variant) return store # No distro was detected. See if the URL even resolves, and if not # give the user a hint that maybe they mistyped. This won't always # be true since some webservers don't allow directory listing. # http://www.redhat.com/archives/virt-tools-list/2014-December/msg00048.html extramsg = "" if not fetcher.hasFile(""): extramsg = (": " + _("The URL could not be accessed, maybe you mistyped?")) raise ValueError( _("Could not find an installable distribution at '%s'%s\n\n" "The location must be the root directory of an install tree.\n" "See virt-install man page for various distro examples." % (fetcher.location, extramsg))) ################## # Distro classes # ################## class Distro(object): """ An image store is a base class for retrieving either a bootable ISO image, or a kernel+initrd pair for a particular OS distribution """ name = None urldistro = None uses_treeinfo = False # osdict variant value os_variant = None _boot_iso_paths = [] _hvm_kernel_paths = [] _xen_kernel_paths = [] version_from_content = [] def __init__(self, fetcher, arch, vmtype): self.fetcher = fetcher self.type = vmtype self.arch = arch self.uri = fetcher.location # This is set externally self.treeinfo = None def isValidStore(self): """Determine if uri points to a tree of the store's distro""" raise NotImplementedError def acquireKernel(self, guest): kernelpath = None initrdpath = None if self.treeinfo: try: kernelpath = self._getTreeinfoMedia("kernel") initrdpath = self._getTreeinfoMedia("initrd") except ConfigParser.NoSectionError: pass if not kernelpath or not initrdpath: # fall back to old code if self.type is None or self.type == "hvm": paths = self._hvm_kernel_paths else: paths = self._xen_kernel_paths for kpath, ipath in paths: if self.fetcher.hasFile(kpath) and self.fetcher.hasFile(ipath): kernelpath = kpath initrdpath = ipath if not kernelpath or not initrdpath: raise RuntimeError(_("Couldn't find %(type)s kernel for " "%(distro)s tree.") % {"distro": self.name, "type": self.type}) return self._kernelFetchHelper(guest, kernelpath, initrdpath) def acquireBootDisk(self, guest): ignore = guest if self.treeinfo: return self.fetcher.acquireFile(self._getTreeinfoMedia("boot.iso")) for path in self._boot_iso_paths: if self.fetcher.hasFile(path): return self.fetcher.acquireFile(path) raise RuntimeError(_("Could not find boot.iso in %s tree." % self.name)) def _check_osvariant_valid(self, os_variant): return OSDB.lookup_os(os_variant) is not None def get_osdict_info(self): """ Return (distro, variant) tuple, checking to make sure they are valid osdict entries """ if not self.os_variant: return None if not self._check_osvariant_valid(self.os_variant): logging.debug("%s set os_variant to %s, which is not in osdict.", self, self.os_variant) return None return self.os_variant def _get_method_arg(self): return "method" def _getTreeinfoMedia(self, mediaName): if self.type == "xen": t = "xen" else: t = self.treeinfo.get("general", "arch") return self.treeinfo.get("images-%s" % t, mediaName) def _fetchAndMatchRegex(self, filename, regex): # Fetch 'filename' and return True/False if it matches the regex try: content = self.fetcher.acquireFileContent(filename) except ValueError: return False for line in content.splitlines(): if re.match(regex, line): return True return False def _kernelFetchHelper(self, guest, kernelpath, initrdpath): # Simple helper for fetching kernel + initrd and performing # cleanup if necessary ignore = guest kernel = self.fetcher.acquireFile(kernelpath) args = '' if not self.fetcher.location.startswith("/"): args += "%s=%s" % (self._get_method_arg(), self.fetcher.location) try: initrd = self.fetcher.acquireFile(initrdpath) return kernel, initrd, args except Exception: os.unlink(kernel) raise class GenericDistro(Distro): """ Generic distro store. Check well known paths for kernel locations as a last resort if we can't recognize any actual distro """ name = "Generic" uses_treeinfo = True _xen_paths = [("images/xen/vmlinuz", "images/xen/initrd.img"), # Fedora ] _hvm_paths = [("images/pxeboot/vmlinuz", "images/pxeboot/initrd.img"), # Fedora ("ppc/ppc64/vmlinuz", "ppc/ppc64/initrd.img"), # CenOS 7 ppc64le ] _iso_paths = ["images/boot.iso", # RH/Fedora "boot/boot.iso", # Suse "current/images/netboot/mini.iso", # Debian "install/images/boot.iso", # Mandriva ] # Holds values to use when actually pulling down media _valid_kernel_path = None _valid_iso_path = None def isValidStore(self): if self.treeinfo: # Use treeinfo to pull down media paths if self.type == "xen": typ = "xen" else: typ = self.treeinfo.get("general", "arch") kernelSection = "images-%s" % typ isoSection = "images-%s" % self.treeinfo.get("general", "arch") if self.treeinfo.has_section(kernelSection): try: self._valid_kernel_path = ( self._getTreeinfoMedia("kernel"), self._getTreeinfoMedia("initrd")) except (ConfigParser.NoSectionError, ConfigParser.NoOptionError) as e: logging.debug(e) if self.treeinfo.has_section(isoSection): try: self._valid_iso_path = self.treeinfo.get(isoSection, "boot.iso") except ConfigParser.NoOptionError as e: logging.debug(e) if self.type == "xen": kern_list = self._xen_paths else: kern_list = self._hvm_paths # If validated media paths weren't found (no treeinfo), check against # list of media location paths. for kern, init in kern_list: if (self._valid_kernel_path is None and self.fetcher.hasFile(kern) and self.fetcher.hasFile(init)): self._valid_kernel_path = (kern, init) break for iso in self._iso_paths: if (self._valid_iso_path is None and self.fetcher.hasFile(iso)): self._valid_iso_path = iso break if self._valid_kernel_path or self._valid_iso_path: return True return False def acquireKernel(self, guest): if self._valid_kernel_path is None: raise ValueError(_("Could not find a kernel path for virt type " "'%s'" % self.type)) return self._kernelFetchHelper(guest, self._valid_kernel_path[0], self._valid_kernel_path[1]) def acquireBootDisk(self, guest): if self._valid_iso_path is None: raise ValueError(_("Could not find a boot iso path for this tree.")) return self.fetcher.acquireFile(self._valid_iso_path) class RedHatDistro(Distro): """ Base image store for any Red Hat related distros which have a common layout """ uses_treeinfo = True _version_number = None _boot_iso_paths = ["images/boot.iso"] _hvm_kernel_paths = [("images/pxeboot/vmlinuz", "images/pxeboot/initrd.img")] _xen_kernel_paths = [("images/xen/vmlinuz", "images/xen/initrd.img")] def isValidStore(self): raise NotImplementedError() def _get_method_arg(self): if (self._version_number is not None and ((self.urldistro == "rhel" and self._version_number >= 7) or (self.urldistro == "fedora" and self._version_number >= 19))): return "inst.repo" return "method" # Fedora distro check class FedoraDistro(RedHatDistro): name = "Fedora" urldistro = "fedora" def isValidStore(self): if not self.treeinfo: return self.fetcher.hasFile("Fedora") if not re.match(".*Fedora.*", self.treeinfo.get("general", "family")): return False ver = self.treeinfo.get("general", "version") if not ver: logging.debug("No version found in .treeinfo") return False logging.debug("Found treeinfo version=%s", ver) latest_variant = OSDB.latest_fedora_version() if re.match("fedora[0-9]+", latest_variant): latest_vernum = int(latest_variant[6:]) else: logging.debug("Failed to parse version number from latest " "fedora variant=%s. Using safe default 22", latest_variant) latest_vernum = 22 # rawhide trees changed to use version=Rawhide in Apr 2016 if ver in ["development", "rawhide", "Rawhide"]: self._version_number = latest_vernum self.os_variant = latest_variant return True # Dev versions can be like '23_Alpha' if "_" in ver: ver = ver.split("_")[0] # Typical versions are like 'fedora-23' vernum = str(ver).split("-")[0] if vernum.isdigit(): vernum = int(vernum) else: logging.debug("Failed to parse version number from treeinfo " "version=%s, using vernum=latest=%s", ver, latest_vernum) vernum = latest_vernum if vernum > latest_vernum: self.os_variant = latest_variant else: self.os_variant = "fedora" + str(vernum) self._version_number = vernum return True # Red Hat Enterprise Linux distro check class RHELDistro(RedHatDistro): name = "Red Hat Enterprise Linux" urldistro = "rhel" def isValidStore(self): if self.treeinfo: # Matches: # Red Hat Enterprise Linux # RHEL Atomic Host m = re.match(".*(Red Hat Enterprise Linux|RHEL).*", self.treeinfo.get("general", "family")) ret = (m is not None) if ret: self._variantFromVersion() return ret if (self.fetcher.hasFile("Server") or self.fetcher.hasFile("Client")): self.os_variant = "rhel5" return True return self.fetcher.hasFile("RedHat") ################################ # osdict autodetection helpers # ################################ def _parseTreeinfoVersion(self, verstr): def _safeint(c): try: val = int(c) except Exception: val = 0 return val version = _safeint(verstr[0]) update = 0 # RHEL has version=5.4, scientific linux=54 updinfo = verstr.split(".") if len(updinfo) > 1: update = _safeint(updinfo[1]) elif len(verstr) > 1: update = _safeint(verstr[1]) return version, update def _variantFromVersion(self): ver = self.treeinfo.get("general", "version") name = None if self.treeinfo.has_option("general", "name"): name = self.treeinfo.get("general", "name") if not ver: return if name and name.startswith("Red Hat Enterprise Linux Server for ARM"): # Kind of a hack, but good enough for the time being version = 7 update = 0 else: version, update = self._parseTreeinfoVersion(ver) self._version_number = version self._setRHELVariant(version, update) def _setRHELVariant(self, version, update): base = "rhel" + str(version) if update < 0: update = 0 ret = None while update >= 0: tryvar = base + ".%s" % update if not self._check_osvariant_valid(tryvar): update -= 1 continue ret = tryvar break if not ret: # Try plain rhel5, rhel6, whatev if self._check_osvariant_valid(base): ret = base if ret: self.os_variant = ret # CentOS distro check class CentOSDistro(RHELDistro): name = "CentOS" urldistro = "centos" def isValidStore(self): if not self.treeinfo: return self.fetcher.hasFile("CentOS") m = re.match(".*CentOS.*", self.treeinfo.get("general", "family")) ret = (m is not None) if ret: self._variantFromVersion() if self.os_variant: new_variant = self.os_variant.replace("rhel", "centos") if self._check_osvariant_valid(new_variant): self.os_variant = new_variant return ret # Scientific Linux distro check class SLDistro(RHELDistro): name = "Scientific Linux" urldistro = None _boot_iso_paths = RHELDistro._boot_iso_paths + ["images/SL/boot.iso"] _hvm_kernel_paths = RHELDistro._hvm_kernel_paths + [ ("images/SL/pxeboot/vmlinuz", "images/SL/pxeboot/initrd.img")] def isValidStore(self): if self.treeinfo: m = re.match(".*Scientific.*", self.treeinfo.get("general", "family")) ret = (m is not None) if ret: self._variantFromVersion() return ret return self.fetcher.hasFile("SL") class SuseDistro(Distro): name = "SUSE" _boot_iso_paths = ["boot/boot.iso"] def __init__(self, *args, **kwargs): Distro.__init__(self, *args, **kwargs) if re.match(r'i[4-9]86', self.arch): self.arch = 'i386' oldkern = "linux" oldinit = "initrd" if self.arch == "x86_64": oldkern += "64" oldinit += "64" if self.arch == "s390x": self._hvm_kernel_paths = [("boot/%s/linux" % self.arch, "boot/%s/initrd" % self.arch)] # No Xen on s390x self._xen_kernel_paths = [] else: # Tested with Opensuse >= 10.2, 11, and sles 10 self._hvm_kernel_paths = [("boot/%s/loader/linux" % self.arch, "boot/%s/loader/initrd" % self.arch)] # Tested with Opensuse 10.0 self._hvm_kernel_paths.append(("boot/loader/%s" % oldkern, "boot/loader/%s" % oldinit)) # Tested with SLES 12 for ppc64le self._hvm_kernel_paths.append(("boot/%s/linux" % self.arch, "boot/%s/initrd" % self.arch)) # Matches Opensuse > 10.2 and sles 10 self._xen_kernel_paths = [("boot/%s/vmlinuz-xen" % self.arch, "boot/%s/initrd-xen" % self.arch)] def _variantFromVersion(self): distro_version = self.version_from_content[1].strip() version = distro_version.split('.', 1)[0].strip() self.os_variant = self.urldistro if int(version) >= 10: if self.os_variant.startswith(("sles", "sled")): sp_version = None if len(distro_version.split('.', 1)) == 2: sp_version = 'sp' + distro_version.split('.', 1)[1].strip() self.os_variant += version if sp_version: self.os_variant += sp_version else: # Tumbleweed 8 digit date if len(version) == 8: self.os_variant += "tumbleweed" else: self.os_variant += distro_version else: self.os_variant += "9" def isValidStore(self): # self.version_from_content is the VERSION line from the contents file if (not self.version_from_content or self.version_from_content[1] is None): return False self._variantFromVersion() self.os_variant = self._detect_osdict_from_url() # Reset kernel name for sle11 source on s390x if self.arch == "s390x": if self.os_variant == "sles11" or self.os_variant == "sled11": self._hvm_kernel_paths = [("boot/%s/vmrdr.ikr" % self.arch, "boot/%s/initrd" % self.arch)] return True def _get_method_arg(self): return "install" ################################ # osdict autodetection helpers # ################################ def _detect_osdict_from_url(self): root = "opensuse" oses = [n for n in OSDB.list_os() if n.name.startswith(root)] for osobj in oses: codename = osobj.name[len(root):] if re.search("/%s/" % codename, self.uri): return osobj.name return self.os_variant class SLESDistro(SuseDistro): urldistro = "sles" class SLEDDistro(SuseDistro): urldistro = "sled" # Suse image store is harder - we fetch the kernel RPM and a helper # RPM and then munge bits together to generate a initrd class OpensuseDistro(SuseDistro): urldistro = "opensuse" class DebianDistro(Distro): # ex. http://ftp.egr.msu.edu/debian/dists/sarge/main/installer-i386/ # daily builds: http://d-i.debian.org/daily-images/amd64/ name = "Debian" urldistro = "debian" def __init__(self, *args, **kwargs): Distro.__init__(self, *args, **kwargs) self._url_prefix = "" self._treeArch = self._find_treearch() self._installer_dirname = self.name.lower() + "-installer" def _find_treearch(self): for pattern in ["^.*/installer-(\w+)/?$", "^.*/daily-images/(\w+)/?$"]: arch = re.findall(pattern, self.uri) if not arch: continue logging.debug("Found pattern=%s treearch=%s in uri", pattern, arch[0]) return arch[0] # Check for standard 'i386' and 'amd64' which will be # in the URI name for --location $ISO mounts for arch in ["i386", "amd64", "x86_64", "arm64"]: if arch in self.uri: logging.debug("Found treearch=%s in uri", arch) if arch == "x86_64": arch = "amd64" return arch # Otherwise default to i386 arch = "i386" logging.debug("No treearch found in uri, defaulting to arch=%s", arch) return arch def _set_media_paths(self): self._boot_iso_paths = ["%s/netboot/mini.iso" % self._url_prefix] hvmroot = "%s/netboot/%s/%s/" % (self._url_prefix, self._installer_dirname, self._treeArch) initrd_basename = "initrd.gz" kernel_basename = "linux" if self._treeArch in ["ppc64el"]: kernel_basename = "vmlinux" if self._treeArch == "s390x": hvmroot = "%s/generic/" % self._url_prefix kernel_basename = "kernel.%s" % self.name.lower() initrd_basename = "initrd.%s" % self.name.lower() self._hvm_kernel_paths = [ (hvmroot + kernel_basename, hvmroot + initrd_basename)] xenroot = "%s/netboot/xen/" % self._url_prefix self._xen_kernel_paths = [(xenroot + "vmlinuz", xenroot + "initrd.gz")] def _check_manifest(self, filename): if not self.fetcher.hasFile(filename): return False if self.arch == "s390x": regex = ".*generic/kernel\.%s.*" % self.name.lower() else: regex = ".*%s.*" % self._installer_dirname if not self._fetchAndMatchRegex(filename, regex): logging.debug("Regex didn't match, not a %s distro", self.name) return False return True def _check_info(self, filename): if not self.fetcher.hasFile(filename): return False regex = "%s.*" % self.name if not self._fetchAndMatchRegex(filename, regex): logging.debug("Regex didn't match, not a %s distro", self.name) return False return True def _is_regular_tree(self): # For regular trees if not self._check_manifest("current/images/MANIFEST"): return False self._url_prefix = "current/images" self._set_media_paths() self.os_variant = self._detect_debian_osdict_from_url() return True def _is_daily_tree(self): # For daily trees if not self._check_manifest("daily/MANIFEST"): return False self._url_prefix = "daily" self._set_media_paths() self.os_variant = self._detect_debian_osdict_from_url() return True def _is_install_cd(self): # For install CDs if not self._check_info(".disk/info"): return False if self.arch == "x86_64": kernel_initrd_pair = ("install.amd/vmlinuz", "install.amd/initrd.gz") elif self.arch == "i686": kernel_initrd_pair = ("install.386/vmlinuz", "install.386/initrd.gz") elif self.arch == "aarch64": kernel_initrd_pair = ("install.a64/vmlinuz", "install.a64/initrd.gz") elif self.arch == "ppc64le": kernel_initrd_pair = ("install/vmlinux", "install/initrd.gz") elif self.arch == "s390x": kernel_initrd_pair = ("boot/linux_vm", "boot/root.bin") else: kernel_initrd_pair = ("install/vmlinuz", "install/initrd.gz") self._hvm_kernel_paths += [kernel_initrd_pair] self._xen_kernel_paths += [kernel_initrd_pair] return True def isValidStore(self): return any(check() for check in [ self._is_regular_tree, self._is_daily_tree, self._is_install_cd, ]) ################################ # osdict autodetection helpers # ################################ def _detect_debian_osdict_from_url(self): root = self.name.lower() oses = [n for n in OSDB.list_os() if n.name.startswith(root)] if self._url_prefix == "daily": logging.debug("Appears to be debian 'daily' URL, using latest " "debian OS") return oses[0].name for osobj in oses: if osobj.codename: # Ubuntu codenames look like 'Warty Warthog' codename = osobj.codename.split()[0].lower() else: if " " not in osobj.label: continue # Debian labels look like 'Debian Sarge' codename = osobj.label.split()[1].lower() if ("/%s/" % codename) in self.uri: logging.debug("Found codename=%s in the URL string", codename) return osobj.name logging.debug("Didn't find any known codename in the URL string") return self.os_variant class UbuntuDistro(DebianDistro): # http://archive.ubuntu.com/ubuntu/dists/natty/main/installer-amd64/ name = "Ubuntu" urldistro = "ubuntu" def _is_tree_iso(self): # For trees based on ISO's if not self._check_info("install/netboot/version.info"): return False self._url_prefix = "install" self._set_media_paths() self.os_variant = self._detect_debian_osdict_from_url() return True def _is_install_cd(self): # For install CDs if not self._check_info(".disk/info"): return False if not self.arch == "s390x": kernel_initrd_pair = ("install/vmlinuz", "install/initrd.gz") else: kernel_initrd_pair = ("boot/kernel.ubuntu", "boot/initrd.ubuntu") self._hvm_kernel_paths += [kernel_initrd_pair] self._xen_kernel_paths += [kernel_initrd_pair] return True class MandrivaDistro(Distro): # ftp://ftp.uwsg.indiana.edu/linux/mandrake/official/2007.1/x86_64/ name = "Mandriva/Mageia" urldistro = "mandriva" _boot_iso_paths = ["install/images/boot.iso"] _xen_kernel_paths = [] def __init__(self, *args, **kwargs): Distro.__init__(self, *args, **kwargs) self._hvm_kernel_paths = [] # At least Mageia 5 uses arch in the names self._hvm_kernel_paths += [ ("isolinux/%s/vmlinuz" % self.arch, "isolinux/%s/all.rdz" % self.arch)] # Kernels for HVM: valid for releases 2007.1, 2008.*, 2009.0 self._hvm_kernel_paths += [ ("isolinux/alt0/vmlinuz", "isolinux/alt0/all.rdz")] def isValidStore(self): # Don't support any paravirt installs if self.type is not None and self.type != "hvm": return False # Mandriva websites / media appear to have a VERSION # file in top level which we can use as our 'magic' # check for validity if not self.fetcher.hasFile("VERSION"): return False for name in ["Mandriva", "Mageia"]: if self._fetchAndMatchRegex("VERSION", ".*%s.*" % name): return True logging.debug("Regex didn't match, not a %s distro", self.name) return False class ALTLinuxDistro(Distro): # altlinux doesn't have installable URLs, so this is just for a # mounted ISO name = "ALT Linux" urldistro = "altlinux" _boot_iso_paths = [("altinst", "live")] _hvm_kernel_paths = [("syslinux/alt0/vmlinuz", "syslinux/alt0/full.cz")] _xen_kernel_paths = [] def isValidStore(self): # Don't support any paravirt installs if self.type is not None and self.type != "hvm": return False if not self.fetcher.hasFile(".disk/info"): return False if self._fetchAndMatchRegex(".disk/info", ".*ALT .*"): return True logging.debug("Regex didn't match, not a %s distro", self.name) return False # Build list of all *Distro classes def _build_distro_list(): allstores = [] for obj in globals().values(): if isinstance(obj, type) and issubclass(obj, Distro) and obj.name: allstores.append(obj) seen_urldistro = [] for obj in allstores: if obj.urldistro and obj.urldistro in seen_urldistro: raise RuntimeError("programming error: duplicate urldistro=%s" % obj.urldistro) seen_urldistro.append(obj.urldistro) # Always stick GenericDistro at the end, since it's a catchall allstores.remove(GenericDistro) allstores.append(GenericDistro) return allstores _allstores = _build_distro_list() virt-manager-1.5.1/virtinst/devicememballoon.py0000664000175100017510000000231213241024270023326 0ustar crobinsocrobinso00000000000000# Copyright (C) 2013 Red Hat, Inc. # # Copyright 2012 # Eiichi Tsukata # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .device import VirtualDevice from .xmlbuilder import XMLProperty class VirtualMemballoon(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_MEMBALLOON MODEL_DEFAULT = "default" MODELS = ["virtio", "xen", "none"] model = XMLProperty("./@model", default_name=MODEL_DEFAULT, default_cb=lambda s: "virtio") VirtualMemballoon.register_type() virt-manager-1.5.1/virtinst/devicewatchdog.py0000664000175100017510000000473313245061760023023 0ustar crobinsocrobinso00000000000000# # Copyright 2010, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .device import VirtualDevice from .xmlbuilder import XMLProperty class VirtualWatchdog(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_WATCHDOG MODEL_I6300 = "i6300esb" MODEL_IB700 = "ib700" MODEL_DIAG288 = "diag288" MODEL_DEFAULT = "default" MODELS = [MODEL_I6300, MODEL_IB700, MODEL_DIAG288] ACTION_SHUTDOWN = "shutdown" ACTION_RESET = "reset" ACTION_POWEROFF = "poweroff" ACTION_PAUSE = "pause" ACTION_NONE = "none" ACTION_DUMP = "dump" ACTION_DEFAULT = "default" ACTIONS = [ACTION_RESET, ACTION_SHUTDOWN, ACTION_POWEROFF, ACTION_PAUSE, ACTION_DUMP, ACTION_NONE] @staticmethod def get_action_desc(action): if action == VirtualWatchdog.ACTION_RESET: return _("Forcefully reset the guest") if action == VirtualWatchdog.ACTION_SHUTDOWN: return _("Gracefully shutdown the guest") if action == VirtualWatchdog.ACTION_POWEROFF: return _("Forcefully power off the guest") if action == VirtualWatchdog.ACTION_PAUSE: return _("Pause the guest") if action == VirtualWatchdog.ACTION_NONE: return _("No action") if action == VirtualWatchdog.ACTION_DUMP: return _("Dump guest memory core") return action _XML_PROP_ORDER = ["model", "action"] model = XMLProperty("./@model", default_name=MODEL_DEFAULT, default_cb=lambda s: s.MODEL_I6300) action = XMLProperty("./@action", default_name=ACTION_DEFAULT, default_cb=lambda s: s.ACTION_RESET) VirtualWatchdog.register_type() virt-manager-1.5.1/virtinst/snapshot.py0000664000175100017510000000507513241024270021671 0ustar crobinsocrobinso00000000000000# # Copyright 2013-2014 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import libvirt from . import util from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty class _SnapshotDisk(XMLBuilder): _XML_ROOT_NAME = "disk" name = XMLProperty("./@name") snapshot = XMLProperty("./@snapshot") class DomainSnapshot(XMLBuilder): @staticmethod def find_free_name(vm, collidelist): return util.generate_name("snapshot", vm.snapshotLookupByName, sep="", start_num=1, force_num=True, collidelist=collidelist) @staticmethod def state_str_to_int(state): statemap = { "nostate": libvirt.VIR_DOMAIN_NOSTATE, "running": libvirt.VIR_DOMAIN_RUNNING, "blocked": libvirt.VIR_DOMAIN_BLOCKED, "paused": libvirt.VIR_DOMAIN_PAUSED, "shutdown": libvirt.VIR_DOMAIN_SHUTDOWN, "shutoff": libvirt.VIR_DOMAIN_SHUTOFF, "crashed": libvirt.VIR_DOMAIN_CRASHED, "pmsuspended": getattr(libvirt, "VIR_DOMAIN_PMSUSPENDED", 7) } if state == "disk-snapshot" or state not in statemap: state = "shutoff" return statemap.get(state, libvirt.VIR_DOMAIN_NOSTATE) _XML_ROOT_NAME = "domainsnapshot" _XML_PROP_ORDER = ["name", "description", "creationTime"] name = XMLProperty("./name") description = XMLProperty("./description") state = XMLProperty("./state") creationTime = XMLProperty("./creationTime", is_int=True) parent = XMLProperty("./parent/name") memory_type = XMLProperty("./memory/@snapshot") disks = XMLChildProperty(_SnapshotDisk, relative_xpath="./disks") ################## # Public helpers # ################## def validate(self): if not self.name: raise RuntimeError(_("A name must be specified.")) virt-manager-1.5.1/virtinst/progress.py0000664000175100017510000004317713245573052021716 0ustar crobinsocrobinso00000000000000# This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the # Free Software Foundation, Inc., # 59 Temple Place, Suite 330, # Boston, MA 02111-1307 USA # This file is part of urlgrabber, a high-level cross-protocol url-grabber # Copyright 2002-2004 Michael D. Stenner, Ryan Tomayko # This code is all straight from python-urlgrabber, which we historically # used the system installed version of. But since the project is in # maintenance mode upstream, and eventually we want to switch to python3, # we are just copying this for now. import sys import time import math import fcntl import struct import termios # Code from http://mail.python.org/pipermail/python-list/2000-May/033365.html def terminal_width(fd=1): """ Get the real terminal width """ try: buf = 'abcdefgh' buf = fcntl.ioctl(fd, termios.TIOCGWINSZ, buf) ret = struct.unpack('hhhh', buf)[1] if ret == 0: return 80 # Add minimum too? return ret except: # IOError return 80 _term_width_val = None _term_width_last = None def terminal_width_cached(fd=1, cache_timeout=1.000): """ Get the real terminal width, but cache it for a bit. """ global _term_width_val global _term_width_last now = time.time() if _term_width_val is None or (now - _term_width_last) > cache_timeout: _term_width_val = terminal_width(fd) _term_width_last = now return _term_width_val class TerminalLine: """ Help create dynamic progress bars, uses terminal_width_cached(). """ def __init__(self, min_rest=0, beg_len=None, fd=1, cache_timeout=1.000): if beg_len is None: beg_len = min_rest self._min_len = min_rest self._llen = terminal_width_cached(fd, cache_timeout) if self._llen < beg_len: self._llen = beg_len self._fin = False def __len__(self): """ Usable length for elements. """ return self._llen - self._min_len def rest_split(self, fixed, elements=2): """ After a fixed length, split the rest of the line length among a number of different elements (default=2). """ if self._llen < fixed: return 0 return (self._llen - fixed) // elements def add(self, element, full_len=None): """ If there is room left in the line, above min_len, add element. Note that as soon as one add fails all the rest will fail too. """ if full_len is None: full_len = len(element) if len(self) < full_len: self._fin = True if self._fin: return '' self._llen -= len(element) return element def rest(self): """ Current rest of line, same as .rest_split(fixed=0, elements=1). """ return self._llen class BaseMeter: def __init__(self): self.update_period = 0.3 # seconds self.filename = None self.url = None self.basename = None self.text = None self.size = None self.start_time = None self.last_amount_read = 0 self.last_update_time = None self.re = RateEstimator() def start(self, filename=None, url=None, basename=None, size=None, now=None, text=None): self.filename = filename self.url = url self.basename = basename self.text = text #size = None ######### TESTING self.size = size if not size is None: self.fsize = format_number(size) + 'B' if now is None: now = time.time() self.start_time = now self.re.start(size, now) self.last_amount_read = 0 self.last_update_time = now self._do_start(now) def _do_start(self, now=None): pass def update(self, amount_read, now=None): # for a real gui, you probably want to override and put a call # to your mainloop iteration function here if now is None: now = time.time() if (not self.last_update_time or (now >= self.last_update_time + self.update_period)): self.re.update(amount_read, now) self.last_amount_read = amount_read self.last_update_time = now self._do_update(amount_read, now) def _do_update(self, amount_read, now=None): pass def end(self, amount_read, now=None): if now is None: now = time.time() self.re.update(amount_read, now) self.last_amount_read = amount_read self.last_update_time = now self._do_end(amount_read, now) def _do_end(self, amount_read, now=None): pass # This is kind of a hack, but progress is gotten from grabber which doesn't # know about the total size to download. So we do this so we can get the data # out of band here. This will be "fixed" one way or anther soon. _text_meter_total_size = 0 _text_meter_sofar_size = 0 def text_meter_total_size(size, downloaded=0): global _text_meter_total_size global _text_meter_sofar_size _text_meter_total_size = size _text_meter_sofar_size = downloaded # # update: No size (minimal: 17 chars) # ----------------------------------- # | # 8-48 1 8 3 6 1 9 5 # # Order: 1. + (17) # 2. + (10, total: 27) # 3. + ( 5, total: 32) # 4. + ( 9, total: 41) # # update: Size, Single file # ------------------------- # | ETA # 8-25 1 3-4 1 6-16 1 8 3 6 1 9 1 3 1 # # Order: 1. + (17) # 2. + (10, total: 27) # 3. +ETA ( 5, total: 32) # 4. + ( 4, total: 36) # 5. + ( 9, total: 45) # 6. + ( 7, total: 52) # # update: Size, All files # ----------------------- # | ETA # 8-22 1 5-7 1 3-4 1 6-12 1 8 3 6 1 9 1 3 1 # # Order: 1. + (17) # 2. + (10, total: 27) # 3. +ETA ( 5, total: 32) # 4. + ( 5, total: 37) # 4. + ( 4, total: 41) # 5. + ( 9, total: 50) # 6. + ( 7, total: 57) # # end # --- # | # 8-56 3 6 1 9 5 # # Order: 1. ( 8) # 2. + ( 9, total: 17) # 3. + (10, total: 27) # 4. + ( 5, total: 32) # def _term_add_bar(tl, bar_max_length, pc): blen = bar_max_length bar = '='*int(blen * pc) if (blen * pc) - int(blen * pc) >= 0.5: bar += '-' return tl.add(' [%-*.*s]' % (blen, blen, bar)) def _term_add_end(tl, osize, size): if osize: # osize should be None or >0, but that's been broken. if size > osize: # Is ??? better? Really need something to say < vs >. return tl.add(' !!! '), True elif size != osize: return tl.add(' ... '), True return tl.add(' ' * 5), False class TextMeter(BaseMeter): def __init__(self, fo=sys.stderr): BaseMeter.__init__(self) self.fo = fo def _do_update(self, amount_read, now=None): etime = self.re.elapsed_time() fread = format_number(amount_read) #self.size = None if self.text is not None: text = self.text else: text = self.basename ave_dl = format_number(self.re.average_rate()) sofar_size = None if _text_meter_total_size: sofar_size = _text_meter_sofar_size + amount_read sofar_pc = (sofar_size * 100) // _text_meter_total_size # Include text + ui_rate in minimal tl = TerminalLine(8, 8+1+8) if tl._llen > 80: use_hours = True # For big screens, make it more readable. else: use_hours = False ui_size = tl.add(' | %5sB' % fread) if self.size is None: ui_time = tl.add(' %s' % format_time(etime, use_hours)) ui_end = tl.add(' ' * 5) ui_rate = tl.add(' %5sB/s' % ave_dl) out = '%-*.*s%s%s%s%s\r' % (tl.rest(), tl.rest(), text, ui_rate, ui_size, ui_time, ui_end) else: rtime = self.re.remaining_time() frtime = format_time(rtime, use_hours) frac = self.re.fraction_read() ui_time = tl.add(' %s' % frtime) ui_end = tl.add(' ETA ') if sofar_size is None: ui_sofar_pc = '' else: ui_sofar_pc = tl.add(' (%i%%)' % sofar_pc, full_len=len(" (100%)")) ui_pc = tl.add(' %2i%%' % (frac*100)) ui_rate = tl.add(' %5sB/s' % ave_dl) # Make text grow a bit before we start growing the bar too blen = 4 + tl.rest_split(8 + 8 + 4) ui_bar = _term_add_bar(tl, blen, frac) out = '\r%-*.*s%s%s%s%s%s%s%s\r' % (tl.rest(), tl.rest(), text, ui_sofar_pc, ui_pc, ui_bar, ui_rate,ui_size,ui_time, ui_end) self.fo.write(out) self.fo.flush() def _do_end(self, amount_read, now=None): global _text_meter_total_size global _text_meter_sofar_size total_size = format_number(amount_read) if self.text is not None: text = self.text else: text = self.basename tl = TerminalLine(8) if tl._llen > 80: use_hours = True # For big screens, make it more readable. else: use_hours = False ui_size = tl.add(' | %5sB' % total_size) ui_time = tl.add(' %s' % format_time(self.re.elapsed_time(), use_hours)) ui_end, not_done = _term_add_end(tl, self.size, amount_read) out = '\r%-*.*s%s%s%s\n' % (tl.rest(), tl.rest(), text, ui_size, ui_time, ui_end) self.fo.write(out) self.fo.flush() # Don't add size to the sofar size until we have all of it. # If we don't have a size, then just pretend/hope we got all of it. if not_done: return if _text_meter_total_size: _text_meter_sofar_size += amount_read if _text_meter_total_size <= _text_meter_sofar_size: _text_meter_total_size = 0 _text_meter_sofar_size = 0 text_progress_meter = TextMeter ###################################################################### # support classes and functions class RateEstimator: def __init__(self, timescale=5.0): self.timescale = timescale def start(self, total=None, now=None): if now is None: now = time.time() self.total = total self.start_time = now self.last_update_time = now self.last_amount_read = 0 self.ave_rate = None def update(self, amount_read, now=None): if now is None: now = time.time() # libcurl calls the progress callback when fetching headers # too, thus amount_read = 0 .. hdr_size .. 0 .. content_size. # Ocassionally we miss the 2nd zero and report avg speed < 0. # Handle read_diff < 0 here. BZ 1001767. if amount_read == 0 or amount_read < self.last_amount_read: # if we just started this file, all bets are off self.last_update_time = now self.last_amount_read = amount_read self.ave_rate = None return #print 'times', now, self.last_update_time time_diff = now - self.last_update_time read_diff = amount_read - self.last_amount_read # First update, on reget is the file size if self.last_amount_read: self.last_update_time = now self.ave_rate = self._temporal_rolling_ave(\ time_diff, read_diff, self.ave_rate, self.timescale) self.last_amount_read = amount_read #print 'results', time_diff, read_diff, self.ave_rate ##################################################################### # result methods def average_rate(self): "get the average transfer rate (in bytes/second)" return self.ave_rate def elapsed_time(self): "the time between the start of the transfer and the most recent update" return self.last_update_time - self.start_time def remaining_time(self): "estimated time remaining" if not self.ave_rate or not self.total: return None return (self.total - self.last_amount_read) / self.ave_rate def fraction_read(self): """the fraction of the data that has been read (can be None for unknown transfer size)""" if self.total is None: return None elif self.total == 0: return 1.0 else: return float(self.last_amount_read) / self.total ######################################################################### # support methods def _temporal_rolling_ave(self, time_diff, read_diff, last_ave, timescale): """a temporal rolling average performs smooth averaging even when updates come at irregular intervals. This is performed by scaling the "epsilon" according to the time since the last update. Specifically, epsilon = time_diff / timescale As a general rule, the average will take on a completely new value after 'timescale' seconds.""" epsilon = time_diff / timescale if epsilon > 1: epsilon = 1.0 return self._rolling_ave(time_diff, read_diff, last_ave, epsilon) def _rolling_ave(self, time_diff, read_diff, last_ave, epsilon): """perform a "rolling average" iteration a rolling average "folds" new data into an existing average with some weight, epsilon. epsilon must be between 0.0 and 1.0 (inclusive) a value of 0.0 means only the old value (initial value) counts, and a value of 1.0 means only the newest value is considered.""" try: recent_rate = read_diff / time_diff except ZeroDivisionError: recent_rate = None if last_ave is None: return recent_rate elif recent_rate is None: return last_ave # at this point, both last_ave and recent_rate are numbers return epsilon * recent_rate + (1 - epsilon) * last_ave def _round_remaining_time(self, rt, start_time=15.0): """round the remaining time, depending on its size If rt is between n*start_time and (n+1)*start_time round downward to the nearest multiple of n (for any counting number n). If rt < start_time, round down to the nearest 1. For example (for start_time = 15.0): 2.7 -> 2.0 25.2 -> 25.0 26.4 -> 26.0 35.3 -> 34.0 63.6 -> 60.0 """ if rt < 0: return 0.0 shift = int(math.log(rt / start_time) / math.log(2)) rt = int(rt) if shift <= 0: return rt return float(int(rt) >> shift << shift) def format_time(seconds, use_hours=0): if seconds is None or seconds < 0: if use_hours: return '--:--:--' else: return '--:--' elif seconds == float('inf'): return 'Infinite' else: seconds = int(seconds) minutes = seconds // 60 seconds = seconds % 60 if use_hours: hours = minutes // 60 minutes = minutes % 60 return '%02i:%02i:%02i' % (hours, minutes, seconds) else: return '%02i:%02i' % (minutes, seconds) def format_number(number, SI=0, space=' '): """Turn numbers into human-readable metric-like numbers""" symbols = ['', # (none) 'k', # kilo 'M', # mega 'G', # giga 'T', # tera 'P', # peta 'E', # exa 'Z', # zetta 'Y'] # yotta if SI: step = 1000.0 else: step = 1024.0 thresh = 999 depth = 0 max_depth = len(symbols) - 1 # we want numbers between 0 and thresh, but don't exceed the length # of our list. In that event, the formatting will be screwed up, # but it'll still show the right number. while number > thresh and depth < max_depth: depth = depth + 1 number = number / step if isinstance(number, int) or isinstance(number, long): # it's an int or a long, which means it didn't get divided, # which means it's already short enough fmt = '%i%s%s' elif number < 9.95: # must use 9.95 for proper sizing. For example, 9.99 will be # rounded to 10.0 with the .1f format string (which is too long) fmt = '%.1f%s%s' else: fmt = '%.0f%s%s' return(fmt % (float(number or 0), space, symbols[depth])) virt-manager-1.5.1/virtinst/hostkeymap.py0000664000175100017510000001313013245573052022220 0ustar crobinsocrobinso00000000000000# # Copyright 2006-2013 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. # import logging import os import re _ETC_VCONSOLE = "/etc/vconsole.conf" _KEYBOARD_DIR = "/etc/sysconfig/keyboard" _XORG_CONF = "/etc/X11/xorg.conf" _CONSOLE_SETUP_CONF = "/etc/default/console-setup" _KEYBOARD_DEFAULT = "/etc/default/keyboard" def _find_xkblayout(f): """ Reads a keyboard layout from a file that defines an XKBLAYOUT variable, e.g. /etc/default/{keyboard,console-setup}. The format of these files is such that they can be 'sourced' in a shell script. Used for both /etc/default/keyboard and /etc/default/console-setup. The former is used by Debian 6.0 (Squeeze) and later. The latter is used by older versions of Debian, and Ubuntu. """ kt = None keymap_re = re.compile(r'\s*XKBLAYOUT="(?P[a-z-]+)"') for line in f: m = keymap_re.match(line) if m: kt = m.group('kt') break return kt def _xorg_keymap(f): """ Look in /etc/X11/xorg.conf for the host machine's keymap, and attempt to map it to a keymap supported by qemu """ kt = None keymap_re = re.compile(r'\s*Option\s+"XkbLayout"\s+"(?P[a-z-]+)"') for line in f: m = keymap_re.match(line) if m: kt = m.group('kt') break return kt def _sysconfig_keyboard(f): kt = None while 1: s = f.readline() if s == "": break s = s.strip() if s.startswith("#"): continue if (re.search("KEYMAP", s) is not None or re.search("KEYTABLE", s) is not None or (re.search("KEYBOARD", s) is not None and re.search("KEYBOARDTYPE", s) is None)): if s.count('"'): delim = '"' elif s.count('='): delim = '=' else: continue kt = s.split(delim)[1].strip() break return kt def _default_keymap(): """ Look in various config files for the host machine's keymap, and attempt to map it to a keymap supported by qemu """ # Set keymap to same as hosts default = "en-us" keymap = None kt = None if "VIRTINST_TEST_SUITE" in os.environ: return default for path, cb in [ (_ETC_VCONSOLE, _sysconfig_keyboard), (_KEYBOARD_DIR, _sysconfig_keyboard), (_XORG_CONF, _xorg_keymap), (_KEYBOARD_DEFAULT, _find_xkblayout), (_CONSOLE_SETUP_CONF, _find_xkblayout)]: if not os.path.exists(path): continue try: f = open(path, "r") kt = cb(f) f.close() if kt: logging.debug("Found keymap=%s in %s", kt, path) break logging.debug("Didn't find keymap in '%s'", path) except Exception as e: logging.debug("Error parsing '%s': %s", path, str(e)) if kt is None: logging.debug("Did not parse any usable keymapping.") return default kt = kt.lower() keymap = sanitize_keymap(kt) if not keymap: logging.debug("Didn't match keymap '%s' in keytable!", kt) return default return keymap ################## # Public helpers # ################## # Host keytable entry : keymap name in qemu/xen # Only use lower case entries: all lookups are .lower()'d keytable = { "ar": "ar", "da": "da", "dk": "da", "de": "de", "de-ch": "de-ch", "en-gb": "en-gb", "gb": "en-gb", "uk": "en-gb", "en-us": "en-us", "us": "en-us", "es": "es", "et": "et", "fi": "fi", "se_fi": "fi", "fo": "fo", "fr": "fr", "fr-be": "fr-be", "be": "fr-be", "fr-ca": "fr-ca", "ca": "fr-ca", "fr-ch": "fr-ch", "fr_ch": "fr-ch", "hr": "hr", "hu": "hu", "is": "is", "it": "it", "ja": "ja", "jp106": "ja", "jp": "ja", "lt": "lt", "lv": "lv", "mk": "mk", "nl": "nl", "nl-be": "nl-be", "no": "no", "pl": "pl", "pt": "pt", "pt-br": "pt-br", "br": "pt-br", "br-abnt2": "pt-br", "ru": "ru", "sl": "sl", "sv": "sv", "th": "th", "tr": "tr", } _cached_keymap = None def default_keymap(): global _cached_keymap if _cached_keymap is None: _cached_keymap = _default_keymap() return _cached_keymap def sanitize_keymap(kt): """ Make sure the passed keymap roughly matches something in keytable """ if kt.lower() in keytable: return keytable[kt] # Try a more intelligent lookup: strip out all '-' and '_', sort # the keytable keys putting the longest first, then compare # by string prefix def len_cmp(a, b): return len(b) - len(a) clean_kt = kt.replace("-", "").replace("_", "") sorted_keys = sorted(keytable.keys(), len_cmp) for key in sorted_keys: origkey = key key = key.replace("-", "").replace("_", "") if clean_kt.startswith(key): return keytable[origkey] return None virt-manager-1.5.1/virtinst/storage.py0000664000175100017510000007546013245573052021516 0ustar crobinsocrobinso00000000000000# # Copyright 2008, 2013, 2015 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import os import threading import time import logging import libvirt from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty from . import util _DEFAULT_DEV_TARGET = "/dev" _DEFAULT_LVM_TARGET_BASE = "/dev/" _DEFAULT_SCSI_TARGET = "/dev/disk/by-path" _DEFAULT_MPATH_TARGET = "/dev/mapper" class _StoragePermissions(XMLBuilder): _XML_ROOT_NAME = "permissions" _XML_PROP_ORDER = ["mode", "owner", "group", "label"] mode = XMLProperty("./mode") owner = XMLProperty("./owner") group = XMLProperty("./group") label = XMLProperty("./label") class _StorageObject(XMLBuilder): """ Base class for building any libvirt storage object. Meaningless to directly instantiate. """ ###################### # Validation helpers # ###################### def _check_name_collision(self, name): raise NotImplementedError() def _validate_name(self, name): if name == self.name: return util.validate_name(_("Storage object"), name) self._check_name_collision(name) return name ############## # Properties # ############## name = XMLProperty("./name", validate_cb=_validate_name, doc=_("Name for the storage object.")) permissions = XMLChildProperty(_StoragePermissions, relative_xpath="./target", is_single=True) def _get_default_pool_path(conn): path = "/var/lib/libvirt/images" if conn.is_session_uri(): path = os.path.expanduser("~/.local/share/libvirt/images") return path class _Host(XMLBuilder): _XML_PROP_ORDER = ["name", "port"] _XML_ROOT_NAME = "host" name = XMLProperty("./@name") port = XMLProperty("./@port", is_int=True) class StoragePool(_StorageObject): """ Base class for building and installing libvirt storage pool xml """ # @group Types: TYPE_* TYPE_DIR = "dir" TYPE_FS = "fs" TYPE_NETFS = "netfs" TYPE_LOGICAL = "logical" TYPE_DISK = "disk" TYPE_ISCSI = "iscsi" TYPE_SCSI = "scsi" TYPE_MPATH = "mpath" TYPE_GLUSTER = "gluster" TYPE_RBD = "rbd" TYPE_SHEEPDOG = "sheepdog" TYPE_ZFS = "zfs" # Pool type descriptions for use in higher level programs _descs = {} _descs[TYPE_DIR] = _("Filesystem Directory") _descs[TYPE_FS] = _("Pre-Formatted Block Device") _descs[TYPE_NETFS] = _("Network Exported Directory") _descs[TYPE_LOGICAL] = _("LVM Volume Group") _descs[TYPE_DISK] = _("Physical Disk Device") _descs[TYPE_ISCSI] = _("iSCSI Target") _descs[TYPE_SCSI] = _("SCSI Host Adapter") _descs[TYPE_MPATH] = _("Multipath Device Enumerator") _descs[TYPE_GLUSTER] = _("Gluster Filesystem") _descs[TYPE_RBD] = _("RADOS Block Device/Ceph") _descs[TYPE_SHEEPDOG] = _("Sheepdog Filesystem") _descs[TYPE_ZFS] = _("ZFS Pool") @staticmethod def get_pool_types(): """ Return list of appropriate pool types """ return StoragePool._descs.keys() @staticmethod def get_pool_type_desc(pool_type): """ Return human readable description for passed pool type """ return StoragePool._descs.get(pool_type, "%s pool" % pool_type) @staticmethod def pool_list_from_sources(conn, pool_type, host=None): """ Return a list of StoragePool instances built from libvirt's pool source enumeration (if supported). @param conn: Libvirt connection @param name: Name for the new pool @param pool_type: Pool type string from I{Types} @param host: Option host string to poll for sources """ if not conn.check_support(conn.SUPPORT_CONN_FINDPOOLSOURCES): return [] if host: source_xml = "" % host else: source_xml = "" try: xml = conn.findStoragePoolSources(pool_type, source_xml, 0) except libvirt.libvirtError as e: if util.is_error_nosupport(e): return [] raise class _EnumerateSource(XMLBuilder): _XML_ROOT_NAME = "source" class _EnumerateSources(XMLBuilder): _XML_ROOT_NAME = "sources" sources = XMLChildProperty(_EnumerateSource) ret = [] sources = _EnumerateSources(conn, xml) for source in sources.sources: source_xml = source.get_xml_config() pool_xml = "\n%s\n" % ( XMLBuilder.xml_indent(source_xml, 2)) parseobj = StoragePool(conn, parsexml=pool_xml) parseobj.type = pool_type obj = StoragePool(conn) obj.type = pool_type obj.source_path = parseobj.source_path for h in parseobj.hosts: parseobj.remove_host(h) obj.add_host_obj(h) obj.source_name = parseobj.source_name obj.format = parseobj.format ret.append(obj) return ret @staticmethod def build_default_pool(conn): """ Helper to build the 'default' storage pool """ if not conn.check_support(conn.SUPPORT_CONN_STORAGE): return pool = None name = "default" path = _get_default_pool_path(conn) if conn.is_session_uri() and not os.path.exists(path): os.makedirs(path) try: pool = conn.storagePoolLookupByName(name) except libvirt.libvirtError: # Try default pool path when "default" name fails pool = StoragePool.lookup_pool_by_path(conn, path) if pool: # This is a libvirt pool object so create a StoragePool from it return StoragePool(conn, parsexml=pool.XMLDesc(0)) try: logging.debug("Attempting to build default pool with target '%s'", path) defpool = StoragePool(conn) defpool.type = defpool.TYPE_DIR defpool.name = name defpool.target_path = path defpool.install(build=True, create=True, autostart=True) return defpool except Exception as e: raise RuntimeError( _("Couldn't create default storage pool '%s': %s") % (path, str(e))) @staticmethod def manage_path(conn, path): """ If the passed path is managed, lookup its storage objects. If the passed path isn't managed, attempt to manage it if we can. :returns: (vol, parent pool) tuple """ from . import diskbackend return diskbackend.manage_path(conn, path) @staticmethod def get_default_dir(conn, build=False): """ Return the default storage dir. If there's a 'default' pool, report that. If there's no default pool, return the dir we would use for the default. """ path = _get_default_pool_path(conn) if (not conn.is_remote() and not conn.check_support(conn.SUPPORT_CONN_STORAGE)): if build and not os.path.exists(path): os.makedirs(path) return path try: for pool in conn.fetch_all_pools(): if pool.name == "default": return pool.target_path except Exception: pass if build: return StoragePool.build_default_pool(conn).target_path return _get_default_pool_path(conn) @staticmethod def lookup_pool_by_path(conn, path): """ Return the first pool with matching matching target path. return the first we find, active or inactive. This iterates over all pools and dumps their xml, so it is NOT quick. @returns: virStoragePool object if found, None otherwise """ if not conn.check_support(conn.SUPPORT_CONN_STORAGE): return None for pool in conn.fetch_all_pools(): xml_path = pool.target_path if xml_path is not None and os.path.abspath(xml_path) == path: return conn.storagePoolLookupByName(pool.name) return None @staticmethod def find_free_name(conn, basename, **kwargs): """ Finds a name similar (or equal) to passed 'basename' that is not in use by another pool. Extra params are passed to generate_name """ def cb(name): for pool in conn.fetch_all_pools(): if pool.name == name: return True return False kwargs["lib_collision"] = False return util.generate_name(basename, cb, **kwargs) ###################### # Validation helpers # ###################### def _check_name_collision(self, name): pool = None try: pool = self.conn.storagePoolLookupByName(name) except libvirt.libvirtError: pass if pool: raise ValueError(_("Name '%s' already in use by another pool." % name)) def _get_default_target_path(self): if not self.supports_property("target_path"): return None if (self.type == self.TYPE_DIR or self.type == self.TYPE_NETFS or self.type == self.TYPE_FS): return os.path.join(self.get_default_dir(self.conn), self.name) if self.type == self.TYPE_LOGICAL: name = self.name if self.source_name: name = self.source_name return _DEFAULT_LVM_TARGET_BASE + name if self.type == self.TYPE_DISK: return _DEFAULT_DEV_TARGET if self.type == self.TYPE_ISCSI or self.type == self.TYPE_SCSI: return _DEFAULT_SCSI_TARGET if self.type == self.TYPE_MPATH: return _DEFAULT_MPATH_TARGET raise RuntimeError("No default target_path for type=%s" % self.type) def _type_to_source_prop(self): if (self.type == self.TYPE_NETFS or self.type == self.TYPE_GLUSTER): return "_source_dir" elif self.type == self.TYPE_SCSI: return "_source_adapter" else: return "_source_device" def _get_source(self): return getattr(self, self._type_to_source_prop()) def _set_source(self, val): return setattr(self, self._type_to_source_prop(), val) source_path = property(_get_source, _set_source) def _default_source_name(self): srcname = None if not self.supports_property("source_name"): srcname = None elif self.type == StoragePool.TYPE_NETFS: srcname = self.name elif self.type == StoragePool.TYPE_RBD: srcname = "rbd" elif self.type == StoragePool.TYPE_GLUSTER: srcname = "gv0" elif ("target_path" in self._propstore and self.target_path and self.target_path.startswith(_DEFAULT_LVM_TARGET_BASE)): # If there is a target path, parse it for an expected VG # location, and pull the name from there vg = self.target_path[len(_DEFAULT_LVM_TARGET_BASE):] srcname = vg.split("/", 1)[0] return srcname def _default_format_cb(self): if not self.supports_property("format"): return None return "auto" ############## # Properties # ############## _XML_ROOT_NAME = "pool" _XML_PROP_ORDER = ["name", "type", "uuid", "capacity", "allocation", "available", "format", "hosts", "_source_dir", "_source_adapter", "_source_device", "source_name", "target_path", "permissions", "auth_type", "auth_username", "auth_secret_uuid"] _source_dir = XMLProperty("./source/dir/@path") _source_adapter = XMLProperty("./source/adapter/@name") _source_device = XMLProperty("./source/device/@path") type = XMLProperty("./@type", doc=_("Storage device type the pool will represent.")) uuid = XMLProperty("./uuid") capacity = XMLProperty("./capacity", is_int=True) allocation = XMLProperty("./allocation", is_int=True) available = XMLProperty("./available", is_int=True) format = XMLProperty("./source/format/@type", default_cb=_default_format_cb) iqn = XMLProperty("./source/initiator/iqn/@name", doc=_("iSCSI initiator qualified name")) source_name = XMLProperty("./source/name", default_cb=_default_source_name, doc=_("Name of the Volume Group")) auth_type = XMLProperty("./source/auth/@type") auth_username = XMLProperty("./source/auth/@username") auth_secret_uuid = XMLProperty("./source/auth/secret/@uuid") target_path = XMLProperty("./target/path", default_cb=_get_default_target_path) def add_host_obj(self, obj): self.add_child(obj) def add_host(self, name, port=None): obj = _Host(self.conn) obj.name = name obj.port = port self.add_child(obj) def remove_host(self, obj): self.remove_child(obj) hosts = XMLChildProperty(_Host, relative_xpath="./source") ###################### # Public API helpers # ###################### def supports_property(self, propname): users = { "source_path": [self.TYPE_FS, self.TYPE_NETFS, self.TYPE_LOGICAL, self.TYPE_DISK, self.TYPE_ISCSI, self.TYPE_SCSI, self.TYPE_GLUSTER], "source_name": [self.TYPE_LOGICAL, self.TYPE_GLUSTER, self.TYPE_RBD, self.TYPE_SHEEPDOG, self.TYPE_ZFS], "hosts": [self.TYPE_NETFS, self.TYPE_ISCSI, self.TYPE_GLUSTER, self.TYPE_RBD, self.TYPE_SHEEPDOG], "format": [self.TYPE_FS, self.TYPE_NETFS, self.TYPE_DISK], "iqn": [self.TYPE_ISCSI], "target_path": [self.TYPE_DIR, self.TYPE_FS, self.TYPE_NETFS, self.TYPE_LOGICAL, self.TYPE_DISK, self.TYPE_ISCSI, self.TYPE_SCSI, self.TYPE_MPATH] } if users.get(propname): return self.type in users[propname] return hasattr(self, propname) def list_formats(self): if self.type == self.TYPE_FS: return ["auto", "ext2", "ext3", "ext4", "ufs", "iso9660", "udf", "gfs", "gfs2", "vfat", "hfs+", "xfs"] if self.type == self.TYPE_NETFS: return ["auto", "nfs", "glusterfs"] if self.type == self.TYPE_DISK: return ["auto", "bsd", "dos", "dvh", "gpt", "mac", "pc98", "sun"] return [] def supports_volume_creation(self): return self.type in [ StoragePool.TYPE_DIR, StoragePool.TYPE_FS, StoragePool.TYPE_NETFS, StoragePool.TYPE_LOGICAL, StoragePool.TYPE_DISK, StoragePool.TYPE_RBD, StoragePool.TYPE_SHEEPDOG, StoragePool.TYPE_ZFS] def get_disk_type(self): if (self.type == StoragePool.TYPE_DISK or self.type == StoragePool.TYPE_LOGICAL or self.type == StoragePool.TYPE_SCSI or self.type == StoragePool.TYPE_MPATH or self.type == StoragePool.TYPE_ZFS): return StorageVolume.TYPE_BLOCK if (self.type == StoragePool.TYPE_GLUSTER or self.type == StoragePool.TYPE_RBD or self.type == StoragePool.TYPE_ISCSI or self.type == StoragePool.TYPE_SHEEPDOG): return StorageVolume.TYPE_NETWORK return StorageVolume.TYPE_FILE ################## # Build routines # ################## def validate(self): if self.supports_property("host") and not self.hosts: raise RuntimeError(_("Hostname is required")) if (self.supports_property("source_path") and self.type != self.TYPE_LOGICAL and not self.source_path): raise RuntimeError(_("Source path is required")) if (self.type == self.TYPE_DISK and self.format == "auto"): # There is no explicit "auto" type for disk pools, but leaving out # the format type seems to do the job for existing formatted disks self.format = None def install(self, meter=None, create=False, build=False, autostart=False): """ Install storage pool xml. """ if (self.type == self.TYPE_LOGICAL and build and not self.source_path): raise ValueError(_("Must explicitly specify source path if " "building pool")) if (self.type == self.TYPE_DISK and build and self.format == "auto"): raise ValueError(_("Must explicitly specify disk format if " "formatting disk device.")) xml = self.get_xml_config() logging.debug("Creating storage pool '%s' with xml:\n%s", self.name, xml) meter = util.ensure_meter(meter) try: pool = self.conn.storagePoolDefineXML(xml, 0) except Exception as e: raise RuntimeError(_("Could not define storage pool: %s") % str(e)) errmsg = None if build: try: pool.build(libvirt.VIR_STORAGE_POOL_BUILD_NEW) except Exception as e: errmsg = _("Could not build storage pool: %s") % str(e) if create and not errmsg: try: pool.create(0) except Exception as e: errmsg = _("Could not start storage pool: %s") % str(e) if autostart and not errmsg: try: pool.setAutostart(True) except Exception as e: errmsg = _("Could not set pool autostart flag: %s") % str(e) if errmsg: # Try and clean up the leftover pool try: pool.undefine() except Exception as e: logging.debug("Error cleaning up pool after failure: " + "%s" % str(e)) raise RuntimeError(errmsg) self.conn.cache_new_pool(pool) return pool class StorageVolume(_StorageObject): """ Base class for building and installing libvirt storage volume xml """ ALL_FORMATS = ["raw", "bochs", "cloop", "dmg", "iso", "qcow", "qcow2", "qed", "vmdk", "vpc", "fat", "vhd", "vdi"] @staticmethod def get_file_extension_for_format(fmt): if not fmt: return "" if fmt == "raw": return ".img" return "." + fmt @staticmethod def find_free_name(pool_object, basename, **kwargs): """ Finds a name similar (or equal) to passed 'basename' that is not in use by another volume. Extra params are passed to generate_name """ pool_object.refresh(0) return util.generate_name(basename, pool_object.storageVolLookupByName, **kwargs) TYPE_FILE = getattr(libvirt, "VIR_STORAGE_VOL_FILE", 0) TYPE_BLOCK = getattr(libvirt, "VIR_STORAGE_VOL_BLOCK", 1) TYPE_DIR = getattr(libvirt, "VIR_STORAGE_VOL_DIR", 2) TYPE_NETWORK = getattr(libvirt, "VIR_STORAGE_VOL_NETWORK", 3) TYPE_NETDIR = getattr(libvirt, "VIR_STORAGE_VOL_NETDIR", 4) def __init__(self, *args, **kwargs): _StorageObject.__init__(self, *args, **kwargs) self._input_vol = None self._pool = None self._pool_xml = None self._reflink = False # Indicate that the volume installation has finished. Used to # definitively tell the storage progress thread to stop polling. self._install_finished = True ###################### # Non XML properties # ###################### def _get_pool(self): return self._pool def _set_pool(self, newpool): if newpool.info()[0] != libvirt.VIR_STORAGE_POOL_RUNNING: raise ValueError(_("pool '%s' must be active.") % newpool.name()) self._pool = newpool self._pool_xml = StoragePool(self.conn, parsexml=self._pool.XMLDesc(0)) pool = property(_get_pool, _set_pool) def _get_input_vol(self): return self._input_vol def _set_input_vol(self, vol): if vol is None: self._input_vol = None return if not isinstance(vol, libvirt.virStorageVol): raise ValueError(_("input_vol must be a virStorageVol")) if not self.conn.check_support( self.conn.SUPPORT_POOL_CREATEVOLFROM, self.pool): raise ValueError(_("Creating storage from an existing volume is" " not supported by this libvirt version.")) self._input_vol = vol input_vol = property(_get_input_vol, _set_input_vol, doc=_("virStorageVolume pointer to clone/use as " "input.")) def _get_reflink(self): return self._reflink def _set_reflink(self, reflink): if (reflink and not self.conn.check_support(self.conn.SUPPORT_POOL_REFLINK)): raise ValueError(_("Creating storage by btrfs COW copy is" " not supported by this libvirt version.")) self._reflink = reflink reflink = property(_get_reflink, _set_reflink, doc="flags for VIR_STORAGE_VOL_CREATE_REFLINK") def sync_input_vol(self, only_format=False): # Pull parameters from input vol into this class parsevol = StorageVolume(self.conn, parsexml=self._input_vol.XMLDesc(0)) self.format = parsevol.format self.capacity = parsevol.capacity self.allocation = parsevol.allocation if only_format: return self.pool = self._input_vol.storagePoolLookupByVolume() ########################## # XML validation helpers # ########################## def _check_name_collision(self, name): vol = None try: vol = self.pool.storageVolLookupByName(name) except libvirt.libvirtError: pass if vol: raise ValueError(_("Name '%s' already in use by another volume." % name)) def _default_format(self): if self.file_type == self.TYPE_FILE: return "raw" return None def _get_vol_type(self): if self.type: if self.type == "file": return self.TYPE_FILE elif self.type == "block": return self.TYPE_BLOCK elif self.type == "dir": return self.TYPE_DIR elif self.type == "network": return self.TYPE_NETWORK return self._pool_xml.get_disk_type() file_type = property(_get_vol_type) ################## # XML properties # ################## _XML_ROOT_NAME = "volume" _XML_PROP_ORDER = ["name", "key", "capacity", "allocation", "format", "target_path", "permissions"] type = XMLProperty("./@type") key = XMLProperty("./key") capacity = XMLProperty("./capacity", is_int=True) allocation = XMLProperty("./allocation", is_int=True) format = XMLProperty("./target/format/@type", default_cb=_default_format) target_path = XMLProperty("./target/path") backing_store = XMLProperty("./backingStore/path") backing_format = XMLProperty("./backingStore/format/@type") def _lazy_refcounts_default_cb(self): if self.format != "qcow2": return False return self.conn.check_support( self.conn.SUPPORT_CONN_QCOW2_LAZY_REFCOUNTS) lazy_refcounts = XMLProperty("./target/features/lazy_refcounts", is_bool=True, default_cb=_lazy_refcounts_default_cb) def _detect_backing_store_format(self): logging.debug("Attempting to detect format for backing_store=%s", self.backing_store) vol, pool = StoragePool.manage_path(self.conn, self.backing_store) if not vol: logging.debug("Didn't find any volume for backing_store") return None # Only set backing format for volumes that support # the 'format' parameter as we know it, like qcow2 etc. volxml = StorageVolume(self.conn, vol.XMLDesc(0)) volxml.pool = pool logging.debug("Found backing store volume XML:\n%s", volxml.get_xml_config()) if volxml.supports_property("format"): logging.debug("Returning format=%s", volxml.format) return volxml.format logging.debug("backing_store volume doesn't appear to have " "a file format we can specify, returning None") return None ###################### # Public API helpers # ###################### def _supports_format(self): if self.file_type == self.TYPE_FILE: return True if self._pool_xml.type == StoragePool.TYPE_GLUSTER: return True return False def supports_property(self, propname): if propname == "format": return self._supports_format() return hasattr(self, propname) def list_formats(self): if self._supports_format(): return self.ALL_FORMATS return [] def list_create_formats(self): if self._supports_format(): return ["raw", "qcow", "qcow2", "qed", "vmdk", "vpc", "vdi"] return None ################## # Build routines # ################## def validate(self): if self._pool_xml.type == StoragePool.TYPE_LOGICAL: if self.allocation != self.capacity: logging.warning(_("Sparse logical volumes are not supported, " "setting allocation equal to capacity")) self.allocation = self.capacity isfatal, errmsg = self.is_size_conflict() if isfatal: raise ValueError(errmsg) if errmsg: logging.warning(errmsg) def install(self, meter=None): """ Build and install storage volume from xml """ if self.backing_store and not self.backing_format: self.backing_format = self._detect_backing_store_format() xml = self.get_xml_config() logging.debug("Creating storage volume '%s' with xml:\n%s", self.name, xml) t = threading.Thread(target=self._progress_thread, name="Checking storage allocation", args=(meter,)) t.setDaemon(True) meter = util.ensure_meter(meter) cloneflags = 0 createflags = 0 if (self.format == "qcow2" and not self.backing_store and not self.conn.is_really_test() and self.conn.check_support( self.conn.SUPPORT_POOL_METADATA_PREALLOC, self.pool)): createflags |= libvirt.VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA if self.reflink: cloneflags |= getattr(libvirt, "VIR_STORAGE_VOL_CREATE_REFLINK", 1) try: self._install_finished = False t.start() meter.start(size=self.capacity, text=_("Allocating '%s'") % self.name) if self.input_vol: vol = self.pool.createXMLFrom(xml, self.input_vol, cloneflags) else: logging.debug("Using vol create flags=%s", createflags) vol = self.pool.createXML(xml, createflags) self._install_finished = True t.join() meter.end(self.capacity) logging.debug("Storage volume '%s' install complete.", self.name) return vol except Exception as e: logging.debug("Error creating storage volume", exc_info=True) raise RuntimeError("Couldn't create storage volume " "'%s': '%s'" % (self.name, str(e))) def _progress_thread(self, meter): vol = None if not meter: return while True: try: if not vol: vol = self.pool.storageVolLookupByName(self.name) vol.info() break except Exception: if time: # pylint: disable=using-constant-test # This 'if' check saves some noise from the test suite time.sleep(.2) if self._install_finished: break if vol is None: logging.debug("Couldn't lookup storage volume in prog thread.") return while not self._install_finished: ignore, ignore, alloc = vol.info() meter.update(alloc) time.sleep(1) def is_size_conflict(self): """ Report if requested size exceeds its pool's available amount @returns: 2 element tuple: 1. True if collision is fatal, false otherwise 2. String message if some collision was encountered. @rtype: 2 element C{tuple}: (C{bool}, C{str}) """ if not self.pool: return (False, "") # pool info is [pool state, capacity, allocation, available] avail = self.pool.info()[3] if self.allocation > avail: return (True, _("There is not enough free space on the storage " "pool to create the volume. " "(%d M requested allocation > %d M available)") % ((self.allocation // (1024 * 1024)), (avail // (1024 * 1024)))) elif self.capacity > avail: return (False, _("The requested volume capacity will exceed the " "available pool space when the volume is fully " "allocated. " "(%d M requested capacity > %d M available)") % ((self.capacity // (1024 * 1024)), (avail // (1024 * 1024)))) return (False, "") virt-manager-1.5.1/virtinst/devicefilesystem.py0000664000175100017510000001256313241024270023376 0ustar crobinsocrobinso00000000000000# # Copyright 2011, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import os from .device import VirtualDevice from .xmlbuilder import XMLProperty class VirtualFilesystem(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_FILESYSTEM TYPE_MOUNT = "mount" TYPE_TEMPLATE = "template" TYPE_FILE = "file" TYPE_BLOCK = "block" TYPE_RAM = "ram" TYPE_DEFAULT = "default" TYPES = [TYPE_MOUNT, TYPE_TEMPLATE, TYPE_FILE, TYPE_BLOCK, TYPE_RAM, TYPE_DEFAULT] MODE_PASSTHROUGH = "passthrough" MODE_MAPPED = "mapped" MODE_SQUASH = "squash" MODE_DEFAULT = "default" MODES = [MODE_PASSTHROUGH, MODE_MAPPED, MODE_SQUASH, MODE_DEFAULT] WRPOLICY_IMM = "immediate" WRPOLICY_DEFAULT = "default" WRPOLICIES = [WRPOLICY_IMM, WRPOLICY_DEFAULT] DRIVER_PATH = "path" DRIVER_HANDLE = "handle" DRIVER_LOOP = "loop" DRIVER_NBD = "nbd" DRIVER_DEFAULT = "default" DRIVERS = [DRIVER_PATH, DRIVER_HANDLE, DRIVER_LOOP, DRIVER_NBD, DRIVER_DEFAULT] _type_prop = XMLProperty("./@type", default_cb=lambda s: None, default_name=TYPE_DEFAULT) accessmode = XMLProperty("./@accessmode", default_cb=lambda s: None, default_name=MODE_DEFAULT) wrpolicy = XMLProperty("./driver/@wrpolicy", default_cb=lambda s: None, default_name=WRPOLICY_DEFAULT) driver = XMLProperty("./driver/@type", default_cb=lambda s: None, default_name=DRIVER_DEFAULT) format = XMLProperty("./driver/@format") readonly = XMLProperty("./readonly", is_bool=True) units = XMLProperty("./source/@units") def _validate_set_target(self, val): # In case of qemu for default fs type (mount) target is not # actually a directory, it is merely a arbitrary string tag # that is exported to the guest as a hint for where to mount if ((self.conn.is_qemu() or self.conn.is_test()) and (self.type is None or self.type == self.TYPE_DEFAULT or self.type == self.TYPE_MOUNT)): pass elif not os.path.isabs(val): raise ValueError(_("Filesystem target '%s' must be an absolute " "path") % val) return val target = XMLProperty("./target/@dir", set_converter=_validate_set_target) _source_dir = XMLProperty("./source/@dir") _source_name = XMLProperty("./source/@name") _source_file = XMLProperty("./source/@file") _source_dev = XMLProperty("./source/@dev") _source_usage = XMLProperty("./source/@usage") def _type_to_source_prop(self): if self.type == VirtualFilesystem.TYPE_TEMPLATE: return "_source_name" elif self.type == VirtualFilesystem.TYPE_FILE: return "_source_file" elif self.type == VirtualFilesystem.TYPE_BLOCK: return "_source_dev" elif self.type == VirtualFilesystem.TYPE_RAM: return "_source_usage" else: return "_source_dir" def _get_source(self): return getattr(self, self._type_to_source_prop()) def _set_source(self, val): return setattr(self, self._type_to_source_prop(), val) source = property(_get_source, _set_source) def _get_type(self): return getattr(self, '_type_prop') def _set_type(self, val): # Get type/value of the attrubute of "source" property old_source_type = self._type_to_source_prop() old_source_value = self.source # Update "type" property new_type = setattr(self, '_type_prop', val) # If the attribute type of 'source' property has changed # restore the value if old_source_type != self._type_to_source_prop(): self.source = old_source_value return new_type type = property(_get_type, _set_type) def set_defaults(self, guest): ignore = guest if self.conn.is_qemu() or self.conn.is_lxc() or self.conn.is_test(): # type=mount is the libvirt default. But hardcode it # here since we need it for the accessmode check if self.type is None or self.type == self.TYPE_DEFAULT: self.type = self.TYPE_MOUNT # libvirt qemu defaults to accessmode=passthrough, but that # really only works well for qemu running as root, which is # not the common case. so use mode=mapped if self.accessmode is None or self.accessmode == self.MODE_DEFAULT: self.accessmode = self.MODE_MAPPED VirtualFilesystem.register_type() virt-manager-1.5.1/virtinst/pollhelpers.py0000664000175100017510000002226513245573052022376 0ustar crobinsocrobinso00000000000000# # Copyright (C) 2013 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. # import logging # Debugging helper to force old style polling # Can be enabled with virt-manager --test-old-poll FORCE_OLD_POLL = False def _new_poll_helper(origmap, typename, listfunc, buildfunc): """ Helper for new style listAll* APIs """ current = {} new = {} objs = [] try: objs = listfunc() except Exception as e: logging.debug("Unable to list all %ss: %s", typename, e) for obj in objs: connkey = obj.name() if connkey not in origmap: # Object is brand new this period current[connkey] = buildfunc(obj, connkey) new[connkey] = current[connkey] else: # Previously known object current[connkey] = origmap[connkey] del(origmap[connkey]) return (origmap.values(), new.values(), current.values()) def _old_poll_helper(origmap, typename, active_list, inactive_list, lookup_func, build_func): """ Helper routine for old style split API libvirt polling. @origmap: Pre-existing mapping of objects, with connkey->obj mapping. objects must have an is_active and set_active API @typename: string describing type of objects we are polling for use in debug messages. @active_list: Function that returns the list of active objects @inactive_list: Function that returns the list of inactive objects @lookup_func: Function to get an object handle for the passed name @build_func: Function that builds a new object class. It is passed args of (raw libvirt object, connkey) """ current = {} new = {} newActiveNames = [] newInactiveNames = [] try: newActiveNames = active_list() except Exception as e: logging.debug("Unable to list active %ss: %s", typename, e) try: newInactiveNames = inactive_list() except Exception as e: logging.debug("Unable to list inactive %ss: %s", typename, e) def check_obj(name): obj = None connkey = name if connkey not in origmap: try: obj = lookup_func(name) except Exception as e: logging.debug("Could not fetch %s '%s': %s", typename, connkey, e) return # Object is brand new this period current[connkey] = build_func(obj, connkey) new[connkey] = current[connkey] else: # Previously known object current[connkey] = origmap[connkey] del(origmap[connkey]) for name in newActiveNames + newInactiveNames: try: check_obj(name) except Exception: logging.exception("Couldn't fetch %s '%s'", typename, name) return (origmap.values(), new.values(), current.values()) def fetch_nets(backend, origmap, build_func): name = "network" if backend.check_support( backend.SUPPORT_CONN_LISTALLNETWORKS) and not FORCE_OLD_POLL: return _new_poll_helper(origmap, name, backend.listAllNetworks, build_func) else: active_list = backend.listNetworks inactive_list = backend.listDefinedNetworks lookup_func = backend.networkLookupByName return _old_poll_helper(origmap, name, active_list, inactive_list, lookup_func, build_func) def fetch_pools(backend, origmap, build_func): name = "pool" if backend.check_support( backend.SUPPORT_CONN_LISTALLSTORAGEPOOLS) and not FORCE_OLD_POLL: return _new_poll_helper(origmap, name, backend.listAllStoragePools, build_func) else: active_list = backend.listStoragePools inactive_list = backend.listDefinedStoragePools lookup_func = backend.storagePoolLookupByName return _old_poll_helper(origmap, name, active_list, inactive_list, lookup_func, build_func) def fetch_volumes(backend, pool, origmap, build_func): name = "volume" if backend.check_support( backend.SUPPORT_POOL_LISTALLVOLUMES, pool) and not FORCE_OLD_POLL: return _new_poll_helper(origmap, name, pool.listAllVolumes, build_func) else: active_list = pool.listVolumes def inactive_list(): return [] lookup_func = pool.storageVolLookupByName return _old_poll_helper(origmap, name, active_list, inactive_list, lookup_func, build_func) def fetch_interfaces(backend, origmap, build_func): name = "interface" if backend.check_support( backend.SUPPORT_CONN_LISTALLINTERFACES) and not FORCE_OLD_POLL: return _new_poll_helper(origmap, name, backend.listAllInterfaces, build_func) else: active_list = backend.listInterfaces inactive_list = backend.listDefinedInterfaces lookup_func = backend.interfaceLookupByName return _old_poll_helper(origmap, name, active_list, inactive_list, lookup_func, build_func) def fetch_nodedevs(backend, origmap, build_func): name = "nodedev" if backend.check_support( backend.SUPPORT_CONN_LISTALLDEVICES) and not FORCE_OLD_POLL: return _new_poll_helper(origmap, name, backend.listAllDevices, build_func) else: def active_list(): return backend.listDevices(None, 0) def inactive_list(): return [] lookup_func = backend.nodeDeviceLookupByName return _old_poll_helper(origmap, name, active_list, inactive_list, lookup_func, build_func) def _old_fetch_vms(backend, origmap, build_func): # We can't easily use _old_poll_helper here because the domain API # doesn't always return names like other objects, it returns # IDs for active VMs newActiveIDs = [] newInactiveNames = [] oldActiveIDs = {} oldInactiveNames = {} current = {} new = {} # Build list of previous vms with proper id/name mappings for vm in origmap.values(): if vm.is_active(): oldActiveIDs[vm.get_id()] = vm else: oldInactiveNames[vm.get_name()] = vm try: newActiveIDs = backend.listDomainsID() except Exception as e: logging.debug("Unable to list active domains: %s", e) try: newInactiveNames = backend.listDefinedDomains() except Exception as e: logging.exception("Unable to list inactive domains: %s", e) def add_vm(vm): connkey = vm.get_name() current[connkey] = vm del(origmap[connkey]) def check_new(rawvm, connkey): if connkey in origmap: vm = origmap[connkey] del(origmap[connkey]) else: vm = build_func(rawvm, connkey) new[connkey] = vm current[connkey] = vm for _id in newActiveIDs: if _id in oldActiveIDs: # No change, copy across existing VM object vm = oldActiveIDs[_id] add_vm(vm) else: # Check if domain is brand new, or old one that changed state try: vm = backend.lookupByID(_id) connkey = vm.name() check_new(vm, connkey) except Exception: logging.exception("Couldn't fetch domain id '%s'", _id) for name in newInactiveNames: if name in oldInactiveNames: # No change, copy across existing VM object vm = oldInactiveNames[name] add_vm(vm) else: # Check if domain is brand new, or old one that changed state try: vm = backend.lookupByName(name) connkey = name check_new(vm, connkey) except Exception: logging.exception("Couldn't fetch domain '%s'", name) return (origmap.values(), new.values(), current.values()) def fetch_vms(backend, origmap, build_func): name = "domain" if backend.check_support( backend.SUPPORT_CONN_LISTALLDOMAINS): return _new_poll_helper(origmap, name, backend.listAllDomains, build_func) else: return _old_fetch_vms(backend, origmap, build_func) virt-manager-1.5.1/virtinst/support.py0000664000175100017510000004031213245573052021552 0ustar crobinsocrobinso00000000000000# # Helper functions for determining if libvirt supports certain features # # Copyright 2009, 2013, 2014 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import libvirt from . import util # Check that command is present in the python bindings, and return the # the requested function def _get_command(funcname, objname=None, obj=None): if not obj: obj = libvirt if objname: if not hasattr(libvirt, objname): return None obj = getattr(libvirt, objname) if not hasattr(obj, funcname): return None return getattr(obj, funcname) # Make sure libvirt object 'objname' has function 'funcname' def _has_command(funcname, objname=None, obj=None): return bool(_get_command(funcname, objname, obj)) # Make sure libvirt object has flag 'flag_name' def _get_flag(flag_name): return _get_command(flag_name) # Try to call the passed function, and look for signs that libvirt or driver # doesn't support it def _try_command(func, run_args, check_all_error=False): try: func(*run_args) except libvirt.libvirtError as e: if util.is_error_nosupport(e): return False if check_all_error: return False except Exception as e: # Other python exceptions likely mean the bindings are horked return False return True # Return the hypervisor version def _split_function_name(function): if not function: return (None, None) output = function.split(".") if len(output) == 1: return (None, output[0]) else: return (output[0], output[1]) def _check_function(function, flag, run_args, data): object_name, function_name = _split_function_name(function) if not function_name: return None # Make sure function is present in either libvirt module or # object_name class flag_tuple = () if not _has_command(function_name, objname=object_name): return False if flag: found_flag = _get_flag(flag) if not bool(found_flag): return False flag_tuple = (found_flag,) if run_args is None: return None # If function requires an object, make sure the passed obj # is of the correct type if object_name: classobj = _get_command(object_name) if not isinstance(data, classobj): raise ValueError( "Passed obj %s with args must be of type %s, was %s" % (data, str(classobj), type(data))) cmd = _get_command(function_name, obj=data) # Function with args specified is all the proof we need return _try_command(cmd, run_args + flag_tuple, check_all_error=bool(flag_tuple)) def _version_str_to_int(verstr): if verstr is None: return None if verstr == 0: return 0 if verstr.count(".") != 2: raise RuntimeError("programming error: version string '%s' needs " "two '.' in it.") return ((int(verstr.split(".")[0]) * 1000000) + (int(verstr.split(".")[1]) * 1000) + (int(verstr.split(".")[2]))) class _SupportCheck(object): """ @version: Minimum libvirt version required for this feature. Not used if 'args' provided. @function: Function name to check exists. If object not specified, function is checked against libvirt module. If run_args is specified, this function will actually be called, so beware. @run_args: Argument tuple to actually test 'function' with, and check for an 'unsupported' error from libvirt. @flag: A flag to check exists. This will be appended to the argument list if run_args are provided, otherwise we will only check against that the flag is present in the python bindings. @hv_version: A dictionary with hypervisor names for keys, and hypervisor versions as values. This is for saying 'this feature is only supported with qemu version 1.5.0' or similar. If the version is 0, then perform no version check. @hv_libvirt_version: Similar to hv_version, but this will check the version of libvirt for a specific hv key. Use this to say 'this feature is supported with qemu and libvirt version 1.0.0, and xen with libvirt version 1.1.0' """ def __init__(self, function=None, run_args=None, flag=None, version=None, hv_version=None, hv_libvirt_version=None): self.function = function self.run_args = run_args self.flag = flag self.version = version self.hv_version = hv_version or {} self.hv_libvirt_version = hv_libvirt_version or {} versions = ([self.version] + self.hv_libvirt_version.values()) for vstr in versions: v = _version_str_to_int(vstr) if vstr is not None and v != 0 and v < 7009: raise RuntimeError("programming error: Cannot enforce " "support checks for libvirt versions less than 0.7.9, " "since required APIs were not available. ver=%s" % vstr) def check_support(self, conn, data): ret = _check_function(self.function, self.flag, self.run_args, data) if ret is not None: return ret # Do this after the function check, since there's an ordering issue # with VirtualConnection hv_type = conn.get_uri_driver() actual_libvirt_version = conn.daemon_version() actual_hv_version = conn.conn_version() # Check that local libvirt version is sufficient v = _version_str_to_int(self.version) if v and (v > actual_libvirt_version): return False if self.hv_version: if hv_type not in self.hv_version: if "all" not in self.hv_version: return False elif (actual_hv_version < _version_str_to_int(self.hv_version[hv_type])): return False if self.hv_libvirt_version: if hv_type not in self.hv_libvirt_version: if "all" not in self.hv_libvirt_version: return False elif (actual_libvirt_version < _version_str_to_int(self.hv_libvirt_version[hv_type])): return False return True _support_id = 0 _support_objs = [] def _make(*args, **kwargs): global _support_id _support_id += 1 obj = _SupportCheck(*args, **kwargs) _support_objs.append(obj) return _support_id SUPPORT_CONN_STORAGE = _make( function="virConnect.listStoragePools", run_args=()) SUPPORT_CONN_NODEDEV = _make( function="virConnect.listDevices", run_args=(None, 0)) SUPPORT_CONN_FINDPOOLSOURCES = _make( function="virConnect.findStoragePoolSources") SUPPORT_CONN_KEYMAP_AUTODETECT = _make(hv_version={"qemu": "0.11.0"}) SUPPORT_CONN_GETHOSTNAME = _make( function="virConnect.getHostname", run_args=()) SUPPORT_CONN_NETWORK = _make(function="virConnect.listNetworks", run_args=()) SUPPORT_CONN_INTERFACE = _make( function="virConnect.listInterfaces", run_args=()) SUPPORT_CONN_MAXVCPUS_XML = _make(version="0.8.5") # Earliest version with working bindings SUPPORT_CONN_STREAM = _make( version="0.9.3", function="virConnect.newStream", run_args=(0,)) SUPPORT_CONN_GETVERSION = _make(function="virConnect.getVersion", run_args=()) SUPPORT_CONN_LIBVERSION = _make( function="virConnect.getLibVersion", run_args=()) SUPPORT_CONN_LISTALLDOMAINS = _make( function="virConnect.listAllDomains", run_args=()) SUPPORT_CONN_LISTALLNETWORKS = _make( function="virConnect.listAllNetworks", run_args=()) SUPPORT_CONN_LISTALLSTORAGEPOOLS = _make( function="virConnect.listAllStoragePools", run_args=()) SUPPORT_CONN_LISTALLINTERFACES = _make( function="virConnect.listAllInterfaces", run_args=()) SUPPORT_CONN_LISTALLDEVICES = _make( function="virConnect.listAllDevices", run_args=()) SUPPORT_CONN_VIRTIO_MMIO = _make( version="1.1.2", hv_version={"qemu": "1.6.0"}) SUPPORT_CONN_DISK_SD = _make(version="1.1.2") # This is an arbitrary check to say whether it's a good idea to # default to qcow2. It might be fine for xen or qemu older than the versions # here, but until someone tests things I'm going to be a bit conservative. SUPPORT_CONN_DEFAULT_QCOW2 = _make( version="0.8.0", hv_version={"qemu": "1.2.0", "test": 0}) SUPPORT_CONN_DEFAULT_USB2 = _make( version="0.9.7", hv_version={"qemu": "1.0.0", "test": 0}) SUPPORT_CONN_CAN_ACPI = _make(hv_version={"xen": "3.1.0", "all": 0}) SUPPORT_CONN_WORKING_XEN_EVENTS = _make(hv_version={"xen": "4.0.0", "all": 0}) SUPPORT_CONN_SOUND_AC97 = _make( version="0.8.0", hv_version={"qemu": "0.11.0"}) SUPPORT_CONN_SOUND_ICH6 = _make( version="0.8.8", hv_version={"qemu": "0.14.0"}) SUPPORT_CONN_GRAPHICS_SPICE = _make( version="0.8.6", hv_version={"qemu": "0.14.0"}) SUPPORT_CONN_CHAR_SPICEVMC = _make( version="0.8.8", hv_version={"qemu": "0.14.0"}) SUPPORT_CONN_DIRECT_INTERFACE = _make( version="0.8.7", hv_version={"qemu": 0, "test": 0}) SUPPORT_CONN_FILESYSTEM = _make( hv_version={"qemu": "0.13.0", "lxc": 0, "openvz": 0, "test": 0}, hv_libvirt_version={"qemu": "0.8.5", "lxc": 0, "openvz": 0, "test": 0}) SUPPORT_CONN_AUTOSOCKET = _make(hv_libvirt_version={"qemu": "1.0.6"}) SUPPORT_CONN_ADVANCED_CLOCK = _make(hv_libvirt_version={"qemu": "0.8.0"}) SUPPORT_CONN_VIRTIO_CONSOLE = _make(hv_libvirt_version={"qemu": "0.8.3"}) SUPPORT_CONN_PANIC_DEVICE = _make( version="1.2.1", hv_version={"qemu": "1.5.0", "test": 0}) SUPPORT_CONN_PM_DISABLE = _make( version="0.10.2", hv_version={"qemu": "1.2.0", "test": 0}) SUPPORT_CONN_QCOW2_LAZY_REFCOUNTS = _make( version="1.1.0", hv_version={"qemu": "1.2.0", "test": 0}) SUPPORT_CONN_USBREDIR = _make( version="0.9.5", hv_version={"qemu": "1.3.0", "test": 0}) SUPPORT_CONN_DEVICE_BOOTORDER = _make( version="0.8.8", hv_version={"qemu": 0, "test": 0}) SUPPORT_CONN_POOL_GLUSTERFS = _make(version="1.2.0") SUPPORT_CONN_CPU_MODEL_NAMES = _make(function="virConnect.getCPUModelNames", run_args=("x86_64", 0)) SUPPORT_CONN_HYPERV_VAPIC = _make( version="1.1.0", hv_version={"qemu": "1.1.0", "test": 0}) SUPPORT_CONN_HYPERV_CLOCK = _make( version="1.2.2", hv_version={"qemu": "2.0.0", "test": 0}) SUPPORT_CONN_HYPERV_CLOCK_RHEL = _make( version="1.2.2", hv_version={"qemu": "1.5.3", "test": 0}) SUPPORT_CONN_LOADER_ROM = _make(version="1.2.9") SUPPORT_CONN_DOMAIN_CAPABILITIES = _make( function="virConnect.getDomainCapabilities", run_args=(None, None, None, None)) SUPPORT_CONN_DOMAIN_RESET = _make(version="0.9.7", hv_version={"qemu": 0}) SUPPORT_CONN_SPICE_COMPRESSION = _make(version="0.9.1") SUPPORT_CONN_VMPORT = _make( version="1.2.16", hv_version={"qemu": "2.2.0", "test": 0}) SUPPORT_CONN_VCPU_PLACEMENT = _make( version="0.9.11", hv_version={"qemu": 0, "test": 0}) SUPPORT_CONN_MEM_STATS_PERIOD = _make( function="virDomain.setMemoryStatsPeriod", version="1.1.1", hv_version={"qemu": 0}) # spice GL is actually enabled with libvirt 1.3.3, but 3.1.0 is the # first version that sorts out the qemu:///system + cgroup issues SUPPORT_CONN_SPICE_GL = _make(version="3.1.0", hv_version={"qemu": "2.6.0", "test": 0}) SUPPORT_CONN_SPICE_RENDERNODE = _make(version="3.1.0", hv_version={"qemu": "2.9.0", "test": 0}) SUPPORT_CONN_VIDEO_VIRTIO_ACCEL3D = _make(version="1.3.0", hv_version={"qemu": "2.5.0", "test": 0}) SUPPORT_CONN_GRAPHICS_LISTEN_NONE = _make(version="2.0.0") SUPPORT_CONN_RNG_URANDOM = _make(version="1.3.4") SUPPORT_CONN_USB3_PORTS = _make(version="1.3.5") SUPPORT_CONN_MACHVIRT_PCI_DEFAULT = _make(version="3.0.0") SUPPORT_CONN_QEMU_XHCI = _make(version="3.3.0") SUPPORT_CONN_VNC_NONE_AUTH = _make(hv_version={"qemu": "2.9.0"}) # This is for disk . xen supports this, but it's # limited to arbitrary new enough xen, since I know libxl can handle it # but I don't think the old xend driver does. SUPPORT_CONN_DISK_DRIVER_NAME_QEMU = _make( hv_version={"qemu": 0, "xen": "4.2.0"}, hv_libvirt_version={"qemu": 0, "xen": "1.1.0"}) ################# # Domain checks # ################# SUPPORT_DOMAIN_GETVCPUS = _make(function="virDomain.vcpus", run_args=()) SUPPORT_DOMAIN_XML_INACTIVE = _make(function="virDomain.XMLDesc", run_args=(), flag="VIR_DOMAIN_XML_INACTIVE") SUPPORT_DOMAIN_XML_SECURE = _make(function="virDomain.XMLDesc", run_args=(), flag="VIR_DOMAIN_XML_SECURE") SUPPORT_DOMAIN_MANAGED_SAVE = _make( function="virDomain.hasManagedSaveImage", run_args=(0,)) SUPPORT_DOMAIN_MIGRATE_DOWNTIME = _make( function="virDomain.migrateSetMaxDowntime", # Use a bogus flags value, so that we don't overwrite existing # downtime value run_args=(30, 12345678)) SUPPORT_DOMAIN_JOB_INFO = _make(function="virDomain.jobInfo", run_args=()) SUPPORT_DOMAIN_CONSOLE_STREAM = _make(version="0.8.6") SUPPORT_DOMAIN_SET_METADATA = _make(version="0.9.10") SUPPORT_DOMAIN_CPU_HOST_MODEL = _make(version="0.9.10") SUPPORT_DOMAIN_LIST_SNAPSHOTS = _make( function="virDomain.listAllSnapshots", run_args=()) SUPPORT_DOMAIN_GET_METADATA = _make(function="virDomain.metadata", run_args=(getattr(libvirt, "VIR_DOMAIN_METADATA_TITLE", 1), None, 0)) SUPPORT_DOMAIN_MEMORY_STATS = _make( function="virDomain.memoryStats", run_args=()) SUPPORT_DOMAIN_STATE = _make(function="virDomain.state", run_args=()) SUPPORT_DOMAIN_OPEN_GRAPHICS = _make(function="virDomain.openGraphicsFD", version="1.2.8", hv_version={"qemu": 0}) SUPPORT_DOMAIN_FEATURE_SMM = _make(version="2.1.0") SUPPORT_DOMAIN_LOADER_SECURE = _make(version="2.1.0") ############### # Pool checks # ############### SUPPORT_POOL_CREATEVOLFROM = _make( function="virStoragePool.createXMLFrom", version="0.8.0") SUPPORT_POOL_ISACTIVE = _make(function="virStoragePool.isActive", run_args=()) SUPPORT_POOL_LISTALLVOLUMES = _make( function="virStoragePool.listAllVolumes", run_args=()) SUPPORT_POOL_METADATA_PREALLOC = _make( flag="VIR_STORAGE_VOL_CREATE_PREALLOC_METADATA", version="1.0.1") SUPPORT_POOL_REFLINK = _make( flag="VIR_STORAGE_VOL_CREATE_REFLINK", version="1.2.13") #################### # Interface checks # #################### SUPPORT_INTERFACE_XML_INACTIVE = _make(function="virInterface.XMLDesc", flag="VIR_INTERFACE_XML_INACTIVE", run_args=()) SUPPORT_INTERFACE_ISACTIVE = _make( function="virInterface.isActive", run_args=()) ################# # Stream checks # ################# # Latest I tested with, and since we will use it by default # for URL installs, want to be sure it works SUPPORT_STREAM_UPLOAD = _make(version="0.9.4") ################## # Network checks # ################## SUPPORT_NET_ISACTIVE = _make(function="virNetwork.isActive", run_args=()) def check_support(virtconn, feature, data=None): """ Attempt to determine if a specific libvirt feature is support given the passed connection. @param virtconn: Libvirt connection to check feature on @param feature: Feature type to check support for @type feature: One of the SUPPORT_* flags @param data: Option libvirt object to use in feature checking @type data: Could be virDomain, virNetwork, virStoragePool, hv name, etc @returns: True if feature is supported, False otherwise """ if "VirtualConnection" in repr(data): data = data.get_conn_for_api_arg() sobj = _support_objs[feature - 1] return sobj.check_support(virtconn, data) def _check_version(virtconn, version): """ Check libvirt version. Useful for the test suite so we don't need to keep adding new support checks. """ sobj = _SupportCheck(version=version) return sobj.check_support(virtconn, None) virt-manager-1.5.1/virtinst/deviceaudio.py0000664000175100017510000000231713241024270022307 0ustar crobinsocrobinso00000000000000# # Copyright 2008-2009, 2013-2014 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .device import VirtualDevice from .xmlbuilder import XMLProperty class VirtualAudio(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_AUDIO MODEL_DEFAULT = "default" MODELS = ["es1370", "sb16", "pcspk", "ac97", "ich6", "ich9"] model = XMLProperty("./@model", default_cb=lambda s: "es1370", default_name=MODEL_DEFAULT) VirtualAudio.register_type() virt-manager-1.5.1/virtinst/domainmemorybacking.py0000664000175100017510000000254613241024270024051 0ustar crobinsocrobinso00000000000000# # Copyright 2014 Fujitsu Limited. # Chen Hanxiao # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .xmlbuilder import XMLBuilder, XMLProperty class DomainMemorybacking(XMLBuilder): """ Class for generating XML """ _XML_ROOT_NAME = "memoryBacking" _XML_PROP_ORDER = ["hugepages", "nosharepages", "locked"] hugepages = XMLProperty("./hugepages", is_bool=True) page_size = XMLProperty("./hugepages/page/@size") page_unit = XMLProperty("./hugepages/page/@unit") page_nodeset = XMLProperty("./hugepages/page/@nodeset") nosharepages = XMLProperty("./nosharepages", is_bool=True) locked = XMLProperty("./locked", is_bool=True) virt-manager-1.5.1/virtinst/devicehostdev.py0000664000175100017510000001234513245061760022675 0ustar crobinsocrobinso00000000000000# # Copyright 2009, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .device import VirtualDevice from .nodedev import NodeDevice from .xmlbuilder import XMLProperty class VirtualHostDevice(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_HOSTDEV def set_from_nodedev(self, nodedev): """ @use_full_usb: If set, and nodedev is USB, specify both vendor and product. Used if user requests bus/add on virt-install command line, or if virt-manager detects a dup USB device and we need to differentiate """ if nodedev.device_type == NodeDevice.CAPABILITY_TYPE_PCI: self.type = "pci" self.domain = nodedev.domain self.bus = nodedev.bus self.slot = nodedev.slot self.function = nodedev.function elif nodedev.device_type == NodeDevice.CAPABILITY_TYPE_USBDEV: self.type = "usb" self.vendor = nodedev.vendor_id self.product = nodedev.product_id count = 0 for dev in self.conn.fetch_all_nodedevs(): if (dev.device_type == NodeDevice.CAPABILITY_TYPE_USBDEV and dev.vendor_id == self.vendor and dev.product_id == self.product): count += 1 if not count: raise RuntimeError(_("Could not find USB device " "(vendorId: %s, productId: %s)") % (self.vendor, self.product)) if count > 1: self.bus = nodedev.bus self.device = nodedev.device elif nodedev.device_type == nodedev.CAPABILITY_TYPE_NET: founddev = None for checkdev in self.conn.fetch_all_nodedevs(): if checkdev.name == nodedev.parent: founddev = checkdev break self.set_from_nodedev(founddev) elif nodedev.device_type == nodedev.CAPABILITY_TYPE_SCSIDEV: self.type = "scsi" self.scsi_adapter = "scsi_host%s" % nodedev.host self.scsi_bus = nodedev.bus self.scsi_target = nodedev.target self.scsi_unit = nodedev.lun self.managed = False else: raise ValueError(_("Unknown node device type %s") % nodedev) def pretty_name(self): def dehex(val): if val.startswith("0x"): val = val[2:] return val def safeint(val, fmt="%.3d"): try: int(val) except Exception: return str(val) return fmt % int(val) label = self.type.upper() if self.vendor and self.product: label += " %s:%s" % (dehex(self.vendor), dehex(self.product)) elif self.bus and self.device: label += " %s:%s" % (safeint(self.bus), safeint(self.device)) elif self.bus and self.slot and self.function and self.domain: label += (" %s:%s:%s.%s" % (dehex(self.domain), dehex(self.bus), dehex(self.slot), dehex(self.function))) return label _XML_PROP_ORDER = ["mode", "type", "managed", "vendor", "product", "domain", "bus", "slot", "function"] mode = XMLProperty("./@mode", default_cb=lambda s: "subsystem") type = XMLProperty("./@type") def _get_default_managed(self): return self.conn.is_xen() and "no" or "yes" managed = XMLProperty("./@managed", is_yesno=True, default_cb=_get_default_managed) vendor = XMLProperty("./source/vendor/@id") product = XMLProperty("./source/product/@id") device = XMLProperty("./source/address/@device") bus = XMLProperty("./source/address/@bus") def _get_default_domain(self): if self.type == "pci": return "0x0" return None domain = XMLProperty("./source/address/@domain", default_cb=_get_default_domain) function = XMLProperty("./source/address/@function") slot = XMLProperty("./source/address/@slot") driver_name = XMLProperty("./driver/@name") rom_bar = XMLProperty("./rom/@bar", is_onoff=True) # type=scsi handling scsi_adapter = XMLProperty("./source/adapter/@name") scsi_bus = XMLProperty("./source/address/@bus", is_int=True) scsi_target = XMLProperty("./source/address/@target", is_int=True) scsi_unit = XMLProperty("./source/address/@unit", is_int=True) VirtualHostDevice.register_type() virt-manager-1.5.1/virtinst/sysinfo.py0000664000175100017510000000622113245061760021527 0ustar crobinsocrobinso00000000000000# # Copyright (C) 2016 Red Hat, Inc. # Copyright (C) 2016 SUSE LINUX Products GmbH, Nuernberg, Germany. # Charles Arnold # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. """ Classes for building and installing with libvirt XML """ import datetime from .xmlbuilder import XMLBuilder, XMLProperty class SYSInfo(XMLBuilder): """ Top level class for object XML """ _XML_ROOT_NAME = "sysinfo" _XML_PROP_ORDER = ["type", "bios_vendor", "bios_version", "bios_date", "bios_release", "system_manufacturer", "system_product", "system_version", "system_serial", "system_uuid", "system_sku", "system_family", "baseBoard_manufacturer", "baseBoard_product", "baseBoard_version", "baseBoard_serial", "baseBoard_asset", "baseBoard_location"] type = XMLProperty("./@type") def _validate_date(self, val): # If supplied, date must be in either mm/dd/yy or mm/dd/yyyy format try: datetime.datetime.strptime(val, '%m/%d/%Y') except ValueError: try: datetime.datetime.strptime(val, '%m/%d/%y') except ValueError: raise RuntimeError(_("SMBios date string '%s' is invalid.") % val) return val bios_date = XMLProperty("./bios/entry[@name='date']", validate_cb=_validate_date) bios_vendor = XMLProperty("./bios/entry[@name='vendor']") bios_version = XMLProperty("./bios/entry[@name='version']") bios_release = XMLProperty("./bios/entry[@name='release']") system_uuid = XMLProperty("./system/entry[@name='uuid']") system_manufacturer = XMLProperty("./system/entry[@name='manufacturer']") system_product = XMLProperty("./system/entry[@name='product']") system_version = XMLProperty("./system/entry[@name='version']") system_serial = XMLProperty("./system/entry[@name='serial']") system_sku = XMLProperty("./system/entry[@name='sku']") system_family = XMLProperty("./system/entry[@name='family']") baseBoard_manufacturer = XMLProperty( "./baseBoard/entry[@name='manufacturer']") baseBoard_product = XMLProperty("./baseBoard/entry[@name='product']") baseBoard_version = XMLProperty("./baseBoard/entry[@name='version']") baseBoard_serial = XMLProperty("./baseBoard/entry[@name='serial']") baseBoard_asset = XMLProperty("./baseBoard/entry[@name='asset']") baseBoard_location = XMLProperty("./baseBoard/entry[@name='location']") virt-manager-1.5.1/virtinst/interface.py0000664000175100017510000002305313245573052022001 0ustar crobinsocrobinso00000000000000# # Copyright 2009, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. """ Classes for building and installing libvirt interface xml """ import logging import libvirt import ipaddr from . import util from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty class _IPAddress(XMLBuilder): _XML_PROP_ORDER = ["address", "prefix"] _XML_ROOT_NAME = "ip" ###################### # Validation helpers # ###################### def _validate_ipaddr(self, addr): ipaddr.IPAddress(addr) return addr address = XMLProperty("./@address", validate_cb=_validate_ipaddr) prefix = XMLProperty("./@prefix", is_int=True) class InterfaceProtocol(XMLBuilder): INTERFACE_PROTOCOL_FAMILY_IPV4 = "ipv4" INTERFACE_PROTOCOL_FAMILY_IPV6 = "ipv6" INTERFACE_PROTOCOL_FAMILIES = [INTERFACE_PROTOCOL_FAMILY_IPV4, INTERFACE_PROTOCOL_FAMILY_IPV6] _XML_ROOT_NAME = "protocol" _XML_PROP_ORDER = ["autoconf", "dhcp", "dhcp_peerdns", "ips", "gateway"] family = XMLProperty("./@family") dhcp = XMLProperty("./dhcp", is_bool=True, doc=_("Whether to enable DHCP")) dhcp_peerdns = XMLProperty("./dhcp/@peerdns", is_yesno=True) gateway = XMLProperty("./route/@gateway", doc=_("Network gateway address")) autoconf = XMLProperty("./autoconf", is_bool=True, doc=_("Whether to enable IPv6 autoconfiguration")) ##################### # IP child handling # ##################### def add_ip(self, addr, prefix=None): ip = _IPAddress(self.conn) ip.address = addr ip.prefix = prefix self.add_child(ip) def remove_ip(self, ip): self.remove_child(ip) ip.clear() ips = XMLChildProperty(_IPAddress) class Interface(XMLBuilder): """ Base class for building any libvirt interface object. Mostly meaningless to directly instantiate. """ INTERFACE_TYPE_BRIDGE = "bridge" INTERFACE_TYPE_BOND = "bond" INTERFACE_TYPE_ETHERNET = "ethernet" INTERFACE_TYPE_VLAN = "vlan" INTERFACE_TYPES = [INTERFACE_TYPE_BRIDGE, INTERFACE_TYPE_BOND, INTERFACE_TYPE_ETHERNET, INTERFACE_TYPE_VLAN] INTERFACE_START_MODE_NONE = "none" INTERFACE_START_MODE_ONBOOT = "onboot" INTERFACE_START_MODE_HOTPLUG = "hotplug" INTERFACE_START_MODES = [INTERFACE_START_MODE_NONE, INTERFACE_START_MODE_ONBOOT, INTERFACE_START_MODE_HOTPLUG] INTERFACE_BOND_MODES = ["active-backup", "balance-alb", "balance-rr", "balance-tlb", "balance-xor", "broadcast", "802.3ad"] INTERFACE_BOND_MONITOR_MODE_ARP = "arpmon" INTERFACE_BOND_MONITOR_MODE_MII = "miimon" INTERFACE_BOND_MONITOR_MODES = [INTERFACE_BOND_MONITOR_MODE_ARP, INTERFACE_BOND_MONITOR_MODE_MII] INTERFACE_BOND_MONITOR_MODE_ARP_VALIDATE_MODES = ["active", "backup", "all"] INTERFACE_BOND_MONITOR_MODE_MII_CARRIER_TYPES = ["netif", "ioctl"] @staticmethod def find_free_name(conn, prefix): """ Generate an unused interface name based on prefix. For example, if prefix="br", we find the first unused name such as "br0", "br1", etc. """ return util.generate_name(prefix, conn.interfaceLookupByName, sep="", force_num=True) _XML_ROOT_NAME = "interface" _XML_PROP_ORDER = ["type", "name", "start_mode", "macaddr", "mtu", "stp", "delay", "bond_mode", "arp_interval", "arp_target", "arp_validate_mode", "mii_frequency", "mii_downdelay", "mii_updelay", "mii_carrier_mode", "tag", "parent_interface", "protocols", "interfaces"] ################## # Child handling # ################## def add_interface(self, obj): self.add_child(obj) def remove_interface(self, obj): self.remove_child(obj) # 'interfaces' property is added outside this class, since it needs # to reference the completed Interface class def add_protocol(self, obj): self.add_child(obj) def remove_protocol(self, obj): self.remove_child(obj) protocols = XMLChildProperty(InterfaceProtocol) ###################### # Validation helpers # ###################### def _validate_name(self, name): if name == self.name: return try: self.conn.interfaceLookupByName(name) except libvirt.libvirtError: return raise ValueError(_("Name '%s' already in use by another interface.") % name) def _validate_mac(self, val): util.validate_macaddr(val) return val ################## # General params # ################## type = XMLProperty("./@type") mtu = XMLProperty("./mtu/@size", is_int=True, doc=_("Maximum transmit size in bytes")) start_mode = XMLProperty("./start/@mode", doc=_("When the interface will be auto-started.")) name = XMLProperty("./@name", validate_cb=_validate_name, doc=_("Name for the interface object.")) macaddr = XMLProperty("./mac/@address", validate_cb=_validate_mac, doc=_("Interface MAC address")) ################# # Bridge params # ################# stp = XMLProperty("./bridge/@stp", is_onoff=True, doc=_("Whether STP is enabled on the bridge")) delay = XMLProperty("./bridge/@delay", doc=_("Delay in seconds before forwarding begins when " "joining a network.")) ############### # Bond params # ############### bond_mode = XMLProperty("./bond/@mode", doc=_("Mode of operation of the bonding device")) arp_interval = XMLProperty("./bond/arpmon/@interval", is_int=True, doc=_("ARP monitoring interval in " "milliseconds")) arp_target = XMLProperty("./bond/arpmon/@target", doc=_("IP target used in ARP monitoring packets")) arp_validate_mode = XMLProperty("./bond/arpmon/@validate", doc=_("ARP monitor validation mode")) mii_carrier_mode = XMLProperty("./bond/miimon/@carrier", doc=_("MII monitoring method.")) mii_frequency = XMLProperty("./bond/miimon/@freq", is_int=True, doc=_("MII monitoring interval in " "milliseconds")) mii_updelay = XMLProperty("./bond/miimon/@updelay", is_int=True, doc=_("Time in milliseconds to wait before " "enabling a slave after link recovery ")) mii_downdelay = XMLProperty("./bond/miimon/@downdelay", is_int=True, doc=_("Time in milliseconds to wait before " "disabling a slave after link failure")) ############### # VLAN params # ############### tag = XMLProperty("./vlan/@tag", is_int=True, doc=_("VLAN device tag number")) parent_interface = XMLProperty("./vlan/interface/@name", doc=_("Parent interface to create VLAN on")) ################## # Build routines # ################## def validate(self): if (self.type == self.INTERFACE_TYPE_VLAN and (self.tag is None or self.parent_interface is None)): raise ValueError(_("VLAN Tag and parent interface are required.")) def install(self, meter=None, create=True): """ Install network interface xml. """ ignore = meter xml = self.get_xml_config() logging.debug("Creating interface '%s' with xml:\n%s", self.name, xml) try: iface = self.conn.interfaceDefineXML(xml, 0) except Exception as e: raise RuntimeError(_("Could not define interface: %s") % str(e)) errmsg = None if create and not errmsg: try: iface.create(0) except Exception as e: errmsg = _("Could not create interface: %s") % str(e) if errmsg: # Try and clean up the leftover pool try: iface.undefine() except Exception as e: logging.debug("Error cleaning up interface after failure: " + "%s" % str(e)) raise RuntimeError(errmsg) return iface Interface.interfaces = XMLChildProperty(Interface, relative_xpath="./%(type)s") virt-manager-1.5.1/virtinst/deviceredirdev.py0000664000175100017510000000377013241024270023016 0ustar crobinsocrobinso00000000000000# # Copyright 2011, 2013 Red Hat, Inc. # Cole Robinson # Marc-Andre Lureau # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .device import VirtualDevice from .xmlbuilder import XMLProperty class VirtualRedirDevice(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_REDIRDEV BUS_DEFAULT = "default" BUSES = ["usb"] TYPE_DEFAULT = "default" TYPES = ["tcp", "spicevmc"] @staticmethod def pretty_type(typ): if typ == "tcp": return "TCP" if typ == "spicevmc": return "SpiceVMC" return typ and typ.capitalize() def parse_friendly_server(self, serverstr): if serverstr.count(":") != 1: raise ValueError(_("Could not determine or unsupported " "format of '%s'") % serverstr) self.host, self.service = serverstr.split(":") _XML_PROP_ORDER = ["bus", "type"] bus = XMLProperty("./@bus", default_cb=lambda s: "usb", default_name=BUS_DEFAULT) type = XMLProperty("./@type", default_cb=lambda s: "spicevmc", default_name=TYPE_DEFAULT) host = XMLProperty("./source/@host") service = XMLProperty("./source/@service", is_int=True) VirtualRedirDevice.register_type() virt-manager-1.5.1/virtinst/xmlbuilder.py0000664000175100017510000011742713245573052022221 0ustar crobinsocrobinso00000000000000# # Base class for all VM devices # # Copyright 2008, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import copy import logging import os import re import string # pylint: disable=deprecated-module import libxml2 from . import util # pylint: disable=protected-access # This whole file is calling around into non-public functions that we # don't want regular API users to touch _trackprops = bool("VIRTINST_TEST_SUITE" in os.environ) _allprops = [] _seenprops = [] # Convenience global to prevent _remove_xpath_node from unlinking the # top relavtive node in certain cases _top_node = None _namespaces = { "qemu": "http://libvirt.org/schemas/domain/qemu/1.0", } class _DocCleanupWrapper(object): def __init__(self, doc): self._doc = doc def __del__(self): self._doc.freeDoc() class _CtxCleanupWrapper(object): def __init__(self, ctx): self._ctx = ctx def __del__(self): self._ctx.xpathFreeContext() self._ctx = None def __getattr__(self, attrname): return getattr(self._ctx, attrname) def _make_xml_context(node): doc = node.doc ctx = _CtxCleanupWrapper(doc.xpathNewContext()) ctx.setContextNode(node) ctx.xpathRegisterNs("qemu", _namespaces["qemu"]) return ctx def _tuplify_lists(*args): """ Similar to zip(), but use None if lists aren't long enough, and don't skip any None list entry """ args = [util.listify(l) for l in args] maxlen = max([len(l) for l in args]) ret = [] for idx in range(maxlen): tup = tuple() for l in args: tup += (idx >= len(l) and (None,) or (l[idx],)) ret.append(tup) return ret def _sanitize_libxml_xml(xml): # Strip starting line if xml.startswith(" # to # # # prevsib = prevSibling(parentnode) if node_is_text(prevsib): sib = libxml2.newText(prevsib.content) else: sib = libxml2.newText("\n") parentnode.addChild(sib) # This case is adding a child element to an already properly # spaced element. Example: # # # # to # # # # sib = parentnode.get_last() content = sib.content sib = sib.addNextSibling(libxml2.newText(" ")) txt = libxml2.newText(content) sib.addNextSibling(newnode) newnode.addNextSibling(txt) return newnode def _build_xpath_node(ctx, xpath): """ Build all nodes for the passed xpath. For example, if 'ctx' xml=, and xpath=./bar/@baz, after this function the 'ctx' XML will be: And the node pointing to @baz will be returned, for the caller to do with as they please. There's also special handling to ensure that setting xpath=./bar[@baz='foo']/frob will create Even if didn't exist before. So we fill in the dependent property expression values """ def _handle_node(nodename, parentnode, parentpath): # If the passed xpath snippet (nodename) exists, return the node # If it doesn't exist, create it, and return the new node # If nodename is a node property, we can handle it up front if nodename.startswith("@"): nodename = nodename.strip("@") return parentnode.setProp(nodename, ""), parentpath if not parentpath: parentpath = nodename else: parentpath += "/%s" % nodename # See if the xpath node already exists node = _get_xpath_node(ctx, parentpath) if node: # xpath node already exists, so we don't need to create anything return node, parentpath # If we don't have a parentnode by this point, the root of the # xpath didn't find anything. Usually a coding error if not parentnode: raise RuntimeError("Could not find XML root node") # Remove conditional xpath elements for node creation. We preserved # them up until this point since it was needed for proper xpath # lookup, but they aren't valid syntax when creating the node if "[" in nodename: nodename = nodename[:nodename.index("[")] nsname = None if ":" in nodename: nsname, nodename = nodename.split(":") newnode = libxml2.newNode(nodename) if nsname: ns = _add_namespace(ctx.contextNode(), nsname) newnode.setNs(ns) return _add_pretty_child(parentnode, newnode), parentpath # Split the xpath and lookup/create each individual piece parentpath = None parentnode = None for nodename in xpath.split("/"): parentnode, parentpath = _handle_node(nodename, parentnode, parentpath) # Check if the xpath snippet had an '=' expression in it, example: # # ./foo[@bar='baz'] # # If so, we also want to set , so that setting # this XML element works as expected in this case. if "[" not in nodename or "=" not in nodename: continue propname, val = nodename.split("[")[1].strip("]").split("=") propobj, ignore = _handle_node(propname, parentnode, parentpath) propobj.setContent(val.strip("'")) return parentnode def _remove_xpath_node(ctx, xpath, dofree=True): """ Remove an XML node tree if it has no content """ nextxpath = xpath root_node = ctx.contextNode() while nextxpath: curxpath = nextxpath is_orig = (curxpath == xpath) node = _get_xpath_node(ctx, curxpath) if curxpath.count("/"): nextxpath, ignore = curxpath.rsplit("/", 1) else: nextxpath = None if not node: continue if node.type not in ["attribute", "element"]: continue if node.type == "element" and (node.children or node.properties): # Only do a deep unlink if it was the original requested path if not is_orig: continue if node == root_node or node == _top_node: # Don't unlink the root node, since it's spread out to all # child objects and it ends up wreaking havoc. break # Look for preceding whitespace and remove it white = node.get_prev() if white and white.type == "text" and not white.content.count("<"): white.unlinkNode() white.freeNode() node.unlinkNode() if dofree: node.freeNode() class XMLChildProperty(property): """ Property that points to a class used for parsing a subsection of of the parent XML. For example when we deligate parsing /domain/cpu/feature of the /domain/cpu class. @child_classes: Single class or list of classes to parse state into @relative_xpath: Relative location where the class is rooted compared to its _XML_ROOT_PATH. So interface xml can have nested interfaces rooted at /interface/bridge/interface, so we pass ./bridge/interface here for example. """ def __init__(self, child_classes, relative_xpath=".", is_single=False): self.child_classes = util.listify(child_classes) self.relative_xpath = relative_xpath self.is_single = is_single self._propname = None if self.is_single and len(self.child_classes) > 1: raise RuntimeError("programming error: Can't specify multiple " "child_classes with is_single") property.__init__(self, self._fget) def __repr__(self): return "" % (str(self.child_classes), id(self)) def _findpropname(self, xmlbuilder): if self._propname is None: for key, val in xmlbuilder._all_child_props().items(): if val is self: self._propname = key break if self._propname is None: raise RuntimeError("Didn't find expected property=%s" % self) return self._propname def _get(self, xmlbuilder): propname = self._findpropname(xmlbuilder) if propname not in xmlbuilder._propstore and not self.is_single: xmlbuilder._propstore[propname] = [] return xmlbuilder._propstore[propname] def _fget(self, xmlbuilder): if self.is_single: return self._get(xmlbuilder) return self._get(xmlbuilder)[:] def clear(self, xmlbuilder): if self.is_single: self._get(xmlbuilder).clear() else: for obj in self._get(xmlbuilder)[:]: xmlbuilder.remove_child(obj) def append(self, xmlbuilder, newobj): # Keep the list ordered by the order of passed in child classes objlist = self._get(xmlbuilder) if len(self.child_classes) == 1: objlist.append(newobj) return idx = 0 for idx, obj in enumerate(objlist): obj = objlist[idx] if (obj.__class__ not in self.child_classes or (self.child_classes.index(newobj.__class__) < self.child_classes.index(obj.__class__))): break idx += 1 objlist.insert(idx, newobj) def remove(self, xmlbuilder, obj): self._get(xmlbuilder).remove(obj) def set(self, xmlbuilder, obj): xmlbuilder._propstore[self._findpropname(xmlbuilder)] = obj def get_prop_xpath(self, xmlbuilder, obj): relative_xpath = self.relative_xpath + "/" + obj._XML_ROOT_NAME match = re.search("%\((.*)\)", self.relative_xpath) if match: valuedict = {} for paramname in match.groups(): valuedict[paramname] = getattr(xmlbuilder, paramname) relative_xpath = relative_xpath % valuedict return relative_xpath class XMLProperty(property): def __init__(self, xpath, doc=None, set_converter=None, validate_cb=None, is_bool=False, is_int=False, is_yesno=False, is_onoff=False, default_cb=None, default_name=None, do_abspath=False): """ Set a XMLBuilder class property that maps to a value in an XML document, indicated by the passed xpath. For example, for a the definition may look like: name = XMLProperty("./name") When building XML from scratch (virt-install), 'name' works similar to a regular class property(). When parsing and editing existing guest XML, we use the xpath value to get/set the value in the parsed XML document. @param doc: option doc string for the property @param xpath: xpath string which maps to the associated property in a typical XML document @param name: Just a string to print for debugging, only needed if xpath isn't specified. @param set_converter: optional function for converting the property value from the virtinst API to the guest XML. For example, the Guest.memory API was once in MiB, but the libvirt domain memory API is in KiB. So, if xpath is specified, on a 'get' operation we convert the XML value with int(val) / 1024. @param validate_cb: Called once when value is set, should raise a RuntimeError if the value is not proper. @param is_bool: Whether this is a boolean property in the XML @param is_int: Whether this is an integer property in the XML @param is_yesno: Whether this is a yes/no property in the XML @param is_onoff: Whether this is an on/off property in the XML @param default_cb: If building XML from scratch, and this property is never explicitly altered, this function is called for setting a default value in the XML, and for any 'get' call before the first explicit 'set'. @param default_name: If the user does a set and passes in this value, instead use the value of default_cb() @param do_abspath: If True, run os.path.abspath on the passed value """ self._xpath = xpath if not self._xpath: raise RuntimeError("XMLProperty: xpath must be passed.") self._propname = None self._is_bool = is_bool self._is_int = is_int self._is_yesno = is_yesno self._is_onoff = is_onoff self._do_abspath = do_abspath self._validate_cb = validate_cb self._convert_value_for_setter_cb = set_converter self._default_cb = default_cb self._default_name = default_name if sum([int(bool(i)) for i in [self._is_bool, self._is_int, self._is_yesno, self._is_onoff]]) > 1: raise RuntimeError("Conflict property converter options.") if self._default_name and not self._default_cb: raise RuntimeError("default_name requires default_cb.") self._is_tracked = False if _trackprops: _allprops.append(self) property.__init__(self, fget=self.getter, fset=self.setter) self.__doc__ = doc def __repr__(self): return "" % (str(self._xpath), id(self)) #################### # Internal helpers # #################### def _findpropname(self, xmlbuilder): """ Map the raw property() instance to the param name it's exposed as in the XMLBuilder class. This is just for debug purposes. """ if self._propname is None: for key, val in xmlbuilder._all_xml_props().items(): if val is self: self._propname = key break if self._propname is None: raise RuntimeError("Didn't find expected property=%s" % self) return self._propname def _make_xpath(self, xmlbuilder): return xmlbuilder.fix_relative_xpath(self._xpath) def _build_node_list(self, xmlbuilder, xpath): """ Build list of nodes that the passed xpaths reference """ nodes = _get_xpath_node(xmlbuilder._xmlstate.xml_ctx, xpath) return util.listify(nodes) def _convert_get_value(self, val): # pylint: disable=redefined-variable-type if self._default_name and val == self._default_name: ret = val elif self._is_bool: ret = bool(val) elif self._is_int and val is not None: intkwargs = {} if "0x" in str(val): intkwargs["base"] = 16 ret = int(val, **intkwargs) elif self._is_yesno and val is not None: ret = bool(val == "yes") elif self._is_onoff and val is not None: ret = bool(val == "on") else: ret = val return ret def _convert_set_value(self, xmlbuilder, val): if self._default_name and val == self._default_name: val = self._default_cb(xmlbuilder) elif self._do_abspath and val is not None: val = os.path.abspath(val) elif self._is_onoff and val is not None: val = bool(val) and "on" or "off" elif self._is_yesno and val is not None: val = bool(val) and "yes" or "no" elif self._is_int and val is not None: intkwargs = {} if "0x" in str(val): intkwargs["base"] = 16 val = int(val, **intkwargs) if self._convert_value_for_setter_cb: val = self._convert_value_for_setter_cb(xmlbuilder, val) return val def _prop_is_unset(self, xmlbuilder): propname = self._findpropname(xmlbuilder) return (propname not in xmlbuilder._propstore) def _default_get_value(self, xmlbuilder): """ Return (can use default, default value) """ ret = (False, -1) if not xmlbuilder._xmlstate.is_build: return ret if not self._prop_is_unset(xmlbuilder): return ret if not self._default_cb: return ret if self._default_name: return (True, self._default_name) return (True, self._default_cb(xmlbuilder)) def _set_default(self, xmlbuilder): """ Encode the property default into the XML and propstore, but only if a default is registered, and only if the property was not already explicitly set by the API user. This is called during the get_xml_config process and shouldn't be called from outside this file. """ candefault, val = self._default_get_value(xmlbuilder) if not candefault: return self.setter(xmlbuilder, val, validate=False) def _nonxml_fset(self, xmlbuilder, val): """ This stores the value in XMLBuilder._propstore dict as propname->value. This saves us from having to explicitly track every variable. """ propstore = xmlbuilder._propstore proporder = xmlbuilder._proporder propname = self._findpropname(xmlbuilder) propstore[propname] = val if propname in proporder: proporder.remove(propname) proporder.append(propname) def _nonxml_fget(self, xmlbuilder): """ The flip side to nonxml_fset, fetch the value from XMLBuilder._propstore """ candefault, val = self._default_get_value(xmlbuilder) if candefault: return val propname = self._findpropname(xmlbuilder) return xmlbuilder._propstore.get(propname, None) def clear(self, xmlbuilder): self.setter(xmlbuilder, None) self._set_xml(xmlbuilder, None) ################################## # The actual getter/setter impls # ################################## def getter(self, xmlbuilder): """ Fetch value at user request. If we are parsing existing XML and the user hasn't done a 'set' yet, return the value from the XML, otherwise return the value from propstore If this is a built from scratch object, we never pull from XML since it's known to the empty, and we may want to return a 'default' value """ if _trackprops and not self._is_tracked: _seenprops.append(self) self._is_tracked = True # pylint: disable=redefined-variable-type if (self._prop_is_unset(xmlbuilder) and not xmlbuilder._xmlstate.is_build): val = self._get_xml(xmlbuilder) else: val = self._nonxml_fget(xmlbuilder) ret = self._convert_get_value(val) return ret def _get_xml(self, xmlbuilder): """ Actually fetch the associated value from the backing XML """ xpath = self._make_xpath(xmlbuilder) node = _get_xpath_node(xmlbuilder._xmlstate.xml_ctx, xpath) if not node: return None content = node.content if self._is_bool: content = True return content def setter(self, xmlbuilder, val, validate=True): """ Set the value at user request. This just stores the value in propstore. Setting the actual XML is only done at get_xml_config time. """ if _trackprops and not self._is_tracked: _seenprops.append(self) self._is_tracked = True if validate and self._validate_cb: self._validate_cb(xmlbuilder, val) self._nonxml_fset(xmlbuilder, self._convert_set_value(xmlbuilder, val)) def _set_xml(self, xmlbuilder, setval, root_node=None): """ Actually set the passed value in the XML document """ if root_node is None: root_node = xmlbuilder._xmlstate.xml_node ctx = xmlbuilder._xmlstate.xml_ctx else: ctx = _make_xml_context(root_node) xpath = self._make_xpath(xmlbuilder) if setval is None or setval is False: _remove_xpath_node(ctx, xpath) return node = _get_xpath_node(ctx, xpath) if not node: node = _build_xpath_node(ctx, xpath) if setval is True: # Boolean property, creating the node is enough return node.setContent(util.xml_escape(str(setval))) class _XMLState(object): def __init__(self, root_name, parsexml, parentxmlstate, relative_object_xpath): self._root_name = root_name self._stub_path = "/%s" % self._root_name self._namespace = "" if ":" in self._root_name: ns = self._root_name.split(":")[0] self._namespace = " xmlns:%s='%s'" % (ns, _namespaces[ns]) # xpath of this object relative to its parent. So for a standalone # this is empty, but if the disk is the forth one in a # it will be set to ./devices/disk[4] self._relative_object_xpath = relative_object_xpath or "" # xpath of the parent. For a disk in a standalone , this # is empty, but if the is part of a , # it will be "./domain" self._parent_xpath = ( parentxmlstate and parentxmlstate.get_root_xpath()) or "" self.xml_ctx = None self.xml_node = None self._xml_root_doc_ref = None self.is_build = False if not parsexml and not parentxmlstate: self.is_build = True self._parse(parsexml, parentxmlstate) def _parse(self, parsexml, parentxmlstate): if parentxmlstate: self._xml_root_doc_ref = None self.xml_node = parentxmlstate.xml_node self.is_build = self.xml_node.virtinst_is_build or self.is_build self.xml_ctx = parentxmlstate.xml_ctx return if not parsexml: parsexml = self.make_xml_stub() elif self._namespace and "xmlns" not in parsexml: # Make sure passed in XML has required xmlns inserted parsexml = parsexml.replace("<" + self._root_name, "<" + self._root_name + self._namespace) try: doc = libxml2.parseDoc(parsexml) except Exception: logging.debug("Error parsing xml=\n%s", parsexml) raise self.xml_node = doc.children self.xml_node.virtinst_is_build = self.is_build self.xml_node.virtinst_node_top_xpath = self._stub_path self.xml_ctx = _make_xml_context(self.xml_node) # This just stores a reference to our root doc wrapper in # the root node, so when the doc is autofree'd when the node # and this xmlstate object are freed self._xml_root_doc_ref = _DocCleanupWrapper(doc) self.xml_node.virtinst_root_doc = self._xml_root_doc_ref def make_xml_stub(self): return "<%s%s/>" % (self._root_name, self._namespace) def set_relative_object_xpath(self, xpath): self._relative_object_xpath = xpath or "" def set_parent_xpath(self, xpath): self._parent_xpath = xpath or "" def get_root_xpath(self): relpath = self._relative_object_xpath if not self._parent_xpath: return relpath return self._parent_xpath + (relpath.startswith(".") and relpath[1:] or relpath) def fix_relative_xpath(self, xpath): fullpath = self.get_root_xpath() if not fullpath or fullpath == self._stub_path: return xpath if xpath.startswith("."): return "%s%s" % (fullpath, xpath.strip(".")) if xpath.count("/") == 1: return fullpath return fullpath + "/" + xpath.split("/", 2)[2] def get_node_top_xpath(self): """ Return the XML path of the root xml_node """ return self.xml_node.virtinst_node_top_xpath def get_node_xml(self, ctx): node = _get_xpath_node(ctx, self.fix_relative_xpath(".")) if not node: return "" return _sanitize_libxml_xml(node.serialize()) class XMLBuilder(object): """ Base for all classes which build or parse domain XML """ # Order that we should apply values to the XML. Keeps XML generation # consistent with what the test suite expects. _XML_PROP_ORDER = [] # Name of the root XML element _XML_ROOT_NAME = None # In some cases, libvirt can incorrectly generate unparseable XML. # These are libvirt bugs, but this allows us to work around it in # for specific XML classes. # # Example: nodedev 'system' XML: # https://bugzilla.redhat.com/show_bug.cgi?id=1184131 _XML_SANITIZE = False @staticmethod def xml_indent(xmlstr, level): """ Indent the passed str the specified number of spaces """ xml = "" if not xmlstr: return xml if not level: return xmlstr return "\n".join((" " * level + l) for l in xmlstr.splitlines()) def __init__(self, conn, parsexml=None, parentxmlstate=None, relative_object_xpath=None): """ Initialize state @param conn: libvirt connection to validate device against @type conn: VirtualConnection @param parsexml: Optional XML string to parse @type parsexml: C{str} The rest of the parameters are for internal use only """ self.conn = conn if self._XML_SANITIZE: parsexml = parsexml.decode('ascii', 'ignore').encode('ascii') parsexml = "".join([c for c in parsexml if c in string.printable]) self._propstore = {} self._proporder = [] self._xmlstate = _XMLState(self._XML_ROOT_NAME, parsexml, parentxmlstate, relative_object_xpath) self._initial_child_parse() def _initial_child_parse(self): # Walk the XML tree and hand of parsing to any registered # child classes for xmlprop in self._all_child_props().values(): if xmlprop.is_single: child_class = xmlprop.child_classes[0] prop_path = xmlprop.get_prop_xpath(self, child_class) obj = child_class(self.conn, parentxmlstate=self._xmlstate, relative_object_xpath=prop_path) xmlprop.set(self, obj) continue if self._xmlstate.is_build: continue for child_class in xmlprop.child_classes: prop_path = xmlprop.get_prop_xpath(self, child_class) nodecount = int(self._xmlstate.xml_ctx.xpathEval( "count(%s)" % self.fix_relative_xpath(prop_path))) for idx in range(nodecount): idxstr = "[%d]" % (idx + 1) obj = child_class(self.conn, parentxmlstate=self._xmlstate, relative_object_xpath=(prop_path + idxstr)) xmlprop.append(self, obj) self._set_child_xpaths() ######################## # Public XML Internals # ######################## def copy(self): """ Do a shallow copy of the device """ ret = copy.copy(self) ret._propstore = ret._propstore.copy() ret._proporder = ret._proporder[:] # XMLChildProperty stores a list in propstore, which dict shallow # copy won't fix for us. for name, value in ret._propstore.items(): if not isinstance(value, list): continue ret._propstore[name] = [obj.copy() for obj in ret._propstore[name]] return ret def get_root_xpath(self): return self._xmlstate.get_root_xpath() def fix_relative_xpath(self, xpath): return self._xmlstate.fix_relative_xpath(xpath) ############################ # Public XML managing APIs # ############################ def get_xml_config(self): """ Return XML string of the object """ data = self._prepare_get_xml() try: return self._do_get_xml_config() finally: self._finish_get_xml(data) def clear(self, leave_stub=False): """ Wipe out all properties of the object :param leave_stub: if True, don't unlink the top stub node, see virtinst/cli usage for an explanation """ global _top_node old_top_node = _top_node try: if leave_stub: _top_node = _get_xpath_node(self._xmlstate.xml_ctx, self.get_root_xpath()) props = self._all_xml_props().values() props += self._all_child_props().values() for prop in props: prop.clear(self) finally: _top_node = old_top_node is_child = bool(re.match("^.*\[\d+\]$", self.get_root_xpath())) if is_child or leave_stub: # User requested to clear an object that is the child of # another object (xpath ends in [1] etc). We can't fully remove # the node in that case, since then the xmlbuilder object is # no longer valid, and all the other child xpaths will be # pointing to the wrong node. So just stub out the content node = _get_xpath_node(self._xmlstate.xml_ctx, self.get_root_xpath()) indent = 2 * self.get_root_xpath().count("/") if node: node.setContent("\n" + (indent * " ")) else: _remove_xpath_node(self._xmlstate.xml_ctx, self.get_root_xpath()) def validate(self): """ Validate any set values and raise an exception if there's a problem """ pass def set_defaults(self, guest): """ Encode any default values if needed """ ignore = guest ################### # Child overrides # ################### def _prepare_get_xml(self): """ Subclasses can override this to do any pre-get_xml_config setup. Returns data to pass to finish_get_xml """ return None def _finish_get_xml(self, data): """ Called after get_xml_config. Data is whatever was returned by _prepare_get_xml """ ignore = data ################ # Internal API # ################ def __get_prop_cache(self, cachename, checkclass): if not hasattr(self.__class__, cachename): ret = {} for c in reversed(type.mro(self.__class__)[:-1]): for key, val in c.__dict__.items(): if isinstance(val, checkclass): ret[key] = val setattr(self.__class__, cachename, ret) return getattr(self.__class__, cachename) def _all_xml_props(self): """ Return a list of all XMLProperty instances that this class has. """ cachename = self.__class__.__name__ + "_cached_xml_props" return self.__get_prop_cache(cachename, XMLProperty) def _all_child_props(self): """ Return a list of all XMLChildProperty instances that this class has. """ cachename = self.__class__.__name__ + "_cached_child_props" return self.__get_prop_cache(cachename, XMLChildProperty) def _set_parent_xpath(self, xpath): self._xmlstate.set_parent_xpath(xpath) for propname in self._all_child_props(): for p in util.listify(getattr(self, propname, [])): p._set_parent_xpath(self.get_root_xpath()) def _set_relative_object_xpath(self, xpath): self._xmlstate.set_relative_object_xpath(xpath) for propname in self._all_child_props(): for p in util.listify(getattr(self, propname, [])): p._set_parent_xpath(self.get_root_xpath()) def _find_child_prop(self, child_class, return_single=False): xmlprops = self._all_child_props() for xmlprop in xmlprops.values(): if xmlprop.is_single and not return_single: continue if child_class in xmlprop.child_classes: return xmlprop raise RuntimeError("programming error: " "Didn't find child property for child_class=%s" % child_class) def _parse_with_children(self, *args, **kwargs): """ Set new backing XML objects in ourselves and all our child props """ self._xmlstate._parse(*args, **kwargs) for propname in self._all_child_props(): for p in util.listify(getattr(self, propname, [])): p._xmlstate._parse(None, self._xmlstate) def add_child(self, obj): """ Insert the passed XMLBuilder object into our XML document. The object needs to have an associated mapping via XMLChildProperty or an error is thrown. """ xmlprop = self._find_child_prop(obj.__class__) xml = obj.get_xml_config() xmlprop.append(self, obj) self._set_child_xpaths() if not obj._xmlstate.is_build: use_xpath = obj.get_root_xpath().rsplit("/", 1)[0] indent = 2 * obj.get_root_xpath().count("/") newnode = libxml2.parseDoc(self.xml_indent(xml, indent)).children parentnode = _build_xpath_node(self._xmlstate.xml_ctx, use_xpath) # Tack newnode on the end _add_pretty_child(parentnode, newnode) obj._parse_with_children(None, self._xmlstate) def remove_child(self, obj): """ Remove the passed XMLBuilder object from our XML document, but ensure its data isn't altered. """ xmlprop = self._find_child_prop(obj.__class__) xmlprop.remove(self, obj) xpath = obj.get_root_xpath() xml = obj.get_xml_config() obj._set_parent_xpath(None) obj._set_relative_object_xpath(None) obj._parse_with_children(xml, None) _remove_xpath_node(self._xmlstate.xml_ctx, xpath, dofree=False) self._set_child_xpaths() def list_children_for_class(self, klass): """ Return a list of all XML child objects with the passed class """ ret = [] for prop in self._all_child_props().values(): ret += [obj for obj in util.listify(prop._get(self)) if obj.__class__ == klass] return ret def child_class_is_singleton(self, klass): """ Return True if the passed class is registered as a singleton child property """ return self._find_child_prop(klass, return_single=True).is_single ################################# # Private XML building routines # ################################# def _set_child_xpaths(self): """ Walk the list of child properties and make sure their xpaths point at their particular element """ typecount = {} for propname, xmlprop in self._all_child_props().items(): for obj in util.listify(getattr(self, propname)): idxstr = "" if not xmlprop.is_single: class_type = obj.__class__ if class_type not in typecount: typecount[class_type] = 0 typecount[class_type] += 1 idxstr = "[%d]" % typecount[class_type] prop_path = xmlprop.get_prop_xpath(self, obj) obj._set_parent_xpath(self.get_root_xpath()) obj._set_relative_object_xpath(prop_path + idxstr) def _do_get_xml_config(self): xmlstub = self._xmlstate.make_xml_stub() try: node = None ctx = self._xmlstate.xml_ctx if self._xmlstate.is_build: node = self._xmlstate.xml_node.docCopyNodeList( self._xmlstate.xml_node.doc) ctx = node self._add_parse_bits(node) ret = self._xmlstate.get_node_xml(ctx) finally: if node: node.freeNode() if ret == xmlstub: ret = "" # Ensure top level XML object always ends with a newline, just # for back compat and readability if (ret and not self.get_root_xpath() and not ret.endswith("\n")): ret += "\n" return ret def _add_parse_bits(self, node): """ Callback that adds the implicitly tracked XML properties to the backing xml. """ origproporder = self._proporder[:] origpropstore = self._propstore.copy() try: return self._do_add_parse_bits(node) finally: self._proporder = origproporder self._propstore = origpropstore def _do_add_parse_bits(self, node): # Set all defaults if the properties have one registered xmlprops = self._all_xml_props() childprops = self._all_child_props() for prop in xmlprops.values(): prop._set_default(self) # Set up preferred XML ordering do_order = self._proporder[:] for key in reversed(self._XML_PROP_ORDER): if key not in xmlprops and key not in childprops: raise RuntimeError("programming error: key '%s' must be " "xml prop or child prop" % key) if key in do_order: do_order.remove(key) do_order.insert(0, key) elif key in childprops: do_order.insert(0, key) for key in childprops.keys(): if key not in do_order: do_order.append(key) # Alter the XML for key in do_order: if key in xmlprops: xmlprops[key]._set_xml(self, self._propstore[key], node) elif key in childprops: for obj in util.listify(getattr(self, key)): obj._add_parse_bits(node) def __repr__(self): return "<%s %s %s>" % (self.__class__.__name__.split(".")[-1], self._XML_ROOT_NAME, id(self)) virt-manager-1.5.1/virtinst/clock.py0000664000175100017510000000266213245573052021137 0ustar crobinsocrobinso00000000000000# # Copyright 2010, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty class _ClockTimer(XMLBuilder): _XML_ROOT_NAME = "timer" name = XMLProperty("./@name") present = XMLProperty("./@present", is_yesno=True) tickpolicy = XMLProperty("./@tickpolicy") class Clock(XMLBuilder): _XML_ROOT_NAME = "clock" TIMER_NAMES = ["platform", "pit", "rtc", "hpet", "tsc", "kvmclock", "hypervclock"] offset = XMLProperty("./@offset") timers = XMLChildProperty(_ClockTimer) def add_timer(self): obj = _ClockTimer(self.conn) self.add_child(obj) return obj def remove_timer(self, obj): self.remove_child(obj) virt-manager-1.5.1/virtinst/domainfeatures.py0000664000175100017510000000472313245573052023052 0ustar crobinsocrobinso00000000000000# # Copyright 2010, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .xmlbuilder import XMLBuilder, XMLProperty class DomainFeatures(XMLBuilder): """ Class for generating XML """ _XML_ROOT_NAME = "features" _XML_PROP_ORDER = ["acpi", "apic", "pae", "gic_version"] acpi = XMLProperty("./acpi", is_bool=True, default_name="default", default_cb=lambda s: False) apic = XMLProperty("./apic", is_bool=True, default_name="default", default_cb=lambda s: False) pae = XMLProperty("./pae", is_bool=True, default_name="default", default_cb=lambda s: False) gic_version = XMLProperty("./gic/@version") hap = XMLProperty("./hap", is_bool=True) viridian = XMLProperty("./viridian", is_bool=True) privnet = XMLProperty("./privnet", is_bool=True) pmu = XMLProperty("./pmu/@state", is_onoff=True) eoi = XMLProperty("./apic/@eoi", is_onoff=True) hyperv_reset = XMLProperty("./hyperv/reset/@state", is_onoff=True) hyperv_vapic = XMLProperty("./hyperv/vapic/@state", is_onoff=True) hyperv_relaxed = XMLProperty("./hyperv/relaxed/@state", is_onoff=True) hyperv_spinlocks = XMLProperty("./hyperv/spinlocks/@state", is_onoff=True) hyperv_spinlocks_retries = XMLProperty("./hyperv/spinlocks/@retries", is_int=True) hyperv_synic = XMLProperty("./hyperv/synic/@state", is_onoff=True) vmport = XMLProperty("./vmport/@state", is_onoff=True, default_name="default", default_cb=lambda s: False) kvm_hidden = XMLProperty("./kvm/hidden/@state", is_onoff=True) pvspinlock = XMLProperty("./pvspinlock/@state", is_onoff=True) smm = XMLProperty("./smm/@state", is_onoff=True) virt-manager-1.5.1/virtinst/cpu.py0000664000175100017510000001574713245573052020643 0ustar crobinsocrobinso00000000000000# # Copyright 2010, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .xmlbuilder import XMLBuilder, XMLProperty, XMLChildProperty class _CPUCellSibling(XMLBuilder): """ Class for generating nodes """ _XML_ROOT_NAME = "sibling" _XML_PROP_ORDER = ["id", "value"] id = XMLProperty("./@id", is_int=True) value = XMLProperty("./@value", is_int=True) class _CPUCell(XMLBuilder): """ Class for generating child XML """ _XML_ROOT_NAME = "cell" _XML_PROP_ORDER = ["id", "cpus", "memory"] id = XMLProperty("./@id", is_int=True) cpus = XMLProperty("./@cpus") memory = XMLProperty("./@memory", is_int=True) siblings = XMLChildProperty(_CPUCellSibling, relative_xpath="./distances") def add_sibling(self): obj = _CPUCellSibling(self.conn) self.add_child(obj) return obj class CPUCache(XMLBuilder): """ Class for generating child XML """ _XML_ROOT_NAME = "cache" _XML_PROP_ORDER = ["mode", "level"] mode = XMLProperty("./@mode") level = XMLProperty("./@level", is_int=True) class CPUFeature(XMLBuilder): """ Class for generating child XML """ POLICIES = ["force", "require", "optional", "disable", "forbid"] _XML_ROOT_NAME = "feature" _XML_PROP_ORDER = ["policy", "name"] name = XMLProperty("./@name") policy = XMLProperty("./@policy") class CPU(XMLBuilder): """ Class for generating XML """ MATCHS = ["minimum", "exact", "strict"] _XML_ROOT_NAME = "cpu" _XML_PROP_ORDER = ["mode", "match", "model", "vendor", "sockets", "cores", "threads", "features"] special_mode_was_set = False # These values are exposed on the command line, so are stable API SPECIAL_MODE_HOST_MODEL_ONLY = "host-model-only" SPECIAL_MODE_HV_DEFAULT = "hv-default" SPECIAL_MODE_HOST_COPY = "host-copy" SPECIAL_MODE_HOST_MODEL = "host-model" SPECIAL_MODE_HOST_PASSTHROUGH = "host-passthrough" SPECIAL_MODE_CLEAR = "clear" SPECIAL_MODES = [SPECIAL_MODE_HOST_MODEL_ONLY, SPECIAL_MODE_HV_DEFAULT, SPECIAL_MODE_HOST_COPY, SPECIAL_MODE_HOST_MODEL, SPECIAL_MODE_HOST_PASSTHROUGH, SPECIAL_MODE_CLEAR] def set_special_mode(self, val): if (val == self.SPECIAL_MODE_HOST_MODEL or val == self.SPECIAL_MODE_HOST_PASSTHROUGH): self.model = None self.vendor = None self.model_fallback = None for f in self.features: self.remove_feature(f) self.mode = val elif val == self.SPECIAL_MODE_HOST_COPY: self.copy_host_cpu() elif (val == self.SPECIAL_MODE_HV_DEFAULT or val == self.SPECIAL_MODE_CLEAR): self.clear() elif val == self.SPECIAL_MODE_HOST_MODEL_ONLY: if self.conn.caps.host.cpu.model: self.clear() self.model = self.conn.caps.host.cpu.model else: raise RuntimeError("programming error: unknown " "special cpu mode '%s'" % val) self.special_mode_was_set = True def add_feature(self, name, policy="require"): feature = CPUFeature(self.conn) feature.name = name feature.policy = policy self.add_child(feature) def remove_feature(self, feature): self.remove_child(feature) features = XMLChildProperty(CPUFeature) cells = XMLChildProperty(_CPUCell, relative_xpath="./numa") def add_cell(self): obj = _CPUCell(self.conn) self.add_child(obj) return obj cache = XMLChildProperty(CPUCache) def set_l3_cache_mode(self): obj = CPUCache(self.conn) self.add_child(obj) return obj def copy_host_cpu(self): """ Enact the equivalent of qemu -cpu host, pulling all info from capabilities about the host CPU """ cpu = self.conn.caps.host.cpu if not cpu.model: raise ValueError(_("No host CPU reported in capabilities")) self.mode = "custom" self.match = "exact" self.model = cpu.model self.vendor = cpu.vendor for feature in self.features: self.remove_feature(feature) for feature in cpu.features: self.add_feature(feature.name) def vcpus_from_topology(self): """ Determine the CPU count represented by topology, or 1 if no topology is set """ self.set_topology_defaults() if self.sockets: return self.sockets * self.cores * self.threads return 1 def set_topology_defaults(self, vcpus=None): """ Fill in unset topology values, using the passed vcpus count if required """ if (self.sockets is None and self.cores is None and self.threads is None): return if vcpus is None: if self.sockets is None: self.sockets = 1 if self.threads is None: self.threads = 1 if self.cores is None: self.cores = 1 vcpus = int(vcpus or 0) if not self.sockets: if not self.cores: self.sockets = vcpus // self.threads else: self.sockets = vcpus // self.cores if not self.cores: if not self.threads: self.cores = vcpus // self.sockets else: self.cores = vcpus // (self.sockets * self.threads) if not self.threads: self.threads = vcpus // (self.sockets * self.cores) return ################## # XML properties # ################## def _set_model(self, val): if val: self.mode = "custom" if not self.match: self.match = "exact" return val model = XMLProperty("./model", set_converter=_set_model) model_fallback = XMLProperty("./model/@fallback") match = XMLProperty("./@match") vendor = XMLProperty("./vendor") mode = XMLProperty("./@mode") sockets = XMLProperty("./topology/@sockets", is_int=True) cores = XMLProperty("./topology/@cores", is_int=True) threads = XMLProperty("./topology/@threads", is_int=True) virt-manager-1.5.1/virtinst/devicevideo.py0000664000175100017510000000344713241024270022321 0ustar crobinsocrobinso00000000000000# # Copyright 2009, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .device import VirtualDevice from .xmlbuilder import XMLProperty class VirtualVideoDevice(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_VIDEO # Default models list MODEL_DEFAULT = "default" MODELS = ["cirrus", "vga", "vmvga", "xen", "qxl", "virtio"] @staticmethod def pretty_model(model): if model in ["qxl", "vmvga", "vga"]: return model.upper() return model.capitalize() _XML_PROP_ORDER = ["model", "vram", "heads", "vgamem"] model = XMLProperty("./model/@type", default_cb=lambda s: "cirrus", default_name=MODEL_DEFAULT) vram = XMLProperty("./model/@vram", is_int=True) vram64 = XMLProperty("./model/@vram64", is_int=True) ram = XMLProperty("./model/@ram", is_int=True) heads = XMLProperty("./model/@heads", is_int=True) vgamem = XMLProperty("./model/@vgamem", is_int=True) accel3d = XMLProperty("./model/acceleration/@accel3d", is_yesno=True) VirtualVideoDevice.register_type() virt-manager-1.5.1/virtinst/deviceinterface.py0000664000175100017510000002373313245573052023166 0ustar crobinsocrobinso00000000000000# # Copyright 2006-2009, 2013 Red Hat, Inc. # Jeremy Katz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import logging import os import random from . import util from .device import VirtualDevice from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty def _random_mac(conn): """Generate a random MAC address. 00-16-3E allocated to xensource 52-54-00 used by qemu/kvm The OUI list is available at http://standards.ieee.org/regauth/oui/oui.txt. The remaining 3 fields are random, with the first bit of the first random field set 0. @return: MAC address string """ if conn.is_qemu(): oui = [0x52, 0x54, 0x00] else: # Xen oui = [0x00, 0x16, 0x3E] mac = oui + [ random.randint(0x00, 0xff), random.randint(0x00, 0xff), random.randint(0x00, 0xff)] return ':'.join(["%02x" % x for x in mac]) def _default_route(): route_file = "/proc/net/route" if not os.path.exists(route_file): logging.debug("route_file=%s does not exist", route_file) return None for line in open(route_file): info = line.split() if len(info) != 11: logging.debug("Unexpected field count=%s when parsing %s", len(info), route_file) break try: route = int(info[1], 16) if route == 0: return info[0] except ValueError: continue return None def _default_bridge(conn): if "VIRTINST_TEST_SUITE" in os.environ: return "eth0" if conn.is_remote(): return None dev = _default_route() if not dev: return None # New style peth0 == phys dev, eth0 == bridge, eth0 == default route if os.path.exists("/sys/class/net/%s/bridge" % dev): return dev # Old style, peth0 == phys dev, eth0 == netloop, xenbr0 == bridge, # vif0.0 == netloop enslaved, eth0 == default route try: defn = int(dev[-1]) except Exception: defn = -1 if (defn >= 0 and os.path.exists("/sys/class/net/peth%d/brport" % defn) and os.path.exists("/sys/class/net/xenbr%d/bridge" % defn)): return "xenbr%d" return None def _default_network(conn): ret = _default_bridge(conn) if ret: return ["bridge", ret] # FIXME: Check that this exists return ["network", "default"] class VirtualPort(XMLBuilder): _XML_ROOT_NAME = "virtualport" type = XMLProperty("./@type") managerid = XMLProperty("./parameters/@managerid", is_int=True) typeid = XMLProperty("./parameters/@typeid", is_int=True) typeidversion = XMLProperty("./parameters/@typeidversion", is_int=True) instanceid = XMLProperty("./parameters/@instanceid") profileid = XMLProperty("./parameters/@profileid") interfaceid = XMLProperty("./parameters/@interfaceid") class VirtualNetworkInterface(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_NET TYPE_BRIDGE = "bridge" TYPE_VIRTUAL = "network" TYPE_USER = "user" TYPE_VHOSTUSER = "vhostuser" TYPE_ETHERNET = "ethernet" TYPE_DIRECT = "direct" network_types = [TYPE_BRIDGE, TYPE_VIRTUAL, TYPE_USER, TYPE_ETHERNET, TYPE_DIRECT] @staticmethod def get_network_type_desc(net_type): """ Return human readable description for passed network type """ desc = net_type.capitalize() if net_type == VirtualNetworkInterface.TYPE_BRIDGE: desc = _("Shared physical device") elif net_type == VirtualNetworkInterface.TYPE_VIRTUAL: desc = _("Virtual networking") elif net_type == VirtualNetworkInterface.TYPE_USER: desc = _("Usermode networking") return desc @staticmethod def generate_mac(conn): """ Generate a random MAC that doesn't conflict with any VMs on the connection. """ if conn.fake_conn_predictable(): # Testing hack return "00:11:22:33:44:55" for ignore in range(256): mac = _random_mac(conn) ret = VirtualNetworkInterface.is_conflict_net(conn, mac) if ret[1] is None: return mac logging.debug("Failed to generate non-conflicting MAC") return None @staticmethod def is_conflict_net(conn, searchmac): """ @returns: a two element tuple: first element is True if fatal collision occured second element is a string description of the collision. Non fatal collisions (mac addr collides with inactive guest) will return (False, "description of collision") """ if searchmac is None: return (False, None) vms = conn.fetch_all_guests() for vm in vms: for nic in vm.get_devices("interface"): nicmac = nic.macaddr or "" if nicmac.lower() == searchmac.lower(): return (True, _("The MAC address '%s' is in use " "by another virtual machine.") % searchmac) return (False, None) def __init__(self, *args, **kwargs): VirtualDevice.__init__(self, *args, **kwargs) self._random_mac = None self._default_bridge = None ############### # XML helpers # ############### def _generate_default_bridge(self): ret = self._default_bridge if ret is None: ret = False default = _default_bridge(self.conn) if default: ret = default self._default_bridge = ret return ret or None def _get_default_bridge(self): if self.type == self.TYPE_BRIDGE: return self._generate_default_bridge() return None def _default_source_mode(self): if self.type == self.TYPE_DIRECT: return "vepa" return None def _get_default_mac(self): if not self._random_mac: self._random_mac = self.generate_mac(self.conn) return self._random_mac def _validate_mac(self, val): util.validate_macaddr(val) return val def _get_source(self): """ Convenience function, try to return the relevant value per the network type. """ if self.type == self.TYPE_VIRTUAL: return self._network if self.type == self.TYPE_BRIDGE: return self._bridge if self.type == self.TYPE_DIRECT: return self._source_dev if self.type == self.TYPE_USER or self.type == self.TYPE_ETHERNET: return None return self._network or self._bridge or self._source_dev def _set_source(self, newsource): """ Convenience function, try to set the relevant value per the network type """ self._bridge = None self._network = None self._source_dev = None if self.type == self.TYPE_VIRTUAL: self._network = newsource elif self.type == self.TYPE_BRIDGE: self._bridge = newsource elif self.type == self.TYPE_DIRECT: self._source_dev = newsource source = property(_get_source, _set_source) ################## # XML properties # ################## _XML_PROP_ORDER = [ "_bridge", "_network", "_source_dev", "source_type", "source_path", "source_mode", "portgroup", "macaddr", "target_dev", "model", "virtualport", "filterref", "rom_bar", "rom_file"] _bridge = XMLProperty("./source/@bridge", default_cb=_get_default_bridge) _network = XMLProperty("./source/@network") _source_dev = XMLProperty("./source/@dev") virtualport = XMLChildProperty(VirtualPort, is_single=True) type = XMLProperty("./@type", default_cb=lambda s: s.TYPE_BRIDGE) trustGuestRxFilters = XMLProperty("./@trustGuestRxFilters", is_yesno=True) macaddr = XMLProperty("./mac/@address", set_converter=_validate_mac, default_cb=_get_default_mac) source_type = XMLProperty("./source/@type") source_path = XMLProperty("./source/@path") source_mode = XMLProperty("./source/@mode", default_cb=_default_source_mode) portgroup = XMLProperty("./source/@portgroup") model = XMLProperty("./model/@type") target_dev = XMLProperty("./target/@dev") filterref = XMLProperty("./filterref/@filter") link_state = XMLProperty("./link/@state") driver_name = XMLProperty("./driver/@name") driver_queues = XMLProperty("./driver/@queues", is_int=True) rom_bar = XMLProperty("./rom/@bar", is_onoff=True) rom_file = XMLProperty("./rom/@file") ############# # Build API # ############# def setup(self, meter=None): ignore = meter if not self.macaddr: return ret, msg = self.is_conflict_net(self.conn, self.macaddr) if msg is None: return if ret is False: logging.warning(msg) else: raise RuntimeError(msg) def set_default_source(self): if (self.conn.is_qemu_session() or self.conn.is_test()): self.type = self.TYPE_USER else: self.type, self.source = _default_network(self.conn) VirtualNetworkInterface.register_type() virt-manager-1.5.1/virtinst/xmlnsqemu.py0000664000175100017510000000314213245573052022067 0ustar crobinsocrobinso00000000000000# Copyright 2017 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty class _XMLNSQemuArg(XMLBuilder): _XML_ROOT_NAME = "qemu:arg" value = XMLProperty("./@value") class _XMLNSQemuEnv(XMLBuilder): _XML_ROOT_NAME = "qemu:env" name = XMLProperty("./@name") value = XMLProperty("./@value") class XMLNSQemu(XMLBuilder): """ Class for generating XML """ _XML_ROOT_NAME = "qemu:commandline" _XML_PROP_ORDER = ["args", "envs"] args = XMLChildProperty(_XMLNSQemuArg) def add_arg(self, value): arg = _XMLNSQemuArg(conn=self.conn) arg.value = value self.add_child(arg) envs = XMLChildProperty(_XMLNSQemuEnv) def add_env(self, name, value): env = _XMLNSQemuEnv(conn=self.conn) env.name = name env.value = value self.add_child(env) virt-manager-1.5.1/virtinst/__init__.py0000664000175100017510000000710413245061760021575 0ustar crobinsocrobinso00000000000000# Copyright (C) 2013, 2014 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from virtcli import CLIConfig as _CLIConfig # pylint: disable=wrong-import-position def _setup_i18n(): import gettext import locale try: locale.setlocale(locale.LC_ALL, '') except Exception: # Can happen if user passed a bogus LANG pass gettext.install("virt-manager", _CLIConfig.gettext_dir) gettext.bindtextdomain("virt-manager", _CLIConfig.gettext_dir) _setup_i18n() stable_defaults = _CLIConfig.stable_defaults from virtinst import util from virtinst import support from virtinst.uri import URI from virtinst.osdict import OSDB from virtinst.osxml import OSXML from virtinst.domainfeatures import DomainFeatures from virtinst.domainnumatune import DomainNumatune from virtinst.domainblkiotune import DomainBlkiotune from virtinst.domainmemorytune import DomainMemorytune from virtinst.domainmemorybacking import DomainMemorybacking from virtinst.domainresource import DomainResource from virtinst.clock import Clock from virtinst.cpu import CPU, CPUFeature from virtinst.cputune import CPUTune from virtinst.seclabel import Seclabel from virtinst.pm import PM from virtinst.idmap import IdMap from virtinst.capabilities import Capabilities from virtinst.domcapabilities import DomainCapabilities from virtinst.interface import Interface, InterfaceProtocol from virtinst.network import Network from virtinst.nodedev import NodeDevice from virtinst.storage import StoragePool, StorageVolume from virtinst.device import VirtualDevice from virtinst.deviceinterface import VirtualNetworkInterface from virtinst.devicegraphics import VirtualGraphics from virtinst.deviceaudio import VirtualAudio from virtinst.deviceinput import VirtualInputDevice from virtinst.devicedisk import VirtualDisk from virtinst.devicehostdev import VirtualHostDevice from virtinst.devicechar import (VirtualChannelDevice, VirtualConsoleDevice, VirtualParallelDevice, VirtualSerialDevice) from virtinst.devicevideo import VirtualVideoDevice from virtinst.devicecontroller import VirtualController from virtinst.devicewatchdog import VirtualWatchdog from virtinst.devicefilesystem import VirtualFilesystem from virtinst.devicesmartcard import VirtualSmartCardDevice from virtinst.deviceredirdev import VirtualRedirDevice from virtinst.devicememballoon import VirtualMemballoon from virtinst.devicetpm import VirtualTPMDevice from virtinst.devicerng import VirtualRNGDevice from virtinst.devicepanic import VirtualPanicDevice from virtinst.installer import (ContainerInstaller, ImportInstaller, PXEInstaller, Installer) from virtinst.distroinstaller import DistroInstaller from virtinst.guest import Guest from virtinst.cloner import Cloner from virtinst.snapshot import DomainSnapshot from virtinst.connection import VirtualConnection virt-manager-1.5.1/virtinst/devicegraphics.py0000664000175100017510000002105513245573052023021 0ustar crobinsocrobinso00000000000000# # Copyright 2006-2009, 2013 Red Hat, Inc. # Jeremy Katz # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import os from .device import VirtualDevice from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty def _get_mode_prop(channel_type): xpath = "./channel[@name='%s']/@mode" % channel_type return XMLProperty(xpath) def _validate_port(name, val): if val is None: return val val = int(val) if val < 5900 and val != -1: raise ValueError(_("%s must be above 5900, or " "-1 for auto allocation") % name) return val class _GraphicsListen(XMLBuilder): _XML_ROOT_NAME = "listen" type = XMLProperty("./@type") address = XMLProperty("./@address") network = XMLProperty("./@network") socket = XMLProperty("./@socket") class VirtualGraphics(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_GRAPHICS TYPE_SDL = "sdl" TYPE_VNC = "vnc" TYPE_RDP = "rdp" TYPE_SPICE = "spice" TYPES = [TYPE_VNC, TYPE_SDL, TYPE_RDP, TYPE_SPICE] CHANNEL_TYPE_MAIN = "main" CHANNEL_TYPE_DISPLAY = "display" CHANNEL_TYPE_INPUTS = "inputs" CHANNEL_TYPE_CURSOR = "cursor" CHANNEL_TYPE_PLAYBACK = "playback" CHANNEL_TYPE_RECORD = "record" CHANNEL_TYPES = [CHANNEL_TYPE_MAIN, CHANNEL_TYPE_DISPLAY, CHANNEL_TYPE_INPUTS, CHANNEL_TYPE_CURSOR, CHANNEL_TYPE_PLAYBACK, CHANNEL_TYPE_RECORD] CHANNEL_MODE_SECURE = "secure" CHANNEL_MODE_INSECURE = "insecure" CHANNEL_MODE_ANY = "any" CHANNEL_MODES = [CHANNEL_MODE_SECURE, CHANNEL_MODE_INSECURE, CHANNEL_MODE_ANY] KEYMAP_LOCAL = "local" KEYMAP_DEFAULT = "default" _special_keymaps = [KEYMAP_LOCAL, KEYMAP_DEFAULT] @staticmethod def valid_keymaps(): """ Return a list of valid keymap values. """ from . import hostkeymap orig_list = hostkeymap.keytable.values() sort_list = [] orig_list.sort() for k in orig_list: if k not in sort_list: sort_list.append(k) return sort_list @staticmethod def pretty_type_simple(gtype): if (gtype in [VirtualGraphics.TYPE_VNC, VirtualGraphics.TYPE_SDL, VirtualGraphics.TYPE_RDP]): return str(gtype).upper() return str(gtype).capitalize() def __init__(self, *args, **kwargs): VirtualDevice.__init__(self, *args, **kwargs) self._local_keymap = -1 _XML_PROP_ORDER = ["type", "gl", "port", "tlsPort", "autoport", "keymap", "listen", "passwd", "display", "xauth"] def _default_keymap(self, force_local=False): if self.type != "vnc" and self.type != "spice": return None if (not force_local and self.conn.check_support( self.conn.SUPPORT_CONN_KEYMAP_AUTODETECT)): return None if self._local_keymap == -1: from . import hostkeymap self._local_keymap = hostkeymap.default_keymap() return self._local_keymap def _set_keymap_converter(self, val): if val == self.KEYMAP_DEFAULT: return self._default_keymap() if val == self.KEYMAP_LOCAL: return self._default_keymap(force_local=True) return val keymap = XMLProperty("./@keymap", default_cb=_default_keymap, set_converter=_set_keymap_converter) def _set_port_converter(self, val): val = _validate_port("Port", val) self.autoport = self._get_default_autoport() return val def _set_tlsport_converter(self, val): val = _validate_port("TLS Port", val) self.autoport = self._get_default_autoport() return val def _listen_need_port(self): listen = self.get_first_listen_type() return not listen or listen in ["address", "network"] def _get_default_port(self): if (self.type == "vnc" or self.type == "spice") and self._listen_need_port(): return -1 return None def _get_default_tlsport(self): if self.type == "spice" and self._listen_need_port(): return -1 return None def _get_default_autoport(self): # By default, don't do this for VNC to maintain back compat with # old libvirt that didn't support 'autoport' if self.type != "spice": return None if (self.port == -1 and self.tlsPort == -1): return True return None port = XMLProperty("./@port", is_int=True, set_converter=_set_port_converter, default_cb=_get_default_port) tlsPort = XMLProperty("./@tlsPort", is_int=True, set_converter=_set_tlsport_converter, default_cb=_get_default_tlsport) autoport = XMLProperty("./@autoport", is_yesno=True, default_cb=_get_default_autoport) channel_main_mode = _get_mode_prop(CHANNEL_TYPE_MAIN) channel_display_mode = _get_mode_prop(CHANNEL_TYPE_DISPLAY) channel_inputs_mode = _get_mode_prop(CHANNEL_TYPE_INPUTS) channel_cursor_mode = _get_mode_prop(CHANNEL_TYPE_CURSOR) channel_playback_mode = _get_mode_prop(CHANNEL_TYPE_PLAYBACK) channel_record_mode = _get_mode_prop(CHANNEL_TYPE_RECORD) def _get_default_display(self): if self.type != "sdl": return None if "DISPLAY" not in os.environ: raise RuntimeError("No DISPLAY environment variable set.") return os.environ["DISPLAY"] def _get_default_xauth(self): if self.type != "sdl": return None return os.path.expanduser("~/.Xauthority") xauth = XMLProperty("./@xauth", default_cb=_get_default_xauth) display = XMLProperty("./@display", default_cb=_get_default_display) def _set_listen(self, val): # Update the corresponding block find_listen = [l for l in self.listens if (l.type == "address" and l.address == self.listen)] if find_listen: if val is None: self.remove_child(find_listen[0]) else: find_listen[0].address = val return val listen = XMLProperty("./@listen", set_converter=_set_listen) type = XMLProperty("./@type", default_cb=lambda s: "vnc", default_name="default") passwd = XMLProperty("./@passwd") passwdValidTo = XMLProperty("./@passwdValidTo") socket = XMLProperty("./@socket") connected = XMLProperty("./@connected") defaultMode = XMLProperty("./@defaultMode") listens = XMLChildProperty(_GraphicsListen) def remove_all_listens(self): for listen in self.listens: self.remove_child(listen) def add_listen(self): obj = _GraphicsListen(self.conn) self.add_child(obj) return obj def get_first_listen_type(self): if len(self.listens) > 0: return self.listens[0].type return None def set_listen_none(self): self.remove_all_listens() self.listen = None self.port = None self.tlsPort = None self.autoport = None self.socket = None if self.conn.check_support( self.conn.SUPPORT_CONN_GRAPHICS_LISTEN_NONE): obj = self.add_listen() obj.type = "none" # Spice bits image_compression = XMLProperty("./image/@compression") streaming_mode = XMLProperty("./streaming/@mode") clipboard_copypaste = XMLProperty("./clipboard/@copypaste", is_yesno=True) mouse_mode = XMLProperty("./mouse/@mode") filetransfer_enable = XMLProperty("./filetransfer/@enable", is_yesno=True) gl = XMLProperty("./gl/@enable", is_yesno=True) rendernode = XMLProperty("./gl/@rendernode") VirtualGraphics.register_type() virt-manager-1.5.1/virtinst/diskbackend.py0000664000175100017510000004564213245573052022313 0ustar crobinsocrobinso00000000000000# # Storage lookup/creation helpers # # Copyright 2013 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import logging import os import re import stat import libvirt from .storage import StoragePool, StorageVolume def _lookup_pool_by_dirname(conn, path): """ Try to find the parent pool for the passed path. If found, and the pool isn't running, attempt to start it up. return pool, or None if not found """ pool = StoragePool.lookup_pool_by_path(conn, os.path.dirname(path)) if not pool: return None # Ensure pool is running if pool.info()[0] != libvirt.VIR_STORAGE_POOL_RUNNING: pool.create(0) return pool def _lookup_vol_by_path(conn, path): """ Try to find a volume matching the full passed path. Call info() on it to ensure the volume wasn't removed behind libvirt's back """ try: vol = conn.storageVolLookupByPath(path) vol.info() return vol, None except libvirt.libvirtError as e: if (hasattr(libvirt, "VIR_ERR_NO_STORAGE_VOL") and e.get_error_code() != libvirt.VIR_ERR_NO_STORAGE_VOL): raise return None, e def _lookup_vol_by_basename(pool, path): """ Try to lookup a volume for 'path' in parent 'pool' by it's filename. This sometimes works in cases where full volume path lookup doesn't, since not all libvirt storage backends implement path lookup. """ name = os.path.basename(path) if name in pool.listVolumes(): return pool.storageVolLookupByName(name) def _stat_disk(path): """ Returns the tuple (isreg, size) """ if not os.path.exists(path): return True, 0 mode = os.stat(path)[stat.ST_MODE] # os.path.getsize('/dev/..') can be zero on some platforms if stat.S_ISBLK(mode): try: fd = os.open(path, os.O_RDONLY) # os.SEEK_END is not present on all systems size = os.lseek(fd, 0, 2) os.close(fd) except Exception: size = 0 return False, size elif stat.S_ISREG(mode): return True, os.path.getsize(path) return True, 0 def check_if_path_managed(conn, path): """ Try to lookup storage objects for the passed path. Returns (volume, parent pool). Only one is returned at a time. """ vol, ignore = _lookup_vol_by_path(conn, path) if vol: return vol, vol.storagePoolLookupByVolume() pool = _lookup_pool_by_dirname(conn, path) if not pool: return None, None # We have the parent pool, but didn't find a volume on first lookup # attempt. Refresh the pool and try again, incase we were just out # of date. try: pool.refresh(0) vol, verr = _lookup_vol_by_path(conn, path) if verr: try: vol = _lookup_vol_by_basename(pool, path) except Exception: pass except Exception as e: vol = None pool = None verr = str(e) if not vol and not pool and verr: raise ValueError(_("Cannot use storage %(path)s: %(err)s") % {'path': path, 'err': verr}) return vol, pool def _can_auto_manage(path): path = path or "" skip_prefixes = ["/dev", "/sys", "/proc"] if path_is_url(path): return False for prefix in skip_prefixes: if path.startswith(prefix + "/") or path == prefix: return False return True def manage_path(conn, path): """ If path is not managed, try to create a storage pool to probe the path """ if not conn.check_support(conn.SUPPORT_CONN_STORAGE): return None, None if not path: return None, None if not path_is_url(path): path = os.path.abspath(path) vol, pool = check_if_path_managed(conn, path) if vol or pool or not _can_auto_manage(path): return vol, pool dirname = os.path.dirname(path) poolname = os.path.basename(dirname).replace(" ", "_") if not poolname: poolname = "dirpool" poolname = StoragePool.find_free_name(conn, poolname) logging.debug("Attempting to build pool=%s target=%s", poolname, dirname) poolxml = StoragePool(conn) poolxml.name = poolname poolxml.type = poolxml.TYPE_DIR poolxml.target_path = dirname pool = poolxml.install(build=False, create=True, autostart=True) vol = _lookup_vol_by_basename(pool, path) return vol, pool def path_is_url(path): """ Detect if path is a URL """ if not path: return False return bool(re.match("[a-zA-Z]+(\+[a-zA-Z]+)?://.*", path)) def _get_dev_type(path, vol_xml, vol_object, pool_xml, remote): """ Try to get device type for volume. """ if vol_xml: if vol_xml.type: return vol_xml.type # If vol_xml.type is None the vol_xml.file_type can return only # these types: block, network or file if vol_xml.file_type == libvirt.VIR_STORAGE_VOL_BLOCK: return "block" elif vol_xml.file_type == libvirt.VIR_STORAGE_VOL_NETWORK: return "network" if vol_object: t = vol_object.info()[0] if t == StorageVolume.TYPE_FILE: return "file" elif t == StorageVolume.TYPE_BLOCK: return "block" elif t == StorageVolume.TYPE_NETWORK: return "network" if pool_xml: t = pool_xml.get_disk_type() if t == StorageVolume.TYPE_BLOCK: return "block" elif t == StorageVolume.TYPE_NETWORK: return "network" if path: if path_is_url(path): return "network" if not remote: if os.path.isdir(path): return "dir" elif _stat_disk(path)[0]: return "file" else: return "block" return "file" ############################################## # Classes for tracking storage media details # ############################################## class _StorageBase(object): """ Storage base class, defining the API used by VirtualDisk """ def __init__(self, conn): self._conn = conn self._parent_pool_xml = None def get_size(self): raise NotImplementedError() def get_dev_type(self): raise NotImplementedError() def get_driver_type(self): raise NotImplementedError() def get_vol_install(self): raise NotImplementedError() def get_vol_object(self): raise NotImplementedError() def get_parent_pool(self): raise NotImplementedError() def get_parent_pool_xml(self): if not self._parent_pool_xml and self.get_parent_pool(): self._parent_pool_xml = StoragePool(self._conn, parsexml=self.get_parent_pool().XMLDesc(0)) return self._parent_pool_xml def validate(self, disk): raise NotImplementedError() def get_path(self): raise NotImplementedError() # Storage creation routines def is_size_conflict(self): raise NotImplementedError() def create(self, progresscb): raise NotImplementedError() def will_create_storage(self): raise NotImplementedError() class _StorageCreator(_StorageBase): """ Base object for classes that will actually create storage on disk """ def __init__(self, conn): _StorageBase.__init__(self, conn) self._pool = None self._vol_install = None self._path = None self._size = None self._dev_type = None ############## # Public API # ############## def create(self, progresscb): raise NotImplementedError() def get_path(self): if self._vol_install and not self._path: xmlobj = StoragePool(self._conn, parsexml=self._vol_install.pool.XMLDesc(0)) if self.get_dev_type() == "network": self._path = self._vol_install.name else: sep = "/" if xmlobj.target_path == "" or xmlobj.target_path[-1] == '/': sep = "" self._path = (xmlobj.target_path + sep + self._vol_install.name) return self._path def get_vol_install(self): return self._vol_install def get_vol_xml(self): return self._vol_install def get_size(self): if self._size is None: self._size = (float(self._vol_install.capacity) / 1024.0 / 1024.0 / 1024.0) return self._size def get_dev_type(self): if not self._dev_type: self._dev_type = _get_dev_type(self._path, self._vol_install, None, self.get_parent_pool_xml(), self._conn.is_remote()) return self._dev_type def get_driver_type(self): if self._vol_install: if self._vol_install.supports_property("format"): return self._vol_install.format return "raw" def validate(self, disk): if disk.device in ["floppy", "cdrom"]: raise ValueError(_("Cannot create storage for %s device.") % disk.device) if self._vol_install: self._vol_install.validate() return if self._size is None: raise ValueError(_("size is required for non-existent disk " "'%s'" % self.get_path())) err, msg = self.is_size_conflict() if err: raise ValueError(msg) if msg: logging.warning(msg) def will_create_storage(self): return True def get_vol_object(self): return None def get_parent_pool(self): if self._vol_install: return self._vol_install.pool return None def exists(self): return False class CloneStorageCreator(_StorageCreator): """ Handles manually copying local files for Cloner Many clone scenarios will use libvirt storage APIs, which will use the ManagedStorageCreator """ def __init__(self, conn, output_path, input_path, size, sparse): _StorageCreator.__init__(self, conn) self._path = output_path self._output_path = output_path self._input_path = input_path self._size = size self._sparse = sparse def is_size_conflict(self): ret = False msg = None if self.get_dev_type() == "block": avail = _stat_disk(self._path)[1] else: vfs = os.statvfs(os.path.dirname(self._path)) avail = vfs.f_frsize * vfs.f_bavail need = long(self._size * 1024 * 1024 * 1024) if need > avail: if self._sparse: msg = _("The filesystem will not have enough free space" " to fully allocate the sparse file when the guest" " is running.") else: ret = True msg = _("There is not enough free space to create the disk.") if msg: msg += (_(" %d M requested > %d M available") % ((need // (1024 * 1024)), (avail // (1024 * 1024)))) return (ret, msg) def create(self, progresscb): text = (_("Cloning %(srcfile)s") % {'srcfile': os.path.basename(self._input_path)}) size_bytes = long(self.get_size() * 1024 * 1024 * 1024) progresscb.start(filename=self._output_path, size=size_bytes, text=text) # Plain file clone self._clone_local(progresscb, size_bytes) def _clone_local(self, meter, size_bytes): if self._input_path == "/dev/null": # Not really sure why this check is here, # but keeping for compat logging.debug("Source dev was /dev/null. Skipping") return if self._input_path == self._output_path: logging.debug("Source and destination are the same. Skipping.") return # If a destination file exists and sparse flag is True, # this priority takes an existing file. if (not os.path.exists(self._output_path) and self._sparse): clone_block_size = 4096 sparse = True fd = None try: fd = os.open(self._output_path, os.O_WRONLY | os.O_CREAT, 0o640) os.ftruncate(fd, size_bytes) finally: if fd: os.close(fd) else: clone_block_size = 1024 * 1024 * 10 sparse = False logging.debug("Local Cloning %s to %s, sparse=%s, block_size=%s", self._input_path, self._output_path, sparse, clone_block_size) zeros = '\0' * 4096 src_fd, dst_fd = None, None try: try: src_fd = os.open(self._input_path, os.O_RDONLY) dst_fd = os.open(self._output_path, os.O_WRONLY | os.O_CREAT, 0o640) i = 0 while 1: l = os.read(src_fd, clone_block_size) s = len(l) if s == 0: meter.end(size_bytes) break # check sequence of zeros if sparse and zeros == l: os.lseek(dst_fd, s, 1) else: b = os.write(dst_fd, l) if s != b: meter.end(i) break i += s if i < size_bytes: meter.update(i) except OSError as e: raise RuntimeError(_("Error cloning diskimage %s to %s: %s") % (self._input_path, self._output_path, str(e))) finally: if src_fd is not None: os.close(src_fd) if dst_fd is not None: os.close(dst_fd) class ManagedStorageCreator(_StorageCreator): """ Handles storage creation via libvirt APIs. All the actual creation logic lives in StorageVolume, this is mostly about pulling out bits from that class and mapping them to VirtualDisk elements """ def __init__(self, conn, vol_install): _StorageCreator.__init__(self, conn) self._pool = vol_install.pool self._vol_install = vol_install def create(self, progresscb): return self._vol_install.install(meter=progresscb) def is_size_conflict(self): return self._vol_install.is_size_conflict() class StorageBackend(_StorageBase): """ Class that carries all the info about any existing storage that the disk references """ def __init__(self, conn, path, vol_object, parent_pool): _StorageBase.__init__(self, conn) self._vol_object = vol_object self._parent_pool = parent_pool self._path = path if self._vol_object is not None: self._path = None if self._vol_object and not self._parent_pool: raise RuntimeError( "programming error: parent_pool must be specified") # Cached bits self._vol_xml = None self._parent_pool_xml = None self._exists = None self._size = None self._dev_type = None ############## # Public API # ############## def get_path(self): if self._vol_object: return self.get_vol_xml().target_path return self._path def get_vol_object(self): return self._vol_object def get_vol_xml(self): if self._vol_xml is None: self._vol_xml = StorageVolume(self._conn, parsexml=self._vol_object.XMLDesc(0)) self._vol_xml.pool = self._parent_pool return self._vol_xml def get_parent_pool(self): return self._parent_pool def get_size(self): """ Return size of existing storage """ if self._size is None: ret = 0 if self._vol_object: ret = self.get_vol_xml().capacity elif self._path: ret = _stat_disk(self._path)[1] self._size = (float(ret) / 1024.0 / 1024.0 / 1024.0) return self._size def exists(self): if self._exists is None: if self._path is None: self._exists = True elif self._vol_object: self._exists = True elif (not self.get_dev_type() == "network" and not self._conn.is_remote() and os.path.exists(self._path)): self._exists = True elif self._parent_pool: self._exists = False elif self.get_dev_type() == "network": self._exists = True elif (self._conn.is_remote() and not _can_auto_manage(self._path)): # This allows users to pass /dev/sdX and we don't try to # validate it exists on the remote connection, since # autopooling /dev is perilous. Libvirt will error if # the device doesn't exist. self._exists = True else: self._exists = False return self._exists def get_dev_type(self): """ Return disk 'type' value per storage settings """ if self._dev_type is None: vol_xml = None if self._vol_object: vol_xml = self.get_vol_xml() self._dev_type = _get_dev_type(self._path, vol_xml, self._vol_object, self.get_parent_pool_xml(), self._conn.is_remote()) return self._dev_type def get_driver_type(self): if self._vol_object: ret = self.get_vol_xml().format if ret != "unknown": return ret return None def validate(self, disk): ignore = disk return def get_vol_install(self): return None def is_size_conflict(self): return (False, None) def will_create_storage(self): return False def create(self, progresscb): ignore = progresscb raise RuntimeError("programming error: %s can't create storage" % self.__class__.__name__) virt-manager-1.5.1/virtinst/deviceinput.py0000664000175100017510000000336413241024270022350 0ustar crobinsocrobinso00000000000000# # Copyright 2009, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .device import VirtualDevice from .xmlbuilder import XMLProperty class VirtualInputDevice(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_INPUT TYPE_MOUSE = "mouse" TYPE_TABLET = "tablet" TYPE_KEYBOARD = "keyboard" TYPE_DEFAULT = "default" TYPES = [TYPE_MOUSE, TYPE_TABLET, TYPE_KEYBOARD, TYPE_DEFAULT] BUS_PS2 = "ps2" BUS_USB = "usb" BUS_XEN = "xen" BUS_DEFAULT = "default" BUSES = [BUS_PS2, BUS_USB, BUS_XEN, BUS_DEFAULT] type = XMLProperty("./@type", default_cb=lambda s: s.TYPE_MOUSE, default_name=TYPE_DEFAULT) def _default_bus(self): if self.type == self.TYPE_TABLET: return self.BUS_USB if self.conn.is_xen(): return self.BUS_XEN return self.BUS_PS2 bus = XMLProperty("./@bus", default_cb=_default_bus, default_name=BUS_DEFAULT) VirtualInputDevice.register_type() virt-manager-1.5.1/virtinst/devicetpm.py0000664000175100017510000000413613245061760022020 0ustar crobinsocrobinso00000000000000# # Copyright 2011, 2013 Red Hat, Inc. # Cole Robinson # Marc-Andre Lureau # # Copyright 2013 IBM Corporation # Author: Stefan Berger # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .device import VirtualDevice from .xmlbuilder import XMLProperty class VirtualTPMDevice(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_TPM TYPE_PASSTHROUGH = "passthrough" TYPE_DEFAULT = "default" TYPES = [TYPE_PASSTHROUGH] MODEL_TIS = "tpm-tis" MODEL_DEFAULT = "default" MODELS = [MODEL_TIS] @staticmethod def get_pretty_type(tpm_type): if tpm_type == VirtualTPMDevice.TYPE_PASSTHROUGH: return _("Passthrough device") return tpm_type def supports_property(self, propname): """ Whether the TPM dev type supports the passed property name """ users = { "device_path": [self.TYPE_PASSTHROUGH], } if users.get(propname): return self.type in users[propname] return hasattr(self, propname) type = XMLProperty("./backend/@type", default_cb=lambda s: s.TYPE_PASSTHROUGH) model = XMLProperty("./@model", default_cb=lambda s: s.MODEL_TIS) device_path = XMLProperty("./backend/device/@path", default_cb=lambda s: "/dev/tpm0") VirtualTPMDevice.register_type() virt-manager-1.5.1/virtinst/nodedev.py0000664000175100017510000003377513245573052021501 0ustar crobinsocrobinso00000000000000# # Copyright 2009, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import logging import os from .xmlbuilder import XMLBuilder, XMLProperty, XMLChildProperty def _compare_int(nodedev_val, hostdev_val): def _intify(val): try: if "0x" in str(val): return int(val or '0x00', 16) else: return int(val) except Exception: return -1 nodedev_val = _intify(nodedev_val) hostdev_val = _intify(hostdev_val) return (nodedev_val == hostdev_val or hostdev_val == -1) class DevNode(XMLBuilder): _XML_ROOT_NAME = "devnode" node_type = XMLProperty("./@type") path = XMLProperty(".") class NodeDevice(XMLBuilder): CAPABILITY_TYPE_SYSTEM = "system" CAPABILITY_TYPE_NET = "net" CAPABILITY_TYPE_PCI = "pci" CAPABILITY_TYPE_USBDEV = "usb_device" CAPABILITY_TYPE_USBBUS = "usb" CAPABILITY_TYPE_STORAGE = "storage" CAPABILITY_TYPE_SCSIBUS = "scsi_host" CAPABILITY_TYPE_SCSIDEV = "scsi" CAPABILITY_TYPE_DRM = "drm" @staticmethod def lookupNodedevFromString(conn, idstring): """ Convert the passed libvirt node device name to a NodeDevice instance, with proper error reporting. If the name is name is not found, we will attempt to parse the name as would be passed to devAddressToNodeDev @param conn: libvirt.virConnect instance to perform the lookup on @param idstring: libvirt node device name to lookup, or address of the form: - bus.addr (ex. 001.003 for a usb device) - vendor:product (ex. 0x1234:0x5678 for a usb device - (domain:)bus:slot.func (ex. 00:10.0 for a pci device) @rtype: L{NodeDevice} instance """ if not conn.check_support(conn.SUPPORT_CONN_NODEDEV): raise ValueError(_("Connection does not support host device " "enumeration.")) # First try and see if this is a libvirt nodedev name for nodedev in conn.fetch_all_nodedevs(): if nodedev.name == idstring: return nodedev try: return _AddressStringToNodedev(conn, idstring) except Exception: logging.debug("Error looking up nodedev from idstring=%s", idstring, exc_info=True) raise @staticmethod def parse(conn, xml): tmpdev = NodeDevice(conn, parsexml=xml, allow_node_instantiate=True) cls = _typeToDeviceClass(tmpdev.device_type) return cls(conn, parsexml=xml, allow_node_instantiate=True) def __init__(self, *args, **kwargs): instantiate = kwargs.pop("allow_node_instantiate", False) if self.__class__ is NodeDevice and not instantiate: raise RuntimeError("Can not instantiate NodeDevice directly") XMLBuilder.__init__(self, *args, **kwargs) _XML_ROOT_NAME = "device" # Libvirt can generate bogus 'system' XML: # https://bugzilla.redhat.com/show_bug.cgi?id=1184131 _XML_SANITIZE = True name = XMLProperty("./name") parent = XMLProperty("./parent") device_type = XMLProperty("./capability/@type") devnodes = XMLChildProperty(DevNode) def get_devnode(self, parent="by-path"): for d in self.devnodes: paths = d.path.split(os.sep) if len(paths) > 2 and paths[-2] == parent: return d if len(self.devnodes) > 0: return self.devnodes[0] return None def pretty_name(self): """ Use device information to attempt to print a human readable device name. @returns: Device description string @rtype C{str} """ return self.name def compare_to_hostdev(self, hostdev): ignore = hostdev return False class SystemDevice(NodeDevice): hw_vendor = XMLProperty("./capability/hardware/vendor") hw_version = XMLProperty("./capability/hardware/version") hw_serial = XMLProperty("./capability/hardware/serial") hw_uuid = XMLProperty("./capability/hardware/uuid") fw_vendor = XMLProperty("./capability/firmware/vendor") fw_version = XMLProperty("./capability/firmware/version") fw_date = XMLProperty("./capability/firmware/release_date") def pretty_name(self): desc = _("System") if self.hw_vendor: desc += ": %s" % self.hw_vendor if self.hw_version: desc += " %s" % self.hw_version return desc class NetDevice(NodeDevice): interface = XMLProperty("./capability/interface") address = XMLProperty("./capability/address") capability_type = XMLProperty("./capability/capability/@type") def pretty_name(self): desc = self.name if self.interface: desc = _("Interface %s") % self.interface return desc class PCIDevice(NodeDevice): domain = XMLProperty("./capability/domain") bus = XMLProperty("./capability/bus") slot = XMLProperty("./capability/slot") function = XMLProperty("./capability/function") product_name = XMLProperty("./capability/product") product_id = XMLProperty("./capability/product/@id") vendor_name = XMLProperty("./capability/vendor") vendor_id = XMLProperty("./capability/vendor/@id") capability_type = XMLProperty("./capability/capability/@type") iommu_group = XMLProperty("./capability/iommuGroup/@number", is_int=True) def pretty_name(self): devstr = "%.4X:%.2X:%.2X:%X" % (int(self.domain), int(self.bus), int(self.slot), int(self.function)) return "%s %s %s" % (devstr, self.vendor_name, self.product_name) def compare_to_hostdev(self, hostdev): if hostdev.type != self.device_type: return False return (_compare_int(self.domain, hostdev.domain) and _compare_int(self.bus, hostdev.bus) and _compare_int(self.slot, hostdev.slot) and _compare_int(self.function, hostdev.function)) class USBDevice(NodeDevice): bus = XMLProperty("./capability/bus") device = XMLProperty("./capability/device") product_name = XMLProperty("./capability/product") product_id = XMLProperty("./capability/product/@id") vendor_name = XMLProperty("./capability/vendor") vendor_id = XMLProperty("./capability/vendor/@id") def pretty_name(self): # Hypervisor may return a rather sparse structure, missing # some ol all stringular descriptions of the device altogether. # Do our best to help user identify the device. # Certain devices pad their vendor with trailing spaces, # such as "LENOVO ". It does not look well. product = str(self.product_name).strip() vendor = str(self.vendor_name).strip() if product == "": product = str(self.product_id) if vendor == "": # No stringular descriptions altogether vendor = str(self.vendor_id) devstr = "%s:%s" % (vendor, product) else: # Only the vendor is known devstr = "%s %s" % (vendor, product) else: if vendor == "": # Sometimes vendor is left out empty, but product is # already descriptive enough or contains the vendor string: # "Lenovo USB Laser Mouse" devstr = product else: # We know everything. Perfect. devstr = "%s %s" % (vendor, product) busstr = "%.3d:%.3d" % (int(self.bus), int(self.device)) desc = "%s %s" % (busstr, devstr) return desc def compare_to_hostdev(self, hostdev): devtype = hostdev.type if devtype == "usb": devtype = "usb_device" if devtype != self.device_type: return False return (_compare_int(self.product_id, hostdev.product) and _compare_int(self.vendor_id, hostdev.vendor) and _compare_int(self.bus, hostdev.bus) and _compare_int(self.device, hostdev.device)) class StorageDevice(NodeDevice): block = XMLProperty("./capability/block") bus = XMLProperty("./capability/bus") drive_type = XMLProperty("./capability/drive_type") size = XMLProperty("./capability/size", is_int=True) model = XMLProperty("./capability/model") vendor = XMLProperty("./capability/vendor") hotpluggable = XMLProperty( "./capability/capability[@type='hotpluggable']", is_bool=True) removable = XMLProperty( "./capability/capability[@type='removable']", is_bool=True) media_size = XMLProperty( "./capability/capability[@type='removable']/media_size", is_int=True) media_label = XMLProperty( "./capability/capability[@type='removable']/media_label") _media_available = XMLProperty( "./capability/capability[@type='removable']/media_available", is_int=True) def _get_media_available(self): m = self._media_available if m is None: return None return bool(m) def _set_media_available(self, val): self._media_available = val media_available = property(_get_media_available, _set_media_available) def pretty_name(self): desc = "" if self.drive_type: desc = self.drive_type if self.block: desc = ": ".join((desc, self.block)) elif self.model: desc = ": ".join((desc, self.model)) else: desc = ": ".join((desc, self.name)) return desc class USBBus(NodeDevice): number = XMLProperty("./capability/number") classval = XMLProperty("./capability/class") subclass = XMLProperty("./capability/subclass") protocol = XMLProperty("./capability/protocol") class SCSIDevice(NodeDevice): host = XMLProperty("./capability/host") bus = XMLProperty("./capability/bus") target = XMLProperty("./capability/target") lun = XMLProperty("./capability/lun") type = XMLProperty("./capability/type") class SCSIBus(NodeDevice): host = XMLProperty("./capability/host") vport_ops = XMLProperty( "./capability/capability[@type='vport_ops']", is_bool=True) fc_host = XMLProperty( "./capability/capability[@type='fc_host']", is_bool=True) wwnn = XMLProperty("./capability/capability[@type='fc_host']/wwnn") wwpn = XMLProperty("./capability/capability[@type='fc_host']/wwpn") class DRMDevice(NodeDevice): drm_type = XMLProperty("./capability/type") def drm_pretty_name(self, conn): parent = NodeDevice.lookupNodedevFromString(conn, self.parent) return "%s (%s)" % (parent.pretty_name(), self.drm_type) def _AddressStringToHostdev(conn, addrstr): from .devicehostdev import VirtualHostDevice hostdev = VirtualHostDevice(conn) try: # Determine addrstr type if addrstr.count(":") in [1, 2] and addrstr.count("."): addrstr, func = addrstr.split(".", 1) addrstr, slot = addrstr.rsplit(":", 1) domain = "0" if addrstr.count(":"): domain, bus = addrstr.split(":", 1) else: bus = addrstr hostdev.type = "pci" hostdev.domain = "0x%.4X" % int(domain, 16) hostdev.function = "0x%.2X" % int(func, 16) hostdev.slot = "0x%.2X" % int(slot, 16) hostdev.bus = "0x%.2X" % int(bus, 16) elif addrstr.count(":"): vendor, product = addrstr.split(":") hostdev.type = "usb" hostdev.vendor = "0x%.4X" % int(vendor, 16) hostdev.product = "0x%.4X" % int(product, 16) elif addrstr.count("."): bus, device = addrstr.split(".", 1) hostdev.type = "usb" hostdev.bus = bus hostdev.device = device else: raise RuntimeError("Unknown address type") except Exception: logging.debug("Error parsing node device string.", exc_info=True) raise return hostdev def _AddressStringToNodedev(conn, addrstr): hostdev = _AddressStringToHostdev(conn, addrstr) # Iterate over node devices and compare count = 0 nodedev = None for xmlobj in conn.fetch_all_nodedevs(): if xmlobj.compare_to_hostdev(hostdev): nodedev = xmlobj count += 1 if count == 1: return nodedev elif count > 1: raise ValueError(_("%s corresponds to multiple node devices") % addrstr) elif count < 1: raise ValueError(_("Did not find a matching node device for '%s'") % addrstr) def _typeToDeviceClass(t): if t == NodeDevice.CAPABILITY_TYPE_SYSTEM: return SystemDevice elif t == NodeDevice.CAPABILITY_TYPE_NET: return NetDevice elif t == NodeDevice.CAPABILITY_TYPE_PCI: return PCIDevice elif t == NodeDevice.CAPABILITY_TYPE_USBDEV: return USBDevice elif t == NodeDevice.CAPABILITY_TYPE_USBBUS: return USBBus elif t == NodeDevice.CAPABILITY_TYPE_STORAGE: return StorageDevice elif t == NodeDevice.CAPABILITY_TYPE_SCSIBUS: return SCSIBus elif t == NodeDevice.CAPABILITY_TYPE_SCSIDEV: return SCSIDevice elif t == NodeDevice.CAPABILITY_TYPE_DRM: return DRMDevice else: return NodeDevice virt-manager-1.5.1/virtinst/domainnumatune.py0000664000175100017510000000611413241024270023051 0ustar crobinsocrobinso00000000000000# # Copyright 2010, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import re from .xmlbuilder import XMLBuilder, XMLProperty def get_phy_cpus(conn): """ Get number of physical CPUs. """ hostinfo = conn.getInfo() pcpus = hostinfo[4] * hostinfo[5] * hostinfo[6] * hostinfo[7] return pcpus class DomainNumatune(XMLBuilder): """ Class for generating XML """ @staticmethod def validate_cpuset(conn, val): if val is None or val == "": return if not isinstance(val, str) or len(val) == 0: raise ValueError(_("cpuset must be string")) if re.match("^[0-9,-^]*$", val) is None: raise ValueError(_("cpuset can only contain numeric, ',', '^', or " "'-' characters")) pcpus = get_phy_cpus(conn) for c in val.split(','): # Redundant commas if not c: continue if "-" in c: (x, y) = c.split('-', 1) x = int(x) y = int(y) if x > y: raise ValueError(_("cpuset contains invalid format.")) if x >= pcpus or y >= pcpus: raise ValueError(_("cpuset's pCPU numbers must be less " "than pCPUs.")) else: if c.startswith("^"): c = c[1:] c = int(c) if c >= pcpus: raise ValueError(_("cpuset's pCPU numbers must be less " "than pCPUs.")) @staticmethod def cpuset_str_to_tuple(conn, cpuset): DomainNumatune.validate_cpuset(conn, cpuset) pinlist = [False] * get_phy_cpus(conn) entries = cpuset.split(",") for e in entries: series = e.split("-", 1) if len(series) == 1: pinlist[int(series[0])] = True continue start = int(series[0]) end = int(series[1]) for i in range(start, end + 1): pinlist[i] = True return tuple(pinlist) MEMORY_MODES = ["interleave", "strict", "preferred"] _XML_ROOT_NAME = "numatune" _XML_PROP_ORDER = ["memory_mode", "memory_nodeset"] memory_nodeset = XMLProperty("./memory/@nodeset") memory_mode = XMLProperty("./memory/@mode") virt-manager-1.5.1/virtinst/domcapabilities.py0000664000175100017510000001236213245573052023173 0ustar crobinsocrobinso00000000000000# # Support for parsing libvirt's domcapabilities XML # # Copyright 2014 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import logging import re from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty class _Value(XMLBuilder): _XML_ROOT_NAME = "value" value = XMLProperty(".") class _HasValues(XMLBuilder): values = XMLChildProperty(_Value) def get_values(self): return [v.value for v in self.values] class _Enum(_HasValues): _XML_ROOT_NAME = "enum" name = XMLProperty("./@name") class _CapsBlock(_HasValues): supported = XMLProperty("./@supported", is_yesno=True) enums = XMLChildProperty(_Enum) def enum_names(self): return [e.name for e in self.enums] def get_enum(self, name): d = dict((e.name, e) for e in self.enums) return d[name] def _make_capsblock(xml_root_name): class TmpClass(_CapsBlock): pass setattr(TmpClass, "_XML_ROOT_NAME", xml_root_name) return TmpClass class _OS(_CapsBlock): _XML_ROOT_NAME = "os" loader = XMLChildProperty(_make_capsblock("loader"), is_single=True) class _Devices(_CapsBlock): _XML_ROOT_NAME = "devices" hostdev = XMLChildProperty(_make_capsblock("hostdev"), is_single=True) disk = XMLChildProperty(_make_capsblock("disk"), is_single=True) class _Features(_CapsBlock): _XML_ROOT_NAME = "features" gic = XMLChildProperty(_make_capsblock("gic"), is_single=True) class DomainCapabilities(XMLBuilder): @staticmethod def build_from_params(conn, emulator, arch, machine, hvtype): xml = None if conn.check_support( conn.SUPPORT_CONN_DOMAIN_CAPABILITIES): try: xml = conn.getDomainCapabilities(emulator, arch, machine, hvtype) except Exception: logging.debug("Error fetching domcapabilities XML", exc_info=True) if not xml: # If not supported, just use a stub object return DomainCapabilities(conn) return DomainCapabilities(conn, parsexml=xml) @staticmethod def build_from_guest(guest): return DomainCapabilities.build_from_params(guest.conn, guest.emulator, guest.os.arch, guest.os.machine, guest.type) # Mapping of UEFI binary names to their associated architectures. We # only use this info to do things automagically for the user, it shouldn't # validate anything the user explicitly enters. _uefi_arch_patterns = { "x86_64": [ ".*OVMF_CODE\.fd", # RHEL ".*ovmf-x64/OVMF.*\.fd", # gerd's firmware repo ".*ovmf-x86_64-.*", # SUSE ".*ovmf.*", ".*OVMF.*", # generic attempt at a catchall ], "aarch64": [ ".*AAVMF_CODE\.fd", # RHEL ".*aarch64/QEMU_EFI.*", # gerd's firmware repo ".*aarch64.*", # generic attempt at a catchall ], } def find_uefi_path_for_arch(self): """ Search the loader paths for one that matches the passed arch """ if not self.arch_can_uefi(): return patterns = self._uefi_arch_patterns.get(self.arch) for pattern in patterns: for path in [v.value for v in self.os.loader.values]: if re.match(pattern, path): return path def label_for_firmware_path(self, path): """ Return a pretty label for passed path, based on if we know about it or not """ if not path: if self.arch in ["i686", "x86_64"]: return _("BIOS") return _("None") for arch, patterns in self._uefi_arch_patterns.items(): for pattern in patterns: if re.match(pattern, path): return (_("UEFI %(arch)s: %(path)s") % {"arch": arch, "path": path}) return _("Custom: %(path)s" % {"path": path}) def arch_can_uefi(self): """ Return True if we know how to setup UEFI for the passed arch """ return self.arch in self._uefi_arch_patterns.keys() def supports_uefi_xml(self): """ Return True if libvirt advertises support for proper UEFI setup """ return ("readonly" in self.os.loader.enum_names() and "yes" in self.os.loader.get_enum("readonly").get_values()) _XML_ROOT_NAME = "domainCapabilities" os = XMLChildProperty(_OS, is_single=True) devices = XMLChildProperty(_Devices, is_single=True) arch = XMLProperty("./arch") features = XMLChildProperty(_Features, is_single=True) virt-manager-1.5.1/virtinst/devicememory.py0000664000175100017510000000343113241024270022514 0ustar crobinsocrobinso00000000000000# # Copyright 2017 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .device import VirtualDevice from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty class VirtualMemoryTarget(XMLBuilder): _XML_ROOT_NAME = "target" size = XMLProperty("./size", is_int=True) node = XMLProperty("./node", is_int=True) label_size = XMLProperty("./label/size", is_int=True) class VirtualMemorySource(XMLBuilder): _XML_ROOT_NAME = "source" pagesize = XMLProperty("./pagesize", is_int=True) nodemask = XMLProperty("./nodemask") path = XMLProperty("./path") class VirtualMemoryDevice(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_MEMORY MODEL_DIMM = "dimm" MODEL_NVDIMM = "nvdimm" models = [MODEL_DIMM, MODEL_NVDIMM] ACCESS_SHARED = "shared" ACCESS_PRIVATE = "private" accesses = [ACCESS_SHARED, ACCESS_PRIVATE] model = XMLProperty("./@model") access = XMLProperty("./@access") source = XMLChildProperty(VirtualMemorySource, is_single=True) target = XMLChildProperty(VirtualMemoryTarget, is_single=True) VirtualMemoryDevice.register_type() virt-manager-1.5.1/virtinst/osxml.py0000664000175100017510000001052513245573052021203 0ustar crobinsocrobinso00000000000000# # Copyright 2010, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .xmlbuilder import XMLBuilder, XMLProperty, XMLChildProperty class _InitArg(XMLBuilder): _XML_ROOT_NAME = "initarg" val = XMLProperty(".") class _BootDevice(XMLBuilder): _XML_ROOT_NAME = "boot" dev = XMLProperty("./@dev") class OSXML(XMLBuilder): """ Class for generating boot device related XML """ BOOT_DEVICE_HARDDISK = "hd" BOOT_DEVICE_CDROM = "cdrom" BOOT_DEVICE_FLOPPY = "fd" BOOT_DEVICE_NETWORK = "network" BOOT_DEVICES = [BOOT_DEVICE_HARDDISK, BOOT_DEVICE_CDROM, BOOT_DEVICE_FLOPPY, BOOT_DEVICE_NETWORK] def is_hvm(self): return self.os_type == "hvm" def is_xenpv(self): return self.os_type in ["xen", "linux"] def is_container(self): return self.os_type == "exe" def is_x86(self): return self.arch == "x86_64" or self.arch == "i686" def is_q35(self): return (self.is_x86() and self.machine and "q35" in self.machine) def is_arm32(self): return self.arch == "armv7l" def is_arm64(self): return self.arch == "aarch64" def is_arm(self): return self.is_arm32() or self.is_arm64() def is_arm_vexpress(self): return self.is_arm() and str(self.machine).startswith("vexpress-") def is_arm_machvirt(self): return self.is_arm() and str(self.machine).startswith("virt") def is_ppc64(self): return self.arch == "ppc64" or self.arch == "ppc64le" def is_pseries(self): return self.is_ppc64() and str(self.machine).startswith("pseries") def is_s390x(self): return self.arch == "s390x" _XML_ROOT_NAME = "os" _XML_PROP_ORDER = ["arch", "os_type", "loader", "loader_ro", "loader_type", "nvram", "nvram_template", "kernel", "initrd", "kernel_args", "dtb", "_bootdevs", "smbios_mode"] def _get_bootorder(self): return [dev.dev for dev in self._bootdevs] def _set_bootorder(self, newdevs): for dev in self._bootdevs: self.remove_child(dev) for d in newdevs: dev = _BootDevice(self.conn) dev.dev = d self.add_child(dev) _bootdevs = XMLChildProperty(_BootDevice) bootorder = property(_get_bootorder, _set_bootorder) initargs = XMLChildProperty(_InitArg) def add_initarg(self, val): obj = _InitArg(self.conn) obj.val = val self.add_child(obj) def set_initargs_string(self, argstring): import shlex for obj in self.initargs: self.remove_child(obj) for val in shlex.split(argstring): self.add_initarg(val) enable_bootmenu = XMLProperty("./bootmenu/@enable", is_yesno=True) useserial = XMLProperty("./bios/@useserial", is_yesno=True) kernel = XMLProperty("./kernel", do_abspath=True) initrd = XMLProperty("./initrd", do_abspath=True) dtb = XMLProperty("./dtb", do_abspath=True) kernel_args = XMLProperty("./cmdline") init = XMLProperty("./init") loader = XMLProperty("./loader") loader_ro = XMLProperty("./loader/@readonly", is_yesno=True) loader_type = XMLProperty("./loader/@type") loader_secure = XMLProperty("./loader/@secure", is_yesno=True) smbios_mode = XMLProperty("./smbios/@mode") nvram = XMLProperty("./nvram", do_abspath=True) nvram_template = XMLProperty("./nvram/@template") arch = XMLProperty("./type/@arch", default_cb=lambda s: s.conn.caps.host.cpu.arch) machine = XMLProperty("./type/@machine") os_type = XMLProperty("./type", default_cb=lambda s: "xen") virt-manager-1.5.1/virtinst/cputune.py0000664000175100017510000000241213245573052021520 0ustar crobinsocrobinso00000000000000# # Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; If not, see . from .xmlbuilder import XMLBuilder, XMLProperty, XMLChildProperty class _VCPUPin(XMLBuilder): """ Class for generating child XML """ _XML_ROOT_NAME = "vcpupin" _XML_PROP_ORDER = ["vcpu", "cpuset"] vcpu = XMLProperty("./@vcpu", is_int=True) cpuset = XMLProperty("./@cpuset") class CPUTune(XMLBuilder): """ Class for generating XML """ _XML_ROOT_NAME = "cputune" vcpus = XMLChildProperty(_VCPUPin) def add_vcpu(self): obj = _VCPUPin(self.conn) self.add_child(obj) return obj virt-manager-1.5.1/virtinst/capabilities.py0000664000175100017510000003146213245573052022475 0ustar crobinsocrobinso00000000000000# # Some code for parsing libvirt's capabilities XML # # Copyright 2007, 2012-2014 Red Hat, Inc. # Mark McLoughlin # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import logging from .cpu import CPU as DomainCPU from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty ################################### # capabilities host parsing # ################################### class _CapsCPU(DomainCPU): arch = XMLProperty("./arch") # capabilities used to just expose these properties as bools _svm_bool = XMLProperty("./features/svm", is_bool=True) _vmx_bool = XMLProperty("./features/vmx", is_bool=True) ############## # Public API # ############## def has_feature(self, name): if name == "svm" and self._svm_bool: return True if name == "vmx" and self._vmx_bool: return True return name in [f.name for f in self.features] ########################### # Caps parsers # ########################### class _CapsTopologyCPU(XMLBuilder): _XML_ROOT_NAME = "cpu" id = XMLProperty("./@id") class _TopologyCell(XMLBuilder): _XML_ROOT_NAME = "cell" cpus = XMLChildProperty(_CapsTopologyCPU, relative_xpath="./cpus") class _CapsTopology(XMLBuilder): _XML_ROOT_NAME = "topology" cells = XMLChildProperty(_TopologyCell, relative_xpath="./cells") ###################################### # Caps and parsers # ###################################### class _CapsSecmodelBaselabel(XMLBuilder): _XML_ROOT_NAME = "baselabel" type = XMLProperty("./@type") content = XMLProperty(".") class _CapsSecmodel(XMLBuilder): _XML_ROOT_NAME = "secmodel" model = XMLProperty("./model") baselabels = XMLChildProperty(_CapsSecmodelBaselabel) class _CapsHost(XMLBuilder): _XML_ROOT_NAME = "host" secmodels = XMLChildProperty(_CapsSecmodel) cpu = XMLChildProperty(_CapsCPU, is_single=True) topology = XMLChildProperty(_CapsTopology, is_single=True) ################################ # and parsers # ################################ class _CapsMachine(XMLBuilder): _XML_ROOT_NAME = "machine" name = XMLProperty(".") canonical = XMLProperty("./@canonical") class _CapsDomain(XMLBuilder): def __init__(self, *args, **kwargs): XMLBuilder.__init__(self, *args, **kwargs) self.machines = [] for m in self._machines: self.machines.append(m.name) if m.canonical: self.machines.append(m.canonical) _XML_ROOT_NAME = "domain" hypervisor_type = XMLProperty("./@type") emulator = XMLProperty("./emulator") _machines = XMLChildProperty(_CapsMachine) class _CapsGuestFeatures(XMLBuilder): _XML_ROOT_NAME = "features" pae = XMLProperty("./pae", is_bool=True) acpi = XMLProperty("./acpi/@default", is_onoff=True) apic = XMLProperty("./apic/@default", is_onoff=True) class _CapsGuest(XMLBuilder): def __init__(self, *args, **kwargs): XMLBuilder.__init__(self, *args, **kwargs) machines = [] for m in self._machines: machines.append(m.name) if m.canonical: machines.append(m.canonical) for d in self.domains: if not d.emulator: d.emulator = self._emulator if not d.machines: d.machines = machines _XML_ROOT_NAME = "guest" os_type = XMLProperty("./os_type") arch = XMLProperty("./arch/@name") loader = XMLProperty("./arch/loader") _emulator = XMLProperty("./arch/emulator") domains = XMLChildProperty(_CapsDomain, relative_xpath="./arch") features = XMLChildProperty(_CapsGuestFeatures, is_single=True) _machines = XMLChildProperty(_CapsMachine, relative_xpath="./arch") ############### # Public APIs # ############### def bestDomainType(self, dtype=None, machine=None): """ Return the recommended domain for use if the user does not explicitly request one. """ domains = [] for d in self.domains: if dtype and d.hypervisor_type != dtype.lower(): continue if machine and machine not in d.machines: continue domains.append(d) if not domains: return None priority = ["kvm", "xen", "qemu"] for t in priority: for d in domains: if d.hypervisor_type == t: return d # Fallback, just return last item in list return domains[-1] def has_install_options(self): """ Return True if there are any install options available """ return bool(len(self.domains) > 0) def is_kvm_available(self): """ Return True if kvm guests can be installed """ if self.os_type != "hvm": return False for d in self.domains: if d.hypervisor_type == "kvm": return True return False def supports_pae(self): """ Return True if capabilities report support for PAE """ return bool(self.features.pae) def supports_acpi(self): """ Return Tree if capabilities report support for ACPI """ return bool(self.features.acpi) def supports_apic(self): """ Return Tree if capabilities report support for APIC """ return bool(self.features.apic) ############################ # Main capabilities object # ############################ class _CapsInfo(object): """ Container object to hold the results of guest_lookup, so users don't need to juggle two objects """ def __init__(self, conn, guest, domain, requested_machine): self.conn = conn self.guest = guest self.domain = domain self._requested_machine = requested_machine self.hypervisor_type = self.domain.hypervisor_type self.os_type = self.guest.os_type self.arch = self.guest.arch self.loader = self.guest.loader self.emulator = self.domain.emulator self.machines = self.domain.machines[:] def get_recommended_machine(self): """ Return the recommended machine type. However, if the user already requested an explicit machine type, via guest_lookup, return that instead. """ if self._requested_machine: return self._requested_machine # For any other HV just let libvirt get us the default, these # are the only ones we've tested. if (not self.conn.is_test() and not self.conn.is_qemu() and not self.conn.is_xen()): return None if self.conn.is_xen() and len(self.machines): return self.machines[0] if (self.arch in ["ppc64", "ppc64le"] and "pseries" in self.machines): return "pseries" if self.arch in ["armv7l", "aarch64"]: if "virt" in self.machines: return "virt" if "vexpress-a15" in self.machines: return "vexpress-a15" if self.arch in ["s390x"]: if "s390-ccw-virtio" in self.machines: return "s390-ccw-virtio" return None class Capabilities(XMLBuilder): def __init__(self, *args, **kwargs): XMLBuilder.__init__(self, *args, **kwargs) self._cpu_models_cache = {} _XML_ROOT_NAME = "capabilities" host = XMLChildProperty(_CapsHost, is_single=True) guests = XMLChildProperty(_CapsGuest) ################### # Private helpers # ################### def _is_xen(self): for g in self.guests: if g.os_type != "xen": continue for d in g.domains: if d.hypervisor_type == "xen": return True return False ############## # Public API # ############## def get_cpu_values(self, arch): if not arch: return [] if not self.conn.check_support(self.conn.SUPPORT_CONN_CPU_MODEL_NAMES): return [] if arch in self._cpu_models_cache: return self._cpu_models_cache[arch] try: names = self.conn.getCPUModelNames(arch, 0) if names == -1: names = [] except Exception as e: logging.debug("Error fetching CPU model names for arch=%s: %s", arch, e) names = [] self._cpu_models_cache[arch] = names return names ############################ # Public XML building APIs # ############################ def _guestForOSType(self, typ=None, arch=None): if self.host is None: return None archs = [arch] if arch is None: archs = [self.host.cpu.arch, None] for a in archs: for g in self.guests: if ((typ is None or g.os_type == typ) and (a is None or g.arch == a)): return g def guest_lookup(self, os_type=None, arch=None, typ=None, machine=None): """ Simple virtualization availability lookup Convenience function for looking up 'Guest' and 'Domain' capabilities objects for the desired virt type. If type, arch, or os_type are none, we return the default virt type associated with those values. These are typically: - os_type : hvm, then xen - typ : kvm over plain qemu - arch : host arch over all others Otherwise the default will be the first listed in the capabilities xml. This function throws C{ValueError}s if any of the requested values are not found. @param typ: Virtualization type ('hvm', 'xen', ...) @param arch: Guest architecture ('x86_64', 'i686' ...) @param os_type: Hypervisor name ('qemu', 'kvm', 'xen', ...) @param machine: Optional machine type to emulate @returns: A _CapsInfo object containing the found guest and domain """ # F22 libxl xen still puts type=linux in the XML, so we need # to handle it for caps lookup if os_type == "linux": os_type = "xen" guest = self._guestForOSType(os_type, arch) if not guest: archstr = _("for arch '%s'") % arch if not arch: archstr = "" osstr = _("virtualization type '%s'") % os_type if not os_type: osstr = _("any virtualization options") raise ValueError(_("Host does not support %(virttype)s %(arch)s") % {'virttype': osstr, 'arch': archstr}) domain = guest.bestDomainType(dtype=typ, machine=machine) if domain is None: machinestr = " with machine '%s'" % machine if not machine: machinestr = "" raise ValueError(_("Host does not support domain type %(domain)s" "%(machine)s for virtualization type " "'%(virttype)s' arch '%(arch)s'") % {'domain': typ, 'virttype': guest.os_type, 'arch': guest.arch, 'machine': machinestr}) capsinfo = _CapsInfo(self.conn, guest, domain, machine) return capsinfo def build_virtinst_guest(self, capsinfo): """ Fill in a new Guest() object from the results of guest_lookup """ from .guest import Guest gobj = Guest(self.conn) gobj.type = capsinfo.hypervisor_type gobj.os.os_type = capsinfo.os_type gobj.os.arch = capsinfo.arch gobj.os.loader = capsinfo.loader gobj.emulator = capsinfo.emulator gobj.os.machine = capsinfo.get_recommended_machine() gobj.capsinfo = capsinfo return gobj def lookup_virtinst_guest(self, *args, **kwargs): """ Call guest_lookup and pass the results to build_virtinst_guest. This is a shortcut for API users that don't need to do anything with the output from guest_lookup """ capsinfo = self.guest_lookup(*args, **kwargs) return self.build_virtinst_guest(capsinfo) virt-manager-1.5.1/virtinst/pm.py0000664000175100017510000000201313241024270020433 0ustar crobinsocrobinso00000000000000# # Copyright 2014 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .xmlbuilder import XMLBuilder, XMLProperty class PM(XMLBuilder): _XML_ROOT_NAME = "pm" suspend_to_mem = XMLProperty("./suspend-to-mem/@enabled", is_yesno=True) suspend_to_disk = XMLProperty("./suspend-to-disk/@enabled", is_yesno=True) virt-manager-1.5.1/virtinst/distroinstaller.py0000664000175100017510000002204013245061760023254 0ustar crobinsocrobinso00000000000000# # Copyright 2006-2009, 2013, 2014 Red Hat, Inc. # Daniel P. Berrange # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import logging import os from . import urlfetcher from . import util from .devicedisk import VirtualDisk from .initrdinject import perform_initrd_injections from .kernelupload import upload_kernel_initrd from .installer import Installer from .osdict import OSDB def _is_url(conn, url): """ Check if passed string is a (pseudo) valid http, ftp, or nfs url. """ if not conn.is_remote() and os.path.exists(url): return os.path.isdir(url) return (url.startswith("http://") or url.startswith("https://") or url.startswith("ftp://") or url.startswith("nfs:")) def _sanitize_url(url): """ Do nothing for http or ftp, but make sure nfs is in the expected format """ if url.startswith("nfs://"): # Convert RFC compliant NFS nfs://server/path/to/distro # to what mount/anaconda expect nfs:server:/path/to/distro # and carry the latter form around internally url = "nfs:" + url[6:] # If we need to add the : after the server index = url.find("/", 4) if index == -1: raise ValueError(_("Invalid NFS format: No path specified.")) if url[index - 1] != ":": url = url[:index] + ":" + url[index:] return url # Enum of the various install media types we can have (MEDIA_LOCATION_DIR, MEDIA_LOCATION_CDROM, MEDIA_LOCATION_URL, MEDIA_CDROM_PATH, MEDIA_CDROM_URL, MEDIA_CDROM_IMPLIED) = range(1, 7) class DistroInstaller(Installer): def __init__(self, *args, **kwargs): Installer.__init__(self, *args, **kwargs) self.livecd = False self._cached_fetcher = None self._cached_store = None self._cdrom_path = None ######################## # Install preparations # ######################## def _get_media_type(self): if self.cdrom and not self.location: # CDROM install requested from a disk already attached to VM return MEDIA_CDROM_IMPLIED if self.location and _is_url(self.conn, self.location): return self.cdrom and MEDIA_CDROM_URL or MEDIA_LOCATION_URL if self.cdrom: return MEDIA_CDROM_PATH if self.location and os.path.isdir(self.location): return MEDIA_LOCATION_DIR return MEDIA_LOCATION_CDROM def _get_fetcher(self, guest, meter): meter = util.ensure_meter(meter) if not self._cached_fetcher: scratchdir = util.make_scratchdir(guest.conn, guest.type) self._cached_fetcher = urlfetcher.fetcherForURI( self.location, scratchdir, meter) self._cached_fetcher.meter = meter return self._cached_fetcher def _get_store(self, guest, fetcher): # Caller is responsible for calling fetcher prepare/cleanup if needed if not self._cached_store: self._cached_store = urlfetcher.getDistroStore(guest, fetcher) return self._cached_store def _prepare_local(self): return self.location def _prepare_cdrom_url(self, guest, fetcher): store = self._get_store(guest, fetcher) media = store.acquireBootDisk(guest) self._tmpfiles.append(media) return media def _prepare_kernel_url(self, guest, fetcher): store = self._get_store(guest, fetcher) kernel, initrd, args = store.acquireKernel(guest) self._tmpfiles.append(kernel) if initrd: self._tmpfiles.append(initrd) perform_initrd_injections(initrd, self.initrd_injections, fetcher.scratchdir) kernel, initrd, tmpvols = upload_kernel_initrd( guest.conn, fetcher.scratchdir, util.get_system_scratchdir(guest.type), fetcher.meter, kernel, initrd) self._tmpvols += tmpvols self._install_kernel = kernel self._install_initrd = initrd if args: self.extraargs.append(args) ########################### # Private installer impls # ########################### def _get_bootdev(self, isinstall, guest): mediatype = self._get_media_type() local = mediatype in [MEDIA_CDROM_PATH, MEDIA_CDROM_IMPLIED, MEDIA_LOCATION_DIR, MEDIA_LOCATION_CDROM] persistent_cd = (local and self.cdrom and self.livecd) if isinstall or persistent_cd: bootdev = "cdrom" else: bootdev = "hd" return bootdev def _validate_location(self, val): """ Valid values for location: 1) it can be a local file (ex. boot.iso), directory (ex. distro tree) or physical device (ex. cdrom media) 2) http, ftp, or nfs path for an install tree """ self._cached_store = None self._cached_fetcher = None if _is_url(self.conn, val): logging.debug("DistroInstaller location is a network source.") return _sanitize_url(val) try: dev = VirtualDisk(self.conn) dev.device = dev.DEVICE_CDROM dev.path = val dev.validate() val = dev.path except Exception as e: logging.debug("Error validating install location", exc_info=True) raise ValueError(_("Validating install media '%s' failed: %s") % (str(val), e)) return val def _prepare(self, guest, meter): mediatype = self._get_media_type() if mediatype == MEDIA_CDROM_IMPLIED: return cdrom_path = None if mediatype == MEDIA_CDROM_PATH or mediatype == MEDIA_LOCATION_CDROM: cdrom_path = self.location if mediatype != MEDIA_CDROM_PATH: fetcher = self._get_fetcher(guest, meter) try: try: fetcher.prepareLocation() except ValueError as e: logging.debug("Error preparing install location", exc_info=True) raise ValueError(_("Invalid install location: ") + str(e)) if mediatype == MEDIA_CDROM_URL: cdrom_path = self._prepare_cdrom_url(guest, fetcher) else: self._prepare_kernel_url(guest, fetcher) finally: fetcher.cleanupLocation() self._cdrom_path = cdrom_path ########################## # Public installer impls # ########################## def has_install_phase(self): return not self.livecd def needs_cdrom(self): mediatype = self._get_media_type() return mediatype in [MEDIA_CDROM_PATH, MEDIA_LOCATION_CDROM, MEDIA_CDROM_URL] def cdrom_path(self): return self._cdrom_path def scratchdir_required(self): mediatype = self._get_media_type() return mediatype in [MEDIA_CDROM_URL, MEDIA_LOCATION_URL, MEDIA_LOCATION_DIR, MEDIA_LOCATION_CDROM] def check_location(self, guest): mediatype = self._get_media_type() if mediatype not in [MEDIA_CDROM_URL, MEDIA_LOCATION_URL]: return True try: fetcher = self._get_fetcher(guest, None) fetcher.prepareLocation() # This will throw an error for us ignore = self._get_store(guest, fetcher) finally: fetcher.cleanupLocation() return True def detect_distro(self, guest): distro = None try: if _is_url(self.conn, self.location): try: fetcher = self._get_fetcher(guest, None) fetcher.prepareLocation() store = self._get_store(guest, fetcher) distro = store.get_osdict_info() finally: fetcher.cleanupLocation() elif self.conn.is_remote(): logging.debug("Can't detect distro for media on " "remote connection.") else: distro = OSDB.lookup_os_by_media(self.location) except Exception: logging.debug("Error attempting to detect distro.", exc_info=True) logging.debug("installer.detect_distro returned=%s", distro) return distro virt-manager-1.5.1/virtinst/devicecontroller.py0000664000175100017510000000763613245061760023413 0ustar crobinsocrobinso00000000000000# # Copyright 2010, 2013, 2014 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .device import VirtualDevice from .xmlbuilder import XMLProperty class VirtualController(VirtualDevice): virtual_device_type = VirtualDevice.VIRTUAL_DEV_CONTROLLER TYPE_IDE = "ide" TYPE_FDC = "fdc" TYPE_SCSI = "scsi" TYPE_SATA = "sata" TYPE_VIRTIOSERIAL = "virtio-serial" TYPE_USB = "usb" TYPE_PCI = "pci" TYPE_CCID = "ccid" TYPES = [TYPE_IDE, TYPE_FDC, TYPE_SCSI, TYPE_SATA, TYPE_VIRTIOSERIAL, TYPE_USB, TYPE_PCI, TYPE_CCID] @staticmethod def pretty_type(ctype): pretty_mappings = { VirtualController.TYPE_IDE: "IDE", VirtualController.TYPE_FDC: _("Floppy"), VirtualController.TYPE_SCSI: "SCSI", VirtualController.TYPE_SATA: "SATA", VirtualController.TYPE_VIRTIOSERIAL: "VirtIO Serial", VirtualController.TYPE_USB: "USB", VirtualController.TYPE_PCI: "PCI", VirtualController.TYPE_CCID: "CCID", } if ctype not in pretty_mappings: return ctype return pretty_mappings[ctype] @staticmethod def get_usb2_controllers(conn): ret = [] ctrl = VirtualController(conn) ctrl.type = "usb" ctrl.model = "ich9-ehci1" ret.append(ctrl) ctrl = VirtualController(conn) ctrl.type = "usb" ctrl.model = "ich9-uhci1" ctrl.master_startport = 0 ret.append(ctrl) ctrl = VirtualController(conn) ctrl.type = "usb" ctrl.model = "ich9-uhci2" ctrl.master_startport = 2 ret.append(ctrl) ctrl = VirtualController(conn) ctrl.type = "usb" ctrl.model = "ich9-uhci3" ctrl.master_startport = 4 ret.append(ctrl) return ret @staticmethod def get_usb3_controller(conn, guest): ctrl = VirtualController(conn) ctrl.type = "usb" ctrl.model = "nec-xhci" if ((guest.os.is_arm_machvirt() or guest.os.is_pseries()) and conn.check_support(conn.SUPPORT_CONN_QEMU_XHCI)): ctrl.model = "qemu-xhci" if conn.check_support(conn.SUPPORT_CONN_USB3_PORTS): ctrl.ports = 8 return ctrl _XML_PROP_ORDER = ["type", "index", "model", "master_startport"] type = XMLProperty("./@type") model = XMLProperty("./@model") vectors = XMLProperty("./@vectors", is_int=True) ports = XMLProperty("./@ports", is_int=True) master_startport = XMLProperty("./master/@startport", is_int=True) index = XMLProperty("./@index", is_int=True, default_cb=lambda s: 0) def pretty_desc(self): ret = self.pretty_type(self.type) if self.type == "scsi": if self.model == "virtio-scsi": ret = "Virtio " + ret elif self.address.type == "spapr-vio": ret = "sPAPR " + ret if self.type == "pci" and self.model == "pcie-root": ret = "PCIe" return ret VirtualController.register_type() virt-manager-1.5.1/virtinst/device.py0000664000175100017510000001656213245573052021307 0ustar crobinsocrobinso00000000000000# # Base class for all VM devices # # Copyright 2008, 2013 Red Hat, Inc. # Cole Robinson # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. from .xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty class VirtualDeviceAlias(XMLBuilder): _XML_ROOT_NAME = "alias" name = XMLProperty("./@name") class VirtualDeviceBoot(XMLBuilder): _XML_ROOT_NAME = "boot" order = XMLProperty("./@order", is_int=True) class VirtualDeviceAddress(XMLBuilder): """ Examples:
""" ADDRESS_TYPE_PCI = "pci" ADDRESS_TYPE_DRIVE = "drive" ADDRESS_TYPE_VIRTIO_SERIAL = "virtio-serial" ADDRESS_TYPE_CCID = "ccid" ADDRESS_TYPE_SPAPR_VIO = "spapr-vio" TYPES = [ADDRESS_TYPE_PCI, ADDRESS_TYPE_DRIVE, ADDRESS_TYPE_VIRTIO_SERIAL, ADDRESS_TYPE_CCID, ADDRESS_TYPE_SPAPR_VIO] _XML_ROOT_NAME = "address" _XML_PROP_ORDER = ["type", "domain", "controller", "bus", "slot", "function", "target", "unit", "multifunction"] def set_addrstr(self, addrstr): if addrstr is None: return if addrstr.count(":") in [1, 2] and addrstr.count("."): self.type = self.ADDRESS_TYPE_PCI addrstr, self.function = addrstr.split(".", 1) addrstr, self.slot = addrstr.rsplit(":", 1) self.domain = "0" if addrstr.count(":"): self.domain, self.bus = addrstr.split(":", 1) elif addrstr == "spapr-vio": self.type = self.ADDRESS_TYPE_SPAPR_VIO else: raise ValueError(_("Could not determine or unsupported " "format of '%s'") % addrstr) def pretty_desc(self): pretty_desc = None if self.type == self.ADDRESS_TYPE_DRIVE: pretty_desc = _("%s:%s:%s:%s" % (self.controller, self.bus, self.target, self.unit)) return pretty_desc def compare_controller(self, controller, dev_bus): if (controller.type == dev_bus and controller.index == self.controller): return True return False type = XMLProperty("./@type") # type=pci domain = XMLProperty("./@domain", is_int=True) bus = XMLProperty("./@bus", is_int=True) slot = XMLProperty("./@slot", is_int=True) function = XMLProperty("./@function", is_int=True) multifunction = XMLProperty("./@multifunction", is_onoff=True) # type=drive controller = XMLProperty("./@controller", is_int=True) unit = XMLProperty("./@unit", is_int=True) port = XMLProperty("./@port", is_int=True) target = XMLProperty("./@target", is_int=True) # type=spapr-vio reg = XMLProperty("./@reg") # type=ccw cssid = XMLProperty("./@cssid") ssid = XMLProperty("./@ssid") devno = XMLProperty("./@devno") # type=isa iobase = XMLProperty("./@iobase") irq = XMLProperty("./@irq") # type=dimm base = XMLProperty("./@base") class VirtualDevice(XMLBuilder): """ Base class for all domain xml device objects. """ VIRTUAL_DEV_DISK = "disk" VIRTUAL_DEV_NET = "interface" VIRTUAL_DEV_INPUT = "input" VIRTUAL_DEV_GRAPHICS = "graphics" VIRTUAL_DEV_AUDIO = "sound" VIRTUAL_DEV_HOSTDEV = "hostdev" VIRTUAL_DEV_SERIAL = "serial" VIRTUAL_DEV_PARALLEL = "parallel" VIRTUAL_DEV_CHANNEL = "channel" VIRTUAL_DEV_CONSOLE = "console" VIRTUAL_DEV_VIDEO = "video" VIRTUAL_DEV_CONTROLLER = "controller" VIRTUAL_DEV_WATCHDOG = "watchdog" VIRTUAL_DEV_FILESYSTEM = "filesystem" VIRTUAL_DEV_SMARTCARD = "smartcard" VIRTUAL_DEV_REDIRDEV = "redirdev" VIRTUAL_DEV_MEMBALLOON = "memballoon" VIRTUAL_DEV_TPM = "tpm" VIRTUAL_DEV_RNG = "rng" VIRTUAL_DEV_PANIC = "panic" VIRTUAL_DEV_MEMORY = "memory" # Ordering in this list is important: it will be the order the # Guest class outputs XML. So changing this may upset the test suite virtual_device_types = [VIRTUAL_DEV_DISK, VIRTUAL_DEV_CONTROLLER, VIRTUAL_DEV_FILESYSTEM, VIRTUAL_DEV_NET, VIRTUAL_DEV_INPUT, VIRTUAL_DEV_GRAPHICS, VIRTUAL_DEV_SERIAL, VIRTUAL_DEV_PARALLEL, VIRTUAL_DEV_CONSOLE, VIRTUAL_DEV_CHANNEL, VIRTUAL_DEV_AUDIO, VIRTUAL_DEV_VIDEO, VIRTUAL_DEV_HOSTDEV, VIRTUAL_DEV_WATCHDOG, VIRTUAL_DEV_SMARTCARD, VIRTUAL_DEV_REDIRDEV, VIRTUAL_DEV_MEMBALLOON, VIRTUAL_DEV_TPM, VIRTUAL_DEV_RNG, VIRTUAL_DEV_PANIC, VIRTUAL_DEV_MEMORY] virtual_device_classes = {} @classmethod def register_type(cls): cls._XML_ROOT_NAME = cls.virtual_device_type VirtualDevice.virtual_device_classes[cls.virtual_device_type] = cls # General device type (disk, interface, etc.) virtual_device_type = None def __init__(self, *args, **kwargs): """ Initialize device state @param conn: libvirt connection to validate device against """ XMLBuilder.__init__(self, *args, **kwargs) self._XML_PROP_ORDER = self._XML_PROP_ORDER + ["alias", "address"] if not self.virtual_device_type: raise ValueError(_("Virtual device type must be set in subclass.")) if self.virtual_device_type not in self.virtual_device_types: raise ValueError(_("Unknown virtual device type '%s'.") % self.virtual_device_type) alias = XMLChildProperty(VirtualDeviceAlias, is_single=True) address = XMLChildProperty(VirtualDeviceAddress, is_single=True) boot = XMLChildProperty(VirtualDeviceBoot, is_single=True) def setup(self, meter=None): """ Perform potentially hazardous device initialization, like storage creation or host device reset @param meter: Optional progress meter to use """ # Will be overwritten by subclasses if necessary. ignore = meter return virt-manager-1.5.1/virt-clone0000775000175100017510000002004213245573052017610 0ustar crobinsocrobinso00000000000000#!/usr/bin/env python2 # # Copyright(c) FUJITSU Limited 2007. # # Script to set up an cloning guest configuration and kick off an cloning # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import argparse import logging import sys import virtinst.cli as cli from virtinst import Cloner from virtinst.cli import fail, print_stdout, print_stderr # General input gathering functions def get_clone_name(new_name, auto_clone, design): if not new_name and auto_clone: # Generate a name to use new_name = design.generate_clone_name() logging.debug("Auto-generated clone name '%s'", new_name) if not new_name: fail(_("A name is required for the new virtual machine," " use '--name NEW_VM_NAME' to specify one.")) design.clone_name = new_name def get_original_guest(guest_name, origfile, design): origxml = None if origfile: f = open(origfile, "r") origxml = f.read() f.close() try: design.original_xml = origxml return except (ValueError, RuntimeError) as e: fail(e) if not guest_name: fail(_("An original machine name is required," " use '--original ORIGINAL_GUEST' and try again.")) design.original_guest = guest_name def get_clone_macaddr(new_mac, design): if new_mac is None or new_mac[0] == "RANDOM": return design.clone_macs = new_mac def get_clone_diskfile(new_diskfiles, design, preserve, auto_clone): if new_diskfiles is None: new_diskfiles = [None] newidx = 0 clonepaths = [] for origpath in [d.path for d in design.original_disks]: if len(new_diskfiles) <= newidx: # Extend the new/passed paths list with None if it's not # long enough new_diskfiles.append(None) newpath = new_diskfiles[newidx] if newpath is None and auto_clone: newpath = design.generate_clone_disk_path(origpath) if origpath is None: newpath = None clonepaths.append(newpath) newidx += 1 design.clone_paths = clonepaths for disk in design.clone_disks: cli.validate_disk(disk, warn_overwrite=not preserve) def parse_args(): desc = _("Duplicate a virtual machine, changing all the unique " "host side configuration like MAC address, name, etc. \n\n" "The VM contents are NOT altered: virt-clone does not change " "anything _inside_ the guest OS, it only duplicates disks and " "does host side changes. So things like changing passwords, " "changing static IP address, etc are outside the scope of " "this tool. For these types of changes, please see virt-sysprep(1).") parser = cli.setupParser("%(prog)s --original [NAME] ...", desc) cli.add_connect_option(parser) geng = parser.add_argument_group(_("General Options")) geng.add_argument("-o", "--original", dest="original_guest", help=_("Name of the original guest; " "The status must be shut off or paused.")) geng.add_argument("--original-xml", help=_("XML file to use as the original guest.")) geng.add_argument("--auto-clone", action="store_true", help=_("Auto generate clone name and storage paths from" " the original guest configuration.")) geng.add_argument("-n", "--name", dest="new_name", help=_("Name for the new guest")) geng.add_argument("-u", "--uuid", dest="new_uuid", help=argparse.SUPPRESS) geng.add_argument("--reflink", action="store_true", dest="reflink", help=_("use btrfs COW lightweight copy")) stog = parser.add_argument_group(_("Storage Configuration")) stog.add_argument("-f", "--file", dest="new_diskfile", action="append", help=_("New file to use as the disk image for the " "new guest")) stog.add_argument("--force-copy", dest="target", action="append", help=_("Force to copy devices (eg, if 'hdc' is a " "readonly cdrom device, --force-copy=hdc)")) stog.add_argument("--nonsparse", action="store_false", dest="sparse", default=True, help=_("Do not use a sparse file for the clone's " "disk image")) stog.add_argument("--preserve-data", action="store_false", dest="preserve", default=True, help=_("Do not clone storage, new disk images specified " "via --file are preserved unchanged")) stog.add_argument("--nvram", dest="new_nvram", help=_("New file to use as storage for nvram VARS")) netg = parser.add_argument_group(_("Networking Configuration")) netg.add_argument("-m", "--mac", dest="new_mac", action="append", help=_("New fixed MAC address for the clone guest. " "Default is a randomly generated MAC")) misc = parser.add_argument_group(_("Miscellaneous Options")) # Just used for clone tests misc.add_argument("--clone-running", action="store_true", default=False, help=argparse.SUPPRESS) cli.add_misc_options(misc, prompt=True, replace=True, printxml=True) return parser.parse_args() def main(conn=None): cli.earlyLogging() options = parse_args() options.quiet = options.quiet or options.xmlonly cli.setupLogging("virt-clone", options.debug, options.quiet) cli.convert_old_force(options) cli.parse_check(options.check) cli.set_prompt(options.prompt) if conn is None: conn = cli.getConnection(options.connect) if (options.new_diskfile is None and options.auto_clone is False and options.xmlonly is False): fail(_("Either --auto-clone or --file is required," " use '--auto-clone or --file' and try again.")) design = Cloner(conn) design.clone_running = options.clone_running design.replace = bool(options.replace) get_original_guest(options.original_guest, options.original_xml, design) get_clone_name(options.new_name, options.auto_clone, design) get_clone_macaddr(options.new_mac, design) if options.new_uuid is not None: design.clone_uuid = options.new_uuid if options.reflink is True: design.reflink = True for i in options.target or []: design.force_target = i design.clone_sparse = options.sparse design.preserve = options.preserve design.clone_nvram = options.new_nvram # This determines the devices that need to be cloned, so that # get_clone_diskfile knows how many new disk paths it needs design.setup_original() get_clone_diskfile(options.new_diskfile, design, not options.preserve, options.auto_clone) # setup design object design.setup_clone() if options.xmlonly: print_stdout(design.clone_xml, do_force=True) else: design.start_duplicate(cli.get_meter()) print_stdout("") print_stdout(_("Clone '%s' created successfully.") % design.clone_name) logging.debug("end clone") return 0 if __name__ == "__main__": try: sys.exit(main()) except SystemExit as sys_e: sys.exit(sys_e.code) except KeyboardInterrupt: print_stderr(_("Installation aborted at user request")) except Exception as main_e: fail(main_e) virt-manager-1.5.1/COPYING0000664000175100017510000004310312574335131016634 0ustar crobinsocrobinso00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. virt-manager-1.5.1/virtcli/0000775000175100017510000000000013245574323017260 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/virtcli/__init__.py0000664000175100017510000000011213240655316021360 0ustar crobinsocrobinso00000000000000# Copyright (C) 2013-2015 Red Hat, Inc. from .cliconfig import CLIConfig virt-manager-1.5.1/virtcli/cliconfig.py0000664000175100017510000000741713245573253021601 0ustar crobinsocrobinso00000000000000# # Copyright (C) 2013, 2014 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. # """ Configuration variables that can be set at build time """ import ConfigParser import os _cfg = ConfigParser.ConfigParser() _filepath = os.path.abspath(__file__) _srcdir = os.path.abspath(os.path.join(os.path.dirname(_filepath), "..")) _cfgpath = os.path.join(os.path.dirname(_filepath), "cli.cfg") if os.path.exists(_cfgpath): _cfg.read(_cfgpath) _istest = "VIRTINST_TEST_SUITE" in os.environ _running_from_srcdir = os.path.exists( os.path.join(_srcdir, "tests", "clitest.py")) def _split_list(commastr): return [d for d in commastr.split(",") if d] def _get_param(name, default): if _istest: return default try: return _cfg.get("config", name) except (ConfigParser.NoOptionError, ConfigParser.NoSectionError): return default def _setup_gsettings_path(schemadir): """ If running from the virt-manager.git srcdir, compile our gsettings schema and use it directly """ import subprocess from distutils.spawn import find_executable exe = find_executable("glib-compile-schemas") if not exe: raise RuntimeError("You must install glib-compile-schemas to run " "virt-manager from git.") ret = subprocess.call([exe, "--strict", schemadir]) if ret != 0: raise RuntimeError("Failed to compile local gsettings schemas") __version__ = "1.5.1" class _CLIConfig(object): def __init__(self): self.cfgpath = _cfgpath self.version = __version__ self.default_qemu_user = _get_param("default_qemu_user", "root") self.stable_defaults = bool(int(_get_param("stable_defaults", "0"))) self.preferred_distros = _split_list( _get_param("preferred_distros", "")) self.hv_packages = _split_list(_get_param("hv_packages", "")) self.askpass_package = _split_list(_get_param("askpass_packages", "")) self.libvirt_packages = _split_list(_get_param("libvirt_packages", "")) self.default_graphics = _get_param("default_graphics", "spice") self.default_hvs = _split_list(_get_param("default_hvs", "")) self.prefix = None self.gettext_dir = None self.ui_dir = None self.icon_dir = None self.gsettings_dir = None self.set_paths_by_prefix(_get_param("prefix", "/usr"), check_source_dir=True) def set_paths_by_prefix(self, prefix, check_source_dir=False): self.prefix = prefix self.gettext_dir = os.path.join(prefix, "share", "locale") if _running_from_srcdir and check_source_dir: self.ui_dir = os.path.join(_srcdir, "ui") self.icon_dir = os.path.join(_srcdir, "data") self.gsettings_dir = self.icon_dir _setup_gsettings_path(self.gsettings_dir) else: self.ui_dir = os.path.join(prefix, "share", "virt-manager", "ui") self.icon_dir = os.path.join(prefix, "share", "virt-manager", "icons") self.gsettings_dir = os.path.join(prefix, "share", "glib-2.0", "schemas") CLIConfig = _CLIConfig() virt-manager-1.5.1/data/0000775000175100017510000000000013245574323016515 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/org.virt-manager.virt-manager.gschema.xml0000664000175100017510000003205413240655316026423 0ustar crobinsocrobinso00000000000000 (-1, -1) VM window dimensions VM window dimensions -1 When to scale the VM graphical console When to scale the VM graphical console. -1 = global default, 0 = never, 1 = only when in full screen mode, 2 = Always ("", -1) Username and secrets ID for graphical password Username and secrets ID for graphical password -1 Automatically resize guest when window size changes Automatically change guest resolution along with virt-manager window. Only works with spice with a vdagent set up. -1 = global default, 0 = off, 1 = on. '' Custom connection description Custom connection description, used in the manager window. If empty, the app generates a default on demand. false Show system tray icon Show system tray icon while app is running 0 Default manager window height Default manager window height 0 Default manager window width Default manager window width [] Libvirt URIs listed in the manager window Libvirt URIs listed in the manager window [] Libvirt URIs to connect to on app startup Libvirt URIs to connect to on app startup false Show disk I/O in summary Show the disk I/O field in the domain list summary view false Show network I/O in summary Show the network I/O field in the domain list summary view true Show guest cpu usage in summary Show the guest cpu usage field in the domain list summary view false Show host cpu usage in summary Show the host cpu usage field in the domain list summary view false Show memory usage in summary Show memory usage field in the domain list summary view 3 The statistics update interval The statistics update interval in seconds true Poll VM CPU stats Whether or not the app will poll VM CPU statistics false Poll disk i/o stats Whether or not the app will poll VM disk i/o statistics false Poll net i/o stats Whether or not the app will poll VM network i/o statistics false Poll memory stats Whether or not the app will poll VM memory statistics [] Saved list of source URLs Saved list of source URLs used to bootstrap OS containers [] Saved list of install URLs Saved list of install URLs [] Saved list of install ISOs Saved list of install ISOs [] Saved list of install kickstarts Saved list of install kickstarts false Enable menu accelerators in console window Whether to enable menu accelerators while connected to the guest graphical console. 1 When to scale the VM graphical console When to scale the VM graphical console. 0 = never, 1 = only when in full screen mode, 2 = Always -1 Automatically resize guest when window size changes Automatically change guest resolution along with virt-manager window. Only works with spice with a vdagent set up. -1 = global default, 0 = off, 1 = on. '' Grab keyboard sequence for the graphical console Grab keyboard sequence for the graphical console true Enable grab keyboard when active and focused Enable grab keyboard when active and focused true Enable SPICE Auto USB redirection in console window Whether to enable SPICE Auto USB redirection while connected to the guest console. true Whether to show VM button toolbar in Details display Whether to show toolbar containing Virtual Machine action buttons (such as Run, Pause, Shutdown) in the details display true Install sound device for new Vms Whether to install a sound device for new VMs 'system' Install selected graphics type for new VM Install selected graphics type for new VM. vnc or spice, system for software configured default 'system' Add spice usbredir HW for new VMs Add spice usbredir HW for new VMs. yes, no, or system for software configured default 'default' Use selected format for new VM storage Use selected format when creating new disk images in new VM wizard 'default' CPU setting to use for new VMs CPU setting to use for new VMs. Limited to VMs matching the host architecture. Possible values: default (virt-manager default), hv-default (qemu's default), host-model-only (just the model, not the additional features), host-model (libvirt's host-model setting). '' Default image path Default path for choosing VM images '' Default media path Default path for choosing media '' Default screenshot path Default path for saving screenshots from VMs [] Ask about fixing permissions Whether to ask about fixing path permissions true Confirm force poweroff request Whether we require confirmation to forcepoweroff a VM false Confirm poweroff request Whether we require confirmation to poweroff/reboot a VM false Confirm pause request Whether we require confirmation to pause a VM true Confirm device removal request Whether we require confirmation to remove a virtual device true Confirm device interface start and stop Whether we require confirmation to start or stop a libvirt virtual interface true Confirm about unapplied device changes Whether we ask the user to apply or discard unapplied device changes true Confirm deleting storage Whether we require a confirmation on deleting storage virt-manager-1.5.1/data/virt-manager.appdata.xml.in0000664000175100017510000000303213240655316023644 0ustar crobinsocrobinso00000000000000 virt-manager.desktop CC0-1.0 GPL-2.0+ <_name>Virtual Machine Manager <_summary>Graphically manage KVM, Xen, or LXC via libvirt <_p> Virtual Machine Manager provides a graphical tool for administering virtual machines for KVM, Xen, and LXC. Start, stop, add or remove virtual devices, connect to a graphical or serial console, and see resource usage statistics for existing VMs on local or remote machines. Uses libvirt as the backend management API. http://virt-manager.org/appdata/en_US/manager.png <_caption>Main manager window http://virt-manager.org/appdata/en_US/details.png <_caption>Virtual machine configuration screen http://virt-manager.org/appdata/en_US/console.png <_caption>Graphical console connection for a virtual machine http://www.virt-manager.org/ https://bugzilla.redhat.com/enter_bug.cgi?product=Virtualization%20Tools&component=virt-manager virt-tools-list@redhat.com virt-manager virt-manager-1.5.1/data/hicolor/0000775000175100017510000000000013245574323020154 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/16x16/0000775000175100017510000000000013245574323020741 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/16x16/actions/0000775000175100017510000000000013245574323022401 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/16x16/actions/vm_new.png0000664000175100017510000000127612574335131024404 0ustar crobinsocrobinso00000000000000‰PNG  IHDRóÿatEXtSoftwareAdobe ImageReadyqÉe<`IDATxÚœSMhQþÞîB’f‘ÚF¼ÔBQh„‚Á›-­ õ "¶"xë)J¼„F…Òž½››žŒ‡*ÔCPT µzšÓümÌf÷ý8ïmRRˆ˜}³óf¾÷ͼyL)… c̬•¯Ö@Èl’^=wÚïd³Ùû‘¦À¤BÆhÑ–NÝý˜€c‡d OVôöpm+µ^þlQ k#“ÉxB õ7Ýßt•÷”vkXR¥O1é„a˜äœcîæƒ%<[8¢$Ø€½–ï2àè¤T¸6{Élp.èÔäIlì‡;4†‘©TWT¢R õíqŠóÐ ørJ´~·áwÁ„”8ö *6dé1˜} ’— €PšO {•£À´}\”÷kð L3êt<2:ê¯!ò×Qß7$ÜS?©14<–fà€¤kµMõ†‡©–â6î.ßÀÞ—1ÜËÍãNvåͨÆÞSžŒJè€@ÉA0È­¾Àë7ëBëé+Í»•¹ŠçBêS§ç”Ôƒoßw¢&™ò¯ ¦ûtß°˜ H7¶'§[Ðu¯¿°$¹Mçj0ˆä0ŠÏw7w&|%UÏÅœÝtRë믘eÕ%£ÒÁÁw–Ëé²eÕSíVó1°VÐyæÉ¤ôë á{Þµ¡NÍ¥™—¯ßØLâh·[ñÏ([{ñüH¥­Ÿ~Ç]) *p#ŸàÎñ²–»åÒx“…Òþ—½¡¬ªòtZi¸ng¤Õ:Rt]ã–emûA—Gq²õÃ^­Vôú™™Jùz¥8¡¦Šù=YWF¼èu<ÿÒå‹é}kXÓ²"ŽúÅ¥EßsÝq»a Îð„€ëzOß[ŸE„É…Ùj1ŸWzßÝÜü)Ž´ ËË" ‚ã­ímõŒ1Q1 C ÃÞmMÓ8™¦‰Z­Fssó_A8û×IˆöÑ´Hô¡!€)BZ¡?.Ôjµ:ÑO È'Xà¿y`šfLÿ¿L¿qêׇÀ~êIEND®B`‚virt-manager-1.5.1/data/hicolor/24x24/0000775000175100017510000000000013245574323020737 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/24x24/actions/0000775000175100017510000000000013245574323022377 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/24x24/actions/vm_new.png0000664000175100017510000000227412574335131024401 0ustar crobinsocrobinso00000000000000‰PNG  IHDRàw=øtEXtSoftwareAdobe ImageReadyqÉe<^IDATxÚ¬UKoEþz^»ëgvñ#8ÚÅJÀŽ£$ âÀ%Š„Rà8 7¸‘ ”µ@A(HøŒ€ó ’ ’²P"EQü¶É®½/ïÎL?†êžÙ+›`PjÕêÙîêú¾ª®êbQa?©Zõú‰1‡ÉŠYAÉäÀúz™åÐþv…•I{5Rê¶Ï­_üñý‰¼Ã¢§ˆÒQK©ÇCˆ½Ôûf ÙAë­›Ø&±y„æLÚU`_ÏÎ~@gÏИ|qÇ‘^EöÀä”Ñ׿…ÞÞ R©qdº.’† ¿ù6šÍßP¯g±Óê) žºê(¥ÎLMMMŽŽŽ‚µ­é¨±šÈý ŠÈ/4ÿI£ ¨,ç¸Þ;Ƹ/ý1˜õÒ™ßÑt Ü^TÏh€ÉB>?¹€Ÿæÿ¸¯OìàØXc 'Ÿ¿¯ëˆökŽe •þ’¾2™5¤6>v¤”Bão¼ú )1(ºMý#=ÈHH`xàr+XTsddüµè̤X£¤‚”Ü,×v°™Eû"#,• ý#-4[M„!G£þl{žwº£yÁ¯ ôgˆbŽTÚa6šMPE’±'æH‘ÎK§Naáz -·ÁƒY¸î‹”0î=a¨»dĈó€sN¬§A^ ¡è?7ž¸Þž<ö46ï4Q­ÕÐ׳ÝÑx ÐC¡vÐjqÒ6HAÿi¼Òž@šÔé¡q2’·‚RU'XHú?cŸ<:I:=¨5ÆÐß]G½Q‰= @+ Û]ãÂx£A.èâe¨C¨müU^„e?ø޵a2;sðR¯cm½ŠÌ誎b·RÃÒ°O@(tBîÞ‘e0wu?^›Goƒ îyÃ)|½I¥KÔêQÚJa4ÿÖ7K±wcçó„}Ì:ÐY&)îu|1û-æ~¾F)ëâÐÁ4Êýº»ož;÷Þw{y'€bqº¨"u>—¥Ò÷\ÊóxèKoKœÞ¡IñM݆Ùôt±X¼§ÕvBm4Ïê<®RaíW\ÇÜ·Sþ`·g³Ó}uIEND®B`‚virt-manager-1.5.1/data/hicolor/24x24/actions/icon_console.png0000664000175100017510000000134612574335131025557 0ustar crobinsocrobinso00000000000000‰PNG  IHDRàw=øtEXtSoftwareAdobe ImageReadyqÉe<ˆIDATxÚÔU=oAóÙ¡Æ"¥-hÒD¢9!ñ'hLAu@TDH@‘³@T¡¡ €WÀo qƒDƒì"‰ŒŒ,Ÿ½³»ÇÌìÞ:çØ(Rì‚‘Öûqã÷æíÌÍEyžÃ&­¶TùçÝÑÑsšZ4’5ávitîí½kmën«•\ÛÞ†¨HItÖ?‡<äˆGÑjd~þk0H>t:¼ I½^‡¯Þ—î×K…~;¹ /Ÿ=ÌpEÆÐÚøý{wœ§¥óܲ#XceÍ>Öh@Úke@iˆf4´Bùc°c–Œqãq&³8YMç9­44˜ÀZwÆÿ%ßI6 * ùŸ#ÐZËÁïÑÈ9Iä9)0¢=2ÍŠ¢Vˆ ÔŒf³™ h08Ku þxÖi5¢µ_|M†ú+¤ Óˆ!à  ›Lä`:C¤Úx@"1:¬E1ƒŸ#Ry¶!dYv^Aa3å¤"ƒ¡6ÚG쀚Ë×.­¦²¹í(/S»$†ëpÉ´ù<òU†TQì;WÀ•XRàl(aIº/ÙþÝ %wfAîîÜ€oß^êEÛݹS*Ù’%ÂÓÇàÊVÍuÁJ qû¹B³õ nñÖÎl¼R6… ŽO¾R Ñkí¢‹/Zw@ JdŒš›t¾Òuû3ðm¹<¥ †Ã¡`’Úùôñ3¬»]»@V|2ßp×Kz½ÞA¿ß_êÓh4 Ùl¶iùcÿÉûe>K Ò´R½Ô¯Öa‹’^«¹ÇÕÒ#*)ï“ÓSN~»¦éÒ/Ú¢Çã[\Ë#ßø.bµj-¹°‚ÿê£ÿW€ ñ5ÅíÎGìIEND®B`‚virt-manager-1.5.1/data/hicolor/24x24/actions/vm_clone_wizard.png0000664000175100017510000000142613240655316026267 0ustar crobinsocrobinso00000000000000‰PNG  IHDRàw=øsBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<“IDATH‰µ•ÏKa‡Ÿ÷Y'éRn»¢H!%”’†‘•At©[Lj¡CtÌ :D]w±S§ö"ô7ä¡ 1\s«‹ZÁ£3óþê°î´»®6f~á…aÞyßçý¼ï33Â9Ça–<ÔÙ¿q1;;{KHYÔZçö=‰ïo8k§ …ÂÜ®ë\qrb"700€”ÏóR¶4kmÒŒ1Xk©Õj¹÷óóE`w@F¹þþ~ž¼xÍÂR5õêÇ/œãу»DaÔ1yÐZ°°Teb|„#A@ÐÕEdººÈd|”ÒDqL)¢8&Œ">|ª´ŒßåÀ:‡uc,JkL²-ë,Ö9h0 QJ„T@}Ï•Ö!pÎaŒAiƒR ¥M}=Îý ´JDqÌÑÀ£ïXg Ð>XpºïoËez²=K%­VuL†ù“Ç™¼z…ƒZÕñ ~m…è8æXÕB0:<ÄçåoŒæƒ[%›Ó÷ïðîÍË]­º}ó:gOa¶ÿoV% ¤««?r¾ïï8“f«zóYzóY®]£ú}•ÅJ•Ÿkë»Z•âØL•Ëå¢R*=‘m±ÊZ‹Þž ‘JkMFlm…hmPÛ“:çPZµff^ÍÑô-y8=Ãík<Ï£¶¶ÎÇ… ‹•¯ ØlÔ¼€ Ú«Ý*ß÷ð¤ÇãçE„É‹çœÃZ‡±·¨ Ùª´562”u«„H)“• !Zžm$©§±éíVí§´ÖH!6ö´[µŸÊd2ql¦DÚŸ~©T:ã :|~ØëîîNîonn²R]ÑÎ÷/Þ+*íãRçׯ<ó<Ï[þ²¼£OJé›8~ ÜhïKà_ë7'¢ÁM\ƒXIEND®B`‚virt-manager-1.5.1/data/hicolor/24x24/apps/0000775000175100017510000000000013245574323021702 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/24x24/apps/virt-manager.png0000664000175100017510000000261012574335131024777 0ustar crobinsocrobinso00000000000000‰PNG  IHDRàw=øsBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<tEXtTitleD1½tEXtAuthorLapo Calamandreiß‘*:tEXtDescriptionDistributed under the terms of LGPLv3/CCBYSAv38€gÍtEXtCreation Time2011-03-19é¯ctEXtCopyrightCC Attribution-NonCommercial-ShareAlike http://creativecommons.org/licenses/by-nc-sa/3.0/ÞåöIDATH‰í•?luÇßïîìóÙ¾ó;qÜ´&‰Ó¤ 1E€TþHN#í L00 êÀÀÀÆ{…X°ˆª¢Qb’§u›Ú±“øïÙw÷»ßÝýîw,©Œ}Ò[žôÞGzÿ¾¨T*Á£4î‘V ø„g/¯¼Å!v À¤}øÁ{×VVV¼ç^¼2Œ}ùo‰#®xÀ€ ‚ä:ô£µ[åoÇðœš(ž§•Ý ¿4;¸þɧËð‹ëد‡ÆEZo%³¯\Vç‹sQM×ÝV³É»ÌÓëÖW““±§.-ÆUUu[Í&ŸH¤ÜÍßvÞ€1€c6^ë z¤õû´6*®‰ÉkXÓßh¬®Å›•íÑFe3Ì<ØÄü·oC¥²)bŒ/lno#AàX6¿W݇ÃÃCÞ0Œ—f——•‡^EOŽF§‘í.xÍã¨IÎ$'R7b½vk!˜Ëoqéxn2›±Ju0Äý~/À<¤sŠD¢ až'U Ä&fZúöÀé‰I¾¶'b–ä]÷:ùŒÖ Ÿè‡ÀüŒ(IØØøu@L±D|8¨ ©],psõVƒ˜É”U«Ý%R°¯Ž[ˤ~Ò äü$ȆåaŒ_HQ˜òGd+]”$‰nïì$M‹€ãØ4¡ur’ý~¸s§ކ D•ˆ®ëÇùé\cãeE¹Ö××™¡é7H,L¦BrRâ¸a<,sÒÜL5(I‡`ßuÁiØ/Šb±8$‡B¨s|<!Ýj6M¿Ïùü¹ÆHÁ¸cÑö«c€aY7Ø ™t žÉL+6ÆY|’“¤ô{=X(ÎÃ~ußK§’P,ÎI²,Ãp8”³™ 4ê‡V0(ÁÒ¥ÅT§Ûƒˆ¬DMl^ý `õûï~®·[.ý€«÷õ<7˜ŒÏK’ÄlÓšUÅÛÚÚ QÛtú‰H8,ƒ"+(›Í½ÚÝHç¤íär¹s†a¨Sù©˜EÌ’eYa¾P(@­VC‰DbÆÇ O§'³œ²T臓ñ0‡P!ß¿ ™, çýñXŒ…BAÔí¶ÉÞ^uÄóY(ƒŒÑ¶KÝH·×ëvÚÝè¡à”Ëe~zúü¿Ÿÿ†ó€ $À\ žËÀ¡TÒ5ýs%¢¼«(J)õ,Ër¨c‹š¦}!Ëò;ÁPÈ ”s0æúxÞ÷ƒpæúY½~ïÇD"õ>cTþûgð@Rfpg€sêÁõˆ(JJ7« ë"ž™EcÚRüz<]ºÄØÛ‹áûlÚ®RüØTòqXpˆq•S’ ó.€ï´íÇsœ¥yÅyú*èÎÃÈ3ŒX§P"V.$ðȃ{³¸m”úT²P(?À•ÈA2CpÆq™%©8ÛÕ‰~³ƒQ„\ïTZÊëÐ?ëአÇSž»Lx ž Á·ƒ€ãTö`ðÝ ’‘LåPï«ýÄ{²vì»IÆRÀ¥hô‰NFL Ã[{A@“ü+d¦Pî­‹ããßBõŽ‘; Þ²õõMQO×,u™#OÝ]K”¸ý%€~qb…¾"§rš„w† ÅišŸKS¹œš’¿¾ÿןI§/_ªJÁôÈÁƒŸÿì½÷f)‹ÞAý,’ƒ!¯ NߣHô'ÄùÞ&jF4Ç`S‰” ]»þKùü‰Ì•ÿL}vïUj8ÆkºT#™L&‰Fôy‹ÃdóS«ƒƒüšÂÌf®ùM¿V0TEÛçº^@ûß E }ß¡d¢Â]׿œÇˆ’öJmG`I~ûH5åU°Í,¦Ûá=N:3†éQ×Ü¿°fŠ•8º:‹´/7K™Ýyì_ Ìà_!)›ìÈZÂ÷Üsä:Ïã½÷á]Hªž‚ñÞ”ú}{³>o$çD"NÚ3T7g0"Úü’LipÀ¢înœCœ¡ó§`˜ûC Ÿâ]ª”£ïÒÙIjì6‹´hJ`¹TdAT®T@Ä2 Jc³%u()ã}Î%%ãu¤§àùkM (H§\Q”L¦a·8új9)ÌÈe¯)Çu«ÚvqZÑJ=ËM°-Ii|÷éOÒ@_/}ïÇÏ®¹?5C”ˆëà·Í„%e‚rÙëÈ÷¯ P_‚Åç·=ï9ü*ÅÑÍ|Š>BÐGKK“DÝ—ë)H «X¿]qœ*àÕ‡\A¦UÙ¿ozüôÓ^¬»®ùÎD]€¦ý§ó? Ž”‹˜@â°;Io <×¢Rù·Ï«4¿Äxƒ´Ÿò˜Ð !YïX_YÍ,Žã†óÃ* ©:bë•п>ó{zãïÿ¬^Ÿ_ ºz-Žq•°æ,-J%xF™8Ñǽ-#H*I`ÈbÌ} üZ³Õòàó gÈÔP­“KCÚß?ô8ù2½òê«×gç—“жE½=¥6V˜,?Û¹È6NŦÂ2Žb˜†Ì2C ¹–€–n& t3R«@Vß ]¢˜G¾óØ×(—¤gÇ_ª^/ÀN×Þ‹Òi›Ò˜R)d'd(,¯Éñ,*`ý²EX"ÀˆZßÂ`]Kà=O˜4ézž9o:”ØFb QùÊ¢¡=:v|œfnå}ï#ðŠÀT\Æ"î¦]7«û«Ì ÀLk8v}ò<Ÿ äãÞØ¨Ö7· êûkcT[u»·Œ«1øKH{@øpÐq+“ÔFʙߣŸ¿ø²ñòúDkÆÓàå¬c ô€m®Óòñ~Eg_;¿¥çµ¤C4¸íµþ›ÿºBÏÿâ7ôÖÛïnùz’­áMÒ(t¶Îw§-IfüäãÛ-Z!ZQMcÀ0cª­––oW1ó”b-b@xmh6?O¯ýù cùvF›Æ€I£†ÙíkèáGÝ‘ .uVJh[>«´³üßXµõ%ôËgŽ´ØqsèÍ<7|Ôzcœ×}ކKrŒçï+üÚ´õ2½E ŸÍç} ɦ‹9_c·nÍnðK­Ÿ´Ô:}LÓ‘5¼tØÈ"Ä_-7 b)}(%[ãaþKÕU¬æC@ðEZoSTø¼ß÷ÙÁN{ É5ƒcÓp€[^Ÿº1=Ò¿{€X ›ª`tínþã B0D>YÂV¬bõ³¾4fjŸÓß8MÝÊxúþÌôûëäÔÙsgéNmCÑàOµýŽãÇŸ›˜˜œœlÙ/›ÍR.—;zøðc;&ü—·ðÌ×ÛòÏV=ð£cÇÆL£:tPíªšV~5RÄ2ßO¹e™¶eYGøä“c·5l¶”–K£|‚ÉEíE¢Qì[QãœÛ–ù¦ººè,®ëõžÛu\l#—éâÅ‹£¸=¶mÚ3ñfËriùèù FÛ„ãèwsw Ü%p—@[ÊÿIô㫆þOIEND®B`‚virt-manager-1.5.1/data/hicolor/48x48/actions/vm_import_wizard.png0000664000175100017510000000364112574335131026515 0ustar crobinsocrobinso00000000000000‰PNG  IHDR00Wù‡tEXtSoftwareAdobe ImageReadyqÉe<CIDATxÚìY[lUþÎlgw» [(È­ ¨Q@¨QB1Bâ&ú€/՘胼lÑø/&Fy0Æ#1Æ7cP0\ ¨ÄB¹´…¶l[zÙèn»s9þ眙éÎÞhkÅ6é¿™™3ç|ß;ÿ9Ë8ç˜É¢a†Ë,Y³f¸”¸_:ôvÓ±ušc>NÇ÷o¿õÖ>¶mïÞ±ã¥Í••U…‚Óùèh›ýõ¨¸õ  mkEEô Žâ“s¾9}˜sÎxÄŒ‰NÁåÙ}澑ٓ÷Pý^dh0êkŽ ‘PR¢Ã¶l¼ùî‡jÜ;Ü{AÓ˜¢ži«¸vßÑÔþÑ ¼-9ÊáòZœmuMÛ¦o›;÷n›±w¾ùüS…‘°æÈ–•5UòÐ4”–†%{ø,ÃrÔõÙïmÒ'áY}y#m •å€m¹ÙQ<ˆ³%I/»š%"©AW±JCþwÚ£8xro¬JM >sÝIõ),hÙF Ó³ü³P¶¤ Ã3ŸA×®¦˜žûL©$ŠXõcøúÂU¼VÓ?þ\®iž›rŒ— c“$0jH¿tIHÿ„ò[ð1?Í–[ÖáwÆñÃõf¼¼$>nbNÜ(k8qæÅß8ˆàþææ×¶H¶tùÌÎ;3nª«ÅYjûÓ5Žmåm¶S '9¨„àZÀ&·yL`Í! |Ž[&¥='ç¦Óàì#eiè7"H˜aܳ¶C±KðÔªåRýI›ëÖá õsì*Ç ±ˆÚ%’{À# ô+°æM£–dæX md¤;¥õíNÇÐm”¡¼z9-ššù1”•E‰†¢LÕy×”Ä{ék3¹ÓiêãD3ǦÈÕ‡å¹L¦ Rß–iI‡Ë›F…YL²€h`Y¹©&’´tt Ði,ÄšçÖ¢¶f)ÊæÏEÊäµ8Òt$G¨¤An¥œz$ÍÑC7[êÖ¢‘~:}…cCðr~š®$€ Œò¿Fø”‚ º.D4t3OŸ9mæ¬xf=6>Yƒ’pÃi·‡L–/gxÁÆt›L3ܾ«Hœ¢ßÿ Ïj ðYÂϦ |¦‡5—7ÉD¢¹ašòºË^€V«[wnAeÕb ظ“Ü7ÿ8¥ÂXB§Ki=›æŠ‡Ä92Â3¬ÉO€³Œ‰;‰É’.Ĭù³é0$÷‰›óqîƮW¶anyâC–Ô|b_US螓Ϥ…ò:nYáïÃoÃJ5=¬ù-`) t¥£hµ%ð/"RC{€AþÌ2ð¹õ‰W±Œ™™9îD?D‚V–q²ñn^¾”£ýb’Y ðcA È FñÄZÍ ìÜY‡Ø¼2´ ð÷<Å¥Ȩ,ÊÓ4m§µ ðä ~#ðmŸ-Â¥] Ž:¾úíž^¿U•‹p­7MõˆJ]¥ÔrN(@ 4Dt ±°ZÌ ‹ôã‘Îw¦¤µæè «O xÚ–øP,šÚñãŸÝس{5ºîª4úhL—ÀË ‰»Ãˆw%p¥wý÷ÐÙÕ Ò^gO­zÛëžFÓíÖ. áo½ü÷¿ï‘0ÕS0¾;ÇóVâ+¡<¶²\G¢MÍÝèéB_¼1ÜÃvåHb9ò pêr;êÖ ¶"Œ£—Ð2…àUz'¥r–ß÷)íŸlNàõW×É jn⯦\ùë<ÊYóp5Y€ fÇ/N9xe«p ´Þ‹bé²Åƒ¸ïÅ·?7bë 6ˆ9~¼r”À_ÿÀ+/)2¤Cx„ʃæ8uâ4gíä&‰ rCì…‡¿/Ô;F4Äýî[xŒµL ü\ŠÚ‡Þg³ÑÓÞ‚w·/æ·ß/ºzR+(MVŒò^”ÁÎ5c{rÊá|%¹¨(ÕºBå½XsXvÁ±û” å«FMŠî×7,Ä”»ûúƹdrÒÏz]6d–ò<£ü(:7«j9_W‡°qEÄÓJQ<βo ÷O xÆ*Ý­gäNwßww‚XÆþP.ÉÜ-);¯‰vïŠwo]´dqÁ¢KáQ£ sK÷pÆæEµÄÂàÖM\¾«ÀeÊ]ó W“•,+ª<ñüNwp¡ã9hÃG~9‚²7zx¬Ÿ¢ÿÈ8ØÐÞÞ^ßÑÑQ´]UUª««÷ïÝûAôÙ^'ð»&ñΞ©{Òøø“O(˜êE,ˆ ’¾ËÇ|5ﮇ7\n—h€¼û?Ú·¯á_Í•T2U_[»¥‘RKtèT‚è:éZ+ È=ÕlÛ"n]/ÖÜbÿs8™Ä¹sçêéqÃÿæBÓ⚉J2•ÜæìÙú)±ÿ¡ÇÀt‘Ù)g ̘áòSe/©{ëiIEND®B`‚virt-manager-1.5.1/data/hicolor/48x48/actions/vm_clone_wizard.png0000664000175100017510000000301112574335131026272 0ustar crobinsocrobinso00000000000000‰PNG  IHDR00Wù‡tEXtSoftwareAdobe ImageReadyqÉe<«IDATxÚìYMh\U>÷½y'­ ‚VIf⺵®\ÔE³) ºéF¥«E°v£!&1ºÑ(T«ÉL ¨”˜•"˜Vhi¡AQÁR¡$EkI‚'yïÞë=÷çýçe&3šÈ oÞï}ïûî9ç;çÞÎ9tr#»v 4I`jzúE±?$¶þ6Çz^ló/ N…/æc‡ž8ÐÛ[„®®|["¯VkpíÚʳg¿ÅÓ(áBý===àäÈv'¢¹ø#zºÅõDüŠ÷p¹7÷Lð›ü›êzƧ›Àè Öø=´är0ÊàðKÃêâãþfÎ-–E$uÏ’XñØô±Ô…èx†„ôàpyŒ{¦ŽÅcâ—q}nž úÌ}ð¦Â(°&Ä/ò,”zîåOS D¬A!bϱ>ÏÇ*- î»QX•ð8 t qÛ™W?}ðq¸¯¯&&Ëpcu]OÐI(q§‘˜¨t!®±ê<Èg\•Œ{Õëë4|Jž&®¢ÅPØ.bÒø|R.C „T©UI*Þ¾<S§æSsO’h0x1úˆ?W¥–—ÂB–'O~‹ç.l«?º´±€Œ˜*µ²ýôëexæsøíÊÕm¿“l€‚¥t_òÇïƒQ%Z‡iu™c#“M÷I ¸èªA±ÒÕÕÕ5ˆ«R«Fþ=1ò­j2Oq•§dËÔŒÕgW¥fÚÚúßpîûK¢˜[h©5U&Ö1 \èüŸ\ï¿ëî}²€‹«R3í™ÃCÿ‰‚Ñp&òtzñÌ"˜µÑîîîŽZÜÍÍÌ|Tû²¹pôèPG-W'dÔ¨ºªRÖìIÍ ,Y1Ês,ƒõqZ9œZ’3¦çj/ϱLÏðµõuåBX¦&²*Õ;•BÑâõÌ×åƒd“©<¯3öÔs©‰,®J™xô´/ÀÅ£ŸðÐ,ÝÔ3r%‰›þf%ˆ„Ö‡’$“KRªôOs¡ˆ*m^Ÿ¨¯£¹¥{èos,‰üˆBBU,öUÀeÊùÐÕð’=xxÿÆõ¿$Ö\JáQ¥6ÿÍé–ÿlrò±åååÑ••ìeq\¾,•JãÇkj)¦ÅàŸÚFŸçšZ kÖ¯OLŒ‰`ÅXÀ ’¾Ë_M]5â ã†Ëå˶å¹mÛ㯌Œ5•m•Ñýû†Bwò9œ|^®ã;âØÊÙrM5)Ô¯ëqÎëŸÿT*°´´4*ní˜ µE&n´U6*ã.^mžñÿ=vºíØéö¯Þɧ˜¢IEND®B`‚virt-manager-1.5.1/data/hicolor/48x48/actions/vm_delete_wizard.png0000664000175100017510000000410412574335131026440 0ustar crobinsocrobinso00000000000000‰PNG  IHDR00Wù‡tEXtSoftwareAdobe ImageReadyqÉe<æIDATxÚìZklU>3;»eK»}íöµ­mA*‘‚$ÑH &Æ„Dþcð5Lô‡Rü£H(éJkÔ$&JŒ¼  Dˆhi B[Ê«Ýmwçá9÷ÎÙn¬<Ns;3{ïl¿sÎwÎ=ç‚dÜË"Ã=.÷¸¯À}îqQÄMs$ò2^à˜s—cÞ‡cë’Å‹79Ðu}ÁÓOÏ]UU 99¾»ùÀ@::ÚgïÞ½‡ à†6'ƒ×ç…Ì››dþ6ðG2¯¶)Ã\!Iô¥`°«˜oؿɚäŸgøÓ„ 1z k…Р(^Ð5¾ºŒÿüãÖϲ²,1 |NfXé^¼#óœÁë¤iƒÝÓUç÷ø£ëø[7Ìg±&ùNËÆ÷9FÄš¦@ªŒ¯­fW,ƒß?†iÏH™Í5"Iù.T>O@,Öš ö\k{æ N•(¾,,Ñ?0€Šx˜…a¹…²_tâßIÔt ªåù!³PªÄ Ë} ¼–’,ð†Ã•·”ËeÙ¢©É@0˜Á¤Q*0`¼J0~ç-IžºÉÇ,ƒ§ÎB¤åÛaH2ã†{ÃŒ3+þ†¡/ñMäáÝ $Ý :S6çîü¼±ðøÌiP*†·W5 í‰{ ÌäÀ‚ð€Ž´¢u5aX¹:Ý=´!Ù6ne&QÈ0±ºg!ÕÔ飚‹†Ëõ‘}j!â ÀY Ù= L&>w ‘4î8.ÌÖ&•*Û~Ø›¶le^NÒË•á*(--M[ßÙÙ /t0ð„qP°°-ÈZ)Œiyõ†ÏaçÞis•a^w‰©*¬ÉCmç- &pMË®õOþqÖoþÎüÕê:_TT‚i[…ã¿I›k˜6ƒÍŸoýdžoP©x’²O™HË6æâs0‚ü@þÜ\¶¦8dUïÔ†éiï—W”3ÏÐÜú/~‚PqbR¼¶|Ý8½ÑᦙddÕòëÐòBÊÊÊ¡¬¼&=X Á“ïŠ?êë'±’EUu¶‘Å,ô¦<<‰•5‰X/tBkÇå5}}})û€šàWz®ÁÞ_3ËÛ¥  ™•¥PàÖäæ@Ž—=õû˜D -ïAEzcqë;z£à=7§ŽxÉ™F5 nCó.uý¼··Nú¢µ•fé‚ÙNã†ÓÌ,CÏTóÐ<•Ù2ö!²ÇŠ‚W…=Ÿk½Š×wH¹MùL‡$]—ÚaâóáÏGaÆÌYP^˜ ù¹>ðãn}òïNx²¡¼ ?ñéìéƒï÷‡YS&`z×àB÷Mh;² –¿õŠ”±ø?…8]W^ˆ;ñ8¨¯ Âd—zz¡®¢Î_¾ùc¼0>\ gÚºa\e”†‚,È…p0|Êehsíô$…>]³,c÷Ä;(™{¦2ؼw+‡SËñ%o®B0yPÈg Â¡Û€).ò0(Š~˜TbœøÙºZTºûz£Õ ůöº»¯ »§¤e §_g y|—©QñMxQÅ˲dk¶Í«"ó#Þ3pC¹î¬a žÌÐ3ã1Û¾$.Ãú¸À°u颞a'IX(ÃX…¢iÒ‹DYtdø93²m³’mÚ÷ïÅK¬­äí£ûg7¬.Áµ¬;ÓyƒÏhHs†f=‹æŸeFô#ŘeS@Ú-!(GŽbï1¦èŽ&ß~2÷ÍÎ];ávœÊr ‹¯G²z Á4Î#yÞ’r¬BpU`óæO"x‰ŒÔêÕ­hkkklooϸ®ºº¢qÎiÅL•tïñÈæÑ£³îfðˆ¦>½´ÏÊñ:‚Ÿ7Ò4J@(ˆEÙ.Ø$KRHª“ĺÔþdÔûÀ{+W®@N7R ·)>òó°ž™<™¹ÞõÔÈà໺ìê1Ó.§U†³Ùy¸¥»U£#•X4ÖØÐ0+J?ZÒ ^lJ¼^¼â½¬x¸T¡@¦Vµé³ïLjÈ–5ÝÖÛÅ:Š*%îè¿Ð¨æÝ™Êx{k©¥4=£ö@4}÷ÀÁƒ£y—Š7‚QRÀ+ÒhÂX_ÇË섚¤Ie0`ÝÓçY¡PÓÚµ+ð²b4ïÎ{~±AT¨¯-5­Šñƒ%5I]e1»ÞÄBÈC5!¸ÑÛWoD™ª¿ÃR{úl5þà§鉀*Ò×zöܲnEÛ÷ÿ¼{n׵Ǡ ››‚¼1P”ï·¼`òÄÕ›1¸ŽhÃJõô±ƒìý;ªÆ@ó¹Ó'<8ž¡P()­xÔëÍ¡³Yk^¨TIÄ0àãØð÷CO×¥£ÔìáØ£Ù ðûÿ[åË &$µl\·Ù>IEND®B`‚virt-manager-1.5.1/data/hicolor/48x48/apps/0000775000175100017510000000000013245574323021716 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/48x48/apps/virt-manager.png0000664000175100017510000000535112574335131025020 0ustar crobinsocrobinso00000000000000‰PNG  IHDR00Wù‡sBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<tEXtTitleD1½tEXtAuthorLapo Calamandreiß‘*:tEXtDescriptionDistributed under the terms of LGPLv3/CCBYSAv38€gÍtEXtCreation Time2011-03-19é¯ctEXtCopyrightCC Attribution-NonCommercial-ShareAlike http://creativecommons.org/licenses/by-nc-sa/3.0/Þå WIDAThí™[l\GÇÿsfæÜöîk|¿ÄŽ›‹“´”’´Eô‚ˆ„D%ú¢©„Ú ¯^ŠT$¤V¢!¡¾"¡â* iT©MŠš&¥¹xmDZwmïÚ»öîžÛœ™áa½Ö&u ˆSÉé{سßõý>}3šÙCΜ9ƒÏ²Œ½.àÕ>À^k`¯µ°×ÚØkíìµööZû{-¶×ÜMgÏž¥•JÅ€×_]Ü-¼ð“—®j­Ém ©ôä_ÜÍxúô“.uW¡‘n®5!·ý ´Ö·}6y÷í·Þø <ôè™ßèǃj­ BˆæDÐít@X›}õÕWånLIiWÞ<ßs.øéûV´~Àkw «ö”بռ?¿=”Ìe«ÅÕÒÀÓ_ïüò£‘h2¾¯®]»f4¡n--)7•9ùðÃMD)%L¥ÎC§N±0 ÕjUÍÏ͵º@×Jej:‰ÆÇù›OøÝ®‘¿°&FŸ^}ãÜaPZÁ&àÉ/}áÙÝ¢0úÞæù‹Ž(­Ã+WšÅ?øÑj©ôˆÒ …b±™Hˆqíú Ôk5hh(¥Œ‰Y×u¿ Àô<ÿÕÒÊ㧸K…b“ãƒK—¡¤lypìÈ´Úòüçï@>ýøUå˜?Š®ÍY:– PÕZšÏt÷ÿq­¸Tj%ŸøÜƒÆaôàüû#;ÃB õýGm‹ÔÑ#‡Á9@à86:;r‚Œ10ÆÇ1§œŸRÞ[­m%eg§&'aš„Žc#á:Ð8ç`”a`°?[©låzGþ°ZX\ÿ@"ÁüŽîSÄ@åJ–!PŽ=¤ÛY^+þ©•œëêy)¾:o ¼1@ Ä0€±þKd°g’R Bûà nšX˜ŸGKJÉ$!¬ÇbQCMSJ!¥Âðð‚  á&Èçó²éÑ´»«kuc}=SZ+¾q'€‘~õ%)ç Œ2}unRDáSÓÓÓ ˜˜86"Âð1ÜX˜nåPÆ`L¢Üäà&G~~õzMÅR RJd²9åyßEÑN-ŸÈ_½r!–bA÷uÕ Æ`0*$›[+[è›Iñœ*­_1@ìVŽÑ‘Y·Ò‰i“s˜œÃ >¸|YC!‚f1><ßÇÖÖæ7Ù-£ï½w1l÷Œ‰&´Z­†J¥b¥j#úÖ® ñJ8Ü»áfR ŒÂ´-$‹ëa>›Nq¢(<›\Zfœ2 Ê(¬{§nrÎÑ Ã å÷/\°D$Ð J™›N§·<¿ Ñðê´V©-רU/]úÀ‰Ú<ÉdÊÁ¬ç{ð|;wc#Cé( Ÿ»+ÀZÂ|­®UÒêî€å: „ ƒÐ^Ç}̪þŒÆr>IùAis|lK[ƒ}‡Z49ÇF¹¼µ±^ÁêêÚN7#!0qèÐjàüa¡X(Âd &çX^\^mÔX^^ºÍ3:2.Zž?¼‚‘á¡‘( 3]]Ú@]¿†"üU%cSÝ Ô@Ð+ÉV…Ï KB´Ö0…Á(¬Ãc7¸Å“­Yæ&—+ÅåqÆ(ò³³! †Ã0Б˧RIÍ9ÛÞ¥4ê: }ß;ØôäBB`ÆŽ6M¾É9!Àl~–Ä"¼ˆøù]@Fê—‹~#•éë…iÛ~€Q'5Ù™ÉÞìföI)âÅ›œžtLn¢¾ïß”R2†¥å%€Í(mn¡œÓã'OÞ´l­¨¬o`µPœ¥Œ1ÊŠÅ"¤Œ5ßÞr-ËÂèèèb+ÿF~n*u\DáW-«£wW߯,x¡ÿ÷ CúÙþPZc«°j#Vr£°B ¥0ƒ9гÅÝÄPûü—0ÊÀ(C*‘Dب/¹Ž Æ(£ívm¶ÕŒ0QZ]ínylËÆZauÁ²L0j€1Šã'NŒ·ò?@:™Ì†qYHï™] £W.—VÝ#ƒ œ!òüÀóù¹Þ8Ž!¥ÄÐÐ >úçÇV?}ëÍ¿©d J)H©`š&ÜdJ)4ª¦iap`ó :Š‚—ß9ÿ79G†‚ÙLºOQ‹¢‘ð<cGE$Äw°;ï]¾µð(õ±þ!ø†FÍ/ Í%2q¥²cX/¯Wk[›]ÐÓÝõuo¥XØX˜Ÿ}QDâéjµFQd…aóÄ9Ðßr©¼sÔN§SPJÄ…å‚1{ãê‹'¦¾¶¼´\'”&[žD2QÝ(•S@µZÅøøèBP›˜8rŒNLLì“Ïç V«ÕL7‘8Ò¼ÑlW§bé¤dÙ”´z¥M3- @QžçÙéTRuærÊuyñÂÅêr±ðëµÕ•Çqzëõúð@_ŸK´´†e™ Ò©¤Ì¤RÊuyá½ ›·[*­Ý°L+Q«ÕƆ†ì8Ž•Œc™J$BíºŽ´MKú¾‡z­¾¶Q]?@ÚßÐÌÌÌ8€žD:ýd6•yYCËV÷?´Öb¥Xø¾RÊs]w(›Ëýà?{ Ë¥ò…7-ËÊvtvý˜´.w!D3Æ·î hÞˆ²ŽRJ‡·>­)¥l-›¢ÛÑ*¨½0½ª-Œ¶ wä·{|‹äÎwdÛ@€…ÿîâ¯Û¢%‚Ý i÷´{ÛsÿG>ÐÒ6Èÿ½î ðYÑgþ¡}€½Ö>À^k`¯µ°×úR‡ ±Ç_IEND®B`‚virt-manager-1.5.1/data/hicolor/22x22/0000775000175100017510000000000013245574323020733 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/22x22/status/0000775000175100017510000000000013245574323022256 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/22x22/status/state_paused.png0000664000175100017510000000142113240655316025440 0ustar crobinsocrobinso00000000000000‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“ pHYs  šœtIMEß " sDc¸žIDAT8ËÕ•¿nÔJÆgÖöf(PDʼÂê†å ""M% ·€@=H)Ù‚·@ H‘hò‘Rš Qà«]ïÌ™9·ðÚ¬ AÁ‘ì±gÆß|óïŒáo yþâÅ~Q÷ED~ ™™÷þ /G£OAƒý®ìåhô)3³KY/c8²²²‚sé´Î9̬½RJç”ãñ˜ããcÌìRc ( ÖÖÖ(ŠbqkßÖpA9ï=gggÄÉ¢j;XU“ÉiÙÄ13²,@Uz½"ÒÎ_(ª’©FõvBí¶ÌŒñxÌáá!EQ°³³ÀÁÁÞ{677Y^^nårÎÕßb¨F² õUmݼ÷”eÉêê*Óé´eT–%Þ{ò<ïä"ƈú@Ð@5â½'ÆH¡““©ÉEªŠª¶À"‚ªÖX ã¾0n’õ+ÀM2Œ LUñ!`)µ‰š““ʲ¤ª*NOO9??oÓ,("XJøÉLƒ¼RJÐÁ`ÀöövkG€­­­vlž„™Á{4hÍx>i‹‘çyÇÏ‹ïóÑ8KUÉbTÊò?vwwÉó‡s_,Ô$f޳݊3Ìj‹j¨±bœù¸ª& ‡ÿ6Ó ¾YpB=ǤÓeàfE6©}¬ªS²Ë½žë"ˆÍ>šÝf«ÕM=" É Vçd¨êG¹~ýÆ}Ù?s&üè &f¶ÿÝ3xÿñÃI5¹öáý‡+[lÆÒ9Çúúú»¥ÁÒë{{÷øžj‹q÷î½/^¼@¿ßg©ß'+ zεÕ5Nùü¹äèèèßgÏž>ZÄÈ;nß¹ƒþÕ›·o®šY¯q@+õœ<ι˜çùèýßnÞºõUßÿé¶H?æÕXIEND®B`‚virt-manager-1.5.1/data/hicolor/22x22/status/state_running.png0000664000175100017510000000156213240655316025645 0ustar crobinsocrobinso00000000000000‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“ pHYs  šœtIMEß !:ç¹QmÿIDAT8ËÕ•½o\EÅ3ïíz‰ÀB ¤*ÓD‚?AAø P(1Æ…åPãŽ@KZ Q :j”X‚‚"A€D ˜õÆoßÜ/Š·^Ç_©BÁ•®FwÞÓ™sÏ=£ÿ[¤.]Zï÷û«)¥t7#"J)\Þܼ)¦q·BLãòææÍ:"æë\ñʇW¹§_“3Ô9“3T)A‚*u5êNX€{à¨êN+ÎgËÏóµ™N¿®xì¡9æ5Ä~kêÁs§çùêÚ6¢ÞyVÔíêáXP À13jSŽ•a#¤”¦lqV_~ŠÓßÏ_üÄŸ;mÇØ‹À,sÄœA¯L•¬j¨*ªNÓ;ce{Wø{WºuTxd~–WŸáéGïãá˜v…á®0 ·Z¥G,&XFT„bASŒ±tÙ´JSŒ[E§²ôz5+/=ÉÒ OPÌiÕQ <À£“MEjSCJ™æi‹A´ÅØ©ã÷íó8èÛ­8¥LZT)u1"óÔ#(¶0jZÞþä;~ümH•Ú¾˜£R:ƪJÁŠúpjøÉºuí/6>ÿQ«Ç‚B'GAU©U”Rºn`Ð˼õñ7|ÿëó ßá‚& ”‚ŠvŒ¥tv‹8îçÄ·¿ìÜveïp)ÆfÊh,¼væzU&¥LΉœ3)grJ¤I’±Ÿî¿;îŽY0 fJ­j´Ex|®*šÒ!f1É4)b"G†”!ˆ®Ú’Q5jU½áVU>¨V ÒÞQ±Z·t_ §Ó=Eï¨êtöìë«)¥5`öØœ0¬8Yì&"ÖOñúú{šqóâõŸ¯?ëîE:–9g¾Ì¾<¿¶vî$‡‰••sç/œ:u/333 ff¨û}ªœQíìÙ¶-Ãá[[[ï\¼øþ»‡1êÃo./S¤|zåê•3Qí9€Ûæ·'OÎÙz½Þæö¾½±´tdï_+ÇyV‘á»§IEND®B`‚virt-manager-1.5.1/data/hicolor/22x22/status/state_shutoff.png0000664000175100017510000000112413240655316025635 0ustar crobinsocrobinso00000000000000‰PNG  IHDRÄ´l;bKGDÿÿÿ ½§“ pHYs  šœtIMEß !( %áIDAT8ËÕ”¿nAÆ¿Ù[¯‘Î" Σ¸2"HHðÔï‚w@~ ¨’(â—Èv**ËÖÞü¡Ø»ËÙ¹;rÃJ«Óîí|3û»oøßÍçóñz½ž©êAsÈóü-®ŠâˆØ¡†¨ØUQ˜gæGÎ9L§S„Ò5ˆšY¯ÛÃÌšÙ^—e‰Édf†· A–eÈóY–Ýéd¸•LD°\.SŒ*|›-3£,KÑ‚] Ìl#‘ªÂ« ˜AD6®¸³*lVi©¼Š@E!ª‘ fûˆÖq* I(Dªš^Thö®m&"–WÕF´Fñáú–µž¯´«½ÏÛ®-,"Õd7n±Ýgtg‘d7Ñû!nèJ¤7bŒFÈ2—˜Á!=oº¨U©AÕnñ1ÂÔàUÌŒáðd׺š]{Ì U½Tm£¢‹tq­®3 ½@þñÑÑ›¢(¾ÅòÛ !Ðññ“çt×ÙìòuŒå‹ÕjõÞÌ«ê§d³Á`ð%ôû—ÏÆã¯VìÚüþã燓áÓOýyï=œspŽ ’€KÆ:Füº¾þxzúòóNÂf†ó‹‹s<¶;‘¨ ""yuvöŽˆ~ßËh±Xì͵+æ/ã¬À‰:ÞÔBIEND®B`‚virt-manager-1.5.1/data/hicolor/22x22/devices/0000775000175100017510000000000013245574323022355 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/22x22/devices/device_pci.png0000664000175100017510000000166112574335131025155 0ustar crobinsocrobinso00000000000000‰PNG  IHDRÄ´l;tEXtSoftwareAdobe ImageReadyqÉe<SIDATxÚ¬UKOSAþæÞ©}ÐÒÛZ¸µTÀâB  Æ1Æ•®0nX°qÉÆF℟à+Fã‚ &&¾‚˜°0Š@->xH‚%"oÛ{{¯gæBA ,ÄINÏÉÜ3ß|óÍ9SfÛ66;Î4žºDî*YÌ"ëäø?ãzSSS©¦iÈçóhoo?·Y`7Y–¬4‰ µµB˲žð£Çئµ¨ˆ7J/Ø 9îݹ?ÃEÜxáð¦€{ž­ÄTx)…‘³0ùóÍ?ÎH˜Š¢y,¤`ŸRQ¤úã¤[¤¾a ûŽ\“±K™Âpú EÊ9çÎ7.ªª:^¸¼/CÛpèà¸Ý®uŸ½z'Gœ[sÍáXÃÊ0ŒBNss³'™LVqU…¤hY [4“É`£Ú¾x¼²¥àÕƒ@©Jì_’ñòG*˜¦¹¡¦·¿•>à™Àþxñw"%Xbgí8^v÷n*4—Ý€8P8†®ïÅÀ@êï´)Îù”Øc•ãˆWM ¦:UåR) cXÎÓ¡Ù–M•d`pð£ô«GKK ÚÚÚJƶˆÇ*1=ýÙ\¡àV¤?¥P^¦Ã_@z(mѼ>Òé!g"‘“Ék¿ˆÁ÷‚.î†ÏëGj´µ»ðuø³dVFÀ©ÁAÉX×Ëñîý: wj´woß÷DŒ2Ý‹@Pô¹ -¤"4çÂü< i áÈ|Í¢TS rý©}M¹™°¾ Öl¹÷ž†0J.ô¼¦>ªæð‡Bù:í;8<þFGfQU­ÂV¶bä#ÐÕÑC«ý£å'Š€ mS³+€X…K2ˆÆUì®’ÇTÔ%BNWP·G“9VÞ&Ö¶Ï‹ÛY“±C:R”û»T·ÇGºû@÷ÏR¬…¸½>¬ô­Ò0£X”TÎÈ™»äEèú1aÈ›61AÌ–b=á‘©T5‹2î~Ñ s§Ï®ÁØ¢3u<ìed…ÉÎG+ ]+ñó§ŠdkÖ2ë0™o5 cL5…!2½#Œˆ«Ù,Ó§Ro5§çTÜ–÷aåSQ£ùZ7+d  ‰þþ~ây*7øO¦'É]&»Iý1÷[€oÀX`÷ÚIEND®B`‚virt-manager-1.5.1/data/hicolor/22x22/devices/device_serial.png0000664000175100017510000000202312574335131025652 0ustar crobinsocrobinso00000000000000‰PNG  IHDRÄ´l;tEXtSoftwareAdobe ImageReadyqÉe<µIDATxÚ´”ïoSUÇ¿çÞÛº®­ííl7»u[+ñ ¸-Ì€/pf³•¬ щiH|GL|g\ˆF¢üŠ?ã;ô˜_èJÜÆPA’ [&s &vĺ´]Û…vkoÛ{}Î `ªL Æ“ûÍsï9ÏóyÎçvê“÷ØLê µ‘,¤i4Cš¶Zë/î‹ì3p?{è6xÉW.•=¥’f.j …"©Àý¾$}®:Ÿ¾0¼·¦lòÜ„ƒ¬B’o«•´…´Ô›ÏçŸÌåòìVŽ/'\.õøðséÆ?OàÜÔä2{³Ùl„Oízšýg0o£ŸªêBgÇfÌÎ͊퉼a >ðÆë^2‘ÞíÝ'ÿ:6}ùêÏyüÝ÷â÷~õµ‘ɬ >3Ðã÷·W%“)ܼãð+%­|ðÃNž© L3å•xëà›I’Qo©Çùᅢ¡Ð ]€}¾fáûÕXt”Ì"ÍüІ`¾R.W^Ú¹cûCá=(—Ëzã—eÅ¢†t:-ö8¶´Uu ­µߎOÅVÒ+?â%ø¨ LÐ0™·9Ò£Q K’$ ±¥LЉ EðÚN§WPà魯¹ŸÐÙهçÃI‡üÅb&xT€ï@ŒŒô˜L&‘ˆÊ ׯÿŒååe$’¿Ýûä™ n·MM.ÔÕYDß7g&\€ß?ñNÔíö&“°ÇÝŒ¡¡A4¸6¬Z>ÆÆNW%V”:ÚÂÂiÖ×ׇà³ýFwW/úû«¯^»†D"L:û7¨êrÂãñ »««ª|b‚⦡Ȋ,Ö¾mëV,,.@uª"`fv.^@ 3¿¿ nê»[n”,»º*Æù¡òX1lF¼ °E¶<§D&~Xkëk…‚X¢SÏfV199µáVØí6á×ÒÒ\Ïy’fhr¥RIÄãq„ØŸŸG*•ÀX4ŠeÛìz~?òÜÓòqîÇýyçΓ˜Š~¾ÙëÅá£GákõaKà146z°ûq;¾þñWìÞÙŽ™…ß«¬è§qîÇýý›ÚE|cS#ÿ‰æY8¶=ìmh·[¬§(K@Q”Gî,5—Ï®Í ·ÂjµÂfµÝý¦*EÐÅ[ëù—Y0t”*º²¤JzÙ¡3V/îgƒÑíUËÎÄoƹ’a¬é’²ŠŠžQh–ë¥âºÁÌæ¢¬° Óu3˜‰vR-W*£ü:è1JFE’´J¹R44­XÓ}ü MÂÿÔþ`_úÄ¡MЊvIEND®B`‚virt-manager-1.5.1/data/hicolor/22x22/devices/device_cpu.png0000664000175100017510000000217312574335131025170 0ustar crobinsocrobinso00000000000000‰PNG  IHDRÄ´l;tEXtSoftwareAdobe ImageReadyqÉe<IDATxÚœUÏk\U>÷½ûÞ&6Š6œEhÁ]]ÔŠ]ŒMWŠ5ø£Ú¤Æn$%à¿ µ‘B›H@±â¦´ )ˆˆº±I“HÒ$fò£$™&‹ÎÏ÷ã^¿sf^ÌTëcÎܹï½ûï|÷;w”µ–’ë¹ç{ú1pŒüðÝ÷#÷;§½'‘=qÜÞÙ,XÿÏ|o8I‚3ïó833#óþÓvïü¾SMó·ß=Ù4óä[ÃMŒ‘­Ÿ3räóy»swÇÎÍÏYcŒ]\\´ÛÛÛvæ÷ßd>{ë–ÝÜÚ´ã7'l…vú×i»¾¾füù'›`03Vø1õÍåËOræ#Gž¦0X2ÖPl EQ$ jÕj5ªU*—«B¬T,ҷׯÓñl–º»»iphhz?¥YøW{{/ñK>ýŒx„H)|è¤Èq,¹£ i­)ŽcŠ#M>~—+e$Èó|º8:šˆ ›¨W¼öF¯ýê‹/ikk‹´ëîJÅ@QÜ`2kfP¥R‘(WJ4;;G7ÆÇéÚ•«*Y§–Æ ÔÞ¾Ÿ½¦.Xƒ¹ÖÆE2ì¶sÏô¦ÐÓä.ªqiõömº I€Å,O³õØýИ>¢L&C0‹Pn #ÙÇ‘Dõñ’÷úúè“sç¨ákjÒxøãó”Jù˜¬W÷# s„ã(f0¦¹Œï±ö÷j¬3râÅ졃)—Ë  ²],Ð庺¾DñvÖ7VÑ_ ;::h2ëŸ5žœš¢–}-°š}ã# @‘„"þÄHüQ’‚³ÑÚÚZr$ìj¬ÙÇÂ8Ÿm­I '0ÚHù †>‘MLZ7¡È7|,gG“Æg?ÄÂHšƒÁ™y hËî [¾ªÛ´nUN~¯ÆNq{g47ÿ‡œO<~˜J¥’tå2G™ªð+G­Z•΋ã°Þ(¦ž Ý‘DÆa¼,ºP?ðPû@Ûƒû/ðƒ_`ò"@eXqc¤RÜÎ|¬e륃µiÈ„÷Ö76äî¡Çº ª:£Œ½¤‘±/Ñ8óhtƒ*`ilŒ…±tœøh[O\ÂŽ@¿¢~BâŒ8gÆ}ûÜ–1>„‘ìë)÷¢ãi÷sÛNÜ[^^¦gŽ¥%Œ8)¿´$sÇ'&pi÷ùÍÉIZ^Y‘ytŒqEENÕZn!ïD'X®ñßrø~æ²8ŒçYßQÙžž‡á¥6ÇD­†ÔëxçÄUÄ5ÄKˆ—ÿÃüŠCökãèvµè¹NE={ìX‹ò}î)c°;žÂñ«öþÉþÛ% ƒ†$‚§Ã& m„m­­áŸ ¢¡Ã½9bIEND®B`‚virt-manager-1.5.1/data/hicolor/22x22/devices/device_mem.png0000664000175100017510000000141712574335131025157 0ustar crobinsocrobinso00000000000000‰PNG  IHDRÄ´l;tEXtSoftwareAdobe ImageReadyqÉe<±IDATxÚìUïKSa~Þ¹MÛJPWfJ霛]ÝDSÑ1…BS‚Š”Ì,ê?(ðSý ‘¤ ¨‚>™•XBF”¶9Ê"„•ÞVùƒp»w÷¾½÷ÞÍü õE¿y.ç=ç>çpî9çÞK(¥ØÑaŸä ñ–æžê§„Á`´¤ÆH’šn;§lìÀIIB¢lÆ_>šèÔéž:Ÿ×²=‚P%€]t{4Mª¤“j¶²Uä/Å2ùdÄ£µ‚R‹LeôÚ:ÀmœDwA+J~æÁ›Ý+oAÓáZñ9xµ4Š>{\›VøîïSè*hc5m9 °ýÈEBJ(9Õ"‰·Ï®n;gÏüœI’ Ä㈠âq‰„‰JjÁ²0ÚךUŽ(ŠŒc<‘q$Ȳ¤òLUY˜~=º÷ÖA”G¹5ØO¿W@e™Êj°‚ %-ñ·³¿p:P¤ua^]g®÷ö«í×{/Õ‡+ÚÁóQÈTRd%ˆJšfPD’¨ÊQd7ÞRì+¼}õág÷ß9ô¬b{ÂLqgà6?8ŽÃt0›Í†ùù9X­V,,,`,m7n 8@¹Ó…©)?öR„B3(.¶"‰`1+ª Ó®ö¸ÅWKK»Üð/O¢4›Ã\t–Ý”Õis9eñ!¦9¦gT_ÙÑr„V´³‚ò\f–§Õs}¡‹ÃñüÁ{¢SJ†Î;á4|Áp« ='²ñÂ[‰ŠŒeŒ´W¡ÒÌc´£—­Ç1è1áŠ-cÝu¸jÏÇÝF3®9òñ梒,n­£NfƒX‹­"Íìdõë OiÓìükÂ:Û-1iºpF}|%‡ðQ{Ì ê¦'þaïäøi„íÄÈc¿IYB†# ™{ð‰XgØ`X!É„F†Œ=HcDrðÙ÷ÄÅ×~Äì‘óIEND®B`‚virt-manager-1.5.1/data/hicolor/22x22/devices/device_usb.png0000664000175100017510000000222012574335131025163 0ustar crobinsocrobinso00000000000000‰PNG  IHDRÄ´l;tEXtSoftwareAdobe ImageReadyqÉe<2IDATxÚtTQL[UþîmW èF‚•Y•Òc‚ ÅAÝD†  > FãA%(É–ìÔíÁ™Ì0X2Èæ¤Ù¦{0>…IÆTd›…áËdS³a€¶ÐÞÞëÿŸÞÛÐVOóåÜžû}ßùÿÿþçHîAâèêìÆÇGzwÓc¡†à¸<=“µ«¢|…žç /ñ&ñ?Cúc7¡×jÍ®ßvÿvädç```Uå)˜š £­­ wîÞÁ­ÛKX^¾;NÜnÚ`6ÑDNøßJ¸Rìt×WUVã;Ž~z¥2Zö9ÄÜw¼O¬ó{æ1Ÿ²kM46ÕÖ=3ݾ-ÿ¤³È%ÛlyÐ4M Ó|žF‡ ”çbee×|ÿÀn·#Ë’…Ü›L¼†o.^øýÉ'j~NŒ˜Ó?AÆÈ̼Š¢ô÷÷£Ðn‰‹ÄQ¸“SS1óYÇzŠÜmðÌúÜûÐŽ‡M™‚lŒùy>üPU cCÏ¡ñÕ‹” m ««KpzzzÀ:Ö/ÜðõÒÒ FÄ»-–¬ú<Û}±( 8pP@’$a¦£ƒÏbüÌ‹8{j¯X3¸¬g½›DÄMÖ{­‡Ãq)ÓW_†ÕjÕû'šœDMâ9:6ëØguu…[t’Ù5ééq%ñ¢rg*Êܘþé64ŠÚ$>&d$Ý™ÿoÖ±Þ÷¢Ùd;X\\DÅÎ|ì(ÌEey¾qŠ0jxå$ÙŒç÷{c`ö3Œ-jD#`úÊ_dJóßàKlL¿–FIRÅ&íííq:öa?Ãxucc#ްgÏ^ Í‘Y*¾ÿqHRš÷•ÀóÒ.œ»Fµß§a°ûÆóÁ` ‰¤Da\ý¸-ú¥è¹ÕS/¾šÅ¯×47·$iØG¿KDWL‚Ç$)þt—–”â˱Y¼¼¿fS*•% ž>x<”•!©‹x¢Æ†±7¸èHKÝGr¹\ÿúBáEú”ˆzͿ׉ƒ|xò¥˜T”ð¸?°–”ZmmFÏ]FÍ3E)TUMâ`=ûW©‘wpÝᣚxúly6¤˜ÍeʈÚxèôé$ëXÏ>‰—ÐáÍP8Ú†`àä ®Îý†ãÇÞ£ˆÓðù±N¬‚8;~>Æa>ëh¼¡ûÄŒ%½ÖcUy?¤Õ°5·¤oÁЉC(zôÑnEE ÂFÀ5%óIG;c”}è®7ßn†ùyÂ-U ¿EB•¦©â0ðA -zP¸Ö•ºBÒ.Ñêg„Kº^N,×gà'üBx‡Do»œ?ttøn,‰ˆ} Kèè<t¹“ô¾xïfk„AÝ|kºq@áa>XhÿöæÍ?ê^{ýƒ&JÝi6›¯æäfÐúwº‘_×q‘¹±#ÔÂü_'Σÿ9÷46ÓVè?çÞsÿóÝï~ÿã2¥neŒ1 ‡Gö)n?¢ ç™ÂAÉÔ ƒšJ¥ß,1kÚ†§Ö(ò ×”d8¸ SêÑ»ï>¥ä¬ÅpH1u„@Xö9Ç}ÊlØöâ‚«{ a´ÃÞ_Y9CgŸ!/ïœÍö°çÞ ‹WQÌ7PÈoÁMŸ@*ý"Κ!6o!ð¿ã¾ïü÷Ο¿¸¹¹©Â(RQ˜xt½‡*ð«*~¤†Ã3JŠ5R/R;› 3IGJY. xíõwñ}õÒXÆGïïaþ€‡ù9?¸ÙÜ 7Î.1GÎ…}þÙ§ãg’>MIÐK!…Ä¡ƒW‘r~ÅôîMÁH§÷ÂM=9Vð¯Ñi¿K ™MÏow=´;]´Ú=lµÚ8¾¸ˆüäú}?´IËJ( †ËD”!aµ:ø­†)–†µëNcáðQ4þí£ëõ°+Ó¦ªrv(Í<úCŽ"ž0s‰ˆGF¢ˆœ±)ò"vçÍ 8rºC:û-U˜O/?N1YÚ|^÷›˜ñp00€~%ÀÜêUƒ÷€YûÀЗ-4¶j°ìÏ(þc8VºÅ‚°@å÷&2š­LÌxÛ‚04k¤#b+8%CŶJXýa«?þ„É\4ÿ »²%1“òº½Ïqâñ'H²,16ŸËÆ10'ix¢=§ªèP2ßùð½H•ábïô]˜œpÉp¤\ ja°ØÆcÇJ¨ÕêÄXh£Æ1°Äv)žzù,šíŽ)½Ú?)bdS÷EÈOpÒVA›0dTA)xýÃ$ÅÏ1c ´07‹_~ÿsl¦ý ¹ú66êÚGãæöS¾¤‘/)·¯¾té”›è©‡Š¬­±ë)§§¡iãºâ/35…¨×/›{Ó :IwÒ4¦f\m4e“}¶='邆.FFu²‡da0Ú2ζç+šÍ¦®ê!táË/¾ÂÍÆæÿ´*ù6î²¼ü¶žFåZ­vn}}}ìé™™”J¥%º\;}ú•OohíÿW*K©ä¹Bž:‰’麱۶3¢!ÍiS¦—¯è¿[ZªT*×ãÜ0I<Ï;¦çD'H·c®ã–oÉøNÙ5d9XJ%½*ëIEND®B`‚virt-manager-1.5.1/data/hicolor/22x22/actions/icon_console.png0000664000175100017510000000131412574335131025546 0ustar crobinsocrobinso00000000000000‰PNG  IHDRÄ´l;tEXtSoftwareAdobe ImageReadyqÉe<nIDATxÚ´U±nAóCEJ[Ф‰DsBâ'hLA€¨ˆ€"gA ò´¸¾Æ  BB²‹$22²tø|;;{ÌÌ®Ïqp)ÎHs³·;÷öÍÎì\TU\†4à’$ysxøŒm—5Ý怵Ÿ8çºw»ÝôÚö6D‹S‰NûUPU‘NÉr(ë?Æãô]¿œ¶Z-xþò5||¾ÕÛéMxñô!fBD`-)èý{w¼‡ Ê‰8r:Gß­!0Ö¢…’ÕÔÏCüS‰üBžjuÑYž¯xŒ`esd`Ç ósò-ûΊy͚ؿ¶ÖêäÏéÔ/*ÓŠ“²ÆŒ² [Ã, "S²%(KS#Æ*!yÆ¿cçA¬€‘²F딀ªIDá¨xó…XDõQÆÅl¦“ó° €Öƒ“­Ç¡€QÈGuúŽE±d¼ÒøP@Ð’õɆK)C·¶:-}§gïýðá–DI ô œ¬¼Ê ,¢Ì£¤?>9V¬gÏêQÑ=²Ü‡ÛHs€¥ÂA ÂM.8Ð@ƒµ‡ÕJ^ཛྷF½ÉÏ“'fw>}÷ûuÜF;[]ñã‡upëL_8Tû§œr`s Ë+6d~ñ%<ûò´sjGŽOÝùÚ'툈x,‚Æ’ƒaÙ‹è0x>¤$Öâ³ÌÁ:ip$"ãdC¶u#Dœ>o CªÉ  ¹¼x! 7{CêùÅÜ:¸üQN"ð{Ý‚œ]¢eøÛ³xñŸâ¡×dÐ+S^qÃt`i•m/<˜˜Á; íÝ—ÁS²Õ=…Ĺ >´ñ7@*oÀ++:…ÁgUýáþ#07~± <7žÀ³£êSd³¶„QwV¯¦é³|ÔÖÌâÃ>Ö ügJ¹¬ó©0‡™†¦(xİC Ù5Ióâ~þmrvÇ!äœQC¨ÁC¸±3\.¶u ¨î¡n I÷ÓÛxwej×±éM¾Qc3èe©`£þF nMEl–M yS@ÞpƦ‘¾6»§yL«qàõž½ù~hïƒþ¿þÏû+Àk…Z€IEND®B`‚virt-manager-1.5.1/data/hicolor/22x22/apps/0000775000175100017510000000000013245574323021676 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/22x22/apps/virt-manager.png0000664000175100017510000000252312574335131024776 0ustar crobinsocrobinso00000000000000‰PNG  IHDRÄ´l;sBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<tEXtTitleD1½tEXtAuthorLapo Calamandreiß‘*:tEXtDescriptionDistributed under the terms of LGPLv3/CCBYSAv38€gÍtEXtCreation Time2011-03-19é¯ctEXtCopyrightCC Attribution-NonCommercial-ShareAlike http://creativecommons.org/licenses/by-nc-sa/3.0/ÞåÁIDAT8í•ËoUÆÏ;o{Æc{ì8vÜ„Ö}„RšHˆ¢Š .ÜJ] RÔ=üˆ¿€%bø ]°C‹T´´‹ÒPh›4RŠ'‰'ñ#®yÜyÞË‚¦‹–eÕoy޾ßâHßùP½^‡W!î•P_ƒÿ0y¡¾8FaïîíÆ€ù®Î!Än"@!à0ÏcÆ0F1ˆ±ÏCßa‹@)J(p—Iͼ‘Ž¢ðÛ‚™U®,Ì.œ?—ÍgÔܹ³§ô$ _žbÿà n?]‡Îò£Ä'þ'º®cÏvÛ·îevšÖþïÿÈ„q Qã­í¬¬üóQ C€·Û;pÐëóžç]›››S8x7ù©ŠM[»ϱo”&&?ôž' ž?maž‡þ OÂ(EQÏsÏuž ¢ ýÕ´Ü  ¡Ì±67ï°7p®ÿöÜHÑðUàÀw\ÍqܯèÖ®ÀK"ȵª©(2,ÿöÀ%„@6Ÿ ‡C8´‡±¢ÈðËí;]âûP,˜Á³õg ÈRÆ#ΧÜÔD鎅¼6Y†Œ%Ä#ï•°X”ÌìPѵ3²,»Ÿ¬šÄ÷A–¥¢çÖít ‚ 2«ÙÙ6¤3™üp4ìT«å”çzW‹Åb K’Äco˜Fö­’’ÊxˆöËHH±©òª4–/û>Yëw{¥riÜ͆Ê(ë8®“àçbèšn—ÆÆ$×u×4M«XMkÑ®ÕjàÇÌMxîã™Ê YÄ”Ûî@zî¢'ÊR®½µíV+•\«Õ /]zGd‰vv÷¤€ø©b±Ý½N03;#¥ÔTÔítŒ0 ap0P9€$pmíï"*ò`¯o’%¢jZM¥ I’S‚(Æ««OÓ”R0s9]M©`ÍXz¿×Ë•)Û¶‡Õê Ã÷ƒk¸V«ÁÒÒdsæYŒÐ…ñÉ*§¿}f”Î*bl„1§®­­vÚí^e¼,ÔNׄ‚iR]×Õ´ìæ†ÕáyOOO§0Çâ(ÔzýÞÕëuh4xòäÉ…ïQ8eÀ€A’PÅuìoÒšþÇq”1Æ(¥ ð¶=úZÓ3_"„b` `cþEPè–eýdùÅ$ õc±gŒ¡Àq·}ß¿ÿâ¿ #!¤C¢è>fLx™:Ž;DG Òh4Ð1Óq±ÿØýÛœ¡×Õt¤¿\ÓÚ‚ce°IEND®B`‚virt-manager-1.5.1/data/hicolor/32x32/0000775000175100017510000000000013245574323020735 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/32x32/status/0000775000175100017510000000000013245574323022260 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/32x32/status/state_paused.png0000664000175100017510000000163112574335131025444 0ustar crobinsocrobinso00000000000000‰PNG  IHDR szzôtEXtSoftwareAdobe ImageReadyqÉe<;IDATxÚÜW½NAž½ÒR‚ý FJIc‘P¦åR)´Ä8´¤} ñ„¹ £$¦ Èøö63³;wËÊg£ØRÖº›½ýûæ¾ù¹±2ÆÀ<[snsW ùppð å&^­cwñú”äy¾¹±ñbme¥ µ™ wpyÙ[;9ù :akyyÒZ Ö!/R`ð§œt¦Œ[¡ðŽë K™“åroÒŽã°3%lb’$…\çð|}ÝnÄCÇ]þ‰"’á%ã„!c´çëé©Å$lÖØ½—–– Š"4ÇBæ·Ia[µg00`¿ßG©™]ÂN4=è ©´‹‡Ã!oÐZO›+d/I:W”#è} ›M Qp 0IÙàSú7àþ~Ÿiö‹Â2Ànç½¹Ø-¤½ÛíýV«U9æ’$³ #™{áÂj©Ae²l¤Cb€h­ —Ωù… h,TÄOhš#Íó¦M™¥Úi›.ç£<pq9«f3¡¤b-¡§f§€Ÿ ËØWpttÄahÓ&I›B#쫨L§á5*gйyN}+ùûAû××V¼HÅV£««~ðE±®1Ö+”ÔŠOj0U%…Gðsaþ<òÇ(·›ØUö\sß@¸ Àr®æ=ÊHy•‘7 9› Bº?üâ¢Dè2¹û* mB!™‹æŒ.žKº5Ø— úeNÒÙÌ8>&aSMxxüùæTª‡Äýþþû—(ž]\\´{½ÞصõzF»ß··ß|œX¸LRàÝÞÞ.ÒÙ&S­d¦²ìu5³qiqÌÏqwÞîììŽýc2IÃÛ›ÛöêjŸ.B +Ù´Vƒ4E‰ý(‰!ÆÐ$›SMA*H†wCø}sçççmNJó’Îø¥º§gtÏ­HRÃÒ¨×ÔgÇÐ{}íÍ“° X`ÅÚÝT_ÇuÕë¤ÈDÐÒ¤Tÿ¤ #éú",Ë¡€¹ù" ¥`v ;ÔR©'\XŽX‡Ø)eåröH¼ø¼Ï¿@hTh4†".”›oÇäŸ fF»@`'"ób‘Ÿiº-…–â­uµp`O-Ôo«†[?ÁÇé…2Ú™b+Æ€­3k‘à¸p.ˆDÄ„¡ª’-Ýq!w=º®„‘7ÓÚи­ÛpÔ¬è;!QfW\iEI§ä0¢O¶ì†Æí[àÆðç{ gÎÅŒˆL]@àRâúËH¬¤ VZ÷ça׎Z¸x÷5Ìü\ß°ìâHh6„0» 2‡ÖÍöª´jKqšp0ªôþÈàiB3@Å(µ«” #ÒÀï<™‚kÆy…i ˆÆ"ÚÇd„Jó¥;V‹E¸ro¾ú¶¦c˜¶£e &ir¢(šFçË©Ð3øÞ~_ó=@óY<Q¹cV¬J2;÷FÆç¡oè=3ö§BŒs ÛàmèU¦¸’ï}öW·!Ÿ;xô–bÀìË}Ú£˜¶¡îòÜâ'¡¾ ´=Çòàû>Ï#íé6Ö=S÷øZ./Šã¦¼Ð¼¼}•ÖÜÆºBÐÙ¹9m€tG±¶hff6‘1êÐH Ïæ Ü•šè*%%n/˜»Ç¸€¯GÊ”Ô/°Éô¼ªÜA8ÀaQäÙÜG9;J9ËŒb Ù>Ò0ôåóWNJ,]ÊžV–6K¡4÷¼®]¢[€^L¢N»Ìh}¯è6a6å„ý÷`“²âþ5}\ºt¹UóÄÄDarr2ulCC466vaõÝ™3§oþõ‡É…îîóHg\A´’›Ji¯É™)S6uÊ üL†Û™L¦ë\gçùÔ“Õ,\Z\*ìÛ·j¶Ô`>—Å”:Ù,j¬ûA“LãQNA—L†CXX\„±±±N±~NutT£êz<:ZX§Ÿ»þœ®&¿ ó@-¤˜…4žžž:Ù¬œ@F’:IéBþä'œÂúçp8ô¿ê" †•sjL­Ž{!@™øª0ð‹@F_Cº‘V§Ówºvìr¶¡+À Ñ<I’ —öðbmmÌ`>–•••ÚÖÖÖÃLÅœÀõÍͧëFãëd™– 4uоìïí}ž+€óóoÜÙyZ­k Œµ°ÖÂ1Fr6k¡'Y–A3ů‡4›Mœœ|œ*0ѬäþþÞ‡ïWWO©ó»££úÜ%øïÿœþAÿ‡æMY%|IEND®B`‚virt-manager-1.5.1/data/hicolor/32x32/actions/0000775000175100017510000000000013245574323022375 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/32x32/actions/vm_new.png0000664000175100017510000000310212574335131024366 0ustar crobinsocrobinso00000000000000‰PNG  IHDR szzôtEXtSoftwareAdobe ImageReadyqÉe<äIDATxÚÄW]lTEþæÞÝ»wÙ½”Jµe—¦€€„€ñA}èƒ Æ_xñ•hBx°Q^±TÞL1&þ€Q¢¨Äà‹F~ ÄH” òcƒÔB¡Ý¶Pöîî½wf<3÷n»‹›‚-âlnæÎΙ9ßùΙsæ2)%fÚcº§­Œ\nÕý¶-–b>“˜CS¶ž’Òe0Æ8Ø`Zˆ³¬îüˆ^{·(åãã+ˆ1¾R0c!o&X `³fÄh~tŒåHz@ q±è§çÎ=×Ã]jÅâòLŒÉUdÎ2CˆÅ‚!C†7Z‰W³Ì˜o– Ï÷I°«„v.õI;. ¯¯È³;wn õkéiŸ®òXŒ£©é/Ô× £¾~u³GvÆH,ErV/I˜(ºëá~Äøx=®ßh€ë:}¥’ýuL±¶£ã‰Ç,ÈÐkZ¤¼ ü!ÏC —žfâÖF­\5ËÞf¼…¤ýÓ¸™on;wvlMŒb ½¥¥…„ãã! (ò*ýXÔ—­´E*ðH^*ÿ‹aê¯Ó¸@FtC…ñRÒ0š‘°ß¡7¢^\&™Ï !GT …qŠu7G†,C=¦¡{ƨ7˜þ¿Š@´RRú5:A …¸Pø‘ò² ä$ ˆ…Ú²]©¿ÿ‘& ÈÄè8°TÊ¥¼ì oÉ-Ñ ð@F ð€˜BVZ-CÚeŸVÛÿÕ!ìøä ÍbÒvÐPïSjˆ©ãÆór£²$1>Oc¥;Œ2ô‡Šþ*ÅåGÈè8VP.ëyïSz5-?ó˼ûQ/~ë»xÇuCø¤>C¢½œôÔäTT«–ÃÑãßãÃÏökþmSŒ«í•nÍ€>†,T&œ©ÛÓë:gtwÐyG²Šàîe㟌} µOؽ¥~í‚°„v½½Y—â°‡åWéEïår\ùÈÊÓ"+’˜>º¢:›’ÒÜÈH@ˆ² BDÃù[n›ahLym*u(ÈjNE•w¨°ö”] DÈ€B«1Dw¡ò¾²ÚA$0¡‹¬¸–«;”,¯Gt—b`J+&©)ÝtÇ®\¬*@*é(·ÈÊ"¤)U—š“|bW5DUÌ|*éy×Å©S§ºh‹éx©³S}XvŸ8y²kš~îž± þëfàn 0ìÀÌ‘aIEND®B`‚virt-manager-1.5.1/data/hicolor/32x32/actions/icon_console.png0000664000175100017510000000207412574335131025554 0ustar crobinsocrobinso00000000000000‰PNG  IHDR szzôtEXtSoftwareAdobe ImageReadyqÉe<ÞIDATxÚÜW½nAž½;; ð‰ó D‚Š4)HI›–Q‰tQpLDèHADxƒŠT¤É#PÅ?Rœ*ñÙ¾Û]ffg÷–9`[â¢óîíîÍ7óÍÜÌDYka’W¾&®@özgç!Ž+x/{ï™1feyùÞâÜ\¦¦êcAî÷p|Ü^ÜÛûáÒìì,Ôê5p©ø‹JF¹hËÊ …¿xÞòè÷üÕñhÓ­ãa!f°‰ȲmàÁ£uI‚ò$t§ Já˜(^÷{A |‡äÆà³5`hç†× ß1R”÷öÕs‡Iجqâõ^º{‡ß¼qÝimÖV¡u8ë-©„—¥v£Ö q^ Å D@œëŠBÃùy?:Þ7¸O\v¦éYÇœuóð"Ê Æ–2Íd%Z¨Ù2ÍÖ•%‚áM ”JŠÑÉê£Bgg9ÌL×YFØ™§„nÞãçЏ•½G@L©P­#Zõ†ó¨½Rš"6esÍ  Á¤!-Ð ¬€qB¬Xg„n«ØŠ"àÀY¡]—•2š¤Ñús†õJ’YÁBmä bEœud­WЗe¡ZØñqa}0r Ç$þ[4,.`ã"ÑMtåyŸ7.R[cLÙÌ’Ù0¯3kj ¹£UÂv_A)%t{=gÀÅj+ÖµV¬÷@±•à \¥à9pÄ;¸Ñëõ˜cA»y°®úÖýwþ7•À 30Àt{p¢ßûrT+‡+ U HåýÁ Dì¨V»´$,ˆc D¿(å}Tˆ…WÕ¬ã$:Ćʮúâ¼cUò]Žër™Ð§bI›¾xŽE8S)ðæå:—bWŽ]ùågœ+™ûrßþ«ˆoŸ%C64.·X휞:LHÅN£““ίª*CCQùžƒköo·ª¦Ä_î9¸€Ë£”X~‰€¥CP¾ˆ%ã€E]ò½ zT=Š:£h\zO†ýo_¿»ìç³e>ÊVž¶(÷kΊºªn¨h®¥®pQ³¡Î&aSOø~÷ã.L¨+~¯þ$Ùlo¿¸Ãí£££f»Ýz¶ÑhÀüü| §_ÖÖž¼»Lö¥ <ÛÚÚD:›ä #EÕöJÏL²Ì]#›òs𦭧›Cÿ1¹Lü›7nÁ̵¨c'[«×¡VÃçI–BŠŸ&w9Rd(•ƒλ]8<4N$ùð‹~ 3¿ßg˜a`È¥K—ð<}®ÕO'€À {õ'—¯“Tå¿IñÁÏþù·§Ãýø§¯ªÞ{:¦”€Rz®”J“׈FÿM¡>¢Tcøÿæ4„hH•wæô©W®]»–¨$÷ZºÙÌ’¬˪=à[@ŠèwlcwŒ¶zv‚Ô{ý5sltTSJ¥ëëëü€Pª…æ»i„ÉÁá¡ñ¾4[ö}Û[ Õí9”¤ lÿÑò“Ëþ~@})ÿrGaýÓlõ“ ¿|ïå—_= /^ÌK×ÿùÆ?>YûÏVßÛùòñⲆh¶Z¤Ýî{óó¸uû¶!=9âûò YÃÐÑÜÛCÅô‹_àîÝ{¤}°À÷ß:~ôþç7oúHúz¹¤cp—W7ð]/ú…ÜÞÙ¦*Óuèç& í6 n€&&'1P( ›ÉÀóÇ•r—Qšy²±Ã00dÛ.!ŸË¡ßwl? .O]¸0tÒ þ¬&+ÛÌÐúFEzî•Z­F<ÏûZ¬—™¡ƒ ÷x.ó}]×ñðÑ×½ †tƒ;=§‡^§SQ*I9ç¸A…a)=BøíNÍM”‡ì0vä/Ÿ$Þ‡^Þ…,ÂHè8ä×oÿöÝÐsÇ G5]‡1;½.‡ssw{2 ƒ•ê Ín¯‡N·cD±FŽz}yisk 2ðBµj8}×ít»xñÅó™À÷ß|°»¶Ö|y;.ÂÂH ù¶kRþQ´V~¨Æ ˜•qÁ9çý••åj³ÙD†Ð…‹£(q=Íí&œc¿Õ¢Ë‹K‚J%Ô0ôÇ}×Åââ¢.]otp°G¿\Xèo66?£ˆU«U{¤\&h”À¶m¸®‡ÏïÌéÒsÿÔív§gggòBp#Š¢ÒT0ÆòK‹K•\6ó!;ö0iûíƒëŸÜy‡Ìßö‚hP€a‚©RÊò<÷¿Ó[W¯^‚+¤ÇIœ”ÅQ¼Újí>rœ~é÷_}Õ@’$&*IöMÓ²:Óß8HšÍýëœS-MSààxK(ÇqRJWé7Ò4ÕŽ¯ C+ ðÕjýAÓ´Ìá$!$aŒv … rø_P«Õ€ Ï”þê›þé="ÇÖ< r(ç9ù˜œNÏð?¤_­² UçTIEND®B`‚virt-manager-1.5.1/data/hicolor/256x256/0000775000175100017510000000000013245574323021115 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/256x256/apps/0000775000175100017510000000000013245574323022060 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/hicolor/256x256/apps/virt-manager.png0000664000175100017510000003261112574335131025161 0ustar crobinsocrobinso00000000000000‰PNG  IHDR\r¨fsBIT|dˆ pHYs × ×B(›xtEXtSoftwarewww.inkscape.org›î<tEXtTitleD1½tEXtAuthorLapo Calamandreiß‘*:tEXtDescriptionDistributed under the terms of LGPLv3/CCBYSAv38€gÍtEXtCreation Time2011-03-19é¯ctEXtCopyrightCC Attribution-NonCommercial-ShareAlike http://creativecommons.org/licenses/by-nc-sa/3.0/Þå IDATxœíy$W}ç¿¿—YU}ŸÓÝÓwÏô !Ä=°°6lƒF¶Aæòµ^‡½Ž dž#v7b½Ž]Ûa $ ƒ8$³kͰæ9$Ð1#ÍÑs÷ÝÓww]™ïí™Y•••uu½>¤ü}*~]YYYÙï÷òý¾ïʃNœ8†a¢‰Øí0 ³{°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&˜õü¸ïWºc LHhJ¤¸ºrëûÔÊЯŽÂT¡S@G¾{ìC¿ü¦D"•DùŰ߅¬$ßÊS'Obnn®ä÷µB‚~ÖÚ˜¸}Ë;aìȱºå–›ï(JU¾Ï-ÌãÔ??Zòû­ •Z[_¾1044´¾åì1ê€Ù7ŒÞ~òÊWp§®HXº À_jܧ^bêPz[OGúÍ‹KÊQ_Y¥ÂáëC¸õå·âßÿAÅÿO¾¥Tp»—wtô[^ž{¾âN« mh¨kyuõ­©d-­­Ú|ØßÎŽN¤Ò©Ši¨Öw­‚z>ào*îôEBý…˜Ä} @§‰Oœ:ujëR½´ºWÀGtú«Z¯¡¡áu3ss0ˆ@Â1A"gD"‚"t½÷›Üo…€##£hnn†! ˜†YÒ a„ZÈvb%¹ú;ºòÓøm"jœžƒiZ}¿éر’~lÅwÓ0ÑÔÜx.ß÷u ÀµWW!è|aü·{oz›uÓ¾ÏþêÕémú–—ˆH¤Ói¬ml@CNA6òfF®p{f†cÂë}‹™8rô(LÓÌoëšišUYðwBჷÞzks½yyüøqE÷期Nß_vëËǵúÞÔÔtÄ&óDÝi`:t¨î´M¯š z'ˆ Ë¨u¥¿ýK|ÔJÛìÚßш6_ Ãʾâp;5048)¥Sëùkº\Mè-jAÿ6¾ïÚÛÛpéâ%§vôU0 JšQh jÜØLNfRÉד—))~‰„#J)446`_w·Vß—W–°¹¹YäÃV}7 ‰žl:õy-j—ÑÒµ²ñ¿'¢dð`Õc ºãÀOfu¤O£?›ºUý~ZãO“]Þçù7 ¥ á6eƒM\ggù äY¾yììƒÐÔÔ„áÑa˜†áX•µ_y¿5 ÄLJ©Ÿq®ö£À:gz,‹aìÀâñX‘ÅbfÎLÓDÌo€É‚ ô¡“'OÖTŽ ¿S.o.^¾ŠD<®Õ÷—Ýr b1S›ïÉd ]Ý775µߦb·#h™ôXèÈt̯áU @“‘R*»ÜÛò˜¶„ÖHÇüÆ_€ð2m> ÀzíÍ !šK‚B{{:;;µí‚©.o„Ü;1†È©åÈg^íW0nhmmÅôÔ ï$¯™ëZñ›S»¼àsÿ§›(Õþø·¾szqaþL5yÙðÈ›HàOË €e[èëëEKs³6ßcñ8–—a[vþ :|€Æ†´¶·íŸ›ù‚¶Â¶Ãh¿È4Ô}z[ôáþ³éÝi­†ás“}$è}:ýÁPï<FO¥íž;síí ‚;&r6œ;·ï~;…ÙÌ^¹Ú+†˜i¢­­ ƒCChjnBcS#khlD¢¡Á±DñDñDÜ­cˆÅã0c1w Ì× 0 Ø–õÉjóÓ ”­ý={öôtvthõýØ-ÇÐÔܤÍ÷••Uôïßÿö%ËêÞÎ2¸hmÀâ¾ÖéÎ…Í_Ñ sô´X“©Òç–{šŸÑšØ*Ø7›ü½]£/¯=6‹x¼³Rd³YŒƒR ÈŒ‹@SØÈׄ†¯ö3 ²œ1L X^ZFÌ4w›¸†ˆyAc5¨áÎà B|éPJŽŒ8úåééëe/à=v¬ Ÿ""£’ïÉd7ßtÙlF›ï-­-˜Ÿ›ÏËP¯ï–-Ñ××k˜$ÔòâÇw¤@jf[.&Â}¤s6ªº–ÑEÛ©6C@|B§hk¶UKóÁj[ ?}æYtvt¹-!w: ns×kþ’7 n€È=%Ö­½eCxM^ûzzÐÖÞæÖvq$âq$ Äâq'(b±\pÄÌüïü•}'‘±º¹üû3TâD«ª•àÙçÏj÷}dd‰DB›ïóóóèïí»ëÔ©S/ÊKë·%ÑVV|„ãáø‘ss·mGzK±oøÂ/)~È£cWýÍØJ695íœëȇ#†ä.;qâ6‘‘[—[ëß úûûs}e"÷a÷GNMKnÍçþVBPîûü¼³ ¥~õ#ùHc©¼èãµø>11Ó4´ú>44è´4ù¾¼²ŒÎ®ŽÞw½ï}ï«¿Äí<Û"WnÝ·IB|^÷X€T;Û †ñI­>ÄLˆÁžý5ù,%®\»Š††¼©¹ePp.]UPPJAúM*ØR:fKH)a+‰®®nض +k9ï–˲aÛ¶m;&%”tö¡¤‚R€R€Tβƒ9¶-»ÿßþõÃ¥ò’[ÞGDýµøžÉd195¥Õw¡¡± Ù¬¥Åw)––—q`xôt—¿`Ûš-DÛ0HâÎÛ.¯·nWšý™X' éÇØÀ2„h¬õw§Ÿ?‹÷F! *÷ž/˜Ò-¬Rú ±mò-Ø– ˲‘µ,DzY((´µµ!™J!•N#J#“Í"ëš•µÜÀ° mé”Ì]#¯Ü@(¸bÞ–%OŒUþù~úy46z×Iéñ½`©TJ›ïKKËØ×³ïuËÉäaEpGØ68xß³ŠèNJ›µld3¿±]iö£”¸Û-…úÒd$»• H&“XZZ†;…|¤  Ý)`ð™-m'(¤ Û¶ ¥ÛöÌFOo/Òé4Òi'2™ŒV>l)sä ȧA9fÙÖ+o¹í¶×óòàM·¾œH¼i+¾/®¬ ¹¹©Õ÷¦¦F@)m¾§R)(¥èðƒÿaûJäö°­†P÷ê@Úö3ûϦ¸KgºÑۡШ8õWÊ^8{‰DC®æÉÕB2ß,õš½JÒV¶r›µaf£©© ÍÍͰ¬,²Ù ,+ëš˶!]s‚ËvƒÉvkB ¥ì\ðy"ÜÜü½¢r`ˆßÝr« ÀÙ‰ í¾ äüÕáûÊÊ*:Ú;~maa¡i»Ë§N¶UV­–‡@´X4V—‰—½°ø†íLw«±ù«ukM÷ѳõtæn, •J!× ˜RNŸÕ1™7•7)‹m``¶e;M][ºËŽå›Ó2×ÄVÊÙ¿´Ý>²í·Þ²Õ{Ž?Ñååå±cÇ:ÜYïׯM:§Ñ÷þÁG$4ù¾±¾ŽÖ–––}}ýwmgÙÔͶ ÀôÑDŠ >[oß¹¨V ±­ƒDÎM*´¥·©ÔÛÙ¼uU-¦ p}jdˆ\m+Fpî³·F:ksc嬧·Â4aÙ–-aûΤr–ƒÁcKéÕº^³ÛÛÞ²›§f.|ÜËK+ÖpÔTïYÛÂÌÌŒV߉Ýûºs~×ë»-%Ö7“èÞ·¯¨´—Ùö¹K)èSÚÚÑyûÀË.-ìÛŽô™X½D¯Ó™^:4´FD¢^!¹ríZ¾âòÁ é6‰=“20"^Â@„ÁÁ·–´]s u®öË×€RJß¶þïÝ&¸3(w×É“'éÔ©SD-bzéêUBhõ}|ü¯…P¿ïÉä&ÚZ[Ž®§R[¾OÂN£ýLÀ ‹‰…ž¥ôÏaLcL™R™ ‰Ê·»­‘}+©ÿL„WjK«! ^«Ee.ü©Ö¤”hmiF¢¡ðÖáD nX”õŸ½­››špéÒ%_Íéx;Z‹º/(™ÛÆ{—RvŸ|ìÔ¿¾ù~á~_‡d2tïëönF¢Å÷X<†©ÉI¤3i-¾Û¶ ùOB§me÷ÜíìÂØ‘³—‰ûtÖ¨ ´ß9øçÚ‰èƒZÓ9Ô«È4J^ôS«]›œÎD{&¥¿ô¦ÈŠ-Xzëã‰z{{s}a¯FóÍrM`ÛÎ÷må¶I[5•ÓéÌ=ÀÖÿÂìâÅKù@M¾—Žz|ϤÓhhhx×Âæf¿Î²¹]ìˆtÅV¾FDó: ÿáMoÐzçàT,ñ!"jÒ™NãèØŠÎý­¯¯ayiª°äŒÄ;ƒUµÙððpnðÌ ï;p8ýcßT›Ûö¶ó~“ÍÚï$à:}ÿé“O!›Éjõ}ÿþýÂ0ĺ.ß-ËF<7Û›_·ßxbh(%¨zļJS z‰>©3}ÔÑjo ½ñÅV žyög¼¨¦ó|×òR]hln‚åž)h»…v}í-‚p“ÎôG†75·zÜÜÄéçžÅúÚ†Ó.eª²æþfttÔ7fÔvN0ä¿óÃr5§o{©œm××VQp?¿:l~v€¢§Ÿ~:ßü×äûÈèX—’Rêô½!ëkíèÞó×ì˜<3Ø:A‚×™†–;“ZÏû‰8hxÝA›A6káÜي溃VjÞ¼`þÜgƒƒCÊ0ŒÂ¦¯¿9,5×§–…MfoÛL&ƒtr³nŸÂìÌŒ"r®¾›››Õê{¢!ή®…¢f¾ƒ€¦Æ†ÊWHî2;z #ÑvÜ3>v<]߃o»¼>@DïÕ™.:0¨HSgðK)ÕÂÜ<„3gÎÀ²­²sÝþScìhn\  |@øËò}æ©3ß@ÙÊÒrÝ~¯,/!“ιמyîtÅyþZ}?xð`w0èëõ=O¼asÓz¹®øÙvTZ÷‰"¢i͵âÀÚ‚¬ëÎÁVÌøé V!`MÕrék5vcalÛ¹¢meu ×®]¯TÑÕl£F!¡àõ‰~±ï™¢QrÿÉ3î•wJå~³¶¶Û²ëò{vf¦@\Ï;L*­ÕïžÞ^ÃŒÅVm%µù.„@¼)±§O ÚQx"‘°@ø´æ±@€°åëާÓ&>¦3=b7Dc¢æ«þ*ÙÌôt.…3§O¿¶h¾}477£««ιîÅ}béõ}'Ðøû¿sûÄK‹7¶ìs&“ÁòâbA˲-œ=^»ïމ"êò]"3ïL§Ó[-ŸÛÍÎßÅÄ2ï'ôšsš^o½ùzzKg4­-ÈwhPgjŒ#cézN} ³õ5lnlÇää$––Vò5™Ü¢jñ±±\Ó6ô\zUxÊlQ_8ð»ÅEçr­ø=;3ít©væô™Ü…@º|kQJÙ:}¦ÙHñ†»t‡‘.v\ž‰]èÑJ}èLck­!Ä=:ÓB­Í0z;Úkÿ©™"¡QRáü¹³È_üR¾_jÞo}¶¿¿ ‰ÆÀ`Xåyò`Øû]6ÁòrícP ³3³*LdW–—1;=£Õ÷D,†ÞžÞ•‚ƒêô]I…˜0ïÙ«»ßû˜‘Ð~³€>|¼Æ;ß69 ¢·èL‡yh8ÿ:Mf[6n,,„~wáüydí¬ï4Ö-ð’îìøØ)³ðZ17èVCújÄùÙ™šý^\\„•ÍR©ïŸá…À)¼õû>~èP—¿¿¯ÃwaˆC?÷ 'öä#ÅwE®íþg\ÓÙï†@÷f§ø@M ên·BÑ“†˜óà¥[Üæçg!¥ú?“©._¼¬m0Ì;­~tl *7ž»µ–^Ü»N>0o^8‡îünmu ɧg¦§Ëæ÷•Ë—‘ÚLjõ}_O‰øJÞïú}WP0LÚòs·“]€ÕÕU÷ëoTfàñ…xH|Xkí?:Š™Z§þˆ3SÓe¿?{öìÖÁ¼ËhÓd±xÜ9=ØWÃyMZÿu÷¹ÓqsŸUÁ²ÿs%?ü–J¦°R¡Û ”Âù ´û~èȑƢÚ]JŸX8ßyj™ÿŒ‚eÿg!Œw&•: 7’êg×neLŽØšƒåø+æ2UÝ9xSnþ:•x>ÝV-vxÔ {àe=¶¶²‚d2Yöÿ...ba~qËaPá•ìø¡C…¹ð‚÷2\¯öt)(üÞé¶ä,/ÌÏÁ¶íªüž™©N,Î_¸°õ@Ÿÿ~CP6Èy1(<›Ð/Aáð­qaîø­í+±kðt¯˜èúú®Qu™LšÏû=0Ú[´×þÓSÓ¡3 þpáüù‚૎Â,hèêìÊÕú^€œ(S ùSq ƒŒ m…ù™ÊcJ)ÌMÏ„þ_k똚œ M5¾‡Y<ÃðÀ`Êïg˜ïAóïߥ/½‰ÇG÷Ô-Ãvûa÷ê"ÜyÛz¢ìƒo»×Ñ«tþßøáQÍ~²Y ‹7ª›C¿zå Ò™tÅ3à M…\Tãœò;~x¼(ÿ*¥¥øÑÝy›™«¸ó °m›ªÍ§óçÏ9g÷õªð½”ÿãGŽ„–¡Jþ…=^Üg]Y9ýëõ‡>vUþâ©ÇS„Kš-”Ú,{ç`Aò­Ž¦ÌáýJ·ÌÎLC*YUliáÊå+ „ߪ8ÓŽÂÌ}ŒŒ¢¡±AÛù éLå¾ýÔôdMù?==äf2—fQÊjð_w7ÚÚZWÃ|¨«¬ÚSßU8qâ„"¢¿Ó8‚DÉsޝ¢‹@¿¦µö9hõcfºú©3€péÒE§€úm+…Ôg†!0>>^¶Ö«ÕfÊt666±¶ºVS>p|w¬Ðÿ-ä…èGo¾¹U§ßî£ÌnO4·¿qÂiKìvBØŸQ¶ ÔÕk‚^þêEzçàŒ…»@Ô ë‘aÀ<<,uŸù·¸¸ˆt*UÐß­ôZ[^…s±P¾< ¿QuÁ?4CÚ®iX]^A&› õ{fzª&Ÿ½×¥‰KPRÅóV^½ßŽŽ SÌŒet_Ó%÷L+`×àÉs–@oå —{)Q|çàS§NˆîÖùÌ¡> m7¾È×þÕO™y¦\¼xþ¦,üVÅöjnjÆàРÞV@HëFÚÒ9óo ù•J¥099`S¾žöºiÆ0::ª½k¥~¥­­ÿ6†UÕ캀Ý[Çq 7…_ˆÜ9øO_÷ηpHçÿIÓZ;Èf²XºqcK’©ÉëH§Sùæl)+Ñò(Õ|?4^¸JPmØå¹9@öËççæ ¤M[ñ›¸xñBnÚ±’UÛ?|(æaˆšÌÿ[·Õæ¶?à¦ö„ü—=úm":§Ui%2ñì]þÿc¥õ~ÿFg;ÌžN­µazj ØRX¶Ä•+WÝæl‰>ß _5/B_oÚÚ;œÓœ·rª³÷;×l)‹NožššÜZä»677µÕµê>Ëøê·ÎŽtvwo÷åkó?ø{Eøèèèè®ß2lOÀ‰'”Ðþü‚ÈÝ9øÕ‹jïÒ¹ÿÄýS03µµ~0\ºxÑM#Šk¾’-‚ QQ«`üÐÁÒ‚R£ ˜ó]°¶º†µ-ûíù~qâbQ+ ªÃY¦tøÐá&]~çX .­nìú-Ãö„€²$¢´æ€ÿ³7Üñ6±øÇ‰Èеo‘ˆ#16¨½xca™L¶®}l¬o`~vÎøó[™ß‡S‘ŒŒ kØXßÀæ¦s‰óÔÔ¤–ü»rù2¤•-ø¬ê·!þz64<€x"ž÷±jý‡Â®ß9xÏÀS›7@øJUj]‹ÁþäèÂB ¤>¦s¿‰ƒƒ Ó Ý059YwÚ¤´qñâE§*/˜(,Úe_EiˆÅ­½ÿ_ÂLà ´- s³³Zn›ÍfpõêuÇÇ ƒ€Õ¾ aâàÁƒ±0ÂÆ ª!RoÞ×ßë.„[Ž=#@À}娖ŒÄ½û >]û$HÓøD„T2‰ååe- 555…d*Yz“2~né ˜ãþØÁEýùÒ 9Ÿ…Àâ LNNB)EºÔùÒ¥‹J–߬’ÿ;0&HU½ï!f Äșµwõ–a{J~Ôb}—ˆÎh,C@ü…Î}Æú{`´6k€©©)в/Û¶1uíújÉmP(kÁ¶B)komEooO•sê¾A7¿ù‚B§Ù®3oÜXÄæÆÆ•ËË€ÿ•ò¢¥¹==û2:.ðòw@ôÁ¶¶Ñöˆ¯0ö”€Â6%¸g ‘¶ÿDë»õ®ÅzºÓ:O‘ëIDATëj×.3Ó3°m[ç>S©üyùš×¼f:3&*ÑÒ÷5Åš©pB T0wvu¢³³Ã¹àEç’aל `‚ãù©¿Üx€ÛDH$uù.H<¹¾¾ôS¿ïM¦øG©är±Húò¡ ËâŸ)<ÙÇûÜ×׃ææf«è,@÷Î?"wPÈ8ˆ·O¢|7ÀK¿À‡…‰Œ3:±7oWx£Õr€ïv: õ ·£al@û~ÿõ‰'°¾º¦o‡„Ï­//ýVpõýÉŸ¼}euíT`[ïû7¿ŽB¶+Xç259‰Ó§O;”7ƯÜ…æV8#áÊÿçŽÁÞŽÜ{ømln"›ÍVél!Dt÷Úòâ}ÁõüÐ]݈ÿ ð+ÿ‰|ëŠü¤@¸|ñÎ_¸_¼ª*\ïyêÜLX~ö-Xvö£ŸýÌg>SÎO¯u§ƒ=5 |zÊþ½Ÿ"ÃÜu q4¬¬,c}m]ë~ÉV÷zùè”S§NÑý÷ßÿÝýôgÏI)_–ß8ü……Ÿüé"ŸøV áÂÄEd3Î4^Q€»ANnPRPä½Sá-…Ä d-k+®ol¬Š/†=çýwÞuŸ“7Œò‹y¿J-·Æå+W¤”R¨¼Ê9o^€{·÷váÞJ\9þ+… ÚüÀù½ô±A0ÚÒ#õ´rêÔ)š˜˜(:pß¾üÂô[ÆoùEÃGevÆšŽ#Ñߣ½ùáü¬¯­éLê3_yèÿÌË¿‰‰‰\¾¶··ÛÃ##Ͷm¿-·½ð¡ŸËÂ-þùeç%ˆ`YY¬®¬ÀGp¶€âå Aå>B8-¥jòPŸû§‡¿ø•`€o|ý+ ïûÀþ­iˆ1ò¥‰ÜTå?‡|Gðù‹ÜgÓ0±¹¹‰õ ÊûLùÖ’OL }-^ˆnÿM·Ü|ê¹§Ÿž,ë®ï8OLLP­ñ¼«c§N¢ÏLË9« >•/n»ðš·á¼Û²0;;«w¿ {KåõŸÿùŸ«þžžÏ´^\Ž|aTb9·÷,xUahpn•éÛÚ xÊ’û'·œr>“óÝVƤ´?ÒC2kßg[ÒçGÀ7åóYQÁvžŸ¹Ï®ÿƒƒƒEÁïÎÜgׯðeçÿæ!ÐOü^_ò9G­Ï Ü5¨ø¹åË›Ó_ÑJÁÎZÃp?ŒæFí055åÜÃNß>×—dö ¾<,²'Ÿ|rÁŒ™_óÖä ªò}VÎgoÙ{v@ðþù^sVI44&ÐݽÏwKñ|Ó?×Ïk¤æŽ´îÊx¼Æ©VÐs_è¡•+oßúæÉ‡miÏå|÷û€ÿ¹Äæ}UÁ

”™‘ Ɖß×2k»"!‰+¥nô™ï?¥ ¾và« â*)õ˜ˆÆ£#¨öa“µÜ“ÿÚÕ«%ȱ³¥ý¥Çzh!ÂãŸø„l0â÷}†o`*7€åß¿T®ûèûžŠ38<è<Ä]ïlç{j/ ÿa'ß²'‚j©ä§Q!X|ðA˲­¤mç|w’äùxè§ÿ‘àRBÚ6dîÁŸy4lÛ†mûž!è.çŸìæ›Î3 TÁcÆü/"Ä;ºö}ÜM{øµÜáBP@5"°ãƒ€%‚¿Ô;ÀÂúÚíM-;þX%³£ÔÙ¾ÕA©’,-.aMçÈ?€äº×w @Ï>ûÓ§½éI%å«üõœ·àÕˆ¾ºËÿóÜßà7ííˆ'Hnlú¾ËŽnï(,±iÆÉT5š¾~õËŒd$~ajê3½ƒCÅ +¾EèÚÀ¶=½=xáÌiK%ž<ö_Qâ©EþÕDÆGûúúþrvvÖöíÐ;®þø×ù?'ÞÊ îè `•Áï©^nù‡×.Ì¿qôð E>ýe;_Í·ŒÃlo-zŽ|½vþÜy¬¯¯kK§”ò©ÿóÈÃÿ…… ´¶øæ7¿)ïxÏ{‰èD¾õ’¯ÉƒOÌ)h T0H‰……ùÂõR–Ø^î;W¾õD@ÖÊ:Ûå¾+6Û¶¾úØÉG¿À ”0ßzì±ÇV~ñ]w†qÐïkÁñ)‘9 ´@„dr“VWWOrÚÿìÀœß¾ô>ÊLåŽÚ‡OŸyîÙ³%Že¥8ÊQ.Æw¬P!øËZ´a¥>Ûk|õN¤(n">¸¶æÚ?“É`vf¦hú«Òéôƒî¢@…Z~öãõ•¯}ݨ=¿¶~zúúpöÜY([â¯ùKm‹ÅN§Ëîe}eõïÊz奰Ÿá{ßX[¿ß4Í·š†¾¢ß·¿×®^+Z_ÎÿâV@ñÖñxìß@¡êájè­§À{ÙVÀn – þÐ{Q<öü _ÍJ¹bI‰°ø@/l%aY–V»~íz®?©Çì•s/œù ³\ŸQ<ðÀK™têë¹1 M-ÃèÛ¿Þc·á™÷ñË×ü *tÃðô,ܤ´'{ìÑŸ¸ÿÈïwðòÇÜûÿú«ÿq2“IOIi£ÀjÃñ[Kk š[›s#%Ÿ9èË«\!×Ê*ZÃ0ÞpâÄ»ŽÁéÞxVÍx@Õìˆjÿ°fJ°àú Àx~áJ*me©ç@ÕòÐÌøè€öà·, “““°•ÔfYËúÚÄÄÄ&Jú"QX\\´&Îû¢”RyBbk²ÁAH‰BóšÂ%ž(ì z÷‚E¹A`†‡RÀÆfÒëûÛ!þ‡V(/^”ë_ÈZrƒw¶ Û²ê²ýûHÚ6¤m‡Šcn °Ê®…+îÔÝ×}7 ƒ_–«,5 ¸ÛׄPÿ»á{7®¬Î~v'jÑÝ Õƒe[Zma~ÉÍM([ê2µ±ºr?ªþÜv=ôÐs©Tê'ªDݪ556¢­­µ¸0Æü5bá¶ž (·Ua”sÈ>÷Ü3Ȇø4ÿzãg?ûÙg³Ù¬UíìN5ÖÛ×aÜÁ™ƒ"+y  aüêØØMm(n”:ÖþتÈnvÊYQ €ùgžz>#­§uÖ a–F³ÉÉIM üä_þå_^@aÓP„äcQÞž={697;óeÛ¹ÖI=¾ù[9ƒ@5‚‘ t›ÿ!ßœiÁ`õŸN§¾}ýòå8¡Á@|îÓŸžÙÜØüvÖ² [u”BOO¯(ôÁ†’vο0ó¦Cw•„mYͯ}ý+?ˆâà;¶@!kìô4`˜*•l®¡°@Äj2ùåÖ†ÆÛ¶+¢1êlC6«yð/Á…{$RÂÉéûB>çh<òÕ¯>úÑ»?ù§Bˆ. CGw'bñ8Òg¯¦ñNßÆÞ’0 زХٙ¹G¤Q8ðJ´„f¦®~ôàøÛ ¡¯Üß¿“ׯW½}©é@ßPPˆ'wÁ¹> \­.߇M±íÓ€!ý¿R•j¶…õw ÆÔÚâÄ‘žßR@B×4šÿÕ0:³­EûÔßôÔ$VWW«žR«d±X|é;?øþ¿·R©rÁî_. ‚¥¥%ûÕ¯yõHcSãmÞÉ:5ç˜@Ï›ÎR –maei%0cíô*ѱlëL‰QÁlŒmË©o=~ê¯,•ð»\¥b0~úÔSWîçßò~aí…gíÕöòwiLÓÄòÒRéTUùVn€Óy¹QLÔ580øä… ç§P,xAÊ|0ÞwëjÀr´\k vc}]¥²Öã1Sü²öT Xo7,ÍSJ)ÌÌ̶Ãbu‹û¾ž\ZpŽa•G‚‹ò6™LZO|ï{ÿâ{Þ{' ´v{ûúpåÒ•ŠÓ]Õ¶„NSÀòòÒI›îWµø³d2‰¥Å_íÞ×óï„ÆV@o_/––‚ºT™r­)3hïìú8€ÓpZ=I÷(<÷¯õK¶öÔåÀ(/€€–gf/=úòþï…RU tTKCO',H@çj,/-#UẵÐÐØ ^8}æQ­ÖàŒ‚{Á°ÃZ_ùúï|gâõoü7OwtvÞ®-La £« óó•7iöA€TP/œ}þq8 |?(ßõ ¶6éÛ?þï}ÿî1M£º»üVAgW ÃPÙlV[ÙTR!Þ{ÓàÈÈ+&¯^½`À"œã¬H«jú{ì¶„ V”Ð0$t<{ýêúM=CWM!Fu&&Ö·¶eWÞ°Fæfg³Æ4aqúÒ¥ @œÚ?‹ÂÂïåYXMà!òÜùsÏÞ~û+µ ôôô`Ú}ØI½xÍìõõõgg§¦f‘f¯ïvŒ¿ßÅ÷¾÷½oyÛÛ¿ßÚÖöóTÃu#•èêî¦êƪI¦”qóÍ·¼òêÕÏÁI@€…*GüÃØmØ2ÿ÷¹'ÿ{S<Þ¤J™j‹Ó ~ºæ¯7dí¬•Ô4‹ÅŒX,[XX¨¦ú/ÕŸSDäu³Dde2™uéóþÇ×zè‘?ñÄYÛ¶•R¦RÊ ”Êu ŠšØªBë+‹™–eazzz£Út?»~{–%¢”mÛÓVªÜgEþ÷ßüõlooÎd2ÝRÊ&¥TÌõ[¸ù৪2eš¦PJ‰µµµrå¨äñö–‰HÁ©åm"²-ËJVóÿka·À¯ÒÁ‘Üಠ§ß³ @mfÓ›ÙtN· †|ÓnË,^ÕWuôß ‚Œk)pò"…|ß…í×Ëoéþ.¹¾¾~å…^XÐ '?M”žfÚN¼t{¢g¹–ãóªûn#ßê Š•=5¾<]\\\]\\¼§+ÕŒ¼ïÁ³î¶“ReßóÑ‚ÓÊK#Ü“È_ÿPË— €`ù Lp°p'|k¹Ó鉀?­Ác¶¿rë쀜8qBÎ6ûÃD Ô€–òýÆü(W8_,bPÔÿõ½‡åMPJÕ†ax5a0Ÿ½ævØ…@xM¨+Ãü˃R¾—kˈÿ,‚ Ùv»|.×2ó/ýõw JHPî±Ó-ðû×y牢ʽƒå€°À/7¼W)§Ø¥ D0‚…$¬ôòÍß ¹T@„±Õü-WS‡¥/aï¥üúàߟ6a;}.”õˆ~˜Túv¿ ¶.¬f*w òþb§””+ÁÖ“¿ øóÅÊh0ü_j`§ºþtù—ƒ¾†°à7x÷_ªæß-Ÿƒ&aAÚ»'Ànúäpzå.¿ ;xå‚ ìsØïJå_0= ŠàòvPÊÿRüA(%A_KÕü{ÅçJâøåر'•¹'@p¹Ô5ÎÁé¥ü• PºX®ù–¯¥ !ïÁåí ÜŠßÞûKÁçò„äE©;ífÀSc–Ãúb~G™÷—a…Á{/uÀƒ5AØ>Ëþ½"®åDп\ªÅã¬ýËù ì]ŸËù^ÍqeGŸ XÃMA+}öÿ&¸¯— ÁƒY.–Ã(•ßaËþ÷àòvSÎ÷à{¹à÷¨äwØ{ð·ÛM5>×"~k`‡[e¦ƒ-m_®æG‰Ï/j „°÷rû Öˆþ|F™å$¬Fô/WëwX9«$r{Ñçj0¸\–]y:p™–€y«µÑ‹] *5߃˕‚ÄO¹|.·\jÛA¹ ®e9H5~¾|®FsTzpè®=¼Ì£ÁjYã¥,ÁïKµª¡\žî¦ÀV+€Õ|öSÉÇ£Ïeůš§ïše]TÍÁy±z­„Ìj×ù©%/÷JWSCÖÊKÅç-¾Ç® €G…g˜Us@öÊAÓM5²ž övþn—ÿ/YŸk ~`€G­6ÆK7ðƒl)Ƚ°…|õØ+ù[¯ÈÕ‹ÎçZƒÞÏž†av–Ý~0Ã0» ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0†€a" ÃD†‰0, aX&°0L„a`˜ÃÀ0æÿá­n†[¯RIEND®B`‚virt-manager-1.5.1/data/icons/0000775000175100017510000000000013245574323017630 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/16x16/0000775000175100017510000000000013245574323020415 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/16x16/actions/0000775000175100017510000000000013245574323022055 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/16x16/actions/vm_new.png0000664000175100017510000000000012574335131035671 1virt-manager-1.5.1/data/hicolor/16x16/actions/vm_new.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/16x16/actions/icon_console.png0000664000175100017510000000000012574335131040227 1virt-manager-1.5.1/data/hicolor/16x16/actions/icon_console.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/16x16/apps/0000775000175100017510000000000013245574323021360 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/16x16/apps/virt-manager.png0000664000175100017510000000000012574335131036701 1virt-manager-1.5.1/data/hicolor/16x16/apps/virt-manager.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/24x24/0000775000175100017510000000000013245574323020413 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/24x24/actions/0000775000175100017510000000000013245574323022053 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/24x24/actions/vm_new.png0000664000175100017510000000000012574335131035665 1virt-manager-1.5.1/data/hicolor/24x24/actions/vm_new.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/24x24/actions/icon_console.png0000664000175100017510000000000012574335131040223 1virt-manager-1.5.1/data/hicolor/24x24/actions/icon_console.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/24x24/actions/vm_clone_wizard.png0000664000175100017510000000000013240655316041444 1virt-manager-1.5.1/data/hicolor/24x24/actions/vm_clone_wizard.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/24x24/apps/0000775000175100017510000000000013245574323021356 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/24x24/apps/virt-manager.png0000664000175100017510000000000012574335131036675 1virt-manager-1.5.1/data/hicolor/24x24/apps/virt-manager.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/48x48/0000775000175100017510000000000013245574323020427 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/48x48/actions/0000775000175100017510000000000013245574323022067 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/48x48/actions/vm_new_wizard.png0000664000175100017510000000000012574335131040655 1virt-manager-1.5.1/data/hicolor/48x48/actions/vm_new_wizard.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/48x48/actions/vm_import_wizard.png0000664000175100017510000000000012574335131042117 1virt-manager-1.5.1/data/hicolor/48x48/actions/vm_import_wizard.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/48x48/actions/vm_clone_wizard.png0000664000175100017510000000000012574335131041473 1virt-manager-1.5.1/data/hicolor/48x48/actions/vm_clone_wizard.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/48x48/actions/vm_delete_wizard.png0000664000175100017510000000000012574335131041777 1virt-manager-1.5.1/data/hicolor/48x48/actions/vm_delete_wizard.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/48x48/apps/0000775000175100017510000000000013245574323021372 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/48x48/apps/virt-manager.png0000664000175100017510000000000012574335131036725 1virt-manager-1.5.1/data/hicolor/48x48/apps/virt-manager.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/0000775000175100017510000000000013245574323020407 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/status/0000775000175100017510000000000013245574323021732 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/status/state_paused.png0000664000175100017510000000000013240655316040000 1virt-manager-1.5.1/data/hicolor/22x22/status/state_paused.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/status/state_running.png0000664000175100017510000000000013240655316040376 1virt-manager-1.5.1/data/hicolor/22x22/status/state_running.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/status/state_shutoff.png0000664000175100017510000000000013240655316040372 1virt-manager-1.5.1/data/hicolor/22x22/status/state_shutoff.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/devices/0000775000175100017510000000000013245574323022031 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/devices/device_pci.png0000664000175100017510000000000012574335131037217 1virt-manager-1.5.1/data/hicolor/22x22/devices/device_pci.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/devices/device_serial.png0000664000175100017510000000000012574335131040427 1virt-manager-1.5.1/data/hicolor/22x22/devices/device_serial.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/devices/device_cpu.png0000664000175100017510000000000012574335131037247 1virt-manager-1.5.1/data/hicolor/22x22/devices/device_cpu.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/devices/device_mem.png0000664000175100017510000000000012574335131037225 1virt-manager-1.5.1/data/hicolor/22x22/devices/device_mem.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/devices/device_usb.png0000664000175100017510000000000012574335131037253 1virt-manager-1.5.1/data/hicolor/22x22/devices/device_usb.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/actions/0000775000175100017510000000000013245574323022047 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/actions/vm_new.png0000664000175100017510000000000012574335131035655 1virt-manager-1.5.1/data/hicolor/22x22/actions/vm_new.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/actions/icon_console.png0000664000175100017510000000000012574335131040213 1virt-manager-1.5.1/data/hicolor/22x22/actions/icon_console.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/actions/icon_details.png0000664000175100017510000000000012574335131040161 1virt-manager-1.5.1/data/hicolor/22x22/actions/icon_details.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/apps/0000775000175100017510000000000013245574323021352 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/22x22/apps/virt-manager.png0000664000175100017510000000000012574335131036665 1virt-manager-1.5.1/data/hicolor/22x22/apps/virt-manager.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/32x32/0000775000175100017510000000000013245574323020411 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/32x32/status/0000775000175100017510000000000013245574323021734 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/32x32/status/state_paused.png0000664000175100017510000000000012574335131040003 1virt-manager-1.5.1/data/hicolor/32x32/status/state_paused.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/32x32/status/state_running.png0000664000175100017510000000000012574335131040401 1virt-manager-1.5.1/data/hicolor/32x32/status/state_running.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/32x32/status/state_shutoff.png0000664000175100017510000000000012574335131040375 1virt-manager-1.5.1/data/hicolor/32x32/status/state_shutoff.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/32x32/actions/0000775000175100017510000000000013245574323022051 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/32x32/actions/vm_new.png0000664000175100017510000000000012574335131035661 1virt-manager-1.5.1/data/hicolor/32x32/actions/vm_new.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/32x32/actions/icon_console.png0000664000175100017510000000000012574335131040217 1virt-manager-1.5.1/data/hicolor/32x32/actions/icon_console.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/32x32/apps/0000775000175100017510000000000013245574323021354 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/32x32/apps/virt-manager.png0000664000175100017510000000000012574335131036671 1virt-manager-1.5.1/data/hicolor/32x32/apps/virt-manager.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/256x256/0000775000175100017510000000000013245574323020571 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/256x256/apps/0000775000175100017510000000000013245574323021534 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/icons/256x256/apps/virt-manager.png0000664000175100017510000000000012574335131037231 1virt-manager-1.5.1/data/hicolor/256x256/apps/virt-manager.pngustar crobinsocrobinso00000000000000virt-manager-1.5.1/data/virt-manager.desktop.in0000664000175100017510000000024612574335131023107 0ustar crobinsocrobinso00000000000000[Desktop Entry] _Name=Virtual Machine Manager _Comment=Manage virtual machines Icon=virt-manager Exec=virt-manager Type=Application Terminal=false Categories=System; virt-manager-1.5.1/data/org.virt-manager.virt-manager.convert0000664000175100017510000000215113240655316025670 0ustar crobinsocrobinso00000000000000[org.virt-manager.virt-manager] system-tray = /apps/virt-manager/system-tray [org.virt-manager.virt-manager.connections] autostart = /apps/virt-manager/connections/autostart uris = /apps/virt-manager/connections/uris [org.virt-manager.virt-manager.details] show-toolbar = /apps/virt-manager/details/show-toolbar [org.virt-manager.virt-manager.paths] image-default = /apps/virt-manager/paths/default-image-path media-default = /apps/virt-manager/paths/default-media-path [org.virt-manager.virt-manager.stats] enable-net-poll = /apps/virt-manager/stats/enable-net-poll enable-disk-poll = /apps/virt-manager/stats/enable-disk-poll enable-memory-poll = /apps/virt-manager/stats/enable-mem-poll enable-cpu-poll = /apps/virt-manager/stats/enable-cpu-poll [org.virt-manager.virt-manager.vmlist-fields] cpu-usage = /apps/virt-manager/vmlist-fields/cpu_usage disk-usage = /apps/virt-manager/vmlist-fields/disk_usage host-cpu-usage = /apps/virt-manager/vmlist-fields/host_cpu_usage memory-usage = /apps/virt-manager/vmlist-fields/memory_usage network-traffic = /apps/virt-manager/vmlist-fields/network_traffic virt-manager-1.5.1/virt-manager.spec0000664000175100017510000001367213245574323021065 0ustar crobinsocrobinso00000000000000# -*- rpm-spec -*- %global with_guestfs 0 %global stable_defaults 0 %global askpass_package "openssh-askpass" %global qemu_user "qemu" %global libvirt_packages "libvirt-daemon-kvm,libvirt-daemon-config-network" %global kvm_packages "" %global preferred_distros "fedora,rhel" %global default_hvs "qemu,xen,lxc" %if 0%{?rhel} %global preferred_distros "rhel,fedora" %global stable_defaults 1 %endif # End local config Name: virt-manager Version: 1.5.1 Release: 1%{?dist} %global verrel %{version}-%{release} Summary: Desktop tool for managing virtual machines via libvirt Group: Applications/Emulators License: GPLv2+ BuildArch: noarch URL: http://virt-manager.org/ Source0: http://virt-manager.org/download/sources/%{name}/%{name}-%{version}.tar.gz Requires: virt-manager-common = %{verrel} Requires: pygobject3 Requires: gtk3 Requires: libvirt-glib >= 0.0.9 Requires: dconf Requires: dbus-x11 # The vte291 package is actually the latest vte with API version 2.91, while # the vte3 package is effectively a compat package with API version 2.90. # virt-manager works fine with either, so pull the latest bits so there's # no ambiguity. Requires: vte291 # For console widget Requires: gtk-vnc2 Requires: spice-gtk3 %if 0%{?rhel} == 7 Requires: gnome-icon-theme %endif BuildRequires: intltool BuildRequires: /usr/bin/pod2man # For python, and python2 rpm macros BuildRequires: python2-devel %description Virtual Machine Manager provides a graphical tool for administering virtual machines for KVM, Xen, and LXC. Start, stop, add or remove virtual devices, connect to a graphical or serial console, and see resource usage statistics for existing VMs on local or remote machines. Uses libvirt as the backend management API. %package common Summary: Common files used by the different Virtual Machine Manager interfaces Group: Applications/Emulators # This version not strictly required: virt-manager should work with older, # however varying amounts of functionality will not be enabled. Requires: libvirt-python >= 0.7.0 Requires: libxml2-python Requires: python-requests Requires: python-ipaddr Requires: libosinfo >= 0.2.10 # Required for gobject-introspection infrastructure Requires: pygobject3-base # Required for pulling files from iso media with isoinfo Requires: genisoimage %description common Common files used by the different virt-manager interfaces, as well as virt-install related tools. %package -n virt-install Summary: Utilities for installing virtual machines Requires: virt-manager-common = %{verrel} # For 'virsh console' Requires: libvirt-client Provides: virt-install Provides: virt-clone Provides: virt-convert Provides: virt-xml Obsoletes: python-virtinst %description -n virt-install Package includes several command line utilities, including virt-install (build and install new VMs) and virt-clone (clone an existing virtual machine). %prep %setup -q %build %if %{qemu_user} %global _qemu_user --qemu-user=%{qemu_user} %endif %if %{kvm_packages} %global _kvm_packages --kvm-package-names=%{kvm_packages} %endif %if %{preferred_distros} %global _preferred_distros --preferred-distros=%{preferred_distros} %endif %if %{libvirt_packages} %global _libvirt_packages --libvirt-package-names=%{libvirt_packages} %endif %if %{askpass_package} %global _askpass_package --askpass-package-names=%{askpass_package} %endif %if %{stable_defaults} %global _stable_defaults --stable-defaults %endif %if %{default_hvs} %global _default_hvs --default-hvs %{default_hvs} %endif python setup.py configure \ %{?_qemu_user} \ %{?_kvm_packages} \ %{?_libvirt_packages} \ %{?_askpass_package} \ %{?_preferred_distros} \ %{?_stable_defaults} \ %{?_default_hvs} %install python setup.py \ --no-update-icon-cache --no-compile-schemas \ install -O1 --root=%{buildroot} %find_lang %{name} # Replace '#!/usr/bin/env python2' with '#!/usr/bin/python2' # The format is ideal for upstream, but not a distro. See: # https://fedoraproject.org/wiki/Features/SystemPythonExecutablesUseSystemPython for f in $(find %{buildroot} -type f -executable -print); do sed -i "1 s|^#!/usr/bin/env python2|#!%{__python2}|" $f || : done # The conversion script was only added to virt-manager after several # Fedora cycles of using gsettings. Installing it now could convert old data # and wipe out recent settings. rm %{buildroot}%{_datadir}/GConf/gsettings/org.virt-manager.virt-manager.convert %post /bin/touch --no-create %{_datadir}/icons/hicolor &>/dev/null || : /usr/bin/update-desktop-database &> /dev/null || : %postun if [ $1 -eq 0 ] ; then /bin/touch --no-create %{_datadir}/icons/hicolor &>/dev/null /usr/bin/gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : /usr/bin/glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || : fi /usr/bin/update-desktop-database &> /dev/null || : %posttrans /usr/bin/gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || : /usr/bin/glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || : %files %doc README.md COPYING NEWS.md %{_bindir}/%{name} %{_mandir}/man1/%{name}.1* %{_datadir}/%{name}/ui/*.ui %{_datadir}/%{name}/virt-manager %{_datadir}/%{name}/virtManager %{_datadir}/%{name}/icons %{_datadir}/icons/hicolor/*/apps/* %{_datadir}/appdata/%{name}.appdata.xml %{_datadir}/applications/%{name}.desktop %{_datadir}/glib-2.0/schemas/org.virt-manager.virt-manager.gschema.xml %files common -f %{name}.lang %dir %{_datadir}/%{name} %{_datadir}/%{name}/virtcli %{_datadir}/%{name}/virtconv %{_datadir}/%{name}/virtinst %files -n virt-install %{_mandir}/man1/virt-install.1* %{_mandir}/man1/virt-clone.1* %{_mandir}/man1/virt-convert.1* %{_mandir}/man1/virt-xml.1* %{_datadir}/%{name}/virt-install %{_datadir}/%{name}/virt-clone %{_datadir}/%{name}/virt-convert %{_datadir}/%{name}/virt-xml %{_bindir}/virt-install %{_bindir}/virt-clone %{_bindir}/virt-convert %{_bindir}/virt-xml virt-manager-1.5.1/ui/0000775000175100017510000000000013245574323016221 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/ui/addhardware.ui0000664000175100017510000034031713245061760021032 0ustar crobinsocrobinso00000000000000 67000 1 10 67000 1 10 67000 1 10 True False gtk-apply False Add New Virtual Hardware False dialog True False 12 vertical 6 True False 12 50 True True never never etched-in True True False False True 0 True False vertical 12 True False True False start start 6 6 6 6 Page title True fill False True 0 True False 6 12 True True left False True False label True False error False True False start vertical 18 True False True True 0 True False 6 6 True False start _Device type: True storage-devtype 0 0 True False start Device Type Field 1 0 True False start _Bus type: True storage-bustype 0 1 True False start 1 1 True True 1 True True True False 6 6 True False start Cac_he mode: True storage-cache 0 0 True False 1 0 True False <b>Ad_vanced options</b> True True True True 2 storage-tab 1 False True False disk 1 False True False start False 6 6 True False start _Type: True controller-type 0 0 True False start _Model: True controller-model 0 1 True False 1 0 True False gtk-info 2 0 True False True True 1 1 controller-tab 2 True False ctrl 2 False True False vertical 6 True False 9 6 True False 6 True True False start True True mac-address-enable False True 0 True True 17 â— aa:bb:cc:dd:ee:ff MAC Address Field False True 1 1 1 True False start _MAC address: True True create-mac-address 0 1 True False start Device mode_l: True net-model 0 2 True False False False 0 0 True False False False 1 0 True False start True True 1 2 False True 0 True False False False False True 1 network-tab 3 True False net 3 False True False 6 6 True False center _Type: True input-type 0 0 True False 1 0 input-tab 4 True False input 4 False True False graphics-tab 5 True False gfx 5 False True False 6 6 True False 1 0 True False end center _Model: True sound-model 0 0 sound-tab 6 True False sound 6 False True False 6 6 True False start 1 1 Host _Device: True host-device 0 0 500 True True True True etched-in True True False 0 1 host-tab 7 True False host 7 False True False 6 6 True True 1 4 True True False True 1 9 True False start 1 7 True False 6 True True True True 0 True False start _Port: True char-port False True 1 True True adjustment3 False True 2 1 6 True False 6 True True True True 0 True False start Po_rt: True char-bind-port False True 1 True True adjustment2 False True 2 1 8 True False start _Path: True char-path 0 4 True False start _Mode: True char-mode 0 7 True False start H_ost: True char-host 0 6 True False start _Bind Host: True char-mode 0 8 True False start Use Te_lnet: True char-use-telnet 0 9 True False start Device _Type: True char-device-type 0 1 True False start 1 1 True False start T_ype: True char-target-type 0 2 True False start 1 2 True False start _Name: True combobox-entry 0 0 True False start True True 20 1 0 True False _Auto socket: True char-auto-socket 0 3 True True False start True 1 3 True False start _Channel: True char-channel 0 5 True True 1 5 char-tab 8 True False char 8 False True False 6 6 True False 1 0 True False start _Model: True video-model 0 0 video-tab 9 True False vid 9 False True False 6 6 True False 1 0 True False start _Model: True watchdog-model 0 0 True False Ac_tion: True watchdog-action 0 1 True False 1 1 watchdog-tab 10 True False wdog 10 False True False vertical filesystem-tab 11 True False fs 11 False True False 6 6 True False 1 0 True False end center _Mode: True smartcard-mode 0 0 smartcard-tab 12 True False sc 12 False True False 6 12 True False 6 True True â— True True 0 True False start _Port: True usbredir-service False True 1 True True adjustment1 1 False True 2 1 1 True False end _Type: True usbredir-list 0 0 True False end _Host: True usbredir-host 0 1 True False start 1 0 usbredir-tab 13 True False usbr 13 False True False 6 6 True True â— 12 1 1 True False start Device _Path: True tpm-device-path 0 1 True False 1 0 True False end _Backend: True tpm-type 0 0 tpm-tab 14 True False tpm 14 False True False 6 6 True False start _Type: True rng-type 0 0 True False 1 0 True False start _Backend Type: True rng-backend-type 0 1 True False 1 1 True False start Backend _Mode: True rng-backend-mode 0 3 True False 1 3 True False start _Host: True rng-connect-host 0 4 True False 6 True True â— True True 0 True False start _Port: True rng-connect-service False True 1 True True â— adjustment3 False True 2 1 4 True False start B_ind Host: True rng-bind-host 0 5 True False 6 True True â— True True 0 True False start P_ort: True rng-bind-service False True 1 True True â— adjustment2 False True 2 1 5 True False start _Device: True rng-device 0 2 True True â— 1 2 rng-tab 15 True False rng 15 False True False 6 6 True False start _Model: True panic-model 0 0 True False 1 0 panic-tab 16 True False panic 16 False True True 1 True True 1 True True 0 True False 12 end gtk-cancel True True True True False False 1 _Finish True True True image1 True False False 2 False True 1 virt-manager-1.5.1/ui/create.ui0000664000175100017510000062411113245061760020024 0ustar crobinsocrobinso00000000000000 128 1 10 8096 1 10 True False gtk-new 400 400 False New VM False dialog True False vertical True False queue True False 6 10 True False vm_new_wizard 6 False False 0 True False True False vertical True False start <span size='large' color='white'>Create a new virtual machine</span> True False True 0 True False start <span color='#59B0E2'>Step foo of bar</span> True True True 1 True True 0 True True 1 False False 0 True False 12 vertical 15 True False 3 3 True True False True False 24 True False start False 12 True False vertical 8 True False start Choose virtualization type False True 0 True False 15 True False vertical 3 _Virtual machine True True False start True True True False False 0 _Container True True False start True True vz-virt-type-hvm False False 1 False True 1 0 0 True False False vertical 8 True False start Choose how you would like to install the operating system False True 0 True False 15 True False vertical 3 _Local install media (ISO image or CDROM) True True False start True True True False True 0 Network _Install (HTTP, FTP, or NFS) True True False start True True method-local False True 1 Network _Boot (PXE) True True False start True True method-local False True 2 Import _existing disk image True True False start True True method-local False True 3 True True 1 0 1 True False vertical 8 True False start Choose the container type False True 0 True False 15 True False vertical 3 _Application container True True False start True True True False False 0 O_perating system container True True False start True True method-container-app False False 1 False True 1 0 2 0 2 True False False 4 6 True False end C_onnection: True create-conn 0 0 True False center 200 True False False True 0 True False start conn label end 25 True True 1 1 0 2 0 0 True False vertical True False start start 6 True False start start False gtk-dialog-warning 0 0 True False start start False Error message bar True 45 1 0 False True 0 0 1 True False vertical 6 True False start start 6 True False start start False gtk-dialog-warning 0 0 True False start start False Error message bar True 45 1 0 0 0 True True start True True False 8 15 True False 6 6 True False 1 2 True False 1 0 True False end _Xen Type: True xen-type 0 0 True False end _Architecture: True arch 0 2 True False end _Machine Type: True machine 0 3 True False 1 3 True False end _Virt Type: True virt-type 0 1 True False 1 1 True False Architecture options 0 1 0 3 True False Name False True False vertical 24 True True False True False 10 True False vertical 6 True False start Locate your install media False True 0 True False 15 True False vertical 4 True False vertical 4 Use CD_ROM or DVD True True False True True True False True 0 True False 20 False False 1 False False 0 Use _ISO image: True True False True True True install-cdrom-radio False True 1 True False 5 True False 20 True False True True True True -1 Bro_wse... True False True True True install-iso-browse False True 1 False True 2 True True 1 True False ISO False True False vertical 6 True False start Provide the operating system install URL False True 0 True False True False 4 6 True False center 15 True False end U_RL: True install-url-entry 0 0 True False True True 13 True True True False True False 4 6 True False end Kerne_l options: True install-urlopts-entry 0 0 True True center True â— 1 0 True False URL _Options True 0 1 2 True False center True True True 1 0 False True 1 1 True False URL 1 False True False False No input needed for pxe. User shouldn't see this. True False 0 2 True False PXE 2 False True False vertical 24 True False vertical 6 True False start Provide the existing stora_ge path: True install-import-entry False True 0 True False 15 True False 6 True True â— True True 0 B_rowse... True True True True install-import-browse False True 1 False True 1 False True 0 True False vertical 6 True False start Direct kernel boot: False True 0 True False 15 True False 6 6 True False start _Kernel path: True kernel 0 1 True False start _Initrd path: True initrd 0 2 True False start _DTB path: True dtb 0 3 True True True 1 1 True True True 1 2 True True True 1 3 Br_owse... True True True True kernel-browse 2 1 Bro_wse... True True True True initrd-browse 2 2 Brow_se... True True True True dtb-browse 2 3 True False 6 True False gtk-dialog-warning False True 0 True False <span size='small'>Specifying a DTB allows use of virtio for improved performance</span> True False True 1 0 0 3 True False start Kerne_l args: True kernel-args 0 4 True True 1 4 2 False True 1 False True 1 3 True False Import 3 False True False start True vertical 6 True False start Provide the _application path: True install-app-entry False True 0 True False 12 True False 6 True True â— True True 0 B_rowse... True True True True install-app-browse False True 1 False True 1 4 True False App Container 4 False True False vertical 6 True False start Provide the existing OS root _directory: True install-oscontainer-fs False True 0 True False 12 True False vertical 12 True False 6 True True â— True True 0 B_rowse... True True True True install-oscontainer-browse False True 1 False True 0 True False 6 True False gtk-dialog-warning False True 0 True False start <small>The OS directory tree must already exist. To enable OS directory tree creation, please install <a href="https://github.com/virt-manager/virt-bootstrap">virt-bootstrap</a></small> True True True 1 False True 1 True False 6 True False gtk-dialog-warning False True 0 True False start <small>The OS directory tree must already exist. Creating an OS directory tree for remote connections is not yet supported.</small> True True True 1 False True 2 Create OS directory tree from container image True True False True False True 3 True False False 10 vertical 10 True False True False Source URI: 0 0 True False True True True Possible URL formats: * file:///path/to/rootfs.tar * docker://registry:port/image:tag * virt-builder://template 1 0 False True 0 Do not verify TLS certificates of registry True True False True False True 1 True True True False True False 10 Username: 0 0 True False 10 Password: 0 1 True True 1 0 True True False â— password 1 1 True False Credentials for accessing the source registry False True 2 False True 4 True False True False Root password: False True 0 True True False â— True True 1 False True 4 True True 1 5 True False OS Container 5 False True False vertical 6 True False start Select _container template: True install-container-template False True 0 True False 12 True False 6 True True 40 False True 0 False True 1 6 True False VZ templates 6 False True True 0 True False vertical 6 True False vertical A_utomatically detect operating system based on install media True True False True True True False True 0 False False 0 False start Choose an operating system type and version False False 1 True False 15 True False 4 6 True False start center - install-os-version-label 2 1 True False start center - install-os-type-label 2 0 True False center install-os-type 1 0 True False start center _Version: True install-os-version 0 1 True False end center OS _type: True install-os-type 0 0 True False center True True install-os-version-entry install-os-version 1 1 False False 2 False True 1 1 True False Install 1 False True False vertical 40 True False vertical 6 True False start Choose Memory and CPU settings False False 0 True False 15 True False 6 True False 4 6 True False end start 6 _Memory (RAM): True 0 0 True False end start 6 C_PUs: True 0 1 True False vertical 4 True True start 7 adjustment3 1 False True 0 True False start True (Insert host mem) True True 1 1 0 True False vertical 4 True True start 7 adjustment2 1 cpus False True 0 True False start True Insert Phys cpu count False True 1 1 1 True True 0 False False 1 False True 0 2 True False start Memory 2 False True False vertical 6 _Enable storage for this virtual machine True True False True True True False False 0 True False 15 False False 1 3 True False Storage 3 False True False vertical 15 True False vertical 6 True False start Ready to begin the installation True False True 0 True False 15 True False False 6 6 True False start label 1 2 True False start label 1 3 True False start label 1 4 C_ustomize configuration before install True True False start False True True 1 6 True True start 25 1 0 True False end False <span color='#484848'>_Name:</span> True True create-vm-name 0 0 True False start label 1 1 True False end False <span color='#484848'>Install:</span> True 0 2 True False end False <span color='#484848'>Memory:</span> True 0 3 True False end False <span color='#484848'>CPUs:</span> True 0 4 True False end False <span color='#484848'>Storage:</span> True 0 5 True False end False <span color='#484848'>OS:</span> True 0 1 True False False 0 6 True False start 3 True False start label True False True 0 True False start label start 27 False True 1 1 5 True True 1 False True 0 True False 6 True False 3 True False gtk-dialog-warning False True 0 True False <small>Specifying an operating system is required for best performance</small> True False True 1 False True 1 True True 6 True False 20 True False vertical 6 True False 6 True False 0 1 True False 6 True False gtk-dialog-warning False True 0 True False <small>pxe warning</small> True False True 1 0 0 False True 0 True False N_etwork selection True advanced-expander False False 2 4 True False Finish 4 False True True 0 True False 12 end gtk-cancel True True True True False False 1 gtk-go-back True False True True True False False 2 gtk-go-forward True True True True False False 3 _Finish True True image20 True False False 4 False True 1 True True 1 virt-manager-1.5.1/ui/createpool.ui0000664000175100017510000007500313240655316020717 0ustar crobinsocrobinso00000000000000 350 False Add a New Storage Pool False dialog True False vertical True False queue True False 6 10 True False gtk-new 6 False False 0 True False True False vertical True False start <span size='large' color='white'>Create storage pool</span> True False True 0 True False start <span color='#59B0E2'>Step foo of bar</span> True False True 1 True True 0 True True 1 False False 0 True False 12 vertical 18 True True False True False 4 6 True False end _Name: True pool-name 0 1 True True â— 1 1 True False 1 2 True False start Select the storage pool type you would like to configure. 0 0 2 True False end _Type: True pool-type 0 2 True False Type False True False vertical True False 4 6 True False end B_uild Pool: True pool-build 0 6 True False 6 True True False start True False True 0 True True â— 25 True True 1 1 5 True False end _Target Path: True pool-target-path 0 0 True False end F_ormat: True pool-format 0 1 True False end Host Na_me: True pool-hostname 0 2 True False end sourcep: True pool-source-path 0 4 True False end Initiator _IQN: True pool-iqn-chk 0 5 B_rowse True True True start True 2 0 True False True True 25 1 0 Bro_wse True True True start True 2 4 True False True True 25 1 4 True False GDK_BUTTON_PRESS_MASK | GDK_STRUCTURE_MASK start 1 1 True True â— 25 1 2 True True False start True True 1 6 True False end Source _Name: True pool-source-name 0 3 True 25 1 3 False True 0 1 True False Details 1 False True True 0 True False 12 end gtk-cancel True True True True False False 1 gtk-go-back True True True True False False 2 gtk-go-forward True True True True False False 3 _Finish True True True True False False 4 False True 2 True True 1 virt-manager-1.5.1/ui/fsdetails.ui0000664000175100017510000004037113245061760020537 0ustar crobinsocrobinso00000000000000 18446744073709 100 1000 True False 6 6 True False True False False True 0 True False start Passthrough True True 1 1 0 True False True False False True 0 True False start Default True True 1 1 3 True False True False False True 0 True False start Default True True 1 1 1 True False True False False True 0 True False start Default True True 1 1 4 True True â— 1 7 E_xport filesystem as readonly mount True True False True True 1 8 True False 6 True True â— True True 0 _Browse... True True True True False True 1 1 5 True False start _Type: True fs-type-combo 0 0 True False start M_ode: True fs-mode-combo 0 3 True False start _Driver: True fs-driver-combo 0 1 True False start _Write Policy: True fs-wrpolicy-combo 0 4 True False start src labelll: True fs-source 0 5 True False start Ta_rget path: True fs-target 0 7 True False 0 8 True False start _Usage: True fs-ram-source-spin 0 6 True False 6 True True end adjustment6 1 False False 0 True False start MiB False True 1 1 6 True False start _Format: True fs-format-combo 0 2 True False True False False True 0 True False start Default True True 1 1 2 virt-manager-1.5.1/ui/host.ui0000664000175100017510000042255213245061760017543 0ustar crobinsocrobinso00000000000000 False Connection Details 750 500 True False vertical True False True False _File True False True False _View Manager True True False gtk-close True False True True accelgroup1 gtk-quit True False True True accelgroup1 False False 0 True True 6 True False vertical True False 6 vertical 18 True False 0 none True False 20 True False 3 3 6 True False end Libvirt URI: 1 0 1 True False start example.com True end 1 1 True True False True True 1 2 True True 30 1 0 True False end _Name: True overview-name 1 0 0 True False end A_utoconnect: True config-autoconnect 0 2 True False <b>Basic details</b> True False True 0 True False vertical True False False 0 none True False 12 True False vertical 3 75 True False False True 0 True False end 60% False True 1 True False <b>CPU usage</b> True True True 0 True False 0 none True False 12 True False vertical 3 75 True False False True 0 True False end 1.59 GiB of 2.2 GiB False True 1 True False <b>Memory usage</b> True True True 1 True True 1 False True 0 True False _Overview True False True False 3 vertical True True 3 200 True False never in 134 True True False net-list False True True True False True False 6 True False vertical 12 True False 5 6 True False 3 True False gtk-missing-image False True 0 True False start Running True True 1 1 2 Some Label True True False start True True 1 3 True False start label True 1 1 True False start label 1 4 True False start Device: 0 1 True False start State: 0 2 True False start A_utostart: True net-autostart 0 3 True False start Domain: True 0 4 True False start Name: 0 0 True True 1 0 False True 0 True True True False 5 6 True False start label True 1 0 True False start label True 1 1 True False start <network-addr> via <gateway-addr> 1 3 True False 3 True False gtk-missing-image False False 0 True False start NAT to any device True True 1 1 2 True False start Network: 0 0 True False start DHCP range: 0 1 True False start Forwarding: 0 2 True False start Static Route: 0 3 True False <b>_IPv4 configuration</b> True True False True 1 True True True False 5 6 True False start label True 1 0 True False start label True 1 1 True False start <network-addr> via <gateway-addr> True 1 3 True False 3 True False gtk-missing-image False False 0 True False start Routed True True 1 1 2 True False start Network: 0 0 True False start DHCP range: 0 1 True False start Forwarding: 0 2 True False start Static Route: 0 3 True False <b>IPv6 configuration</b> True False True 2 True True True False vertical Enable i_nbound QoS True True False start True True False True 0 True False 5 6 True True 1 1 True True 1 2 True False start Average (KiB/sec): 0 0 True False start Burst (KiB): 0 2 True True 1 0 True False start Peak (KiB/sec): 0 1 False True 1 Enable ou_tbound QoS True True False start True True False True 2 True False 5 6 True True 1 1 True True 1 2 True True 1 0 True False start Burst (KiB/sec): 0 2 True False start Peak (KiB/sec): 0 1 True False start Average (KiB/sec): 0 0 False True 3 True False <b>_QoS configuration</b> True True False True 3 True True True False vertical 3 True False 5 6 True False start label True 1 0 True False start Physical Function: 0 0 False True 0 True False start Virtual Functions: True False True 1 144 True True in True True True True 2 True False <b>_SR-IOV information</b> True True True True 4 True False info False True False some error here net-error-label 1 True False error 1 False True True True True 0 True False 3 True False True True True False Add Network True False gtk-add net-add False False 0 True True True False Start Network True False gtk-media-play net-start False False 1 True True True False Stop Network True False gtk-stop net-stop False False 2 True True True False Delete Network True False gtk-delete net-delete False False 3 True True 0 True False gtk-apply True True False True False False 0 False True 1 False True 1 1 True False _Virtual Networks True 1 False True False 2 True False _Storage True 2 False True False 3 vertical True True 3 200 True False never in 134 True True False interface-list False True True True False True False 6 True False vertical 12 True False 6 12 True False start <b>Name</b> True 0 0 2 True False start start MAC: 0 1 True False start start insert mac True 1 1 True False start center State: 0 2 True False center 3 True False start gtk-missing-image False True 0 True False Active False False 1 1 2 True False start Start mode: 0 3 True False center True True False False True 0 False start unknown startmode True True 1 1 3 True False start In use by: 0 4 True False start center foo, bar 1 4 False True 0 True True True False 5 6 True False start Mode: 0 0 True False start start True label 1 0 True False start Address: 0 1 True False start center True label True 1 1 True False <b>IPv4 Configuration</b> True False True 1 True True True False 5 6 True False start Mode: 0 0 True False start True label 1 0 True False start start Address: 0 1 True False start start True label True 1 1 True False <b>IPv6 Configuration</b> True False True 2 True False vertical 3 True False start <b>Slave Interfaces</b> True False False 0 True True etched-in True True True True 1 True True 3 True False Info False True False some message here center interface-error-label 1 True False Error 1 False True True True True 0 True False 3 True False True True True True Add Interface True False gtk-add interface-add False False 0 True True True True Start Interface True False gtk-media-play interface-start False False 1 True True True True Stop Interface True False gtk-stop interface-stop False False 2 True True True True Delete Interface True False gtk-delete interface-delete False False 3 True True 0 True False gtk-apply True True True True False False 0 False True 1 False True 1 3 True False N_etwork Interfaces True 3 False True True 1 virt-manager-1.5.1/ui/about.ui0000664000175100017510000000556413245061760017700 0ustar crobinsocrobinso00000000000000 False True dialog Virtual Machine Manager Copyright (C) 2006-2018 Red Hat Inc. Powered by libvirt http://virt-manager.org/ http://virt-manager.org/ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Daniel P. Berrange <berrange@redhat.com> Cole Robinson <crobinso@redhat.com> Hugh O. Brock <hbrock@redhat.com> translator-credits Máirín Duffy <duffy@redhat.com> Mike Langlie <mlanglie@redhat.com> Jeremy Perry <jeperry@redhat.com> Jakub Steiner <jsteiner@redhat.com> virt-manager False vertical False False True end 0 virt-manager-1.5.1/ui/clone.ui0000664000175100017510000016302013240655316017657 0ustar crobinsocrobinso00000000000000 True False gtk-new False Clone Virtual Machine dialog True False vertical True False queue True False 6 10 True False vm_clone_wizard 6 False False 0 True False True False start <span size='large' color='white'>Clone virtual machine</span> True True True 0 True True 1 False True 0 True False 12 vertical 12 True False vertical 18 True False vertical 12 True False 6 6 True False start orig name end 1 0 True False start Create clone based on: 0 0 True False end Destination host: 0 1 True False start dest host end 0 1 1 True True 0 True False 12 True False 10 12 True False True vertical True False start No networking devices True True 0 True False vertical 6 True True 1 1 1 True False end start <span color='#484848'>Networking:</span> True 0 1 True False True True vertical True False start No storage to clone False True 0 True True never True False True False vertical True False True False 6 True False vertical 12 False False 0 True False False False 1 False False 0 True False False False 1 True True 1 1 2 True False end start True <span color='#484848'>Storage:</span> True 0 2 True False end center <span color='#484848'>_Name:</span> True True clone-new-name 0 0 True True center 3 3 â— 1 0 True True 1 True True 0 True False vertical 12 True False 3 True False start gtk-info False True 0 True False start False <span size='small'>Cloning creates a new, independent copy of the original disk. Sharing uses the existing disk image for both the original and the new machine.</span> True False True 1 True True 0 True False 3 True False start start gtk-dialog-warning False True 0 True False <span size='small'>Cloning does <u>not</u> alter the guest OS contents. If you need to do things like change passwords or static IPs, please see the virt-sysprep(1) tool.</span> True False True 1 True True 1 True True 1 True True 0 True False 12 end gtk-cancel True True True True False False end 1 C_lone True True True image1 True False False end 2 False True 1 True True 1 False 5 Change MAC address center-on-parent True dialog True False vertical 2 True False end gtk-cancel True True True True False False 0 gtk-ok True True True True False False 1 False True end 0 True False 6 6 True False vertical 12 True False 12 True False 6 6 True False 2 True False start type string 2 0 True False True 2 True False start orig-mac 20 2 1 True True True 2 2 True False end New _MAC: True change-mac-new 0 2 2 True False 6 7 True False network-idle 6 0 0 2 True False end center <span color='#484848'>Type:</span> True 1 0 True False end center <span color='#484848'>MAC:</span> True 1 1 True True 0 False True 0 False True 1 change-mac-cancel change-mac-ok False 5 Change storage path center-on-parent True dialog True False vertical 2 True False end gtk-cancel True True True True False False 0 gtk-ok True True True True False False 1 False True end 0 True False 6 vertical 12 True False 6 6 True False 18 18 True False gtk-harddisk 6 0 1 True False center True 6 12 True False start size 1 2 True False start target 1 1 True False start orig-path start 25 1 0 True False end end <span color='#484848'>Size:</span> True 0 2 True False end <span color='#484848'>Target:</span> True 0 1 True False end center <span color='#484848'>Path:</span> True 0 0 1 1 True False start Existing disk 0 0 2 False False 0 True False 6 6 6 True False 22 True False end <span color='#484848'>New _Path:</span> True True change-storage-new 0 1 Create a new disk (c_lone) for the virtual machine True True False True True 0 0 3 True True center 25 1 1 _Browse... True True True True 2 1 True True 1 False True 1 change-storage-cancel change-storage-ok virt-manager-1.5.1/ui/choosecd.ui0000664000175100017510000003077113245061760020353 0ustar crobinsocrobinso00000000000000 True True 6 Choose Media False center-on-parent dialog center True False vertical 6 True False end gtk-cancel True True True False True False False 0 gtk-ok True True True False True False False 1 False True end 0 True False 3 0 none True False 6 10 True False 6 6 True False True 6 True True â— True True 0 _Browse... True True True True False False 1 1 1 P_hysical Device True True False True True True 0 2 2 True False start 0 _Image Location True True False True True physical-media 0 0 2 True False 21 True False start _Location: True iso-path 0 1 True False 21 True False start _Device Media: True 0 3 True False False False 1 3 True False <b>Choose Source Device or File</b> True False True 1 Cancel OK virt-manager-1.5.1/ui/storagelist.ui0000664000175100017510000010437613245061760021127 0ustar crobinsocrobinso00000000000000 True False gtk-apply True False 3 True False end 3 True False True True False Add Pool True False gtk-add pool-add False False 0 True True False Start Pool True False gtk-media-play pool-start False False 1 True True False Stop Pool True False gtk-stop pool-stop False False 2 True True False Delete Pool True False gtk-delete pool-delete False False 3 True True 0 True False 6 True True True Browse local filesystem True False 2 2 True False _Browse Local True False False 0 gtk-cancel True True True Cancel and close dialog True True True 1 Choose Volume True True True Choose the selected volume image3 True True 2 gtk-apply True True False Apply pool changes True False False 3 False True 1 0 1 True True True True 3 200 True True never in 134 True True False pool-list False True True True False True False 6 True False vertical 6 True False 5 8 True False 3 True False start gtk-missing-image False True 0 True False Active False False 1 1 3 Some label True True False start True True 1 4 True False start label True 1 2 True True 1 0 True False start Name: 0 0 True False start Location: 0 2 True False start State: 0 3 True False start A_utostart: True pool-autostart 0 4 True False start Size: 0 1 True False start label 1 1 False True 0 True False vertical 3 True False 6 True False start <b>Volumes</b> True False False 0 True False True True False True True False gtk-add vol-new False False 0 True True True True Refresh volume list True False gtk-refresh vol-refresh False True 1 True True False Delete volume True True False gtk-delete vol-delete False False 2 True True 1 False False 0 True True in True True vol-list True True 1 True True 1 True False info False True False some error here pool-error-label 1 True False error 1 False True True 0 0 virt-manager-1.5.1/ui/createnet.ui0000664000175100017510000030307013240655316020532 0ustar crobinsocrobinso00000000000000 True False gtk-new False Create a new virtual network False dialog True False vertical 6 True False True False 6 10 True False network-idle 6 False False 0 True False True False vertical True False start <span size='large' color='white'>Create virtual network</span> True False True 0 True False start <span color='#59B0E2'>Step foo of bar</span> True False True 1 True True 0 True True 1 False True 0 True False 12 vertical 12 True True False True False vertical 12 True False start Choose a name for your virtual network: True True False False 0 True False 15 True False True 3 4 True True 16 25 False False Net Name Field 1 0 True False True False gtk-dialog-info False True 0 True False <b>Example:</b> network1 True False False 1 1 1 True False end Network _Name: True True right net-name 0 0 True False 0 1 False True 1 True False Name False True False vertical 6 True False start Choose <b>IPv4</b> address space for the virtual network: True True 45 False True 0 Enable IPv4 network address space definition True True False True False True 1 True False 15 True False vertical 18 True False vertical 3 True False 6 True False end _Network: True False True 0 True True start 20 â— 25 False False False True 1 False True 0 True False True False start 3 3 3 3 gtk-dialog-info False False 0 True False vertical 6 True False start start <b>Hint:</b> The network should be chosen from one of the IPv4 private address ranges. eg 10.0.0.0/8 or 192.168.0.0/16 True True 40 50 False False 0 True False 3 6 True False start 192.168.100.1 1 0 True False start ? 1 1 True False end Gateway: 0 0 True False end Type: 0 1 False True 1 False True 1 False True 1 False True 0 True False 3 6 True True 15 â— 25 False False 1 1 True True 15 â— False False 1 2 True False end Start: 0 1 True False end End: 0 2 Enable DHCPv4 True True False start True 0 0 2 False True 1 True False 3 6 Enable Static Route Definition True True False start True 0 0 2 True True 20 â— False False 1 1 True False end <b>to</b> Network: True 0 1 True False end <b>via</b> Gateway: True 0 2 True True 15 â— 25 False False 1 2 False True 2 True True 2 1 True False IPv4 1 False True False vertical 6 True False start Choose <b>IPv6</b> address space for the virtual network: True True 45 False True 0 Enable IPv6 network address space definition True True False True False True 1 True False 15 True False vertical 18 True False vertical 3 True False 6 True False end _Network: True False True 0 True True start 40 â— 25 False False False True 1 False True 0 True False True False start 3 3 3 3 gtk-dialog-info False False 0 True False vertical 6 True False start start <b>Note:</b> The network could be chosen from one of the IPv6 private address ranges. eg FC00::/7. The prefix must be <b>64</b>. A typical IPv6 network address will look something like: fd00:e81d:a6d7:55::/64 True True 45 False True 0 True False 3 6 True False start fd00:100::1 1 0 True False start ? 1 1 True False end Type: 0 1 True False end Gateway: 0 0 False True 1 False True 1 False True 1 False False 0 True False 3 6 True True 40 â— 25 False False 1 1 True True 40 â— False False 1 2 True False end Start: 0 1 True False start End: 0 2 Enable DHCPv6 True True False start True 0 0 2 False True 1 True False 3 6 Enable Static Route Definition True True False start True 0 0 2 True False start <b>to</b> Network: True 0 1 True False end <b>via</b> Gateway: True 0 2 True True 45 â— 25 False False 1 1 True True 40 â— False False 1 2 False True 2 True True 2 2 True False IPv6 2 False True False vertical 6 True False start Connected to a <b>physical network</b>: True True 50 False False 1 True False 15 True False vertical 18 True False vertical 6 True False vertical _Isolated virtual network True True False start start True True net-forward-dev False True 0 For_warding to physical network True True False start start True True True False True 1 False True 0 True False 25 True False 4 6 True False end _Destination: True net-forward 0 0 True False end _Mode: True net-forward-mode 0 1 True False Physical Network 1 0 True False 1 1 False True 1 True False vertical 6 _Pool containing all of VFs of a SR-IOV device True True False start start True True net-forward-dev False True 0 True False 25 True False 4 6 True False end True Device _List: True net-forward 0 0 200 True False True 1 0 False True 1 False True 2 False True 0 True False vertical 3 Enable IPv6 internal routing/networking True True False start 12 True False True 0 True False 25 True False start If an IPv6 network address is <b>not</b> specified, this will enable IPv6 internal routing between virtual machines. By default, IPv4 internal routing is enabled. True True 30 False True 1 False True 1 True False 6 True False start DNS Domain Name: False False 0 True True 20 â— 20 False False False False 1 False True 2 True True 2 3 True False Misc 3 False True True 1 True False 12 end gtk-cancel True True True True False False 1 gtk-go-back True True True True False False 2 gtk-go-forward True True True True True False False 3 _Finish True True image2 True False False 4 False True 2 False True 1 virt-manager-1.5.1/ui/storagebrowse.ui0000664000175100017510000000164613240655316021452 0ustar crobinsocrobinso00000000000000 False 6 Choose Storage Volume 750 500 True dialog True False virt-manager-1.5.1/ui/delete.ui0000664000175100017510000002434713240655316020031 0ustar crobinsocrobinso00000000000000 450 350 False Delete Virtual Machine center-on-parent dialog True False vertical 6 True False queue True False 6 10 True False vm_delete_wizard 6 False False 0 True False start <span size='large' color='white'>Placeholder</span> True False True 1 False True 0 True False 12 vertical 18 True False vertical 6 True False 3 True False gtk-dialog-warning False True 0 True False <small>This VM is currently running and will be forced off before being deleted</small> True False True 1 0 0 Delete _associated storage files True True False start True True 0 1 True True True True never etched-in True True 0 2 True True 0 True False 6 end gtk-cancel True True True True False False 0 gtk-delete True True True True False False 1 False True 1 True True 1 virt-manager-1.5.1/ui/asyncjob.ui0000664000175100017510000002132313240655316020366 0ustar crobinsocrobinso00000000000000 False 12 Operation in progress False center-on-parent 300 200 dialog True True False True False vertical 5 True False True False start 3 3 10 10 gtk-dialog-info 6 False False 0 True False start start Please wait a few moments... True 50 True True 1 True True 0 False 6 True False 3 3 gtk-dialog-warning False True 0 400 True False some warning True 40 True True 1 False True 1 True False start start 3 3 3 3 Processing... False False 2 True False 0.10000000149 False False 3 True False 12 gtk-cancel True True True True False False end 1 False False end 4 True True 380 200 True True in True False _Details True False False True 5 virt-manager-1.5.1/ui/createvol.ui0000664000175100017510000007512013240655316020546 0ustar crobinsocrobinso00000000000000 100000 1 1 1000 100000 1 1 1000 True False gtk-new True False gtk-open False Add a Storage Volume False dialog True False vertical 6 True False queue True False 6 10 True False gtk-new 6 False False 0 True False True False start <span size='large' color='white'>Create storage volume</span> True True True 0 True True 1 False True 0 True False 12 vertical 18 True False 1 True False vertical 12 True False start Create a storage unit to be used directly by a virtual machine. False True 0 True False 18 True False True 4 6 True False 2 True True â— 30 True True 0 True False suffix False False 1 1 0 True False start 1 1 True False start _Name: True vol-name 0 0 True False start F_ormat: True vol-format 0 1 0 0 True False vertical 5 True False vertical True False start <b>Storage Volume Quota</b> True False False 0 True False 3 True False (parent-name) False False 0 True False available space: True False False 1 True False (space) False False 2 False False 1 False False 0 True False 8 4 6 True True â— 1.0 adjustment2 10 1 1 1 0 True True â— 1.0 adjustment1 10 1 1 1 1 True False start GiB 2 1 True False start GiB 2 0 True False end Max Ca_pacity: True vol-capacity 0 0 True False end _Allocation: True vol-allocation 0 1 False False 1 0 2 True True False True False 6 True False Path: 0 0 True True True 1 0 Browse... True True True image2 2 0 True False False Backing store 0 1 True True 1 True True 0 True False 6 end gtk-cancel True True True True False False 1 _Finish True True True image1 True False False 2 False True 1 False True 1 virt-manager-1.5.1/ui/gfxdetails.ui0000664000175100017510000005605313245061760020717 0ustar crobinsocrobinso00000000000000 5900 50000 5901 1 10 5900 50000 5900 1 10 True False 6 6 True False 6 True True False start start 6 True False False 0 True False vertical 3 True True False â— graphics-password False True 0 Show passwor_d True True False True True False True 1 True True 1 1 5 True False end _Type: True graphics-type 0 0 True False end Addr_ess: True graphics-address 0 2 True False end start 6 Pa_ssword: True graphics-password-chk 0 5 True False end _Port: True graphics-port 0 3 True False False False True False end T_LS port: True graphics-tlsport 0 4 True False 6 Aut_o True True False start True True graphics-tlsport-auto True True 0 True True â— 5901 adjustment4 1 True True if-valid 5901 graphics-tlsport False True 1 1 4 True False end Ke_ymap: True graphics-keymap 0 6 True False start False True True start False 1 6 True False 6 A_uto True True False start True True graphics-port-auto True True 0 True True â— 5900 adjustment5 1 True True if-valid 5900 graphics-port False False 1 1 3 True False end Display: 0 7 True False end XAuth: 0 8 True False start label 1 7 True False start label 1 8 True False start True True 1 2 True False start True True 1 0 True False end start Open_GL: True graphics-opengl 0 9 True False end L_isten type: True graphics-listen-type 0 1 True False start True True 1 1 True False vertical 3 True False 3 True True False True False True 0 False gtk-dialog-warning False True 1 0 0 False 3 True False start False True True start graphics-rendernode False True 1 False gtk-dialog-warning False True 2 0 1 1 9 virt-manager-1.5.1/ui/connect.ui0000664000175100017510000004417413245061760020217 0ustar crobinsocrobinso00000000000000 True False gtk-connect False 6 Add Connection False dialog True False vertical 6 True False end gtk-cancel True True True False True False False 0 Co_nnect True True True True True image1 True False False 1 False True end 0 True False 6 6 6 True False Hypervisor Select 1 0 True False start _Hypervisor: True hypervisor 0 0 True False Method 1 3 True False 0 6 2 Connect to _remote host True True False True True 0 2 2 True False start _Autoconnect: True autoconnect 0 7 True True False True True Autoconnect 1 7 True True â— Username 1 4 True False True True Hostname 1 5 True False start 24 H_ostname: True hostname 0 5 True False start 24 2 2 _Username: True True username-entry 0 4 True False start 24 Me_thod: True transport 0 3 True False 3 True False start start gtk-dialog-warning False True 0 True False False <small>QEMU usermode session is not the virt-manager default. It is likely that any pre-existing QEMU/KVM guests will not be available. Networking options are very limited. </small> True 20 False False 1 0 1 2 True False start Cu_stom URI: True uri-entry 0 9 True True True uri-entry 1 9 True False start uri end 22 uri-label 1 8 True False start Generated URI: 0 8 False True 1 cancel connect virt-manager-1.5.1/ui/netlist.ui0000664000175100017510000004004313240655316020240 0ustar crobinsocrobinso00000000000000 True False 6 6 True False start False _Bridge name: True net-bridge-name 0 1 True False start False Source m_ode: True net-source-mode 0 2 True True start True 1 1 True False start False 6 True False gtk-dialog-warning False True 0 True False start <small>In most configurations, macvtap does not work for host to guest network communication.</small> True True 35 False True 1 0 4 2 True False start True True True 1 2 True False 6 True False start False False True 0 True False gtk-dialog-warning False True 1 0 0 2 True False start False _Portgroup: True net-portgroup 0 3 True False start True True True 1 3 True False end start 3 3 _Network source: True net-source True True False 2 True False 3 6 True True center â— 30 1 4 True False end center Ins_tance id: True vport-instanceid 0 4 True True center â— 30 1 3 True False end center Typ_eid version: True vport-typeidversion 0 3 True True center â— 30 1 2 True False end center T_ypeid: True vport-typeid 0 2 True True center â— 30 1 1 True False end center M_anagerid: True vport-managerid 0 1 True False end center _Type: True True vport-type 0 0 True True center â— 30 1 0 False True 0 True False Virtual _port True True virt-manager-1.5.1/ui/migrate.ui0000664000175100017510000012376013245061760020215 0ustar crobinsocrobinso00000000000000 70000 1 10 300 400 False Migrate the virtual machine False 400 300 dialog True False vertical 6 True False queue True False 6 10 True False vm_clone_wizard 6 False False 0 True False start <span size='large' color='white'>Placeholder</span> True False True 1 False True 0 True False 12 vertical 18 True False vertical 12 True False 6 6 True False end <span color='#484848'>Migrating VM:</span> True 0 0 True False end <span color='#484848'>Original host:</span> True 0 1 True False end <span color='#484848'>New _host:</span> True True migrate-dest 0 2 True False start label end 1 0 True False start label end 1 1 True False 1 2 False True 0 True False vertical 18 True False 0 none True False 22 True False 12 True False 6 6 True False end _Address: True migrate-set-address 0 0 True False start _Port: True migrate-set-port 0 2 True True False start True 1 0 True True False start True 1 2 True False True True â— 0 adjustment1 False True 0 True False start Let libvirt decide True True 1 2 2 True False True True â— False True 0 True False start Let libvirt decide False True 1 2 0 True False 6 True False start gtk-dialog-warning False True 0 True False start <span size="small">foo bar baz foo bar baz foo bar baz foo bar baz foo bar baz foo bar baz foo bar baz fo</span> True True 40 False True 1 2 1 0 1 True False 6 True False Tunnel migration through the libvirtd connection channel, rather than having the hypervisor open a separate network connection to the destination. The source libvirt instance connects directly to the destination libvirt instance. This can simplify setup since no additional firewall ports need to be open, and will encrypt migration traffic if your libvirt connection is encrypted. But it can be difficult to make this work with SSH transport. end M_ode: True migrate-mode False True 0 True False start False False True 1 0 0 True False 6 True False True 6 True False start gtk-dialog-warning False True 0 True False start <span size="small">foo bar baz foo bar baz foo bar baz foo bar baz foo bar baz foo bar baz</span> True True 0 40 False True 1 1 1 True False start False _URI: True migrate-tunnel-uri 0 0 True True True 1 0 0 2 True False <b>Connectivity</b> True False True 0 True True 6 True False 22 True False 6 6 True False By default libvirt will refuse to migrate a VM for certain configurations that could lead to malfunctioning guests, like if a disk's cache mode is not 'none'. Enabling this option tells libvirt to skip those checks. start A_llow unsafe: True migrate-unsafe 0 0 True True False start True 1 0 True False By default, the migrated VM config is removed from the source host, and saved persistently on the destination host. The destination host is considered the new home of the VM. If 'temporary' is selected, the migration is considered only a temporary move: the source host maintains a copy of the VM config, and the running copy moved to the destination is only transient, and will disappear when it is shutdown. start _Temporary move: True migrate-temporary 0 1 True True False start True 1 1 True False Advanced options False True 1 False True 1 True True 0 True False 6 end gtk-cancel True True True True False False 1 _Migrate True True True True False False 2 False True 1 True True 1 virt-manager-1.5.1/ui/details.ui0000664000175100017510000151412713245061760020214 0ustar crobinsocrobinso00000000000000 1 10240000 50 1 25 1000000000 1024 1000000000 10 1000000000 1024 1000000000 10 65536 1 25 65536 1 25 10000000 1000 1 25 10000000 1000 1 25 65536 10 1 25 65536 10 1 25 1 10240000 50 1 25 1 256 1 1 10 1 256 1 1 10 1 256 1 1 10 1 1024 1 1 2 1 1024 2 1 2 1000000000 1024 1000000000 10 True False gtk-apply True False gtk-add False Virtual Machine 800 600 True False vertical True False True False _File True False True False _View Manager True True False gtk-close True False True True accelgroup1 gtk-quit True False True True accelgroup1 True False Virtual _Machine True False True False True False _Take Screenshot True True False Redirect host USB device to virtual machine with SPICE graphics. _Redirect USB device True True False _View True False True False _Console True True True True False _Details True True details-menu-view-console True False Sna_pshots True True details-menu-view-console True False True False _Fullscreen True True False _Resize to VM True True False _Scale Display True True False True False _Always True True True False _Only when Fullscreen True True details-menu-view-scale-always True False _Never True True details-menu-view-scale-always True False True False Auto _resize VM with window True True False _Text Consoles True True False True False T_oolbar True True True False Send _Key True False False 0 True False True False True False Show the graphical console Console icon_console True False True True False Show virtual hardware details Details gtk-info control-vm-console False True True False False True True False Power on the virtual machine Run True gtk-media-play False True True False Pause the virtual machine Pause True gtk-media-pause False True True False Shut down the virtual machine _Shut Down True False False True False False True True False Snapshots vm_clone_wizard control-vm-console False True True False Switch to fullscreen view end gtk-fullscreen True True True True 0 False both-horiz True False Begin Installation True _Begin Installation True gtk-apply False True True False True _Cancel Installation True gtk-cancel False True True True 1 False True 1 True True False True False 12 12 True False vertical 6 True True never in True True False hw-list hw-list-scroll True True 0 A_dd Hardware True True False image80 True add-hardware False False 1 False True 0 True False vertical 6 True True left False True False vertical 12 True False 0 none True False 3 12 True False 3 6 6 True False start Status: 0 2 True False start UUID: 0 1 True False start _Name: True overview-name 0 0 True False start 8ffc926e-b4da-b3b6-552f-e37b92f918d5 True 1 1 True True False 1 0 True False start T_itle: True overview-title 0 3 True True 1 3 True False 3 True False start Shut down 1 0 22 True False start gtk-missing-image 0 0 1 2 True False start start D_escription: True overview-description 0 4 True True in 80 True True True word 2 2 1 4 True False <b>Basic Details</b> True False True 0 True False 0 none True False 3 12 True False 3 6 6 True False start Hypervisor: 0 0 True False start Architecture: 0 1 True False start foo True 1 0 True False start foo True 1 1 True False start foooooooooooooo True 1 2 True False start Emulator: 0 2 True False end start Machine _Type: True 0 3 True False start start Chipse_t: True middle 0 5 True False start start Firmware: 0 4 True False 3 True False True False False True 0 True False start False label False True 1 False True 0 True False gtk-dialog-warning False True 1 1 4 True False True False start False True 0 True False label False True 1 1 3 True False True False start False False True 0 True False start start True label False True 1 1 5 True False <b>Hypervisor Details</b> True False True 1 True True True False 3 12 True False vertical 6 6 Enable User Namespace True True False start True 0 0 True False 6 6 True False end User ID: 15 0 1 True False end Group ID: 15 0 2 True False Start 20 1 0 True False Target 20 2 0 True False Count 20 3 0 True False 15 0 0 True True 6 adjustment16 2 1 True True adjustment17 2 2 True True 6 adjustment18 3 1 True True adjustment19 3 2 True False 0 1 2 True False 0 10 1 1 0 1 True False <b>User Namespace</b> True True True 2 overview-tab True False over False True False start vertical True False vertical 12 True False 0 none True False 12 True False 3 6 6 True False end Product name: 0 2 True False start foo True 1 0 True False end Hostname: 0 0 True False end Operating system: 0 1 True False start foo True 1 2 True False start foo 1 1 True False <b>Operating System</b> True False True 0 True True True False 3 21 150 True True etched-in True True True False <b>Applications</b> True False True 1 False True 0 True False start end vertical 6 True False start start gtk-dialog-warning 0 0 True False start start Error message bar 80 1 0 True True 1 Refresh True True True end False False 2 inspection-tab 1 False True False inspect 1 False True False vertical True False vertical 12 True False 0 none True False 12 True False vertical 3 75 True False False True 0 True False end 18% False True 1 True False <b>CPU usage</b> True False False 0 True False 0 none True False 12 True False vertical 3 75 True False False True 0 True False end 30 MiB of 128 MiB False True 1 True False <b>Memory usage</b> True False False 1 True False 0 none True False 12 True False vertical 3 75 True False False True 0 True False end 0 KiBytes/s 0 KiBytes/s True False True 1 True False <b>Disk I/O</b> True False False 2 True False 0 none True False 12 True False vertical 3 75 True False False True 0 True False end 0 KiBytes/s 0 KiBytes/s True False True 1 True False <b>Network I/O</b> True False False 3 False True 0 performance-tab 2 False True False stat 2 False True False start vertical 12 True False 0 none True False 3 12 True False 6 True False 3 6 12 True False start center 8 True 1 0 True False start center Logical host CPUs: 0 0 True False start center Ma_ximum allocation: True cpu-maxvcpus 0 2 True False start center Current a_llocation: True cpu-vcpus 0 1 True True â— adjustment6 1 2 True True center â— adjustment7 1 True if-valid Virtual CPU Select 1 1 False True 0 True False 6 True False start gtk-dialog-warning False False 0 300 True False start <small>Overcommitting vCPUs can hurt performance</small> True True 32 True True 1 True True 1 True False <b>CPUs</b> True False False 0 True False 0 none True False 3 12 True False start start 3 12 True False start M_odel: True combobox-entry 0 1 Copy host CP_U configuration True True False start True True 0 0 2 True False True True cpu-model 1 1 True False <b>Configu_ration</b> True True True True 1 True True True False 23 12 True False vertical 4 Manuall_y set CPU topology True True False True True True False True 0 True False start 0 True False 6 True False 4 12 True False start Thread_s: True cpu-threads 0 2 True False start Cor_es: True cpu-cores 0 1 True False start Socke_ts: True cpu-sockets 0 0 True True start False â— adjustment3 1 0 True True start False True â— adjustment4 1 1 True True start True True â— adjustment5 1 2 False True 0 True False 6 True False start end gtk-dialog-warning False False 0 300 True False start end <small>Selected CPU model does not support Hyper-Threading</small> True True 32 True True 1 True True 1 False True 1 True False <b>To_pology</b> True True False True 2 cpu-tab 3 True False cpu 3 False True False vertical True False 0 none True False 3 12 True False 3 6 6 True False end center Current a_llocation: True mem-memory 0 1 True False end center Ma_ximum allocation: True mem-maxmem 0 2 True False end center Total host memory: 0 0 True False start center 2 GiB True 1 0 True False center True 3 True True â— adjustment2 2 True if-valid Memory Select False True 0 True False start MiB True True 1 1 1 True False center 3 True True â— adjustment1 2 True if-valid Max Memory Select False True 0 True False start MiB True True 1 1 2 True False <b>Memory</b> True True True 0 memory-tab 4 True False mem 4 False True False 24 True False 0 none True False 3 12 Start virt_ual machine on host boot up True True False True True True False <b>Autostart</b> True 0 0 True False 0 none True False 3 12 True False 6 6 True True â— 25 1 0 True False start Init _path: True boot-init-path 0 0 True False start Init ar_gs: True boot-init-args 0 1 True True 25 1 1 True False <b>Container init</b> True 0 3 True True start False True False 3 12 True False vertical 6 Ena_ble direct kernel boot True True False start True True False True 0 True False 6 True False 6 True False start 8 8 Ke_rnel path: True boot-kernel 0 0 True False start 8 8 _Initrd path: True boot-initrd 0 1 True False center True 6 True True â— True True 0 Browse True True True initrd-browse False True 1 1 1 True False center True 6 True True â— True True 0 Browse True True True kernel-browse False True 1 1 0 True False start 8 8 Kernel ar_gs: True boot-kernel-args 0 3 True True True â— 40 1 3 True False start 8 8 D_TB path: True boot-dtb 0 2 True False center True 6 True True â— True True 0 Browse True True True dtb-browse False True 1 1 2 False True 0 False True 1 True False <b>Dir_ect kernel boot</b> True True 0 2 True False 0 none True False 3 12 True False vertical 6 Enable boot me_nu True True False start True True False True 0 True False start False 6 6 125 125 True True never in True True False 0 0 True False vertical 6 True False True True start True False gtk-go-up boot-moveup False True 0 True False True True start False True False gtk-go-down boot-movedown False True 1 1 0 True True 1 True False <b>Boot device order</b> True 0 1 boot-tab 5 True False boot 5 False True False vertical 12 True False 0 none True False 3 12 True False vertical 12 True False 3 4 8 True False end R_eadonly: True disk-readonly 0 3 True False end Sharea_ble: True disk-shareable 0 4 True True False True 1 3 True True False start True 1 4 True False end Storage size: 0 2 True False start size 1 2 True False end Source path: True 0 0 True False start disk True 1 1 True False 6 True False start path True start disk-source-path False True 0 gtk-connect True True True True True Connect or disconnect media True False True 1 1 0 True False end Device type: True 0 1 True False end Removab_le: True disk-removable 0 5 True True False start True True 1 5 False True 0 True True True False vertical 6 True False 3 8 True False end Disk b_us: True disk-bus-combobox-entry 0 0 True True â— 20 1 1 True False True True 1 0 True False end Seria_l number: True disk-serial 0 1 True False vertical 6 True True False True 0 True False 3 True False gtk-dialog-warning False True 0 True False <small>Changing this will not change the disk image format, it only tells libvirt about the existing image format. </small> True True 30 False False 1 False True 1 1 3 True False end start 4 4 Storage forma_t: True disk-format 0 3 True False end _SGIO: True disk-sgio-entry 0 2 True False True True 1 2 False True 0 True True True False 3 8 True False end Cac_he mode: True cachemode-entry-box 0 0 True False True True 1 0 True False True True 1 1 True False end _IO mode: True iomode-entry-box 0 1 True False _Performance options True False True 1 True False Advanced _options True expander4 False True 1 True False <b>Virtual Disk</b> True False True 0 True False 5 end False False end 1 disk-tab 6 True False dsk 6 False True False vertical 12 True False 0 none True False 3 12 True False 3 6 6 True False end Device mode_l: True network-model-combobox 0 1 True False end MAC address: True 0 2 True False start False True True 1 1 True False False False 0 0 True False False False 1 0 True False True False start mac True False True 0 True True False True 1 1 2 True False <b>Virtual Network Interface</b> True False True 0 True False True True 1 network-tab 7 True False net 7 False True False vertical 12 True False 0 none True False 3 12 True False 3 4 8 True False end Type: True 0 0 True False end Mode: 0 1 True False start label401 True 1 1 True False start label403 True 1 0 True False <b>Virtual Input Device</b> True False False 0 input-tab 8 True False inp 8 False True False vertical True False 0 none True False 3 12 True False <b>Display title</b> True False True 0 graphics-tab 9 True False gfx 9 False True False vertical True False 0 none True False 3 12 True False 3 4 8 True False start center M_odel: True combobox-entry12 0 0 True False True True 1 0 True False <b>Sound Device</b> True True True 0 sound-tab 10 True False snd 10 False True False vertical True False 0 none True False 3 12 True False 3 4 8 True False end Device type: 0 0 True False start label506 True 1 0 True False start label508 True 1 1 True False start label 1 3 True False start label 1 4 True False start label508 True 1 5 True False start label 1 2 True False end Source host: 0 2 True False end Bind host: 0 3 True False end Target type: 0 4 True False end Target name: 0 5 True False end Source path: 0 1 True False <b>insert type</b> True True True 0 char-tab 11 True False chr 11 False True False vertical True False 0 none True False 3 12 True False 6 6 True False start Device: 0 0 True False start label True 1 0 True False start ROM _BAR: True hostdev-rombar 0 1 True True False start True 1 1 True False <b>Physical Host Device</b> True True True 0 host-tab 12 True False phy 12 False True False vertical True False 0 none True False 12 3 6 6 True False end M_odel: True combobox-entry13 0 0 True False True True 1 0 True False end RAM: 0 1 True False start label True 1 1 True False end Heads: 0 2 True False start label True 1 2 True False end _3D acceleration: True video-3d 0 3 True True False True 1 3 True False <b>Video</b> True True True 0 video-tab 13 True False vid 13 False True False vertical True False 0 none True False 3 12 True False 4 8 True False end center Ac_tion: True combobox-entry14 0 1 True False end center M_odel: True combobox-entry15 0 0 True False True True 1 1 True False True True 1 0 True False <b>Watchdog</b> True True True 0 watchdog-tab 14 True False wdog 14 False True False 0 none True False 3 12 True False 6 6 True False end Type: 0 0 True False start foo 1 0 True False True True controller-model 1 1 True False end False M_odel: True combobox-entry16 0 1 True False end start False Devices: True 0 2 True False vertical 3 270 100 True True in True True True True 0 1 2 True False <b>Controller</b> True controller-tab 15 True False ctrl 15 False True False 0 none True False 3 12 True False <b>Filesystem</b> True filesystem-tab 16 True False fs 16 False True False vertical True False 0 none True False 3 12 True False 3 2 8 4 True False start M_ode: True combobox-entry17 GTK_FILL True False True True smartcard-mode 1 2 GTK_FILL GTK_FILL True False <b>Smartcard Device</b> True True True 0 smartcard-tab 17 True False sc 17 False True False 0 none True False 3 12 True False 3 4 8 True False start Type: 0 0 True False start Address: 0 1 True False start foo:12 1 1 True False start redir type 1 0 True False <b>Redirected device</b> True redir-tab 18 True False rd 18 False True False vertical 12 True False 0 none True False 3 12 True False 3 4 8 True False start tpm-dev-type 1 0 True False start tpm-device-path 1 1 True False end Type: 0 0 True False end Path: 0 1 True False <b>TPM Device</b> True True True 0 tpm-tab 19 True False tpm 19 False True False 0 none True False 12 True False 3 4 8 True False start rng-type 1 0 True False end Type: True 0 0 True False start rng-device 1 1 True False end Host Device: 0 1 True False end Backend type: 0 2 True False start rng-backend-type 1 2 True False end Mode: 0 3 True False start rng-mode 1 3 True False end Host: 0 4 True False start rng-connect-host 1 4 True False end Service: 0 5 True False start rng-connect-service 1 5 True False end Bind Host: 0 6 True False start rng-bind-host 1 6 True False end Bind Service: 0 7 True False start rng-bind-service 1 7 True False end Rate (period): 0 8 True False start rng-rate-period 1 8 True False end Rate (bytes): 0 9 True False start rng-rate-bytes 1 9 True False <b>Random Number Generator</b> True rng-tab 20 True False rng 20 False True False 0 none True False 12 True False 4 8 True False start 3 3 Model: 0 0 True False start panic-model 1 0 True False <b>Panic Notifier</b> True panic-tab 21 True False panic 21 False True True 0 True False 12 end gtk-remove True True True False True config-remove False False 0 gtk-cancel True True True True config-cancel False False 1 gtk-apply True False True True False True config-apply False False 2 False True 1 True True 1 True False Details False True True False True False center center <b>The console is currently unavailable</b> True center True True 60 60 True True False Unavailable False True False 3 3 3 3 3 True False start _Password: True console-auth-password 1 2 GTK_FILL True True False 1 2 1 2 _Save this password in your keyring True True False Check to save password, uncheck to forget password. start True True 1 2 2 3 GTK_FILL True False start _Username: True console-auth-username GTK_FILL True True 1 2 _Login True True False image70 True 2 3 1 2 GTK_FILL True False 2 3 GTK_FILL GTK_FILL True False 2 3 GTK_FILL GTK_FILL True False 2 3 2 3 GTK_FILL GTK_FILL 1 True False Auth 1 False True True serial-pages 2 True False Serial 2 False True False True True True False queue none console-gfx-viewport -1 3 True False Graphics 3 False 1 True False Console 1 False True False vertical 2 True False Snapshots 2 False True True 2 virt-manager-1.5.1/ui/snapshots.ui0000664000175100017510000012551713245061760020611 0ustar crobinsocrobinso00000000000000 True False gtk-new False Create snapshot False dialog True False vertical 6 True False queue True False 6 10 True False gtk-new 6 False False 0 True False True False start <span size='large' color='white'>Create snapshot</span> True True True 0 True True 1 False True 0 True False 12 vertical 18 True False 6 6 True False start _Name: True snapshot-new-name 0 0 True True â— 1 0 True False start start _Description: True snapshot-new-description 0 2 300 125 True True in True True 1 2 True False start Status: 0 1 True False 3 True False gtk-cancel False True 0 True False start Shut down False True 1 1 1 True False start start Screenshot: 0 3 True False start gtk-missing-image 1 3 False True 0 True False 6 end gtk-cancel True True True True False True 0 _Finish True True True image3 True False True 1 False True 1 False True 1 600 400 False True False True True 12 vertical 6 True True 200 True True True never in True True False snapshot-list False False True False 12 True True False True False vertical 12 True False 6 6 True False start start Description: 0 5 80 True True True in True True 2 2 1 5 True False start VM State: 0 3 True False 3 True False gtk-cancel False True 0 True False start Shut down False True 1 1 3 True False start Timestamp: 0 2 True False start label 1 2 True False start <b>snapshot 'foo'</b> True 0 0 2 True False start Snapshot Mode: 0 4 True False start label 1 4 True False start start Screenshot: 0 6 True False True False gtk-missing-image False True 0 True False No screenshot available False True 1 1 6 True False 3 True False gtk-info 2 False True 0 True False start <small><i>This was the most recently applied snapshot.</i></small> True False True 1 0 1 2 False True 0 True False details False True False error label snapshot-error-label 1 True False empty 1 False True True True True 0 True False 6 True False True True True True Create new snapshot Create new snapshot True False gtk-add snapshot-add False False 0 True True True Run selected snapshot True False gtk-media-play snapshot-start False False 1 True True True Refresh snapshot list True False gtk-refresh snapshot-refresh False True 2 True True True True Delete selected snapshot Delete selected snapshot True False gtk-delete snapshot-delete False False 3 True True 0 True False 6 end gtk-apply True True True True Save updated snapshot metadata Save updated snapshot metadata True snapshot-apply False True 0 False True 1 False True 1 virt-manager-1.5.1/ui/addstorage.ui0000664000175100017510000002502613245061760020676 0ustar crobinsocrobinso00000000000000 1000000 0.10000000000000001 10 True False vertical 6 True False vertical 3 True True False start True True True False C_reate a disk image for the virtual machine True True True True 0 True False 22 True False vertical 4 True False 6 True True end 0.0 adjustment1 1 1 False False 0 True False _GiB True storage-size False True 1 False False 0 True False start <span color='#484848'>Free Space</span> True False False 1 False False 1 True True 0 True False False False 2 True False vertical 6 True True False start True True storage-create True False _Select or create custom storage True True False True 0 True False False 6 True True True True True False _Manage... True storage-browse storage-browse False True 0 True True 25 storage-entry True True 1 False True 1 False False 3 virt-manager-1.5.1/ui/manager.ui0000664000175100017510000006030413245061760020171 0ustar crobinsocrobinso00000000000000 True False gtk-add True False gtk-properties True False gtk-properties False Virtual Machine Manager 550 550 center True False vertical True False True False _File True False _Add Connection... True False True image2 False True False _New Virtual Machine True True False gtk-close True False True True accelgroup1 gtk-quit True False True True accelgroup1 True False _Edit True False _Connection Details True False True image5 False _Virtual Machine Details True False True image4 False gtk-delete True False True True accelgroup1 True False gtk-preferences True False True True accelgroup1 True False _View True False True False _Graph True True False True False _Guest CPU Usage True True True False _Host CPU Usage True True False _Memory Usage True True False _Disk I/O True True True False _Network I/O True True True False _Help True False gtk-about True False True True accelgroup1 False False 0 True False vertical True False False True False True Create a new virtual machine New True vm_new_large False True True False False True True False True Show the virtual machine console and details True _Open True icon_console False True True False True Power on the virtual machine _Run True gtk-media-play False True True False True Pause the virtual machine _Pause True gtk-media-pause False True True False True Shut down the virtual machine _Shut Down True False False False True 0 True True False True True True True vm-list True False manager False True False error 1 True False error 1 False True True 1 True True 1 virt-manager-1.5.1/ui/preferences.ui0000664000175100017510000015624713245061760021074 0ustar crobinsocrobinso00000000000000 1 60 1 5 False 12 Preferences False dialog True False vertical 12 True True True False 12 0 none True False 12 True False 6 6 Enable _system tray icon True True False True True 0 0 True False <b>General</b> True True False _General True False True False start start False 12 0 none True False 12 True False 3 6 True False start Poll _Disk I/O True prefs-stats-enable-disk 0 2 True True False start True 1 2 True False start Poll _Network I/O True prefs-stats-enable-net 0 3 True True False start True 1 3 True False start Poll _Memory stats True prefs-stats-enable-memory 0 4 True True False start True 1 4 True False start _Update status every True 0 0 True False 3 True True â— adjustment1 cpu-poll False True 0 True False start seconds False True 1 1 0 True False start Poll C_PU usage True prefs-stats-enable-cpu 0 1 True True False start True 1 1 True False <b>Stats Options</b> True 1 True False P_olling True 1 False True False 12 vertical 12 True False 0 none True False 12 True False 6 6 True False start Gra_phics type: True prefs-graphics-type 0 1 True False Default storage format for new disk images. start _Storage format: True prefs-storage-format 0 3 True False 1 1 True False Default storage format for new disk images. 1 3 True True False start True True True 1 0 True False start _Add sound device: True prefs-new-vm-sound 0 0 True False Default CPU setting for new VMs. This is typically a tradeoff between performance and migration compatibility: if using the 'copy host' option, your servers will need identical CPUs in order to migrate the VM. start CPU _default: True prefs-cpu-default 0 4 True False 1 4 True False start Add Spice _USB Redirection: True prefs-add-spice-usbredir 0 2 True False start prefs-add-spice-usbredir 1 2 True False <b>New VM Defaults</b> True False True 0 2 True False N_ew VM True 2 False True False 12 0 none True False 12 True False 3 6 True False start Graphical console _scaling: True 0 0 True False True False start Gr_ab keys: True prefs-keys-grab-changebtn False True 0 True False start Not supported True True 8 1 0 2 True False 1 0 True True False When the guest graphical console has keyboard focus, do not disable shortcuts for console window menus (Alt+F -> File, etc.) Normally these are disabled to ensure that typing in the guest does not accidentally perform an operation in virt-manager's console window. start True 1 3 True False When the guest graphical console has keyboard focus, do not disable shortcuts for console window menus (Alt+F -> File, etc.) Normally these are disabled to ensure that typing in the guest does not accidentally perform an operation in virt-manager's console window. start _Force console shortcuts: True prefs-console-accels 0 3 Change... True True True start False 1 2 True False Change guest resolution when the guest window size is changed. Only works with properly configured guest using spice and the desktop agent. start _Resize guest with window: True prefs-console-resizeguest 2 0 1 True False 1 1 True False <b>Graphical Consoles</b> True 3 True False Conso_le True 3 False True False 12 0 none True False 6 12 True False 6 12 True False start _Force Poweroff: True prefs-confirm-forcepoweroff 0 0 True True False True 1 0 True False start Poweroff/_Reboot/Save: True prefs-confirm-poweroff 0 1 True False start _Pause: True prefs-confirm-pause 0 2 True True False True 1 1 True True False True 1 2 True True False True 1 4 True False start Device re_moval: True prefs-confirm-removedev 0 4 True False start _Interface start/stop: True prefs-confirm-interface 0 3 True True False True 1 3 True False start _Unapplied changes: True prefs-confirm-unapplied 0 5 True True False True 1 5 True False start _Deleting storage: True prefs-confirm-delstorage 0 6 True True False start True 1 6 True False <b>Confirmations</b> True 4 True False Feed_back True 4 False True True 0 True False end gtk-close True True True True False False 1 False True 1 300 5 5 virt-manager-1.5.1/ui/createinterface.ui0000664000175100017510000037504013245061760021711 0ustar crobinsocrobinso00000000000000 4095 1 10 1024 0.01 1 False 5 Bridge configuration center-on-parent True dialog True False vertical 2 True False end gtk-ok True True True True False False 1 False True end 0 True False 0 none True False 3 12 True False 6 6 True False start Forward _delay: True bridge-delay 0 0 True False start Enable _STP: True bridge-stp 0 1 True True False True 1 1 True False 3 True True â— adjustment2 0.050000000000000003 2 True True 0 True False seconds True True 1 1 0 True False <b>Bridge configuration</b> True False True 1 bridge-ok 1024 1 10 10000 1 10 10000 1 10 10000 1 10 False 5 Bonding configuration center-on-parent True dialog True False vertical 2 True False end gtk-ok True True True True False False 1 False True end 0 True False 0 none True False 3 12 True False vertical 6 True False 6 6 True False start B_ond monitor mode: True bond-monitor-mode 0 1 True False 1 0 True False 1 1 True False start _Bond mode: True bond-mode 0 0 False True 0 True True False True False 0 none True False 12 True False 6 6 True False start Target address: 0 2 True False start Interval: 0 0 True False 3 True True â— adjustment6 False True 0 True False start seconds False True 1 1 0 True True True â— 1 2 True False True True False False True 0 1 1 True False start Validate mode: 0 1 True False <b>ARP settings</b> True True False arp False True False 0 none True False 12 True False 6 6 True False start Frequency: 0 0 True False start Up delay: 0 1 True False start Down delay: 0 2 True False start Carrier type: 0 3 True False True 3 True True â— adjustment5 False True 0 True False start seconds True True 1 1 0 True False True 3 True True â— adjustment4 False True 0 True False start seconds True True 1 1 1 True False True 3 True True â— adjustment3 False True 0 True False start seconds True True 1 1 2 True False True True False False True 0 1 3 True False <b>MII settings</b> True 1 True False mii 1 False True False 2 True False default 2 False True True 1 True False <b>Bond configuration</b> True False True 1 bond-ok True False gtk-new False Configure network interface 300 400 dialog True False vertical True False queue True False 6 10 True False network-idle 6 False False 0 True False True False vertical True False start <span size='large' color='white'>Configure network interface</span> True False True 0 True False start <span color='#59B0E2'>Step foo of bar</span> True False True 1 True True 0 True True 1 False False 0 True False 12 vertical 15 True True False True False vertical 6 True False start Select the interface type you would like to configure. False True 0 True False 12 True False start _Interface type: True interface-type False True 0 True False False True 1 False True 1 True False Type False True False vertical 12 True False 6 12 True False start _Name: True interface-name-entry 0 0 True False True True True â— False True 0 True False start name label True True 1 1 0 True False start _Start mode: True interface-startmode 0 1 True False True 6 True False False True 0 1 1 True False start _Activate now: True interface-activate 0 2 True True False True True 1 2 True False vertical True False start _VLAN tag: True vlan-tag True False 0 True False start Bridge settings: True False 1 True False start Bond mode: True False 2 0 4 True False True vertical True False True True â— adjustment1 False True 0 False False 0 True False 6 True False start bridge desc True True 0 C_onfigure True True True True bridge-configure False True 1 False False 1 True False 6 True False start bond desc True True 0 C_onfigure True True True True bond-configure False True 1 False False 2 1 4 True False start IP settings: 0 3 True False True 6 True False start ip desc True True 0 Config_ure True True True True ip-configure False True 1 1 3 False True 0 True False vertical 3 True False start Insert list desc: False True 0 True True etched-in True True True True 1 True True 1 1 True False Details 1 False True True 0 True False 12 end gtk-cancel True True True True False False 1 gtk-go-back True False True True True False False 2 gtk-go-forward True True True True False False 3 _Finish True True image1 True False False 4 False True 1 True True 1 False 5 IP Configuration center-on-parent True dialog True False vertical 2 True False end gtk-ok True True True True False False 1 False True end 0 True False 0 none True False 3 True False vertical 6 True False vertical 6 _Copy interface configuration from: True True False True True True ip-do-manual False True 0 True False 18 True False 6 True False False True 0 False True 1 False True 0 True False vertical 6 Ma_nually configure: True True False True True True False True 0 True False 18 True True False True False 6 vertical 12 True False 12 True False start _Mode: True ipv4-mode False True 0 True False ipv4-mode False True 1 False True 0 True False vertical 6 True False start Static configuration: False True 0 True False 6 True False 6 6 True False end _Address: True ipv4-address 0 0 True False end _Gateway: True ipv4-gateway 0 1 True True True â— 1 0 True True True â— 1 1 False True 1 True True 1 True False IPv4 False True False 6 vertical 12 True False 12 True False start _Mode: True ipv6-mode False True 0 True False ipv6-mode False True 1 A_utoconf True True False True True True True 2 False True 0 True False vertical 6 True False start Static configuration: False True 0 True False 6 True False vertical 6 True False vertical 3 True False start Addresses: False True 0 True False 12 True True etched-in True True False True True 0 True False vertical 6 gtk-add True True True True False True 0 gtk-remove True True True True False True 1 True False True True 2 False True 1 True True 1 True True 0 True False 6 True False start _Gateway: True False True 0 True True â— True True 1 False True 1 True True 1 True True 1 1 True False IPv6 1 False True True 1 True True 1 True False <b>IP Configuration</b> True False True 1 ip-ok virt-manager-1.5.1/tests/0000775000175100017510000000000013245574323016746 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/tests/hostkeymap/0000775000175100017510000000000013245574323021132 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/tests/hostkeymap/console-setup-debian9.txt0000664000175100017510000000043513245061760026002 0ustar crobinsocrobinso00000000000000# CONFIGURATION FILE FOR SETUPCON # Consult the console-setup(5) manual page. ACTIVE_CONSOLES="/dev/tty[1-6]" CHARMAP="UTF-8" CODESET="Lat15" FONTFACE="Fixed" FONTSIZE="8x16" VIDEOMODE= # The following is an example how to use a braille font # FONT='lat9w-08.psf.gz brl-8x8.psf' virt-manager-1.5.1/tests/hostkeymap/sysconfig-comments.txt0000664000175100017510000000046413245061760025522 0ustar crobinsocrobinso00000000000000# Path: Hardware/Keyboard ## Description: Keyboard settings ## Type: string ## Default: "" ## ServiceRestart: kbd # # Keyboard settings for the text console # # Keyboard mapping # (/usr/share/kbd/keymaps/) # e.g. KEYTABLE="de-latin1-nodeadkeys", "us" or empty for US settings # KEYTABLE="" virt-manager-1.5.1/tests/hostkeymap/default-keyboard-debian9.txt0000664000175100017510000000022613245061760026422 0ustar crobinsocrobinso00000000000000# KEYBOARD CONFIGURATION FILE # Consult the keyboard(5) manual page. XKBMODEL="pc105" XKBLAYOUT="us" XKBVARIANT="" XKBOPTIONS="" BACKSPACE="guess" virt-manager-1.5.1/tests/hostkeymap/xorg-rhel5.txt0000664000175100017510000000106613245061760023666 0ustar crobinsocrobinso00000000000000# Xorg configuration created by pyxf86config Section "ServerLayout" Identifier "Default Layout" Screen 0 "Screen0" 0 0 InputDevice "Keyboard0" "CoreKeyboard" EndSection Section "InputDevice" Identifier "Keyboard0" Driver "kbd" Option "XkbModel" "pc105" Option "XkbLayout" "us" EndSection Section "Device" Identifier "Videocard0" Driver "vesa" EndSection Section "Screen" Identifier "Screen0" Device "Videocard0" DefaultDepth 24 SubSection "Display" Viewport 0 0 Depth 24 EndSubSection EndSection virt-manager-1.5.1/tests/hostkeymap/sysconfig-rhel5.txt0000664000175100017510000000004013245061760024702 0ustar crobinsocrobinso00000000000000KEYBOARDTYPE="pc" KEYTABLE="us" virt-manager-1.5.1/tests/test_inject.py0000775000175100017510000001262313245573052021640 0ustar crobinsocrobinso00000000000000#!/usr/bin/env python2 # Copyright (C) 2013, 2014 Red Hat, Inc. from __future__ import print_function import atexit import os import logging import sys import unittest from tests import utils from virtinst import Guest from virtinst import urlfetcher from virtinst import util from virtinst.initrdinject import perform_initrd_injections cleanup = [] _alldistros = {} testconn = utils.open_testdefault() guest = Guest(testconn) guest.os.os_type = "hvm" guest.os.arch = "x86_64" meter = util.make_meter(quiet=False) DEVFEDORA_URL = "http://dl.fedoraproject.org/pub/fedora/linux/development/%s/Server/%s/os/" FEDORA_URL = "http://dl.fedoraproject.org/pub/fedora/linux/releases/%s/Server/%s/os/" (WARN_RHEL4, WARN_RHEL5, WARN_LATEST) = range(1, 4) def prompt(): sys.stdout.write("(press enter to continue)") sys.stdout.flush() return sys.stdin.readline() class Distro(object): def __init__(self, name, url, warntype=WARN_LATEST, ks2=False, virtio=True): self.name = name self.url = url self.virtio = virtio self.warntype = warntype self.ks = "tests/inject-data/old-kickstart.ks" if ks2: self.ks = "tests/inject-data/new-kickstart.ks" self.kernel = None self.initrd = None def _add(*args, **kwargs): _d = Distro(*args, **kwargs) _alldistros[_d.name] = _d _add("centos-4.9", "http://vault.centos.org/4.9/os/x86_64", warntype=WARN_RHEL4, ks2=True, virtio=False) _add("centos-5.11", "http://vault.centos.org/5.11/os/x86_64/", warntype=WARN_RHEL5) _add("centos-6-latest", "http://ftp.linux.ncsu.edu/pub/CentOS/6/os/x86_64/", warntype=WARN_RHEL5) _add("centos-7-latest", "http://ftp.linux.ncsu.edu/pub/CentOS/7/os/x86_64/", ks2=True) _add("fedora-27", FEDORA_URL % ("27", "x86_64"), ks2=True) def exit_cleanup(): for f in cleanup or []: try: os.unlink(f) except Exception: pass atexit.register(exit_cleanup) def _fetch_distro(distro): print("Fetching distro=%s" % distro.name) fetcher = urlfetcher.fetcherForURI(distro.url, "/tmp", meter) origenv = os.environ.pop("VIRTINST_TEST_SUITE") try: fetcher.prepareLocation() store = urlfetcher.getDistroStore(guest, fetcher) kernel, initrd, ignore = store.acquireKernel(guest) cleanup.append(kernel) cleanup.append(initrd) distro.kernel = kernel distro.initrd = initrd except Exception: logging.error("Fetching distro=%s failed", distro.name, exc_info=True) finally: fetcher.cleanupLocation() if origenv: os.environ["VIRTINST_TEST_SUITE"] = origenv def _test_distro(distro): os.system("clear") print("\n") if distro.warntype == WARN_RHEL4: print("RHEL4: Makes its way to the text installer, then chokes ") print("on our bogus URI http://HEY-THIS-IS-OUR-BAD-KICKSTART-URL.com/") elif distro.warntype == WARN_RHEL5: print("RHEL5, RHEL6, Fedora < 17: You'll get an error about a ") print("bogus bootproto ITREADTHEKICKSTART. This means anaconda ") print("read our busted kickstart.") else: print("RHEL7, Fedora >= 17: Chokes on the bogus URI in the early ") print("console screen when fetching the installer squashfs image.") originitrd = distro.initrd kernel = distro.kernel newinitrd = originitrd + ".copy" injectfile = distro.ks os.system("cp -f %s %s" % (originitrd, newinitrd)) cleanup.append(newinitrd) perform_initrd_injections(newinitrd, [injectfile], ".") nic = distro.virtio and "virtio" or "rtl8139" append = "-append \"ks=file:/%s\"" % os.path.basename(injectfile) cmd = ("sudo qemu-kvm -enable-kvm -name %s " "-cpu host -m 1500 -display gtk " "-net bridge,br=virbr0 -net nic,model=%s " "-kernel %s -initrd %s %s" % (distro.name, nic, kernel, newinitrd, append)) print("\n\n" + cmd) os.system(cmd) _printinitrd = False _printfetch = False class FetchTests(unittest.TestCase): def setUp(self): self.failfast = True global _printfetch if _printfetch: return print(""" This is an interactive test. First step is we need to go and fetch a bunch of distro kernel/initrd from public trees. This is going to take a while. Let it run then come back later and we will be waiting to continue. """) prompt() _printfetch = True class InjectTests(unittest.TestCase): def setUp(self): global _printinitrd if _printinitrd: return print(""" Okay, we have all the media. We are going to perform the initrd injection of some broken kickstarts, then manually launch a qemu instance to verify the kickstart is detected. How you know it's working depends on the distro. When each test launches, we will print the manual verification instructions. """) prompt() _printinitrd = True def _make_tests(): def _make_fetch_cb(_d): return lambda s: _fetch_distro(_d) def _make_check_cb(_d): return lambda s: _test_distro(_d) idx = 0 for dname, dobj in _alldistros.items(): idx += 1 setattr(FetchTests, "testFetch%.3d_%s" % (idx, dname.replace("-", "_")), _make_fetch_cb(dobj)) setattr(InjectTests, "testInitrd%.3d_%s" % (idx, dname.replace("-", "_")), _make_check_cb(dobj)) _make_tests() virt-manager-1.5.1/tests/checkprops.py0000664000175100017510000000241213245573052021456 0ustar crobinsocrobinso00000000000000 import traceback import unittest import virtinst class CheckPropsTest(unittest.TestCase): maxDiff = None def testCheckProps(self): # pylint: disable=protected-access # Access to protected member, needed to unittest stuff # If a certain environment variable is set, XMLBuilder tracks # every property registered and every one of those that is # actually altered. The test suite sets that env variable. # # test000ClearProps resets the 'set' list, and this test # ensures that every property we know about has been touched # by one of the above tests. fail = [p for p in virtinst.xmlbuilder._allprops if p not in virtinst.xmlbuilder._seenprops] try: self.assertEqual([], fail) except AssertionError: msg = "".join(traceback.format_exc()) + "\n\n" msg += ("This means that there are XML properties that are\n" "untested in the test suite. This could be caused\n" "by a previous test suite failure, or if you added\n" "a new property and didn't extend the test suite.\n" "Look into extending clitest.py and/or xmlparse.py.") self.fail(msg) virt-manager-1.5.1/tests/pylint.cfg0000664000175100017510000000257513240655316020754 0ustar crobinsocrobinso00000000000000[MESSAGES CONTROL] # Disable the message, report, category or checker with the given id(s). You # can either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). disable=Design,Similarities,invalid-name,missing-docstring,line-too-long,too-many-lines,superfluous-parens,bad-whitespace,locally-disabled,no-self-use,unnecessary-lambda,star-args,fixme,global-statement,bare-except,anomalous-backslash-in-string,broad-except,cyclic-import,bad-continuation,locally-enabled,unidiomatic-typecheck,redefined-variable-type,bad-option-value,wrong-import-position,consider-using-ternary,no-else-return,len-as-condition [REPORTS] reports=no score=no [FORMAT] # Maximum number of characters on a single line. max-line-length=80 [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME,XXX,TODO [VARIABLES] # A regular expression matching the beginning of the name of dummy variables # (i.e. not used). dummy-variables-rgx=ignore.*|.*_ignore # Argument names that match this expression will be ignored. Default to name # with leading underscore ignored-argument-names=_.*|ignore.*|.*_ignore # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins=_ virt-manager-1.5.1/tests/osdict.py0000664000175100017510000000605013245573052020604 0ustar crobinsocrobinso00000000000000# Copyright (C) 2013 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import unittest from virtinst import OSDB from tests import utils class TestOSDB(unittest.TestCase): """ Test osdict/OSDB """ def test_osdict_aliases_ro(self): aliases = getattr(OSDB, "_aliases") if len(aliases) != 42: raise AssertionError(_("OSDB._aliases changed size. It " "should never be extended, since it is only for back " "compat with pre-libosinfo osdict.py")) def test_osdict_types_ro(self): # 'types' should rarely be altered, this check will make # doubly sure that a new type isn't accidentally added approved_types = OSDB.list_types() for osobj in OSDB.list_os(): if osobj.get_typename() not in approved_types: raise AssertionError("OS entry '%s' has OS type '%s'.\n" "The type list should NOT be extended without a lot of " "thought, please make sure you know what you are doing." % (osobj.name, osobj.get_typename())) def test_recommended_resources(self): conn = utils.open_testdriver() guest = conn.caps.lookup_virtinst_guest() assert not OSDB.lookup_os("generic").get_recommended_resources(guest) res = OSDB.lookup_os("fedora21").get_recommended_resources(guest) assert res["n-cpus"] == 2 guest.type = "qemu" res = OSDB.lookup_os("fedora21").get_recommended_resources(guest) assert res["n-cpus"] == 1 def test_list_os(self): full_list = OSDB.list_os() pref_list = OSDB.list_os(typename="linux", sortpref=["fedora", "rhel"]) support_list = OSDB.list_os(only_supported=True) assert full_list[0] is not pref_list[0] assert len(full_list) > len(support_list) assert len(OSDB.list_os(typename="generic")) == 1 # Verify that sort order actually worked found_fedora = False found_rhel = False for idx, osobj in enumerate(pref_list[:]): if osobj.name.startswith("fedora"): found_fedora = True continue for osobj2 in pref_list[idx:]: if osobj2.name.startswith("rhel"): found_rhel = True continue break break assert found_fedora and found_rhel virt-manager-1.5.1/tests/uriparse.py0000664000175100017510000000516413240655316021155 0ustar crobinsocrobinso00000000000000# Copyright (C) 2015 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import unittest from virtinst import URI class TestURI(unittest.TestCase): """ Test virtinst URI module """ def _compare(self, uri, scheme='', transport='', port='', username='', path='', hostname='', query='', fragment='', is_ipv6=False, host_is_ipv4_string=False): uriinfo = URI(uri) self.assertEqual(scheme, uriinfo.scheme) self.assertEqual(transport, uriinfo.transport) self.assertEqual(port, uriinfo.port) self.assertEqual(username, uriinfo.username) self.assertEqual(path, uriinfo.path) self.assertEqual(hostname, uriinfo.hostname) self.assertEqual(query, uriinfo.query) self.assertEqual(fragment, uriinfo.fragment) self.assertEqual(is_ipv6, uriinfo.is_ipv6) self.assertEqual(host_is_ipv4_string, uriinfo.host_is_ipv4_string) def testURIs(self): self._compare("lxc://", scheme="lxc") self._compare("qemu:///session", scheme="qemu", path="/session") self._compare("http://foobar.com:5901/my/example.path#my-frag", scheme="http", hostname="foobar.com", port="5901", path='/my/example.path', fragment="my-frag") self._compare( "gluster+tcp://[1:2:3:4:5:6:7:8]:24007/testvol/dir/a.img", scheme="gluster", transport="tcp", hostname="1:2:3:4:5:6:7:8", port="24007", path="/testvol/dir/a.img", is_ipv6=True) self._compare( "qemu+ssh://root@192.168.2.3/system?no_verify=1", scheme="qemu", transport="ssh", username="root", hostname="192.168.2.3", path="/system", query="no_verify=1", host_is_ipv4_string=True) self._compare( "qemu+ssh://foo%5Cbar@hostname/system", scheme="qemu", path="/system", transport="ssh", hostname="hostname", username="foo\\bar") virt-manager-1.5.1/tests/utils.py0000664000175100017510000001404013245573052020455 0ustar crobinsocrobinso00000000000000# Copyright (C) 2013, 2014 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import difflib import os import virtinst import virtinst.cli import virtinst.uri # pylint: disable=protected-access # Access to protected member, needed to unittest stuff class _CLIState(object): """ Class containing any bits passed in from setup.py """ def __init__(self): self.regenerate_output = False self.use_coverage = False clistate = _CLIState() _capsprefix = ",caps=%s/tests/capabilities-xml/" % os.getcwd() _domcapsprefix = ",domcaps=%s/tests/capabilities-xml/" % os.getcwd() uri_test_default = "__virtinst_test__test:///default,predictable" uri_test = "__virtinst_test__test:///%s/tests/testdriver.xml,predictable" % os.getcwd() uri_test_remote = uri_test + ",remote" _uri_qemu = "%s,qemu" % uri_test _uri_kvm_domcaps = (_uri_qemu + _domcapsprefix + "kvm-x86_64-domcaps.xml") _uri_kvm_domcaps_q35 = (_uri_qemu + _domcapsprefix + "kvm-x86_64-domcaps-q35.xml") _uri_kvm_aarch64_domcaps = (_uri_qemu + _domcapsprefix + "kvm-aarch64-domcaps.xml") uri_kvm_nodomcaps = (_uri_qemu + _capsprefix + "kvm-x86_64.xml") uri_kvm_rhel = (_uri_kvm_domcaps + _capsprefix + "kvm-x86_64-rhel7.xml") uri_kvm = (_uri_kvm_domcaps + _capsprefix + "kvm-x86_64.xml") uri_kvm_q35 = (_uri_kvm_domcaps_q35 + _capsprefix + "kvm-x86_64.xml") uri_kvm_session = uri_kvm + ",session" uri_kvm_armv7l = (_uri_kvm_domcaps + _capsprefix + "kvm-armv7l.xml") uri_kvm_aarch64 = (_uri_kvm_aarch64_domcaps + _capsprefix + "kvm-aarch64.xml") uri_kvm_ppc64le = (_uri_kvm_domcaps + _capsprefix + "kvm-ppc64le.xml") uri_kvm_s390x = (_uri_kvm_domcaps + _capsprefix + "kvm-s390x.xml") uri_kvm_s390x_KVMIBM = (_uri_kvm_domcaps + _capsprefix + "kvm-s390x-KVMIBM.xml") uri_xen = uri_test + _capsprefix + "xen-rhel5.4.xml,xen" uri_lxc = uri_test + _capsprefix + "lxc.xml,lxc" uri_vz = uri_test + _capsprefix + "vz.xml,vz" def get_debug(): return ("DEBUG_TESTS" in os.environ and os.environ["DEBUG_TESTS"] == "1") def _make_uri(base, connver=None, libver=None): if connver: base += ",connver=%s" % connver if libver: base += ",libver=%s" % libver return base _conn_cache = {} def openconn(uri): """ Extra super caching to speed up the test suite. We basically cache the first guest/pool/vol poll attempt for each URI, and save it across multiple reopenings of that connection. We aren't caching libvirt objects, just parsed XML objects. This works fine since generally every test uses a fresh virConnect, or undoes the persistent changes it makes. """ virtinst.util.register_libvirt_error_handler() conn = virtinst.cli.getConnection(uri) # For the basic test:///default URI, skip this caching, so we have # an option to test the stock code if uri == uri_test_default: return conn if uri not in _conn_cache: conn.fetch_all_guests() conn.fetch_all_pools() conn.fetch_all_vols() conn.fetch_all_nodedevs() _conn_cache[uri] = {} for key, value in conn._fetch_cache.items(): _conn_cache[uri][key] = value[:] # Prime the internal connection cache for key, value in _conn_cache[uri].items(): conn._fetch_cache[key] = value[:] def cb_cache_new_pool(poolobj): # Used by clonetest.py nvram-newpool test if poolobj.name() == "nvram-newpool": from virtinst import StorageVolume vol = StorageVolume(conn) vol.pool = poolobj vol.name = "clone-orig-vars.fd" vol.capacity = 1024 * 1024 vol.install() conn._cache_new_pool_raw(poolobj) conn.cb_cache_new_pool = cb_cache_new_pool return conn def open_testdefault(): return openconn(uri_test_default) def open_testdriver(): return openconn(uri_test) def open_kvm(connver=None, libver=None): return openconn(_make_uri(uri_kvm, connver, libver)) def open_kvm_rhel(connver=None): return openconn(_make_uri(uri_kvm_rhel, connver)) def open_test_remote(): return openconn(uri_test_remote) def test_create(testconn, xml, define_func="defineXML"): xml = virtinst.uri.sanitize_xml_for_test_define(xml) try: func = getattr(testconn, define_func) obj = func(xml) except Exception as e: raise RuntimeError(str(e) + "\n" + xml) try: obj.create() obj.destroy() obj.undefine() except Exception: try: obj.destroy() except Exception: pass try: obj.undefine() except Exception: pass def read_file(filename): """Helper function to read a files contents and return them""" f = open(filename, "r") out = f.read() f.close() return out def diff_compare(actual_out, filename=None, expect_out=None): """Compare passed string output to contents of filename""" if not expect_out: if not os.path.exists(filename) or clistate.regenerate_output: open(filename, "w").write(actual_out) expect_out = read_file(filename) diff = "".join(difflib.unified_diff(expect_out.splitlines(1), actual_out.splitlines(1), fromfile=filename or '', tofile="Generated Output")) if diff: raise AssertionError("Conversion outputs did not match.\n%s" % diff) virt-manager-1.5.1/tests/magicuri0000775000175100017510000000521613245573052020476 0ustar crobinsocrobinso00000000000000#!/usr/bin/python import argparse import os import sys def parse_options(): hvs = ["qemu", "xen", "lxc", "test", "vz"] description = ("Generate a fake URI for use with virt-manager/virtinst " "that wraps a standard test:/// URI but pretends to be a different " "hypervisor. See virtinst/uri.py MagicURI for format details. " "Example: magicuri qemu --fake-remote") parser = argparse.ArgumentParser(description=description) parser.add_argument("hv", help="URI hypervisor to mock", choices=hvs) parser.add_argument("--capsfile", help="Path to file to use for capabilities XML") parser.add_argument("--domcapsfile", help="Path to file to use for domain capabilities XML") parser.add_argument("--driverxml", help="Path to driver xml (defaults to testdriver.xml)") parser.add_argument("--fake-remote", action="store_true", help="Fake a remote connection") options = parser.parse_args() testdir = os.path.dirname(__file__) capsdir = os.path.join(testdir, "capabilities-xml/") hv = options.hv capsfile = None domcapsfile = None if hv == "qemu": capsfile = capsdir + "kvm-x86_64.xml" domcapsfile = capsdir + "kvm-x86_64-domcaps.xml" elif hv == "xen": capsfile = capsdir + "xen-rhel5.4.xml" elif hv == "lxc": capsfile = capsdir + "lxc.xml" elif hv == "vz": capsfile = capsdir + "vz.xml" elif hv != "test": parser.print_help() sys.exit(1) if options.capsfile: capsfile = os.path.abspath(options.capsfile) if options.domcapsfile: domcapsfile = os.path.abspath(options.domcapsfile) driverxml = os.path.join(testdir, "testdriver.xml") if options.driverxml: driverxml = os.path.abspath(options.driverxml) return hv, capsfile, domcapsfile, options.fake_remote, driverxml def main(): hv, capsfile, domcapsfile, fake_remote, driverxml = parse_options() uri = "__virtinst_test__test://%s" % driverxml if hv != "test": uri += ",%s" % hv if capsfile: uri += ",caps=%s" % capsfile if domcapsfile: uri += ",domcaps=%s" % domcapsfile if fake_remote: uri += ",remote" if driverxml and not os.path.exists(driverxml): print("%s does not exist" % capsfile) return 1 if capsfile and not os.path.exists(capsfile): print("%s does not exist" % capsfile) return 1 if domcapsfile and not os.path.exists(domcapsfile): print("%s does not exist" % domcapsfile) return 1 print(uri) return 0 if __name__ == "__main__": sys.exit(main()) virt-manager-1.5.1/tests/nodedev-xml/0000775000175100017510000000000013245574323021170 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/tests/nodedev-xml/devxml/0000775000175100017510000000000013245574323022467 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/tests/nodedev-xml/devxml/usbdev1.xml0000664000175100017510000000021413243650062024550 0ustar crobinsocrobinso00000000000000 virt-manager-1.5.1/tests/nodedev-xml/devxml/usbdev2.xml0000664000175100017510000000025613243650062024557 0ustar crobinsocrobinso00000000000000
virt-manager-1.5.1/tests/nodedev-xml/devxml/pcidev.xml0000664000175100017510000000022013243650062024446 0ustar crobinsocrobinso00000000000000
virt-manager-1.5.1/tests/clone-xml/0000775000175100017510000000000013245574323020644 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/tests/clone-xml/noclone-storage-out.xml0000664000175100017510000000225713243650062025271 0ustar crobinsocrobinso00000000000000 clone-new 12345678-1234-1234-1234-123456789012 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/nvram-auto-out.xml0000664000175100017510000000116513243650061024257 0ustar crobinsocrobinso00000000000000 clone-new 12345678-1234-1234-1234-123456789012 262144 262144 1 hvm /usr/share/ovmf/ovmf-efi.fd /nvram/clone-new_VARS.fd destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/cross-pool-disks-out.xml0000664000175100017510000000065013243650061025377 0ustar crobinsocrobinso00000000000000 new1.img 1000000 50000 new2.img 1000000 50000 virt-manager-1.5.1/tests/clone-xml/nvram-newpool-in.xml0000664000175100017510000000117713245061760024600 0ustar crobinsocrobinso00000000000000 clone-orig aaa3ae22-fed2-bfbd-ac02-3bea3bcfad82 262144 262144 1 hvm /usr/share/ovmf/ovmf-efi.fd /nvram-newpool/clone-orig-vars.fd destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/managed-storage-in.xml0000664000175100017510000000222012574335131025020 0ustar crobinsocrobinso00000000000000 clone-orig aaa3ae22-fed2-bfbd-ac02-3bea3bcfad82 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/general-cfg-out.xml0000664000175100017510000000217213240655316024344 0ustar crobinsocrobinso00000000000000 clone-new 12345678-1234-1234-1234-123456789012 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/empty-disks-in.xml0000664000175100017510000000244312574335131024242 0ustar crobinsocrobinso00000000000000 clone-orig aaa3ae22-fed2-bfbd-ac02-3bea3bcfad82 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/managed-storage-out.xml0000664000175100017510000000221313243650061025217 0ustar crobinsocrobinso00000000000000 clone-new 12345678-1234-1234-1234-123456789012 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/nvram-auto-in.xml0000664000175100017510000000116713240655316024065 0ustar crobinsocrobinso00000000000000 clone-orig aaa3ae22-fed2-bfbd-ac02-3bea3bcfad82 262144 262144 1 hvm /usr/share/ovmf/ovmf-efi.fd /nvram/clone-orig_VARS.fd destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/general-cfg-in.xml0000664000175100017510000000226612574335131024146 0ustar crobinsocrobinso00000000000000 clone-orig aaa3ae22-fed2-bfbd-ac02-3bea3bcfad82 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/readonly-disks-in.xml0000664000175100017510000000301512574335131024715 0ustar crobinsocrobinso00000000000000 clone-orig aaa3ae22-fed2-bfbd-ac02-3bea3bcfad82 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/graphics-password-in.xml0000664000175100017510000000116413245061760025430 0ustar crobinsocrobinso00000000000000 clone-orig aaa3ae22-fed2-bfbd-ac02-3bea3bcfad82 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/nostorage-out.xml0000664000175100017510000000063413243650062024170 0ustar crobinsocrobinso00000000000000 clone-new 12345678-1234-1234-1234-123456789012 8388608 2097152 2 hvm destroy restart destroy virt-manager-1.5.1/tests/clone-xml/readonly-disks-out.xml0000664000175100017510000000300512574335131025115 0ustar crobinsocrobinso00000000000000 clone-new 12345678-1234-1234-1234-123456789012 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/skip-in.xml0000664000175100017510000000245113240655316022737 0ustar crobinsocrobinso00000000000000 clone-orig aaa3ae22-fed2-bfbd-ac02-3bea3bcfad82 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/nvram-newpool-out.xml0000664000175100017510000000117513245061760024777 0ustar crobinsocrobinso00000000000000 clone-new 12345678-1234-1234-1234-123456789012 262144 262144 1 hvm /usr/share/ovmf/ovmf-efi.fd /nvram-newpool/clone-new_VARS.fd destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/empty-disks-out.xml0000664000175100017510000000243312574335131024442 0ustar crobinsocrobinso00000000000000 clone-new 12345678-1234-1234-1234-123456789012 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/skip-out.xml0000664000175100017510000000244513243650061023136 0ustar crobinsocrobinso00000000000000 clone-new 12345678-1234-1234-1234-123456789012 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/cross-pool-in.xml0000664000175100017510000000215712574335131024073 0ustar crobinsocrobinso00000000000000 clone-orig aaa3ae22-fed2-bfbd-ac02-3bea3bcfad82 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/nostorage-in.xml0000664000175100017510000000063612574335131023774 0ustar crobinsocrobinso00000000000000 clone-orig 19618dc6-7895-956d-6056-8ebcd8061234 8388608 2097152 2 hvm destroy restart destroy virt-manager-1.5.1/tests/clone-xml/fullpool-in.xml0000664000175100017510000000141213240655316023621 0ustar crobinsocrobinso00000000000000 test-full-clone 204800 409600 abcd5678-aaaa-1234-1234-12345678FFFF hvm /usr/lib/xen/boot/hvmloader destroy restart destroy 5 /usr/lib/xen/bin/qemu-dm virt-manager-1.5.1/tests/clone-xml/force-out.xml0000664000175100017510000000243113243650061023261 0ustar crobinsocrobinso00000000000000 clone-new 12345678-1234-1234-1234-123456789012 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/graphics-password-out.xml0000664000175100017510000000116313245061760025630 0ustar crobinsocrobinso00000000000000 clone-new 12345678-1234-1234-1234-123456789012 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/cross-pool-out.xml0000664000175100017510000000214413243650061024264 0ustar crobinsocrobinso00000000000000 clone-new 12345678-1234-1234-1234-123456789012 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/force-in.xml0000664000175100017510000000245113240655316023067 0ustar crobinsocrobinso00000000000000 clone-orig aaa3ae22-fed2-bfbd-ac02-3bea3bcfad82 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/clone-xml/noclone-storage-in.xml0000664000175100017510000000226012574335131025065 0ustar crobinsocrobinso00000000000000 clone-orig aaa3ae22-fed2-bfbd-ac02-3bea3bcfad82 262144 262144 1 hvm destroy restart destroy /usr/bin/qemu-kvm virt-manager-1.5.1/tests/test_urls.py0000664000175100017510000002110613245573052021342 0ustar crobinsocrobinso00000000000000# Copyright (C) 2013 Red Hat, Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, # MA 02110-1301 USA. import logging import os import sys import time import traceback import unittest from tests import utils from virtinst import Guest from virtinst import urlfetcher from virtinst import util from virtinst.urlfetcher import ALTLinuxDistro from virtinst.urlfetcher import CentOSDistro from virtinst.urlfetcher import DebianDistro from virtinst.urlfetcher import FedoraDistro from virtinst.urlfetcher import GenericDistro from virtinst.urlfetcher import MandrivaDistro from virtinst.urlfetcher import RHELDistro from virtinst.urlfetcher import SLDistro from virtinst.urlfetcher import SuseDistro from virtinst.urlfetcher import UbuntuDistro class _DistroURL(object): def __init__(self, name, url, detectdistro, testxen, testbootiso, testshortcircuit): self.name = name self.url = url self.detectdistro = detectdistro self.arch = self._find_arch() self.distroclass = self._distroclass_for_name(self.name) self.testxen = testxen self.testbootiso = testbootiso # If True, pass in the expected distro value to getDistroStore # so it can short circuit the lookup checks. Speeds up the tests # and exercises the shortcircuit infrastructure self.testshortcircuit = testshortcircuit def _distroclass_for_name(self, name): # Map the test case name to the expected urlfetcher distro # class we should be detecting if "fedora" in name: return FedoraDistro if "centos" in name: return CentOSDistro if "rhel" in name: return RHELDistro if "suse" in name: return SuseDistro if "debian" in name: return DebianDistro if name.startswith("sl-"): return SLDistro if "ubuntu" in name: return UbuntuDistro if "mageia" in name: return MandrivaDistro if "altlinux" in name: return ALTLinuxDistro if "generic" in name: return GenericDistro raise RuntimeError("name=%s didn't map to any distro class. Extend " "_distroclass_for_name" % name) def _find_arch(self): if ("i686" in self.url or "i386" in self.url or "i586" in self.url): return "i686" if ("arm64" in self.url or "aarch64" in self.url): return "aarch64" if ("ppc64el" in self.url or "ppc64le" in self.url): return "ppc64le" if "s390" in self.url: return "s390x" if ("x86_64" in self.url or "amd64" in self.url): return "x86_64" return "x86_64" testconn = utils.open_testdefault() hvmguest = Guest(testconn) hvmguest.os.os_type = "hvm" xenguest = Guest(testconn) xenguest.os.os_type = "xen" meter = util.make_meter(quiet=not utils.get_debug()) def _storeForDistro(fetcher, guest): """ Helper to lookup the Distro store object, basically detecting the URL. Handle occasional proxy errors """ for ignore in range(0, 10): try: return urlfetcher.getDistroStore(guest, fetcher) except Exception as e: if str(e).count("502"): logging.debug("Caught proxy error: %s", str(e)) time.sleep(.5) continue raise raise # pylint: disable=misplaced-bare-raise def _testURL(fetcher, distroobj): """ Test that our URL detection logic works for grabbing kernel, xen kernel, and boot.iso """ distname = distroobj.name arch = distroobj.arch hvmguest.os.arch = arch xenguest.os.arch = arch if distroobj.testshortcircuit: hvmguest.os_variant = distroobj.detectdistro xenguest.os_variant = distroobj.detectdistro else: hvmguest.os_variant = None xenguest.os_variant = None try: hvmstore = _storeForDistro(fetcher, hvmguest) xenstore = None if distroobj.testxen: xenstore = _storeForDistro(fetcher, xenguest) except Exception: raise AssertionError("\nFailed to detect URLDistro class:\n" "name = %s\n" "url = %s\n\n%s" % (distname, fetcher.location, "".join(traceback.format_exc()))) for s in [hvmstore, xenstore]: if (s and distroobj.distroclass and not isinstance(s, distroobj.distroclass)): raise AssertionError("Unexpected URLDistro class:\n" "found = %s\n" "expect = %s\n" "name = %s\n" "url = %s" % (s.__class__, distroobj.distroclass, distname, fetcher.location)) # Make sure the stores are reporting correct distro name/variant if (s and distroobj.detectdistro and distroobj.detectdistro != s.get_osdict_info()): raise AssertionError( "Detected OS did not match expected values:\n" "found = %s\n" "expect = %s\n" "name = %s\n" "url = %s\n" "store = %s" % (s.os_variant, distroobj.detectdistro, distname, fetcher.location, distroobj.distroclass)) # Do this only after the distro detection, since we actually need # to fetch files for that part def fakeAcquireFile(filename): logging.debug("Fake acquiring %s", filename) return fetcher.hasFile(filename) fetcher.acquireFile = fakeAcquireFile # Fetch boot iso if distroobj.testbootiso: boot = hvmstore.acquireBootDisk(hvmguest) logging.debug("acquireBootDisk: %s", str(boot)) if boot is not True: raise AssertionError("%s-%s: bootiso fetching failed" % (distname, arch)) # Fetch regular kernel kern = hvmstore.acquireKernel(hvmguest) logging.debug("acquireKernel (hvm): %s", str(kern)) if kern[0] is not True or kern[1] is not True: AssertionError("%s-%s: hvm kernel fetching failed" % (distname, arch)) # Fetch xen kernel if xenstore: kern = xenstore.acquireKernel(xenguest) logging.debug("acquireKernel (xen): %s", str(kern)) if kern[0] is not True or kern[1] is not True: raise AssertionError("%s-%s: xen kernel fetching" % (distname, arch)) def _testURLWrapper(distroobj): os.environ.pop("VIRTINST_TEST_SUITE", None) logging.debug("Testing for media arch=%s distroclass=%s", distroobj.arch, distroobj.distroclass) sys.stdout.write("\nTesting %-25s " % distroobj.name) sys.stdout.flush() fetcher = urlfetcher.fetcherForURI(distroobj.url, "/tmp", meter) try: fetcher.prepareLocation() return _testURL(fetcher, distroobj) finally: fetcher.cleanupLocation() # Register tests to be picked up by unittest class URLTests(unittest.TestCase): pass def _make_tests(): import ConfigParser cfg = ConfigParser.ConfigParser() cfg.read("tests/test_urls.ini") manualpath = "tests/test_urls_manual.ini" cfg.read(manualpath) if not os.path.exists(manualpath): print("NOTE: Pass in manual data with %s" % manualpath) urls = {} for name in cfg.sections(): vals = dict(cfg.items(name)) d = _DistroURL(name, vals["url"], vals.get("distro", None), vals.get("testxen", "0") == "1", vals.get("testbootiso", "0") == "1", vals.get("testshortcircuit", "0") == "1") urls[d.name] = d keys = urls.keys() keys.sort() for key in keys: distroobj = urls[key] def _make_wrapper(d): return lambda _self: _testURLWrapper(d) setattr(URLTests, "testURL%s" % key.replace("-", "_"), _make_wrapper(distroobj)) _make_tests() virt-manager-1.5.1/tests/cli-test-xml/0000775000175100017510000000000013245574323021270 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/tests/cli-test-xml/fakefedoratree/0000775000175100017510000000000013245574323024237 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/tests/cli-test-xml/fakefedoratree/.treeinfo0000664000175100017510000000163512574335131026054 0ustar crobinsocrobinso00000000000000[general] family = Fedora timestamp = 1329856240.07 variant = Fedora version = 17 packagedir = arch = x86_64 [stage2] mainimage = LiveOS/squashfs.img [images-x86_64] kernel = images/pxeboot/vmlinuz initrd = images/pxeboot/initrd.img boot.iso = images/boot.iso [images-xen] kernel = images/pxeboot/vmlinuz initrd = images/pxeboot/initrd.img [checksums] images/boot.iso = sha256:a3c57709481b7bdc5fab8d5bd4a58aadbbf92df6cfe4bfafdebb280bf3de4a68 images/macboot.img = sha256:1022a1750882d731c27e096e5541a961290356d2faae8533757172454b59b64f images/efiboot.img = sha256:7a8214df0627ee0116eb32c8462a0a71bc2f31b1e4a7a6d1fea497eae330d66b images/pxeboot/initrd.img = sha256:dfb445af75d8a5e1f2ac1a021caf3854f96b6bbea249a3b37ea7929bdcad10a8 images/pxeboot/vmlinuz = sha256:dba59f0711ec8a2ef6b8981be15286ee2ea4d9b9e4d66eec0bb27b0518d463a5 repodata/repomd.xml = sha256:26f1267b3cce890db94129993e722f0fbe760361d0096b1399328ecd2c210d74 virt-manager-1.5.1/tests/cli-test-xml/fakefedoratree/images/0000775000175100017510000000000013245574323025504 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/tests/cli-test-xml/fakefedoratree/images/pxeboot/0000775000175100017510000000000013245574323027164 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/tests/cli-test-xml/fakefedoratree/images/pxeboot/initrd.img0000664000175100017510000000001312574335131031141 0ustar crobinsocrobinso00000000000000testinitrd virt-manager-1.5.1/tests/cli-test-xml/fakefedoratree/images/pxeboot/vmlinuz0000664000175100017510000000001412574335131030602 0ustar crobinsocrobinso00000000000000testvmlinuz virt-manager-1.5.1/tests/cli-test-xml/fakefedoratree/images/boot.iso0000664000175100017510000000001012574335131027146 0ustar crobinsocrobinso00000000000000testiso virt-manager-1.5.1/tests/cli-test-xml/fakefedoratree/images/xen/0000775000175100017510000000000013245574323026276 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/tests/cli-test-xml/fakefedoratree/images/xen/initrd.img0000664000175100017510000000001312574335131030253 0ustar crobinsocrobinso00000000000000testinitrd virt-manager-1.5.1/tests/cli-test-xml/fakefedoratree/images/xen/vmlinuz0000664000175100017510000000001412574335131027714 0ustar crobinsocrobinso00000000000000testvmlinuz virt-manager-1.5.1/tests/cli-test-xml/clone-disk.xml0000664000175100017510000000167712574335131024051 0ustar crobinsocrobinso00000000000000 origtest db69fa1f-eef0-e567-3c20-3ef16f10376b 8388608 2097152 2 hvm destroy restart destroy virt-manager-1.5.1/tests/cli-test-xml/compare/0000775000175100017510000000000013245574323022716 5ustar crobinsocrobinso00000000000000virt-manager-1.5.1/tests/cli-test-xml/compare/virt-install-qemu-32-on-64.xml0000664000175100017510000000256713243650076030130 0ustar crobinsocrobinso00000000000000 foobar 00000000-1111-2222-3333-444444444444 65536 65536 1 hvm /usr/bin/qemu-kvm /dev/urandom virt-manager-1.5.1/tests/cli-test-xml/compare/virt-xml-edit-pos-num.xml0000664000175100017510000000050613243650115027532 0ustar crobinsocrobinso00000000000000 - + Domain 'test-for-virtxml' defined successfully. Changes will take effect after the next domain shutdown.virt-manager-1.5.1/tests/cli-test-xml/compare/virt-install-aarch64-kvm-gic.xml0000664000175100017510000000245513243650100030641 0ustar crobinsocrobinso00000000000000 foobar 00000000-1111-2222-3333-444444444444 65536 65536 1 hvm /usr/share/AAVMF/AAVMF_CODE.fd /usr/bin/qemu-system-aarch64
/dev/urandom virt-manager-1.5.1/tests/cli-test-xml/compare/virt-xml-edit-clear-disk.xml0000664000175100017510000000076713243650116030164 0ustar crobinsocrobinso00000000000000 /usr/lib/xen/bin/qemu-dm - - + - -
Domain 'test-for-virtxml' defined successfully. Changes will take effect after the next domain shutdown.virt-manager-1.5.1/tests/cli-test-xml/compare/virt-xml-edit-neg-num.xml0000664000175100017510000000060413243650115027501 0ustar crobinsocrobinso00000000000000 Domain 'test-for-virtxml' defined successfully. Changes will take effect after the next domain shutdown.virt-manager-1.5.1/tests/cli-test-xml/compare/virt-xml-edit-simple-disk-remove-path.xml0000664000175100017510000000057313243650113032604 0ustar crobinsocrobinso00000000000000 /usr/lib/xen/bin/qemu-dm -
Domain 'test-for-virtxml' defined successfully. Changes will take effect after the next domain shutdown.virt-manager-1.5.1/tests/cli-test-xml/compare/virt-install-arm-virt-f20.xml0000664000175100017510000000224113243650077030212 0ustar crobinsocrobinso00000000000000 foobar 00000000-1111-2222-3333-444444444444 65536 65536 1 hvm /f19-arm.kernel /f19-arm.initrd console=ttyAMA0,1234 rw root=/dev/vda3 /usr/bin/qemu-system-arm /dev/urandom virt-manager-1.5.1/tests/cli-test-xml/compare/virt-install-quiet-url.xml0000664000175100017510000000000013243650076030001 0ustar crobinsocrobinso00000000000000virt-manager-1.5.1/tests/cli-test-xml/compare/virt-xml-edit-select-network-mac.xml0000664000175100017510000000057213243650116031644 0ustar crobinsocrobinso00000000000000