Add support for manage/unmanage in GPFS driver

Added support for manage/unmanage in GPFS NFS driver.
This patch added functions that allow share on Spectrum Scale
node to be managed by OpenStack if existing fileset is an
independent fileset and doesn't have any NFS export
over the fileset path. Also, share can be unmanaged from
OpenStack but still left in Spectrum Scale cluster.

Implements: blueprint gpfs-manage-support

Change-Id: I9134408b59c30ac4bc593f287294741f6e996136
This commit is contained in:
digvijay2016 2016-09-22 16:36:02 +05:30
parent f427dfe00b
commit fb4b0b86e9
5 changed files with 564 additions and 17 deletions

View File

@ -61,7 +61,7 @@ Mapping of share drivers and share features support
+----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
| Huawei | K | L | L | L | K | M | \- |
+----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
| IBM GPFS | K | \- | L | \- | K | K | \- |
| IBM GPFS | K | O | L | \- | K | K | \- |
+----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
| LVM | M | \- | M | \- | M | M | \- |
+----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+

View File

@ -119,6 +119,12 @@ df: CommandFilter, df, root
chmod: CommandFilter, chmod, root
# manila/share/drivers/ibm/gpfs.py: 'mmnfs', 'export', '%s', '%s'
mmnfs: CommandFilter, mmnfs, root
# manila/share/drivers/ibm/gpfs.py: 'mmlsfileset', '%s', '-J', '%s', '-L'
mmlsfileset: CommandFilter, mmlsfileset, root
# manila/share/drivers/ibm/gpfs.py: 'mmchfileset', '%s', '-J', '%s', '-j', '%s'
mmchfileset: CommandFilter, mmchfileset, root
# manila/share/drivers/ibm/gpfs.py: 'mmlsquota', '-j', '-J', '%s', '%s'
mmlsquota: CommandFilter, mmlsquota, root
# manila/share/drivers/ganesha/manager.py: 'mv', '%s', '%s'
mv: CommandFilter, mv, root

View File

@ -44,7 +44,7 @@ import six
from manila.common import constants
from manila import exception
from manila.i18n import _
from manila.i18n import _, _LI
from manila.share import driver
from manila.share.drivers.helpers import NFSHelper
from manila.share import share_types
@ -564,6 +564,178 @@ class GPFSShareDriver(driver.ExecuteMixin, driver.GaneshaMixin,
LOG.error(msg)
raise exception.InvalidParameterValue(err=msg)
def _is_share_valid(self, fsdev, location):
try:
out, __ = self._gpfs_execute('mmlsfileset', fsdev, '-J',
location, '-L', '-Y')
except exception.ProcessExecutionError:
msg = (_('Given share path %(share_path)s does not exist at '
'mount point %(mount_point)s.')
% {'share_path': location, 'mount_point': fsdev})
LOG.exception(msg)
raise exception.ManageInvalidShare(reason=msg)
lines = out.splitlines()
try:
validation_token = lines[0].split(':').index('allocInodes')
alloc_inodes = lines[1].split(':')[validation_token]
except (IndexError, ValueError):
msg = (_('Failed to check share at %s.') % location)
LOG.exception(msg)
raise exception.GPFSException(msg)
return alloc_inodes != '0'
def _get_share_name(self, fsdev, location):
try:
out, __ = self._gpfs_execute('mmlsfileset', fsdev, '-J',
location, '-L', '-Y')
except exception.ProcessExecutionError:
msg = (_('Given share path %(share_path)s does not exist at '
'mount point %(mount_point)s.')
% {'share_path': location, 'mount_point': fsdev})
LOG.exception(msg)
raise exception.ManageInvalidShare(reason=msg)
lines = out.splitlines()
try:
validation_token = lines[0].split(':').index('filesetName')
share_name = lines[1].split(':')[validation_token]
except (IndexError, ValueError):
msg = (_('Failed to check share at %s.') % location)
LOG.exception(msg)
raise exception.GPFSException(msg)
return share_name
def _manage_existing(self, fsdev, share, old_share_name):
new_share_name = share['name']
new_export_location = self._local_path(new_share_name)
try:
self._gpfs_execute('mmunlinkfileset', fsdev, old_share_name, '-f')
except exception.ProcessExecutionError:
msg = _('Failed to unlink fileset for share %s.') % new_share_name
LOG.exception(msg)
raise exception.GPFSException(msg)
LOG.debug('Unlinked the fileset of share %s.', old_share_name)
try:
self._gpfs_execute('mmchfileset', fsdev, old_share_name,
'-j', new_share_name)
except exception.ProcessExecutionError:
msg = _('Failed to rename fileset for share %s.') % new_share_name
LOG.exception(msg)
raise exception.GPFSException(msg)
LOG.debug('Renamed the fileset from %(old_share)s to %(new_share)s.',
{'old_share': old_share_name, 'new_share': new_share_name})
try:
self._gpfs_execute('mmlinkfileset', fsdev, new_share_name, '-J',
new_export_location)
except exception.ProcessExecutionError:
msg = _('Failed to link fileset for the share %s.'
) % new_share_name
LOG.exception(msg)
raise exception.GPFSException(msg)
LOG.debug('Linked the fileset of share %(share_name)s at location '
'%(export_location)s.',
{'share_name': new_share_name,
'export_location': new_export_location})
try:
self._gpfs_execute('chmod', '777', new_export_location)
except exception.ProcessExecutionError:
msg = _('Failed to set permissions for share %s.') % new_share_name
LOG.exception(msg)
raise exception.GPFSException(msg)
LOG.debug('Changed the permission of share %s.', new_share_name)
try:
out, __ = self._gpfs_execute('mmlsquota', '-j', new_share_name,
'-Y', fsdev)
except exception.ProcessExecutionError:
msg = _('Failed to check size for share %s.') % new_share_name
LOG.exception(msg)
raise exception.GPFSException(msg)
lines = out.splitlines()
try:
quota_limit = lines[0].split(':').index('blockLimit')
quota_status = lines[1].split(':')[quota_limit]
except (IndexError, ValueError):
msg = _('Failed to check quota for share %s.') % new_share_name
LOG.exception(msg)
raise exception.GPFSException(msg)
share_size = int(quota_status)
# Note: since share_size returns integer value in KB,
# we are checking whether share is less than 1GiB.
# (units.Mi * KB = 1GB)
if share_size < units.Mi:
try:
self._gpfs_execute('mmsetquota', fsdev + ':' + new_share_name,
'--block', '0:1G')
except exception.ProcessExecutionError:
msg = _('Failed to set quota for share %s.') % new_share_name
LOG.exception(msg)
raise exception.GPFSException(msg)
LOG.info(_LI('Existing share %(shr)s has size %(size)s KB '
'which is below 1GiB, so extended it to 1GiB.') %
{'shr': new_share_name, 'size': share_size})
share_size = 1
else:
orig_share_size = share_size
share_size = int(math.ceil(float(share_size) / units.Mi))
if orig_share_size != share_size * units.Mi:
try:
self._gpfs_execute('mmsetquota', fsdev + ':' +
new_share_name, '--block', '0:' +
str(share_size) + 'G')
except exception.ProcessExecutionError:
msg = _('Failed to set quota for share %s.'
) % new_share_name
LOG.exception(msg)
raise exception.GPFSException(msg)
new_export_location = self._get_helper(share).create_export(
new_export_location)
return share_size, new_export_location
def manage_existing(self, share, driver_options):
old_export = share['export_location'].split(':')
try:
ces_ip = old_export[0]
old_export_location = old_export[1]
except IndexError:
msg = _('Incorrect export path. Expected format: '
'IP:/gpfs_mount_point_base/share_id.')
LOG.exception(msg)
raise exception.ShareBackendException(msg=msg)
if ces_ip not in self.configuration.gpfs_nfs_server_list:
msg = _('The CES IP %s is not present in the '
'configuration option "gpfs_nfs_server_list".') % ces_ip
raise exception.ShareBackendException(msg=msg)
fsdev = self._get_gpfs_device()
if not self._is_share_valid(fsdev, old_export_location):
err_msg = _('Given share path %s does not have a valid '
'share.') % old_export_location
raise exception.ManageInvalidShare(reason=err_msg)
share_name = self._get_share_name(fsdev, old_export_location)
out = self._get_helper(share)._has_client_access(old_export_location)
if out:
err_msg = _('Clients have access to %s share currently. Evict any '
'clients before trying again.') % share_name
raise exception.ManageInvalidShare(reason=err_msg)
share_size, new_export_location = self._manage_existing(
fsdev, share, share_name)
return {"size": share_size, "export_locations": new_export_location}
def _update_share_stats(self):
"""Retrieve stats info from share volume group."""
@ -679,6 +851,23 @@ class KNFSHelper(NASHelperBase):
LOG.error(msg)
raise exception.GPFSException(msg)
def _has_client_access(self, local_path, access_to=None):
try:
out, __ = self._execute('exportfs', run_as_root=True)
except exception.ProcessExecutionError:
msg = _('Failed to check exports on the systems.')
LOG.exception(msg)
raise exception.GPFSException(msg)
if access_to:
if (re.search(re.escape(local_path) + '[\s\n]*'
+ re.escape(access_to), out)):
return True
else:
if re.findall(local_path + '\\b', ''.join(out)):
return True
return False
def _publish_access(self, *cmd, **kwargs):
check_exit_code = kwargs.get('check_exit_code', True)
@ -739,19 +928,9 @@ class KNFSHelper(NASHelperBase):
raise exception.InvalidShareAccess(reason='Only ip access type '
'supported.')
# check if present in export
try:
out, __ = self._execute('exportfs', run_as_root=True)
except exception.ProcessExecutionError as e:
msg = (_('Failed to check exports on the systems. '
' Error: %s.') % e)
LOG.error(msg)
raise exception.GPFSException(msg)
out = self._has_client_access(local_path, access['access_to'])
out = re.search(re.escape(local_path) + '[\s\n]*'
+ re.escape(access['access_to']), out)
if out is not None:
if out:
access_type = access['access_type']
access_to = access['access_to']
raise exception.ShareAccessExists(access_type=access_type,

View File

@ -45,6 +45,7 @@ class GPFSShareDriverTestCase(test.TestCase):
self._helper_fake = mock.Mock()
CONF.set_default('driver_handles_share_servers', False)
CONF.set_default('share_backend_name', 'GPFS')
self.fake_conf = config.Configuration(None)
self._driver = gpfs.GPFSShareDriver(execute=self._gpfs_execute,
configuration=self.fake_conf)
@ -55,6 +56,7 @@ class GPFSShareDriverTestCase(test.TestCase):
self.fakedev = "/dev/gpfs0"
self.fakefspath = "/gpfs0"
self.fakesharepath = "/gpfs0/share-fakeid"
self.fakeexistingshare = "existingshare"
self.fakesnapshotpath = "/gpfs0/.snapshots/snapshot-fakesnapshotid"
self.fake_ces_exports = """
@ -74,7 +76,8 @@ mmcesnfslsexport:nfsexports:HEADER:version:reserved:reserved:Path:Delegations:Cl
self._driver._helpers = {
'KNFS': self._helper_fake
}
self.share = fake_share.fake_share(share_proto='NFS')
self.share = fake_share.fake_share(share_proto='NFS',
host='fakehost@fakehost#GPFS')
self.server = {
'backend_details': {
'ip': '1.2.3.4',
@ -86,7 +89,8 @@ mmcesnfslsexport:nfsexports:HEADER:version:reserved:reserved:Path:Delegations:Cl
self.local_ip = "192.11.22.1"
self.remote_ip = "192.11.22.2"
self.remote_ip2 = "2.2.2.2"
gpfs_nfs_server_list = [self.remote_ip, self.local_ip, self.remote_ip2]
gpfs_nfs_server_list = [self.remote_ip, self.local_ip, self.remote_ip2,
"fake_location"]
self._knfs_helper.configuration.gpfs_nfs_server_list = \
gpfs_nfs_server_list
self._ces_helper.configuration.gpfs_nfs_server_list = \
@ -671,6 +675,333 @@ mmcesnfslsexport:nfsexports:HEADER:version:reserved:reserved:Path:Delegations:Cl
'rsync', '-rp', self.fakesnapshotpath + '/', self.fakesharepath
)
@ddt.data("mmlsfileset::allocInodes:\nmmlsfileset::100096:",
"mmlsfileset::allocInodes:\nmmlsfileset::0:")
def test__is_share_valid_with_quota(self, fakeout):
self._driver._gpfs_execute = mock.Mock(return_value=(fakeout, ''))
result = self._driver._is_share_valid(self.fakedev, self.fakesharepath)
self._driver._gpfs_execute.assert_called_once_with(
'mmlsfileset', self.fakedev, '-J', self.fakesharepath, '-L', '-Y')
if fakeout == "mmlsfileset::allocInodes:\nmmlsfileset::100096:":
self.assertTrue(result)
else:
self.assertFalse(result)
def test__is_share_valid_exception(self):
self._driver._gpfs_execute = mock.Mock(
side_effect=exception.ProcessExecutionError)
self.assertRaises(exception.ManageInvalidShare,
self._driver._is_share_valid, self.fakedev,
self.fakesharepath)
self._driver._gpfs_execute.assert_called_once_with(
'mmlsfileset', self.fakedev, '-J', self.fakesharepath, '-L', '-Y')
def test__is_share_valid_no_share_exist_exception(self):
fakeout = "mmlsfileset::allocInodes:"
self._driver._gpfs_execute = mock.Mock(return_value=(fakeout, ''))
self.assertRaises(exception.GPFSException,
self._driver._is_share_valid, self.fakedev,
self.fakesharepath)
self._driver._gpfs_execute.assert_called_once_with(
'mmlsfileset', self.fakedev, '-J', self.fakesharepath, '-L', '-Y')
def test__get_share_name(self):
fakeout = "mmlsfileset::filesetName:\nmmlsfileset::existingshare:"
self._driver._gpfs_execute = mock.Mock(return_value=(fakeout, ''))
result = self._driver._get_share_name(self.fakedev, self.fakesharepath)
self.assertEqual('existingshare', result)
def test__get_share_name_exception(self):
self._driver._gpfs_execute = mock.Mock(
side_effect=exception.ProcessExecutionError)
self.assertRaises(exception.ManageInvalidShare,
self._driver._get_share_name, self.fakedev,
self.fakesharepath)
self._driver._gpfs_execute.assert_called_once_with(
'mmlsfileset', self.fakedev, '-J', self.fakesharepath, '-L', '-Y')
def test__get_share_name_no_share_exist_exception(self):
fakeout = "mmlsfileset::filesetName:"
self._driver._gpfs_execute = mock.Mock(return_value=(fakeout, ''))
self.assertRaises(exception.GPFSException,
self._driver._get_share_name, self.fakedev,
self.fakesharepath)
self._driver._gpfs_execute.assert_called_once_with(
'mmlsfileset', self.fakedev, '-J', self.fakesharepath, '-L', '-Y')
@ddt.data("mmlsquota::blockLimit:\nmmlsquota::1048577",
"mmlsquota::blockLimit:\nmmlsquota::1048576",
"mmlsquota::blockLimit:\nmmlsquota::0")
def test__manage_existing(self, fakeout):
self._driver._gpfs_execute = mock.Mock(return_value=(fakeout, ''))
self._helper_fake.create_export.return_value = 'fakelocation'
self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
actual_size, actual_path = self._driver._manage_existing(
self.fakedev, self.share, self.fakeexistingshare)
self._driver._gpfs_execute.assert_any_call('mmunlinkfileset',
self.fakedev,
self.fakeexistingshare,
'-f')
self._driver._gpfs_execute.assert_any_call('mmchfileset',
self.fakedev,
self.fakeexistingshare,
'-j', self.share['name'])
self._driver._gpfs_execute.assert_any_call('mmlinkfileset',
self.fakedev,
self.share['name'],
'-J', self.fakesharepath)
self._driver._gpfs_execute.assert_any_call('chmod',
'777',
self.fakesharepath)
if fakeout == "mmlsquota::blockLimit:\nmmlsquota::1048577":
self._driver._gpfs_execute.assert_called_with('mmsetquota',
self.fakedev + ':' +
self.share['name'],
'--block',
'0:2G')
self.assertEqual(2, actual_size)
self.assertEqual('fakelocation', actual_path)
elif fakeout == "mmlsquota::blockLimit:\nmmlsquota::0":
self._driver._gpfs_execute.assert_called_with('mmsetquota',
self.fakedev + ':' +
self.share['name'],
'--block',
'0:1G')
self.assertEqual(1, actual_size)
self.assertEqual('fakelocation', actual_path)
else:
self.assertEqual(1, actual_size)
self.assertEqual('fakelocation', actual_path)
def test__manage_existing_fileset_unlink_exception(self):
self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
self._driver._gpfs_execute = mock.Mock(
side_effect=exception.ProcessExecutionError)
self.assertRaises(exception.GPFSException,
self._driver._manage_existing, self.fakedev,
self.share, self.fakeexistingshare)
self._driver._local_path.assert_called_once_with(self.share['name'])
self._driver._gpfs_execute.assert_called_once_with(
'mmunlinkfileset', self.fakedev, self.fakeexistingshare, '-f')
def test__manage_existing_fileset_creation_exception(self):
self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
self.mock_object(self._driver, '_gpfs_execute', mock.Mock(
side_effect=['', exception.ProcessExecutionError]))
self.assertRaises(exception.GPFSException,
self._driver._manage_existing, self.fakedev,
self.share, self.fakeexistingshare)
self._driver._local_path.assert_any_call(self.share['name'])
self._driver._gpfs_execute.assert_has_calls([
mock.call('mmunlinkfileset', self.fakedev, self.fakeexistingshare,
'-f'),
mock.call('mmchfileset', self.fakedev, self.fakeexistingshare,
'-j', self.share['name'])])
def test__manage_existing_fileset_relink_exception(self):
self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
self.mock_object(self._driver, '_gpfs_execute', mock.Mock(
side_effect=['', '', exception.ProcessExecutionError]))
self.assertRaises(exception.GPFSException,
self._driver._manage_existing, self.fakedev,
self.share, self.fakeexistingshare)
self._driver._local_path.assert_any_call(self.share['name'])
self._driver._gpfs_execute.assert_has_calls([
mock.call('mmunlinkfileset', self.fakedev, self.fakeexistingshare,
'-f'),
mock.call('mmchfileset', self.fakedev, self.fakeexistingshare,
'-j', self.share['name']),
mock.call('mmlinkfileset', self.fakedev, self.share['name'], '-J',
self.fakesharepath)])
def test__manage_existing_permission_change_exception(self):
self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
self.mock_object(self._driver, '_gpfs_execute', mock.Mock(
side_effect=['', '', '', exception.ProcessExecutionError]))
self.assertRaises(exception.GPFSException,
self._driver._manage_existing, self.fakedev,
self.share, self.fakeexistingshare)
self._driver._local_path.assert_any_call(self.share['name'])
self._driver._gpfs_execute.assert_has_calls([
mock.call('mmunlinkfileset', self.fakedev, self.fakeexistingshare,
'-f'),
mock.call('mmchfileset', self.fakedev, self.fakeexistingshare,
'-j', self.share['name']),
mock.call('mmlinkfileset', self.fakedev, self.share['name'], '-J',
self.fakesharepath),
mock.call('chmod', '777', self.fakesharepath)])
def test__manage_existing_checking_quota_of_fileset_exception(self):
self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
self.mock_object(self._driver, '_gpfs_execute', mock.Mock(
side_effect=['', '', '', '', exception.ProcessExecutionError]))
self.assertRaises(exception.GPFSException,
self._driver._manage_existing, self.fakedev,
self.share, self.fakeexistingshare)
self._driver._local_path.assert_any_call(self.share['name'])
self._driver._gpfs_execute.assert_has_calls([
mock.call('mmunlinkfileset', self.fakedev, self.fakeexistingshare,
'-f'),
mock.call('mmchfileset', self.fakedev, self.fakeexistingshare,
'-j', self.share['name']),
mock.call('mmlinkfileset', self.fakedev, self.share['name'], '-J',
self.fakesharepath),
mock.call('chmod', '777', self.fakesharepath),
mock.call('mmlsquota', '-j', self.share['name'], '-Y',
self.fakedev)])
def test__manage_existing_unable_to_get_quota_of_fileset_exception(self):
fakeout = "mmlsquota::blockLimit:"
self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
self._driver._gpfs_execute = mock.Mock(return_value=(fakeout, ''))
self.assertRaises(exception.GPFSException,
self._driver._manage_existing, self.fakedev,
self.share, self.fakeexistingshare)
self._driver._local_path.assert_any_call(self.share['name'])
self._driver._gpfs_execute.assert_any_call('mmunlinkfileset',
self.fakedev,
self.fakeexistingshare,
'-f')
self._driver._gpfs_execute.assert_any_call('mmchfileset',
self.fakedev,
self.fakeexistingshare,
'-j', self.share['name'])
self._driver._gpfs_execute.assert_any_call('mmlinkfileset',
self.fakedev,
self.share['name'],
'-J', self.fakesharepath)
self._driver._gpfs_execute.assert_any_call('chmod',
'777',
self.fakesharepath)
self._driver._gpfs_execute.assert_called_with(
'mmlsquota', '-j', self.share['name'], '-Y', self.fakedev)
def test__manage_existing_set_quota_of_fileset_less_than_1G_exception(
self):
sizestr = '1G'
mock_out = "mmlsquota::blockLimit:\nmmlsquota::0:", None
self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
self.mock_object(self._driver, '_gpfs_execute', mock.Mock(
side_effect=['', '', '', '', mock_out,
exception.ProcessExecutionError]))
self.assertRaises(exception.GPFSException,
self._driver._manage_existing, self.fakedev,
self.share, self.fakeexistingshare)
self._driver._local_path.assert_any_call(self.share['name'])
self._driver._gpfs_execute.assert_has_calls([
mock.call('mmunlinkfileset', self.fakedev, self.fakeexistingshare,
'-f'),
mock.call('mmchfileset', self.fakedev, self.fakeexistingshare,
'-j', self.share['name']),
mock.call('mmlinkfileset', self.fakedev, self.share['name'], '-J',
self.fakesharepath),
mock.call('chmod', '777', self.fakesharepath),
mock.call('mmlsquota', '-j', self.share['name'], '-Y',
self.fakedev),
mock.call('mmsetquota', self.fakedev + ':' + self.share['name'],
'--block', '0:' + sizestr)])
def test__manage_existing_set_quota_of_fileset_grater_than_1G_exception(
self):
sizestr = '2G'
mock_out = "mmlsquota::blockLimit:\nmmlsquota::1048577:", None
self._driver._local_path = mock.Mock(return_value=self.fakesharepath)
self.mock_object(self._driver, '_gpfs_execute', mock.Mock(
side_effect=['', '', '', '', mock_out,
exception.ProcessExecutionError]))
self.assertRaises(exception.GPFSException,
self._driver._manage_existing, self.fakedev,
self.share, self.fakeexistingshare)
self._driver._local_path.assert_any_call(self.share['name'])
self._driver._gpfs_execute.assert_has_calls([
mock.call('mmunlinkfileset', self.fakedev, self.fakeexistingshare,
'-f'),
mock.call('mmchfileset', self.fakedev, self.fakeexistingshare,
'-j', self.share['name']),
mock.call('mmlinkfileset', self.fakedev, self.share['name'], '-J',
self.fakesharepath),
mock.call('chmod', '777', self.fakesharepath),
mock.call('mmlsquota', '-j', self.share['name'], '-Y',
self.fakedev),
mock.call('mmsetquota', self.fakedev + ':' + self.share['name'],
'--block', '0:' + sizestr)])
def test_manage_existing(self):
self._driver._manage_existing = mock.Mock(return_value=('1',
'fakelocation'))
self._driver._get_gpfs_device = mock.Mock(return_value=self.fakedev)
self._driver._is_share_valid = mock.Mock(return_value=True)
self._driver._get_share_name = mock.Mock(return_value=self.
fakeexistingshare)
self._helper_fake._has_client_access = mock.Mock(return_value=[])
result = self._driver.manage_existing(self.share, {})
self.assertEqual('1', result['size'])
self.assertEqual('fakelocation', result['export_locations'])
def test_manage_existing_incorrect_path_exception(self):
share = fake_share.fake_share(export_location="wrong_ip::wrong_path")
self.assertRaises(exception.ShareBackendException,
self._driver.manage_existing, share, {})
def test_manage_existing_incorrect_ip_exception(self):
share = fake_share.fake_share(export_location="wrong_ip:wrong_path")
self.assertRaises(exception.ShareBackendException,
self._driver.manage_existing, share, {})
def test__manage_existing_invalid_export_exception(self):
share = fake_share.fake_share(export_location="wrong_ip/wrong_path")
self.assertRaises(exception.ShareBackendException,
self._driver.manage_existing, share, {})
@ddt.data(True, False)
def test_manage_existing_invalid_share_exception(self, valid_share):
self._driver._get_gpfs_device = mock.Mock(return_value=self.fakedev)
self._driver._is_share_valid = mock.Mock(return_value=valid_share)
if valid_share:
self._driver._get_share_name = mock.Mock(return_value=self.
fakeexistingshare)
self._helper_fake._has_client_access = mock.Mock()
else:
self.assertFalse(self._helper_fake._has_client_access.called)
self.assertRaises(exception.ManageInvalidShare,
self._driver.manage_existing, self.share, {})
def test__gpfs_local_execute(self):
self.mock_object(utils, 'execute', mock.Mock(return_value=True))
cmd = "testcmd"
@ -730,6 +1061,28 @@ mmcesnfslsexport:nfsexports:HEADER:version:reserved:reserved:Path:Delegations:Cl
self._knfs_helper.get_export_options,
share, access, 'KNFS', options_not_allowed)
@ddt.data(("/gpfs0/share-fakeid\t10.0.0.1", None),
("", None),
("/gpfs0/share-fakeid\t10.0.0.1", "10.0.0.1"),
("/gpfs0/share-fakeid\t10.0.0.1", "10.0.0.2"))
@ddt.unpack
def test_knfs__has_client_access(self, mock_out, access_to):
self._knfs_helper._execute = mock.Mock(return_value=[mock_out, 0])
result = self._knfs_helper._has_client_access(self.fakesharepath,
access_to)
self._ces_helper._execute.assert_called_once_with('exportfs',
check_exit_code=True,
run_as_root=True)
if mock_out == "/gpfs0/share-fakeid\t10.0.0.1":
if access_to in (None, "10.0.0.1"):
self.assertTrue(result)
else:
self.assertFalse(result)
else:
self.assertFalse(result)
def test_knfs_allow_access(self):
self._knfs_helper._execute = mock.Mock(
return_value=['/fs0 <world>', 0]
@ -1041,7 +1394,8 @@ mmcesnfslsexport:nfsexports:HEADER:version:reserved:reserved:Path:Delegations:Cl
access = self.access
local_path = self.fakesharepath
self._ces_helper.allow_access(local_path, self.share, access)
self._ces_helper.allow_access(self.fakesharepath, self.share,
self.access)
self._ces_helper._execute.assert_has_calls([
mock.call('mmnfs', 'export', 'list', '-n', local_path, '-Y'),

View File

@ -0,0 +1,8 @@
---
features:
- Added manila manage/unmanage feature support for
GPFS driver.
The existing fileset should be an independent fileset
and should not have any NFS export over the fileset
path. With this prerequisite existing GPFS filesets
can be brought under Manila management.