Arik Hadas has uploaded a new change for review. Change subject: RAM snapshots feature ......................................................................
RAM snapshots feature This patch adds the ability to take live snapshot of a VM that includes its memory state, and to restore memory state that is saved as part of a snapshot when reverting back to it. There is a detailed description of the design at the feature page: http://wiki.ovirt.org/Features/RAM_Snapshots Change-Id: I62401940afb0228cbd9dd3611b6ed8e0ff67c82c Signed-off-by: Arik Hadas <aha...@redhat.com> --- M vdsm/API.py M vdsm/BindingXMLRPC.py M vdsm/libvirtvm.py 3 files changed, 76 insertions(+), 14 deletions(-) git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/72/15072/1 diff --git a/vdsm/API.py b/vdsm/API.py index ee72116..509addd 100644 --- a/vdsm/API.py +++ b/vdsm/API.py @@ -632,11 +632,15 @@ self.log.info('network %s: using %s', network, ip) return ip - def snapshot(self, snapDrives): + def snapshot(self, snapDrives, snapMemory): v = self._cif.vmContainer.get(self._UUID) if not v: return errCode['noVM'] - return v.snapshot(snapDrives) + memoryParams = {} + if snapMemory: + memoryParams['dst'], memoryParams['dstparams'] = \ + self._getHibernationPaths(snapMemory) + return v.snapshot(snapDrives, memoryParams) def merge(self, mergeDrives): v = self._cif.vmContainer.get(self._UUID) diff --git a/vdsm/BindingXMLRPC.py b/vdsm/BindingXMLRPC.py index 9a4db12..9f9de19 100644 --- a/vdsm/BindingXMLRPC.py +++ b/vdsm/BindingXMLRPC.py @@ -280,9 +280,9 @@ vm = API.VM(vmId) return vm.vmUpdateDevice(params) - def vmSnapshot(self, vmId, snapDrives): + def vmSnapshot(self, vmId, snapDrives, snapMemory=''): vm = API.VM(vmId) - return vm.snapshot(snapDrives) + return vm.snapshot(snapDrives, snapMemory) def vmMerge(self, vmId, mergeDrives): vm = API.VM(vmId) diff --git a/vdsm/libvirtvm.py b/vdsm/libvirtvm.py index 14bd92e..8d30a9c 100644 --- a/vdsm/libvirtvm.py +++ b/vdsm/libvirtvm.py @@ -26,6 +26,8 @@ from xml.dom.minidom import parseString as _domParseStr import time import threading +import pickle +import re import vm from vdsm.define import ERROR, doneCode, errCode @@ -1554,11 +1556,18 @@ # Reinitialize the merge statuses self._checkMerge() elif 'restoreState' in self.conf: - hooks.before_vm_dehibernate(self.conf.pop('_srcDomXML'), self.conf) + restoreFromSnapshot = self.conf.pop('restoreFromSnapshot', False) + srcDomXML = self.conf.pop('_srcDomXML') + if not restoreFromSnapshot: + hooks.before_vm_dehibernate(srcDomXML, self.conf) fname = self.cif.prepareVolumePath(self.conf['restoreState']) try: - self._connection.restore(fname) + if restoreFromSnapshot: + srcDomXML = self._correctDiskVolumes(srcDomXML) + self._connection.restoreFlags(fname, srcDomXML) + else: + self._connection.restore(fname) finally: self.cif.teardownVolumePath(self.conf['restoreState']) @@ -1585,6 +1594,22 @@ self.setDownStatus(ERROR, 'failed to start libvirt vm') return self._domDependentInit() + + def _correctDiskVolumes(self, srcDomXML): + """ + Update each image in the given XML to point to the right volume. + Each image should have a newer volume than the one that was the + newer when the snapshot was taken, since we create new volume + for each image on 'preview' operation. + """ + for vmDrive in self._devices[vm.DISK_DEVICES]: + if vmDrive.device == 'disk': + pathToImageDir = os.path.dirname(vmDrive.path) + pattern = '(' + pathToImageDir + '.*)\'' + mo = re.search(pattern, srcDomXML) + if mo: + srcDomXML = srcDomXML.replace(mo.group(1), vmDrive.path) + return srcDomXML def hotplugNic(self, params): if self.isMigrating(): @@ -2078,7 +2103,7 @@ self.saveState() - def snapshot(self, snapDrives): + def snapshot(self, snapDrives, memoryParams): """Live snapshot command""" def _diskSnapshot(vmDev, newPath): @@ -2121,6 +2146,21 @@ except: self.log.error("Unable to teardown drive: %s", vmDevName, exc_info=True) + + def _memorySnapshot(memoryVolumePath): + """Libvirt snapshot XML""" + + memory = xml.dom.minidom.Element('memory') + memory.setAttribute('snapshot', 'external') + memory.setAttribute('file', memoryVolumePath) + return memory + + def _vmConfForSnapshot(): + """Returns the needed vm configuration with the memory snapshot""" + + return {'restoreFromSnapshot': True, + '_srcDomXML': self._dom.XMLDesc(0), + 'elapsedTimeOffset': time.time() - self._startTime} snap = xml.dom.minidom.Element('domainsnapshot') disks = xml.dom.minidom.Element('disks') @@ -2176,16 +2216,34 @@ return {'status': doneCode} snap.appendChild(disks) - snapxml = snap.toprettyxml() - self.log.debug(snapxml) - - snapFlags = (libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY | - libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT | + snapFlags = (libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_REUSE_EXT | libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_NO_METADATA) - if utils.tobool(self.conf.get('qgaEnable', 'true')): - snapFlags |= libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE + if memoryParams: + # Adding the memory volume to the snapshot xml + memoryVol = memoryParams['dst'] + memoryVolPath = self.cif.prepareVolumePath(memoryVol) + memorysnapelem = _memorySnapshot(memoryVolPath) + snap.appendChild(memorysnapelem) + + # Save the needed vm configuration + vmConfVol = memoryParams['dstparams'] + vmConfVolPath = self.cif.prepareVolumePath(vmConfVol) + vmConf = _vmConfForSnapshot() + try: + with file(vmConfVolPath, "w") as f: + pickle.dump(vmConf, f) + finally: + self.cif.teardownVolumePath(vmConfVol) + else: + snapFlags |= libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_DISK_ONLY + + if utils.tobool(self.conf.get('qgaEnable', 'true')): + snapFlags |= libvirt.VIR_DOMAIN_SNAPSHOT_CREATE_QUIESCE + + snapxml = snap.toprettyxml() + self.log.debug(snapxml) # We need to stop the collection of the stats for two reasons, one # is to prevent spurious libvirt errors about missing drive paths -- To view, visit http://gerrit.ovirt.org/15072 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I62401940afb0228cbd9dd3611b6ed8e0ff67c82c Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Arik Hadas <aha...@redhat.com> _______________________________________________ vdsm-patches mailing list vdsm-patches@lists.fedorahosted.org https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches