Change in vdsm[master]: tests: added NFS support to functional tests

ykleinbe at redhat.com ykleinbe at redhat.com
Tue Sep 16 14:50:41 UTC 2014


Yoav Kleinberger has uploaded a new change for review.

Change subject: tests: added NFS support to functional tests
......................................................................

tests: added NFS support to functional tests

In this patch, I introduce a new NFS storage context for the storage
functional tests. Since there is much shared logic between NFS and
LocalFS storage context, I introduce a common superclass.

Change-Id: I1781fc400c0604855d3143dde22ccb29e6cc8013
Signed-off-by: Yoav Kleinberger <ykleinbe at redhat.com>
---
M tests/functional/basicStorageTest.py
M tests/functional/testlib/storagecontexts/base.py
A tests/functional/testlib/storagecontexts/filebased.py
M tests/functional/testlib/storagecontexts/iscsi.py
M tests/functional/testlib/storagecontexts/localfs.py
A tests/functional/testlib/storagecontexts/nfs.py
6 files changed, 249 insertions(+), 114 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/vdsm refs/changes/90/32990/1

diff --git a/tests/functional/basicStorageTest.py b/tests/functional/basicStorageTest.py
index c01d14b..438f8c8 100644
--- a/tests/functional/basicStorageTest.py
+++ b/tests/functional/basicStorageTest.py
@@ -4,6 +4,7 @@
 from functional.testlib import controlvdsm
 from functional.testlib.storagecontexts import localfs
 from functional.testlib.storagecontexts import iscsi
+from functional.testlib.storagecontexts import nfs
 
 
 class TestBasicStorageDomain(object):
@@ -23,6 +24,9 @@
     def testCreateVolumeISCSI(self):
         self._testCreateVolume(iscsi.ISCSI)
 
+    def testCreateVolumeNFS(self):
+        self._testCreateVolume(nfs.NFS)
+
     def _testCreateVolume(self, storageBackend):
         with storageBackend() as (vdsm, verify):
             storageServerID = vdsm.connectStorageServer()
diff --git a/tests/functional/testlib/storagecontexts/base.py b/tests/functional/testlib/storagecontexts/base.py
index 7179694..2e308ad 100644
--- a/tests/functional/testlib/storagecontexts/base.py
+++ b/tests/functional/testlib/storagecontexts/base.py
@@ -73,16 +73,47 @@
 class StorageBackend(object):
     def __init__(self):
         self._vdsmCaller = vdsmcaller.VDSMCaller()
+        self._domainID = self._newUUID()
+        self._poolID = self._newUUID()
+        self._imageID = self._newUUID()
+        self._volumeID = self._newUUID()
+        self._connectionID = self._newUUID()
+
+    def connectionID(self):
+        return self._connectionID
+
+    def volumeID(self):
+        return self._volumeID
+
+    def imageID(self):
+        return self._imageID
+
+    def poolID(self):
+        return self._poolID
+
+    def domainID(self):
+        return self._domainID
 
     def vdsm(self):
         return self._vdsmCaller
 
-    def newUUID(self):
+    def _newUUID(self):
         return str(uuid.uuid4())
 
     def randomName(self, base):
         return "%s_%04d" % (base, random.randint(1, 10000))
 
+    def createStoragePool(self):
+        POOL_TYPE_DEPRECATED = 0
+        self.vdsm().createStoragePool(
+            POOL_TYPE_DEPRECATED,
+            self.poolID(),
+            self.randomName('pool'),
+            self.domainID(),
+            [self.domainID()],
+            1)
+        return self.poolID()
+
     def connectStoragePool(self, poolID, masterDomainID):
         SCSI_KEY_DEPRECATED = 0
         self.vdsm().connectStoragePool(
diff --git a/tests/functional/testlib/storagecontexts/filebased.py b/tests/functional/testlib/storagecontexts/filebased.py
new file mode 100644
index 0000000..bdb15d7
--- /dev/null
+++ b/tests/functional/testlib/storagecontexts/filebased.py
@@ -0,0 +1,69 @@
+import os
+import storage.volume
+import storage.image
+from . import base
+import logging
+
+
+class Verify(base.Verify):
+
+    def rhevMountPoint(self):
+        raise Exception('you must override this function')
+
+    def storageServerConnected(self):
+        self.sleepWhileVDSMCompletesTask(duration=2)
+        assert os.path.exists(self.rhevMountPoint())
+
+    def storageDomainCreated(self, domainID):
+        self.sleepWhileVDSMCompletesTask(duration=1)
+        self._directIOTestFileExists()
+        domainRoot = os.path.join(self.rhevMountPoint(), domainID)
+        expectedFiles = [
+            'images',
+            'dom_md',
+            'dom_md/leases',
+            'dom_md/inbox',
+            'dom_md/outbox',
+            'dom_md/metadata',
+            'dom_md/ids']
+        expectedFullPaths =\
+            [os.path.join(domainRoot, path) for path in expectedFiles]
+        for path in expectedFullPaths:
+            logging.info('verifying path: %s' % path)
+            assert os.path.exists(path)
+
+    def _directIOTestFileExists(self):
+        directIOTestFile = os.path.join(
+            self.rhevMountPoint(),
+            '__DIRECT_IO_TEST__')
+        assert os.path.exists(directIOTestFile)
+
+    def volumeCreated(self, volumeInfo):
+        taskID, domainID, imageID, volumeID = volumeInfo
+        self.waitUntilVDSMTaskFinished(taskID, 20)
+        domainRoot = os.path.join(self.rhevMountPoint(), domainID)
+        imageDirectory = os.path.join(domainRoot, 'images', imageID)
+        assert os.path.exists(imageDirectory)
+        volumeFile = os.path.join(imageDirectory, volumeID)
+        volumeLease = '%s.lease' % volumeFile
+        volumeMeta = '%s.meta' % volumeFile
+        for path in volumeFile, volumeLease, volumeMeta:
+            logging.info('verifying path: %s' % path)
+            assert os.path.exists(path)
+
+
+class FileBased(base.StorageBackend):
+    def createVolume(self, size):
+        PREALLOCATE = 1
+        result = self.vdsm().createVolume(
+            self.domainID(),
+            self.poolID(),
+            self.imageID(),
+            self.largeIntegerXMLRPCWorkaround(size),
+            storage.volume.RAW_FORMAT,
+            PREALLOCATE,
+            storage.image.DATA_DISK_TYPE,
+            self.volumeID(),
+            self.randomName('volume_description'))
+        taskID = result['uuid']
+        return taskID, self.domainID(), self.imageID(), self.volumeID()
diff --git a/tests/functional/testlib/storagecontexts/iscsi.py b/tests/functional/testlib/storagecontexts/iscsi.py
index 0e891ee..eb19715 100644
--- a/tests/functional/testlib/storagecontexts/iscsi.py
+++ b/tests/functional/testlib/storagecontexts/iscsi.py
@@ -60,11 +60,7 @@
         base.StorageBackend.__init__(self)
         self._iqn = 'iqn.1970-01.functional.test:%04d' %\
             random.randint(1, 10000)
-        self._volumeGroup = {'uuid': self.newUUID(), 'vgs_uuid': None}
-        self._poolID = self.newUUID()
-        self._connectionID = self.newUUID()
-        self._imageID = self.newUUID()
-        self._volumeID = self.newUUID()
+        self._volumeGroup = {'uuid': self.domainID(), 'vgs_uuid': None}
 
     def _targetcli(self, command):
         commandAsList = command.split()
@@ -77,6 +73,16 @@
         self._fileioBackstore = self.randomName('backfile')
         logging.info('using %s, %s' %
                      (self._fileioBackstore, self._storageFile))
+        self._setupISCSITarget()
+        return (self,
+                Verify(
+                    self._iqn,
+                    self._volumeGroup,
+                    self.vdsm,
+                    self.volumeID())
+                )
+
+    def _setupISCSITarget(self):
         self._targetcli('/backstores/fileio create %s %s 10G' %
                         (self._fileioBackstore, self._storageFile))
         self._targetcli('/iscsi create %s' % self._iqn)
@@ -88,13 +94,6 @@
         self._targetcli('/iscsi/%s/tpg1 set attribute '
                         'generate_node_acls=1 '
                         'cache_dynamic_acls=1' % self._iqn)
-        return (self,
-                Verify(
-                    self._iqn,
-                    self._volumeGroup,
-                    self.vdsm,
-                    self._volumeID)
-                )
 
     def __exit__(self, *args):
         doubleDashed = self._volumeGroup['uuid'].replace('-', '--')
@@ -145,27 +144,13 @@
             'user': '',
             'tpgt': '1',
             'password': '',
-            'id': self._connectionID,
+            'id': self.connectionID(),
             'port': '3260'
             }
         self.vdsm().disconnectStorageServer(
             storage.sd.ISCSI_DOMAIN,
-            self._poolID,
+            self.poolID(),
             [connection])
-
-    def createStoragePool(self):
-        POOL_TYPE_DEPRECATED = 0
-        self.vdsm().createStoragePool(
-            POOL_TYPE_DEPRECATED,
-            self._poolID,
-            self.randomName('pool'),
-            self._domainID(),
-            [self._domainID()],
-            1)
-        return self._poolID
-
-    def _domainID(self):
-        return self._volumeGroup['uuid']
 
     def _createVG(self):
         lun = self._findLUN()
@@ -194,14 +179,14 @@
     def createVolume(self, size):
         PREALLOCATE = 1
         result = self.vdsm().createVolume(
-            self._domainID(),
-            self._poolID,
-            self._imageID,
+            self.domainID(),
+            self.poolID(),
+            self.imageID(),
             self.largeIntegerXMLRPCWorkaround(size),
             storage.volume.RAW_FORMAT,
             PREALLOCATE,
             storage.image.DATA_DISK_TYPE,
-            self._volumeID,
+            self.volumeID(),
             self.randomName('iscsi_description'))
         logging.info('createVolume result: %s' % result)
         return result['uuid']
diff --git a/tests/functional/testlib/storagecontexts/localfs.py b/tests/functional/testlib/storagecontexts/localfs.py
index ef341a0..6ba2914 100644
--- a/tests/functional/testlib/storagecontexts/localfs.py
+++ b/tests/functional/testlib/storagecontexts/localfs.py
@@ -5,67 +5,24 @@
 import storage.sd
 import storage.volume
 import storage.image
-from . import base
+from . import filebased
 
 
-class Verify(base.Verify):
+class Verify(filebased.Verify):
     def __init__(self, directory, vdsm):
-        base.Verify.__init__(self, vdsm)
+        filebased.Verify.__init__(self, vdsm)
         self._directory = directory
 
-    def storageServerConnected(self):
-        self.sleepWhileVDSMCompletesTask(duration=2)
+    def rhevMountPoint(self):
         transformedDirectory = self._directory.replace('/', '_')
-        expectedSymlink = os.path.join(
+        result = os.path.join(
             '/rhev/data-center/mnt/',
             transformedDirectory)
-        assert os.path.lexists(expectedSymlink)
-
-    def storageDomainCreated(self, domainID):
-        self.sleepWhileVDSMCompletesTask(duration=1)
-        self._directIOTestFileExists()
-        domainRoot = os.path.join(self._directory, domainID)
-        expectedFiles = [
-            'images',
-            'dom_md',
-            'dom_md/leases',
-            'dom_md/inbox',
-            'dom_md/outbox',
-            'dom_md/metadata',
-            'dom_md/ids']
-        expectedFullPaths =\
-            [os.path.join(domainRoot, path) for path in expectedFiles]
-        for path in expectedFullPaths:
-            assert os.path.exists(path)
-
-    def _directIOTestFileExists(self):
-        self.sleepWhileVDSMCompletesTask(duration=1)
-        directIOTestFile = os.path.join(self._directory, '__DIRECT_IO_TEST__')
-        assert os.path.exists(directIOTestFile)
-
-    def volumeCreated(self, volumeInfo):
-        taskID, domainID, imageID, volumeID = volumeInfo
-        self.waitUntilVDSMTaskFinished(taskID, 20)
-        domain_directory = os.path.join(self._directory, domainID)
-        image_directory = os.path.join(domain_directory, 'images', imageID)
-        assert os.path.exists(image_directory)
-        volume_file = os.path.join(image_directory, volumeID)
-        volume_lease = '%s.lease' % volume_file
-        volume_meta = '%s.meta' % volume_file
-        for path in volume_file, volume_lease, volume_meta:
-            assert os.path.exists(path)
+        return result
 
 
-class LocalFS(base.StorageBackend):
+class LocalFS(filebased.FileBased):
     _NON_EXISTANT_POOL = '00000000-0000-0000-0000-000000000000'
-
-    def __init__(self):
-        base.StorageBackend.__init__(self)
-        self._domainID = self.newUUID()
-        self._poolID = self.newUUID()
-        self._imageID = self.newUUID()
-        self._volumeID = self.newUUID()
-        self._connectionID = self.newUUID()
 
     def __enter__(self):
         self._createDirectoryForLocalFSStorage()
@@ -87,13 +44,13 @@
             'user': '',
             'tpgt': '1',
             'password': '******',
-            'id': self._connectionID,
+            'id': self.connectionID(),
             'port': ''}
         result = self.vdsm().connectStorageServer(
             storage.sd.LOCALFS_DOMAIN,
             self._NON_EXISTANT_POOL,
             [localFilesystemConnection])
-        assert result['statuslist'][0]['id'] == self._connectionID
+        assert result['statuslist'][0]['id'] == self.connectionID()
 
     def disconnectStorageServer(self):
         localFilesystemConnection = {
@@ -102,46 +59,20 @@
             'user': '',
             'tpgt': '1',
             'password': '******',
-            'id': self._connectionID,
+            'id': self.connectionID(),
             'port': ''}
         self.vdsm().disconnectStorageServer(
             storage.sd.LOCALFS_DOMAIN,
             self._NON_EXISTANT_POOL,
             [localFilesystemConnection])
 
-    def createStoragePool(self):
-        POOL_TYPE_DEPRECATED = 0
-        self.vdsm().createStoragePool(
-            POOL_TYPE_DEPRECATED,
-            self._poolID,
-            self.randomName('pool'),
-            self._domainID,
-            [self._domainID],
-            1)
-        return self._poolID
-
     def createStorageDomain(self):
         DOMAIN_VERSION = 3
         self.vdsm().createStorageDomain(
             storage.sd.LOCALFS_DOMAIN,
-            self._domainID,
+            self.domainID(),
             'some_name',
             self._directory,
             storage.sd.DATA_DOMAIN,
             DOMAIN_VERSION)
-        return self._domainID
-
-    def createVolume(self, size):
-        PREALLOCATE = 1
-        result = self.vdsm().createVolume(
-            self._domainID,
-            self._poolID,
-            self._imageID,
-            self.largeIntegerXMLRPCWorkaround(size),
-            storage.volume.RAW_FORMAT,
-            PREALLOCATE,
-            storage.image.DATA_DISK_TYPE,
-            self._volumeID,
-            self.randomName('localfs_description'))
-        taskID = result['uuid']
-        return taskID, self._domainID, self._imageID, self._volumeID
+        return self.domainID()
diff --git a/tests/functional/testlib/storagecontexts/nfs.py b/tests/functional/testlib/storagecontexts/nfs.py
new file mode 100644
index 0000000..cdde3a1
--- /dev/null
+++ b/tests/functional/testlib/storagecontexts/nfs.py
@@ -0,0 +1,115 @@
+import subprocess
+import tempfile
+import pwd
+import shutil
+import os
+import storage.sd
+from . import filebased
+
+
+class Verify(filebased.Verify):
+    def __init__(self, directory, vdsm):
+        filebased.Verify.__init__(self, vdsm)
+        self._directory = directory
+
+    def rhevMountPoint(self):
+        transformedDirectory = self._directory.replace('/', '_')
+        result = os.path.join(
+            '/rhev/data-center/mnt/',
+            '127.0.0.1:%s' % transformedDirectory)
+        return result
+
+
+class NFS(filebased.FileBased):
+    _NON_EXISTANT_POOL = '00000000-0000-0000-0000-000000000000'
+
+    def __enter__(self):
+        self._setupNFSExport()
+        return self, Verify(self._directory, self.vdsm)
+
+    def _setupNFSExport(self):
+        self._export()
+        self._restartNFSServer()
+        mountPoint = tempfile.mkdtemp()
+        COMMAND = 'sudo --non-interactive mount -t nfs localhost:%s %s' %\
+            (self._directory, mountPoint)
+        subprocess.check_call(COMMAND, shell=True)
+        self._setPermissions(mountPoint)
+        subprocess.check_call(
+            'sudo --non-interactive umount %s' % mountPoint, shell=True)
+        os.rmdir(mountPoint)
+
+    def _export(self):
+        self._directory = tempfile.mkdtemp('', 'nfstest', '/var/tmp')
+        self._previousExports = open('/etc/exports').read()
+        with open('/etc/exports', 'a') as f:
+            line = '%s 127.0.0.1(rw,sync,no_root_squash,no_all_squash,fsid=0)\n'\
+                % self._directory
+            f.write(line)
+
+    def _unexport(self):
+        self._umount()
+        with open('/etc/exports', 'w') as f:
+            f.write(self._previousExports)
+        self._restartNFSServer()
+
+    def _umount(self):
+        COMMAND = 'sudo --non-interactive umount 127.0.0.1:%s'\
+            % self._directory
+        code = subprocess.call(COMMAND, shell=True)
+
+    def _setPermissions(self, directory):
+        vdsmUser = pwd.getpwnam('vdsm')
+        os.chown(directory, vdsmUser.pw_uid, vdsmUser.pw_gid)
+        os.chmod(directory, 0755)
+
+    def _restartNFSServer(self):
+        subprocess.check_call(
+            'sudo --non-interactive service nfs-server restart', shell=True)
+
+    def __exit__(self, *args):
+        self._unexport()
+        shutil.rmtree(self._directory)
+
+    def connectStorageServer(self):
+        connection = {
+            'connection': self._nfsPath(),
+            'iqn': '',
+            'user': '',
+            'tpgt': '1',
+            'password': '******',
+            'id': self.connectionID(),
+            'port': ''}
+        result = self.vdsm().connectStorageServer(
+            storage.sd.NFS_DOMAIN,
+            self._NON_EXISTANT_POOL,
+            [connection])
+        assert result['statuslist'][0]['id'] == self.connectionID()
+
+    def disconnectStorageServer(self):
+        connection = {
+            'connection': self._nfsPath(),
+            'iqn': '',
+            'user': '',
+            'tpgt': '1',
+            'password': '******',
+            'id': self.connectionID(),
+            'port': ''}
+        self.vdsm().disconnectStorageServer(
+            storage.sd.LOCALFS_DOMAIN,
+            self._NON_EXISTANT_POOL,
+            [connection])
+
+    def createStorageDomain(self):
+        DOMAIN_VERSION = 3
+        self.vdsm().createStorageDomain(
+            storage.sd.NFS_DOMAIN,
+            self.domainID(),
+            'some_name',
+            self._nfsPath(),
+            storage.sd.DATA_DOMAIN,
+            DOMAIN_VERSION)
+        return self.domainID()
+
+    def _nfsPath(self):
+        return '127.0.0.1:%s' % self._directory


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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I1781fc400c0604855d3143dde22ccb29e6cc8013
Gerrit-PatchSet: 1
Gerrit-Project: vdsm
Gerrit-Branch: master
Gerrit-Owner: Yoav Kleinberger <ykleinbe at redhat.com>


More information about the vdsm-patches mailing list