1
0
mirror of https://src.fedoraproject.org/rpms/virt-manager.git synced 2025-07-16 17:14:53 +00:00

Fix parsing rawhide .treeinfo (bz #989162)

Fix spice with TLS (bz #904295)
Reduce impact of memory leak (bz #972371)
This commit is contained in:
Cole Robinson
2013-09-24 11:42:18 -04:00
parent b39288a2d1
commit ff5bbfd309
8 changed files with 1024 additions and 1 deletions

View File

@@ -0,0 +1,24 @@
From 17406905d786734e9d30b3a808314f7bb1e28891 Mon Sep 17 00:00:00 2001
From: Lars Seipel <lars.seipel@gmail.com>
Date: Mon, 29 Jul 2013 12:28:22 -0400
Subject: [PATCH] Fix rawhide URL installs
https://bugzilla.redhat.com/show_bug.cgi?id=989162
(cherry picked from commit 72648c9185e3ccb27fb9896a4e7a48f1769c8a4e)
---
virtinst/OSDistro.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/virtinst/OSDistro.py b/virtinst/OSDistro.py
index 5ecfdf6..780823c 100644
--- a/virtinst/OSDistro.py
+++ b/virtinst/OSDistro.py
@@ -512,7 +512,7 @@ class FedoraDistro(RedHatDistro):
if ret:
lateststr, latestnum = self._latestFedoraVariant()
ver = self.treeinfo.get("general", "version")
- if ver == "development":
+ if ver == "development" or ver == "rawhide":
self.os_variant = self._latestFedoraVariant()
elif ver:
vernum = int(str(ver).split("-")[0])

View File

@@ -0,0 +1,94 @@
From 11eb5ff728413ca1b3c6404e4e42550add553355 Mon Sep 17 00:00:00 2001
From: Cole Robinson <crobinso@redhat.com>
Date: Sun, 1 Sep 2013 16:08:14 -0400
Subject: [PATCH] console: Fix spice with TLS (bz #904295)
We now use the same CA trust store as virt-viewer's default, which is:
~/.spicec/spice_truststore.pem
(cherry picked from commit cdc82e62a236d0e737851c693d6673f65ca278c1)
Conflicts:
virtManager/console.py
---
virtManager/console.py | 26 +++++++++++++++-----------
1 file changed, 15 insertions(+), 11 deletions(-)
diff --git a/virtManager/console.py b/virtManager/console.py
index 001318e..90db31c 100644
--- a/virtManager/console.py
+++ b/virtManager/console.py
@@ -63,6 +63,7 @@ class ConnectionInfo(object):
self.gport = gdev.port and str(gdev.port) or None
self.gsocket = gdev.socket
self.gaddr = gdev.listen or "127.0.0.1"
+ self.gtlsport = gdev.tlsPort or None
self.transport, self.connuser = conn.get_transport()
self._connhost = conn.get_uri_hostname() or "127.0.0.1"
@@ -80,19 +81,22 @@ class ConnectionInfo(object):
def get_conn_host(self):
host = self._connhost
port = self._connport
+ tlsport = None
if not self.need_tunnel():
port = self.gport
+ tlsport = self.gtlsport
if self.gaddr != "0.0.0.0":
host = self.gaddr
- return host, port
+ return host, port, tlsport
def logstring(self):
return ("proto=%s trans=%s connhost=%s connuser=%s "
- "connport=%s gaddr=%s gport=%s gsocket=%s" %
+ "connport=%s gaddr=%s gport=%s gtlsport=%s gsocket=%s" %
(self.gtype, self.transport, self._connhost, self.connuser,
- self._connport, self.gaddr, self.gport, self.gsocket))
+ self._connport, self.gaddr, self.gport, self.gtlsport,
+ self.gsocket))
def console_active(self):
if self.gsocket:
return True
@@ -111,7 +115,7 @@ class Tunnel(object):
if self.outfd is not None:
return -1
- host, port = ginfo.get_conn_host()
+ host, port, ignore = ginfo.get_conn_host()
# Build SSH cmd
argv = ["ssh", "ssh"]
@@ -406,7 +410,7 @@ class VNCViewer(Viewer):
return self.display.is_open()
def open_host(self, ginfo, password=None):
- host, port = ginfo.get_conn_host()
+ host, port, ignore = ginfo.get_conn_host()
if not ginfo.gsocket:
logging.debug("VNC connection to %s:%s", host, port)
@@ -553,14 +557,14 @@ class SpiceViewer(Viewer):
return self.display_channel.get_properties("width", "height")
def open_host(self, ginfo, password=None):
- host, port = ginfo.get_conn_host()
-
- uri = "spice://"
- uri += str(host) + "?port=" + str(port)
- logging.debug("spice uri: %s", uri)
+ host, port, tlsport = ginfo.get_conn_host()
self.spice_session = SpiceClientGLib.Session()
- self.spice_session.set_property("uri", uri)
+ SpiceClientGLib.set_session_option(self.spice_session)
+ self.spice_session.set_property("host", str(host))
+ self.spice_session.set_property("port", str(port))
+ if tlsport:
+ self.spice_session.set_property("tls-port", str(tlsport))
if password:
self.spice_session.set_property("password", password)
GObject.GObject.connect(self.spice_session, "channel-new",

View File

@@ -0,0 +1,165 @@
From 0c452553f19bcaf9cf5ebc52d1d18014ffe10160 Mon Sep 17 00:00:00 2001
From: Cole Robinson <crobinso@redhat.com>
Date: Sun, 1 Sep 2013 21:35:23 -0400
Subject: [PATCH] manager: Disable graph data func if graph isn't visible
Seems like pygobject is a bit leaky with tree row accesses, and
the cell cb hammers on that quite a bit, even if the graph isn't showing.
(cherry picked from commit db7db9ab47dd00d746cf8a3359c1c26dbfcfa50e)
---
virtManager/manager.py | 82 ++++++++++++++++++++++----------------------------
1 file changed, 36 insertions(+), 46 deletions(-)
diff --git a/virtManager/manager.py b/virtManager/manager.py
index bdc21cf..ca9d909 100644
--- a/virtManager/manager.py
+++ b/virtManager/manager.py
@@ -270,15 +270,11 @@ class vmmManager(vmmGObjectUI):
self.config.on_stats_enable_net_poll_changed(self.enable_polling,
COL_NETWORK))
+ self.toggle_guest_cpu_usage_visible_widget()
+ self.toggle_host_cpu_usage_visible_widget()
+ self.toggle_disk_io_visible_widget()
+ self.toggle_network_traffic_visible_widget()
- self.widget("menu_view_stats_guest_cpu").set_active(
- self.config.is_vmlist_guest_cpu_usage_visible())
- self.widget("menu_view_stats_host_cpu").set_active(
- self.config.is_vmlist_host_cpu_usage_visible())
- self.widget("menu_view_stats_disk").set_active(
- self.config.is_vmlist_disk_io_visible())
- self.widget("menu_view_stats_network").set_active(
- self.config.is_vmlist_network_traffic_visible())
def init_toolbar(self):
self.widget("vm-new").set_icon_name("vm_new")
@@ -428,7 +424,7 @@ class vmmManager(vmmGObjectUI):
nameCol.add_attribute(name_txt, 'foreground', ROW_COLOR)
nameCol.set_sort_column_id(COL_NAME)
- def make_stats_column(title, datafunc, is_visible, colnum):
+ def make_stats_column(title, colnum):
col = Gtk.TreeViewColumn(title)
col.set_min_width(140)
@@ -443,29 +439,15 @@ class vmmManager(vmmGObjectUI):
img.set_property("reversed", True)
col.pack_start(img, True)
col.add_attribute(img, 'visible', ROW_IS_VM)
- col.set_cell_data_func(img, datafunc, None)
- col.set_visible(is_visible)
col.set_sort_column_id(colnum)
vmlist.append_column(col)
return col
- self.guestcpucol = make_stats_column(_("CPU usage"),
- self.guest_cpu_usage_img,
- self.config.is_vmlist_guest_cpu_usage_visible(),
- COL_GUEST_CPU)
- self.hostcpucol = make_stats_column(_("Host CPU usage"),
- self.host_cpu_usage_img,
- self.config.is_vmlist_host_cpu_usage_visible(),
- COL_HOST_CPU)
- self.diskcol = make_stats_column(_("Disk I/O"),
- self.disk_io_img,
- self.config.is_vmlist_disk_io_visible(),
- COL_DISK)
- self.netcol = make_stats_column(_("Network I/O"),
- self.network_traffic_img,
- self.config.is_vmlist_network_traffic_visible(),
- COL_NETWORK)
+ self.guestcpucol = make_stats_column(_("CPU usage"), COL_GUEST_CPU)
+ self.hostcpucol = make_stats_column(_("Host CPU usage"), COL_HOST_CPU)
+ self.diskcol = make_stats_column(_("Disk I/O"), COL_DISK)
+ self.netcol = make_stats_column(_("Network I/O"), COL_NETWORK)
model.set_sort_func(COL_NAME, self.vmlist_name_sorter)
model.set_sort_func(COL_GUEST_CPU, self.vmlist_guest_cpu_usage_sorter)
@@ -1196,25 +1178,33 @@ class vmmManager(vmmGObjectUI):
current_text = current_text + disabled_text
widget.set_label(current_text)
- def toggle_network_traffic_visible_widget(self):
- val = self.config.is_vmlist_network_traffic_visible()
- self.netcol.set_visible(val)
- self.widget("menu_view_stats_network").set_active(val)
+ def _toggle_graph_helper(self, do_show, col, datafunc, menu):
+ img = -1
+ for child in col.get_cells():
+ if isinstance(child, CellRendererSparkline):
+ img = child
+ datafunc = do_show and datafunc or None
- def toggle_disk_io_visible_widget(self):
- val = self.config.is_vmlist_disk_io_visible()
- self.diskcol.set_visible(val)
- self.widget("menu_view_stats_disk").set_active(val)
+ col.set_cell_data_func(img, datafunc, None)
+ col.set_visible(do_show)
+ self.widget(menu).set_active(do_show)
+ def toggle_network_traffic_visible_widget(self):
+ self._toggle_graph_helper(
+ self.config.is_vmlist_network_traffic_visible(), self.netcol,
+ self.network_traffic_img, "menu_view_stats_network")
+ def toggle_disk_io_visible_widget(self):
+ self._toggle_graph_helper(
+ self.config.is_vmlist_disk_io_visible(), self.diskcol,
+ self.disk_io_img, "menu_view_stats_disk")
def toggle_guest_cpu_usage_visible_widget(self):
- val = self.config.is_vmlist_guest_cpu_usage_visible()
- self.guestcpucol.set_visible(val)
- self.widget("menu_view_stats_guest_cpu").set_active(val)
-
+ self._toggle_graph_helper(
+ self.config.is_vmlist_guest_cpu_usage_visible(), self.guestcpucol,
+ self.guest_cpu_usage_img, "menu_view_stats_guest_cpu")
def toggle_host_cpu_usage_visible_widget(self):
- val = self.config.is_vmlist_host_cpu_usage_visible()
- self.hostcpucol.set_visible(val)
- self.widget("menu_view_stats_host_cpu").set_active(val)
+ self._toggle_graph_helper(
+ self.config.is_vmlist_host_cpu_usage_visible(), self.hostcpucol,
+ self.host_cpu_usage_img, "menu_view_stats_host_cpu")
def toggle_stats_visible(self, src, stats_id):
visible = src.get_active()
@@ -1236,7 +1226,7 @@ class vmmManager(vmmGObjectUI):
self.toggle_stats_visible(src, COL_NETWORK)
def guest_cpu_usage_img(self, column_ignore, cell, model, _iter, data):
- obj = model.get_value(_iter, ROW_HANDLE)
+ obj = model[_iter][ROW_HANDLE]
if obj is None or not hasattr(obj, "conn"):
return
@@ -1244,7 +1234,7 @@ class vmmManager(vmmGObjectUI):
cell.set_property('data_array', data)
def host_cpu_usage_img(self, column_ignore, cell, model, _iter, data):
- obj = model.get_value(_iter, ROW_HANDLE)
+ obj = model[_iter][ROW_HANDLE]
if obj is None or not hasattr(obj, "conn"):
return
@@ -1252,7 +1242,7 @@ class vmmManager(vmmGObjectUI):
cell.set_property('data_array', data)
def disk_io_img(self, column_ignore, cell, model, _iter, data):
- obj = model.get_value(_iter, ROW_HANDLE)
+ obj = model[_iter][ROW_HANDLE]
if obj is None or not hasattr(obj, "conn"):
return
@@ -1260,7 +1250,7 @@ class vmmManager(vmmGObjectUI):
cell.set_property('data_array', data)
def network_traffic_img(self, column_ignore, cell, model, _iter, data):
- obj = model.get_value(_iter, ROW_HANDLE)
+ obj = model[_iter][ROW_HANDLE]
if obj is None or not hasattr(obj, "conn"):
return

View File

@@ -0,0 +1,46 @@
From 89d78c1af3f84113ea0d18b4229e98d16c12bfef Mon Sep 17 00:00:00 2001
From: "Richard W.M. Jones" <rjones@redhat.com>
Date: Fri, 28 Jun 2013 18:45:53 +0100
Subject: [PATCH] inspection: Check can_set_row_none before setting icon to
None.
Previously one could set the icon field of a tree model to None, but
with Gtk3 and older versions of pygobject3 this would fail.
Use can_set_row_none to test for this condition and work around it.
The previous traceback was:
Traceback (most recent call last):
File "/home/rjones/d/virt-manager/virtManager/manager.py", line 981, in vm_inspection_changed
self.get_inspection_icon_pixbuf(vm, 16, 16)
File "/usr/lib64/python2.7/site-packages/gi/overrides/Gtk.py", line 1152, in __setitem__
self.model.set_value(self.iter, key, value)
File "/usr/lib64/python2.7/site-packages/gi/overrides/Gtk.py", line 1298, in set_value
Gtk.TreeStore.set_value(self, treeiter, column, value)
File "/usr/lib64/python2.7/site-packages/gi/types.py", line 47, in function
return info.invoke(*args, **kwargs)
TypeError: Argument 3 does not allow None as a value
(cherry picked from commit 9d5c1cdb1c03a8c045ae94ab5324aa7dda68e695)
---
virtManager/manager.py | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/virtManager/manager.py b/virtManager/manager.py
index ca9d909..3682429 100644
--- a/virtManager/manager.py
+++ b/virtManager/manager.py
@@ -959,8 +959,10 @@ class vmmManager(vmmGObjectUI):
return
row = self.rows[self.vm_row_key(vm)]
- row[ROW_INSPECTION_OS_ICON] = \
- self.get_inspection_icon_pixbuf(vm, 16, 16)
+ new_icon = self.get_inspection_icon_pixbuf(vm, 16, 16)
+ if not can_set_row_none:
+ new_icon = new_icon or ""
+ row[ROW_INSPECTION_OS_ICON] = new_icon
model.row_changed(row.path, row.iter)
def get_inspection_icon_pixbuf(self, vm, w, h):

View File

@@ -0,0 +1,147 @@
From 6df408590cf0c4c094bcc5e8700700118e2d71c6 Mon Sep 17 00:00:00 2001
From: Giuseppe Scrivano <gscrivan@redhat.com>
Date: Fri, 16 Aug 2013 15:59:33 +0200
Subject: [PATCH] virt-manager: ignore VIR_ERR_NO_DOMAIN when a domain was just
deleted
Some callbacks could try to access a domain that was just deleted and
not accessible anymore. Detect these cases and don't propagate the
exception.
Signed-off-by: Giuseppe Scrivano <gscrivan@redhat.com>
(cherry picked from commit c1fa43ebb90c26c57f72faaf6c0b6a5c19221dd4)
Conflicts:
virtManager/uihelpers.py
---
virtManager/details.py | 10 ++++++++--
virtManager/domain.py | 14 +++++++++-----
virtManager/manager.py | 29 ++++++++++++++++++-----------
virtManager/uihelpers.py | 5 +++++
4 files changed, 40 insertions(+), 18 deletions(-)
diff --git a/virtManager/details.py b/virtManager/details.py
index b2d496e..79db2cf 100644
--- a/virtManager/details.py
+++ b/virtManager/details.py
@@ -2598,8 +2598,14 @@ class vmmDetails(vmmGObjectUI):
# If the dialog is visible, we want to make sure the XML is always
# up to date
- if self.is_visible():
- self.vm.refresh_xml()
+ try:
+ if self.is_visible():
+ self.vm.refresh_xml()
+ except libvirt.libvirtError, e:
+ if uihelpers.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
+ self.close()
+ return
+ raise
# Stats page needs to be refreshed every tick
if (page == PAGE_DETAILS and
diff --git a/virtManager/domain.py b/virtManager/domain.py
index bd3d964..486664f 100644
--- a/virtManager/domain.py
+++ b/virtManager/domain.py
@@ -32,6 +32,7 @@ from virtinst.VirtualCharDevice import VirtualCharSpicevmcDevice
import virtinst.support as support
from virtManager import util
+from virtManager import uihelpers
from virtManager.libvirtobject import vmmLibvirtObject
@@ -406,7 +407,12 @@ class vmmDomain(vmmLibvirtObject):
caps=self.conn.get_capabilities())
def _reparse_xml(self, ignore=None):
- self._guest = self._build_guest(self._get_domain_xml())
+ try:
+ self._guest = self._build_guest(self._get_domain_xml())
+ except libvirt.libvirtError, e:
+ if uihelpers.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
+ return
+ raise
##############################
@@ -1566,14 +1572,12 @@ class vmmDomain(vmmLibvirtObject):
"""
try:
info = self._backend.info()
+ self._update_status(info[0])
except libvirt.libvirtError, e:
- if (hasattr(libvirt, "VIR_ERR_NO_DOMAIN") and
- e.get_error_code() == getattr(libvirt, "VIR_ERR_NO_DOMAIN")):
- # Possibly a transient domain that was removed on shutdown
+ if uihelpers.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
return
raise
- self._update_status(info[0])
def _update_status(self, status):
"""
diff --git a/virtManager/manager.py b/virtManager/manager.py
index 3682429..97cb068 100644
--- a/virtManager/manager.py
+++ b/virtManager/manager.py
@@ -35,6 +35,7 @@ from virtManager.baseclass import vmmGObjectUI
from virtManager.graphwidgets import CellRendererSparkline
from virtManager import util as util
+import libvirt
# Number of data points for performance graphs
GRAPH_LEN = 40
@@ -936,18 +937,24 @@ class vmmManager(vmmGObjectUI):
if self.vm_row_key(vm) not in self.rows:
return
- row = self.rows[self.vm_row_key(vm)]
- row[ROW_NAME] = vm.get_name()
- row[ROW_STATUS] = vm.run_status()
- row[ROW_STATUS_ICON] = vm.run_status_icon_name()
- row[ROW_IS_VM_RUNNING] = vm.is_active()
- row[ROW_MARKUP] = self._build_vm_markup(row)
- if config_changed:
- desc = vm.get_description()
- if not can_set_row_none:
- desc = desc or ""
- row[ROW_HINT] = util.xml_escape(desc)
+ try:
+ row = self.rows[self.vm_row_key(vm)]
+ row[ROW_NAME] = vm.get_name()
+ row[ROW_STATUS] = vm.run_status()
+ row[ROW_STATUS_ICON] = vm.run_status_icon_name()
+ row[ROW_IS_VM_RUNNING] = vm.is_active()
+ row[ROW_MARKUP] = self._build_vm_markup(row)
+
+ if config_changed:
+ desc = vm.get_description()
+ if not can_set_row_none:
+ desc = desc or ""
+ row[ROW_HINT] = util.xml_escape(desc)
+ except libvirt.libvirtError, e:
+ if uihelpers.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
+ return
+ raise
model.row_changed(row.path, row.iter)
diff --git a/virtManager/uihelpers.py b/virtManager/uihelpers.py
index ba69ee9..ff254ab 100644
--- a/virtManager/uihelpers.py
+++ b/virtManager/uihelpers.py
@@ -1027,3 +1027,8 @@ def build_keycombo_menu(cb):
menu.show_all()
return menu
+
+def exception_is_libvirt_error(e, error):
+ import libvirt
+ return (hasattr(libvirt, error) and
+ e.get_error_code() == getattr(libvirt, error))

View File

@@ -0,0 +1,316 @@
From c3e576155228cc3f3f05d3953edadbf589b74d8c Mon Sep 17 00:00:00 2001
From: Cole Robinson <crobinso@redhat.com>
Date: Sun, 1 Sep 2013 18:36:58 -0400
Subject: [PATCH] manager: Merge some row creation, drop unneeded row keys
(cherry picked from commit 1bd6026515324430adbdd7a8b666e1b6a64879c3)
Conflicts:
virtManager/manager.py
---
virtManager/manager.py | 174 ++++++++++++++++++++++---------------------------
1 file changed, 79 insertions(+), 95 deletions(-)
diff --git a/virtManager/manager.py b/virtManager/manager.py
index 97cb068..2770b2f 100644
--- a/virtManager/manager.py
+++ b/virtManager/manager.py
@@ -42,18 +42,16 @@ GRAPH_LEN = 40
# fields in the tree model data set
(ROW_HANDLE,
-ROW_NAME,
+ROW_SORT_KEY,
ROW_MARKUP,
-ROW_STATUS,
ROW_STATUS_ICON,
-ROW_KEY,
ROW_HINT,
ROW_IS_CONN,
ROW_IS_CONN_CONNECTED,
ROW_IS_VM,
ROW_IS_VM_RUNNING,
ROW_COLOR,
-ROW_INSPECTION_OS_ICON) = range(13)
+ROW_INSPECTION_OS_ICON) = range(11)
# Columns in the tree view
COL_NAME = 0
@@ -78,6 +76,24 @@ def _style_get_prop(widget, propname):
return value.get_int()
+def _get_inspection_icon_pixbuf(vm, w, h):
+ # libguestfs gives us the PNG data as a string.
+ png_data = vm.inspection.icon
+ if png_data is None:
+ return None
+
+ try:
+ pb = GdkPixbuf.PixbufLoader()
+ pb.set_size(w, h)
+ pb.write(png_data)
+ pb.close()
+ return pb.get_pixbuf()
+ except:
+ logging.exception("Error loading inspection icon data")
+ vm.inspection.icon = None
+ return None
+
+
class vmmManager(vmmGObjectUI):
__gsignals__ = {
"action-show-connect": (GObject.SignalFlags.RUN_FIRST, None, []),
@@ -380,11 +396,9 @@ class vmmManager(vmmGObjectUI):
rowtypes = []
rowtypes.insert(ROW_HANDLE, object) # backing object
- rowtypes.insert(ROW_NAME, str) # object name
+ rowtypes.insert(ROW_SORT_KEY, str) # object name
rowtypes.insert(ROW_MARKUP, str) # row markup text
- rowtypes.insert(ROW_STATUS, str) # object status string
rowtypes.insert(ROW_STATUS_ICON, str) # status icon name
- rowtypes.insert(ROW_KEY, str) # key/uuid
rowtypes.insert(ROW_HINT, str) # row tooltip
rowtypes.insert(ROW_IS_CONN, bool) # if object is a connection
rowtypes.insert(ROW_IS_CONN_CONNECTED, bool) # if conn is connected
@@ -764,8 +778,8 @@ class vmmManager(vmmGObjectUI):
hint += " (%s)" % _("Double click to connect")
return hint
- def _build_conn_markup(self, conn, row):
- name = util.xml_escape(row[ROW_NAME])
+ def _build_conn_markup(self, conn, name):
+ name = util.xml_escape(name)
text = name
if conn.state == conn.STATE_DISCONNECTED:
text += " - " + _("Not Connected")
@@ -781,31 +795,44 @@ class vmmManager(vmmGObjectUI):
color = "#5b5b5b"
return color
- def _build_vm_markup(self, row):
+ def _build_vm_markup(self, name, status):
domtext = ("<span size='smaller' weight='bold'>%s</span>" %
- util.xml_escape(row[ROW_NAME]))
- statetext = "<span size='smaller'>%s</span>" % row[ROW_STATUS]
+ util.xml_escape(name))
+ statetext = "<span size='smaller'>%s</span>" % status
return domtext + "\n" + statetext
- def _build_vm_row(self, vm):
- row = []
+ def _build_row(self, conn, vm):
+ if conn:
+ name = conn.get_pretty_desc_inactive(False)
+ markup = self._build_conn_markup(conn, name)
+ status = ("<span size='smaller'>%s</span>" %
+ conn.get_state_text())
+ status_icon = None
+ hint = self._build_conn_hint(conn)
+ color = self._build_conn_color(conn)
+ os_icon = None
+ else:
+ name = vm.get_name()
+ status = vm.run_status()
+ markup = self._build_vm_markup(name, status)
+ status_icon = vm.run_status_icon_name()
+ hint = vm.get_description()
+ color = None
+ os_icon = _get_inspection_icon_pixbuf(vm, 16, 16)
- row.insert(ROW_HANDLE, vm)
- row.insert(ROW_NAME, vm.get_name())
- row.insert(ROW_MARKUP, "")
- row.insert(ROW_STATUS, vm.run_status())
- row.insert(ROW_STATUS_ICON, vm.run_status_icon_name())
- row.insert(ROW_KEY, vm.get_uuid())
- row.insert(ROW_HINT, util.xml_escape(vm.get_description()))
- row.insert(ROW_IS_CONN, False)
- row.insert(ROW_IS_CONN_CONNECTED, True)
- row.insert(ROW_IS_VM, True)
- row.insert(ROW_IS_VM_RUNNING, vm.is_active())
- row.insert(ROW_COLOR, None)
- row.insert(ROW_INSPECTION_OS_ICON,
- self.get_inspection_icon_pixbuf(vm, 16, 16))
-
- row[ROW_MARKUP] = self._build_vm_markup(row)
+ row = []
+ row.insert(ROW_HANDLE, conn or vm)
+ row.insert(ROW_SORT_KEY, name)
+ row.insert(ROW_MARKUP, markup)
+ row.insert(ROW_STATUS_ICON, status_icon)
+ row.insert(ROW_HINT, util.xml_escape(hint))
+ row.insert(ROW_IS_CONN, bool(conn))
+ row.insert(ROW_IS_CONN_CONNECTED,
+ bool(conn) and conn.state != conn.STATE_DISCONNECTED)
+ row.insert(ROW_IS_VM, bool(vm))
+ row.insert(ROW_IS_VM_RUNNING, bool(vm) and vm.is_active())
+ row.insert(ROW_COLOR, color)
+ row.insert(ROW_INSPECTION_OS_ICON, os_icon)
return row
@@ -814,7 +841,7 @@ class vmmManager(vmmGObjectUI):
if row_key in self.rows:
return
- row = self._build_vm_row(vm)
+ row = self._build_row(None, vm)
parent = self.rows[conn.get_uri()].iter
_iter = model.append(parent, row)
@@ -824,28 +851,8 @@ class vmmManager(vmmGObjectUI):
# Expand a connection when adding a vm to it
self.widget("vm-list").expand_row(model.get_path(parent), False)
- def _build_conn_row(self, conn):
- row = []
- row.insert(ROW_HANDLE, conn)
- row.insert(ROW_NAME, conn.get_pretty_desc_inactive(False))
- row.insert(ROW_MARKUP, self._build_conn_markup(conn, row))
- row.insert(ROW_STATUS, ("<span size='smaller'>%s</span>" %
- conn.get_state_text()))
- row.insert(ROW_STATUS_ICON, None)
- row.insert(ROW_KEY, conn.get_uri())
- row.insert(ROW_HINT, self._build_conn_hint(conn))
- row.insert(ROW_IS_CONN, True)
- row.insert(ROW_IS_CONN_CONNECTED,
- conn.state != conn.STATE_DISCONNECTED)
- row.insert(ROW_IS_VM, False)
- row.insert(ROW_IS_VM_RUNNING, False)
- row.insert(ROW_COLOR, self._build_conn_color(conn))
- row.insert(ROW_INSPECTION_OS_ICON, None)
-
- return row
-
def _append_conn(self, model, conn):
- row = self._build_conn_row(conn)
+ row = self._build_row(conn, None)
_iter = model.append(None, row)
path = model.get_path(_iter)
@@ -877,11 +884,11 @@ class vmmManager(vmmGObjectUI):
if row[ROW_IS_CONN]:
connrows.append(row)
for row in connrows:
- descs.append(row[ROW_NAME])
+ descs.append(row[ROW_SORT_KEY])
for row in connrows:
conn = row[ROW_HANDLE]
- name = row[ROW_NAME]
+ name = row[ROW_SORT_KEY]
if descs.count(name) <= 1:
continue
@@ -919,7 +926,7 @@ class vmmManager(vmmGObjectUI):
missing = True
for row in range(model.iter_n_children(parent)):
_iter = model.iter_nth_child(parent, row)
- if model.get_value(_iter, ROW_KEY) == vm.get_uuid():
+ if model.get_value(_iter, ROW_HANDLE) == vm:
missing = False
break
@@ -931,20 +938,18 @@ class vmmManager(vmmGObjectUI):
self.vm_resources_sampled(vm)
def vm_resources_sampled(self, vm, config_changed=False):
- vmlist = self.widget("vm-list")
- model = vmlist.get_model()
-
- if self.vm_row_key(vm) not in self.rows:
+ row = self.rows.get(self.vm_row_key(vm), None)
+ if row is None:
return
-
try:
- row = self.rows[self.vm_row_key(vm)]
- row[ROW_NAME] = vm.get_name()
- row[ROW_STATUS] = vm.run_status()
+ name = vm.get_name()
+ status = vm.run_status()
+
+ row[ROW_SORT_KEY] = name
row[ROW_STATUS_ICON] = vm.run_status_icon_name()
row[ROW_IS_VM_RUNNING] = vm.is_active()
- row[ROW_MARKUP] = self._build_vm_markup(row)
+ row[ROW_MARKUP] = self._build_vm_markup(name, status)
if config_changed:
desc = vm.get_description()
@@ -956,53 +961,32 @@ class vmmManager(vmmGObjectUI):
return
raise
- model.row_changed(row.path, row.iter)
+ self.widget("vm-list").get_model().row_changed(row.path, row.iter)
def vm_inspection_changed(self, vm):
- vmlist = self.widget("vm-list")
- model = vmlist.get_model()
-
- if self.vm_row_key(vm) not in self.rows:
+ row = self.rows.get(self.vm_row_key(vm), None)
+ if row is None:
return
row = self.rows[self.vm_row_key(vm)]
- new_icon = self.get_inspection_icon_pixbuf(vm, 16, 16)
+ new_icon = _get_inspection_icon_pixbuf(vm, 16, 16)
if not can_set_row_none:
new_icon = new_icon or ""
row[ROW_INSPECTION_OS_ICON] = new_icon
- model.row_changed(row.path, row.iter)
-
- def get_inspection_icon_pixbuf(self, vm, w, h):
- # libguestfs gives us the PNG data as a string.
- png_data = vm.inspection.icon
- if png_data is None:
- return None
- try:
- pb = GdkPixbuf.PixbufLoader()
- pb.set_size(w, h)
- pb.write(png_data)
- pb.close()
- return pb.get_pixbuf()
- except:
- logging.exception("Error loading inspection icon data")
- vm.inspection.icon = None
- return None
+ self.widget("vm-list").get_model().row_changed(row.path, row.iter)
def conn_state_changed(self, conn):
self.conn_resources_sampled(conn)
self.vm_selected()
def conn_resources_sampled(self, conn, newname=None):
- vmlist = self.widget("vm-list")
- model = vmlist.get_model()
+ model = self.widget("vm-list").get_model()
row = self.rows[conn.get_uri()]
if newname:
- row[ROW_NAME] = newname
- row[ROW_MARKUP] = self._build_conn_markup(conn, row)
- row[ROW_STATUS] = ("<span size='smaller'>%s</span>" %
- conn.get_state_text())
+ row[ROW_SORT_KEY] = newname
+ row[ROW_MARKUP] = self._build_conn_markup(conn, row[ROW_SORT_KEY])
row[ROW_IS_CONN_CONNECTED] = conn.state != conn.STATE_DISCONNECTED
row[ROW_COLOR] = self._build_conn_color(conn)
row[ROW_HINT] = self._build_conn_hint(conn)
@@ -1131,8 +1115,8 @@ class vmmManager(vmmGObjectUI):
#################
def vmlist_name_sorter(self, model, iter1, iter2, ignore):
- return cmp(model.get_value(iter1, ROW_NAME),
- model.get_value(iter2, ROW_NAME))
+ return cmp(model.get_value(iter1, ROW_SORT_KEY),
+ model.get_value(iter2, ROW_SORT_KEY))
def vmlist_guest_cpu_usage_sorter(self, model, iter1, iter2, ignore):
obj1 = model.get_value(iter1, ROW_HANDLE)

View File

@@ -0,0 +1,204 @@
From ed5dc524c54e72ee7f75749f11eb0606dddee8ea Mon Sep 17 00:00:00 2001
From: Cole Robinson <crobinso@redhat.com>
Date: Mon, 2 Sep 2013 09:09:31 -0400
Subject: [PATCH] manager: Separate stats and state update callbacks
There's no need to be resetting row keys like VM name, state, on every
'resources-sampled' signals, since we have had finer grained status-changed
and config-changed signals for a while. This seems to reduce the memory
leak on F19 as well.
(cherry picked from commit f141c77c452d4807b516bdc40a0e86235bf5243a)
Conflicts:
virtManager/manager.py
---
virtManager/manager.py | 100 ++++++++++++++++++++++++++-----------------------
1 file changed, 53 insertions(+), 47 deletions(-)
diff --git a/virtManager/manager.py b/virtManager/manager.py
index 2770b2f..6773ff3 100644
--- a/virtManager/manager.py
+++ b/virtManager/manager.py
@@ -185,9 +185,9 @@ class vmmManager(vmmGObjectUI):
self.init_toolbar()
self.init_context_menus()
- self.vm_selected()
- self.widget("vm-list").get_selection().connect("changed",
- self.vm_selected)
+ self.update_current_selection()
+ self.widget("vm-list").get_selection().connect(
+ "changed", self.update_current_selection)
self.max_disk_rate = 10.0
self.max_net_rate = 10.0
@@ -750,9 +750,9 @@ class vmmManager(vmmGObjectUI):
def vm_added(self, conn, vmuuid):
vm = conn.get_vm(vmuuid)
+ vm.connect("config-changed", self.vm_config_changed)
vm.connect("status-changed", self.vm_status_changed)
- vm.connect("resources-sampled", self.vm_resources_sampled)
- vm.connect("config-changed", self.vm_resources_sampled, True)
+ vm.connect("resources-sampled", self.vm_row_updated)
vm.connect("inspection-changed", self.vm_inspection_changed)
vmlist = self.widget("vm-list")
@@ -868,7 +868,7 @@ class vmmManager(vmmGObjectUI):
conn.connect("vm-added", self.vm_added)
conn.connect("vm-removed", self.vm_removed)
- conn.connect("resources-sampled", self.conn_resources_sampled)
+ conn.connect("resources-sampled", self.conn_row_updated)
conn.connect("state-changed", self.conn_state_changed)
conn.connect("connect-error", self._connect_error)
@@ -893,7 +893,7 @@ class vmmManager(vmmGObjectUI):
continue
newname = conn.get_pretty_desc_inactive(False, True)
- self.conn_resources_sampled(conn, newname)
+ self.conn_state_changed(conn, newname=newname)
def remove_conn(self, engine_ignore, uri):
model = self.widget("vm-list").get_model()
@@ -916,28 +916,13 @@ class vmmManager(vmmGObjectUI):
# State/UI updating methods #
#############################
- def vm_status_changed(self, vm, oldstatus, newstatus):
- ignore = newstatus
- ignore = oldstatus
- parent = self.rows[vm.conn.get_uri()].iter
- vmlist = self.widget("vm-list")
- model = vmlist.get_model()
-
- missing = True
- for row in range(model.iter_n_children(parent)):
- _iter = model.iter_nth_child(parent, row)
- if model.get_value(_iter, ROW_HANDLE) == vm:
- missing = False
- break
-
- if missing:
- self._append_vm(model, vm, vm.conn)
-
- # Update run/shutdown/pause button states
- self.vm_selected()
- self.vm_resources_sampled(vm)
+ def vm_row_updated(self, vm):
+ row = self.rows.get(self.vm_row_key(vm), None)
+ if row is None:
+ return
+ self.widget("vm-list").get_model().row_changed(row.path, row.iter)
- def vm_resources_sampled(self, vm, config_changed=False):
+ def vm_config_changed(self, vm):
row = self.rows.get(self.vm_row_key(vm), None)
if row is None:
return
@@ -951,17 +936,37 @@ class vmmManager(vmmGObjectUI):
row[ROW_IS_VM_RUNNING] = vm.is_active()
row[ROW_MARKUP] = self._build_vm_markup(name, status)
- if config_changed:
- desc = vm.get_description()
- if not can_set_row_none:
- desc = desc or ""
- row[ROW_HINT] = util.xml_escape(desc)
+ desc = vm.get_description()
+ if not can_set_row_none:
+ desc = desc or ""
+ row[ROW_HINT] = util.xml_escape(desc)
except libvirt.libvirtError, e:
if uihelpers.exception_is_libvirt_error(e, "VIR_ERR_NO_DOMAIN"):
return
raise
- self.widget("vm-list").get_model().row_changed(row.path, row.iter)
+ self.vm_row_updated(vm)
+
+ def vm_status_changed(self, vm, oldstatus, newstatus):
+ ignore = newstatus
+ ignore = oldstatus
+ parent = self.rows[vm.conn.get_uri()].iter
+ vmlist = self.widget("vm-list")
+ model = vmlist.get_model()
+
+ missing = True
+ for row in range(model.iter_n_children(parent)):
+ _iter = model.iter_nth_child(parent, row)
+ if model.get_value(_iter, ROW_HANDLE) == vm:
+ missing = False
+ break
+
+ if missing:
+ self._append_vm(model, vm, vm.conn)
+
+ # Update run/shutdown/pause button states
+ self.update_current_selection()
+ self.vm_config_changed(vm)
def vm_inspection_changed(self, vm):
row = self.rows.get(self.vm_row_key(vm), None)
@@ -974,16 +979,10 @@ class vmmManager(vmmGObjectUI):
new_icon = new_icon or ""
row[ROW_INSPECTION_OS_ICON] = new_icon
- self.widget("vm-list").get_model().row_changed(row.path, row.iter)
-
- def conn_state_changed(self, conn):
- self.conn_resources_sampled(conn)
- self.vm_selected()
+ self.vm_row_updated(vm)
- def conn_resources_sampled(self, conn, newname=None):
- model = self.widget("vm-list").get_model()
+ def conn_state_changed(self, conn, newname=None):
row = self.rows[conn.get_uri()]
-
if newname:
row[ROW_SORT_KEY] = newname
row[ROW_MARKUP] = self._build_conn_markup(conn, row[ROW_SORT_KEY])
@@ -994,20 +993,27 @@ class vmmManager(vmmGObjectUI):
if conn.get_state() in [vmmConnection.STATE_DISCONNECTED,
vmmConnection.STATE_CONNECTING]:
# Connection went inactive, delete any VM child nodes
- parent = self.rows[conn.get_uri()].iter
+ parent = row.iter
if parent is not None:
+ model = self.widget("vm-list").get_model()
child = model.iter_children(parent)
while child is not None:
- del self.rows[self.vm_row_key(model.get_value(child,
- ROW_HANDLE))]
+ vm = model[child][ROW_HANDLE]
+ del self.rows[self.vm_row_key(vm)]
model.remove(child)
child = model.iter_children(parent)
+ self.conn_row_updated(conn)
+ self.update_current_selection()
+
+ def conn_row_updated(self, conn):
+ row = self.rows[conn.get_uri()]
+
self.max_disk_rate = max(self.max_disk_rate, conn.disk_io_max_rate())
self.max_net_rate = max(self.max_net_rate,
conn.network_traffic_max_rate())
- model.row_changed(row.path, row.iter)
+ self.widget("vm-list").get_model().row_changed(row.path, row.iter)
def change_run_text(self, can_restore):
if can_restore:
@@ -1019,7 +1025,7 @@ class vmmManager(vmmGObjectUI):
self.vmmenu_items["run"].get_child().set_label(text)
self.widget("vm-run").set_label(strip_text)
- def vm_selected(self, ignore=None):
+ def update_current_selection(self, ignore=None):
vm = self.current_vm()
show_open = bool(vm)

View File

@@ -21,7 +21,7 @@
%define _version 0.10.0
%define _release 1
%define _release 2
# This macro is used for the continuous automated builds. It just
@@ -40,6 +40,17 @@ Group: Applications/Emulators
License: GPLv2+
URL: http://virt-manager.org/
Source0: http://virt-manager.org/download/sources/%{name}/%{name}-%{version}.tar.gz
# Fix parsing rawhide .treeinfo (bz #989162)
Patch0001: 0001-Fix-rawhide-URL-installs.patch
# Fix spice with TLS (bz #904295)
Patch0002: 0002-console-Fix-spice-with-TLS-bz-904295.patch
# Reduce impact of memory leak (bz #972371)
Patch0003: 0003-manager-Disable-graph-data-func-if-graph-isn-t-visib.patch
Patch0004: 0004-inspection-Check-can_set_row_none-before-setting-ico.patch
Patch0005: 0005-virt-manager-ignore-VIR_ERR_NO_DOMAIN-when-a-domain-.patch
Patch0006: 0006-manager-Merge-some-row-creation-drop-unneeded-row-ke.patch
Patch0007: 0007-manager-Separate-stats-and-state-update-callbacks.patch
BuildArch: noarch
@@ -104,6 +115,17 @@ machine).
%prep
%setup -q
# Fix parsing rawhide .treeinfo (bz #989162)
%patch0001 -p1
# Fix spice with TLS (bz #904295)
%patch0002 -p1
# Reduce impact of memory leak (bz #972371)
%patch0003 -p1
%patch0004 -p1
%patch0005 -p1
%patch0006 -p1
%patch0007 -p1
%build
%if %{qemu_user}
%define _qemu_user --qemu-user=%{qemu_user}
@@ -213,6 +235,11 @@ fi
%changelog
* Tue Sep 24 2013 Cole Robinson <crobinso@redhat.com> - 0.10.0-2
- Fix parsing rawhide .treeinfo (bz #989162)
- Fix spice with TLS (bz #904295)
- Reduce impact of memory leak (bz #972371)
* Wed Jun 19 2013 Cole Robinson <crobinso@redhat.com> - 0.10.0-1
- Rebased to version 0.10.0
- Fix screenshots (bz #969410)