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
This commit is contained in:
parent
5a23d639b0
commit
f88df34e31
@ -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):
|
||||
|
@ -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']
|
||||
|
@ -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>
|
||||
|
@ -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 = {
|
||||
|
@ -313,20 +313,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)
|
||||
|
||||
@ -515,6 +519,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,
|
||||
|
@ -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'
|
||||
},
|
||||
]
|
||||
|
||||
@ -1199,3 +1225,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
|
||||
|
@ -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.
|
Loading…
x
Reference in New Issue
Block a user