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):
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)
'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
from cinder.volume import driver
VERSION = 1.0
+GPFS_CLONE_MIN_RELEASE = 1200
+
LOG = logging.getLogger(__name__)
gpfs_opts = [
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)
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:
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."""
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