Zhou Zheng Sheng has uploaded a new change for review. Change subject: tests: add iscsi storage functional test ......................................................................
tests: add iscsi storage functional test Change-Id: Icaef5d6145b8f493b5eaab0b75564f88a4cb82ce Signed-off-by: Zhou Zheng Sheng <[email protected]> --- M tests/functional/xmlrpcTests.py M vdsm.spec.in 2 files changed, 191 insertions(+), 12 deletions(-) git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/42/9842/1 diff --git a/tests/functional/xmlrpcTests.py b/tests/functional/xmlrpcTests.py index c259533..82128f1 100644 --- a/tests/functional/xmlrpcTests.py +++ b/tests/functional/xmlrpcTests.py @@ -27,20 +27,25 @@ from testrunner import VdsmTestCase as TestCaseBase from nose.plugins.skip import SkipTest +import selinux from vdsm.config import config from vdsm.constants import VDSM_USER, VDSM_GROUP, QEMU_PROCESS_USER, EXT_SUDO +from vdsm.constants import EXT_DD import storage.sd import storage.volume from storage.misc import execCmd from storage.misc import RollbackContext +from storage.fileUtils import createdir from vdsm.utils import CommandPath +from vdsm.utils import retry from vdsm import vdscli if not config.getboolean('vars', 'xmlrpc_enable'): raise SkipTest("XML-RPC Bindings are disabled") _mkinitrd = CommandPath("mkinird", "/usr/bin/mkinitrd") +_tgtadm = CommandPath("tgtadm", "/usr/sbin/tgtadm") def readableBy(filePath, user): @@ -198,6 +203,11 @@ def testLocalfs(self): conf = storageLayouts['localfs'] + with RollbackContext() as rollback: + self._createVdsmStorageLayout(conf, rollback) + + def testIscsi(self): + conf = storageLayouts['iscsi'] with RollbackContext() as rollback: self._createVdsmStorageLayout(conf, rollback) @@ -387,24 +397,157 @@ class IscsiServer(object): - def __init__(self, vdsmServer): + def __init__(self, vdsmServer, asserts): self.s = vdsmServer + self.asserts = asserts + self.address = '127.0.0.1' + + def _createTarget(self, tid, iqn): + rc, out, err = execCmd( + [_tgtadm.cmd, '--lld', 'iscsi', '--op', 'new', '--mode', 'target', + '--tid', str(tid), '-T', iqn]) + self.asserts.assertEquals(rc, 0) + + def _deleteTarget(self, tid): + rc, out, err = execCmd( + [_tgtadm.cmd, '--lld', 'iscsi', '--op', 'delete', '--mode', + 'target', '--tid', str(tid), '--force']) + self.asserts.assertEquals(rc, 0) + + def _tryCreateTarget(self, iqn, rollback): + for i in range(1, 100): + try: + self._createTarget(i, iqn) + except AssertionError: + continue + + rollback.prependDefer( + lambda tid=i: self._deleteTarget(tid)) + return i + + raise RuntimeError("Can not create iscsi target") + + def _addLUN(self, tid, lunid, backingStore): + rc, out, err = execCmd( + [_tgtadm.cmd, '--lld', 'iscsi', '--op', 'new', '--mode', + 'logicalunit', '--tid', str(tid), '--lun', str(lunid), + '-b', backingStore]) + self.asserts.assertEquals(rc, 0) + + def _deleteLUN(self, tid, lunid): + rc, out, err = execCmd( + [_tgtadm.cmd, '--lld', 'iscsi', '--op', 'delete', '--mode', + 'logicalunit', '--tid', str(tid), '--lun', str(lunid)]) + self.asserts.assertEquals(rc, 0) + + def _tryAddLUN(self, tid, lunid, backingStore, rollback): + self._addLUN(tid, lunid, backingStore) + rollback.prependDefer(lambda: self._deleteLUN(tid, lunid)) + + def _bindAddress(self, tid, address): + rc, out, err = execCmd( + [_tgtadm.cmd, '--lld', 'iscsi', '--op', 'bind', '--mode', 'target', + '--tid', str(tid), '-I', address]) + self.asserts.assertEquals(rc, 0) + + def _tryCreateEmptyImage(self, diskPath, rollback): + rc, out, err = execCmd( + [EXT_DD, 'if=/dev/zero', 'of=%s' % diskPath, 'bs=1M', 'seek=10240', + 'count=0']) + self.asserts.assertEquals(rc, 0) + rollback.prependDefer( + lambda diskPath=diskPath: os.unlink(diskPath)) def _createBackend(self, backendDef, rollback): - # Create iscsi target - pass + pathTgtd = '/var/lib/tgtd' + createdir(pathTgtd) # needn't delete this dir, so no undo is added + os.chown(pathTgtd, 0, 0) + selinux.restorecon(pathTgtd) + + connections = {} + for uuid, conn in backendDef.iteritems(): + iqn = conn['iqn'] + diskPath = "%s/%s" % (pathTgtd, uuid) + self._tryCreateEmptyImage(diskPath, rollback) + os.chown(diskPath, 0, 0) + selinux.restorecon(diskPath) + tid = self._tryCreateTarget(iqn, rollback) + self._tryAddLUN(tid, 1, diskPath, rollback) + self._bindAddress(tid, self.address) + connections[uuid] = { + 'type': 'iscsi', + 'params': {'portal': {'host': self.address}, 'iqn': iqn}} + + return connections def _connectBackend(self, connections, rollback): - # Connect iscsi storage server - pass + r = self.s.storageServer_ConnectionRefs_acquire(connections) + self.asserts.assertVdsOK(r) - def _genTypeSpecificArgs(self, connections, rollback): - # Create VG - # Generate UUIDs of those VG - pass + def releaseConnection(): + import time + time.sleep(30) + r = self.s.storageServer_ConnectionRefs_release( + connections.keys()) + time.sleep(30) + # test will fail if we do not sleep. + # the LUN can not be removed from the target. + # tgtadm will say it is still occupied, + # and iscsiadm still have avtive sessions + # even if we remove the storage domain and pools + # and connections. + # Why ? + self.asserts.assertVdsOK(r) + + rollback.prependDefer(releaseConnection) + for _refid, status in r['results'].iteritems(): + self.asserts.assertEquals(status, 0) + + def _tryCreateVG(self, vgName, devName, rollback): + r = self.s.createVG(vgName, [devName]) + self.asserts.assertVdsOK(r) + vgid = r['uuid'] + rollback.prependDefer( + lambda: self.asserts.assertVdsOK( + self.s.removeVG(vgid))) + return vgid + + def _genTypeSpecificArgs(self, backendDef, rollback): + iqns = map(lambda conn: conn['iqn'], + backendDef.itervalues()) + + def getIqnDevs(iqns=iqns): + '''find the related device of a iqn''' + r = self.s.getDeviceList() + devList = r['devList'] + self.asserts.assertVdsOK(r) + iqnDevs = {} + for iqn in iqns: + for dev in devList: + if iqn in map(lambda p: p['iqn'], dev['pathlist']): + iqnDevs[iqn] = dev['GUID'] + break + else: + raise RuntimeError( + 'Can not find related device of iqn %s' % iqn) + return iqnDevs + + # changes on the devices may not be known to VDSM immediately + iqnDevs = retry(getIqnDevs, expectedException=RuntimeError, + timeout=40, sleep=5) + + args = {} + for uuid, conn in backendDef.iteritems(): + iqn = conn['iqn'] + vgid = self._tryCreateVG(conn['sd'], iqnDevs[iqn], rollback) + args[uuid] = vgid + + return args def prepare(self, backendDef, rollback): - pass + connections = self._createBackend(backendDef, rollback) + self._connectBackend(connections, rollback) + return self._genTypeSpecificArgs(backendDef, rollback) storageLayouts = \ @@ -443,5 +586,40 @@ "bace8f68-4c5a-43f2-acb4-fa8daf58c0f9"]}}}, 'nfs': {'server': 'blah', 'conn': 'blah', 'sd': 'blah', 'sp': 'blah', 'img': 'blah', 'layout': 'blah'}, - 'iscsi': {'server': 'blah', 'conn': 'blah', 'sd': 'blah', 'sp': 'blah', - 'img': 'blah', 'layout': 'blah'}} + 'iscsi': { + 'server': IscsiServer, + 'conn': { + '3bd3092e-096b-4409-a2de-e10313a0d8af': { + 'iqn': 'iqn.2012-12.org.ovirt.tests:vdsmtests0', + 'sd': '3f330c2c-9b01-4167-9df5-cf665f95e3a6'}, + '28ba1368-9f5c-4441-a7fd-94e85435564b': { + 'iqn': 'iqn.2012-12.org.ovirt.tests:vdsmtests1', + 'sd': 'a73a818b-3341-457a-8139-a6a71194ab7a'}}, + 'sd': { + "3f330c2c-9b01-4167-9df5-cf665f95e3a6": { + "name": "test iscsi domain0", + "type": "iscsi", "class": "Data", + "connUUID": "3bd3092e-096b-4409-a2de-e10313a0d8af"}, + "a73a818b-3341-457a-8139-a6a71194ab7a": { + "name": "test iscsi domain1", + "type": "iscsi", "class": "Data", + "connUUID": "28ba1368-9f5c-4441-a7fd-94e85435564b"}}, + 'sp': { + "39178935-1f2e-4cd1-8c2d-4f47097d80a3": { + "name": "iscsi storage pool", "master_ver": 1, "host": 1, + "master_uuid": "3f330c2c-9b01-4167-9df5-cf665f95e3a6"}}, + 'img': { + "a81db3fc-5586-4e35-9785-912c28ada09d": { + "description": "Test iscsi volume0", "type": "leaf", + "volid": "a921cdf0-b322-4ee8-84e6-8e87c65c016f", + "format": "cow", "preallocate": "sparse", "size": 20971520}, + "35c728e1-edf1-4068-8f25-02d21feb85cd": { + "description": "test iscsi volume1", "type": "leaf", + "volid": "eb42c709-42a2-4227-a5b6-f368df3a2613", + "format": "cow", "preallocate": "sparse", "size": 20971520}}, + 'layout': { + "39178935-1f2e-4cd1-8c2d-4f47097d80a3": { + "3f330c2c-9b01-4167-9df5-cf665f95e3a6": [ + "a81db3fc-5586-4e35-9785-912c28ada09d"], + "a73a818b-3341-457a-8139-a6a71194ab7a": [ + "35c728e1-edf1-4068-8f25-02d21feb85cd"]}}}} diff --git a/vdsm.spec.in b/vdsm.spec.in index 9830afe..11fc3fc 100644 --- a/vdsm.spec.in +++ b/vdsm.spec.in @@ -220,6 +220,7 @@ Requires: vdsm = %{version}-%{release} Requires: dracut Requires: python-nose +Requires: scsi-target-utils BuildArch: noarch %description tests -- To view, visit http://gerrit.ovirt.org/9842 To unsubscribe, visit http://gerrit.ovirt.org/settings Gerrit-MessageType: newchange Gerrit-Change-Id: Icaef5d6145b8f493b5eaab0b75564f88a4cb82ce Gerrit-PatchSet: 1 Gerrit-Project: vdsm Gerrit-Branch: master Gerrit-Owner: Zhou Zheng Sheng <[email protected]> _______________________________________________ vdsm-patches mailing list [email protected] https://lists.fedorahosted.org/mailman/listinfo/vdsm-patches
