NetApp cDOT: Add gateway information to create static routes

Add tenant routes/gateway to Vservers created by the driver.

Change-Id: Id33c0e13d265d50f74f86ab8fb2c533eefa4b783
Closes-Bug: #1698258
Closes-Bug: #1612655
(cherry picked from commit f88df34e31)
This commit is contained in:
Goutham Pacha Ravi 2017-06-18 21:17:56 -04:00
parent b5f2fb77e9
commit 11c8145b96
7 changed files with 179 additions and 7 deletions

View File

@ -608,6 +608,31 @@ class NetAppCmodeClient(client_base.NetAppBaseClient):
}
raise exception.NetAppException(msg % msg_args)
@na_utils.trace
def create_route(self, gateway, destination='0.0.0.0/0'):
try:
api_args = {
'destination': destination,
'gateway': gateway,
'return-record': 'true',
}
self.send_request('net-routes-create', api_args)
except netapp_api.NaApiError as e:
p = re.compile('.*Duplicate route exists.*', re.IGNORECASE)
if (e.code == netapp_api.EAPIERROR and re.match(p, e.message)):
LOG.debug('Route to %(destination)s via gateway %(gateway)s '
'exists.',
{'destination': destination, 'gateway': gateway})
else:
msg = _('Failed to create a route to %(destination)s via '
'gateway %(gateway)s: %(err_msg)s')
msg_args = {
'destination': destination,
'gateway': gateway,
'err_msg': e.message,
}
raise exception.NetAppException(msg % msg_args)
@na_utils.trace
def _ensure_broadcast_domain_for_port(self, node, port, mtu,
ipspace=DEFAULT_IPSPACE):

View File

@ -181,6 +181,9 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
network_info,
ipspace_name)
self._create_vserver_routes(vserver_client,
network_info)
vserver_client.enable_nfs(
self.configuration.netapp_enabled_share_protocols)
@ -254,6 +257,20 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
self._create_lif(vserver_client, vserver_name, ipspace_name,
node_name, lif_name, network_allocation)
@na_utils.trace
def _create_vserver_routes(self, vserver_client, network_info):
"""Create Vserver route and set gateways."""
route_gateways = []
# NOTE(gouthamr): Use the gateway from the tenant subnet/s
# for the static routes. Do not configure a route for the admin
# subnet because fast path routing will work for incoming
# connections and there are no requirements for outgoing
# connections on the admin network yet.
for net_allocation in (network_info['network_allocations']):
if net_allocation['gateway'] not in route_gateways:
vserver_client.create_route(net_allocation['gateway'])
route_gateways.append(net_allocation['gateway'])
@na_utils.trace
def _get_node_data_port(self, node):
port_names = self._client.list_node_data_ports(node)
@ -358,7 +375,6 @@ class NetAppCmodeMultiSVMFileStorageLibrary(
@na_utils.trace
def _delete_vserver_vlans(self, network_interfaces_on_vlans):
"""Delete Vserver's VLAN configuration from ports"""
for interface in network_interfaces_on_vlans:
try:
home_port = interface['home-port']

View File

@ -75,6 +75,8 @@ VLAN = '1001'
VLAN_PORT = 'e0a-1001'
IP_ADDRESS = '10.10.10.10'
NETMASK = '255.255.255.0'
GATEWAY = '10.10.10.1'
SUBNET = '10.10.10.0/24'
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}
@ -2313,6 +2315,23 @@ PERF_OBJECT_INSTANCE_LIST_INFO_RESPONSE = etree.XML("""
</instances>
</results>""")
NET_ROUTES_CREATE_RESPONSE = etree.XML("""
<results status="passed">
<result>
<net-vs-routes-info>
<address-family>ipv4</address-family>
<destination>%(subnet)s</destination>
<gateway>%(gateway)s</gateway>
<metric>20</metric>
<vserver>%(vserver)s</vserver>
</net-vs-routes-info>
</result>
</results>""" % {
'gateway': GATEWAY,
'vserver': VSERVER_NAME,
'subnet': SUBNET,
})
FAKE_VOL_XML = """<volume-info xmlns='http://www.netapp.com/filer/admin'>
<name>open123</name>
<state>online</state>

View File

@ -1045,6 +1045,57 @@ class NetAppClientCmodeTestCase(test.TestCase):
fake.PORT,
fake.VLAN)
def test_create_route(self):
api_response = netapp_api.NaElement(
fake.NET_ROUTES_CREATE_RESPONSE)
expected_api_args = {
'destination': fake.SUBNET,
'gateway': fake.GATEWAY,
'return-record': 'true',
}
self.mock_object(
self.client, 'send_request', mock.Mock(return_value=api_response))
self.client.create_route(fake.GATEWAY, destination=fake.SUBNET)
self.client.send_request.assert_called_once_with(
'net-routes-create', expected_api_args)
def test_create_route_duplicate(self):
self.mock_object(client_cmode.LOG, 'debug')
expected_api_args = {
'destination': fake.SUBNET,
'gateway': fake.GATEWAY,
'return-record': 'true',
}
self.mock_object(
self.client, 'send_request',
mock.Mock(side_effect=self._mock_api_error(
code=netapp_api.EAPIERROR, message='Duplicate route exists.')))
self.client.create_route(fake.GATEWAY, destination=fake.SUBNET)
self.client.send_request.assert_called_once_with(
'net-routes-create', expected_api_args)
self.assertEqual(1, client_cmode.LOG.debug.call_count)
def test_create_route_api_error(self):
expected_api_args = {
'destination': fake.SUBNET,
'gateway': fake.GATEWAY,
'return-record': 'true',
}
self.mock_object(
self.client, 'send_request',
mock.Mock(side_effect=self._mock_api_error()))
self.assertRaises(exception.NetAppException,
self.client.create_route,
fake.GATEWAY, destination=fake.SUBNET)
self.client.send_request.assert_called_once_with(
'net-routes-create', expected_api_args)
def test_ensure_broadcast_domain_for_port_domain_match(self):
port_info = {

View File

@ -314,20 +314,24 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
mock.Mock(return_value=fake.IPSPACE))
self.mock_object(self.library, '_create_vserver_lifs')
self.mock_object(self.library, '_create_vserver_admin_lif')
self.mock_object(self.library, '_create_vserver_routes')
self.library._create_vserver(vserver_name, fake.NETWORK_INFO)
self.library._create_ipspace.assert_called_with(fake.NETWORK_INFO)
self.library._client.create_vserver.assert_called_with(
self.library._create_ipspace.assert_called_once_with(fake.NETWORK_INFO)
self.library._client.create_vserver.assert_called_once_with(
vserver_name, fake.ROOT_VOLUME_AGGREGATE, fake.ROOT_VOLUME,
fake.AGGREGATES, fake.IPSPACE)
self.library._get_api_client.assert_called_with(vserver=vserver_name)
self.library._create_vserver_lifs.assert_called_with(
self.library._get_api_client.assert_called_once_with(
vserver=vserver_name)
self.library._create_vserver_lifs.assert_called_once_with(
vserver_name, vserver_client, fake.NETWORK_INFO, fake.IPSPACE)
self.library._create_vserver_admin_lif.assert_called_with(
self.library._create_vserver_admin_lif.assert_called_once_with(
vserver_name, vserver_client, fake.NETWORK_INFO, fake.IPSPACE)
self.library._create_vserver_routes.assert_called_once_with(
vserver_client, fake.NETWORK_INFO)
vserver_client.enable_nfs.assert_called_once_with(versions)
self.library._client.setup_security_services.assert_called_with(
self.library._client.setup_security_services.assert_called_once_with(
fake.NETWORK_INFO['security_services'], vserver_client,
vserver_name)
@ -516,6 +520,22 @@ class NetAppFileStorageLibraryTestCase(test.TestCase):
self.assertFalse(self.library._create_lif.called)
@ddt.data(
fake.get_network_info(fake.USER_NETWORK_ALLOCATIONS,
fake.ADMIN_NETWORK_ALLOCATIONS),
fake.get_network_info(fake.USER_NETWORK_ALLOCATIONS_IPV6,
fake.ADMIN_NETWORK_ALLOCATIONS))
def test_create_vserver_routes(self, network_info):
expected_gateway = network_info['network_allocations'][0]['gateway']
vserver_client = mock.Mock()
self.mock_object(vserver_client, 'create_route')
retval = self.library._create_vserver_routes(
vserver_client, network_info)
self.assertIsNone(retval)
vserver_client.create_route.assert_called_once_with(expected_gateway)
def test_get_node_data_port(self):
self.mock_object(self.client,

View File

@ -230,6 +230,7 @@ USER_NETWORK_ALLOCATIONS = [
'network_type': 'vlan',
'label': 'user',
'mtu': MTU,
'gateway': '10.10.10.1',
},
{
'id': '7eabdeed-bad2-46ea-bd0f-a33884c869e0',
@ -239,6 +240,30 @@ USER_NETWORK_ALLOCATIONS = [
'network_type': 'vlan',
'label': 'user',
'mtu': MTU,
'gateway': '10.10.10.1',
}
]
USER_NETWORK_ALLOCATIONS_IPV6 = [
{
'id': '234dbb10-9a36-46f2-8d89-3d909830c356',
'ip_address': 'fd68:1a09:66ab:8d51:0:10:0:1',
'cidr': 'fd68:1a09:66ab:8d51::/64',
'segmentation_id': '2000',
'network_type': 'vlan',
'label': 'user',
'mtu': MTU,
'gateway': 'fd68:1a09:66ab:8d51:0:0:0:1',
},
{
'id': '6677deed-bad2-46ea-bd0f-a33884c869e0',
'ip_address': 'fd68:1a09:66ab:8d51:0:10:0:2',
'cidr': 'fd68:1a09:66ab:8d51::/64',
'segmentation_id': '2000',
'network_type': 'vlan',
'label': 'user',
'mtu': MTU,
'gateway': 'fd68:1a09:66ab:8d51:0:0:0:1',
}
]
@ -251,6 +276,7 @@ ADMIN_NETWORK_ALLOCATIONS = [
'network_type': 'flat',
'label': 'admin',
'mtu': MTU,
'gateway': '10.10.20.1'
},
]
@ -1200,3 +1226,11 @@ def get_config_cmode():
config.netapp_volume_snapshot_reserve_percent = 8
config.netapp_vserver = VSERVER1
return config
def get_network_info(user_network_allocation, admin_network_allocation):
net_info = copy.deepcopy(NETWORK_INFO)
net_info['network_allocations'] = user_network_allocation
net_info['admin_network_allocations'] = admin_network_allocation
return net_info

View File

@ -0,0 +1,7 @@
---
fixes:
- The NetApp DHSS=True driver now creates static routes with the gateway
specified on the tenant networks. Potential beneficiaries of this bug-fix
are deployers/users whose CIFS security service (e.g. Active Directory)
is not part of the tenant network, but a route exists via the tenant
network gateway.