Merge "Add "update_access" interface support for VNX."
This commit is contained in:
commit
4936ffceac
manila
share/drivers/dell_emc/plugins
tests/share/drivers/dell_emc/plugins/vnx
@ -61,6 +61,11 @@ class StorageConnection(object):
|
||||
def deny_access(self, context, share, access, share_server):
|
||||
"""Deny access to the share."""
|
||||
|
||||
def update_access(self, context, share, access_rules, add_rules,
|
||||
delete_rules, share_server=None):
|
||||
"""Update access rules for given share."""
|
||||
raise NotImplementedError()
|
||||
|
||||
def raise_connect_error(self):
|
||||
"""Check for setup error."""
|
||||
pass
|
||||
|
@ -370,6 +370,61 @@ class VNXStorageConnection(driver.StorageConnection):
|
||||
self._get_context('NFSShare').allow_share_access(
|
||||
share['id'], host_ip, vdm_name, access_level)
|
||||
|
||||
def update_access(self, context, share, access_rules, add_rules,
|
||||
delete_rules, share_server=None):
|
||||
# deleting rules
|
||||
for rule in delete_rules:
|
||||
self.deny_access(context, share, rule, share_server)
|
||||
|
||||
# adding rules
|
||||
for rule in add_rules:
|
||||
self.allow_access(context, share, rule, share_server)
|
||||
|
||||
# recovery mode
|
||||
if not (add_rules or delete_rules):
|
||||
white_list = []
|
||||
for rule in access_rules:
|
||||
self.allow_access(context, share, rule, share_server)
|
||||
white_list.append(rule['access_to'])
|
||||
self.clear_access(share, share_server, white_list)
|
||||
|
||||
def clear_access(self, share, share_server, white_list):
|
||||
share_proto = share['share_proto'].upper()
|
||||
share_name = share['id']
|
||||
if share_proto == 'CIFS':
|
||||
self._cifs_clear_access(share_name, share_server, white_list)
|
||||
elif share_proto == 'NFS':
|
||||
self._nfs_clear_access(share_name, share_server, white_list)
|
||||
|
||||
@vnx_utils.log_enter_exit
|
||||
def _cifs_clear_access(self, share_name, share_server, white_list):
|
||||
"""Clear access for CIFS share except hosts in the white list."""
|
||||
vdm_name = self._get_share_server_name(share_server)
|
||||
|
||||
# Check if CIFS server exists.
|
||||
server_name = vdm_name
|
||||
status, server = self._get_context('CIFSServer').get(server_name,
|
||||
vdm_name)
|
||||
if status != constants.STATUS_OK:
|
||||
message = (_("CIFS server %(server_name)s has issue. "
|
||||
"Detail: %(status)s") %
|
||||
{'server_name': server_name, 'status': status})
|
||||
raise exception.EMCVnxXMLAPIError(err=message)
|
||||
|
||||
self._get_context('CIFSShare').clear_share_access(
|
||||
share_name=share_name,
|
||||
mover_name=vdm_name,
|
||||
domain=server['domain'],
|
||||
white_list_users=white_list)
|
||||
|
||||
@vnx_utils.log_enter_exit
|
||||
def _nfs_clear_access(self, share_name, share_server, white_list):
|
||||
"""Clear access for NFS share except hosts in the white list."""
|
||||
self._get_context('NFSShare').clear_share_access(
|
||||
share_name=share_name,
|
||||
mover_name=self._get_share_server_name(share_server),
|
||||
white_list_hosts=white_list)
|
||||
|
||||
def deny_access(self, context, share, access, share_server=None):
|
||||
"""Deny access to a share."""
|
||||
share_proto = share['share_proto']
|
||||
|
@ -1730,6 +1730,47 @@ class CIFSShare(StorageObject):
|
||||
LOG.error(message)
|
||||
raise exception.EMCVnxXMLAPIError(err=message)
|
||||
|
||||
def get_share_access(self, mover_name, share_name):
|
||||
get_str = 'sharesd %s dump' % share_name
|
||||
get_access = [
|
||||
'env', 'NAS_DB=/nas', '/nas/bin/.server_config', mover_name,
|
||||
'-v', "%s" % get_str,
|
||||
]
|
||||
|
||||
try:
|
||||
out, err = self._execute_cmd(get_access, check_exit_code=True)
|
||||
except processutils.ProcessExecutionError:
|
||||
msg = _('Failed to get access list of CIFS share %s.') % share_name
|
||||
LOG.exception(msg)
|
||||
raise exception.EMCVnxXMLAPIError(err=msg)
|
||||
|
||||
ret = {}
|
||||
name_pattern = re.compile(r"Unix user '(.+?)'")
|
||||
access_pattern = re.compile(r"ALLOWED:(.+?):")
|
||||
|
||||
name = None
|
||||
for line in out.splitlines():
|
||||
if name is None:
|
||||
names = name_pattern.findall(line)
|
||||
if names:
|
||||
name = names[0].lower()
|
||||
else:
|
||||
accesses = access_pattern.findall(line)
|
||||
if accesses:
|
||||
ret[name] = accesses[0].lower()
|
||||
name = None
|
||||
return ret
|
||||
|
||||
def clear_share_access(self, mover_name, share_name, domain,
|
||||
white_list_users):
|
||||
existing_users = self.get_share_access(mover_name, share_name)
|
||||
white_list_users_set = set(user.lower() for user in white_list_users)
|
||||
users_to_remove = set(existing_users.keys()) - white_list_users_set
|
||||
for user in users_to_remove:
|
||||
self.deny_share_access(mover_name, share_name, user, domain,
|
||||
existing_users[user])
|
||||
return users_to_remove
|
||||
|
||||
|
||||
@vnx_utils.decorate_all_methods(vnx_utils.log_enter_exit,
|
||||
debug_only=True)
|
||||
@ -1948,9 +1989,45 @@ class NFSShare(StorageObject):
|
||||
|
||||
do_deny_access(share_name, host_ip, mover_name)
|
||||
|
||||
def clear_share_access(self, share_name, mover_name, white_list_hosts):
|
||||
@utils.synchronized('emc-shareaccess-' + share_name)
|
||||
def do_clear_access(share_name, mover_name, white_list_hosts):
|
||||
def hosts_to_remove(orig_list):
|
||||
if white_list_hosts is None:
|
||||
ret = set()
|
||||
else:
|
||||
ret = set(white_list_hosts).intersection(set(orig_list))
|
||||
return ret
|
||||
|
||||
status, share = self.get(share_name, mover_name)
|
||||
if constants.STATUS_OK != status:
|
||||
message = (_('Query nfs share %(path)s failed. '
|
||||
'Reason %(err)s.') %
|
||||
{'path': share_name, 'err': status})
|
||||
raise exception.EMCVnxXMLAPIError(err=message)
|
||||
|
||||
self._set_share_access('/' + share_name,
|
||||
mover_name,
|
||||
hosts_to_remove(share['RwHosts']),
|
||||
hosts_to_remove(share['RoHosts']),
|
||||
hosts_to_remove(share['RootHosts']),
|
||||
hosts_to_remove(share['AccessHosts']))
|
||||
|
||||
# Update self.nfs_share_map
|
||||
self.get(share_name, mover_name, force=True,
|
||||
check_exit_code=True)
|
||||
|
||||
do_clear_access(share_name, mover_name, white_list_hosts)
|
||||
|
||||
def _set_share_access(self, path, mover_name, rw_hosts, ro_hosts,
|
||||
root_hosts, access_hosts):
|
||||
|
||||
if access_hosts is None:
|
||||
access_hosts = set()
|
||||
|
||||
if '-0.0.0.0/0.0.0.0' not in access_hosts:
|
||||
access_hosts.add('-0.0.0.0/0.0.0.0')
|
||||
|
||||
access_str = ('access=%(access)s'
|
||||
% {'access': ':'.join(access_hosts)})
|
||||
if root_hosts:
|
||||
@ -1959,6 +2036,7 @@ class NFSShare(StorageObject):
|
||||
access_str += ',rw=%(rw)s' % {'rw': ':'.join(rw_hosts)}
|
||||
if ro_hosts:
|
||||
access_str += ',ro=%(ro)s' % {'ro': ':'.join(ro_hosts)}
|
||||
|
||||
set_nfs_share_access_cmd = [
|
||||
'env', 'NAS_DB=/nas', '/nas/bin/server_export', mover_name,
|
||||
'-ignore',
|
||||
|
@ -134,6 +134,15 @@ class FakeData(object):
|
||||
emc_nas_password = 'fakepassword'
|
||||
share_backend_name = 'EMC_NAS_Storage'
|
||||
|
||||
cifs_access = """
|
||||
1478607389: SMB:11: Unix user 'Guest' UID=32769
|
||||
1478607389: SMB:10: FindUserUid:Access_Password 'Guest',1=0x8001 T=0
|
||||
1478607389: SHARE: 6: ALLOWED:fullcontrol:S-1-5-15-3399d125-6dcdf5f4
|
||||
1478607389: SMB:11: Unix user 'Administrator' UID=32768
|
||||
1478607389: SMB:10: FindUserUid:Access_Password 'Administrator',
|
||||
1478607389: SHARE: 6: ALLOWED:fullcontrol:S-1-5-15-3399d125
|
||||
"""
|
||||
|
||||
|
||||
class StorageObjectTestData(object):
|
||||
def __init__(self):
|
||||
@ -1106,7 +1115,10 @@ class CIFSServerTestData(StorageObjectTestData):
|
||||
)
|
||||
|
||||
@response
|
||||
def resp_get_succeed(self, mover_id, is_vdm, join_domain):
|
||||
def resp_get_succeed(self, mover_id, is_vdm, join_domain,
|
||||
cifs_server_name=None):
|
||||
if cifs_server_name is None:
|
||||
cifs_server_name = self.cifs_server_name
|
||||
return (
|
||||
'<QueryStatus maxSeverity="ok"/>'
|
||||
'<CifsServer interfaces="%(ip)s" type="W2K" '
|
||||
@ -1122,7 +1134,7 @@ class CIFSServerTestData(StorageObjectTestData):
|
||||
'alias': self.cifs_server_name[-12:],
|
||||
'domain': self.domain_name,
|
||||
'join_domain': 'true' if join_domain else 'false',
|
||||
'comp_name': self.cifs_server_name}
|
||||
'comp_name': cifs_server_name}
|
||||
)
|
||||
|
||||
@response
|
||||
@ -1256,8 +1268,10 @@ class CIFSShareTestData(StorageObjectTestData):
|
||||
]
|
||||
|
||||
def cmd_change_access(self, access_level=const.ACCESS_LEVEL_RW,
|
||||
action='grant'):
|
||||
account = self.domain_user + '@' + self.domain_name
|
||||
action='grant', user=None):
|
||||
if user is None:
|
||||
user = self.domain_user
|
||||
account = user + '@' + self.domain_name
|
||||
|
||||
if access_level == const.ACCESS_LEVEL_RW:
|
||||
str_access = 'fullcontrol'
|
||||
@ -1277,6 +1291,14 @@ class CIFSShareTestData(StorageObjectTestData):
|
||||
'-v', '%s' % allow_str,
|
||||
]
|
||||
|
||||
def cmd_get_access(self):
|
||||
get_str = 'sharesd %s dump' % self.share_name
|
||||
return [
|
||||
'env', 'NAS_DB=/nas',
|
||||
'/nas/bin/.server_config', self.vdm_name,
|
||||
'-v', '%s' % get_str,
|
||||
]
|
||||
|
||||
def output_allow_access(self):
|
||||
return (
|
||||
"Command succeeded: :3 sharesd %(share)s grant "
|
||||
@ -1373,7 +1395,7 @@ class NFSShareTestData(StorageObjectTestData):
|
||||
'access=-0.0.0.0/0.0.0.0:%(host)s root=%(host)s '
|
||||
'rw=%(rw_host)s\n'
|
||||
% {'mover_name': self.vdm_name,
|
||||
'host': rw_hosts,
|
||||
'host': ":".join(rw_hosts),
|
||||
'path': self.path,
|
||||
'rw_host': ":".join(rw_hosts)}
|
||||
)
|
||||
@ -1383,7 +1405,7 @@ class NFSShareTestData(StorageObjectTestData):
|
||||
'access=-0.0.0.0/0.0.0.0:%(host)s root=%(host)s '
|
||||
'ro=%(ro_host)s\n'
|
||||
% {'mover_name': self.vdm_name,
|
||||
'host': ro_hosts,
|
||||
'host': ":".join(ro_hosts),
|
||||
'path': self.path,
|
||||
'ro_host': ":".join(ro_hosts)}
|
||||
)
|
||||
|
@ -975,6 +975,158 @@ class StorageConnectionTestCase(test.TestCase):
|
||||
]
|
||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||
|
||||
def test_update_access_add_cifs_rw(self):
|
||||
share_server = fakes.SHARE_SERVER
|
||||
share = fakes.CIFS_SHARE
|
||||
access = fakes.CIFS_RW_ACCESS
|
||||
|
||||
hook = utils.RequestSideEffect()
|
||||
hook.append(self.vdm.resp_get_succeed())
|
||||
hook.append(self.cifs_server.resp_get_succeed(
|
||||
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True))
|
||||
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||
|
||||
ssh_hook = utils.SSHSideEffect()
|
||||
ssh_hook.append(self.cifs_share.output_allow_access())
|
||||
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||
|
||||
self.connection.update_access(None, share, [], [access], [],
|
||||
share_server=share_server)
|
||||
|
||||
expected_calls = [
|
||||
mock.call(self.vdm.req_get()),
|
||||
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
|
||||
]
|
||||
xml_req_mock.assert_has_calls(expected_calls)
|
||||
|
||||
ssh_calls = [
|
||||
mock.call(self.cifs_share.cmd_change_access(), True),
|
||||
]
|
||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||
|
||||
def test_update_access_deny_nfs(self):
|
||||
share_server = fakes.SHARE_SERVER
|
||||
share = fakes.NFS_SHARE
|
||||
access = fakes.NFS_RW_ACCESS
|
||||
|
||||
rw_hosts = copy.deepcopy(fakes.FakeData.rw_hosts)
|
||||
rw_hosts.append(access['access_to'])
|
||||
|
||||
ssh_hook = utils.SSHSideEffect()
|
||||
ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||
rw_hosts=rw_hosts,
|
||||
ro_hosts=fakes.FakeData.ro_hosts))
|
||||
ssh_hook.append(self.nfs_share.output_set_access_success())
|
||||
ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||
rw_hosts=fakes.FakeData.rw_hosts,
|
||||
ro_hosts=fakes.FakeData.ro_hosts))
|
||||
ssh_cmd_mock = utils.EMCNFSShareMock(side_effect=ssh_hook)
|
||||
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||
|
||||
self.connection.update_access(None, share, [], [], [access],
|
||||
share_server=share_server)
|
||||
|
||||
ssh_calls = [
|
||||
mock.call(self.nfs_share.cmd_get(), True),
|
||||
mock.call(self.nfs_share.cmd_set_access(
|
||||
rw_hosts=self.nfs_share.rw_hosts,
|
||||
ro_hosts=self.nfs_share.ro_hosts), True),
|
||||
mock.call(self.nfs_share.cmd_get(), True),
|
||||
]
|
||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||
|
||||
def test_update_access_recover_nfs_rule(self):
|
||||
share_server = fakes.SHARE_SERVER
|
||||
share = fakes.NFS_SHARE
|
||||
access = fakes.NFS_RW_ACCESS
|
||||
hosts = ['192.168.1.5']
|
||||
|
||||
rw_hosts = copy.deepcopy(fakes.FakeData.rw_hosts)
|
||||
rw_hosts.append(access['access_to'])
|
||||
|
||||
ssh_hook = utils.SSHSideEffect()
|
||||
ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||
rw_hosts=rw_hosts,
|
||||
ro_hosts=fakes.FakeData.ro_hosts))
|
||||
ssh_hook.append(self.nfs_share.output_set_access_success())
|
||||
ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||
rw_hosts=hosts,
|
||||
ro_hosts=[]))
|
||||
ssh_cmd_mock = utils.EMCNFSShareMock(side_effect=ssh_hook)
|
||||
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||
|
||||
self.connection.update_access(None, share, [access], [], [],
|
||||
share_server=share_server)
|
||||
|
||||
ssh_calls = [
|
||||
mock.call(self.nfs_share.cmd_get(), True),
|
||||
mock.call(self.nfs_share.cmd_set_access(
|
||||
rw_hosts=hosts,
|
||||
ro_hosts=[]), True),
|
||||
mock.call(self.nfs_share.cmd_get(), True),
|
||||
]
|
||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||
|
||||
def test_update_access_recover_cifs_rule(self):
|
||||
share_server = fakes.SHARE_SERVER
|
||||
share = fakes.CIFS_SHARE
|
||||
access = fakes.CIFS_RW_ACCESS
|
||||
|
||||
hook = utils.RequestSideEffect()
|
||||
hook.append(self.vdm.resp_get_succeed())
|
||||
hook.append(self.cifs_server.resp_get_succeed(
|
||||
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True))
|
||||
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||
|
||||
ssh_hook = utils.SSHSideEffect()
|
||||
ssh_hook.append(self.cifs_share.output_allow_access())
|
||||
ssh_hook.append(fakes.FakeData.cifs_access)
|
||||
ssh_hook.append('Command succeeded')
|
||||
|
||||
ssh_cmd_mock = mock.Mock(side_effect=ssh_hook)
|
||||
self.connection.manager.connectors['SSH'].run_ssh = ssh_cmd_mock
|
||||
|
||||
self.connection.update_access(None, share, [access], [], [],
|
||||
share_server=share_server)
|
||||
|
||||
expected_calls = [
|
||||
mock.call(self.vdm.req_get()),
|
||||
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
|
||||
]
|
||||
xml_req_mock.assert_has_calls(expected_calls)
|
||||
|
||||
ssh_calls = [
|
||||
mock.call(self.cifs_share.cmd_change_access(), True),
|
||||
mock.call(self.cifs_share.cmd_get_access(), True),
|
||||
mock.call(self.cifs_share.cmd_change_access(
|
||||
action='revoke', user='guest'), True),
|
||||
]
|
||||
ssh_cmd_mock.assert_has_calls(ssh_calls)
|
||||
|
||||
def test_cifs_clear_access_server_not_found(self):
|
||||
server = fakes.SHARE_SERVER
|
||||
|
||||
hook = utils.RequestSideEffect()
|
||||
hook.append(self.vdm.resp_get_succeed())
|
||||
hook.append(self.cifs_server.resp_get_succeed(
|
||||
mover_id=self.vdm.vdm_id, is_vdm=True, join_domain=True,
|
||||
cifs_server_name='cifs_server_name'))
|
||||
xml_req_mock = utils.EMCMock(side_effect=hook)
|
||||
self.connection.manager.connectors['XML'].request = xml_req_mock
|
||||
|
||||
self.assertRaises(exception.EMCVnxXMLAPIError,
|
||||
self.connection._cifs_clear_access,
|
||||
'share_name', server, None)
|
||||
|
||||
expected_calls = [
|
||||
mock.call(self.vdm.req_get()),
|
||||
mock.call(self.cifs_server.req_get(self.vdm.vdm_id)),
|
||||
]
|
||||
xml_req_mock.assert_has_calls(expected_calls)
|
||||
|
||||
def test_allow_cifs_rw_access(self):
|
||||
share_server = fakes.SHARE_SERVER
|
||||
share = fakes.CIFS_SHARE
|
||||
|
@ -2738,6 +2738,63 @@ class CIFSShareTestCase(StorageObjectTestCaseBase):
|
||||
]
|
||||
context.conn['SSH'].run_ssh.assert_has_calls(ssh_calls)
|
||||
|
||||
def test_get_share_access(self):
|
||||
self.ssh_hook.append(fakes.FakeData.cifs_access)
|
||||
|
||||
context = self.manager.getStorageContext('CIFSShare')
|
||||
context.conn['SSH'].run_ssh = mock.Mock(side_effect=self.ssh_hook)
|
||||
|
||||
ret = context.get_share_access(
|
||||
mover_name=self.vdm.vdm_name,
|
||||
share_name=self.cifs_share.share_name)
|
||||
|
||||
ssh_calls = [
|
||||
mock.call(self.cifs_share.cmd_get_access(), True),
|
||||
]
|
||||
self.assertEqual(2, len(ret))
|
||||
self.assertEqual(constants.CIFS_ACL_FULLCONTROL, ret['administrator'])
|
||||
self.assertEqual(constants.CIFS_ACL_FULLCONTROL, ret['guest'])
|
||||
context.conn['SSH'].run_ssh.assert_has_calls(ssh_calls)
|
||||
|
||||
def test_get_share_access_failed(self):
|
||||
expt_err = processutils.ProcessExecutionError(
|
||||
stdout=self.nfs_share.fake_output)
|
||||
self.ssh_hook.append(ex=expt_err)
|
||||
|
||||
context = self.manager.getStorageContext('CIFSShare')
|
||||
context.conn['SSH'].run_ssh = mock.Mock(side_effect=self.ssh_hook)
|
||||
|
||||
self.assertRaises(exception.EMCVnxXMLAPIError,
|
||||
context.get_share_access,
|
||||
mover_name=self.vdm.vdm_name,
|
||||
share_name=self.cifs_share.share_name)
|
||||
|
||||
ssh_calls = [
|
||||
mock.call(self.cifs_share.cmd_get_access(), True),
|
||||
]
|
||||
context.conn['SSH'].run_ssh.assert_has_calls(ssh_calls)
|
||||
|
||||
def test_clear_share_access_has_white_list(self):
|
||||
self.ssh_hook.append(fakes.FakeData.cifs_access)
|
||||
self.ssh_hook.append('Command succeeded')
|
||||
|
||||
context = self.manager.getStorageContext('CIFSShare')
|
||||
context.conn['SSH'].run_ssh = mock.Mock(side_effect=self.ssh_hook)
|
||||
|
||||
to_remove = context.clear_share_access(
|
||||
mover_name=self.vdm.vdm_name,
|
||||
share_name=self.cifs_share.share_name,
|
||||
domain=self.cifs_server.domain_name,
|
||||
white_list_users=['guest'])
|
||||
|
||||
ssh_calls = [
|
||||
mock.call(self.cifs_share.cmd_get_access(), True),
|
||||
mock.call(self.cifs_share.cmd_change_access(action='revoke'),
|
||||
True),
|
||||
]
|
||||
self.assertEqual({'administrator'}, to_remove)
|
||||
context.conn['SSH'].run_ssh.assert_has_calls(ssh_calls)
|
||||
|
||||
|
||||
class NFSShareTestCase(StorageObjectTestCaseBase):
|
||||
def setUp(self):
|
||||
@ -3010,6 +3067,32 @@ class NFSShareTestCase(StorageObjectTestCaseBase):
|
||||
]
|
||||
context.conn['SSH'].run_ssh.assert_has_calls(ssh_calls)
|
||||
|
||||
def test_clear_share_access(self):
|
||||
hosts = ['192.168.1.1', '192.168.1.3']
|
||||
|
||||
self.ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||
rw_hosts=self.nfs_share.rw_hosts,
|
||||
ro_hosts=self.nfs_share.ro_hosts))
|
||||
self.ssh_hook.append(self.nfs_share.output_set_access_success())
|
||||
self.ssh_hook.append(self.nfs_share.output_get_succeed(
|
||||
rw_hosts=[hosts[0]], ro_hosts=[hosts[1]]))
|
||||
|
||||
context = self.manager.getStorageContext('NFSShare')
|
||||
context.conn['SSH'].run_ssh = utils.EMCNFSShareMock(
|
||||
side_effect=self.ssh_hook)
|
||||
|
||||
context.clear_share_access(share_name=self.nfs_share.share_name,
|
||||
mover_name=self.vdm.vdm_name,
|
||||
white_list_hosts=hosts)
|
||||
|
||||
ssh_calls = [
|
||||
mock.call(self.nfs_share.cmd_get()),
|
||||
mock.call(self.nfs_share.cmd_set_access(
|
||||
rw_hosts=[hosts[0]], ro_hosts=[hosts[1]])),
|
||||
mock.call(self.nfs_share.cmd_get()),
|
||||
]
|
||||
context.conn['SSH'].run_ssh.assert_has_calls(ssh_calls)
|
||||
|
||||
def test_deny_ro_share_access(self):
|
||||
ro_hosts = copy.deepcopy(self.nfs_share.ro_hosts)
|
||||
ro_hosts.append(self.nfs_share.nfs_host_ip)
|
||||
@ -3085,3 +3168,18 @@ class NFSShareTestCase(StorageObjectTestCaseBase):
|
||||
self.nfs_share.ro_hosts)),
|
||||
]
|
||||
context.conn['SSH'].run_ssh.assert_has_calls(ssh_calls)
|
||||
|
||||
def test_clear_share_access_failed_to_get_share(self):
|
||||
self.ssh_hook.append("no output.")
|
||||
|
||||
context = self.manager.getStorageContext('NFSShare')
|
||||
context.conn['SSH'].run_ssh = mock.Mock(side_effect=self.ssh_hook)
|
||||
|
||||
self.assertRaises(exception.EMCVnxXMLAPIError,
|
||||
context.clear_share_access,
|
||||
share_name=self.nfs_share.share_name,
|
||||
mover_name=self.vdm.vdm_name,
|
||||
white_list_hosts=None)
|
||||
|
||||
context.conn['SSH'].run_ssh.assert_called_once_with(
|
||||
self.nfs_share.cmd_get(), False)
|
||||
|
@ -135,6 +135,15 @@ class EMCNFSShareMock(mock.Mock):
|
||||
|
||||
return option_map
|
||||
|
||||
@staticmethod
|
||||
def _opt_value_from_map(opt_map, key):
|
||||
value = opt_map.get(key)
|
||||
if value:
|
||||
ret = set(value.split(':'))
|
||||
else:
|
||||
ret = set()
|
||||
return ret
|
||||
|
||||
def _option_check(self, expect, actual):
|
||||
if '-option' in actual and '-option' in expect:
|
||||
exp_option = expect[expect.index('-option') + 1]
|
||||
@ -144,8 +153,8 @@ class EMCNFSShareMock(mock.Mock):
|
||||
act_opt_map = self._option_parser(act_option)
|
||||
|
||||
for key in exp_opt_map:
|
||||
exp_set = set(exp_opt_map[key].split(':'))
|
||||
act_set = set(act_opt_map[key].split(':'))
|
||||
exp_set = self._opt_value_from_map(exp_opt_map, key)
|
||||
act_set = self._opt_value_from_map(act_opt_map, key)
|
||||
if exp_set != act_set:
|
||||
return False
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user