From 2ab8c6ce030af9847ee26d72c5dc4d2c914c18c4 Mon Sep 17 00:00:00 2001 From: Cole Robinson Date: Wed, 12 May 2010 12:57:32 -0400 Subject: [PATCH] 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. --- src/virtManager/connection.py | 10 ++++++++++ src/virtManager/details.py | 13 +++++++++++++ src/virtManager/domain.py | 22 +++++++++++++++------- src/virtManager/engine.py | 33 ++++++++++++++++++++------------- src/virtManager/manager.py | 12 ++++++++++++ 5 files changed, 70 insertions(+), 20 deletions(-) diff --git a/src/virtManager/connection.py b/src/virtManager/connection.py index c53c87624..9a15db3a6 100644 --- a/src/virtManager/connection.py +++ b/src/virtManager/connection.py @@ -127,6 +127,7 @@ class vmmConnection(gobject.GObject): self._nodedev_capable = None self._xml_flags = {} + self._support_dict = {} # Physical network interfaces: name -> virtinst.NodeDevice self.nodedevs = {} @@ -532,6 +533,15 @@ class vmmConnection(gobject.GObject): 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): key = "interface" diff --git a/src/virtManager/details.py b/src/virtManager/details.py index 06d43c1ac..b25963bf3 100644 --- a/src/virtManager/details.py +++ b/src/virtManager/details.py @@ -815,6 +815,16 @@ class vmmDetails(gobject.GObject): if newpage == PAGE_CONSOLE or newpage >= PAGE_DYNAMIC_OFFSET: 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): self.toggle_toolbar(self.window.get_widget("details-menu-view-toolbar")) @@ -824,6 +834,9 @@ class vmmDetails(gobject.GObject): paused = vm.is_paused() 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("control-run").set_sensitive(run) self.window.get_widget("details-menu-run").set_sensitive(run) diff --git a/src/virtManager/domain.py b/src/virtManager/domain.py index b7837e0cf..00a9b0ca5 100644 --- a/src/virtManager/domain.py +++ b/src/virtManager/domain.py @@ -77,6 +77,8 @@ class vmmDomainBase(vmmLibvirtObject): self._startup_vcpus = None + self.managedsave_supported = False + self._network_traffic = None self._disk_io = None @@ -228,6 +230,9 @@ class vmmDomainBase(vmmLibvirtObject): return "-" return str(i) + def hasSavedImage(self): + return False + def get_abi_type(self): return str(vutil.get_xml_path(self.get_xml(), "/domain/os/type")).lower() @@ -1181,6 +1186,7 @@ class vmmDomain(vmmDomainBase): self.getvcpus_supported = support.check_domain_support(self._backend, support.SUPPORT_DOMAIN_GETVCPUS) + self.managedsave_supported = self.connection.get_dom_managedsave_supported(self._backend) self.toggle_sample_network_traffic() self.toggle_sample_disk_io() @@ -1303,14 +1309,16 @@ class vmmDomain(vmmDomainBase): self._backend.resume() self._update_status() - def save(self, filename, background=True): - if background: - conn = util.dup_conn(self.config, self.connection) - vm = conn.lookupByID(self.get_id()) - else: - vm = self._backend + def hasSavedImage(self): + if not self.managedsave_supported: + return False + return self._backend.hasManagedSaveImage(0) - 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() def destroy(self): diff --git a/src/virtManager/engine.py b/src/virtManager/engine.py index 12e45eab3..7634f3c64 100644 --- a/src/virtManager/engine.py +++ b/src/virtManager/engine.py @@ -713,12 +713,13 @@ class vmmEngine(gobject.GObject): def save_domain(self, src, uri, uuid): conn = self._lookup_connection(uri) vm = conn.get_vm(uuid) + managed = bool(vm.managedsave_supported) do_prompt = self.config.get_confirm_poweroff() - if conn.is_remote(): - # FIXME: This should work with remote storage stuff + if managed and conn.is_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 if do_prompt: @@ -733,16 +734,18 @@ class vmmEngine(gobject.GObject): return self.config.set_confirm_poweroff(not skip_prompt) - path = util.browse_local(src.window.get_widget("vmm-details"), - _("Save Virtual Machine"), - self.config, conn, - dialog_type=gtk.FILE_CHOOSER_ACTION_SAVE, - browse_reason=self.config.CONFIG_DIR_SAVE) + path = None + if not managed: + path = util.browse_local(src.window.get_widget("vmm-details"), + _("Save Virtual Machine"), + self.config, conn, + dialog_type=gtk.FILE_CHOOSER_ACTION_SAVE, + browse_reason=self.config.CONFIG_DIR_SAVE) + if not path: + return - if not path: - return - - progWin = vmmAsyncJob(self.config, self._save_callback, [vm, path], + progWin = vmmAsyncJob(self.config, self._save_callback, + [vm, path], _("Saving Virtual Machine")) progWin.run() error, details = progWin.get_error() @@ -752,7 +755,11 @@ class vmmEngine(gobject.GObject): def _save_callback(self, vm, file_to_save, asyncjob): 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: asyncjob.set_error(str(e), "".join(traceback.format_exc())) diff --git a/src/virtManager/manager.py b/src/virtManager/manager.py index ec3b799d7..3b42b021f 100644 --- a/src/virtManager/manager.py +++ b/src/virtManager/manager.py @@ -969,6 +969,15 @@ class vmmManager(gobject.GObject): child = model.iter_children(parent) 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): conn = self.current_connection() @@ -987,6 +996,9 @@ class vmmManager(gobject.GObject): show_pause = bool(vm and vm.is_pauseable()) 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-run").set_sensitive(show_run) self.window.get_widget("vm-shutdown").set_sensitive(show_shutdown)