[NetApp] Fix kerberos security service issues

- Fixes the zapi calls for setting up a kerberos, which have
changed since ONTAP 8.3.
- Fixes kerberos configuration cleanup when deleting a
share server.
- Fixes access rules authentication methods for NFS when a
share server is configured for Kerberos.

Change-Id: I60b4f92979045b1fdb90ad8df4f65c1dfe463ae8
Closes-Bug: #1901189
Closes-Bug: #1904746
Closes-Bug: #1907669
Co-Authored-By: Felipe Rodrigues <felipefuty01@gmail.com>
Signed-off-by: Douglas Viroel <viroel@gmail.com>
This commit is contained in:
Felipe Rodrigues 2020-11-05 18:23:18 +00:00 committed by Douglas Viroel
parent dcdc1a98bb
commit 68ad590c37
7 changed files with 303 additions and 73 deletions

View File

@ -1143,7 +1143,7 @@ class API(base.Base):
statuses = (constants.STATUS_AVAILABLE, constants.STATUS_ERROR,
constants.STATUS_INACTIVE)
if not (force or share_instance['status'] in statuses):
msg = _("Share instance status must be one of %(statuses)s") % {
msg = _("Share instance status must be one of %(statuses)s") % {
"statuses": statuses}
raise exception.InvalidShareInstance(reason=msg)

View File

@ -83,6 +83,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
self.features.add_feature('CLUSTER_PEER_POLICY', supported=ontapi_1_30)
self.features.add_feature('ADVANCED_DISK_PARTITIONING',
supported=ontapi_1_30)
self.features.add_feature('KERBEROS_VSERVER', supported=ontapi_1_30)
self.features.add_feature('FLEXVOL_ENCRYPTION', supported=ontapi_1_110)
self.features.add_feature('SVM_DR', supported=ontapi_1_140)
self.features.add_feature('ADAPTIVE_QOS', supported=ontapi_1_140)
@ -452,7 +453,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
def _terminate_vserver_services(self, vserver_name, vserver_client,
security_services):
for service in security_services:
if service['type'] == 'active_directory':
if service['type'].lower() == 'active_directory':
api_args = {
'admin-password': service['password'],
'admin-username': service['user'],
@ -465,6 +466,8 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
'Vserver %s.', vserver_name)
else:
vserver_client.send_request('cifs-server-delete')
elif service['type'].lower() == 'kerberos':
vserver_client.disable_kerberos(service)
@na_utils.trace
def is_nve_supported(self):
@ -1435,7 +1438,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
vserver_name)
elif security_service['type'].lower() == 'kerberos':
self.create_kerberos_realm(security_service)
vserver_client.create_kerberos_realm(security_service)
vserver_client.configure_kerberos(security_service,
vserver_name)
@ -1549,12 +1552,16 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
def create_kerberos_realm(self, security_service):
"""Creates Kerberos realm on cluster."""
if not self.features.KERBEROS_VSERVER:
msg = _('Kerberos realms owned by Vserver are supported on ONTAP '
'8.3 or later.')
raise exception.NetAppException(msg)
api_args = {
'admin-server-ip': security_service['server'],
'admin-server-port': '749',
'clock-skew': '5',
'comment': '',
'config-name': security_service['id'],
'kdc-ip': security_service['server'],
'kdc-port': '88',
'kdc-vendor': 'other',
@ -1575,6 +1582,11 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
def configure_kerberos(self, security_service, vserver_name):
"""Configures Kerberos for NFS on Vserver."""
if not self.features.KERBEROS_VSERVER:
msg = _('Kerberos realms owned by Vserver are supported on ONTAP '
'8.3 or later.')
raise exception.NetAppException(msg)
self.configure_dns(security_service)
spn = self._get_kerberos_service_principal_name(
security_service, vserver_name)
@ -1590,8 +1602,9 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
'admin-user-name': security_service['user'],
'interface-name': lif_name,
'is-kerberos-enabled': 'true',
'service-principal-name': spn,
'service-principal-name': spn
}
self.send_request('kerberos-config-modify', api_args)
@na_utils.trace
@ -1601,6 +1614,69 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
security_service['domain'] + '@' +
security_service['domain'].upper())
@na_utils.trace
def disable_kerberos(self, security_service):
"""Disable Kerberos in all Vserver LIFs."""
lifs = self.list_network_interfaces()
# NOTE(dviroel): If the Vserver has no LIFs, there are no Kerberos
# to be disabled.
for lif_name in lifs:
api_args = {
'admin-password': security_service['password'],
'admin-user-name': security_service['user'],
'interface-name': lif_name,
'is-kerberos-enabled': 'false',
}
try:
self.send_request('kerberos-config-modify', api_args)
except netapp_api.NaApiError as e:
disabled_msg = "Kerberos is already disabled"
if (e.code == netapp_api.EAPIERROR and
disabled_msg in e.message):
# NOTE(dviroel): do not raise an error for 'Kerberos is
# already disabled in this LIF'.
continue
msg = _("Failed to disable Kerberos: %s.")
raise exception.NetAppException(msg % e.message)
@na_utils.trace
def is_kerberos_enabled(self):
"""Check if Kerberos in enabled in all LIFs."""
if not self.features.KERBEROS_VSERVER:
msg = _('Kerberos realms owned by Vserver are supported on ONTAP '
'8.3 or later.')
raise exception.NetAppException(msg)
lifs = self.list_network_interfaces()
if not lifs:
LOG.debug("There are no LIFs configured for this Vserver. "
"Kerberos is disabled.")
return False
# NOTE(dviroel): All LIFs must have kerberos enabled
for lif in lifs:
api_args = {
'interface-name': lif,
'desired-attributes': {
'kerberos-config-info': {
'is-kerberos-enabled': None,
}
}
}
result = self.send_request('kerberos-config-get', api_args)
attributes = result.get_child_by_name('attributes')
kerberos_info = attributes.get_child_by_name(
'kerberos-config-info')
kerberos_enabled = kerberos_info.get_child_content(
'is-kerberos-enabled')
if kerberos_enabled == 'false':
return False
return True
@na_utils.trace
def configure_dns(self, security_service):
api_args = {
@ -2922,51 +2998,58 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
self.send_request('cifs-share-delete', {'share-name': share_name})
@na_utils.trace
def add_nfs_export_rule(self, policy_name, client_match, readonly):
def add_nfs_export_rule(self, policy_name, client_match, readonly,
auth_methods):
rule_indices = self._get_nfs_export_rule_indices(policy_name,
client_match)
if not rule_indices:
self._add_nfs_export_rule(policy_name, client_match, readonly)
self._add_nfs_export_rule(policy_name, client_match, readonly,
auth_methods)
else:
# Update first rule and delete the rest
self._update_nfs_export_rule(
policy_name, client_match, readonly, rule_indices.pop(0))
policy_name, client_match, readonly, rule_indices.pop(0),
auth_methods)
self._remove_nfs_export_rules(policy_name, rule_indices)
@na_utils.trace
def _add_nfs_export_rule(self, policy_name, client_match, readonly):
def _add_nfs_export_rule(self, policy_name, client_match, readonly,
auth_methods):
api_args = {
'policy-name': policy_name,
'client-match': client_match,
'ro-rule': {
'security-flavor': 'sys',
},
'rw-rule': {
'security-flavor': 'sys' if not readonly else 'never',
},
'super-user-security': {
'security-flavor': 'sys',
},
'ro-rule': [],
'rw-rule': [],
'super-user-security': [],
}
for am in auth_methods:
api_args['ro-rule'].append({'security-flavor': am})
api_args['rw-rule'].append({'security-flavor': am})
api_args['super-user-security'].append({'security-flavor': am})
if readonly:
# readonly, overwrite with auth method 'never'
api_args['rw-rule'] = [{'security-flavor': 'never'}]
self.send_request('export-rule-create', api_args)
@na_utils.trace
def _update_nfs_export_rule(self, policy_name, client_match, readonly,
rule_index):
rule_index, auth_methods):
api_args = {
'policy-name': policy_name,
'rule-index': rule_index,
'client-match': client_match,
'ro-rule': {
'security-flavor': 'sys'
},
'rw-rule': {
'security-flavor': 'sys' if not readonly else 'never'
},
'super-user-security': {
'security-flavor': 'sys'
},
'ro-rule': [],
'rw-rule': [],
'super-user-security': [],
}
for am in auth_methods:
api_args['ro-rule'].append({'security-flavor': am})
api_args['rw-rule'].append({'security-flavor': am})
api_args['super-user-security'].append({'security-flavor': am})
if readonly:
api_args['rw-rule'] = [{'security-flavor': 'never'}]
self.send_request('export-rule-modify', api_args)
@na_utils.trace

View File

@ -92,11 +92,14 @@ class NetAppCmodeNFSHelper(base.NetAppBaseHelper):
# Create new export policy
self._client.create_nfs_export_policy(temp_new_export_policy_name)
# Get authentication methods, based on Vserver configuration
auth_methods = self._get_auth_methods()
# Add new rules to new policy
for address in addresses:
self._client.add_nfs_export_rule(
temp_new_export_policy_name, address,
self._is_readonly(new_rules[address]))
self._is_readonly(new_rules[address]), auth_methods)
# Rename policy currently in force
LOG.info('Renaming NFS export policy for share %(share)s to '
@ -187,6 +190,19 @@ class NetAppCmodeNFSHelper(base.NetAppBaseHelper):
self._client.rename_nfs_export_policy(actual_export_policy,
expected_export_policy)
@na_utils.trace
def _get_auth_methods(self):
"""Returns authentication methods for export policy rules.
This method returns the authentication methods to be configure in an
export policy rule, based on security services configuration set in
the current Vserver. If Kerberos is enabled in vServer LIFs, the auth
methods will be configure to support 'krb5', 'krb5i' and 'krb5p'. The
default authentication method is 'sys' (AUTH_SYS).
"""
kerberos_enabled = self._client.is_kerberos_enabled()
return ['krb5', 'krb5i', 'krb5p'] if kerberos_enabled else ['sys']
@na_utils.trace
def cleanup_demoted_replica(self, share, share_name):
return

View File

@ -2713,6 +2713,20 @@ SNAPMIRROR_POLICY_GET_ITER_RESPONSE = etree.XML("""
'vserver_name': VSERVER_NAME,
})
KERBEROS_CONFIG_GET_RESPONSE = etree.XML("""
<results status="passed">
<attributes>
<kerberos-config-info>
<interface-name>%(lif_name)s</interface-name>
<is-kerberos-enabled>true</is-kerberos-enabled>
<vserver>%(vserver_name)s</vserver>
</kerberos-config-info>
</attributes>
</results>""" % {
'lif_name': LIF_NAME,
'vserver_name': VSERVER_NAME,
})
FAKE_VOL_XML = """<volume-info>
<name>open123</name>
<state>online</state>

View File

@ -2374,7 +2374,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
def test_setup_security_services_kerberos(self):
self.mock_object(self.client, 'send_request')
self.mock_object(self.client, 'create_kerberos_realm')
self.mock_object(self.vserver_client, 'create_kerberos_realm')
self.mock_object(self.vserver_client, 'configure_kerberos')
self.client.setup_security_services([fake.KERBEROS_SECURITY_SERVICE],
@ -2394,7 +2394,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
}
self.client.send_request.assert_has_calls([
mock.call('vserver-modify', vserver_modify_args)])
self.client.create_kerberos_realm.assert_has_calls([
self.vserver_client.create_kerberos_realm.assert_has_calls([
mock.call(fake.KERBEROS_SECURITY_SERVICE)])
self.vserver_client.configure_kerberos.assert_has_calls([
mock.call(fake.KERBEROS_SECURITY_SERVICE, fake.VSERVER_NAME)])
@ -2574,7 +2574,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
fake.VSERVER_NAME)
def test_create_kerberos_realm(self):
self.client.features.add_feature('KERBEROS_VSERVER')
self.mock_object(self.client, 'send_request')
self.client.create_kerberos_realm(fake.KERBEROS_SECURITY_SERVICE)
@ -2584,7 +2584,6 @@ class NetAppClientCmodeTestCase(test.TestCase):
'admin-server-port': '749',
'clock-skew': '5',
'comment': '',
'config-name': fake.KERBEROS_SECURITY_SERVICE['id'],
'kdc-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
'kdc-port': '88',
'kdc-vendor': 'other',
@ -2597,7 +2596,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
mock.call('kerberos-realm-create', kerberos_realm_create_args)])
def test_create_kerberos_realm_already_present(self):
self.client.features.add_feature('KERBEROS_VSERVER')
self.mock_object(self.client,
'send_request',
self._mock_api_error(code=netapp_api.EDUPLICATEENTRY))
@ -2609,7 +2608,6 @@ class NetAppClientCmodeTestCase(test.TestCase):
'admin-server-port': '749',
'clock-skew': '5',
'comment': '',
'config-name': fake.KERBEROS_SECURITY_SERVICE['id'],
'kdc-ip': fake.KERBEROS_SECURITY_SERVICE['server'],
'kdc-port': '88',
'kdc-vendor': 'other',
@ -2623,7 +2621,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
self.assertEqual(1, client_cmode.LOG.debug.call_count)
def test_create_kerberos_realm_api_error(self):
self.client.features.add_feature('KERBEROS_VSERVER')
self.mock_object(self.client, 'send_request', self._mock_api_error())
self.assertRaises(exception.NetAppException,
@ -2631,7 +2629,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
fake.KERBEROS_SECURITY_SERVICE)
def test_configure_kerberos(self):
self.client.features.add_feature('KERBEROS_VSERVER')
self.mock_object(self.client, 'send_request')
self.mock_object(self.client, 'configure_dns')
self.mock_object(self.client,
@ -2668,7 +2666,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
kerberos_config_modify_args2)])
def test_configure_kerberos_no_network_interfaces(self):
self.client.features.add_feature('KERBEROS_VSERVER')
self.mock_object(self.client, 'send_request')
self.mock_object(self.client, 'configure_dns')
self.mock_object(self.client,
@ -2683,6 +2681,82 @@ class NetAppClientCmodeTestCase(test.TestCase):
self.client.configure_dns.assert_called_with(
fake.KERBEROS_SECURITY_SERVICE)
def test_disable_kerberos(self):
self.mock_object(self.client, 'send_request')
self.mock_object(self.client,
'list_network_interfaces',
mock.Mock(return_value=['lif1', 'lif2']))
self.client.disable_kerberos(fake.KERBEROS_SECURITY_SERVICE)
kerberos_config_modify_args1 = {
'admin-password': fake.KERBEROS_SECURITY_SERVICE['password'],
'admin-user-name': fake.KERBEROS_SECURITY_SERVICE['user'],
'interface-name': 'lif1',
'is-kerberos-enabled': 'false',
}
kerberos_config_modify_args2 = {
'admin-password': fake.KERBEROS_SECURITY_SERVICE['password'],
'admin-user-name': fake.KERBEROS_SECURITY_SERVICE['user'],
'interface-name': 'lif2',
'is-kerberos-enabled': 'false',
}
self.client.send_request.assert_has_calls([
mock.call('kerberos-config-modify',
kerberos_config_modify_args1),
mock.call('kerberos-config-modify',
kerberos_config_modify_args2)])
self.client.list_network_interfaces.assert_called_once()
def test_disable_kerberos_already_disabled(self):
self.mock_object(self.client, 'send_request',
self._mock_api_error(
code=netapp_api.EAPIERROR,
message='Kerberos is already disabled'))
self.mock_object(self.client,
'list_network_interfaces',
mock.Mock(return_value=['lif1']))
self.client.disable_kerberos(fake.KERBEROS_SECURITY_SERVICE)
kerberos_config_modify_args = {
'admin-password': fake.KERBEROS_SECURITY_SERVICE['password'],
'admin-user-name': fake.KERBEROS_SECURITY_SERVICE['user'],
'interface-name': 'lif1',
'is-kerberos-enabled': 'false',
}
self.client.send_request.assert_called_once_with(
'kerberos-config-modify', kerberos_config_modify_args)
self.client.list_network_interfaces.assert_called_once()
def test_is_kerberos_enabled(self):
self.client.features.add_feature('KERBEROS_VSERVER')
api_response = netapp_api.NaElement(
fake.KERBEROS_CONFIG_GET_RESPONSE)
self.mock_object(self.client, 'send_request',
mock.Mock(return_value=api_response))
self.mock_object(self.client,
'list_network_interfaces',
mock.Mock(return_value=['lif1']))
result = self.client.is_kerberos_enabled()
kerberos_config_get_args = {
'interface-name': 'lif1',
'desired-attributes': {
'kerberos-config-info': {
'is-kerberos-enabled': None,
}
}
}
self.assertTrue(result)
self.client.send_request.assert_called_once_with(
'kerberos-config-get', kerberos_config_get_args)
self.client.list_network_interfaces.assert_called_once()
def test_get_kerberos_service_principal_name(self):
spn = self.client._get_kerberos_service_principal_name(
@ -4796,15 +4870,17 @@ class NetAppClientCmodeTestCase(test.TestCase):
self.client, '_add_nfs_export_rule')
mock_update_nfs_export_rule = self.mock_object(
self.client, '_update_nfs_export_rule')
auth_methods = ['sys']
self.client.add_nfs_export_rule(fake.EXPORT_POLICY_NAME,
fake.IP_ADDRESS,
False)
False,
auth_methods)
mock_get_nfs_export_rule_indices.assert_called_once_with(
fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS)
mock_add_nfs_export_rule.assert_called_once_with(
fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS, False)
fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS, False, auth_methods)
self.assertFalse(mock_update_nfs_export_rule.called)
def test_add_nfs_export_rule_single_existing(self):
@ -4818,16 +4894,19 @@ class NetAppClientCmodeTestCase(test.TestCase):
self.client, '_update_nfs_export_rule')
mock_remove_nfs_export_rules = self.mock_object(
self.client, '_remove_nfs_export_rules')
auth_methods = ['sys']
self.client.add_nfs_export_rule(fake.EXPORT_POLICY_NAME,
fake.IP_ADDRESS,
False)
False,
auth_methods)
mock_get_nfs_export_rule_indices.assert_called_once_with(
fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS)
self.assertFalse(mock_add_nfs_export_rule.called)
mock_update_nfs_export_rule.assert_called_once_with(
fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS, False, '1')
fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS, False, '1',
auth_methods)
mock_remove_nfs_export_rules.assert_called_once_with(
fake.EXPORT_POLICY_NAME, [])
@ -4842,71 +4921,82 @@ class NetAppClientCmodeTestCase(test.TestCase):
self.client, '_update_nfs_export_rule')
mock_remove_nfs_export_rules = self.mock_object(
self.client, '_remove_nfs_export_rules')
auth_methods = ['sys']
self.client.add_nfs_export_rule(fake.EXPORT_POLICY_NAME,
fake.IP_ADDRESS,
False)
False,
auth_methods)
mock_get_nfs_export_rule_indices.assert_called_once_with(
fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS)
self.assertFalse(mock_add_nfs_export_rule.called)
mock_update_nfs_export_rule.assert_called_once_with(
fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS, False, '2')
fake.EXPORT_POLICY_NAME, fake.IP_ADDRESS, False, '2', auth_methods)
mock_remove_nfs_export_rules.assert_called_once_with(
fake.EXPORT_POLICY_NAME, ['4', '6'])
@ddt.data({'readonly': False, 'rw_security_flavor': 'sys'},
{'readonly': True, 'rw_security_flavor': 'never'})
@ddt.data({'readonly': False, 'auth_method': 'sys'},
{'readonly': True, 'auth_method': 'sys'})
@ddt.unpack
def test__add_nfs_export_rule(self, readonly, rw_security_flavor):
def test__add_nfs_export_rule(self, readonly, auth_method):
self.mock_object(self.client, 'send_request')
self.client._add_nfs_export_rule(fake.EXPORT_POLICY_NAME,
fake.IP_ADDRESS,
readonly)
readonly,
[auth_method])
export_rule_create_args = {
'policy-name': fake.EXPORT_POLICY_NAME,
'client-match': fake.IP_ADDRESS,
'ro-rule': {
'security-flavor': 'sys',
},
'rw-rule': {
'security-flavor': rw_security_flavor,
},
'super-user-security': {
'security-flavor': 'sys',
},
'ro-rule': [
{'security-flavor': auth_method},
],
'rw-rule': [
{'security-flavor': auth_method},
],
'super-user-security': [
{'security-flavor': auth_method},
],
}
if readonly:
export_rule_create_args['rw-rule'] = [
{'security-flavor': 'never'}
]
self.client.send_request.assert_has_calls(
[mock.call('export-rule-create', export_rule_create_args)])
@ddt.data({'readonly': False, 'rw_security_flavor': 'sys', 'index': '2'},
{'readonly': True, 'rw_security_flavor': 'never', 'index': '4'})
@ddt.data({'readonly': False, 'auth_method': 'sys', 'index': '2'},
{'readonly': True, 'auth_method': 'krb5', 'index': '4'})
@ddt.unpack
def test_update_nfs_export_rule(self, readonly, rw_security_flavor, index):
def test_update_nfs_export_rule(self, readonly, auth_method, index):
self.mock_object(self.client, 'send_request')
self.client._update_nfs_export_rule(fake.EXPORT_POLICY_NAME,
fake.IP_ADDRESS,
readonly,
index)
index,
[auth_method])
export_rule_modify_args = {
'policy-name': fake.EXPORT_POLICY_NAME,
'rule-index': index,
'client-match': fake.IP_ADDRESS,
'ro-rule': {
'security-flavor': 'sys',
},
'rw-rule': {
'security-flavor': rw_security_flavor,
},
'super-user-security': {
'security-flavor': 'sys',
},
'ro-rule': [
{'security-flavor': auth_method},
],
'rw-rule': [
{'security-flavor': auth_method},
],
'super-user-security': [
{'security-flavor': auth_method},
],
}
if readonly:
export_rule_modify_args['rw-rule'] = [
{'security-flavor': 'never'}
]
self.client.send_request.assert_has_calls(
[mock.call('export-rule-modify', export_rule_modify_args)])

View File

@ -83,6 +83,10 @@ class NetAppClusteredNFSHelperTestCase(test.TestCase):
'_get_temp_export_policy_name',
mock.Mock(side_effect=['fake_new_export_policy',
'fake_old_export_policy']))
fake_auth_method = 'fake_auth_method'
self.mock_object(self.helper,
'_get_auth_methods',
mock.Mock(return_value=fake_auth_method))
self.helper.update_access(fake.CIFS_SHARE,
fake.SHARE_NAME,
@ -91,7 +95,8 @@ class NetAppClusteredNFSHelperTestCase(test.TestCase):
self.mock_client.create_nfs_export_policy.assert_called_once_with(
'fake_new_export_policy')
self.mock_client.add_nfs_export_rule.assert_called_once_with(
'fake_new_export_policy', fake.CLIENT_ADDRESS_1, False)
'fake_new_export_policy', fake.CLIENT_ADDRESS_1, False,
fake_auth_method)
(self.mock_client.set_nfs_export_policy_for_volume.
assert_called_once_with(fake.SHARE_NAME, 'fake_new_export_policy'))
(self.mock_client.soft_delete_nfs_export_policy.
@ -219,3 +224,12 @@ class NetAppClusteredNFSHelperTestCase(test.TestCase):
self.assertFalse(self.mock_client.create_nfs_export_policy.called)
self.mock_client.rename_nfs_export_policy.assert_called_once_with(
'fake', fake.EXPORT_POLICY_NAME)
@ddt.data((False, ['sys']), (True, ['krb5', 'krb5i', 'krb5p']))
@ddt.unpack
def test__get_security_flavors(self, kerberos_enabled, security_flavors):
self.mock_client.is_kerberos_enabled.return_value = kerberos_enabled
result = self.helper._get_auth_methods()
self.assertEqual(security_flavors, result)

View File

@ -0,0 +1,13 @@
---
fixes:
- |
NetApp ONTAP driver is now fixed to properly configure and clean up share
servers with Kerberos security service, for clustered ONTAP 8.3 or higher.
Access rules are now configured with the correct NFS authentication methods
based on the security service configured in the share server. Please refer to
`Launchpad Bug #1901189 <https://bugs.launchpad.net/manila/+bug/1901189>`_,
`Launchpad Bug #1904746 <https://bugs.launchpad.net/manila/+bug/1904746>`_,
and `Launchpad Bug #1907669 <https://bugs.launchpad.net/manila/+bug/1907669>`_
for more details.