From 58f872a205f1cc09c02cac1733b452340af626d4 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Wed, 14 Mar 2018 18:17:03 -0400 Subject: [PATCH] clone: Convert to per-connection singleton-ish pattern And convert the dialog VM handling to match other dialogs --- virtManager/clone.py | 62 ++++++++++++++++++++++++++---------------- virtManager/details.py | 1 - virtManager/engine.py | 24 ---------------- virtManager/manager.py | 1 - virtManager/systray.py | 1 - virtManager/vmmenu.py | 7 ++++- 6 files changed, 44 insertions(+), 52 deletions(-) diff --git a/virtManager/clone.py b/virtManager/clone.py index 43d39122..6934debf 100644 --- a/virtManager/clone.py +++ b/virtManager/clone.py @@ -128,11 +128,23 @@ def do_we_default(conn, vol, path, ro, shared, devtype): class vmmCloneVM(vmmGObjectUI): - def __init__(self, orig_vm): - vmmGObjectUI.__init__(self, "clone.ui", "vmm-clone") - self.orig_vm = orig_vm + _instances = {} - self.conn = self.orig_vm.conn + @classmethod + def show_instance(cls, parentobj, vm): + try: + # Maintain one dialog per connection + uri = vm.conn.get_uri() + if uri not in cls._instances: + cls._instances[uri] = cls() + cls._instances[uri].show(parentobj.topwin, vm) + except Exception as e: + parentobj.err.show_err( + _("Error launching clone dialog: %s") % str(e)) + + def __init__(self): + vmmGObjectUI.__init__(self, "clone.ui", "vmm-clone") + self.vm = None self.clone_design = None self.storage_list = {} @@ -169,10 +181,17 @@ class vmmCloneVM(vmmGObjectUI): }) self.bind_escape_key_close() - self.set_initial_state() + self._init_ui() - def show(self, parent): + @property + def conn(self): + if self.vm: + return self.vm.conn + return None + + def show(self, parent, vm): logging.debug("Showing clone wizard") + self.vm = vm self.reset_state() self.topwin.set_transient_for(parent) self.topwin.resize(1, 1) @@ -184,7 +203,7 @@ class vmmCloneVM(vmmGObjectUI): self.change_storage_close() self.topwin.hide() - self.orig_vm = None + self.vm = None self.clone_design = None self.storage_list = {} self.target_list = [] @@ -194,8 +213,6 @@ class vmmCloneVM(vmmGObjectUI): return 1 def _cleanup(self): - self.conn = None - self.change_mac.destroy() self.change_mac = None @@ -217,7 +234,7 @@ class vmmCloneVM(vmmGObjectUI): # First time setup - def set_initial_state(self): + def _init_ui(self): blue = Gdk.Color.parse("#0072A8")[1] self.widget("header").modify_bg(Gtk.StateType.NORMAL, blue) @@ -255,7 +272,7 @@ class vmmCloneVM(vmmGObjectUI): def build_new_clone_design(self, new_name=None): design = Cloner(self.conn.get_backend()) - design.original_guest = self.orig_vm.get_name() + design.original_guest = self.vm.get_name() if not new_name: new_name = design.generate_clone_name() design.clone_name = new_name @@ -295,7 +312,7 @@ class vmmCloneVM(vmmGObjectUI): self.net_list[origmac] = net_row self.mac_list.append(origmac) - for net in self.orig_vm.get_network_devices(): + for net in self.vm.get_network_devices(): mac = net.macaddr net_dev = net.source net_type = net.type @@ -310,7 +327,7 @@ class vmmCloneVM(vmmGObjectUI): elif net_type == VirtualNetworkInterface.TYPE_VIRTUAL: net = None - for netobj in self.orig_vm.conn.list_nets(): + for netobj in self.vm.conn.list_nets(): if netobj.get_name() == net_dev: net = netobj break @@ -340,7 +357,7 @@ class vmmCloneVM(vmmGObjectUI): """ Determine which storage is cloneable, and which isn't """ - diskinfos = self.orig_vm.get_disk_devices() + diskinfos = self.vm.get_disk_devices() cd = self.clone_design storage_list = {} @@ -481,7 +498,7 @@ class vmmCloneVM(vmmGObjectUI): failinfo = disk[STORAGE_INFO_FAILINFO] target = disk[STORAGE_INFO_TARGET] - orig_name = self.orig_vm.get_name() + orig_name = self.vm.get_name() disk_label = os.path.basename(origpath) info_label = None @@ -676,10 +693,6 @@ class vmmCloneVM(vmmGObjectUI): self.widget("vmm-change-storage").show_all() - def set_orig_vm(self, new_orig): - self.orig_vm = new_orig - self.conn = self.orig_vm.conn - def change_mac_finish(self, ignore): orig = self.widget("change-mac-orig").get_text() new = self.widget("change-mac-new").get_text() @@ -798,7 +811,7 @@ class vmmCloneVM(vmmGObjectUI): self.clone_design = cd return True - def _finish_cb(self, error, details): + def _finish_cb(self, error, details, conn): self.reset_finish_cursor() if error is not None: @@ -807,8 +820,8 @@ class vmmCloneVM(vmmGObjectUI): self.err.show_err(error, details=details) return + conn.schedule_priority_tick(pollvm=True) self.close() - self.conn.schedule_priority_tick(pollvm=True) def finish(self, src_ignore): try: @@ -826,13 +839,14 @@ class vmmCloneVM(vmmGObjectUI): if self.clone_design.clone_disks: text = title + _(" and selected storage (this may take a while)") - progWin = vmmAsyncJob(self._async_clone, [], self._finish_cb, [], + progWin = vmmAsyncJob(self._async_clone, [], + self._finish_cb, [self.conn], title, text, self.topwin) progWin.run() def _async_clone(self, asyncjob): try: - self.orig_vm.set_cloning(True) + self.vm.set_cloning(True) meter = asyncjob.get_meter() refresh_pools = [] @@ -859,7 +873,7 @@ class vmmCloneVM(vmmGObjectUI): "VM clone.", poolname, exc_info=True) finally: - self.orig_vm.set_cloning(False) + self.vm.set_cloning(False) def change_storage_browse(self, ignore): def callback(src_ignore, txt): diff --git a/virtManager/details.py b/virtManager/details.py index 85783da2..f5dbd8e3 100644 --- a/virtManager/details.py +++ b/virtManager/details.py @@ -341,7 +341,6 @@ class vmmDetails(vmmGObjectUI): __gsignals__ = { "action-exit-app": (GObject.SignalFlags.RUN_FIRST, None, []), "action-view-manager": (GObject.SignalFlags.RUN_FIRST, None, []), - "action-clone-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), "details-closed": (GObject.SignalFlags.RUN_FIRST, None, []), "details-opened": (GObject.SignalFlags.RUN_FIRST, None, []), "customize-finished": (GObject.SignalFlags.RUN_FIRST, None, []), diff --git a/virtManager/engine.py b/virtManager/engine.py index 353c9a30..1062b74f 100644 --- a/virtManager/engine.py +++ b/virtManager/engine.py @@ -30,7 +30,6 @@ 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 .create import vmmCreate @@ -55,7 +54,6 @@ class _ConnState(object): self.probeConnection = probe - self.windowClone = None self.windowDetails = {} self.windowHost = None @@ -179,7 +177,6 @@ class vmmEngine(vmmGObject): 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-clone-domain", self._do_show_clone) self._systray.connect("action-exit-app", self.exit_app) self.add_gsettings_handle( @@ -504,8 +501,6 @@ class vmmEngine(vmmGObject): connstate = self._connstates[uri] if connstate.windowHost: connstate.windowHost.cleanup() - if connstate.windowClone: - connstate.windowClone.cleanup() detailsmap = connstate.windowDetails for win in list(detailsmap.values()): @@ -656,7 +651,6 @@ class vmmEngine(vmmGObject): 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-clone-domain", self._do_show_clone) obj.connect("details-opened", self.increment_window_counter) obj.connect("details-closed", self.decrement_window_counter) @@ -689,7 +683,6 @@ class vmmEngine(vmmGObject): return self.windowManager obj = vmmManager() - obj.connect("action-clone-domain", self._do_show_clone) obj.connect("action-show-domain", self._do_show_vm) obj.connect("action-show-create", self._do_show_create) obj.connect("action-show-host", self._do_show_host) @@ -735,23 +728,6 @@ class vmmEngine(vmmGObject): except Exception as e: src.err.show_err(_("Error launching manager: %s") % str(e)) - def _do_show_clone(self, src, uri, connkey): - conn = self._connobjs[uri] - connstate = self._connstates[uri] - orig_vm = conn.get_vm(connkey) - - clone_window = connstate.windowClone - try: - if clone_window is None: - clone_window = vmmCloneVM(orig_vm) - connstate.windowClone = clone_window - else: - clone_window.set_orig_vm(orig_vm) - - clone_window.show(src.topwin) - except Exception as e: - src.err.show_err(_("Error setting clone parameters: %s") % str(e)) - ########################################## # Window launchers from virt-manager cli # diff --git a/virtManager/manager.py b/virtManager/manager.py index ce7a65f3..10fbda1c 100644 --- a/virtManager/manager.py +++ b/virtManager/manager.py @@ -95,7 +95,6 @@ class vmmManager(vmmGObjectUI): "action-show-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), "action-show-host": (GObject.SignalFlags.RUN_FIRST, None, [str]), "action-show-create": (GObject.SignalFlags.RUN_FIRST, None, [str]), - "action-clone-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), "action-exit-app": (GObject.SignalFlags.RUN_FIRST, None, []), "manager-closed": (GObject.SignalFlags.RUN_FIRST, None, []), "manager-opened": (GObject.SignalFlags.RUN_FIRST, None, []), diff --git a/virtManager/systray.py b/virtManager/systray.py index 187047f6..91029506 100644 --- a/virtManager/systray.py +++ b/virtManager/systray.py @@ -33,7 +33,6 @@ class vmmSystray(vmmGObject): __gsignals__ = { "action-toggle-manager": (GObject.SignalFlags.RUN_FIRST, None, []), "action-view-manager": (GObject.SignalFlags.RUN_FIRST, None, []), - "action-clone-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), "action-show-host": (GObject.SignalFlags.RUN_FIRST, None, [str]), "action-show-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), "action-exit-app": (GObject.SignalFlags.RUN_FIRST, None, []), diff --git a/virtManager/vmmenu.py b/virtManager/vmmenu.py index b8220db7..166e13ef 100644 --- a/virtManager/vmmenu.py +++ b/virtManager/vmmenu.py @@ -129,7 +129,7 @@ class VMActionMenu(_VMMenu): self.add(Gtk.SeparatorMenuItem()) self._add_action(_("Clone..."), "clone", - _make_emit_cb("action-clone-domain"), iconname=None) + VMActionUI.clone, iconname=None) self._add_action(_("Migrate..."), "migrate", VMActionUI.migrate, iconname=None) self._add_action(_("_Delete"), "delete", @@ -338,3 +338,8 @@ class VMActionUI(object): def migrate(src, vm): from .migrate import vmmMigrateDialog vmmMigrateDialog.show_instance(src, vm) + + @staticmethod + def clone(src, vm): + from .clone import vmmCloneVM + vmmCloneVM.show_instance(src, vm)