mirror of
https://github.com/virt-manager/virt-manager.git
synced 2025-02-25 18:55:27 -06:00
Support libvirt managed save/restore
If a VM has a saved image, we s/Run/Restore/g for all the Run UI so the user is aware they will be restoring from a saved state.
This commit is contained in:
parent
225f4d344a
commit
2ab8c6ce03
@ -127,6 +127,7 @@ class vmmConnection(gobject.GObject):
|
|||||||
self._nodedev_capable = None
|
self._nodedev_capable = None
|
||||||
|
|
||||||
self._xml_flags = {}
|
self._xml_flags = {}
|
||||||
|
self._support_dict = {}
|
||||||
|
|
||||||
# Physical network interfaces: name -> virtinst.NodeDevice
|
# Physical network interfaces: name -> virtinst.NodeDevice
|
||||||
self.nodedevs = {}
|
self.nodedevs = {}
|
||||||
@ -532,6 +533,15 @@ class vmmConnection(gobject.GObject):
|
|||||||
|
|
||||||
return self._get_flags_helper(vm, key, check_func)
|
return self._get_flags_helper(vm, key, check_func)
|
||||||
|
|
||||||
|
def get_dom_managedsave_supported(self, vm):
|
||||||
|
key = virtinst.support.SUPPORT_DOMAIN_MANAGED_SAVE
|
||||||
|
if key not in self._support_dict:
|
||||||
|
val = virtinst.support.check_domain_support(vm, key)
|
||||||
|
logging.debug("Connection managed save support: %s" % val)
|
||||||
|
self._support_dict[key] = val
|
||||||
|
|
||||||
|
return self._support_dict[key]
|
||||||
|
|
||||||
def get_interface_flags(self, iface):
|
def get_interface_flags(self, iface):
|
||||||
key = "interface"
|
key = "interface"
|
||||||
|
|
||||||
|
@ -815,6 +815,16 @@ class vmmDetails(gobject.GObject):
|
|||||||
if newpage == PAGE_CONSOLE or newpage >= PAGE_DYNAMIC_OFFSET:
|
if newpage == PAGE_CONSOLE or newpage >= PAGE_DYNAMIC_OFFSET:
|
||||||
self.last_console_page = newpage
|
self.last_console_page = newpage
|
||||||
|
|
||||||
|
def change_run_text(self, can_restore):
|
||||||
|
if can_restore:
|
||||||
|
text = _("_Restore")
|
||||||
|
else:
|
||||||
|
text = _("_Run")
|
||||||
|
strip_text = text.replace("_", "")
|
||||||
|
|
||||||
|
self.window.get_widget("details-menu-run").get_child().set_label(text)
|
||||||
|
self.window.get_widget("control-run").set_label(strip_text)
|
||||||
|
|
||||||
def update_widget_states(self, vm, status, ignore=None):
|
def update_widget_states(self, vm, status, ignore=None):
|
||||||
self.toggle_toolbar(self.window.get_widget("details-menu-view-toolbar"))
|
self.toggle_toolbar(self.window.get_widget("details-menu-view-toolbar"))
|
||||||
|
|
||||||
@ -824,6 +834,9 @@ class vmmDetails(gobject.GObject):
|
|||||||
paused = vm.is_paused()
|
paused = vm.is_paused()
|
||||||
ro = vm.is_read_only()
|
ro = vm.is_read_only()
|
||||||
|
|
||||||
|
if vm.managedsave_supported:
|
||||||
|
self.change_run_text(vm.hasSavedImage())
|
||||||
|
|
||||||
self.window.get_widget("details-menu-destroy").set_sensitive(destroy)
|
self.window.get_widget("details-menu-destroy").set_sensitive(destroy)
|
||||||
self.window.get_widget("control-run").set_sensitive(run)
|
self.window.get_widget("control-run").set_sensitive(run)
|
||||||
self.window.get_widget("details-menu-run").set_sensitive(run)
|
self.window.get_widget("details-menu-run").set_sensitive(run)
|
||||||
|
@ -77,6 +77,8 @@ class vmmDomainBase(vmmLibvirtObject):
|
|||||||
|
|
||||||
self._startup_vcpus = None
|
self._startup_vcpus = None
|
||||||
|
|
||||||
|
self.managedsave_supported = False
|
||||||
|
|
||||||
self._network_traffic = None
|
self._network_traffic = None
|
||||||
self._disk_io = None
|
self._disk_io = None
|
||||||
|
|
||||||
@ -228,6 +230,9 @@ class vmmDomainBase(vmmLibvirtObject):
|
|||||||
return "-"
|
return "-"
|
||||||
return str(i)
|
return str(i)
|
||||||
|
|
||||||
|
def hasSavedImage(self):
|
||||||
|
return False
|
||||||
|
|
||||||
def get_abi_type(self):
|
def get_abi_type(self):
|
||||||
return str(vutil.get_xml_path(self.get_xml(),
|
return str(vutil.get_xml_path(self.get_xml(),
|
||||||
"/domain/os/type")).lower()
|
"/domain/os/type")).lower()
|
||||||
@ -1181,6 +1186,7 @@ class vmmDomain(vmmDomainBase):
|
|||||||
|
|
||||||
self.getvcpus_supported = support.check_domain_support(self._backend,
|
self.getvcpus_supported = support.check_domain_support(self._backend,
|
||||||
support.SUPPORT_DOMAIN_GETVCPUS)
|
support.SUPPORT_DOMAIN_GETVCPUS)
|
||||||
|
self.managedsave_supported = self.connection.get_dom_managedsave_supported(self._backend)
|
||||||
|
|
||||||
self.toggle_sample_network_traffic()
|
self.toggle_sample_network_traffic()
|
||||||
self.toggle_sample_disk_io()
|
self.toggle_sample_disk_io()
|
||||||
@ -1303,14 +1309,16 @@ class vmmDomain(vmmDomainBase):
|
|||||||
self._backend.resume()
|
self._backend.resume()
|
||||||
self._update_status()
|
self._update_status()
|
||||||
|
|
||||||
def save(self, filename, background=True):
|
def hasSavedImage(self):
|
||||||
if background:
|
if not self.managedsave_supported:
|
||||||
conn = util.dup_conn(self.config, self.connection)
|
return False
|
||||||
vm = conn.lookupByID(self.get_id())
|
return self._backend.hasManagedSaveImage(0)
|
||||||
else:
|
|
||||||
vm = self._backend
|
|
||||||
|
|
||||||
vm.save(filename)
|
def save(self, filename=None):
|
||||||
|
if not self.managedsave_supported:
|
||||||
|
self._backend.save(filename)
|
||||||
|
else:
|
||||||
|
self._backend.managedSave(0)
|
||||||
self._update_status()
|
self._update_status()
|
||||||
|
|
||||||
def destroy(self):
|
def destroy(self):
|
||||||
|
@ -713,12 +713,13 @@ class vmmEngine(gobject.GObject):
|
|||||||
def save_domain(self, src, uri, uuid):
|
def save_domain(self, src, uri, uuid):
|
||||||
conn = self._lookup_connection(uri)
|
conn = self._lookup_connection(uri)
|
||||||
vm = conn.get_vm(uuid)
|
vm = conn.get_vm(uuid)
|
||||||
|
managed = bool(vm.managedsave_supported)
|
||||||
do_prompt = self.config.get_confirm_poweroff()
|
do_prompt = self.config.get_confirm_poweroff()
|
||||||
|
|
||||||
if conn.is_remote():
|
if managed and conn.is_remote():
|
||||||
# FIXME: This should work with remote storage stuff
|
|
||||||
self.err.val_err(_("Saving virtual machines over remote "
|
self.err.val_err(_("Saving virtual machines over remote "
|
||||||
"connections is not yet supported."))
|
"connections is not supported with this "
|
||||||
|
"libvirt version or hypervisor."))
|
||||||
return
|
return
|
||||||
|
|
||||||
if do_prompt:
|
if do_prompt:
|
||||||
@ -733,16 +734,18 @@ class vmmEngine(gobject.GObject):
|
|||||||
return
|
return
|
||||||
self.config.set_confirm_poweroff(not skip_prompt)
|
self.config.set_confirm_poweroff(not skip_prompt)
|
||||||
|
|
||||||
path = util.browse_local(src.window.get_widget("vmm-details"),
|
path = None
|
||||||
_("Save Virtual Machine"),
|
if not managed:
|
||||||
self.config, conn,
|
path = util.browse_local(src.window.get_widget("vmm-details"),
|
||||||
dialog_type=gtk.FILE_CHOOSER_ACTION_SAVE,
|
_("Save Virtual Machine"),
|
||||||
browse_reason=self.config.CONFIG_DIR_SAVE)
|
self.config, conn,
|
||||||
|
dialog_type=gtk.FILE_CHOOSER_ACTION_SAVE,
|
||||||
|
browse_reason=self.config.CONFIG_DIR_SAVE)
|
||||||
|
if not path:
|
||||||
|
return
|
||||||
|
|
||||||
if not path:
|
progWin = vmmAsyncJob(self.config, self._save_callback,
|
||||||
return
|
[vm, path],
|
||||||
|
|
||||||
progWin = vmmAsyncJob(self.config, self._save_callback, [vm, path],
|
|
||||||
_("Saving Virtual Machine"))
|
_("Saving Virtual Machine"))
|
||||||
progWin.run()
|
progWin.run()
|
||||||
error, details = progWin.get_error()
|
error, details = progWin.get_error()
|
||||||
@ -752,7 +755,11 @@ class vmmEngine(gobject.GObject):
|
|||||||
|
|
||||||
def _save_callback(self, vm, file_to_save, asyncjob):
|
def _save_callback(self, vm, file_to_save, asyncjob):
|
||||||
try:
|
try:
|
||||||
vm.save(file_to_save)
|
conn = util.dup_conn(self.config, vm.connection,
|
||||||
|
return_conn_class=True)
|
||||||
|
newvm = conn.get_vm(vm.get_uuid())
|
||||||
|
|
||||||
|
newvm.save(file_to_save)
|
||||||
except Exception, e:
|
except Exception, e:
|
||||||
asyncjob.set_error(str(e), "".join(traceback.format_exc()))
|
asyncjob.set_error(str(e), "".join(traceback.format_exc()))
|
||||||
|
|
||||||
|
@ -969,6 +969,15 @@ class vmmManager(gobject.GObject):
|
|||||||
child = model.iter_children(parent)
|
child = model.iter_children(parent)
|
||||||
model.row_changed(row.path, row.iter)
|
model.row_changed(row.path, row.iter)
|
||||||
|
|
||||||
|
def change_run_text(self, can_restore):
|
||||||
|
if can_restore:
|
||||||
|
text = _("_Restore")
|
||||||
|
else:
|
||||||
|
text = _("_Run")
|
||||||
|
strip_text = text.replace("_", "")
|
||||||
|
|
||||||
|
self.vmmenu_items["run"].get_child().set_label(text)
|
||||||
|
self.window.get_widget("vm-run").set_label(strip_text)
|
||||||
|
|
||||||
def vm_selected(self, ignore=None):
|
def vm_selected(self, ignore=None):
|
||||||
conn = self.current_connection()
|
conn = self.current_connection()
|
||||||
@ -987,6 +996,9 @@ class vmmManager(gobject.GObject):
|
|||||||
show_pause = bool(vm and vm.is_pauseable())
|
show_pause = bool(vm and vm.is_pauseable())
|
||||||
show_shutdown = bool(vm and vm.is_stoppable())
|
show_shutdown = bool(vm and vm.is_stoppable())
|
||||||
|
|
||||||
|
if vm and vm.managedsave_supported:
|
||||||
|
self.change_run_text(vm.hasSavedImage())
|
||||||
|
|
||||||
self.window.get_widget("vm-open").set_sensitive(show_open)
|
self.window.get_widget("vm-open").set_sensitive(show_open)
|
||||||
self.window.get_widget("vm-run").set_sensitive(show_run)
|
self.window.get_widget("vm-run").set_sensitive(show_run)
|
||||||
self.window.get_widget("vm-shutdown").set_sensitive(show_shutdown)
|
self.window.get_widget("vm-shutdown").set_sensitive(show_shutdown)
|
||||||
|
Loading…
Reference in New Issue
Block a user