engine: break out vmmConnectionManager

Have a separate class for tracking the connection list, and emitting
conn-added and conn-removed signals. It exists as a singleton instance
that UI classes can talk directly to
This commit is contained in:
Cole Robinson 2018-03-14 13:13:22 -04:00
parent befafe9dc7
commit f088537798
8 changed files with 277 additions and 253 deletions

View File

@ -605,21 +605,16 @@ class vmmConfig(object):
# Manager view connection list
def add_conn(self, uri):
uris = self.conf.get("/connections/uris")
if uris is None:
uris = []
if uris.count(uri) == 0:
def get_conn_uris(self):
return self.conf.get("/connections/uris") or []
def add_conn_uri(self, uri):
uris = self.get_conn_uris()
if uri not in uris:
uris.insert(len(uris) - 1, uri)
self.conf.set("/connections/uris", uris)
def remove_conn(self, uri):
uris = self.conf.get("/connections/uris")
if uris is None:
return
if uris.count(uri) != 0:
def remove_conn_uri(self, uri):
uris = self.get_conn_uris()
if uri in uris:
uris.remove(uri)
self.conf.set("/connections/uris", uris)
@ -628,9 +623,6 @@ class vmmConfig(object):
uris.remove(uri)
self.conf.set("/connections/autoconnect", uris)
def get_conn_uris(self):
return self.conf.get("/connections/uris")
# Manager default window size
def get_manager_window_size(self):
w = self.conf.get("/manager-window-width")

View File

@ -0,0 +1,83 @@
#
# Copyright (C) 2018 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
# MA 02110-1301 USA.
#
import logging
from gi.repository import GObject
from .baseclass import vmmGObject
from .connection import vmmConnection
class vmmConnectionManager(vmmGObject):
"""
Tracks the list of connections, emits conn-added and conn-removed
"""
__gsignals__ = {
"conn-added": (GObject.SignalFlags.RUN_FIRST, None, [object]),
"conn-removed": (GObject.SignalFlags.RUN_FIRST, None, [str]),
}
_instance = None
@classmethod
def get_instance(cls, *args, **kwargs):
if not cls._instance:
cls._instance = vmmConnectionManager(*args, **kwargs)
return cls._instance
def __init__(self):
vmmGObject.__init__(self)
self._conns = {}
# Load URIs from gsettings
for uri in self.config.get_conn_uris():
self.add_conn(uri)
def _cleanup(self):
for conn in self._conns.values():
uri = conn.get_uri()
try:
self.emit("conn-removed", uri)
conn.cleanup()
except Exception:
logging.exception("Error cleaning up conn=%s", uri)
self._conns = {}
@property
def conns(self):
return self._conns.copy()
def add_conn(self, uri):
if uri in self._conns:
return self._conns[uri]
conn = vmmConnection(uri)
self._conns[uri] = conn
self.config.add_conn_uri(uri)
self.emit("conn-added", conn)
return conn
def remove_conn(self, uri):
if uri not in self._conns:
return
conn = self._conns.pop(uri)
self.config.remove_conn_uri(uri)
self.emit("conn-removed", uri)
conn.cleanup()

View File

@ -34,14 +34,15 @@ import virtinst
from virtinst import util
from . import uiutil
from .baseclass import vmmGObjectUI
from .addstorage import vmmAddStorage
from .asyncjob import vmmAsyncJob
from .storagebrowse import vmmStorageBrowser
from .connmanager import vmmConnectionManager
from .baseclass import vmmGObjectUI
from .details import vmmDetails
from .domain import vmmDomainVirtinst
from .netlist import vmmNetworkList
from .mediacombo import vmmMediaCombo
from .addstorage import vmmAddStorage
from .netlist import vmmNetworkList
from .storagebrowse import vmmStorageBrowser
# Number of seconds to wait for media detection
DETECT_TIMEOUT = 20
@ -122,9 +123,8 @@ class vmmCreate(vmmGObjectUI):
"create-closed": (GObject.SignalFlags.RUN_FIRST, None, []),
}
def __init__(self, engine):
def __init__(self):
vmmGObjectUI.__init__(self, "create.ui", "vmm-create")
self.engine = engine
self.conn = None
self._capsinfo = None
@ -932,7 +932,8 @@ class vmmCreate(vmmGObjectUI):
model.clear()
default = -1
for connobj in self.engine.connobjs.values():
connmanager = vmmConnectionManager.get_instance()
for connobj in connmanager.conns.values():
if not connobj.is_active():
continue
@ -955,7 +956,7 @@ class vmmCreate(vmmGObjectUI):
if not no_conns:
conn_list.set_active(default)
activeuri, activedesc = model[default]
activeconn = self.engine.connobjs[activeuri]
activeconn = connmanager.conns[activeuri]
self.widget("create-conn-label").set_text(activedesc)
if len(model) <= 1:
@ -1426,8 +1427,9 @@ class vmmCreate(vmmGObjectUI):
def _conn_changed(self, src):
uri = uiutil.get_list_selection(src)
newconn = None
connmanager = vmmConnectionManager.get_instance()
if uri:
newconn = self.engine.connobjs[uri]
newconn = connmanager.conns[uri]
# If we aren't visible, let reset_state handle this for us, which
# has a better chance of reporting error

View File

@ -26,14 +26,13 @@ import traceback
from gi.repository import Gio
from gi.repository import GLib
from gi.repository import GObject
from gi.repository import Gtk
from . import packageutils
from .baseclass import vmmGObject
from .clone import vmmCloneVM
from .connmanager import vmmConnectionManager
from .connect import vmmConnect
from .connection import vmmConnection
from .create import vmmCreate
from .delete import vmmDeleteDialog
from .details import vmmDetails
@ -52,6 +51,17 @@ DETAILS_CONSOLE = 3
PRIO_LOW) = range(1, 3)
class _ConnState(object):
def __init__(self, uri, probe):
self.uri = uri
self.probeConnection = probe
self.windowClone = None
self.windowDetails = {}
self.windowHost = None
class vmmEngine(vmmGObject):
CLI_SHOW_MANAGER = "manager"
CLI_SHOW_DOMAIN_CREATOR = "creator"
@ -60,11 +70,6 @@ class vmmEngine(vmmGObject):
CLI_SHOW_DOMAIN_CONSOLE = "console"
CLI_SHOW_HOST_SUMMARY = "summary"
__gsignals__ = {
"conn-added": (GObject.SignalFlags.RUN_FIRST, None, [object]),
"conn-removed": (GObject.SignalFlags.RUN_FIRST, None, [str]),
}
def __init__(self):
vmmGObject.__init__(self)
@ -73,7 +78,7 @@ class vmmEngine(vmmGObject):
self.windowManager = None
self.windowMigrate = None
self.conns = {}
self._connstates = {}
self.err = vmmErrorDialog()
self.err.set_find_parent_cb(self._find_error_parent_cb)
@ -94,7 +99,7 @@ class vmmEngine(vmmGObject):
self._tick_thread.daemon = True
self._tick_queue = queue.PriorityQueue(100)
vmmInspection.get_instance(self)
vmmInspection.get_instance()
# Counter keeping track of how many manager and details windows
# are open. When it is decremented to 0, close the app or
@ -105,18 +110,16 @@ class vmmEngine(vmmGObject):
self.config.on_stats_update_interval_changed(self.reschedule_timer))
self.schedule_timer()
self.load_stored_uris()
for uri in self._connobjs:
self._add_conn(uri, False)
self._tick_thread.start()
self.tick()
@property
def connobjs(self):
ret = {}
for uri, conndict in self.conns.items():
ret[uri] = conndict["conn"]
return ret
def _connobjs(self):
return vmmConnectionManager.get_instance().conns
############################
@ -146,7 +149,7 @@ class vmmEngine(vmmGObject):
def _default_startup(self, skip_autostart, cliuri):
self._init_systray()
uris = list(self.conns.keys())
uris = list(self._connstates.keys())
if not uris:
logging.debug("No stored URIs found.")
else:
@ -177,7 +180,7 @@ class vmmEngine(vmmGObject):
def _init_systray(self):
self._systray = vmmSystray(self)
self._systray = vmmSystray()
self._systray.connect("action-toggle-manager", self._do_toggle_manager)
self._systray.connect("action-show-domain", self._do_show_vm)
self._systray.connect("action-migrate-domain", self._do_show_migrate)
@ -207,17 +210,18 @@ class vmmEngine(vmmGObject):
logging.debug("Determining default libvirt URI")
ret = None
packages_verified = False
try:
libvirt_packages = self.config.libvirt_packages
packages = self.config.hv_packages + libvirt_packages
ret = packageutils.check_packagekit(manager, manager.err, packages)
packages_verified = packageutils.check_packagekit(
manager, manager.err, packages)
except Exception:
logging.exception("Error talking to PackageKit")
tryuri = None
if ret:
if packages_verified:
tryuri = "qemu:///system"
elif not self.config.test_first_run:
tryuri = vmmConnect.default_uri()
@ -233,28 +237,26 @@ class vmmEngine(vmmGObject):
# Do the initial connection in an idle callback, so the
# packagekit async dialog has a chance to go away
def idle_connect():
do_start = packageutils.start_libvirtd()
connected = self.connect_to_uri(tryuri,
autoconnect=True, do_start=do_start)
if not connected and do_start:
libvirtd_started = packageutils.start_libvirtd()
connected = False
try:
self.connect_to_uri(tryuri, autoconnect=True)
connected = True
except Exception:
logging.exception("Error connecting to %s", tryuri)
if not connected and not libvirtd_started:
manager.err.ok(_("Libvirt service must be started"), warnmsg)
self.idle_add(idle_connect)
def load_stored_uris(self):
uris = self.config.get_conn_uris() or []
for uri in uris:
conn = self.make_conn(uri)
self.register_conn(conn, skip_config=True)
def autostart_conns(self):
"""
We serialize conn autostart, so polkit/ssh-askpass doesn't spam
"""
connections_queue = queue.Queue()
auto_conns = [uri for uri in self.conns
if self.conns[uri]["conn"].get_autoconnect()]
auto_conns = [conn.get_uri() for conn in self._connobjs.values() if
conn.get_autoconnect()]
def add_next_to_queue():
if not auto_conns:
@ -267,55 +269,52 @@ class vmmEngine(vmmGObject):
add_next_to_queue()
conn.disconnect_by_func(state_change_cb)
def connect(uri):
self.connect_to_uri(uri)
def handle_queue():
while True:
uri = connections_queue.get()
if uri is None:
return
if uri not in self.conns:
if uri not in self._connobjs:
add_next_to_queue()
continue
conn = self.conns[uri]["conn"]
conn = self._connobjs[uri]
conn.connect("state-changed", state_change_cb)
self.idle_add(connect, uri)
self.idle_add(self.connect_to_uri, uri)
add_next_to_queue()
self._start_thread(handle_queue, "Conn autostart thread")
def _do_vm_removed(self, conn, connkey):
hvuri = conn.get_uri()
if connkey not in self.conns[hvuri]["windowDetails"]:
detailsmap = self._connstates[conn.get_uri()].windowDetails
if connkey not in detailsmap:
return
self.conns[hvuri]["windowDetails"][connkey].cleanup()
del(self.conns[hvuri]["windowDetails"][connkey])
detailsmap[connkey].cleanup()
detailsmap.pop(connkey)
def _do_vm_renamed(self, conn, oldconnkey, newconnkey):
hvuri = conn.get_uri()
if oldconnkey not in self.conns[hvuri]["windowDetails"]:
detailsmap = self._connstates[conn.get_uri()].windowDetails
if oldconnkey not in detailsmap:
return
self.conns[hvuri]["windowDetails"][newconnkey] = (
self.conns[hvuri]["windowDetails"].pop(oldconnkey))
detailsmap[newconnkey] = detailsmap.pop(oldconnkey)
def _do_conn_changed(self, conn):
if conn.is_active() or conn.is_connecting():
return
hvuri = conn.get_uri()
uri = conn.get_uri()
for connkey in self.conns[hvuri]["windowDetails"].keys():
self.conns[hvuri]["windowDetails"][connkey].cleanup()
del(self.conns[hvuri]["windowDetails"][connkey])
detailsmap = self._connstates[conn.get_uri()].windowDetails
for connkey in list(detailsmap):
detailsmap[connkey].cleanup()
detailsmap.pop(connkey)
if (self.windowCreate and
self.windowCreate.conn and
self.windowCreate.conn.get_uri() == hvuri):
self.windowCreate.conn.get_uri() == uri):
self.windowCreate.close()
def reschedule_timer(self, *args, **kwargs):
@ -348,8 +347,7 @@ class vmmEngine(vmmGObject):
self._add_obj_to_tick_queue(conn, True, **kwargs)
def tick(self):
for uri in self.conns:
conn = self.conns[uri]["conn"]
for conn in self._connobjs.values():
self._add_obj_to_tick_queue(conn, False,
stats_update=True, pollvm=True)
return 1
@ -429,9 +427,10 @@ class vmmEngine(vmmGObject):
# Do this last, so any manually 'disconnected' signals
# take precedence over cleanup signal removal
for uri in self.conns:
self.cleanup_conn(uri)
self.conns = {}
for uri in self._connstates:
self._cleanup_connstate(uri)
self._connstates = {}
vmmConnectionManager.get_instance().cleanup()
def _exit_app_if_no_windows(self, src=None):
def cb():
@ -469,10 +468,9 @@ class vmmEngine(vmmGObject):
focus, and use that
"""
windowlist = [self.windowManager]
for conndict in list(self.conns.values()):
windowlist.extend(list(conndict["windowDetails"].values()))
windowlist.extend(
[conndict["windowHost"] for conndict in list(self.conns.values())])
for connstate in self._connstates.values():
windowlist.extend(list(connstate.windowDetails.values()))
windowlist += [connstate.windowHost]
use_win = None
for window in windowlist:
@ -487,95 +485,49 @@ class vmmEngine(vmmGObject):
if use_win:
return use_win.topwin
def make_conn(self, uri, probe=False):
conn = self._check_conn(uri)
if conn:
return conn
conn = vmmConnection(uri)
self.conns[uri] = {
"conn": conn,
"windowHost": None,
"windowDetails": {},
"windowClone": None,
"probeConnection": probe
}
def _add_conn(self, uri, probe):
if uri in self._connstates:
return self._connobjs[uri]
connstate = _ConnState(uri, probe)
conn = vmmConnectionManager.get_instance().add_conn(uri)
conn.connect("vm-removed", self._do_vm_removed)
conn.connect("vm-renamed", self._do_vm_renamed)
conn.connect("state-changed", self._do_conn_changed)
conn.connect("connect-error", self._connect_error)
conn.connect("priority-tick", self._schedule_priority_tick)
self._connstates[uri] = connstate
return conn
def _remove_conn(self, _src, uri):
self._cleanup_connstate(uri)
self._connstates.pop(uri)
vmmConnectionManager.get_instance().remove_conn(uri)
def register_conn(self, conn, skip_config=False):
# if `skip_config' then the connection is only showed in the ui and
# not added to the config.
if not skip_config and conn.get_uri() not in \
(self.config.get_conn_uris() or []):
self.config.add_conn(conn.get_uri())
self.emit("conn-added", conn)
def connect_to_uri(self, uri, autoconnect=None, probe=False):
conn = self._add_conn(uri, probe=probe)
if autoconnect is not None:
conn.set_autoconnect(bool(autoconnect))
conn.open()
def connect_to_uri(self, uri, autoconnect=None, do_start=True, probe=False):
def _cleanup_connstate(self, uri):
try:
conn = self.make_conn(uri, probe=probe)
self.register_conn(conn)
connstate = self._connstates[uri]
if connstate.windowHost:
connstate.windowHost.cleanup()
if connstate.windowClone:
connstate.windowClone.cleanup()
if autoconnect is not None:
conn.set_autoconnect(bool(autoconnect))
if do_start:
conn.open()
else:
try:
conn.open()
except Exception:
return None
return conn
except Exception:
logging.exception("Error connecting to %s", uri)
return None
def cleanup_conn(self, uri):
try:
if self.conns[uri]["windowHost"]:
self.conns[uri]["windowHost"].cleanup()
if self.conns[uri]["windowClone"]:
self.conns[uri]["windowClone"].cleanup()
details = self.conns[uri]["windowDetails"]
for win in list(details.values()):
detailsmap = connstate.windowDetails
for win in list(detailsmap.values()):
win.cleanup()
self.conns[uri]["conn"].cleanup()
except Exception:
logging.exception("Error cleaning up conn in engine")
def remove_conn(self, src, uri):
ignore = src
self.cleanup_conn(uri)
del(self.conns[uri])
self.emit("conn-removed", uri)
self.config.remove_conn(uri)
def _check_conn(self, uri):
conn = self.conns.get(uri)
if conn:
return conn["conn"]
return None
def _lookup_conn(self, uri):
conn = self._check_conn(uri)
if not conn:
raise RuntimeError(_("Unknown connection URI %s") % uri)
return conn
def _connect_error(self, conn, errmsg, tb, warnconsole):
errmsg = errmsg.strip(" \n")
tb = tb.strip(" \n")
@ -618,7 +570,7 @@ class vmmEngine(vmmGObject):
hint += _("Verify that the 'libvirtd' daemon is running.")
show_errmsg = False
probe_connection = self.conns[conn.get_uri()]["probeConnection"]
connstate = self._connstates[conn.get_uri()]
msg = _("Unable to connect to libvirt %s." % conn.get_uri())
if show_errmsg:
msg += "\n\n%s" % errmsg
@ -631,17 +583,17 @@ class vmmEngine(vmmGObject):
details += "Libvirt URI is: %s\n\n" % conn.get_uri()
details += tb
if probe_connection:
if connstate.probeConnection:
msg += "\n\n"
msg += _("Would you still like to remember this connection?")
title = _("Virtual Machine Manager Connection Failure")
if probe_connection:
if connstate.probeConnection:
remember_connection = self.err.show_err(msg, details, title,
buttons=Gtk.ButtonsType.YES_NO,
dialog_type=Gtk.MessageType.QUESTION, modal=True)
if remember_connection:
self.conns[conn.get_uri()]["probeConnection"] = False
connstate.probeConnection = False
else:
self.idle_add(self._do_edit_connect, self.windowManager, conn)
else:
@ -657,10 +609,11 @@ class vmmEngine(vmmGObject):
####################
def _get_host_dialog(self, uri):
if self.conns[uri]["windowHost"]:
return self.conns[uri]["windowHost"]
connstate = self._connstates[uri]
if connstate.windowHost:
return connstate.windowHost
conn = self._lookup_conn(uri)
conn = self._connobjs[uri]
obj = vmmHost(conn)
obj.connect("action-exit-app", self.exit_app)
@ -668,8 +621,8 @@ class vmmEngine(vmmGObject):
obj.connect("host-opened", self.increment_window_counter)
obj.connect("host-closed", self.decrement_window_counter)
self.conns[uri]["windowHost"] = obj
return self.conns[uri]["windowHost"]
connstate.windowHost = obj
return connstate.windowHost
def _do_show_host(self, src, uri):
try:
@ -682,12 +635,11 @@ class vmmEngine(vmmGObject):
if self.windowConnect:
return self.windowConnect
def completed(src, uri, autoconnect):
ignore = src
return self.connect_to_uri(uri, autoconnect, probe=True)
def completed(_src, uri, autoconnect):
self.connect_to_uri(uri, autoconnect, probe=True)
def cancelled(src):
if not list(self.conns.keys()):
if not self._connstates:
self.exit_app(src)
obj = vmmConnect()
@ -707,16 +659,15 @@ class vmmEngine(vmmGObject):
try:
self._do_show_connect(src, False)
finally:
self.remove_conn(None, connection.get_uri())
self._remove_conn(src, connection.get_uri())
def _get_details_dialog(self, uri, connkey):
if connkey in self.conns[uri]["windowDetails"]:
return self.conns[uri]["windowDetails"][connkey]
detailsmap = self._connstates[uri].windowDetails
if connkey in detailsmap:
return detailsmap[connkey]
conn = self._lookup_conn(uri)
obj = vmmDetails(conn.get_vm(connkey))
obj = vmmDetails(self._connobjs[uri].get_vm(connkey))
obj.connect("action-exit-app", self.exit_app)
obj.connect("action-view-manager", self._do_show_manager)
obj.connect("action-migrate-domain", self._do_show_migrate)
@ -726,12 +677,12 @@ class vmmEngine(vmmGObject):
obj.connect("details-closed", self.decrement_window_counter)
obj.connect("inspection-refresh", self._do_refresh_inspection)
self.conns[uri]["windowDetails"][connkey] = obj
return self.conns[uri]["windowDetails"][connkey]
detailsmap[connkey] = obj
return detailsmap[connkey]
def _show_vm_helper(self, src, uri, vm, page, forcepage):
def _show_vm_helper(self, src, uri, connkey, page, forcepage):
try:
details = self._get_details_dialog(uri, vm.get_connkey())
details = self._get_details_dialog(uri, connkey)
if forcepage or not details.is_visible():
if page == DETAILS_PERF:
@ -748,15 +699,13 @@ class vmmEngine(vmmGObject):
src.err.show_err(_("Error launching details: %s") % str(e))
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)
self._show_vm_helper(src, uri, connkey, None, False)
def get_manager(self):
if self.windowManager:
return self.windowManager
obj = vmmManager(self)
obj = vmmManager()
obj.connect("action-migrate-domain", self._do_show_migrate)
obj.connect("action-delete-domain", self._do_delete_domain)
obj.connect("action-clone-domain", self._do_show_clone)
@ -767,7 +716,7 @@ class vmmEngine(vmmGObject):
obj.connect("action-exit-app", self.exit_app)
obj.connect("manager-opened", self.increment_window_counter)
obj.connect("manager-closed", self.decrement_window_counter)
obj.connect("remove-conn", self.remove_conn)
obj.connect("remove-conn", self._remove_conn)
self.windowManager = obj
return self.windowManager
@ -792,7 +741,7 @@ class vmmEngine(vmmGObject):
if self.windowCreate:
return self.windowCreate
obj = vmmCreate(self)
obj = vmmCreate()
obj.connect("action-show-domain", self._do_show_vm)
obj.connect("create-opened", self.increment_window_counter)
obj.connect("create-closed", self.decrement_window_counter)
@ -807,25 +756,25 @@ class vmmEngine(vmmGObject):
def _do_show_migrate(self, src, uri, connkey):
try:
conn = self._lookup_conn(uri)
vm = conn.get_vm(connkey)
vm = self._connobjs[uri].get_vm(connkey)
if not self.windowMigrate:
self.windowMigrate = vmmMigrateDialog(self)
self.windowMigrate = vmmMigrateDialog()
self.windowMigrate.show(src.topwin, vm)
except Exception as e:
src.err.show_err(_("Error launching migrate dialog: %s") % str(e))
def _do_show_clone(self, src, uri, connkey):
conn = self._lookup_conn(uri)
conn = self._connobjs[uri]
connstate = self._connstates[uri]
orig_vm = conn.get_vm(connkey)
clone_window = self.conns[uri]["windowClone"]
clone_window = connstate.windowClone
try:
if clone_window is None:
clone_window = vmmCloneVM(orig_vm)
self.conns[uri]["windowClone"] = clone_window
connstate.windowClone = clone_window
else:
clone_window.set_orig_vm(orig_vm)
@ -833,13 +782,22 @@ class vmmEngine(vmmGObject):
except Exception as e:
src.err.show_err(_("Error setting clone parameters: %s") % str(e))
def _do_refresh_inspection(self, src_ignore, uri, connkey):
inspection = vmmInspection.get_instance(self)
def _do_delete_domain(self, src, uri, connkey):
vm = self._connobjs[uri].get_vm(connkey)
try:
if not self.delete_dialog:
self.delete_dialog = vmmDeleteDialog()
self.delete_dialog.show(vm, src.topwin)
except Exception as e:
src.err.show_err(_("Error launching delete dialog: %s") % str(e))
def _do_refresh_inspection(self, _src, uri, connkey):
inspection = vmmInspection.get_instance()
if not inspection:
return
conn = self._lookup_conn(uri)
vm = conn.get_vm(connkey)
vm = self._connobjs[uri].get_vm(connkey)
inspection.vm_refresh(vm)
@ -855,7 +813,7 @@ class vmmEngine(vmmGObject):
if clistr.isdigit():
clistr = int(clistr)
for vm in self.conns[uri]["conn"].list_vms():
for vm in self._connobjs[uri].list_vms():
if clistr == vm.get_id():
return vm
elif clistr == vm.get_name():
@ -872,7 +830,7 @@ class vmmEngine(vmmGObject):
(uri, clistr), modal=True)
return
self._show_vm_helper(src, uri, vm, page, True)
self._show_vm_helper(src, uri, vm.get_connkey(), page, True)
def _show_manager(self):
self._do_show_manager(None)
@ -946,16 +904,11 @@ class vmmEngine(vmmGObject):
self._show_manager()
return
conn = self.make_conn(uri)
self.register_conn(conn, skip_config=True)
conn = self._add_conn(uri, False)
if conn.is_disconnected():
# Schedule connection open
def connect():
# We need to wrap this to ignore the return value, otherwise
# the callback will be rescheduled
self.connect_to_uri(uri)
self.idle_add(connect)
self.idle_add(self.connect_to_uri, uri)
if show_window:
if conn.is_active():
@ -975,14 +928,3 @@ class vmmEngine(vmmGObject):
# In case of cli error, we may need to exit the app
logging.debug("Error handling cli command", exc_info=True)
self._exit_app_if_no_windows()
def _do_delete_domain(self, src, uri, connkey):
conn = self._lookup_conn(uri)
vm = conn.get_vm(connkey)
try:
if not self.delete_dialog:
self.delete_dialog = vmmDeleteDialog()
self.delete_dialog.show(vm, src.topwin)
except Exception as e:
src.err.show_err(_("Error launching delete dialog: %s") % str(e))

View File

@ -23,6 +23,7 @@ import queue
import threading
from .baseclass import vmmGObject
from .connmanager import vmmConnectionManager
from .domain import vmmInspectionData
@ -39,11 +40,11 @@ class vmmInspection(vmmGObject):
_libguestfs_installed = None
@classmethod
def get_instance(cls, engine):
def get_instance(cls):
if not cls._instance:
if not cls.libguestfs_installed():
return None
cls._instance = cls(engine)
cls._instance = cls()
return cls._instance
@classmethod
@ -62,7 +63,7 @@ class vmmInspection(vmmGObject):
cls._libguestfs_installed = False
return cls._libguestfs_installed
def __init__(self, engine):
def __init__(self):
vmmGObject.__init__(self)
self._thread = None
@ -76,10 +77,11 @@ class vmmInspection(vmmGObject):
if not val:
return
engine.connect("conn-added", self._conn_added)
engine.connect("conn-removed", self._conn_removed)
for conn in engine.connobjs.values():
self._conn_added(engine, conn)
connmanager = vmmConnectionManager.get_instance()
connmanager.connect("conn-added", self._conn_added)
connmanager.connect("conn-removed", self._conn_removed)
for conn in connmanager.conns.values():
self._conn_added(connmanager, conn)
self._start()
@ -89,11 +91,11 @@ class vmmInspection(vmmGObject):
self._conns = {}
self._cached_data = {}
def _conn_added(self, _engine, conn):
def _conn_added(self, _src, conn):
obj = ("conn_added", conn)
self._q.put(obj)
def _conn_removed(self, _engine, uri):
def _conn_removed(self, _src, uri):
obj = ("conn_removed", uri)
self._q.put(obj)

View File

@ -32,6 +32,7 @@ from virtinst import util
from . import vmmenu
from . import uiutil
from .baseclass import vmmGObjectUI
from .connmanager import vmmConnectionManager
from .graphwidgets import CellRendererSparkline
# Number of data points for performance graphs
@ -103,7 +104,7 @@ class vmmManager(vmmGObjectUI):
"remove-conn": (GObject.SignalFlags.RUN_FIRST, None, [str]),
}
def __init__(self, engine):
def __init__(self):
vmmGObjectUI.__init__(self, "manager.ui", "vmm-manager")
# Mapping of rowkey -> tree model rows to
@ -183,10 +184,11 @@ class vmmManager(vmmGObjectUI):
self.enable_polling(COL_NETWORK)
self.enable_polling(COL_MEM)
engine.connect("conn-added", self._conn_added)
engine.connect("conn-removed", self._conn_removed)
for conn in engine.connobjs.values():
self._conn_added(engine, conn)
connmanager = vmmConnectionManager.get_instance()
connmanager.connect("conn-added", self._conn_added)
connmanager.connect("conn-removed", self._conn_removed)
for conn in connmanager.conns.values():
self._conn_added(connmanager, conn)
##################
@ -658,7 +660,7 @@ class vmmManager(vmmGObjectUI):
return row
def _conn_added(self, _engine, conn):
def _conn_added(self, _src, conn):
# Make sure error page isn't showing
self.widget("vm-notebook").set_current_page(0)
@ -679,9 +681,7 @@ class vmmManager(vmmGObjectUI):
for vm in conn.list_vms():
self.vm_added(conn, vm.get_connkey())
def _conn_removed(self, _engine, uri):
# Called from engine.py signal conn-removed
def _conn_removed(self, _src, uri):
model = self.widget("vm-list").get_model()
parent = self.rows[uri].iter

View File

@ -28,8 +28,9 @@ from gi.repository import Pango
from virtinst import util
from . import uiutil
from .baseclass import vmmGObjectUI
from .asyncjob import vmmAsyncJob
from .baseclass import vmmGObjectUI
from .connmanager import vmmConnectionManager
from .domain import vmmDomain
@ -40,7 +41,7 @@ NUM_COLS = 3
class vmmMigrateDialog(vmmGObjectUI):
def __init__(self, engine):
def __init__(self):
vmmGObjectUI.__init__(self, "migrate.ui", "vmm-migrate")
self.vm = None
self.conn = None
@ -58,7 +59,15 @@ class vmmMigrateDialog(vmmGObjectUI):
})
self.bind_escape_key_close()
self._init_state(engine)
self._init_state()
connmanager = vmmConnectionManager.get_instance()
connmanager.connect("conn-added", self._conn_added)
connmanager.connect("conn-removed", self._conn_removed)
for conn in connmanager.conns.values():
self._conn_added(connmanager, conn)
self.widget("migrate-dest").emit("changed")
def _cleanup(self):
@ -89,7 +98,7 @@ class vmmMigrateDialog(vmmGObjectUI):
# Init helpers #
################
def _init_state(self, engine):
def _init_state(self):
blue = Gdk.color_parse("#0072A8")
self.widget("header").modify_bg(Gtk.StateType.NORMAL, blue)
@ -129,14 +138,6 @@ class vmmMigrateDialog(vmmGObjectUI):
combo.set_model(model)
uiutil.init_combo_text_column(combo, 0)
# Hook up signals to get connection listing
engine.connect("conn-added", self._conn_added)
engine.connect("conn-removed", self._conn_removed)
for conn in engine.connobjs.values():
self._conn_added(engine, conn)
self.widget("migrate-dest").emit("changed")
self.widget("migrate-mode").set_tooltip_text(
self.widget("migrate-mode-label").get_tooltip_text())
self.widget("migrate-unsafe").set_tooltip_text(
@ -272,10 +273,10 @@ class vmmMigrateDialog(vmmGObjectUI):
self.widget("migrate-direct-box").set_visible(not is_tunnel)
self.widget("migrate-tunnel-box").set_visible(is_tunnel)
def _conn_added(self, _engine, conn):
def _conn_added(self, _src, conn):
self._conns[conn.get_uri()] = conn
def _conn_removed(self, _engine, uri):
def _conn_removed(self, _src, uri):
del(self._conns[uri])

View File

@ -25,6 +25,7 @@ from gi.repository import Gtk
from . import vmmenu
from .baseclass import vmmGObject
from .connmanager import vmmConnectionManager
from .error import vmmErrorDialog
@ -40,7 +41,7 @@ class vmmSystray(vmmGObject):
"action-exit-app": (GObject.SignalFlags.RUN_FIRST, None, []),
}
def __init__(self, engine):
def __init__(self):
vmmGObject.__init__(self)
self.topwin = None
@ -59,10 +60,11 @@ class vmmSystray(vmmGObject):
self.show_systray()
engine.connect("conn-added", self._conn_added)
engine.connect("conn-removed", self._conn_removed)
for conn in engine.connobjs.values():
self._conn_added(engine, conn)
connmanager = vmmConnectionManager.get_instance()
connmanager.connect("conn-added", self._conn_added)
connmanager.connect("conn-removed", self._conn_removed)
for conn in connmanager.conns.values():
self._conn_added(connmanager, conn)
def is_visible(self):