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

Reply via email to