mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-08-29 09:49:33 +03:00
engine: Move VM action callbacks to vmmenu.py
Call the callbacks directly rather than using signals. engine.py has become a bit of a catchall for shared functionality and this is a step towards disentangling it
This commit is contained in:
@ -339,14 +339,6 @@ def _label_for_os_type(os_type):
|
||||
|
||||
class vmmDetails(vmmGObjectUI):
|
||||
__gsignals__ = {
|
||||
"action-save-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-destroy-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-suspend-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-resume-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-run-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-shutdown-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-reset-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-reboot-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-exit-app": (GObject.SignalFlags.RUN_FIRST, None, []),
|
||||
"action-view-manager": (GObject.SignalFlags.RUN_FIRST, None, []),
|
||||
"action-migrate-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
@ -470,16 +462,6 @@ class vmmDetails(vmmGObjectUI):
|
||||
"on_details_cancel_customize_clicked": self._customize_cancel_clicked,
|
||||
|
||||
"on_details_menu_virtual_manager_activate": self.control_vm_menu,
|
||||
"on_details_menu_run_activate": self.control_vm_run,
|
||||
"on_details_menu_poweroff_activate": self.control_vm_shutdown,
|
||||
"on_details_menu_reboot_activate": self.control_vm_reboot,
|
||||
"on_details_menu_save_activate": self.control_vm_save,
|
||||
"on_details_menu_reset_activate": self.control_vm_reset,
|
||||
"on_details_menu_destroy_activate": self.control_vm_destroy,
|
||||
"on_details_menu_pause_activate": self.control_vm_pause,
|
||||
"on_details_menu_clone_activate": self.control_vm_clone,
|
||||
"on_details_menu_migrate_activate": self.control_vm_migrate,
|
||||
"on_details_menu_delete_activate": self.control_vm_delete,
|
||||
"on_details_menu_screenshot_activate": self.control_vm_screenshot,
|
||||
"on_details_menu_usb_redirection": self.control_vm_usb_redirection,
|
||||
"on_details_menu_view_toolbar_activate": self.toggle_toolbar,
|
||||
@ -1433,13 +1415,9 @@ class vmmDetails(vmmGObjectUI):
|
||||
self.set_pause_state(not do_pause)
|
||||
|
||||
if do_pause:
|
||||
self.emit("action-suspend-domain",
|
||||
self.vm.conn.get_uri(),
|
||||
self.vm.get_connkey())
|
||||
vmmenu.VMActionUI.suspend(self, self.vm)
|
||||
else:
|
||||
self.emit("action-resume-domain",
|
||||
self.vm.conn.get_uri(),
|
||||
self.vm.get_connkey())
|
||||
vmmenu.VMActionUI.resume(self, self.vm)
|
||||
|
||||
def control_vm_menu(self, src_ignore):
|
||||
can_usb = bool(self.console.details_viewer_has_usb_redirection() and
|
||||
@ -1449,40 +1427,10 @@ class vmmDetails(vmmGObjectUI):
|
||||
def control_vm_run(self, src_ignore):
|
||||
if self.has_unapplied_changes(self.get_hw_row()):
|
||||
return
|
||||
self.emit("action-run-domain",
|
||||
self.vm.conn.get_uri(), self.vm.get_connkey())
|
||||
vmmenu.VMActionUI.run(self, self.vm)
|
||||
|
||||
def control_vm_shutdown(self, src_ignore):
|
||||
self.emit("action-shutdown-domain",
|
||||
self.vm.conn.get_uri(), self.vm.get_connkey())
|
||||
|
||||
def control_vm_reboot(self, src_ignore):
|
||||
self.emit("action-reboot-domain",
|
||||
self.vm.conn.get_uri(), self.vm.get_connkey())
|
||||
|
||||
def control_vm_save(self, src_ignore):
|
||||
self.emit("action-save-domain",
|
||||
self.vm.conn.get_uri(), self.vm.get_connkey())
|
||||
|
||||
def control_vm_reset(self, src_ignore):
|
||||
self.emit("action-reset-domain",
|
||||
self.vm.conn.get_uri(), self.vm.get_connkey())
|
||||
|
||||
def control_vm_destroy(self, src_ignore):
|
||||
self.emit("action-destroy-domain",
|
||||
self.vm.conn.get_uri(), self.vm.get_connkey())
|
||||
|
||||
def control_vm_clone(self, src_ignore):
|
||||
self.emit("action-clone-domain",
|
||||
self.vm.conn.get_uri(), self.vm.get_connkey())
|
||||
|
||||
def control_vm_migrate(self, src_ignore):
|
||||
self.emit("action-migrate-domain",
|
||||
self.vm.conn.get_uri(), self.vm.get_connkey())
|
||||
|
||||
def control_vm_delete(self, src_ignore):
|
||||
self.emit("action-delete-domain",
|
||||
self.vm.conn.get_uri(), self.vm.get_connkey())
|
||||
vmmenu.VMActionUI.shutdown(self, self.vm)
|
||||
|
||||
def control_vm_screenshot(self, src):
|
||||
ignore = src
|
||||
|
@ -39,7 +39,6 @@ from .preferences import vmmPreferences
|
||||
from .manager import vmmManager
|
||||
from .migrate import vmmMigrateDialog
|
||||
from .details import vmmDetails
|
||||
from .asyncjob import vmmAsyncJob
|
||||
from .create import vmmCreate
|
||||
from .host import vmmHost
|
||||
from .error import vmmErrorDialog
|
||||
@ -176,14 +175,6 @@ class vmmEngine(vmmGObject):
|
||||
def _init_systray(self):
|
||||
self._systray = vmmSystray()
|
||||
self._systray.connect("action-toggle-manager", self._do_toggle_manager)
|
||||
self._systray.connect("action-suspend-domain", self._do_suspend_domain)
|
||||
self._systray.connect("action-resume-domain", self._do_resume_domain)
|
||||
self._systray.connect("action-run-domain", self._do_run_domain)
|
||||
self._systray.connect("action-shutdown-domain", self._do_shutdown_domain)
|
||||
self._systray.connect("action-reboot-domain", self._do_reboot_domain)
|
||||
self._systray.connect("action-destroy-domain", self._do_destroy_domain)
|
||||
self._systray.connect("action-reset-domain", self._do_reset_domain)
|
||||
self._systray.connect("action-save-domain", self._do_save_domain)
|
||||
self._systray.connect("action-show-domain", self._do_show_vm)
|
||||
self._systray.connect("action-migrate-domain", self._do_show_migrate)
|
||||
self._systray.connect("action-delete-domain", self._do_delete_domain)
|
||||
@ -781,14 +772,6 @@ class vmmEngine(vmmGObject):
|
||||
conn = self._lookup_conn(uri)
|
||||
|
||||
obj = vmmDetails(conn.get_vm(connkey))
|
||||
obj.connect("action-save-domain", self._do_save_domain)
|
||||
obj.connect("action-destroy-domain", self._do_destroy_domain)
|
||||
obj.connect("action-reset-domain", self._do_reset_domain)
|
||||
obj.connect("action-suspend-domain", self._do_suspend_domain)
|
||||
obj.connect("action-resume-domain", self._do_resume_domain)
|
||||
obj.connect("action-run-domain", self._do_run_domain)
|
||||
obj.connect("action-shutdown-domain", self._do_shutdown_domain)
|
||||
obj.connect("action-reboot-domain", self._do_reboot_domain)
|
||||
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)
|
||||
@ -829,14 +812,6 @@ class vmmEngine(vmmGObject):
|
||||
return self.windowManager
|
||||
|
||||
obj = vmmManager()
|
||||
obj.connect("action-suspend-domain", self._do_suspend_domain)
|
||||
obj.connect("action-resume-domain", self._do_resume_domain)
|
||||
obj.connect("action-run-domain", self._do_run_domain)
|
||||
obj.connect("action-shutdown-domain", self._do_shutdown_domain)
|
||||
obj.connect("action-reboot-domain", self._do_reboot_domain)
|
||||
obj.connect("action-destroy-domain", self._do_destroy_domain)
|
||||
obj.connect("action-reset-domain", self._do_reset_domain)
|
||||
obj.connect("action-save-domain", self._do_save_domain)
|
||||
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)
|
||||
@ -1059,178 +1034,6 @@ class vmmEngine(vmmGObject):
|
||||
logging.debug("Error handling cli command", exc_info=True)
|
||||
self._exit_app_if_no_windows()
|
||||
|
||||
|
||||
#######################################
|
||||
# Domain actions run/destroy/save ... #
|
||||
#######################################
|
||||
|
||||
def _do_save_domain(self, src, uri, connkey):
|
||||
conn = self._lookup_conn(uri)
|
||||
vm = conn.get_vm(connkey)
|
||||
|
||||
if not src.err.chkbox_helper(self.config.get_confirm_poweroff,
|
||||
self.config.set_confirm_poweroff,
|
||||
text1=_("Are you sure you want to save '%s'?") % vm.get_name()):
|
||||
return
|
||||
|
||||
_cancel_cb = None
|
||||
if vm.getjobinfo_supported:
|
||||
_cancel_cb = (self._save_cancel, vm)
|
||||
|
||||
def cb(asyncjob):
|
||||
vm.save(meter=asyncjob.get_meter())
|
||||
def finish_cb(error, details):
|
||||
if error is not None:
|
||||
error = _("Error saving domain: %s") % error
|
||||
src.err.show_err(error, details=details)
|
||||
|
||||
progWin = vmmAsyncJob(cb, [],
|
||||
finish_cb, [],
|
||||
_("Saving Virtual Machine"),
|
||||
_("Saving virtual machine memory to disk "),
|
||||
src.topwin, cancel_cb=_cancel_cb)
|
||||
progWin.run()
|
||||
|
||||
def _save_cancel(self, asyncjob, vm):
|
||||
logging.debug("Cancelling save job")
|
||||
if not vm:
|
||||
return
|
||||
|
||||
try:
|
||||
vm.abort_job()
|
||||
except Exception as e:
|
||||
logging.exception("Error cancelling save job")
|
||||
asyncjob.show_warning(_("Error cancelling save job: %s") % str(e))
|
||||
return
|
||||
|
||||
asyncjob.job_canceled = True
|
||||
return
|
||||
|
||||
def _do_destroy_domain(self, src, uri, connkey):
|
||||
conn = self._lookup_conn(uri)
|
||||
vm = conn.get_vm(connkey)
|
||||
|
||||
if not src.err.chkbox_helper(
|
||||
self.config.get_confirm_forcepoweroff,
|
||||
self.config.set_confirm_forcepoweroff,
|
||||
text1=_("Are you sure you want to force poweroff '%s'?" %
|
||||
vm.get_name()),
|
||||
text2=_("This will immediately poweroff the VM without "
|
||||
"shutting down the OS and may cause data loss.")):
|
||||
return
|
||||
|
||||
logging.debug("Destroying vm '%s'", vm.get_name())
|
||||
vmmAsyncJob.simple_async_noshow(vm.destroy, [], src,
|
||||
_("Error shutting down domain"))
|
||||
|
||||
def _do_suspend_domain(self, src, uri, connkey):
|
||||
conn = self._lookup_conn(uri)
|
||||
vm = conn.get_vm(connkey)
|
||||
|
||||
if not src.err.chkbox_helper(self.config.get_confirm_pause,
|
||||
self.config.set_confirm_pause,
|
||||
text1=_("Are you sure you want to pause '%s'?" %
|
||||
vm.get_name())):
|
||||
return
|
||||
|
||||
logging.debug("Pausing vm '%s'", vm.get_name())
|
||||
vmmAsyncJob.simple_async_noshow(vm.suspend, [], src,
|
||||
_("Error pausing domain"))
|
||||
|
||||
def _do_resume_domain(self, src, uri, connkey):
|
||||
conn = self._lookup_conn(uri)
|
||||
vm = conn.get_vm(connkey)
|
||||
|
||||
logging.debug("Unpausing vm '%s'", vm.get_name())
|
||||
vmmAsyncJob.simple_async_noshow(vm.resume, [], src,
|
||||
_("Error unpausing domain"))
|
||||
|
||||
def _do_run_domain(self, src, uri, connkey):
|
||||
conn = self._lookup_conn(uri)
|
||||
vm = conn.get_vm(connkey)
|
||||
|
||||
logging.debug("Starting vm '%s'", vm.get_name())
|
||||
|
||||
if vm.has_managed_save():
|
||||
def errorcb(error, details):
|
||||
# This is run from the main thread
|
||||
res = src.err.show_err(
|
||||
_("Error restoring domain") + ": " + error,
|
||||
details=details,
|
||||
text2=_(
|
||||
"The domain could not be restored. Would you like\n"
|
||||
"to remove the saved state and perform a regular\n"
|
||||
"start up?"),
|
||||
dialog_type=Gtk.MessageType.WARNING,
|
||||
buttons=Gtk.ButtonsType.YES_NO,
|
||||
modal=True)
|
||||
|
||||
if not res:
|
||||
return
|
||||
|
||||
try:
|
||||
vm.remove_saved_image()
|
||||
self._do_run_domain(src, uri, connkey)
|
||||
except Exception as e:
|
||||
src.err.show_err(_("Error removing domain state: %s")
|
||||
% str(e))
|
||||
|
||||
# VM will be restored, which can take some time, so show progress
|
||||
title = _("Restoring Virtual Machine")
|
||||
text = _("Restoring virtual machine memory from disk")
|
||||
vmmAsyncJob.simple_async(vm.startup, [], src,
|
||||
title, text, "", errorcb=errorcb)
|
||||
|
||||
else:
|
||||
# Regular startup
|
||||
errorintro = _("Error starting domain")
|
||||
vmmAsyncJob.simple_async_noshow(vm.startup, [], src, errorintro)
|
||||
|
||||
def _do_shutdown_domain(self, src, uri, connkey):
|
||||
conn = self._lookup_conn(uri)
|
||||
vm = conn.get_vm(connkey)
|
||||
|
||||
if not src.err.chkbox_helper(self.config.get_confirm_poweroff,
|
||||
self.config.set_confirm_poweroff,
|
||||
text1=_("Are you sure you want to poweroff '%s'?" %
|
||||
vm.get_name())):
|
||||
return
|
||||
|
||||
logging.debug("Shutting down vm '%s'", vm.get_name())
|
||||
vmmAsyncJob.simple_async_noshow(vm.shutdown, [], src,
|
||||
_("Error shutting down domain"))
|
||||
|
||||
def _do_reboot_domain(self, src, uri, connkey):
|
||||
conn = self._lookup_conn(uri)
|
||||
vm = conn.get_vm(connkey)
|
||||
|
||||
if not src.err.chkbox_helper(self.config.get_confirm_poweroff,
|
||||
self.config.set_confirm_poweroff,
|
||||
text1=_("Are you sure you want to reboot '%s'?" %
|
||||
vm.get_name())):
|
||||
return
|
||||
|
||||
logging.debug("Rebooting vm '%s'", vm.get_name())
|
||||
vmmAsyncJob.simple_async_noshow(vm.reboot, [], src,
|
||||
_("Error rebooting domain"))
|
||||
|
||||
def _do_reset_domain(self, src, uri, connkey):
|
||||
conn = self._lookup_conn(uri)
|
||||
vm = conn.get_vm(connkey)
|
||||
|
||||
if not src.err.chkbox_helper(
|
||||
self.config.get_confirm_forcepoweroff,
|
||||
self.config.set_confirm_forcepoweroff,
|
||||
text1=_("Are you sure you want to force reset '%s'?" %
|
||||
vm.get_name()),
|
||||
text2=_("This will immediately reset the VM without "
|
||||
"shutting down the OS and may cause data loss.")):
|
||||
return
|
||||
|
||||
logging.debug("Resetting vm '%s'", vm.get_name())
|
||||
vmmAsyncJob.simple_async_noshow(vm.reset, [], src,
|
||||
_("Error resetting domain"))
|
||||
|
||||
def _do_delete_domain(self, src, uri, connkey):
|
||||
conn = self._lookup_conn(uri)
|
||||
vm = conn.get_vm(connkey)
|
||||
|
@ -96,14 +96,6 @@ class vmmManager(vmmGObjectUI):
|
||||
"action-show-host": (GObject.SignalFlags.RUN_FIRST, None, [str]),
|
||||
"action-show-preferences": (GObject.SignalFlags.RUN_FIRST, None, []),
|
||||
"action-show-create": (GObject.SignalFlags.RUN_FIRST, None, [str]),
|
||||
"action-suspend-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-resume-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-run-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-shutdown-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-reset-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-reboot-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-destroy-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-save-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-migrate-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-delete-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-clone-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
@ -534,34 +526,14 @@ class vmmManager(vmmGObjectUI):
|
||||
self.set_pause_state(not do_pause)
|
||||
|
||||
if do_pause:
|
||||
self.pause_vm(None)
|
||||
vmmenu.VMActionUI.suspend(self, self.current_vm())
|
||||
else:
|
||||
self.resume_vm(None)
|
||||
vmmenu.VMActionUI.resume(self, self.current_vm())
|
||||
|
||||
def start_vm(self, ignore):
|
||||
vm = self.current_vm()
|
||||
if vm is None:
|
||||
return
|
||||
self.emit("action-run-domain", vm.conn.get_uri(), vm.get_connkey())
|
||||
|
||||
def poweroff_vm(self, ignore):
|
||||
vm = self.current_vm()
|
||||
if vm is None:
|
||||
return
|
||||
self.emit("action-shutdown-domain",
|
||||
vm.conn.get_uri(), vm.get_connkey())
|
||||
|
||||
def pause_vm(self, ignore):
|
||||
vm = self.current_vm()
|
||||
if vm is None:
|
||||
return
|
||||
self.emit("action-suspend-domain", vm.conn.get_uri(), vm.get_connkey())
|
||||
|
||||
def resume_vm(self, ignore):
|
||||
vm = self.current_vm()
|
||||
if vm is None:
|
||||
return
|
||||
self.emit("action-resume-domain", vm.conn.get_uri(), vm.get_connkey())
|
||||
vmmenu.VMActionUI.run(self, self.current_vm())
|
||||
def poweroff_vm(self, _src):
|
||||
vmmenu.VMActionUI.shutdown(self, self.current_vm())
|
||||
|
||||
def close_conn(self, ignore):
|
||||
conn = self.current_conn()
|
||||
|
@ -32,14 +32,6 @@ class vmmSystray(vmmGObject):
|
||||
__gsignals__ = {
|
||||
"action-toggle-manager": (GObject.SignalFlags.RUN_FIRST, None, []),
|
||||
"action-view-manager": (GObject.SignalFlags.RUN_FIRST, None, []),
|
||||
"action-suspend-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-resume-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-run-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-shutdown-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-reset-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-reboot-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-destroy-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-save-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-migrate-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-delete-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
"action-clone-domain": (GObject.SignalFlags.RUN_FIRST, None, [str, str]),
|
||||
|
@ -18,8 +18,12 @@
|
||||
# MA 02110-1301 USA.
|
||||
#
|
||||
|
||||
import logging
|
||||
|
||||
from gi.repository import Gtk
|
||||
|
||||
from .asyncjob import vmmAsyncJob
|
||||
|
||||
|
||||
####################################################################
|
||||
# Build toolbar shutdown button menu (manager and details toolbar) #
|
||||
@ -34,8 +38,8 @@ class _VMMenu(Gtk.Menu):
|
||||
|
||||
self._init_state()
|
||||
|
||||
def _add_action(self, label, signal,
|
||||
iconname="system-shutdown", addcb=True):
|
||||
def _add_action(self, label, widgetname, cb,
|
||||
iconname="system-shutdown"):
|
||||
if label.startswith("gtk-"):
|
||||
item = Gtk.ImageMenuItem.new_from_stock(label, None)
|
||||
else:
|
||||
@ -49,19 +53,17 @@ class _VMMenu(Gtk.Menu):
|
||||
Gtk.IconSize.MENU)
|
||||
item.set_image(icon)
|
||||
|
||||
item.vmm_widget_name = signal
|
||||
if addcb:
|
||||
item.connect("activate", self._action_cb)
|
||||
item.vmm_widget_name = widgetname
|
||||
if cb:
|
||||
def _cb(_menuitem):
|
||||
_vm = self._current_vm_cb()
|
||||
if _vm:
|
||||
return cb(self._parent, _vm)
|
||||
item.connect("activate", _cb)
|
||||
|
||||
self.add(item)
|
||||
return item
|
||||
|
||||
def _action_cb(self, src):
|
||||
vm = self._current_vm_cb()
|
||||
if not vm:
|
||||
return
|
||||
self._parent.emit("action-%s-domain" % src.vmm_widget_name,
|
||||
vm.conn.get_uri(), vm.get_connkey())
|
||||
|
||||
def _init_state(self):
|
||||
raise NotImplementedError()
|
||||
def update_widget_states(self, vm):
|
||||
@ -69,13 +71,17 @@ class _VMMenu(Gtk.Menu):
|
||||
|
||||
|
||||
class VMShutdownMenu(_VMMenu):
|
||||
"""
|
||||
Shutdown submenu for reboot, forceoff, reset, etc.
|
||||
"""
|
||||
def _init_state(self):
|
||||
self._add_action(_("_Reboot"), "reboot")
|
||||
self._add_action(_("_Shut Down"), "shutdown")
|
||||
self._add_action(_("F_orce Reset"), "reset")
|
||||
self._add_action(_("_Force Off"), "destroy")
|
||||
self._add_action(_("_Reboot"), "reboot", VMActionUI.reboot)
|
||||
self._add_action(_("_Shut Down"), "shutdown", VMActionUI.shutdown)
|
||||
self._add_action(_("F_orce Reset"), "reset", VMActionUI.reset)
|
||||
self._add_action(_("_Force Off"), "destroy", VMActionUI.destroy)
|
||||
self.add(Gtk.SeparatorMenuItem())
|
||||
self._add_action(_("Sa_ve"), "save", iconname=Gtk.STOCK_SAVE)
|
||||
self._add_action(_("Sa_ve"), "save", VMActionUI.save,
|
||||
iconname=Gtk.STOCK_SAVE)
|
||||
|
||||
self.show_all()
|
||||
|
||||
@ -84,8 +90,8 @@ class VMShutdownMenu(_VMMenu):
|
||||
"reboot": bool(vm and vm.is_stoppable()),
|
||||
"shutdown": bool(vm and vm.is_stoppable()),
|
||||
"reset": bool(vm and vm.is_stoppable()),
|
||||
"save": bool(vm and vm.is_destroyable()),
|
||||
"destroy": bool(vm and vm.is_destroyable()),
|
||||
"save": bool(vm and vm.is_destroyable()),
|
||||
}
|
||||
|
||||
for child in self.get_children():
|
||||
@ -103,21 +109,37 @@ class VMShutdownMenu(_VMMenu):
|
||||
|
||||
|
||||
class VMActionMenu(_VMMenu):
|
||||
"""
|
||||
VM submenu for run, pause, shutdown, clone, etc
|
||||
"""
|
||||
def _init_state(self):
|
||||
self._add_action(_("_Run"), "run", Gtk.STOCK_MEDIA_PLAY)
|
||||
self._add_action(_("_Pause"), "suspend", Gtk.STOCK_MEDIA_PAUSE)
|
||||
self._add_action(_("R_esume"), "resume", Gtk.STOCK_MEDIA_PAUSE)
|
||||
s = self._add_action(_("_Shut Down"), "shutdown", addcb=False)
|
||||
self._add_action(_("_Run"), "run", VMActionUI.run,
|
||||
iconname=Gtk.STOCK_MEDIA_PLAY)
|
||||
self._add_action(_("_Pause"), "suspend", VMActionUI.suspend,
|
||||
Gtk.STOCK_MEDIA_PAUSE)
|
||||
self._add_action(_("R_esume"), "resume", VMActionUI.resume,
|
||||
Gtk.STOCK_MEDIA_PAUSE)
|
||||
s = self._add_action(_("_Shut Down"), "shutdown", None)
|
||||
s.set_submenu(VMShutdownMenu(self._parent, self._current_vm_cb))
|
||||
|
||||
def _make_emit_cb(_name):
|
||||
def _emit_cb(_src, _vm):
|
||||
return _src.emit(_name, _vm.conn.get_uri(), _vm.get_name())
|
||||
return _emit_cb
|
||||
|
||||
self.add(Gtk.SeparatorMenuItem())
|
||||
self._add_action(_("Clone..."), "clone", None)
|
||||
self._add_action(_("Migrate..."), "migrate", None)
|
||||
self._add_action(_("_Delete"), "delete", Gtk.STOCK_DELETE)
|
||||
self._add_action(_("Clone..."), "clone",
|
||||
_make_emit_cb("action-clone-domain"), iconname=None)
|
||||
self._add_action(_("Migrate..."), "migrate",
|
||||
_make_emit_cb("action-migrate-domain"), iconname=None)
|
||||
self._add_action(_("_Delete"), "delete",
|
||||
_make_emit_cb("action-delete-domain"),
|
||||
iconname=Gtk.STOCK_DELETE)
|
||||
|
||||
if self._show_open:
|
||||
self.add(Gtk.SeparatorMenuItem())
|
||||
self._add_action(Gtk.STOCK_OPEN, "show", None)
|
||||
self._add_action(Gtk.STOCK_OPEN, "show",
|
||||
_make_emit_cb("action-show-domain"), iconname=None)
|
||||
|
||||
self.show_all()
|
||||
|
||||
@ -148,3 +170,162 @@ class VMActionMenu(_VMMenu):
|
||||
for child in self.get_children():
|
||||
if getattr(child, "vmm_widget_name", None) == "run":
|
||||
child.get_child().set_label(text)
|
||||
|
||||
|
||||
class VMActionUI(object):
|
||||
"""
|
||||
Singleton object for handling VM actions, asking for confirmation,
|
||||
showing errors/progress dialogs, etc.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def save_cancel(asyncjob, vm):
|
||||
logging.debug("Cancelling save job")
|
||||
if not vm:
|
||||
return
|
||||
|
||||
try:
|
||||
vm.abort_job()
|
||||
except Exception as e:
|
||||
logging.exception("Error cancelling save job")
|
||||
asyncjob.show_warning(_("Error cancelling save job: %s") % str(e))
|
||||
return
|
||||
|
||||
asyncjob.job_canceled = True
|
||||
return
|
||||
|
||||
@staticmethod
|
||||
def save(src, vm):
|
||||
if not src.err.chkbox_helper(src.config.get_confirm_poweroff,
|
||||
src.config.set_confirm_poweroff,
|
||||
text1=_("Are you sure you want to save '%s'?") % vm.get_name()):
|
||||
return
|
||||
|
||||
_cancel_cb = None
|
||||
if vm.getjobinfo_supported:
|
||||
_cancel_cb = (VMActionUI.save_cancel, vm)
|
||||
|
||||
def cb(asyncjob):
|
||||
vm.save(meter=asyncjob.get_meter())
|
||||
def finish_cb(error, details):
|
||||
if error is not None:
|
||||
error = _("Error saving domain: %s") % error
|
||||
src.err.show_err(error, details=details)
|
||||
|
||||
progWin = vmmAsyncJob(cb, [],
|
||||
finish_cb, [],
|
||||
_("Saving Virtual Machine"),
|
||||
_("Saving virtual machine memory to disk "),
|
||||
src.topwin, cancel_cb=_cancel_cb)
|
||||
progWin.run()
|
||||
|
||||
@staticmethod
|
||||
def destroy(src, vm):
|
||||
if not src.err.chkbox_helper(
|
||||
src.config.get_confirm_forcepoweroff,
|
||||
src.config.set_confirm_forcepoweroff,
|
||||
text1=_("Are you sure you want to force poweroff '%s'?" %
|
||||
vm.get_name()),
|
||||
text2=_("This will immediately poweroff the VM without "
|
||||
"shutting down the OS and may cause data loss.")):
|
||||
return
|
||||
|
||||
logging.debug("Destroying vm '%s'", vm.get_name())
|
||||
vmmAsyncJob.simple_async_noshow(vm.destroy, [], src,
|
||||
_("Error shutting down domain"))
|
||||
|
||||
@staticmethod
|
||||
def suspend(src, vm):
|
||||
if not src.err.chkbox_helper(src.config.get_confirm_pause,
|
||||
src.config.set_confirm_pause,
|
||||
text1=_("Are you sure you want to pause '%s'?" %
|
||||
vm.get_name())):
|
||||
return
|
||||
|
||||
logging.debug("Pausing vm '%s'", vm.get_name())
|
||||
vmmAsyncJob.simple_async_noshow(vm.suspend, [], src,
|
||||
_("Error pausing domain"))
|
||||
|
||||
@staticmethod
|
||||
def resume(src, vm):
|
||||
logging.debug("Unpausing vm '%s'", vm.get_name())
|
||||
vmmAsyncJob.simple_async_noshow(vm.resume, [], src,
|
||||
_("Error unpausing domain"))
|
||||
|
||||
@staticmethod
|
||||
def run(src, vm):
|
||||
logging.debug("Starting vm '%s'", vm.get_name())
|
||||
|
||||
if vm.has_managed_save():
|
||||
def errorcb(error, details):
|
||||
# This is run from the main thread
|
||||
res = src.err.show_err(
|
||||
_("Error restoring domain") + ": " + error,
|
||||
details=details,
|
||||
text2=_(
|
||||
"The domain could not be restored. Would you like\n"
|
||||
"to remove the saved state and perform a regular\n"
|
||||
"start up?"),
|
||||
dialog_type=Gtk.MessageType.WARNING,
|
||||
buttons=Gtk.ButtonsType.YES_NO,
|
||||
modal=True)
|
||||
|
||||
if not res:
|
||||
return
|
||||
|
||||
try:
|
||||
vm.remove_saved_image()
|
||||
VMActionUI.run(src, vm)
|
||||
except Exception as e:
|
||||
src.err.show_err(_("Error removing domain state: %s")
|
||||
% str(e))
|
||||
|
||||
# VM will be restored, which can take some time, so show progress
|
||||
title = _("Restoring Virtual Machine")
|
||||
text = _("Restoring virtual machine memory from disk")
|
||||
vmmAsyncJob.simple_async(vm.startup, [], src,
|
||||
title, text, "", errorcb=errorcb)
|
||||
|
||||
else:
|
||||
# Regular startup
|
||||
errorintro = _("Error starting domain")
|
||||
vmmAsyncJob.simple_async_noshow(vm.startup, [], src, errorintro)
|
||||
|
||||
@staticmethod
|
||||
def shutdown(src, vm):
|
||||
if not src.err.chkbox_helper(src.config.get_confirm_poweroff,
|
||||
src.config.set_confirm_poweroff,
|
||||
text1=_("Are you sure you want to poweroff '%s'?" %
|
||||
vm.get_name())):
|
||||
return
|
||||
|
||||
logging.debug("Shutting down vm '%s'", vm.get_name())
|
||||
vmmAsyncJob.simple_async_noshow(vm.shutdown, [], src,
|
||||
_("Error shutting down domain"))
|
||||
|
||||
@staticmethod
|
||||
def reboot(src, vm):
|
||||
if not src.err.chkbox_helper(src.config.get_confirm_poweroff,
|
||||
src.config.set_confirm_poweroff,
|
||||
text1=_("Are you sure you want to reboot '%s'?" %
|
||||
vm.get_name())):
|
||||
return
|
||||
|
||||
logging.debug("Rebooting vm '%s'", vm.get_name())
|
||||
vmmAsyncJob.simple_async_noshow(vm.reboot, [], src,
|
||||
_("Error rebooting domain"))
|
||||
|
||||
@staticmethod
|
||||
def reset(src, vm):
|
||||
if not src.err.chkbox_helper(
|
||||
src.config.get_confirm_forcepoweroff,
|
||||
src.config.set_confirm_forcepoweroff,
|
||||
text1=_("Are you sure you want to force reset '%s'?" %
|
||||
vm.get_name()),
|
||||
text2=_("This will immediately reset the VM without "
|
||||
"shutting down the OS and may cause data loss.")):
|
||||
return
|
||||
|
||||
logging.debug("Resetting vm '%s'", vm.get_name())
|
||||
vmmAsyncJob.simple_async_noshow(vm.reset, [], src,
|
||||
_("Error resetting domain"))
|
||||
|
Reference in New Issue
Block a user