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

Reply via email to