self.driver._cluster_id = '123456'
self.driver._gpfs_device = '/dev/gpfs'
self.driver._storage_pool = 'system'
+ self.driver._encryption_state = 'yes'
self.flags(volume_driver=self.driver_name,
gpfs_mount_point_base=self.volumes_path)
host = {'host': 'foo', 'capabilities': cap}
self.assertEqual('testpath', self.driver._can_migrate_locally(host))
+ @mock.patch('cinder.volume.drivers.ibm.gpfs.GPFSDriver.'
+ '_get_gpfs_encryption_status')
+ @mock.patch('cinder.volume.drivers.ibm.gpfs.GPFSDriver.'
+ '_get_gpfs_cluster_release_level')
@mock.patch('cinder.volume.drivers.ibm.gpfs.GPFSDriver._verify_gpfs_pool')
@mock.patch('cinder.volume.drivers.ibm.gpfs.GPFSDriver.'
'_get_filesystem_from_path')
mock_exec,
mock_get_gpfs_cluster_id,
mock_get_filesystem_from_path,
- mock_verify_gpfs_pool):
+ mock_verify_gpfs_pool,
+ mock_get_gpfs_fs_rel_lev,
+ mock_verify_encryption_state):
+ ctxt = self.context
+ mock_get_gpfs_cluster_id.return_value = self.driver._cluster_id
+ mock_get_filesystem_from_path.return_value = '/dev/gpfs'
+ mock_verify_gpfs_pool.return_value = True
+ mock_get_gpfs_fs_rel_lev.return_value = 1405
+ mock_verify_encryption_state.return_value = 'Yes'
+ self.driver.do_setup(ctxt)
+
+ @mock.patch('cinder.volume.drivers.ibm.gpfs.GPFSDriver.'
+ '_get_gpfs_cluster_release_level')
+ @mock.patch('cinder.volume.drivers.ibm.gpfs.GPFSDriver._verify_gpfs_pool')
+ @mock.patch('cinder.volume.drivers.ibm.gpfs.GPFSDriver.'
+ '_get_filesystem_from_path')
+ @mock.patch('cinder.volume.drivers.ibm.gpfs.GPFSDriver.'
+ '_get_gpfs_cluster_id')
+ @mock.patch('cinder.utils.execute')
+ def test_do_setup_no_encryption(self,
+ mock_exec,
+ mock_get_gpfs_cluster_id,
+ mock_get_filesystem_from_path,
+ mock_verify_gpfs_pool,
+ mock_get_gpfs_fs_rel_lev):
ctxt = self.context
mock_get_gpfs_cluster_id.return_value = self.driver._cluster_id
mock_get_filesystem_from_path.return_value = '/dev/gpfs'
mock_verify_gpfs_pool.return_value = True
+ mock_get_gpfs_fs_rel_lev.return_value = 1403
self.driver.do_setup(ctxt)
@mock.patch('cinder.volume.drivers.ibm.gpfs.GPFSDriver._verify_gpfs_pool')
stats = self.driver.get_volume_stats()
self.assertEqual('GPFS', stats['volume_backend_name'])
self.assertEqual('file', stats['storage_protocol'])
+ self.assertTrue(stats['gpfs_encryption_rest'])
stats = self.driver.get_volume_stats(True)
self.assertEqual('GPFS', stats['volume_backend_name'])
self.assertEqual('file', stats['storage_protocol'])
+ self.assertTrue(stats['gpfs_encryption_rest'])
+
+ @mock.patch('cinder.utils.execute')
+ def test_get_gpfs_encryption_status_true(self, mock_exec):
+ mock_exec.return_value = ('mmlsfs::HEADER:version:reserved:reserved:'
+ 'deviceName:fieldName:data:remarks:\n'
+ 'mmlsfs::0:1:::gpfs:encryption:Yes:', '')
+ self.assertEqual('Yes', self.driver._get_gpfs_encryption_status())
+
+ @mock.patch('cinder.utils.execute')
+ def test_get_gpfs_encryption_status_false(self, mock_exec):
+ mock_exec.return_value = ('mmlsfs::HEADER:version:reserved:reserved:'
+ 'deviceName:fieldName:data:remarks:\n'
+ 'mmlsfs::0:1:::gpfs:encryption:No:', '')
+ self.assertEqual('No', self.driver._get_gpfs_encryption_status())
+
+ @mock.patch('cinder.utils.execute')
+ def test_get_gpfs_encryption_status_fail(self, mock_exec):
+ mock_exec.side_effect = (
+ processutils.ProcessExecutionError(stdout='test', stderr='test'))
+ self.assertRaises(exception.VolumeBackendAPIException,
+ self.driver._get_gpfs_encryption_status)
@mock.patch('cinder.volume.drivers.ibm.gpfs.GPFSDriver.'
'_update_volume_stats')
from cinder.volume.drivers.san import san
GPFS_CLONE_MIN_RELEASE = 1200
+GPFS_ENC_MIN_RELEASE = 1404
MIGRATION_ALLOWED_DEST_TYPE = ['GPFSDriver', 'GPFSNFSDriver']
LOG = logging.getLogger(__name__)
1.1.0 - Add volume retype, refactor volume migration
1.2.0 - Add consistency group support
1.3.0 - Add NFS based GPFS storage backend support
+ 1.3.1 - Add GPFS native encryption (encryption of data at rest) support
"""
- VERSION = "1.3.0"
+ VERSION = "1.3.1"
def __init__(self, *args, **kwargs):
super(GPFSDriver, self).__init__(*args, **kwargs)
LOG.error(msg)
raise exception.VolumeBackendAPIException(data=msg)
+ _gpfs_cluster_release_level = self._get_gpfs_cluster_release_level()
+ if _gpfs_cluster_release_level >= GPFS_ENC_MIN_RELEASE:
+ self._encryption_state = self._get_gpfs_encryption_status()
+ else:
+ LOG.info(_LI('Downlevel GPFS Cluster Detected. GPFS '
+ 'encryption-at-rest feature not enabled in cluster '
+ 'daemon level %(cur)s - must be at least at '
+ 'level %(min)s.'),
+ {'cur': _gpfs_cluster_release_level,
+ 'min': GPFS_ENC_MIN_RELEASE})
+
def check_for_setup_error(self):
"""Returns an error if prerequisites aren't met."""
self._check_gpfs_state()
)
return volume_path
+ def _get_gpfs_encryption_status(self):
+ """Determine if the backend is configured with key manager."""
+ try:
+ (out, err) = self.gpfs_execute('mmlsfs', self._gpfs_device,
+ '--encryption', '-Y')
+ lines = out.splitlines()
+ value_token = lines[0].split(':').index('data')
+ encryption_status = lines[1].split(':')[value_token]
+ return encryption_status
+ except processutils.ProcessExecutionError as exc:
+ LOG.error(_LE('Failed to issue mmlsfs command, error: %s.'),
+ exc.stderr)
+ raise exception.VolumeBackendAPIException(data=exc.stderr)
+
def ensure_export(self, context, volume):
"""Synchronously recreates an export for a logical volume."""
pass
'root_path': gpfs_base})
data['consistencygroup_support'] = 'True'
+
+ if self._encryption_state.lower() == 'yes':
+ data['gpfs_encryption_rest'] = 'True'
+
self._stats = data
def clone_image(self, context, volume,