Merge "Enable Manila multi-SVM driver on NetApp cDOT 8.3"
This commit is contained in:
commit
1d00bfdfd2
@ -42,6 +42,7 @@ EVOLNOTCLONE = '13170'
|
||||
EVOL_NOT_MOUNTED = '14716'
|
||||
ESIS_CLONE_NOT_LICENSED = '14956'
|
||||
EOBJECTNOTFOUND = '15661'
|
||||
E_VIFMGR_PORT_ALREADY_ASSIGNED_TO_BROADCAST_DOMAIN = '18605'
|
||||
|
||||
|
||||
class NaServer(object):
|
||||
|
@ -47,6 +47,10 @@ class NetAppBaseClient(object):
|
||||
minor = res.get_child_content('minor-version')
|
||||
return major, minor
|
||||
|
||||
def _init_features(self):
|
||||
"""Set up the repository of available Data ONTAP features."""
|
||||
self.features = Features()
|
||||
|
||||
def check_is_naelement(self, elem):
|
||||
"""Checks if object is instance of NaElement."""
|
||||
if not isinstance(elem, netapp_api.NaElement):
|
||||
@ -74,3 +78,19 @@ class NetAppBaseClient(object):
|
||||
def send_ems_log_message(self, message_dict):
|
||||
"""Sends a message to the Data ONTAP EMS log."""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class Features(object):
|
||||
|
||||
def __init__(self):
|
||||
self.defined_features = set()
|
||||
|
||||
def add_feature(self, name, supported=True):
|
||||
if not isinstance(supported, bool):
|
||||
raise TypeError("Feature value must be a bool type.")
|
||||
self.defined_features.add(name)
|
||||
setattr(self, name, supported)
|
||||
|
||||
def __getattr__(self, name):
|
||||
# NOTE(cknight): Needed to keep pylint happy.
|
||||
raise AttributeError
|
||||
|
@ -32,6 +32,8 @@ from manila.share.drivers.netapp import utils as na_utils
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
DELETED_PREFIX = 'deleted_manila_'
|
||||
DEFAULT_IPSPACE = 'Default'
|
||||
DEFAULT_BROADCAST_DOMAIN = 'OpenStack'
|
||||
|
||||
|
||||
class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
@ -46,6 +48,19 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
(major, minor) = self.get_ontapi_version(cached=False)
|
||||
self.connection.set_api_version(major, minor)
|
||||
|
||||
self._init_features()
|
||||
|
||||
def _init_features(self):
|
||||
"""Initialize cDOT feature support map."""
|
||||
super(NetAppCmodeClient, self)._init_features()
|
||||
|
||||
ontapi_version = self.get_ontapi_version(cached=True)
|
||||
ontapi_1_30 = ontapi_version >= (1, 30)
|
||||
|
||||
self.features.add_feature('BROADCAST_DOMAINS', supported=ontapi_1_30)
|
||||
self.features.add_feature('IPSPACES', supported=ontapi_1_30)
|
||||
self.features.add_feature('SUBNETS', supported=ontapi_1_30)
|
||||
|
||||
def _invoke_vserver_api(self, na_element, vserver):
|
||||
server = copy.copy(self.connection)
|
||||
server.set_vserver(vserver)
|
||||
@ -265,7 +280,7 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
},
|
||||
},
|
||||
'desired-attributes': {
|
||||
'node-details-info': {
|
||||
'net-port-info': {
|
||||
'port': None,
|
||||
'node': None,
|
||||
'operational-speed': None,
|
||||
@ -350,6 +365,9 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
self._create_vlan(node, port, vlan)
|
||||
home_port_name = '%(port)s-%(tag)s' % {'port': port, 'tag': vlan}
|
||||
|
||||
if self.features.BROADCAST_DOMAINS:
|
||||
self._ensure_broadcast_domain_for_port(node, home_port_name)
|
||||
|
||||
interface_name = (lif_name_template %
|
||||
{'node': node, 'net_allocation_id': allocation_id})
|
||||
|
||||
@ -393,6 +411,104 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
msg_args = {'vlan': vlan, 'port': port, 'err_msg': e.message}
|
||||
raise exception.NetAppException(msg % msg_args)
|
||||
|
||||
@na_utils.trace
|
||||
def _ensure_broadcast_domain_for_port(self, node, port,
|
||||
domain=DEFAULT_BROADCAST_DOMAIN,
|
||||
ipspace=DEFAULT_IPSPACE):
|
||||
"""Ensure a port is in a broadcast domain. Create one if necessary."""
|
||||
|
||||
if self._get_broadcast_domain_for_port(node, port):
|
||||
return
|
||||
|
||||
if not self._broadcast_domain_exists(domain, ipspace):
|
||||
self._create_broadcast_domain(domain, ipspace)
|
||||
|
||||
self._add_port_to_broadcast_domain(node, port, domain, ipspace)
|
||||
|
||||
@na_utils.trace
|
||||
def _get_broadcast_domain_for_port(self, node, port):
|
||||
"""Get broadcast domain for a specific port."""
|
||||
api_args = {
|
||||
'query': {
|
||||
'net-port-info': {
|
||||
'node': node,
|
||||
'port': port,
|
||||
},
|
||||
},
|
||||
'desired-attributes': {
|
||||
'net-port-info': {
|
||||
'broadcast-domain': None,
|
||||
},
|
||||
},
|
||||
}
|
||||
result = self.send_request('net-port-get-iter', api_args)
|
||||
|
||||
net_port_info_list = result.get_child_by_name(
|
||||
'attributes-list') or netapp_api.NaElement('none')
|
||||
port_info = net_port_info_list.get_children()
|
||||
if not port_info:
|
||||
msg = _('Could not find port %(port)s on node %(node)s.')
|
||||
msg_args = {'port': port, 'node': node}
|
||||
raise exception.NetAppException(msg % msg_args)
|
||||
|
||||
return port_info[0].get_child_content('broadcast-domain')
|
||||
|
||||
@na_utils.trace
|
||||
def _broadcast_domain_exists(self, domain, ipspace):
|
||||
"""Check if a broadcast domain exists."""
|
||||
api_args = {
|
||||
'query': {
|
||||
'net-port-broadcast-domain-info': {
|
||||
'ipspace': ipspace,
|
||||
'broadcast-domain': domain,
|
||||
},
|
||||
},
|
||||
'desired-attributes': {
|
||||
'net-port-broadcast-domain-info': None,
|
||||
},
|
||||
}
|
||||
result = self.send_request('net-port-broadcast-domain-get-iter',
|
||||
api_args)
|
||||
return self._has_records(result)
|
||||
|
||||
@na_utils.trace
|
||||
def _create_broadcast_domain(self, domain, ipspace, mtu=1500):
|
||||
"""Create a broadcast domain."""
|
||||
api_args = {
|
||||
'ipspace': ipspace,
|
||||
'broadcast-domain': domain,
|
||||
'mtu': mtu,
|
||||
}
|
||||
self.send_request('net-port-broadcast-domain-create', api_args)
|
||||
|
||||
@na_utils.trace
|
||||
def _add_port_to_broadcast_domain(self, node, port, domain, ipspace):
|
||||
|
||||
qualified_port_name = ':'.join([node, port])
|
||||
try:
|
||||
api_args = {
|
||||
'ipspace': ipspace,
|
||||
'broadcast-domain': domain,
|
||||
'ports': {
|
||||
'net-qualified-port-name': qualified_port_name,
|
||||
}
|
||||
}
|
||||
self.send_request('net-port-broadcast-domain-add-ports', api_args)
|
||||
except netapp_api.NaApiError as e:
|
||||
if e.code == (netapp_api.
|
||||
E_VIFMGR_PORT_ALREADY_ASSIGNED_TO_BROADCAST_DOMAIN):
|
||||
LOG.debug('Port %(port)s already exists in broadcast domain '
|
||||
'%(domain)s', {'port': port, 'domain': domain})
|
||||
else:
|
||||
msg = _('Failed to add port %(port)s to broadcast domain '
|
||||
'%(domain)s. %(err_msg)s')
|
||||
msg_args = {
|
||||
'port': qualified_port_name,
|
||||
'domain': domain,
|
||||
'err_msg': e.message,
|
||||
}
|
||||
raise exception.NetAppException(msg % msg_args)
|
||||
|
||||
@na_utils.trace
|
||||
def network_interface_exists(self, vserver_name, node, port, ip, netmask,
|
||||
vlan):
|
||||
@ -595,12 +711,14 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
|
||||
def setup_security_services(self, security_services, vserver_client,
|
||||
vserver_name):
|
||||
api_args = {
|
||||
'name-mapping-switch': {
|
||||
'nmswitch': 'ldap,file',
|
||||
},
|
||||
'name-server-switch': {
|
||||
'nsswitch': 'ldap,file',
|
||||
},
|
||||
'name-mapping-switch': [
|
||||
{'nmswitch': 'ldap'},
|
||||
{'nmswitch': 'file'}
|
||||
],
|
||||
'name-server-switch': [
|
||||
{'nsswitch': 'ldap'},
|
||||
{'nsswitch': 'file'}
|
||||
],
|
||||
'vserver-name': vserver_name,
|
||||
}
|
||||
self.send_request('vserver-modify', api_args)
|
||||
|
@ -42,8 +42,6 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
||||
@na_utils.trace
|
||||
def check_for_setup_error(self):
|
||||
|
||||
self._check_data_ontap_version()
|
||||
|
||||
if self._have_cluster_creds:
|
||||
if self.configuration.netapp_vserver:
|
||||
msg = _LW('Vserver is specified in the configuration. This is '
|
||||
@ -65,17 +63,6 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
|
||||
super(NetAppCmodeMultiSVMFileStorageLibrary, self).\
|
||||
check_for_setup_error()
|
||||
|
||||
def _check_data_ontap_version(self):
|
||||
# Temporary check to indicate that the Kilo multi-SVM driver does not
|
||||
# support cDOT 8.3 or higher.
|
||||
ontapi_version = self._client.get_ontapi_version()
|
||||
if ontapi_version >= (1, 30):
|
||||
msg = _('Clustered Data ONTAP 8.3.0 or higher is not '
|
||||
'supported by this version of the driver when the '
|
||||
'configuration option driver_handles_share_servers '
|
||||
'is set to True.')
|
||||
raise exception.NetAppException(msg)
|
||||
|
||||
@na_utils.trace
|
||||
def _get_vserver(self, share_server=None):
|
||||
|
||||
|
@ -60,6 +60,9 @@ NETMASK = '255.255.255.0'
|
||||
NET_ALLOCATION_ID = 'fake_allocation_id'
|
||||
LIF_NAME_TEMPLATE = 'os_%(net_allocation_id)s'
|
||||
LIF_NAME = LIF_NAME_TEMPLATE % {'net_allocation_id': NET_ALLOCATION_ID}
|
||||
IPSPACE = 'fake_ipspace'
|
||||
BROADCAST_DOMAIN = 'fake_domain'
|
||||
MTU = 9000
|
||||
|
||||
EMS_MESSAGE = {
|
||||
'computer-name': 'fake_host',
|
||||
@ -431,6 +434,43 @@ SORTED_PORTS_ALL_SPEEDS = (
|
||||
{'node': NODE_NAME, 'port': 'port7'},
|
||||
)
|
||||
|
||||
NET_PORT_GET_ITER_BROADCAST_DOMAIN_RESPONSE = etree.XML("""
|
||||
<results status="passed">
|
||||
<attributes-list>
|
||||
<net-port-info>
|
||||
<broadcast-domain>%(domain)s</broadcast-domain>
|
||||
<node>%(node)s</node>
|
||||
<port>%(port)s</port>
|
||||
</net-port-info>
|
||||
</attributes-list>
|
||||
<num-records>1</num-records>
|
||||
</results>
|
||||
""" % {'domain': BROADCAST_DOMAIN, 'node': NODE_NAME, 'port': PORT})
|
||||
|
||||
NET_PORT_GET_ITER_BROADCAST_DOMAIN_MISSING_RESPONSE = etree.XML("""
|
||||
<results status="passed">
|
||||
<attributes-list>
|
||||
<net-port-info>
|
||||
<node>%(node)s</node>
|
||||
<port>%(port)s</port>
|
||||
</net-port-info>
|
||||
</attributes-list>
|
||||
<num-records>1</num-records>
|
||||
</results>
|
||||
""" % {'node': NODE_NAME, 'port': PORT})
|
||||
|
||||
NET_PORT_BROADCAST_DOMAIN_GET_ITER_RESPONSE = etree.XML("""
|
||||
<results status="passed">
|
||||
<attributes-list>
|
||||
<net-port-broadcast-domain-info>
|
||||
<broadcast-domain>%(domain)s</broadcast-domain>
|
||||
<ipspace>%(ipspace)s</ipspace>
|
||||
</net-port-broadcast-domain-info>
|
||||
</attributes-list>
|
||||
<num-records>1</num-records>
|
||||
</results>
|
||||
""" % {'domain': BROADCAST_DOMAIN, 'ipspace': IPSPACE})
|
||||
|
||||
NET_INTERFACE_GET_ITER_RESPONSE = etree.XML("""
|
||||
<results status="passed">
|
||||
<attributes-list>
|
||||
|
@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
from oslo_log import log
|
||||
|
||||
@ -56,6 +57,12 @@ class NetAppBaseClientTestCase(test.TestCase):
|
||||
self.assertEqual(1, major)
|
||||
self.assertEqual(20, minor)
|
||||
|
||||
def test_init_features(self):
|
||||
|
||||
self.client._init_features()
|
||||
|
||||
self.assertSetEqual(set(), self.client.features.defined_features)
|
||||
|
||||
def test_check_is_naelement(self):
|
||||
|
||||
element = netapp_api.NaElement('name')
|
||||
@ -121,4 +128,39 @@ class NetAppBaseClientTestCase(test.TestCase):
|
||||
|
||||
self.assertRaises(NotImplementedError,
|
||||
self.client.send_ems_log_message,
|
||||
{})
|
||||
{})
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class FeaturesTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(FeaturesTestCase, self).setUp()
|
||||
self.features = client_base.Features()
|
||||
|
||||
def test_init(self):
|
||||
self.assertSetEqual(set(), self.features.defined_features)
|
||||
|
||||
def test_add_feature_default(self):
|
||||
self.features.add_feature('FEATURE_1')
|
||||
|
||||
self.assertTrue(self.features.FEATURE_1)
|
||||
self.assertIn('FEATURE_1', self.features.defined_features)
|
||||
|
||||
@ddt.data(True, False)
|
||||
def test_add_feature(self, value):
|
||||
self.features.add_feature('FEATURE_2', value)
|
||||
|
||||
self.assertEqual(value, self.features.FEATURE_2)
|
||||
self.assertIn('FEATURE_2', self.features.defined_features)
|
||||
|
||||
@ddt.data('True', 'False', 0, 1, 1.0, None, [], {}, (True,))
|
||||
def test_add_feature_type_error(self, value):
|
||||
self.assertRaises(TypeError,
|
||||
self.features.add_feature,
|
||||
'FEATURE_3',
|
||||
value)
|
||||
self.assertNotIn('FEATURE_3', self.features.defined_features)
|
||||
|
||||
def test_get_attr_missing(self):
|
||||
self.assertRaises(AttributeError, getattr, self.features, 'FEATURE_4')
|
||||
|
@ -63,6 +63,31 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
def _mock_api_error(self, code='fake'):
|
||||
return mock.Mock(side_effect=netapp_api.NaApiError(code=code))
|
||||
|
||||
def test_init_features_ontapi_1_21(self):
|
||||
|
||||
self.mock_object(client_base.NetAppBaseClient,
|
||||
'get_ontapi_version',
|
||||
mock.Mock(return_value=(1, 21)))
|
||||
|
||||
self.client._init_features()
|
||||
|
||||
self.assertFalse(self.client.features.BROADCAST_DOMAINS)
|
||||
self.assertFalse(self.client.features.IPSPACES)
|
||||
self.assertFalse(self.client.features.SUBNETS)
|
||||
|
||||
@ddt.data((1, 30), (1, 40), (2, 0))
|
||||
def test_init_features_ontapi_1_30(self, ontapi_version):
|
||||
|
||||
self.mock_object(client_base.NetAppBaseClient,
|
||||
'get_ontapi_version',
|
||||
mock.Mock(return_value=ontapi_version))
|
||||
|
||||
self.client._init_features()
|
||||
|
||||
self.assertTrue(self.client.features.BROADCAST_DOMAINS)
|
||||
self.assertTrue(self.client.features.IPSPACES)
|
||||
self.assertTrue(self.client.features.SUBNETS)
|
||||
|
||||
def test_invoke_vserver_api(self):
|
||||
|
||||
self.client._invoke_vserver_api('fake-api', 'fake_vserver')
|
||||
@ -487,7 +512,7 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
},
|
||||
},
|
||||
'desired-attributes': {
|
||||
'node-details-info': {
|
||||
'net-port-info': {
|
||||
'port': None,
|
||||
'node': None,
|
||||
'operational-speed': None,
|
||||
@ -559,8 +584,14 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
|
||||
self.assertListEqual([], result)
|
||||
|
||||
def test_create_network_interface(self):
|
||||
@ddt.data((True, True), (True, False), (False, True), (False, False))
|
||||
@ddt.unpack
|
||||
def test_create_network_interface(self, broadcast_domains_supported,
|
||||
use_vlans):
|
||||
|
||||
self.client.features.add_feature('BROADCAST_DOMAINS',
|
||||
broadcast_domains_supported)
|
||||
self.mock_object(self.client, '_ensure_broadcast_domain_for_port')
|
||||
self.mock_object(self.client, '_create_vlan')
|
||||
self.mock_object(self.client, 'send_request')
|
||||
|
||||
@ -572,50 +603,32 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
{'data-protocol': 'cifs'}
|
||||
],
|
||||
'home-node': fake.NODE_NAME,
|
||||
'home-port': fake.VLAN_PORT,
|
||||
'home-port': fake.VLAN_PORT if use_vlans else fake.PORT,
|
||||
'netmask': fake.NETMASK,
|
||||
'interface-name': fake.LIF_NAME,
|
||||
'role': 'data',
|
||||
'vserver': fake.VSERVER_NAME,
|
||||
}
|
||||
self.client.create_network_interface(fake.IP_ADDRESS, fake.NETMASK,
|
||||
fake.VLAN, fake.NODE_NAME,
|
||||
fake.PORT, fake.VSERVER_NAME,
|
||||
fake.VLAN if use_vlans else None,
|
||||
fake.NODE_NAME, fake.PORT,
|
||||
fake.VSERVER_NAME,
|
||||
fake.NET_ALLOCATION_ID,
|
||||
fake.LIF_NAME_TEMPLATE)
|
||||
|
||||
self.client._create_vlan.assert_called_with(fake.NODE_NAME, fake.PORT,
|
||||
fake.VLAN)
|
||||
if use_vlans:
|
||||
self.client._create_vlan.assert_called_with(
|
||||
fake.NODE_NAME, fake.PORT, fake.VLAN)
|
||||
else:
|
||||
self.assertFalse(self.client._create_vlan.called)
|
||||
|
||||
self.client.send_request.assert_has_calls([
|
||||
mock.call('net-interface-create', lif_create_args)])
|
||||
if broadcast_domains_supported:
|
||||
self.client._ensure_broadcast_domain_for_port.assert_called_with(
|
||||
fake.NODE_NAME, fake.VLAN_PORT if use_vlans else fake.PORT)
|
||||
else:
|
||||
self.assertFalse(
|
||||
self.client._ensure_broadcast_domain_for_port.called)
|
||||
|
||||
def test_create_network_interface_no_vlan(self):
|
||||
|
||||
self.mock_object(self.client, '_create_vlan')
|
||||
self.mock_object(self.client, 'send_request')
|
||||
|
||||
lif_create_args = {
|
||||
'address': fake.IP_ADDRESS,
|
||||
'administrative-status': 'up',
|
||||
'data-protocols': [
|
||||
{'data-protocol': 'nfs'},
|
||||
{'data-protocol': 'cifs'}
|
||||
],
|
||||
'home-node': fake.NODE_NAME,
|
||||
'home-port': fake.PORT,
|
||||
'netmask': fake.NETMASK,
|
||||
'interface-name': fake.LIF_NAME,
|
||||
'role': 'data',
|
||||
'vserver': fake.VSERVER_NAME,
|
||||
}
|
||||
self.client.create_network_interface(fake.IP_ADDRESS, fake.NETMASK,
|
||||
None, fake.NODE_NAME,
|
||||
fake.PORT, fake.VSERVER_NAME,
|
||||
fake.NET_ALLOCATION_ID,
|
||||
fake.LIF_NAME_TEMPLATE)
|
||||
|
||||
self.assertFalse(self.client._create_vlan.called)
|
||||
self.client.send_request.assert_has_calls([
|
||||
mock.call('net-interface-create', lif_create_args)])
|
||||
|
||||
@ -665,6 +678,229 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
fake.PORT,
|
||||
fake.VLAN)
|
||||
|
||||
def test_ensure_broadcast_domain_for_port_has_domain(self):
|
||||
|
||||
self.mock_object(self.client,
|
||||
'_get_broadcast_domain_for_port',
|
||||
mock.Mock(return_value=fake.BROADCAST_DOMAIN))
|
||||
self.mock_object(self.client, '_broadcast_domain_exists')
|
||||
self.mock_object(self.client, '_create_broadcast_domain')
|
||||
self.mock_object(self.client, '_add_port_to_broadcast_domain')
|
||||
|
||||
self.client._ensure_broadcast_domain_for_port(fake.NODE_NAME,
|
||||
fake.PORT)
|
||||
|
||||
self.client._get_broadcast_domain_for_port.assert_has_calls([
|
||||
mock.call(fake.NODE_NAME, fake.PORT)])
|
||||
self.assertFalse(self.client._broadcast_domain_exists.called)
|
||||
self.assertFalse(self.client._create_broadcast_domain.called)
|
||||
self.assertFalse(self.client._add_port_to_broadcast_domain.called)
|
||||
|
||||
def test_ensure_broadcast_domain_for_port_domain_not_found(self):
|
||||
|
||||
self.mock_object(self.client,
|
||||
'_get_broadcast_domain_for_port',
|
||||
mock.Mock(return_value=None))
|
||||
self.mock_object(self.client,
|
||||
'_broadcast_domain_exists',
|
||||
mock.Mock(return_value=False))
|
||||
self.mock_object(self.client, '_create_broadcast_domain')
|
||||
self.mock_object(self.client, '_add_port_to_broadcast_domain')
|
||||
|
||||
self.client._ensure_broadcast_domain_for_port(
|
||||
fake.NODE_NAME, fake.PORT, domain=fake.BROADCAST_DOMAIN,
|
||||
ipspace=fake.IPSPACE)
|
||||
|
||||
self.client._get_broadcast_domain_for_port.assert_has_calls([
|
||||
mock.call(fake.NODE_NAME, fake.PORT)])
|
||||
self.client._broadcast_domain_exists.assert_has_calls([
|
||||
mock.call(fake.BROADCAST_DOMAIN, fake.IPSPACE)])
|
||||
self.client._create_broadcast_domain.assert_has_calls([
|
||||
mock.call(fake.BROADCAST_DOMAIN, fake.IPSPACE)])
|
||||
self.client._add_port_to_broadcast_domain.assert_has_calls([
|
||||
mock.call(fake.NODE_NAME, fake.PORT, fake.BROADCAST_DOMAIN,
|
||||
fake.IPSPACE)])
|
||||
|
||||
def test_ensure_broadcast_domain_for_port_domain_found(self):
|
||||
|
||||
self.mock_object(self.client,
|
||||
'_get_broadcast_domain_for_port',
|
||||
mock.Mock(return_value=None))
|
||||
self.mock_object(self.client,
|
||||
'_broadcast_domain_exists',
|
||||
mock.Mock(return_value=True))
|
||||
self.mock_object(self.client, '_create_broadcast_domain')
|
||||
self.mock_object(self.client, '_add_port_to_broadcast_domain')
|
||||
|
||||
self.client._ensure_broadcast_domain_for_port(
|
||||
fake.NODE_NAME, fake.PORT, domain=fake.BROADCAST_DOMAIN,
|
||||
ipspace=fake.IPSPACE)
|
||||
|
||||
self.client._get_broadcast_domain_for_port.assert_has_calls([
|
||||
mock.call(fake.NODE_NAME, fake.PORT)])
|
||||
self.client._broadcast_domain_exists.assert_has_calls([
|
||||
mock.call(fake.BROADCAST_DOMAIN, fake.IPSPACE)])
|
||||
self.assertFalse(self.client._create_broadcast_domain.called)
|
||||
self.client._add_port_to_broadcast_domain.assert_has_calls([
|
||||
mock.call(fake.NODE_NAME, fake.PORT, fake.BROADCAST_DOMAIN,
|
||||
fake.IPSPACE)])
|
||||
|
||||
def test_get_broadcast_domain_for_port(self):
|
||||
|
||||
api_response = netapp_api.NaElement(
|
||||
fake.NET_PORT_GET_ITER_BROADCAST_DOMAIN_RESPONSE)
|
||||
self.mock_object(self.client,
|
||||
'send_request',
|
||||
mock.Mock(return_value=api_response))
|
||||
|
||||
net_port_get_iter_args = {
|
||||
'query': {
|
||||
'net-port-info': {
|
||||
'node': fake.NODE_NAME,
|
||||
'port': fake.PORT,
|
||||
},
|
||||
},
|
||||
'desired-attributes': {
|
||||
'net-port-info': {
|
||||
'broadcast-domain': None,
|
||||
},
|
||||
},
|
||||
}
|
||||
result = self.client._get_broadcast_domain_for_port(fake.NODE_NAME,
|
||||
fake.PORT)
|
||||
|
||||
self.client.send_request.assert_has_calls([
|
||||
mock.call('net-port-get-iter', net_port_get_iter_args)])
|
||||
self.assertEqual(fake.BROADCAST_DOMAIN, result)
|
||||
|
||||
def test_get_broadcast_domain_for_port_port_not_found(self):
|
||||
|
||||
api_response = netapp_api.NaElement(
|
||||
fake.NO_RECORDS_RESPONSE)
|
||||
self.mock_object(self.client,
|
||||
'send_request',
|
||||
mock.Mock(return_value=api_response))
|
||||
|
||||
self.assertRaises(exception.NetAppException,
|
||||
self.client._get_broadcast_domain_for_port,
|
||||
fake.NODE_NAME,
|
||||
fake.PORT)
|
||||
|
||||
def test_get_broadcast_domain_for_port_domain_not_found(self):
|
||||
|
||||
api_response = netapp_api.NaElement(
|
||||
fake.NET_PORT_GET_ITER_BROADCAST_DOMAIN_MISSING_RESPONSE)
|
||||
self.mock_object(self.client,
|
||||
'send_request',
|
||||
mock.Mock(return_value=api_response))
|
||||
|
||||
result = self.client._get_broadcast_domain_for_port(fake.NODE_NAME,
|
||||
fake.PORT)
|
||||
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_broadcast_domain_exists(self):
|
||||
|
||||
api_response = netapp_api.NaElement(
|
||||
fake.NET_PORT_BROADCAST_DOMAIN_GET_ITER_RESPONSE)
|
||||
self.mock_object(self.client,
|
||||
'send_request',
|
||||
mock.Mock(return_value=api_response))
|
||||
|
||||
result = self.client._broadcast_domain_exists(fake.BROADCAST_DOMAIN,
|
||||
fake.IPSPACE)
|
||||
|
||||
net_port_broadcast_domain_get_iter_args = {
|
||||
'query': {
|
||||
'net-port-broadcast-domain-info': {
|
||||
'ipspace': fake.IPSPACE,
|
||||
'broadcast-domain': fake.BROADCAST_DOMAIN,
|
||||
},
|
||||
},
|
||||
'desired-attributes': {
|
||||
'net-port-broadcast-domain-info': None,
|
||||
},
|
||||
}
|
||||
self.client.send_request.assert_has_calls([
|
||||
mock.call('net-port-broadcast-domain-get-iter',
|
||||
net_port_broadcast_domain_get_iter_args)])
|
||||
self.assertTrue(result)
|
||||
|
||||
def test_broadcast_domain_exists_not_found(self):
|
||||
|
||||
api_response = netapp_api.NaElement(
|
||||
fake.NO_RECORDS_RESPONSE)
|
||||
self.mock_object(self.client,
|
||||
'send_request',
|
||||
mock.Mock(return_value=api_response))
|
||||
|
||||
result = self.client._broadcast_domain_exists(fake.BROADCAST_DOMAIN,
|
||||
fake.IPSPACE)
|
||||
|
||||
self.assertFalse(result)
|
||||
|
||||
def test_create_broadcast_domain(self):
|
||||
|
||||
self.mock_object(self.client, 'send_request')
|
||||
|
||||
result = self.client._create_broadcast_domain(fake.BROADCAST_DOMAIN,
|
||||
fake.IPSPACE,
|
||||
mtu=fake.MTU)
|
||||
|
||||
net_port_broadcast_domain_create_args = {
|
||||
'ipspace': fake.IPSPACE,
|
||||
'broadcast-domain': fake.BROADCAST_DOMAIN,
|
||||
'mtu': fake.MTU,
|
||||
}
|
||||
self.assertIsNone(result)
|
||||
self.client.send_request.assert_has_calls([
|
||||
mock.call('net-port-broadcast-domain-create',
|
||||
net_port_broadcast_domain_create_args)])
|
||||
|
||||
def test_add_port_to_broadcast_domain(self):
|
||||
|
||||
self.mock_object(self.client, 'send_request')
|
||||
|
||||
add_port_to_broadcast_domain_args = {
|
||||
'ipspace': fake.IPSPACE,
|
||||
'broadcast-domain': fake.BROADCAST_DOMAIN,
|
||||
'ports': {
|
||||
'net-qualified-port-name': ':'.join([fake.NODE_NAME,
|
||||
fake.VLAN_PORT])
|
||||
}
|
||||
}
|
||||
result = self.client._add_port_to_broadcast_domain(
|
||||
fake.NODE_NAME, fake.VLAN_PORT, fake.BROADCAST_DOMAIN,
|
||||
fake.IPSPACE)
|
||||
|
||||
self.assertIsNone(result)
|
||||
self.client.send_request.assert_has_calls([
|
||||
mock.call('net-port-broadcast-domain-add-ports',
|
||||
add_port_to_broadcast_domain_args)])
|
||||
|
||||
def test_add_port_to_broadcast_domain_already_present(self):
|
||||
|
||||
self.mock_object(self.client, 'send_request', self._mock_api_error(
|
||||
code=netapp_api.
|
||||
E_VIFMGR_PORT_ALREADY_ASSIGNED_TO_BROADCAST_DOMAIN))
|
||||
|
||||
result = self.client._add_port_to_broadcast_domain(
|
||||
fake.NODE_NAME, fake.VLAN_PORT, fake.BROADCAST_DOMAIN,
|
||||
fake.IPSPACE)
|
||||
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_add_port_to_broadcast_domain_api_error(self):
|
||||
|
||||
self.mock_object(self.client, 'send_request', self._mock_api_error())
|
||||
|
||||
self.assertRaises(exception.NetAppException,
|
||||
self.client._add_port_to_broadcast_domain,
|
||||
fake.NODE_NAME,
|
||||
fake.VLAN_PORT,
|
||||
fake.BROADCAST_DOMAIN,
|
||||
fake.IPSPACE)
|
||||
|
||||
def test_network_interface_exists(self):
|
||||
|
||||
api_response = netapp_api.NaElement(
|
||||
@ -1029,11 +1265,16 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
fake.VSERVER_NAME)
|
||||
|
||||
vserver_modify_args = {
|
||||
'name-mapping-switch': {'nmswitch': 'ldap,file'},
|
||||
'name-server-switch': {'nsswitch': 'ldap,file'},
|
||||
'name-mapping-switch': [
|
||||
{'nmswitch': 'ldap'},
|
||||
{'nmswitch': 'file'},
|
||||
],
|
||||
'name-server-switch': [
|
||||
{'nsswitch': 'ldap'},
|
||||
{'nsswitch': 'file'},
|
||||
],
|
||||
'vserver-name': fake.VSERVER_NAME
|
||||
}
|
||||
|
||||
self.client.send_request.assert_has_calls([
|
||||
mock.call('vserver-modify', vserver_modify_args)])
|
||||
self.vserver_client.configure_ldap.assert_has_calls([
|
||||
@ -1049,11 +1290,16 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
fake.VSERVER_NAME)
|
||||
|
||||
vserver_modify_args = {
|
||||
'name-mapping-switch': {'nmswitch': 'ldap,file'},
|
||||
'name-server-switch': {'nsswitch': 'ldap,file'},
|
||||
'name-mapping-switch': [
|
||||
{'nmswitch': 'ldap'},
|
||||
{'nmswitch': 'file'},
|
||||
],
|
||||
'name-server-switch': [
|
||||
{'nsswitch': 'ldap'},
|
||||
{'nsswitch': 'file'},
|
||||
],
|
||||
'vserver-name': fake.VSERVER_NAME
|
||||
}
|
||||
|
||||
self.client.send_request.assert_has_calls([
|
||||
mock.call('vserver-modify', vserver_modify_args)])
|
||||
self.vserver_client.configure_active_directory.assert_has_calls([
|
||||
@ -1070,11 +1316,16 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
fake.VSERVER_NAME)
|
||||
|
||||
vserver_modify_args = {
|
||||
'name-mapping-switch': {'nmswitch': 'ldap,file'},
|
||||
'name-server-switch': {'nsswitch': 'ldap,file'},
|
||||
'name-mapping-switch': [
|
||||
{'nmswitch': 'ldap'},
|
||||
{'nmswitch': 'file'},
|
||||
],
|
||||
'name-server-switch': [
|
||||
{'nsswitch': 'ldap'},
|
||||
{'nsswitch': 'file'},
|
||||
],
|
||||
'vserver-name': fake.VSERVER_NAME
|
||||
}
|
||||
|
||||
self.client.send_request.assert_has_calls([
|
||||
mock.call('vserver-modify', vserver_modify_args)])
|
||||
self.client.create_kerberos_realm.assert_has_calls([
|
||||
@ -1093,11 +1344,16 @@ class NetAppClientCmodeTestCase(test.TestCase):
|
||||
fake.VSERVER_NAME)
|
||||
|
||||
vserver_modify_args = {
|
||||
'name-mapping-switch': {'nmswitch': 'ldap,file'},
|
||||
'name-server-switch': {'nsswitch': 'ldap,file'},
|
||||
'name-mapping-switch': [
|
||||
{'nmswitch': 'ldap'},
|
||||
{'nmswitch': 'file'},
|
||||
],
|
||||
'name-server-switch': [
|
||||
{'nsswitch': 'ldap'},
|
||||
{'nsswitch': 'file'},
|
||||
],
|
||||
'vserver-name': fake.VSERVER_NAME
|
||||
}
|
||||
|
||||
self.client.send_request.assert_has_calls([
|
||||
mock.call('vserver-modify', vserver_modify_args)])
|
||||
|
||||
|
@ -65,14 +65,11 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.mock_object(self.library,
|
||||
'_find_matching_aggregates',
|
||||
mock.Mock(return_value=fake.AGGREGATES))
|
||||
mock_check_data_ontap_version = self.mock_object(
|
||||
self.library, '_check_data_ontap_version')
|
||||
mock_super = self.mock_object(lib_base.NetAppCmodeFileStorageLibrary,
|
||||
'check_for_setup_error')
|
||||
|
||||
self.library.check_for_setup_error()
|
||||
|
||||
self.assertTrue(mock_check_data_ontap_version.called)
|
||||
self.assertTrue(self.library._find_matching_aggregates.called)
|
||||
mock_super.assert_called_once_with()
|
||||
|
||||
@ -107,17 +104,6 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
|
||||
self.library.check_for_setup_error)
|
||||
self.assertTrue(self.library._find_matching_aggregates.called)
|
||||
|
||||
@ddt.data((1, 20), (1, 21))
|
||||
def test_check_data_ontap_version(self, version):
|
||||
self.library._client.get_ontapi_version.return_value = version
|
||||
self.assertIsNone(self.library._check_data_ontap_version())
|
||||
|
||||
@ddt.data((1, 30), (1, 31), (1, 40), (2, 0))
|
||||
def test_check_data_ontap_version_too_new(self, version):
|
||||
self.library._client.get_ontapi_version.return_value = version
|
||||
self.assertRaises(exception.NetAppException,
|
||||
self.library._check_data_ontap_version)
|
||||
|
||||
def test_get_vserver_no_share_server(self):
|
||||
|
||||
self.assertRaises(exception.InvalidInput,
|
||||
|
Loading…
Reference in New Issue
Block a user