Adam Litke has uploaded a new change for review.
Change subject: tests: Add a live merge functional test ......................................................................
tests: Add a live merge functional test
Test whether we can successfully merge the active layer. Uses lots of the functional test infrastructure! Only runs if vdsm says it can support live merge.
Change-Id: Idd5a2f7eedaef9e90981256de66fc3ed21658e89 Signed-off-by: Adam Litke alitke@redhat.com --- M tests/functional/utils.py M tests/functional/virtTests.py 2 files changed, 185 insertions(+), 5 deletions(-)
git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/24/29824/1
diff --git a/tests/functional/utils.py b/tests/functional/utils.py index 494be98..e3cdba6 100644 --- a/tests/functional/utils.py +++ b/tests/functional/utils.py @@ -228,3 +228,41 @@ def updateVmPolicy(self, vmId, vcpuLimit): result = self.vdscli.updateVmPolicy([vmId, vcpuLimit]) return result['status']['code'], result['status']['message'] + + def getTaskStatus(self, taskId): + result = self.vdscli.getTaskStatus(taskId) + return result['status']['code'], result['status']['message'],\ + result['taskStatus'] + + def getVolumeInfo(self, sdId, spId, imgId, volId): + result = self.vdscli.getVolumeInfo(sdId, spId, imgId, volId) + return result['status']['code'], result['status']['message'],\ + result['info'] + + def createVolume(self, sdId, spId, imgId, size, volFormat, preallocate, + diskType, volId, desc, baseImgId, baseVolId): + result = self.vdscli.createVolume(sdId, spId, imgId, size, volFormat, + preallocate, diskType, volId, desc, + baseImgId, baseVolId) + return result['status']['code'], result['status']['message'],\ + result['uuid'] + + def deleteVolume(self, sdId, spId, imgId, volIds, postZero=False, + force=False): + result = self.vdscli.deleteVolume(sdId, spId, imgId, volIds, postZero, + force) + return result['status']['code'], result['status']['message'],\ + result['uuid'] + + def snapshot(self, vmId, snapDrives, snapMemVolHandle=''): + result = self.vdscli.snapshot(vmId, snapDrives, snapMemVolHandle) + return result['status']['code'], result['status']['message'] + + def merge(self, vmId, drive, base, top, bandwidth, jobId): + result = self.vdscli.merge(vmId, drive, base, top, bandwidth, jobId) + return result['status']['code'], result['status']['message'] + + def list(self, fullStatus=False, vmList=()): + result = self.vdscli.list(fullStatus, vmList) + return result['status']['code'], result['status']['message'], \ + result['vmList'] diff --git a/tests/functional/virtTests.py b/tests/functional/virtTests.py index 94ce240..b811b92 100644 --- a/tests/functional/virtTests.py +++ b/tests/functional/virtTests.py @@ -22,6 +22,7 @@ import math import tempfile import logging +import uuid from stat import S_IROTH from functools import partial, wraps
@@ -32,7 +33,8 @@ from testrunner import temporaryPath
from vdsm.utils import CommandPath, RollbackContext -import storageTests as storage +import storageTests +import storage from storage.misc import execCmd
from utils import VdsProxy, SUCCESS @@ -109,6 +111,18 @@ return method(self, *args, **kwargs) else: raise SkipTest('KVM is not enabled') + return wrapped + + +def requireLiveMerge(method): + @wraps(method) + def wrapped(self, *args, **kwargs): + status, msg, result = self.vdsm.getVdsCapabilities() + self.assertEqual(status, SUCCESS, msg) + if result.get('liveMerge') == 'true': + return method(self, *args, **kwargs) + else: + raise SkipTest('Live Merge is not available') return wrapped
@@ -227,9 +241,9 @@ @requireKVM @permutations([['localfs'], ['iscsi'], ['nfs']]) def testVmWithStorage(self, backendType): - disk = storage.StorageTest() + disk = storageTests.StorageTest() disk.setUp() - conf = storage.storageLayouts[backendType] + conf = storageTests.storageLayouts[backendType] drives = disk.generateDriveConf(conf) customization = {'vmId': '88888888-eeee-ffff-aaaa-111111111111', 'vmName': 'testVmWithStorage' + backendType, @@ -247,8 +261,8 @@ def testVmWithDevice(self, *devices): customization = {'vmId': '77777777-ffff-3333-bbbb-222222222222', 'vmName': 'testVm', 'devices': [], 'display': 'vnc'} - storageLayout = storage.storageLayouts['localfs'] - diskSpecs = storage.StorageTest.generateDriveConf(storageLayout) + storageLayout = storageTests.storageLayouts['localfs'] + diskSpecs = storageTests.StorageTest.generateDriveConf(storageLayout) pciSpecs = {'bus': '0x00', 'domain': '0x0000', 'function': '0x0', 'type': 'pci'} ccidSpecs = {'slot': '0', 'controller': '0', 'type': 'ccid'} @@ -412,3 +426,131 @@ self.vdsm.updateVmPolicy(customization['vmId'], '50') self.assertEqual(status, SUCCESS, msg) + + +@expandPermutations +class LiveMergeTest(VirtTestBase): + def _waitTask(self, taskId): + def assertTaskOK(): + status, msg, result = self.vdsm.getTaskStatus(taskId) + self.assertEqual(status, SUCCESS, msg) + self.assertEquals(result['taskState'], 'finished') + + self.retryAssert(assertTaskOK, timeout=60) + + def _waitBlockJobs(self, vmId, jobIds): + def assertJobsGone(): + status, msg, result = self.vdsm.getVmStats(vmId) + self.assertEqual(status, SUCCESS, msg) + self.assertTrue('vmJobs' in result) + self.assertTrue(all([x not in result['vmJobs'].keys() + for x in jobIds])) + + self.retryAssert(assertJobsGone, timeout=60) + + def _snapshotVM(self, vmId, drives, rollback): + snapDrives = [] + for drive in drives: + sd = drive['domainID'] + sp = drive['poolID'] + img = drive['imageID'] + vol = drive['volumeID'] + newVol = str(uuid.uuid4()) + volFormat = storage.volume.COW_FORMAT + preallocate = storage.volume.SPARSE_VOL + desc = 'snapshot for %s' % vol + + # Create volume and wait + status, msg, result = self.vdsm.getVolumeInfo(sd, sp, img, vol) + self.assertEqual(status, SUCCESS, msg) + size = result['capacity'] + diskType = result['disktype'] + + status, msg, taskId = self.vdsm.createVolume(sd, sp, img, size, + volFormat, + preallocate, diskType, + newVol, desc, img, + vol) + self.assertEqual(status, SUCCESS, msg) + self._waitTask(taskId) + undo = lambda sd=sd, sp=sp, img=img, vol=newVol: \ + self._waitTask(self.vdsm.deleteVolume(sd, sp, img, vol)[2]) + rollback.prependDefer(undo) + + snapDrives.append({'domainID': sd, + 'imageID': img, + 'volumeID': newVol, + 'baseVolumeID': vol}) + + # Create snapshot + status, msg = self.vdsm.snapshot(vmId, snapDrives) + self.assertEqual(status, SUCCESS, msg) + return snapDrives + + def _orderChain(self, vmId, dev, chain): + parentMap = {} + for vol in chain: + status, msg, info = self.vdsm.getVolumeInfo(dev['domainID'], + dev['poolID'], + dev['imageID'], vol) + self.assertEqual(status, SUCCESS, msg) + parent = info['parent'] + parentMap[vol] = parent + + vol = dev['volumeID'] + chain = list() + while True: + chain.insert(0, vol) + vol = parentMap.get(vol, '00000000-0000-0000-0000-000000000000') + if vol == '00000000-0000-0000-0000-000000000000': + break + return chain + + def _getVolumeChains(self, vmId): + chains = {} + status, msg, result = self.vdsm.list(True, (vmId,)) + self.assertEqual(status, SUCCESS, msg) + vmDef = result[0] + for dev in vmDef['devices']: + if dev['device'] != 'disk': + continue + chains[dev['imageID']] = self._orderChain(vmId, dev, + [x['volumeID'] for x in + dev['volumeChain']]) + return chains + + @requireKVM + @requireLiveMerge + def testCapable(self): + pass + + @permutations([['localfs']]) + def testMergeActiveLayer(self, backendType): + disk = storageTests.StorageTest() + disk.setUp() + conf = storageTests.storageLayouts[backendType] + drives = disk.generateDriveConf(conf) + vmId = '12121212-abab-baba-abab-222222222222' + customization = {'vmId': vmId, + 'vmName': 'testMergeActive' + backendType, + 'drives': drives, + 'display': 'vnc'} + + with RollbackContext() as rollback: + disk.createVdsmStorageLayout(conf, 3, rollback) + with RunningVm(self.vdsm, customization) as vm: + self._waitForStartup(vm, VM_MINIMAL_UPTIME) + snapDrives = self._snapshotVM(vmId, drives, rollback) + chains = {} + jobIds = [] + for drive in snapDrives: + base = drive['baseVolumeID'] + top = drive['volumeID'] + jobId = str(uuid.uuid4()) + chains[drive['imageID']] = [base, top] + status, msg = self.vdsm.merge(vmId, drive, base, top, 0, + jobId) + jobIds.append(jobId) + self._waitBlockJobs(vmId, jobIds) + actual = self._getVolumeChains(vmId) + self.assertEquals(chains, actual)