clone: Convert to per-connection singleton-ish pattern

And convert the dialog VM handling to match other dialogs
This commit is contained in:
Cole Robinson 2018-03-14 18:17:03 -04:00
parent b94a9fdffb
commit 58f872a205
6 changed files with 44 additions and 52 deletions

View File

@ -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):

View File

@ -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, []),

View File

@ -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 #

View File

@ -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, []),

View File

@ -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, []),

View File

@ -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)