]> review.fuel-infra Code Review - openstack-build/cinder-build.git/commitdiff
GPFS Verify min release level for mmclone command
authorBill Owen <billowen@us.ibm.com>
Mon, 5 Aug 2013 18:32:27 +0000 (11:32 -0700)
committerBill Owen <billowen@us.ibm.com>
Mon, 5 Aug 2013 18:32:27 +0000 (11:32 -0700)
The gpfs driver makes heavy use of mmclone command.  This command
was added fairly recently.  Verify that the GPFS cluster is operating
at a level that supports mmclone at startup during prerequisite
checking in check_for_setup_error.

Need to verify:
1.  That gpfs cluster is at required level
2.  That filesystem(s) are also operating at required level.

Change-Id: Ie71d0b814d77b544e1a456d110882c1a02a5b2e5
Fixes: bug #1204266
cinder/tests/test_gpfs.py
cinder/volume/drivers/gpfs.py
etc/cinder/rootwrap.d/volume.filters

index f8ab970f64f1255463d603c2d8877ae84e67eb54..171649e8b254ca8fc184077ed37068693fe6119a 100644 (file)
@@ -342,6 +342,10 @@ class GPFSDriverTestCase(test.TestCase):
                        self._fake_gpfs_get_state_active)
         self.stubs.Set(GPFSDriver, '_is_gpfs_path',
                        self._fake_is_gpfs_path)
+        self.stubs.Set(GPFSDriver, '_get_gpfs_cluster_release_level',
+                       self._fake_gpfs_compatible_cluster_release_level)
+        self.stubs.Set(GPFSDriver, '_get_gpfs_filesystem_release_level',
+                       self._fake_gpfs_compatible_filesystem_release_level)
         self.driver.check_for_setup_error()
 
     def test_check_for_setup_error_gpfs_not_active(self):
@@ -357,6 +361,32 @@ class GPFSDriverTestCase(test.TestCase):
                        self._fake_gpfs_get_state_active)
         self.stubs.Set(GPFSDriver, '_is_gpfs_path',
                        self._fake_is_not_gpfs_path)
+        self.stubs.Set(GPFSDriver, '_get_gpfs_cluster_release_level',
+                       self._fake_gpfs_compatible_cluster_release_level)
+        self.stubs.Set(GPFSDriver, '_get_gpfs_filesystem_release_level',
+                       self._fake_gpfs_compatible_filesystem_release_level)
+        self.assertRaises(exception.VolumeBackendAPIException,
+                          self.driver.check_for_setup_error)
+
+    def test_check_for_setup_error_incompatible_cluster_version(self):
+        self.stubs.Set(GPFSDriver, '_get_gpfs_state',
+                       self._fake_gpfs_get_state_active)
+        self.stubs.Set(GPFSDriver, '_is_gpfs_path',
+                       self._fake_is_gpfs_path)
+        self.stubs.Set(GPFSDriver, '_get_gpfs_cluster_release_level',
+                       self._fake_gpfs_incompatible_cluster_release_level)
+        self.assertRaises(exception.VolumeBackendAPIException,
+                          self.driver.check_for_setup_error)
+
+    def test_check_for_setup_error_incompatible_filesystem_version(self):
+        self.stubs.Set(GPFSDriver, '_get_gpfs_state',
+                       self._fake_gpfs_get_state_active)
+        self.stubs.Set(GPFSDriver, '_is_gpfs_path',
+                       self._fake_is_gpfs_path)
+        self.stubs.Set(GPFSDriver, '_get_gpfs_cluster_release_level',
+                       self._fake_gpfs_compatible_cluster_release_level)
+        self.stubs.Set(GPFSDriver, '_get_gpfs_filesystem_release_level',
+                       self._fake_gpfs_incompatible_filesystem_release_level)
         self.assertRaises(exception.VolumeBackendAPIException,
                           self.driver.check_for_setup_error)
 
@@ -405,6 +435,24 @@ class GPFSDriverTestCase(test.TestCase):
                         '1:quorum node:(undefined):')
         return inactive_txt
 
+    def _fake_gpfs_compatible_cluster_release_level(self):
+        release = 1400
+        return release
+
+    def _fake_gpfs_incompatible_cluster_release_level(self):
+        release = 1105
+        return release
+
+    def _fake_gpfs_compatible_filesystem_release_level(self, path=None):
+        release = 1400
+        fs = '/dev/gpfs'
+        return fs, release
+
+    def _fake_gpfs_incompatible_filesystem_release_level(self, path=None):
+        release = 1105
+        fs = '/dev/gpfs'
+        return fs, release
+
     def _fake_is_gpfs_path(self, path):
         pass
 
index ecaf572f8c9b9bd494753bc8ed1f636bb15a3cb7..fe4577ce487606044293adcb85b62209831057a0 100644 (file)
@@ -32,6 +32,8 @@ from cinder import units
 from cinder.volume import driver
 
 VERSION = 1.0
+GPFS_CLONE_MIN_RELEASE = 1200
+
 LOG = logging.getLogger(__name__)
 
 gpfs_opts = [
@@ -91,6 +93,32 @@ class GPFSDriver(driver.VolumeDriver):
                                  gpfs_state)
             raise exception.VolumeBackendAPIException(data=exception_message)
 
+    def _get_filesystem_from_path(self, path):
+        (out, _) = self._execute('df', path, run_as_root=True)
+        lines = out.splitlines()
+        fs = lines[1].split()[0]
+        return fs
+
+    def _get_gpfs_filesystem_release_level(self, path):
+        fs = self._get_filesystem_from_path(path)
+        (out, _) = self._execute('mmlsfs', fs, '-V', '-Y',
+                                 run_as_root=True)
+        lines = out.splitlines()
+        value_token = lines[0].split(':').index('data')
+        fs_release_level_str = lines[1].split(':')[value_token]
+        # at this point, release string looks like "13.23 (3.5.0.7)"
+        # extract first token and convert to whole number value
+        fs_release_level = int(float(fs_release_level_str.split()[0]) * 100)
+        return fs, fs_release_level
+
+    def _get_gpfs_cluster_release_level(self):
+        (out, _) = self._execute('mmlsconfig', 'minreleaseLeveldaemon', '-Y',
+                                 run_as_root=True)
+        lines = out.splitlines()
+        value_token = lines[0].split(':').index('value')
+        min_release_level = lines[1].split(':')[value_token]
+        return int(min_release_level)
+
     def _is_gpfs_path(self, directory):
         self._execute('mmlsattr', directory, run_as_root=True)
 
@@ -131,6 +159,16 @@ class GPFSDriver(driver.VolumeDriver):
             LOG.warn(msg)
             raise exception.VolumeBackendAPIException(data=msg)
 
+        _gpfs_cluster_release_level = self._get_gpfs_cluster_release_level()
+        if not _gpfs_cluster_release_level >= GPFS_CLONE_MIN_RELEASE:
+            msg = (_('Downlevel GPFS Cluster Detected.  GPFS Clone feature '
+                     'not enabled in cluster daemon level %(cur)s - must '
+                     'be at least at level %(min)s.') %
+                   {'cur': _gpfs_cluster_release_level,
+                    'min': GPFS_CLONE_MIN_RELEASE})
+            LOG.error(msg)
+            raise exception.VolumeBackendAPIException(data=msg)
+
         for directory in [self.configuration.gpfs_mount_point_base,
                           self.configuration.gpfs_images_dir]:
             if directory is None:
@@ -155,6 +193,17 @@ class GPFSDriver(driver.VolumeDriver):
                 LOG.error(msg)
                 raise exception.VolumeBackendAPIException(data=msg)
 
+            fs, fslevel = self._get_gpfs_filesystem_release_level(directory)
+            if not fslevel >= GPFS_CLONE_MIN_RELEASE:
+                msg = (_('The GPFS filesystem %(fs)s is not at the required '
+                         'release level.  Current level is %(cur)s, must be '
+                         'at least %(min)s.') %
+                       {'fs': fs,
+                        'cur': fslevel,
+                        'min': GPFS_CLONE_MIN_RELEASE})
+                LOG.error(msg)
+                raise exception.VolumeBackendAPIException(data=msg)
+
     def _create_sparse_file(self, path, size):
         """Creates file with 0 disk usage."""
 
index 53c7a8bfac21997d13998d62a2faf6b63967b48e..b095475b9b12cb217e6dea95b148ca53c3fc2514 100644 (file)
@@ -73,5 +73,7 @@ blockdev: CommandFilter, blockdev, root
 mmgetstate: CommandFilter, /usr/lpp/mmfs/bin/mmgetstate, root
 mmclone: CommandFilter, /usr/lpp/mmfs/bin/mmclone, root
 mmlsattr: CommandFilter, /usr/lpp/mmfs/bin/mmlsattr, root
+mmlsconfig: CommandFilter, /usr/lpp/mmfs/bin/mmlsconfig, root
+mmlsfs: CommandFilter, /usr/lpp/mmfs/bin/mmlsfs, root
 find: CommandFilter, find, root
 mkfs: CommandFilter, mkfs, root