From 3e1ed9fdaacc4165f6b1954987dc29e65d32dad5 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Apr 16 2014 21:23:33 +0000 Subject: gfxdetails: Show port number for active autoport VM (bz #1081614) connection: Hook into domain balloon event (bz #1081424) details: Fix showing vcpus values in 'customize' dialog (bz #1083903) details: Fix changing graphics type (bz #1083903) createpool: Clarify iscsi IQN fields (bz #1084011) More fixes for errors on libvirtd disconnect (bz #1069351) --- diff --git a/0001-gfxdetails-Show-port-number-for-active-autoport-VM-b.patch b/0001-gfxdetails-Show-port-number-for-active-autoport-VM-b.patch new file mode 100644 index 0000000..8dd3244 --- /dev/null +++ b/0001-gfxdetails-Show-port-number-for-active-autoport-VM-b.patch @@ -0,0 +1,36 @@ +From 5307267536c7c1f7bf09bae81bff9aec3ee2622a Mon Sep 17 00:00:00 2001 +From: Cole Robinson +Date: Sun, 30 Mar 2014 17:34:26 -0400 +Subject: [PATCH] gfxdetails: Show port number for active autoport VM (bz + 1081614) + +(cherry picked from commit 7f802e287c21a6395a0e9f5435c1eab78b2ce6b5) +--- + virtManager/gfxdetails.py | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/virtManager/gfxdetails.py b/virtManager/gfxdetails.py +index 0141f7e..d6865a8 100644 +--- a/virtManager/gfxdetails.py ++++ b/virtManager/gfxdetails.py +@@ -154,15 +154,20 @@ class vmmGraphicsDetails(vmmGObjectUI): + 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 --git a/0002-connection-Hook-into-domain-balloon-event-bz-1081424.patch b/0002-connection-Hook-into-domain-balloon-event-bz-1081424.patch new file mode 100644 index 0000000..d78919b --- /dev/null +++ b/0002-connection-Hook-into-domain-balloon-event-bz-1081424.patch @@ -0,0 +1,112 @@ +From 33a602c79792cfdbdc97be4e6c6c9acc04e4ba97 Mon Sep 17 00:00:00 2001 +From: Cole Robinson +Date: Mon, 31 Mar 2014 12:43:49 -0400 +Subject: [PATCH] connection: Hook into domain balloon event (bz 1081424) + +(cherry picked from commit adf3545671b155ca37c82bff0ab96d0c038ffee8) +--- + virtManager/connection.py | 60 +++++++++++++++++++++++++++++++++++------------ + 1 file changed, 45 insertions(+), 15 deletions(-) + +diff --git a/virtManager/connection.py b/virtManager/connection.py +index bc8a81f..27d5bd9 100644 +--- a/virtManager/connection.py ++++ b/virtManager/connection.py +@@ -99,9 +99,9 @@ class vmmConnection(vmmGObject): + 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 = {} + +@@ -840,6 +840,16 @@ class vmmConnection(vmmGObject): + # 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.UUIDString(), 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 +@@ -872,19 +882,41 @@ class vmmConnection(vmmGObject): + + def _add_conn_events(self): + try: +- self._domain_cb_id = self.get_backend().domainEventRegisterAny( ++ 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: + 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: +@@ -936,15 +968,13 @@ class vmmConnection(vmmGObject): + + 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) ++ self._domain_cb_ids = [] ++ ++ for eid in self._network_cb_ids: ++ self._backend.networkEventDeregisterAny(eid) ++ self._network_cb_ids = [] + except: + logging.debug("Failed to deregister events in conn cleanup", + exc_info=True) diff --git a/0003-details-Fix-showing-vcpus-values-in-customize-dialog.patch b/0003-details-Fix-showing-vcpus-values-in-customize-dialog.patch new file mode 100644 index 0000000..4fd0e92 --- /dev/null +++ b/0003-details-Fix-showing-vcpus-values-in-customize-dialog.patch @@ -0,0 +1,42 @@ +From 842835b3120d5c0825fa30f7dcc9c4090454c7e2 Mon Sep 17 00:00:00 2001 +From: Cole Robinson +Date: Thu, 3 Apr 2014 10:30:37 -0400 +Subject: [PATCH] details: Fix showing vcpus values in 'customize' dialog (bz + 1083903) + +(cherry picked from commit ee6a541167b787a84cc5c7e553089cbd5ab9ada3) +--- + virtManager/details.py | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/virtManager/details.py b/virtManager/details.py +index c1833ae..ea9d91a 100644 +--- a/virtManager/details.py ++++ b/virtManager/details.py +@@ -2533,6 +2533,12 @@ class vmmDetails(vmmGObjectUI): + 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 +2556,10 @@ class vmmDetails(vmmGObjectUI): + 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) diff --git a/0004-details-Fix-changing-graphics-type-bz-1083903.patch b/0004-details-Fix-changing-graphics-type-bz-1083903.patch new file mode 100644 index 0000000..5670f34 --- /dev/null +++ b/0004-details-Fix-changing-graphics-type-bz-1083903.patch @@ -0,0 +1,308 @@ +From e8e4ad674d537c8531eb665a87dc6d40e6e3dd25 Mon Sep 17 00:00:00 2001 +From: Cole Robinson +Date: Thu, 3 Apr 2014 10:53:54 -0400 +Subject: [PATCH] details: Fix changing graphics type (bz 1083903) + +And clean up the API usage to avoid these types of issues in the future. + +(cherry picked from commit 932e6e00bb08647800a62e59f61c8adee9c5de59) +--- + virtManager/addhardware.py | 8 ++++---- + virtManager/create.py | 13 ++++++++----- + virtManager/createinterface.py | 2 +- + virtManager/details.py | 4 ++-- + virtManager/fsdetails.py | 20 ++++++++++---------- + virtManager/gfxdetails.py | 4 ++-- + virtManager/manager.py | 2 +- + virtManager/migrate.py | 4 ++-- + virtManager/netlist.py | 10 ++++------ + virtManager/storagebrowse.py | 4 ++-- + virtManager/uiutil.py | 8 +++++--- + 11 files changed, 41 insertions(+), 38 deletions(-) + +diff --git a/virtManager/addhardware.py b/virtManager/addhardware.py +index c7ee0f0..653fdf5 100644 +--- a/virtManager/addhardware.py ++++ b/virtManager/addhardware.py +@@ -905,12 +905,12 @@ class vmmAddHardware(vmmGObjectUI): + + # 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 +933,7 @@ class vmmAddHardware(vmmGObjectUI): + 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): +@@ -1016,7 +1016,7 @@ class vmmAddHardware(vmmGObjectUI): + 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"] +diff --git a/virtManager/create.py b/virtManager/create.py +index 29f7c92..86f8bd3 100644 +--- a/virtManager/create.py ++++ b/virtManager/create.py +@@ -935,8 +935,8 @@ class vmmCreate(vmmGObjectUI): + 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,8 +960,10 @@ class vmmCreate(vmmGObjectUI): + 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 +@@ -1142,7 +1144,8 @@ class vmmCreate(vmmGObjectUI): + 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 +diff --git a/virtManager/createinterface.py b/virtManager/createinterface.py +index 77fb6e1..809da13 100644 +--- a/virtManager/createinterface.py ++++ b/virtManager/createinterface.py +@@ -775,7 +775,7 @@ class vmmCreateInterface(vmmGObjectUI): + 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() +diff --git a/virtManager/details.py b/virtManager/details.py +index ea9d91a..10b03ce 100644 +--- a/virtManager/details.py ++++ b/virtManager/details.py +@@ -1096,7 +1096,7 @@ class vmmDetails(vmmGObjectUI): + 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 +1104,7 @@ class vmmDetails(vmmGObjectUI): + 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() +diff --git a/virtManager/fsdetails.py b/virtManager/fsdetails.py +index f47bd55..ce78912 100644 +--- a/virtManager/fsdetails.py ++++ b/virtManager/fsdetails.py +@@ -155,16 +155,16 @@ class vmmFSDetails(vmmGObjectUI): + 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 +172,12 @@ class vmmFSDetails(vmmGObjectUI): + 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 --git a/virtManager/gfxdetails.py b/virtManager/gfxdetails.py +index d6865a8..1fcf643 100644 +--- a/virtManager/gfxdetails.py ++++ b/virtManager/gfxdetails.py +@@ -134,9 +134,9 @@ class vmmGraphicsDetails(vmmGObjectUI): + 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 +diff --git a/virtManager/manager.py b/virtManager/manager.py +index 4c99a44..b611e0d 100644 +--- a/virtManager/manager.py ++++ b/virtManager/manager.py +@@ -427,7 +427,7 @@ class vmmManager(vmmGObjectUI): + ################## + + 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() +diff --git a/virtManager/migrate.py b/virtManager/migrate.py +index f392737..f5cb86c 100644 +--- a/virtManager/migrate.py ++++ b/virtManager/migrate.py +@@ -184,7 +184,7 @@ class vmmMigrateDialog(vmmGObjectUI): + 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 +212,7 @@ class vmmMigrateDialog(vmmGObjectUI): + 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 --git a/virtManager/netlist.py b/virtManager/netlist.py +index 0e24f4e..01ad2e4 100644 +--- a/virtManager/netlist.py ++++ b/virtManager/netlist.py +@@ -284,13 +284,11 @@ class vmmNetworkList(vmmGObjectUI): + ############### + + 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 + +@@ -472,9 +470,9 @@ class vmmNetworkList(vmmGObjectUI): + return + + 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 + +diff --git a/virtManager/storagebrowse.py b/virtManager/storagebrowse.py +index 3f61352..30b5c2a 100644 +--- a/virtManager/storagebrowse.py ++++ b/virtManager/storagebrowse.py +@@ -221,7 +221,7 @@ class vmmStorageBrowser(vmmGObjectUI): + 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 + try: +@@ -232,7 +232,7 @@ class vmmStorageBrowser(vmmGObjectUI): + 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() +diff --git a/virtManager/uiutil.py b/virtManager/uiutil.py +index 364aaa7..2ce6c9a 100644 +--- a/virtManager/uiutil.py ++++ b/virtManager/uiutil.py +@@ -58,9 +58,11 @@ def spin_get_helper(widget): + 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 +147,7 @@ def get_combo_entry(combo, rowidx=0): + 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 --git a/0005-createpool-Clarify-iscsi-IQN-fields-bz-1084011.patch b/0005-createpool-Clarify-iscsi-IQN-fields-bz-1084011.patch new file mode 100644 index 0000000..05fc37c --- /dev/null +++ b/0005-createpool-Clarify-iscsi-IQN-fields-bz-1084011.patch @@ -0,0 +1,49 @@ +From e99370e30b845b4ca645c9ace040f80356264e9e Mon Sep 17 00:00:00 2001 +From: Cole Robinson +Date: Thu, 3 Apr 2014 11:19:03 -0400 +Subject: [PATCH] createpool: Clarify iscsi IQN fields (bz 1084011) + +(cherry picked from commit 8fa2aad1d31f811bb09505595c6401bdf6b90d78) +--- + ui/createpool.ui | 4 ++-- + virtManager/createpool.py | 5 +++++ + 2 files changed, 7 insertions(+), 2 deletions(-) + +diff --git a/ui/createpool.ui b/ui/createpool.ui +index 5f3972f..21693a9 100644 +--- a/ui/createpool.ui ++++ b/ui/createpool.ui +@@ -315,7 +315,7 @@ + True + False + 1 +- _Source Path: ++ sourcep: + True + + +@@ -330,7 +330,7 @@ + True + False + 1 +- _IQN: ++ Initiator _IQN: + True + pool-iqn-chk + +diff --git a/virtManager/createpool.py b/virtManager/createpool.py +index abc35fb..ae94e35 100644 +--- a/virtManager/createpool.py ++++ b/virtManager/createpool.py +@@ -277,6 +277,11 @@ class vmmCreatePool(vmmGObjectUI): + 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 --git a/0006-error-Don-t-log-redundant-details-bits.patch b/0006-error-Don-t-log-redundant-details-bits.patch new file mode 100644 index 0000000..c4585a8 --- /dev/null +++ b/0006-error-Don-t-log-redundant-details-bits.patch @@ -0,0 +1,35 @@ +From 5b6694efd7686684272c2d662bde52386ea1dc4f Mon Sep 17 00:00:00 2001 +From: Cole Robinson +Date: Wed, 16 Apr 2014 12:12:07 -0400 +Subject: [PATCH] error: Don't log redundant details bits + +(cherry picked from commit 341a453d28e2b8dc97d22cd810d40bffac948af0) +--- + virtManager/error.py | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/virtManager/error.py b/virtManager/error.py +index 8a788ce..1f77a1f 100644 +--- a/virtManager/error.py ++++ b/virtManager/error.py +@@ -75,14 +75,16 @@ class vmmErrorDialog(vmmGObject): + 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): + 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, diff --git a/0007-engine-More-work-to-fix-cascading-error-dialogs.patch b/0007-engine-More-work-to-fix-cascading-error-dialogs.patch new file mode 100644 index 0000000..e0a21bb --- /dev/null +++ b/0007-engine-More-work-to-fix-cascading-error-dialogs.patch @@ -0,0 +1,180 @@ +From a9d30657b1865fa6efbced51e744b0450298e48a Mon Sep 17 00:00:00 2001 +From: Cole Robinson +Date: Wed, 16 Apr 2014 10:32:52 -0400 +Subject: [PATCH] engine: More work to fix cascading error dialogs + +If a remote network connection stalls, the tick queue becomes backed +up while we wait for the hung connection to continue. While this +happens, the queue is filled up with other requests to poll the hung +connection. + +When the connection finally times out, the tick thread closes the +connection via an idle callback. However before that callback gets +a chance to run, all the other poll requests for the dead connection +are processed, all launching their own error dialog. + +Mark the connection as 'closing' before conn.close is scheduled, and +use it to short circuit the tick() routine. + +(cherry picked from commit 1f7604b2413a7a4431703f300fd854489e864c71) +--- + virtManager/connection.py | 46 ++++++++++++++++++++++++++++++++++++++++++-- + virtManager/engine.py | 49 +++++++++++------------------------------------ + 2 files changed, 55 insertions(+), 40 deletions(-) + +diff --git a/virtManager/connection.py b/virtManager/connection.py +index 27d5bd9..ffc2f27 100644 +--- a/virtManager/connection.py ++++ b/virtManager/connection.py +@@ -89,6 +89,7 @@ class vmmConnection(vmmGObject): + self.connectThread = None + self.connectError = None + self._backend = virtinst.VirtualConnection(self._uri) ++ self._closing = False + + self._caps = None + self._caps_xml = None +@@ -959,6 +960,10 @@ class vmmConnection(vmmGObject): + 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: +@@ -1004,6 +1009,7 @@ class vmmConnection(vmmGObject): + self.vms = {} + + self._change_state(self.STATE_DISCONNECTED) ++ self._closing = False + + def _cleanup(self): + self.close() +@@ -1166,7 +1172,43 @@ class vmmConnection(vmmGObject): + 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, +@@ -1175,7 +1217,7 @@ class vmmConnection(vmmGObject): + 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: +diff --git a/virtManager/engine.py b/virtManager/engine.py +index 0e5e15d..e41c829 100644 +--- a/virtManager/engine.py ++++ b/virtManager/engine.py +@@ -28,8 +28,8 @@ import logging + import re + import Queue + import threading ++import traceback + +-import libvirt + from virtinst import util + + from virtManager import packageutils +@@ -338,46 +338,19 @@ class vmmEngine(vmmGObject): + + 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 diff --git a/virt-manager.spec b/virt-manager.spec index d27578c..98d29b0 100644 --- a/virt-manager.spec +++ b/virt-manager.spec @@ -20,7 +20,7 @@ %define _version 1.0.1 -%define _release 1 +%define _release 2 # This macro is used for the continuous automated builds. It just @@ -39,6 +39,20 @@ Group: Applications/Emulators License: GPLv2+ URL: http://virt-manager.org/ Source0: http://virt-manager.org/download/sources/%{name}/%{name}-%{version}.tar.gz + +# gfxdetails: Show port number for active autoport VM (bz #1081614) +Patch0001: 0001-gfxdetails-Show-port-number-for-active-autoport-VM-b.patch +# connection: Hook into domain balloon event (bz #1081424) +Patch0002: 0002-connection-Hook-into-domain-balloon-event-bz-1081424.patch +# details: Fix showing vcpus values in 'customize' dialog (bz #1083903) +Patch0003: 0003-details-Fix-showing-vcpus-values-in-customize-dialog.patch +# details: Fix changing graphics type (bz #1083903) +Patch0004: 0004-details-Fix-changing-graphics-type-bz-1083903.patch +# createpool: Clarify iscsi IQN fields (bz #1084011) +Patch0005: 0005-createpool-Clarify-iscsi-IQN-fields-bz-1084011.patch +# More fixes for errors on libvirtd disconnect (bz #1069351) +Patch0006: 0006-error-Don-t-log-redundant-details-bits.patch +Patch0007: 0007-engine-More-work-to-fix-cascading-error-dialogs.patch BuildArch: noarch @@ -105,6 +119,20 @@ machine). %prep %setup -q +# gfxdetails: Show port number for active autoport VM (bz #1081614) +%patch0001 -p1 +# connection: Hook into domain balloon event (bz #1081424) +%patch0002 -p1 +# details: Fix showing vcpus values in 'customize' dialog (bz #1083903) +%patch0003 -p1 +# details: Fix changing graphics type (bz #1083903) +%patch0004 -p1 +# createpool: Clarify iscsi IQN fields (bz #1084011) +%patch0005 -p1 +# More fixes for errors on libvirtd disconnect (bz #1069351) +%patch0006 -p1 +%patch0007 -p1 + %build %if %{qemu_user} %define _qemu_user --qemu-user=%{qemu_user} @@ -213,6 +241,14 @@ fi %changelog +* Wed Apr 16 2014 Cole Robinson - 1.0.1-2 +- gfxdetails: Show port number for active autoport VM (bz #1081614) +- connection: Hook into domain balloon event (bz #1081424) +- details: Fix showing vcpus values in 'customize' dialog (bz #1083903) +- details: Fix changing graphics type (bz #1083903) +- createpool: Clarify iscsi IQN fields (bz #1084011) +- More fixes for errors on libvirtd disconnect (bz #1069351) + * Sat Mar 22 2014 Cole Robinson - 1.0.1-1 - Rebased to version 1.0.1 - virt-install/virt-xml: New --memorybacking option (Chen Hanxiao)