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): class vmmCloneVM(vmmGObjectUI):
def __init__(self, orig_vm): _instances = {}
vmmGObjectUI.__init__(self, "clone.ui", "vmm-clone")
self.orig_vm = orig_vm
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.clone_design = None
self.storage_list = {} self.storage_list = {}
@ -169,10 +181,17 @@ class vmmCloneVM(vmmGObjectUI):
}) })
self.bind_escape_key_close() 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") logging.debug("Showing clone wizard")
self.vm = vm
self.reset_state() self.reset_state()
self.topwin.set_transient_for(parent) self.topwin.set_transient_for(parent)
self.topwin.resize(1, 1) self.topwin.resize(1, 1)
@ -184,7 +203,7 @@ class vmmCloneVM(vmmGObjectUI):
self.change_storage_close() self.change_storage_close()
self.topwin.hide() self.topwin.hide()
self.orig_vm = None self.vm = None
self.clone_design = None self.clone_design = None
self.storage_list = {} self.storage_list = {}
self.target_list = [] self.target_list = []
@ -194,8 +213,6 @@ class vmmCloneVM(vmmGObjectUI):
return 1 return 1
def _cleanup(self): def _cleanup(self):
self.conn = None
self.change_mac.destroy() self.change_mac.destroy()
self.change_mac = None self.change_mac = None
@ -217,7 +234,7 @@ class vmmCloneVM(vmmGObjectUI):
# First time setup # First time setup
def set_initial_state(self): def _init_ui(self):
blue = Gdk.Color.parse("#0072A8")[1] blue = Gdk.Color.parse("#0072A8")[1]
self.widget("header").modify_bg(Gtk.StateType.NORMAL, blue) 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): def build_new_clone_design(self, new_name=None):
design = Cloner(self.conn.get_backend()) 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: if not new_name:
new_name = design.generate_clone_name() new_name = design.generate_clone_name()
design.clone_name = new_name design.clone_name = new_name
@ -295,7 +312,7 @@ class vmmCloneVM(vmmGObjectUI):
self.net_list[origmac] = net_row self.net_list[origmac] = net_row
self.mac_list.append(origmac) 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 mac = net.macaddr
net_dev = net.source net_dev = net.source
net_type = net.type net_type = net.type
@ -310,7 +327,7 @@ class vmmCloneVM(vmmGObjectUI):
elif net_type == VirtualNetworkInterface.TYPE_VIRTUAL: elif net_type == VirtualNetworkInterface.TYPE_VIRTUAL:
net = None 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: if netobj.get_name() == net_dev:
net = netobj net = netobj
break break
@ -340,7 +357,7 @@ class vmmCloneVM(vmmGObjectUI):
""" """
Determine which storage is cloneable, and which isn't 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 cd = self.clone_design
storage_list = {} storage_list = {}
@ -481,7 +498,7 @@ class vmmCloneVM(vmmGObjectUI):
failinfo = disk[STORAGE_INFO_FAILINFO] failinfo = disk[STORAGE_INFO_FAILINFO]
target = disk[STORAGE_INFO_TARGET] target = disk[STORAGE_INFO_TARGET]
orig_name = self.orig_vm.get_name() orig_name = self.vm.get_name()
disk_label = os.path.basename(origpath) disk_label = os.path.basename(origpath)
info_label = None info_label = None
@ -676,10 +693,6 @@ class vmmCloneVM(vmmGObjectUI):
self.widget("vmm-change-storage").show_all() 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): def change_mac_finish(self, ignore):
orig = self.widget("change-mac-orig").get_text() orig = self.widget("change-mac-orig").get_text()
new = self.widget("change-mac-new").get_text() new = self.widget("change-mac-new").get_text()
@ -798,7 +811,7 @@ class vmmCloneVM(vmmGObjectUI):
self.clone_design = cd self.clone_design = cd
return True return True
def _finish_cb(self, error, details): def _finish_cb(self, error, details, conn):
self.reset_finish_cursor() self.reset_finish_cursor()
if error is not None: if error is not None:
@ -807,8 +820,8 @@ class vmmCloneVM(vmmGObjectUI):
self.err.show_err(error, details=details) self.err.show_err(error, details=details)
return return
conn.schedule_priority_tick(pollvm=True)
self.close() self.close()
self.conn.schedule_priority_tick(pollvm=True)
def finish(self, src_ignore): def finish(self, src_ignore):
try: try:
@ -826,13 +839,14 @@ class vmmCloneVM(vmmGObjectUI):
if self.clone_design.clone_disks: if self.clone_design.clone_disks:
text = title + _(" and selected storage (this may take a while)") 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) title, text, self.topwin)
progWin.run() progWin.run()
def _async_clone(self, asyncjob): def _async_clone(self, asyncjob):
try: try:
self.orig_vm.set_cloning(True) self.vm.set_cloning(True)
meter = asyncjob.get_meter() meter = asyncjob.get_meter()
refresh_pools = [] refresh_pools = []
@ -859,7 +873,7 @@ class vmmCloneVM(vmmGObjectUI):
"VM clone.", poolname, exc_info=True) "VM clone.", poolname, exc_info=True)
finally: finally:
self.orig_vm.set_cloning(False) self.vm.set_cloning(False)
def change_storage_browse(self, ignore): def change_storage_browse(self, ignore):
def callback(src_ignore, txt): def callback(src_ignore, txt):

View File

@ -341,7 +341,6 @@ class vmmDetails(vmmGObjectUI):
__gsignals__ = { __gsignals__ = {
"action-exit-app": (GObject.SignalFlags.RUN_FIRST, None, []), "action-exit-app": (GObject.SignalFlags.RUN_FIRST, None, []),
"action-view-manager": (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-closed": (GObject.SignalFlags.RUN_FIRST, None, []),
"details-opened": (GObject.SignalFlags.RUN_FIRST, None, []), "details-opened": (GObject.SignalFlags.RUN_FIRST, None, []),
"customize-finished": (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 . import packageutils
from .baseclass import vmmGObject from .baseclass import vmmGObject
from .clone import vmmCloneVM
from .connmanager import vmmConnectionManager from .connmanager import vmmConnectionManager
from .connect import vmmConnect from .connect import vmmConnect
from .create import vmmCreate from .create import vmmCreate
@ -55,7 +54,6 @@ class _ConnState(object):
self.probeConnection = probe self.probeConnection = probe
self.windowClone = None
self.windowDetails = {} self.windowDetails = {}
self.windowHost = None self.windowHost = None
@ -179,7 +177,6 @@ class vmmEngine(vmmGObject):
self._systray = vmmSystray() self._systray = vmmSystray()
self._systray.connect("action-toggle-manager", self._do_toggle_manager) self._systray.connect("action-toggle-manager", self._do_toggle_manager)
self._systray.connect("action-show-domain", self._do_show_vm) 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._systray.connect("action-exit-app", self.exit_app)
self.add_gsettings_handle( self.add_gsettings_handle(
@ -504,8 +501,6 @@ class vmmEngine(vmmGObject):
connstate = self._connstates[uri] connstate = self._connstates[uri]
if connstate.windowHost: if connstate.windowHost:
connstate.windowHost.cleanup() connstate.windowHost.cleanup()
if connstate.windowClone:
connstate.windowClone.cleanup()
detailsmap = connstate.windowDetails detailsmap = connstate.windowDetails
for win in list(detailsmap.values()): for win in list(detailsmap.values()):
@ -656,7 +651,6 @@ class vmmEngine(vmmGObject):
obj = vmmDetails(self._connobjs[uri].get_vm(connkey)) obj = vmmDetails(self._connobjs[uri].get_vm(connkey))
obj.connect("action-exit-app", self.exit_app) obj.connect("action-exit-app", self.exit_app)
obj.connect("action-view-manager", self._do_show_manager) 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-opened", self.increment_window_counter)
obj.connect("details-closed", self.decrement_window_counter) obj.connect("details-closed", self.decrement_window_counter)
@ -689,7 +683,6 @@ class vmmEngine(vmmGObject):
return self.windowManager return self.windowManager
obj = vmmManager() obj = vmmManager()
obj.connect("action-clone-domain", self._do_show_clone)
obj.connect("action-show-domain", self._do_show_vm) obj.connect("action-show-domain", self._do_show_vm)
obj.connect("action-show-create", self._do_show_create) obj.connect("action-show-create", self._do_show_create)
obj.connect("action-show-host", self._do_show_host) obj.connect("action-show-host", self._do_show_host)
@ -735,23 +728,6 @@ class vmmEngine(vmmGObject):
except Exception as e: except Exception as e:
src.err.show_err(_("Error launching manager: %s") % str(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 # # 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-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
"action-show-host": (GObject.SignalFlags.RUN_FIRST, None, [str]), "action-show-host": (GObject.SignalFlags.RUN_FIRST, None, [str]),
"action-show-create": (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, []), "action-exit-app": (GObject.SignalFlags.RUN_FIRST, None, []),
"manager-closed": (GObject.SignalFlags.RUN_FIRST, None, []), "manager-closed": (GObject.SignalFlags.RUN_FIRST, None, []),
"manager-opened": (GObject.SignalFlags.RUN_FIRST, None, []), "manager-opened": (GObject.SignalFlags.RUN_FIRST, None, []),

View File

@ -33,7 +33,6 @@ class vmmSystray(vmmGObject):
__gsignals__ = { __gsignals__ = {
"action-toggle-manager": (GObject.SignalFlags.RUN_FIRST, None, []), "action-toggle-manager": (GObject.SignalFlags.RUN_FIRST, None, []),
"action-view-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-host": (GObject.SignalFlags.RUN_FIRST, None, [str]),
"action-show-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]), "action-show-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
"action-exit-app": (GObject.SignalFlags.RUN_FIRST, None, []), "action-exit-app": (GObject.SignalFlags.RUN_FIRST, None, []),

View File

@ -129,7 +129,7 @@ class VMActionMenu(_VMMenu):
self.add(Gtk.SeparatorMenuItem()) self.add(Gtk.SeparatorMenuItem())
self._add_action(_("Clone..."), "clone", self._add_action(_("Clone..."), "clone",
_make_emit_cb("action-clone-domain"), iconname=None) VMActionUI.clone, iconname=None)
self._add_action(_("Migrate..."), "migrate", self._add_action(_("Migrate..."), "migrate",
VMActionUI.migrate, iconname=None) VMActionUI.migrate, iconname=None)
self._add_action(_("_Delete"), "delete", self._add_action(_("_Delete"), "delete",
@ -338,3 +338,8 @@ class VMActionUI(object):
def migrate(src, vm): def migrate(src, vm):
from .migrate import vmmMigrateDialog from .migrate import vmmMigrateDialog
vmmMigrateDialog.show_instance(src, vm) vmmMigrateDialog.show_instance(src, vm)
@staticmethod
def clone(src, vm):
from .clone import vmmCloneVM
vmmCloneVM.show_instance(src, vm)