diff --git a/manila/share/api.py b/manila/share/api.py
index 423f042f77..bea2845707 100644
--- a/manila/share/api.py
+++ b/manila/share/api.py
@@ -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)
diff --git a/manila/share/drivers/netapp/dataontap/client/client_cmode.py b/manila/share/drivers/netapp/dataontap/client/client_cmode.py
index 6b1f4c3a5f..70ee191a6d 100644
--- a/manila/share/drivers/netapp/dataontap/client/client_cmode.py
+++ b/manila/share/drivers/netapp/dataontap/client/client_cmode.py
@@ -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
diff --git a/manila/share/drivers/netapp/dataontap/protocols/nfs_cmode.py b/manila/share/drivers/netapp/dataontap/protocols/nfs_cmode.py
index d81388d07f..ac920ac933 100644
--- a/manila/share/drivers/netapp/dataontap/protocols/nfs_cmode.py
+++ b/manila/share/drivers/netapp/dataontap/protocols/nfs_cmode.py
@@ -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
diff --git a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py
index c35a42914e..cceb7f7339 100644
--- a/manila/tests/share/drivers/netapp/dataontap/client/fakes.py
+++ b/manila/tests/share/drivers/netapp/dataontap/client/fakes.py
@@ -2713,6 +2713,20 @@ SNAPMIRROR_POLICY_GET_ITER_RESPONSE = etree.XML("""
'vserver_name': VSERVER_NAME,
})
+KERBEROS_CONFIG_GET_RESPONSE = etree.XML("""
+
+
+
+ %(lif_name)s
+ true
+ %(vserver_name)s
+
+
+ """ % {
+ 'lif_name': LIF_NAME,
+ 'vserver_name': VSERVER_NAME,
+})
+
FAKE_VOL_XML = """
open123
online
diff --git a/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py b/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py
index 63a4b4fc1d..cedf7d0d61 100644
--- a/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py
+++ b/manila/tests/share/drivers/netapp/dataontap/client/test_client_cmode.py
@@ -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)])
diff --git a/manila/tests/share/drivers/netapp/dataontap/protocols/test_nfs_cmode.py b/manila/tests/share/drivers/netapp/dataontap/protocols/test_nfs_cmode.py
index 3ce0240fee..be9886beaf 100644
--- a/manila/tests/share/drivers/netapp/dataontap/protocols/test_nfs_cmode.py
+++ b/manila/tests/share/drivers/netapp/dataontap/protocols/test_nfs_cmode.py
@@ -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)
diff --git a/releasenotes/notes/1901189-netapp-fix-kerberos-setup-357753068a5645ad.yaml b/releasenotes/notes/1901189-netapp-fix-kerberos-setup-357753068a5645ad.yaml
new file mode 100644
index 0000000000..dda65abfb0
--- /dev/null
+++ b/releasenotes/notes/1901189-netapp-fix-kerberos-setup-357753068a5645ad.yaml
@@ -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 `_,
+ `Launchpad Bug #1904746 `_,
+ and `Launchpad Bug #1907669 `_
+ for more details.
+
+