# Copyright (c) 2012 OpenStack Foundation. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or # implied. # See the License for the specific language governing permissions and # limitations under the License. import contextlib from eventlet import greenthread import mock import netaddr from neutron.api.v2 import attributes from neutron.common import constants from neutron.common import exceptions as n_exc from neutron import context from neutron.extensions import dvr as dist_router from neutron.extensions import external_net from neutron.extensions import l3 from neutron.extensions import l3_ext_gw_mode from neutron.extensions import portbindings from neutron.extensions import portsecurity as psec from neutron.extensions import providernet as pnet from neutron.extensions import securitygroup as secgrp from neutron import manager from neutron.tests.unit import _test_extension_portbindings as test_bindings import neutron.tests.unit.db.test_allowedaddresspairs_db as test_addr_pair import neutron.tests.unit.db.test_db_base_plugin_v2 as test_plugin import neutron.tests.unit.extensions.test_l3 as test_l3_plugin import neutron.tests.unit.extensions.test_l3_ext_gw_mode as test_ext_gw_mode import neutron.tests.unit.extensions.test_portsecurity as test_psec import neutron.tests.unit.extensions.test_securitygroup as ext_sg from neutron.tests.unit import testlib_api from oslo_config import cfg from oslo_db import exception as db_exc from oslo_utils import uuidutils import six import webob.exc from vmware_nsx._i18n import _ from vmware_nsx.common import nsx_constants from vmware_nsx.db import nsxv_db from vmware_nsx.extensions import ( routersize as router_size) from vmware_nsx.extensions import ( routertype as router_type) from vmware_nsx.extensions import ( vnicindex as ext_vnic_idx) from vmware_nsx.plugins.nsx_v.vshield.common import ( constants as vcns_const) from vmware_nsx.plugins.nsx_v.vshield import edge_utils from vmware_nsx.tests import unit as vmware from vmware_nsx.tests.unit.extensions import test_vnic_index from vmware_nsx.tests.unit.nsx_v.vshield import fake_vcns from vmware_nsx.tests.unit import test_utils PLUGIN_NAME = 'vmware_nsx.plugin.NsxVPlugin' _uuid = uuidutils.generate_uuid class NsxVPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase): def _create_network(self, fmt, name, admin_state_up, arg_list=None, providernet_args=None, **kwargs): data = {'network': {'name': name, 'admin_state_up': admin_state_up, 'tenant_id': self._tenant_id}} # Fix to allow the router:external attribute and any other # attributes containing a colon to be passed with # a double underscore instead kwargs = dict((k.replace('__', ':'), v) for k, v in kwargs.items()) if external_net.EXTERNAL in kwargs: arg_list = (external_net.EXTERNAL, ) + (arg_list or ()) attrs = kwargs if providernet_args: attrs.update(providernet_args) for arg in (('admin_state_up', 'tenant_id', 'shared') + (arg_list or ())): # Arg must be present and not empty if arg in kwargs: data['network'][arg] = kwargs[arg] network_req = self.new_create_request('networks', data, fmt) if (kwargs.get('set_context') and 'tenant_id' in kwargs): # create a specific auth context for this request network_req.environ['neutron.context'] = context.Context( '', kwargs['tenant_id']) return network_req.get_response(self.api) @mock.patch.object(edge_utils.EdgeManager, '_deploy_edge') def setUp(self, mock_deploy_edge, plugin=PLUGIN_NAME, ext_mgr=None, service_plugins=None): test_utils.override_nsx_ini_test() mock_vcns = mock.patch(vmware.VCNS_NAME, autospec=True) mock_vcns_instance = mock_vcns.start() self.fc2 = fake_vcns.FakeVcns() mock_vcns_instance.return_value = self.fc2 edge_utils.query_dhcp_service_config = mock.Mock(return_value=[]) self.mock_create_dhcp_service = mock.patch("%s.%s" % ( vmware.EDGE_MANAGE_NAME, 'create_dhcp_edge_service')) self.mock_create_dhcp_service.start() mock_update_dhcp_service = mock.patch("%s.%s" % ( vmware.EDGE_MANAGE_NAME, 'update_dhcp_edge_service')) mock_update_dhcp_service.start() mock_delete_dhcp_service = mock.patch("%s.%s" % ( vmware.EDGE_MANAGE_NAME, 'delete_dhcp_edge_service')) mock_delete_dhcp_service.start() super(NsxVPluginV2TestCase, self).setUp(plugin=plugin, ext_mgr=ext_mgr) self.addCleanup(self.fc2.reset_all) plugin_instance = manager.NeutronManager.get_plugin() plugin_instance._get_edge_id_by_rtr_id = mock.Mock() plugin_instance._get_edge_id_by_rtr_id.return_value = False def test_get_vlan_network_name(self): p = manager.NeutronManager.get_plugin() id = uuidutils.generate_uuid() net = {'name': '', 'id': id} expected = id self.assertEqual(expected, p._get_vlan_network_name(net)) net = {'name': 'pele', 'id': id} expected = '%s-%s' % ('pele', id) self.assertEqual(expected, p._get_vlan_network_name(net)) name = 'X' * 500 net = {'name': name, 'id': id} expected = '%s-%s' % (name[:43], id) self.assertEqual(expected, p._get_vlan_network_name(net)) def test_create_port_anticipating_allocation(self): with self.network(shared=True) as network: with self.subnet(network=network, cidr='10.0.0.0/24') as subnet: fixed_ips = [{'subnet_id': subnet['subnet']['id']}, {'subnet_id': subnet['subnet']['id'], 'ip_address': '10.0.0.3'}] self._create_port(self.fmt, network['network']['id'], webob.exc.HTTPCreated.code, fixed_ips=fixed_ips) class TestNetworksV2(test_plugin.TestNetworksV2, NsxVPluginV2TestCase): def test_create_network_vlan_transparent(self): self.skipTest("Currently no support in plugin for this") def _test_create_bridge_network(self, vlan_id=0): net_type = vlan_id and 'vlan' or 'flat' name = 'bridge_net' expected = [('subnets', []), ('name', name), ('admin_state_up', True), ('status', 'ACTIVE'), ('shared', False), (pnet.NETWORK_TYPE, net_type), (pnet.PHYSICAL_NETWORK, 'tzuuid'), (pnet.SEGMENTATION_ID, vlan_id)] providernet_args = {pnet.NETWORK_TYPE: net_type, pnet.PHYSICAL_NETWORK: 'tzuuid'} if vlan_id: providernet_args[pnet.SEGMENTATION_ID] = vlan_id with self.network(name=name, providernet_args=providernet_args, arg_list=(pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK, pnet.SEGMENTATION_ID)) as net: for k, v in expected: self.assertEqual(net['network'][k], v) def test_create_bridge_network(self): self._test_create_bridge_network() def test_create_bridge_vlan_network(self): self._test_create_bridge_network(vlan_id=123) def test_create_bridge_vlan_network_outofrange_returns_400(self): with testlib_api.ExpectedException( webob.exc.HTTPClientError) as ctx_manager: self._test_create_bridge_network(vlan_id=5000) self.assertEqual(ctx_manager.exception.code, 400) def test_create_external_portgroup_network(self): name = 'ext_net' expected = [('subnets', []), ('name', name), ('admin_state_up', True), ('status', 'ACTIVE'), ('shared', False), (external_net.EXTERNAL, True), (pnet.NETWORK_TYPE, 'portgroup'), (pnet.PHYSICAL_NETWORK, 'tzuuid')] providernet_args = {pnet.NETWORK_TYPE: 'portgroup', pnet.PHYSICAL_NETWORK: 'tzuuid', external_net.EXTERNAL: True} with self.network(name=name, providernet_args=providernet_args, arg_list=(pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK, external_net.EXTERNAL)) as net: for k, v in expected: self.assertEqual(net['network'][k], v) def test_delete_network_after_removing_subnet(self): gateway_ip = '10.0.0.1' cidr = '10.0.0.0/24' fmt = 'json' # Create new network res = self._create_network(fmt=fmt, name='net', admin_state_up=True) network = self.deserialize(fmt, res) subnet = self._make_subnet(fmt, network, gateway_ip, cidr, ip_version=4) req = self.new_delete_request('subnets', subnet['subnet']['id']) sub_del_res = req.get_response(self.api) self.assertEqual(sub_del_res.status_int, 204) req = self.new_delete_request('networks', network['network']['id']) net_del_res = req.get_response(self.api) self.assertEqual(net_del_res.status_int, 204) def test_list_networks_with_shared(self): with self.network(name='net1'): with self.network(name='net2', shared=True): req = self.new_list_request('networks') res = self.deserialize('json', req.get_response(self.api)) self.assertEqual(len(res['networks']), 2) req_2 = self.new_list_request('networks') req_2.environ['neutron.context'] = context.Context('', 'somebody') res = self.deserialize('json', req_2.get_response(self.api)) # tenant must see a single network self.assertEqual(len(res['networks']), 1) def test_create_network_name_exceeds_40_chars(self): name = 'this_is_a_network_whose_name_is_longer_than_40_chars' with self.network(name=name) as net: # Assert neutron name is not truncated self.assertEqual(net['network']['name'], name) def test_update_network_with_admin_false(self): data = {'network': {'admin_state_up': False}} with self.network() as net: plugin = manager.NeutronManager.get_plugin() self.assertRaises(NotImplementedError, plugin.update_network, context.get_admin_context(), net['network']['id'], data) def test_create_extend_dvs_provider_network(self): name = 'provider_net' expected = [('subnets', []), ('name', name), ('admin_state_up', True), ('status', 'ACTIVE'), ('shared', False), (pnet.NETWORK_TYPE, 'flat'), (pnet.PHYSICAL_NETWORK, 'dvs-uuid')] providernet_args = {pnet.NETWORK_TYPE: 'flat', pnet.PHYSICAL_NETWORK: 'dvs-uuid'} with self.network(name=name, providernet_args=providernet_args, arg_list=(pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK)) as net: for k, v in expected: self.assertEqual(net['network'][k], v) def test_create_same_vlan_network_with_different_dvs(self): name = 'dvs-provider-net' expected = [('subnets', []), ('name', name), ('admin_state_up', True), ('status', 'ACTIVE'), ('shared', False), (pnet.NETWORK_TYPE, 'vlan'), (pnet.SEGMENTATION_ID, 43), (pnet.PHYSICAL_NETWORK, 'dvs-uuid-1')] providernet_args = {pnet.NETWORK_TYPE: 'vlan', pnet.SEGMENTATION_ID: 43, pnet.PHYSICAL_NETWORK: 'dvs-uuid-1'} with self.network(name=name, providernet_args=providernet_args, arg_list=(pnet.NETWORK_TYPE, pnet.SEGMENTATION_ID, pnet.PHYSICAL_NETWORK)) as net: for k, v in expected: self.assertEqual(net['network'][k], v) expected_same_vlan = [(pnet.NETWORK_TYPE, 'vlan'), (pnet.SEGMENTATION_ID, 43), (pnet.PHYSICAL_NETWORK, 'dvs-uuid-2')] providernet_args_1 = {pnet.NETWORK_TYPE: 'vlan', pnet.SEGMENTATION_ID: 43, pnet.PHYSICAL_NETWORK: 'dvs-uuid-2'} with self.network(name=name, providernet_args=providernet_args_1, arg_list=(pnet.NETWORK_TYPE, pnet.SEGMENTATION_ID, pnet.PHYSICAL_NETWORK)) as net1: for k, v in expected_same_vlan: self.assertEqual(net1['network'][k], v) def test_create_vxlan_with_tz_provider_network(self): name = 'provider_net_vxlan' expected = [('subnets', []), ('name', name), ('admin_state_up', True), ('status', 'ACTIVE'), ('shared', False), (pnet.NETWORK_TYPE, 'vxlan'), (pnet.PHYSICAL_NETWORK, 'vdnscope-2')] providernet_args = {pnet.NETWORK_TYPE: 'vxlan', pnet.PHYSICAL_NETWORK: 'vdnscope-2'} with self.network(name=name, providernet_args=providernet_args, arg_list=(pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK)) as net: for k, v in expected: self.assertEqual(net['network'][k], v) class TestVnicIndex(NsxVPluginV2TestCase, test_vnic_index.VnicIndexDbTestCase): def test_update_port_twice_with_the_same_index(self): """Tests that updates which does not modify the port vnic index association do not produce any errors """ with self.subnet() as subnet: with self.port(subnet=subnet) as port: res = self._port_index_update(port['port']['id'], 2) self.assertEqual(2, res['port'][ext_vnic_idx.VNIC_INDEX]) res = self._port_index_update(port['port']['id'], 2) self.assertEqual(2, res['port'][ext_vnic_idx.VNIC_INDEX]) class TestPortsV2(NsxVPluginV2TestCase, test_plugin.TestPortsV2, test_bindings.PortBindingsTestCase, test_bindings.PortBindingsHostTestCaseMixin, test_bindings.PortBindingsVnicTestCaseMixin): VIF_TYPE = nsx_constants.VIF_TYPE_DVS HAS_PORT_FILTER = True def test_update_port_mac_v6_slaac(self): self.skipTest('No DHCP v6 Support yet') def test_update_port_invalid_fixed_ip_address_v6_slaac(self): self.skipTest('No DHCP v6 Support yet') def test_update_port_excluding_ipv6_slaac_subnet_from_fixed_ips(self): self.skipTest('No DHCP v6 Support yet') def test_requested_subnet_id_v6_slaac(self): self.skipTest('No DHCP v6 Support yet') def test_ip_allocation_for_ipv6_subnet_slaac_address_mode(self): self.skipTest('No DHCP v6 Support yet') def test_requested_fixed_ip_address_v6_slaac_router_iface(self): self.skipTest('No DHCP v6 Support yet') def test_update_port_with_ipv6_slaac_subnet_in_fixed_ips(self): self.skipTest('No DHCP v6 Support yet') def test_requested_invalid_fixed_ip_address_v6_slaac(self): self.skipTest('No DHCP v6 Support yet') def test_delete_port_with_ipv6_slaac_address(self): self.skipTest('No DHCP v6 Support yet') def test_ip_allocation_for_ipv6_2_subnet_slaac_mode(self): self.skipTest('No DHCP v6 Support yet') def _test_create_port_with_ipv6_subnet_in_fixed_ips(self, addr_mode, ipv6_pd=False): self.skipTest('No DHCP v6 Support yet') def test_create_port_json(self): keys = [('admin_state_up', True), ('status', self.port_create_status)] with self.port(name='myname') as port: for k, v in keys: self.assertEqual(port['port'][k], v) self.assertIn('mac_address', port['port']) ips = port['port']['fixed_ips'] self.assertEqual(len(ips), 1) self.assertEqual(ips[0]['ip_address'], '10.0.0.3') self.assertEqual('myname', port['port']['name']) def test_list_ports(self): # for this test we need to enable overlapping ips cfg.CONF.set_default('allow_overlapping_ips', True) with self.subnet(enable_dhcp=False) as subnet,\ self.port(subnet) as port1,\ self.port(subnet) as port2,\ self.port(subnet) as port3: self._test_list_resources('port', [port1, port2, port3]) def test_list_ports_public_network(self): with self.network(shared=True) as network: with self.subnet(network, enable_dhcp=False) as subnet,\ self.port(subnet, tenant_id='tenant_1') as port1,\ self.port(subnet, tenant_id='tenant_2') as port2: # Admin request - must return both ports self._test_list_resources('port', [port1, port2]) # Tenant_1 request - must return single port q_context = context.Context('', 'tenant_1') self._test_list_resources('port', [port1], neutron_context=q_context) # Tenant_2 request - must return single port q_context = context.Context('', 'tenant_2') self._test_list_resources('port', [port2], neutron_context=q_context) def test_list_ports_with_pagination_emulated(self): helper_patcher = mock.patch( 'neutron.api.v2.base.Controller._get_pagination_helper', new=test_plugin._fake_get_pagination_helper) helper_patcher.start() cfg.CONF.set_default('allow_overlapping_ips', True) with self.subnet(enable_dhcp=False) as subnet,\ self.port(subnet, mac_address='00:00:00:00:00:01') as port1,\ self.port(subnet, mac_address='00:00:00:00:00:02') as port2,\ self.port(subnet, mac_address='00:00:00:00:00:03') as port3: self._test_list_with_pagination('port', (port1, port2, port3), ('mac_address', 'asc'), 2, 2) def test_list_ports_with_pagination_native(self): if self._skip_native_pagination: self.skipTest("Skip test for not implemented pagination feature") cfg.CONF.set_default('allow_overlapping_ips', True) with self.subnet(enable_dhcp=False) as subnet,\ self.port(subnet, mac_address='00:00:00:00:00:01') as port1,\ self.port(subnet, mac_address='00:00:00:00:00:02') as port2,\ self.port(subnet, mac_address='00:00:00:00:00:03') as port3: self._test_list_with_pagination('port', (port1, port2, port3), ('mac_address', 'asc'), 2, 2) def test_list_ports_with_sort_emulated(self): helper_patcher = mock.patch( 'neutron.api.v2.base.Controller._get_sorting_helper', new=test_plugin._fake_get_sorting_helper) helper_patcher.start() cfg.CONF.set_default('allow_overlapping_ips', True) with self.subnet(enable_dhcp=False) as subnet,\ self.port(subnet, admin_state_up='True', mac_address='00:00:00:00:00:01') as port1,\ self.port(subnet, admin_state_up='False', mac_address='00:00:00:00:00:02') as port2,\ self.port(subnet, admin_state_up='False', mac_address='00:00:00:00:00:03') as port3: self._test_list_with_sort('port', (port3, port2, port1), [('admin_state_up', 'asc'), ('mac_address', 'desc')]) def test_list_ports_with_sort_native(self): if self._skip_native_sorting: self.skipTest("Skip test for not implemented sorting feature") cfg.CONF.set_default('allow_overlapping_ips', True) with self.subnet(enable_dhcp=False) as subnet,\ self.port(subnet, admin_state_up='True', mac_address='00:00:00:00:00:01') as port1,\ self.port(subnet, admin_state_up='False', mac_address='00:00:00:00:00:02') as port2,\ self.port(subnet, admin_state_up='False', mac_address='00:00:00:00:00:03') as port3: self._test_list_with_sort('port', (port3, port2, port1), [('admin_state_up', 'asc'), ('mac_address', 'desc')]) def test_update_port_delete_ip(self): # This test case overrides the default because the nsx plugin # implements port_security/security groups and it is not allowed # to remove an ip address from a port unless the security group # is first removed. with self.subnet() as subnet: with self.port(subnet=subnet) as port: data = {'port': {'admin_state_up': False, 'fixed_ips': [], secgrp.SECURITYGROUPS: []}} req = self.new_update_request('ports', data, port['port']['id']) res = self.deserialize('json', req.get_response(self.api)) self.assertEqual(res['port']['admin_state_up'], data['port']['admin_state_up']) self.assertEqual(res['port']['fixed_ips'], data['port']['fixed_ips']) def _update_port_index(self, port_id, device_id, index): data = {'port': {'device_id': device_id, 'vnic_index': index}} req = self.new_update_request('ports', data, port_id) res = self.deserialize('json', req.get_response(self.api)) return res @mock.patch.object(edge_utils.EdgeManager, 'delete_dhcp_binding') def test_update_port_index(self, delete_dhcp_binding): q_context = context.Context('', 'tenant_1') device_id = _uuid() with self.subnet() as subnet: with self.port(subnet=subnet, device_id=device_id, device_owner='compute:None') as port: self.assertIsNone(port['port']['vnic_index']) vnic_index = 3 res = self._update_port_index( port['port']['id'], device_id, vnic_index) self.assertEqual(vnic_index, res['port']['vnic_index']) # Updating the vnic_index to None implies the vnic does # no longer obtain the addresses associated with this port, # we need to inactivate previous addresses configurations for # this vnic in the context of this network spoofguard policy. self.fc2.inactivate_vnic_assigned_addresses = ( mock.Mock().inactivate_vnic_assigned_addresses) policy_id = nsxv_db.get_spoofguard_policy_id( q_context.session, port['port']['network_id']) res = self._update_port_index(port['port']['id'], '', None) vnic_id = '%s.%03d' % (device_id, vnic_index) (self.fc2.inactivate_vnic_assigned_addresses. assert_called_once_with(policy_id, vnic_id)) self.assertTrue(delete_dhcp_binding.called) def test_update_port_with_compute_device_owner(self): """ Test that DHCP binding is created when ports 'device_owner' is updated to compute, for example when attaching an interface to a instance with existing port. """ with self.port() as port: with mock.patch(PLUGIN_NAME + '._create_dhcp_static_binding'): update = {'port': {'device_owner'}} self.new_update_request('ports', update, port['port']['id']) def test_create_port_public_network_with_ip(self): with self.network(shared=True) as network: with self.subnet(enable_dhcp=False, network=network, cidr='10.0.0.0/24') as subnet: keys = [('admin_state_up', True), ('status', self.port_create_status), ('fixed_ips', [{'subnet_id': subnet['subnet']['id'], 'ip_address': '10.0.0.2'}])] port_res = self._create_port(self.fmt, network['network']['id'], webob.exc.HTTPCreated.code, tenant_id='another_tenant', set_context=True) port = self.deserialize(self.fmt, port_res) for k, v in keys: self.assertEqual(port['port'][k], v) self.assertIn('mac_address', port['port']) self._delete('ports', port['port']['id']) def test_no_more_port_exception(self): with self.subnet(enable_dhcp=False, cidr='10.0.0.0/31', gateway_ip=None) as subnet: id = subnet['subnet']['network_id'] res = self._create_port(self.fmt, id) data = self.deserialize(self.fmt, res) msg = str(n_exc.IpAddressGenerationFailure(net_id=id)) self.assertEqual(data['NeutronError']['message'], msg) self.assertEqual(res.status_int, webob.exc.HTTPConflict.code) def test_ports_vif_host(self): cfg.CONF.set_default('allow_overlapping_ips', True) host_arg = {portbindings.HOST_ID: self.hostname} with self.subnet(enable_dhcp=False) as subnet,\ self.port(subnet, name='name1', arg_list=(portbindings.HOST_ID,), **host_arg),\ self.port(subnet, name='name2'): ctx = context.get_admin_context() ports = self._list('ports', neutron_context=ctx)['ports'] self.assertEqual(2, len(ports)) for port in ports: if port['name'] == 'name1': self._check_response_portbindings_host(port) else: self.assertFalse(port[portbindings.HOST_ID]) # By default user is admin - now test non admin user ctx = context.Context(user_id=None, tenant_id=self._tenant_id, is_admin=False, read_deleted="no") ports = self._list('ports', neutron_context=ctx)['ports'] self.assertEqual(2, len(ports)) for non_admin_port in ports: self._check_response_no_portbindings_host(non_admin_port) def test_ports_vif_host_update(self): cfg.CONF.set_default('allow_overlapping_ips', True) host_arg = {portbindings.HOST_ID: self.hostname} with self.subnet(enable_dhcp=False) as subnet,\ self.port(subnet, name='name1', arg_list=(portbindings.HOST_ID,), **host_arg) as port1,\ self.port(subnet, name='name2') as port2: data = {'port': {portbindings.HOST_ID: 'testhosttemp'}} req = self.new_update_request( 'ports', data, port1['port']['id']) req.get_response(self.api) req = self.new_update_request( 'ports', data, port2['port']['id']) ctx = context.get_admin_context() req.get_response(self.api) ports = self._list('ports', neutron_context=ctx)['ports'] self.assertEqual(2, len(ports)) for port in ports: self.assertEqual('testhosttemp', port[portbindings.HOST_ID]) def test_ports_vif_details(self): plugin = manager.NeutronManager.get_plugin() cfg.CONF.set_default('allow_overlapping_ips', True) with self.subnet(enable_dhcp=False) as subnet,\ self.port(subnet), self.port(subnet): ctx = context.get_admin_context() ports = plugin.get_ports(ctx) self.assertEqual(len(ports), 2) for port in ports: self._check_response_portbindings(port) # By default user is admin - now test non admin user ctx = self._get_non_admin_context() ports = self._list('ports', neutron_context=ctx)['ports'] self.assertEqual(len(ports), 2) for non_admin_port in ports: self._check_response_no_portbindings(non_admin_port) def test_ports_vnic_type(self): cfg.CONF.set_default('allow_overlapping_ips', True) vnic_arg = {portbindings.VNIC_TYPE: self.vnic_type} with self.subnet(enable_dhcp=False) as subnet,\ self.port(subnet, name='name1', arg_list=(portbindings.VNIC_TYPE,), **vnic_arg),\ self.port(subnet, name='name2'): ctx = context.get_admin_context() ports = self._list('ports', neutron_context=ctx)['ports'] self.assertEqual(2, len(ports)) for port in ports: if port['name'] == 'name1': self._check_response_portbindings_vnic_type(port) else: self.assertEqual(portbindings.VNIC_NORMAL, port[portbindings.VNIC_TYPE]) # By default user is admin - now test non admin user ctx = context.Context(user_id=None, tenant_id=self._tenant_id, is_admin=False, read_deleted="no") ports = self._list('ports', neutron_context=ctx)['ports'] self.assertEqual(2, len(ports)) for non_admin_port in ports: self._check_response_portbindings_vnic_type(non_admin_port) def test_ports_vnic_type_list(self): cfg.CONF.set_default('allow_overlapping_ips', True) vnic_arg = {portbindings.VNIC_TYPE: self.vnic_type} with self.subnet(enable_dhcp=False) as subnet,\ self.port(subnet, name='name1', arg_list=(portbindings.VNIC_TYPE,), **vnic_arg) as port1,\ self.port(subnet, name='name2') as port2,\ self.port(subnet, name='name3', arg_list=(portbindings.VNIC_TYPE,), **vnic_arg) as port3: self._test_list_resources('port', (port1, port2, port3), query_params='%s=%s' % ( portbindings.VNIC_TYPE, self.vnic_type)) def test_range_allocation(self): with self.subnet(enable_dhcp=False, gateway_ip='10.0.0.3', cidr='10.0.0.0/29') as subnet: kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id']}, {'subnet_id': subnet['subnet']['id']}, {'subnet_id': subnet['subnet']['id']}, {'subnet_id': subnet['subnet']['id']}, {'subnet_id': subnet['subnet']['id']}]} net_id = subnet['subnet']['network_id'] res = self._create_port(self.fmt, net_id=net_id, **kwargs) port = self.deserialize(self.fmt, res) ips = port['port']['fixed_ips'] self.assertEqual(len(ips), 5) alloc = ['10.0.0.1', '10.0.0.2', '10.0.0.4', '10.0.0.5', '10.0.0.6'] for ip in ips: self.assertIn(ip['ip_address'], alloc) self.assertEqual(ip['subnet_id'], subnet['subnet']['id']) alloc.remove(ip['ip_address']) self.assertEqual(len(alloc), 0) self._delete('ports', port['port']['id']) with self.subnet(enable_dhcp=False, gateway_ip='11.0.0.6', cidr='11.0.0.0/29') as subnet: kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id']}, {'subnet_id': subnet['subnet']['id']}, {'subnet_id': subnet['subnet']['id']}, {'subnet_id': subnet['subnet']['id']}, {'subnet_id': subnet['subnet']['id']}]} net_id = subnet['subnet']['network_id'] res = self._create_port(self.fmt, net_id=net_id, **kwargs) port = self.deserialize(self.fmt, res) ips = port['port']['fixed_ips'] self.assertEqual(len(ips), 5) alloc = ['11.0.0.1', '11.0.0.2', '11.0.0.3', '11.0.0.4', '11.0.0.5'] for ip in ips: self.assertIn(ip['ip_address'], alloc) self.assertEqual(ip['subnet_id'], subnet['subnet']['id']) alloc.remove(ip['ip_address']) self.assertEqual(len(alloc), 0) self._delete('ports', port['port']['id']) def test_requested_duplicate_ip(self): with self.subnet(enable_dhcp=False) as subnet: with self.port(subnet=subnet) as port: ips = port['port']['fixed_ips'] self.assertEqual(len(ips), 1) self.assertEqual(ips[0]['ip_address'], '10.0.0.2') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) # Check configuring of duplicate IP kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id'], 'ip_address': ips[0]['ip_address']}]} net_id = port['port']['network_id'] res = self._create_port(self.fmt, net_id=net_id, **kwargs) self.assertEqual(res.status_int, webob.exc.HTTPConflict.code) def test_requested_invalid_fixed_ips(self): with self.subnet(enable_dhcp=False) as subnet: with self.port(subnet=subnet) as port: ips = port['port']['fixed_ips'] self.assertEqual(len(ips), 1) self.assertEqual(ips[0]['ip_address'], '10.0.0.2') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) # Test invalid subnet_id kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id']}, {'subnet_id': '00000000-ffff-ffff-ffff-000000000000'}]} net_id = port['port']['network_id'] res = self._create_port(self.fmt, net_id=net_id, **kwargs) port2 = self.deserialize(self.fmt, res) self.assertEqual(res.status_int, webob.exc.HTTPNotFound.code) # Test invalid IP address on specified subnet_id kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id'], 'ip_address': '1.1.1.1'}]} net_id = port['port']['network_id'] res = self._create_port(self.fmt, net_id=net_id, **kwargs) port2 = self.deserialize(self.fmt, res) self.assertEqual(res.status_int, webob.exc.HTTPClientError.code) # Test invalid addresses - IP's not on subnet or network # address or broadcast address bad_ips = ['1.1.1.1', '10.0.0.0', '10.0.0.255'] net_id = port['port']['network_id'] for ip in bad_ips: kwargs = {"fixed_ips": [{'ip_address': ip}]} res = self._create_port(self.fmt, net_id=net_id, **kwargs) port2 = self.deserialize(self.fmt, res) self.assertEqual(res.status_int, webob.exc.HTTPClientError.code) # Enable allocation of gateway address kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id'], 'ip_address': '10.0.0.1'}]} net_id = port['port']['network_id'] res = self._create_port(self.fmt, net_id=net_id, **kwargs) port2 = self.deserialize(self.fmt, res) ips = port2['port']['fixed_ips'] self.assertEqual(len(ips), 1) self.assertEqual(ips[0]['ip_address'], '10.0.0.1') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) self._delete('ports', port2['port']['id']) def test_requested_split(self): with self.subnet(enable_dhcp=False) as subnet: with self.port(subnet=subnet) as port: ports_to_delete = [] ips = port['port']['fixed_ips'] self.assertEqual(len(ips), 1) self.assertEqual(ips[0]['ip_address'], '10.0.0.2') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) # Allocate specific IP kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id'], 'ip_address': '10.0.0.5'}]} net_id = port['port']['network_id'] res = self._create_port(self.fmt, net_id=net_id, **kwargs) port2 = self.deserialize(self.fmt, res) ports_to_delete.append(port2) ips = port2['port']['fixed_ips'] self.assertEqual(len(ips), 1) self.assertEqual(ips[0]['ip_address'], '10.0.0.5') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) # Allocate specific IP's allocated = ['10.0.0.3', '10.0.0.4', '10.0.0.6'] for a in allocated: res = self._create_port(self.fmt, net_id=net_id) port2 = self.deserialize(self.fmt, res) ports_to_delete.append(port2) ips = port2['port']['fixed_ips'] self.assertEqual(len(ips), 1) self.assertEqual(ips[0]['ip_address'], a) self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) for p in ports_to_delete: self._delete('ports', p['port']['id']) def test_requested_ips_only(self): with self.subnet(enable_dhcp=False) as subnet: with self.port(subnet=subnet) as port: ips = port['port']['fixed_ips'] self.assertEqual(len(ips), 1) self.assertEqual(ips[0]['ip_address'], '10.0.0.2') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) ips_only = ['10.0.0.18', '10.0.0.20', '10.0.0.22', '10.0.0.21', '10.0.0.3', '10.0.0.17', '10.0.0.19'] ports_to_delete = [] for i in ips_only: kwargs = {"fixed_ips": [{'ip_address': i}]} net_id = port['port']['network_id'] res = self._create_port(self.fmt, net_id=net_id, **kwargs) port = self.deserialize(self.fmt, res) ports_to_delete.append(port) ips = port['port']['fixed_ips'] self.assertEqual(len(ips), 1) self.assertEqual(ips[0]['ip_address'], i) self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) for p in ports_to_delete: self._delete('ports', p['port']['id']) def test_requested_subnet_id(self): with self.subnet(enable_dhcp=False) as subnet: with self.port(subnet=subnet) as port: ips = port['port']['fixed_ips'] self.assertEqual(len(ips), 1) self.assertEqual(ips[0]['ip_address'], '10.0.0.2') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) # Request an IP from specific subnet kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id']}]} net_id = port['port']['network_id'] res = self._create_port(self.fmt, net_id=net_id, **kwargs) port2 = self.deserialize(self.fmt, res) ips = port2['port']['fixed_ips'] self.assertEqual(len(ips), 1) self.assertEqual(ips[0]['ip_address'], '10.0.0.3') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) self._delete('ports', port2['port']['id']) def test_requested_subnet_id_v4_and_v6(self): with self.subnet(enable_dhcp=False) as subnet: # Get an IPv4 and IPv6 address tenant_id = subnet['subnet']['tenant_id'] net_id = subnet['subnet']['network_id'] res = self._create_subnet( self.fmt, tenant_id=tenant_id, net_id=net_id, cidr='2607:f0d0:1002:51::/124', ip_version=6, gateway_ip=attributes.ATTR_NOT_SPECIFIED, enable_dhcp=False) subnet2 = self.deserialize(self.fmt, res) kwargs = {"fixed_ips": [{'subnet_id': subnet['subnet']['id']}, {'subnet_id': subnet2['subnet']['id']}]} res = self._create_port(self.fmt, net_id=net_id, **kwargs) port3 = self.deserialize(self.fmt, res) ips = port3['port']['fixed_ips'] self.assertEqual(len(ips), 2) self.assertEqual(ips[0]['ip_address'], '10.0.0.2') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) self.assertEqual(ips[1]['ip_address'], '2607:f0d0:1002:51::2') self.assertEqual(ips[1]['subnet_id'], subnet2['subnet']['id']) res = self._create_port(self.fmt, net_id=net_id) port4 = self.deserialize(self.fmt, res) # Check that a v4 and a v6 address are allocated ips = port4['port']['fixed_ips'] self.assertEqual(len(ips), 2) self.assertEqual(ips[0]['ip_address'], '10.0.0.3') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) self.assertEqual(ips[1]['ip_address'], '2607:f0d0:1002:51::3') self.assertEqual(ips[1]['subnet_id'], subnet2['subnet']['id']) self._delete('ports', port3['port']['id']) self._delete('ports', port4['port']['id']) def test_update_port_add_additional_ip(self): """Test update of port with additional IP.""" with self.subnet(enable_dhcp=False) as subnet: with self.port(subnet=subnet) as port: data = {'port': {'admin_state_up': False, 'fixed_ips': [{'subnet_id': subnet['subnet']['id']}, {'subnet_id': subnet['subnet']['id']}]}} req = self.new_update_request('ports', data, port['port']['id']) res = self.deserialize(self.fmt, req.get_response(self.api)) self.assertEqual(res['port']['admin_state_up'], data['port']['admin_state_up']) ips = res['port']['fixed_ips'] self.assertEqual(len(ips), 2) self.assertEqual(ips[0]['ip_address'], '10.0.0.3') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) self.assertEqual(ips[1]['ip_address'], '10.0.0.4') self.assertEqual(ips[1]['subnet_id'], subnet['subnet']['id']) def test_update_port_update_ip(self): """Test update of port IP. Check that a configured IP 10.0.0.2 is replaced by 10.0.0.10. """ with self.subnet(enable_dhcp=False) as subnet: with self.port(subnet=subnet) as port: ips = port['port']['fixed_ips'] self.assertEqual(len(ips), 1) self.assertEqual(ips[0]['ip_address'], '10.0.0.2') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) data = {'port': {'fixed_ips': [{'subnet_id': subnet['subnet']['id'], 'ip_address': "10.0.0.10"}]}} req = self.new_update_request('ports', data, port['port']['id']) res = self.deserialize(self.fmt, req.get_response(self.api)) ips = res['port']['fixed_ips'] self.assertEqual(len(ips), 1) self.assertEqual(ips[0]['ip_address'], '10.0.0.10') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) def test_update_port_update_ip_address_only(self): with self.subnet(enable_dhcp=False) as subnet: with self.port(subnet=subnet) as port: ips = port['port']['fixed_ips'] self.assertEqual(len(ips), 1) self.assertEqual(ips[0]['ip_address'], '10.0.0.2') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) data = {'port': {'fixed_ips': [{'subnet_id': subnet['subnet']['id'], 'ip_address': "10.0.0.10"}, {'ip_address': "10.0.0.2"}]}} req = self.new_update_request('ports', data, port['port']['id']) res = self.deserialize(self.fmt, req.get_response(self.api)) ips = res['port']['fixed_ips'] self.assertEqual(len(ips), 2) self.assertEqual(ips[0]['ip_address'], '10.0.0.2') self.assertEqual(ips[0]['subnet_id'], subnet['subnet']['id']) self.assertEqual(ips[1]['ip_address'], '10.0.0.10') self.assertEqual(ips[1]['subnet_id'], subnet['subnet']['id']) def test_requested_subnet_id_v4_and_v6_slaac(self): self.skipTest('No DHCP v6 Support yet') def test_create_router_port_ipv4_and_ipv6_slaac_no_fixed_ips(self): self.skipTest('No DHCP v6 Support yet') def test_create_port_with_multiple_ipv4_and_ipv6_subnets(self): # This test should fail as the NSX-v plugin should cause Neutron to # return a 400 status code with testlib_api.ExpectedException( webob.exc.HTTPClientError) as ctx_manager: super(TestPortsV2, self).\ test_create_port_with_multiple_ipv4_and_ipv6_subnets() self.assertEqual(ctx_manager.exception.code, 400) class TestSubnetsV2(NsxVPluginV2TestCase, test_plugin.TestSubnetsV2): def setUp(self, plugin=PLUGIN_NAME, ext_mgr=None, service_plugins=None): super(TestSubnetsV2, self).setUp() self.context = context.get_admin_context() def test__subnet_ipv6_not_supported(self): with self.network() as network: data = {'subnet': {'network_id': network['network']['id'], 'gateway': 'fe80::1', 'cidr': '2607:f0d0:1002:51::/64', 'ip_version': '6', 'tenant_id': network['network']['tenant_id']}} subnet_req = self.new_create_request('subnets', data) res = subnet_req.get_response(self.api) self.assertEqual(res.status_int, webob.exc.HTTPClientError.code) def test_create_subnet_ipv6_pd_gw_values(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_ipv6_slaac_with_port_on_network(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_ipv6_slaac_with_snat_intf_on_network(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_dhcpv6_stateless_with_port_on_network(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_ipv6_slaac_with_dhcp_port_on_network(self): self.skipTest('No DHCP v6 Support yet') def test_delete_subnet_ipv6_slaac_port_exists(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_ipv6_slaac_with_router_intf_on_network(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_ipv6_out_of_cidr_lla(self): self.skipTest('No DHCP v6 Support yet') def test_update_subnet_inconsistent_ipv6_hostroute_dst_v4(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_only_ip_version_v6(self): self.skipTest('No DHCP v6 Support yet') def test_update_subnet_ipv6_address_mode_fails(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_with_v6_allocation_pool(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_with_v6_pd_allocation_pool(self): self.skipTest('No DHCP v6 Support yet') def test_update_subnet_ipv6_ra_mode_fails(self): self.skipTest('No DHCP v6 Support yet') def test_delete_subnet_ipv6_slaac_router_port_exists(self): self.skipTest('No DHCP v6 Support yet') def test_update_subnet_inconsistent_ipv6_hostroute_np_v4(self): self.skipTest('No DHCP v6 Support yet') def test_update_subnet_inconsistent_ipv6_gatewayv4(self): self.skipTest('No DHCP v6 Support yet') def test_update_subnet_ipv6_attributes_fails(self): self.skipTest('No DHCP v6 Support yet') def test_update_subnet_ipv6_cannot_disable_dhcp(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_V6_pd_slaac(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_V6_pd_stateless(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_V6_pd_statefull(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_V6_pd_no_mode(self): self.skipTest('No DHCP v6 Support yet') def _create_subnet_bulk(self, fmt, number, net_id, name, ip_version=4, **kwargs): base_data = {'subnet': {'network_id': net_id, 'ip_version': ip_version, 'enable_dhcp': False, 'tenant_id': self._tenant_id}} # auto-generate cidrs as they should not overlap overrides = dict((k, v) for (k, v) in zip(range(number), [{'cidr': "10.0.%s.0/24" % num} for num in range(number)])) kwargs.update({'override': overrides}) return self._create_bulk(fmt, number, 'subnet', base_data, **kwargs) def test_create_subnet_with_two_host_routes(self): self.skipTest("Skip test for not implemented host_routes feature") def test_delete_subnet_with_route(self): self.skipTest("Skip test for not implemented host_routes feature") def test_update_subnet_adding_additional_host_routes_and_dns(self): self.skipTest("Skip test for not implemented host_routes feature") def test_delete_subnet_with_dns_and_route(self): self.skipTest("Skip test for not implemented host_routes feature") def test_update_subnet_route(self): self.skipTest("Skip test for not implemented host_routes feature") def test_update_subnet_route_to_None(self): self.skipTest("Skip test for not implemented host_routes feature") def test_create_subnet_with_one_host_route(self): self.skipTest("Skip test for not implemented host_routes feature") def test_create_subnet_nonzero_cidr(self): awkward_cidrs = [{'nonezero': '10.129.122.5/8', 'corrected': '10.0.0.0/8'}, {'nonezero': '11.129.122.5/15', 'corrected': '11.128.0.0/15'}, {'nonezero': '12.129.122.5/16', 'corrected': '12.129.0.0/16'}, {'nonezero': '13.129.122.5/18', 'corrected': '13.129.64.0/18'}, {'nonezero': '14.129.122.5/22', 'corrected': '14.129.120.0/22'}, {'nonezero': '15.129.122.5/24', 'corrected': '15.129.122.0/24'}, {'nonezero': '16.129.122.5/28', 'corrected': '16.129.122.0/28'}, ] for cidr in awkward_cidrs: with self.subnet(enable_dhcp=False, cidr=cidr['nonezero']) as subnet: # the API should accept and correct these cidrs for users self.assertEqual(cidr['corrected'], subnet['subnet']['cidr']) with self.subnet(enable_dhcp=False, cidr='17.129.122.5/32', gateway_ip=None) as subnet: self.assertEqual('17.129.122.5/32', subnet['subnet']['cidr']) def test_create_subnet_ipv6_attributes(self): # Expected to fail for now as we don't support IPv6 for NSXv cidr = "fe80::/80" with testlib_api.ExpectedException( webob.exc.HTTPClientError) as ctx_manager: self._test_create_subnet(cidr=cidr) self.assertEqual(ctx_manager.exception.code, 400) def test_create_subnet_with_different_dhcp_server(self): self.mock_create_dhcp_service.stop() name = 'dvs-provider-net' providernet_args = {pnet.NETWORK_TYPE: 'vlan', pnet.SEGMENTATION_ID: 43, pnet.PHYSICAL_NETWORK: 'dvs-uuid'} with self.network(name=name, do_delete=False, providernet_args=providernet_args, arg_list=(pnet.NETWORK_TYPE, pnet.SEGMENTATION_ID, pnet.PHYSICAL_NETWORK)) as net: self._test_create_subnet(network=net, cidr='10.0.0.0/24') dhcp_router_id = (vcns_const.DHCP_EDGE_PREFIX + net['network']['id'])[:36] dhcp_server_id = nsxv_db.get_nsxv_router_binding( self.context.session, dhcp_router_id)['edge_id'] providernet_args_1 = {pnet.NETWORK_TYPE: 'vlan', pnet.SEGMENTATION_ID: 43, pnet.PHYSICAL_NETWORK: 'dvs-uuid-1'} with self.network(name=name, do_delete=False, providernet_args=providernet_args_1, arg_list=(pnet.NETWORK_TYPE, pnet.SEGMENTATION_ID, pnet.PHYSICAL_NETWORK)) as net1: self._test_create_subnet(network=net1, cidr='10.0.1.0/24') router_id = (vcns_const.DHCP_EDGE_PREFIX + net1['network']['id'])[:36] dhcp_server_id_1 = nsxv_db.get_nsxv_router_binding( self.context.session, router_id)['edge_id'] self.assertNotEqual(dhcp_server_id, dhcp_server_id_1) def test_create_subnet_with_different_dhcp_by_flat_net(self): self.mock_create_dhcp_service.stop() name = 'flat-net' providernet_args = {pnet.NETWORK_TYPE: 'flat', pnet.PHYSICAL_NETWORK: 'dvs-uuid'} with self.network(name=name, do_delete=False, providernet_args=providernet_args, arg_list=(pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK)) as net: self._test_create_subnet(network=net, cidr='10.0.0.0/24') dhcp_router_id = (vcns_const.DHCP_EDGE_PREFIX + net['network']['id'])[:36] dhcp_server_id = nsxv_db.get_nsxv_router_binding( self.context.session, dhcp_router_id)['edge_id'] providernet_args_1 = {pnet.NETWORK_TYPE: 'flat', pnet.PHYSICAL_NETWORK: 'dvs-uuid'} with self.network(name=name, do_delete=False, providernet_args=providernet_args_1, arg_list=(pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK)) as net1: self._test_create_subnet(network=net1, cidr='10.0.1.0/24') router_id = (vcns_const.DHCP_EDGE_PREFIX + net1['network']['id'])[:36] dhcp_server_id_1 = nsxv_db.get_nsxv_router_binding( self.context.session, router_id)['edge_id'] self.assertNotEqual(dhcp_server_id, dhcp_server_id_1) def test_create_subnet_ipv6_slaac_with_db_reference_error(self): self.skipTest('Currently not support') def test_create_subnet_ipv6_gw_values(self): # This test should fail with response code 400 as IPv6 subnets with # DHCP are not supported by this plugin with testlib_api.ExpectedException( webob.exc.HTTPClientError) as ctx_manager: super(TestSubnetsV2, self).test_create_subnet_ipv6_gw_values() self.assertEqual(ctx_manager.exception.code, 400) def test_create_subnet_only_ip_version_v6_old(self): self.skipTest('Currently not supported') class TestSubnetPoolsV2(NsxVPluginV2TestCase, test_plugin.TestSubnetsV2): def setUp(self, plugin=PLUGIN_NAME, ext_mgr=None, service_plugins=None): super(TestSubnetPoolsV2, self).setUp() self.context = context.get_admin_context() def test_create_subnet_V6_pd_stateless(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_V6_pd_slaac(self): self.skipTest('No DHCP v6 Support yet') def test_create_subnet_dhcpv6_stateless_with_port_on_network(self): self.skipTest('Not supported') def test_create_subnet_ipv6_gw_values(self): self.skipTest('Not supported') def test_create_subnet_ipv6_out_of_cidr_lla(self): self.skipTest('Not supported') def test_create_subnet_ipv6_pd_gw_values(self): self.skipTest('Not supported') def test_create_subnet_ipv6_slaac_with_db_reference_error(self): self.skipTest('Not supported') def test_create_subnet_ipv6_slaac_with_dhcp_port_on_network(self): self.skipTest('Not supported') def test_create_subnet_ipv6_slaac_with_port_on_network(self): self.skipTest('Not supported') def test_create_subnet_ipv6_slaac_with_router_intf_on_network(self): self.skipTest('Not supported') def test_create_subnet_ipv6_slaac_with_snat_intf_on_network(self): self.skipTest('Not supported') def test_create_subnet_only_ip_version_v6(self): self.skipTest('Not supported') def test_create_subnet_with_one_host_route(self): self.skipTest("Skip test for not implemented host_routes feature") def test_create_subnet_with_two_host_routes(self): self.skipTest("Skip test for not implemented host_routes feature") def test_create_subnet_with_v6_allocation_pool(self): self.skipTest('Not supported') def test_create_subnet_with_v6_pd_allocation_pool(self): self.skipTest('Not supported') def test_delete_subnet_ipv6_slaac_port_exists(self): self.skipTest('Not supported') def test_delete_subnet_ipv6_slaac_router_port_exists(self): self.skipTest('Not supported') def test_delete_subnet_with_dns_and_route(self): self.skipTest("Skip test for not implemented host_routes feature") def test_delete_subnet_with_route(self): self.skipTest("Skip test for not implemented host_routes feature") def test_update_subnet_adding_additional_host_routes_and_dns(self): self.skipTest("Skip test for not implemented host_routes feature") def test_update_subnet_inconsistent_ipv6_gatewayv4(self): self.skipTest('Not supported') def test_update_subnet_inconsistent_ipv6_hostroute_dst_v4(self): self.skipTest('Not supported') def test_update_subnet_inconsistent_ipv6_hostroute_np_v4(self): self.skipTest('Not supported') def test_update_subnet_ipv6_address_mode_fails(self): self.skipTest('Not supported') def test_update_subnet_ipv6_attributes_fails(self): self.skipTest('Not supported') def test_update_subnet_ipv6_cannot_disable_dhcp(self): self.skipTest('Not supported') def test_update_subnet_ipv6_ra_mode_fails(self): self.skipTest('Not supported') def test_update_subnet_route(self): self.skipTest("Skip test for not implemented host_routes feature") def test_update_subnet_route_to_None(self): self.skipTest("Skip test for not implemented host_routes feature") def test_create_subnet_only_ip_version_v6_old(self): self.skipTest('Currently not supported') class TestBasicGet(test_plugin.TestBasicGet, NsxVPluginV2TestCase): pass class TestV2HTTPResponse(test_plugin.TestV2HTTPResponse, NsxVPluginV2TestCase): pass class TestL3ExtensionManager(object): def get_resources(self): # Simulate extension of L3 attribute map # First apply attribute extensions for key in l3.RESOURCE_ATTRIBUTE_MAP.keys(): l3.RESOURCE_ATTRIBUTE_MAP[key].update( l3_ext_gw_mode.EXTENDED_ATTRIBUTES_2_0.get(key, {})) l3.RESOURCE_ATTRIBUTE_MAP[key].update( dist_router.EXTENDED_ATTRIBUTES_2_0.get(key, {})) l3.RESOURCE_ATTRIBUTE_MAP[key].update( router_type.EXTENDED_ATTRIBUTES_2_0.get(key, {})) l3.RESOURCE_ATTRIBUTE_MAP[key].update( router_size.EXTENDED_ATTRIBUTES_2_0.get(key, {})) # Finally add l3 resources to the global attribute map attributes.RESOURCE_ATTRIBUTE_MAP.update( l3.RESOURCE_ATTRIBUTE_MAP) return l3.L3.get_resources() def get_actions(self): return [] def get_request_extensions(self): return [] def backup_l3_attribute_map(): """Return a backup of the original l3 attribute map.""" return dict((res, attrs.copy()) for (res, attrs) in six.iteritems(l3.RESOURCE_ATTRIBUTE_MAP)) def restore_l3_attribute_map(map_to_restore): """Ensure changes made by fake ext mgrs are reverted.""" l3.RESOURCE_ATTRIBUTE_MAP = map_to_restore class L3NatTest(test_l3_plugin.L3BaseForIntTests, NsxVPluginV2TestCase): def _restore_l3_attribute_map(self): l3.RESOURCE_ATTRIBUTE_MAP = self._l3_attribute_map_bk def setUp(self, plugin=PLUGIN_NAME, ext_mgr=None, service_plugins=None): self._l3_attribute_map_bk = {} for item in l3.RESOURCE_ATTRIBUTE_MAP: self._l3_attribute_map_bk[item] = ( l3.RESOURCE_ATTRIBUTE_MAP[item].copy()) cfg.CONF.set_override('task_status_check_interval', 200, group="nsxv") cfg.CONF.set_override('api_extensions_path', vmware.NSXEXT_PATH) l3_attribute_map_bk = backup_l3_attribute_map() self.addCleanup(restore_l3_attribute_map, l3_attribute_map_bk) ext_mgr = ext_mgr or TestL3ExtensionManager() super(L3NatTest, self).setUp( plugin=plugin, ext_mgr=ext_mgr, service_plugins=service_plugins) self.plugin_instance = manager.NeutronManager.get_plugin() self._plugin_name = "%s.%s" % ( self.plugin_instance.__module__, self.plugin_instance.__class__.__name__) self._plugin_class = self.plugin_instance.__class__ def tearDown(self): plugin = manager.NeutronManager.get_plugin() _manager = plugin.nsx_v.task_manager # wait max ~10 seconds for all tasks to be finished for i in range(100): if not _manager.has_pending_task(): break greenthread.sleep(0.1) if _manager.has_pending_task(): _manager.show_pending_tasks() raise Exception(_("Tasks not completed")) _manager.stop() # Ensure the manager thread has been stopped self.assertIsNone(_manager._thread) super(L3NatTest, self).tearDown() def _create_l3_ext_network(self, vlan_id=None): name = 'l3_ext_net' return self.network(name=name, router__external=True) def _create_router(self, fmt, tenant_id, name=None, admin_state_up=None, set_context=False, arg_list=None, **kwargs): data = {'router': {'tenant_id': tenant_id}} if name: data['router']['name'] = name if admin_state_up: data['router']['admin_state_up'] = admin_state_up for arg in (('admin_state_up', 'tenant_id') + (arg_list or ())): # Arg must be present and not empty if kwargs.get(arg): data['router'][arg] = kwargs[arg] router_req = self.new_create_request('routers', data, fmt) if set_context and tenant_id: # create a specific auth context for this request router_req.environ['neutron.context'] = context.Context( '', tenant_id) return router_req.get_response(self.ext_api) def _make_router(self, fmt, tenant_id, name=None, admin_state_up=None, external_gateway_info=None, set_context=False, arg_list=None, **kwargs): if external_gateway_info: arg_list = ('external_gateway_info', ) + (arg_list or ()) res = self._create_router(fmt, tenant_id, name, admin_state_up, set_context, arg_list=arg_list, external_gateway_info=external_gateway_info, **kwargs) return self.deserialize(fmt, res) @contextlib.contextmanager def router(self, name=None, admin_state_up=True, fmt=None, tenant_id=_uuid(), external_gateway_info=None, set_context=False, **kwargs): # avoid name duplication of edge if not name: name = _uuid() router = self._make_router(fmt or self.fmt, tenant_id, name, admin_state_up, external_gateway_info, set_context, **kwargs) yield router def _recursive_sort_list(self, lst): sorted_list = [] for ele in lst: if isinstance(ele, list): sorted_list.append(self._recursive_sort_list(ele)) elif isinstance(ele, dict): sorted_list.append(self._recursive_sort_dict(ele)) else: sorted_list.append(ele) return sorted(sorted_list) def _recursive_sort_dict(self, dct): sorted_dict = {} for k, v in dct.items(): if isinstance(v, list): sorted_dict[k] = self._recursive_sort_list(v) elif isinstance(v, dict): sorted_dict[k] = self._recursive_sort_dict(v) else: sorted_dict[k] = v return sorted_dict def _update_router_enable_snat(self, router_id, network_id, enable_snat): return self._update('routers', router_id, {'router': {'external_gateway_info': {'network_id': network_id, 'enable_snat': enable_snat}}}) class L3NatTestCaseBase(test_l3_plugin.L3NatTestCaseMixin): def test_floatingip_multi_external_one_internal(self): with self.subnet(cidr="10.0.0.0/24", enable_dhcp=False) as ext1,\ self.subnet(cidr="11.0.0.0/24", enable_dhcp=False) as ext2,\ self.subnet(cidr="12.0.0.0/24", enable_dhcp=False) as inter1: network_ex_id1 = ext1['subnet']['network_id'] network_ex_id2 = ext2['subnet']['network_id'] self._set_net_external(network_ex_id1) self._set_net_external(network_ex_id2) r2i_fixed_ips = [{'ip_address': '12.0.0.2'}] with self.router(no_delete=True) as r1,\ self.router(no_delete=True) as r2,\ self.port(subnet=inter1, fixed_ips=r2i_fixed_ips) as r2i: self._add_external_gateway_to_router( r1['router']['id'], network_ex_id1) self._router_interface_action('add', r1['router']['id'], inter1['subnet']['id'], None) self._add_external_gateway_to_router( r2['router']['id'], network_ex_id2) self._router_interface_action('add', r2['router']['id'], None, r2i['port']['id']) with self.port(subnet=inter1, fixed_ips=[{'ip_address': '12.0.0.3'}] ) as private_port: fp1 = self._make_floatingip(self.fmt, network_ex_id1, private_port['port']['id'], floating_ip='10.0.0.3') fp2 = self._make_floatingip(self.fmt, network_ex_id2, private_port['port']['id'], floating_ip='11.0.0.3') self.assertEqual(fp1['floatingip']['router_id'], r1['router']['id']) self.assertEqual(fp2['floatingip']['router_id'], r2['router']['id']) def test_create_floatingip_with_multisubnet_id(self): with self.network() as network: self._set_net_external(network['network']['id']) with self.subnet(network, enable_dhcp=False, cidr='10.0.12.0/24') as subnet1: with self.subnet(network, enable_dhcp=False, cidr='10.0.13.0/24') as subnet2: with self.router(): res = self._create_floatingip( self.fmt, subnet1['subnet']['network_id'], subnet_id=subnet1['subnet']['id']) fip1 = self.deserialize(self.fmt, res) res = self._create_floatingip( self.fmt, subnet1['subnet']['network_id'], subnet_id=subnet2['subnet']['id']) fip2 = self.deserialize(self.fmt, res) self.assertTrue( fip1['floatingip']['floating_ip_address'].startswith('10.0.12')) self.assertTrue( fip2['floatingip']['floating_ip_address'].startswith('10.0.13')) def test_create_floatingip_with_wrong_subnet_id(self): with self.network() as network1: self._set_net_external(network1['network']['id']) with self.subnet(network1, enable_dhcp=False, cidr='10.0.12.0/24') as subnet1: with self.network() as network2: self._set_net_external(network2['network']['id']) with self.subnet(network2, enable_dhcp=False, cidr='10.0.13.0/24') as subnet2: with self.router(): res = self._create_floatingip( self.fmt, subnet1['subnet']['network_id'], subnet_id=subnet2['subnet']['id']) self.assertEqual(res.status_int, webob.exc.HTTPBadRequest.code) @mock.patch.object(edge_utils, "update_firewall") def test_router_set_gateway_with_nosnat(self, mock): expected_fw = [{'action': 'allow', 'enabled': True, 'source_ip_address': [], 'destination_ip_address': []}] nosnat_fw = [{'action': 'allow', 'enabled': True, 'source_vnic_groups': ["external"], 'destination_ip_address': []}] with self.router() as r1,\ self.subnet() as ext_subnet,\ self.subnet(cidr='11.0.0.0/24') as s1,\ self.subnet(cidr='12.0.0.0/24') as s2: self._set_net_external(ext_subnet['subnet']['network_id']) self._router_interface_action( 'add', r1['router']['id'], s1['subnet']['id'], None) expected_fw[0]['source_ip_address'] = ['11.0.0.0/24'] expected_fw[0]['destination_ip_address'] = ['11.0.0.0/24'] fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual(self._recursive_sort_list(expected_fw), self._recursive_sort_list(fw_rules)) self._add_external_gateway_to_router( r1['router']['id'], ext_subnet['subnet']['network_id']) fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual(self._recursive_sort_list(expected_fw), self._recursive_sort_list(fw_rules)) self._update_router_enable_snat( r1['router']['id'], ext_subnet['subnet']['network_id'], False) nosnat_fw[0]['destination_ip_address'] = ['11.0.0.0/24'] fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual( self._recursive_sort_list(expected_fw + nosnat_fw), self._recursive_sort_list(fw_rules)) self._router_interface_action('add', r1['router']['id'], s2['subnet']['id'], None) expected_fw[0]['source_ip_address'] = ['12.0.0.0/24', '11.0.0.0/24'] expected_fw[0]['destination_ip_address'] = ['12.0.0.0/24', '11.0.0.0/24'] nosnat_fw[0]['destination_ip_address'] = ['11.0.0.0/24', '12.0.0.0/24'] fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual( self._recursive_sort_list(expected_fw + nosnat_fw), self._recursive_sort_list(fw_rules)) self._router_interface_action('remove', r1['router']['id'], s1['subnet']['id'], None) expected_fw[0]['source_ip_address'] = ['12.0.0.0/24'] expected_fw[0]['destination_ip_address'] = ['12.0.0.0/24'] nosnat_fw[0]['destination_ip_address'] = ['12.0.0.0/24'] fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual( self._recursive_sort_list(expected_fw + nosnat_fw), self._recursive_sort_list(fw_rules)) self._update_router_enable_snat( r1['router']['id'], ext_subnet['subnet']['network_id'], True) fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual( self._recursive_sort_list(expected_fw), self._recursive_sort_list(fw_rules)) self._router_interface_action('remove', r1['router']['id'], s2['subnet']['id'], None) self._remove_external_gateway_from_router( r1['router']['id'], ext_subnet['subnet']['network_id']) def test_router_add_interface_port_bad_tenant_returns_404(self): self.skipTest('TBD') def test_router_add_interface_subnet_with_bad_tenant_returns_404(self): self.skipTest('TBD') def test_create_floatingip_ipv6_only_network_returns_400(self): with self.subnet(cidr="2001:db8::/48", ip_version=6, enable_dhcp=False) as public_sub: self._set_net_external(public_sub['subnet']['network_id']) res = self._create_floatingip( self.fmt, public_sub['subnet']['network_id']) self.assertEqual(res.status_int, webob.exc.HTTPBadRequest.code) def test_create_floatingip_ipv6_and_ipv4_network_creates_ipv4(self): with self.network() as n,\ self.subnet(cidr="2001:db8::/48", ip_version=6, network=n, enable_dhcp=False),\ self.subnet(cidr="192.168.1.0/24", ip_version=4, network=n, enable_dhcp=False): self._set_net_external(n['network']['id']) fip = self._make_floatingip(self.fmt, n['network']['id']) self.assertEqual(fip['floatingip']['floating_ip_address'], '192.168.1.2') def test_create_floatingip_with_assoc_to_ipv6_subnet(self): with self.subnet() as public_sub: self._set_net_external(public_sub['subnet']['network_id']) with self.subnet(cidr="2001:db8::/48", ip_version=6, enable_dhcp=False) as private_sub: with self.port(subnet=private_sub) as private_port: res = self._create_floatingip( self.fmt, public_sub['subnet']['network_id'], port_id=private_port['port']['id']) self.assertEqual(res.status_int, webob.exc.HTTPBadRequest.code) def test_create_floatingip_with_assoc_to_ipv4_and_ipv6_port(self): with self.network() as n,\ self.subnet(cidr='10.0.0.0/24', network=n) as s4,\ self.subnet(cidr='2001:db8::/64', ip_version=6, network=n, enable_dhcp=False),\ self.port(subnet=s4) as p: self.assertEqual(len(p['port']['fixed_ips']), 2) ipv4_address = next(i['ip_address'] for i in p['port']['fixed_ips'] if netaddr.IPAddress(i['ip_address']).version == 4) with self.floatingip_with_assoc(port_id=p['port']['id']) as fip: self.assertEqual(fip['floatingip']['fixed_ip_address'], ipv4_address) floating_ip = netaddr.IPAddress( fip['floatingip']['floating_ip_address']) self.assertEqual(floating_ip.version, 4) def test_router_add_interface_multiple_ipv6_subnets_same_net(self): """Test router-interface-add for multiple ipv6 subnets on a network. Verify that adding multiple ipv6 subnets from the same network to a router places them all on the same router interface. """ with self.router() as r, self.network() as n: with (self.subnet(network=n, cidr='fd00::1/64', enable_dhcp=False, ip_version=6) ) as s1, self.subnet(network=n, cidr='fd01::1/64', ip_version=6, enable_dhcp=False) as s2: body = self._router_interface_action('add', r['router']['id'], s1['subnet']['id'], None) pid1 = body['port_id'] body = self._router_interface_action('add', r['router']['id'], s2['subnet']['id'], None) pid2 = body['port_id'] self.assertEqual(pid1, pid2) port = self._show('ports', pid1) self.assertEqual(2, len(port['port']['fixed_ips'])) port_subnet_ids = [fip['subnet_id'] for fip in port['port']['fixed_ips']] self.assertIn(s1['subnet']['id'], port_subnet_ids) self.assertIn(s2['subnet']['id'], port_subnet_ids) self._router_interface_action('remove', r['router']['id'], s1['subnet']['id'], None) self._router_interface_action('remove', r['router']['id'], s2['subnet']['id'], None) def test_router_add_interface_multiple_ipv6_subnets_different_net(self): """Test router-interface-add for ipv6 subnets on different networks. Verify that adding multiple ipv6 subnets from different networks to a router places them on different router interfaces. """ with self.router() as r, self.network() as n1, self.network() as n2: with (self.subnet(network=n1, cidr='fd00::1/64', enable_dhcp=False, ip_version=6) ) as s1, self.subnet(network=n2, cidr='fd01::1/64', ip_version=6, enable_dhcp=False) as s2: body = self._router_interface_action('add', r['router']['id'], s1['subnet']['id'], None) pid1 = body['port_id'] body = self._router_interface_action('add', r['router']['id'], s2['subnet']['id'], None) pid2 = body['port_id'] self.assertNotEqual(pid1, pid2) self._router_interface_action('remove', r['router']['id'], s1['subnet']['id'], None) self._router_interface_action('remove', r['router']['id'], s2['subnet']['id'], None) def test_router_add_interface_ipv6_port_existing_network_returns_400(self): """Ensure unique IPv6 router ports per network id. Adding a router port containing one or more IPv6 subnets with the same network id as an existing router port should fail. This is so there is no ambiguity regarding on which port to add an IPv6 subnet when executing router-interface-add with a subnet and no port. """ with self.network() as n, self.router() as r: with self.subnet(network=n, cidr='fd00::/64', ip_version=6, enable_dhcp=False) as s1, ( self.subnet(network=n, cidr='fd01::/64', ip_version=6, enable_dhcp=False)) as s2: with self.port(subnet=s1) as p: self._router_interface_action('add', r['router']['id'], s2['subnet']['id'], None) exp_code = webob.exc.HTTPBadRequest.code self._router_interface_action('add', r['router']['id'], None, p['port']['id'], expected_code=exp_code) self._router_interface_action('remove', r['router']['id'], s2['subnet']['id'], None) def test_router_add_interface_multiple_ipv6_subnet_port(self): """A port with multiple IPv6 subnets can be added to a router Create a port with multiple associated IPv6 subnets and attach it to a router. The action should succeed. """ with self.network() as n, self.router() as r: with self.subnet(network=n, cidr='fd00::/64', ip_version=6, enable_dhcp=False) as s1, ( self.subnet(network=n, cidr='fd01::/64', ip_version=6, enable_dhcp=False)) as s2: fixed_ips = [{'subnet_id': s1['subnet']['id']}, {'subnet_id': s2['subnet']['id']}] with self.port(subnet=s1, fixed_ips=fixed_ips) as p: self._router_interface_action('add', r['router']['id'], None, p['port']['id']) self._router_interface_action('remove', r['router']['id'], None, p['port']['id']) def test_router_add_interface_ipv6_subnet_without_gateway_ip(self): with self.router() as r: with self.subnet(ip_version=6, cidr='fe80::/64', gateway_ip=None, enable_dhcp=False) as s: error_code = webob.exc.HTTPBadRequest.code self._router_interface_action('add', r['router']['id'], s['subnet']['id'], None, expected_code=error_code) def test_router_delete_ipv6_slaac_subnet_inuse_returns_409(self): self.skipTest('No DHCP v6 Support yet') def test_router_delete_dhcpv6_stateless_subnet_inuse_returns_409(self): self.skipTest('No DHCP v6 Support yet') def test_router_add_iface_ipv6_ext_ra_subnet_returns_400(self): self.skipTest('No DHCP v6 Support yet') def test_router_remove_ipv6_subnet_from_interface(self): self.skipTest('No DHCP v6 Support yet') def test_router_update_gateway_add_multiple_prefixes_ipv6(self): self.skipTest('No DHCP v6 Support yet') def test_router_update_gateway_upon_subnet_create_ipv6(self): self.skipTest('No DHCP v6 Support yet') def test_router_update_gateway_upon_subnet_create_max_ips_ipv6(self): self.skipTest('No DHCP v6 Support yet') class IPv6ExpectedFailuresTestMixin(object): def test_router_add_interface_ipv6_subnet(self): # Expect a 400 statuc code as IPv6 subnets w/DHCP are not supported with testlib_api.ExpectedException( webob.exc.HTTPClientError) as ctx_manager: super(IPv6ExpectedFailuresTestMixin, self).\ test_router_add_interface_ipv6_subnet() self.assertEqual(ctx_manager.exception.code, 400) def test_router_add_iface_ipv6_ext_ra_subnet_returns_400(self): # This returns a 400 too, but as an exception is raised the response # code need to be asserted differently with testlib_api.ExpectedException( webob.exc.HTTPClientError) as ctx_manager: super(IPv6ExpectedFailuresTestMixin, self).\ test_router_add_iface_ipv6_ext_ra_subnet_returns_400() self.assertEqual(ctx_manager.exception.code, 400) def test_router_add_gateway_multiple_subnets_ipv6(self): # Expect a 400 statuc code as IPv6 subnets w/DHCP are not supported with testlib_api.ExpectedException( webob.exc.HTTPClientError) as ctx_manager: super(IPv6ExpectedFailuresTestMixin, self).\ test_router_add_gateway_multiple_subnets_ipv6() self.assertEqual(ctx_manager.exception.code, 400) class TestExclusiveRouterTestCase(L3NatTest, L3NatTestCaseBase, test_l3_plugin.L3NatDBIntTestCase, IPv6ExpectedFailuresTestMixin, NsxVPluginV2TestCase): def setUp(self, plugin=PLUGIN_NAME, ext_mgr=None, service_plugins=None): super(TestExclusiveRouterTestCase, self).setUp( plugin=plugin, ext_mgr=ext_mgr, service_plugins=service_plugins) self.plugin_instance.nsx_v.is_subnet_in_use = mock.Mock() self.plugin_instance.nsx_v.is_subnet_in_use.return_value = False def _create_router(self, fmt, tenant_id, name=None, admin_state_up=None, set_context=False, arg_list=None, **kwargs): data = {'router': {'tenant_id': tenant_id}} if name: data['router']['name'] = name if admin_state_up: data['router']['admin_state_up'] = admin_state_up for arg in (('admin_state_up', 'tenant_id') + (arg_list or ())): # Arg must be present and not empty if arg in kwargs and kwargs[arg]: data['router'][arg] = kwargs[arg] data['router']['router_type'] = kwargs.get('router_type', 'exclusive') router_req = self.new_create_request('routers', data, fmt) if set_context and tenant_id: # create a specific auth context for this request router_req.environ['neutron.context'] = context.Context( '', tenant_id) return router_req.get_response(self.ext_api) def _test_create_l3_ext_network(self, vlan_id=0): name = 'l3_ext_net' expected = [('subnets', []), ('name', name), ('admin_state_up', True), ('status', 'ACTIVE'), ('shared', False), (external_net.EXTERNAL, True)] with self._create_l3_ext_network(vlan_id) as net: for k, v in expected: self.assertEqual(net['network'][k], v) def test_create_router_fail_at_the_backend(self): p = manager.NeutronManager.get_plugin() edge_manager = p.edge_manager with mock.patch.object(edge_manager, 'create_lrouter', side_effect=[n_exc.NeutronException]): router = {'router': {'admin_state_up': True, 'name': 'e161be1d-0d0d-4046-9823-5a593d94f72c', 'tenant_id': context.get_admin_context().tenant_id, 'router_type': 'exclusive'}} self.assertRaises(n_exc.NeutronException, p.create_router, context.get_admin_context(), router) self._test_list_resources('router', ()) def test_create_l3_ext_network_with_dhcp(self): with self._create_l3_ext_network() as net: with testlib_api.ExpectedException( webob.exc.HTTPClientError) as ctx_manager: with self.subnet(network=net): self.assertEqual(ctx_manager.exception.code, 400) def test_create_l3_ext_network_without_vlan(self): self._test_create_l3_ext_network() def _test_router_create_with_gwinfo_and_l3_ext_net(self, vlan_id=None, validate_ext_gw=False): with self._create_l3_ext_network(vlan_id) as net: with self.subnet(network=net, enable_dhcp=False) as s: data = {'router': {'tenant_id': 'whatever'}} data['router']['name'] = 'router1' data['router']['external_gateway_info'] = { 'network_id': s['subnet']['network_id']} router_req = self.new_create_request('routers', data, self.fmt) res = router_req.get_response(self.ext_api) router = self.deserialize(self.fmt, res) self.assertEqual( s['subnet']['network_id'], (router['router']['external_gateway_info'] ['network_id'])) if validate_ext_gw: pass def test_router_create_with_gwinfo_and_l3_ext_net(self): self._test_router_create_with_gwinfo_and_l3_ext_net() def test_router_create_with_gwinfo_and_l3_ext_net_with_vlan(self): self._test_router_create_with_gwinfo_and_l3_ext_net(444) def test_router_create_with_different_sizes(self): data = {'router': { 'tenant_id': 'whatever', 'name': 'test_router', 'router_type': 'exclusive'}} for size in ['compact', 'large', 'xlarge', 'quadlarge']: data['router']['router_size'] = size router_req = self.new_create_request('routers', data, self.fmt) res = router_req.get_response(self.ext_api) router = self.deserialize(self.fmt, res) self.assertEqual(size, router['router']['router_size']) def test_router_create_overriding_default_edge_size(self): data = {'router': { 'tenant_id': 'whatever', 'name': 'test_router', 'router_type': 'exclusive'}} cfg.CONF.set_override('exclusive_router_appliance_size', 'xlarge', group='nsxv') router_req = self.new_create_request('routers', data, self.fmt) res = router_req.get_response(self.ext_api) router = self.deserialize(self.fmt, res) self.assertEqual('xlarge', router['router']['router_size']) def test_router_add_gateway_invalid_network_returns_404(self): # NOTE(salv-orlando): This unit test has been overridden # as the nsx plugin support the ext_gw_mode extension # which mandates an uuid for the external network identifier with self.router() as r: self._add_external_gateway_to_router( r['router']['id'], uuidutils.generate_uuid(), expected_code=webob.exc.HTTPNotFound.code) def _test_router_update_gateway_on_l3_ext_net(self, vlan_id=None, validate_ext_gw=False, distributed=False): with self.router( arg_list=('distributed',), distributed=distributed) as r: with self.subnet() as s1: with self._create_l3_ext_network(vlan_id) as net: with self.subnet(network=net, enable_dhcp=False) as s2: self._set_net_external(s1['subnet']['network_id']) try: self._add_external_gateway_to_router( r['router']['id'], s1['subnet']['network_id']) body = self._show('routers', r['router']['id']) net_id = (body['router'] ['external_gateway_info']['network_id']) self.assertEqual(net_id, s1['subnet']['network_id']) # Plug network with external mapping self._set_net_external(s2['subnet']['network_id']) self._add_external_gateway_to_router( r['router']['id'], s2['subnet']['network_id']) body = self._show('routers', r['router']['id']) net_id = (body['router'] ['external_gateway_info']['network_id']) self.assertEqual(net_id, s2['subnet']['network_id']) if validate_ext_gw: pass finally: # Cleanup self._remove_external_gateway_from_router( r['router']['id'], s2['subnet']['network_id']) def test_router_update_gateway_on_l3_ext_net(self): self._test_router_update_gateway_on_l3_ext_net() def test_router_update_gateway_on_l3_ext_net_with_vlan(self): self._test_router_update_gateway_on_l3_ext_net(444) def test_router_update_gateway_with_existing_floatingip(self): with self._create_l3_ext_network() as net: with self.subnet(network=net, enable_dhcp=False) as subnet: with self.floatingip_with_assoc() as fip: self._add_external_gateway_to_router( fip['floatingip']['router_id'], subnet['subnet']['network_id'], expected_code=webob.exc.HTTPConflict.code) def test_router_list_by_tenant_id(self): with self.router(), self.router(): with self.router(tenant_id='custom') as router: self._test_list_resources('router', [router], query_params="tenant_id=custom") def test_create_l3_ext_network_with_vlan(self): self._test_create_l3_ext_network(666) def test_floatingip_with_assoc_fails(self): self._test_floatingip_with_assoc_fails( self._plugin_name + '._check_and_get_fip_assoc') def test_floatingip_with_invalid_create_port(self): self._test_floatingip_with_invalid_create_port(self._plugin_name) def test_floatingip_update(self): super(TestExclusiveRouterTestCase, self).test_floatingip_update( constants.FLOATINGIP_STATUS_DOWN) def test_floatingip_disassociate(self): with self.port() as p: private_sub = {'subnet': {'id': p['port']['fixed_ips'][0]['subnet_id']}} with self.floatingip_no_assoc(private_sub) as fip: self.assertEqual(fip['floatingip']['status'], constants.FLOATINGIP_STATUS_DOWN) port_id = p['port']['id'] body = self._update('floatingips', fip['floatingip']['id'], {'floatingip': {'port_id': port_id}}) self.assertEqual(body['floatingip']['port_id'], port_id) self.assertEqual(body['floatingip']['status'], constants.FLOATINGIP_STATUS_ACTIVE) # Disassociate body = self._update('floatingips', fip['floatingip']['id'], {'floatingip': {'port_id': None}}) body = self._show('floatingips', fip['floatingip']['id']) self.assertIsNone(body['floatingip']['port_id']) self.assertIsNone(body['floatingip']['fixed_ip_address']) self.assertEqual(body['floatingip']['status'], constants.FLOATINGIP_STATUS_DOWN) def test_update_floatingip_with_edge_router_update_failure(self): p = manager.NeutronManager.get_plugin() with self.subnet() as subnet,\ self.port(subnet=subnet) as p1,\ self.port(subnet=subnet) as p2: p1_id = p1['port']['id'] p2_id = p2['port']['id'] with self.floatingip_with_assoc(port_id=p1_id) as fip: with self._mock_edge_router_update_with_exception(): self.assertRaises(object, p.update_floatingip, context.get_admin_context(), fip['floatingip']['id'], floatingip={'floatingip': {'port_id': p2_id}}) res = self._list( 'floatingips', query_params="port_id=%s" % p1_id) self.assertEqual(len(res['floatingips']), 1) res = self._list( 'floatingips', query_params="port_id=%s" % p2_id) self.assertEqual(len(res['floatingips']), 0) def test_create_floatingip_with_edge_router_update_failure(self): p = manager.NeutronManager.get_plugin() with self.subnet(cidr='200.0.0.0/24') as public_sub: public_network_id = public_sub['subnet']['network_id'] self._set_net_external(public_network_id) with self.port() as private_port: port_id = private_port['port']['id'] tenant_id = private_port['port']['tenant_id'] subnet_id = private_port['port']['fixed_ips'][0]['subnet_id'] with self.router() as r: self._add_external_gateway_to_router( r['router']['id'], public_sub['subnet']['network_id']) self._router_interface_action('add', r['router']['id'], subnet_id, None) floatingip = {'floatingip': { 'tenant_id': tenant_id, 'floating_network_id': public_network_id, 'port_id': port_id}} with self._mock_edge_router_update_with_exception(): self.assertRaises(object, p.create_floatingip, context.get_admin_context(), floatingip=floatingip) res = self._list( 'floatingips', query_params="port_id=%s" % port_id) self.assertEqual(len(res['floatingips']), 0) # Cleanup self._router_interface_action('remove', r['router']['id'], subnet_id, None) self._remove_external_gateway_from_router( r['router']['id'], public_network_id) @contextlib.contextmanager def _mock_edge_router_update_with_exception(self): nsx_router_update = PLUGIN_NAME + '._update_edge_router' with mock.patch(nsx_router_update) as update_edge: update_edge.side_effect = object() yield update_edge @mock.patch.object(edge_utils, "update_firewall") def test_router_interfaces_with_update_firewall(self, mock): s1_cidr = '10.0.0.0/24' s2_cidr = '11.0.0.0/24' with self.router() as r,\ self.subnet(cidr=s1_cidr) as s1,\ self.subnet(cidr=s2_cidr) as s2: self._router_interface_action('add', r['router']['id'], s1['subnet']['id'], None) self._router_interface_action('add', r['router']['id'], s2['subnet']['id'], None) expected_cidrs = [s1_cidr, s2_cidr] expected_fw = [{'action': 'allow', 'enabled': True, 'source_ip_address': expected_cidrs, 'destination_ip_address': expected_cidrs}] fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual(self._recursive_sort_list(expected_fw), self._recursive_sort_list(fw_rules)) self._router_interface_action('remove', r['router']['id'], s1['subnet']['id'], None) self._router_interface_action('remove', r['router']['id'], s2['subnet']['id'], None) @mock.patch.object(edge_utils, "update_firewall") def test_router_interfaces_different_tenants_update_firewall(self, mock): tenant_id = _uuid() other_tenant_id = _uuid() s1_cidr = '10.0.0.0/24' s2_cidr = '11.0.0.0/24' with self.router(tenant_id=tenant_id) as r,\ self.network(tenant_id=tenant_id) as n1,\ self.network(tenant_id=other_tenant_id) as n2,\ self.subnet(network=n1, cidr=s1_cidr) as s1,\ self.subnet(network=n2, cidr=s2_cidr) as s2: self._router_interface_action('add', r['router']['id'], s2['subnet']['id'], None) self._router_interface_action('add', r['router']['id'], s1['subnet']['id'], None, tenant_id=tenant_id) expected_cidrs = [s1_cidr, s2_cidr] expected_fw = [{'action': 'allow', 'enabled': True, 'source_ip_address': expected_cidrs, 'destination_ip_address': expected_cidrs}] fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual(self._recursive_sort_list(expected_fw), self._recursive_sort_list(fw_rules)) self._router_interface_action('remove', r['router']['id'], s1['subnet']['id'], None, tenant_id=tenant_id) self._router_interface_action('remove', r['router']['id'], s2['subnet']['id'], None) expected_fw = [] fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual(expected_fw, fw_rules) def test_delete_ext_net_with_disassociated_floating_ips(self): with self.network() as net: net_id = net['network']['id'] self._set_net_external(net_id) with self.subnet(network=net, enable_dhcp=False): self._make_floatingip(self.fmt, net_id) def test_create_router_gateway_fails(self): self.skipTest('not supported') class ExtGwModeTestCase(NsxVPluginV2TestCase, test_ext_gw_mode.ExtGwModeIntTestCase): pass class NsxVSecurityGroupsTestCase(ext_sg.SecurityGroupDBTestCase): def setUp(self, plugin=PLUGIN_NAME, ext_mgr=None, service_plugins=None): test_utils.override_nsx_ini_test() mock_vcns = mock.patch(vmware.VCNS_NAME, autospec=True) mock_vcns_instance = mock_vcns.start() self.fc2 = fake_vcns.FakeVcns() mock_vcns_instance.return_value = self.fc2 edge_utils.query_dhcp_service_config = mock.Mock(return_value=[]) mock_create_dhcp_service = mock.patch("%s.%s" % ( vmware.EDGE_MANAGE_NAME, 'create_dhcp_edge_service')) mock_create_dhcp_service.start() mock_update_dhcp_service = mock.patch("%s.%s" % ( vmware.EDGE_MANAGE_NAME, 'update_dhcp_edge_service')) mock_update_dhcp_service.start() mock_delete_dhcp_service = mock.patch("%s.%s" % ( vmware.EDGE_MANAGE_NAME, 'delete_dhcp_edge_service')) mock_delete_dhcp_service.start() super(NsxVSecurityGroupsTestCase, self).setUp(plugin=plugin, ext_mgr=ext_mgr) self.plugin = manager.NeutronManager.get_plugin() self.addCleanup(self.fc2.reset_all) class NsxVTestSecurityGroup(ext_sg.TestSecurityGroups, NsxVSecurityGroupsTestCase): @mock.patch.object(edge_utils.EdgeManager, '_deploy_edge') def setUp(self, mock_deploy, plugin=PLUGIN_NAME, ext_mgr=None, service_plugins=None): super(NsxVTestSecurityGroup, self).setUp( plugin=plugin, ext_mgr=ext_mgr, service_plugins=service_plugins) plugin_instance = manager.NeutronManager.get_plugin() plugin_instance._get_edge_id_by_rtr_id = mock.Mock() plugin_instance._get_edge_id_by_rtr_id.return_value = False def test_list_ports_security_group(self): with self.network() as n: with self.subnet(n, enable_dhcp=False): self._create_port(self.fmt, n['network']['id']) req = self.new_list_request('ports') res = req.get_response(self.api) ports = self.deserialize(self.fmt, res) port = ports['ports'][0] self.assertEqual(len(port[secgrp.SECURITYGROUPS]), 1) self._delete('ports', port['id']) def test_vnic_security_group_membership(self): p = manager.NeutronManager.get_plugin() self.fc2.add_member_to_security_group = ( mock.Mock().add_member_to_security_group) self.fc2.remove_member_from_security_group = ( mock.Mock().remove_member_from_security_group) nsx_sg_id = str(self.fc2._securitygroups['ids']) device_id = _uuid() port_index = 0 # The expected vnic-id format by NsxV vnic_id = '%s.%03d' % (device_id, port_index) with self.port(device_id=device_id, device_owner='compute:None') as port: (self.fc2.add_member_to_security_group .assert_called_once_with(p.sg_container_id, nsx_sg_id)) self.fc2.add_member_to_security_group.reset_mock() data = {'port': {'vnic_index': port_index}} self.new_update_request('ports', data, port['port']['id']).get_response(self.api) # The vnic should be added as a member to the nsx-security-groups # which match the port security-groups (self.fc2.add_member_to_security_group .assert_called_once_with(nsx_sg_id, vnic_id)) # The vnic should be removed from the nsx-security-groups which match # the deleted port security-groups #TODO(kobis): Port is not removed automatically # (self.fc2.remove_member_from_security_group # .assert_called_once_with(nsx_sg_id, vnic_id)) def test_skip_duplicate_default_sg_error(self): num_called = [0] original_func = self.plugin.create_security_group def side_effect(context, security_group, default_sg): # can't always raise, or create_security_group will hang self.assertTrue(default_sg) self.assertTrue(num_called[0] < 2) num_called[0] += 1 ret = original_func(context, security_group, default_sg) if num_called[0] == 1: return ret # make another call to cause an exception. # NOTE(yamamoto): raising the exception by ourselves # doesn't update the session state appropriately. self.assertRaises(db_exc.DBDuplicateEntry(), original_func, context, security_group, default_sg) with mock.patch.object(self.plugin, 'create_security_group', side_effect=side_effect): self.plugin.create_network( context.get_admin_context(), {'network': {'name': 'foo', 'admin_state_up': True, 'shared': False, 'tenant_id': 'bar', 'port_security_enabled': True}}) def test_create_secgroup_deleted_upon_fw_section_create_fail(self): _context = context.Context('', 'tenant_id') sg = {'security_group': {'name': 'default', 'tenant_id': 'tenant_id', 'description': ''}} expected_id = str(self.fc2._securitygroups['ids']) with mock.patch.object(self.fc2, 'create_section') as create_section: with mock.patch.object(self.fc2, 'delete_security_group') as delete_sg: create_section.side_effect = webob.exc.HTTPInternalServerError self.assertRaises(webob.exc.HTTPInternalServerError, self.plugin.create_security_group, _context.elevated(), sg, default_sg=True) delete_sg.assert_called_once_with(expected_id) def test_create_security_group_rule_with_specific_id(self): # This test is aimed to test the security-group db mixin pass class TestVdrTestCase(L3NatTest, L3NatTestCaseBase, test_l3_plugin.L3NatDBIntTestCase, IPv6ExpectedFailuresTestMixin, NsxVPluginV2TestCase): def test_create_router_fail_at_the_backend(self): p = manager.NeutronManager.get_plugin() edge_manager = p.edge_manager with mock.patch.object(edge_manager, 'create_lrouter', side_effect=[n_exc.NeutronException]): router = {'router': {'admin_state_up': True, 'name': 'e161be1d-0d0d-4046-9823-5a593d94f72c', 'tenant_id': context.get_admin_context().tenant_id, 'distributed': True}} self.assertRaises(n_exc.NeutronException, p.create_router, context.get_admin_context(), router) self._test_list_resources('router', ()) def test_update_port_device_id_to_different_tenants_router(self): self.skipTest('TBD') def test_router_add_and_remove_gateway_tenant_ctx(self): self.skipTest('TBD') def _create_router(self, fmt, tenant_id, name=None, admin_state_up=None, set_context=False, arg_list=None, **kwargs): data = {'router': {'tenant_id': tenant_id}} if name: data['router']['name'] = name if admin_state_up: data['router']['admin_state_up'] = admin_state_up for arg in (('admin_state_up', 'tenant_id') + (arg_list or ())): # Arg must be present and not empty if arg in kwargs and kwargs[arg]: data['router'][arg] = kwargs[arg] if 'distributed' in kwargs: data['router']['distributed'] = kwargs[arg] else: data['router']['distributed'] = True router_req = self.new_create_request('routers', data, fmt) if set_context and tenant_id: # create a specific auth context for this request router_req.environ['neutron.context'] = context.Context( '', tenant_id) return router_req.get_response(self.ext_api) def _test_router_create_with_distributed(self, dist_input, dist_expected, return_code=201, **kwargs): data = {'tenant_id': 'whatever'} data['name'] = 'router1' data['distributed'] = dist_input for k, v in six.iteritems(kwargs): data[k] = v router_req = self.new_create_request( 'routers', {'router': data}, self.fmt) res = router_req.get_response(self.ext_api) self.assertEqual(return_code, res.status_int) if res.status_int == 201: router = self.deserialize(self.fmt, res) self.assertIn('distributed', router['router']) if dist_input: self.assertNotIn('router_type', router['router']) self.assertEqual(dist_expected, router['router']['distributed']) def test_create_router_fails_with_router_type(self): self._test_router_create_with_distributed(True, True, return_code=400, router_type="shared") def test_router_create_distributed(self): self._test_router_create_with_distributed(True, True) def test_router_create_not_distributed(self): self._test_router_create_with_distributed(False, False) def test_router_create_distributed_unspecified(self): self._test_router_create_with_distributed(None, False) def test_floatingip_with_assoc_fails(self): self._test_floatingip_with_assoc_fails( self._plugin_name + '._check_and_get_fip_assoc') def test_floatingip_update(self): super(TestVdrTestCase, self).test_floatingip_update( constants.FLOATINGIP_STATUS_DOWN) def test_floatingip_with_invalid_create_port(self): self._test_floatingip_with_invalid_create_port(self._plugin_name) def test_router_add_gateway_invalid_network_returns_404(self): with self.router() as r: self._add_external_gateway_to_router( r['router']['id'], uuidutils.generate_uuid(), expected_code=webob.exc.HTTPNotFound.code) def test_router_add_interfaces_with_multiple_subnets_on_same_network(self): with self.router() as r,\ self.network() as n,\ self.subnet(network=n) as s1,\ self.subnet(network=n, cidr='11.0.0.0/24') as s2: self._router_interface_action('add', r['router']['id'], s1['subnet']['id'], None) err_code = webob.exc.HTTPBadRequest.code self._router_interface_action('add', r['router']['id'], s2['subnet']['id'], None, err_code) self._router_interface_action('remove', r['router']['id'], s1['subnet']['id'], None) def test_delete_ext_net_with_disassociated_floating_ips(self): with self.network() as net: net_id = net['network']['id'] self._set_net_external(net_id) with self.subnet(network=net, enable_dhcp=False): self._make_floatingip(self.fmt, net_id) def test_router_add_interface_multiple_ipv4_subnets(self): self.skipTest('TBD') def test_router_remove_ipv6_subnet_from_interface(self): self.skipTest('TBD') def test_router_add_interface_multiple_ipv6_subnets_same_net(self): self.skipTest('TBD') def test_router_add_interface_multiple_ipv6_subnets_different_net(self): self.skipTest('TBD') def test_create_router_gateway_fails(self): self.skipTest('not supported') class TestNSXvAllowedAddressPairs(NsxVPluginV2TestCase, test_addr_pair.TestAllowedAddressPairs): def setUp(self, plugin=PLUGIN_NAME): super(TestNSXvAllowedAddressPairs, self).setUp(plugin=plugin) # NOTE: the tests below are skipped due to the fact that they update the # mac address. The NSX|V does not support address pairs when a MAC address # is configured. def test_create_port_allowed_address_pairs(self): pass def test_update_add_address_pairs(self): pass def test_equal_to_max_allowed_address_pair(self): pass def test_update_port_security_off_address_pairs(self): pass def test_create_port_security_true_allowed_address_pairs(self): pass def test_create_port_security_false_allowed_address_pairs(self): pass def test_create_port_remove_allowed_address_pairs(self): pass def test_create_overlap_with_fixed_ip(self): pass def test_get_vlan_network_name(self): pass class TestNSXPortSecurity(test_psec.TestPortSecurity, NsxVPluginV2TestCase): def setUp(self, plugin=PLUGIN_NAME): super(TestNSXPortSecurity, self).setUp(plugin=plugin) def test_create_port_fails_with_secgroup_and_port_security_false(self): # Security Groups can be used even when port-security is disabled pass def test_update_port_security_off_with_security_group(self): # Security Groups can be used even when port-security is disabled pass def test_create_port_security_overrides_network_value(self): pass def test_create_port_with_security_group_and_net_sec_false(self): pass def test_create_port_security_doese_not_overrides_network_value(self): """NSXv plugin port port-security-enabled is decided by the networks port-security state """ res = self._create_network('json', 'net1', True, arg_list=('port_security_enabled',), port_security_enabled=False) net = self.deserialize('json', res) res = self._create_port('json', net['network']['id'], arg_list=('port_security_enabled',), port_security_enabled=True) port = self.deserialize('json', res) self.assertEqual(port['port'][psec.PORTSECURITY], False) self._delete('ports', port['port']['id']) def test_update_port_remove_port_security_security_group(self): pass def test_update_port_remove_port_security_security_group_read(self): pass def test_update_port_port_security_raise_not_implemented(self): with self.network() as net: with self.subnet(network=net) as sub: with self.port(subnet=sub) as port: update_port = {'port': {psec.PORTSECURITY: False}} plugin = manager.NeutronManager.get_plugin() self.assertRaises(NotImplementedError, plugin.update_port, context.get_admin_context(), port['port']['id'], update_port) class TestSharedRouterTestCase(L3NatTest, L3NatTestCaseBase, test_l3_plugin.L3NatTestCaseMixin, NsxVPluginV2TestCase): def _create_router(self, fmt, tenant_id, name=None, admin_state_up=None, set_context=False, arg_list=None, **kwargs): data = {'router': {'tenant_id': tenant_id}} if name: data['router']['name'] = name if admin_state_up: data['router']['admin_state_up'] = admin_state_up for arg in (('admin_state_up', 'tenant_id') + (arg_list or ())): # Arg must be present and not empty if arg in kwargs and kwargs[arg]: data['router'][arg] = kwargs[arg] data['router']['router_type'] = kwargs.get('router_type', 'shared') router_req = self.new_create_request('routers', data, fmt) if set_context and tenant_id: # create a specific auth context for this request router_req.environ['neutron.context'] = context.Context( '', tenant_id) return router_req.get_response(self.ext_api) def test_router_create_with_no_edge(self): name = 'router1' tenant_id = _uuid() expected_value = [('name', name), ('tenant_id', tenant_id), ('admin_state_up', True), ('status', 'ACTIVE'), ('external_gateway_info', None)] with self.router(name='router1', admin_state_up=True, tenant_id=tenant_id) as router: for k, v in expected_value: self.assertEqual(router['router'][k], v) self.assertEqual( [], self.plugin_instance.edge_manager.get_routers_on_same_edge( context.get_admin_context(), router['router']['id'])) def test_router_create_with_size_fail_at_backend(self): data = {'router': { 'tenant_id': 'whatever', 'router_type': 'shared', 'router_size': 'large'}} router_req = self.new_create_request('routers', data, self.fmt) res = router_req.get_response(self.ext_api) router = self.deserialize(self.fmt, res) msg = ('Bad router request: ' 'Cannot specify router-size for shared router.') self.assertEqual("BadRequest", router['NeutronError']['type']) self.assertEqual(msg, router['NeutronError']['message']) def test_router_create_with_gwinfo_with_no_edge(self): with self._create_l3_ext_network() as net: with self.subnet(network=net, enable_dhcp=False) as s: data = {'router': {'tenant_id': 'whatever'}} data['router']['name'] = 'router1' data['router']['external_gateway_info'] = { 'network_id': s['subnet']['network_id']} router_req = self.new_create_request('routers', data, self.fmt) res = router_req.get_response(self.ext_api) router = self.deserialize(self.fmt, res) self.assertEqual( s['subnet']['network_id'], (router['router']['external_gateway_info'] ['network_id'])) self.assertEqual( [], self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), router['router']['id'])) def test_router_update_gateway_with_no_edge(self): with self.router() as r: with self.subnet() as s1: with self._create_l3_ext_network() as net: with self.subnet(network=net, enable_dhcp=False) as s2: self._set_net_external(s1['subnet']['network_id']) try: self._add_external_gateway_to_router( r['router']['id'], s1['subnet']['network_id']) body = self._show('routers', r['router']['id']) net_id = (body['router'] ['external_gateway_info']['network_id']) self.assertEqual(net_id, s1['subnet']['network_id']) self.assertEqual( [], self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r['router']['id'])) # Plug network with external mapping self._set_net_external(s2['subnet']['network_id']) self._add_external_gateway_to_router( r['router']['id'], s2['subnet']['network_id']) body = self._show('routers', r['router']['id']) net_id = (body['router'] ['external_gateway_info']['network_id']) self.assertEqual(net_id, s2['subnet']['network_id']) self.assertEqual( [], self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r['router']['id'])) finally: # Cleanup self._remove_external_gateway_from_router( r['router']['id'], s2['subnet']['network_id']) def test_router_update_gateway_with_existing_floatingip_with_edge(self): with self._create_l3_ext_network() as net: with self.subnet(network=net, enable_dhcp=False) as subnet: with self.floatingip_with_assoc() as fip: self._add_external_gateway_to_router( fip['floatingip']['router_id'], subnet['subnet']['network_id'], expected_code=webob.exc.HTTPConflict.code) self.assertNotEqual( [], self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), fip['floatingip']['router_id'])) def test_router_set_gateway_with_interfaces_with_edge(self): with self.router() as r, self.subnet() as s1: self._set_net_external(s1['subnet']['network_id']) try: self._add_external_gateway_to_router( r['router']['id'], s1['subnet']['network_id']) body = self._show('routers', r['router']['id']) net_id = (body['router'] ['external_gateway_info']['network_id']) self.assertEqual(net_id, s1['subnet']['network_id']) self.assertEqual( [], self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r['router']['id'])) with self.subnet(cidr='11.0.0.0/24') as s11: with self.subnet(cidr='12.0.0.0/24') as s12: self._router_interface_action('add', r['router']['id'], s11['subnet']['id'], None) self._router_interface_action('add', r['router']['id'], s12['subnet']['id'], None) self.assertIsNotNone( self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r['router']['id'])) self._router_interface_action('remove', r['router']['id'], s11['subnet']['id'], None) self.assertIsNotNone( self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r['router']['id'])) self._router_interface_action('remove', r['router']['id'], s12['subnet']['id'], None) self.assertEqual( [], self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r['router']['id'])) finally: # Cleanup self._remove_external_gateway_from_router( r['router']['id'], s1['subnet']['network_id']) @mock.patch.object(edge_utils, "update_firewall") def test_routers_set_gateway_with_nosnat(self, mock): expected_fw1 = [{'action': 'allow', 'enabled': True, 'source_ip_address': [], 'destination_ip_address': []}] expected_fw2 = [{'action': 'allow', 'enabled': True, 'source_ip_address': [], 'destination_ip_address': []}] nosnat_fw1 = [{'action': 'allow', 'enabled': True, 'source_vnic_groups': ["external"], 'destination_ip_address': []}] nosnat_fw2 = [{'action': 'allow', 'enabled': True, 'source_vnic_groups': ["external"], 'destination_ip_address': []}] with self.router() as r1, self.router() as r2,\ self.subnet() as ext_subnet,\ self.subnet(cidr='11.0.0.0/24') as s1,\ self.subnet(cidr='12.0.0.0/24') as s2: self._set_net_external(ext_subnet['subnet']['network_id']) self._router_interface_action( 'add', r1['router']['id'], s1['subnet']['id'], None) expected_fw1[0]['source_ip_address'] = ['11.0.0.0/24'] expected_fw1[0]['destination_ip_address'] = ['11.0.0.0/24'] fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual(self._recursive_sort_list(expected_fw1), self._recursive_sort_list(fw_rules)) self._router_interface_action('add', r2['router']['id'], s2['subnet']['id'], None) self._add_external_gateway_to_router( r1['router']['id'], ext_subnet['subnet']['network_id']) self._add_external_gateway_to_router( r2['router']['id'], ext_subnet['subnet']['network_id']) expected_fw2[0]['source_ip_address'] = ['12.0.0.0/24'] expected_fw2[0]['destination_ip_address'] = ['12.0.0.0/24'] fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual( self._recursive_sort_list(expected_fw1 + expected_fw2), self._recursive_sort_list(fw_rules)) self._update_router_enable_snat( r1['router']['id'], ext_subnet['subnet']['network_id'], False) nosnat_fw1[0]['destination_ip_address'] = ['11.0.0.0/24'] fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual( self._recursive_sort_list(expected_fw1 + expected_fw2 + nosnat_fw1), self._recursive_sort_list(fw_rules)) self._update_router_enable_snat( r2['router']['id'], ext_subnet['subnet']['network_id'], False) nosnat_fw2[0]['destination_ip_address'] = ['12.0.0.0/24'] fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual( self._recursive_sort_list(expected_fw1 + expected_fw2 + nosnat_fw1 + nosnat_fw2), self._recursive_sort_list(fw_rules)) self._update_router_enable_snat( r2['router']['id'], ext_subnet['subnet']['network_id'], True) fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual( self._recursive_sort_list(expected_fw1 + expected_fw2 + nosnat_fw1), self._recursive_sort_list(fw_rules)) self._router_interface_action('remove', r2['router']['id'], s2['subnet']['id'], None) fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual( self._recursive_sort_list(expected_fw1 + nosnat_fw1), self._recursive_sort_list(fw_rules)) self._remove_external_gateway_from_router( r1['router']['id'], ext_subnet['subnet']['network_id']) fw_rules = mock.call_args[0][3]['firewall_rule_list'] self.assertEqual( self._recursive_sort_list(expected_fw1), self._recursive_sort_list(fw_rules)) self._router_interface_action('remove', r1['router']['id'], s1['subnet']['id'], None) self._remove_external_gateway_from_router( r2['router']['id'], ext_subnet['subnet']['network_id']) def test_routers_with_interface_on_same_edge(self): with self.router() as r1, self.router() as r2,\ self.subnet(cidr='11.0.0.0/24') as s11,\ self.subnet(cidr='12.0.0.0/24') as s12: self._router_interface_action('add', r1['router']['id'], s11['subnet']['id'], None) self._router_interface_action('add', r2['router']['id'], s12['subnet']['id'], None) routers_expected = [r1['router']['id'], r2['router']['id']] routers_1 = (self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r1['router']['id'])) self.assertEqual(routers_expected, routers_1) routers_2 = (self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r2['router']['id'])) self.assertEqual(routers_expected, routers_2) self._router_interface_action('remove', r1['router']['id'], s11['subnet']['id'], None) self._router_interface_action('remove', r2['router']['id'], s12['subnet']['id'], None) def test_routers_with_overlap_interfaces(self): with self.router() as r1, self.router() as r2,\ self.subnet(cidr='11.0.0.0/24') as s11,\ self.subnet(cidr='11.0.0.0/24') as s12: self._router_interface_action('add', r1['router']['id'], s11['subnet']['id'], None) self._router_interface_action('add', r2['router']['id'], s12['subnet']['id'], None) r1_expected = [r1['router']['id']] routers_1 = (self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r1['router']['id'])) self.assertEqual(r1_expected, routers_1) r2_expected = [r2['router']['id']] routers_2 = (self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r2['router']['id'])) self.assertEqual(r2_expected, routers_2) self._router_interface_action('remove', r1['router']['id'], s11['subnet']['id'], None) self._router_interface_action('remove', r2['router']['id'], s12['subnet']['id'], None) def test_routers_with_overlap_interfaces_with_migration(self): with self.router() as r1, self.router() as r2,\ self.subnet(cidr='11.0.0.0/24') as s11,\ self.subnet(cidr='12.0.0.0/24') as s12,\ self.subnet(cidr='11.0.0.0/24') as s13: self._router_interface_action('add', r1['router']['id'], s11['subnet']['id'], None) self._router_interface_action('add', r2['router']['id'], s12['subnet']['id'], None) r1_expected = [r1['router']['id'], r2['router']['id']] routers_1 = (self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r1['router']['id'])) self.assertEqual(r1_expected, routers_1) self._router_interface_action('add', r2['router']['id'], s13['subnet']['id'], None) r1_expected = [r1['router']['id']] routers_1 = (self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r1['router']['id'])) self.assertEqual(r1_expected, routers_1) self._router_interface_action('remove', r1['router']['id'], s11['subnet']['id'], None) self._router_interface_action('remove', r2['router']['id'], s12['subnet']['id'], None) self._router_interface_action('remove', r2['router']['id'], s13['subnet']['id'], None) def test_routers_with_different_subnet_on_same_network(self): with self.router() as r1, self.router() as r2,\ self.network() as net,\ self.subnet(network=net, cidr='12.0.0.0/24') as s1,\ self.subnet(network=net, cidr='13.0.0.0/24') as s2: self._router_interface_action('add', r1['router']['id'], s1['subnet']['id'], None) self._router_interface_action('add', r2['router']['id'], s2['subnet']['id'], None) routers_2 = (self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r2['router']['id'])) self.assertEqual(1, len(routers_2)) self._router_interface_action('remove', r1['router']['id'], s1['subnet']['id'], None) self._router_interface_action('remove', r2['router']['id'], s2['subnet']['id'], None) def test_routers_with_different_subnet_on_same_network_migration(self): with self.router() as r1, self.router() as r2, self.network() as net,\ self.subnet(cidr='11.0.0.0/24') as s1,\ self.subnet(network=net, cidr='12.0.0.0/24') as s2,\ self.subnet(network=net, cidr='13.0.0.0/24') as s3: self._router_interface_action('add', r1['router']['id'], s1['subnet']['id'], None) self._router_interface_action('add', r2['router']['id'], s2['subnet']['id'], None) routers_2 = (self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r2['router']['id'])) self.assertEqual(2, len(routers_2)) self._router_interface_action('add', r2['router']['id'], s3['subnet']['id'], None) routers_2 = (self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r2['router']['id'])) self.assertEqual(2, len(routers_2)) self._router_interface_action('remove', r2['router']['id'], s3['subnet']['id'], None) self._router_interface_action('add', r1['router']['id'], s3['subnet']['id'], None) routers_2 = (self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r2['router']['id'])) self.assertEqual(1, len(routers_2)) self._router_interface_action('remove', r1['router']['id'], s3['subnet']['id'], None) self._router_interface_action('remove', r1['router']['id'], s1['subnet']['id'], None) self._router_interface_action('remove', r2['router']['id'], s2['subnet']['id'], None) def test_routers_set_same_gateway_on_same_edge(self): with self.router() as r1, self.router() as r2,\ self.network() as ext_net,\ self.subnet(cidr='11.0.0.0/24') as s1,\ self.subnet(cidr='12.0.0.0/24') as s2,\ self.subnet(network=ext_net, cidr='13.0.0.0/24'): self._set_net_external(ext_net['network']['id']) self._router_interface_action('add', r1['router']['id'], s1['subnet']['id'], None) self._router_interface_action('add', r2['router']['id'], s2['subnet']['id'], None) self._add_external_gateway_to_router( r1['router']['id'], ext_net['network']['id']) self._add_external_gateway_to_router( r2['router']['id'], ext_net['network']['id']) routers_2 = (self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r2['router']['id'])) self.assertEqual(2, len(routers_2)) self._router_interface_action('remove', r1['router']['id'], s1['subnet']['id'], None) self._router_interface_action('remove', r2['router']['id'], s2['subnet']['id'], None) self._remove_external_gateway_from_router( r1['router']['id'], ext_net['network']['id']) self._remove_external_gateway_from_router( r2['router']['id'], ext_net['network']['id']) def test_routers_set_different_gateway_on_different_edge(self): with self.router() as r1, self.router() as r2,\ self.network() as ext1, self.network() as ext2,\ self.subnet(cidr='11.0.0.0/24') as s1,\ self.subnet(cidr='12.0.0.0/24') as s2,\ self.subnet(network=ext1, cidr='13.0.0.0/24'),\ self.subnet(network=ext2, cidr='14.0.0.0/24'): self._set_net_external(ext1['network']['id']) self._set_net_external(ext2['network']['id']) self._router_interface_action('add', r1['router']['id'], s1['subnet']['id'], None) self._router_interface_action('add', r2['router']['id'], s2['subnet']['id'], None) self._add_external_gateway_to_router( r1['router']['id'], ext1['network']['id']) self._add_external_gateway_to_router( r2['router']['id'], ext1['network']['id']) routers_2 = (self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r2['router']['id'])) self.assertEqual(2, len(routers_2)) self._add_external_gateway_to_router( r2['router']['id'], ext2['network']['id']) routers_2 = (self.plugin_instance.edge_manager. get_routers_on_same_edge( context.get_admin_context(), r2['router']['id'])) self.assertEqual(1, len(routers_2)) self._router_interface_action('remove', r1['router']['id'], s1['subnet']['id'], None) self._router_interface_action('remove', r2['router']['id'], s2['subnet']['id'], None) self._remove_external_gateway_from_router( r1['router']['id'], ext1['network']['id']) self._remove_external_gateway_from_router( r2['router']['id'], ext2['network']['id']) def test_get_available_and_conflicting_ids_with_no_conflict(self): with self.router() as r1, self.router() as r2,\ self.subnet(cidr='11.0.0.0/24') as s1,\ self.subnet(cidr='12.0.0.0/24') as s2: self._router_interface_action('add', r1['router']['id'], s1['subnet']['id'], None) self._router_interface_action('add', r2['router']['id'], s2['subnet']['id'], None) router_driver = (self.plugin_instance._router_managers. get_tenant_router_driver(context, 'shared')) available_router_ids, conflict_router_ids = ( router_driver._get_available_and_conflicting_ids( context.get_admin_context(), r1['router']['id'])) self.assertIn(r2['router']['id'], available_router_ids) self.assertEqual(0, len(conflict_router_ids)) def test_get_available_and_conflicting_ids_with_conflict(self): with self.router() as r1, self.router() as r2,\ self.subnet(cidr='11.0.0.0/24') as s1,\ self.subnet(cidr='11.0.0.0/24') as s2: self._router_interface_action('add', r1['router']['id'], s1['subnet']['id'], None) self._router_interface_action('add', r2['router']['id'], s2['subnet']['id'], None) router_driver = (self.plugin_instance._router_managers. get_tenant_router_driver(context, 'shared')) available_router_ids, conflict_router_ids = ( router_driver._get_available_and_conflicting_ids( context.get_admin_context(), r1['router']['id'])) self.assertIn(r2['router']['id'], conflict_router_ids) self.assertEqual(0, len(available_router_ids)) def test_get_available_and_conflicting_ids_with_diff_gw(self): with self.router() as r1, self.router() as r2,\ self.network() as ext1, self.network() as ext2,\ self.subnet(cidr='11.0.0.0/24') as s1,\ self.subnet(cidr='12.0.0.0/24') as s2,\ self.subnet(network=ext1, cidr='13.0.0.0/24'),\ self.subnet(network=ext2, cidr='14.0.0.0/24'): self._set_net_external(ext1['network']['id']) self._set_net_external(ext2['network']['id']) self._router_interface_action('add', r1['router']['id'], s1['subnet']['id'], None) self._router_interface_action('add', r2['router']['id'], s2['subnet']['id'], None) self._add_external_gateway_to_router( r1['router']['id'], ext1['network']['id']) self._add_external_gateway_to_router( r2['router']['id'], ext2['network']['id']) router_driver = (self.plugin_instance._router_managers. get_tenant_router_driver(context, 'shared')) available_router_ids, conflict_router_ids = ( router_driver._get_available_and_conflicting_ids( context.get_admin_context(), r1['router']['id'])) self.assertIn(r2['router']['id'], conflict_router_ids) self.assertEqual(0, len(available_router_ids))