group-based-policy/gbpservice/neutron/tests/unit/services/grouppolicy/test_aim_mapping_driver.py

6295 lines
297 KiB
Python

# 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.
from gbpservice.neutron.plugins.ml2plus import patch_neutron # noqa
import copy
import hashlib
import mock
import netaddr
from aim.api import infra as aim_infra
from aim.api import resource as aim_resource
from aim.api import status as aim_status
from aim import context as aim_context
from keystoneclient.v3 import client as ksc_client
from netaddr import IPSet
from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
from neutron.common import utils as n_utils
from neutron.db import api as db_api
from neutron.db.models import securitygroup as sg_models
from neutron.extensions import dns
from neutron.notifiers import nova
from neutron.tests.unit.db import test_db_base_plugin_v2 as test_plugin
from neutron.tests.unit.extensions import test_address_scope
from neutron.tests.unit.extensions import test_securitygroup
from neutron_lib.callbacks import registry
from neutron_lib import constants as n_constants
from neutron_lib import context as nctx
from neutron_lib.plugins import directory
from opflexagent import constants as ocst
from oslo_config import cfg
import webob.exc
from gbpservice.network.neutronv2 import local_api
from gbpservice.neutron.db.grouppolicy import group_policy_mapping_db
from gbpservice.neutron.extensions import cisco_apic
from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import (
mechanism_driver as md)
from gbpservice.neutron.services.grouppolicy.common import (
constants as gp_const)
from gbpservice.neutron.services.grouppolicy.common import utils
from gbpservice.neutron.services.grouppolicy import config
from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import (
aim_mapping as aimd)
from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import (
apic_mapping_lib as alib)
from gbpservice.neutron.services.grouppolicy.drivers import nsp_manager
from gbpservice.neutron.tests.unit.plugins.ml2plus import (
test_apic_aim as test_aim_md)
from gbpservice.neutron.tests.unit.services.grouppolicy import (
test_extension_driver_api as test_ext_base)
from gbpservice.neutron.tests.unit.services.grouppolicy import (
test_neutron_resources_driver as test_nr_base)
ML2PLUS_PLUGIN = 'gbpservice.neutron.plugins.ml2plus.plugin.Ml2PlusPlugin'
DEFAULT_FILTER_ENTRY = {'arp_opcode': u'unspecified',
'dest_from_port': u'unspecified',
'dest_to_port': u'unspecified',
'ether_type': u'unspecified',
'fragment_only': False,
'icmpv4_type': u'unspecified',
'icmpv6_type': u'unspecified',
'ip_protocol': u'unspecified',
'source_from_port': u'unspecified',
'source_to_port': u'unspecified',
'stateful': False,
'tcp_flags': u'unspecified'}
AGENT_TYPE = ocst.AGENT_TYPE_OPFLEX_OVS
AGENT_CONF = {'alive': True, 'binary': 'somebinary',
'topic': 'sometopic', 'agent_type': AGENT_TYPE,
'configurations': {'opflex_networks': None,
'bridge_mappings': {'physnet1': 'br-eth1'}}}
AGENT_TYPE_DVS = md.AGENT_TYPE_DVS
AGENT_CONF_DVS = {'alive': True, 'binary': 'somebinary',
'topic': 'sometopic', 'agent_type': AGENT_TYPE_DVS,
'configurations': {'opflex_networks': None}}
BOOKED_PORT_VALUE = 'myBookedPort'
AP = cisco_apic.AP
BD = cisco_apic.BD
DN = cisco_apic.DIST_NAMES
EPG = cisco_apic.EPG
EXTERNAL_NETWORK = cisco_apic.EXTERNAL_NETWORK
SNAT_HOST_POOL = cisco_apic.SNAT_HOST_POOL
VRF = cisco_apic.VRF
CIDR = 'apic:external_cidrs'
PROV = 'apic:external_provided_contracts'
CONS = 'apic:external_consumed_contracts'
def aim_object_to_dict(obj):
result = {}
for key, value in obj.__dict__.items():
if key in obj.user_attributes():
result[key] = value
return result
class AIMBaseTestCase(test_nr_base.CommonNeutronBaseTestCase,
test_ext_base.ExtensionDriverTestBase,
test_aim_md.ApicAimTestMixin,
test_address_scope.AddressScopeTestCase):
_extension_drivers = ['aim_extension', 'apic_segmentation_label',
'apic_allowed_vm_name']
_extension_path = None
def setUp(self, policy_drivers=None, core_plugin=None, ml2_options=None,
l3_plugin=None, sc_plugin=None, trunk_plugin=None,
qos_plugin=None, **kwargs):
self.nova_client1 = mock.patch(
'gbpservice.neutron.plugins.ml2plus.drivers.apic_aim.'
'nova_client.NovaClient.get_servers').start()
self.nova_client1.return_value = []
core_plugin = core_plugin or ML2PLUS_PLUGIN
if not l3_plugin:
l3_plugin = "apic_aim_l3"
# The dummy driver configured here is meant to be the second driver
# invoked and helps in rollback testing. We mock the dummy driver
# methods to raise an exception and validate that DB operations
# performed up until that point (including those in the aim_mapping)
# driver are rolled back.
policy_drivers = policy_drivers or ['aim_mapping', 'dummy']
if not cfg.CONF.group_policy.extension_drivers:
config.cfg.CONF.set_override(
'extension_drivers', self._extension_drivers,
group='group_policy')
if self._extension_path:
config.cfg.CONF.set_override(
'api_extensions_path', self._extension_path)
self.agent_conf = AGENT_CONF
ml2_opts = ml2_options or {'mechanism_drivers': ['logger', 'apic_aim'],
'extension_drivers': ['apic_aim',
'port_security',
'dns'],
'type_drivers': ['opflex', 'local', 'vlan'],
'tenant_network_types': ['opflex']}
self._default_es_name = 'default'
self.useFixture(test_aim_md.AimSqlFixture())
super(AIMBaseTestCase, self).setUp(
policy_drivers=policy_drivers, core_plugin=core_plugin,
ml2_options=ml2_opts, l3_plugin=l3_plugin,
sc_plugin=sc_plugin, qos_plugin=qos_plugin,
trunk_plugin=trunk_plugin)
self.db_session = db_api.get_writer_session()
self.initialize_db_config(self.db_session)
self.l3_plugin = directory.get_plugin(n_constants.L3)
config.cfg.CONF.set_override('network_vlan_ranges',
['physnet1:1000:1099'],
group='ml2_type_vlan')
cfg.CONF.set_override(
'default_external_segment_name', self._default_es_name,
group='group_policy_implicit_policy')
self.saved_keystone_client = ksc_client.Client
ksc_client.Client = test_aim_md.FakeKeystoneClient
self.first_tenant_id = test_plugin.TEST_TENANT_ID
self._tenant_id = self.first_tenant_id
self._neutron_context = nctx.Context(
'', kwargs.get('tenant_id', self._tenant_id),
is_admin=False)
self._neutron_context._session = self.db_session
self._neutron_admin_context = nctx.get_admin_context()
self._aim_mgr = None
self._aim_context = aim_context.AimContext(
self._neutron_context.session)
self._dummy = None
self._name_mapper = None
self._driver = None
nova_client = mock.patch(
'gbpservice.neutron.plugins.ml2plus.drivers.apic_aim.'
'nova_client.NovaClient.get_server').start()
vm = mock.Mock()
vm.name = 'someid'
nova_client.return_value = vm
self.extension_attributes = ('router:external', DN, 'apic:svi',
'apic:nat_type', 'apic:snat_host_pool',
CIDR, PROV, CONS)
# REVISIT: Note that the aim_driver sets create_auto_ptg to
# True by default, hence this feature is always ON by default.
# However, as a better unit testing strategy, we turn this OFF
# for the base case, and turn it ON for select set of tests
# which test in addition to what has been already tested in the
# base case. It can be evaluated in the future if the base
# testing strategy itself should evolve to always test with
# the feature turned ON.
self.driver.create_auto_ptg = False
self._t1_aname = self.name_mapper.project(None, 't1')
self._dn_t1_l1_n1 = ('uni/tn-%s/out-l1/instP-n1' % self._t1_aname)
self._mock_aim_obj_eq_operator()
def tearDown(self):
ksc_client.Client = self.saved_keystone_client
# We need to do the following to avoid non-aim tests
# picking up the patched version of the method in patch_neutron
registry._get_callback_manager()._notify_loop = (
patch_neutron.original_notify_loop)
super(AIMBaseTestCase, self).tearDown()
def _setup_external_network(self, name, dn=None, router_tenant=None):
DN = 'apic:distinguished_names'
kwargs = {'router:external': True}
if dn:
kwargs[DN] = {'ExternalNetwork': dn}
extn_attr = ('router:external', DN,
'apic:nat_type', 'apic:snat_host_pool')
net = self._make_network(self.fmt, name, True,
arg_list=extn_attr,
**kwargs)['network']
subnet = self._make_subnet(
self.fmt, {'network': net}, '100.100.0.1',
'100.100.0.0/16')['subnet']
router = self._make_router(
self.fmt, router_tenant or net['tenant_id'], 'router1',
external_gateway_info={'network_id': net['id']})['router']
return net, router, subnet
def _bind_port_to_host(self, port_id, host):
data = {'port': {'binding:host_id': host,
'device_owner': 'compute:',
'device_id': 'someid'}}
return super(AIMBaseTestCase, self)._bind_port_to_host(
port_id, host, data=data)
def _bind_other_port_to_host(self, port_id, host,
owner=n_constants.DEVICE_OWNER_DHCP):
data = {'port': {'binding:host_id': host,
'device_owner': owner,
'device_id': 'someid'}}
return super(AIMBaseTestCase, self)._bind_port_to_host(
port_id, host, data=data)
def _make_address_scope_for_vrf(self, vrf_dn, ip_version=4,
expected_status=None, **kwargs):
attrs = {'ip_version': ip_version}
if vrf_dn:
attrs[DN] = {'VRF': vrf_dn}
attrs.update(kwargs)
req = self.new_create_request('address-scopes',
{'address_scope': attrs}, self.fmt)
neutron_context = nctx.Context('', kwargs.get('tenant_id',
self._tenant_id))
req.environ['neutron.context'] = neutron_context
res = req.get_response(self.ext_api)
if expected_status:
self.assertEqual(expected_status, res.status_int)
elif res.status_int >= webob.exc.HTTPClientError.code:
raise webob.exc.HTTPClientError(code=res.status_int)
return self.deserialize(self.fmt, res)
@property
def driver(self):
# aim_mapping policy driver reference
if not self._driver:
self._driver = (
self._gbp_plugin.policy_driver_manager.policy_drivers[
'aim_mapping'].obj)
return self._driver
@property
def dummy(self):
# dummy policy driver reference
if not self._dummy:
self._dummy = (
self._gbp_plugin.policy_driver_manager.policy_drivers[
'dummy'].obj)
return self._dummy
@property
def aim_mgr(self):
if not self._aim_mgr:
self._aim_mgr = self.driver.aim
return self._aim_mgr
@property
def name_mapper(self):
if not self._name_mapper:
self._name_mapper = self.driver.name_mapper
return self._name_mapper
def _switch_to_tenant1(self):
self._tenant_id = self.first_tenant_id
self._neutron_context.tenant = self._tenant_id
def _switch_to_tenant2(self):
self._tenant_id = 'test_tenant-2'
self._neutron_context.tenant = self._tenant_id
def _show_subnet(self, id):
req = self.new_show_request('subnets', id, fmt=self.fmt)
return self.deserialize(self.fmt,
req.get_response(self.api))['subnet']
def _show_port(self, id):
req = self.new_show_request('ports', id, fmt=self.fmt)
return self.deserialize(self.fmt, req.get_response(self.api))['port']
def _show_network(self, id):
req = self.new_show_request('networks', id, fmt=self.fmt)
return self.deserialize(self.fmt,
req.get_response(self.api))['network']
def _show_subnetpool(self, id):
req = self.new_show_request('subnetpools', id, fmt=self.fmt)
return self.deserialize(self.fmt,
req.get_response(self.api))['subnetpool']
def _test_aim_resource_status(self, aim_resource_obj, gbp_resource):
aim_status = self.aim_mgr.get_status(
self._aim_context, aim_resource_obj)
if aim_status.is_error():
self.assertEqual(gp_const.STATUS_ERROR, gbp_resource['status'])
elif aim_status.is_build():
self.assertEqual(gp_const.STATUS_BUILD, gbp_resource['status'])
else:
self.assertEqual(gp_const.STATUS_ACTIVE, gbp_resource['status'])
def _create_3_direction_rules(self, shared=False):
a1 = self.create_policy_action(name='a1',
action_type='allow',
shared=shared)['policy_action']
cl_attr = {'protocol': 'tcp', 'port_range': 80}
cls = []
for direction in ['bi', 'in', 'out']:
if direction == 'out':
cl_attr['protocol'] = 'udp'
cls.append(self.create_policy_classifier(
direction=direction, shared=shared,
**cl_attr)['policy_classifier'])
rules = []
for classifier in cls:
rules.append(self.create_policy_rule(
policy_classifier_id=classifier['id'],
policy_actions=[a1['id']],
shared=shared)['policy_rule'])
return rules
def _validate_status(self, show_method, resource_id):
# This validation is used in the case where GBP resource status is
# derived from Neutron and AIM resources which it maps to. In this
# test we manipulate the state of AIM resources to test that the
# different status states are correctly reflected in the L2P.
AIM_STATUS = aim_status.AciStatus.SYNC_PENDING
def mock_get_aim_status(aim_context, aim_resource,
create_if_absent=True):
astatus = aim_status.AciStatus(resource_root=aim_resource.root)
astatus.sync_status = AIM_STATUS
return astatus
orig_get_status = self.aim_mgr.get_status
res = getattr(self, show_method)(resource_id, expected_res_status=200)[
show_method[5:]]
self.assertEqual(gp_const.STATUS_BUILD, res['status'])
AIM_STATUS = aim_status.AciStatus.SYNCED
# Temporarily patch aim_mgr.get_status to set status from test
self.aim_mgr.get_status = mock_get_aim_status
res = getattr(self, show_method)(resource_id, expected_res_status=200)[
show_method[5:]]
self.assertEqual(gp_const.STATUS_ACTIVE, res['status'])
AIM_STATUS = aim_status.AciStatus.SYNC_FAILED
res = getattr(self, show_method)(resource_id, expected_res_status=200)[
show_method[5:]]
self.assertEqual(gp_const.STATUS_ERROR, res['status'])
# Restore aim_mgr.get_status
self.aim_mgr.get_status = orig_get_status
def _validate_implicit_contracts_created(self, l3p_id, l2p=None):
aim_tenant_name = md.COMMON_TENANT_NAME
if l2p:
net = self._plugin.get_network(self._context, l2p['network_id'])
default_epg_dn = net['apic:distinguished_names']['EndpointGroup']
default_epg = self.aim_mgr.get(self._aim_context,
aim_resource.EndpointGroup.from_dn(
default_epg_dn))
default_epg_provided_contract_names = (
default_epg.provided_contract_names[:])
for acontract in default_epg_provided_contract_names:
if not acontract.endswith(l3p_id):
default_epg_provided_contract_names.remove(acontract)
self.assertEqual(2, len(default_epg_provided_contract_names))
default_epg_consumed_contract_names = (
default_epg.consumed_contract_names[:])
for acontract in default_epg_consumed_contract_names:
if not acontract.endswith(l3p_id):
default_epg_consumed_contract_names.remove(acontract)
self.assertEqual(1, len(default_epg_consumed_contract_names))
contracts = [alib.SERVICE_PREFIX, alib.IMPLICIT_PREFIX]
for contract_name_prefix in contracts:
contract_name = str(self.name_mapper.l3_policy(
self._neutron_context.session, l3p_id,
prefix=contract_name_prefix))
aim_contracts = self.aim_mgr.find(
self._aim_context, aim_resource.Contract, name=contract_name)
for acontract in aim_contracts[:]:
# Remove contracts created by MD or created for other tenants
if not acontract.name.endswith(l3p_id):
aim_contracts.remove(acontract)
self.assertEqual(1, len(aim_contracts))
if l2p:
self.assertTrue(contract_name in
default_epg.provided_contract_names)
aim_contract_subjects = self.aim_mgr.find(
self._aim_context, aim_resource.ContractSubject,
name=contract_name)
for acontractsub in aim_contract_subjects[:]:
# Remove contract_subjects created by MD or created
# for other tenants
if not acontractsub.name.endswith(l3p_id):
aim_contract_subjects.remove(acontractsub)
self.assertEqual(1, len(aim_contract_subjects))
self.assertEqual(0, len(aim_contract_subjects[0].in_filters))
self.assertEqual(0, len(aim_contract_subjects[0].out_filters))
if contract_name_prefix == alib.SERVICE_PREFIX:
self.assertEqual(11, len(aim_contract_subjects[0].bi_filters))
else:
self.assertEqual(1, len(aim_contract_subjects[0].bi_filters))
if l2p:
self.assertTrue(contract_name in
default_epg.consumed_contract_names)
aim_filters = self.aim_mgr.find(
self._aim_context, aim_resource.Filter,
tenant_name=aim_tenant_name)
for afilter in aim_filters[:]:
# Remove filters created by MD or created for other tenants
if not afilter.name.endswith(l3p_id):
aim_filters.remove(afilter)
self.assertEqual(12, len(aim_filters))
aim_filter_entries = self.aim_mgr.find(
self._aim_context, aim_resource.FilterEntry,
tenant_name=aim_tenant_name)
for afilterentry in aim_filter_entries[:]:
# Remove filter_entries created by MD or created for other tenants
if not afilterentry.filter_name.endswith(l3p_id):
aim_filter_entries.remove(afilterentry)
self.assertEqual(12, len(aim_filter_entries))
entries_attrs = alib.get_service_contract_filter_entries().values()
entries_attrs.extend(alib.get_arp_filter_entry().values())
expected_entries_attrs = []
for entry in entries_attrs:
new_entry = copy.deepcopy(DEFAULT_FILTER_ENTRY)
new_entry.update(alib.map_to_aim_filter_entry(entry))
expected_entries_attrs.append(
{k: unicode(new_entry[k]) for k in new_entry})
entries_attrs = [aim_object_to_dict(x) for x in aim_filter_entries]
observed_entries_attrs = []
for entry in entries_attrs:
observed_entries_attrs.append(
{k: unicode(entry[k]) for k in entry if k not in [
'name', 'display_name', 'filter_name', 'tenant_name',
'monitored']})
self.assertItemsEqual(expected_entries_attrs, observed_entries_attrs)
def _validate_implicit_contracts_exist(self, l3p_id):
self._validate_implicit_contracts_created(l3p_id)
def _validate_implicit_contracts_deleted(self, l3p_id):
aim_tenant_name = md.COMMON_TENANT_NAME
contracts = [alib.SERVICE_PREFIX, alib.IMPLICIT_PREFIX]
for contract_name_prefix in contracts:
contract_name = str(self.name_mapper.l3_policy(
self._neutron_context.session, l3p_id,
prefix=contract_name_prefix))
aim_contracts = self.aim_mgr.find(
self._aim_context, aim_resource.Contract, name=contract_name)
for acontract in aim_contracts[:]:
# Remove contracts created by MD or created for other tenants
if not acontract.name.endswith(l3p_id):
aim_contracts.remove(acontract)
self.assertEqual(0, len(aim_contracts))
aim_contract_subjects = self.aim_mgr.find(
self._aim_context, aim_resource.ContractSubject,
name=contract_name)
for acontractsub in aim_contract_subjects[:]:
# Remove contract_subjects created by MD or created
# for other tenants
if not acontractsub.name.endswith(l3p_id):
aim_contract_subjects.remove(acontractsub)
self.assertEqual(0, len(aim_contract_subjects))
aim_filter_entries = self.aim_mgr.find(
self._aim_context, aim_resource.FilterEntry,
tenant_name=aim_tenant_name)
for afilterentry in aim_filter_entries[:]:
# Remove filter_entries created by MD or created for other tenants
if not afilterentry.filter_name.endswith(l3p_id):
aim_filter_entries.remove(afilterentry)
self.assertEqual(0, len(aim_filter_entries))
aim_filters = self.aim_mgr.find(
self._aim_context, aim_resource.Filter,
tenant_name=aim_tenant_name)
for afilter in aim_filters[:]:
# Remove filters created by MD or created for other tenants
if not afilter.name.endswith(l3p_id):
aim_filters.remove(afilter)
self.assertEqual(0, len(aim_filters))
def _extend_subnet_prefixes(self, prefixes, l3p, subnetpools_version):
if subnetpools_version:
for spool_id in l3p[subnetpools_version]:
prefixes.extend(self._show_subnetpool(spool_id)['prefixes'])
# TODO(tbachman): change isomorphic default to False, once
# non-isomorphic VRFs are supported
def _validate_create_l3_policy(self, l3p, subnetpool_prefixes=None,
compare_subnetpool_shared_attr=True,
isomorphic=True):
# subnetpool_prefixes should be set only when the l3p has only
# one subnetpool configured; if not, the default None value should
# be used and the subnetpools should be validated in the calling test
# function.
# compare_subnetpool_shared_attr is set to False in the case explicit
# unshared subnetpool is created on shared address_scope.
prefixes_list = []
ascp_ids = []
ip_versions = []
subnetpools_versions = []
ip_version = l3p['ip_version']
if ip_version == 4 or ip_version == 46:
subnetpools_versions.append('subnetpools_v4')
ascp_ids.append(l3p['address_scope_v4_id'])
ip_versions.append(4)
if ip_version == 6 or ip_version == 46:
subnetpools_versions.append('subnetpools_v6')
ascp_ids.append(l3p['address_scope_v6_id'])
ip_versions.append(6)
if subnetpool_prefixes:
for version in subnetpools_versions:
self._extend_subnet_prefixes(prefixes_list, l3p, version)
self.assertItemsEqual(subnetpool_prefixes, prefixes_list)
params = {'ids': ascp_ids}
req = self.new_list_request('address-scopes',
params=params, fmt=self.fmt)
res = self.deserialize(self.fmt, req.get_response(self.ext_api))
ascopes = res['address_scopes']
for ascope in ascopes:
self.assertIn(ascope['ip_version'], ip_versions)
self.assertEqual(l3p['shared'], ascope['shared'])
if len(ascopes) == 2 and isomorphic:
self.assertEqual(ascopes[0][DN][VRF], ascopes[1][DN][VRF])
self.assertEqual(gp_const.STATUS_BUILD, l3p['status'])
self.assertIsNotNone(ascp_ids)
routers = l3p['routers']
self.assertIsNotNone(routers)
self.assertEqual(len(routers), 1)
router_id = routers[0]
for version in subnetpools_versions:
sp_id = l3p[version][0]
subpool = self._show_subnetpool(sp_id)
req = self.new_show_request('subnetpools', sp_id, fmt=self.fmt)
res = self.deserialize(self.fmt, req.get_response(self.api))
subpool = res['subnetpool']
self.assertIn(subpool['prefixes'][0], l3p['ip_pool'])
self.assertIn(subpool['ip_version'], ip_versions)
if compare_subnetpool_shared_attr:
self.assertEqual(l3p['shared'], subpool['shared'])
router = self._get_object('routers', router_id, self.ext_api)['router']
self.assertEqual('l3p_l3p1', router['name'])
self._validate_implicit_contracts_created(l3p['id'])
# L3P's shared flag update is not supported for aim_mapping
res = self.update_l3_policy(
l3p['id'], shared=(not l3p['shared']),
expected_res_status=webob.exc.HTTPBadRequest.code)
self.assertEqual('SharedAttributeUpdateNotSupported',
res['NeutronError']['type'])
def _validate_delete_l3_policy(self, l3p,
explicit_address_scope=False,
explicit_subnetpool=False,
v4_default=False, v6_default=False):
ascp_ids = []
subnetpools_versions = []
ip_version = l3p['ip_version']
if ip_version == 4 or ip_version == 46:
subnetpools_versions.append('subnetpools_v4')
ascp_ids.append(l3p['address_scope_v4_id'])
if ip_version == 6 or ip_version == 46:
subnetpools_versions.append('subnetpools_v6')
ascp_ids.append(l3p['address_scope_v6_id'])
router_id = l3p['routers'][0]
req = self.new_delete_request('l3_policies', l3p['id'])
res = req.get_response(self.ext_api)
self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
for version in subnetpools_versions:
sp_id = l3p[version][0]
req = self.new_show_request('subnetpools', sp_id, fmt=self.fmt)
res = req.get_response(self.api)
if explicit_subnetpool or (
version == 'subnetpools_v4' and v4_default) or (
version == 'subnetpools_v6' and v6_default):
self.assertEqual(webob.exc.HTTPOk.code, res.status_int)
else:
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
params = {'ids': ascp_ids}
req = self.new_list_request('address-scopes',
params=params, fmt=self.fmt)
res = req.get_response(self.ext_api)
if explicit_address_scope or v4_default or v6_default:
self.assertEqual(webob.exc.HTTPOk.code, res.status_int)
else:
res = self.deserialize(self.fmt, req.get_response(self.ext_api))
self.assertEqual(res['address_scopes'], [])
req = self.new_show_request('routers', router_id, fmt=self.fmt)
res = req.get_response(self.ext_api)
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
self._validate_implicit_contracts_deleted(l3p['id'])
# TODO(Sumit): Add test for implicit address_scope not deleted
# when it has associated subnetpools
def _get_provided_consumed_prs_lists(self, shared=False):
prs_dict = {}
prs_type = ['provided', 'consumed']
for ptype in prs_type:
rules = self._create_3_direction_rules(shared)
prs = self.create_policy_rule_set(
name="ctr", shared=shared,
policy_rules=[x['id'] for x in rules])['policy_rule_set']
prs_dict[ptype] = prs
return prs_dict
def _make_ext_subnet(self, network_name, cidr, tenant_id=None, dn=None,
nat_type=None, ext_cidrs=None, enable_dhcp=True,
shared_net=False):
kwargs = {'router:external': True}
if dn:
kwargs[DN] = {'ExternalNetwork': dn}
if nat_type is not None:
kwargs['apic:nat_type'] = nat_type
elif getattr(self, 'nat_type', None) is not None:
kwargs['apic:nat_type'] = self.nat_type
if ext_cidrs:
kwargs[CIDR] = ext_cidrs
if shared_net:
kwargs['shared'] = True
if tenant_id:
kwargs['tenant_id'] = tenant_id
net = self._make_network(self.fmt, network_name, True,
arg_list=self.extension_attributes,
**kwargs)['network']
gw = str(netaddr.IPAddress(netaddr.IPNetwork(cidr).first + 1))
subnet = self._make_subnet(
self.fmt, {'network': net}, gw, cidr,
enable_dhcp=enable_dhcp,
tenant_id=(kwargs.get('tenant_id') or self._tenant_id))['subnet']
return subnet
def _router_gw(self, router):
gw = router['external_gateway_info']
return gw['network_id'] if gw else None
def _show_all(self, resource_type, ids):
resource_type_plural = resource_type + 's' # Won't work always
return [self._show(resource_type_plural, res_id)[resource_type]
for res_id in ids]
def _delete_prs_dicts_and_rules(self, prs_dicts):
for prs in prs_dicts:
prs_id = prs_dicts[prs]['id']
rules = prs_dicts[prs]['policy_rules']
self.delete_policy_rule_set(prs_id, expected_res_status=204)
for rule in rules:
self.delete_policy_rule(rule, expected_res_status=204)
def _validate_contracts(self, ptg, aim_epg, prs_lists, l2p):
l3p_id = l2p['l3_policy_id']
implicit_contract_name = str(self.name_mapper.l3_policy(
self._neutron_context.session, l3p_id,
prefix=alib.IMPLICIT_PREFIX))
service_contract_name = str(self.name_mapper.l3_policy(
self._neutron_context.session, l3p_id,
prefix=alib.SERVICE_PREFIX))
l3p = self.show_l3_policy(l3p_id, expected_res_status=200)
router_id = l3p['l3_policy']['routers'][0]
router_contract_name = self.name_mapper.router(
self._neutron_context.session, router_id)
expected_prov_contract_names = []
expected_cons_contract_names = []
if ptg['id'].startswith(aimd.AUTO_PTG_PREFIX):
expected_prov_contract_names = [implicit_contract_name,
service_contract_name,
router_contract_name]
expected_cons_contract_names = [implicit_contract_name,
router_contract_name]
else:
expected_prov_contract_names = [implicit_contract_name]
expected_cons_contract_names = [implicit_contract_name,
service_contract_name]
if prs_lists['provided']:
aim_prov_contract_name = str(self.name_mapper.policy_rule_set(
self._neutron_context.session, prs_lists['provided']['id']))
expected_prov_contract_names.append(aim_prov_contract_name)
self.assertItemsEqual(expected_prov_contract_names,
aim_epg.provided_contract_names)
if prs_lists['consumed']:
aim_cons_contract_name = str(self.name_mapper.policy_rule_set(
self._neutron_context.session, prs_lists['consumed']['id']))
expected_cons_contract_names.append(aim_cons_contract_name)
self.assertItemsEqual(expected_cons_contract_names,
aim_epg.consumed_contract_names)
def _validate_router_interface_created(self, num_address_families=1):
# check port is created on default router
ports = self._plugin.get_ports(self._context)
total_ports = total_subnets = num_address_families
self.assertEqual(total_ports, len(ports))
routers = self._l3_plugin.get_routers(self._context)
self.assertEqual(1, len(routers))
subnets = self._plugin.get_subnets(self._context)
self.assertEqual(total_subnets, len(subnets))
subnet_ids = [subnet['id'] for subnet in subnets]
for port in ports:
self.assertEqual('network:router_interface',
port['device_owner'])
self.assertEqual(routers[0]['id'],
port['device_id'])
self.assertEqual(1, len(port['fixed_ips']))
self.assertIn(port['fixed_ips'][0]['subnet_id'], subnet_ids)
def _test_policy_target_group_aim_mappings(self, ptg, prs_lists, l2p,
num_address_families=1):
self._validate_router_interface_created(
num_address_families=num_address_families)
ptg_id = ptg['id']
if ptg['id'].startswith(aimd.AUTO_PTG_PREFIX):
# the test policy.json restricts auto-ptg access to admin
ptg_show = self.show_policy_target_group(
ptg_id, is_admin_context=True,
expected_res_status=200)['policy_target_group']
else:
ptg_show = self.show_policy_target_group(
ptg_id, expected_res_status=200)['policy_target_group']
aim_epg_name = self.driver.apic_epg_name_for_policy_target_group(
self._neutron_context.session, ptg_id,
context=self._neutron_context)
aim_tenant_name = self.name_mapper.project(None, self._tenant_id)
aim_app_profile_name = self.driver.aim_mech_driver.ap_name
aim_app_profiles = self.aim_mgr.find(
self._aim_context, aim_resource.ApplicationProfile,
tenant_name=aim_tenant_name, name=aim_app_profile_name)
self.assertEqual(1, len(aim_app_profiles))
req = self.new_show_request('networks', l2p['network_id'],
fmt=self.fmt)
net = self.deserialize(self.fmt,
req.get_response(self.api))['network']
bd = self.aim_mgr.get(
self._aim_context, aim_resource.BridgeDomain.from_dn(
net['apic:distinguished_names']['BridgeDomain']))
aim_epgs = self.aim_mgr.find(
self._aim_context, aim_resource.EndpointGroup, name=aim_epg_name)
self.assertEqual(1, len(aim_epgs))
self.assertEqual(aim_epg_name, aim_epgs[0].name)
self.assertEqual(aim_tenant_name, aim_epgs[0].tenant_name)
if not ptg['id'].startswith(aimd.AUTO_PTG_PREFIX):
# display_name of default EPG should not be mutated
# if the name of the auto-ptg is edited, but should
# and this should be validated in the auto-ptg tests
epg_display_name = ptg['name'].replace(' ', '_')
self.assertEqual(epg_display_name, aim_epgs[0].display_name)
self.assertEqual(bd.name, aim_epgs[0].bd_name)
self._validate_contracts(ptg, aim_epgs[0], prs_lists, l2p)
self.assertEqual(aim_epgs[0].dn,
ptg['apic:distinguished_names']['EndpointGroup'])
self._test_aim_resource_status(aim_epgs[0], ptg)
self.assertEqual(aim_epgs[0].dn,
ptg_show['apic:distinguished_names']['EndpointGroup'])
self._test_aim_resource_status(aim_epgs[0], ptg_show)
def _validate_l2_policy_deleted(self, l2p, implicit_l3p=True):
l2p_id = l2p['id']
l3p_id = l2p['l3_policy_id']
network_id = l2p['network_id']
self.delete_l2_policy(l2p_id, expected_res_status=204)
self.show_l2_policy(l2p_id, expected_res_status=404)
req = self.new_show_request('networks', network_id, fmt=self.fmt)
res = req.get_response(self.api)
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
l2ps = self._gbp_plugin.get_l2_policies(
self._neutron_context)
if len(l2ps) == 0:
apic_tenant_name = self.name_mapper.project(None, self._tenant_id)
epgs = self.aim_mgr.find(
self._aim_context, aim_resource.EndpointGroup,
tenant_name=apic_tenant_name)
self.assertEqual(0, len(epgs))
if implicit_l3p:
self.show_l3_policy(l3p_id, expected_res_status=404)
else:
self._validate_implicit_contracts_exist(l3p_id)
def _get_nsp_ptg_fip_mapping(self, ptg_id):
ctx = nctx.get_admin_context()
with ctx.session.begin(subtransactions=True):
return (ctx.session.query(
nsp_manager.ServicePolicyPTGFipMapping).
filter_by(policy_target_group_id=ptg_id).
all())
def _validate_contract_subject_filters(
self, contract_subject, policy_rules):
self.assertFalse(contract_subject.bi_filters)
expected_in_filters = []
expected_out_filters = []
for idx in range(0, len(policy_rules)):
pc = self.show_policy_classifier(
policy_rules[idx]['policy_classifier_id'])['policy_classifier']
fwd_filter = self.name_mapper.policy_rule(None,
policy_rules[idx]['id'])
protocol = pc['protocol']
if protocol in alib.REVERSIBLE_PROTOCOLS:
rev_filter = 'reverse-%s' % fwd_filter
else:
rev_filter = None
direction = pc['direction']
if direction == gp_const.GP_DIRECTION_IN:
expected_in_filters.append(fwd_filter)
if rev_filter:
expected_out_filters.append(rev_filter)
elif direction == gp_const.GP_DIRECTION_OUT:
expected_out_filters.append(fwd_filter)
if rev_filter:
expected_in_filters.append(rev_filter)
else:
expected_in_filters.append(fwd_filter)
expected_out_filters.append(fwd_filter)
if rev_filter:
expected_in_filters.append(rev_filter)
expected_out_filters.append(rev_filter)
self.assertItemsEqual(expected_in_filters,
contract_subject.in_filters)
self.assertItemsEqual(expected_out_filters,
contract_subject.out_filters)
def _validate_merged_status(self, contract, contract_subject, prs):
merged_status = self.driver._merge_aim_status(
self._neutron_context.session,
[contract, contract_subject])
self.assertEqual(merged_status, prs['status'])
def _validate_policy_rule_set_aim_mapping(self, prs, rules):
self.show_policy_rule_set(prs['id'], expected_res_status=200)
aim_contract_name = str(self.name_mapper.policy_rule_set(
self._neutron_context.session, prs['id']))
aim_contracts = self.aim_mgr.find(
self._aim_context, aim_resource.Contract, name=aim_contract_name)
self.assertEqual(1, len(aim_contracts))
self.assertEqual(prs['name'], aim_contracts[0].display_name)
aim_contract_subjects = self.aim_mgr.find(
self._aim_context, aim_resource.ContractSubject,
name=aim_contract_name)
self.assertEqual(1, len(aim_contract_subjects))
self._validate_contract_subject_filters(
aim_contract_subjects[0], rules)
self._validate_merged_status(
aim_contracts[0], aim_contract_subjects[0], prs)
def _validate_policy_rule_deleted(self, prs):
aim_contract_name = str(self.name_mapper.policy_rule_set(
self._neutron_context.session, prs['id']))
self.show_policy_rule_set(prs['id'], expected_res_status=404)
aim_contracts = self.aim_mgr.find(
self._aim_context, aim_resource.Contract, name=aim_contract_name)
self.assertEqual(0, len(aim_contracts))
def _check_ip_in_cidr(self, ip_addr, cidr):
self.assertTrue(netaddr.IPAddress(ip_addr) in netaddr.IPNetwork(cidr))
class TestGBPStatus(AIMBaseTestCase):
def test_status_merging(self):
gbp_active = {'status': gp_const.STATUS_ACTIVE}
gbp_objs = [gbp_active, gbp_active]
mstatus = self.driver._merge_gbp_status(gbp_objs)
self.assertEqual(gp_const.STATUS_ACTIVE, mstatus)
gbp_build = {'status': gp_const.STATUS_BUILD}
gbp_objs = [gbp_active, gbp_build]
mstatus = self.driver._merge_gbp_status(gbp_objs)
self.assertEqual(gp_const.STATUS_BUILD, mstatus)
gbp_error = {'status': gp_const.STATUS_ERROR}
gbp_objs = [gbp_active, gbp_build, gbp_error]
mstatus = self.driver._merge_gbp_status(gbp_objs)
self.assertEqual(gp_const.STATUS_ERROR, mstatus)
class TestAIMStatus(AIMBaseTestCase):
def test_status_merging(self):
def mock_get_aim_status(aim_context, aim_resource,
create_if_absent=True):
astatus = aim_status.AciStatus(resource_root=aim_resource.root)
if aim_resource.status == '':
return
elif aim_resource.status == 'build':
astatus.sync_status = aim_status.AciStatus.SYNC_PENDING
elif aim_resource.status == 'error':
astatus.sync_status = aim_status.AciStatus.SYNC_FAILED
else:
astatus.sync_status = aim_status.AciStatus.SYNCED
return astatus
orig_get_status = self.aim_mgr.get_status
self.aim_mgr.get_status = mock_get_aim_status
aim_active = aim_resource.Tenant(name='active')
aim_active.status = 'active'
aim_objs_active = [aim_active, aim_active, aim_active]
mstatus = self.driver._merge_aim_status(self._neutron_context.session,
aim_objs_active)
self.assertEqual(gp_const.STATUS_ACTIVE, mstatus)
aim_build = aim_resource.Tenant(name='build')
aim_build.status = 'build'
aim_none = aim_resource.Tenant(name='none')
aim_none.status = ''
aim_objs_build = [aim_active, aim_active, aim_build]
mstatus = self.driver._merge_aim_status(self._neutron_context.session,
aim_objs_build)
self.assertEqual(gp_const.STATUS_BUILD, mstatus)
aim_objs_build = [aim_active, aim_active, aim_none]
mstatus = self.driver._merge_aim_status(self._neutron_context.session,
aim_objs_build)
self.assertEqual(gp_const.STATUS_BUILD, mstatus)
aim_error = aim_resource.Tenant(name='error')
aim_error.status = 'error'
aim_objs_error = [aim_active, aim_build, aim_error]
mstatus = self.driver._merge_aim_status(self._neutron_context.session,
aim_objs_error)
self.assertEqual(gp_const.STATUS_ERROR, mstatus)
self.aim_mgr.get_status = orig_get_status
class TestL3Policy(AIMBaseTestCase):
def _test_update_l3_policy_subnetpool(
self, l3p, prefixes, ip_version=4, implicit_pool=True, shared=False,
tenant_id=None, subnet_prefix_length=24):
if ip_version == 4 or ip_version == 46:
subnetpools_version = 'subnetpools_v4'
ascp_id = l3p['address_scope_v4_id']
if ip_version == 6 or ip_version == 46:
subnetpools_version = 'subnetpools_v6'
ascp_id = l3p['address_scope_v6_id']
implicit_subpool = []
if implicit_pool:
implicit_subpool = l3p['subnetpools_v4'] if ip_version == 4 else (
l3p['subnetpools_v6'])
if not tenant_id:
tenant_id = self._tenant_id
sp2 = self._make_subnetpool(
self.fmt, prefixes, name='sp2', address_scope_id=ascp_id,
tenant_id=tenant_id, shared=shared)['subnetpool']
self.assertEqual(ascp_id, sp2['address_scope_id'])
self.assertEqual(prefixes, sp2['prefixes'])
implicit_ip_pool = l3p['ip_pool']
implicit_subnet_prefix_length = l3p['subnet_prefix_length']
# Preserve existing subnetpools including implicitly created subnetpool
new_subnetpools = implicit_subpool + [sp2['id']]
attrs = {'id': l3p['id'], subnetpools_version: new_subnetpools}
l3p = self.update_l3_policy(**attrs)['l3_policy']
prefixlist = [prefix.strip() for prefix in l3p['ip_pool'].split(',')]
implicitlist = [prefix.strip()
for prefix in implicit_ip_pool.split(',')]
for prefix in prefixlist:
self.assertIn(prefix, prefixes + implicitlist)
self.assertEqual(l3p['subnet_prefix_length'], subnet_prefix_length)
self.assertItemsEqual(new_subnetpools, l3p[subnetpools_version])
attrs = {'id': l3p['id'], subnetpools_version: implicit_subpool}
l3p = self.update_l3_policy(**attrs)['l3_policy']
self.assertEqual(implicit_ip_pool, l3p['ip_pool'])
self.assertEqual(implicit_subnet_prefix_length,
l3p['subnet_prefix_length'])
self.assertItemsEqual(implicit_subpool, l3p[subnetpools_version])
req = self.new_delete_request('subnetpools', sp2['id'])
res = req.get_response(self.api)
self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
def _extend_ip_pool(self, ip_pool, prefixes):
if ip_pool:
return ','.join(ip_pool.split(',') + prefixes.split(','))
else:
return prefixes
# TODO(tbachman): change isomorphic default to False, once
# non-isomorphic VRFs are supported
def _create_l3_policy_for_lifecycle_tests(
self, explicit_address_scope=False, explicit_subnetpool=False,
ip_version=4, ip_pool=None, subnet_prefix_length=24,
tenant_id=None, shared=False, v4_default=False,
v6_default=False, isomorphic=True,
no_address_scopes=False):
if not tenant_id:
tenant_id = self._tenant_id
attrs = {'name': 'l3p1', 'ip_version': ip_version, 'shared': shared,
'ip_pool': ip_pool,
'subnet_prefix_length': subnet_prefix_length}
address_scope_v4 = address_scope_v6 = None
if explicit_address_scope or v4_default or v6_default:
if ip_version == 4 or ip_version == 46:
address_scope_v4 = self._make_address_scope(
self.fmt, 4, name='as1v4',
shared=shared)['address_scope']
if not v4_default:
attrs['address_scope_v4_id'] = address_scope_v4['id']
if ip_version == 6 or ip_version == 46:
if ((isomorphic and address_scope_v4) or
(v4_default and v6_default)):
address_scope_v6 = self._make_address_scope_for_vrf(
address_scope_v4[DN][VRF],
6, name='as1v6', shared=shared)['address_scope']
self.assertEqual(address_scope_v6[DN],
address_scope_v4[DN])
else:
address_scope_v6 = self._make_address_scope(
self.fmt, 6, name='as1v6',
shared=shared)['address_scope']
if not v6_default:
attrs['address_scope_v6_id'] = address_scope_v6['id']
ip_pool_v4 = ip_pool_v6 = None
if ip_version == 4 or ip_version == 46:
if not ip_pool:
ip_pool_v4 = '192.168.0.0/16'
if explicit_subnetpool or v4_default:
sp = self._make_subnetpool(
self.fmt, [ip_pool_v4], name='sp1v4',
is_default=v4_default,
address_scope_id=address_scope_v4['id'],
tenant_id=tenant_id, shared=shared)['subnetpool']
if explicit_subnetpool:
attrs['subnetpools_v4'] = [sp['id']]
if ip_version == 6 or ip_version == 46:
if not ip_pool:
ip_pool_v6 = 'fd6d:8d64:af0c::/64'
if explicit_subnetpool or v6_default:
sp = self._make_subnetpool(
self.fmt, [ip_pool_v6], name='sp1v6',
is_default=v6_default,
address_scope_id=address_scope_v6['id'],
tenant_id=tenant_id, shared=shared)['subnetpool']
if explicit_subnetpool:
attrs['subnetpools_v6'] = [sp['id']]
if ip_pool_v4 and not v4_default and not no_address_scopes:
attrs['ip_pool'] = self._extend_ip_pool(attrs['ip_pool'],
ip_pool_v4)
if ip_pool_v6 and not v6_default and not no_address_scopes:
attrs['ip_pool'] = self._extend_ip_pool(attrs['ip_pool'],
ip_pool_v6)
# Create L3 policy with implicit address_scope, subnetpool and router
l3p = self.create_l3_policy(**attrs)['l3_policy']
self._validate_create_l3_policy(l3p,
utils.convert_ip_pool_string_to_list(l3p['ip_pool']),
isomorphic=isomorphic)
self._validate_status('show_l3_policy', l3p['id'])
return l3p
# TODO(tbachman): change isomorphic default to False, once
# non-isomorphic VRFs are supported
def _test_l3_policy_lifecycle(self, explicit_address_scope=False,
explicit_subnetpool=False,
ip_version=4, ip_pool=None,
subnet_prefix_length=24, tenant_id=None,
shared=False, v4_default=False,
v6_default=False, isomorphic=True,
no_address_scopes=False):
l3p = self._create_l3_policy_for_lifecycle_tests(
explicit_address_scope=explicit_address_scope,
explicit_subnetpool=explicit_subnetpool, ip_version=ip_version,
ip_pool=ip_pool, subnet_prefix_length=subnet_prefix_length,
tenant_id=tenant_id, shared=shared,
v4_default=v4_default,
v6_default=v6_default,
isomorphic=isomorphic,
no_address_scopes=no_address_scopes)
if not tenant_id:
tenant_id = l3p['tenant_id']
if ip_version == 4 or ip_version == 46:
self._test_update_l3_policy_subnetpool(
l3p, prefixes=['10.0.0.0/8'], ip_version=4, shared=shared,
tenant_id=tenant_id)
if ip_version == 6 or ip_version == 46:
self._test_update_l3_policy_subnetpool(
l3p, prefixes=['fd6d:8d64:af0c:1::/64'], ip_version=6,
shared=shared, tenant_id=tenant_id)
# TODO(Sumit): Test update of other relevant attributes
self._validate_delete_l3_policy(
l3p, explicit_address_scope=explicit_address_scope,
explicit_subnetpool=explicit_subnetpool,
v4_default=v4_default, v6_default=v6_default)
def test_unshared_l3_policy_v4_lifecycle_implicit_address_scope(self):
self._test_l3_policy_lifecycle()
def test_shared_l3_policy_v4_lifecycle_implicit_address_scope(self):
self._test_l3_policy_lifecycle(shared=True)
def test_unshared_l3_policy_v6_lifecycle_implicit_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=6)
def test_shared_l3_policy_v6_lifecycle_implicit_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=6, shared=True)
def test_unshared_l3_policy_dual_lifecycle_implicit_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46)
def test_unshared_l3_policy_dual_lifecycle_implicit_2_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46,
v4_default=True, v6_default=True)
def test_unshared_l3_policy_dual_lifecycle_implicit_3_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46, v4_default=True)
def test_unshared_l3_policy_dual_lifecycle_implicit_4_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46, v6_default=True)
def test_shared_l3_policy_dual_lifecycle_implicit_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46, shared=True)
def test_shared_l3_policy_dual_lifecycle_implicit_2_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46, shared=True,
v4_default=True, v6_default=True)
def test_shared_l3_policy_dual_lifecycle_implicit_3_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46, shared=True,
v4_default=True)
def test_shared_l3_policy_dual_lifecycle_implicit_4_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46, shared=True,
v6_default=True)
def test_unshared_l3_policy_lifecycle_explicit_address_scope_v4(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True)
def test_shared_l3_policy_lifecycle_explicit_address_scope_v4(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
shared=True)
def test_unshared_l3_policy_lifecycle_explicit_address_scope_v6(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
ip_version=6)
def test_shared_l3_policy_lifecycle_explicit_address_scope_v6(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
ip_version=6, shared=True)
def test_unshared_l3_policy_lifecycle_explicit_address_scope_dual(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
ip_version=46)
def test_unshared_l3_policy_lifecycle_explicit_address_scope_iso(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
ip_version=46, isomorphic=True)
def test_shared_l3_policy_lifecycle_explicit_address_scope_dual(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
ip_version=46, shared=True)
def test_shared_l3_policy_lifecycle_explicit_address_scope_iso(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
ip_version=46, shared=True, isomorphic=True)
def test_unshared_create_l3_policy_explicit_subnetpool_v4(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
explicit_subnetpool=True)
def test_shared_create_l3_policy_explicit_subnetpool_v4(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
explicit_subnetpool=True, shared=True)
def test_unshared_create_l3_policy_explicit_subnetpool_v6(self):
self._test_l3_policy_lifecycle(
explicit_address_scope=True, explicit_subnetpool=True,
ip_version=6)
def test_shared_create_l3_policy_explicit_subnetpool_v6(self):
self._test_l3_policy_lifecycle(
explicit_address_scope=True, explicit_subnetpool=True,
ip_version=6, shared=True)
def test_unshared_create_l3_policy_explicit_subnetpool_dual(self):
self._test_l3_policy_lifecycle(
explicit_address_scope=True, explicit_subnetpool=True,
ip_version=46, ip_pool=None)
def test_shared_create_l3_policy_explicit_subnetpool_dual(self):
self._test_l3_policy_lifecycle(
explicit_address_scope=True, explicit_subnetpool=True,
ip_version=46, shared=True)
def test_unshared_l3_policy_lifecycle_no_address_scope(self):
self.assertRaises(webob.exc.HTTPClientError,
self._test_l3_policy_lifecycle,
no_address_scopes=True)
def test_unshared_l3_policy_lifecycle_no_address_scope(self):
with self.address_scope(ip_version=4, shared=True) as ascpv4:
ascpv4 = ascpv4['address_scope']
with self.address_scope(ip_version=6, shared=True) as ascpv6:
ascpv6 = ascpv6['address_scope']
self.assertRaises(webob.exc.HTTPClientError,
self.create_l3_policy,
ip_version=46,
address_scope_v4_id=ascpv4['id'],
address_scope_v6_id=ascpv6['id'])
def test_create_l3p_shared_addr_scp_explicit_unshared_subnetpools(self):
with self.address_scope(ip_version=4, shared=True) as ascpv4:
ascpv4 = ascpv4['address_scope']
with self.subnetpool(
name='sp1v4', prefixes=['192.168.0.0/16'],
tenant_id=ascpv4['tenant_id'], default_prefixlen=24,
address_scope_id=ascpv4['id'], shared=False) as sp1v4:
sp1v4 = sp1v4['subnetpool']
# As admin, create a subnetpool in a different tenant
# but associated with the same address_scope
sp2v4 = self._make_subnetpool(
self.fmt, ['10.1.0.0/16'], name='sp2v4',
tenant_id='test-tenant-2', address_scope_id=ascpv4['id'],
default_prefixlen=24, shared=False,
admin=True)['subnetpool']
l3p = self.create_l3_policy(
name="l3p1", subnetpools_v4=[sp1v4['id'], sp2v4['id']]
)['l3_policy']
self.assertEqual(ascpv4['id'], sp1v4['address_scope_id'])
self.assertEqual(ascpv4['id'], l3p['address_scope_v4_id'])
for prefix in sp1v4['prefixes'] + sp2v4['prefixes']:
self.assertIn(prefix, l3p['ip_pool'])
self.assertEqual(24, l3p['subnet_prefix_length'])
self._validate_create_l3_policy(
l3p, compare_subnetpool_shared_attr=False)
self.assertEqual(2, len(l3p['subnetpools_v4']))
sp3v4 = self._make_subnetpool(
self.fmt, ['10.2.0.0/16'], name='sp3v4',
tenant_id='test-tenant-3', address_scope_id=ascpv4['id'],
default_prefixlen=24, shared=False,
admin=True)['subnetpool']
l3p = self.update_l3_policy(
l3p['id'],
subnetpools_v4=[sp1v4['id'], sp2v4['id'], sp3v4['id']])[
'l3_policy']
self.assertEqual(3, len(l3p['subnetpools_v4']))
self._validate_create_l3_policy(
l3p, compare_subnetpool_shared_attr=False)
self._validate_delete_l3_policy(
l3p, explicit_address_scope=True, explicit_subnetpool=True)
def _test_update_l3_policy_replace_implicit_subnetpool(
self, in_use=False, shared=False):
if in_use:
# We will create a L2P with auto-ptg so that a subnet
# is created that is associated with the implcit
# subnetpool of the l3p
self.driver.create_auto_ptg = True
l3p = self._create_l3_policy_for_lifecycle_tests(shared=shared)
ascp_id = l3p['address_scope_v4_id']
implicit_ip_pool = l3p['ip_pool']
implicit_subnet_prefix_length = l3p['subnet_prefix_length']
implicit_subpool_id = l3p['subnetpools_v4'][0]
# if address_scope is shared, use a different tenant for subnetpool
# to simulate cross-tenant scenario
sp_tenant_id = 'test-tenant-2' if shared else self._tenant_id
new_prefixes = ['10.0.0.0/16']
# if address_scope is shared, subnetpool is created in a different
# tenant, so use admin role
sp2 = self._make_subnetpool(
self.fmt, new_prefixes, name='sp2', address_scope_id=ascp_id,
tenant_id=sp_tenant_id, admin=shared)['subnetpool']
self.assertEqual(ascp_id, sp2['address_scope_id'])
self.assertEqual(new_prefixes, sp2['prefixes'])
attrs = {'id': l3p['id'], 'subnetpools_v4': [sp2['id']]}
if in_use:
# Add an L2 Policy to the L3 Policy, with create_auto_ptg = True,
# which will create a PTG for the L2P
l2p = self.create_l2_policy(name="l2p0",
l3_policy_id=l3p['id'])['l2_policy']
attrs['expected_res_status'] = webob.exc.HTTPBadRequest.code
# Try replacing the existing prefix/subnetpool with the one
# created above -- it should fail
self.update_l3_policy(**attrs)
# Remove the L2 policy, so that we can now replace the
# subnetpool
self.delete_l2_policy(l2p['id'], expected_res_status=204)
attrs['expected_res_status'] = webob.exc.HTTPOk.code
l3p = self.update_l3_policy(**attrs)['l3_policy']
self.assertEqual(sp2['id'], l3p['subnetpools_v4'][0])
for prefix in sp2['prefixes']:
self.assertIn(prefix, l3p['ip_pool'])
self.assertNotEqual(implicit_ip_pool, l3p['ip_pool'])
if implicit_subnet_prefix_length:
self.assertEqual(implicit_subnet_prefix_length,
l3p['subnet_prefix_length'])
# implicit subnetpool is deleted
req = self.new_show_request('subnetpools', implicit_subpool_id,
fmt=self.fmt)
res = req.get_response(self.api)
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
# Reset in case it was set earlier
self.driver.create_auto_ptg = False
def test_update_unshared_l3_policy_replace_implicit_subnetpool(self):
self._test_update_l3_policy_replace_implicit_subnetpool()
def test_update_shared_l3_policy_replace_implicit_subnetpool(self):
self._test_update_l3_policy_replace_implicit_subnetpool(shared=True)
def test_update_shared_l3_policy_replace_in_use_implicit_subnetpool(self):
self._test_update_l3_policy_replace_implicit_subnetpool(in_use=True,
shared=True)
def _check_routers_connections(self, l3p, ext_nets, eps, subnets):
routers = self._show_all('router', l3p['routers'])
routers = [r for r in routers if self._router_gw(r)]
self.assertEqual(len(ext_nets), len(routers))
self.assertEqual(sorted(ext_nets),
sorted([self._router_gw(r) for r in routers]))
session = self._neutron_context.session
for ext_net, ep in zip(ext_nets, eps):
router = [r for r in routers if self._router_gw(r) == ext_net]
prov = sorted([str(self.name_mapper.policy_rule_set(session, c))
for c in ep['provided_policy_rule_sets']])
cons = sorted([str(self.name_mapper.policy_rule_set(session, c))
for c in ep['consumed_policy_rule_sets']])
self.assertEqual(prov, sorted(router[0][PROV]))
self.assertEqual(cons, sorted(router[0][CONS]))
subnets = sorted(subnets)
for router in routers:
intf_ports = self._list('ports',
query_params=('device_id=' + router['id'] +
'&device_owner=network:router_interface')
)['ports']
intf_subnets = sorted([p['fixed_ips'][0]['subnet_id']
for p in intf_ports if p['fixed_ips']])
self.assertEqual(subnets, intf_subnets,
'Router %s' % router['name'])
def test_external_segment_routers(self):
ess = []
eps = []
ext_nets = []
for x in range(0, 2):
es_sub = self._make_ext_subnet('net%d' % x, '90.9%d.0.0/16' % x,
dn='uni/tn-t1/out-l%d/instP-n%x' % (x, x))
es = self.create_external_segment(
name='seg%d' % x, subnet_id=es_sub['id'],
external_routes=[{'destination': '12%d.0.0.0/24' % (8 + x),
'nexthop': None}])['external_segment']
ess.append(es)
prs1 = self.create_policy_rule_set(name='prs1')['policy_rule_set']
prs2 = self.create_policy_rule_set(name='prs2')['policy_rule_set']
ep = self.create_external_policy(
name='ep%d' % x,
provided_policy_rule_sets={prs1['id']: 'scope'},
consumed_policy_rule_sets={prs2['id']: 'scope'},
external_segments=[es['id']])['external_policy']
eps.append(ep)
ext_nets.append(es_sub['network_id'])
es_dict = {es['id']: [] for es in ess}
l3p = self.create_l3_policy(name='l3p1',
external_segments=es_dict)['l3_policy']
self._check_routers_connections(l3p, ext_nets, eps, [])
es_dict.pop(ess[0]['id'])
l3p = self.update_l3_policy(l3p['id'],
external_segments=es_dict)['l3_policy']
self._check_routers_connections(l3p, ext_nets[1:], eps[1:], [])
es_dict = {ess[0]['id']: ['']}
l3p = self.update_l3_policy(l3p['id'],
external_segments=es_dict)['l3_policy']
self._check_routers_connections(l3p, ext_nets[0:1], eps[0:1], [])
self.delete_l3_policy(l3p['id'])
for r in l3p['routers']:
self._show('routers', r, expected_code=404)
def test_external_segment_l2p_subnets(self):
ess = []
ext_nets = []
for x in range(0, 2):
es_sub = self._make_ext_subnet('net%d' % x, '90.9%d.0.0/16' % x,
dn='uni/tn-t1/out-l%d/instP-n%x' % (x, x))
es = self.create_external_segment(
name='seg%d' % x, subnet_id=es_sub['id'],
external_routes=[{'destination': '12%d.0.0.0/24' % (8 + x),
'nexthop': None}])['external_segment']
ess.append(es)
ext_nets.append(es_sub['network_id'])
l3p = self.create_l3_policy(name='l3p1',
external_segments={ess[0]['id']: []})['l3_policy']
all_subnets = []
ptgs = []
for x in range(0, 2):
l2p = self.create_l2_policy(name='l2p%d' % x,
l3_policy_id=l3p['id'])['l2_policy']
ptg = self.create_policy_target_group(name='ptg%d' % x,
l2_policy_id=l2p['id'])['policy_target_group']
ptgs.append(ptg)
all_subnets.extend(ptg['subnets'])
self._check_routers_connections(l3p, ext_nets[0:1], [],
all_subnets)
l3p = self.update_l3_policy(l3p['id'],
external_segments={ess[1]['id']: []})['l3_policy']
self._check_routers_connections(l3p, ext_nets[1:], [], all_subnets)
for ptg in ptgs:
self.delete_policy_target_group(ptg['id'])
# verify subnets were deleted
for s in ptg['subnets']:
self._show('subnets', s, expected_code=404)
def test_external_address(self):
es_sub = self._make_ext_subnet('net1', '90.90.0.0/16',
dn='uni/tn-t1/out-l1/instP-n1')
es = self.create_external_segment(
subnet_id=es_sub['id'])['external_segment']
l3p = self.create_l3_policy(
external_segments={es['id']: ['90.90.0.10']})['l3_policy']
routers = self._show_all('router', l3p['routers'])
routers = [r for r in routers if self._router_gw(r)]
self.assertEqual(1, len(routers))
ext_ip = routers[0]['external_gateway_info']['external_fixed_ips']
self.assertEqual([{'ip_address': '90.90.0.10',
'subnet_id': es_sub['id']}],
ext_ip)
def test_one_l3_policy_ip_on_es(self):
# Verify L3P created with more than 1 IP on ES fails
es_sub = self._make_ext_subnet('net1', '90.90.0.0/16',
dn='uni/tn-t1/out-l1/instP-n1')
es = self.create_external_segment(
subnet_id=es_sub['id'])['external_segment']
res = self.create_l3_policy(
external_segments={es['id']: ['90.90.0.2', '90.90.0.3']},
expected_res_status=400)
self.assertEqual('OnlyOneAddressIsAllowedPerExternalSegment',
res['NeutronError']['type'])
# Verify L3P updated to more than 1 IP on ES fails
sneaky_l3p = self.create_l3_policy(
external_segments={es['id']: ['90.90.0.2']},
expected_res_status=201)['l3_policy']
res = self.update_l3_policy(
sneaky_l3p['id'], expected_res_status=400,
external_segments={es['id']: ['90.90.0.2', '90.90.0.3']})
self.assertEqual('OnlyOneAddressIsAllowedPerExternalSegment',
res['NeutronError']['type'])
def test_one_l3_policy_per_es_with_no_nat(self):
# Verify only one L3P can connect to ES with no-NAT
es_sub = self._make_ext_subnet('net1', '90.90.0.0/16',
dn='uni/tn-t1/out-l1/instP-n1',
nat_type='')
es = self.create_external_segment(
subnet_id=es_sub['id'])['external_segment']
self.create_l3_policy(external_segments={es['id']: []})
res = self.create_l3_policy(
external_segments={es['id']: []},
expected_res_status=400)
self.assertEqual('OnlyOneL3PolicyIsAllowedPerExternalSegment',
res['NeutronError']['type'])
def test_l3_policy_with_multiple_routers(self):
with self.router() as r1, self.router() as r2:
res = self.create_l3_policy(
routers=[r1['router']['id'], r2['router']['id']],
expected_res_status=400)
self.assertEqual('L3PolicyMultipleRoutersNotSupported',
res['NeutronError']['type'])
class TestLegacyL3Policy(TestL3Policy):
def setUp(self, **kwargs):
orig_create_per_l3p_implicit_contracts = (
aimd.AIMMappingDriver._create_per_l3p_implicit_contracts)
def _create_per_l3p_implicit_contracts(self):
session = nctx.get_admin_context().session
with session.begin(subtransactions=True):
l3p_db = group_policy_mapping_db.L3PolicyMapping(
id='1234', tenant_id='some_tenant',
name='test-l3p', description='test-desc',
ip_version=4, ip_pool='10.0.0.0/8',
subnet_prefix_length=24, shared=False)
session.add(l3p_db)
session.flush()
orig_create_per_l3p_implicit_contracts(self)
aimd.AIMMappingDriver._create_per_l3p_implicit_contracts = (
orig_create_per_l3p_implicit_contracts)
aimd.AIMMappingDriver._create_per_l3p_implicit_contracts = (
_create_per_l3p_implicit_contracts)
super(TestLegacyL3Policy, self).setUp(**kwargs)
def test_create_implicit_contracts(self):
self._validate_implicit_contracts_created('1234')
l3p = self.create_l3_policy()['l3_policy']
context = type('', (object,), {})()
context._plugin_context = self._context
self.driver._delete_implicit_contracts(context, l3p)
self._validate_implicit_contracts_deleted(l3p['id'])
self.driver._create_per_l3p_implicit_contracts()
self._validate_implicit_contracts_created(l3p['id'])
class TestL3PolicyRollback(AIMBaseTestCase):
def test_l3_policy_create_fail(self):
orig_func = self.dummy.create_l3_policy_precommit
self.dummy.create_l3_policy_precommit = mock.Mock(
side_effect=Exception)
self.create_l3_policy(name="l3p1", expected_res_status=500)
self.assertEqual([], self._plugin.get_address_scopes(self._context,
filters={}))
self.assertEqual([], self._plugin.get_subnetpools(self._context,
filters={}))
self.assertEqual([], self._l3_plugin.get_routers(self._context))
self.assertEqual([], self._gbp_plugin.get_l3_policies(self._context))
# restore mock
self.dummy.create_l3_policy_precommit = orig_func
def test_l3_policy_update_fail(self):
orig_func = self.dummy.update_l3_policy_precommit
self.dummy.update_l3_policy_precommit = mock.Mock(
side_effect=Exception)
l3p = self.create_l3_policy(name="l3p1")['l3_policy']
l3p_id = l3p['id']
self.update_l3_policy(l3p_id, expected_res_status=500,
name="new name")
new_l3p = self.show_l3_policy(l3p_id, expected_res_status=200)
self.assertEqual(l3p['name'],
new_l3p['l3_policy']['name'])
# restore mock
self.dummy.update_l3_policy_precommit = orig_func
def test_l3_policy_delete_fail(self):
orig_func = self.dummy.delete_l3_policy_precommit
self.dummy.delete_l3_policy_precommit = mock.Mock(
side_effect=Exception)
l3p = self.create_l3_policy(name="l3p1")['l3_policy']
l3p_id = l3p['id']
self.delete_l3_policy(l3p_id, expected_res_status=500)
self.show_l3_policy(l3p_id, expected_res_status=200)
self.assertEqual(
1, len(self._plugin.get_address_scopes(self._context,
filters={})))
self.assertEqual(1, len(self._plugin.get_subnetpools(self._context,
filters={})))
self.assertEqual(1, len(self._l3_plugin.get_routers(self._context)))
# restore mock
self.dummy.delete_l3_policy_precommit = orig_func
class TestL2PolicyBase(test_nr_base.TestL2Policy, AIMBaseTestCase):
def _validate_default_epg_implicit_contracts(self, l2p):
self._validate_implicit_contracts_created(
l2p['l3_policy_id'], l2p=l2p)
def _validate_bd_tenant(self, l2p, expected_tenant):
network_id = l2p['network_id']
self.assertIsNotNone(network_id)
req = self.new_show_request('networks', network_id, fmt=self.fmt)
net = self.deserialize(self.fmt, req.get_response(self.api))['network']
self.assertIsNotNone(net['id'])
self.assertEqual(l2p['shared'], net['shared'])
bd = self.driver._get_bd_by_dn(
self._context, net[DN][BD])
self.assertEqual(
self.name_mapper.project(None, expected_tenant), bd.tenant_name)
def _validate_epg_tenant(self, ptg, expected_tenant):
epg = self.driver._get_epg_by_dn(
self._context, ptg[DN][EPG])
self.assertEqual(
self.name_mapper.project(None, expected_tenant), epg.tenant_name)
class TestL2Policy(TestL2PolicyBase):
def _test_l2_policy_lifecycle_implicit_l3p(self,
shared=False):
self.assertEqual(0, len(self.aim_mgr.find(
self._aim_context, aim_resource.Contract)))
self.assertEqual(1, len(self.aim_mgr.find(
self._aim_context, aim_resource.Filter)))
self.assertEqual(1, len(self.aim_mgr.find(
self._aim_context, aim_resource.FilterEntry)))
l2p0 = self.create_l2_policy(name="l2p0",
shared=shared)['l2_policy']
# This validates that the infra and implicit Contracts, etc.
# are created after the first L2P creation
self._validate_default_epg_implicit_contracts(l2p0)
l2p = self.create_l2_policy(name="l2p1",
shared=shared)['l2_policy']
self.assertEqual(gp_const.STATUS_BUILD, l2p['status'])
# This validates that the infra and implicit Contracts, etc.
# are not created after the second L2P creation
self._validate_default_epg_implicit_contracts(l2p)
l2p_id = l2p['id']
network_id = l2p['network_id']
l3p_id = l2p['l3_policy_id']
self.assertIsNotNone(network_id)
self.assertIsNotNone(l3p_id)
req = self.new_show_request('networks', network_id, fmt=self.fmt)
net = self.deserialize(self.fmt, req.get_response(self.api))['network']
self.assertIsNotNone(net['id'])
self.assertEqual(l2p['shared'], net['shared'])
self.show_l3_policy(l3p_id, expected_res_status=200)
self.show_l2_policy(l2p_id, expected_res_status=200)
self._validate_status('show_l2_policy', l2p_id)
self.update_l2_policy(l2p_id, expected_res_status=200,
name="new name")
self._switch_to_tenant2()
# Create l2p in a different tenant, check infra and implicit contracts
# created for that tenant
l2p_tenant2 = self.create_l2_policy(
name='l2p-alternate-tenant', shared=shared)['l2_policy']
self._validate_default_epg_implicit_contracts(l2p_tenant2)
self._switch_to_tenant1()
self._validate_l2_policy_deleted(l2p)
self._validate_l2_policy_deleted(l2p0)
# Validate that the Contracts still exist in the other tenant
self._switch_to_tenant2()
self._validate_default_epg_implicit_contracts(l2p_tenant2)
self._validate_l2_policy_deleted(l2p_tenant2)
self._switch_to_tenant1()
def test_unshared_l2_policy_lifecycle_implicit_l3p(self):
self._test_l2_policy_lifecycle_implicit_l3p()
def test_shared_l2_policy_lifecycle_implicit_l3p(self):
self._test_l2_policy_lifecycle_implicit_l3p(shared=True)
def _test_l2_policy_lifecycle_explicit_l3p(self, shared=False):
l3p = self.create_l3_policy(name="l3p1",
shared=shared)['l3_policy']
l2p = self.create_l2_policy(name="l2p1",
shared=shared,
l3_policy_id=l3p['id'])['l2_policy']
self.assertEqual(gp_const.STATUS_BUILD, l2p['status'])
self._validate_default_epg_implicit_contracts(l2p)
self.assertEqual(l2p['shared'], l3p['shared'])
network_id = l2p['network_id']
l3p_id = l2p['l3_policy_id']
self.assertIsNotNone(network_id)
self.assertIsNotNone(l3p_id)
req = self.new_show_request('networks', network_id, fmt=self.fmt)
net = self.deserialize(self.fmt, req.get_response(self.api))['network']
self.assertIsNotNone(net['id'])
self.assertEqual(l2p['shared'], net['shared'])
self._validate_l2_policy_deleted(l2p, implicit_l3p=False)
self.delete_l3_policy(l3p_id)
def test_unshared_l2_policy_lifecycle_explicit_l3p(self):
self._test_l2_policy_lifecycle_explicit_l3p()
def test_shared_l2_policy_lifecycle_explicit_l3p(self):
self._test_l2_policy_lifecycle_explicit_l3p(shared=True)
def test_unshared_l2_policy_shared_l3p_cross_tenant(self):
l3p = self.create_l3_policy(name="l3p1",
shared=True)['l3_policy']
self._switch_to_tenant2()
l2p = self.create_l2_policy(name="l2p1",
shared=False,
l3_policy_id=l3p['id'])['l2_policy']
self.assertEqual(gp_const.STATUS_BUILD, l2p['status'])
self._validate_default_epg_implicit_contracts(l2p)
l3p_id = l2p['l3_policy_id']
self.assertIsNotNone(l3p_id)
self.assertEqual(l2p['shared'], not l3p['shared'])
# BD is in tenant2 since there is no PTG yet in the L2P
self._validate_bd_tenant(l2p, l2p['tenant_id'])
ptg = self.create_policy_target_group(
l2_policy_id=l2p['id'])['policy_target_group']
# After creation of first PTG, BD is now in L3P's tenant
self._validate_bd_tenant(l2p, l3p['tenant_id'])
# EPG is now in L3P's tenant
self._validate_epg_tenant(ptg, l3p['tenant_id'])
self.delete_policy_target_group(ptg['id'], expected_res_status=204)
self._validate_l2_policy_deleted(l2p, implicit_l3p=False)
self._switch_to_tenant1()
self.delete_l3_policy(l3p_id)
class TestL2PolicyWithAutoPTG(TestL2PolicyBase):
def setUp(self, **kwargs):
super(TestL2PolicyWithAutoPTG, self).setUp(**kwargs)
self.driver.create_auto_ptg = True
def tearDown(self):
super(TestL2PolicyWithAutoPTG, self).tearDown()
self.driver.create_auto_ptg = False
def _get_auto_ptg(self, l2p):
ptg = self._gbp_plugin.get_policy_target_groups(
self._neutron_context)[0]
l2p_id = ptg['l2_policy_id']
auto_ptg_id = aimd.AUTO_PTG_ID_PREFIX % hashlib.md5(l2p_id).hexdigest()
self.assertEqual(auto_ptg_id, ptg['id'])
self.assertEqual(aimd.AUTO_PTG_NAME_PREFIX % l2p_id, str(ptg['name']))
return ptg
def _test_auto_ptg(self, l2p, shared=False):
ptg = self._get_auto_ptg(l2p)
self.assertEqual(shared, ptg['shared'])
prs_lists = self._get_provided_consumed_prs_lists(shared)
# the test policy.json restricts auto-ptg access to admin
ptg = self.update_policy_target_group(
ptg['id'], is_admin_context=True,
expected_res_status=webob.exc.HTTPOk.code,
name='new name', description='something-else',
provided_policy_rule_sets={prs_lists['provided']['id']:
'scope'},
consumed_policy_rule_sets={prs_lists['consumed']['id']:
'scope'})['policy_target_group']
self._test_policy_target_group_aim_mappings(
ptg, prs_lists, l2p)
# Shared status cannot be updated
self.update_policy_target_group(
ptg['id'], is_admin_context=True, shared=(not shared),
expected_res_status=webob.exc.HTTPBadRequest.code)
# Auto PTG cannot be deleted by user
res = self.delete_policy_target_group(
ptg['id'], expected_res_status=webob.exc.HTTPBadRequest.code)
self.assertEqual('AutoPTGDeleteNotSupported',
res['NeutronError']['type'])
aim_epg_name = self.driver.apic_epg_name_for_policy_target_group(
self._neutron_context.session, ptg['id'],
context=self._neutron_context)
aim_epg = self.aim_mgr.find(
self._aim_context, aim_resource.EndpointGroup,
name=aim_epg_name)[0]
aim_epg_display_name = aim_epg.display_name
ptg = self.update_policy_target_group(
ptg['id'], expected_res_status=webob.exc.HTTPOk.code,
is_admin_context=True,
name='new name', description='something-else',
provided_policy_rule_sets={},
consumed_policy_rule_sets={})['policy_target_group']
self._test_policy_target_group_aim_mappings(
ptg, {'provided': None, 'consumed': None}, l2p)
aim_epg = self.aim_mgr.find(
self._aim_context, aim_resource.EndpointGroup,
name=aim_epg_name)[0]
self.assertEqual(aim_epg_display_name, aim_epg.display_name)
self._delete_prs_dicts_and_rules(prs_lists)
self._validate_l2_policy_deleted(l2p)
self.show_policy_target_group(ptg['id'], expected_res_status=404)
def _test_multiple_l2p_post_create(self, shared=False):
l2p = self.create_l2_policy(name="l2p0", shared=shared)['l2_policy']
self._test_auto_ptg(l2p, shared=shared)
# At this time first l2p and auto-ptg for that l2p are deleted
self.create_l2_policy(name="l2p1", shared=shared)['l2_policy']
self.create_l2_policy(name="l2p2", shared=shared)['l2_policy']
# Two new l2ps are created, and each one should have their own auto-ptg
ptgs = self._gbp_plugin.get_policy_target_groups(self._neutron_context)
self.assertEqual(2, len(ptgs))
def test_auto_ptg_lifecycle_shared(self):
self._test_multiple_l2p_post_create(shared=True)
def test_auto_ptg_lifecycle_unshared(self):
self._test_multiple_l2p_post_create()
def _test_epg_policy_enforcement_attr(self, ptg):
aim_epg_name = self.driver.apic_epg_name_for_policy_target_group(
db_api.get_writer_session(), ptg['id'],
context=self._neutron_context)
aim_epg = self.aim_mgr.find(
self._aim_context, aim_resource.EndpointGroup,
name=aim_epg_name)[0]
if aim_epg.policy_enforcement_pref == (
aim_resource.EndpointGroup.POLICY_UNENFORCED):
self.assertTrue(ptg['intra_ptg_allow'])
elif aim_epg.policy_enforcement_pref == (
aim_resource.EndpointGroup.POLICY_ENFORCED):
self.assertFalse(ptg['intra_ptg_allow'])
def _test_application_profile(self, apg, exists=True):
ap_name = self.driver.apic_ap_name_for_application_policy_group(
self._neutron_context.session, apg['id'])
aim_ap_list = self.aim_mgr.find(
self._aim_context, aim_resource.ApplicationProfile,
name=ap_name)
if exists:
self.assertEqual(1, len(aim_ap_list))
self.assertEqual(ap_name, aim_ap_list[0].name)
apg = self.show_application_policy_group(
apg['id'], expected_res_status=200)['application_policy_group']
ap = self.aim_mgr.get(
self._aim_context, aim_resource.ApplicationProfile.from_dn(
apg[DN][AP][0]))
self.assertEqual(aim_ap_list[0].name, ap.name)
else:
self.assertEqual(0, len(aim_ap_list))
def test_ptg_lifecycle(self):
# Once the testing strategy evolves to always assuming auto_ptg
# being present, this UT can be removed/merged with the UTs in the
# TestPolicyTargetGroup class
apg = self.create_application_policy_group()[
'application_policy_group']
apg_id = apg['id']
self.show_application_policy_group(apg_id, expected_res_status=200)
ptg = self.create_policy_target_group(application_policy_group_id=
apg['id'])['policy_target_group']
self.assertEqual(apg_id, ptg['application_policy_group_id'])
self._test_application_profile(apg)
self._test_epg_policy_enforcement_attr(ptg)
ptg_id = ptg['id']
l2p = self.show_l2_policy(ptg['l2_policy_id'],
expected_res_status=200)['l2_policy']
l3p = self.show_l3_policy(l2p['l3_policy_id'],
expected_res_status=200)['l3_policy']
ascopes = self._plugin.get_address_scopes(self._context,
filters={})
self.assertEqual(l3p['address_scope_v4_id'], ascopes[0]['id'])
subpools = self._plugin.get_subnetpools(self._context, filters={})
self.assertEqual(l3p['subnetpools_v4'], [subpools[0]['id']])
self.assertEqual(l3p['address_scope_v4_id'],
subpools[0]['address_scope_id'])
routers = self._l3_plugin.get_routers(self._context)
self.assertEqual(l3p['routers'], [routers[0]['id']])
req = self.new_show_request('subnets', ptg['subnets'][0], fmt=self.fmt)
subnet = self.deserialize(self.fmt,
req.get_response(self.api))['subnet']
self.assertIsNotNone(subnet['id'])
self.assertEqual(l3p['subnetpools_v4'][0],
subnet['subnetpool_id'])
new_apg = self.create_application_policy_group()[
'application_policy_group']
prs_lists = self._get_provided_consumed_prs_lists()
ptg = self.update_policy_target_group(
ptg_id, expected_res_status=200,
provided_policy_rule_sets={prs_lists['provided']['id']:
'scope'},
consumed_policy_rule_sets={prs_lists['consumed']['id']:
'scope'},
application_policy_group_id=new_apg['id'])['policy_target_group']
self._test_application_profile(new_apg)
self._test_application_profile(apg, exists=False)
self._test_epg_policy_enforcement_attr(ptg)
ptg = self.update_policy_target_group(
ptg_id, expected_res_status=200,
application_policy_group_id=None)['policy_target_group']
self._test_application_profile(new_apg, exists=False)
ptg = self.update_policy_target_group(
ptg_id, expected_res_status=200,
application_policy_group_id=new_apg['id'])['policy_target_group']
self._test_application_profile(new_apg)
auto_ptg_id = self.driver._get_auto_ptg_id(ptg['l2_policy_id'])
# the test policy.json restricts auto-ptg access to admin
auto_ptg = self.show_policy_target_group(
auto_ptg_id, is_admin_context=True,
expected_res_status=200)['policy_target_group']
self._test_epg_policy_enforcement_attr(auto_ptg)
res = self.update_policy_target_group(
auto_ptg_id, expected_res_status=webob.exc.HTTPBadRequest.code,
is_admin_context=True, application_policy_group_id=new_apg['id'])
self.assertEqual('ExplicitAPGAssociationNotSupportedForAutoPTG',
res['NeutronError']['type'])
ptg2 = self.create_policy_target_group(
application_policy_group_id=new_apg['id'])['policy_target_group']
self.delete_policy_target_group(ptg_id, expected_res_status=204)
self._test_application_profile(new_apg)
self.show_policy_target_group(ptg_id, expected_res_status=404)
self.delete_policy_target_group(ptg2['id'], expected_res_status=204)
self._test_application_profile(new_apg, exists=False)
self.show_policy_target_group(ptg2['id'], expected_res_status=404)
self.show_l2_policy(ptg['l2_policy_id'], expected_res_status=404)
self.delete_application_policy_group(apg_id, expected_res_status=204)
self.show_application_policy_group(apg_id, expected_res_status=404)
self.assertEqual([], self._plugin.get_ports(self._context))
self.assertEqual([], self._plugin.get_subnets(self._context))
self.assertEqual([], self._plugin.get_networks(self._context))
self.assertEqual([], self._plugin.get_address_scopes(self._context,
filters={}))
self.assertEqual([], self._plugin.get_subnetpools(self._context,
filters={}))
self.assertEqual([], self._l3_plugin.get_routers(self._context))
def test_auto_ptg_rbac(self):
ptg = self.create_policy_target_group()['policy_target_group']
# non-admin can create pt on non-auto-ptg
self.create_policy_target(policy_target_group_id=ptg['id'],
expected_res_status=201)
# admin can create pt on non-auto-ptg
self.create_policy_target(policy_target_group_id=ptg['id'],
is_admin_context=True,
expected_res_status=201)
# non-admin can retrieve and update non-auto-ptg
self.show_policy_target_group(ptg['id'], expected_res_status=200)
self.update_policy_target_group(
ptg['id'], expected_res_status=200, name='new_name')
# admin can retrieve and update non-auto-ptg
self.show_policy_target_group(ptg['id'], is_admin_context=True,
expected_res_status=200)
self.update_policy_target_group(
ptg['id'], is_admin_context=True, expected_res_status=200,
name='new_name')
auto_ptg_id = self.driver._get_auto_ptg_id(ptg['l2_policy_id'])
# non-admin cannot retrieve or update auto-ptg
self.show_policy_target_group(auto_ptg_id, expected_res_status=404)
self.update_policy_target_group(
auto_ptg_id, expected_res_status=404, name='new_name')
# admin can retrieve and update auto-ptg
self.show_policy_target_group(auto_ptg_id, is_admin_context=True,
expected_res_status=200)
self.update_policy_target_group(
auto_ptg_id, is_admin_context=True, expected_res_status=200,
name='new_name')
# admin can create pt on auto-ptg
self.create_policy_target(
policy_target_group_id=auto_ptg_id, is_admin_context=True,
expected_res_status=201)
# non-admin cannot create pt on auto-ptg
self.create_policy_target(policy_target_group_id=auto_ptg_id,
expected_res_status=403)
def test_auto_ptg_tenant_unshared_l2_policy_shared_l3p(self):
l3p = self.create_l3_policy(name="l3p1",
shared=True)['l3_policy']
self._switch_to_tenant2()
l2p = self.create_l2_policy(name="l2p1",
shared=False,
l3_policy_id=l3p['id'])['l2_policy']
self.assertEqual(gp_const.STATUS_BUILD, l2p['status'])
self.assertEqual(l2p['shared'], not l3p['shared'])
self._validate_default_epg_implicit_contracts(l2p)
# After creation of auto-ptg, BD is now in L3P's tenant
self._validate_bd_tenant(l2p, l3p['tenant_id'])
ptg = self._get_auto_ptg(l2p)
# Default EPG is in L3P's tenant
self._validate_epg_tenant(ptg, l3p['tenant_id'])
self._validate_l2_policy_deleted(l2p, implicit_l3p=False)
self._switch_to_tenant1()
self.delete_l3_policy(l3p['id'])
def test_unshared_l2_policy_shared_l3p_get_gbp_details(self):
l3p = self.create_l3_policy(name="l3p1",
shared=True)['l3_policy']
self._switch_to_tenant2()
l2p = self.create_l2_policy(name="l2p1",
shared=False,
l3_policy_id=l3p['id'])['l2_policy']
self.assertEqual(gp_const.STATUS_BUILD, l2p['status'])
self.assertEqual(l2p['shared'], not l3p['shared'])
self._validate_default_epg_implicit_contracts(l2p)
# After creation of auto-ptg, BD is now in L3P's tenant
self._validate_bd_tenant(l2p, l3p['tenant_id'])
ptg = self._get_auto_ptg(l2p)
# Default EPG is in L3P's tenant
self._validate_epg_tenant(ptg, l3p['tenant_id'])
subnet_id = ptg['subnets'][0]
req = self.new_show_request('subnets', subnet_id)
subnet = self.deserialize(self.fmt, req.get_response(self.api))
with self.port(subnet=subnet) as port:
port_id = port['port']['id']
self._bind_port_to_host(port_id, 'h1')
mapping = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % port_id,
host='h1')
self.assertEqual(
self.name_mapper.network(None, l2p['network_id']),
mapping['endpoint_group_name'])
self.assertEqual(
self.name_mapper.project(None, l3p['tenant_id']),
mapping['ptg_tenant'])
self.assertNotEqual(ptg['tenant_id'], mapping['ptg_tenant'])
req = self.new_delete_request('ports', port_id)
res = req.get_response(self.api)
self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
self._validate_l2_policy_deleted(l2p, implicit_l3p=False)
self._switch_to_tenant1()
self.delete_l3_policy(l3p['id'])
def test_ep_notification_on_apg_update(self):
# Once the testing strategy evolves to always assuming auto_ptg
# being present, this UT can be removed/merged with the UTs in the
# TestPolicyTargetGroup class
mock_notif = mock.Mock()
self.driver.aim_mech_driver.notifier.port_update = mock_notif
apg = self.create_application_policy_group()[
'application_policy_group']
apg_id = apg['id']
self.show_application_policy_group(apg_id, expected_res_status=200)
ptg = self.create_policy_target_group(application_policy_group_id=
apg_id)['policy_target_group']
self.assertEqual(apg_id, ptg['application_policy_group_id'])
pt = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
self._bind_port_to_host(pt['port_id'], 'h1')
port = self._plugin.get_port(self._context, pt['port_id'])
mapping = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % pt['port_id'],
host='h1')
ap_name = self.driver.apic_ap_name_for_application_policy_group(
self._neutron_context.session, apg_id)
self.assertEqual(ap_name, mapping['app_profile_name'])
new_apg = self.create_application_policy_group()[
'application_policy_group']
ptg = self.update_policy_target_group(
ptg['id'], expected_res_status=200,
application_policy_group_id=new_apg['id'])['policy_target_group']
mapping = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % pt['port_id'],
host='h1')
ap_name = self.driver.apic_ap_name_for_application_policy_group(
self._neutron_context.session, new_apg['id'])
self.assertEqual(ap_name, mapping['app_profile_name'])
mock_notif.assert_called_once_with(mock.ANY, port)
class TestL2PolicyRollback(TestL2PolicyBase):
def test_l2_policy_create_fail(self):
orig_func = self.dummy.create_l2_policy_precommit
self.dummy.create_l2_policy_precommit = mock.Mock(
side_effect=Exception)
self.create_l2_policy(name="l2p1", expected_res_status=500)
self.assertEqual([], self._plugin.get_networks(self._context))
self.assertEqual([], self._gbp_plugin.get_l2_policies(self._context))
self.assertEqual([], self._gbp_plugin.get_l3_policies(self._context))
aim_tenant_name = md.COMMON_TENANT_NAME
aim_contracts = self.aim_mgr.find(
self._aim_context, aim_resource.Contract,
tenant_name=aim_tenant_name)
self.assertEqual(0, len(aim_contracts))
aim_contract_subjects = self.aim_mgr.find(
self._aim_context, aim_resource.ContractSubject,
tenant_name=aim_tenant_name)
self.assertEqual(0, len(aim_contract_subjects))
aim_filters = self.aim_mgr.find(
self._aim_context, aim_resource.Filter,
tenant_name=aim_tenant_name)
self.assertEqual(1, len(aim_filters))
aim_filter_entries = self.aim_mgr.find(
self._aim_context, aim_resource.FilterEntry,
tenant_name=aim_tenant_name)
self.assertEqual(1, len(aim_filter_entries))
# restore mock
self.dummy.create_l2_policy_precommit = orig_func
def test_l2_policy_update_fail(self):
orig_func = self.dummy.update_l2_policy_precommit
self.dummy.update_l2_policy_precommit = mock.Mock(
side_effect=Exception)
l2p = self.create_l2_policy(name="l2p1")['l2_policy']
l2p_id = l2p['id']
self.update_l2_policy(l2p_id, expected_res_status=500,
name="new name")
new_l2p = self.show_l2_policy(l2p_id, expected_res_status=200)
self.assertEqual(l2p['name'],
new_l2p['l2_policy']['name'])
self._validate_default_epg_implicit_contracts(l2p)
# restore mock
self.dummy.update_l2_policy_precommit = orig_func
def test_l2_policy_delete_fail(self):
orig_func = self.dummy.delete_l2_policy_precommit
self.dummy.delete_l2_policy_precommit = mock.Mock(
side_effect=Exception)
l2p = self.create_l2_policy(name="l2p1")['l2_policy']
l2p_id = l2p['id']
network_id = l2p['network_id']
l3p_id = l2p['l3_policy_id']
self.delete_l2_policy(l2p_id, expected_res_status=500)
req = self.new_show_request('networks', network_id, fmt=self.fmt)
res = self.deserialize(self.fmt, req.get_response(self.api))
self.assertIsNotNone(res['network']['id'])
self.show_l3_policy(l3p_id, expected_res_status=200)
self.show_l2_policy(l2p_id, expected_res_status=200)
self._validate_default_epg_implicit_contracts(l2p)
# restore mock
self.dummy.delete_l2_policy_precommit = orig_func
class TestPolicyTargetGroupVmmDomains(AIMBaseTestCase):
def test_policy_target_group_aim_domains(self):
self.aim_mgr.create(self._aim_context,
aim_resource.VMMDomain(type='OpenStack',
name='vm1'),
overwrite=True)
self.aim_mgr.create(self._aim_context,
aim_resource.VMMDomain(type='OpenStack',
name='vm2'),
overwrite=True)
self.aim_mgr.create(self._aim_context,
aim_resource.VMMDomain(type='VMware',
name='vm3'),
overwrite=True)
self.aim_mgr.create(self._aim_context,
aim_resource.PhysicalDomain(name='ph1'),
overwrite=True)
self.aim_mgr.create(self._aim_context,
aim_resource.PhysicalDomain(name='ph2'),
overwrite=True)
ptg = self.create_policy_target_group(name="ptg1")[
'policy_target_group']
aim_epg_name = self.driver.apic_epg_name_for_policy_target_group(
self._neutron_context.session, ptg['id'],
context=self._neutron_context)
aim_tenant_name = self.name_mapper.project(None, self._tenant_id)
aim_app_profile_name = self.driver.aim_mech_driver.ap_name
aim_app_profiles = self.aim_mgr.find(
self._aim_context, aim_resource.ApplicationProfile,
tenant_name=aim_tenant_name, name=aim_app_profile_name)
self.assertEqual(1, len(aim_app_profiles))
aim_epg = self.aim_mgr.get(
self._aim_context, aim_resource.EndpointGroup(
tenant_name=aim_tenant_name,
app_profile_name=aim_app_profile_name, name=aim_epg_name))
self.assertEqual(set([]),
set([vmm['name'] for vmm in aim_epg.vmm_domains]))
self.assertEqual(set([]),
set([phys['name']
for phys in aim_epg.physical_domains]))
class TestPolicyTargetGroupIpv4(AIMBaseTestCase):
def setUp(self, *args, **kwargs):
super(TestPolicyTargetGroupIpv4, self).setUp(*args, **kwargs)
self.ip_dict = {4: {'address_scope_id_key': 'address_scope_v4_id',
'subnetpools_id_key': 'subnetpools_v4',
'cidrs': [('192.168.0.0/24', 24),
('10.0.0.0/16', 26)],
'address_scope': None,
'subnetpools': []}}
def _family_specific_subnet_validation(self, subnet):
pass
def _verify_implicit_subnets_in_ptg(self, ptg, l3p=None):
# Verify that implicit subnetpools exist for each address family,
# and that the PTG was allocated a subnet with a prefix from
# each address family
for ip_version in self.ip_dict.keys():
family_subnets = []
for subnet_id in ptg['subnets']:
req = self.new_show_request('subnets', subnet_id, fmt=self.fmt)
subnet = self.deserialize(self.fmt,
req.get_response(self.api))['subnet']
self.assertIsNotNone(subnet['id'])
if netaddr.IPNetwork(subnet['cidr']).version == ip_version:
family_subnets.append(subnet)
self.assertNotEqual(family_subnets, [])
cidrlist = [cidr for cidr, _ in self.ip_dict[ip_version]['cidrs']]
for subnet in family_subnets:
ip_ver = subnet['ip_version']
check = IPSet(cidrlist).issuperset(
IPSet([subnet['cidr']]))
self.assertTrue(check)
if l3p:
self.assertIn(subnet['subnetpool_id'],
l3p[self.ip_dict[ip_ver]['subnetpools_id_key']])
self._family_specific_subnet_validation(subnet)
def test_policy_target_group_lifecycle_implicit_l2p(self):
prs_lists = self._get_provided_consumed_prs_lists()
ptg = self.create_policy_target_group(
name="ptg1",
provided_policy_rule_sets={prs_lists['provided']['id']: 'scope'},
consumed_policy_rule_sets={prs_lists['consumed']['id']: 'scope'})[
'policy_target_group']
ptg_id = ptg['id']
l2p = self.show_l2_policy(ptg['l2_policy_id'],
expected_res_status=200)['l2_policy']
l3p = self.show_l3_policy(l2p['l3_policy_id'],
expected_res_status=200)['l3_policy']
self._verify_implicit_subnets_in_ptg(ptg, l3p)
self._test_policy_target_group_aim_mappings(ptg, prs_lists, l2p,
num_address_families=len(self.ip_dict.keys()))
new_name = 'new name'
new_prs_lists = self._get_provided_consumed_prs_lists()
ptg = self.update_policy_target_group(
ptg_id, expected_res_status=200, name=new_name,
provided_policy_rule_sets={new_prs_lists['provided']['id']:
'scope'},
consumed_policy_rule_sets={new_prs_lists['consumed']['id']:
'scope'})['policy_target_group']
self._test_policy_target_group_aim_mappings(ptg, new_prs_lists, l2p,
num_address_families=len(self.ip_dict.keys()))
self.delete_policy_target_group(ptg_id, expected_res_status=204)
self.show_policy_target_group(ptg_id, expected_res_status=404)
# Implicitly created subnet should be deleted
for subnet_id in ptg['subnets']:
req = self.new_show_request('subnets', subnet_id, fmt=self.fmt)
res = req.get_response(self.api)
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
# check router ports are deleted too
self.assertEqual([], self._plugin.get_ports(self._context))
# Implicitly created L2P should be deleted
self.show_l2_policy(ptg['l2_policy_id'], expected_res_status=404)
aim_epgs = self.aim_mgr.find(
self._aim_context, aim_resource.EndpointGroup)
self.assertEqual(0, len(aim_epgs))
def test_policy_target_group_lifecycle_explicit_l2p(self):
# TODO(Sumit): Refactor the common parts of this and the implicit test
l2p = self.create_l2_policy(name="l2p1")['l2_policy']
l2p_id = l2p['id']
ptg = self.create_policy_target_group(
name="ptg1", l2_policy_id=l2p_id)['policy_target_group']
ptg_id = ptg['id']
ptg_show = self.show_policy_target_group(
ptg_id, expected_res_status=200)['policy_target_group']
self.assertEqual(l2p_id, ptg['l2_policy_id'])
self.show_l2_policy(ptg['l2_policy_id'], expected_res_status=200)
self._verify_implicit_subnets_in_ptg(ptg)
self._validate_router_interface_created(
num_address_families=len(self.ip_dict.keys()))
ptg_name = ptg['name']
aim_epg_name = self.driver.apic_epg_name_for_policy_target_group(
self._neutron_context.session, ptg_id, ptg_name,
context=self._neutron_context)
aim_tenant_name = self.name_mapper.project(None, self._tenant_id)
aim_app_profile_name = self.driver.aim_mech_driver.ap_name
aim_app_profiles = self.aim_mgr.find(
self._aim_context, aim_resource.ApplicationProfile,
tenant_name=aim_tenant_name, name=aim_app_profile_name)
self.assertEqual(1, len(aim_app_profiles))
req = self.new_show_request('networks', l2p['network_id'],
fmt=self.fmt)
net = self.deserialize(self.fmt,
req.get_response(self.api))['network']
bd = self.aim_mgr.get(
self._aim_context, aim_resource.BridgeDomain.from_dn(
net[DN][BD]))
aim_epgs = self.aim_mgr.find(
self._aim_context, aim_resource.EndpointGroup, name=aim_epg_name)
self.assertEqual(1, len(aim_epgs))
self.assertEqual(aim_epg_name, aim_epgs[0].name)
self.assertEqual(aim_tenant_name, aim_epgs[0].tenant_name)
self.assertEqual(bd.name, aim_epgs[0].bd_name)
self.assertEqual(aim_epgs[0].dn,
ptg[DN][EPG])
self._test_aim_resource_status(aim_epgs[0], ptg)
self.assertEqual(aim_epgs[0].dn, ptg_show[DN][EPG])
new_name = 'new name'
new_prs_lists = self._get_provided_consumed_prs_lists()
self.update_policy_target_group(
ptg_id, expected_res_status=200, name=new_name,
provided_policy_rule_sets={new_prs_lists['provided']['id']:
'scope'},
consumed_policy_rule_sets={new_prs_lists['consumed']['id']:
'scope'})['policy_target_group']
aim_epg_name = self.driver.apic_epg_name_for_policy_target_group(
self._neutron_context.session, ptg_id, new_name,
context=self._neutron_context)
aim_epgs = self.aim_mgr.find(
self._aim_context, aim_resource.EndpointGroup, name=aim_epg_name)
self.assertEqual(1, len(aim_epgs))
self.assertEqual(aim_epg_name, aim_epgs[0].name)
self._validate_contracts(ptg, aim_epgs[0], new_prs_lists, l2p)
self.assertEqual(bd.name, aim_epgs[0].bd_name)
self.delete_policy_target_group(ptg_id, expected_res_status=204)
self.show_policy_target_group(ptg_id, expected_res_status=404)
# Implicitly created subnet should be deleted
for subnet_id in ptg['subnets']:
req = self.new_show_request('subnets', subnet_id, fmt=self.fmt)
res = req.get_response(self.api)
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
# Explicitly created L2P should not be deleted
self.show_l2_policy(ptg['l2_policy_id'], expected_res_status=200)
aim_epgs = self.aim_mgr.find(
self._aim_context, aim_resource.EndpointGroup, name=aim_epg_name)
self.assertEqual(0, len(aim_epgs))
def _create_explicit_subnetpools(self):
vrf_dn = None
for ip_version in self.ip_dict.keys():
ascp = self._make_address_scope_for_vrf(vrf_dn,
ip_version, name='as1v' + str(ip_version))
ascp = ascp['address_scope']
vrf_dn = ascp[DN][VRF]
self.ip_dict[ip_version]['address_scope'] = ascp
count = 0
for cidr, prefixlen in self.ip_dict[ip_version]['cidrs']:
with self.subnetpool(
name='spv%s%s' % (str(ip_version), count),
prefixes=[cidr],
tenant_id=ascp['tenant_id'],
default_prefixlen=prefixlen,
address_scope_id=ascp['id']) as sp:
sp = sp['subnetpool']
self.ip_dict[ip_version]['subnetpools'].append(sp)
self.assertEqual(ascp['id'], sp['address_scope_id'])
def test_create_ptg_explicit_subnetpools(self):
self._create_explicit_subnetpools()
kwargs = {'name': "l3p1", 'ip_pool': None}
for ip_version in self.ip_dict.keys():
kwargs[self.ip_dict[ip_version]['subnetpools_id_key']] = [sp['id']
for sp in self.ip_dict[ip_version]['subnetpools']]
if len(self.ip_dict.keys()) == 1:
kwargs['ip_version'] = self.ip_dict.keys()[0]
else:
kwargs['ip_version'] = 46
l3p = self.create_l3_policy(**kwargs)['l3_policy']
for ip_version in self.ip_dict.keys():
self.assertEqual(self.ip_dict[ip_version]['address_scope']['id'],
l3p[self.ip_dict[ip_version]['address_scope_id_key']])
subnetpool_prefixes = []
for ip_version in self.ip_dict.keys():
cidrlist = self.ip_dict[ip_version]['cidrs']
subnetpool_prefixes.extend([cidr for cidr, _ in cidrlist])
self._validate_create_l3_policy(
l3p, subnetpool_prefixes=subnetpool_prefixes)
for ip_version in self.ip_dict.keys():
sp_key = self.ip_dict[ip_version]['subnetpools_id_key']
self.assertEqual(len(self.ip_dict[ip_version]['subnetpools']),
len(l3p[sp_key]))
l2p = self.create_l2_policy(
name='l2p', l3_policy_id=l3p['id'])['l2_policy']
l2p_id = l2p['id']
ptg = self.create_policy_target_group(
name="ptg1", l2_policy_id=l2p_id)['policy_target_group']
ptg_id = ptg['id']
self.show_policy_target_group(
ptg_id, expected_res_status=200)['policy_target_group']
for subnet_id in ptg['subnets']:
req = self.new_show_request(
'subnets', subnet_id, fmt=self.fmt)
res = self.deserialize(self.fmt, req.get_response(self.api))
subnet = res['subnet']
cidrlist = [cidr for cidr, _ in
self.ip_dict[subnet['ip_version']]['cidrs']]
check = IPSet(cidrlist).issuperset(
IPSet([subnet['cidr']]))
self.assertTrue(check)
self.delete_policy_target_group(
ptg_id, expected_res_status=204)
self.show_policy_target_group(ptg_id, expected_res_status=404)
# Implicitly created subnet should be deleted
req = self.new_show_request(
'subnets', ptg['subnets'][0], fmt=self.fmt)
res = req.get_response(self.api)
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
self.delete_l2_policy(l2p_id, expected_res_status=204)
self._validate_delete_l3_policy(
l3p, explicit_address_scope=True, explicit_subnetpool=True)
def test_ptg_delete_no_subnet_delete(self):
ptg = self.create_policy_target_group(
name="ptg1")['policy_target_group']
ptg_id = ptg['id']
ptg2 = self.create_policy_target_group(
name="ptg2", l2_policy_id=ptg['l2_policy_id'])[
'policy_target_group']
self.assertEqual(ptg['subnets'], ptg2['subnets'])
self.show_l2_policy(ptg['l2_policy_id'], expected_res_status=200)
self._verify_implicit_subnets_in_ptg(ptg)
self.delete_policy_target_group(ptg_id, expected_res_status=204)
self.show_policy_target_group(ptg_id, expected_res_status=404)
# Implicitly created subnet should not be deleted
self._verify_implicit_subnets_in_ptg(ptg)
self._validate_router_interface_created(
num_address_families=len(self.ip_dict.keys()))
def test_delete_ptg_after_router_interface_delete(self):
ptg = self.create_policy_target_group(
name="ptg1")['policy_target_group']
ptg_id = ptg['id']
self._validate_router_interface_created(
num_address_families=len(self.ip_dict.keys()))
router_id = self._l3_plugin.get_routers(self._context)[0]['id']
subnet_id = self._plugin.get_subnets(self._context)[0]['id']
info = self._l3_plugin.remove_router_interface(
self._context, router_id, {'subnet_id': subnet_id})
self.assertIn(subnet_id, info['subnet_ids'])
self.delete_policy_target_group(ptg_id, expected_res_status=204)
def test_policy_target_group_intra_ptg_allow(self):
ptg = self.create_policy_target_group(
intra_ptg_allow=False)['policy_target_group']
self.assertFalse(ptg['intra_ptg_allow'])
aim_epg_name = self.driver.apic_epg_name_for_policy_target_group(
self._neutron_context.session, ptg['id'],
context=self._neutron_context)
aim_epgs = self.aim_mgr.find(
self._aim_context, aim_resource.EndpointGroup, name=aim_epg_name)
self.assertEqual(1, len(aim_epgs))
self.assertEqual(aim_resource.EndpointGroup.POLICY_ENFORCED,
aim_epgs[0].policy_enforcement_pref)
ptg = self.update_policy_target_group(
ptg['id'], intra_ptg_allow=True)['policy_target_group']
self.assertTrue(ptg['intra_ptg_allow'])
aim_epgs = self.aim_mgr.find(
self._aim_context, aim_resource.EndpointGroup, name=aim_epg_name)
self.assertEqual(aim_resource.EndpointGroup.POLICY_UNENFORCED,
aim_epgs[0].policy_enforcement_pref)
class TestPolicyTargetGroupIpv6(TestPolicyTargetGroupIpv4):
def setUp(self, *args, **kwargs):
cfg.CONF.set_override(
'default_ip_version', 6,
group='group_policy_implicit_policy')
cfg.CONF.set_override(
'default_ip_pool', '2001:db8:1::/64',
group='group_policy_implicit_policy')
cfg.CONF.set_override(
'default_ipv6_ra_mode', 'slaac',
group='resource_mapping')
cfg.CONF.set_override(
'default_ipv6_address_mode', 'slaac',
group='resource_mapping')
super(TestPolicyTargetGroupIpv6, self).setUp(*args, **kwargs)
self.ip_dict = {6: {'address_scope_id_key': 'address_scope_v6_id',
'subnetpools_id_key': 'subnetpools_v6',
'cidrs': [('2001:db8:1::/64', 65),
('2001:db8:2::/64', 66)],
'address_scope': None,
'subnetpools': []}}
def _family_specific_subnet_validation(self, subnet):
if subnet['ip_version'] is 6:
self.assertEqual(subnet['ipv6_ra_mode'], 'slaac')
self.assertEqual(subnet['ipv6_address_mode'], 'slaac')
class TestPolicyTargetGroupDualStack(TestPolicyTargetGroupIpv4):
def setUp(self, *args, **kwargs):
cfg.CONF.set_override(
'default_ip_pool', '10.0.0.0/8,2001:db8:1::/64',
group='group_policy_implicit_policy')
cfg.CONF.set_override(
'default_ip_version', 46,
group='group_policy_implicit_policy')
super(TestPolicyTargetGroupDualStack, self).setUp(*args, **kwargs)
self.ip_dict = {4: {'address_scope_id_key': 'address_scope_v4_id',
'subnetpools_id_key': 'subnetpools_v4',
'cidrs': [('192.168.0.0/24', 24),
('10.0.0.0/16', 26)],
'address_scope': None,
'subnetpools': []},
6: {'address_scope_id_key': 'address_scope_v6_id',
'subnetpools_id_key': 'subnetpools_v6',
'cidrs': [('2001:db8:1::/64', 65),
('2001:db8:2::/64', 66)],
'address_scope': None,
'subnetpools': []}}
# TODO(Sumit): Add tests here which tests different scenarios for subnet
# allocation for PTGs
# 1. Multiple PTGs share the subnets associated with the l2_policy
# 2. Associated subnets are correctly used for IP address allocation
# 3. New subnets are created when the last available is exhausted
# 4. If multiple subnets are present, all are deleted at the time of
# l2_policy deletion
# 5. 'prefixlen', 'cidr', and 'subnetpool_id' overrides as a part of
# the subnet_specifics dictionary
class TestPolicyTargetGroupRollback(AIMBaseTestCase):
def test_policy_target_group_create_fail(self):
orig_func = self.dummy.create_policy_target_group_precommit
self.dummy.create_policy_target_group_precommit = mock.Mock(
side_effect=Exception)
self.create_policy_target_group(name="ptg1", expected_res_status=500)
self.assertEqual([], self._plugin.get_ports(self._context))
self.assertEqual([], self._plugin.get_subnets(self._context))
self.assertEqual([], self._plugin.get_networks(self._context))
self.assertEqual([], self._gbp_plugin.get_policy_target_groups(
self._context))
self.assertEqual([], self._gbp_plugin.get_l2_policies(self._context))
self.assertEqual([], self._gbp_plugin.get_l3_policies(self._context))
# restore mock
self.dummy.create_policy_target_group_precommit = orig_func
def test_policy_target_group_update_fail(self):
orig_func = self.dummy.update_policy_target_group_precommit
self.dummy.update_policy_target_group_precommit = mock.Mock(
side_effect=Exception)
ptg = self.create_policy_target_group(name="ptg1")
ptg_id = ptg['policy_target_group']['id']
self.update_policy_target_group(ptg_id, expected_res_status=500,
name="new name")
new_ptg = self.show_policy_target_group(ptg_id,
expected_res_status=200)
self.assertEqual(ptg['policy_target_group']['name'],
new_ptg['policy_target_group']['name'])
# restore mock
self.dummy.update_policy_target_group_precommit = orig_func
def test_policy_target_group_delete_fail(self):
orig_func = self.dummy.delete_l3_policy_precommit
self.dummy.delete_policy_target_group_precommit = mock.Mock(
side_effect=Exception)
ptg = self.create_policy_target_group(name="ptg1")
ptg_id = ptg['policy_target_group']['id']
l2p_id = ptg['policy_target_group']['l2_policy_id']
subnet_id = ptg['policy_target_group']['subnets'][0]
l2p = self.show_l2_policy(l2p_id, expected_res_status=200)
l3p_id = l2p['l2_policy']['l3_policy_id']
self.delete_policy_target_group(ptg_id, expected_res_status=500)
req = self.new_show_request('subnets', subnet_id, fmt=self.fmt)
res = self.deserialize(self.fmt, req.get_response(self.api))
self.assertIsNotNone(res['subnet']['id'])
self.show_policy_target_group(ptg_id, expected_res_status=200)
self.show_l2_policy(l2p_id, expected_res_status=200)
self.show_l3_policy(l3p_id, expected_res_status=200)
# restore mock
self.dummy.delete_l3_policy_precommit = orig_func
class TestGbpDetailsForML2(AIMBaseTestCase,
test_securitygroup.SecurityGroupsTestCase):
# REVISIT: Once the new RPC handler implementation in the apic_aim
# mechanism driver is complete and tested, move this unit test
# class to test_apic_aim (or a new module) and remove the
# enable_raw_sql and enable_new_rpc flags.
def setUp(self, *args, **kwargs):
super(TestGbpDetailsForML2, self).setUp(*args, **kwargs)
cfg.CONF.set_override('path_mtu', 1000, group='ml2')
cfg.CONF.set_override('global_physnet_mtu', 1000, None)
cfg.CONF.set_override('advertise_mtu', True, group='aim_mapping')
def _verify_gbp_details_assertions(self, mapping, req_mapping, port_id,
expected_epg_name, expected_epg_tenant,
subnets, dhcp_port, default_route=None,
map_tenant_name=True):
self.assertEqual(mapping, req_mapping['gbp_details'])
self.assertEqual(port_id, mapping['port_id'])
self.assertEqual(expected_epg_name, mapping['endpoint_group_name'])
expected_epg_ap_name = self.driver.aim_mech_driver.ap_name
self.assertEqual(expected_epg_ap_name, mapping['app_profile_name'])
exp_tenant = (self.name_mapper.project(None, expected_epg_tenant)
if map_tenant_name else expected_epg_tenant)
self.assertEqual(exp_tenant, mapping['ptg_tenant'])
self.assertEqual('someid', mapping['vm-name'])
self.assertTrue(mapping['enable_dhcp_optimization'])
self.assertFalse(mapping['enable_metadata_optimization'])
self.assertEqual(1, len(mapping['subnets']))
mapping_cidrs = [subnet['cidr'] for subnet in mapping['subnets']]
for subnet in subnets:
self.assertIn(subnet['subnet']['cidr'], mapping_cidrs)
dhcp_server_ports = mapping['subnets'][0]['dhcp_server_ports']
self.assertIn(dhcp_port['mac_address'],
dhcp_server_ports.keys())
dhcp_server_port = dhcp_server_ports[dhcp_port['mac_address']]
self.assertEqual(dhcp_server_port[0],
dhcp_port['fixed_ips'][0]['ip_address'])
self.assertEqual([dhcp_port['fixed_ips'][0]['ip_address']],
mapping['subnets'][0]['dhcp_server_ips'])
if default_route:
self.assertTrue(
{'destination': '0.0.0.0/0', 'nexthop': default_route} in
mapping['subnets'][0]['host_routes'],
"Default route missing in %s" % mapping['subnets'][0])
# Verify Neutron details
self.assertEqual(port_id, req_mapping['neutron_details']['port_id'])
def _verify_vrf_details_assertions(self, vrf_mapping, expected_vrf_name,
expected_l3p_id, expected_subnets,
expected_vrf_tenant):
self.assertEqual(expected_vrf_name, vrf_mapping['vrf_name'])
self.assertEqual(expected_vrf_tenant, vrf_mapping['vrf_tenant'])
self.assertEqual(set(expected_subnets),
set(vrf_mapping['vrf_subnets']))
self.assertEqual(expected_l3p_id,
vrf_mapping['l3_policy_id'])
def _verify_fip_details(self, mapping, fip, ext_epg_tenant,
ext_epg_name, ext_epg_app_profile='OpenStack'):
self.assertEqual(1, len(mapping['floating_ip']))
fip_mapping = mapping['floating_ip'][0]
# REVISIT: The port_id, project_id, and floating_network_id
# are not used by the agent, and the new RPC implementation
# doesn't provide them, so these assertions are commented out
# until the RPC implementations are cleaned up.
self.assertEqual(fip['id'], fip_mapping['id'])
# self.assertEqual(fip['port_id'], fip_mapping['port_id'])
# self.assertEqual(fip['project_id'], fip_mapping['project_id'])
self.assertEqual(fip['fixed_ip_address'],
fip_mapping['fixed_ip_address'])
self.assertEqual(fip['floating_ip_address'],
fip_mapping['floating_ip_address'])
# self.assertEqual(fip['floating_network_id'],
# fip_mapping['floating_network_id'])
self.assertEqual(ext_epg_name, fip_mapping['nat_epg_name'])
self.assertEqual(ext_epg_tenant, fip_mapping['nat_epg_tenant'])
self.assertEqual(ext_epg_app_profile,
fip_mapping['nat_epg_app_profile'])
def _verify_ip_mapping_details(self, mapping, ext_segment_name,
ext_epg_tenant, ext_epg_name,
ext_epg_app_profile='OpenStack'):
self.assertTrue({'external_segment_name': ext_segment_name,
'nat_epg_name': ext_epg_name,
'nat_epg_app_profile': ext_epg_app_profile,
'nat_epg_tenant': ext_epg_tenant}
in mapping['ip_mapping'])
def _verify_host_snat_ip_details(self, mapping, ext_segment_name,
snat_ip, subnet_cidr):
gw, prefix = subnet_cidr.split('/')
self._check_ip_in_cidr(snat_ip, subnet_cidr)
mapping['host_snat_ips'][0].pop('host_snat_ip', None)
self.assertEqual({'external_segment_name': ext_segment_name,
'gateway_ip': gw,
'prefixlen': int(prefix)},
mapping['host_snat_ips'][0])
def _do_test_get_gbp_details(self, pre_vrf=None,
enable_raw_sql=False,
enable_new_rpc=False):
self.driver.aim_mech_driver.enable_raw_sql_for_device_rpc = (
enable_raw_sql)
self.driver.aim_mech_driver.enable_new_rpc = enable_new_rpc
self.driver.aim_mech_driver.apic_optimized_dhcp_lease_time = 100
ext_net1, rtr1, ext_net1_sub = self._setup_external_network(
'es1', dn='uni/tn-t1/out-l1/instP-n1')
ext_net2, rtr2, ext_net2_sub1 = self._setup_external_network(
'es2', dn='uni/tn-t1/out-l2/instP-n2')
ext_net2_sub2 = self._make_subnet(
self.fmt, {'network': {'id': ext_net2_sub1['network_id'],
'tenant_id': ext_net2_sub1['tenant_id']}},
'200.200.0.1', '200.200.0.0/16')['subnet']
self._update('subnets', ext_net2_sub2['id'],
{'subnet': {SNAT_HOST_POOL: True}})
if pre_vrf:
as_id = self._make_address_scope_for_vrf(
pre_vrf.dn, name='as1')['address_scope']['id']
else:
scope = self._make_address_scope(
self.fmt, 4, name='as1')['address_scope']
as_id = scope['id']
pool = self._make_subnetpool(self.fmt, ['10.0.0.0/8'], name='sp1',
tenant_id=self._tenant_id,
address_scope_id=as_id,
default_prefixlen=24)['subnetpool']
pool_id = pool['id']
network = self._make_network(self.fmt, 'net1', True)
net1 = network['network']
# Make two subnets on the network
gw1_ip = '10.0.1.1'
subnet1 = self._make_subnet(
self.fmt, network, gw1_ip, cidr='10.0.1.0/24',
subnetpool_id=pool_id)['subnet']
network = self._make_network(self.fmt, 'net2', True)
net2 = network['network']
gw2_ip = '10.0.2.1'
subnet2 = self._make_subnet(
self.fmt, network, gw2_ip, cidr='10.0.2.0/24',
subnetpool_id=pool_id)['subnet']
# Make a DHCP port on each subnet
dhcp_subnet1 = [{'subnet_id': subnet1['id']}]
dhcp_p1 = self._make_port(self.fmt, net1['id'],
device_owner='dhcp:',
fixed_ips=dhcp_subnet1)['port']
self._bind_other_port_to_host(dhcp_p1['id'], 'h1')
dhcp_subnet2 = [{'subnet_id': subnet2['id']}]
dhcp_p2 = self._make_port(self.fmt, net2['id'],
device_owner='dhcp:',
fixed_ips=dhcp_subnet2)['port']
self._bind_other_port_to_host(dhcp_p2['id'], 'h2')
# Make a VM port
p1 = self._make_port(self.fmt, net1['id'],
device_owner='compute:')['port']
self._bind_port_to_host(p1['id'], 'h1')
self._router_interface_action('add', rtr1['id'], subnet1['id'], None)
self._router_interface_action('add', rtr2['id'], subnet2['id'], None)
fip = self._make_floatingip(self.fmt, ext_net1_sub['network_id'],
port_id=p1['id'])['floatingip']
mapping = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1['id'],
host='h1')
req_mapping = self.driver.request_endpoint_details(
nctx.get_admin_context(),
request={'device': 'tap%s' % p1['id'],
'timestamp': 0, 'request_id': 'request_id'},
host='h1')
epg_name = self.name_mapper.network(self._neutron_context.session,
net1['id'])
epg_tenant = net1['tenant_id']
net_db = self._get_object('networks', net1['id'], self.api)['network']
subnets = [self._get_object('subnets', subnet_id, self.api)
for subnet_id in net_db['subnets']
if subnet_id == p1['fixed_ips'][0]['subnet_id']]
self._verify_gbp_details_assertions(
mapping, req_mapping, p1['id'], epg_name,
epg_tenant, subnets, dhcp_p1)
if pre_vrf:
vrf_name = pre_vrf.name
vrf_tenant = pre_vrf.tenant_name
else:
vrf_name = self.name_mapper.address_scope(
None, as_id)
vrf_tenant = self.name_mapper.project(None,
self._tenant_id)
vrf_id = '%s %s' % (vrf_tenant, vrf_name)
subpools = self._get_object('subnetpools', pool_id,
self.api)['subnetpool']
prefixlist = [prefix.strip() for prefix in subpools['prefixes']]
self._verify_vrf_details_assertions(
mapping, vrf_name, vrf_id, prefixlist, vrf_tenant)
self._verify_fip_details(mapping, fip, 't1', 'EXT-l1')
# Create event on a second host to verify that the SNAT
# port gets created for this second host
p2 = self._make_port(self.fmt, net2['id'],
device_owner='compute:')['port']
self._bind_port_to_host(p2['id'], 'h2')
# As admin, create a SG in a different tenant then associate
# with the same port
sg = self._make_security_group(
self.fmt, 'sg_1', 'test',
tenant_id='test-tenant-2')['security_group']
port = self._plugin.get_port(self._context, p2['id'])
port['security_groups'].append(sg['id'])
port = self._plugin.update_port(
self._context, port['id'], {'port': port})
# Set the bad MTU through extra_dhcp_opts, it should fall back
# to the network MTU
data = {'port': {'extra_dhcp_opts': [{'opt_name': '26',
'opt_value': 'garbage'}]}}
port = self._update('ports', port['id'], data)['port']
mapping = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p2['id'],
host='h2')
req_mapping = self.driver.request_endpoint_details(
nctx.get_admin_context(),
request={'device': 'tap%s' % p2['id'],
'timestamp': 0, 'request_id': 'request_id'},
host='h2')
epg_name = self.name_mapper.network(self._neutron_context.session,
net2['id'])
epg_tenant = net2['tenant_id']
net_db = self._get_object('networks', net2['id'], self.api)['network']
subnets = [self._get_object('subnets', subnet_id, self.api)
for subnet_id in net_db['subnets']
if subnet_id == p2['fixed_ips'][0]['subnet_id']]
self._verify_gbp_details_assertions(
mapping, req_mapping, p2['id'], epg_name,
epg_tenant, subnets, dhcp_p2)
self.assertEqual(p2['id'], mapping['port_id'])
self._verify_ip_mapping_details(mapping,
'uni:tn-t1:out-l2:instP-n2', 't1', 'EXT-l2')
self._verify_host_snat_ip_details(mapping,
'uni:tn-t1:out-l2:instP-n2', '200.200.0.3', '200.200.0.1/16')
# Make sure 2nd RPC returned SNAT IP allocated in 1st RPC.
self._verify_host_snat_ip_details(req_mapping['gbp_details'],
'uni:tn-t1:out-l2:instP-n2', '200.200.0.3', '200.200.0.1/16')
self.assertEqual(1000, mapping['interface_mtu'])
self.assertEqual(100, mapping['dhcp_lease_time'])
sg_list = []
ctx = nctx.get_admin_context()
port_sgs = (ctx.session.query(sg_models.SecurityGroup.id,
sg_models.SecurityGroup.tenant_id).
filter(sg_models.SecurityGroup.id.
in_(port['security_groups'])).
all())
for sg_id, tenant_id in port_sgs:
sg_tenant = self.name_mapper.project(None, tenant_id)
sg_list.append(
{'policy-space': sg_tenant,
'name': sg_id})
sg_list.append({'policy-space': 'common',
'name': self.driver.aim_mech_driver.apic_system_id +
'_DefaultSecurityGroup'})
self.assertEqual(sg_list, mapping['security_group'])
# Set the right MTU through extra_dhcp_opts
data = {'port': {'extra_dhcp_opts': [{'opt_name': 'interface-mtu',
'opt_value': '2000'}]}}
port = self._update('ports', port['id'], data)['port']
mapping = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p2['id'],
host='h2')
self.assertEqual(2000, mapping['interface_mtu'])
def test_get_gbp_details(self):
self._do_test_get_gbp_details()
def test_get_gbp_details_with_raw_sql(self):
self._do_test_get_gbp_details(enable_raw_sql=True)
def test_get_gbp_details_with_new_rpc(self):
self._do_test_get_gbp_details(enable_new_rpc=True)
def test_get_gbp_details_pre_existing_vrf(self):
aim_ctx = aim_context.AimContext(self.db_session)
vrf = self.aim_mgr.create(
aim_ctx, aim_resource.VRF(tenant_name='common', name='ctx1',
monitored=True))
self._do_test_get_gbp_details(pre_vrf=vrf)
def test_get_gbp_details_pre_existing_vrf_with_raw_sql(self):
aim_ctx = aim_context.AimContext(self.db_session)
vrf = self.aim_mgr.create(
aim_ctx, aim_resource.VRF(tenant_name='common', name='ctx1',
monitored=True))
self._do_test_get_gbp_details(pre_vrf=vrf,
enable_raw_sql=True)
def test_get_gbp_details_pre_existing_vrf_with_new_rpc(self):
aim_ctx = aim_context.AimContext(self.db_session)
vrf = self.aim_mgr.create(
aim_ctx, aim_resource.VRF(tenant_name='common', name='ctx1',
monitored=True))
self._do_test_get_gbp_details(pre_vrf=vrf,
enable_new_rpc=True)
class TestPolicyTarget(AIMBaseTestCase,
test_securitygroup.SecurityGroupsTestCase):
def setUp(self, *args, **kwargs):
super(TestPolicyTarget, self).setUp(*args, **kwargs)
cfg.CONF.set_override('path_mtu', 1000, group='ml2')
cfg.CONF.set_override('global_physnet_mtu', 1000, None)
cfg.CONF.set_override('advertise_mtu', True, group='aim_mapping')
def _doms(self, domains, with_type=True):
if with_type:
return [(str(dom['name']), str(dom['type']))
for dom in domains]
else:
return [str(dom['name']) for dom in domains]
def test_policy_target_lifecycle_implicit_port(self):
ptg = self.create_policy_target_group(
name="ptg1")['policy_target_group']
ptg_id = ptg['id']
pt = self.create_policy_target(
name="pt1", policy_target_group_id=ptg_id)['policy_target']
pt_id = pt['id']
self.show_policy_target(pt_id, expected_res_status=200)
req = self.new_show_request('ports', pt['port_id'], fmt=self.fmt)
res = self.deserialize(self.fmt, req.get_response(self.api))
self.assertIsNotNone(res['port']['id'])
self.assertEqual(1, len(res['port']['security_groups']))
self.update_policy_target(pt_id, expected_res_status=200,
name="new name")
new_pt = self.show_policy_target(pt_id, expected_res_status=200)
self.assertEqual('new name', new_pt['policy_target']['name'])
self.delete_policy_target(pt_id, expected_res_status=204)
self.show_policy_target(pt_id, expected_res_status=404)
req = self.new_show_request('ports', pt['port_id'], fmt=self.fmt)
res = req.get_response(self.api)
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
def test_policy_target_segmentation_label_update(self):
if not 'apic_segmentation_label' in self._extension_drivers:
self.skipTest("apic_segmentation_label ED not configured")
mock_notif = mock.Mock()
self.driver.aim_mech_driver.notifier.port_update = mock_notif
ptg = self.create_policy_target_group(
name="ptg1")['policy_target_group']
pt = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
self.assertItemsEqual([], pt['segmentation_labels'])
segmentation_labels = ['a=b', 'c=d']
self._bind_port_to_host(pt['port_id'], 'h1')
pt = self.update_policy_target(
pt['id'], expected_res_status=200,
segmentation_labels=segmentation_labels)['policy_target']
self.assertItemsEqual(segmentation_labels, pt['segmentation_labels'])
port = self._plugin.get_port(self._context, pt['port_id'])
mock_notif.assert_called_once_with(mock.ANY, port)
mock_notif.reset_mock()
pt = self.update_policy_target(
pt['id'], name='updated-pt',
expected_res_status=200)['policy_target']
self.assertItemsEqual(segmentation_labels, pt['segmentation_labels'])
mock_notif.assert_not_called()
def test_policy_target_with_default_domains(self):
aim_ctx = aim_context.AimContext(self.db_session)
self.aim_mgr.create(aim_ctx,
aim_resource.VMMDomain(type='OpenStack',
name='vm1'),
overwrite=True)
self.aim_mgr.create(aim_ctx,
aim_resource.VMMDomain(type='OpenStack',
name='vm2'),
overwrite=True)
self.aim_mgr.create(aim_ctx,
aim_resource.VMMDomain(type='VMware',
name='vm3'),
overwrite=True)
ptg = self.create_policy_target_group(
name="ptg1")['policy_target_group']
pt = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
self._bind_port_to_host(pt['port_id'], 'h1')
aim_epg_name = self.driver.apic_epg_name_for_policy_target_group(
self._neutron_context.session, ptg['id'],
context=self._neutron_context)
aim_tenant_name = self.name_mapper.project(None, self._tenant_id)
aim_app_profile_name = self.driver.aim_mech_driver.ap_name
aim_epg = self.aim_mgr.get(
self._aim_context, aim_resource.EndpointGroup(
tenant_name=aim_tenant_name,
app_profile_name=aim_app_profile_name, name=aim_epg_name))
self.assertEqual(set([('vm1', 'OpenStack'),
('vm2', 'OpenStack')]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains,
with_type=False)))
# move port to another host
self._bind_port_to_host(pt['port_id'], 'h2')
aim_epg = self.aim_mgr.get(aim_ctx, aim_epg)
self.assertEqual(set([('vm1', 'OpenStack'),
('vm2', 'OpenStack')]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains,
with_type=False)))
# delete port
self.delete_policy_target(pt['id'], expected_res_status=204)
aim_epg = self.aim_mgr.get(aim_ctx, aim_epg)
self.assertEqual(set([('vm1', 'OpenStack'),
('vm2', 'OpenStack')]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains,
with_type=False)))
def test_policy_target_with_default_domains_explicit_port(self):
aim_ctx = aim_context.AimContext(self.db_session)
self.aim_mgr.create(aim_ctx,
aim_resource.VMMDomain(type='OpenStack',
name='vm1'),
overwrite=True)
self.aim_mgr.create(aim_ctx,
aim_resource.VMMDomain(type='OpenStack',
name='vm2'),
overwrite=True)
self.aim_mgr.create(aim_ctx,
aim_resource.VMMDomain(type='VMware',
name='vm3'),
overwrite=True)
with self.port() as port:
port_id = port['port']['id']
self._bind_port_to_host(port_id, 'h1')
ptg = self.create_policy_target_group(
name="ptg1")['policy_target_group']
pt = self.create_policy_target(
policy_target_group_id=ptg['id'],
port_id=port_id)['policy_target']
aim_epg_name = self.driver.apic_epg_name_for_policy_target_group(
self._neutron_context.session, ptg['id'],
context=self._neutron_context)
aim_tenant_name = self.name_mapper.project(None, self._tenant_id)
aim_app_profile_name = self.driver.aim_mech_driver.ap_name
aim_epg = self.aim_mgr.get(
self._aim_context, aim_resource.EndpointGroup(
tenant_name=aim_tenant_name,
app_profile_name=aim_app_profile_name, name=aim_epg_name))
self.assertEqual(set([('vm1', 'OpenStack'),
('vm2', 'OpenStack')]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains,
with_type=False)))
# move port to another host
self._bind_port_to_host(pt['port_id'], 'h2')
aim_epg = self.aim_mgr.get(aim_ctx, aim_epg)
self.assertEqual(set([('vm1', 'OpenStack'),
('vm2', 'OpenStack')]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains,
with_type=False)))
# delete port
self.delete_policy_target(pt['id'], expected_res_status=204)
aim_epg = self.aim_mgr.get(aim_ctx, aim_epg)
self.assertEqual(set([('vm1', 'OpenStack'),
('vm2', 'OpenStack')]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains,
with_type=False)))
def test_policy_target_with_specific_domains(self):
aim_ctx = aim_context.AimContext(self.db_session)
hd_mapping = aim_infra.HostDomainMappingV2(host_name='opflex-1',
domain_name='vm1',
domain_type='OpenStack')
self.aim_mgr.create(aim_ctx, hd_mapping)
hd_mapping = aim_infra.HostDomainMappingV2(host_name='opflex-2',
domain_name='vm2',
domain_type='OpenStack')
self.aim_mgr.create(aim_ctx, hd_mapping)
hd_mapping = aim_infra.HostDomainMappingV2(host_name='opflex-2a',
domain_name='vm2',
domain_type='OpenStack')
self.aim_mgr.create(aim_ctx, hd_mapping)
hd_mapping = aim_infra.HostDomainMappingV2(host_name='*',
domain_name='phys1',
domain_type='PhysDom')
self.aim_mgr.create(aim_ctx, hd_mapping)
hd_mapping = aim_infra.HostDomainMappingV2(host_name='opflex-1',
domain_name='phys2',
domain_type='PhysDom')
self.aim_mgr.create(aim_ctx, hd_mapping)
ptg = self.create_policy_target_group(
name="ptg1")['policy_target_group']
pt = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
self._bind_port_to_host(pt['port_id'], 'opflex-1')
aim_epg_name = self.driver.apic_epg_name_for_policy_target_group(
self._neutron_context.session, ptg['id'],
context=self._neutron_context)
aim_tenant_name = self.name_mapper.project(None, self._tenant_id)
aim_app_profile_name = self.driver.aim_mech_driver.ap_name
aim_epg = self.aim_mgr.get(
self._aim_context, aim_resource.EndpointGroup(
tenant_name=aim_tenant_name,
app_profile_name=aim_app_profile_name, name=aim_epg_name))
self.assertEqual(set([('vm1', 'OpenStack')]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains,
with_type=False)))
# move port to another host
self._bind_port_to_host(pt['port_id'], 'opflex-2')
aim_epg = self.aim_mgr.get(aim_ctx, aim_epg)
self.assertEqual(set([('vm2', 'OpenStack')]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains,
with_type=False)))
# create another port on a host that belongs to the same domain
pt1 = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
self._bind_port_to_host(pt1['port_id'], 'opflex-2a')
aim_epg = self.aim_mgr.get(aim_ctx, aim_epg)
self.assertEqual(set([('vm2', 'OpenStack')]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains,
with_type=False)))
# delete 1st port
self.delete_policy_target(pt['id'], expected_res_status=204)
aim_epg = self.aim_mgr.get(aim_ctx, aim_epg)
self.assertEqual(set([('vm2', 'OpenStack')]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains,
with_type=False)))
# delete the last port
self.delete_policy_target(pt1['id'], expected_res_status=204)
aim_epg = self.aim_mgr.get(aim_ctx, aim_epg)
self.assertEqual(set([]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains)))
def test_policy_target_with_specific_domains_explicit_port(self):
aim_ctx = aim_context.AimContext(self.db_session)
hd_mapping = aim_infra.HostDomainMappingV2(host_name='opflex-1',
domain_name='vm1',
domain_type='OpenStack')
self.aim_mgr.create(aim_ctx, hd_mapping)
hd_mapping = aim_infra.HostDomainMappingV2(host_name='opflex-2',
domain_name='vm2',
domain_type='OpenStack')
self.aim_mgr.create(aim_ctx, hd_mapping)
hd_mapping = aim_infra.HostDomainMappingV2(host_name='opflex-2a',
domain_name='vm2',
domain_type='OpenStack')
self.aim_mgr.create(aim_ctx, hd_mapping)
hd_mapping = aim_infra.HostDomainMappingV2(host_name='*',
domain_name='phys1',
domain_type='PhysDom')
self.aim_mgr.create(aim_ctx, hd_mapping)
hd_mapping = aim_infra.HostDomainMappingV2(host_name='opflex-1',
domain_name='phys2',
domain_type='PhysDom')
self.aim_mgr.create(aim_ctx, hd_mapping)
with self.port() as port:
port_id = port['port']['id']
self._bind_port_to_host(port_id, 'opflex-1')
ptg = self.create_policy_target_group(
name="ptg1")['policy_target_group']
pt = self.create_policy_target(
policy_target_group_id=ptg['id'],
port_id=port_id)['policy_target']
aim_epg_name = self.driver.apic_epg_name_for_policy_target_group(
self._neutron_context.session, ptg['id'],
context=self._neutron_context)
aim_tenant_name = self.name_mapper.project(None, self._tenant_id)
aim_app_profile_name = self.driver.aim_mech_driver.ap_name
aim_epg = self.aim_mgr.get(
self._aim_context, aim_resource.EndpointGroup(
tenant_name=aim_tenant_name,
app_profile_name=aim_app_profile_name, name=aim_epg_name))
self.assertEqual(set([('vm1', 'OpenStack')]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains,
with_type=False)))
# move port to another host
self._bind_port_to_host(port_id, 'opflex-2')
aim_epg = self.aim_mgr.get(aim_ctx, aim_epg)
self.assertEqual(set([('vm2', 'OpenStack')]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains,
with_type=False)))
with self.port() as port1:
# create another port on a host that belongs to the same domain
port_id1 = port1['port']['id']
self._bind_port_to_host(port_id1, 'opflex-2a')
pt1 = self.create_policy_target(
policy_target_group_id=ptg['id'],
port_id=port_id1)['policy_target']
aim_epg = self.aim_mgr.get(aim_ctx, aim_epg)
self.assertEqual(set([('vm2', 'OpenStack')]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains,
with_type=False)))
# delete 1st pt
self.delete_policy_target(pt['id'], expected_res_status=204)
aim_epg = self.aim_mgr.get(aim_ctx, aim_epg)
self.assertEqual(set([('vm2', 'OpenStack')]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains,
with_type=False)))
# delete the last pt
self.delete_policy_target(pt1['id'], expected_res_status=204)
aim_epg = self.aim_mgr.get(aim_ctx, aim_epg)
self.assertEqual(set([]),
set(self._doms(aim_epg.vmm_domains)))
self.assertEqual(set([]),
set(self._doms(aim_epg.physical_domains)))
def _verify_gbp_details_assertions(self, mapping, req_mapping, port_id,
expected_epg_name, expected_epg_tenant,
subnet, default_route=None,
map_tenant_name=True,
prefix_ap_name=False):
self.assertEqual(mapping, req_mapping['gbp_details'])
self.assertEqual(port_id, mapping['port_id'])
self.assertEqual(expected_epg_name, mapping['endpoint_group_name'])
# This method is not used with APGs, but it is used with
# external network in common tenant.
expected_epg_ap_name = (
self.driver.aim_mech_driver.ap_name if not prefix_ap_name else
self.driver.aim_mech_driver.apic_system_id + '_' +
self.driver.aim_mech_driver.ap_name)
self.assertEqual(expected_epg_ap_name, mapping['app_profile_name'])
exp_tenant = (self.name_mapper.project(None, expected_epg_tenant)
if map_tenant_name else expected_epg_tenant)
self.assertEqual(exp_tenant, mapping['ptg_tenant'])
self.assertEqual('someid', mapping['vm-name'])
self.assertTrue(mapping['enable_dhcp_optimization'])
self.assertFalse(mapping['enable_metadata_optimization'])
self.assertEqual(1, len(mapping['subnets']))
self.assertEqual(subnet['subnet']['cidr'],
mapping['subnets'][0]['cidr'])
if default_route:
self.assertTrue(
{'destination': '0.0.0.0/0', 'nexthop': default_route} in
mapping['subnets'][0]['host_routes'],
"Default route missing in %s" % mapping['subnets'][0])
# Verify Neutron details
self.assertEqual(port_id, req_mapping['neutron_details']['port_id'])
def _verify_vrf_details_assertions(self, vrf_mapping, expected_vrf_name,
expected_l3p_id, expected_subnets,
expected_vrf_tenant):
self.assertEqual(expected_vrf_name, vrf_mapping['vrf_name'])
self.assertEqual(expected_vrf_tenant, vrf_mapping['vrf_tenant'])
self.assertEqual(set(expected_subnets),
set(vrf_mapping['vrf_subnets']))
self.assertEqual(expected_l3p_id,
vrf_mapping['l3_policy_id'])
def _setup_external_segment(self, name, dn=None):
kwargs = {'router:external': True}
if dn:
kwargs[DN] = {EXTERNAL_NETWORK: dn}
extn_attr = ('router:external', DN)
net = self._make_network(self.fmt, name, True,
arg_list=extn_attr,
**kwargs)['network']
subnet = self._make_subnet(
self.fmt, {'network': net}, '100.100.0.1',
'100.100.0.0/16')['subnet']
ext_seg = self.create_external_segment(name=name,
subnet_id=subnet['id'])['external_segment']
return ext_seg, subnet
def _verify_fip_details(self, mapping, fip, ext_epg_tenant,
ext_epg_name, ext_epg_app_profile='OpenStack'):
self.assertEqual(1, len(mapping['floating_ip']))
fip_mapping = mapping['floating_ip'][0]
# REVISIT: The port_id, project_id, and floating_network_id
# are not used by the agent, and the new RPC implementation
# doesn't provide them, so these assertions are commented out
# until the RPC implementations are cleaned up.
self.assertEqual(fip['id'], fip_mapping['id'])
# self.assertEqual(fip['port_id'], fip_mapping['port_id'])
# self.assertEqual(fip['project_id'], fip_mapping['project_id'])
self.assertEqual(fip['fixed_ip_address'],
fip_mapping['fixed_ip_address'])
self.assertEqual(fip['floating_ip_address'],
fip_mapping['floating_ip_address'])
# self.assertEqual(fip['floating_network_id'],
# fip_mapping['floating_network_id'])
self.assertEqual(ext_epg_name, fip_mapping['nat_epg_name'])
self.assertEqual(ext_epg_tenant, fip_mapping['nat_epg_tenant'])
self.assertEqual(ext_epg_app_profile,
fip_mapping['nat_epg_app_profile'])
def _verify_ip_mapping_details(self, mapping, ext_segment_name,
ext_epg_tenant, ext_epg_name,
ext_epg_app_profile='OpenStack'):
self.assertTrue({'external_segment_name': ext_segment_name,
'nat_epg_name': ext_epg_name,
'nat_epg_app_profile': ext_epg_app_profile,
'nat_epg_tenant': ext_epg_tenant}
in mapping['ip_mapping'])
def _verify_host_snat_ip_details(self, mapping, ext_segment_name,
snat_ip, subnet_cidr):
gw, prefix = subnet_cidr.split('/')
self._check_ip_in_cidr(snat_ip, subnet_cidr)
mapping['host_snat_ips'][0].pop('host_snat_ip', None)
self.assertEqual({'external_segment_name': ext_segment_name,
'gateway_ip': gw,
'prefixlen': int(prefix)},
mapping['host_snat_ips'][0])
def _do_test_get_gbp_details(self, pre_vrf=None, enable_raw_sql=False,
enable_new_rpc=False):
self.driver.aim_mech_driver.enable_raw_sql_for_device_rpc = (
enable_raw_sql)
self.driver.aim_mech_driver.enable_new_rpc = enable_new_rpc
self.driver.aim_mech_driver.apic_optimized_dhcp_lease_time = 100
es1, es1_sub = self._setup_external_segment(
'es1', dn='uni/tn-t1/out-l1/instP-n1')
es2, es2_sub1 = self._setup_external_segment(
'es2', dn='uni/tn-t1/out-l2/instP-n2')
es2_sub2 = self._make_subnet(
self.fmt, {'network': {'id': es2_sub1['network_id'],
'tenant_id': es2_sub1['tenant_id']}},
'200.200.0.1', '200.200.0.0/16')['subnet']
self._update('subnets', es2_sub2['id'],
{'subnet': {SNAT_HOST_POOL: True}})
as_id = (self._make_address_scope_for_vrf(
pre_vrf.dn, name='as1')['address_scope']['id']
if pre_vrf else None)
l3p = self.create_l3_policy(name='myl3',
external_segments={es1['id']: [], es2['id']: []},
address_scope_v4_id=as_id)['l3_policy']
l2p = self.create_l2_policy(name='myl2',
l3_policy_id=l3p['id'])['l2_policy']
ptg = self.create_policy_target_group(
name="ptg1", l2_policy_id=l2p['id'])['policy_target_group']
segmentation_labels = ['label1', 'label2']
pt1 = self.create_policy_target(
policy_target_group_id=ptg['id'],
segmentation_labels=segmentation_labels)['policy_target']
self._bind_port_to_host(pt1['port_id'], 'h1')
fip = self._make_floatingip(self.fmt, es1_sub['network_id'],
port_id=pt1['port_id'])['floatingip']
mapping = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % pt1['port_id'],
host='h1')
if 'apic_segmentation_label' in self._extension_drivers:
self.assertItemsEqual(segmentation_labels,
mapping['segmentation_labels'])
req_mapping = self.driver.request_endpoint_details(
nctx.get_admin_context(),
request={'device': 'tap%s' % pt1['port_id'],
'timestamp': 0, 'request_id': 'request_id'},
host='h1')
epg_name = self.driver.apic_epg_name_for_policy_target_group(
self._neutron_context.session, ptg['id'], ptg['name'],
context=self._neutron_context)
epg_tenant = ptg['tenant_id']
subnet = self._get_object('subnets', ptg['subnets'][0], self.api)
self._verify_gbp_details_assertions(
mapping, req_mapping, pt1['port_id'], epg_name, epg_tenant, subnet)
if pre_vrf:
vrf_name = pre_vrf.name
vrf_tenant = pre_vrf.tenant_name
else:
vrf_name = self.name_mapper.address_scope(
None, l3p['address_scope_v4_id'])
vrf_tenant = self.name_mapper.project(None,
self._tenant_id)
vrf_id = '%s %s' % (vrf_tenant, vrf_name)
prefixlist = [prefix.strip() for prefix in l3p['ip_pool'].split(',')]
self._verify_vrf_details_assertions(
mapping, vrf_name, vrf_id, prefixlist, vrf_tenant)
self._verify_fip_details(mapping, fip, 't1', 'EXT-l1')
self._verify_ip_mapping_details(mapping,
'uni:tn-t1:out-l2:instP-n2', 't1', 'EXT-l2')
self._verify_host_snat_ip_details(mapping,
'uni:tn-t1:out-l2:instP-n2', '200.200.0.2', '200.200.0.1/16')
# Create event on a second host to verify that the SNAT
# port gets created for this second host
pt2 = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
self._bind_port_to_host(pt2['port_id'], 'h1')
# As admin, create a SG in a different tenant then associate
# with the same port
sg = self._make_security_group(
self.fmt, 'sg_1', 'test',
tenant_id='test-tenant-2')['security_group']
port = self._plugin.get_port(self._context, pt2['port_id'])
port['security_groups'].append(sg['id'])
port = self._plugin.update_port(
self._context, port['id'], {'port': port})
# Set the bad MTU through extra_dhcp_opts, it should fall back
# to the network MTU
data = {'port': {'extra_dhcp_opts': [{'opt_name': '26',
'opt_value': 'garbage'}]}}
port = self._update('ports', port['id'], data)['port']
mapping = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % pt2['port_id'],
host='h1')
self.assertEqual(pt2['port_id'], mapping['port_id'])
self._verify_ip_mapping_details(mapping,
'uni:tn-t1:out-l1:instP-n1', 't1', 'EXT-l1')
self._verify_ip_mapping_details(mapping,
'uni:tn-t1:out-l2:instP-n2', 't1', 'EXT-l2')
self._verify_host_snat_ip_details(mapping,
'uni:tn-t1:out-l2:instP-n2', '200.200.0.3', '200.200.0.1/16')
self.assertEqual(1000, mapping['interface_mtu'])
self.assertEqual(100, mapping['dhcp_lease_time'])
sg_list = []
ctx = nctx.get_admin_context()
port_sgs = (ctx.session.query(sg_models.SecurityGroup.id,
sg_models.SecurityGroup.tenant_id).
filter(sg_models.SecurityGroup.id.
in_(port['security_groups'])).
all())
for sg_id, tenant_id in port_sgs:
sg_tenant = self.name_mapper.project(None, tenant_id)
sg_list.append(
{'policy-space': sg_tenant,
'name': sg_id})
sg_list.append({'policy-space': 'common',
'name': self.driver.aim_mech_driver.apic_system_id +
'_DefaultSecurityGroup'})
self.assertEqual(sg_list, mapping['security_group'])
# Set the right MTU through extra_dhcp_opts
data = {'port': {'extra_dhcp_opts': [{'opt_name': 'interface-mtu',
'opt_value': '2000'}]}}
port = self._update('ports', port['id'], data)['port']
mapping = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % pt2['port_id'],
host='h1')
self.assertEqual(2000, mapping['interface_mtu'])
def _do_test_gbp_details_no_pt(self, use_as=True, routed=True,
pre_vrf=None, enable_raw_sql=False,
enable_new_rpc=False):
self.driver.aim_mech_driver.enable_raw_sql_for_device_rpc = (
enable_raw_sql)
self.driver.aim_mech_driver.enable_new_rpc = enable_new_rpc
# Create port and bind it
address_scope = self._make_address_scope_for_vrf(
pre_vrf.dn if pre_vrf else None,
name='as1')['address_scope']
kargs = {}
if use_as:
kargs['address_scope_id'] = address_scope['id']
subnetpool = self._make_subnetpool(
self.fmt, ['10.10.0.0/26', '1.1.0.0/16'],
name='as1', tenant_id=self._tenant_id, **kargs)['subnetpool']
self._make_subnetpool(
self.fmt, ['2.1.0.0/16'],
name='as2', address_scope_id=address_scope['id'],
tenant_id=self._tenant_id)
ext_net1, router1, _ = self._setup_external_network(
'l1', dn='uni/tn-t1/out-l1/instP-n1')
ext_net2, router2, _ = self._setup_external_network(
'l2', dn='uni/tn-t1/out-l2/instP-n2')
ext_net2_sub2 = self._make_subnet(
self.fmt, {'network': ext_net2}, '200.200.0.1',
'200.200.0.0/16')['subnet']
self._update('subnets', ext_net2_sub2['id'],
{'subnet': {SNAT_HOST_POOL: True}})
self.assertTrue(
n_utils.is_extension_supported(self._l3_plugin,
dns.Dns.get_alias()))
network = self._make_network(self.fmt, 'net1', True,
arg_list=('dns_domain',),
dns_domain='mydomain.')
with self.subnet(network=network, cidr='1.1.2.0/24',
subnetpool_id=subnetpool['id']) as subnet:
if routed:
self.l3_plugin.add_router_interface(
nctx.get_admin_context(), router1['id'],
{'subnet_id': subnet['subnet']['id']})
with self.port(subnet=subnet) as intf_port:
if routed:
self.l3_plugin.add_router_interface(
nctx.get_admin_context(), router2['id'],
{'port_id': intf_port['port']['id']})
with self.port(subnet=subnet) as port:
port_id = port['port']['id']
network = network['network']
if routed:
fip = self.l3_plugin.create_floatingip(
nctx.get_admin_context(),
{'floatingip': {'floating_network_id':
ext_net1['id'],
'tenant_id': network['tenant_id'],
'port_id': port_id}})
self._bind_port_to_host(port_id, 'h1')
mapping = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % port_id,
host='h1')
self.assertEqual('mydomain.', mapping['dns_domain'])
req_mapping = self.driver.request_endpoint_details(
nctx.get_admin_context(),
request={'device': 'tap%s' % port_id,
'timestamp': 0, 'request_id': 'request_id'},
host='h1')
if not routed:
vrf_name = ('%s_UnroutedVRF' %
self.driver.aim_mech_driver.apic_system_id)
vrf_tenant = 'common'
elif use_as and pre_vrf:
vrf_name = pre_vrf.name
vrf_tenant = pre_vrf.tenant_name
else:
vrf_name = (self.name_mapper.address_scope(
None, address_scope['id'])
if use_as else 'DefaultVRF')
vrf_tenant = self.name_mapper.project(None,
self._tenant_id)
vrf_id = '%s %s' % (vrf_tenant, vrf_name)
vrf_mapping = self.driver.get_vrf_details(
self._neutron_admin_context, vrf_id=vrf_id)
epg_name = self.name_mapper.network(
self._neutron_context.session, network['id'])
epg_tenant = network['tenant_id']
self._verify_gbp_details_assertions(
mapping, req_mapping, port_id, epg_name, epg_tenant,
subnet, default_route='1.1.2.1')
supernet = ['1.1.2.0/24']
if use_as:
supernet = ['10.10.0.0/26', '1.1.0.0/16', '2.1.0.0/16']
self._verify_vrf_details_assertions(
mapping, vrf_name, vrf_id, supernet, vrf_tenant)
self._verify_vrf_details_assertions(
vrf_mapping, vrf_name, vrf_id, supernet, vrf_tenant)
if routed:
self._verify_fip_details(mapping, fip, 't1', 'EXT-l1')
self._verify_ip_mapping_details(mapping,
'uni:tn-t1:out-l2:instP-n2', 't1', 'EXT-l2')
self._verify_host_snat_ip_details(mapping,
'uni:tn-t1:out-l2:instP-n2', '200.200.0.2',
'200.200.0.1/16')
else:
self.assertFalse(mapping['floating_ip'])
self.assertFalse(mapping['ip_mapping'])
self.assertFalse(mapping['host_snat_ips'])
self.assertEqual(1000, mapping['interface_mtu'])
# Set the right MTU through extra_dhcp_opts
data = {'port': {'extra_dhcp_opts': [{'opt_name': '26',
'opt_value': '2100'}]}}
port = self._update('ports', port_id, data)['port']
mapping = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % port_id,
host='h1')
self.assertEqual(2100, mapping['interface_mtu'])
def test_get_gbp_details(self):
self._do_test_get_gbp_details()
def test_get_gbp_details_with_raw_sql(self):
self._do_test_get_gbp_details(enable_raw_sql=True)
def test_get_gbp_details_with_new_rpc(self):
self._do_test_get_gbp_details(enable_new_rpc=True)
def test_get_gbp_details_pre_existing_vrf(self):
aim_ctx = aim_context.AimContext(self.db_session)
vrf = self.aim_mgr.create(
aim_ctx, aim_resource.VRF(tenant_name='common', name='ctx1',
monitored=True))
self._do_test_get_gbp_details(pre_vrf=vrf)
def test_get_gbp_details_pre_existing_vrf_with_raw_sql(self):
aim_ctx = aim_context.AimContext(self.db_session)
vrf = self.aim_mgr.create(
aim_ctx, aim_resource.VRF(tenant_name='common', name='ctx1',
monitored=True))
self._do_test_get_gbp_details(pre_vrf=vrf, enable_raw_sql=True)
def test_get_gbp_details_pre_existing_vrf_with_new_rpc(self):
aim_ctx = aim_context.AimContext(self.db_session)
vrf = self.aim_mgr.create(
aim_ctx, aim_resource.VRF(tenant_name='common', name='ctx1',
monitored=True))
self._do_test_get_gbp_details(pre_vrf=vrf, enable_new_rpc=True)
def test_get_gbp_details_no_pt(self):
# Test that traditional Neutron ports behave correctly from the
# RPC perspective
self._do_test_gbp_details_no_pt()
def test_get_gbp_details_no_pt_with_raw_sql(self):
# Test that traditional Neutron ports behave correctly from the
# RPC perspective
self._do_test_gbp_details_no_pt(enable_raw_sql=True)
def test_get_gbp_details_no_pt_with_new_rpc(self):
# Test that traditional Neutron ports behave correctly from the
# RPC perspective
self._do_test_gbp_details_no_pt(enable_new_rpc=True)
def test_get_gbp_details_no_pt_pre_existing_vrf(self):
aim_ctx = aim_context.AimContext(self.db_session)
vrf = self.aim_mgr.create(
aim_ctx, aim_resource.VRF(tenant_name='common', name='ctx1',
monitored=True))
self._do_test_gbp_details_no_pt(pre_vrf=vrf)
def test_get_gbp_details_no_pt_pre_existing_vrf_with_raw_sql(self):
aim_ctx = aim_context.AimContext(self.db_session)
vrf = self.aim_mgr.create(
aim_ctx, aim_resource.VRF(tenant_name='common', name='ctx1',
monitored=True))
self._do_test_gbp_details_no_pt(pre_vrf=vrf, enable_raw_sql=True)
def test_get_gbp_details_no_pt_pre_existing_vrf_with_new_rpc(self):
aim_ctx = aim_context.AimContext(self.db_session)
vrf = self.aim_mgr.create(
aim_ctx, aim_resource.VRF(tenant_name='common', name='ctx1',
monitored=True))
self._do_test_gbp_details_no_pt(pre_vrf=vrf, enable_new_rpc=True)
def test_get_gbp_details_no_pt_no_as(self):
self._do_test_gbp_details_no_pt(use_as=False)
def test_get_gbp_details_no_pt_no_as_with_raw_sql(self):
self._do_test_gbp_details_no_pt(use_as=False, enable_raw_sql=True)
def test_get_gbp_details_no_pt_no_as_with_new_rpc(self):
self._do_test_gbp_details_no_pt(use_as=False, enable_new_rpc=True)
def test_get_gbp_details_no_pt_no_as_unrouted(self):
self._do_test_gbp_details_no_pt(use_as=False, routed=False)
def test_get_gbp_details_no_pt_no_as_unrouted_with_raw_sql(self):
self._do_test_gbp_details_no_pt(use_as=False, routed=False,
enable_raw_sql=True)
def test_get_gbp_details_no_pt_no_as_unrouted_with_new_rpc(self):
self._do_test_gbp_details_no_pt(use_as=False, routed=False,
enable_new_rpc=True)
def _test_gbp_details_ext_net_no_pt(self, enable_raw_sql=False,
enable_new_rpc=False):
self.driver.aim_mech_driver.enable_raw_sql_for_device_rpc = (
enable_raw_sql)
self.driver.aim_mech_driver.enable_new_rpc = enable_new_rpc
# Test ports created on Neutron external networks
ext_net1, _, sn1 = self._setup_external_network(
'l1', dn='uni/tn-common/out-l1/instP-n1')
sn1 = {'subnet': sn1}
ext_net2, _, sn2 = self._setup_external_network(
'l2', dn='uni/tn-t1/out-l2/instP-n2')
sn2 = {'subnet': sn2}
# create unmanaged BDs in the VRF connected to L3outs
aim_ctx = aim_context.AimContext(self.db_session)
self.aim_mgr.create(
aim_ctx, aim_resource.BridgeDomain(tenant_name='common',
name='extra_bd_in_common-l1',
vrf_name='EXT-l1'))
self.aim_mgr.create(
aim_ctx, aim_resource.BridgeDomain(tenant_name='t1',
name='extra_bd_in_t1-l1',
vrf_name='EXT-l1'))
self.aim_mgr.create(
aim_ctx, aim_resource.BridgeDomain(tenant_name='t1',
name='extra_bd_in_t1-l2',
vrf_name='EXT-l2'))
with self.port(subnet=sn1) as port:
port_id = port['port']['id']
self._bind_port_to_host(port_id, 'h1')
sn1_1 = self._make_subnet(self.fmt, {'network': ext_net1},
'200.200.0.1', '200.200.0.0/16')
mapping = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % port_id,
host='h1')
req_mapping = self.driver.request_endpoint_details(
self._neutron_admin_context,
request={'device': 'tap%s' % port_id,
'timestamp': 0, 'request_id': 'request_id'},
host='h1')
self._verify_gbp_details_assertions(
mapping, req_mapping, port_id, "EXT-l1", "common", sn1,
map_tenant_name=False, prefix_ap_name=True)
vrf_id = '%s %s' % ("common", "openstack_EXT-l1")
vrf_mapping = self.driver.get_vrf_details(
self._neutron_admin_context, vrf_id=vrf_id)
supernet = [sn1['subnet']['cidr'], sn1_1['subnet']['cidr']]
self._verify_vrf_details_assertions(
mapping, "openstack_EXT-l1", vrf_id, supernet, "common")
self._verify_vrf_details_assertions(
vrf_mapping, "openstack_EXT-l1", vrf_id, supernet, "common")
with self.port(subnet=sn2) as port:
port_id = port['port']['id']
self._bind_port_to_host(port_id, 'h1')
sn2_1 = self._make_subnet(self.fmt, {'network': ext_net2},
'250.250.0.1', '250.250.0.0/16')
mapping = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % port_id,
host='h1')
req_mapping = self.driver.request_endpoint_details(
nctx.get_admin_context(),
request={'device': 'tap%s' % port_id,
'timestamp': 0, 'request_id': 'request_id'},
host='h1')
self._verify_gbp_details_assertions(
mapping, req_mapping, port_id, "EXT-l2", "t1", sn2,
map_tenant_name=False)
vrf_id = '%s %s' % ("t1", "EXT-l2")
vrf_mapping = self.driver.get_vrf_details(
self._neutron_admin_context, vrf_id=vrf_id)
supernet = [sn2['subnet']['cidr'], sn2_1['subnet']['cidr']]
self._verify_vrf_details_assertions(
mapping, "EXT-l2", vrf_id, supernet, "t1")
self._verify_vrf_details_assertions(
vrf_mapping, "EXT-l2", vrf_id, supernet, "t1")
def test_gbp_details_ext_net_no_pt(self):
self._test_gbp_details_ext_net_no_pt()
def test_gbp_details_ext_net_no_pt_with_raw_sql(self):
self._test_gbp_details_ext_net_no_pt(enable_raw_sql=True)
def test_gbp_details_ext_net_no_pt_with_new_rpc(self):
self._test_gbp_details_ext_net_no_pt(enable_new_rpc=True)
def test_ip_address_owner_update(self):
l3p = self.create_l3_policy(name='myl3')['l3_policy']
l2p = self.create_l2_policy(name='myl2',
l3_policy_id=l3p['id'])['l2_policy']
ptg = self.create_policy_target_group(
name="ptg1", l2_policy_id=l2p['id'])['policy_target_group']
net_id = l2p['network_id']
pt1 = self.create_policy_target(
name="pt1", policy_target_group_id=ptg['id'])['policy_target']
pt2 = self.create_policy_target(name="pt2",
policy_target_group_id=ptg['id'])['policy_target']
self._bind_port_to_host(pt1['port_id'], 'h1')
self._bind_port_to_host(pt2['port_id'], 'h2')
ip_owner_info = {'port': pt1['port_id'], 'ip_address_v4': '1.2.3.4'}
self.driver.aim_mech_driver._notify_port_update = mock.Mock()
# set new owner
self.driver.ip_address_owner_update(self._context,
ip_owner_info=ip_owner_info, host='h1')
obj = self.driver.aim_mech_driver.get_port_for_ha_ipaddress(
'1.2.3.4', net_id)
self.assertEqual(pt1['port_id'], obj['port_id'])
self.driver.aim_mech_driver._notify_port_update.assert_called_with(
mock.ANY, pt1['port_id'])
# update existing owner
self.driver.aim_mech_driver._notify_port_update.reset_mock()
ip_owner_info['port'] = pt2['port_id']
self.driver.ip_address_owner_update(self._context,
ip_owner_info=ip_owner_info, host='h2')
obj = self.driver.aim_mech_driver.get_port_for_ha_ipaddress(
'1.2.3.4', net_id)
self.assertEqual(pt2['port_id'], obj['port_id'])
exp_calls = [
mock.call(mock.ANY, pt1['port_id']),
mock.call(mock.ANY, pt2['port_id'])]
self._check_call_list(exp_calls,
self.driver.aim_mech_driver._notify_port_update.call_args_list)
def test_bind_port_with_allowed_vm_names(self):
allowed_vm_names = ['safe_vm*', '^secure_vm*']
l3p = self.create_l3_policy(name='myl3',
allowed_vm_names=allowed_vm_names)['l3_policy']
l2p = self.create_l2_policy(
name='myl2', l3_policy_id=l3p['id'])['l2_policy']
ptg = self.create_policy_target_group(
name="ptg1", l2_policy_id=l2p['id'])['policy_target_group']
pt = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
nova_client = mock.patch(
'gbpservice.neutron.plugins.ml2plus.drivers.apic_aim.'
'nova_client.NovaClient.get_server').start()
vm = mock.Mock()
vm.name = 'secure_vm1'
nova_client.return_value = vm
newp1 = self._bind_port_to_host(pt['port_id'], 'h1')
self.assertEqual(newp1['port']['binding:vif_type'], 'ovs')
# bind again
vm.name = 'bad_vm1'
newp1 = self._bind_port_to_host(pt['port_id'], 'h2')
self.assertEqual(newp1['port']['binding:vif_type'], 'binding_failed')
# update l3p with empty allowed_vm_names
l3p = self.update_l3_policy(l3p['id'], tenant_id=l3p['tenant_id'],
allowed_vm_names=[],
expected_res_status=200)['l3_policy']
newp1 = self._bind_port_to_host(pt['port_id'], 'h3')
self.assertEqual(newp1['port']['binding:vif_type'], 'ovs')
class TestPolicyTargetDvs(AIMBaseTestCase):
def setUp(self):
super(TestPolicyTargetDvs, self).setUp()
self.driver.aim_mech_driver._dvs_notifier = mock.MagicMock()
self.driver.aim_mech_driver.dvs_notifier.bind_port_call = mock.Mock(
return_value={'key': BOOKED_PORT_VALUE})
def _verify_dvs_notifier(self, notifier, port, host):
# can't use getattr() with mock, so use eval instead
try:
dvs_mock = eval('self.driver.aim_mech_driver.dvs_notifier.' +
notifier)
except Exception:
self.assertTrue(False,
"The method " + notifier + " was not called")
return
self.assertTrue(dvs_mock.called)
a1, a2, a3, a4 = dvs_mock.call_args[0]
self.assertEqual(a1['id'], port['id'])
if notifier != 'delete_port_call':
self.assertEqual(a2['id'], port['id'])
self.assertEqual(a4, host)
def _pg_name(self, project, profile, network):
return ('prj_' + str(project) + '|' + str(profile) + '|' + network)
def test_bind_port_dvs(self):
self.agent_conf = AGENT_CONF_DVS
l3p = self.create_l3_policy(name='myl3')['l3_policy']
l2p = self.create_l2_policy(
name='myl2', l3_policy_id=l3p['id'])['l2_policy']
ptg = self.create_policy_target_group(
name="ptg1", l2_policy_id=l2p['id'])['policy_target_group']
pt = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
newp1 = self._bind_port_to_host(pt['port_id'], 'h1')
vif_details = newp1['port']['binding:vif_details']
self.assertIsNotNone(vif_details.get('dvs_port_group_name'))
pg = self._pg_name(ptg['tenant_id'],
self.driver.aim_mech_driver.ap_name, ptg['id'])
self.assertEqual(pg, vif_details.get('dvs_port_group_name'))
port_key = newp1['port']['binding:vif_details'].get('dvs_port_key')
self.assertIsNotNone(port_key)
self.assertEqual(port_key, BOOKED_PORT_VALUE)
self._verify_dvs_notifier('update_postcommit_port_call',
newp1['port'], 'h1')
self.delete_policy_target(pt['id'], expected_res_status=204)
self._verify_dvs_notifier('delete_port_call', newp1['port'], 'h1')
def test_bind_port_dvs_with_opflex_different_hosts(self):
l3p = self.create_l3_policy(name='myl3')['l3_policy']
l2p = self.create_l2_policy(
name='myl2', l3_policy_id=l3p['id'])['l2_policy']
ptg = self.create_policy_target_group(
name="ptg1", l2_policy_id=l2p['id'])['policy_target_group']
self.agent_conf = AGENT_CONF
pt2 = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
newp2 = self._bind_port_to_host(pt2['port_id'], 'h2')
vif_details = newp2['port']['binding:vif_details']
self.assertIsNone(vif_details.get('dvs_port_group_name'))
pt1 = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
self.agent_conf = AGENT_CONF_DVS
self.driver.aim_mech_driver.dvs_notifier.reset_mock()
newp1 = self._bind_port_to_host(pt1['port_id'], 'h2')
port_key = newp1['port']['binding:vif_details'].get('dvs_port_key')
self.assertIsNotNone(port_key)
self.assertEqual(port_key, BOOKED_PORT_VALUE)
vif_details = newp1['port']['binding:vif_details']
self.assertIsNotNone(vif_details.get('dvs_port_group_name'))
pg = self._pg_name(ptg['tenant_id'],
self.driver.aim_mech_driver.ap_name, ptg['id'])
self.assertEqual(pg, vif_details.get('dvs_port_group_name'))
self._verify_dvs_notifier('update_postcommit_port_call',
newp1['port'], 'h2')
self.delete_policy_target(pt1['id'], expected_res_status=204)
self._verify_dvs_notifier('delete_port_call', newp1['port'], 'h2')
def test_bind_ports_opflex_same_host(self):
l3p = self.create_l3_policy(name='myl3')['l3_policy']
l2p = self.create_l2_policy(
name='myl2', l3_policy_id=l3p['id'])['l2_policy']
ptg = self.create_policy_target_group(
name="ptg1", l2_policy_id=l2p['id'])['policy_target_group']
pt1 = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
newp1 = self._bind_port_to_host(pt1['port_id'], 'h1')
vif_details = newp1['port']['binding:vif_details']
self.assertIsNone(vif_details.get('dvs_port_group_name'))
port_key = newp1['port']['binding:vif_details'].get('dvs_port_key')
self.assertIsNone(port_key)
dvs_mock = self.driver.aim_mech_driver.dvs_notifier
dvs_mock.update_postcommit_port_call.assert_not_called()
self.delete_policy_target(pt1['id'], expected_res_status=204)
dvs_mock.delete_port_call.assert_not_called()
self.driver.aim_mech_driver.dvs_notifier.reset_mock()
pt2 = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
newp2 = self._bind_port_to_host(pt2['port_id'], 'h1')
vif_details = newp2['port']['binding:vif_details']
self.assertIsNone(vif_details.get('dvs_port_group_name'))
port_key = newp2['port']['binding:vif_details'].get('dvs_port_key')
self.assertIsNone(port_key)
dvs_mock.assert_not_called()
self.delete_policy_target(pt2['id'], expected_res_status=204)
dvs_mock.assert_not_called()
def test_bind_ports_dvs_with_opflex_same_host(self):
self.agent_conf = AGENT_CONF_DVS
l3p = self.create_l3_policy(name='myl3')['l3_policy']
l2p = self.create_l2_policy(
name='myl2', l3_policy_id=l3p['id'])['l2_policy']
ptg = self.create_policy_target_group(
name="ptg1", l2_policy_id=l2p['id'])['policy_target_group']
pt1 = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
newp1 = self._bind_port_to_host(pt1['port_id'], 'h1')
vif_details = newp1['port']['binding:vif_details']
self.assertIsNotNone(vif_details.get('dvs_port_group_name'))
port_key = newp1['port']['binding:vif_details'].get('dvs_port_key')
self.assertIsNotNone(port_key)
self.assertEqual(port_key, BOOKED_PORT_VALUE)
self._verify_dvs_notifier('update_postcommit_port_call',
newp1['port'], 'h1')
self.delete_policy_target(pt1['id'], expected_res_status=204)
self._verify_dvs_notifier('delete_port_call', newp1['port'], 'h1')
self.driver.aim_mech_driver.dvs_notifier.reset_mock()
self.agent_conf = AGENT_CONF
pt2 = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
newp2 = self._bind_other_port_to_host(pt2['port_id'], 'h1')
vif_details = newp2['port']['binding:vif_details']
self.assertIsNone(vif_details.get('dvs_port_group_name'))
port_key = newp2['port']['binding:vif_details'].get('dvs_port_key')
self.assertIsNone(port_key)
dvs_mock = self.driver.aim_mech_driver.dvs_notifier
dvs_mock.update_postcommit_port_call.assert_not_called()
self.delete_policy_target(pt2['id'], expected_res_status=204)
dvs_mock.delete_port_call.assert_not_called()
def test_bind_port_dvs_shared(self):
self.agent_conf = AGENT_CONF_DVS
ptg = self.create_policy_target_group(shared=True,
name="ptg1")['policy_target_group']
pt = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
newp1 = self._bind_port_to_host(pt['port_id'], 'h1')
vif_details = newp1['port']['binding:vif_details']
self.assertIsNotNone(vif_details.get('dvs_port_group_name'))
pg = self._pg_name(ptg['tenant_id'],
self.driver.aim_mech_driver.ap_name, ptg['id'])
self.assertEqual(pg, vif_details.get('dvs_port_group_name'))
port_key = newp1['port']['binding:vif_details'].get('dvs_port_key')
self.assertIsNotNone(port_key)
self.assertEqual(port_key, BOOKED_PORT_VALUE)
self._verify_dvs_notifier('update_postcommit_port_call',
newp1['port'], 'h1')
self.delete_policy_target(pt['id'], expected_res_status=204)
self._verify_dvs_notifier('delete_port_call', newp1['port'], 'h1')
class TestPolicyTargetRollback(AIMBaseTestCase):
def test_policy_target_create_fail(self):
orig_func = self.dummy.create_policy_target_precommit
self.dummy.create_policy_target_precommit = mock.Mock(
side_effect=Exception)
ptg_id = self.create_policy_target_group(
name="ptg1")['policy_target_group']['id']
ports = self._plugin.get_ports(self._context)
self.create_policy_target(name="pt1",
policy_target_group_id=ptg_id,
expected_res_status=500)
self.assertEqual([],
self._gbp_plugin.get_policy_targets(self._context))
new_ports = self._plugin.get_ports(self._context)
self.assertItemsEqual(ports, new_ports)
# restore mock
self.dummy.create_policy_target_precommit = orig_func
def test_policy_target_update_fail(self):
orig_func = self.dummy.update_policy_target_precommit
self.dummy.update_policy_target_precommit = mock.Mock(
side_effect=Exception)
ptg = self.create_policy_target_group(
name="ptg1")['policy_target_group']
ptg_id = ptg['id']
pt = self.create_policy_target(
name="pt1", policy_target_group_id=ptg_id)['policy_target']
pt_id = pt['id']
self.update_policy_target(pt_id, expected_res_status=500,
name="new name")
new_pt = self.show_policy_target(pt_id, expected_res_status=200)
self.assertEqual(pt['name'], new_pt['policy_target']['name'])
# restore mock
self.dummy.update_policy_target_precommit = orig_func
def test_policy_target_delete_fail(self):
orig_func = self.dummy.delete_policy_target_precommit
self.dummy.delete_policy_target_precommit = mock.Mock(
side_effect=Exception)
self._gbp_plugin.policy_driver_manager.policy_drivers[
'aim_mapping'].obj._delete_port = mock.Mock(
side_effect=Exception)
ptg = self.create_policy_target_group(
name="ptg1")['policy_target_group']
ptg_id = ptg['id']
pt = self.create_policy_target(
name="pt1", policy_target_group_id=ptg_id)['policy_target']
pt_id = pt['id']
port_id = pt['port_id']
self.delete_policy_target(pt_id, expected_res_status=500)
self.show_policy_target(pt_id, expected_res_status=200)
req = self.new_show_request('ports', port_id, fmt=self.fmt)
res = self.deserialize(self.fmt, req.get_response(self.api))
self.assertIsNotNone(res['port']['id'])
# restore mock
self.dummy.delete_policy_target_precommit = orig_func
class TestPolicyRuleBase(AIMBaseTestCase):
def _validate_filter_entry(self, policy_rule, afilter, filter_entry):
filter_entry_name = 'os-entry-0'
self.assertEqual(filter_entry_name, filter_entry.name)
pc = self.show_policy_classifier(
policy_rule['policy_classifier_id'])['policy_classifier']
expected_entries = alib.get_filter_entries_for_policy_classifier(pc)
if 'reverse' in afilter.name:
del expected_entries['forward_rules']
else:
del expected_entries['reverse_rules']
expected_filter_entry = self.driver._aim_filter_entry(
self._neutron_context.session, afilter, filter_entry_name,
alib.map_to_aim_filter_entry(
expected_entries.items()[0][1].items()[0][1]))
self.assertItemsEqual(
aim_object_to_dict(expected_filter_entry),
# special processing to convert unicode to str
dict((str(k), str(v)) for k, v in aim_object_to_dict(
filter_entry).items()))
def _validate_1_to_many_reverse_filter_entries(
self, policy_rule, afilter, filter_entries):
pc = self.show_policy_classifier(
policy_rule['policy_classifier_id'])['policy_classifier']
expected_entries = alib.get_filter_entries_for_policy_classifier(pc)
for e_name, value in expected_entries['reverse_rules'].items():
expected_filter_entry = self.driver._aim_filter_entry(
self._neutron_context.session, afilter, e_name,
alib.map_to_aim_filter_entry(value))
filter_entry = (
entry for entry in filter_entries if entry.name == e_name
).next()
self.assertItemsEqual(
aim_object_to_dict(expected_filter_entry),
# special processing to convert unicode to str
dict((str(k), str(v)) for k, v in aim_object_to_dict(
filter_entry).items()))
def _test_policy_rule_aim_mapping(self, policy_rule):
aim_filter_name = str(self.name_mapper.policy_rule(
self._neutron_context.session, policy_rule['id']))
filter_names = [aim_filter_name]
protocol = self.show_policy_classifier(
policy_rule['policy_classifier_id'])[
'policy_classifier']['protocol']
if protocol in alib.REVERSIBLE_PROTOCOLS:
aim_reverse_filter_name = str(self.name_mapper.policy_rule(
self._neutron_context.session, policy_rule['id'],
prefix=alib.REVERSE_PREFIX))
filter_names.append(aim_reverse_filter_name)
aim_tenant_name = md.COMMON_TENANT_NAME
filter_entries, aim_obj_list = [], []
for filter_name in filter_names:
aim_filters = self.aim_mgr.find(
self._aim_context, aim_resource.Filter, name=filter_name)
aim_obj_list.append(aim_filters[0])
self.assertEqual(1, len(aim_filters))
self.assertEqual(filter_name, aim_filters[0].name)
self.assertEqual(aim_tenant_name, aim_filters[0].tenant_name)
pr_display_name = policy_rule['name'].replace(' ', '_')
self.assertEqual(pr_display_name, aim_filters[0].display_name)
aim_filter_entries = self.aim_mgr.find(
self._aim_context, aim_resource.FilterEntry,
tenant_name=aim_filters[0].tenant_name,
filter_name=aim_filters[0].name)
if protocol == 'tcp' or protocol == 'udp' or not (
filter_name.startswith('reverse')):
# this will also check the forward entries for
# icmp and no protocol case
self.assertEqual(1, len(aim_filter_entries))
self._validate_filter_entry(policy_rule, aim_filters[0],
aim_filter_entries[0])
elif protocol == 'icmp':
# this is only for reverse entries with ICMP
self.assertEqual(4, len(aim_filter_entries))
self._validate_1_to_many_reverse_filter_entries(
policy_rule, aim_filters[0], aim_filter_entries)
else:
# this is only for reverse entries when no protocol
# is specified. One entry for TCP, one for UDP and
# four entries for ICMP
self.assertEqual(6, len(aim_filter_entries))
self._validate_1_to_many_reverse_filter_entries(
policy_rule, aim_filters[0], aim_filter_entries)
filter_entries.append(aim_filter_entries[0])
aim_obj_list.extend(filter_entries)
self.assertEqual(
filter_entries[0].dn,
policy_rule[DN]['Forward-FilterEntries'][0])
if len(filter_names) > 1:
self.assertEqual(
filter_entries[1].dn, policy_rule[
DN]['Reverse-FilterEntries'][0])
merged_status = self._gbp_plugin.policy_driver_manager.policy_drivers[
'aim_mapping'].obj._merge_aim_status(self._neutron_context.session,
aim_obj_list)
self.assertEqual(merged_status, policy_rule['status'])
def _test_policy_rule_delete_aim_mapping(self, policy_rule):
aim_filter_name = str(self.name_mapper.policy_rule(
self._neutron_context.session, policy_rule['id']))
aim_reverse_filter_name = str(self.name_mapper.policy_rule(
self._neutron_context.session, policy_rule['id'],
prefix=alib.REVERSE_PREFIX))
for filter_name in [aim_filter_name, aim_reverse_filter_name]:
aim_filters = self.aim_mgr.find(
self._aim_context, aim_resource.Filter, name=filter_name)
self.assertEqual(0, len(aim_filters))
class TestPolicyRule(TestPolicyRuleBase):
def _test_policy_classifier_update(self, pr):
orig_pc_id = pr['policy_classifier_id']
pc = self.create_policy_classifier(
direction='in', protocol='tcp', port_range=80)['policy_classifier']
new_pr = self.update_policy_rule(
pr['id'], expected_res_status=200,
policy_classifier_id=pc['id'])['policy_rule']
self._test_policy_rule_aim_mapping(new_pr)
prs = self.create_policy_rule_set(
name="ctr", policy_rules=[new_pr['id']])[
'policy_rule_set']
self._validate_policy_rule_set_aim_mapping(prs, [new_pr])
# Remove Classifier port
self.update_policy_classifier(pc['id'], port_range=None)
new_pr = self.update_policy_rule(
pr['id'], expected_res_status=200,
policy_classifier_id=pc['id'])['policy_rule']
self._test_policy_rule_aim_mapping(new_pr)
# Change direction
self.update_policy_classifier(pc['id'], direction='out')
new_pr = self.update_policy_rule(
pr['id'], expected_res_status=200,
policy_classifier_id=pc['id'])['policy_rule']
self._test_policy_rule_aim_mapping(new_pr)
# Check with protocol that does not require reverse filter
self.update_policy_classifier(pc['id'], protocol=None)
new_pr = self.update_policy_rule(
pr['id'], expected_res_status=200,
policy_classifier_id=pc['id'])['policy_rule']
self._test_policy_rule_aim_mapping(new_pr)
self.delete_policy_rule_set(prs['id'], expected_res_status=204)
new_pr = self.update_policy_rule(
pr['id'], expected_res_status=200,
policy_classifier_id=orig_pc_id)['policy_rule']
self._test_policy_rule_aim_mapping(new_pr)
self.delete_policy_classifier(pc['id'], expected_res_status=204)
def _test_policy_rule_lifecycle(self, protocol, direction):
action1 = self.create_policy_action(
action_type='redirect')['policy_action']
if protocol == 'ANY':
classifier = self.create_policy_classifier(
direction=direction)['policy_classifier']
elif protocol in ['TCP', 'UDP']:
classifier = self.create_policy_classifier(
protocol=protocol, port_range="22",
direction=direction)['policy_classifier']
else:
classifier = self.create_policy_classifier(
protocol='ICMP',
direction=direction)['policy_classifier']
pr = self.create_policy_rule(
name="pr1", policy_classifier_id=classifier['id'],
policy_actions=[action1['id']])['policy_rule']
pr_id = pr['id']
pr_name = pr['name']
self.show_policy_rule(pr_id, expected_res_status=200)
self._test_policy_rule_aim_mapping(pr)
pr_name = 'new name'
new_pr = self.update_policy_rule(pr_id, expected_res_status=200,
name=pr_name)['policy_rule']
self._test_policy_rule_aim_mapping(new_pr)
self._test_policy_classifier_update(new_pr)
self.delete_policy_rule(pr_id, expected_res_status=204)
self.show_policy_rule(pr_id, expected_res_status=404)
self._test_policy_rule_delete_aim_mapping(new_pr)
def test_policy_rule_lifecycle_tcp_in(self):
self._test_policy_rule_lifecycle(protocol='TCP', direction='in')
def test_policy_rule_lifecycle_tcp_out(self):
self._test_policy_rule_lifecycle(protocol='TCP', direction='out')
def test_policy_rule_lifecycle_tcp_bi(self):
self._test_policy_rule_lifecycle(protocol='TCP', direction='bi')
def test_policy_rule_lifecycle_icmp_in(self):
self._test_policy_rule_lifecycle(protocol='ICMP', direction='in')
def test_policy_rule_lifecycle_icmp_out(self):
self._test_policy_rule_lifecycle(protocol='ICMP', direction='out')
def test_policy_rule_lifecycle_icmp_bi(self):
self._test_policy_rule_lifecycle(protocol='ICMP', direction='bi')
def test_policy_rule_lifecycle_udp_in(self):
self._test_policy_rule_lifecycle(protocol='UDP', direction='in')
def test_policy_rule_lifecycle_udp_out(self):
self._test_policy_rule_lifecycle(protocol='UDP', direction='out')
def test_policy_rule_lifecycle_udp_bi(self):
self._test_policy_rule_lifecycle(protocol='UDP', direction='bi')
def test_policy_rule_lifecycle_any_in(self):
self._test_policy_rule_lifecycle(protocol='ANY', direction='in')
def test_policy_rule_lifecycle_any_out(self):
self._test_policy_rule_lifecycle(protocol='ANY', direction='out')
def test_policy_rule_lifecycle_any_bi(self):
self._test_policy_rule_lifecycle(protocol='ANY', direction='bi')
class TestPolicyRuleRollback(TestPolicyRuleBase):
def test_policy_rule_create_fail(self):
orig_func = self.dummy.create_policy_rule_precommit
self.dummy.create_policy_rule_precommit = mock.Mock(
side_effect=Exception)
action1 = self.create_policy_action(
action_type='redirect')['policy_action']
classifier = self.create_policy_classifier(
protocol='TCP', port_range="22",
direction='bi')['policy_classifier']
self.create_policy_rule(
name="pr1", policy_classifier_id=classifier['id'],
policy_actions=[action1['id']], expected_res_status=500)
self.assertEqual([],
self._gbp_plugin.get_policy_rules(self._context))
aim_filters = self.aim_mgr.find(
self._aim_context, aim_resource.Filter)
self.assertEqual(1, len(aim_filters))
aim_filter_entries = self.aim_mgr.find(
self._aim_context, aim_resource.FilterEntry)
self.assertEqual(1, len(aim_filter_entries))
# restore mock
self.dummy.create_policy_rule_precommit = orig_func
def test_policy_rule_update_fail(self):
orig_func = self.dummy.update_policy_rule_precommit
self.dummy.update_policy_rule_precommit = mock.Mock(
side_effect=Exception)
action1 = self.create_policy_action(
action_type='redirect')['policy_action']
classifier = self.create_policy_classifier(
protocol='TCP', port_range="22",
direction='bi')['policy_classifier']
pr = self.create_policy_rule(
name="pr1", policy_classifier_id=classifier['id'],
policy_actions=[action1['id']])['policy_rule']
self._test_policy_rule_aim_mapping(pr)
self.update_policy_rule(pr['id'], expected_res_status=500,
name='new name')
self._test_policy_rule_aim_mapping(pr)
# restore mock
self.dummy.update_policy_rule_precommit = orig_func
def test_policy_rule_delete_fail(self):
orig_func = self.dummy.delete_policy_rule_precommit
self.dummy.delete_policy_rule_precommit = mock.Mock(
side_effect=Exception)
action1 = self.create_policy_action(
action_type='redirect')['policy_action']
classifier = self.create_policy_classifier(
protocol='TCP', port_range="22",
direction='bi')['policy_classifier']
pr = self.create_policy_rule(
name="pr1", policy_classifier_id=classifier['id'],
policy_actions=[action1['id']])['policy_rule']
pr_id = pr['id']
self.delete_policy_rule(pr_id, expected_res_status=500)
self._test_policy_rule_aim_mapping(pr)
# restore mock
self.dummy.delete_policy_rule_precommit = orig_func
class TestPolicyRuleSet(AIMBaseTestCase):
def test_policy_rule_set_lifecycle(self):
rules = self._create_3_direction_rules()
prs = self.create_policy_rule_set(
name="ctr", policy_rules=[x['id'] for x in rules])[
'policy_rule_set']
self._validate_policy_rule_set_aim_mapping(prs, rules)
# update directions of policy classifiers
for r in rules:
pc = self.show_policy_classifier(
r['policy_classifier_id'])['policy_classifier']
if pc['direction'] == 'in':
new_direction = 'bi'
elif pc['direction'] == 'out':
new_direction = 'in'
else:
new_direction = 'out'
self.update_policy_classifier(pc['id'],
direction=new_direction)
self._validate_policy_rule_set_aim_mapping(prs, rules)
new_rules = self._create_3_direction_rules()
prs = self.update_policy_rule_set(
prs['id'], policy_rules=[x['id'] for x in new_rules],
expected_res_status=200)['policy_rule_set']
self._validate_policy_rule_set_aim_mapping(prs, new_rules)
self.delete_policy_rule_set(prs['id'], expected_res_status=204)
class TestPolicyRuleSetRollback(AIMBaseTestCase):
def test_policy_rule_set_create_fail(self):
orig_func = self.dummy.create_policy_rule_set_precommit
self.dummy.create_policy_rule_set_precommit = mock.Mock(
side_effect=Exception)
rules = self._create_3_direction_rules()
self.create_policy_rule_set(
name="ctr", policy_rules=[x['id'] for x in rules],
expected_res_status=500)
self.assertEqual(
[], self._gbp_plugin.get_policy_rule_sets(self._context))
aim_contracts = self.aim_mgr.find(
self._aim_context, aim_resource.Contract)
self.assertEqual(0, len(aim_contracts))
aim_contract_subjects = self.aim_mgr.find(
self._aim_context, aim_resource.ContractSubject)
self.assertEqual(0, len(aim_contract_subjects))
# restore mock
self.dummy.create_policy_rule_set_precommit = orig_func
def test_policy_rule_set_update_fail(self):
orig_func = self.dummy.update_policy_rule_set_precommit
self.dummy.update_policy_rule_set_precommit = mock.Mock(
side_effect=Exception)
rules = self._create_3_direction_rules()
prs = self.create_policy_rule_set(
name="ctr", policy_rules=[x['id'] for x in rules])[
'policy_rule_set']
self.update_policy_rule_set(
prs['id'], expected_res_status=500, name='new name')
self._validate_policy_rule_set_aim_mapping(prs, rules)
# restore mock
self.dummy.update_policy_rule_set_precommit = orig_func
def test_policy_rule_set_delete_fail(self):
orig_func = self.dummy.delete_policy_rule_set_precommit
self.dummy.delete_policy_rule_set_precommit = mock.Mock(
side_effect=Exception)
rules = self._create_3_direction_rules()
prs = self.create_policy_rule_set(
name="ctr", policy_rules=[x['id'] for x in rules])[
'policy_rule_set']
self.delete_policy_rule_set(prs['id'], expected_res_status=500)
self._validate_policy_rule_set_aim_mapping(prs, rules)
# restore mock
self.dummy.delete_policy_rule_set_precommit = orig_func
class NotificationTest(AIMBaseTestCase):
block_dhcp_notifier = False
def setUp(self, policy_drivers=None, core_plugin=None, ml2_options=None,
l3_plugin=None, sc_plugin=None, **kwargs):
self.queue_notification_call_count = 0
self.max_notification_queue_length = 0
self.notification_queue = None
self.post_notifications_from_queue_call_count = 0
super(NotificationTest, self).setUp(
policy_drivers=policy_drivers, core_plugin=core_plugin,
ml2_options=ml2_options, l3_plugin=l3_plugin,
sc_plugin=sc_plugin, **kwargs)
self.orig_enqueue = local_api._enqueue
# The functions are patched below to instrument how
# many times the functions are called and also to track
# the queue length.
def _enqueue(session, transaction_key, entry):
self.queue_notification_call_count += 1
self.orig_enqueue(session, transaction_key, entry)
if session.notification_queue:
key = session.notification_queue.keys()[0]
length = len(session.notification_queue[key])
if length > self.max_notification_queue_length:
self.max_notification_queue_length = length
self.notification_queue = session.notification_queue
local_api._enqueue = _enqueue
self.orig_send_or_queue_notification = (
local_api.send_or_queue_notification)
def send_or_queue_notification(
session, transaction_key, notifier_obj, notifier_method, args):
self.orig_send_or_queue_notification(session,
transaction_key, notifier_obj, notifier_method, args)
self.notification_queue = session.notification_queue
local_api.send_or_queue_notification = send_or_queue_notification
self.orig_send_or_queue_registry_notification = (
local_api.send_or_queue_registry_notification)
def send_or_queue_registry_notification(
session, transaction_key, resource, event, trigger, **kwargs):
self.orig_send_or_queue_registry_notification(session,
transaction_key, resource, event, trigger, **kwargs)
if session:
self.notification_queue = session.notification_queue
local_api.send_or_queue_registry_notification = (
send_or_queue_registry_notification)
self.orig_post_notifications_from_queue = (
local_api.post_notifications_from_queue)
def post_notifications_from_queue(session, transaction_key):
self.post_notifications_from_queue_call_count += 1
self.orig_post_notifications_from_queue(session, transaction_key)
self.notification_queue = session.notification_queue
local_api.post_notifications_from_queue = (
post_notifications_from_queue)
self.orig_discard_notifications_after_rollback = (
local_api.discard_notifications_after_rollback)
def discard_notifications_after_rollback(session):
self.orig_discard_notifications_after_rollback(session)
self.notification_queue = session.notification_queue
local_api.discard_notifications_after_rollback = (
discard_notifications_after_rollback)
def tearDown(self):
super(NotificationTest, self).tearDown()
local_api.QUEUE_OUT_OF_PROCESS_NOTIFICATIONS = False
local_api._enqueue = self.orig_enqueue
local_api.send_or_queue_notification = (
self.orig_send_or_queue_notification)
local_api.send_or_queue_registry_notification = (
self.orig_send_or_queue_registry_notification)
local_api.post_notifications_from_queue = (
self.orig_post_notifications_from_queue)
local_api.discard_notifications_after_rollback = (
self.orig_discard_notifications_after_rollback)
def _expected_dhcp_agent_call_list(self):
# This testing strategy assumes the sequence of notifications
# that result from the sequence of operations currently
# performed. If the internal orchestration logic changes resulting
# in a change in the sequence of operations, the following
# list should be updated accordingly.
# The 2nd argument is the resource object that is created,
# and can be potentially verified for further detail
calls = [
mock.call().notify(mock.ANY, mock.ANY, "network.create.end"),
mock.call().notify(mock.ANY, mock.ANY, "subnet.create.end"),
mock.call().notify(mock.ANY, mock.ANY, "port.create.end"),
mock.call().notify(mock.ANY, mock.ANY, "port.create.end"),
mock.call().notify(mock.ANY, mock.ANY, "port.delete.end"),
mock.call().notify(mock.ANY, mock.ANY, "port.delete.end"),
mock.call().notify(mock.ANY, mock.ANY, "subnet.delete.end"),
mock.call().notify(mock.ANY, mock.ANY, "network.delete.end")]
return calls
def _test_notifier(self, notifier, expected_calls,
batch_notifications=False):
local_api.QUEUE_OUT_OF_PROCESS_NOTIFICATIONS = batch_notifications
ptg = self.create_policy_target_group(name="ptg1")
ptg_id = ptg['policy_target_group']['id']
pt = self.create_policy_target(
name="pt1", policy_target_group_id=ptg_id)['policy_target']
self.assertEqual(pt['policy_target_group_id'], ptg_id)
self.new_delete_request(
'policy_targets', pt['id']).get_response(self.ext_api)
self.new_delete_request(
'policy_target_groups', ptg_id).get_response(self.ext_api)
sg_rules = self._plugin.get_security_group_rules(
self._neutron_context)
sg_ids = set([x['security_group_id'] for x in sg_rules])
for sg_id in sg_ids:
self.new_delete_request(
'security-groups', sg_id).get_response(self.ext_api)
# Remove any port update calls for port-binding
new_mock = mock.MagicMock()
call_list = []
for call in notifier.mock_calls:
if call[1][-1] != 'port.update.end':
call_list.append(call)
new_mock.mock_calls = call_list
new_mock.assert_has_calls(expected_calls(), any_order=False)
# test that no notifications have been left out
self.assertEqual({}, self.notification_queue)
return new_mock
def _deep_replace_in_value(self, d, str1, str2):
for k, v in d.items():
if isinstance(v, str) and str1 in v:
d[k] = v.replace(str1, str2)
if isinstance(v, dict):
self._deep_replace_in_value(v, str1, str2)
def _deep_replace_by_key(self, d, key, str2):
if not isinstance(d, dict):
return
if key in d:
d[key] = str2
for k, v in d.items():
if isinstance(v, dict):
self._deep_replace_by_key(v, key, str2)
if isinstance(v, list):
for i in v:
self._deep_replace_by_key(i, key, str2)
def _test_notifications(self, no_batch, with_batch):
for n1, n2 in zip(no_batch, with_batch):
# replace ids from resource dicts since its random
# id can appear in inner dictionaries: we use deep replace
for n in [n1, n2]:
for resource, dct in n[0][1].items():
if 'id' in dct:
self._deep_replace_in_value(dct, dct['id'], 'XXX')
for random_key in ('subnetpool_id', 'network_id',
'mac_address', 'subnet_id',
'ip_address', 'device_id',
'security_groups', 'id'):
self._deep_replace_by_key(dct, random_key, 'XXX')
# test the resource objects are identical with and without batch
self.assertEqual(n1[0][1], n2[0][1])
# test that all the same events are pushed with and without batch
self.assertEqual(n1[0][2], n2[0][2])
def test_dhcp_notifier(self):
with mock.patch.object(dhcp_rpc_agent_api.DhcpAgentNotifyAPI,
'notify') as dhcp_notifier_no_batch:
no_batch = self._test_notifier(dhcp_notifier_no_batch,
self._expected_dhcp_agent_call_list, False)
self.assertEqual(0, self.queue_notification_call_count)
self.assertEqual(0, self.max_notification_queue_length)
self.assertEqual(0, self.post_notifications_from_queue_call_count)
self.fake_uuid = 0
with mock.patch.object(dhcp_rpc_agent_api.DhcpAgentNotifyAPI,
'notify') as dhcp_notifier_with_batch:
batch = self._test_notifier(dhcp_notifier_with_batch,
self._expected_dhcp_agent_call_list, True)
self.assertLess(0, self.queue_notification_call_count)
self.assertLess(0, self.max_notification_queue_length)
# There are 4 transactions - one for create PTG,
# one for create PT, one for delete PT, and one for
# delete PTG. Delete PT notification is sent without queueing,
# which leaves us with 3 sets of queued notifications.
self.assertEqual(3, self.post_notifications_from_queue_call_count)
self._test_notifications(no_batch.call_args_list, batch.call_args_list)
def test_notifiers_with_transaction_rollback(self):
# No notifications should get pushed in this case
orig_func = self.dummy.create_policy_target_group_precommit
self.dummy.create_policy_target_group_precommit = mock.Mock(
side_effect=Exception)
local_api.QUEUE_OUT_OF_PROCESS_NOTIFICATIONS = True
with mock.patch.object(dhcp_rpc_agent_api.DhcpAgentNotifyAPI,
'notify') as dhcp_notifier:
with mock.patch.object(nova.Notifier,
'send_network_change') as nova_notifier:
self.create_policy_target_group(name="ptg1",
expected_res_status=500)
# Remove any port updates, as those don't count
args_list = []
new_dhcp = mock.MagicMock()
for call_args in dhcp_notifier.call_args_list:
if call_args[0][-1] != 'port.update.end':
args_list.append(call_args)
new_dhcp.call_args_list = args_list
# test that notifier was not called
self.assertEqual([], new_dhcp.call_args_list)
self.assertEqual([], nova_notifier.call_args_list)
# test that notification queue has been flushed
self.assertEqual({}, self.notification_queue)
# test that the push notifications func itself was not called
self.assertEqual(
0, self.post_notifications_from_queue_call_count)
# restore mock
self.dummy.create_policy_target_group_precommit = orig_func
class TestImplicitExternalSegment(AIMBaseTestCase):
def setUp(self):
self._default_es_name = 'default'
super(TestImplicitExternalSegment, self).setUp()
cfg.CONF.set_override(
'default_external_segment_name', self._default_es_name,
group='group_policy_implicit_policy')
def _create_external_segment(self, **kwargs):
es_sub = self._make_ext_subnet(
'net', '100.90.0.0/16',
tenant_id=(kwargs.get('tenant_id') or self._tenant_id),
dn='uni/tn-t1/out-l0/instP-n')
return self.create_external_segment(subnet_id=es_sub['id'],
**kwargs)
def _create_default_es(self, **kwargs):
es_sub = self._make_ext_subnet(
'net1', kwargs.pop('subnet_cidr', '90.90.0.0/16'),
tenant_id=(kwargs.get('tenant_id') or self._tenant_id),
dn=self._dn_t1_l1_n1)
return self.create_external_segment(name=self._default_es_name,
subnet_id=es_sub['id'],
**kwargs)
def _test_implicit_lifecycle(self, shared=False):
# Create default ES
es = self._create_default_es(shared=shared)['external_segment']
# Create non-default ES
ndes = self._create_external_segment(
name='non-default-name')['external_segment']
# Create EP without ES set
ep = self.create_external_policy()['external_policy']
self.assertEqual(es['id'], ep['external_segments'][0])
# Verify persisted
req = self.new_show_request('external_policies', ep['id'],
fmt=self.fmt)
ep = self.deserialize(
self.fmt, req.get_response(self.ext_api))['external_policy']
self.assertEqual(es['id'], ep['external_segments'][0])
# Verify update
ep = self.update_external_policy(
ep['id'], expected_res_status=200,
external_segments=[ndes['id']])['external_policy']
self.assertEqual(ndes['id'], ep['external_segments'][0])
self.assertEqual(1, len(ep['external_segments']))
# Create L3P without ES set
l3p = self.create_l3_policy()['l3_policy']
self.assertEqual(es['id'], l3p['external_segments'].keys()[0])
# Verify persisted
req = self.new_show_request('l3_policies', l3p['id'],
fmt=self.fmt)
l3p = self.deserialize(
self.fmt, req.get_response(self.ext_api))['l3_policy']
self.assertEqual(es['id'], l3p['external_segments'].keys()[0])
# Verify update
l3p = self.update_l3_policy(
l3p['id'], expected_res_status=200,
external_segments={ndes['id']: []})['l3_policy']
self.assertEqual(ndes['id'], l3p['external_segments'].keys()[0])
self.assertEqual(1, len(l3p['external_segments']))
# Verify only one visible ES can exist
res = self._create_default_es(expected_res_status=400,
subnet_cidr='10.10.0.0/28')
self.assertEqual('DefaultExternalSegmentAlreadyExists',
res['NeutronError']['type'])
def test_implicit_lifecycle(self):
self._test_implicit_lifecycle()
def test_implicit_lifecycle_shared(self):
self._test_implicit_lifecycle(True)
def test_implicit_shared_visibility(self):
es = self._create_default_es(shared=True,
tenant_id='onetenant')['external_segment']
ep = self.create_external_policy(
tenant_id='anothertenant')['external_policy']
self.assertEqual(es['id'], ep['external_segments'][0])
self.assertEqual(1, len(ep['external_segments']))
l3p = self.create_l3_policy(
tenant_id='anothertenant')['l3_policy']
self.assertEqual(es['id'], l3p['external_segments'].keys()[0])
self.assertEqual(1, len(ep['external_segments']))
res = self._create_default_es(expected_res_status=400,
tenant_id='anothertenant',
subnet_cidr='10.10.0.0/28')
self.assertEqual('DefaultExternalSegmentAlreadyExists',
res['NeutronError']['type'])
class TestExternalSegment(AIMBaseTestCase):
def test_external_segment_lifecycle(self):
es_sub = self._make_ext_subnet('net1', '90.90.0.0/16',
dn=self._dn_t1_l1_n1)
es = self.create_external_segment(
name='seg1', subnet_id=es_sub['id'],
external_routes=[{'destination': '129.0.0.0/24',
'nexthop': None},
{'destination': '128.0.0.0/16',
'nexthop': None}])['external_segment']
self.assertEqual('90.90.0.0/16', es['cidr'])
self.assertEqual(4, es['ip_version'])
es_net = self._show('networks', es_sub['network_id'])['network']
self.assertEqual(['128.0.0.0/16', '129.0.0.0/24'],
sorted(es_net[CIDR]))
es = self.update_external_segment(es['id'],
external_routes=[{'destination': '129.0.0.0/24',
'nexthop': None}])['external_segment']
es_net = self._show('networks', es_sub['network_id'])['network']
self.assertEqual(['129.0.0.0/24'], sorted(es_net[CIDR]))
self.delete_external_segment(es['id'])
es_net = self._show('networks', es_sub['network_id'])['network']
self.assertEqual(['0.0.0.0/0'], es_net[CIDR])
def test_implicit_subnet(self):
res = self.create_external_segment(name='seg1',
expected_res_status=400)
self.assertEqual('ImplicitSubnetNotSupported',
res['NeutronError']['type'])
def test_invalid_subnet(self):
with self.network() as net:
with self.subnet(network=net) as sub:
res = self.create_external_segment(
name='seg1', subnet_id=sub['subnet']['id'],
expected_res_status=400)
self.assertEqual('InvalidSubnetForES',
res['NeutronError']['type'])
class TestExternalPolicy(AIMBaseTestCase):
def _check_router_contracts(self, routers, prov_prs, cons_prs):
session = self._neutron_context.session
prov = sorted([str(self.name_mapper.policy_rule_set(session, c))
for c in prov_prs])
cons = sorted([str(self.name_mapper.policy_rule_set(session, c))
for c in cons_prs])
for router in self._show_all('router', routers):
self.assertEqual(prov, sorted(router[PROV]),
'Router %s' % router)
self.assertEqual(cons, sorted(router[CONS]),
'Router %s' % router)
def test_external_policy_lifecycle(self):
ess = []
es_nets = {}
for x in range(0, 3):
es_sub = self._make_ext_subnet('net%d' % x, '90.9%d.0.0/16' % x,
dn='uni/tn-t1/out-l%d/instP-n%x' % (x, x))
es = self.create_external_segment(
name='seg%d' % x, subnet_id=es_sub['id'],
external_routes=[{'destination': '13%d.0.0.0/24' % x,
'nexthop': None}])['external_segment']
ess.append(es['id'])
es_nets[es_sub['network_id']] = es['id']
routers = {}
for x in range(0, 3):
l3p = self.create_l3_policy(name='l3p%d' % x,
external_segments={ess[x]: [''],
ess[(x + 1) % len(ess)]: ['']}
)['l3_policy']
l3p_routers = self._show_all('router', l3p['routers'])
for r in l3p_routers:
net = self._router_gw(r)
if net:
routers.setdefault(es_nets[net], []).append(r['id'])
self._check_router_contracts(routers[ess[0]] +
routers[ess[1]] +
routers[ess[2]], [], [])
prss = []
rules = self._create_3_direction_rules()
for x in range(0, 4):
prs = self.create_policy_rule_set(name='prs%d' % x,
policy_rules=[x['id'] for x in rules])['policy_rule_set']
prss.append(prs['id'])
ep1 = self.create_external_policy(name='ep1',
external_segments=[ess[0], ess[1]],
provided_policy_rule_sets={p: 'scope' for p in prss[0:2]},
consumed_policy_rule_sets={p: 'scope' for p in prss[2:4]}
)['external_policy']
self._check_router_contracts(routers[ess[0]] + routers[ess[1]],
prss[0:2], prss[2:4])
self._check_router_contracts(routers[ess[2]], [], [])
ep1 = self.update_external_policy(ep1['id'],
provided_policy_rule_sets={p: 'scope' for p in prss[1:4]},
consumed_policy_rule_sets={p: 'scope' for p in prss[0:3]}
)['external_policy']
self._check_router_contracts(routers[ess[0]] + routers[ess[1]],
prss[1:4], prss[0:3])
self._check_router_contracts(routers[ess[2]], [], [])
ep1 = self.update_external_policy(ep1['id'],
external_segments=[ess[1], ess[2]],
provided_policy_rule_sets={p: 'scope' for p in prss[0:2]},
consumed_policy_rule_sets={p: 'scope' for p in prss[2:4]}
)['external_policy']
self._check_router_contracts(routers[ess[1]] + routers[ess[2]],
prss[0:2], prss[2:4])
self._check_router_contracts(routers[ess[0]], [], [])
self.delete_external_policy(ep1['id'])
self._check_router_contracts(routers[ess[0]] + routers[ess[1]] +
routers[ess[2]], [], [])
def test_shared_external_policy(self):
res = self.create_external_policy(shared=True,
expected_res_status=400)
self.assertEqual('SharedExternalPolicyUnsupported',
res['NeutronError']['type'])
def test_multiple_external_policy_for_es(self):
es_sub = self._make_ext_subnet('net1', '90.90.0.0/16',
dn='uni/tn-t1/out-l1/instP-n1')
es = self.create_external_segment(
name='seg1', subnet_id=es_sub['id'])['external_segment']
self.create_external_policy(external_segments=[es['id']])
res = self.create_external_policy(external_segments=[es['id']],
expected_res_status=400)
self.assertEqual('MultipleExternalPoliciesForL3Policy',
res['NeutronError']['type'])
ep2 = self.create_external_policy()['external_policy']
res = self.update_external_policy(ep2['id'],
external_segments=[es['id']],
expected_res_status=400)
self.assertEqual('MultipleExternalPoliciesForL3Policy',
res['NeutronError']['type'])
class TestNatPool(AIMBaseTestCase):
def _test_overlapping_peer_rejected(self, shared1=False, shared2=False):
shared_net = shared1 or shared2
routes = [{'destination': '0.0.0.0/0', 'nexthop': None}]
sub = self._make_ext_subnet('net1', '192.168.0.0/24',
shared_net=shared_net,
dn='uni/tn-t1/out-l1/instP-n1')
es = self.create_external_segment(
name="default", subnet_id=sub['id'],
external_routes=routes, shared=shared_net,
expected_res_status=webob.exc.HTTPCreated.code)['external_segment']
# Allowed
self.create_nat_pool(external_segment_id=es['id'], ip_version=4,
ip_pool='192.168.1.0/24', shared=shared1,
expected_res_status=webob.exc.HTTPCreated.code)
# Fails
res = self.create_nat_pool(
external_segment_id=es['id'], ip_version=4,
ip_pool='192.168.1.0/24', shared=shared2,
expected_res_status=webob.exc.HTTPBadRequest.code)
self.assertEqual('OverlappingNATPoolInES', res['NeutronError']['type'])
def test_overlapping_peer_rejected1(self):
self._test_overlapping_peer_rejected(False, False)
def test_overlapping_peer_rejected2(self):
self._test_overlapping_peer_rejected(True, False)
def test_overlapping_peer_rejected3(self):
self._test_overlapping_peer_rejected(True, True)
def test_overlapping_peer_rejected4(self):
self._test_overlapping_peer_rejected(False, True)
def _test_implicit_subnet_created(self, shared=False):
routes = [{'destination': '0.0.0.0/0', 'nexthop': None}]
sub = self._make_ext_subnet('net1', '192.168.0.0/24',
shared_net=shared,
dn='uni/tn-t1/out-l1/instP-n1')
es = self.create_external_segment(
name="default", subnet_id=sub['id'],
external_routes=routes, shared=shared,
expected_res_status=webob.exc.HTTPCreated.code)['external_segment']
nat_pool = self.create_nat_pool(
external_segment_id=es['id'], ip_version=4,
ip_pool='192.168.1.0/24', shared=shared,
expected_res_status=webob.exc.HTTPCreated.code)['nat_pool']
self.assertIsNotNone(nat_pool['subnet_id'])
subnet = self._get_object('subnets', nat_pool['subnet_id'],
self.api)['subnet']
self.assertEqual('192.168.1.0/24', subnet['cidr'])
def test_implicit_subnet_created(self):
self._test_implicit_subnet_created()
def test_implicit_subnet_created_shared(self):
self._test_implicit_subnet_created(True)
def _test_partially_overlapping_subnets_rejected(self, shared=False):
routes = [{'destination': '0.0.0.0/0', 'nexthop': None}]
sub = self._make_ext_subnet('net1', '192.168.0.0/24',
shared_net=shared,
dn='uni/tn-t1/out-l1/instP-n1')
gw = str(netaddr.IPAddress(
netaddr.IPNetwork('192.168.1.0/28').first + 1))
net = self._get_object('networks', sub['network_id'], self.api)
self._make_subnet(self.fmt, net, gw, '192.168.1.0/28')['subnet']
es = self.create_external_segment(
name="default", subnet_id=sub['id'],
external_routes=routes, shared=shared,
expected_res_status=webob.exc.HTTPCreated.code)['external_segment']
# Disallowed because they partially overlaps
res = self.create_nat_pool(
external_segment_id=es['id'], ip_version=4,
ip_pool='192.168.1.0/24', shared=shared,
expected_res_status=webob.exc.HTTPBadRequest.code)
self.assertEqual('OverlappingSubnetForNATPoolInES',
res['NeutronError']['type'])
def test_partially_overlapping_subnets_rejected(self):
self._test_partially_overlapping_subnets_rejected()
def test_partially_overlapping_subnets_rejected_shared(self):
self._test_partially_overlapping_subnets_rejected(True)
def _test_overlapping_subnets(self, shared=False):
routes = [{'destination': '0.0.0.0/0', 'nexthop': None}]
sub = self._make_ext_subnet('net1', '192.168.0.0/24',
shared_net=shared,
dn='uni/tn-t1/out-l1/instP-n1')
gw = str(netaddr.IPAddress(
netaddr.IPNetwork('192.168.1.0/24').first + 1))
net = self._get_object('networks', sub['network_id'], self.api)
sub2 = self._make_subnet(self.fmt, net, gw, '192.168.1.0/24')['subnet']
es = self.create_external_segment(
name="default", subnet_id=sub['id'],
external_routes=routes, shared=shared,
expected_res_status=webob.exc.HTTPCreated.code)['external_segment']
# Sub2 associated with the newly created NAT pool
nat_pool = self.create_nat_pool(
external_segment_id=es['id'], ip_version=4,
ip_pool='192.168.1.0/24', shared=shared,
expected_res_status=webob.exc.HTTPCreated.code)['nat_pool']
self.assertEqual(sub2['id'], nat_pool['subnet_id'])
def test_overlapping_subnets(self):
self._test_overlapping_subnets()
def test_overlapping_subnets_shared(self):
self._test_overlapping_subnets(True)
def _test_subnet_swap(self, owned=True):
routes = [{'destination': '0.0.0.0/0', 'nexthop': None}]
sub = self._make_ext_subnet('net1', '192.168.0.0/24',
dn='uni/tn-t1/out-l1/instP-n1')
es = self.create_external_segment(
name="default", subnet_id=sub['id'], external_routes=routes,
expected_res_status=webob.exc.HTTPCreated.code)['external_segment']
# Use same IP pool as ES sub_id if we don't have to own
# the subnet.
ip_pool = '192.168.1.0/24' if owned else '192.168.0.0/24'
nat_pool = self.create_nat_pool(
external_segment_id=es['id'], ip_version=4, ip_pool=ip_pool,
expected_res_status=webob.exc.HTTPCreated.code)['nat_pool']
# Subnet deleted on 'delete'
sub_id = nat_pool['subnet_id']
self.delete_nat_pool(
nat_pool['id'], expected_res_status=webob.exc.HTTPNoContent.code)
self._get_object('subnets', sub_id, self.api,
expected_res_status=404 if owned else 200)
# Subnet deleted on 'update'
nat_pool = self.create_nat_pool(
external_segment_id=es['id'], ip_version=4, ip_pool=ip_pool,
expected_res_status=webob.exc.HTTPCreated.code)['nat_pool']
sub_id = nat_pool['subnet_id']
sub2 = self._make_ext_subnet('net1', '192.167.0.0/24',
dn='uni/tn-t1/out-l2/instP-n2')
es2 = self.create_external_segment(
name="nondefault", subnet_id=sub2['id'],
external_routes=routes,
expected_res_status=webob.exc.HTTPCreated.code)['external_segment']
# Update External Segment
nat_pool = self.update_nat_pool(
nat_pool['id'], external_segment_id=es2['id'])['nat_pool']
self.assertNotEqual(nat_pool['subnet_id'], sub_id)
self.assertIsNotNone(nat_pool['subnet_id'])
# Verify subnet deleted
self._get_object('subnets', sub_id, self.api,
expected_res_status=404 if owned else 200)
def test_owned_subnet_deleted(self):
self._test_subnet_swap(True)
def test_not_owned_subnet_not_deleted(self):
self._test_subnet_swap(False)
def test_delete_with_fip_allocated(self):
sub = self._make_ext_subnet('net1', '192.168.0.0/30',
enable_dhcp=False,
dn='uni/tn-t1/out-l1/instP-n1')
net = self._get_object('networks', sub['network_id'], self.api)
es = self.create_external_segment(
name="default", subnet_id=sub['id'])['external_segment']
nat_pool = self.create_nat_pool(
external_segment_id=es['id'], ip_version=4,
ip_pool='192.168.1.0/24')['nat_pool']
fip_data = {'floatingip': {
'tenant_id': net['network']['tenant_id'],
'floating_network_id': net['network']['id'],
'subnet_id': nat_pool['subnet_id']}}
for i in range(3):
self._l3_plugin.create_floatingip(
nctx.get_admin_context(), fip_data)
res = self.delete_nat_pool(nat_pool['id'], expected_res_status=409)
self.assertEqual('NatPoolInUseByPort', res['NeutronError']['type'])
class TestNetworkServicePolicy(AIMBaseTestCase):
def test_create_nsp_multiple_ptgs(self):
nsp = self.create_network_service_policy(
network_service_params=[
{"type": "ip_single", "value": "self_subnet",
"name": "vip"}],
expected_res_status=webob.exc.HTTPCreated.code)[
'network_service_policy']
# Create two PTGs that use this NSP
ptg1 = self.create_policy_target_group(
network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
ptg2 = self.create_policy_target_group(
network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
# Update the PTGs and unset the NSP used
self.update_policy_target_group(
ptg1['id'],
network_service_policy_id=None,
expected_res_status=webob.exc.HTTPOk.code)
self.update_policy_target_group(
ptg2['id'],
network_service_policy_id=None,
expected_res_status=webob.exc.HTTPOk.code)
self.update_policy_target_group(
ptg1['id'],
network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPOk.code)
self.delete_policy_target_group(
ptg1['id'],
expected_res_status=204)
def test_unsupported_nsp_parameters_rejected(self):
self.create_network_service_policy(
network_service_params=[
{"type": "ip_pool", "value": "self_subnet", "name": "vip"}],
expected_res_status=webob.exc.HTTPBadRequest.code)
self.create_network_service_policy(
network_service_params=[
{"type": "ip_pool", "value": "external_subnet",
"name": "vip"}],
expected_res_status=webob.exc.HTTPBadRequest.code)
self.create_network_service_policy(
network_service_params=[
{"type": "ip_single", "value": "self_subnet", "name": "vip"},
{"type": "ip_single", "value": "self_subnet", "name": "vip"}],
expected_res_status=webob.exc.HTTPBadRequest.code)
def test_nsp_cleanup_on_unset(self):
ptg = self.create_policy_target_group(
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
ptg_subnet_id = ptg['subnets'][0]
subnet = self._show_subnet(ptg_subnet_id)
initial_allocation_pool = subnet['allocation_pools']
nsp = self.create_network_service_policy(
network_service_params=[
{"type": "ip_single", "value": "self_subnet",
"name": "vip"}],
expected_res_status=webob.exc.HTTPCreated.code)[
'network_service_policy']
# Update PTG, associating a NSP with it and verify that an IP is
# reserved from the PTG subnet allocation pool
self.update_policy_target_group(
ptg['id'],
network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPOk.code)
subnet = self._show_subnet(ptg_subnet_id)
allocation_pool_after_nsp = subnet['allocation_pools']
self.assertEqual(
netaddr.IPAddress(initial_allocation_pool[0].get('start')),
netaddr.IPAddress(allocation_pool_after_nsp[0].get('start')))
self.assertEqual(
netaddr.IPAddress(initial_allocation_pool[0].get('end')),
netaddr.IPAddress(allocation_pool_after_nsp[0].get('end')) + 1)
# Update the PTGs and unset the NSP used and verify that the IP is
# restored to the PTG subnet allocation pool
self.update_policy_target_group(
ptg['id'],
network_service_policy_id=None,
expected_res_status=webob.exc.HTTPOk.code)
subnet = self._show_subnet(ptg_subnet_id)
allocation_pool_after_nsp_cleanup = subnet['allocation_pools']
self.assertEqual(
initial_allocation_pool, allocation_pool_after_nsp_cleanup)
def test_create_nsp_ip_pool_multiple_ptgs(self):
routes = [{'destination': '0.0.0.0/0', 'nexthop': None}]
sub = self._make_ext_subnet('net1', '192.168.0.0/24',
dn='uni/tn-t1/out-l1/instP-n1')
es = self.create_external_segment(
name="default", subnet_id=sub['id'], external_routes=routes,
expected_res_status=webob.exc.HTTPCreated.code)['external_segment']
self.create_nat_pool(
external_segment_id=es['id'], ip_version=4,
ip_pool='192.168.0.0/24',
expected_res_status=webob.exc.HTTPCreated.code)
nsp = self.create_network_service_policy(
network_service_params=[
{"type": "ip_pool", "value": "nat_pool",
"name": "external_access"}],
expected_res_status=webob.exc.HTTPCreated.code)[
'network_service_policy']
l3p = self.create_l3_policy(name='l3p1',
external_segments={es['id']: []})['l3_policy']
l2p = self.create_l2_policy(name='l2p1',
l3_policy_id=l3p['id'])['l2_policy']
# Create two PTGs that use this NSP
ptg1 = self.create_policy_target_group(
l2_policy_id=l2p['id'], network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
ptg2 = self.create_policy_target_group(
l2_policy_id=l2p['id'], network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
pt = self.create_policy_target(
name="pt1", policy_target_group_id=ptg1['id'])
port_id = pt['policy_target']['port_id']
req = self.new_show_request('ports', port_id, fmt=self.fmt)
port = self.deserialize(self.fmt,
req.get_response(self.api))['port']
res = self._list('floatingips')['floatingips']
self.assertEqual(1, len(res))
self.assertEqual(res[0]['fixed_ip_address'],
port['fixed_ips'][0]['ip_address'])
pt2 = self.create_policy_target(
name="pt2", policy_target_group_id=ptg1['id'])
port2_id = pt2['policy_target']['port_id']
req = self.new_show_request('ports', port2_id, fmt=self.fmt)
port = self.deserialize(self.fmt,
req.get_response(self.api))['port']
res = self._list('floatingips')['floatingips']
self.assertEqual(2, len(res))
# Update the PTGs and unset the NSP used
# TODO(Sumit): Remove the floating IPs here
self.update_policy_target_group(
ptg1['id'], network_service_policy_id=None,
expected_res_status=webob.exc.HTTPOk.code)
self.update_policy_target_group(
ptg2['id'], network_service_policy_id=None,
expected_res_status=webob.exc.HTTPOk.code)
self.delete_policy_target_group(
ptg1['id'], expected_res_status=204)
self.delete_policy_target_group(
ptg2['id'], expected_res_status=204)
def test_nsp_fip_single(self):
routes = [{'destination': '0.0.0.0/0', 'nexthop': None}]
sub = self._make_ext_subnet('net1', '192.168.0.0/24',
dn='uni/tn-t1/out-l1/instP-n1')
es = self.create_external_segment(
name="default", subnet_id=sub['id'], external_routes=routes,
expected_res_status=webob.exc.HTTPCreated.code)['external_segment']
self.create_nat_pool(
external_segment_id=es['id'], ip_version=4,
ip_pool='192.168.0.0/24',
expected_res_status=webob.exc.HTTPCreated.code)
nsp = self.create_network_service_policy(
network_service_params=[
{"type": "ip_single", "value": "nat_pool",
"name": "external_access"}],
expected_res_status=webob.exc.HTTPCreated.code)[
'network_service_policy']
l3p = self.create_l3_policy(name='l3p1',
external_segments={es['id']: []})['l3_policy']
l2p = self.create_l2_policy(name='l2p1',
l3_policy_id=l3p['id'])['l2_policy']
ptg = self.create_policy_target_group(
l2_policy_id=l2p['id'],
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
# Update PTG, associating a NSP with it and verify that a FIP
# is allocated
self.update_policy_target_group(
ptg['id'], network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPOk.code)
mapping = self._get_nsp_ptg_fip_mapping(ptg['id'])
self.assertNotEqual([], mapping)
self.assertEqual(mapping[0].service_policy_id, nsp['id'])
self.assertIsNotNone(mapping[0].floatingip_id)
# Update the PTGs and unset the NSP used and verify that the IP
# is restored to the PTG subnet allocation pool
self.update_policy_target_group(
ptg['id'], network_service_policy_id=None,
expected_res_status=webob.exc.HTTPOk.code)
mapping = self._get_nsp_ptg_fip_mapping(ptg['id'])
self.assertEqual([], mapping)
self.delete_policy_target_group(
ptg['id'], expected_res_status=204)
def test_nsp_fip_single_different_pool(self):
routes = [{'destination': '0.0.0.0/0', 'nexthop': None}]
sub = self._make_ext_subnet('net1', '192.168.0.0/24',
dn='uni/tn-t1/out-l1/instP-n1')
es = self.create_external_segment(
name="default", subnet_id=sub['id'], external_routes=routes,
expected_res_status=webob.exc.HTTPCreated.code)['external_segment']
self.create_nat_pool(
external_segment_id=es['id'], ip_version=4,
ip_pool='192.168.1.0/24',
expected_res_status=webob.exc.HTTPCreated.code)
nsp = self.create_network_service_policy(
network_service_params=[
{"type": "ip_single", "value": "nat_pool",
"name": "external_access"}],
expected_res_status=webob.exc.HTTPCreated.code)[
'network_service_policy']
l3p = self.create_l3_policy(name='l3p1',
external_segments={es['id']: []})['l3_policy']
l2p = self.create_l2_policy(name='l2p1',
l3_policy_id=l3p['id'])['l2_policy']
ptg = self.create_policy_target_group(
l2_policy_id=l2p['id'],
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
# Update PTG, associating a NSP with it and verify that a FIP
# is allocated
self.update_policy_target_group(
ptg['id'], network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPOk.code)
mapping = self._get_nsp_ptg_fip_mapping(ptg['id'])
self.assertNotEqual([], mapping)
self.assertEqual(mapping[0].service_policy_id, nsp['id'])
self.assertIsNotNone(mapping[0].floatingip_id)
fip = self._get_object(
'floatingips', mapping[0].floatingip_id, self.ext_api)[
'floatingip']
# Verify FIP is in the new subnet
self.assertTrue(
netaddr.IPAddress(fip['floating_ip_address']) in
netaddr.IPNetwork('192.168.1.0/24'),
"IP %s not in pool %s" % (fip['floating_ip_address'],
'192.168.1.0/24'))
# Update the PTGs and unset the NSP used and verify that the IP
# is restored to the PTG subnet allocation pool
self.update_policy_target_group(
ptg['id'], network_service_policy_id=None,
expected_res_status=webob.exc.HTTPOk.code)
mapping = self._get_nsp_ptg_fip_mapping(ptg['id'])
self.assertEqual([], mapping)
self.delete_policy_target_group(
ptg['id'], expected_res_status=204)
def test_nsp_rejected_without_nat_pool(self):
routes = [{'destination': '0.0.0.0/0', 'nexthop': None}]
sub = self._make_ext_subnet('net1', '192.168.0.0/24',
dn='uni/tn-t1/out-l1/instP-n1')
es = self.create_external_segment(
name="default", subnet_id=sub['id'], external_routes=routes,
expected_res_status=webob.exc.HTTPCreated.code)['external_segment']
nsp = self.create_network_service_policy(
network_service_params=[
{"type": "ip_single", "value": "nat_pool",
"name": "external_access"}],
expected_res_status=webob.exc.HTTPCreated.code)[
'network_service_policy']
l3p = self.create_l3_policy(name='l3p1',
external_segments={es['id']: []})['l3_policy']
l2p = self.create_l2_policy(name='l2p1',
l3_policy_id=l3p['id'])['l2_policy']
ptg = self.create_policy_target_group(
l2_policy_id=l2p['id'],
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
data = self.create_policy_target_group(
l2_policy_id=l2p['id'], network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPBadRequest.code)
self.assertEqual('NSPRequiresNatPool', data['NeutronError']['type'])
self.update_policy_target_group(
ptg['id'], network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPBadRequest.code)
self.assertEqual('NSPRequiresNatPool', data['NeutronError']['type'])
def test_reject_nsp_without_es(self):
nsp = self.create_network_service_policy(
network_service_params=[
{"type": "ip_pool", "value": "nat_pool",
"name": "test"}],
expected_res_status=webob.exc.HTTPCreated.code)[
'network_service_policy']
# create PTG with NSP fails when ES is not present
data = self.create_policy_target_group(
network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPBadRequest.code)
self.assertEqual('NSPRequiresES',
data['NeutronError']['type'])
ptg = self.create_policy_target_group(
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
# update PTG with NSP fails when ES is not present
data = self.update_policy_target_group(
ptg['id'],
network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPBadRequest.code)
self.assertEqual('NSPRequiresES',
data['NeutronError']['type'])
def test_reject_l3p_update_with_es(self):
routes = [{'destination': '0.0.0.0/0', 'nexthop': None}]
sub1 = self._make_ext_subnet('net1', '192.168.0.0/24',
dn='uni/tn-t1/out-l1/instP-n1')
es1 = self.create_external_segment(
name="default", subnet_id=sub1['id'], external_routes=routes,
expected_res_status=webob.exc.HTTPCreated.code)['external_segment']
self.create_nat_pool(
external_segment_id=es1['id'], ip_version=4,
ip_pool='192.168.0.0/24',
expected_res_status=webob.exc.HTTPCreated.code)
nsp = self.create_network_service_policy(
network_service_params=[
{"type": "ip_pool", "value": "nat_pool",
"name": "external_access"}],
expected_res_status=webob.exc.HTTPCreated.code)[
'network_service_policy']
l3p = self.create_l3_policy(name='l3p1',
external_segments={es1['id']: []})['l3_policy']
l2p = self.create_l2_policy(name='l2p1',
l3_policy_id=l3p['id'])['l2_policy']
self.create_policy_target_group(
l2_policy_id=l2p['id'],
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
self.create_policy_target_group(
l2_policy_id=l2p['id'], network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
req = self.new_list_request('l3_policies', fmt=self.fmt)
l3ps = self.deserialize(self.fmt, req.get_response(self.ext_api))[
'l3_policies']
sub2 = self._make_ext_subnet('net2', '192.167.0.0/24',
dn='uni/tn-t1/out-l2/instP-n2')
es2 = self.create_external_segment(
name='nondefault', subnet_id=sub2['id'], external_routes=routes,
expected_res_status=webob.exc.HTTPCreated.code)['external_segment']
res = self.update_l3_policy(
l3ps[0]['id'], expected_res_status=409,
external_segments={es2['id']: []})
self.assertEqual('L3PEsinUseByNSP', res['NeutronError']['type'])
def test_nsp_delete_nat_pool_rejected(self):
routes = [{'destination': '0.0.0.0/0', 'nexthop': None}]
sub = self._make_ext_subnet('net1', '192.168.0.0/24',
dn='uni/tn-t1/out-l1/instP-n1')
es = self.create_external_segment(
name="default", subnet_id=sub['id'], external_routes=routes,
expected_res_status=webob.exc.HTTPCreated.code)['external_segment']
nat_pool = self.create_nat_pool(
external_segment_id=es['id'], ip_version=4,
ip_pool='192.168.0.0/24',
expected_res_status=webob.exc.HTTPCreated.code)['nat_pool']
nsp = self.create_network_service_policy(
network_service_params=[
{"type": "ip_pool", "value": "nat_pool",
"name": "external_access"}],
expected_res_status=webob.exc.HTTPCreated.code)[
'network_service_policy']
l3p = self.create_l3_policy(name='l3p1',
external_segments={es['id']: []})['l3_policy']
l2p = self.create_l2_policy(name='l2p1',
l3_policy_id=l3p['id'])['l2_policy']
self.create_policy_target_group(
l2_policy_id=l2p['id'], network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
res = self.delete_nat_pool(nat_pool['id'], expected_res_status=409)
self.assertEqual('NatPoolinUseByNSP', res['NeutronError']['type'])
def test_update_nsp_nat_pool_after_pt_create(self):
routes = [{'destination': '0.0.0.0/0', 'nexthop': None}]
sub = self._make_ext_subnet('net1', '192.168.0.0/24',
dn='uni/tn-t1/out-l1/instP-n1')
es = self.create_external_segment(
name="default", subnet_id=sub['id'], external_routes=routes,
expected_res_status=webob.exc.HTTPCreated.code)['external_segment']
self.create_nat_pool(
external_segment_id=es['id'], ip_version=4,
ip_pool='192.168.0.0/24',
expected_res_status=webob.exc.HTTPCreated.code)['nat_pool']
nsp = self.create_network_service_policy(
network_service_params=[
{"type": "ip_pool", "value": "nat_pool",
"name": "external_access"}],
expected_res_status=webob.exc.HTTPCreated.code)[
'network_service_policy']
l3p = self.create_l3_policy(name='l3p1',
external_segments={es['id']: []})['l3_policy']
l2p = self.create_l2_policy(name='l2p1',
l3_policy_id=l3p['id'])['l2_policy']
# Create a PTG and PTs and then associate the NSP
ptg1 = self.create_policy_target_group(
l2_policy_id=l2p['id'],
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
pt = self.create_policy_target(
name="pt1", policy_target_group_id=ptg1['id'])
port_id = pt['policy_target']['port_id']
pt2 = self.create_policy_target(
name="pt2", policy_target_group_id=ptg1['id'])
port2_id = pt2['policy_target']['port_id']
res = self._list('floatingips')['floatingips']
self.assertEqual(0, len(res))
self.update_policy_target_group(
ptg1['id'], network_service_policy_id=nsp['id'],
expected_res_status=webob.exc.HTTPOk.code)
res = self._list('floatingips')['floatingips']
self.assertEqual(2, len(res))
req = self.new_show_request('ports', port_id, fmt=self.fmt)
port1 = self.deserialize(self.fmt, req.get_response(self.api))['port']
req = self.new_show_request('ports', port2_id, fmt=self.fmt)
port2 = self.deserialize(self.fmt, req.get_response(self.api))['port']
port_fixed_ips = [port1['fixed_ips'][0]['ip_address'],
port2['fixed_ips'][0]['ip_address']]
fip_fixed_ips = [res[0]['fixed_ip_address'],
res[1]['fixed_ip_address']]
self.assertEqual(set(port_fixed_ips), set(fip_fixed_ips))
self.update_policy_target_group(
ptg1['id'], network_service_policy_id=None,
expected_res_status=webob.exc.HTTPOk.code)
res = self._list('floatingips')['floatingips']
self.assertEqual(0, len(res))
def test_nsp_cleanup_multiple_on_unset(self):
ptg = self.create_policy_target_group(
expected_res_status=webob.exc.HTTPCreated.code)[
'policy_target_group']
ptg_subnet_id = ptg['subnets'][0]
subnet = self._show_subnet(ptg_subnet_id)
nsp = self.create_network_service_policy(
network_service_params=[
{"type": "ip_single", "value": "self_subnet",
"name": "vip"}],
expected_res_status=webob.exc.HTTPCreated.code)[
'network_service_policy']
nsp2 = self.create_network_service_policy(
network_service_params=[
{"type": "ip_single", "value": "self_subnet",
"name": "vip"}],
expected_res_status=webob.exc.HTTPCreated.code)[
'network_service_policy']
# Update PTG, associating an NSP with it and verify that an IP is
# reserved from the PTG subnet allocation pool. Also test updating
# the PTG with a different NSP and then resetting it back to the
# initially set NSP
self._verify_update_ptg_with_nsp(ptg['id'], nsp['id'], subnet)
self._verify_update_ptg_with_nsp(ptg['id'], nsp2['id'], subnet)
self._verify_update_ptg_with_nsp(ptg['id'], nsp['id'], subnet)
def _verify_update_ptg_with_nsp(self, ptg_id, nsp_id, ptg_subnet_no_nsp):
ptg_subnet_id = ptg_subnet_no_nsp['id']
initial_allocation_pool = ptg_subnet_no_nsp['allocation_pools']
self.update_policy_target_group(
ptg_id,
network_service_policy_id=nsp_id,
expected_res_status=webob.exc.HTTPOk.code)
subnet = self._show_subnet(ptg_subnet_id)
allocation_pool_after_nsp = subnet['allocation_pools']
self.assertEqual(
netaddr.IPAddress(initial_allocation_pool[0].get('start')),
netaddr.IPAddress(allocation_pool_after_nsp[0].get('start')))
self.assertEqual(
netaddr.IPAddress(initial_allocation_pool[0].get('end')),
netaddr.IPAddress(allocation_pool_after_nsp[0].get('end')) + 1)
class TestNestedDomain(AIMBaseTestCase):
def setUp(self, **kwargs):
super(TestNestedDomain, self).setUp(**kwargs)
self.plugin = self._plugin
def _test_get_nested_domain_details(self, vlans_arg):
self._register_agent('host1', test_aim_md.AGENT_CONF_OPFLEX)
expt_vlans = [2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14]
kwargs = {'apic:nested_domain_name': 'myk8s',
'apic:nested_domain_type': 'k8s',
'apic:nested_domain_infra_vlan': '4093',
'apic:nested_domain_service_vlan': '1000',
'apic:nested_domain_node_network_vlan': '1001',
'apic:nested_domain_allowed_vlans': vlans_arg,
}
net = self._make_network(self.fmt, 'net1', True,
arg_list=tuple(kwargs.keys()), **kwargs)
self._make_subnet(self.fmt, net, '10.0.1.1', '10.0.1.0/24')
p1 = self._make_port(self.fmt, net['network']['id'],
device_owner='compute:')['port']
p1 = self._bind_port_to_host(p1['id'], 'host1')['port']
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1['id'],
host='host1')
self.assertEqual('myk8s', details['nested_domain_name'])
self.assertEqual('k8s', details['nested_domain_type'])
self.assertEqual(4093, details['nested_domain_infra_vlan'])
self.assertEqual(1000, details['nested_domain_service_vlan'])
self.assertEqual(1001, details['nested_domain_node_network_vlan'])
self.assertItemsEqual(expt_vlans,
details['nested_domain_allowed_vlans'])
self.assertEqual(4094, details['nested_host_vlan'])
def test_get_nested_domain_details_vlan_dict_input(self):
vlan_dict = {'vlans_list': ['2', '3', '4', '3'],
'vlan_ranges': [{'start': '6', 'end': '9'},
{'start': '11', 'end': '14'}]}
self._test_get_nested_domain_details(vlan_dict)
def test_get_nested_domain_details_vlan_string_input(self):
vlan_str = "{'vlans_list': ['2', '3', '4', '3'], " + (
"'vlan_ranges': [{'start': '6', 'end': '9'}, ") + (
"{'start': '11', 'end': '14'}]}")
self._test_get_nested_domain_details(vlan_str)
def test_no_nested_domain_details_for_regular_network(self):
self._register_agent('host1', test_aim_md.AGENT_CONF_OPFLEX)
net = self._make_network(self.fmt, 'net1', True)
self._make_subnet(self.fmt, net, '10.0.1.1', '10.0.1.0/24')
p1 = self._make_port(self.fmt, net['network']['id'],
device_owner='compute:')['port']
p1 = self._bind_port_to_host(p1['id'], 'host1')['port']
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1['id'],
host='host1')
self.assertEqual('', details['nested_domain_name'])
self.assertEqual('', details['nested_domain_type'])
self.assertIsNone(details['nested_domain_infra_vlan'])
self.assertIsNone(details['nested_domain_service_vlan'])
self.assertIsNone(details['nested_domain_node_network_vlan'])
self.assertItemsEqual([], details['nested_domain_allowed_vlans'])
self.assertIsNone(details['nested_host_vlan'])
class TestNestedDomainWithRawSql(TestNestedDomain):
def setUp(self, **kwargs):
super(TestNestedDomainWithRawSql, self).setUp(**kwargs)
self.driver.aim_mech_driver.enable_raw_sql_for_device_rpc = True
class TestNestedDomainWithNewRpc(TestNestedDomain):
def setUp(self, **kwargs):
super(TestNestedDomainWithNewRpc, self).setUp(**kwargs)
self.driver.aim_mech_driver.enable_new_rpc = True
class TestNeutronPortOperation(AIMBaseTestCase):
def setUp(self, **kwargs):
super(TestNeutronPortOperation, self).setUp(**kwargs)
# Doing the following assignment since the call to _register_agent
# needs self.plugin to point to the neutron core plugin.
# TODO(Sumit): Ideally, the self.plugin of the GBP test cases should be
# consistent with the neutron test setup and point to the neutron
# core plugin. The self._gbp_plugin already points to the GBP service
# plugin and should be used instead.
self.plugin = self._plugin
def test_port_security_port(self):
self._register_agent('host1', test_aim_md.AGENT_CONF_OPFLEX)
net = self._make_network(self.fmt, 'net1', True)
self._make_subnet(self.fmt, net, '10.0.1.1', '10.0.1.0/24')
# test compute port
p1 = self._make_port(self.fmt, net['network']['id'],
device_owner='compute:')['port']
p1 = self._bind_port_to_host(p1['id'], 'host1')['port']
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1['id'],
host='host1')
self.assertFalse(details['promiscuous_mode'])
p2 = self._make_port(self.fmt, net['network']['id'],
arg_list=('port_security_enabled',),
device_owner='compute:',
port_security_enabled=True)['port']
p2 = self._bind_port_to_host(p2['id'], 'host1')['port']
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p2['id'],
host='host1')
self.assertFalse(details['promiscuous_mode'])
p3 = self._make_port(self.fmt, net['network']['id'],
arg_list=('port_security_enabled',),
device_owner='compute:',
port_security_enabled=False)['port']
p3 = self._bind_port_to_host(p3['id'], 'host1')['port']
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p3['id'],
host='host1')
self.assertTrue(details['promiscuous_mode'])
# REVISIT: Test port name ending with PROMISCUOUS_SUFFIX, or
# is that deprecated?
# test DHCP port
p1_dhcp = self._make_port(self.fmt, net['network']['id'],
device_owner=n_constants.DEVICE_OWNER_DHCP)['port']
p1_dhcp = self._bind_port_to_host(p1_dhcp['id'], 'host1')['port']
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1_dhcp['id'],
host='host1')
self.assertTrue(details['promiscuous_mode'])
p2_dhcp = self._make_port(self.fmt, net['network']['id'],
arg_list=('port_security_enabled',), port_security_enabled=True,
device_owner=n_constants.DEVICE_OWNER_DHCP)['port']
p2_dhcp = self._bind_port_to_host(p2_dhcp['id'], 'host1')['port']
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p2_dhcp['id'],
host='host1')
self.assertTrue(details['promiscuous_mode'])
p3_dhcp = self._make_port(self.fmt, net['network']['id'],
arg_list=('port_security_enabled',), port_security_enabled=False,
device_owner=n_constants.DEVICE_OWNER_DHCP)['port']
p3_dhcp = self._bind_port_to_host(p3_dhcp['id'], 'host1')['port']
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p3_dhcp['id'],
host='host1')
self.assertTrue(details['promiscuous_mode'])
# REVISIT: If we support proxy groups, we also need to test
# that promiscuous_mode is True when the port belongs to a PT
# that has a cluster_id, is not the master, and the master has
# a group_default_gateway.
def _aap_is_cidr(self, aap):
cidr = netaddr.IPNetwork(aap['ip_address'])
if cidr.prefixlen != 32:
return True
else:
return False
def _test_gbp_details_for_allowed_address_pair(self, allow_addr,
owned_addr, update_addr, update_owned_addr):
self._register_agent('h1', test_aim_md.AGENT_CONF_OPFLEX)
self._register_agent('h2', test_aim_md.AGENT_CONF_OPFLEX)
net = self._make_network(self.fmt, 'net1', True)
sub1 = self._make_subnet(self.fmt, net, '10.0.0.1', '10.0.0.0/24')[
'subnet']
sub2 = self._make_subnet(self.fmt, net, '1.2.3.1', '1.2.3.0/24')[
'subnet']
# create 2 ports configured with the same allowed-addresses
p1 = self._make_port(self.fmt, net['network']['id'],
arg_list=('allowed_address_pairs',),
device_owner='compute:',
fixed_ips=[{'subnet_id': sub1['id']}],
allowed_address_pairs=allow_addr)['port']
p2 = self._make_port(self.fmt, net['network']['id'],
arg_list=('allowed_address_pairs',),
device_owner='compute:',
fixed_ips=[{'subnet_id': sub1['id']}],
allowed_address_pairs=allow_addr)['port']
self._bind_port_to_host(p1['id'], 'h1')
self._bind_port_to_host(p2['id'], 'h2')
# Call agent => plugin RPC to get the details for each port. The
# results should only have the configured AAPs, with none of them
# active.
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1['id'],
host='h1')
self.assertEqual(sorted(allow_addr),
sorted(details['allowed_address_pairs']))
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p2['id'],
host='h2')
self.assertEqual(sorted(allow_addr),
sorted(details['allowed_address_pairs']))
# Call agent => plugin RPC, requesting ownership of a /32 IP
ip_owner_info = {'port': p1['id'],
'ip_address_v4': owned_addr[0],
'network_id': p1['network_id']}
self.driver.aim_mech_driver.update_ip_owner(ip_owner_info)
# Call RPC sent by the agent to get the details for p1
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1['id'],
host='h1')
# response should be a list containing both configured and owned AAPs.
# Only the owned entries will have the 'active' property (set to True).
def _get_expected_aaps(allow_addr, owned_addr):
extra_aaps = []
expected_aaps = copy.deepcopy(allow_addr)
for aap in expected_aaps:
if aap['ip_address'] == owned_addr:
aap['active'] = True
elif self._aap_is_cidr(aap):
# If the configured AAP is a CIDR, the response should
# include both the CIDR (not active) and the owned IP
# address (i.e. /32) from that CIDR (active)
extra_aaps.append({'ip_address': owned_addr,
'mac_address': aap['mac_address'],
'active': True})
if extra_aaps:
expected_aaps.extend(extra_aaps)
return expected_aaps
expected_aaps1 = _get_expected_aaps(allow_addr, owned_addr[0])
self.assertEqual(sorted(expected_aaps1),
sorted(details['allowed_address_pairs']))
# Call RPC sent by the agent, requesting ownership of a /32 IP
ip_owner_info = {'port': p2['id'],
'ip_address_v4': owned_addr[1],
'network_id': p2['network_id']}
self.driver.aim_mech_driver.update_ip_owner(ip_owner_info)
# Call RPC sent by the agent to get the details for p2
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p2['id'],
host='h2')
expected_aaps2 = _get_expected_aaps(allow_addr, owned_addr[1])
self.assertEqual(sorted(expected_aaps2),
sorted(details['allowed_address_pairs']))
# set allowed-address as fixed-IP of ports p3 and p4, which also have
# floating-IPs. Verify that FIP is "stolen" by p1 and p2
net_ext, rtr, _ = self._setup_external_network(
'l1', dn='uni/tn-t1/out-l1/instP-n1')
p3 = self._make_port(self.fmt, net['network']['id'],
device_owner='compute:',
fixed_ips=[{'subnet_id': sub2['id'],
'ip_address': '1.2.3.250'}])['port']
p4 = self._make_port(self.fmt, net['network']['id'],
device_owner='compute:',
fixed_ips=[{'subnet_id': sub2['id'],
'ip_address': '1.2.3.251'}])['port']
self.l3_plugin.add_router_interface(
self._neutron_admin_context, rtr['id'], {'subnet_id': sub1['id']})
self.l3_plugin.add_router_interface(
self._neutron_admin_context, rtr['id'], {'subnet_id': sub2['id']})
fip1 = self._make_floatingip(self.fmt, net_ext['id'],
port_id=p3['id'])['floatingip']
fip2 = self._make_floatingip(self.fmt, net_ext['id'],
port_id=p4['id'])['floatingip']
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1['id'],
host='h1')
self.assertEqual(1, len(details['floating_ip']))
self.assertEqual(
fip1['floating_ip_address'],
details['floating_ip'][0]['floating_ip_address'])
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p2['id'],
host='h2')
self.assertEqual(1, len(details['floating_ip']))
self.assertEqual(
fip2['floating_ip_address'],
details['floating_ip'][0]['floating_ip_address'])
# verify FIP updates: update to p3, p4 should also update p1 and p2
self.driver.aim_mech_driver._notify_port_update = mock.Mock()
self.driver.aim_mech_driver._notify_port_update_for_fip(
self._neutron_admin_context, p3['id'])
expected_calls = [
mock.call(mock.ANY, p)
for p in sorted([p1['id'], p2['id'], p3['id']])]
self._check_call_list(
expected_calls,
self.driver.aim_mech_driver._notify_port_update.call_args_list)
self.driver.aim_mech_driver._notify_port_update.reset_mock()
self.driver.aim_mech_driver._notify_port_update_for_fip(
self._neutron_admin_context, p4['id'])
expected_calls = [
mock.call(mock.ANY, p)
for p in sorted([p1['id'], p2['id'], p4['id']])]
self._check_call_list(
expected_calls,
self.driver.aim_mech_driver._notify_port_update.call_args_list)
# Change the allowed address pair, and verify that the IP(s)
# from the old pair are removed from the mapping table
p1 = self._update('ports', p1['id'],
{'port': {'allowed_address_pairs': update_addr}},
neutron_context=self._neutron_admin_context)['port']
ips = self.driver.aim_mech_driver.get_ha_ipaddresses_for_port(p1['id'])
self.assertEqual(ips, [])
# Request ownership of the new AAP
ip_owner_info = {'port': p1['id'],
'ip_address_v4': update_owned_addr[0],
'network_id': p1['network_id']}
self.driver.aim_mech_driver.update_ip_owner(ip_owner_info)
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1['id'],
host='h1')
expected_aaps3 = _get_expected_aaps(update_addr, update_owned_addr[0])
self.assertEqual(sorted(expected_aaps3),
sorted(details['allowed_address_pairs']))
p2 = self._update('ports', p2['id'],
{'port': {'allowed_address_pairs': update_addr}},
neutron_context=self._neutron_admin_context)['port']
ips = self.driver.aim_mech_driver.get_ha_ipaddresses_for_port(p2['id'])
self.assertEqual(ips, [])
# Request ownership of the new AAP
ip_owner_info = {'port': p2['id'],
'ip_address_v4': update_owned_addr[1],
'network_id': p2['network_id']}
self.driver.aim_mech_driver.update_ip_owner(ip_owner_info)
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p2['id'],
host='h2')
expected_aaps4 = _get_expected_aaps(update_addr, update_owned_addr[1])
self.assertEqual(sorted(expected_aaps4),
sorted(details['allowed_address_pairs']))
def test_gbp_details_for_allowed_address_pair(self):
# 'aap' is configured, 'owned' is IP requested from agent
allow_addr = [{'ip_address': '1.2.3.250',
'mac_address': '00:00:00:AA:AA:AA'},
{'ip_address': '1.2.3.251',
'mac_address': '00:00:00:BB:BB:BB'}]
owned_addr = ['1.2.3.250', '1.2.3.251']
update_addr = [{'ip_address': '2.3.4.250',
'mac_address': '00:00:00:CC:CC:CC'},
{'ip_address': '2.3.4.251',
'mac_address': '00:00:00:DD:DD:DD'}]
update_owned_addr = ['2.3.4.250', '2.3.4.251']
self._test_gbp_details_for_allowed_address_pair(allow_addr,
owned_addr, update_addr, update_owned_addr)
def test_gbp_details_for_allowed_address_pair_cidr(self):
# 'aap' is configured, 'owned' is IP requested from agent
allow_addr = [{'ip_address': '1.2.3.0/24',
'mac_address': '00:00:00:AA:AA:AA'}]
owned_addr = ['1.2.3.250', '1.2.3.251']
update_addr = [{'ip_address': '2.3.4.0/24',
'mac_address': '00:00:00:BB:BB:BB'}]
update_owned_addr = ['2.3.4.250', '2.3.4.251']
self._test_gbp_details_for_allowed_address_pair(allow_addr,
owned_addr, update_addr, update_owned_addr)
def test_port_bound_other_agent(self):
# REVISIT: This test should call request_endpoint_details
# rather than get_gbp_details, since the Opflex agent no
# longer calls get_gbp_details. The new
# request_endpoint_details implementation returns a response
# without a gbp_details key to indicate that the port either
# isn't bound or is bound to a different host. For now, we
# accept either RPC implemention's response from
# get_gbp_details.
self._register_agent('h1', test_aim_md.AGENT_CONF_OPFLEX)
self._register_agent('h2', test_aim_md.AGENT_CONF_OPFLEX)
net = self._make_network(self.fmt, 'net1', True)
self._make_subnet(self.fmt, net, '10.0.1.1', '10.0.1.0/24')
# First test an unbound port
p1 = self._make_port(self.fmt, net['network']['id'],
device_owner='compute:')['port']
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1['id'],
host='h1')
self.assertEqual('', details.get('host', ''))
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1['id'],
host='h2')
self.assertEqual('', details.get('host', ''))
# Test port bound to h2, queries from h1 and h2
p1 = self._bind_port_to_host(p1['id'], 'h2')['port']
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1['id'],
host='h1')
self.assertEqual('h2', details.get('host', 'h2'))
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1['id'],
host='h2')
self.assertEqual('h2', details['host'])
# Test rebind of port to h1, queries from h1 and h2
p1 = self._bind_port_to_host(p1['id'], 'h1')['port']
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1['id'],
host='h1')
self.assertEqual('h1', details['host'])
details = self.driver.get_gbp_details(
self._neutron_admin_context, device='tap%s' % p1['id'],
host='h2')
self.assertEqual('h1', details.get('host', 'h1'))
# REVISIT: This test class is disabled because two of its tests fail
# with the following SQL error:
#
# OperationalError: (sqlite3.OperationalError) near "'1.2.3.250'":
# syntax error [SQL: u"SELECT DISTINCT id FROM ports JOIN
# ipallocations AS ipallocations_1 ON ipallocations_1.port_id =
# ports.id WHERE ports.network_id =
# 'e7b26ed0-9b92-47b5-a5ca-fd9b19dd4bc2' AND
# ipallocations_1.ip_address in (u'1.2.3.250')"] (Background on this
# error at: http://sqlalche.me/e/e3q8)
#
# class TestNeutronPortOperationWithRawSql(TestNeutronPortOperation):
#
# def setUp(self, **kwargs):
# super(TestNeutronPortOperationWithRawSql, self).setUp(**kwargs)
# self.driver.aim_mech_driver.enable_raw_sql_for_device_rpc = True
class TestNeutronPortOperationWithNewRpc(TestNeutronPortOperation):
def setUp(self, **kwargs):
super(TestNeutronPortOperationWithNewRpc, self).setUp(**kwargs)
self.driver.aim_mech_driver.enable_new_rpc = True
class TestPerL3PImplicitContractsConfig(TestL2PolicyWithAutoPTG):
def setUp(self, **kwargs):
aimd.cfg.CONF.set_override('create_per_l3p_implicit_contracts',
False, "aim_mapping")
self.mock_create = mock.Mock()
aimd.AIMMappingDriver._create_per_l3p_implicit_contracts = (
self.mock_create)
super(TestPerL3PImplicitContractsConfig, self).setUp(**kwargs)
def tearDown(self):
super(TestPerL3PImplicitContractsConfig, self).tearDown()
aimd.cfg.CONF.set_override('create_per_l3p_implicit_contracts',
True, group='aim_mapping')
self.driver.create_per_l3p_implicit_contracts = True
def test_create_not_called(self):
self.mock_create.assert_not_called()
class TestVlanAwareVM(AIMBaseTestCase):
def setUp(self, *args, **kwargs):
super(TestVlanAwareVM, self).setUp(trunk_plugin='trunk', **kwargs)
def _do_test_gbp_details_no_pt(self):
network = self._make_network(self.fmt, 'net1', True)
with self.subnet(network=network, cidr='1.1.2.0/24') as subnet:
with self.port(subnet=subnet) as port:
with self.port(subnet=subnet) as subp:
port_id = port['port']['id']
subp_id = subp['port']['id']
trunk = self._create_resource('trunk', port_id=port_id)
self.driver._trunk_plugin.add_subports(
nctx.get_admin_context(), trunk['trunk']['id'],
{'sub_ports': [{'port_id': subp_id,
'segmentation_type': 'vlan',
'segmentation_id': 100}]})
self._bind_port_to_host(port_id, 'h1')
req_mapping = self.driver.request_endpoint_details(
nctx.get_admin_context(),
request={'device': 'tap%s' % port_id,
'timestamp': 0, 'request_id': 'request_id'},
host='h1')
self.assertEqual(req_mapping['trunk_details']['trunk_id'],
trunk['trunk']['id'])
self.assertEqual(
req_mapping['trunk_details']['master_port_id'],
trunk['trunk']['port_id'])
self.assertEqual(
req_mapping['trunk_details']['subports'],
[{'port_id': subp_id,
'segmentation_type': 'vlan',
'segmentation_id': 100}])
# Retrieve the subport
self._bind_port_to_host(subp_id, 'h1')
req_mapping = self.driver.request_endpoint_details(
nctx.get_admin_context(),
request={'device': 'tap%s' % subp_id,
'timestamp': 0, 'request_id': 'request_id'},
host='h1')
self.assertEqual(req_mapping['trunk_details']['trunk_id'],
trunk['trunk']['id'])
self.assertEqual(
req_mapping['trunk_details']['master_port_id'],
port_id)
self.assertEqual(
req_mapping['trunk_details']['subports'],
[{'port_id': subp_id,
'segmentation_type': 'vlan',
'segmentation_id': 100}])
def test_trunk_master_port(self):
self._do_test_gbp_details_no_pt()
class TestVlanAwareVMWithRawSql(TestVlanAwareVM):
def setUp(self, **kwargs):
super(TestVlanAwareVMWithRawSql, self).setUp(**kwargs)
self.driver.aim_mech_driver.enable_raw_sql_for_device_rpc = True
class TestVlanAwareVMWithNewRpc(TestVlanAwareVM):
def setUp(self, **kwargs):
super(TestVlanAwareVMWithNewRpc, self).setUp(**kwargs)
self.driver.aim_mech_driver.enable_new_rpc = True
class TestL2PolicyRouteInjection(AIMBaseTestCase):
def _verify_rpc_response(self, port_id, inject, metadata):
# Invoke request_endpoint_details RPC handler.
request = {'device': 'tap%s' % port_id, 'timestamp': 0,
'request_id': 'a_request_id'}
response = self.driver.request_endpoint_details(
nctx.get_admin_context(), request=request, host='host1')
# Check subnet details.
subnet_details = response['gbp_details']['subnets'][0]
expected_host_routes = []
if inject:
self.assertIn('gateway_ip', subnet_details)
expected_host_routes.append(
{'destination': '0.0.0.0/0',
'nexthop': subnet_details['gateway_ip']})
if metadata:
expected_host_routes.append(
{'destination': '169.254.169.254/16',
'nexthop': subnet_details['dns_nameservers'][0]})
else:
self.assertNotIn('gateway_ip', subnet_details)
self.assertEqual(sorted(expected_host_routes),
sorted(subnet_details['host_routes']))
def _test_route_injection(self, inject):
# Create GBP resources and bind port.
l2p = self.create_l2_policy(
inject_default_route=inject)['l2_policy']
ptg = self.create_policy_target_group(
l2_policy_id=l2p['id'])['policy_target_group']
pt = self.create_policy_target(
policy_target_group_id=ptg['id'])['policy_target']
port_id = pt['port_id']
self._bind_port_to_host(port_id, 'host1')
# Test without metadata route.
self._verify_rpc_response(port_id, inject, False)
# Create a DHCP port on the PTG's subnet to enable metadata
# route injection.
fixed_ips = [{'subnet_id': ptg['subnets'][0]}]
self._make_port(
self.fmt, l2p['network_id'], fixed_ips=fixed_ips,
device_owner='network:dhcp')
# Test with metadata route.
self._verify_rpc_response(port_id, inject, True)
def test_route_injection_on(self):
self._test_route_injection(True)
def test_route_injection_off(self):
self._test_route_injection(False)
class TestL2PolicyRouteInjectionWithRawSql(TestL2PolicyRouteInjection):
def setUp(self, **kwargs):
super(TestL2PolicyRouteInjectionWithRawSql, self).setUp(**kwargs)
self.driver.aim_mech_driver.enable_raw_sql_for_device_rpc = True
class TestL2PolicyRouteInjectionWithNewRpc(TestL2PolicyRouteInjection):
def setUp(self, **kwargs):
super(TestL2PolicyRouteInjectionWithNewRpc, self).setUp(**kwargs)
self.driver.aim_mech_driver.enable_new_rpc = True