Merge "Add support for manage/unmanage in GPFS driver"
This commit is contained in:
commit
3fa64b76ab
doc/source/devref
etc/manila/rootwrap.d
manila
releasenotes/notes
@ -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 | \- |
|
||||
+----------------------------------------+-----------------------+-----------------------+--------------+--------------+------------------------+----------------------------+--------------------------+
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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'),
|
||||
|
@ -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.
|
Loading…
x
Reference in New Issue
Block a user