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(a)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(a)redhat.com>