From 92c230d1113403b506e115416dff1218479b7116 Mon Sep 17 00:00:00 2001 From: Pavel Hrdina Date: Mon, 6 Mar 2017 09:43:10 +0100 Subject: [PATCH] domain: add support to rename domain with nvram vars file Libvirt storage API doesn't support renaming storage volumes so we need to copy the nvram file and remove the old one. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=1368922 Signed-off-by: Pavel Hrdina --- virtManager/details.py | 2 +- virtManager/domain.py | 76 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/virtManager/details.py b/virtManager/details.py index d6fef9676..a2097ec81 100644 --- a/virtManager/details.py +++ b/virtManager/details.py @@ -1975,7 +1975,7 @@ class vmmDetails(vmmGObjectUI): # This needs to be last if self.edited(EDIT_NAME): # Renaming is pretty convoluted, so do it here synchronously - self.vm.define_name(self.widget("overview-name").get_text()) + self.vm.rename_domain(self.widget("overview-name").get_text()) if not kwargs and not hotplug_args: # Saves some useless redefine attempts diff --git a/virtManager/domain.py b/virtManager/domain.py index d9e17dbb2..4eb9fa474 100644 --- a/virtManager/domain.py +++ b/virtManager/domain.py @@ -32,6 +32,7 @@ from virtinst import DomainSnapshot from virtinst import Guest from virtinst import util from virtinst import VirtualController +from virtinst import VirtualDisk from .libvirtobject import vmmLibvirtObject @@ -479,6 +480,10 @@ class vmmDomain(vmmLibvirtObject): return "-" return str(i) + def has_nvram(self): + return bool(self.get_xmlobj().os.loader_ro is True and + self.get_xmlobj().os.loader_type == "pflash") + ################## # Support checks # ################## @@ -552,11 +557,65 @@ class vmmDomain(vmmLibvirtObject): raise RuntimeError(_("Could not find specified device in the " "inactive VM configuration: %s") % repr(origdev)) + def _copy_nvram_file(self, new_name): + """ + We need to do this copy magic because there is no Libvirt storage API + to rename storage volume. + """ + old_nvram = VirtualDisk(self.conn.get_backend()) + old_nvram.path = self.get_xmlobj().os.nvram + + nvram_dir = os.path.dirname(old_nvram.path) + new_nvram_path = os.path.join(nvram_dir, "%s_VARS.fd" % new_name) + + new_nvram = VirtualDisk(self.conn.get_backend()) + new_nvram.path = new_nvram_path + + nvram_install = VirtualDisk.build_vol_install( + self.conn.get_backend(), os.path.basename(new_nvram.path), + new_nvram.get_parent_pool(), new_nvram.get_size(), False) + nvram_install.input_vol = old_nvram.get_vol_object() + nvram_install.sync_input_vol(only_format=True) + + new_nvram.set_vol_install(nvram_install) + new_nvram.validate() + new_nvram.setup() + + return new_nvram, old_nvram + ############################## # Persistent XML change APIs # ############################## + def rename_domain(self, new_name): + new_nvram = None + old_nvram = None + if self.has_nvram(): + try: + new_nvram, old_nvram = self._copy_nvram_file(new_name) + except Exception as error: + raise RuntimeError("Cannot rename nvram VARS: '%s'" % error) + + try: + self.define_name(new_name) + except Exception as error: + if new_nvram: + try: + new_nvram.get_vol_object().delete(0) + except Exception as warn: + logging.debug("rename failed and new nvram was not " + "removed: '%s'", warn) + raise error + + if new_nvram: + try: + old_nvram.get_vol_object().delete(0) + except Exception as warn: + logging.debug("old nvram file was not removed: '%s'", warn) + + self.define_overview(nvram=new_nvram.path) + # Device Add/Remove def add_device(self, devobj): """ @@ -621,7 +680,8 @@ class vmmDomain(vmmLibvirtObject): self._redefine_xmlobj(guest) def define_overview(self, machine=_SENTINEL, description=_SENTINEL, - title=_SENTINEL, idmap_list=_SENTINEL, loader=_SENTINEL): + title=_SENTINEL, idmap_list=_SENTINEL, loader=_SENTINEL, + nvram=_SENTINEL): guest = self._make_xmlobj_to_define() if machine != _SENTINEL: guest.os.machine = machine @@ -644,6 +704,9 @@ class vmmDomain(vmmLibvirtObject): guest.os.loader_type = "pflash" guest.os.loader_ro = True + if nvram != _SENTINEL: + guest.os.nvram = nvram + if idmap_list != _SENTINEL: if idmap_list is not None: # pylint: disable=unpacking-non-sequence @@ -1426,14 +1489,21 @@ class vmmDomain(vmmLibvirtObject): @vmmLibvirtObject.lifecycle_action def delete(self, force=True): + """ + @force: True if we are deleting domain, False if we are renaming domain + + If the domain is renamed we need to keep the nvram file. + """ flags = 0 if force: flags |= getattr(libvirt, "VIR_DOMAIN_UNDEFINE_SNAPSHOTS_METADATA", 0) flags |= getattr(libvirt, "VIR_DOMAIN_UNDEFINE_MANAGED_SAVE", 0) - if (self.get_xmlobj().os.loader_ro is True and - self.get_xmlobj().os.loader_type == "pflash"): + if self.has_nvram(): flags |= getattr(libvirt, "VIR_DOMAIN_UNDEFINE_NVRAM", 0) + else: + if self.has_nvram(): + flags |= getattr(libvirt, "VIR_DOMAIN_UNDEFINE_KEEP_NVRAM", 0) try: self._backend.undefineFlags(flags) except libvirt.libvirtError: