From: Marcin Krol Date: Thu, 12 Jun 2014 12:08:53 +0000 (+0000) Subject: - numerous upstream fixes from project git, see X-Git-Tag: auto/ti/virt-manager-1.0.1-2~1 X-Git-Url: http://git.pld-linux.org/gitweb.cgi?a=commitdiff_plain;h=6288b4e1a47f1bb44dbcf330f8401dbfe2e0b02f;p=packages%2Fvirt-manager.git - numerous upstream fixes from project git, see https://git.fedorahosted.org/cgit/virt-manager.git/log/ for details --- diff --git a/virt-manager-git.patch b/virt-manager-git.patch new file mode 100644 index 0000000..8f015e1 --- /dev/null +++ b/virt-manager-git.patch @@ -0,0 +1,8683 @@ +diff -urN virt-manager-1.0.1/data/virt-manager.appdata.xml virt-manager/data/virt-manager.appdata.xml +--- virt-manager-1.0.1/data/virt-manager.appdata.xml 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/data/virt-manager.appdata.xml 2014-06-12 11:22:20.805891891 +0000 +@@ -2,7 +2,8 @@ + + + virt-manager.desktop +- CC0 ++ CC0-1.0 ++ GPL-2.0+ + Virtual Machine Manager + Graphically manage KVM, Xen, or LXC via libvirt + +diff -urN virt-manager-1.0.1/man/virt-install.pod virt-manager/man/virt-install.pod +--- virt-manager-1.0.1/man/virt-install.pod 2014-03-22 16:27:02.000000000 +0000 ++++ virt-manager/man/virt-install.pod 2014-06-12 11:22:20.806891891 +0000 +@@ -123,6 +123,18 @@ + + Use --metadata=? to see a list of all available sub options. Complete details at L + ++=item --events OPT=VAL,[...] ++ ++Specify events values for the guest. Possible options include on_poweroff, on_reboot, and on_crash. ++ ++Use --events=? to see a list of all available sub options. Complete details at L ++ ++=item --resource OPT=VAL,[...] ++ ++Specify resource partitioning for the guest. ++ ++Use --resource=? to see a list of all available sub options. Complete details at L ++ + =item --vcpus=VCPUS[,maxvcpus=MAX][,sockets=#][,cores=#][,threads=#][,cpuset=CPUSET] + + Number of virtual cpus to configure for the guest. If 'maxvcpus' is specified, +@@ -264,7 +276,7 @@ + + =item --pm=PMOPTS + +-Configure guest power management features. Example suboptions include suspend_to_ram=on|off and suspend_to_disk=on|off ++Configure guest power management features. Example suboptions include suspend_to_mem=on|off and suspend_to_disk=on|off + + Use --pm=? to see a list of all available sub options. Complete details at L + +@@ -278,7 +290,7 @@ + + =item --cdrom=CDROM + +-File or device use as a virtual CD-ROM device for fully virtualized guests. ++File or device used as a virtual CD-ROM device for fully virtualized guests. + It can be path to an ISO image, or to a CDROM device. It can also be a URL + from which to fetch/access a minimal boot ISO image. The URLs take the same + format as described for the C<--location> argument. If a cdrom has been +@@ -399,11 +411,8 @@ + the install media (currently only supported for URL installs). Autodetection + can be disabled with the special value 'none'. + +-If the special value 'list' is passed, virt-install will print the full +-list of variant values and exit. The printed format is not a stable +-interface, DO NOT PARSE IT. +- +-Use '--os-variant list' to see the full OS list ++Use the command "osinfo-query os" to get the list of the accepted OS ++variants. + + =item --boot=BOOTOPTS + +@@ -527,7 +536,7 @@ + + =item B + +-Disk device type. Value can be 'cdrom', 'disk', or 'floppy'. Default is ++Disk device type. Value can be 'cdrom', 'disk', 'lun' or 'floppy'. Default is + 'disk'. If a 'cdrom' is specified, and no install method is chosen, the + cdrom is used as the install media. + +@@ -576,6 +585,13 @@ + 'writethrough' provides read caching. 'writeback' provides + read and write caching. + ++=item B ++ ++Whether discard (also known as "trim" or "unmap") requests are ignored ++or passed to the filesystem. The value can be either "unmap" (allow ++the discard request to be passed) or "ignore" (ignore the discard ++request). Since 1.0.6 (QEMU and KVM only) ++ + =item B + + Disk image format. For file volumes, this can be 'raw', 'qcow2', 'vmdk', etc. See format types in L for possible values. This is often mapped to the B value as well. +diff -urN virt-manager-1.0.1/man/virt-manager.pod virt-manager/man/virt-manager.pod +--- virt-manager-1.0.1/man/virt-manager.pod 2014-03-22 16:27:02.000000000 +0000 ++++ virt-manager/man/virt-manager.pod 2014-06-12 11:22:20.806891891 +0000 +@@ -93,7 +93,7 @@ + + =head1 BUGS + +-Please see L ++Please see L + + =head1 COPYRIGHT + +diff -urN virt-manager-1.0.1/setup.py virt-manager/setup.py +--- virt-manager-1.0.1/setup.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/setup.py 2014-06-12 11:22:20.912891892 +0000 +@@ -1,8 +1,6 @@ + #!/usr/bin/env python2 + # Copyright (C) 2013, 2014 Red Hat, Inc. + +-# pylint: disable=W0201 +-# Attribute defined outside __init__: custom commands require breaking this + + import datetime + import glob +@@ -22,6 +20,8 @@ + from virtcli import cliconfig + + ++# pylint: disable=attribute-defined-outside-init ++ + def _generate_potfiles_in(): + def find(dirname, ext): + ret = [] +@@ -324,6 +324,8 @@ + "Hide config bits that are not considered stable (default=no)"), + ("default-graphics=", None, + "Default graphics type (spice or vnc) (default=spice)"), ++ ("with-bhyve=", None, ++ "whether enable Bhyve connection support (default=no)"), + + ] + description = "Configure the build, similar to ./configure" +@@ -341,6 +343,7 @@ + self.preferred_distros = None + self.stable_defaults = None + self.default_graphics = None ++ self.with_bhyve = None + + + def run(self): +@@ -364,6 +367,8 @@ + self.stable_defaults) + if self.default_graphics is not None: + template += "default_graphics = %s\n" % self.default_graphics ++ if self.with_bhyve is not None: ++ template += "with_bhyve = %s\n" % self.with_bhyve + + file(cliconfig.cfgpath, "w").write(template) + print "Generated %s" % cliconfig.cfgpath +diff -urN virt-manager-1.0.1/tests/capabilities.py virt-manager/tests/capabilities.py +--- virt-manager-1.0.1/tests/capabilities.py 2014-03-22 16:26:50.000000000 +0000 ++++ virt-manager/tests/capabilities.py 2014-06-12 11:22:20.913891892 +0000 +@@ -20,6 +20,7 @@ + + from tests import utils + from virtinst import CapabilitiesParser as capabilities ++from virtinst.capabilities import _CPUMapFileValues + + + def build_host_feature_dict(feature_list): +@@ -221,6 +222,7 @@ + test_utils(new_caps_no_kvm, False, True, False, False, False) + + def testCPUMap(self): ++ _CPUMapFileValues.update_cpu_filename("tests/capabilities-xml/cpu_map.xml") + caps = self._buildCaps("libvirt-0.7.6-qemu-caps.xml") + cpu_64 = caps.get_cpu_values(None, "x86_64") + cpu_32 = caps.get_cpu_values(None, "i486") +diff -urN virt-manager-1.0.1/tests/clitest.py virt-manager/tests/clitest.py +--- virt-manager-1.0.1/tests/clitest.py 2014-03-22 16:26:50.000000000 +0000 ++++ virt-manager/tests/clitest.py 2014-06-12 11:22:21.018891898 +0000 +@@ -123,12 +123,10 @@ + } + + +- + ###################### + # Test class helpers # + ###################### + +- + class Command(object): + """ + Instance of a single cli command to test +@@ -378,7 +376,7 @@ + self.categories = {} + self.cmds = [] + +- def _default_args(self, cli, iscompare): ++ def _default_args(self, cli, iscompare, auto_printarg): + args = "" + if not iscompare: + args = "--debug" +@@ -392,7 +390,7 @@ + if "--ram " not in cli: + args += " --ram 64" + +- if iscompare: ++ if iscompare and auto_printarg: + if self.appname == "virt-install": + if (not cli.count("--print-xml") and + not cli.count("--print-step") and +@@ -418,11 +416,13 @@ + return obj + + def _add(self, catname, testargs, valid, compfile, +- skip_check=None, compare_check=None, input_file=None): ++ skip_check=None, compare_check=None, input_file=None, ++ auto_printarg=True): + + category = self.categories[catname] + args = category.default_args + " " + testargs +- args = self._default_args(args, bool(compfile)) + " " + args ++ args = (self._default_args(args, bool(compfile), auto_printarg) + ++ " " + args) + cmdstr = "./%s %s" % (self.appname, args) + + cmd = Command(cmdstr) +@@ -472,6 +472,7 @@ + c.add_valid("--memtune hard_limit=10,soft_limit=20,swap_hard_limit=30,min_guarantee=40") # --memtune + c.add_valid("--memorybacking hugepages=yes,nosharepages=yes,locked=yes") # --memorybacking nosharepages,locked + c.add_valid("--idmap uid_start=0,uid_target=1000,uid_count=10,gid_start=0,gid_target=1000,gid_count=10") # --idmap ++c.add_valid("--resource partition=/virtualmachines/production") # --resource + c.add_compare("--connect %(DEFAULTURI)s --cpuset auto --vcpus 2", "cpuset-auto") # --cpuset=auto actually works + c.add_invalid("--vcpus 32 --cpuset=969-1000") # Bogus cpuset + c.add_invalid("--vcpus 32 --cpuset=autofoo") # Bogus cpuset +@@ -545,7 +546,7 @@ + + c = vinst.add_category("misc", "--nographics --noautoconsole") + c.add_valid("--panic help --disk=?") # Make sure introspection doesn't blow up +-c.add_compare("", "noargs-fail") # No arguments ++c.add_compare("", "noargs-fail", auto_printarg=False) # No arguments + c.add_compare("--hvm --nodisks --pxe --print-step all", "simple-pxe") # Diskless PXE install + c.add_compare("--hvm --cdrom %(EXISTIMG2)s --file %(EXISTIMG1)s --os-variant win2k3 --wait 0 --vcpus cores=4 --controller usb,model=none", "w2k3-cdrom") # HVM windows install with disk + c.add_compare("""--hvm --pxe \ +@@ -554,12 +555,12 @@ + --controller usb,model=ich9-uhci2,address=0:0:4.1,index=0,master=2 \ + --controller usb,model=ich9-uhci3,address=0:0:4.2,index=0,master=4 \ + --disk %(EXISTUPPER)s,cache=writeback,io=threads,perms=sh,serial=WD-WMAP9A966149,boot_order=2 \ +---disk %(NEWIMG1)s,sparse=false,size=.001,perms=ro,error_policy=enospace \ ++--disk %(NEWIMG1)s,sparse=false,size=.001,perms=ro,error_policy=enospace,discard=unmap \ + --disk device=cdrom,bus=sata,read_bytes_sec=1,read_iops_sec=2,total_bytes_sec=10,total_iops_sec=20,write_bytes_sec=5,write_iops_sec=6 \ + --disk size=1 \ + --serial tcp,host=:2222,mode=bind,protocol=telnet \ + --filesystem /source,/target,mode=squash \ +---network user,mac=12:34:56:78:11:22 \ ++--network user,mac=12:34:56:78:11:22,portgroup=foo \ + --network bridge=foobar,model=virtio,driver_name=qemu,driver_queues=3 \ + --network type=direct,source=eth5,source_mode=vepa,target=mytap12,virtualport_type=802.1Qbg,virtualport_managerid=12,virtualport_typeid=1193046,virtualport_typeidversion=1,virtualport_instanceid=09b11c53-8b5c-4eeb-8f00-d84eaa0aaa3b,boot_order=1 \ + --channel spicevmc \ +@@ -581,7 +582,7 @@ + c.add_valid("--hvm --import --disk path=%(EXISTIMG1)s") # FV Import install + c.add_valid("--hvm --import --disk path=%(EXISTIMG1)s --prompt --force") # Working scenario w/ prompt shouldn't ask anything + c.add_valid("--paravirt --import --disk path=%(EXISTIMG1)s") # PV Import install +-c.add_valid("--paravirt --import --disk path=%(EXISTIMG1)s --print-xml") # PV Import install, print single XML ++c.add_valid("--paravirt --disk path=%(EXISTIMG1)s --print-xml") # print single XML, implied import install + c.add_valid("--hvm --import --disk path=%(EXISTIMG1)s,device=floppy") # Import a floppy disk + c.add_valid("--hvm --nodisks --pxe --autostart") # --autostart flag + c.add_valid("--hvm --nodisks --pxe --description \"foobar & baz\"") # --description +@@ -805,6 +806,7 @@ + c.add_compare("""--metadata name=foo-my-new-name,uuid=12345678-12F4-1234-1234-123456789AFA,description="hey this is my + new + very,very=new desc\\\'",title="This is my,funky=new title" """, "edit-simple-metadata") ++c.add_compare("--events on_poweroff=destroy,on_reboot=restart,on_crash=preserve", "edit-simple-events") + c.add_compare("--memory 500,maxmemory=1000,hugepages=off", "edit-simple-memory") + c.add_compare("--vcpus 10,maxvcpus=20,cores=5,sockets=4,threads=1", "edit-simple-vcpus") + c.add_compare("--cpu model=pentium2,+x2apic,forbid=pbe", "edit-simple-cpu") +@@ -923,8 +925,8 @@ + + + c = vclon.add_category("misc", "") +-c.add_compare("--connect %(KVMURI)s -o test-for-clone --auto-clone --clone-running", "clone-auto1") +-c.add_compare("-o test-clone-simple --name newvm --auto-clone --clone-running", "clone-auto2") ++c.add_compare("--connect %(KVMURI)s -o test-for-clone --auto-clone --clone-running", "clone-auto1", compare_check=support.SUPPORT_CONN_BARE_BACKINGSTORE) ++c.add_compare("-o test-clone-simple --name newvm --auto-clone --clone-running", "clone-auto2", compare_check=support.SUPPORT_CONN_BARE_BACKINGSTORE) + c.add_valid("-o test --auto-clone") # Auto flag, no storage + c.add_valid("--original-xml %(CLONE_DISK_XML)s --auto-clone") # Auto flag w/ storage, + c.add_valid("--original-xml %(CLONE_STORAGE_XML)s --auto-clone") # Auto flag w/ managed storage, +diff -urN virt-manager-1.0.1/tests/cli-test-xml/compare/virt-clone-clone-auto1.xml virt-manager/tests/cli-test-xml/compare/virt-clone-clone-auto1.xml +--- virt-manager-1.0.1/tests/cli-test-xml/compare/virt-clone-clone-auto1.xml 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/tests/cli-test-xml/compare/virt-clone-clone-auto1.xml 2014-06-12 11:22:20.914891892 +0000 +@@ -22,16 +22,19 @@ + + + ++ + +
+ + + ++ + + +
+ + ++ + + +
+@@ -39,6 +42,7 @@ + + + ++ + + + +@@ -46,11 +50,13 @@ + + + ++ + +
+ + + ++ + +
+ +diff -urN virt-manager-1.0.1/tests/cli-test-xml/compare/virt-clone-clone-auto2.xml virt-manager/tests/cli-test-xml/compare/virt-clone-clone-auto2.xml +--- virt-manager-1.0.1/tests/cli-test-xml/compare/virt-clone-clone-auto2.xml 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/tests/cli-test-xml/compare/virt-clone-clone-auto2.xml 2014-06-12 11:22:20.914891892 +0000 +@@ -22,6 +22,7 @@ + + + ++ + +
+ +diff -urN virt-manager-1.0.1/tests/cli-test-xml/compare/virt-convert-ovf-compare.xml virt-manager/tests/cli-test-xml/compare/virt-convert-ovf-compare.xml +--- virt-manager-1.0.1/tests/cli-test-xml/compare/virt-convert-ovf-compare.xml 2014-02-18 22:43:49.000000000 +0000 ++++ virt-manager/tests/cli-test-xml/compare/virt-convert-ovf-compare.xml 2014-06-12 11:22:20.914891892 +0000 +@@ -1,5 +1,3 @@ +-Copying test.ovf-disk1.vmdk to /tmp/test.ovf-disk1 +-Copying testfile to /tmp/testfile + + test.ovf + 00000000-1111-2222-3333-444444444444 +diff -urN virt-manager-1.0.1/tests/cli-test-xml/compare/virt-convert-vmx-compare.xml virt-manager/tests/cli-test-xml/compare/virt-convert-vmx-compare.xml +--- virt-manager-1.0.1/tests/cli-test-xml/compare/virt-convert-vmx-compare.xml 2014-02-18 22:43:49.000000000 +0000 ++++ virt-manager/tests/cli-test-xml/compare/virt-convert-vmx-compare.xml 2014-06-12 11:22:20.914891892 +0000 +@@ -1,4 +1,3 @@ +-Running /usr/bin/qemu-img convert -O qcow2 fedora.vmdk /var/lib/libvirt/images/fedora.qcow2 + + fedora + 00000000-1111-2222-3333-444444444444 +diff -urN virt-manager-1.0.1/tests/cli-test-xml/compare/virt-install-many-devices.xml virt-manager/tests/cli-test-xml/compare/virt-install-many-devices.xml +--- virt-manager-1.0.1/tests/cli-test-xml/compare/virt-install-many-devices.xml 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/tests/cli-test-xml/compare/virt-install-many-devices.xml 2014-06-12 11:22:20.914891892 +0000 +@@ -3,10 +3,6 @@ + 00000000-1111-2222-3333-444444444444 + 65536 + 65536 +- 1 +- +- +- + + 200 + +@@ -14,6 +10,10 @@ + 300 + + ++ 1 ++ ++ ++ + + hvm + /foo/bar +@@ -52,7 +52,7 @@ + + + +- ++ + + + +@@ -93,6 +93,7 @@ + + + ++ + + + +@@ -147,10 +148,6 @@ + 00000000-1111-2222-3333-444444444444 + 65536 + 65536 +- 1 +- +- +- + + 200 + +@@ -158,6 +155,10 @@ + 300 + + ++ 1 ++ ++ ++ + + hvm + /foo/bar +@@ -196,7 +197,7 @@ + + + +- ++ + + + +@@ -237,6 +238,7 @@ + + + ++ + + + +diff -urN virt-manager-1.0.1/tests/cli-test-xml/compare/virt-xml-edit-clear-disk.xml virt-manager/tests/cli-test-xml/compare/virt-xml-edit-clear-disk.xml +--- virt-manager-1.0.1/tests/cli-test-xml/compare/virt-xml-edit-clear-disk.xml 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/tests/cli-test-xml/compare/virt-xml-edit-clear-disk.xml 2014-06-12 11:22:20.916891892 +0000 +@@ -4,10 +4,10 @@ + - + - + + +-+ + + - + -
+++ + + + +diff -urN virt-manager-1.0.1/tests/cli-test-xml/compare/virt-xml-edit-simple-events.xml virt-manager/tests/cli-test-xml/compare/virt-xml-edit-simple-events.xml +--- virt-manager-1.0.1/tests/cli-test-xml/compare/virt-xml-edit-simple-events.xml 1970-01-01 00:00:00.000000000 +0000 ++++ virt-manager/tests/cli-test-xml/compare/virt-xml-edit-simple-events.xml 2014-06-12 11:22:20.916891892 +0000 +@@ -0,0 +1,11 @@ ++ ++ destroy ++ restart ++- restart +++ preserve ++ ++ ++ ++ ++Domain 'test-many-devices' defined successfully. ++Changes will take effect after the next domain shutdown. +\ No newline at end of file +diff -urN virt-manager-1.0.1/tests/image.py virt-manager/tests/image.py +--- virt-manager-1.0.1/tests/image.py 2014-03-22 16:26:50.000000000 +0000 ++++ virt-manager/tests/image.py 2014-06-12 11:22:21.065891894 +0000 +@@ -25,7 +25,7 @@ + qemuuri = "__virtinst_test__test:///default,caps=%s/tests/capabilities-xml/capabilities-kvm.xml,qemu,predictable" % os.getcwd() + + +-# pylint: disable=W0212 ++# pylint: disable=protected-access + # Access to protected member, needed to unittest stuff + + class TestImageParser(unittest.TestCase): +diff -urN virt-manager-1.0.1/tests/__init__.py virt-manager/tests/__init__.py +--- virt-manager-1.0.1/tests/__init__.py 2014-03-22 16:26:50.000000000 +0000 ++++ virt-manager/tests/__init__.py 2014-06-12 11:22:20.912891892 +0000 +@@ -33,7 +33,7 @@ + + from tests import utils + +-# pylint: disable=W0212 ++# pylint: disable=protected-access + # Access to protected member, needed to unittest stuff + + # Force certain helpers to return consistent values +diff -urN virt-manager-1.0.1/tests/misc.py virt-manager/tests/misc.py +--- virt-manager-1.0.1/tests/misc.py 2014-03-22 16:26:50.000000000 +0000 ++++ virt-manager/tests/misc.py 2014-06-12 11:22:21.088891894 +0000 +@@ -22,8 +22,7 @@ + import sys + import unittest + +-_badmodules = ["gi.repository.Gtk", "gi.repository.GObject", +- "gi.repository.Gdk", "gi.repository.GLib"] ++_badmodules = ["gi.repository.Gtk", "gi.repository.Gdk"] + + + def _restore_modules(fn): +diff -urN virt-manager-1.0.1/tests/pep8.cfg virt-manager/tests/pep8.cfg +--- virt-manager-1.0.1/tests/pep8.cfg 2014-01-18 20:55:50.000000000 +0000 ++++ virt-manager/tests/pep8.cfg 2014-06-12 11:22:21.115891895 +0000 +@@ -2,7 +2,7 @@ + + format = pylint + +-# E12*: # Continuation line indents ++# E1* : # Continuation line indents + # E203: # Space before : in dictionary defs + # E221: # Multiple spaces before operator + # (warngs about column aligning assigments) +@@ -11,4 +11,4 @@ + # E303: # Too many blank lines + # E501: # Line too long + +-ignore=E121,E122,E123,E124,E125,E126,E127,E128,E203,E221,E241,E301,E303,E501 ++ignore=E121,E122,E123,E124,E125,E126,E127,E128,E129,E131,E203,E221,E241,E301,E303,E501 +diff -urN virt-manager-1.0.1/tests/pylint.cfg virt-manager/tests/pylint.cfg +--- virt-manager-1.0.1/tests/pylint.cfg 2014-03-22 15:53:22.000000000 +0000 ++++ virt-manager/tests/pylint.cfg 2014-06-12 11:22:21.115891895 +0000 +@@ -34,29 +34,7 @@ + # multiple time (only on the command line, not in the configuration file where + # it should appear only once). + +-# Design: Things like 'too many arguments' +-# C0103: Name doesn't match some style regex +-# C0111: No docstring +-# C0301: Line too long +-# C0302: Too many lines in module +-# C0325: Superfluous parens +-# C0326: Bad whitespace +-# I0011: Warn about locally disabled pylint msgs +-# R0201: Method could be a function +-# +-# W0108: Lambda may not be necessary +-# W0142: Used * or ** magic* +-# W0603: Using the global statement +-# W0702: No exception type specified for 'catch' +-# W0703: Catch 'Exception' +-# W1401: Anomalous backslash in string +-# +-# May be useful to enable someday +-# Similarities: Code duplication +-# W1001: Use of 'property' on old style class, +-# pylint can't detect our Gtk subclasses are new style +-# W0511: FIXME and XXX: messages +-disable=Design,Similarities,C0103,C0111,C0301,C0302,C0325,C0326,I0011,R0201,W0108,W0142,W0603,W0702,W0703,W1401,W1001,W0511 ++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 + + + [REPORTS] +diff -urN virt-manager-1.0.1/tests/storage.py virt-manager/tests/storage.py +--- virt-manager-1.0.1/tests/storage.py 2014-03-22 16:26:50.000000000 +0000 ++++ virt-manager/tests/storage.py 2014-06-12 11:22:21.116891895 +0000 +@@ -23,7 +23,7 @@ + + from tests import utils + +-# pylint: disable=W0212 ++# pylint: disable=protected-access + # Access to protected member, needed to unittest stuff + + basepath = os.path.join(os.getcwd(), "tests", "storage-xml") +@@ -188,10 +188,10 @@ + + # Test creating with many devices + # XXX: Need to wire this up +- #createPool(self.conn, +- # StoragePool.TYPE_LOGICAL, "pool-logical-manydev", +- # source_path=["/tmp/path1", "/tmp/path2", "/tmp/path3"], +- # target_path=None) ++ # createPool(self.conn, ++ # StoragePool.TYPE_LOGICAL, "pool-logical-manydev", ++ # source_path=["/tmp/path1", "/tmp/path2", "/tmp/path3"], ++ # target_path=None) + + def testDiskPool(self): + poolobj = createPool(self.conn, +diff -urN virt-manager-1.0.1/tests/testdriver.xml virt-manager/tests/testdriver.xml +--- virt-manager-1.0.1/tests/testdriver.xml 2014-03-06 17:34:47.000000000 +0000 ++++ virt-manager/tests/testdriver.xml 2014-06-12 11:22:21.117891895 +0000 +@@ -1115,10 +1115,28 @@ + + + +- plainbridge ++ plainbridge-portgroups + b1b9d7c6-f620-048f-71ee-ca3ba1ac3e98 + + ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +diff -urN virt-manager-1.0.1/tests/test_urls.py virt-manager/tests/test_urls.py +--- virt-manager-1.0.1/tests/test_urls.py 2014-03-22 16:26:50.000000000 +0000 ++++ virt-manager/tests/test_urls.py 2014-06-12 11:22:21.117891895 +0000 +@@ -37,7 +37,7 @@ + from virtinst.urlfetcher import MandrivaDistro + + +-# pylint: disable=W0212 ++# pylint: disable=protected-access + # Access to protected member, needed to unittest stuff + + OLD_FEDORA_URL = "https://archives.fedoraproject.org/pub/archive/fedora/linux/releases/%s/Fedora/%s/os/" +diff -urN virt-manager-1.0.1/tests/utils.py virt-manager/tests/utils.py +--- virt-manager-1.0.1/tests/utils.py 2014-03-22 16:26:50.000000000 +0000 ++++ virt-manager/tests/utils.py 2014-06-12 11:22:21.117891895 +0000 +@@ -31,7 +31,7 @@ + # DON'T EDIT THIS. Use 'setup.py test --regenerate-output' + REGENERATE_OUTPUT = False + +-# pylint: disable=W0212 ++# pylint: disable=protected-access + # Access to protected member, needed to unittest stuff + + _capsprefix = ",caps=%s/tests/capabilities-xml/" % os.getcwd() +diff -urN virt-manager-1.0.1/tests/xmlconfig.py virt-manager/tests/xmlconfig.py +--- virt-manager-1.0.1/tests/xmlconfig.py 2014-03-22 16:26:50.000000000 +0000 ++++ virt-manager/tests/xmlconfig.py 2014-06-12 11:22:21.121891895 +0000 +@@ -34,7 +34,7 @@ + + from tests import utils + +-# pylint: disable=W0212 ++# pylint: disable=protected-access + # Access to protected member, needed to unittest stuff + + _testconn = utils.open_testdriver() +@@ -870,7 +870,7 @@ + g.add_device(redir1) + g.add_device(redir2) + +- #Panic Notifier device ++ # Panic Notifier device + pdev = VirtualPanicDevice(g.conn) + g.add_device(pdev) + +diff -urN virt-manager-1.0.1/tests/xmlparse.py virt-manager/tests/xmlparse.py +--- virt-manager-1.0.1/tests/xmlparse.py 2014-03-22 16:26:50.000000000 +0000 ++++ virt-manager/tests/xmlparse.py 2014-06-12 11:22:21.124891895 +0000 +@@ -90,7 +90,7 @@ + return guest, outfile + + def test000ClearProps(self): +- # pylint: disable=W0212 ++ # pylint: disable=protected-access + # Access to protected member, needed to unittest stuff + virtinst.xmlbuilder._seenprops = [] + +@@ -155,6 +155,10 @@ + check("initrd", None) + check("kernel_args", None) + ++ guest.os.set_initargs_string("foo 'bar baz' frib") ++ self.assertEqual([i.val for i in guest.os.initargs], ++ ["foo", "bar baz", "frib"]) ++ + check = self._make_checker(guest.features) + check("acpi", True, False) + check("apic", True, True) +@@ -209,6 +213,9 @@ + check("gid_target", None, 1000) + check("gid_count", None, 10) + ++ check = self._make_checker(guest.resource) ++ check("partition", None, "/virtualmachines/production") ++ + check = self._make_checker(guest.get_devices("memballoon")[0]) + check("model", "virtio", "none") + +@@ -331,6 +338,7 @@ + check("driver_cache", None, "writeback") + check("driver_io", None, "threads") + check("driver_io", "threads", "native") ++ check("driver_discard", None, "unmap") + check("iotune_ris", 1, 0) + check("iotune_rbs", 2, 0) + check("iotune_wis", 3, 0) +@@ -361,6 +369,7 @@ + console2 = guest.get_devices("console")[1] + channel1 = guest.get_devices("channel")[0] + channel2 = guest.get_devices("channel")[1] ++ channel3 = guest.get_devices("channel")[2] + + check = self._make_checker(serial1) + check("type", "null", "udp") +@@ -408,6 +417,12 @@ + check("target_address", "1.2.3.4", "5.6.7.8") + check("target_port", 4567, 1199) + ++ check = self._make_checker(channel3) ++ check("type", "spiceport") ++ check("source_channel", "org.spice-space.webdav.0", "test.1") ++ check("target_type", "virtio") ++ check("target_name", "org.spice-space.webdav.0", "test.2") ++ + self._alter_compare(guest.get_xml_config(), outfile) + + def testAlterControllers(self): +@@ -478,6 +493,7 @@ + check("type", "direct") + check("source", "eth0.1") + check("source_mode", "vepa", "bridge") ++ check("portgroup", None, "sales") + check("driver_name", None, "vhost") + check("driver_queues", None, 5) + +@@ -958,7 +974,7 @@ + check("autoconf", True, False) + + check = self._make_checker(iface.protocols[1].ips[1]) +- check("address", "fe80::215:58ff:fe6e:5", "foobar") ++ check("address", "fe80::215:58ff:fe6e:5", "2002::") + check("prefix", 64, 38) + + # Remove a child interface, verify it's data remains intact +@@ -1127,6 +1143,11 @@ + check("mode", "nat", "route") + check("dev", None, "eth22") + ++ self.assertEquals(len(net.portgroups), 2) ++ check = self._make_checker(net.portgroups[0]) ++ check("name", "engineering", "foo") ++ check("default", True, False) ++ + self.assertEqual(len(net.ips), 4) + check = self._make_checker(net.ips[0]) + check("address", "192.168.7.1", "192.168.8.1") +@@ -1175,7 +1196,7 @@ + utils.diff_compare(guest.get_xml_config(), outfile) + + def testzzzzCheckProps(self): +- # pylint: disable=W0212 ++ # pylint: disable=protected-access + # Access to protected member, needed to unittest stuff + + # If a certain environment variable is set, XMLBuilder tracks +diff -urN virt-manager-1.0.1/tests/xmlparse-xml/change-chars-in.xml virt-manager/tests/xmlparse-xml/change-chars-in.xml +--- virt-manager-1.0.1/tests/xmlparse-xml/change-chars-in.xml 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/tests/xmlparse-xml/change-chars-in.xml 2014-06-12 11:22:21.122891895 +0000 +@@ -44,5 +44,9 @@ + + + ++ ++ ++ ++ + + +diff -urN virt-manager-1.0.1/tests/xmlparse-xml/change-chars-out.xml virt-manager/tests/xmlparse-xml/change-chars-out.xml +--- virt-manager-1.0.1/tests/xmlparse-xml/change-chars-out.xml 2014-02-27 22:10:39.000000000 +0000 ++++ virt-manager/tests/xmlparse-xml/change-chars-out.xml 2014-06-12 11:22:21.122891895 +0000 +@@ -47,5 +47,9 @@ + + + ++ ++ ++ ++ + + +diff -urN virt-manager-1.0.1/tests/xmlparse-xml/change-disk-out.xml virt-manager/tests/xmlparse-xml/change-disk-out.xml +--- virt-manager-1.0.1/tests/xmlparse-xml/change-disk-out.xml 2014-02-27 22:10:39.000000000 +0000 ++++ virt-manager/tests/xmlparse-xml/change-disk-out.xml 2014-06-12 11:22:21.122891895 +0000 +@@ -50,7 +50,7 @@ + 5 + 6 + +- ++ + + + +diff -urN virt-manager-1.0.1/tests/xmlparse-xml/change-guest-out.xml virt-manager/tests/xmlparse-xml/change-guest-out.xml +--- virt-manager-1.0.1/tests/xmlparse-xml/change-guest-out.xml 2014-03-22 16:16:24.000000000 +0000 ++++ virt-manager/tests/xmlparse-xml/change-guest-out.xml 2014-06-12 11:22:21.122891895 +0000 +@@ -10,6 +10,9 @@ + /sbin/init + + ++ foo ++ bar baz ++ frib + + + +@@ -78,17 +81,6 @@ + + Hey title changed! + Hey desc changed& +- +- +- +- +- +- +- 2048 +- 200 +- 400 +- 500 +- + + 200 + +@@ -96,9 +88,23 @@ + 300 + + ++ ++ 2048 ++ 200 ++ 400 ++ 500 ++ ++ ++ ++ ++ ++ + pygrub + + + + ++ ++ /virtualmachines/production ++ + +diff -urN virt-manager-1.0.1/tests/xmlparse-xml/change-nics-out.xml virt-manager/tests/xmlparse-xml/change-nics-out.xml +--- virt-manager-1.0.1/tests/xmlparse-xml/change-nics-out.xml 2014-02-27 22:10:40.000000000 +0000 ++++ virt-manager/tests/xmlparse-xml/change-nics-out.xml 2014-06-12 11:22:21.123891895 +0000 +@@ -40,7 +40,7 @@ + + + +- ++ + + + +diff -urN virt-manager-1.0.1/tests/xmlparse-xml/interface-test-bridge-ip-out.xml virt-manager/tests/xmlparse-xml/interface-test-bridge-ip-out.xml +--- virt-manager-1.0.1/tests/xmlparse-xml/interface-test-bridge-ip-out.xml 2014-02-27 22:10:40.000000000 +0000 ++++ virt-manager/tests/xmlparse-xml/interface-test-bridge-ip-out.xml 2014-06-12 11:22:21.123891895 +0000 +@@ -15,7 +15,7 @@ + + + +- ++ + + + +diff -urN virt-manager-1.0.1/tests/xmlparse-xml/network-multi-in.xml virt-manager/tests/xmlparse-xml/network-multi-in.xml +--- virt-manager-1.0.1/tests/xmlparse-xml/network-multi-in.xml 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/tests/xmlparse-xml/network-multi-in.xml 2014-06-12 11:22:21.124891895 +0000 +@@ -22,4 +22,22 @@ + + + ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + +diff -urN virt-manager-1.0.1/tests/xmlparse-xml/network-multi-out.xml virt-manager/tests/xmlparse-xml/network-multi-out.xml +--- virt-manager-1.0.1/tests/xmlparse-xml/network-multi-out.xml 2014-02-27 22:10:40.000000000 +0000 ++++ virt-manager/tests/xmlparse-xml/network-multi-out.xml 2014-06-12 11:22:21.124891895 +0000 +@@ -24,6 +24,24 @@ + + + ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +diff -urN virt-manager-1.0.1/ui/about.ui virt-manager/ui/about.ui +--- virt-manager-1.0.1/ui/about.ui 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/ui/about.ui 2014-06-12 11:22:21.124891895 +0000 +@@ -6,7 +6,7 @@ + True + dialog + Virtual Machine Manager +- Copyright (C) 2006-2011 Red Hat Inc. ++ Copyright (C) 2006-2014 Red Hat Inc. + Powered by libvirt + http://virt-manager.org/ + http://virt-manager.org/ +diff -urN virt-manager-1.0.1/ui/addhardware.ui virt-manager/ui/addhardware.ui +--- virt-manager-1.0.1/ui/addhardware.ui 2014-03-12 21:17:20.000000000 +0000 ++++ virt-manager/ui/addhardware.ui 2014-06-12 11:22:21.135891895 +0000 +@@ -327,6 +327,83 @@ + + + ++ ++ True ++ False ++ 6 ++ 6 ++ ++ ++ True ++ False ++ 0 ++ _Type: ++ True ++ ++ ++ 0 ++ 0 ++ 1 ++ 1 ++ ++ ++ ++ ++ True ++ False ++ 0 ++ _Model: ++ True ++ ++ ++ 0 ++ 1 ++ 1 ++ 1 ++ ++ ++ ++ ++ True ++ False ++ ++ ++ ++ 1 ++ 0 ++ 1 ++ 1 ++ ++ ++ ++ ++ True ++ False ++ ++ ++ 1 ++ 1 ++ 1 ++ 1 ++ ++ ++ ++ ++ 2 ++ ++ ++ ++ ++ True ++ False ++ Controller ++ ++ ++ 2 ++ False ++ ++ ++ + + True + False +@@ -491,7 +568,7 @@ + + + +- 2 ++ 3 + + + +@@ -501,7 +578,7 @@ + net + + +- 2 ++ 3 + False + + +@@ -539,7 +616,7 @@ + + + +- 3 ++ 4 + + + +@@ -549,7 +626,7 @@ + input + + +- 3 ++ 4 + False + + +@@ -562,7 +639,7 @@ + + + +- 4 ++ 5 + + + +@@ -572,7 +649,7 @@ + gfx + + +- 4 ++ 5 + False + + +@@ -611,7 +688,7 @@ + + + +- 5 ++ 6 + + + +@@ -621,7 +698,7 @@ + sound + + +- 5 ++ 6 + False + + +@@ -671,7 +748,7 @@ + + + +- 6 ++ 7 + + + +@@ -681,7 +758,7 @@ + host + + +- 6 ++ 7 + False + + +@@ -713,7 +790,7 @@ + + + 1 +- 8 ++ 9 + 1 + 1 + +@@ -726,7 +803,7 @@ + + + 1 +- 5 ++ 7 + 1 + 1 + +@@ -828,7 +905,7 @@ + + + 1 +- 7 ++ 8 + 1 + 1 + +@@ -860,7 +937,7 @@ + + + 0 +- 5 ++ 8 + 1 + 1 + +@@ -908,7 +985,7 @@ + + + 0 +- 8 ++ 9 + 1 + 1 + +@@ -1039,9 +1116,36 @@ + 1 + + ++ ++ ++ True ++ False ++ 0 ++ _Channel: ++ True ++ ++ ++ 0 ++ 5 ++ 1 ++ 1 ++ ++ ++ ++ ++ True ++ True ++ ++ ++ 1 ++ 5 ++ 1 ++ 1 ++ ++ + + +- 7 ++ 8 + + + +@@ -1051,7 +1155,7 @@ + char + + +- 7 ++ 8 + False + + +@@ -1090,7 +1194,7 @@ + + + +- 8 ++ 9 + + + +@@ -1100,7 +1204,7 @@ + vid + + +- 8 ++ 9 + False + + +@@ -1169,7 +1273,7 @@ + + + +- 9 ++ 10 + + + +@@ -1179,7 +1283,7 @@ + wdog + + +- 9 ++ 10 + False + + +@@ -1193,7 +1297,7 @@ + + + +- 10 ++ 11 + + + +@@ -1203,7 +1307,7 @@ + fs + + +- 10 ++ 11 + False + + +@@ -1242,7 +1346,7 @@ + + + +- 11 ++ 12 + + + +@@ -1252,7 +1356,7 @@ + sc + + +- 11 ++ 12 + False + + +@@ -1362,7 +1466,7 @@ + + + +- 12 ++ 13 + + + +@@ -1372,7 +1476,7 @@ + usbr + + +- 12 ++ 13 + False + + +@@ -1441,7 +1545,7 @@ + + + +- 13 ++ 14 + + + +@@ -1451,7 +1555,7 @@ + tpm + + +- 13 ++ 14 + False + + +@@ -1709,7 +1813,7 @@ + + + +- 14 ++ 15 + + + +@@ -1719,7 +1823,7 @@ + rng + + +- 14 ++ 15 + False + + +@@ -1786,7 +1890,7 @@ + + + +- 15 ++ 16 + + + +@@ -1796,7 +1900,7 @@ + panic + + +- 15 ++ 16 + False + + +diff -urN virt-manager-1.0.1/ui/connect.ui virt-manager/ui/connect.ui +--- virt-manager-1.0.1/ui/connect.ui 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/ui/connect.ui 2014-06-12 11:22:21.136891895 +0000 +@@ -259,6 +259,7 @@ + 0 + H_ostname: + True ++ hostname + + + 0 +@@ -295,6 +296,7 @@ + 0 + Me_thod: + True ++ transport + + + 0 +diff -urN virt-manager-1.0.1/ui/createinterface.ui virt-manager/ui/createinterface.ui +--- virt-manager-1.0.1/ui/createinterface.ui 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/ui/createinterface.ui 2014-06-12 11:22:21.137891895 +0000 +@@ -697,7 +697,9 @@ + True + False + 0 +- Forward delay: ++ Forward _delay: ++ True ++ bridge-delay + + + GTK_FILL +@@ -709,7 +711,9 @@ + True + False + 0 +- Enable STP: ++ Enable _STP: ++ True ++ bridge-stp + + + 1 +@@ -1961,7 +1965,7 @@ + + + +- _Configure ++ Config_ure + True + True + True +diff -urN virt-manager-1.0.1/ui/createnet.ui virt-manager/ui/createnet.ui +--- virt-manager-1.0.1/ui/createnet.ui 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/ui/createnet.ui 2014-06-12 11:22:21.138891895 +0000 +@@ -1,7 +1,7 @@ + +- ++ + +- ++ + + True + False +@@ -152,12 +152,12 @@ + 25 + False + False ++ + + + Net Name Field + + +- + + + 1 +@@ -1251,7 +1251,7 @@ + 1 + _Destination: + True +- net-forward-dev ++ net-forward + + + 0 +@@ -1268,6 +1268,7 @@ + 1 + _Mode: + True ++ net-forward-mode + + + 0 +diff -urN virt-manager-1.0.1/ui/createpool.ui virt-manager/ui/createpool.ui +--- virt-manager-1.0.1/ui/createpool.ui 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/ui/createpool.ui 2014-06-12 11:22:21.138891895 +0000 +@@ -216,6 +216,7 @@ + 1 + B_uild Pool: + True ++ pool-build + + + 0 +@@ -272,6 +273,7 @@ + 1 + _Target Path: + True ++ pool-target-path + + + 0 +@@ -287,6 +289,7 @@ + 1 + F_ormat: + True ++ pool-format + + + 0 +@@ -302,6 +305,7 @@ + 1 + Host Na_me: + True ++ pool-hostname + + + 0 +@@ -315,8 +319,9 @@ + True + False + 1 +- _Source Path: ++ sourcep: + True ++ pool-source-path + + + 0 +@@ -330,7 +335,7 @@ + True + False + 1 +- _IQN: ++ Initiator _IQN: + True + pool-iqn-chk + +@@ -463,8 +468,9 @@ + True + False + 1 +- _Source Name: ++ Source _Name: + True ++ pool-source-name + + + 0 +diff -urN virt-manager-1.0.1/ui/create.ui virt-manager/ui/create.ui +--- virt-manager-1.0.1/ui/create.ui 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/ui/create.ui 2014-06-12 11:22:21.137891895 +0000 +@@ -1676,21 +1676,6 @@ + + + +- +- True +- False +- +- +- +- 1 +- 2 +- 1 +- 2 +- GTK_FILL +- +- +- +- + + True + False +@@ -1732,6 +1717,27 @@ + GTK_FILL + + ++ ++ ++ ++ True ++ False ++ True ++ ++ ++ ++ True ++ ++ ++ ++ ++ 1 ++ 2 ++ 1 ++ 2 ++ GTK_FILL ++ ++ + + + +diff -urN virt-manager-1.0.1/ui/createvol.ui virt-manager/ui/createvol.ui +--- virt-manager-1.0.1/ui/createvol.ui 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/ui/createvol.ui 2014-06-12 11:22:21.138891895 +0000 +@@ -1,7 +1,7 @@ + +- ++ + +- ++ + + 100000 + 1 +@@ -209,7 +209,7 @@ + True + False + 0 +- _Format: ++ F_ormat: + True + vol-format + +diff -urN virt-manager-1.0.1/ui/details.ui virt-manager/ui/details.ui +--- virt-manager-1.0.1/ui/details.ui 2014-03-19 11:57:24.000000000 +0000 ++++ virt-manager/ui/details.ui 2014-06-12 11:22:21.146891895 +0000 +@@ -1,7 +1,7 @@ + +- ++ + +- ++ + + + 1 +@@ -1018,6 +1018,118 @@ + 1 + + ++ ++ ++ True ++ False ++ 2 ++ 1 ++ 0 ++ Chipse_t: ++ True ++ middle ++ ++ ++ 0 ++ 4 ++ 1 ++ 1 ++ ++ ++ ++ ++ True ++ False ++ 3 ++ ++ ++ False ++ 6 ++ ++ ++ True ++ False ++ start ++ False ++ 0 ++ gtk-dialog-warning ++ ++ ++ False ++ True ++ 0 ++ ++ ++ ++ ++ True ++ False ++ <small>Q35 is not the default chipset and has received far less testing. ++Once this change is made it is difficult to go back. Only use this ++if you know what you are doing.</small> ++ True ++ ++ ++ False ++ True ++ 1 ++ ++ ++ ++ ++ 0 ++ 1 ++ 1 ++ 1 ++ ++ ++ ++ ++ True ++ False ++ ++ ++ True ++ False ++ start ++ False ++ ++ ++ ++ False ++ True ++ 0 ++ ++ ++ ++ ++ True ++ False ++ 0 ++ label ++ ++ ++ False ++ True ++ 1 ++ ++ ++ ++ ++ 0 ++ 0 ++ 1 ++ 1 ++ ++ ++ ++ ++ 1 ++ 4 ++ 1 ++ 1 ++ ++ + + + +@@ -1919,12 +2031,12 @@ + 1 + True + if-valid ++ + + + Virtual CPU Select + + +- + + + 1 +@@ -2319,12 +2431,12 @@ + True + True + ● ++ + + + Virtual CPU Affinity Select + + +- + + + False +@@ -2553,12 +2665,12 @@ + 2 + True + if-valid ++ + + + Memory Select + + +- + + + False +@@ -2602,12 +2714,12 @@ + 2 + True + if-valid ++ + + + Max Memory Select + + +- + + + False +@@ -2733,34 +2845,68 @@ + 3 + 12 + +- ++ + True + False +- 12 ++ 6 ++ 6 ++ ++ ++ True ++ True ++ ● ++ 25 ++ ++ ++ ++ 1 ++ 0 ++ 1 ++ 1 ++ ++ + + + True + False +- Init path: ++ Init _path: ++ True ++ boot-init-path + + +- False +- True +- 0 ++ 0 ++ 0 ++ 1 ++ 1 + + + +- ++ ++ True ++ False ++ Init ar_gs: ++ True ++ boot-init-args ++ ++ ++ 0 ++ 1 ++ 1 ++ 1 ++ ++ ++ ++ + True + True +- ● + 25 +- ++ + + +- False +- True +- 1 ++ 1 ++ 1 ++ 1 ++ 1 + + + +@@ -3517,6 +3663,8 @@ + True + False + 1 ++ 0 ++ 4 + Storage forma_t: + True + +@@ -3558,25 +3706,6 @@ + + + +- +- True +- False +- True +- +- +- +- True +- +- +- +- +- 1 +- 2 +- 1 +- 1 +- +- +- + + True + False +@@ -3610,6 +3739,77 @@ + 1 + + ++ ++ ++ True ++ False ++ vertical ++ 6 ++ ++ ++ True ++ False ++ 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 ++ 2 ++ 1 ++ 1 ++ ++ + + + False +@@ -4208,14 +4408,12 @@ + 3 + 12 + +- ++ + True + False + 3 +- 2 +- 2 +- 8 + 4 ++ 8 + + + True +@@ -4225,8 +4423,10 @@ + True + + +- GTK_FILL +- ++ 0 ++ 0 ++ 1 ++ 1 + + + +@@ -4237,10 +4437,10 @@ + Mode: + + ++ 0 + 1 +- 2 +- GTK_FILL +- ++ 1 ++ 1 + + + +@@ -4253,11 +4453,9 @@ + + + 1 +- 2 + 1 +- 2 +- GTK_FILL +- ++ 1 ++ 1 + + + +@@ -4270,8 +4468,9 @@ + + + 1 +- 2 +- ++ 0 ++ 1 ++ 1 + + + +diff -urN virt-manager-1.0.1/ui/netlist.ui virt-manager/ui/netlist.ui +--- virt-manager-1.0.1/ui/netlist.ui 2014-03-10 15:17:58.000000000 +0000 ++++ virt-manager/ui/netlist.ui 2014-06-12 11:22:21.149891895 +0000 +@@ -96,7 +96,7 @@ + + + 0 +- 3 ++ 4 + 2 + 1 + +@@ -111,7 +111,7 @@ + + + +- False ++ True + + + +@@ -161,6 +161,45 @@ + 1 + + ++ ++ ++ True ++ False ++ start ++ False ++ 0 ++ _Portgroup: ++ True ++ net-portgroup ++ ++ ++ 0 ++ 3 ++ 1 ++ 1 ++ ++ ++ ++ ++ True ++ False ++ start ++ True ++ True ++ ++ ++ ++ True ++ ++ ++ ++ ++ 1 ++ 3 ++ 1 ++ 1 ++ ++ + + + True +diff -urN virt-manager-1.0.1/ui/preferences.ui virt-manager/ui/preferences.ui +--- virt-manager-1.0.1/ui/preferences.ui 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/ui/preferences.ui 2014-06-12 11:22:21.149891895 +0000 +@@ -880,6 +880,7 @@ + 0 + _Interface start/stop: + True ++ prefs-confirm-interface + + + 0 +diff -urN virt-manager-1.0.1/virtcli/cliconfig.py virt-manager/virtcli/cliconfig.py +--- virt-manager-1.0.1/virtcli/cliconfig.py 2014-03-22 22:37:44.000000000 +0000 ++++ virt-manager/virtcli/cliconfig.py 2014-06-12 11:22:21.168891895 +0000 +@@ -53,9 +53,15 @@ + 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.") + + os.environ["GSETTINGS_SCHEMA_DIR"] = schemadir +- ret = subprocess.call(["glib-compile-schemas", "--strict", schemadir]) ++ ret = subprocess.call([exe, "--strict", schemadir]) + if ret != 0: + raise RuntimeError("Failed to compile local gsettings schemas") + +@@ -88,3 +94,4 @@ + askpass_package = _split_list(_get_param("askpass_packages", "")) + libvirt_packages = _split_list(_get_param("libvirt_packages", "")) + default_graphics = _get_param("default_graphics", "spice") ++with_bhyve = bool(int(_get_param("with_bhyve", "0"))) +diff -urN virt-manager-1.0.1/virt-clone virt-manager/virt-clone +--- virt-manager-1.0.1/virt-clone 2014-03-22 16:27:02.000000000 +0000 ++++ virt-manager/virt-clone 2014-06-12 11:22:21.150891895 +0000 +@@ -31,7 +31,7 @@ + from virtinst.cli import fail, print_stdout, print_stderr + + +-### General input gathering functions ++# 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 +diff -urN virt-manager-1.0.1/virtconv/formats.py virt-manager/virtconv/formats.py +--- virt-manager-1.0.1/virtconv/formats.py 2014-03-06 17:51:59.000000000 +0000 ++++ virt-manager/virtconv/formats.py 2014-06-12 11:22:21.168891895 +0000 +@@ -174,16 +174,18 @@ + """ + Public interface for actually performing the conversion + """ +- def __init__(self, conn, input_file, print_cb=None, input_name=None): ++ def __init__(self, conn, input_file, print_cb=-1, input_name=None): + self.conn = conn + self._err_clean = [] + self._force_clean = [] + +- if print_cb is None: ++ if print_cb == -1 or print_cb is None: + def cb(msg): +- print msg +- print_cb = cb +- self.print_cb = print_cb ++ if print_cb == -1: ++ print msg ++ self.print_cb = cb ++ else: ++ self.print_cb = print_cb + + parser = None + if input_name: +@@ -195,7 +197,7 @@ + (self._input_file, + self.parser, + self._force_clean) = _find_input(input_file, parser, self.print_cb) +- self._top_dir = os.path.dirname(self._input_file) ++ self._top_dir = os.path.dirname(os.path.abspath(self._input_file)) + + logging.debug("converter not input_file=%s parser=%s", + self._input_file, self.parser) +@@ -270,7 +272,7 @@ + disk_format = None + + if destdir is None: +- destdir = StoragePool.get_default_path(self.conn) ++ destdir = StoragePool.get_default_path(self.conn, build=not dry) + + guest = self.get_guest() + for disk in guest.get_devices("disk"): +diff -urN virt-manager-1.0.1/virtconv/ovf.py virt-manager/virtconv/ovf.py +--- virt-manager-1.0.1/virtconv/ovf.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtconv/ovf.py 2014-06-12 11:22:21.168891895 +0000 +@@ -285,7 +285,7 @@ + ifaces = [] + for node in ctx.xpathEval(vhbase % DEVICE_ETHERNET): + iface = virtinst.VirtualNetworkInterface(conn) +- # XXX: Just ignore 'source' info and choose the default ++ # XXX: Just ignore 'source' info and choose the default + net_model = _get_child_content(node, "ResourceSubType") + if net_model and not net_model.isdigit(): + iface.model = net_model.lower() +diff -urN virt-manager-1.0.1/virt-convert virt-manager/virt-convert +--- virt-manager-1.0.1/virt-convert 2014-03-22 16:27:02.000000000 +0000 ++++ virt-manager/virt-convert 2014-06-12 11:22:21.150891895 +0000 +@@ -97,9 +97,12 @@ + options.quiet = True + + conscb = options.autoconsole and cli.show_console_for_guest or None ++ print_cb = print_stdout ++ if options.quiet: ++ print_cb = None + + converter = VirtConverter(conn, options.input, +- input_name=options.input_format, print_cb=print_stdout) ++ input_name=options.input_format, print_cb=print_cb) + try: + converter.convert_disks(options.disk_format or "none", + destdir=options.destination, dry=options.dry) +diff -urN virt-manager-1.0.1/virt-image virt-manager/virt-image +--- virt-manager-1.0.1/virt-image 2014-03-22 16:27:02.000000000 +0000 ++++ virt-manager/virt-image 2014-06-12 11:22:21.150891895 +0000 +@@ -33,7 +33,7 @@ + from virtinst import virtimage + + +-### Option parsing ++# Option parsing + def parse_args(): + parser = cli.setupParser( + "%(prog)s image.xml [OPTIONS]", +diff -urN virt-manager-1.0.1/virtinst/capabilities.py virt-manager/virtinst/capabilities.py +--- virt-manager-1.0.1/virtinst/capabilities.py 2014-03-20 18:04:29.000000000 +0000 ++++ virt-manager/virtinst/capabilities.py 2014-06-12 11:22:21.169891895 +0000 +@@ -102,16 +102,21 @@ + Fallback method to lists cpu models, parsed directly from libvirt's local + cpu_map.xml + """ ++ _cpu_filename = "/usr/share/libvirt/cpu_map.xml" ++ + def __init__(self): + _CPUAPIValues.__init__(self) + self.archmap = {} +- cpu_filename = "/usr/share/libvirt/cpu_map.xml" +- xml = file(cpu_filename).read() ++ xml = file(self._cpu_filename).read() + + util.parse_node_helper(xml, "cpus", + self._parseXML, + RuntimeError) + ++ @staticmethod ++ def update_cpu_filename(name): ++ _CPUMapFileValues._cpu_filename = name ++ + def _parseXML(self, node): + child = node.children + while child: +@@ -221,7 +226,7 @@ + self.threads = 1 + self.features = CapabilityFeatures() + +- if not node is None: ++ if node is not None: + self.parseXML(node) + + def parseXML(self, node): +@@ -263,7 +268,7 @@ + self.topology = None + self.secmodels = [] + +- if not node is None: ++ if node is not None: + self.parseXML(node) + + def get_secmodel(self): +@@ -296,7 +301,7 @@ + + self.features = CapabilityFeatures() + +- if not node is None: ++ if node is not None: + self.parseXML(node) + + def parseXML(self, node): +@@ -403,7 +408,7 @@ + def __init__(self, node=None): + self.cells = [] + +- if not node is None: ++ if node is not None: + self.parseXML(node) + + def parseXML(self, node): +@@ -419,7 +424,7 @@ + self.id = None + self.cpus = [] + +- if not node is None: ++ if node is not None: + self.parseXML(node) + + def parseXML(self, node): +@@ -435,7 +440,7 @@ + def __init__(self, node=None): + self.id = None + +- if not node is None: ++ if node is not None: + self.parseXML(node) + + def parseXML(self, node): +@@ -448,7 +453,7 @@ + self.doi = None + self.baselabels = {} + +- if not node is None: ++ if node is not None: + self.parseXML(node) + + def parseXML(self, node): +diff -urN virt-manager-1.0.1/virtinst/cli.py virt-manager/virtinst/cli.py +--- virt-manager-1.0.1/virtinst/cli.py 2014-03-22 16:27:02.000000000 +0000 ++++ virt-manager/virtinst/cli.py 2014-06-12 11:22:21.169891895 +0000 +@@ -117,7 +117,7 @@ + quiet = do_quiet + + vi_dir = None +- if not "VIRTINST_TEST_SUITE" in os.environ: ++ if "VIRTINST_TEST_SUITE" not in os.environ: + vi_dir = util.get_cache_dir() + + if vi_dir and not os.access(vi_dir, os.W_OK): +@@ -347,7 +347,7 @@ + return child + + os.execvp(args[0], args) +- os._exit(1) # pylint: disable=W0212 ++ os._exit(1) # pylint: disable=protected-access + + + def _gfx_console(guest): +@@ -787,8 +787,9 @@ + 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")) ++ 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" +@@ -797,6 +798,10 @@ + help=_("Set domain XML. Ex:\n" + "--clock offset=localtime,rtc_tickpolicy=catchup")) + geng.add_argument("--pm", help=_("Config power management features")) ++ geng.add_argument("--events", ++ help=_("Config OS lifecycle operation management features")) ++ geng.add_argument("--resource", action="append", ++ help=_("Config OS resource management features")) + + + def add_boot_options(insg): +@@ -926,7 +931,8 @@ + elif self.setter_cb: + self.setter_cb(opts, inst, self.cliname, val) + else: +- exec("inst." + self.attrname + " = val") # pylint: disable=W0122 ++ exec( # pylint: disable=exec-used ++ "inst." + self.attrname + " = val") + + + class VirtOptionString(object): +@@ -1135,7 +1141,7 @@ + for optstr in optlist: + optinst = inst + if self.devclass and not inst: +- optinst = self.devclass(guest.conn) # pylint: disable=E1102 ++ optinst = self.devclass(guest.conn) # pylint: disable=not-callable + + try: + devs = self._parse_single_optstr(guest, optstr, optinst) +@@ -1224,6 +1230,29 @@ + self.set_param("description", "description", can_comma=True) + + ++#################### ++# --events parsing # ++#################### ++ ++class ParserEvents(VirtCLIParser): ++ def _init_params(self): ++ self.set_param("on_poweroff", "on_poweroff") ++ self.set_param("on_reboot", "on_reboot") ++ self.set_param("on_crash", "on_crash") ++ ++ ++###################### ++# --resource parsing # ++###################### ++ ++class ParserResource(VirtCLIParser): ++ def _init_params(self): ++ self.remove_first = "partition" ++ self.clear_attr = "resource" ++ ++ self.set_param("resource.partition", "partition") ++ ++ + ###################### + # --numatune parsing # + ###################### +@@ -1410,6 +1439,12 @@ + self.set_param("os.os_type", "os_type") + self.set_param("emulator", "emulator") + ++ def set_initargs_cb(opts, inst, cliname, val): ++ ignore = opts ++ ignore = cliname ++ inst.os.set_initargs_string(val) ++ self.set_param("os.initargs", "initargs", setter_cb=set_initargs_cb) ++ + # Order matters for boot devices, we handle it specially in parse + def noset_cb(val): + ignore = val +@@ -1420,7 +1455,7 @@ + # Build boot order + boot_order = [] + for cliname, ignore in opts.orderedopts: +- if not cliname in inst.os.BOOT_DEVICES: ++ if cliname not in inst.os.BOOT_DEVICES: + continue + + del(opts.opts[cliname]) +@@ -1637,6 +1672,7 @@ + self.set_param("bus", "bus") + self.set_param("removable", "removable", is_onoff=True) + self.set_param("driver_cache", "cache") ++ self.set_param("driver_discard", "discard") + self.set_param("driver_name", "driver_name") + self.set_param("driver_type", "driver_type") + self.set_param("driver_io", "io") +@@ -1742,6 +1778,7 @@ + self.set_param("type", "type", setter_cb=set_type_cb) + self.set_param("source", "source") + self.set_param("source_mode", "source_mode") ++ self.set_param("portgroup", "portgroup") + self.set_param("target_dev", "target") + self.set_param("model", "model") + self.set_param("macaddr", "mac", setter_cb=set_mac_cb) +@@ -1966,11 +2003,11 @@ + def _parse(self, optsobj, inst): + opts = optsobj.opts + +- # pylint: disable=W0201 ++ # pylint: disable=attribute-defined-outside-init + # Defined outside init, but its easier this way + self._cli_backend_mode = "connect" + self._cli_backend_type = "udp" +- # pylint: enable=W0201 ++ # pylint: enable=attribute-defined-outside-init + + if opts.get("type", "").startswith("/"): + # Allow --rng /dev/random +@@ -2210,6 +2247,8 @@ + parsermap[parserobj.option_variable_name] = parserobj + + register_parser("metadata", ParserMetadata) ++ register_parser("events", ParserEvents) ++ register_parser("resource", ParserResource) + register_parser("memory", ParserMemory) + register_parser("memtune", ParserMemorytune) + register_parser("vcpus", ParserVCPU) +diff -urN virt-manager-1.0.1/virtinst/connection.py virt-manager/virtinst/connection.py +--- virt-manager-1.0.1/virtinst/connection.py 2014-03-20 18:04:29.000000000 +0000 ++++ virt-manager/virtinst/connection.py 2014-06-12 11:22:21.170891895 +0000 +@@ -185,7 +185,7 @@ + Returns a list of Guest() objects + """ + if self.cb_fetch_all_guests: +- return self.cb_fetch_all_guests() # pylint: disable=E1102 ++ return self.cb_fetch_all_guests() # pylint: disable=not-callable + return self._fetch_all_guests_cached() + + def _fetch_all_pools_cached(self): +@@ -206,7 +206,7 @@ + Returns a list of StoragePool objects + """ + if self.cb_fetch_all_pools: +- return self.cb_fetch_all_pools() # pylint: disable=E1102 ++ return self.cb_fetch_all_pools() # pylint: disable=not-callable + return self._fetch_all_pools_cached() + + def _fetch_all_vols_cached(self): +@@ -236,12 +236,12 @@ + Returns a list of StorageVolume objects + """ + if self.cb_fetch_all_vols: +- return self.cb_fetch_all_vols() # pylint: disable=E1102 ++ return self.cb_fetch_all_vols() # pylint: disable=not-callable + return self._fetch_all_vols_cached() + + def clear_cache(self, pools=False): + if self.cb_clear_cache: +- self.cb_clear_cache(pools=pools) # pylint: disable=E1102 ++ self.cb_clear_cache(pools=pools) # pylint: disable=not-callable + return + + if pools: +diff -urN virt-manager-1.0.1/virtinst/devicechar.py virt-manager/virtinst/devicechar.py +--- virt-manager-1.0.1/virtinst/devicechar.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtinst/devicechar.py 2014-06-12 11:22:21.170891895 +0000 +@@ -38,10 +38,12 @@ + TYPE_UDP = "udp" + TYPE_UNIX = "unix" + TYPE_SPICEVMC = "spicevmc" ++ TYPE_SPICEPORT = "spiceport" ++ + # 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] ++ _TYPES_FOR_CHANNEL = [TYPE_SPICEVMC, TYPE_SPICEPORT] + TYPES = _TYPES_FOR_ALL + + MODE_CONNECT = "connect" +@@ -67,9 +69,11 @@ + 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_LIBGUESTFS, ++ CHANNEL_NAME_SPICE_WEBDAV] + + @staticmethod + def pretty_channel_name(val): +@@ -79,6 +83,8 @@ + return "qemu-ga" + if val == _VirtualCharDevice.CHANNEL_NAME_LIBGUESTFS: + return "libguestfs" ++ if val == _VirtualCharDevice.CHANNEL_NAME_SPICE_WEBDAV: ++ return "spice-webdav" + return None + + @staticmethod +@@ -110,6 +116,8 @@ + desc = _("Unix socket") + elif ctype == _VirtualCharDevice.TYPE_SPICEVMC: + desc = _("Spice agent") ++ elif ctype == _VirtualCharDevice.TYPE_SPICEPORT: ++ desc = _("Spice port") + + return desc + +@@ -137,6 +145,7 @@ + "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], + "protocol" : [self.TYPE_TCP], + "bind_host" : [self.TYPE_UDP], + "bind_port" : [self.TYPE_UDP], +@@ -170,7 +179,7 @@ + + _XML_PROP_ORDER = ["type", "_has_mode_bind", "_has_mode_connect", + "bind_host", "bind_port", +- "source_mode", "_source_path", ++ "source_mode", "_source_path", "source_channel", + "source_host", "source_port", + "target_type", "target_name"] + +@@ -191,6 +200,9 @@ + self._source_path = val + source_path = property(_get_source_path, _set_source_path) + ++ source_channel = XMLProperty(xpath="./source/@channel", ++ doc=_("Source channel name.")) ++ + def _get_default_source_mode(self): + if self.type == self.TYPE_UDP: + return self.MODE_CONNECT +diff -urN virt-manager-1.0.1/virtinst/devicedisk.py virt-manager/virtinst/devicedisk.py +--- virt-manager-1.0.1/virtinst/devicedisk.py 2014-03-10 15:17:52.000000000 +0000 ++++ virt-manager/virtinst/devicedisk.py 2014-06-12 11:22:21.170891895 +0000 +@@ -169,6 +169,10 @@ + 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" +@@ -494,7 +498,7 @@ + _XML_PROP_ORDER = [ + "type", "device", + "driver_name", "driver_type", +- "driver_cache", "driver_io", "error_policy", ++ "driver_cache", "driver_discard", "driver_io", "error_policy", + "_xmlpath", "target", "bus", + ] + +@@ -607,6 +611,7 @@ + read_only = XMLProperty("./readonly", is_bool=True) + shareable = XMLProperty("./shareable", is_bool=True) + driver_cache = XMLProperty("./driver/@cache") ++ driver_discard = XMLProperty("./driver/@discard") + driver_io = XMLProperty("./driver/@io") + + error_policy = XMLProperty("./driver/@error_policy") +diff -urN virt-manager-1.0.1/virtinst/devicefilesystem.py virt-manager/virtinst/devicefilesystem.py +--- virt-manager-1.0.1/virtinst/devicefilesystem.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtinst/devicefilesystem.py 2014-06-12 11:22:21.170891895 +0000 +@@ -100,7 +100,8 @@ + # 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() and +- (self.type == self.TYPE_DEFAULT or ++ (self.type is None or ++ self.type == self.TYPE_DEFAULT or + self.type == self.TYPE_MOUNT)): + pass + elif not os.path.isabs(val): +diff -urN virt-manager-1.0.1/virtinst/deviceinterface.py virt-manager/virtinst/deviceinterface.py +--- virt-manager-1.0.1/virtinst/deviceinterface.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtinst/deviceinterface.py 2014-06-12 11:22:21.171891895 +0000 +@@ -208,7 +208,7 @@ + ################## + + _XML_PROP_ORDER = [ +- "_bridge", "_network", "_source_dev", "source_mode", ++ "_bridge", "_network", "_source_dev", "source_mode", "portgroup", + "macaddr", "target_dev", "model", "virtualport", + "filterref"] + +@@ -226,6 +226,7 @@ + + 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") +diff -urN virt-manager-1.0.1/virtinst/diskbackend.py virt-manager/virtinst/diskbackend.py +--- virt-manager-1.0.1/virtinst/diskbackend.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtinst/diskbackend.py 2014-06-12 11:22:21.171891895 +0000 +@@ -86,9 +86,9 @@ + if not vol: + pool = StoragePool.lookup_pool_by_path(conn, os.path.dirname(path)) + +- # Is pool running? ++ # Ensure pool is running + if pool and pool.info()[0] != libvirt.VIR_STORAGE_POOL_RUNNING: +- pool = None ++ pool.create(0) + + # Attempt to lookup path as a storage volume + if pool and not vol: +@@ -137,13 +137,14 @@ + return vol, pool, path_is_pool + + dirname = os.path.dirname(path) +- poolname = StoragePool.find_free_name( +- conn, os.path.basename(dirname) or "pool") ++ 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 = poolxml.find_free_name( +- conn, os.path.basename(dirname) or "dirpool") ++ poolxml.name = poolname + poolxml.type = poolxml.TYPE_DIR + poolxml.target_path = dirname + pool = poolxml.install(build=False, create=True, autostart=True) +diff -urN virt-manager-1.0.1/virtinst/distroinstaller.py virt-manager/virtinst/distroinstaller.py +--- virt-manager-1.0.1/virtinst/distroinstaller.py 2014-03-06 17:52:00.000000000 +0000 ++++ virt-manager/virtinst/distroinstaller.py 2014-06-12 11:22:21.172891895 +0000 +@@ -1,5 +1,5 @@ + # +-# Copyright 2006-2009, 2013 Red Hat, Inc. ++# Copyright 2006-2009, 2013, 2014 Red Hat, Inc. + # Daniel P. Berrange + # + # This program is free software; you can redistribute it and/or modify +@@ -30,6 +30,7 @@ + from virtinst import Installer + from virtinst import VirtualDisk + from virtinst import urlfetcher ++from virtinst import osdict + + + def _is_url(conn, url): +@@ -166,7 +167,7 @@ + file_proc = subprocess.Popen(["file", "-z", initrd], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE) +- if not "ext2 filesystem" in file_proc.communicate()[0]: ++ if "ext2 filesystem" not in file_proc.communicate()[0]: + return False + except: + logging.exception("Failed to file command for rhel4 initrd detection") +@@ -473,6 +474,15 @@ + + def detect_distro(self, guest): + try: ++ if not _is_url(self.conn, self.location): ++ name = osdict.lookup_os_by_media(self.location) ++ if name: ++ logging.debug("installer.detect_distro returned=%s", name) ++ return name ++ except: ++ logging.debug("libosinfo detect failed", exc_info=True) ++ ++ try: + ret = urlfetcher.detectMediaDistro(guest, self.location) + logging.debug("installer.detect_distro returned=%s", ret) + return ret +diff -urN virt-manager-1.0.1/virtinst/domainresource.py virt-manager/virtinst/domainresource.py +--- virt-manager-1.0.1/virtinst/domainresource.py 1970-01-01 00:00:00.000000000 +0000 ++++ virt-manager/virtinst/domainresource.py 2014-06-12 11:22:21.172891895 +0000 +@@ -0,0 +1,31 @@ ++# ++# 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 virtinst.xmlbuilder import XMLBuilder, XMLProperty ++ ++ ++class DomainResource(XMLBuilder): ++ """ ++ Class for generating XML ++ """ ++ ++ _XML_ROOT_NAME = "resource" ++ _XML_PROP_ORDER = ["partition"] ++ ++ partition = XMLProperty("./partition") +diff -urN virt-manager-1.0.1/virtinst/guest.py virt-manager/virtinst/guest.py +--- virt-manager-1.0.1/virtinst/guest.py 2014-03-22 16:25:24.000000000 +0000 ++++ virt-manager/virtinst/guest.py 2014-06-12 11:22:21.173891895 +0000 +@@ -39,6 +39,7 @@ + from virtinst import DomainMemorybacking + from virtinst import DomainBlkiotune + from virtinst import DomainFeatures ++from virtinst import DomainResource + from virtinst import PM + from virtinst import IdMap + from virtinst.xmlbuilder import XMLBuilder, XMLProperty, XMLChildProperty +@@ -93,9 +94,9 @@ + + _XML_ROOT_NAME = "domain" + _XML_PROP_ORDER = ["type", "name", "uuid", "title", "description", +- "maxmemory", "memory", "memoryBacking", "vcpus", "curvcpus", "memtune", +- "numatune", "blkiotune", "bootloader", "os", "idmap", "features", +- "cpu", "clock", "on_poweroff", "on_reboot", "on_crash", "pm", ++ "maxmemory", "memory", "blkiotune", "memtune", "memoryBacking", ++ "vcpus", "curvcpus", "numatune", "bootloader", "os", "idmap", "features", ++ "cpu", "clock", "on_poweroff", "on_reboot", "on_crash", "resource", "pm", + "emulator", "_devices", "seclabel"] + + def __init__(self, *args, **kwargs): +@@ -196,6 +197,7 @@ + memtune = XMLChildProperty(DomainMemorytune, is_single=True) + memoryBacking = XMLChildProperty(DomainMemorybacking, is_single=True) + idmap = XMLChildProperty(IdMap, is_single=True) ++ resource = XMLChildProperty(DomainResource, is_single=True) + + + ############################### +diff -urN virt-manager-1.0.1/virtinst/__init__.py virt-manager/virtinst/__init__.py +--- virt-manager-1.0.1/virtinst/__init__.py 2014-03-22 16:16:24.000000000 +0000 ++++ virt-manager/virtinst/__init__.py 2014-06-12 11:22:21.168891895 +0000 +@@ -29,6 +29,7 @@ + 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.seclabel import Seclabel +diff -urN virt-manager-1.0.1/virtinst/interface.py virt-manager/virtinst/interface.py +--- virt-manager-1.0.1/virtinst/interface.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtinst/interface.py 2014-06-12 11:22:21.173891895 +0000 +@@ -23,6 +23,7 @@ + import logging + + import libvirt ++import ipaddr + + from virtinst import util + from virtinst.xmlbuilder import XMLBuilder, XMLChildProperty, XMLProperty +@@ -32,7 +33,15 @@ + _XML_PROP_ORDER = ["address", "prefix"] + _XML_ROOT_NAME = "ip" + +- address = XMLProperty("./@address") ++ ###################### ++ # 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) + + +diff -urN virt-manager-1.0.1/virtinst/network.py virt-manager/virtinst/network.py +--- virt-manager-1.0.1/virtinst/network.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtinst/network.py 2014-06-12 11:22:21.173891895 +0000 +@@ -82,6 +82,13 @@ + return Network.pretty_forward_desc(self.mode, self.dev) + + ++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 +@@ -172,6 +179,7 @@ + delay = XMLProperty("./bridge/@delay", is_int=True) + macaddr = XMLProperty("./mac/@address") + ++ portgroups = XMLChildProperty(_NetworkPortgroup) + ips = XMLChildProperty(_NetworkIP) + routes = XMLChildProperty(_NetworkRoute) + +@@ -184,6 +192,7 @@ + self._add_child(route) + return route + ++ + ################## + # build routines # + ################## +diff -urN virt-manager-1.0.1/virtinst/nodedev.py virt-manager/virtinst/nodedev.py +--- virt-manager-1.0.1/virtinst/nodedev.py 2014-03-22 14:17:11.000000000 +0000 ++++ virt-manager/virtinst/nodedev.py 2014-06-12 11:22:21.173891895 +0000 +@@ -169,9 +169,10 @@ + iommu_group = XMLProperty("./capability/iommuGroup/@number", is_int=True) + + def pretty_name(self): +- devstr = "%.2X:%.2X:%X" % (int(self.bus), +- int(self.slot), +- int(self.function)) ++ 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) + +diff -urN virt-manager-1.0.1/virtinst/osdict.py virt-manager/virtinst/osdict.py +--- virt-manager-1.0.1/virtinst/osdict.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtinst/osdict.py 2014-06-12 11:22:21.173891895 +0000 +@@ -21,13 +21,48 @@ + + _SENTINEL = -1234 + _allvariants = {} +- +- +-def lookup_os(key): +- ret = _allvariants.get(key) +- if ret is None: +- return ret +- return ret ++from datetime import datetime ++from gi.repository import Libosinfo as libosinfo ++from inspect import isfunction ++ ++_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", ++ "vista" : "winvista", ++ "winxp64" : "winxp", ++} + + + def _sort(tosort, sortpref=None): +@@ -40,6 +75,10 @@ + # by their 'distro' tag first and foremost + for key, osinfo in tosort.items(): + sortby = osinfo.sortby or key ++ # Hack to allow "sortby" duplicates. Remove when this never happens ++ # with libosinfo ++ while sortby_mappings.get(sortby): ++ sortby = sortby + ".1" + sortby_mappings[sortby] = key + + distro = osinfo.urldistro or "zzzzzzz" +@@ -59,7 +98,7 @@ + sorted_distro_list.sort() + sortpref.reverse() + for prefer in sortpref: +- if not prefer in sorted_distro_list: ++ if prefer not in sorted_distro_list: + continue + sorted_distro_list.remove(prefer) + sorted_distro_list.insert(0, prefer) +@@ -73,38 +112,6 @@ + return retlist + + +-def list_os(list_types=False, typename=None, +- filtervars=None, only_supported=False, +- **kwargs): +- sortmap = {} +- filtervars = filtervars or [] +- +- for key, osinfo in _allvariants.items(): +- if list_types and not osinfo.is_type: +- continue +- if not list_types and osinfo.is_type: +- continue +- if typename and typename != osinfo.typename: +- continue +- if filtervars and osinfo.name not in filtervars: +- continue +- if only_supported and not osinfo.supported: +- continue +- sortmap[key] = osinfo +- return _sort(sortmap, **kwargs) +- +- +-def lookup_osdict_key(variant, key, default): +- val = _SENTINEL +- if variant is not None: +- if not hasattr(_allvariants[variant], key): +- raise ValueError("Unknown osdict property '%s'" % key) +- val = getattr(_allvariants[variant], key) +- if val == _SENTINEL: +- val = default +- return val +- +- + class _OSVariant(object): + """ + Object tracking guest OS specific configuration bits. +@@ -123,8 +130,9 @@ + it is still pretty useful, so we fake it here. New types should + not be added often. + @parent: Name of a pre-created variant that we want to extend. So +- fedoraFOO would have parent fedoraFOO-1. It's used for inheiriting ++ fedoraFOO would have parent fedoraFOO-1. It's used for inheriting + values. ++ @typename: The family of the OS, e.g. "linux", "windows", "unix". + @sortby: A different key to use for sorting the distro list. By default + it's 'name', so this doesn't need to be specified. + @urldistro: This is a distro class. It's wired up in urlfetcher to give +@@ -149,7 +157,7 @@ + their usage. + """ + def __init__(self, name, label, is_type=False, +- sortby=None, parent=_SENTINEL, ++ sortby=None, parent=_SENTINEL, typename=_SENTINEL, + urldistro=_SENTINEL, supported=_SENTINEL, + three_stage_install=_SENTINEL, + acpi=_SENTINEL, apic=_SENTINEL, clock=_SENTINEL, +@@ -184,7 +192,10 @@ + self.sortby = sortby + + self.is_type = bool(is_type) +- self.typename = _get_default("typename", ++ ++ self.typename = typename ++ if typename == _SENTINEL: ++ self.typename = _get_default("typename", + self.is_type and self.name or _SENTINEL) + + # 'types' should rarely be altered, this check will make +@@ -219,6 +230,10 @@ + self.virtioconsole = _get_default("virtioconsole", virtioconsole) + self.qemu_ga = _get_default("qemu_ga", qemu_ga) + ++ def get_recommended_resources(self, arch): ++ ignore1 = arch ++ return None ++ + + def _add_type(*args, **kwargs): + kwargs["is_type"] = True +@@ -231,107 +246,357 @@ + _allvariants[v.name] = v + + +-_add_type("linux", "Linux") +-_add_var("rhel2.1", "Red Hat Enterprise Linux 2.1", urldistro="rhel", parent="linux") +-_add_var("rhel3", "Red Hat Enterprise Linux 3", parent="rhel2.1") +-_add_var("rhel4", "Red Hat Enterprise Linux 4", supported=True, parent="rhel3") +-_add_var("rhel5", "Red Hat Enterprise Linux 5", supported=False, parent="rhel4") +-_add_var("rhel5.4", "Red Hat Enterprise Linux 5.4 or later", supported=True, virtiodisk=True, virtionet=True, parent="rhel5") +-_add_var("rhel6", "Red Hat Enterprise Linux 6", inputtype="tablet", inputbus="usb", parent="rhel5.4") +-_add_var("rhel7", "Red Hat Enterprise Linux 7 (or later)", parent="rhel6", qemu_ga=True, virtioconsole=True, virtiommio=True) +- +-_add_var("fedora5", "Fedora Core 5", sortby="fedora05", urldistro="fedora", parent="linux") +-_add_var("fedora6", "Fedora Core 6", sortby="fedora06", parent="fedora5") +-_add_var("fedora7", "Fedora 7", sortby="fedora07", parent="fedora6") +-_add_var("fedora8", "Fedora 8", sortby="fedora08", parent="fedora7") +-# Apparently F9 has selinux errors when installing with virtio: +-# https://bugzilla.redhat.com/show_bug.cgi?id=470386 +-_add_var("fedora9", "Fedora 9", sortby="fedora09", virtionet=True, parent="fedora8") +-_add_var("fedora10", "Fedora 10", virtiodisk=True, parent="fedora9") +-_add_var("fedora11", "Fedora 11", inputtype="tablet", inputbus="usb", parent="fedora10") +-_add_var("fedora12", "Fedora 12", parent="fedora11") +-_add_var("fedora13", "Fedora 13", parent="fedora12") +-_add_var("fedora14", "Fedora 14", parent="fedora13") +-_add_var("fedora15", "Fedora 15", parent="fedora14") +-_add_var("fedora16", "Fedora 16", parent="fedora15") +-_add_var("fedora17", "Fedora 17", parent="fedora16") +-_add_var("fedora18", "Fedora 18", supported=True, virtioconsole=True, qemu_ga=True, parent="fedora17") +-_add_var("fedora19", "Fedora 19", virtiommio=True, parent="fedora18") +-_add_var("fedora20", "Fedora 20 (or later)", parent="fedora19") +- +-_add_var("opensuse11", "openSuse 11", urldistro="suse", supported=True, virtiodisk=True, virtionet=True, parent="linux") +-_add_var("opensuse12", "openSuse 12 (or later)", parent="opensuse11") +- +-_add_var("sles10", "Suse Linux Enterprise Server", urldistro="suse", supported=True, parent="linux") +-_add_var("sles11", "Suse Linux Enterprise Server 11 (or later)", supported=True, virtiodisk=True, virtionet=True, parent="sles10") +- +-_add_var("mandriva2009", "Mandriva Linux 2009 and earlier", urldistro="mandriva", parent="linux") +-_add_var("mandriva2010", "Mandriva Linux 2010 (or later)", virtiodisk=True, virtionet=True, parent="mandriva2009") +- +-_add_var("mes5", "Mandriva Enterprise Server 5.0", urldistro="mandriva", parent="linux") +-_add_var("mes5.1", "Mandriva Enterprise Server 5.1 (or later)", supported=True, virtiodisk=True, virtionet=True, parent="mes5") +-_add_var("mbs1", "Mandriva Business Server 1 (or later)", supported=True, virtiodisk=True, virtionet=True, parent="linux") +- +-_add_var("mageia1", "Mageia 1 (or later)", urldistro="mandriva", supported=True, virtiodisk=True, virtionet=True, inputtype="tablet", inputbus="usb", parent="linux") +- +-_add_var("altlinux", "ALT Linux (or later)", urldistro="altlinux", supported=True, virtiodisk=True, virtionet=True, inputtype="tablet", inputbus="usb", parent="linux") +- +-_add_var("debianetch", "Debian Etch", urldistro="debian", sortby="debian4", parent="linux") +-_add_var("debianlenny", "Debian Lenny", sortby="debian5", supported=True, virtiodisk=True, virtionet=True, parent="debianetch") +-_add_var("debiansqueeze", "Debian Squeeze", sortby="debian6", virtiodisk=True, virtionet=True, inputtype="tablet", inputbus="usb", parent="debianlenny") +-_add_var("debianwheezy", "Debian Wheezy (or later)", sortby="debian7", parent="debiansqueeze") +- +-_add_var("ubuntuhardy", "Ubuntu 8.04 LTS (Hardy Heron)", urldistro="ubuntu", virtionet=True, parent="linux") +-_add_var("ubuntuintrepid", "Ubuntu 8.10 (Intrepid Ibex)", parent="ubuntuhardy") +-_add_var("ubuntujaunty", "Ubuntu 9.04 (Jaunty Jackalope)", virtiodisk=True, parent="ubuntuintrepid") +-_add_var("ubuntukarmic", "Ubuntu 9.10 (Karmic Koala)", parent="ubuntujaunty") +-_add_var("ubuntulucid", "Ubuntu 10.04 LTS (Lucid Lynx)", supported=True, parent="ubuntukarmic") +-_add_var("ubuntumaverick", "Ubuntu 10.10 (Maverick Meerkat)", supported=False, parent="ubuntulucid") +-_add_var("ubuntunatty", "Ubuntu 11.04 (Natty Narwhal)", parent="ubuntumaverick") +-_add_var("ubuntuoneiric", "Ubuntu 11.10 (Oneiric Ocelot)", parent="ubuntunatty") +-_add_var("ubuntuprecise", "Ubuntu 12.04 LTS (Precise Pangolin)", supported=True, parent="ubuntuoneiric") +-_add_var("ubuntuquantal", "Ubuntu 12.10 (Quantal Quetzal)", parent="ubuntuprecise") +-_add_var("ubunturaring", "Ubuntu 13.04 (Raring Ringtail)", videomodel="vmvga", parent="ubuntuquantal") +-_add_var("ubuntusaucy", "Ubuntu 13.10 (Saucy Salamander) (or later)", parent="ubunturaring") +- +-_add_var("generic24", "Generic 2.4.x kernel", parent="linux") +-_add_var("generic26", "Generic 2.6.x kernel", parent="generic24") +-_add_var("virtio26", "Generic 2.6.25 or later kernel with virtio", sortby="genericvirtio26", virtiodisk=True, virtionet=True, parent="generic26") ++class _OsVariantOsInfo(_OSVariant): + ++ @staticmethod ++ def is_windows(o): ++ return o.get_family() in ['win9x', 'winnt', 'win16'] ++ ++ def _is_three_stage_install(self): ++ if _OsVariantOsInfo.is_windows(self._os): ++ return True ++ return _SENTINEL ++ ++ def _get_clock(self): ++ if _OsVariantOsInfo.is_windows(self._os) or \ ++ self._os.get_family() in ['solaris']: ++ return "localtime" ++ return _SENTINEL ++ ++ def _is_acpi(self): ++ if self._os.get_family() in ['msdos']: ++ return False ++ return _SENTINEL ++ ++ def _is_apic(self): ++ if self._os.get_family() in ['msdos']: ++ return False ++ return _SENTINEL ++ ++ def _get_netmodel(self): ++ if self._os.get_distro() == "fedora": ++ return _SENTINEL ++ ++ fltr = libosinfo.Filter() ++ fltr.add_constraint("class", "net") ++ devs = self._os.get_all_devices(fltr) ++ if devs.get_length(): ++ return devs.get_nth(0).get_name() ++ return _SENTINEL ++ ++ def _get_videomodel(self): ++ if self._os.get_short_id() in {"ubuntu13.10", "ubuntu13.04"}: ++ return "vmvga" ++ ++ if _OsVariantOsInfo.is_windows(self._os): ++ return "vga" ++ ++ if self._os.get_distro() == "fedora": ++ return _SENTINEL ++ ++ fltr = libosinfo.Filter() ++ fltr.add_constraint("class", "video") ++ devs = self._os.get_all_devices(fltr) ++ if devs.get_length(): ++ return devs.get_nth(0).get_name() ++ return _SENTINEL ++ ++ def _get_inputtype(self): ++ fltr = libosinfo.Filter() ++ fltr.add_constraint("class", "input") ++ devs = self._os.get_all_devices(fltr) ++ if devs.get_length(): ++ return devs.get_nth(0).get_name() ++ return _SENTINEL ++ ++ def get_inputbus(self): ++ fltr = libosinfo.Filter() ++ fltr.add_constraint("class", "input") ++ devs = self._os.get_all_devices(fltr) ++ if devs.get_length(): ++ return devs.get_nth(0).get_bus_type() ++ return _SENTINEL ++ ++ def _get_diskbus(self): ++ return _SENTINEL ++ ++ @staticmethod ++ def is_os_related_to(o, related_os_list): ++ if o.get_short_id() in related_os_list: ++ return True ++ related = o.get_related(libosinfo.ProductRelationship.DERIVES_FROM) ++ clones = o.get_related(libosinfo.ProductRelationship.CLONES) ++ for r in related.get_elements() + clones.get_elements(): ++ if r.get_short_id() in related_os_list or \ ++ _OsVariantOsInfo.is_os_related_to(r, related_os_list): ++ return True ++ ++ return False ++ ++ def _get_xen_disable_acpi(self): ++ if _OsVariantOsInfo.is_os_related_to(self._os, ["winxp", "win2k"]): ++ return True ++ return _SENTINEL ++ ++ def _is_virtiodisk(self): ++ if self._os.get_distro() == "fedora": ++ if self._os.get_version() == "unknown": ++ return _SENTINEL ++ return int(self._os.get_version() >= 10) or _SENTINEL ++ ++ 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 _SENTINEL ++ ++ def _is_virtionet(self): ++ if self._os.get_distro() == "fedora": ++ if self._os.get_version() == "unknown": ++ return _SENTINEL ++ return int(self._os.get_version() >= 9) or _SENTINEL ++ ++ 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 _SENTINEL ++ ++ def _is_virtioconsole(self): ++ if self._os.get_distro() == "fedora": ++ if self._os.get_version() == "unknown": ++ return _SENTINEL ++ return int(self._os.get_version()) >= 18 or _SENTINEL ++ ++ fltr = libosinfo.Filter() ++ fltr.add_constraint("class", "console") ++ devs = self._os.get_all_devices(fltr) ++ for dev in range(devs.get_length()): ++ d = devs.get_nth(dev) ++ if d.get_name() == "virtio-console": ++ return True ++ return _SENTINEL ++ ++ def _is_virtiommio(self): ++ if _OsVariantOsInfo.is_os_related_to(self._os, ["fedora19"]): ++ return True ++ return _SENTINEL ++ ++ def _is_qemu_ga(self): ++ if self._os.get_distro() == "fedora": ++ if self._os.get_version() == "unknown": ++ return _SENTINEL ++ return int(self._os.get_version()) >= 18 or _SENTINEL ++ return _SENTINEL ++ ++ def _get_typename(self): ++ if self._os.get_family() in ['linux']: ++ return "linux" ++ ++ if self._os.get_family() in ['win9x', 'winnt', 'win16']: ++ return "windows" ++ ++ if self._os.get_family() in ['solaris']: ++ return "solaris" ++ ++ if self._os.get_family() in ['openbsd', 'freebsd', 'netbsd']: ++ return "unix" ++ ++ return "other" ++ ++ def _get_sortby(self): ++ 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: ++ pass ++ ++ distro = self._os.get_distro() ++ return "%s-%s" % (distro, version) ++ ++ def _get_supported(self): ++ d = self._os.get_eol_date_string() ++ if self._os.get_distro() == "msdos": ++ return False ++ return d is None or datetime.strptime(d, "%Y-%m-%d") > datetime.now() ++ ++ def _get_urldistro(self): ++ urldistro = self._os.get_distro() ++ remap = { ++ "opensuse" : "suse", ++ "sles" : "suse", ++ "mes" : "mandriva" ++ } ++ ++ if remap.get(urldistro): ++ return remap[urldistro] ++ ++ return urldistro ++ ++ def _get_name(self): ++ return self._os.get_short_id() ++ ++ def get_label(self): ++ return self._os.get_name() ++ ++ def __init__(self, o): ++ self._os = o ++ name = self._get_name() ++ label = self.get_label() ++ sortby = self._get_sortby() ++ is_type = False ++ typename = self._get_typename() ++ urldistro = self._get_urldistro() ++ supported = self._get_supported() ++ three_stage_install = self._is_three_stage_install() ++ acpi = self._is_acpi() ++ apic = self._is_apic() ++ clock = self._get_clock() ++ xen_disable_acpi = self._get_xen_disable_acpi() ++ virtiommio = self._is_virtiommio() ++ qemu_ga = self._is_qemu_ga() ++ virtioconsole = lambda: self._is_virtioconsole() ++ netmodel = lambda: self._get_netmodel() ++ videomodel = lambda: self._get_videomodel() ++ diskbus = lambda: self._get_diskbus() ++ inputtype = lambda: self._get_inputtype() ++ inputbus = lambda: self.get_inputbus() ++ virtiodisk = lambda: self._is_virtiodisk() ++ virtionet = lambda: self._is_virtionet() ++ _OSVariant.__init__(self, name=name, label=label, is_type=is_type, ++ typename=typename, sortby=sortby, parent="generic", ++ urldistro=urldistro, supported=supported, ++ three_stage_install=three_stage_install, acpi=acpi, apic=apic, ++ clock=clock, netmodel=netmodel, diskbus=diskbus, ++ inputtype=inputtype, inputbus=inputbus, videomodel=videomodel, ++ virtionet=virtionet, virtiodisk=virtiodisk, ++ virtiommio=virtiommio, virtioconsole=virtioconsole, ++ xen_disable_acpi=xen_disable_acpi, qemu_ga=qemu_ga) ++ ++ def get_recommended_resources(self, arch): ++ ret = {} ++ def read_resource(resources, arch): ++ for i in range(resources.get_length()): ++ r = resources.get_nth(i) ++ if r.get_architecture() == arch: ++ ret["ram"] = r.get_ram() ++ ret["cpu"] = r.get_cpu() ++ ret["n-cpus"] = r.get_n_cpus() ++ ret["storage"] = r.get_storage() ++ break + +-_add_type("windows", "Windows", clock="localtime", three_stage_install=True, inputtype="tablet", inputbus="usb", videomodel="vga") +-_add_var("win2k", "Microsoft Windows 2000", sortby="mswin4", xen_disable_acpi=True, parent="windows") +-_add_var("winxp", "Microsoft Windows XP", sortby="mswin5", supported=True, xen_disable_acpi=True, parent="windows") +-_add_var("winxp64", "Microsoft Windows XP (x86_64)", supported=True, sortby="mswin564", parent="windows") +-_add_var("win2k3", "Microsoft Windows Server 2003", supported=True, sortby="mswinserv2003", parent="windows") +-_add_var("win2k8", "Microsoft Windows Server 2008 (or later)", supported=True, sortby="mswinserv2008", parent="windows") +-_add_var("vista", "Microsoft Windows Vista", supported=True, sortby="mswin6", parent="windows") +-_add_var("win7", "Microsoft Windows 7 (or later)", supported=True, sortby="mswin7", parent="windows") ++ read_resource(self._os.get_recommended_resources(), "all") ++ read_resource(self._os.get_recommended_resources(), arch) + ++ return ret + ++_add_type("linux", "Linux") ++_add_type("windows", "Windows", clock="localtime", three_stage_install=True, inputtype="tablet", inputbus="usb", videomodel="vga") + _add_type("solaris", "Solaris", clock="localtime") +-_add_var("solaris9", "Sun Solaris 9", parent="solaris") +-_add_var("solaris10", "Sun Solaris 10", inputtype="tablet", inputbus="usb", parent="solaris") +-# https://bugzilla.redhat.com/show_bug.cgi?id=894017 claims tablet doesn't work for solaris 11 +-_add_var("solaris11", "Sun Solaris 11 (or later)", inputtype=None, inputbus=None, parent="solaris") +-_add_var("opensolaris", "Sun OpenSolaris (or later)", inputtype="tablet", inputbus="usb", parent="solaris") +- + _add_type("unix", "UNIX") +-# http: //www.nabble.com/Re%3A-Qemu%3A-bridging-on-FreeBSD-7.0-STABLE-p15919603.html +-_add_var("freebsd6", "FreeBSD 6.x", netmodel="ne2k_pci", parent="unix") +-_add_var("freebsd7", "FreeBSD 7.x", parent="freebsd6") +-_add_var("freebsd8", "FreeBSD 8.x", supported=True, netmodel="e1000", parent="freebsd7") +-_add_var("freebsd9", "FreeBSD 9.x", parent="freebsd8") +-_add_var("freebsd10", "FreeBSD 10.x (or later)", supported=False, virtiodisk=True, virtionet=True, parent="freebsd9") +- +-# http: //calamari.reverse-dns.net: 980/cgi-bin/moin.cgi/OpenbsdOnQemu +-# https: //www.redhat.com/archives/et-mgmt-tools/2008-June/msg00018.html +-_add_var("openbsd4", "OpenBSD 4.x (or later)", netmodel="pcnet", parent="unix") +- +- + _add_type("other", "Other") +-_add_var("msdos", "MS-DOS", acpi=False, apic=False, parent="other") +-_add_var("netware4", "Novell Netware 4", parent="other") +-_add_var("netware5", "Novell Netware 5", parent="other") +-_add_var("netware6", "Novell Netware 6 (or later)", parent="other") + _add_var("generic", "Generic", supported=True, parent="other") ++ ++ ++_os_data_loaded = False ++_os_loader = None ++ ++ ++def _get_os_loader(): ++ global _os_loader ++ if _os_loader: ++ return _os_loader ++ _os_loader = libosinfo.Loader() ++ _os_loader.process_default_path() ++ return _os_loader ++ ++ ++def _load_os_data(): ++ global _os_data_loaded ++ if _os_data_loaded: ++ return ++ loader = _get_os_loader() ++ db = loader.get_db() ++ oslist = db.get_os_list() ++ for os in range(oslist.get_length()): ++ osi = _OsVariantOsInfo(oslist.get_nth(os)) ++ _allvariants[osi.name] = osi ++ _os_data_loaded = True ++ ++ ++def lookup_os(key): ++ _load_os_data() ++ key = _aliases.get(key) or key ++ ret = _allvariants.get(key) ++ if ret is None: ++ return ret ++ return ret ++ ++ ++def list_os(list_types=False, typename=None, ++ filtervars=None, only_supported=False, ++ **kwargs): ++ _load_os_data() ++ sortmap = {} ++ filtervars = filtervars or [] ++ ++ for key, osinfo in _allvariants.items(): ++ if list_types and not osinfo.is_type: ++ continue ++ if not list_types and osinfo.is_type: ++ continue ++ if typename and typename != osinfo.typename: ++ continue ++ if filtervars: ++ filtervars = [lookup_os(x).name for x in filtervars] ++ if osinfo.name not in filtervars: ++ continue ++ if only_supported and not osinfo.supported: ++ continue ++ sortmap[key] = osinfo ++ return _sort(sortmap, **kwargs) ++ ++ ++def lookup_osdict_key(variant, key, default): ++ _load_os_data() ++ val = _SENTINEL ++ if variant is not None: ++ os = lookup_os(variant) ++ if not hasattr(os, key): ++ raise ValueError("Unknown osdict property '%s'" % key) ++ val = getattr(os, key) ++ if isfunction(val): ++ val = val() ++ if val == _SENTINEL: ++ val = default ++ return val ++ ++ ++def get_recommended_resources(variant, arch): ++ _load_os_data() ++ v = _allvariants.get(variant) ++ if v is None: ++ return None ++ ++ return v.get_recommended_resources(arch) ++ ++ ++def lookup_os_by_media(location): ++ loader = _get_os_loader() ++ media = libosinfo.Media.create_from_location(location, None) ++ ret = loader.get_db().guess_os_from_media(media) ++ if ret and len(ret) > 0 and ret[0]: ++ return ret[0].get_short_id() ++ return None +diff -urN virt-manager-1.0.1/virtinst/osxml.py virt-manager/virtinst/osxml.py +--- virt-manager-1.0.1/virtinst/osxml.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtinst/osxml.py 2014-06-12 11:22:21.173891895 +0000 +@@ -20,6 +20,11 @@ + from virtinst.xmlbuilder import XMLBuilder, XMLProperty, XMLChildProperty + + ++class _InitArg(XMLBuilder): ++ _XML_ROOT_NAME = "initarg" ++ val = XMLProperty(".") ++ ++ + class _BootDevice(XMLBuilder): + _XML_ROOT_NAME = "boot" + dev = XMLProperty("./@dev") +@@ -72,6 +77,18 @@ + _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) + +diff -urN virt-manager-1.0.1/virtinst/pollhelpers.py virt-manager/virtinst/pollhelpers.py +--- virt-manager-1.0.1/virtinst/pollhelpers.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtinst/pollhelpers.py 2014-06-12 11:22:21.174891895 +0000 +@@ -19,10 +19,12 @@ + + import logging + +-from virtinst import util + ++# Debugging helper to force old style polling ++_force_old_poll = False + +-def _new_poll_helper(origmap, typename, listfunc, keyfunc, buildfunc): ++ ++def _new_poll_helper(origmap, typename, listfunc, buildfunc): + """ + Helper for new style listAll* APIs + """ +@@ -36,16 +38,16 @@ + logging.debug("Unable to list all %ss: %s", typename, e) + + for obj in objs: +- key = getattr(obj, keyfunc)() ++ connkey = obj.name() + +- if key not in origmap: ++ if connkey not in origmap: + # Object is brand new this period +- current[key] = buildfunc(obj, key) +- new[key] = current[key] ++ current[connkey] = buildfunc(obj, connkey) ++ new[connkey] = current[connkey] + else: + # Previously known object +- current[key] = origmap[key] +- del origmap[key] ++ current[connkey] = origmap[connkey] ++ del(origmap[connkey]) + + return (origmap, new, current) + +@@ -55,7 +57,7 @@ + lookup_func, build_func): + """ + Helper routine for old style split API libvirt polling. +- @origmap: Pre-existing mapping of objects, with key->obj mapping. ++ @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. +@@ -63,7 +65,7 @@ + @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, key (usually UUID)) ++ args of (raw libvirt object, connkey) + """ + current = {} + new = {} +@@ -79,22 +81,26 @@ + except Exception, e: + logging.debug("Unable to list inactive %ss: %s", typename, e) + +- def check_obj(key): +- if key not in origmap: +- try: +- obj = lookup_func(key) +- except Exception, e: +- logging.debug("Could not fetch %s '%s': %s", +- typename, key, e) +- return ++ def check_obj(name): ++ obj = None ++ connkey = name ++ ++ if connkey not in origmap: ++ if connkey not in origmap: ++ try: ++ obj = lookup_func(name) ++ except Exception, e: ++ logging.debug("Could not fetch %s '%s': %s", ++ typename, connkey, e) ++ return + + # Object is brand new this period +- current[key] = build_func(obj, key) +- new[key] = current[key] ++ current[connkey] = build_func(obj, connkey) ++ new[connkey] = current[connkey] + else: + # Previously known object +- current[key] = origmap[key] +- del origmap[key] ++ current[connkey] = origmap[connkey] ++ del(origmap[connkey]) + + for name in newActiveNames + newInactiveNames: + try: +@@ -109,10 +115,9 @@ + name = "network" + + if backend.check_support( +- backend.SUPPORT_CONN_LISTALLNETWORKS): ++ backend.SUPPORT_CONN_LISTALLNETWORKS) and not _force_old_poll: + return _new_poll_helper(origmap, name, +- backend.listAllNetworks, +- "UUIDString", build_func) ++ backend.listAllNetworks, build_func) + else: + active_list = backend.listNetworks + inactive_list = backend.listDefinedNetworks +@@ -127,10 +132,9 @@ + name = "pool" + + if backend.check_support( +- backend.SUPPORT_CONN_LISTALLSTORAGEPOOLS): ++ backend.SUPPORT_CONN_LISTALLSTORAGEPOOLS) and not _force_old_poll: + return _new_poll_helper(origmap, name, +- backend.listAllStoragePools, +- "UUIDString", build_func) ++ backend.listAllStoragePools, build_func) + else: + active_list = backend.listStoragePools + inactive_list = backend.listDefinedStoragePools +@@ -145,10 +149,9 @@ + name = "volume" + + if backend.check_support( +- backend.SUPPORT_POOL_LISTALLVOLUMES, pool): ++ backend.SUPPORT_POOL_LISTALLVOLUMES, pool) and not _force_old_poll: + return _new_poll_helper(origmap, name, +- pool.listAllVolumes, +- "name", build_func) ++ pool.listAllVolumes, build_func) + else: + active_list = pool.listVolumes + inactive_list = lambda: [] +@@ -162,10 +165,9 @@ + name = "interface" + + if backend.check_support( +- backend.SUPPORT_CONN_LISTALLINTERFACES): ++ backend.SUPPORT_CONN_LISTALLINTERFACES) and not _force_old_poll: + return _new_poll_helper(origmap, name, +- backend.listAllInterfaces, +- "name", build_func) ++ backend.listAllInterfaces, build_func) + else: + active_list = backend.listInterfaces + inactive_list = backend.listDefinedInterfaces +@@ -179,10 +181,9 @@ + def fetch_nodedevs(backend, origmap, build_func): + name = "nodedev" + if backend.check_support( +- backend.SUPPORT_CONN_LISTALLDEVICES): ++ backend.SUPPORT_CONN_LISTALLDEVICES) and not _force_old_poll: + return _new_poll_helper(origmap, name, +- backend.listAllDevices, +- "name", build_func) ++ backend.listAllDevices, build_func) + else: + active_list = lambda: backend.listDevices(None, 0) + inactive_list = lambda: [] +@@ -205,8 +206,7 @@ + new = {} + + # Build list of previous vms with proper id/name mappings +- for uuid in origmap: +- vm = origmap[uuid] ++ for vm in origmap.values(): + if vm.is_active(): + oldActiveIDs[vm.get_id()] = vm + else: +@@ -223,20 +223,20 @@ + logging.exception("Unable to list inactive domains: %s", e) + + def add_vm(vm): +- uuid = vm.get_uuid() ++ connkey = vm.get_name() + +- current[uuid] = vm +- del(origmap[uuid]) ++ current[connkey] = vm ++ del(origmap[connkey]) + +- def check_new(rawvm, uuid): +- if uuid in origmap: +- vm = origmap[uuid] +- del(origmap[uuid]) ++ def check_new(rawvm, connkey): ++ if connkey in origmap: ++ vm = origmap[connkey] ++ del(origmap[connkey]) + else: +- vm = build_func(rawvm, uuid) +- new[uuid] = vm ++ vm = build_func(rawvm, connkey) ++ new[connkey] = vm + +- current[uuid] = vm ++ current[connkey] = vm + + for _id in newActiveIDs: + if _id in oldActiveIDs: +@@ -247,9 +247,9 @@ + # Check if domain is brand new, or old one that changed state + try: + vm = backend.lookupByID(_id) +- uuid = util.uuidstr(vm.UUID()) ++ connkey = vm.name() + +- check_new(vm, uuid) ++ check_new(vm, connkey) + except: + logging.exception("Couldn't fetch domain id '%s'", _id) + +@@ -263,9 +263,9 @@ + # Check if domain is brand new, or old one that changed state + try: + vm = backend.lookupByName(name) +- uuid = util.uuidstr(vm.UUID()) ++ connkey = name + +- check_new(vm, uuid) ++ check_new(vm, connkey) + except: + logging.exception("Couldn't fetch domain '%s'", name) + +@@ -275,9 +275,8 @@ + def fetch_vms(backend, origmap, build_func): + name = "domain" + if backend.check_support( +- backend.SUPPORT_CONN_LISTALLDOMAINS): ++ backend.SUPPORT_CONN_LISTALLDOMAINS): + return _new_poll_helper(origmap, name, +- backend.listAllDomains, +- "UUIDString", build_func) ++ backend.listAllDomains, build_func) + else: + return _old_fetch_vms(backend, origmap, build_func) +diff -urN virt-manager-1.0.1/virtinst/storage.py virt-manager/virtinst/storage.py +--- virt-manager-1.0.1/virtinst/storage.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtinst/storage.py 2014-06-12 11:22:21.174891895 +0000 +@@ -213,7 +213,7 @@ + + + @staticmethod +- def get_default_path(conn): ++ def get_default_path(conn, build=True): + """ + Return the default storage path. If there's a 'default' pool, + report that. If there's no default pool, return the path we would +@@ -230,7 +230,9 @@ + except: + pass + +- return StoragePool.build_default_pool(conn).target_path ++ if build: ++ return StoragePool.build_default_pool(conn).target_path ++ return _get_default_pool_path(conn) + + + @staticmethod +diff -urN virt-manager-1.0.1/virtinst/support.py virt-manager/virtinst/support.py +--- virt-manager-1.0.1/virtinst/support.py 2014-03-20 18:04:29.000000000 +0000 ++++ virt-manager/virtinst/support.py 2014-06-12 11:22:21.174891895 +0000 +@@ -293,6 +293,7 @@ + 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_BARE_BACKINGSTORE = _make(version="1.2.4") + + + # Domain checks +diff -urN virt-manager-1.0.1/virtinst/urlfetcher.py virt-manager/virtinst/urlfetcher.py +--- virt-manager-1.0.1/virtinst/urlfetcher.py 2014-03-06 17:52:00.000000000 +0000 ++++ virt-manager/virtinst/urlfetcher.py 2014-06-12 11:22:21.175891895 +0000 +@@ -151,9 +151,16 @@ + self.ftp = None + + def prepareLocation(self): +- url = urlparse.urlparse(self._make_path("")) +- self.ftp = ftplib.FTP(url[1]) +- self.ftp.login() ++ try: ++ url = urlparse.urlparse(self._make_path("")) ++ if not url[1]: ++ raise ValueError(_("Invalid install location")) ++ self.ftp = ftplib.FTP(url[1]) ++ self.ftp.login() ++ except Exception, e: ++ raise ValueError(_("Opening URL %s failed: %s.") % ++ (self.location, str(e))) ++ + + def hasFile(self, filename): + path = self._make_path(filename) +@@ -658,7 +665,7 @@ + """ + ret = None + for osinfo in osdict.list_os(typename="linux"): +- if osinfo.name.startswith("fedora"): ++ if osinfo.name.startswith("fedora") and "unknown" not in osinfo.name: + # First fedora* occurence should be the newest + ret = osinfo.name + break +diff -urN virt-manager-1.0.1/virtinst/util.py virt-manager/virtinst/util.py +--- virt-manager-1.0.1/virtinst/util.py 2014-02-28 18:01:32.000000000 +0000 ++++ virt-manager/virtinst/util.py 2014-06-12 11:22:21.175891895 +0000 +@@ -434,20 +434,6 @@ + return getattr(libvirt, key) + + +-def uuidstr(rawuuid): +- hx = ['0', '1', '2', '3', '4', '5', '6', '7', +- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'] +- uuid = [] +- for i in range(16): +- uuid.append(hx[((ord(rawuuid[i]) >> 4) & 0xf)]) +- uuid.append(hx[(ord(rawuuid[i]) & 0xf)]) +- if i == 3 or i == 5 or i == 7 or i == 9: +- uuid.append('-') +- return "".join(uuid) +- +- +- +- + def get_system_scratchdir(hvtype): + if "VIRTINST_TEST_SUITE" in os.environ: + return os.getcwd() +@@ -495,7 +481,7 @@ + ret = "" + try: + # We don't want to depend on glib for virt-install +- from gi.repository import GLib # pylint: disable=E0611 ++ from gi.repository import GLib + ret = GLib.get_user_cache_dir() + except ImportError: + pass +diff -urN virt-manager-1.0.1/virtinst/virtimage.py virt-manager/virtinst/virtimage.py +--- virt-manager-1.0.1/virtinst/virtimage.py 2014-03-22 12:36:51.000000000 +0000 ++++ virt-manager/virtinst/virtimage.py 2014-06-12 11:22:21.175891895 +0000 +@@ -53,7 +53,7 @@ + self.descr = None + self.version = None + self.release = None +- if not node is None: ++ if node is not None: + self.parseXML(node) + + def abspath(self, p): +@@ -97,7 +97,7 @@ + self.memory = None + self.interface = 0 + self.graphics = None +- if not node is None: ++ if node is not None: + self.parseXML(node) + + def parseXML(self, node): +@@ -151,7 +151,7 @@ + self.drives = [] + self.arch = None + self.features = ImageFeatures() +- if not node is None: ++ if node is not None: + self.parseXML(node) + + def parseXML(self, node): +@@ -221,7 +221,7 @@ + self.size = None + self.use = None + self.csum = {} +- if not node is None: ++ if node is not None: + self.parseXML(node) + + def parseXML(self, node): +@@ -260,7 +260,7 @@ + if hashlib: + if "sha256" in self.csum: + csumvalue = self.csum["sha256"] +- m = hashlib.sha256() # pylint: disable=E1101 ++ m = hashlib.sha256() + + elif "sha1" in self.csum: + csumvalue = self.csum["sha1"] +diff -urN virt-manager-1.0.1/virtinst/xmlbuilder.py virt-manager/virtinst/xmlbuilder.py +--- virt-manager-1.0.1/virtinst/xmlbuilder.py 2014-03-06 17:52:00.000000000 +0000 ++++ virt-manager/virtinst/xmlbuilder.py 2014-06-12 11:22:21.176891895 +0000 +@@ -29,7 +29,7 @@ + from virtinst import util + + +-# pylint: disable=W0212 ++# pylint: disable=protected-access + # This whole file is calling around into non-public functions that we + # don't want regular API users to touch + +diff -urN virt-manager-1.0.1/virt-install virt-manager/virt-install +--- virt-manager-1.0.1/virt-install 2014-03-22 16:27:02.000000000 +0000 ++++ virt-manager/virt-install 2014-06-12 11:22:21.151891895 +0000 +@@ -36,9 +36,6 @@ + ############################## + + install_methods = "--location URL, --cdrom CD/ISO, --pxe, --import, --boot hd|cdrom|..." +-install_missing = (_("An install method must be specified\n(%(methods)s)") % +- {"methods" : install_methods}) +-disk_missing = _("--disk storage must be specified (override with --nodisks)") + + + def install_specified(location, cdpath, pxe, import_install): +@@ -263,13 +260,17 @@ + not storage_specified(options.disk, + options.nodisks, + options.filesystem)): +- msg += "\n" + disk_missing ++ msg += "\n" + ( ++ _("--disk storage must be specified (override with --nodisks)")) + + if (not guest.os.is_container() and ++ not (options.xmlonly or options.xmlstep) and + (not install_specified(options.location, options.cdrom, + options.pxe, options.import_install)) and + (not cdrom_specified(guest, options.disk))): +- msg += "\n" + install_missing ++ msg += "\n" + ( ++ _("An install method must be specified\n(%(methods)s)") % ++ {"methods" : install_methods}) + + if msg: + fail(msg) +@@ -416,6 +417,8 @@ + fail(_("A disk device must be specified with --import.")) + options.import_install = True + instclass = virtinst.ImportInstaller ++ elif options.xmlstep or options.xmlonly: ++ instclass = virtinst.ImportInstaller + else: + instclass = virtinst.DistroInstaller + +@@ -838,13 +841,6 @@ + + check_cdrom_option_error(options) + +- if options.distro_variant == "list": +- logging.debug("OS list requested") +- for t in virtinst.osdict.list_os(list_types=True): +- for v in virtinst.osdict.list_os(typename=t.name): +- print "%-20s : %s" % (v.name, v.label) +- return 0 +- + cli.set_force(options.force) + cli.set_prompt(options.prompt) + +diff -urN virt-manager-1.0.1/virt-manager virt-manager/virt-manager +--- virt-manager-1.0.1/virt-manager 2014-03-22 16:27:02.000000000 +0000 ++++ virt-manager/virt-manager 2014-06-12 11:22:21.151891895 +0000 +@@ -26,10 +26,8 @@ + import sys + import traceback + +-# pylint: disable=E0611 + from gi.repository import GObject + from gi.repository import LibvirtGLib +-# pylint: enable=E0611 + + from virtinst import util as util + from virtinst import cli as virtinstcli +@@ -62,7 +60,7 @@ + # 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=W0212 ++ os._exit(0) # pylint: disable=protected-access + + os.setsid() + +@@ -123,7 +121,7 @@ + return parser.parse_known_args() + + +-def launch_specific_window(engine, show, uri, uuid): ++def launch_specific_window(engine, show, uri, clistr): + if not show: + return + +@@ -131,11 +129,11 @@ + if show == 'creator': + engine.show_domain_creator(uri) + elif show == 'editor': +- engine.show_domain_editor(uri, uuid) ++ engine.show_domain_editor(uri, clistr) + elif show == 'performance': +- engine.show_domain_performance(uri, uuid) ++ engine.show_domain_performance(uri, clistr) + elif show == 'console': +- engine.show_domain_console(uri, uuid) ++ engine.show_domain_console(uri, clistr) + elif show == 'summary': + engine.show_host_summary(uri) + +@@ -174,7 +172,7 @@ + origargv = sys.argv + try: + sys.argv = origargv[:1] + leftovers[:] +- from gi.repository import Gtk # pylint: disable=E0611 ++ from gi.repository import Gtk + leftovers = sys.argv[1:] + + # This will error if Gtk wasn't correctly initialized +diff -urN virt-manager-1.0.1/virtManager/addhardware.py virt-manager/virtManager/addhardware.py +--- virt-manager-1.0.1/virtManager/addhardware.py 2014-03-22 22:05:09.000000000 +0000 ++++ virt-manager/virtManager/addhardware.py 2014-06-12 11:22:21.153891895 +0000 +@@ -22,10 +22,8 @@ + import traceback + import collections + +-# pylint: disable=E0611 + from gi.repository import Gtk + from gi.repository import Gdk +-# pylint: enable=E0611 + + import virtinst + from virtinst import (VirtualChannelDevice, VirtualParallelDevice, +@@ -44,22 +42,24 @@ + from virtManager.baseclass import vmmGObjectUI + from virtManager.addstorage import vmmAddStorage + +-PAGE_ERROR = 0 +-PAGE_DISK = 1 +-PAGE_NETWORK = 2 +-PAGE_INPUT = 3 +-PAGE_GRAPHICS = 4 +-PAGE_SOUND = 5 +-PAGE_HOSTDEV = 6 +-PAGE_CHAR = 7 +-PAGE_VIDEO = 8 +-PAGE_WATCHDOG = 9 +-PAGE_FILESYSTEM = 10 +-PAGE_SMARTCARD = 11 +-PAGE_USBREDIR = 12 +-PAGE_TPM = 13 +-PAGE_RNG = 14 +-PAGE_PANIC = 15 ++(PAGE_ERROR, ++PAGE_DISK, ++PAGE_CONTROLLER, ++PAGE_NETWORK, ++PAGE_INPUT, ++PAGE_GRAPHICS, ++PAGE_SOUND, ++PAGE_HOSTDEV, ++PAGE_CHAR, ++PAGE_VIDEO, ++PAGE_WATCHDOG, ++PAGE_FILESYSTEM, ++PAGE_SMARTCARD, ++PAGE_USBREDIR, ++PAGE_TPM, ++PAGE_RNG, ++PAGE_PANIC, ++) = range(0, 17) + + + class vmmAddHardware(vmmGObjectUI): +@@ -113,6 +113,8 @@ + "on_rng_type_changed": self.change_rng, + "on_rng_backend_mode_changed": self.change_rng, + "on_rng_backend_type_changed": self.change_rng, ++ ++ "on_controller_type_changed": self.populate_controller_model, + }) + self.bind_escape_key_close() + +@@ -314,6 +316,19 @@ + combo = self.widget("panic-type") + self.build_panic_address_type(combo) + ++ # Controller widgets ++ combo = self.widget("controller-type") ++ target_model = Gtk.ListStore(str, str) ++ combo.set_model(target_model) ++ uiutil.set_combo_text_column(combo, 1) ++ combo = self.widget("controller-model") ++ target_model = Gtk.ListStore(str, str) ++ combo.set_model(target_model) ++ uiutil.set_combo_text_column(combo, 1) ++ # FIXME: we should deal with controller model ++ combo.set_visible(False) ++ self.widget("controller-model-label").set_visible(False) ++ + # Available HW options + is_local = not self.conn.is_remote() + is_storage_capable = self.conn.is_storage_capable() +@@ -333,6 +348,7 @@ + + add_hw_option("Storage", "drive-harddisk", PAGE_DISK, have_storage, + have_storage and storage_tooltip or None) ++ add_hw_option("Controller", "device_pci", PAGE_CONTROLLER, True, None) + add_hw_option("Network", "network-idle", PAGE_NETWORK, True, None) + add_hw_option("Input", "input-mouse", PAGE_INPUT, self.vm.is_hvm(), + _("Not supported for this guest type.")) +@@ -421,6 +437,7 @@ + self.widget("char-target-type").set_active(0) + self.widget("char-target-name").set_active(0) + self.widget("char-path").set_text("") ++ self.widget("char-channel").set_text("") + self.widget("char-host").set_text("127.0.0.1") + self.widget("char-port").set_value(4555) + self.widget("char-bind-host").set_text("127.0.0.1") +@@ -455,6 +472,9 @@ + # Panic device params + self.widget("panic-iobase").set_text("0x505") + ++ # Controller device params ++ self.populate_controller_type() ++ + self.set_hw_selection(0) + + +@@ -719,6 +739,27 @@ + combo.set_active_iter(row.iter) + break + ++ @staticmethod ++ def populate_controller_model_combo(combo, controller_type, widget_name, add_default=False): ++ model = combo.get_model() ++ model.clear() ++ ++ if controller_type == virtinst.VirtualController.TYPE_USB: ++ model.append(["default", "Default"]) ++ model.append(["ich9-ehci1", "USB 2"]) ++ model.append(["nec-xhci", "USB 3"]) ++ if widget_name is not None: ++ widget_name.set_sensitive(False) ++ elif controller_type == virtinst.VirtualController.TYPE_SCSI: ++ model.append(["default", "Default"]) ++ model.append(["virtio-scsi", "VirtIO SCSI"]) ++ else: ++ if add_default: ++ model.append([None, "Default"]) ++ combo.set_sensitive(False) ++ if widget_name is not None: ++ widget_name.set_sensitive(True) ++ + + ######################### + # UI population methods # +@@ -813,6 +854,30 @@ + if not create: + format_list.get_child().set_text("") + ++ def populate_controller_type(self): ++ widget = self.widget("controller-type") ++ model = widget.get_model() ++ model.clear() ++ ++ for t in VirtualController.TYPES: ++ if t == VirtualController.TYPE_PCI: ++ continue ++ model.append([t, VirtualController.pretty_type(t)]) ++ ++ if len(model) > 0: ++ widget.set_active(0) ++ ++ def populate_controller_model(self, src): ++ ignore = src ++ ++ controller_type = self.get_config_controller_type() ++ modellist = self.widget("controller-model") ++ modellist.set_sensitive(True) ++ self.populate_controller_model_combo(modellist, controller_type, None, True) ++ ++ if len(modellist.get_model()) > 0: ++ modellist.set_active(0) ++ + + ######################## + # get_config_* methods # +@@ -905,12 +970,12 @@ + + # Input getters + def get_config_input(self): +- row = uiutil.get_list_selection(self.widget("input-type")) ++ row = uiutil.get_list_selection(self.widget("input-type"), None) + return row[1], row[2] + + # Network getters + def get_config_net_model(self): +- return uiutil.get_list_selection(self.widget("net-model"))[0] ++ return uiutil.get_list_selection(self.widget("net-model"), 0) + + def get_config_macaddr(self): + macaddr = None +@@ -933,7 +998,7 @@ + return usb_info + + def get_config_host_device_info(self): +- return uiutil.get_list_selection(self.widget("host-device")) ++ return uiutil.get_list_selection(self.widget("host-device"), None) + + # Video Getters + def get_config_video_model(self): +@@ -1008,6 +1073,13 @@ + def get_config_rng_backend_mode(self): + return uiutil.get_list_selection(self.widget("rng-backend-mode"), 0) + ++ # CONTROLLER getters ++ def get_config_controller_type(self): ++ return uiutil.get_list_selection(self.widget("controller-type"), 0) ++ ++ def get_config_controller_model(self): ++ return uiutil.get_list_selection(self.widget("controller-model"), 0) ++ + ################ + # UI listeners # + ################ +@@ -1016,7 +1088,7 @@ + uiutil.set_list_selection(self.widget("hw-list"), page) + + def get_hw_selection(self): +- return uiutil.get_list_selection(self.widget("hw-list")) ++ return uiutil.get_list_selection(self.widget("hw-list"), None) + + def update_char_device_type_model(self): + stable_blacklist = ["pipe", "udp"] +@@ -1052,6 +1124,8 @@ + sens = row[3] + msg = row[4] or "" + ++ self.widget("create-finish").set_sensitive(sens) ++ + if not sens: + page = PAGE_ERROR + self.widget("hardware-info").set_text(msg) +@@ -1113,6 +1187,8 @@ + return _("Error") + if page == PAGE_DISK: + return _("Storage") ++ if page == PAGE_CONTROLLER: ++ return _("Controller") + if page == PAGE_NETWORK: + return _("Network") + if page == PAGE_INPUT: +@@ -1184,6 +1260,9 @@ + settype = None + if text == VirtualChannelDevice.CHANNEL_NAME_SPICE: + settype = "spicevmc" ++ elif text == VirtualChannelDevice.CHANNEL_NAME_SPICE_WEBDAV: ++ settype = "spiceport" ++ self.widget("char-channel").set_text(text) + elif (text == VirtualChannelDevice.CHANNEL_NAME_QEMUGA or + text == VirtualChannelDevice.CHANNEL_NAME_LIBGUESTFS): + settype = "unix" +@@ -1196,6 +1275,7 @@ + + char_widget_mappings = { + "source_path" : "char-path", ++ "source_channel" : "char-channel", + "source_mode" : "char-mode", + "source_host" : "char-host", + "bind_host" : "char-bind-host", +@@ -1366,6 +1446,8 @@ + return True + elif page_num == PAGE_DISK: + return self.validate_page_storage() ++ elif page_num == PAGE_CONTROLLER: ++ return self.validate_page_controller() + elif page_num == PAGE_NETWORK: + return self.validate_page_network() + elif page_num == PAGE_INPUT: +@@ -1581,6 +1663,7 @@ + devclass.type = devtype + + source_path = self.widget("char-path").get_text() ++ source_channel = self.widget("char-channel").get_text() + source_mode = uiutil.get_list_selection(modebox, 0) + source_host = self.widget("char-host").get_text() + bind_host = self.widget("char-bind-host").get_text() +@@ -1605,6 +1688,7 @@ + + value_mappings = { + "source_path" : source_path, ++ "source_channel" : source_channel, + "source_mode" : source_mode, + "source_host" : source_host, + "source_port" : source_port, +@@ -1719,6 +1803,20 @@ + except Exception, e: + return self.err.val_err(_("Panic device parameter error"), e) + ++ def validate_page_controller(self): ++ conn = self.conn.get_backend() ++ controller_type = self.get_config_controller_type() ++ self._dev = VirtualController(conn) ++ ++ controllers = self.vm.get_controller_devices() ++ controller_num = [x for x in controllers if ++ (x.type == controller_type)] ++ if len(controller_num) > 0: ++ index_new = max([x.index for x in controller_num]) + 1 ++ self._dev.index = index_new ++ ++ self._dev.type = controller_type ++ + def validate_page_rng(self): + conn = virtinst.VirtualRNGDevice.BACKEND_MODE_CONNECT in \ + self.get_config_rng_backend_mode() +diff -urN virt-manager-1.0.1/virtManager/addstorage.py virt-manager/virtManager/addstorage.py +--- virt-manager-1.0.1/virtManager/addstorage.py 2014-03-12 21:21:28.000000000 +0000 ++++ virt-manager/virtManager/addstorage.py 2014-06-12 11:22:21.153891895 +0000 +@@ -21,10 +21,8 @@ + import os + import statvfs + +-# pylint: disable=E0611 + from gi.repository import GObject + from gi.repository import Gtk +-# pylint: enable=E0611 + + import virtinst + from virtManager import uiutil +@@ -258,7 +256,8 @@ + return path + + def is_default_storage(self): +- return self.widget("config-storage-create").get_active() ++ return self.widget("config-storage-create").is_visible() and \ ++ self.widget("config-storage-create").get_active() + + def _check_ideal_path(self, path, vmname, collidelist): + # See if the ideal disk path (/default/pool/vmname.img) +@@ -320,7 +319,7 @@ + if is_default: + path = self.get_default_path(vmname, collidelist) + else: +- path = self.widget("config-storage-entry").get_text() ++ path = self.widget("config-storage-entry").get_text().strip() + + if is_default: + path = self._check_ideal_path(path, vmname, collidelist) +diff -urN virt-manager-1.0.1/virtManager/asyncjob.py virt-manager/virtManager/asyncjob.py +--- virt-manager-1.0.1/virtManager/asyncjob.py 2014-03-22 14:20:45.000000000 +0000 ++++ virt-manager/virtManager/asyncjob.py 2014-06-12 11:22:21.153891895 +0000 +@@ -22,11 +22,9 @@ + import threading + import traceback + +-# pylint: disable=E0611 + from gi.repository import Gdk + from gi.repository import GLib + from gi.repository import Gtk +-# pylint: enable=E0611 + + import libvirt + import urlgrabber +@@ -191,7 +189,6 @@ + self._bg_thread = threading.Thread(target=cb_wrapper, + args=[callback, self] + args) + self._bg_thread.daemon = True +- logging.debug("Creating async job for function cb=%s", callback) + + self.builder.connect_signals({ + "on_async_job_delete_event" : self._on_window_delete, +diff -urN virt-manager-1.0.1/virtManager/autodrawer.py virt-manager/virtManager/autodrawer.py +--- virt-manager-1.0.1/virtManager/autodrawer.py 2014-03-22 14:33:09.000000000 +0000 ++++ virt-manager/virtManager/autodrawer.py 2014-06-12 11:22:21.153891895 +0000 +@@ -22,18 +22,12 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import Gdk + from gi.repository import GLib + from gi.repository import Gtk +-# pylint: enable=E0611 + + from virtManager import uiutil + +-# pylint: disable=E1101 +-# pylint can't detect functions we inheirit from Gtk, ex: +-# OverBox.set_over: Instance of 'OverBox' has no 'remove' member +- + # pylint: disable=arguments-differ + # Newer pylint can detect, but warns that overridden arguments are wrong + +@@ -247,8 +241,8 @@ + # There's something weird here with destroying this gdk window, + # then destroying the over/under widgets. Error seems harmless + # but lets shut it up anyways. +- #self.underWin.destroy() +- #self.overWin.destroy() ++ # self.underWin.destroy() ++ # self.overWin.destroy() + + self.underWin = None + self.overWin = None +diff -urN virt-manager-1.0.1/virtManager/baseclass.py virt-manager/virtManager/baseclass.py +--- virt-manager-1.0.1/virtManager/baseclass.py 2014-03-22 14:59:03.000000000 +0000 ++++ virt-manager/virtManager/baseclass.py 2014-06-12 11:22:21.153891895 +0000 +@@ -25,12 +25,10 @@ + + from virtManager import config + +-# pylint: disable=E0611 + from gi.repository import Gdk + from gi.repository import GLib + from gi.repository import GObject + from gi.repository import Gtk +-# pylint: enable=E0611 + + + class vmmGObject(GObject.GObject): +diff -urN virt-manager-1.0.1/virtManager/choosecd.py virt-manager/virtManager/choosecd.py +--- virt-manager-1.0.1/virtManager/choosecd.py 2014-03-20 18:04:29.000000000 +0000 ++++ virt-manager/virtManager/choosecd.py 2014-06-12 11:22:21.153891895 +0000 +@@ -20,9 +20,7 @@ + + import logging + +-# pylint: disable=E0611 + from gi.repository import GObject +-# pylint: enable=E0611 + + from virtManager.baseclass import vmmGObjectUI + from virtManager.mediadev import MEDIA_FLOPPY +diff -urN virt-manager-1.0.1/virtManager/clone.py virt-manager/virtManager/clone.py +--- virt-manager-1.0.1/virtManager/clone.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/clone.py 2014-06-12 11:22:21.154891895 +0000 +@@ -21,10 +21,8 @@ + import logging + import os + +-# pylint: disable=E0611 + from gi.repository import Gtk + from gi.repository import Gdk +-# pylint: enable=E0611 + + from virtManager import uiutil + from virtManager.baseclass import vmmGObjectUI +@@ -306,7 +304,11 @@ + label = _("Usermode") + + elif net_type == VirtualNetworkInterface.TYPE_VIRTUAL: +- net = self.orig_vm.conn.get_net_by_name(net_dev) ++ net = None ++ for netobj in self.orig_vm.conn.list_nets(): ++ if netobj.get_name() == net_dev: ++ net = netobj ++ break + + if net: + label = "" +diff -urN virt-manager-1.0.1/virtManager/config.py virt-manager/virtManager/config.py +--- virt-manager-1.0.1/virtManager/config.py 2014-03-10 18:54:58.000000000 +0000 ++++ virt-manager/virtManager/config.py 2014-06-12 11:22:21.154891895 +0000 +@@ -20,11 +20,9 @@ + import os + import logging + +-# pylint: disable=E0611 + from gi.repository import Gio + from gi.repository import GLib + from gi.repository import Gtk +-# pylint: enable=E0611 + + from virtinst import CPU + from virtManager.keyring import vmmKeyring, vmmSecret +@@ -152,7 +150,7 @@ + self.conf = SettingsWrapper("org.virt-manager.virt-manager") + + # We don't create it straight away, since we don't want +- # to block the app pending user authorizaation to access ++ # to block the app pending user authorization to access + # the keyring + self.keyring = None + +@@ -163,6 +161,7 @@ + self.libvirt_packages = cliconfig.libvirt_packages + self.askpass_package = cliconfig.askpass_package + self.default_graphics_from_config = cliconfig.default_graphics ++ self.with_bhyve = cliconfig.with_bhyve + self.cli_usbredir = None + + self.default_storage_format_from_config = "qcow2" +@@ -183,7 +182,7 @@ + def check_inspection(self): + try: + # Check we can open the Python guestfs module. +- from guestfs import GuestFS # pylint: disable=F0401 ++ from guestfs import GuestFS # pylint: disable=import-error + GuestFS(close_on_exit=False) + return True + except: +diff -urN virt-manager-1.0.1/virtManager/connectauth.py virt-manager/virtManager/connectauth.py +--- virt-manager-1.0.1/virtManager/connectauth.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/connectauth.py 2014-06-12 11:22:21.154891895 +0000 +@@ -18,10 +18,8 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import GLib + from gi.repository import Gio +-# pylint: enable=E0611 + + import logging + import os +@@ -81,7 +79,7 @@ + """ + Libvirt openAuth callback for username/password credentials + """ +- from gi.repository import Gtk # pylint: disable=E0611 ++ from gi.repository import Gtk + + dialog = Gtk.Dialog("Authentication required", None, 0, + (Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, +diff -urN virt-manager-1.0.1/virtManager/connection.py virt-manager/virtManager/connection.py +--- virt-manager-1.0.1/virtManager/connection.py 2014-03-22 22:13:52.000000000 +0000 ++++ virt-manager/virtManager/connection.py 2014-06-12 11:22:21.155891895 +0000 +@@ -18,9 +18,7 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import GObject +-# pylint: enable=E0611 + + import logging + import os +@@ -46,6 +44,10 @@ + from virtManager.storagepool import vmmStoragePool + + ++# debugging helper to turn off events ++_disable_libvirt_events = False ++ ++ + class vmmConnection(vmmGObject): + __gsignals__ = { + "vm-added": (GObject.SignalFlags.RUN_FIRST, None, [str]), +@@ -86,9 +88,10 @@ + self._uri = "xen:///" + + self.state = self.STATE_DISCONNECTED +- self.connectThread = None +- self.connectError = None ++ self._connectThread = None ++ self._connectError = None + self._backend = virtinst.VirtualConnection(self._uri) ++ self._closing = False + + self._caps = None + self._caps_xml = None +@@ -99,26 +102,26 @@ + self._nodedev_capable = None + + self.using_domain_events = False +- self._domain_cb_id = None ++ self._domain_cb_ids = [] + self.using_network_events = False +- self._network_cb_id = None ++ self._network_cb_ids = [] + + self._xml_flags = {} + + # Physical network interfaces: name -> virtinst.NodeDevice +- self.nodedevs = {} ++ self._nodedevs = {} + # Physical network interfaces: name (eth0) -> vmmNetDevice +- self.netdevs = {} ++ self._netdevs = {} + # Physical media devices: vmmMediaDevice.key -> vmmMediaDevice +- self.mediadevs = {} ++ self._mediadevs = {} + # Connection Storage pools: name -> vmmInterface +- self.interfaces = {} +- # Connection Storage pools: UUID -> vmmStoragePool +- self.pools = {} +- # Virtual networks UUUID -> vmmNetwork object +- self.nets = {} +- # Virtual machines. UUID -> vmmDomain object +- self.vms = {} ++ self._interfaces = {} ++ # Connection Storage pools: name -> vmmStoragePool ++ self._pools = {} ++ # Virtual networks: name -> vmmNetwork object ++ self._nets = {} ++ # Virtual machines: name -> vmmDomain object ++ self._vms = {} + # Resource utilization statistics + self.record = [] + self.hostinfo = None +@@ -168,14 +171,14 @@ + def _init_virtconn(self): + self._backend.cb_fetch_all_guests = ( + lambda: [obj.get_xmlobj(refresh_if_nec=False) +- for obj in self.vms.values()]) ++ for obj in self._vms.values()]) + self._backend.cb_fetch_all_pools = ( + lambda: [obj.get_xmlobj(refresh_if_nec=False) +- for obj in self.pools.values()]) ++ for obj in self._pools.values()]) + + def fetch_all_vols(): + ret = [] +- for pool in self.pools.values(): ++ for pool in self._pools.values(): + for vol in pool.get_volumes(refresh=False).values(): + try: + ret.append(vol.get_xmlobj(refresh_if_nec=False)) +@@ -287,14 +290,14 @@ + handle_id = vmmGObject.connect(self, name, callback, *args) + + if name == "vm-added": +- for uuid in self.vms.keys(): +- self.emit("vm-added", uuid) ++ for connkey in self._vms.keys(): ++ self.emit("vm-added", connkey) + elif name == "mediadev-added": +- for dev in self.mediadevs.values(): ++ for dev in self._mediadevs.values(): + self.emit("mediadev-added", dev) + elif name == "nodedev-added": +- for key in self.nodedevs.keys(): +- self.emit("nodedev-added", key) ++ for connkey in self._nodedevs.keys(): ++ self.emit("nodedev-added", connkey) + + return handle_id + +@@ -581,6 +584,23 @@ + + return self._get_flags_helper(iface, key, check_func) + ++ def get_default_pool(self): ++ for p in self._pools.values(): ++ if p.get_name() == "default": ++ return p ++ return None ++ ++ def get_vol_by_path(self, path): ++ # path_exists will handle stuff like refreshing a busted pool ++ if not virtinst.VirtualDisk.path_exists(self.get_backend(), path): ++ return None ++ ++ for pool in self._pools.values(): ++ for vol in pool.get_volumes().values(): ++ if vol.get_target_path() == path: ++ return vol ++ return None ++ + + ################################### + # Connection state getter/setters # +@@ -628,6 +648,7 @@ + def is_connecting(self): + return self.state == self.STATE_CONNECTING + ++ + ################################# + # Libvirt object lookup methods # + ################################# +@@ -659,7 +680,7 @@ + if mac: + netdev_list[name].mac = mac + +- for name, iface in self.interfaces.items(): ++ for name, iface in self._interfaces.items(): + interface_to_netdev(iface) + + for nodedev in self.get_nodedevs("net"): +@@ -679,21 +700,37 @@ + # XXX: How to handle added/removed signals to clients? + return netdev_list + +- def get_vm(self, uuid): +- return self.vms[uuid] +- def get_net(self, uuid): +- return self.nets[uuid] +- def get_net_device(self, path): +- return self.netdevs[path] +- def get_pool(self, uuid): +- return self.pools[uuid] +- def get_interface(self, name): +- return self.interfaces[name] +- def get_nodedev(self, name): +- return self.nodedevs[name] ++ def list_netdevs(self): ++ # Update netdev list ++ if self.netdev_use_libvirt: ++ self._netdevs = self._build_libvirt_netdev_list() ++ return self._netdevs.values() ++ ++ def get_vm(self, connkey): ++ return self._vms[connkey] ++ def list_vms(self): ++ return self._vms.values() ++ ++ def get_net(self, connkey): ++ return self._nets[connkey] ++ def list_nets(self): ++ return self._nets.values() ++ ++ def get_pool(self, connkey): ++ return self._pools[connkey] ++ def list_pools(self): ++ return self._pools.values() ++ ++ def get_interface(self, connkey): ++ return self._interfaces[connkey] ++ def list_interfaces(self): ++ return self._interfaces.values() ++ ++ def get_nodedev(self, connkey): ++ return self._nodedevs[connkey] + def get_nodedevs(self, devtype=None, devcap=None): + retdevs = [] +- for dev in self.nodedevs.values(): ++ for dev in self._nodedevs.values(): + xmlobj = dev.get_xmlobj() + if devtype and xmlobj.device_type != devtype: + continue +@@ -731,46 +768,6 @@ + + return count + +- def get_net_by_name(self, name): +- for net in self.nets.values(): +- if net.get_name() == name: +- return net +- +- def get_pool_by_path(self, path): +- for pool in self.pools.values(): +- if pool.get_target_path() == path: +- return pool +- return None +- +- def get_pool_by_name(self, name): +- for p in self.pools.values(): +- if p.get_name() == name: +- return p +- return None +- def get_default_pool(self): +- return self.get_pool_by_name("default") +- +- def get_vol_by_path(self, path): +- for pool in self.pools.values(): +- for vol in pool.get_volumes().values(): +- if vol.get_target_path() == path: +- return vol +- return None +- +- def list_vm_uuids(self): +- return self.vms.keys() +- def list_net_uuids(self): +- return self.nets.keys() +- def list_net_device_paths(self): +- # Update netdev list +- if self.netdev_use_libvirt: +- self.netdevs = self._build_libvirt_netdev_list() +- return self.netdevs.keys() +- def list_pool_uuids(self): +- return self.pools.keys() +- def list_interface_names(self): +- return self.interfaces.keys() +- + + ################################### + # Libvirt object creation methods # +@@ -840,11 +837,21 @@ + # event driven setup is hard, so we end up doing more polling than + # necessary on most events. + ++ def _domain_xml_misc_event(self, conn, domain, *args): ++ # Just trigger a domain XML refresh for hotplug type events ++ ignore = conn ++ ignore = args ++ ++ obj = self._vms.get(domain.name(), None) ++ if not obj: ++ return ++ self.idle_add(obj.refresh_xml, True) ++ + def _domain_lifecycle_event(self, conn, domain, event, reason, userdata): + ignore = conn + ignore = reason + ignore = userdata +- obj = self.vms.get(domain.UUIDString(), None) ++ obj = self._vms.get(domain.name(), None) + + if obj: + # If the domain disappeared, this will catch it and trigger +@@ -860,7 +867,7 @@ + ignore = conn + ignore = reason + ignore = userdata +- obj = self.nets.get(network.UUIDString(), None) ++ obj = self._nets.get(network.name(), None) + + if obj: + self.idle_add(obj.force_update_status, True) +@@ -872,19 +879,47 @@ + + def _add_conn_events(self): + try: +- self._domain_cb_id = self.get_backend().domainEventRegisterAny( ++ if _disable_libvirt_events: ++ raise RuntimeError("_disable_libvirt_events = True") ++ ++ self._domain_cb_ids.append( ++ self.get_backend().domainEventRegisterAny( + None, libvirt.VIR_DOMAIN_EVENT_ID_LIFECYCLE, +- self._domain_lifecycle_event, None) ++ self._domain_lifecycle_event, None)) + self.using_domain_events = True + logging.debug("Using domain events") + except Exception, e: + self.using_domain_events = False + logging.debug("Error registering domain events: %s", e) + ++ def _add_domain_xml_event(eventid, typestr): ++ if not self.using_domain_events: ++ return ++ try: ++ self._domain_cb_ids.append( ++ self.get_backend().domainEventRegisterAny( ++ None, eventid, self._domain_xml_misc_event, None)) ++ except Exception, e: ++ logging.debug("Error registering domain %s event: %s", ++ typestr, e) ++ ++ _add_domain_xml_event( ++ getattr(libvirt, "VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE", 13), ++ "balloon") ++ _add_domain_xml_event( ++ getattr(libvirt, "VIR_DOMAIN_EVENT_ID_TRAY_CHANGE", 10), "tray") ++ _add_domain_xml_event( ++ getattr(libvirt, "VIR_DOMAIN_EVENT_ID_DEVICE_REMOVED", 15), ++ "device removed") ++ + try: ++ if _disable_libvirt_events: ++ raise RuntimeError("_disable_libvirt_events = True") ++ + eventid = getattr(libvirt, "VIR_NETWORK_EVENT_ID_LIFECYCLE", 0) +- self._network_cb_id = self.get_backend().networkEventRegisterAny( +- None, eventid, self._network_lifecycle_event, None) ++ self._network_cb_ids.append( ++ self.get_backend().networkEventRegisterAny( ++ None, eventid, self._network_lifecycle_event, None)) + self.using_network_events = True + logging.debug("Using network events") + except Exception, e: +@@ -897,7 +932,7 @@ + #################### + + def _nodedev_mediadev_added(self, ignore1, name): +- if name in self.mediadevs: ++ if name in self._mediadevs: + return + + vobj = self.get_nodedev(name) +@@ -905,15 +940,17 @@ + if not mediadev: + return + +- self.mediadevs[name] = mediadev ++ self._mediadevs[name] = mediadev ++ logging.debug("mediadev=%s added", name) + self.emit("mediadev-added", mediadev) + + def _nodedev_mediadev_removed(self, ignore1, name): +- if name not in self.mediadevs: ++ if name not in self._mediadevs: + return + +- self.mediadevs[name].cleanup() +- del(self.mediadevs[name]) ++ self._mediadevs[name].cleanup() ++ del(self._mediadevs[name]) ++ logging.debug("mediadev=%s removed", name) + self.emit("mediadev-removed", name) + + +@@ -927,6 +964,10 @@ + self.config.set_conn_autoconnect(self.get_uri(), val) + + def close(self): ++ if self.state != self.STATE_DISCONNECTED: ++ logging.debug("conn.close() uri=%s", self.get_uri()) ++ self._closing = True ++ + def cleanup(devs): + for dev in devs.values(): + try: +@@ -936,54 +977,53 @@ + + try: + if not self._backend.is_closed(): +- if self._domain_cb_id is not None: +- self._backend.domainEventDeregisterAny( +- self._domain_cb_id) +- self._domain_cb_id = None +- +- if self._network_cb_id is not None: +- self._backend.networkEventDeregisterAny( +- self._network_cb_id) +- self._network_cb_id = None ++ for eid in self._domain_cb_ids: ++ self._backend.domainEventDeregisterAny(eid) ++ for eid in self._network_cb_ids: ++ self._backend.networkEventDeregisterAny(eid) + except: + logging.debug("Failed to deregister events in conn cleanup", + exc_info=True) ++ finally: ++ self._domain_cb_ids = [] ++ self._network_cb_ids = [] + + self._backend.close() + self.record = [] + +- cleanup(self.nodedevs) +- self.nodedevs = {} ++ cleanup(self._nodedevs) ++ self._nodedevs = {} + +- cleanup(self.netdevs) +- self.netdevs = {} ++ cleanup(self._netdevs) ++ self._netdevs = {} + +- cleanup(self.mediadevs) +- self.mediadevs = {} ++ cleanup(self._mediadevs) ++ self._mediadevs = {} + +- cleanup(self.interfaces) +- self.interfaces = {} ++ cleanup(self._interfaces) ++ self._interfaces = {} + +- cleanup(self.pools) +- self.pools = {} ++ cleanup(self._pools) ++ self._pools = {} + +- cleanup(self.nets) +- self.nets = {} ++ cleanup(self._nets) ++ self._nets = {} + +- cleanup(self.vms) +- self.vms = {} ++ cleanup(self._vms) ++ self._vms = {} + + self._change_state(self.STATE_DISCONNECTED) ++ self._closing = False + + def _cleanup(self): + self.close() +- self.connectError = None ++ self._connectError = None + + def open(self, sync=False): + if self.state != self.STATE_DISCONNECTED: + return + +- self.connectError = None ++ self._connectError = None + self._change_state(self.STATE_CONNECTING) + + if sync: +@@ -993,17 +1033,17 @@ + else: + logging.debug("Scheduling background open thread for " + + self.get_uri()) +- self.connectThread = threading.Thread(target=self._open_thread, ++ self._connectThread = threading.Thread(target=self._open_thread, + name="Connect %s" % self.get_uri()) +- self.connectThread.setDaemon(True) +- self.connectThread.start() ++ self._connectThread.setDaemon(True) ++ self._connectThread.start() + + def _do_creds_password(self, creds): + try: + return connectauth.creds_dialog(creds) + except Exception, e: + # Detailed error message, in English so it can be Googled. +- self.connectError = ( ++ self._connectError = ( + "Failed to get credentials for '%s':\n%s\n%s" % + (self.get_uri(), str(e), "".join(traceback.format_exc()))) + return -1 +@@ -1055,14 +1095,14 @@ + if connectauth.acquire_tgt(): + continue + +- self.connectError = (str(exc), tb, warnconsole) ++ self._connectError = (str(exc), tb, warnconsole) + break + + # We want to kill off this thread asap, so schedule an + # idle event to inform the UI of result + logging.debug("Background open thread complete, scheduling notify") + self.idle_add(self._open_notify) +- self.connectThread = None ++ self._connectThread = None + + def _open_notify(self): + logging.debug("Notifying open result") +@@ -1085,9 +1125,9 @@ + force=True) + + if self.state == self.STATE_DISCONNECTED: +- if self.connectError: +- self.idle_emit("connect-error", *self.connectError) +- self.connectError = None ++ if self._connectError: ++ self.idle_emit("connect-error", *self._connectError) ++ self._connectError = None + + + ####################### +@@ -1096,33 +1136,33 @@ + + def _update_nets(self, dopoll): + if not dopoll or not self.is_network_capable(): +- return {}, {}, self.nets +- return pollhelpers.fetch_nets(self._backend, self.nets.copy(), ++ return {}, {}, self._nets ++ return pollhelpers.fetch_nets(self._backend, self._nets.copy(), + (lambda obj, key: vmmNetwork(self, obj, key))) + + def _update_pools(self, dopoll): + if not dopoll or not self.is_storage_capable(): +- return {}, {}, self.pools +- return pollhelpers.fetch_pools(self._backend, self.pools.copy(), ++ return {}, {}, self._pools ++ return pollhelpers.fetch_pools(self._backend, self._pools.copy(), + (lambda obj, key: vmmStoragePool(self, obj, key))) + + def _update_interfaces(self, dopoll): + if not dopoll or not self.is_interface_capable(): +- return {}, {}, self.interfaces ++ return {}, {}, self._interfaces + return pollhelpers.fetch_interfaces(self._backend, +- self.interfaces.copy(), ++ self._interfaces.copy(), + (lambda obj, key: vmmInterface(self, obj, key))) + + def _update_nodedevs(self, dopoll): + if not dopoll or not self.is_nodedev_capable(): +- return {}, {}, self.nodedevs +- return pollhelpers.fetch_nodedevs(self._backend, self.nodedevs.copy(), ++ return {}, {}, self._nodedevs ++ return pollhelpers.fetch_nodedevs(self._backend, self._nodedevs.copy(), + (lambda obj, key: vmmNodeDevice(self, obj, key))) + + def _update_vms(self, dopoll): + if not dopoll: +- return {}, {}, self.vms +- return pollhelpers.fetch_vms(self._backend, self.vms.copy(), ++ return {}, {}, self._vms ++ return pollhelpers.fetch_vms(self._backend, self._vms.copy(), + (lambda obj, key: vmmDomain(self, obj, key))) + + +@@ -1136,7 +1176,43 @@ + kwargs["stats_update"] = False + self.idle_emit("priority-tick", kwargs) + +- def tick(self, stats_update, ++ def tick(self, *args, **kwargs): ++ e = None ++ try: ++ self._tick(*args, **kwargs) ++ except KeyboardInterrupt: ++ raise ++ except Exception, e: ++ pass ++ ++ if e is None: ++ return ++ ++ from_remote = getattr(libvirt, "VIR_FROM_REMOTE", None) ++ from_rpc = getattr(libvirt, "VIR_FROM_RPC", None) ++ sys_error = getattr(libvirt, "VIR_ERR_SYSTEM_ERROR", None) ++ ++ dom = -1 ++ code = -1 ++ if isinstance(e, libvirt.libvirtError): ++ dom = e.get_error_domain() ++ code = e.get_error_code() ++ ++ logging.debug("Error polling connection %s", ++ self.get_uri(), exc_info=True) ++ ++ if (dom in [from_remote, from_rpc] and ++ code in [sys_error]): ++ e = None ++ logging.debug("Not showing user error since libvirtd " ++ "appears to have stopped.") ++ ++ self._closing = True ++ self.idle_add(self.close) ++ if e: ++ raise e # pylint: disable=raising-bad-type ++ ++ def _tick(self, stats_update, + pollvm=False, pollnet=False, + pollpool=False, polliface=False, + pollnodedev=False, pollmedia=False, +@@ -1145,7 +1221,7 @@ + main update function: polls for new objects, updates stats, ... + @force: Perform the requested polling even if async events are in use + """ +- if self.state != self.STATE_ACTIVE: ++ if self.state != self.STATE_ACTIVE or self._closing: + return + + if not pollvm: +@@ -1177,15 +1253,15 @@ + return + + if pollvm: +- self.vms = vms ++ self._vms = vms + if pollnet: +- self.nets = nets ++ self._nets = nets + if polliface: +- self.interfaces = interfaces ++ self._interfaces = interfaces + if pollpool: +- self.pools = pools ++ self._pools = pools + if pollnodedev: +- self.nodedevs = nodedevs ++ self._nodedevs = nodedevs + + # Make sure device polling is setup + if not self.netdev_initialized: +@@ -1195,40 +1271,48 @@ + self._init_mediadev() + + # Update VM states +- for uuid, obj in goneVMs.items(): +- self.emit("vm-removed", uuid) ++ for connkey, obj in goneVMs.items(): ++ logging.debug("domain=%s removed", obj.get_name()) ++ self.emit("vm-removed", connkey) + obj.cleanup() +- for uuid, obj in newVMs.items(): +- ignore = obj +- self.emit("vm-added", uuid) ++ for connkey, obj in newVMs.items(): ++ logging.debug("domain=%s status=%s added", ++ obj.get_name(), obj.run_status()) ++ self.emit("vm-added", connkey) + + # Update virtual network states +- for uuid, obj in goneNets.items(): +- self.emit("net-removed", uuid) ++ for connkey, obj in goneNets.items(): ++ logging.debug("network=%s removed", obj.get_name()) ++ self.emit("net-removed", connkey) + obj.cleanup() +- for uuid, obj in newNets.items(): ++ for connkey, obj in newNets.items(): ++ logging.debug("network=%s added", obj.get_name()) + obj.connect("started", self._obj_signal_proxy, +- "net-started", uuid) ++ "net-started", connkey) + obj.connect("stopped", self._obj_signal_proxy, +- "net-stopped", uuid) +- self.emit("net-added", uuid) ++ "net-stopped", connkey) ++ self.emit("net-added", connkey) + + # Update storage pool states +- for uuid, obj in gonePools.items(): +- self.emit("pool-removed", uuid) ++ for connkey, obj in gonePools.items(): ++ logging.debug("pool=%s removed", obj.get_name()) ++ self.emit("pool-removed", connkey) + obj.cleanup() +- for uuid, obj in newPools.items(): ++ for connkey, obj in newPools.items(): ++ logging.debug("pool=%s added", obj.get_name()) + obj.connect("started", self._obj_signal_proxy, +- "pool-started", uuid) ++ "pool-started", connkey) + obj.connect("stopped", self._obj_signal_proxy, +- "pool-stopped", uuid) +- self.emit("pool-added", uuid) ++ "pool-stopped", connkey) ++ self.emit("pool-added", connkey) + + # Update interface states + for name, obj in goneInterfaces.items(): ++ logging.debug("interface=%s removed", obj.get_name()) + self.emit("interface-removed", name) + obj.cleanup() + for name, obj in newInterfaces.items(): ++ logging.debug("interface=%s added", obj.get_name()) + obj.connect("started", self._obj_signal_proxy, + "interface-started", name) + obj.connect("stopped", self._obj_signal_proxy, +@@ -1267,7 +1351,7 @@ + if pollnodedev: + add_to_ticklist(nodedevs.values()) + if pollmedia: +- add_to_ticklist(self.mediadevs.values()) ++ add_to_ticklist(self._mediadevs.values()) + + for obj, args in ticklist: + try: +diff -urN virt-manager-1.0.1/virtManager/connect.py virt-manager/virtManager/connect.py +--- virt-manager-1.0.1/virtManager/connect.py 2014-02-18 22:43:05.000000000 +0000 ++++ virt-manager/virtManager/connect.py 2014-06-12 11:22:21.154891895 +0000 +@@ -22,11 +22,9 @@ + import logging + import socket + +-# pylint: disable=E0611 + from gi.repository import Gio + from gi.repository import GObject + from gi.repository import Gtk +-# pylint: enable=E0611 + + from virtManager import uiutil + from virtManager.baseclass import vmmGObjectUI +@@ -34,7 +32,8 @@ + (HV_QEMU, + HV_XEN, + HV_LXC, +-HV_QEMU_SESSION) = range(4) ++HV_QEMU_SESSION, ++HV_BHYVE) = range(5) + + (CONN_SSH, + CONN_TCP, +@@ -155,6 +154,8 @@ + model.append(["Xen"]) + model.append(["LXC (Linux Containers)"]) + model.append(["QEMU/KVM user session"]) ++ if self.config.with_bhyve: ++ model.append(["Bhyve"]) + combo.set_model(model) + uiutil.set_combo_text_column(combo, 0) + +@@ -366,6 +367,8 @@ + hvstr = "xen" + elif hv == HV_QEMU or hv == HV_QEMU_SESSION: + hvstr = "qemu" ++ elif hv == HV_BHYVE: ++ hvstr = "bhyve" + else: + hvstr = "lxc" + +@@ -387,7 +390,7 @@ + hoststr += addrstr + "/" + + uri = hvstr + hoststr +- if hv == HV_QEMU: ++ if hv in (HV_QEMU, HV_BHYVE): + uri += "system" + elif hv == HV_QEMU_SESSION: + uri += "session" +diff -urN virt-manager-1.0.1/virtManager/console.py virt-manager/virtManager/console.py +--- virt-manager-1.0.1/virtManager/console.py 2014-03-22 14:56:43.000000000 +0000 ++++ virt-manager/virtManager/console.py 2014-06-12 11:22:21.155891895 +0000 +@@ -20,14 +20,12 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import GObject + from gi.repository import Gtk + from gi.repository import Gdk + from gi.repository import GtkVnc + from gi.repository import SpiceClientGtk + from gi.repository import SpiceClientGLib +-# pylint: enable=E0611 + + import libvirt + +@@ -282,7 +280,7 @@ + os.dup(self._outfds[1].fileno()) + os.dup(self._errfds[1].fileno()) + os.execlp(*argv) +- os._exit(1) # pylint: disable=W0212 ++ os._exit(1) # pylint: disable=protected-access + else: + self._outfds[1].close() + self._errfds[1].close() +@@ -466,7 +464,6 @@ + + def set_grab_keyboard(self): + self.display.set_keyboard_grab(self.config.get_grab_keyboard()) +- self.display.force_grab(self.config.get_grab_keyboard()) + + def _desktop_resize(self, src_ignore, w, h): + self.desktop_resolution = (w, h) +@@ -1401,7 +1398,7 @@ + logging.debug("Viewer connected") + self.activate_viewer_page() + +- # Had a succesfull connect, so reset counters now ++ # Had a successful connect, so reset counters now + self.viewerRetriesScheduled = 0 + self.viewerRetryDelay = 125 + +@@ -1549,7 +1546,7 @@ + + if not self.force_resize and is_resizeguest: + # With resize guest, we don't want to maintain aspect ratio, +- # since the guest can resize to arbitray resolutions. ++ # since the guest can resize to arbitrary resolutions. + self.viewer.display.set_size_request(req.width, req.height) + return + +diff -urN virt-manager-1.0.1/virtManager/createinterface.py virt-manager/virtManager/createinterface.py +--- virt-manager-1.0.1/virtManager/createinterface.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/createinterface.py 2014-06-12 11:22:21.157891895 +0000 +@@ -18,10 +18,8 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import Gtk + from gi.repository import Gdk +-# pylint: enable=E0611 + + import logging + +@@ -168,8 +166,7 @@ + @staticmethod + def iface_in_use_by(conn, name): + use_str = "" +- for i in conn.list_interface_names(): +- iface = conn.get_interface(i) ++ for iface in conn.list_interfaces(): + if name in iface.get_slave_names(): + if use_str: + use_str += ", " +@@ -511,8 +508,8 @@ + phys.address] + + row_dict = {} +- for name in self.conn.list_interface_names(): +- iface = self.conn.get_interface(name) ++ for iface in self.conn.list_interfaces(): ++ name = iface.get_name() + key = iface.get_xmlobj() + iface_type = iface.get_type() + active = iface.is_active() +@@ -764,7 +761,7 @@ + def build_ip_info(self): + def build_ip(addr_str): + if not addr_str: +- return None, None ++ raise ValueError(_("Please enter an IP address")) + ret = addr_str.rsplit("/", 1) + address = ret[0] + prefix = None +@@ -775,7 +772,7 @@ + is_manual = self.widget("ip-do-manual").get_active() + + copy_row = uiutil.get_list_selection( +- self.widget("ip-copy-interface-combo")) ++ self.widget("ip-copy-interface-combo"), None) + + v4_mode = self.widget("ipv4-mode").get_active() + v4_addr = self.widget("ipv4-address").get_text() +@@ -818,9 +815,10 @@ + if not ipv6.dhcp: + if v6_gate: + ipv6.gateway = v6_gate +- addr, prefix = build_ip(v4_addr) +- if addr: +- ipv6.add_ip(addr, prefix) ++ for v6_addr in v6_addrlist: ++ addr, prefix = build_ip(v6_addr) ++ if addr: ++ ipv6.add_ip(addr, prefix) + + return [is_manual, copy_name, ipv4, ipv6, proto_xml] + +diff -urN virt-manager-1.0.1/virtManager/createnet.py virt-manager/virtManager/createnet.py +--- virt-manager-1.0.1/virtManager/createnet.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/createnet.py 2014-06-12 11:22:21.157891895 +0000 +@@ -23,10 +23,8 @@ + + import ipaddr + +-# pylint: disable=E0611 + from gi.repository import Gtk + from gi.repository import Gdk +-# pylint: enable=E0611 + + from virtinst import Network + +@@ -171,10 +169,9 @@ + fw_model = self.widget("net-forward").get_model() + fw_model.clear() + fw_model.append([_("Any physical device"), None]) +- for path in self.conn.list_net_device_paths(): +- net = self.conn.get_net_device(path) +- fw_model.append([_("Physical device %s") % (net.get_name()), +- net.get_name()]) ++ for netdev in self.conn.list_netdevs(): ++ fw_model.append([_("Physical device %s") % (netdev.get_name()), ++ netdev.get_name()]) + + self.widget("net-forward").set_active(0) + self.widget("net-forward-mode").set_active(0) +@@ -268,9 +265,13 @@ + return self.err.val_err(_("Invalid Network Address"), + _("The network must be an IPv4 address")) + +- if ip.numhosts < 16: ++ if ip.numhosts < 8: + return self.err.val_err(_("Invalid Network Address"), +- _("The network must address at least 16 addresses.")) ++ _("The network must address at least 8 addresses.")) ++ ++ if ip.prefixlen < 15: ++ return self.err.val_err(_("Invalid Network Address"), ++ _("The network prefix must be >= 15")) + + if not ip.is_private: + res = self.err.yes_no(_("Check Network Address"), +@@ -562,7 +563,7 @@ + src.modify_bg(Gtk.StateType.NORMAL, _red) + return + +- valid_ip = (ip.numhosts >= 16 and ip.is_private) ++ valid_ip = (ip.numhosts >= 8 and ip.is_private) + gateway = (ip.prefixlen != 32 and str(ip.network + 1) or "") + info = (ip.is_private and _("Private") or _("Other/Public")) + start = int(ip.numhosts / 2) +diff -urN virt-manager-1.0.1/virtManager/createpool.py virt-manager/virtManager/createpool.py +--- virt-manager-1.0.1/virtManager/createpool.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/createpool.py 2014-06-12 11:22:21.158891895 +0000 +@@ -1,5 +1,5 @@ + # +-# Copyright (C) 2008, 2013 Red Hat, Inc. ++# Copyright (C) 2008, 2013, 2014 Red Hat, Inc. + # Copyright (C) 2008 Cole Robinson + # + # This program is free software; you can redistribute it and/or modify +@@ -18,10 +18,8 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import Gtk + from gi.repository import Gdk +-# pylint: enable=E0611 + + import logging + +@@ -263,7 +261,7 @@ + iqn = self._pool.supports_property("iqn") + builddef, buildsens = self.get_build_default() + +- # Source path broswing is meaningless for net pools ++ # Source path browsing is meaningless for net pools + if self._pool.type in [StoragePool.TYPE_NETFS, + StoragePool.TYPE_ISCSI, + StoragePool.TYPE_SCSI]: +@@ -277,6 +275,11 @@ + show_row("pool-iqn", iqn) + show_row("pool-source-name", src_name) + ++ if iqn: ++ self.widget("pool-source-label").set_label(_("_Source IQN:")) ++ else: ++ self.widget("pool-source-label").set_label(_("_Source Path:")) ++ + if tgt: + self.widget("pool-target-path").get_child().set_text( + self._pool.target_path) +diff -urN virt-manager-1.0.1/virtManager/create.py virt-manager/virtManager/create.py +--- virt-manager-1.0.1/virtManager/create.py 2014-03-20 18:04:29.000000000 +0000 ++++ virt-manager/virtManager/create.py 2014-06-12 11:22:21.156891895 +0000 +@@ -22,11 +22,9 @@ + import threading + import time + +-# pylint: disable=E0611 + from gi.repository import GObject + from gi.repository import Gtk + from gi.repository import Gdk +-# pylint: enable=E0611 + + import virtinst + from virtinst import util +@@ -132,7 +130,7 @@ + "on_install_url_box_changed": self.url_box_changed, + "on_install_local_cdrom_toggled": self.toggle_local_cdrom, + "on_install_local_cdrom_combo_changed": self.detect_media_os, +- "on_install_local_box_changed": self.detect_media_os, ++ "on_install_local_box_changed": self.local_box_changed, + "on_install_local_browse_clicked": self.browse_iso, + "on_install_import_browse_clicked": self.browse_import, + "on_install_app_browse_clicked": self.browse_app, +@@ -297,6 +295,12 @@ + uiutil.set_combo_text_column(os_variant_list, 1) + os_variant_list.set_row_separator_func(sep_func, os_variant_list) + ++ entry = self.widget("install-os-version-entry") ++ completion = Gtk.EntryCompletion() ++ entry.set_completion(completion) ++ completion.set_text_column(1) ++ completion.set_inline_completion(True) ++ + # Archtecture + # [value, label] + archList = self.widget("config-arch") +@@ -379,13 +383,21 @@ + # Install container OS + self.widget("install-oscontainer-fs").set_text("") + +- # Mem / CPUs +- self.widget("config-mem").set_value(DEFAULT_MEM) +- self.widget("config-cpus").set_value(1) +- + # Storage + self.widget("enable-storage").set_active(True) + self.addstorage.reset_state() ++ self.addstorage.widget("config-storage-create").set_active(True) ++ self.addstorage.widget("config-storage-entry").set_text("") ++ self.addstorage.widget("config-storage-nosparse").set_active(True) ++ ++ fmt = self.conn.get_default_storage_format() ++ can_alloc = fmt in ["raw"] ++ self.addstorage.widget("config-storage-nosparse").set_active(can_alloc) ++ self.addstorage.widget("config-storage-nosparse").set_sensitive(can_alloc) ++ self.addstorage.widget("config-storage-nosparse").set_tooltip_text( ++ not can_alloc and ++ (_("Disk format '%s' does not support full allocation.") % fmt) or ++ "") + + # Final page + self.widget("summary-customize").set_active(False) +@@ -543,6 +555,11 @@ + + self.mediacombo = vmmMediaCombo(self.conn, self.builder, self.topwin, + MEDIA_CDROM) ++ def mediacombo_changed(src): ++ ignore = src ++ self.mediaDetected = False ++ self.detect_media_os() ++ self.mediacombo.combo.connect("changed", mediacombo_changed) + self.mediacombo.reset_state() + self.widget("install-local-cdrom-align").add( + self.mediacombo.top_box) +@@ -844,6 +861,9 @@ + # Add action option + self._add_os_row(model, label=_("Show all OS options"), action=True) + ++ completion = self.widget("install-os-version-entry").get_completion() ++ completion.set_model(model) ++ + def populate_media_model(self, model, urls): + model.clear() + if urls is not None: +@@ -875,7 +895,7 @@ + self.set_caps_state() + + def populate_summary(self): +- distro, version, dlabel, vlabel = self.get_config_os_info() ++ distro, version, ignore1, dlabel, vlabel = self.get_config_os_info() + mem = self.pretty_memory(int(self.guest.memory)) + cpu = str(int(self.guest.vcpus)) + +@@ -935,8 +955,8 @@ + return self.widget("create-vm-name").get_text() + + def get_config_machine(self): +- return uiutil.get_list_selection(self.widget("config-machine"), +- rowindex=0, check_visible=True) ++ return uiutil.get_list_selection(self.widget("config-machine"), 0, ++ check_visible=True) + + def is_install_page(self): + notebook = self.widget("create-pages") +@@ -960,12 +980,24 @@ + return INSTALL_PAGE_CONTAINER_OS + + def get_config_os_info(self): +- drow = uiutil.get_list_selection(self.widget("install-os-type")) +- vrow = uiutil.get_list_selection(self.widget("install-os-version")) ++ drow = uiutil.get_list_selection( ++ self.widget("install-os-type"), None) ++ vrow = uiutil.get_list_selection( ++ self.widget("install-os-version"), None) + distro = None + dlabel = None + variant = None +- vlabel = None ++ variant_found = False ++ vlabel = self.widget("install-os-version-entry").get_text() ++ ++ for i in self.widget("install-os-version").get_model(): ++ if not i[2] and not i[3] and i[1] == vlabel: ++ variant = i[0] ++ variant_found = True ++ break ++ ++ if vlabel and not variant_found: ++ return (None, None, False, None, None) + + if drow: + distro = drow[0] +@@ -976,6 +1008,7 @@ + + return (distro and str(distro), + variant and str(variant), ++ True, + str(dlabel), str(vlabel)) + + def get_config_local_media(self, store_media=False): +@@ -1074,7 +1107,7 @@ + + if row: + ntype = row[0] +- key = row[6] ++ connkey = row[6] + + expand = (ntype != "network" and ntype != "bridge") + if (ntype is None or +@@ -1083,7 +1116,7 @@ + elif ntype != virtinst.VirtualNetworkInterface.TYPE_VIRTUAL: + show_pxe_warn = False + else: +- obj = self.conn.get_net(key) ++ obj = self.conn.get_net(connkey) + show_pxe_warn = not obj.can_pxe() + + show_warn = (show_pxe_warn and pxe_install) +@@ -1109,16 +1142,22 @@ + + self.change_caps(self.capsguest.os_type, arch) + +- def url_box_changed(self, ignore): ++ def media_box_changed(self, widget): + self.mediaDetected = False + +- # If the url_entry has focus, don't fire detect_media_os, it means ++ # If the widget has focus, don't fire detect_media_os, it means + # the user is probably typing +- if self.widget("install-url-box").get_child().has_focus(): ++ if self.widget(widget).get_child().has_focus(): + return + + self.detect_media_os() + ++ def url_box_changed(self, ignore): ++ self.media_box_changed("install-url-box") ++ ++ def local_box_changed(self, ignore): ++ self.media_box_changed("install-local-box") ++ + def should_detect_media(self): + return (self.is_detect_active() and not self.mediaDetected) + +@@ -1138,11 +1177,13 @@ + self.widget("install-os-version").set_visible(not dodetect) + + if dodetect: ++ self.widget("install-os-version-entry").set_text("") + self.mediaDetected = False + self.detect_media_os() + + def _selected_os_row(self): +- return uiutil.get_list_selection(self.widget("install-os-type")) ++ return uiutil.get_list_selection( ++ self.widget("install-os-type"), None) + + def change_os_type(self, box): + ignore = box +@@ -1155,8 +1196,8 @@ + self.populate_os_type_model() + return + +- variant = self.widget("install-os-version") +- variant.set_active(0) ++ self.widget("install-os-version-entry").set_text("") ++ self.widget("install-os-version-entry").grab_focus() + + def change_os_version(self, box): + show_all = uiutil.get_list_selection(box, 3) +@@ -1167,6 +1208,7 @@ + type_row = self._selected_os_row() + if not type_row: + return ++ old_type = type_row[0] + + self.show_all_os = True + self.populate_os_type_model() +@@ -1174,7 +1216,7 @@ + os_type_list = self.widget("install-os-type") + os_type_model = os_type_list.get_model() + for idx in range(len(os_type_model)): +- if os_type_model[idx][0] == type_row[0]: ++ if os_type_model[idx][0] == old_type: + os_type_list.set_active(idx) + break + +@@ -1182,6 +1224,7 @@ + is_active = src.get_active() + if is_active and self.mediacombo.get_path(): + # Local CDROM was selected with media preset, detect distro ++ self.mediaDetected = False + self.detect_media_os() + + self.widget("install-local-cdrom-align").set_sensitive(is_active) +@@ -1190,6 +1233,8 @@ + uselocal = src.get_active() + self.widget("install-local-box").set_sensitive(uselocal) + self.widget("install-local-browse").set_sensitive(uselocal) ++ self.mediaDetected = False ++ self.detect_media_os() + + def detect_visibility_changed(self, src, ignore=None): + is_visible = src.get_visible() +@@ -1241,11 +1286,7 @@ + INSTALL_PAGE_CONTAINER_OS] + osbox.set_visible(iscontainer) + +- # Detection only works/ is valid for URL, +- # FIXME: Also works for CDROM if running as root (since we need to +- # mount the iso/cdrom), but we should probably make this work for +- # more distros (like windows) before we enable it +- if (instpage == INSTALL_PAGE_URL): ++ if instpage in (INSTALL_PAGE_ISO, INSTALL_PAGE_URL): + detectbox.show() + else: + detectbox.hide() +@@ -1295,7 +1336,8 @@ + if self.have_startup_error: + return + +- if curpage == PAGE_INSTALL and self.should_detect_media(): ++ if (curpage == PAGE_INSTALL and self.should_detect_media() ++ and self.get_config_detectable_media()): + # Make sure we have detected the OS before validating the page + self.detect_media_os(forward=True) + return +@@ -1325,20 +1367,24 @@ + self.widget("header-pagenum").set_markup(page_lbl) + + def page_changed(self, ignore1, ignore2, pagenum): +- # Update page number +- self.set_page_num_text(pagenum) +- +- self.widget("create-back").set_sensitive(pagenum != PAGE_NAME) +- self.widget("create-forward").set_visible(pagenum != PAGE_FINISH) +- self.widget("create-finish").set_visible(pagenum == PAGE_FINISH) +- + if pagenum == PAGE_INSTALL: + self.detect_media_os() + self.widget("install-os-distro-box").set_visible( + not self.container_install()) + elif pagenum == PAGE_FINISH: ++ try: ++ self.populate_summary() ++ except Exception, e: ++ self.err.show_err(_("Error populating summary page: %s") % ++ str(e)) ++ return ++ + self.widget("create-finish").grab_focus() +- self.populate_summary() ++ ++ self.set_page_num_text(pagenum) ++ self.widget("create-back").set_sensitive(pagenum != PAGE_NAME) ++ self.widget("create-forward").set_visible(pagenum != PAGE_FINISH) ++ self.widget("create-finish").set_visible(pagenum == PAGE_FINISH) + + for nr in range(self.widget("create-pages").get_n_pages()): + page = self.widget("create-pages").get_nth_page(nr) +@@ -1434,7 +1480,7 @@ + self.conn.get_backend().lookupByName, + start_num=force_num and 1 or 2, force_num=force_num, + sep=not force_num and "-" or "", +- collidelist=[vm.get_name() for vm in self.conn.vms.values()]) ++ collidelist=[vm.get_name() for vm in self.conn.list_vms()]) + + def validate_install_page(self): + instmethod = self.get_config_install_page() +@@ -1446,7 +1492,10 @@ + is_import = False + init = None + fs = None +- distro, variant, ignore1, ignore2 = self.get_config_os_info() ++ distro, variant, valid, ignore1, ignore2 = self.get_config_os_info() ++ ++ if not valid: ++ return self.err.val_err(_("Please specify a valid OS variant.")) + + if instmethod == INSTALL_PAGE_ISO: + instclass = virtinst.DistroInstaller +@@ -1583,6 +1632,24 @@ + self.addstorage.check_path_search( + self, self.conn, path) + ++ res = virtinst.osdict.get_recommended_resources(variant, self.capsguest.arch) ++ ++ # Change the default values suggested to the user. ++ ram_size = DEFAULT_MEM ++ if res and res.get("ram") > 0: ++ ram_size = res["ram"] / (1024 ** 2) ++ self.widget("config-mem").set_value(ram_size) ++ ++ n_cpus = 1 ++ if res and res.get("n-cpus") > 0: ++ n_cpus = res["n-cpus"] ++ self.widget("config-cpus").set_value(n_cpus) ++ ++ storage_size = 8 ++ if res and res.get("storage"): ++ storage_size = int(res["storage"]) / (1024 ** 3) ++ self.addstorage.widget("config-storage-size").set_value(storage_size) ++ + # Validation passed, store the install path (if there is one) in + # gconf + self.get_config_local_media(store_media=True) +@@ -1762,7 +1829,7 @@ + self.close() + + # Launch details dialog for new VM +- self.emit("action-show-domain", self.conn.get_uri(), self.guest.uuid) ++ self.emit("action-show-domain", self.conn.get_uri(), self.guest.name) + + + def start_install(self, guest): +@@ -1789,11 +1856,20 @@ + # Wait for VM to show up + self.conn.schedule_priority_tick(pollvm=True) + count = 0 +- while (guest.uuid not in self.conn.vms) and (count < 100): ++ foundvm = None ++ while count < 100: ++ for vm in self.conn.list_vms(): ++ if vm.get_uuid() == guest.uuid: ++ foundvm = vm ++ if foundvm: ++ break + count += 1 + time.sleep(.1) + +- vm = self.conn.get_vm(guest.uuid) ++ if not foundvm: ++ raise RuntimeError( ++ _("VM '%s' didn't show up after expected time.") % guest.name) ++ vm = foundvm + vm.tick() + + if vm.is_shutoff(): +@@ -1866,36 +1942,19 @@ + # Helper method to set the OS Type/Variant selections to the passed + # values, or -1 if not present. + model = os_widget.get_model() +- + def set_val(): +- idx = 0 +- for idx in range(0, len(model)): ++ for idx in range(len(model)): + row = model[idx] + if value and row[0] == value: +- break +- +- if idx == len(os_widget.get_model()) - 1: +- idx = -1 +- +- os_widget.set_active(idx) +- if idx == -1: +- os_widget.set_active(0) +- +- if idx >= 0: +- return row[1] +- if self.show_all_os: +- return None ++ os_widget.set_active(idx) ++ return row[1] ++ os_widget.set_active(0) + + ret = set_val() +- if ret: +- return ret +- +- # Trigger the last element in the list, which turns on show_all_os +- os_widget.set_active(len(model) - 1) +- ret = set_val() +- if ret: +- return ret +- return _("Unknown") ++ if not ret and not self.show_all_os: ++ os_widget.set_active(len(model) - 1) ++ ret = set_val() ++ return ret or _("Unknown") + + def set_distro_selection(self, variant): + # Wrapper to change OS Type/Variant values, and update the distro +diff -urN virt-manager-1.0.1/virtManager/createvol.py virt-manager/virtManager/createvol.py +--- virt-manager-1.0.1/virtManager/createvol.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/createvol.py 2014-06-12 11:22:21.158891895 +0000 +@@ -20,11 +20,9 @@ + + import logging + +-# pylint: disable=E0611 + from gi.repository import GObject + from gi.repository import Gtk + from gi.repository import Gdk +-# pylint: enable=E0611 + + from virtManager import uiutil + from virtManager.baseclass import vmmGObjectUI +@@ -283,9 +281,6 @@ + self.show_err(_("Uncaught error validating input: %s") % str(e)) + return + +- logging.debug("Creating volume with xml:\n%s", +- self.vol.get_xml_config()) +- + self.topwin.set_sensitive(False) + self.topwin.get_window().set_cursor( + Gdk.Cursor.new(Gdk.CursorType.WATCH)) +diff -urN virt-manager-1.0.1/virtManager/delete.py virt-manager/virtManager/delete.py +--- virt-manager-1.0.1/virtManager/delete.py 2014-03-10 15:17:52.000000000 +0000 ++++ virt-manager/virtManager/delete.py 2014-06-12 11:22:21.158891895 +0000 +@@ -18,10 +18,8 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import Gtk + from gi.repository import Gdk +-# pylint: enable=E0611 + + import os + import stat +diff -urN virt-manager-1.0.1/virtManager/details.py virt-manager/virtManager/details.py +--- virt-manager-1.0.1/virtManager/details.py 2014-03-22 21:58:14.000000000 +0000 ++++ virt-manager/virtManager/details.py 2014-06-12 11:22:21.162891895 +0000 +@@ -21,11 +21,9 @@ + import logging + import traceback + +-# pylint: disable=E0611 + from gi.repository import GObject + from gi.repository import Gtk + from gi.repository import Gdk +-# pylint: enable=E0611 + + import libvirt + +@@ -349,6 +347,8 @@ + return _("Tablet") + elif dev.type == "mouse": + return _("Mouse") ++ elif dev.type == "keyboard": ++ return _("Keyboard") + return _("Input") + + if devtype in ["serial", "parallel", "console"]: +@@ -435,6 +435,12 @@ + return typemap[devtype] + + ++def _chipset_label_from_machine(machine): ++ if machine and "q35" in machine: ++ return "Q35" ++ return "i440FX" ++ ++ + class vmmDetails(vmmGObjectUI): + __gsignals__ = { + "action-save-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), +@@ -530,6 +536,7 @@ + + self.oldhwkey = None + self.addhwmenu = None ++ self._addhwmenuitems = None + self.keycombo_menu = None + self.init_menus() + self.init_details() +@@ -584,6 +591,7 @@ + "on_overview_name_changed": lambda *x: self.enable_apply(x, EDIT_NAME), + "on_overview_title_changed": lambda *x: self.enable_apply(x, EDIT_TITLE), + "on_machine_type_changed": lambda *x: self.enable_apply(x, EDIT_MACHTYPE), ++ "on_overview_chipset_changed": lambda *x: self.enable_apply(x, EDIT_MACHTYPE), + "on_idmap_uid_target_changed": lambda *x: self.enable_apply(x, EDIT_IDMAP), + "on_idmap_uid_count_changed": lambda *x: self.enable_apply(x, EDIT_IDMAP), + "on_idmap_gid_target_changed": lambda *x: self.enable_apply(x, EDIT_IDMAP), +@@ -618,6 +626,7 @@ + "on_boot_initrd_browse_clicked": self.browse_initrd, + "on_boot_dtb_browse_clicked": self.browse_dtb, + "on_boot_init_path_changed": lambda *x: self.enable_apply(x, EDIT_INIT), ++ "on_boot_init_args_changed": lambda *x: self.enable_apply(x, EDIT_INIT), + + "on_disk_readonly_changed": lambda *x: self.enable_apply(x, EDIT_DISK_RO), + "on_disk_shareable_changed": lambda *x: self.enable_apply(x, EDIT_DISK_SHARE), +@@ -625,7 +634,7 @@ + "on_disk_cache_combo_changed": lambda *x: self.enable_apply(x, EDIT_DISK_CACHE), + "on_disk_io_combo_changed": lambda *x: self.enable_apply(x, EDIT_DISK_IO), + "on_disk_bus_combo_changed": lambda *x: self.enable_apply(x, EDIT_DISK_BUS), +- "on_disk_format_changed": lambda *x: self.enable_apply(x, EDIT_DISK_FORMAT), ++ "on_disk_format_changed": self.disk_format_changed, + "on_disk_serial_changed": lambda *x: self.enable_apply(x, EDIT_DISK_SERIAL), + "on_disk_iotune_changed": self.iotune_changed, + +@@ -706,6 +715,7 @@ + self.vm = None + self.conn = None + self.addhwmenu = None ++ self._addhwmenuitems = None + + self.gfxdetails.cleanup() + self.gfxdetails = None +@@ -778,7 +788,7 @@ + show_open=False) + for child in submenu.get_children(): + submenu.remove(child) +- newmenu.add(child) # pylint: disable=E1101 ++ newmenu.add(child) + topmenu.set_submenu(newmenu) + topmenu.show_all() + +@@ -801,8 +811,9 @@ + rmHW.show() + rmHW.connect("activate", self.remove_xml_dev) + +- self.addhwmenu.add(addHW) +- self.addhwmenu.add(rmHW) ++ self._addhwmenuitems = {"add" : addHW, "remove" : rmHW} ++ for i in self._addhwmenuitems.values(): ++ self.addhwmenu.add(i) + + # Don't allowing changing network/disks for Dom0 + dom0 = self.vm.is_management_domain() +@@ -883,30 +894,56 @@ + uiutil.set_combo_text_column(machtype_combo, 0) + machtype_model.set_sort_column_id(0, Gtk.SortType.ASCENDING) + ++ machines = [] ++ try: ++ ignore, domain = caps.guest_lookup( ++ os_type=self.vm.get_abi_type(), ++ arch=self.vm.get_arch(), ++ typ=self.vm.get_hv_type(), ++ machine=self.vm.get_machtype()) ++ ++ machines = domain.machines[:] ++ except: ++ logging.exception("Error determining machine list") ++ + show_machine = (arch not in ["i686", "x86_64"] and + not self.vm.is_management_domain()) +- uiutil.set_grid_row_visible(self.widget("machine-type"), +- show_machine) ++ uiutil.set_grid_row_visible(self.widget("machine-type"), show_machine) + + if show_machine: +- machines = [] +- +- try: +- ignore, domain = caps.guest_lookup( +- os_type=self.vm.get_abi_type(), +- arch=self.vm.get_arch(), +- typ=self.vm.get_hv_type(), +- machine=self.vm.get_machtype()) +- +- machines = domain.machines[:] +- except: +- logging.exception("Error determining machine list") +- + for machine in machines: + if machine == "none": + continue + machtype_model.append([machine]) + ++ # Chipset ++ combo = self.widget("overview-chipset") ++ model = Gtk.ListStore(str, str) ++ combo.set_model(model) ++ model.append([_chipset_label_from_machine("pc"), "pc"]) ++ if "q35" in machines: ++ model.append([_chipset_label_from_machine("q35"), "q35"]) ++ combo.set_active(0) ++ ++ def chipset_changed(*args): ++ ignore = args ++ combo = self.widget("overview-chipset") ++ model = combo.get_model() ++ show_warn = (combo.get_active() >= 0 and ++ model[combo.get_active()][1] == "q35") ++ uiutil.set_grid_row_visible( ++ self.widget("overview-chipset-warn-box"), show_warn) ++ combo.connect("changed", chipset_changed) ++ ++ self.widget("overview-chipset").set_visible(self.is_customize_dialog) ++ self.widget("overview-chipset-label").set_visible( ++ not self.is_customize_dialog) ++ show_chipset = ((self.conn.is_qemu() or self.conn.is_test_conn()) and ++ arch in ["i686", "x86_64"] and ++ not self.vm.is_management_domain()) ++ uiutil.set_grid_row_visible( ++ self.widget("overview-chipset-title"), show_chipset) ++ + # Inspection page + apps_list = self.widget("inspection-apps") + apps_model = Gtk.ListStore(str, str, str) +@@ -1075,6 +1112,22 @@ + if event.button != 3: + return + ++ devobj = self.get_hw_selection(HW_LIST_COL_DEVICE) ++ if not devobj: ++ return ++ ++ # force select the list entry before showing popup_menu ++ path_tuple = widget.get_path_at_pos(int(event.x), int(event.y)) ++ if path_tuple is None: ++ return False ++ path = path_tuple[0] ++ _iter = widget.get_model().get_iter(path) ++ widget.get_selection().select_iter(_iter) ++ ++ rmdev = self._addhwmenuitems["remove"] ++ rmdev.set_visible(self.widget("config-remove").get_visible()) ++ rmdev.set_sensitive(self.widget("config-remove").get_sensitive()) ++ + self.addhwmenu.popup(None, None, None, None, 0, event.time) + + def control_fullscreen(self, src): +@@ -1096,7 +1149,7 @@ + self.widget("toolbar-box").hide() + + def get_boot_selection(self): +- return uiutil.get_list_selection(self.widget("config-boot-list")) ++ return uiutil.get_list_selection(self.widget("config-boot-list"), None) + + def set_hw_selection(self, page, disable_apply=True): + if disable_apply: +@@ -1104,7 +1157,7 @@ + uiutil.set_list_selection(self.widget("hw-list"), page) + + def get_hw_row(self): +- return uiutil.get_list_selection(self.widget("hw-list")) ++ return uiutil.get_list_selection(self.widget("hw-list"), None) + + def get_hw_selection(self, field): + row = self.get_hw_row() +@@ -1433,11 +1486,11 @@ + if not self.vm.is_paused(): + self.emit("action-suspend-domain", + self.vm.conn.get_uri(), +- self.vm.get_uuid()) ++ self.vm.get_connkey()) + else: + self.emit("action-resume-domain", + self.vm.conn.get_uri(), +- self.vm.get_uuid()) ++ self.vm.get_connkey()) + + def control_vm_menu(self, src_ignore): + can_usb = bool(self.console.viewer and +@@ -1447,39 +1500,39 @@ + + def control_vm_run(self, src_ignore): + self.emit("action-run-domain", +- self.vm.conn.get_uri(), self.vm.get_uuid()) ++ self.vm.conn.get_uri(), self.vm.get_connkey()) + + def control_vm_shutdown(self, src_ignore): + self.emit("action-shutdown-domain", +- self.vm.conn.get_uri(), self.vm.get_uuid()) ++ self.vm.conn.get_uri(), self.vm.get_connkey()) + + def control_vm_reboot(self, src_ignore): + self.emit("action-reboot-domain", +- self.vm.conn.get_uri(), self.vm.get_uuid()) ++ self.vm.conn.get_uri(), self.vm.get_connkey()) + + def control_vm_save(self, src_ignore): + self.emit("action-save-domain", +- self.vm.conn.get_uri(), self.vm.get_uuid()) ++ self.vm.conn.get_uri(), self.vm.get_connkey()) + + def control_vm_reset(self, src_ignore): + self.emit("action-reset-domain", +- self.vm.conn.get_uri(), self.vm.get_uuid()) ++ self.vm.conn.get_uri(), self.vm.get_connkey()) + + def control_vm_destroy(self, src_ignore): + self.emit("action-destroy-domain", +- self.vm.conn.get_uri(), self.vm.get_uuid()) ++ self.vm.conn.get_uri(), self.vm.get_connkey()) + + def control_vm_clone(self, src_ignore): + self.emit("action-clone-domain", +- self.vm.conn.get_uri(), self.vm.get_uuid()) ++ self.vm.conn.get_uri(), self.vm.get_connkey()) + + def control_vm_migrate(self, src_ignore): + self.emit("action-migrate-domain", +- self.vm.conn.get_uri(), self.vm.get_uuid()) ++ self.vm.conn.get_uri(), self.vm.get_connkey()) + + def control_vm_delete(self, src_ignore): + self.emit("action-delete-domain", +- self.vm.conn.get_uri(), self.vm.get_uuid()) ++ self.vm.conn.get_uri(), self.vm.get_connkey()) + + def control_vm_screenshot(self, src): + ignore = src +@@ -1787,6 +1840,10 @@ + boot_list.get_selection().emit("changed") + self.enable_apply(EDIT_BOOTORDER) + ++ def disk_format_changed(self, ignore): ++ self.widget("disk-format-warn").show() ++ self.enable_apply(EDIT_DISK_FORMAT) ++ + # IO Tuning + def iotune_changed(self, ignore): + iotune_rbs = int(self.get_text("disk-iotune-rbs") or 0) +@@ -1958,8 +2015,12 @@ + hotplug_args["title"] = kwargs["title"] + + if self.edited(EDIT_MACHTYPE): +- kwargs["machine"] = uiutil.get_combo_entry( +- self.widget("machine-type")) ++ if self.widget("overview-chipset").is_visible(): ++ kwargs["machine"] = uiutil.get_list_selection( ++ self.widget("overview-chipset"), 1) ++ else: ++ kwargs["machine"] = uiutil.get_combo_entry( ++ self.widget("machine-type")) + + if self.edited(EDIT_DESC): + desc_widget = self.widget("overview-description") +@@ -2068,6 +2129,7 @@ + + if self.edited(EDIT_INIT): + kwargs["init"] = self.get_text("boot-init-path") ++ kwargs["initargs"] = self.get_text("boot-init-args") or "" + if not kwargs["init"]: + return self.err.val_err(_("An init path must be specified")) + +@@ -2169,7 +2231,8 @@ + kwargs["addrstr"] = addrstr + + if self.edited(EDIT_NET_SOURCE): +- kwargs["ntype"], kwargs["source"], kwargs["mode"] = ( ++ (kwargs["ntype"], kwargs["source"], ++ kwargs["mode"], kwargs["portgroup"]) = ( + self.netlist.get_network_selection()) + + if self.edited(EDIT_NET_VPORT): +@@ -2418,10 +2481,17 @@ + + # Machine settings + machtype = self.vm.get_machtype() +- if not arch in ["i686", "x86_64"]: ++ if arch not in ["i686", "x86_64"]: + if machtype is not None: + uiutil.set_combo_entry(self.widget("machine-type"), machtype) + ++ chipset = _chipset_label_from_machine(machtype) ++ if self.widget("overview-chipset").is_visible(): ++ uiutil.set_combo_entry( ++ self.widget("overview-chipset"), chipset) ++ elif self.widget("overview-chipset-label").is_visible(): ++ self.widget("overview-chipset-label").set_text(chipset) ++ + # User namespace idmap setting + is_container = self.vm.is_container() + self.widget("config-idmap-expander").set_visible(is_container) +@@ -2533,6 +2603,12 @@ + self.vm.network_traffic_vector()) + + def refresh_config_cpu(self): ++ # This bit needs to come first, since CPU values can be affected ++ # by whether topology is enabled ++ cpu = self.vm.get_cpu_config() ++ show_top = bool(cpu.sockets or cpu.cores or cpu.threads) ++ self.widget("cpu-topology-enable").set_active(show_top) ++ + conn = self.vm.conn + host_active_count = conn.host_active_processor_count() + maxvcpus = self.vm.vcpu_max_count() +@@ -2550,13 +2626,10 @@ + self.widget("config-vcpus-warn-box").set_visible(warn) + + # CPU model config +- cpu = self.vm.get_cpu_config() +- show_top = bool(cpu.sockets or cpu.cores or cpu.threads) + sockets = cpu.sockets or 1 + cores = cpu.cores or 1 + threads = cpu.threads or 1 + +- self.widget("cpu-topology-enable").set_active(show_top) + self.widget("cpu-sockets").set_value(sockets) + self.widget("cpu-cores").set_value(cores) + self.widget("cpu-threads").set_value(threads) +@@ -2679,6 +2752,7 @@ + + self.widget("disk-format").set_sensitive(show_format) + self.widget("disk-format").get_child().set_text(driver_type) ++ self.widget("disk-format-warn").hide() + + no_default = not self.is_customize_dialog + +@@ -2730,19 +2804,24 @@ + dev = _("Xen Mouse") + elif ident == "mouse:ps2": + dev = _("PS/2 Mouse") ++ elif ident == "keyboard:ps2": ++ dev = _("PS/2 Keyboard") + else: + dev = inp.bus + " " + inp.type + ++ mode = None + if inp.type == "tablet": + mode = _("Absolute Movement") +- else: ++ elif inp.type == "mouse": + mode = _("Relative Movement") + + self.widget("input-dev-type").set_text(dev) +- self.widget("input-dev-mode").set_text(mode) ++ self.widget("input-dev-mode").set_text(mode or "") ++ uiutil.set_grid_row_visible(self.widget("input-dev-mode"), bool(mode)) + + # Can't remove primary Xen or PS/2 mice +- if inp.type == "mouse" and inp.bus in ("xen", "ps2"): ++ if ((inp.type == "mouse" and inp.bus in ("xen", "ps2")) or ++ (inp.type == "keyboard" and inp.bus in ("xen", "ps2"))): + self.widget("config-remove").set_sensitive(False) + else: + self.widget("config-remove").set_sensitive(True) +@@ -3018,21 +3097,11 @@ + combo = self.widget("controller-model") + uiutil.set_grid_row_visible(combo, True) + +- model = combo.get_model() +- model.clear() +- if dev.type == virtinst.VirtualController.TYPE_USB: +- model.append(["default", "Default"]) +- model.append(["ich9-ehci1", "USB 2"]) +- model.append(["nec-xhci", "USB 3"]) +- self.widget("config-remove").set_sensitive(False) +- if dev.type == virtinst.VirtualController.TYPE_SCSI: +- model.append(["default", "Default"]) +- model.append(["virtio-scsi", "VirtIO SCSI"]) +- else: +- self.widget("config-remove").set_sensitive(True) ++ vmmAddHardware.populate_controller_model_combo(combo, dev.type, ++ self.widget("config-remove"), False) + + uiutil.set_combo_entry(self.widget("controller-model"), +- dev.model or "default") ++ dev.model or "Default") + + def refresh_filesystem_page(self): + dev = self.get_hw_selection(HW_LIST_COL_DEVICE) +@@ -3100,8 +3169,9 @@ + self.widget("boot-dtb-box").set_visible(show_dtb) + + # populate +- init = self.vm.get_init() ++ init, initargs = self.vm.get_init() + self.widget("boot-init-path").set_text(init or "") ++ self.widget("boot-init-args").set_text(initargs or "") + + # Boot menu populate + menu = self.vm.get_boot_menu() or False +diff -urN virt-manager-1.0.1/virtManager/domain.py virt-manager/virtManager/domain.py +--- virt-manager-1.0.1/virtManager/domain.py 2014-03-22 22:16:55.000000000 +0000 ++++ virt-manager/virtManager/domain.py 2014-06-12 11:22:21.163891895 +0000 +@@ -18,9 +18,7 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import GObject +-# pylint: enable=E0611 + + import logging + import os +@@ -173,8 +171,9 @@ + + self.refresh_xml() + +- def get_name(self): +- return self.get_xmlobj().name ++ def _backend_get_name(self): ++ return self._backend.getName() ++ + def _XMLDesc(self, flags): + return self._backend.getXMLDesc(flags=flags) + +@@ -284,7 +283,6 @@ + def __init__(self, conn, backend, key): + vmmLibvirtObject.__init__(self, conn, backend, key, Guest) + +- self.uuid = key + self.cloning = False + + self.record = [] +@@ -299,7 +297,7 @@ + self.reboot_listener = None + self._is_management_domain = None + self._id = None +- self._name = None ++ self._uuid = None + self._snapshot_list = None + + self.lastStatus = libvirt.VIR_DOMAIN_SHUTOFF +@@ -361,7 +359,7 @@ + self.toggle_sample_mem_stats() + self.toggle_sample_cpu_stats() + +- self.force_update_status(from_event=True) ++ self.force_update_status(from_event=True, log=False) + + # Hook up listeners that need to be cleaned up + self.add_gconf_handle( +@@ -414,11 +412,6 @@ + def _using_events(self): + return self.conn.using_domain_events + +- def get_name(self): +- if self._name is None: +- self._name = self._backend.name() +- return self._name +- + def get_id(self): + if self._id is None: + self._id = self._backend.ID() +@@ -645,7 +638,7 @@ + + def define_boot(self, boot_order=_SENTINEL, boot_menu=_SENTINEL, + kernel=_SENTINEL, initrd=_SENTINEL, dtb=_SENTINEL, +- kernel_args=_SENTINEL, init=_SENTINEL): ++ kernel_args=_SENTINEL, init=_SENTINEL, initargs=_SENTINEL): + + def _change_boot_order(guest): + boot_dev_order = [] +@@ -681,6 +674,7 @@ + guest.os.enable_bootmenu = bool(boot_menu) + if init != _SENTINEL: + guest.os.init = init ++ guest.os.set_initargs_string(initargs) + + if kernel != _SENTINEL: + guest.os.kernel = kernel or None +@@ -768,7 +762,8 @@ + ntype=_SENTINEL, source=_SENTINEL, + mode=_SENTINEL, model=_SENTINEL, addrstr=_SENTINEL, + vtype=_SENTINEL, managerid=_SENTINEL, typeid=_SENTINEL, +- typeidversion=_SENTINEL, instanceid=_SENTINEL): ++ typeidversion=_SENTINEL, instanceid=_SENTINEL, ++ portgroup=_SENTINEL): + + def change(editdev): + if ntype != _SENTINEL: +@@ -777,6 +772,7 @@ + editdev.type = ntype + editdev.source = source + editdev.source_mode = mode or None ++ editdev.portgroup = portgroup or None + + if model != _SENTINEL: + if editdev.model != model: +@@ -1065,7 +1061,9 @@ + return self.get_xmlobj().os.is_hvm() + + def get_uuid(self): +- return self.uuid ++ if self._uuid is None: ++ self._uuid = self._backend.UUIDString() ++ return self._uuid + def get_abi_type(self): + return self.get_xmlobj().os.os_type + def get_hv_type(self): +@@ -1075,7 +1073,12 @@ + def get_arch(self): + return self.get_xmlobj().os.arch + def get_init(self): +- return self.get_xmlobj().os.init ++ import pipes ++ init = self.get_xmlobj().os.init ++ initargs = " ".join( ++ [pipes.quote(i.val) for i in self.get_xmlobj().os.initargs]) ++ return init, initargs ++ + def get_emulator(self): + return self.get_xmlobj().emulator + def get_machtype(self): +@@ -1675,7 +1678,7 @@ + status = libvirt.VIR_DOMAIN_NOSTATE + return vm_status_icons[status] + +- def force_update_status(self, from_event=False): ++ def force_update_status(self, from_event=False, log=True): + """ + Fetch current domain state and clear status cache + """ +@@ -1684,12 +1687,16 @@ + + try: + info = self._backend.info() ++ if log: ++ logging.debug("domain=%s status changed to %d=%s", ++ self.get_name(), info[0], self.pretty_run_status(info[0])) ++ + self._update_status(info[0]) +- except libvirt.libvirtError: ++ except libvirt.libvirtError, e: + # Transient domain might have disappeared, tell the connection + # to update the domain list +- logging.debug("force_update_status: Triggering domain " +- "list refresh") ++ logging.debug("Error setting domain status: %s\nDomain might " ++ "have disappeared, triggering connection tick", e) + self.conn.schedule_priority_tick(pollvm=True, force=True) + + def _update_status(self, status): +@@ -1722,37 +1729,37 @@ + ################## + + def on_console_scaling_changed(self, *args, **kwargs): +- return self.config.listen_pervm(self.uuid, "/scaling", ++ return self.config.listen_pervm(self.get_uuid(), "/scaling", + *args, **kwargs) + def set_console_scaling(self, value): +- self.config.set_pervm(self.uuid, "/scaling", value) ++ self.config.set_pervm(self.get_uuid(), "/scaling", value) + def get_console_scaling(self): +- ret = self.config.get_pervm(self.uuid, "/scaling") ++ ret = self.config.get_pervm(self.get_uuid(), "/scaling") + if ret == -1: + return self.config.get_console_scaling() + return ret + + def on_console_resizeguest_changed(self, *args, **kwargs): +- return self.config.listen_pervm(self.uuid, "/resize-guest", ++ return self.config.listen_pervm(self.get_uuid(), "/resize-guest", + *args, **kwargs) + def set_console_resizeguest(self, value): +- self.config.set_pervm(self.uuid, "/resize-guest", value) ++ self.config.set_pervm(self.get_uuid(), "/resize-guest", value) + def get_console_resizeguest(self): +- ret = self.config.get_pervm(self.uuid, "/resize-guest") ++ ret = self.config.get_pervm(self.get_uuid(), "/resize-guest") + if ret == -1: + return self.config.get_console_resizeguest() + return ret + + def set_details_window_size(self, w, h): +- self.config.set_pervm(self.uuid, "/vm-window-size", (w, h)) ++ self.config.set_pervm(self.get_uuid(), "/vm-window-size", (w, h)) + def get_details_window_size(self): +- ret = self.config.get_pervm(self.uuid, "/vm-window-size") ++ ret = self.config.get_pervm(self.get_uuid(), "/vm-window-size") + return ret + + def get_console_password(self): +- return self.config.get_pervm(self.uuid, "/console-password") ++ return self.config.get_pervm(self.get_uuid(), "/console-password") + def set_console_password(self, username, keyid): +- return self.config.set_pervm(self.uuid, "/console-password", ++ return self.config.set_pervm(self.get_uuid(), "/console-password", + (username, keyid)) + + def get_cache_dir(self): +@@ -1953,6 +1960,8 @@ + + def get_name(self): + return self._backend.name ++ def get_uuid(self): ++ return self._backend.uuid + def get_id(self): + return -1 + def hasSavedImage(self): +diff -urN virt-manager-1.0.1/virtManager/engine.py virt-manager/virtManager/engine.py +--- virt-manager-1.0.1/virtManager/engine.py 2014-02-28 18:01:44.000000000 +0000 ++++ virt-manager/virtManager/engine.py 2014-06-12 11:22:21.163891895 +0000 +@@ -18,18 +18,16 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import GLib + from gi.repository import GObject + from gi.repository import Gtk +-# pylint: enable=E0611 + + import logging + import re + import Queue + import threading ++import traceback + +-import libvirt + from virtinst import util + + from virtManager import packageutils +@@ -276,13 +274,13 @@ + thread.start() + + +- def _do_vm_removed(self, conn, vmuuid): ++ def _do_vm_removed(self, conn, connkey): + hvuri = conn.get_uri() +- if vmuuid not in self.conns[hvuri]["windowDetails"]: ++ if connkey not in self.conns[hvuri]["windowDetails"]: + return + +- self.conns[hvuri]["windowDetails"][vmuuid].cleanup() +- del(self.conns[hvuri]["windowDetails"][vmuuid]) ++ self.conns[hvuri]["windowDetails"][connkey].cleanup() ++ del(self.conns[hvuri]["windowDetails"][connkey]) + + def _do_conn_changed(self, conn): + if (conn.get_state() == conn.STATE_ACTIVE or +@@ -291,9 +289,9 @@ + + hvuri = conn.get_uri() + +- for vmuuid in self.conns[hvuri]["windowDetails"].keys(): +- self.conns[hvuri]["windowDetails"][vmuuid].cleanup() +- del(self.conns[hvuri]["windowDetails"][vmuuid]) ++ for connkey in self.conns[hvuri]["windowDetails"].keys(): ++ self.conns[hvuri]["windowDetails"][connkey].cleanup() ++ del(self.conns[hvuri]["windowDetails"][connkey]) + + if (self.windowCreate and + self.windowCreate.conn and +@@ -338,46 +336,19 @@ + + def _handle_tick_queue(self): + while True: +- ignore1, ignore2, obj, kwargs = self._tick_queue.get() +- self._tick_single_conn(obj, kwargs) ++ ignore1, ignore2, conn, kwargs = self._tick_queue.get() ++ try: ++ conn.tick(**kwargs) ++ except Exception, e: ++ tb = "".join(traceback.format_exc()) ++ error_msg = (_("Error polling connection '%s': %s") ++ % (conn.get_uri(), e)) ++ self.idle_add(lambda: self.err.show_err(error_msg, ++ details=tb)) ++ + self._tick_queue.task_done() + return 1 + +- def _tick_single_conn(self, conn, kwargs): +- e = None +- try: +- conn.tick(**kwargs) +- except KeyboardInterrupt: +- raise +- except Exception, e: +- pass +- +- if e is None: +- return +- +- from_remote = getattr(libvirt, "VIR_FROM_REMOTE", None) +- from_rpc = getattr(libvirt, "VIR_FROM_RPC", None) +- sys_error = getattr(libvirt, "VIR_ERR_SYSTEM_ERROR", None) +- +- dom = -1 +- code = -1 +- if isinstance(e, libvirt.libvirtError): +- dom = e.get_error_domain() +- code = e.get_error_code() +- +- if (dom in [from_remote, from_rpc] and +- code in [sys_error]): +- logging.exception("Could not refresh connection %s", +- conn.get_uri()) +- logging.debug("Closing connection since libvirtd " +- "appears to have stopped") +- else: +- error_msg = _("Error polling connection '%s': %s") \ +- % (conn.get_uri(), e) +- self.idle_add(lambda: self.err.show_err(error_msg)) +- +- self.idle_add(conn.close) +- + + def increment_window_counter(self, src): + ignore = src +@@ -700,8 +671,8 @@ + if self.conns[uri]["windowHost"]: + return self.conns[uri]["windowHost"] + +- con = self._lookup_conn(uri) +- obj = vmmHost(con) ++ conn = self._lookup_conn(uri) ++ obj = vmmHost(conn) + + obj.connect("action-exit-app", self.exit_app) + obj.connect("action-view-manager", self._do_show_manager) +@@ -751,13 +722,13 @@ + self.remove_conn(None, connection.get_uri()) + + +- def _get_details_dialog(self, uri, uuid): +- if uuid in self.conns[uri]["windowDetails"]: +- return self.conns[uri]["windowDetails"][uuid] ++ def _get_details_dialog(self, uri, connkey): ++ if connkey in self.conns[uri]["windowDetails"]: ++ return self.conns[uri]["windowDetails"][connkey] + +- con = self._lookup_conn(uri) ++ conn = self._lookup_conn(uri) + +- obj = vmmDetails(con.get_vm(uuid)) ++ obj = vmmDetails(conn.get_vm(connkey)) + obj.connect("action-save-domain", self._do_save_domain) + obj.connect("action-destroy-domain", self._do_destroy_domain) + obj.connect("action-reset-domain", self._do_reset_domain) +@@ -774,33 +745,12 @@ + obj.connect("details-opened", self.increment_window_counter) + obj.connect("details-closed", self.decrement_window_counter) + +- self.conns[uri]["windowDetails"][uuid] = obj +- return self.conns[uri]["windowDetails"][uuid] ++ self.conns[uri]["windowDetails"][connkey] = obj ++ return self.conns[uri]["windowDetails"][connkey] + +- def _find_vm_by_id(self, uri, domstr): +- vms = self.conns[uri]["conn"].vms +- if domstr in vms: +- return domstr +- for vm in vms.values(): +- if domstr.isdigit(): +- if int(domstr) == vm.get_id(): +- return vm.get_uuid() +- elif domstr == vm.get_name(): +- return vm.get_uuid() +- +- def _show_vm_helper(self, src, uri, domstr, page=None, forcepage=False): ++ def _show_vm_helper(self, src, uri, vm, page, forcepage): + try: +- uuid = self._find_vm_by_id(uri, domstr) +- if not uuid: +- # This will only happen if --show-* option was used during +- # virt-manager launch and an invalid UUID is passed. +- # The error message must be sync otherwise the user will not +- # know why the application ended. +- self.err.show_err("%s does not have VM '%s'" % +- (uri, domstr), modal=True) +- return +- +- details = self._get_details_dialog(uri, uuid) ++ details = self._get_details_dialog(uri, vm.get_connkey()) + + if forcepage or not details.is_visible(): + if page == DETAILS_PERF: +@@ -819,8 +769,10 @@ + if self._can_exit(): + self.idle_add(self.exit_app, src) + +- def _do_show_vm(self, src, uri, uuid): +- self._show_vm_helper(src, uri, uuid) ++ def _do_show_vm(self, src, uri, connkey): ++ conn = self._lookup_conn(uri) ++ vm = conn.get_vm(connkey) ++ self._show_vm_helper(src, uri, vm, None, False) + + def get_manager(self): + if self.windowManager: +@@ -887,10 +839,10 @@ + except Exception, e: + src.err.show_err(_("Error launching manager: %s") % str(e)) + +- def _do_show_migrate(self, src, uri, uuid): ++ def _do_show_migrate(self, src, uri, connkey): + try: + conn = self._lookup_conn(uri) +- vm = conn.get_vm(uuid) ++ vm = conn.get_vm(connkey) + + if not self.windowMigrate: + self.windowMigrate = vmmMigrateDialog(vm, self) +@@ -900,9 +852,9 @@ + except Exception, e: + src.err.show_err(_("Error launching migrate dialog: %s") % str(e)) + +- def _do_show_clone(self, src, uri, uuid): +- con = self._lookup_conn(uri) +- orig_vm = con.get_vm(uuid) ++ def _do_show_clone(self, src, uri, connkey): ++ conn = self._lookup_conn(uri) ++ orig_vm = conn.get_vm(connkey) + clone_window = self.conns[uri]["windowClone"] + + try: +@@ -930,26 +882,51 @@ + self.show_manager() + self._do_show_create(self.get_manager(), uri) + +- def show_domain_console(self, uri, uuid): +- self.idle_add(self._show_vm_helper, self.get_manager(), uri, uuid, +- page=DETAILS_CONSOLE, forcepage=True) +- +- def show_domain_editor(self, uri, uuid): +- self.idle_add(self._show_vm_helper, self.get_manager(), uri, uuid, +- page=DETAILS_CONFIG, forcepage=True) +- +- def show_domain_performance(self, uri, uuid): +- self.idle_add(self._show_vm_helper, self.get_manager(), uri, uuid, +- page=DETAILS_PERF, forcepage=True) ++ ++ def _find_vm_by_cli_str(self, uri, clistr): ++ """ ++ Lookup a VM by a string passed in on the CLI. Can be either ++ ID, domain name, or UUID ++ """ ++ if clistr.isdigit(): ++ clistr = int(clistr) ++ ++ for vm in self.conns[uri]["conn"].list_vms(): ++ if clistr == vm.get_id(): ++ return vm ++ elif clistr == vm.get_name(): ++ return vm ++ elif clistr == vm.get_uuid(): ++ return vm ++ ++ def _cli_show_vm_helper(self, uri, clistr, page): ++ src = self.get_manager() ++ ++ vm = self._find_vm_by_cli_str(uri, clistr) ++ if not vm: ++ src.err.show_err("%s does not have VM '%s'" % ++ (uri, clistr), modal=True) ++ return ++ ++ self._show_vm_helper(src, uri, vm, page, True) ++ ++ def show_domain_console(self, uri, clistr): ++ self.idle_add(self._cli_show_vm_helper, uri, clistr, DETAILS_CONSOLE) ++ ++ def show_domain_editor(self, uri, clistr): ++ self.idle_add(self._cli_show_vm_helper, uri, clistr, DETAILS_CONFIG) ++ ++ def show_domain_performance(self, uri, clistr): ++ self.idle_add(self._cli_show_vm_helper, uri, clistr, DETAILS_PERF) + + + ####################################### + # Domain actions run/destroy/save ... # + ####################################### + +- def _do_save_domain(self, src, uri, uuid): ++ def _do_save_domain(self, src, uri, connkey): + conn = self._lookup_conn(uri) +- vm = conn.get_vm(uuid) ++ vm = conn.get_vm(connkey) + managed = bool(vm.managedsave_supported) + + if not managed and conn.is_remote(): +@@ -1022,9 +999,9 @@ + vmmAsyncJob.simple_async_noshow(conn.restore, [path], src, + _("Error restoring domain")) + +- def _do_destroy_domain(self, src, uri, uuid): ++ def _do_destroy_domain(self, src, uri, connkey): + conn = self._lookup_conn(uri) +- vm = conn.get_vm(uuid) ++ vm = conn.get_vm(connkey) + + if not src.err.chkbox_helper( + self.config.get_confirm_forcepoweroff, +@@ -1039,9 +1016,9 @@ + vmmAsyncJob.simple_async_noshow(vm.destroy, [], src, + _("Error shutting down domain")) + +- def _do_suspend_domain(self, src, uri, uuid): ++ def _do_suspend_domain(self, src, uri, connkey): + conn = self._lookup_conn(uri) +- vm = conn.get_vm(uuid) ++ vm = conn.get_vm(connkey) + + if not src.err.chkbox_helper(self.config.get_confirm_pause, + self.config.set_confirm_pause, +@@ -1053,17 +1030,17 @@ + vmmAsyncJob.simple_async_noshow(vm.suspend, [], src, + _("Error pausing domain")) + +- def _do_resume_domain(self, src, uri, uuid): ++ def _do_resume_domain(self, src, uri, connkey): + conn = self._lookup_conn(uri) +- vm = conn.get_vm(uuid) ++ vm = conn.get_vm(connkey) + + logging.debug("Unpausing vm '%s'", vm.get_name()) + vmmAsyncJob.simple_async_noshow(vm.resume, [], src, + _("Error unpausing domain")) + +- def _do_run_domain(self, src, uri, uuid): ++ def _do_run_domain(self, src, uri, connkey): + conn = self._lookup_conn(uri) +- vm = conn.get_vm(uuid) ++ vm = conn.get_vm(connkey) + + logging.debug("Starting vm '%s'", vm.get_name()) + +@@ -1086,7 +1063,7 @@ + + try: + vm.removeSavedImage() +- self._do_run_domain(src, uri, uuid) ++ self._do_run_domain(src, uri, connkey) + except Exception, e: + src.err.show_err(_("Error removing domain state: %s") + % str(e)) +@@ -1102,9 +1079,9 @@ + errorintro = _("Error starting domain") + vmmAsyncJob.simple_async_noshow(vm.startup, [], src, errorintro) + +- def _do_shutdown_domain(self, src, uri, uuid): ++ def _do_shutdown_domain(self, src, uri, connkey): + conn = self._lookup_conn(uri) +- vm = conn.get_vm(uuid) ++ vm = conn.get_vm(connkey) + + if not src.err.chkbox_helper(self.config.get_confirm_poweroff, + self.config.set_confirm_poweroff, +@@ -1116,9 +1093,9 @@ + vmmAsyncJob.simple_async_noshow(vm.shutdown, [], src, + _("Error shutting down domain")) + +- def _do_reboot_domain(self, src, uri, uuid): ++ def _do_reboot_domain(self, src, uri, connkey): + conn = self._lookup_conn(uri) +- vm = conn.get_vm(uuid) ++ vm = conn.get_vm(connkey) + + if not src.err.chkbox_helper(self.config.get_confirm_poweroff, + self.config.set_confirm_poweroff, +@@ -1155,9 +1132,9 @@ + + vmmAsyncJob.simple_async_noshow(reboot_cb, [], src, "") + +- def _do_reset_domain(self, src, uri, uuid): ++ def _do_reset_domain(self, src, uri, connkey): + conn = self._lookup_conn(uri) +- vm = conn.get_vm(uuid) ++ vm = conn.get_vm(connkey) + + if not src.err.chkbox_helper( + self.config.get_confirm_forcepoweroff, +@@ -1172,10 +1149,13 @@ + vmmAsyncJob.simple_async_noshow(vm.reset, [], src, + _("Error resetting domain")) + +- def _do_delete_domain(self, src, uri, uuid): ++ def _do_delete_domain(self, src, uri, connkey): + conn = self._lookup_conn(uri) +- vm = conn.get_vm(uuid) ++ vm = conn.get_vm(connkey) + +- if not self.delete_dialog: +- self.delete_dialog = vmmDeleteDialog() +- self.delete_dialog.show(vm, src.topwin) ++ try: ++ if not self.delete_dialog: ++ self.delete_dialog = vmmDeleteDialog() ++ self.delete_dialog.show(vm, src.topwin) ++ except Exception, e: ++ src.err.show_err(_("Error launching delete dialog: %s") % str(e)) +diff -urN virt-manager-1.0.1/virtManager/error.py virt-manager/virtManager/error.py +--- virt-manager-1.0.1/virtManager/error.py 2014-03-22 14:19:18.000000000 +0000 ++++ virt-manager/virtManager/error.py 2014-06-12 11:22:21.163891895 +0000 +@@ -17,9 +17,7 @@ + # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + # MA 02110-1301 USA. + +-# pylint: disable=E0611 + from gi.repository import Gtk +-# pylint: enable=E0611 + + import logging + import traceback +@@ -75,14 +73,16 @@ + if tb != "None": + details += "\n\n" + tb + ++ if debug: ++ debugmsg = "error dialog message:\nsummary=%s" % summary ++ if details and details != summary: ++ debugmsg += "\ndetails=%s" % details ++ logging.debug(debugmsg) ++ + # Make sure we have consistent details for error dialogs +- if (dialog_type == Gtk.MessageType.ERROR and not summary in details): ++ if (dialog_type == Gtk.MessageType.ERROR and summary not in details): + details = summary + "\n\n" + details + +- if debug: +- logging.debug("error dialog message:\nsummary=%s\ndetails=%s", +- summary, details) +- + dialog = _errorDialog(parent=self.get_parent(), + flags=0, + message_type=dialog_type, +@@ -294,10 +294,6 @@ + """ + Custom error dialog with optional check boxes or details drop down + """ +- # pylint: disable=E1101 +- # pylint can't detect functions we inheirit from Gtk, ex: +- # Instance of '_errorDialog' has no 'set_title' member +- + def __init__(self, *args, **kwargs): + Gtk.MessageDialog.__init__(self, *args, **kwargs) + +@@ -324,7 +320,8 @@ + self.chk_align.add(self.chk_vbox) + + self.chk_align.show_all() +- self.vbox.pack_start(self.chk_align, False, False, 0) ++ self.vbox.pack_start( # pylint: disable=no-member ++ self.chk_align, False, False, 0) + + def init_details(self): + # Init details buffer +@@ -342,7 +339,8 @@ + details.set_border_width(6) + sw.add(details) + self.buf_expander.add(sw) +- self.vbox.pack_start(self.buf_expander, False, False, 0) ++ self.vbox.pack_start( # pylint: disable=no-member ++ self.buf_expander, False, False, 0) + self.buf_expander.show_all() + + def show_dialog(self, primary_text, secondary_text="", +diff -urN virt-manager-1.0.1/virtManager/fsdetails.py virt-manager/virtManager/fsdetails.py +--- virt-manager-1.0.1/virtManager/fsdetails.py 2014-03-10 15:17:52.000000000 +0000 ++++ virt-manager/virtManager/fsdetails.py 2014-06-12 11:22:21.164891895 +0000 +@@ -19,10 +19,8 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import Gtk + from gi.repository import GObject +-# pylint: enable=E0611 + + from virtinst import VirtualFilesystem, StorageVolume + from virtinst import util +@@ -155,16 +153,16 @@ + return self._dev + + def get_config_fs_mode(self): +- return uiutil.get_list_selection(self.widget("fs-mode-combo"), +- rowindex=0, check_visible=True) ++ return uiutil.get_list_selection(self.widget("fs-mode-combo"), 0, ++ check_visible=True) + + def get_config_fs_wrpolicy(self): +- return uiutil.get_list_selection(self.widget("fs-wrpolicy-combo"), +- rowindex=0, check_visible=True) ++ return uiutil.get_list_selection(self.widget("fs-wrpolicy-combo"), 0, ++ check_visible=True) + + def get_config_fs_type(self): +- return uiutil.get_list_selection(self.widget("fs-type-combo"), +- rowindex=0, check_visible=True) ++ return uiutil.get_list_selection(self.widget("fs-type-combo"), 0, ++ check_visible=True) + + def get_config_fs_readonly(self): + if not self.widget("fs-readonly").is_visible(): +@@ -172,12 +170,12 @@ + return self.widget("fs-readonly").get_active() + + def get_config_fs_driver(self): +- return uiutil.get_list_selection(self.widget("fs-driver-combo"), +- rowindex=0, check_visible=True) ++ return uiutil.get_list_selection(self.widget("fs-driver-combo"), 0, ++ check_visible=True) + + def get_config_fs_format(self): +- return uiutil.get_list_selection(self.widget("fs-format-combo"), +- rowindex=0, check_visible=True) ++ return uiutil.get_list_selection(self.widget("fs-format-combo"), 0, ++ check_visible=True) + + # Setters + def set_dev(self, dev): +diff -urN virt-manager-1.0.1/virtManager/gfxdetails.py virt-manager/virtManager/gfxdetails.py +--- virt-manager-1.0.1/virtManager/gfxdetails.py 2014-03-22 22:24:42.000000000 +0000 ++++ virt-manager/virtManager/gfxdetails.py 2014-06-12 11:22:21.164891895 +0000 +@@ -19,10 +19,8 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import Gtk + from gi.repository import GObject +-# pylint: enable=E0611 + + import virtinst + from virtManager import uiutil +@@ -134,9 +132,9 @@ + self.widget("graphics-password-chk").set_active(False) + + def get_values(self): +- gtype = uiutil.get_list_selection(self.widget("graphics-type")) ++ gtype = uiutil.get_list_selection(self.widget("graphics-type"), 0) + port, tlsport = self._get_config_graphics_ports() +- addr = uiutil.get_list_selection(self.widget("graphics-address")) ++ addr = uiutil.get_list_selection(self.widget("graphics-address"), 0) + keymap = uiutil.get_combo_entry(self.widget("graphics-keymap")) + if keymap == "auto": + keymap = None +@@ -154,15 +152,20 @@ + auto = self.widget(basename + "-auto") + widget = self.widget(basename) + auto.set_inconsistent(False) ++ label = auto.get_label().split(" (")[0] + + if val == -1 or gfx.autoport: + auto.set_active(True) ++ if val and val != -1: ++ label += " (%s %s)" % (_("Port"), val) + elif val is None: + auto.set_inconsistent(True) + else: + auto.set_active(False) + widget.set_value(val) + ++ auto.set_label(label) ++ + gtype = gfx.type + is_vnc = (gtype == "vnc") + is_sdl = (gtype == "sdl") +diff -urN virt-manager-1.0.1/virtManager/graphwidgets.py virt-manager/virtManager/graphwidgets.py +--- virt-manager-1.0.1/virtManager/graphwidgets.py 2014-03-22 14:33:02.000000000 +0000 ++++ virt-manager/virtManager/graphwidgets.py 2014-06-12 11:22:21.164891895 +0000 +@@ -16,14 +16,8 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import GObject + from gi.repository import Gtk +-# pylint: enable=E0611 +- +-# pylint: disable=E1101 +-# pylint can't detect functions we inheirit from Gtk, ex: +-# Instance of 'Sparkline' has no 'get_style_context' member + + # pylint: disable=arguments-differ + # Newer pylint can detect, but warns that overridden arguments are wrong +diff -urN virt-manager-1.0.1/virtManager/host.py virt-manager/virtManager/host.py +--- virt-manager-1.0.1/virtManager/host.py 2014-03-20 00:10:58.000000000 +0000 ++++ virt-manager/virtManager/host.py 2014-06-12 11:22:21.164891895 +0000 +@@ -20,11 +20,9 @@ + + import logging + +-# pylint: disable=E0611 + from gi.repository import GObject + from gi.repository import Gtk + from gi.repository import Gdk +-# pylint: enable=E0611 + + from virtinst import VirtualDisk + from virtinst import StoragePool +@@ -242,7 +240,7 @@ + self.widget("interface-list").append_column(interfaceCol) + interfaceListModel.set_sort_column_id(1, Gtk.SortType.ASCENDING) + +- # Starmode combo ++ # Startmode combo + vmmCreateInterface.build_interface_startmode_combo( + self.widget("interface-startmode")) + +@@ -507,25 +505,25 @@ + self.enable_net_apply(EDIT_NET_AUTOSTART) + + def current_network(self): +- key = uiutil.get_list_selection(self.widget("net-list"), 0) ++ connkey = uiutil.get_list_selection(self.widget("net-list"), 0) + try: +- return key and self.conn.get_net(key) ++ return connkey and self.conn.get_net(connkey) + except KeyError: + return None + +- def refresh_network(self, src_ignore, uuid): ++ def refresh_network(self, src_ignore, connkey): + uilist = self.widget("net-list") + sel = uilist.get_selection() + model, treeiter = sel.get_selected() +- net = self.conn.get_net(uuid) ++ net = self.conn.get_net(connkey) + net.tick() + + for row in uilist.get_model(): +- if row[0] == uuid: ++ if row[0] == connkey: + row[4] = net.is_active() + + if treeiter is not None: +- if model[treeiter][0] == uuid: ++ if model[treeiter][0] == connkey: + self.net_selected(sel) + + def set_net_error_page(self, msg): +@@ -540,8 +538,10 @@ + return + + self.widget("network-pages").set_current_page(0) ++ connkey = model[treeiter][0] ++ + try: +- net = self.conn.get_net(model[treeiter][0]) ++ net = self.conn.get_net(connkey) + except KeyError: + self.disable_net_apply() + return +@@ -672,7 +672,9 @@ + _("Isolated network")) + self.disable_net_apply() + +- def repopulate_networks(self, src_ignore=None, uuid_ignore=None): ++ def repopulate_networks(self, src=None, connkey=None): ++ ignore = src ++ ignore = connkey + self.populate_networks(self.widget("net-list").get_model()) + + def populate_networks(self, model): +@@ -681,14 +683,13 @@ + net_list = self.widget("net-list") + net_list.get_selection().unselect_all() + model.clear() +- for uuid in self.conn.list_net_uuids(): +- net = self.conn.get_net(uuid) +- model.append([uuid, net.get_name(), "network-idle", ++ for net in self.conn.list_nets(): ++ model.append([net.get_connkey(), net.get_name(), "network-idle", + Gtk.IconSize.LARGE_TOOLBAR, + bool(net.is_active())]) + + uiutil.set_row_selection(net_list, +- curnet and curnet.get_uuid() or None) ++ curnet and curnet.get_connkey() or None) + + + # ------------------------------ +@@ -802,12 +803,12 @@ + if cp is None: + return + cp.refresh() +- self.refresh_storage_pool(None, cp.get_uuid()) ++ self.refresh_storage_pool(None, cp.get_connkey()) + + def current_pool(self): +- key = uiutil.get_list_selection(self.widget("pool-list"), 0) ++ connkey = uiutil.get_list_selection(self.widget("pool-list"), 0) + try: +- return key and self.conn.get_pool(key) ++ return connkey and self.conn.get_pool(connkey) + except KeyError: + return None + +@@ -816,9 +817,9 @@ + if not pool: + return None + +- key = uiutil.get_list_selection(self.widget("vol-list"), 0) ++ connkey = uiutil.get_list_selection(self.widget("vol-list"), 0) + try: +- return key and pool.get_volume(key) ++ return connkey and pool.get_volume(connkey) + except KeyError: + return None + +@@ -869,17 +870,17 @@ + return + + self.widget("storage-pages").set_current_page(0) +- uuid = model[treeiter][0] ++ connkey = model[treeiter][0] + + try: +- self.populate_pool_state(uuid) ++ self.populate_pool_state(connkey) + except Exception, e: + logging.exception(e) + self.set_storage_error_page(_("Error selecting pool: %s") % e) + self.disable_pool_apply() + +- def populate_pool_state(self, uuid): +- pool = self.conn.get_pool(uuid) ++ def populate_pool_state(self, connkey): ++ pool = self.conn.get_pool(connkey) + pool.tick() + auto = pool.get_autostart() + active = pool.is_active() +@@ -921,10 +922,11 @@ + self.widget("vol-add").set_tooltip_text( + _("Pool does not support volume creation")) + +- def refresh_storage_pool(self, src_ignore, uuid): +- refresh_pool_in_list(self.widget("pool-list"), self.conn, uuid) ++ def refresh_storage_pool(self, src, connkey): ++ ignore = src ++ refresh_pool_in_list(self.widget("pool-list"), self.conn, connkey) + curpool = self.current_pool() +- if curpool.get_uuid() != uuid: ++ if curpool.get_connkey() != connkey: + return + + # Currently selected pool changed state: force a 'pool_selected' to +@@ -978,7 +980,9 @@ + clipboard.set_text(target_path, -1) + + +- def repopulate_storage_pools(self, src_ignore=None, uuid_ignore=None): ++ def repopulate_storage_pools(self, src=None, connkey=None): ++ ignore = src ++ ignore = connkey + pool_list = self.widget("pool-list") + populate_storage_pools(pool_list, self.conn, self.current_pool()) + +@@ -1055,9 +1059,9 @@ + self.refresh_interface(None, cp.get_name()) + + def current_interface(self): +- key = uiutil.get_list_selection(self.widget("interface-list"), 0) ++ connkey = uiutil.get_list_selection(self.widget("interface-list"), 0) + try: +- return key and self.conn.get_interface(key) ++ return connkey and self.conn.get_interface(connkey) + except KeyError: + return None + +@@ -1096,10 +1100,10 @@ + return + + self.widget("interface-pages").set_current_page(INTERFACE_PAGE_INFO) +- name = model[treeiter][0] ++ connkey = model[treeiter][0] + + try: +- self.populate_interface_state(name) ++ self.populate_interface_state(connkey) + except Exception, e: + logging.exception(e) + self.set_interface_error_page(_("Error selecting interface: %s") % +@@ -1107,8 +1111,9 @@ + + self.widget("interface-apply").set_sensitive(False) + +- def populate_interface_state(self, name): +- interface = self.conn.get_interface(name) ++ def populate_interface_state(self, connkey): ++ interface = self.conn.get_interface(connkey) ++ name = interface.get_name() + children = interface.get_slaves() + itype = interface.get_type() + mac = interface.get_mac() +@@ -1191,11 +1196,14 @@ + self.widget("interface-child-box").set_visible(show_child) + self.populate_interface_children() + +- def refresh_interface(self, src_ignore, name): ++ def refresh_interface(self, src, connkey): ++ ignore = src ++ + iface_list = self.widget("interface-list") + sel = iface_list.get_selection() + model, treeiter = sel.get_selected() +- iface = self.conn.get_interface(name) ++ iface = self.conn.get_interface(connkey) ++ name = iface.get_name() + iface.tick() + + for row in iface_list.get_model(): +@@ -1213,7 +1221,9 @@ + self.widget("interface-start").set_sensitive(False) + self.widget("interface-apply").set_sensitive(False) + +- def repopulate_interfaces(self, src_ignore=None, name_ignore=None): ++ def repopulate_interfaces(self, src=None, connkey=None): ++ ignore = src ++ ignore = connkey + interface_list = self.widget("interface-list") + self.populate_interfaces(interface_list.get_model()) + +@@ -1223,14 +1233,13 @@ + iface_list = self.widget("interface-list") + iface_list.get_selection().unselect_all() + model.clear() +- for name in self.conn.list_interface_names(): +- iface = self.conn.get_interface(name) +- model.append([name, iface.get_name(), "network-idle", +- Gtk.IconSize.LARGE_TOOLBAR, ++ for iface in self.conn.list_interfaces(): ++ model.append([iface.get_connkey(), iface.get_name(), ++ "network-idle", Gtk.IconSize.LARGE_TOOLBAR, + bool(iface.is_active())]) + + uiutil.set_row_selection(iface_list, +- curiface and curiface.get_name() or None) ++ curiface and curiface.get_connkey() or None) + + def populate_interface_children(self): + interface = self.current_interface() +@@ -1268,13 +1277,15 @@ + poolListModel.set_sort_column_id(1, Gtk.SortType.ASCENDING) + + +-def refresh_pool_in_list(pool_list, conn, uuid): ++def refresh_pool_in_list(pool_list, conn, connkey): + for row in pool_list.get_model(): +- if row[0] == uuid: +- # Update active sensitivity and percent available for passed uuid +- row[3] = get_pool_size_percent(conn, uuid) +- row[2] = conn.get_pool(uuid).is_active() +- return ++ if row[0] != connkey: ++ continue ++ ++ # Update active sensitivity and percent available for passed key ++ row[3] = get_pool_size_percent(conn, connkey) ++ row[2] = conn.get_pool(connkey).is_active() ++ return + + + def populate_storage_pools(pool_list, conn, curpool): +@@ -1283,19 +1294,20 @@ + pool_list.set_model(None) + pool_list.get_selection().unselect_all() + model.clear() +- for uuid in conn.list_pool_uuids(): +- per = get_pool_size_percent(conn, uuid) +- pool = conn.get_pool(uuid) ++ for pool in conn.list_pools(): ++ connkey = pool.get_connkey() ++ per = get_pool_size_percent(conn, connkey) ++ pool = conn.get_pool(connkey) + + name = pool.get_name() + typ = StoragePool.get_pool_type_desc(pool.get_type()) + label = "%s\n%s" % (name, typ) + +- model.append([uuid, label, pool.is_active(), per]) ++ model.append([connkey, label, pool.is_active(), per]) + + pool_list.set_model(model) + uiutil.set_row_selection(pool_list, +- curpool and curpool.get_uuid() or None) ++ curpool and curpool.get_connkey() or None) + + + def populate_storage_volumes(list_widget, pool, sensitive_cb): +@@ -1335,8 +1347,8 @@ + model.append(row) + + +-def get_pool_size_percent(conn, uuid): +- pool = conn.get_pool(uuid) ++def get_pool_size_percent(conn, connkey): ++ pool = conn.get_pool(connkey) + cap = pool.get_capacity() + alloc = pool.get_allocation() + if not cap or alloc is None: +diff -urN virt-manager-1.0.1/virtManager/inspection.py virt-manager/virtManager/inspection.py +--- virt-manager-1.0.1/virtManager/inspection.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/inspection.py 2014-06-12 11:22:21.164891895 +0000 +@@ -23,7 +23,7 @@ + import os + import re + +-from guestfs import GuestFS # pylint: disable=F0401 ++from guestfs import GuestFS # pylint: disable=import-error + + from virtManager.baseclass import vmmGObject + from virtManager.domain import vmmInspectionData +@@ -64,9 +64,9 @@ + self._q.put(obj) + + # Called by the main thread whenever a VM is added to vmlist. +- def vm_added(self, conn, uuid): ++ def vm_added(self, conn, connkey): + ignore = conn +- ignore = uuid ++ ignore = connkey + obj = ("vm_added") + self._q.put(obj) + +@@ -118,7 +118,7 @@ + # Any VMs we've not seen yet? If so, process them. + def _process_vms(self): + for conn in self._conns.itervalues(): +- for vmuuid in conn.list_vm_uuids(): ++ for vm in conn.list_vms(): + if not conn.is_active(): + break + +@@ -127,9 +127,9 @@ + data.error = True + self._set_vm_inspection_data(vm, data) + ++ vmuuid = vm.get_uuid() + prettyvm = vmuuid + try: +- vm = conn.get_vm(vmuuid) + prettyvm = conn.get_uri() + ":" + vm.get_name() + + if vmuuid in self._vmseen: +diff -urN virt-manager-1.0.1/virtManager/interface.py virt-manager/virtManager/interface.py +--- virt-manager-1.0.1/virtManager/interface.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/interface.py 2014-06-12 11:22:21.165891895 +0000 +@@ -27,7 +27,6 @@ + def __init__(self, conn, backend, key): + vmmLibvirtObject.__init__(self, conn, backend, key, Interface) + +- self._name = key + self._active = True + + (self._inactive_xml_flags, +@@ -68,9 +67,6 @@ + def is_active(self): + return self._active + +- def get_name(self): +- return self._name +- + def get_mac(self): + return self.get_xmlobj().macaddr + +diff -urN virt-manager-1.0.1/virtManager/keyring.py virt-manager/virtManager/keyring.py +--- virt-manager-1.0.1/virtManager/keyring.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/keyring.py 2014-06-12 11:22:21.165891895 +0000 +@@ -20,10 +20,8 @@ + + import logging + +-# pylint: disable=E0611 + from gi.repository import Gio + from gi.repository import GLib +-# pylint: enable=E0611 + + + class vmmSecret(object): +diff -urN virt-manager-1.0.1/virtManager/libvirtobject.py virt-manager/virtManager/libvirtobject.py +--- virt-manager-1.0.1/virtManager/libvirtobject.py 2014-02-18 21:54:02.000000000 +0000 ++++ virt-manager/virtManager/libvirtobject.py 2014-06-12 11:22:21.165891895 +0000 +@@ -18,9 +18,7 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import GObject +-# pylint: enable=E0611 + + import logging + +@@ -51,6 +49,10 @@ + self._inactive_xml_flags = 0 + self._active_xml_flags = 0 + ++ # Cache object name ++ self._name = None ++ self.get_name() ++ + self.connect("config-changed", self._reparse_xml) + + @staticmethod +@@ -77,7 +79,7 @@ + + def get_backend(self): + return self._backend +- def get_key(self): ++ def get_connkey(self): + return self._key + + def change_name_backend(self, newbackend): +@@ -109,8 +111,6 @@ + # Functions that should probably be overridden in sub class # + ############################################################# + +- def get_name(self): +- raise NotImplementedError() + def _XMLDesc(self, flags): + raise NotImplementedError() + def _using_events(self): +@@ -123,8 +123,17 @@ + def delete(self, force=True): + ignore = force + +- def force_update_status(self, from_event=False): ++ def force_update_status(self, from_event=False, log=True): + ignore = from_event ++ ignore = log ++ ++ def get_name(self): ++ if self._name is None: ++ self._name = self._backend_get_name() ++ return self._name ++ ++ def _backend_get_name(self): ++ return self._backend.name() + + + ################## +diff -urN virt-manager-1.0.1/virtManager/manager.py virt-manager/virtManager/manager.py +--- virt-manager-1.0.1/virtManager/manager.py 2014-02-25 20:39:29.000000000 +0000 ++++ virt-manager/virtManager/manager.py 2014-06-12 11:22:21.166891895 +0000 +@@ -20,12 +20,10 @@ + + import logging + +-# pylint: disable=E0611 + from gi.repository import GObject + from gi.repository import Gtk + from gi.repository import Gdk + from gi.repository import GdkPixbuf +-# pylint: enable=E0611 + + from virtinst import util + +@@ -118,7 +116,7 @@ + + self.ignore_pause = False + +- # Mapping of VM UUID -> tree model rows to ++ # Mapping of rowkey -> tree model rows to + # allow O(1) access instead of O(n) + self.rows = {} + +@@ -241,7 +239,7 @@ + self.hostcpucol = None + self.netcol = None + +- self.vmmenu.destroy() # pylint: disable=E1101 ++ self.vmmenu.destroy() + self.vmmenu = None + self.connmenu.destroy() + self.connmenu = None +@@ -427,7 +425,7 @@ + ################## + + def current_row(self): +- return uiutil.get_list_selection(self.widget("vm-list")) ++ return uiutil.get_list_selection(self.widget("vm-list"), None) + + def current_vm(self): + row = self.current_row() +@@ -447,12 +445,6 @@ + else: + return handle.conn + +- def current_vmuuid(self): +- vm = self.current_vm() +- if vm is None: +- return None +- return vm.get_uuid() +- + def current_conn_uri(self, default_selection=False): + vmlist = self.widget("vm-list") + model = vmlist.get_model() +@@ -506,7 +498,7 @@ + return + + if vm: +- self.emit("action-show-domain", conn.get_uri(), vm.get_uuid()) ++ self.emit("action-show-domain", conn.get_uri(), vm.get_connkey()) + else: + if not self.open_conn(): + self.emit("action-show-host", conn.get_uri()) +@@ -517,7 +509,7 @@ + if vm is None: + self._do_delete_conn(conn) + else: +- self.emit("action-delete-domain", conn.get_uri(), vm.get_uuid()) ++ self.emit("action-delete-domain", conn.get_uri(), vm.get_connkey()) + + def _do_delete_conn(self, conn): + if conn is None: +@@ -555,27 +547,28 @@ + + def start_vm(self, ignore): + vm = self.current_vm() +- if vm is not None: +- self.emit("action-run-domain", +- vm.conn.get_uri(), vm.get_uuid()) ++ if vm is None: ++ return ++ self.emit("action-run-domain", vm.conn.get_uri(), vm.get_connkey()) + + def poweroff_vm(self, ignore): + vm = self.current_vm() +- if vm is not None: +- self.emit("action-shutdown-domain", +- vm.conn.get_uri(), vm.get_uuid()) ++ if vm is None: ++ return ++ self.emit("action-shutdown-domain", ++ vm.conn.get_uri(), vm.get_connkey()) + + def pause_vm(self, ignore): + vm = self.current_vm() +- if vm is not None: +- self.emit("action-suspend-domain", +- vm.conn.get_uri(), vm.get_uuid()) ++ if vm is None: ++ return ++ self.emit("action-suspend-domain", vm.conn.get_uri(), vm.get_connkey()) + + def resume_vm(self, ignore): + vm = self.current_vm() +- if vm is not None: +- self.emit("action-resume-domain", +- vm.conn.get_uri(), vm.get_uuid()) ++ if vm is None: ++ return ++ self.emit("action-resume-domain", vm.conn.get_uri(), vm.get_connkey()) + + def close_conn(self, ignore): + conn = self.current_conn() +@@ -596,8 +589,8 @@ + def vm_row_key(self, vm): + return vm.get_uuid() + ":" + vm.conn.get_uri() + +- def vm_added(self, conn, vmuuid): +- vm = conn.get_vm(vmuuid) ++ def vm_added(self, conn, connkey): ++ vm = conn.get_vm(connkey) + if self.vm_row_key(vm) in self.rows: + return + +@@ -611,14 +604,14 @@ + + self._append_vm(model, vm, conn) + +- def vm_removed(self, conn, vmuuid): ++ def vm_removed(self, conn, connkey): + vmlist = self.widget("vm-list") + model = vmlist.get_model() + + parent = self.rows[conn.get_uri()].iter + for row in range(model.iter_n_children(parent)): + vm = model[model.iter_nth_child(parent, row)][ROW_HANDLE] +- if vm.get_uuid() == vmuuid: ++ if vm.get_connkey() == connkey: + model.remove(model.iter_nth_child(parent, row)) + del self.rows[self.vm_row_key(vm)] + break +@@ -930,8 +923,7 @@ + # Popup the vm menu + vm = model[_iter][ROW_HANDLE] + self.vmmenu.update_widget_states(vm) +- self.vmmenu.popup( # pylint: disable=E1101 +- None, None, None, None, 0, event.time) ++ self.vmmenu.popup(None, None, None, None, 0, event.time) + else: + # Pop up connection menu + conn = model[_iter][ROW_HANDLE] +diff -urN virt-manager-1.0.1/virtManager/mediacombo.py virt-manager/virtManager/mediacombo.py +--- virt-manager-1.0.1/virtManager/mediacombo.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/mediacombo.py 2014-06-12 11:22:21.166891895 +0000 +@@ -17,9 +17,7 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import Gtk +-# pylint: enable=E0611 + + from virtManager import uiutil + from virtManager.baseclass import vmmGObjectUI +diff -urN virt-manager-1.0.1/virtManager/mediadev.py virt-manager/virtManager/mediadev.py +--- virt-manager-1.0.1/virtManager/mediadev.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/mediadev.py 2014-06-12 11:22:21.166891895 +0000 +@@ -18,9 +18,7 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import GObject +-# pylint: enable=E0611 + + import logging + +diff -urN virt-manager-1.0.1/virtManager/migrate.py virt-manager/virtManager/migrate.py +--- virt-manager-1.0.1/virtManager/migrate.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/migrate.py 2014-06-12 11:22:21.166891895 +0000 +@@ -22,11 +22,9 @@ + import logging + import threading + +-# pylint: disable=E0611 + from gi.repository import Gdk + from gi.repository import GLib + from gi.repository import Gtk +-# pylint: enable=E0611 + + import libvirt + from virtinst import util +@@ -184,7 +182,7 @@ + self.reset_state() + + def destconn_changed(self, src): +- row = uiutil.get_list_selection(src) ++ row = uiutil.get_list_selection(src, None) + tooltip = "" + if row: + tooltip = _("A valid destination connection must be selected.") +@@ -212,7 +210,7 @@ + self.widget("migrate-port").set_sensitive(enable) + + def get_config_destconn(self): +- row = uiutil.get_list_selection(self.widget("migrate-dest")) ++ row = uiutil.get_list_selection(self.widget("migrate-dest"), None) + if not row or not row[2]: + return None + return row[1] +diff -urN virt-manager-1.0.1/virtManager/netlist.py virt-manager/virtManager/netlist.py +--- virt-manager-1.0.1/virtManager/netlist.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/netlist.py 2014-06-12 11:22:21.166891895 +0000 +@@ -19,10 +19,8 @@ + + import logging + +-# pylint: disable=E0611 + from gi.repository import Gtk + from gi.repository import GObject +-# pylint: enable=E0611 + + import virtinst + from virtManager import uiutil +@@ -43,6 +41,7 @@ + self.builder.connect_signals({ + "on_net_source_changed": self._on_net_source_changed, + "on_net_source_mode_changed": self._emit_changed, ++ "on_net_portgroup_changed": self._emit_changed, + "on_net_bridge_name_changed": self._emit_changed, + + "on_vport_type_changed": self._emit_vport_changed, +@@ -95,9 +94,14 @@ + model.append(["vepa", "VEPA"]) + model.append(["private", "Private"]) + model.append(["passthrough", "Passthrough"]) +- + combo.set_active(0) + ++ combo = self.widget("net-portgroup") ++ # [xml value, label] ++ model = Gtk.ListStore(str, str) ++ combo.set_model(model) ++ uiutil.set_combo_text_column(combo, 1) ++ + self.conn.connect("net-added", self._repopulate_network_list) + self.conn.connect("net-removed", self._repopulate_network_list) + self.conn.connect("interface-added", self._repopulate_network_list) +@@ -136,8 +140,7 @@ + hasNet = False + netIdxLabel = None + +- for uuid in self.conn.list_net_uuids(): +- net = self.conn.get_net(uuid) ++ for net in self.conn.list_nets(): + nettype = virtinst.VirtualNetworkInterface.TYPE_VIRTUAL + + label = self._pretty_network_desc(nettype, net.get_name(), net) +@@ -152,7 +155,7 @@ + + vnet_dict[label] = self._build_source_row( + nettype, net.get_name(), label, True, +- net.is_active(), key=net.get_uuid()) ++ net.is_active(), key=net.get_connkey()) + + # Build a list of vnet bridges, so we know not to list them + # in the physical interface list +@@ -169,7 +172,7 @@ + + def _find_physical_devices(self, vnet_bridges): + vnet_taps = [] +- for vm in self.conn.vms.values(): ++ for vm in self.conn.list_vms(): + for nic in vm.get_network_devices(refresh_if_nec=False): + if nic.target_dev and nic.target_dev not in vnet_taps: + vnet_taps.append(nic.target_dev) +@@ -180,8 +183,8 @@ + brIdxLabel = None + skip_ifaces = ["lo"] + +- for name in self.conn.list_net_device_paths(): +- br = self.conn.get_net_device(name) ++ for br in self.conn.list_netdevs(): ++ name = br.name + bridge_name = br.get_bridge() + nettype = virtinst.VirtualNetworkInterface.TYPE_BRIDGE + +@@ -284,15 +287,13 @@ + ############### + + def get_network_row(self): +- return uiutil.get_list_selection(self.widget("net-source")) ++ return uiutil.get_list_selection(self.widget("net-source"), None) + + def get_network_selection(self): +- net_list = self.widget("net-source") + bridge_entry = self.widget("net-bridge-name") +- +- row = uiutil.get_list_selection(net_list) ++ row = self.get_network_row() + if not row: +- return None, None, None ++ return None, None, None, None + + net_type = row[0] + net_src = row[1] +@@ -304,9 +305,13 @@ + + mode = None + if self.widget("net-source-mode").is_visible(): +- mode = uiutil.get_list_selection(self.widget("net-source-mode"), 0) ++ mode = uiutil.get_combo_entry(self.widget("net-source-mode"), 0) + +- return net_type, net_src, mode ++ portgroup = None ++ if self.widget("net-portgroup").is_visible(): ++ portgroup = uiutil.get_combo_entry(self.widget("net-portgroup"), 0) ++ ++ return net_type, net_src, mode, portgroup + + def get_vport(self): + vport_type = self.widget("vport-type").get_text() +@@ -319,7 +324,7 @@ + vport_idver, vport_instid) + + def validate_network(self, macaddr, model=None): +- nettype, devname, mode = self.get_network_selection() ++ nettype, devname, mode, portgroup = self.get_network_selection() + if nettype is None: + return None + +@@ -328,7 +333,7 @@ + # Make sure VirtualNetwork is running + netobj = None + if nettype == virtinst.VirtualNetworkInterface.TYPE_VIRTUAL: +- for net in self.conn.nets.values(): ++ for net in self.conn.list_nets(): + if net.get_name() == devname: + netobj = net + break +@@ -358,6 +363,7 @@ + net.macaddr = macaddr + net.model = model + net.source_mode = mode ++ net.portgroup = portgroup + if net.model == "spapr-vlan": + net.address.set_addrstr("spapr-vio") + +@@ -395,6 +401,7 @@ + + self.widget("net-bridge-name").set_text("") + self.widget("net-source-mode").set_active(0) ++ self.widget("net-portgroup").get_child().set_text("") + + self.widget("vport-type").set_text("") + self.widget("vport-managerid").set_text("") +@@ -443,6 +450,9 @@ + combo.set_active_iter(rowiter) + combo.emit("changed") + ++ if net.portgroup: ++ uiutil.set_combo_entry(self.widget("net-portgroup"), net.portgroup) ++ + + ############# + # Listeners # +@@ -471,15 +481,27 @@ + netlist.set_active_iter(row.iter) + return + ++ def _populate_portgroups(self, portgroups): ++ combo = self.widget("net-portgroup") ++ model = combo.get_model() ++ model.clear() ++ ++ default = None ++ for p in portgroups: ++ model.append([p.name, p.name]) ++ if p.default: ++ default = p.name ++ ++ uiutil.set_combo_entry(combo, default) ++ + def _on_net_source_changed(self, src): ++ ignore = src + self._emit_changed() +- +- row = uiutil.get_list_selection(src) ++ row = self.get_network_row() + if not row: + return + + is_direct = (row[0] == virtinst.VirtualNetworkInterface.TYPE_DIRECT) +- + self.widget("vport-expander").set_visible(is_direct) + uiutil.set_grid_row_visible(self.widget("net-source-mode"), is_direct) + uiutil.set_grid_row_visible( +@@ -490,3 +512,12 @@ + show_bridge = row[5] + uiutil.set_grid_row_visible( + self.widget("net-bridge-name"), show_bridge) ++ ++ portgroups = [] ++ connkey = row[6] ++ if connkey and row[0] == virtinst.VirtualNetworkInterface.TYPE_VIRTUAL: ++ portgroups = self.conn.get_net(connkey).get_xmlobj().portgroups ++ ++ uiutil.set_grid_row_visible( ++ self.widget("net-portgroup"), bool(portgroups)) ++ self._populate_portgroups(portgroups) +diff -urN virt-manager-1.0.1/virtManager/network.py virt-manager/virtManager/network.py +--- virt-manager-1.0.1/virtManager/network.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/network.py 2014-06-12 11:22:21.167891895 +0000 +@@ -54,8 +54,6 @@ + # Required class methods # + ########################## + +- def get_name(self): +- return self._backend.name() + def _XMLDesc(self, flags): + return self._backend.XMLDesc(flags) + def _define(self, xml): +@@ -83,7 +81,8 @@ + self.idle_emit(state and "started" or "stopped") + self._active = state + +- def force_update_status(self, from_event=False): ++ def force_update_status(self, from_event=False, log=True): ++ ignore = log + if self._using_events() and not from_event: + return + +diff -urN virt-manager-1.0.1/virtManager/nodedev.py virt-manager/virtManager/nodedev.py +--- virt-manager-1.0.1/virtManager/nodedev.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/nodedev.py 2014-06-12 11:22:21.167891895 +0000 +@@ -34,8 +34,6 @@ + + def _XMLDesc(self, flags): + return self._backend.XMLDesc(flags) +- def get_name(self): +- return self._name + def is_active(self): + return True + +diff -urN virt-manager-1.0.1/virtManager/packageutils.py virt-manager/virtManager/packageutils.py +--- virt-manager-1.0.1/virtManager/packageutils.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/packageutils.py 2014-06-12 11:22:21.167891895 +0000 +@@ -18,9 +18,7 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import Gio +-# pylint: enable=E0611 + + import logging + import time +@@ -53,7 +51,12 @@ + return + + try: +- packagekit_install(parent, packages) ++ for package in packages[:]: ++ if packagekit_isinstalled(package): ++ packages.remove(package) ++ ++ if packages: ++ packagekit_install(parent, packages) + except Exception, e: + # PackageKit frontend should report an error for us, so just log + # the actual error +@@ -63,6 +66,16 @@ + return True + + ++def packagekit_isinstalled(package): ++ bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) ++ pk_control = Gio.DBusProxy.new_sync(bus, 0, None, ++ "org.freedesktop.PackageKit", ++ "/org/freedesktop/PackageKit", ++ "org.freedesktop.PackageKit.Query", None) ++ ++ return pk_control.IsInstalled("(ss)", package, "") ++ ++ + def packagekit_install(parent, package_list): + bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) + pk_control = Gio.DBusProxy.new_sync(bus, 0, None, +@@ -74,7 +87,7 @@ + try: + # Need to import GdkX11 just to get access to get_xid function + # This will likely fail on wayland in the future, so ignore errors +- from gi.repository import GdkX11 # pylint: disable=E0611 ++ from gi.repository import GdkX11 # pylint: disable=no-name-in-module + ignore = GdkX11 + + if parent and parent.topwin.get_window(): +diff -urN virt-manager-1.0.1/virtManager/preferences.py virt-manager/virtManager/preferences.py +--- virt-manager-1.0.1/virtManager/preferences.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/preferences.py 2014-06-12 11:22:21.167891895 +0000 +@@ -20,10 +20,8 @@ + + import logging + +-# pylint: disable=E0611 + from gi.repository import Gtk + from gi.repository import Gdk +-# pylint: enable=E0611 + + from virtManager import uiutil + from virtManager.baseclass import vmmGObjectUI +@@ -303,10 +301,10 @@ + dialog.set_default_size(325, 160) + dialog.set_border_width(6) + +- infolabel = Gtk.Label(label= +- _("You can now define grab keys by pressing them.\n" +- "To confirm your selection please click OK button\n" +- "while you have desired keys pressed.")) ++ infolabel = Gtk.Label( ++ label=_("You can now define grab keys by pressing them.\n" ++ "To confirm your selection please click OK button\n" ++ "while you have desired keys pressed.")) + keylabel = Gtk.Label(label=_("Please press desired grab key combination")) + + vbox = Gtk.VBox() +diff -urN virt-manager-1.0.1/virtManager/serialcon.py virt-manager/virtManager/serialcon.py +--- virt-manager-1.0.1/virtManager/serialcon.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/serialcon.py 2014-06-12 11:22:21.167891895 +0000 +@@ -25,12 +25,10 @@ + import fcntl + import logging + +-# pylint: disable=E0611 + from gi.repository import Gdk + from gi.repository import GLib + from gi.repository import Gtk + from gi.repository import Vte +-# pylint: enable=E0611 + + import libvirt + +@@ -284,7 +282,7 @@ + "connection") + elif not vm.is_active(): + err = _("Serial console not available for inactive guest") +- elif not ctype in usable_types: ++ elif ctype not in usable_types: + err = (_("Console for device type '%s' not yet supported") % + ctype) + elif (not is_remote and +@@ -378,6 +376,14 @@ + self.box.append_page(self.error_label, Gtk.Label("")) + self.box.show_all() + ++ scrollbar.hide() ++ scrollbar.get_adjustment().connect( ++ "changed", self._scrollbar_adjustment_changed, scrollbar) ++ ++ def _scrollbar_adjustment_changed(self, adjustment, scrollbar): ++ scrollbar.set_visible( ++ adjustment.get_upper() > adjustment.get_page_size()) ++ + def _cleanup(self): + self.console.cleanup() + self.console = None +diff -urN virt-manager-1.0.1/virtManager/snapshots.py virt-manager/virtManager/snapshots.py +--- virt-manager-1.0.1/virtManager/snapshots.py 2014-03-10 15:17:52.000000000 +0000 ++++ virt-manager/virtManager/snapshots.py 2014-06-12 11:22:21.167891895 +0000 +@@ -24,12 +24,10 @@ + import os + import StringIO + +-# pylint: disable=E0611 + from gi.repository import Gdk + from gi.repository import GdkPixbuf + from gi.repository import Gtk + from gi.repository import Pango +-# pylint: enable=E0611 + + from virtinst import DomainSnapshot + from virtinst import util +@@ -379,6 +377,11 @@ + return + + try: ++ # Perform two screenshots, because qemu + qxl has a bug where ++ # screenshot generally only shows the data from the previous ++ # screenshot request: ++ # https://bugs.launchpad.net/qemu/+bug/1314293 ++ self._take_screenshot() + mime, sdata = self._take_screenshot() + except: + logging.exception("Error taking screenshot") +@@ -553,10 +556,15 @@ + + def _on_start_clicked(self, ignore): + snap = self._get_selected_snapshot() +- result = self.err.yes_no(_("Are you sure you want to run " +- "snapshot '%s'? All disk changes since " +- "the last snapshot was created will be " +- "discarded.") % snap.get_name()) ++ msg = _("Are you sure you want to run snapshot '%s'? " ++ "All %s changes since the last snapshot was created will be " ++ "discarded.") ++ if self.vm.is_active(): ++ msg = msg % (snap.get_name(), _("disk")) ++ else: ++ msg = msg % (snap.get_name(), _("disk and configuration")) ++ ++ result = self.err.yes_no(msg) + if not result: + return + +diff -urN virt-manager-1.0.1/virtManager/storagebrowse.py virt-manager/virtManager/storagebrowse.py +--- virt-manager-1.0.1/virtManager/storagebrowse.py 2014-03-10 15:17:52.000000000 +0000 ++++ virt-manager/virtManager/storagebrowse.py 2014-06-12 11:22:21.167891895 +0000 +@@ -20,10 +20,8 @@ + + import logging + +-# pylint: disable=E0611 + from gi.repository import GObject + from gi.repository import Gtk +-# pylint: enable=E0611 + + from virtManager import host + from virtManager.asyncjob import vmmAsyncJob +@@ -184,8 +182,9 @@ + if not self._first_run: + self._first_run = True + pool = self.conn.get_default_pool() +- uiutil.set_row_selection( +- self.widget("pool-list"), pool and pool.get_uuid() or None) ++ uiutil.set_row_selection(self.widget("pool-list"), ++ pool and pool.get_connkey() or None) ++ + # Manually trigger vol_selected, so buttons are in the correct state + self.vol_selected() + self.pool_selected() +@@ -221,18 +220,20 @@ + return data["enable_create"] + + def current_pool(self): +- row = uiutil.get_list_selection(self.widget("pool-list")) ++ row = uiutil.get_list_selection(self.widget("pool-list"), None) + if not row: + return ++ ++ connkey = row[0] + try: +- return self.conn.get_pool(row[0]) ++ return self.conn.get_pool(connkey) + except KeyError: + return None + + def current_vol_row(self): + if not self.current_pool(): + return +- return uiutil.get_list_selection(self.widget("vol-list")) ++ return uiutil.get_list_selection(self.widget("vol-list"), None) + + def current_vol(self): + pool = self.current_pool() +@@ -241,18 +242,22 @@ + return + return pool.get_volume(row[0]) + +- def refresh_storage_pool(self, src_ignore, uuid): ++ def refresh_storage_pool(self, src, connkey): ++ ignore = src ++ + pool_list = self.widget("pool-list") +- host.refresh_pool_in_list(pool_list, self.conn, uuid) ++ host.refresh_pool_in_list(pool_list, self.conn, connkey) + curpool = self.current_pool() +- if curpool.get_uuid() != uuid: ++ if curpool.get_connkey() != connkey: + return + + # Currently selected pool changed state: force a 'pool_selected' to + # update vol list + self.pool_selected(self.widget("pool-list").get_selection()) + +- def repopulate_storage_pools(self, src_ignore=None, uuid_ignore=None): ++ def repopulate_storage_pools(self, src=None, connkey=None): ++ ignore = src ++ ignore = connkey + pool_list = self.widget("pool-list") + host.populate_storage_pools(pool_list, self.conn, self.current_pool()) + +@@ -329,7 +334,7 @@ + return + cp.refresh() + +- self.refresh_storage_pool(None, cp.get_uuid()) ++ self.refresh_storage_pool(None, cp.get_connkey()) + name = createvol and createvol.vol.name or None + + vol_list = self.widget("vol-list") +diff -urN virt-manager-1.0.1/virtManager/storagepool.py virt-manager/virtManager/storagepool.py +--- virt-manager-1.0.1/virtManager/storagepool.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/storagepool.py 2014-06-12 11:22:21.167891895 +0000 +@@ -18,9 +18,9 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 ++import logging ++ + from gi.repository import GObject +-# pylint: enable=E0611 + + from virtinst import pollhelpers + from virtinst import StoragePool, StorageVolume +@@ -38,10 +38,13 @@ + # Required class methods # + ########################## + +- def get_name(self): +- return self.get_xmlobj().name + def _XMLDesc(self, flags): +- return self._backend.XMLDesc(flags) ++ try: ++ return self._backend.XMLDesc(flags) ++ except Exception, e: ++ logging.debug("XMLDesc for vol=%s failed: %s", ++ self._backend.key(), e) ++ raise + + + ########### +@@ -49,8 +52,10 @@ + ########### + + def get_parent_pool(self): +- pobj = self._backend.storagePoolLookupByVolume() +- return self.conn.get_pool_by_name(pobj.name()) ++ name = self._backend.storagePoolLookupByVolume().name() ++ for pool in self.conn.list_pools(): ++ if pool.get_name() == name: ++ return pool + + def delete(self, force=True): + ignore = force +@@ -110,8 +115,6 @@ + # Required class methods # + ########################## + +- def get_name(self): +- return self.get_xmlobj().name + def _XMLDesc(self, flags): + return self._backend.XMLDesc(flags) + def _define(self, xml): +@@ -198,8 +201,8 @@ + self.update_volumes() + return self._volumes + +- def get_volume(self, uuid): +- return self._volumes[uuid] ++ def get_volume(self, key): ++ return self._volumes[key] + + def update_volumes(self, refresh=False): + if not self.is_active(): +diff -urN virt-manager-1.0.1/virtManager/systray.py virt-manager/virtManager/systray.py +--- virt-manager-1.0.1/virtManager/systray.py 2014-03-22 15:00:01.000000000 +0000 ++++ virt-manager/virtManager/systray.py 2014-06-12 11:22:21.167891895 +0000 +@@ -20,17 +20,15 @@ + + import logging + +-# pylint: disable=E0611 + from gi.repository import GObject + from gi.repository import Gtk +-# pylint: enable=E0611 + + from virtManager import vmmenu + from virtManager.baseclass import vmmGObject + from virtManager.error import vmmErrorDialog + + try: +- from gi.repository import AppIndicator3 # pylint: disable=E0611 ++ from gi.repository import AppIndicator3 # pylint: disable=no-name-in-module + except: + AppIndicator3 = None + +@@ -166,12 +164,12 @@ + + # Helper functions + def _get_vm_menu_item(self, vm): +- uuid = vm.get_uuid() ++ connkey = vm.get_connkey() + uri = vm.conn.get_uri() + + if uri in self.conn_vm_menuitems: +- if uuid in self.conn_vm_menuitems[uri]: +- return self.conn_vm_menuitems[uri][uuid] ++ if connkey in self.conn_vm_menuitems[uri]: ++ return self.conn_vm_menuitems[uri][connkey] + return None + + def _set_vm_status_icon(self, vm, menu_item): +@@ -232,7 +230,7 @@ + self.populate_vm_list(conn) + + def conn_removed(self, engine_ignore, uri): +- if not uri in self.conn_menuitems: ++ if uri not in self.conn_menuitems: + return + + menu_item = self.conn_menuitems[uri] +@@ -258,8 +256,8 @@ + vm_submenu.remove(c) + + vm_mappings = {} +- for vm in conn.vms.values(): +- vm_mappings[vm.get_name()] = vm.get_uuid() ++ for vm in conn.list_vms(): ++ vm_mappings[vm.get_name()] = vm.get_connkey() + + vm_names = vm_mappings.keys() + vm_names.sort() +@@ -272,30 +270,30 @@ + + for i in range(0, len(vm_names)): + name = vm_names[i] +- uuid = vm_mappings[name] +- if uuid in self.conn_vm_menuitems[uri]: +- vm_item = self.conn_vm_menuitems[uri][uuid] ++ connkey = vm_mappings[name] ++ if connkey in self.conn_vm_menuitems[uri]: ++ vm_item = self.conn_vm_menuitems[uri][connkey] + vm_submenu.insert(vm_item, i) + +- def vm_added(self, conn, uuid): ++ def vm_added(self, conn, connkey): + uri = conn.get_uri() +- vm = conn.get_vm(uuid) ++ vm = conn.get_vm(connkey) + if not vm: + return + vm.connect("status-changed", self.vm_state_changed) + + vm_mappings = self.conn_vm_menuitems[uri] +- if uuid in vm_mappings: ++ if connkey in vm_mappings: + return + + # Build VM list entry + menu_item = Gtk.ImageMenuItem.new_with_label(vm.get_name()) + menu_item.set_use_underline(False) + +- vm_mappings[uuid] = menu_item ++ vm_mappings[connkey] = menu_item + vm_action_menu = vmmenu.VMActionMenu(self, lambda: vm) + menu_item.set_submenu(vm_action_menu) +- self.vm_action_dict[uuid] = vm_action_menu ++ self.vm_action_dict[connkey] = vm_action_menu + + # Add VM to menu list + self.populate_vm_list(conn) +@@ -304,26 +302,28 @@ + self.vm_state_changed(vm) + menu_item.show() + +- def vm_removed(self, conn, uuid): ++ def vm_removed(self, conn, connkey): + uri = conn.get_uri() + vm_mappings = self.conn_vm_menuitems[uri] + if not vm_mappings: + return + +- if uuid in vm_mappings: +- conn_item = self.conn_menuitems[uri] +- vm_menu_item = vm_mappings[uuid] +- vm_menu = conn_item.get_submenu() +- vm_menu.remove(vm_menu_item) +- vm_menu_item.destroy() +- del(vm_mappings[uuid]) +- +- if len(vm_menu.get_children()) == 0: +- placeholder = Gtk.MenuItem.new_with_label( +- _("No virtual machines")) +- placeholder.show() +- placeholder.set_sensitive(False) +- vm_menu.add(placeholder) ++ if connkey not in vm_mappings: ++ return ++ ++ conn_item = self.conn_menuitems[uri] ++ vm_menu_item = vm_mappings[connkey] ++ vm_menu = conn_item.get_submenu() ++ vm_menu.remove(vm_menu_item) ++ vm_menu_item.destroy() ++ del(vm_mappings[connkey]) ++ ++ if len(vm_menu.get_children()) == 0: ++ placeholder = Gtk.MenuItem.new_with_label( ++ _("No virtual machines")) ++ placeholder.show() ++ placeholder.set_sensitive(False) ++ vm_menu.add(placeholder) + + def vm_state_changed(self, vm, ignore=None, ignore2=None): + menu_item = self._get_vm_menu_item(vm) +@@ -333,7 +333,7 @@ + self._set_vm_status_icon(vm, menu_item) + + # Update action widget states +- menu = self.vm_action_dict[vm.get_uuid()] ++ menu = self.vm_action_dict[vm.get_connkey()] + menu.update_widget_states(vm) + + def exit_app(self, ignore): +diff -urN virt-manager-1.0.1/virtManager/uiutil.py virt-manager/virtManager/uiutil.py +--- virt-manager-1.0.1/virtManager/uiutil.py 2014-03-22 22:00:07.000000000 +0000 ++++ virt-manager/virtManager/uiutil.py 2014-06-12 11:22:21.168891895 +0000 +@@ -18,10 +18,8 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import GObject + from gi.repository import Gtk +-# pylint: enable=E0611 + + try: + import gi +@@ -58,9 +56,11 @@ + return adj.get_value() + + +-def get_list_selection(widget, rowindex=None, check_visible=False): ++def get_list_selection(widget, rowindex, check_visible=False): + """ +- Helper to simplify getting the selected row in a list/tree/combo ++ Helper to simplify getting the selected row and value in a list/tree/combo ++ ++ If rowindex is None, return the whole row. + """ + if check_visible and not widget.get_visible(): + return None +@@ -145,7 +145,7 @@ + Helper to get the value specified in a combo box, with or + without and entry + """ +- row = get_list_selection(combo) ++ row = get_list_selection(combo, None) + if row: + return row[rowidx] + if not combo.get_has_entry(): +diff -urN virt-manager-1.0.1/virtManager/vmmenu.py virt-manager/virtManager/vmmenu.py +--- virt-manager-1.0.1/virtManager/vmmenu.py 2014-02-17 17:37:52.000000000 +0000 ++++ virt-manager/virtManager/vmmenu.py 2014-06-12 11:22:21.168891895 +0000 +@@ -18,9 +18,7 @@ + # MA 02110-1301 USA. + # + +-# pylint: disable=E0611 + from gi.repository import Gtk +-# pylint: enable=E0611 + + + #################################################################### +@@ -28,9 +26,6 @@ + #################################################################### + + class _VMMenu(Gtk.Menu): +- # pylint: disable=E1101 +- # pylint can't detect functions we inheirit from Gtk, ex self.add +- + def __init__(self, src, current_vm_cb, show_open=True): + Gtk.Menu.__init__(self) + self._parent = src +@@ -65,7 +60,7 @@ + if not vm: + return + self._parent.emit("action-%s-domain" % src.vmm_widget_name, +- vm.conn.get_uri(), vm.get_uuid()) ++ vm.conn.get_uri(), vm.get_connkey()) + + def _init_state(self): + raise NotImplementedError() +@@ -74,9 +69,6 @@ + + + class VMShutdownMenu(_VMMenu): +- # pylint: disable=E1101 +- # pylint can't detect functions we inheirit from Gtk, ex self.add +- + def _init_state(self): + self._add_action(_("_Reboot"), "reboot") + self._add_action(_("_Shut Down"), "shutdown") +@@ -103,9 +95,6 @@ + + + class VMActionMenu(_VMMenu): +- # pylint: disable=E1101 +- # pylint can't detect functions we inheirit from Gtk, ex self.add +- + def _init_state(self): + self._add_action(_("_Run"), "run", Gtk.STOCK_MEDIA_PLAY) + self._add_action(_("_Pause"), "suspend", Gtk.STOCK_MEDIA_PAUSE)