Change in vdsm[master]: LiveMerge: Add Image.scanVolumes API

alitke at redhat.com alitke at redhat.com
Wed Mar 19 21:35:30 UTC 2014


Adam Litke has uploaded a new change for review.

Change subject: LiveMerge: Add Image.scanVolumes API
......................................................................

LiveMerge: Add Image.scanVolumes API

TODO:
 - Revisit function naming

Change-Id: I9e50d7292b98b5dbf1f0978efe5f0de589b3dbc0
Signed-off-by: Adam Litke <alitke at redhat.com>
---
M client/vdsClient.py
M vdsm/API.py
M vdsm/BindingXMLRPC.py
M vdsm/storage/hsm.py
M vdsm/vm.py
5 files changed, 94 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/18/25918/1

diff --git a/client/vdsClient.py b/client/vdsClient.py
index 6344ed6..d818a5a 100644
--- a/client/vdsClient.py
+++ b/client/vdsClient.py
@@ -1385,6 +1385,19 @@
             return image['status']['code'], image['status']['message']
         return 0, image['uuid']
 
+    def imageScanVolumes(self, args):
+        spUUID = args[0]
+        sdUUID = args[1]
+        imgUUID = args[2]
+
+        if len(args) > 3:
+            chain = self.s.imageScanVolumes(spUUID, sdUUID, imgUUID, args[3])
+        else:
+            chain = self.s.imageScanVolumes(spUUID, sdUUID, imgUUID)
+        if chain['status']['code']:
+            return chain['status']['code'], chain['status']['message']
+        return 0, '\n'.join(chain['volumes'])
+
     def mergeSnapshots(self, args):
         sdUUID = args[0]
         spUUID = args[1]
@@ -2411,6 +2424,14 @@
                        'Do it by collapse and copy the whole chain '
                        '(baseVolUUID->srcVolUUID)'
                        )),
+        'scanVolumeChain': (serv.imageScanVolumes,
+                            ('<spUUID> <sdUUID> <imgUUID> [<vmUUID>]',
+                             'Return the volumes that are actually in the '
+                             'image chain according to the hypervisor. '
+                             'If vmUUID is provided and the VM is runing, '
+                             'the VM will be queried.  Otherwise the storage '
+                             'itself will be scanned.'
+                             )),
         'mergeSnapshots': (serv.mergeSnapshots,
                            ('<sdUUID> <spUUID> <vmUUID> <imgUUID> <Ancestor '
                             'Image uuid> <Successor Image uuid> [<postZero>]',
diff --git a/vdsm/API.py b/vdsm/API.py
index ae959ef..7e3f18e 100644
--- a/vdsm/API.py
+++ b/vdsm/API.py
@@ -866,6 +866,20 @@
             methodArgs, callback, self._spUUID, self._sdUUID, self._UUID,
             volUUID)
 
+    def scanVolumes(self, vmUUID=None):
+        # If vmUUID is provided, we try to ask the running VM for the current
+        # state which is already synchronized with qemu.  Otherwise, we use
+        # qemu-img on the volumes directly to determine current state.
+        if vmUUID:
+            try:
+                v = self._cif.vmContainer.get(vmUUID)
+                if v:
+                    return v.getImageVolumes(self._UUID)
+            except KeyError:
+                pass
+        return self._irs.imageScanVolumes(self._spUUID, self._sdUUID,
+                                          self._UUID)
+
 
 class LVMVolumeGroup(APIBase):
     ctorArgs = ['lvmvolumegroupID']
diff --git a/vdsm/BindingXMLRPC.py b/vdsm/BindingXMLRPC.py
index 259c262..d523957 100644
--- a/vdsm/BindingXMLRPC.py
+++ b/vdsm/BindingXMLRPC.py
@@ -601,6 +601,10 @@
         image = API.Image(imgUUID, spUUID, sdUUID)
         return image.download(methodArgs, volUUID)
 
+    def imageScanVolumes(self, spUUID, sdUUID, imgUUID, vmUUID=None):
+        image = API.Image(imgUUID, spUUID, sdUUID)
+        return image.scanVolumes(vmUUID)
+
     def poolConnect(self, spUUID, hostID, scsiKey, msdUUID, masterVersion,
                     domainsMap=None, options=None):
         pool = API.StoragePool(spUUID)
@@ -949,6 +953,7 @@
                 (self.imageSyncData, 'syncImageData'),
                 (self.imageUpload, 'uploadImage'),
                 (self.imageDownload, 'downloadImage'),
+                (self.imageScanVolumes, 'imageScanVolumes'),
                 (self.poolConnect, 'connectStoragePool'),
                 (self.poolConnectStorageServer, 'connectStorageServer'),
                 (self.poolCreate, 'createStoragePool'),
diff --git a/vdsm/storage/hsm.py b/vdsm/storage/hsm.py
index 2e9dbe5..58fbc61 100644
--- a/vdsm/storage/hsm.py
+++ b/vdsm/storage/hsm.py
@@ -1772,6 +1772,45 @@
             misc.parseBool(postZero), misc.parseBool(force))
 
     @public
+    def imageScanVolumes(self, spUUID, sdUUID, imgUUID):
+        argsStr = ("spUUID=%s, sdUUID=%s, imgUUID=%s" %
+                   (spUUID, sdUUID, imgUUID))
+        vars.task.setDefaultException(se.StorageException("%s" % argsStr))
+
+        backingFiles = {}
+        leafVol = None
+        dom = sdCache.produce(sdUUID=sdUUID)
+        repoPath = os.path.join(self.storage_repository, dom.getPools()[0])
+        volclass = dom.getVolumeClass()
+        knownVols = volclass.getImageVolumes(repoPath, sdUUID, imgUUID)
+
+        imageResourcesNamespace = sd.getNamespace(sdUUID, IMAGE_NAMESPACE)
+        with rmanager.acquireResource(imageResourcesNamespace, imgUUID,
+                                      rm.LockType.shared):
+            # TODO: Do we need to ensure that they get deactivated also?
+            dom.activateVolumes(imgUUID, knownVols)
+
+            for volUUID in knownVols:
+                vol = dom.produceVolume(imgUUID, volUUID)
+                if vol.isLeaf():
+                    leafVol = volUUID
+                qemuImgFormat = volume.fmt2str(vol.getFormat())
+                imgInfo = qemuImg.info(vol.volumePath, qemuImgFormat)
+                backingFile = imgInfo.get('backingfile')
+                if backingFile is not None:
+                    # XXX: Is there a proper API for getting the volume UUID
+                    # from a path string?
+                    backingVol = os.path.basename(backingFile)
+                    backingFiles[volUUID] = backingVol
+
+        volUUID = leafVol
+        retVolumes = [leafVol]
+        while backingFiles.get(volUUID) is not None:
+            volUUID = backingFiles[volUUID]
+            retVolumes.insert(0, volUUID)
+        return dict(volumes=retVolumes)
+
+    @public
     def mergeSnapshots(self, sdUUID, spUUID, vmUUID, imgUUID, ancestor,
                        successor, postZero=False):
         """
diff --git a/vdsm/vm.py b/vdsm/vm.py
index 6e3fbeb..0a68ee0 100644
--- a/vdsm/vm.py
+++ b/vdsm/vm.py
@@ -5275,6 +5275,21 @@
         hooks.before_vm_migrate_destination(srcDomXML, self.conf)
         return True
 
+    def getImageVolumes(self, imageID):
+        targetDrive = None
+        for drive in self._devices[DISK_DEVICES][:]:
+            try:
+                if drive.imageID == imageID:
+                    targetDrive = drive
+            except AttributeError:
+                continue
+        if targetDrive is None:
+            return {'status': errCode['imageErr']}
+        volumes = []
+        for v in targetDrive.volumeChain:
+            volumes.append(v['volumeID'])
+        return {'status': doneCode, 'volumes': volumes}
+
 
 # A little unrelated hack to make xml.dom.minidom.Document.toprettyxml()
 # not wrap Text node with whitespace.


-- 
To view, visit http://gerrit.ovirt.org/25918
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I9e50d7292b98b5dbf1f0978efe5f0de589b3dbc0
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Adam Litke <alitke at redhat.com>


More information about the vdsm-patches mailing list