Use top-level contract references

Contract references in aci-integration-module (AIM) were previously
created or destroyed by modifying list members of the ExternalNetwork
resource.  This caused problems when the ExternalNetwork was monitored
state but the contract references were meant to be configured state,
as the view of the monitored universe/state could be inconsistent from
time to time, causing the contract references to inadvertently get
deleted.

A recent commit (9076bd8738e27052e75ec53052e509c54c4b91ea) in AIM made
the contract references top-level resources, so that their creation or
removal can only be made directly. The aim_lib module was changed to
support passing lists of provided and consumed contracts expclicitly,
in order to adopt these changes.

Change-Id: I14b01bea751823c3e3b70df3e7f41ea5babd9522
This commit is contained in:
Thomas Bachman 2022-09-27 16:32:10 +00:00
parent d1f32d9958
commit 2e5ec528b6
5 changed files with 394 additions and 128 deletions

View File

@ -330,11 +330,27 @@ def do_ap_name_change(session, conf=None):
eid = (ext_net.tenant_name, ext_net.l3out_name, ext_net.name)
for vrf in vrfs:
if eid in clone_ext_nets:
ext_net.provided_contract_names = clone_ext_nets[
eid].provided_contract_names
ext_net.consumed_contract_names = clone_ext_nets[
eid].consumed_contract_names
ns.connect_vrf(aim_ctx, ext_net, vrf)
p_cons = clone_ext_nets[eid].provided_contract_names
c_cons = clone_ext_nets[eid].provided_contract_names
prov = []
cons = []
ext_net = clone_ext_nets[eid]
for p_con in p_cons:
prov.append(
aim_resource.ExternalNetworkProvidedContract(
tenant_name=ext_net.tenant_name,
l3out_name=ext_net.l3out_name,
ext_net_name=ext_net.ext_net_name,
name=p_con.name))
for c_con in c_cons:
cons.append(
aim_resource.ExternalNetworkConsumedContract(
tenant_name=ext_net.tenant_name,
l3out_name=ext_net.l3out_name,
ext_net_name=ext_net.ext_net_name,
name=p_con.name))
ns.connect_vrf(aim_ctx, ext_net, vrf,
provided_contracts=prov, consumed_contracts=cons)
def do_apic_aim_security_group_migration(session):

View File

@ -743,6 +743,26 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
res = aim_resource.QosDppPol(**i)
self.aim.create(aim_ctx, res, overwrite=True)
def _create_external_epg_contract(self, aim_ctx, klass,
ext_net, contract):
new_contract = klass(
tenant_name=ext_net.tenant_name,
l3out_name=ext_net.l3out_name,
ext_net_name=ext_net.name,
name=contract.name)
self.aim.create(aim_ctx, new_contract, overwrite=True)
def _delete_external_epg_contract(self, aim_ctx, klass,
ext_net, contract):
old_contract = klass(
tenant_name=ext_net.tenant_name,
l3out_name=ext_net.l3out_name,
ext_net_name=ext_net.name,
name=contract.name)
old_contract_db = self.aim.get(aim_ctx, old_contract)
if old_contract_db:
self.aim.delete(aim_ctx, old_contract_db)
def create_qos_policy_precommit(self, context, policy):
"""Create a QoS policy.
:param context: neutron api request context
@ -2347,16 +2367,24 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
# this could be internal or external EPG
epg = self.aim.get(aim_ctx, epg)
if epg:
contracts = epg.consumed_contract_names
if contract.name not in contracts:
contracts.append(contract.name)
epg = self.aim.update(aim_ctx, epg,
consumed_contract_names=contracts)
contracts = epg.provided_contract_names
if contract.name not in contracts:
contracts.append(contract.name)
epg = self.aim.update(aim_ctx, epg,
provided_contract_names=contracts)
if isinstance(epg, aim_resource.ExternalNetwork):
self._create_external_epg_contract(aim_ctx,
aim_resource.ExternalNetworkProvidedContract,
epg, contract)
self._create_external_epg_contract(aim_ctx,
aim_resource.ExternalNetworkConsumedContract,
epg, contract)
else:
contracts = epg.consumed_contract_names
if contract.name not in contracts:
contracts.append(contract.name)
epg = self.aim.update(aim_ctx, epg,
consumed_contract_names=contracts)
contracts = epg.provided_contract_names
if contract.name not in contracts:
contracts.append(contract.name)
epg = self.aim.update(aim_ctx, epg,
provided_contract_names=contracts)
# If external-gateway is set, handle external-connectivity changes.
# External network is not supported for SVI network for now.
@ -2458,16 +2486,23 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
# Contract.
if router_id not in router_ids and epg:
epg = self.aim.get(aim_ctx, epg)
if isinstance(epg, aim_resource.ExternalNetwork):
self._delete_external_epg_contract(aim_ctx,
aim_resource.ExternalNetworkProvidedContract,
epg, contract)
self._delete_external_epg_contract(aim_ctx,
aim_resource.ExternalNetworkConsumedContract,
epg, contract)
else:
contracts = [name for name in epg.consumed_contract_names
if name != contract.name]
epg = self.aim.update(aim_ctx, epg,
consumed_contract_names=contracts)
contracts = [name for name in epg.consumed_contract_names
if name != contract.name]
epg = self.aim.update(aim_ctx, epg,
consumed_contract_names=contracts)
contracts = [name for name in epg.provided_contract_names
if name != contract.name]
epg = self.aim.update(aim_ctx, epg,
provided_contract_names=contracts)
contracts = [name for name in epg.provided_contract_names
if name != contract.name]
epg = self.aim.update(aim_ctx, epg,
provided_contract_names=contracts)
nets_to_notify = set()
ports_to_notify = set()
@ -4812,17 +4847,37 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
vrf = aim_resource.VRF(tenant_name=vrf.tenant_name, name=vrf.name)
rtr_dbs = self._get_routers_for_vrf(session, vrf)
prov = set()
cons = set()
prov_dict = {}
cons_dict = {}
def update_contracts(router):
def update_contracts(router, ext_net):
contract = self._map_router(session, router, True)
prov.add(contract.name)
cons.add(contract.name)
prov_dict[
contract.name] = aim_resource.ExternalNetworkProvidedContract(
tenant_name=ext_net.tenant_name,
l3out_name=ext_net.l3out_name,
ext_net_name=ext_net.name,
name=contract.name)
cons_dict[
contract.name] = aim_resource.ExternalNetworkConsumedContract(
tenant_name=ext_net.tenant_name,
l3out_name=ext_net.l3out_name,
ext_net_name=ext_net.name,
name=contract.name)
r_info = self.get_router_extn_db(session, router['id'])
prov.update(r_info[a_l3.EXTERNAL_PROVIDED_CONTRACTS])
cons.update(r_info[a_l3.EXTERNAL_CONSUMED_CONTRACTS])
for p_con in r_info[a_l3.EXTERNAL_PROVIDED_CONTRACTS]:
prov_dict[
p_con] = aim_resource.ExternalNetworkProvidedContract(
tenant_name=ext_net.tenant_name,
l3out_name=ext_net.l3out_name,
ext_net_name=ext_net.name, name=p_con)
for c_con in r_info[a_l3.EXTERNAL_CONSUMED_CONTRACTS]:
cons_dict[
c_con] = aim_resource.ExternalNetworkConsumedContract(
tenant_name=ext_net.tenant_name,
l3out_name=ext_net.l3out_name,
ext_net_name=ext_net.name, name=c_con)
if old_network:
_, ext_net, ns = self._get_aim_nat_strategy(old_network)
@ -4833,15 +4888,19 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
rtr_old = [r for r in rtr_dbs
if (r.gw_port_id and
r.gw_port.network_id in eqv_nets)]
prov = set()
cons = set()
prov_dict = {}
cons_dict = {}
for r in rtr_old:
update_contracts(r)
update_contracts(r, ext_net)
if rtr_old:
ext_net.provided_contract_names = sorted(prov)
ext_net.consumed_contract_names = sorted(cons)
ns.connect_vrf(aim_ctx, ext_net, vrf)
prov_list = list(prov_dict.values())
cons_list = list(cons_dict.values())
provided = sorted(prov_list, key=lambda x: x.name)
consumed = sorted(cons_list, key=lambda x: x.name)
ns.connect_vrf(aim_ctx, ext_net, vrf,
provided_contracts=provided,
consumed_contracts=consumed)
else:
ns.disconnect_vrf(aim_ctx, ext_net, vrf)
if new_network:
@ -4853,14 +4912,18 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
rtr_new = [r for r in rtr_dbs
if (r.gw_port_id and
r.gw_port.network_id in eqv_nets)]
prov = set()
cons = set()
prov_dict = {}
cons_dict = {}
for r in rtr_new:
update_contracts(r)
update_contracts(router)
ext_net.provided_contract_names = sorted(prov)
ext_net.consumed_contract_names = sorted(cons)
ns.connect_vrf(aim_ctx, ext_net, vrf)
update_contracts(r, ext_net)
update_contracts(router, ext_net)
prov_list = list(prov_dict.values())
cons_list = list(cons_dict.values())
provided = sorted(prov_list, key=lambda x: x.name)
consumed = sorted(cons_list, key=lambda x: x.name)
ns.connect_vrf(aim_ctx, ext_net, vrf,
provided_contracts=provided,
consumed_contracts=consumed)
def _is_port_bound(self, port):
return port.get(portbindings.VIF_TYPE) not in [
@ -6507,6 +6570,10 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
mgr.register_aim_resource_class(aim_resource.ContractSubject)
mgr.register_aim_resource_class(aim_resource.EndpointGroup)
mgr.register_aim_resource_class(aim_resource.ExternalNetwork)
mgr.register_aim_resource_class(
aim_resource.ExternalNetworkProvidedContract)
mgr.register_aim_resource_class(
aim_resource.ExternalNetworkConsumedContract)
mgr.register_aim_resource_class(aim_resource.ExternalSubnet)
mgr.register_aim_resource_class(aim_resource.Filter)
mgr.register_aim_resource_class(aim_resource.FilterEntry)
@ -7209,12 +7276,30 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
for router_id in routers:
contract = self._map_router(
mgr.expected_session, router_dbs[router_id], True)
prov.add(contract.name)
cons.add(contract.name)
prov.update(router_ext_prov[router_id])
cons.update(router_ext_cons[router_id])
ext_net.provided_contract_names = sorted(prov)
ext_net.consumed_contract_names = sorted(cons)
prov.add(aim_resource.ExternalNetworkProvidedContract(
tenant_name=ext_net.tenant_name,
l3out_name=ext_net.l3out_name,
ext_net_name=ext_net.name,
name=contract.name))
cons.add(aim_resource.ExternalNetworkProvidedContract(
tenant_name=ext_net.tenant_name,
l3out_name=ext_net.l3out_name,
ext_net_name=ext_net.name,
name=contract.name))
for p_con in router_ext_prov[router_id]:
prov.add(aim_resource.ExternalNetworkProvidedContract(
tenant_name=ext_net.tenant_name,
l3out_name=ext_net.l3out_name,
ext_net_name=ext_net.name,
name=p_con))
for c_con in router_ext_cons[router_id]:
cons.add(aim_resource.ExternalNetworkConsumedContract(
tenant_name=ext_net.tenant_name,
l3out_name=ext_net.l3out_name,
ext_net_name=ext_net.name,
name=c_con))
provided = sorted(prov, key=lambda x: x.name)
consumed = sorted(cons, key=lambda x: x.name)
int_vrf = int_vrfs[key]
# Keep only the identity attributes of the VRF so that
@ -7224,7 +7309,8 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
# of the L3Outside's display_name.
int_vrf = aim_resource.VRF(
tenant_name=int_vrf.tenant_name, name=int_vrf.name)
ns.connect_vrf(mgr.expected_aim_ctx, ext_net, int_vrf)
ns.connect_vrf(mgr.expected_aim_ctx, ext_net, int_vrf,
provided_contracts=provided, consumed_contracts=consumed)
return bd, epg, vrf

View File

@ -584,10 +584,20 @@ class SfcAIMDriver(SfcAIMDriverBase):
contract = self._get_flc_contract(prov_group, sg)
# TODO(ivar): if provider/consumer are in different tenants, export
# the contract
if contract.name not in cons_group.consumed_contract_names:
cons_group.consumed_contract_names.append(contract.name)
if contract.name not in prov_group.provided_contract_names:
prov_group.provided_contract_names.append(contract.name)
if isinstance(cons_group, aim_resource.ExternalNetwork):
self.aim_mech._create_external_epg_contract(aim_ctx,
aim_resource.ExternalNetworkConsumedContract,
cons_group, contract)
else:
if contract.name not in cons_group.consumed_contract_names:
cons_group.consumed_contract_names.append(contract.name)
if isinstance(prov_group, aim_resource.ExternalNetwork):
self.aim_mech._create_external_epg_contract(aim_ctx,
aim_resource.ExternalNetworkProvidedContract,
prov_group, contract)
else:
if contract.name not in prov_group.provided_contract_names:
prov_group.provided_contract_names.append(contract.name)
self.aim.create(aim_ctx, cons_group, overwrite=True)
self.aim.create(aim_ctx, prov_group, overwrite=True)
@ -651,18 +661,44 @@ class SfcAIMDriver(SfcAIMDriverBase):
contract = self._get_flc_contract(p_group, sg)
try:
if prefix == FLOWC_SRC:
epg.consumed_contract_names.remove(contract.name)
if isinstance(epg, aim_resource.ExternalNetwork):
self.aim_mech._delete_external_epg_contract(aim_ctx,
aim_resource.ExternalNetworkConsumedContract,
epg, contract)
else:
epg.consumed_contract_names.remove(contract.name)
else:
epg.provided_contract_names.remove(contract.name)
if isinstance(epg, aim_resource.ExternalNetwork):
self.aim_mech._delete_external_epg_contract(aim_ctx,
aim_resource.ExternalNetworkProvidedContract,
epg, contract)
else:
epg.provided_contract_names.remove(contract.name)
except ValueError:
LOG.warning("Contract %(name)s not present in EPG %(epg)s",
{'name': contract.name, 'epg': epg})
else:
epg = self.aim.create(aim_ctx, epg, overwrite=True)
if (ext_net and not epg.consumed_contract_names and not
epg.provided_contract_names):
# Only remove external network if completely empty
self.aim.delete(aim_ctx, epg, cascade=True)
if ext_net:
if isinstance(epg, aim_resource.ExternalNetwork):
contract_params = {
'tenant_name': ext_net.tenant_name,
'l3out_name': ext_net.l3out_name,
'ext_net_name': ext_net.name}
p_cons = self.aim.find(aim_ctx,
aim_resource.ExternalNetworkProvidedContract,
**contract_params)
c_cons = self.aim.find(aim_ctx,
aim_resource.ExternalNetworkProvidedContract,
**contract_params)
if not p_cons and not c_cons:
# Only remove if completely empty
self.aim.delete(aim_ctx, epg, cascade=True)
else:
if (not epg.consumed_contract_names and
not epg.provided_contract_names):
# Only remove if completely empty
self.aim.delete(aim_ctx, epg, cascade=True)
def _get_chains_by_classifier_id(self, plugin_context, flowc_id):
context = plugin_context

View File

@ -8179,33 +8179,54 @@ class TestExternalConnectivityBase(object):
# Connect the router interfaces to the subnets
vrf_objs = {}
rtr_contracts = {}
for tenant, router_list in six.iteritems(objs):
tenant_aname = self.name_mapper.project(None, tenant)
a_vrf = aim_resource.VRF(tenant_name=tenant_aname,
name='DefaultVRF')
a_ext_net = aim_resource.ExternalNetwork(
tenant_name=self.t1_aname, l3out_name='l1', name='n1')
prov = []
cons = []
for router, subnets, addr_scope in router_list:
if addr_scope:
a_vrf.name = self.name_mapper.address_scope(
None, addr_scope['id'])
self.fix_l3out_vrf(self.t1_aname, 'l1', a_vrf.name)
contract = self.name_mapper.router(None, router['id'])
a_ext_net.provided_contract_names.append(contract)
a_ext_net.provided_contract_names.extend(
router[PROV])
a_ext_net.provided_contract_names.sort()
a_ext_net.consumed_contract_names.append(contract)
a_ext_net.consumed_contract_names.extend(
router[CONS])
a_ext_net.consumed_contract_names.sort()
prov.append(aim_resource.ExternalNetworkProvidedContract(
tenant_name=a_ext_net.tenant_name,
l3out_name=a_ext_net.l3out_name,
ext_net_name=a_ext_net.name,
name=contract))
cons.append(aim_resource.ExternalNetworkConsumedContract(
tenant_name=a_ext_net.tenant_name,
l3out_name=a_ext_net.l3out_name,
ext_net_name=a_ext_net.name,
name=contract))
for con in router[PROV]:
prov.append(aim_resource.ExternalNetworkProvidedContract(
tenant_name=a_ext_net.tenant_name,
l3out_name=a_ext_net.l3out_name,
ext_net_name=a_ext_net.name,
name=con))
for con in router[CONS]:
cons.append(aim_resource.ExternalNetworkConsumedContract(
tenant_name=a_ext_net.tenant_name,
l3out_name=a_ext_net.l3out_name,
ext_net_name=a_ext_net.name,
name=con))
for idx in range(0, len(subnets)):
self.mock_ns.reset_mock()
self._router_interface_action('add', router['id'],
subnets[idx]['id'], None)
if idx == 0:
cv.assert_called_once_with(mock.ANY, a_ext_net, a_vrf)
provided = sorted(prov, key=lambda x: x.name)
consumed = sorted(cons, key=lambda x: x.name)
cv.assert_called_once_with(mock.ANY, a_ext_net, a_vrf,
provided_contracts=provided,
consumed_contracts=consumed)
else:
cv.assert_not_called()
@ -8216,6 +8237,7 @@ class TestExternalConnectivityBase(object):
self._check_bd_l3out(aim_ctx, aim_bd, 'l1')
self._validate()
rtr_contracts[router['id']] = (prov, cons)
vrf_objs[tenant] = a_ext_net
# Remove the router interfaces
@ -8226,17 +8248,30 @@ class TestExternalConnectivityBase(object):
a_ext_net = vrf_objs.pop(tenant)
num_router = len(router_list)
for router, subnets, addr_scope in router_list:
prov, cons = rtr_contracts[router['id']]
if addr_scope:
a_vrf.name = self.name_mapper.address_scope(
None, addr_scope['id'])
self.fix_l3out_vrf(self.t1_aname, 'l1', a_vrf.name)
contract = self.name_mapper.router(None, router['id'])
a_ext_net.provided_contract_names.remove(contract)
a_ext_net.consumed_contract_names.remove(contract)
prov.remove(aim_resource.ExternalNetworkProvidedContract(
tenant_name=a_ext_net.tenant_name,
l3out_name=a_ext_net.l3out_name,
ext_net_name=a_ext_net.name, name=contract))
cons.remove(aim_resource.ExternalNetworkConsumedContract(
tenant_name=a_ext_net.tenant_name,
l3out_name=a_ext_net.l3out_name,
ext_net_name=a_ext_net.name, name=contract))
for c in router[PROV]:
a_ext_net.provided_contract_names.remove(c)
prov.remove(aim_resource.ExternalNetworkProvidedContract(
tenant_name=a_ext_net.tenant_name,
l3out_name=a_ext_net.l3out_name,
ext_net_name=a_ext_net.name, name=c))
for c in router[CONS]:
a_ext_net.consumed_contract_names.remove(c)
cons.remove(aim_resource.ExternalNetworkConsumedContract(
tenant_name=a_ext_net.tenant_name,
l3out_name=a_ext_net.l3out_name,
ext_net_name=a_ext_net.name, name=c))
for idx in range(0, len(subnets)):
self.mock_ns.reset_mock()
@ -8250,8 +8285,12 @@ class TestExternalConnectivityBase(object):
if idx == len(subnets) - 1:
num_router -= 1
if num_router:
cv.assert_called_once_with(mock.ANY, a_ext_net,
a_vrf)
provided = sorted(prov, key=lambda x: x.name)
consumed = sorted(cons, key=lambda x: x.name)
cv.assert_called_once_with(
mock.ANY, a_ext_net, a_vrf,
provided_contracts=provided,
consumed_contracts=consumed)
else:
dv.assert_called_once_with(mock.ANY, a_ext_net,
a_vrf)
@ -8333,10 +8372,27 @@ class TestExternalConnectivityBase(object):
ext_net1['id']}}})
contract = self.name_mapper.router(None, router['id'])
a_ext_net1 = aim_resource.ExternalNetwork(
tenant_name=self.t1_aname, l3out_name='l1', name='n1',
provided_contract_names=sorted(['pr-1', contract]),
consumed_contract_names=sorted(['co-1', contract]))
cv.assert_called_once_with(mock.ANY, a_ext_net1, a_vrf)
tenant_name=self.t1_aname, l3out_name='l1', name='n1')
p1_ext1 = aim_resource.ExternalNetworkProvidedContract(
tenant_name=a_ext_net1.tenant_name,
l3out_name=a_ext_net1.l3out_name,
ext_net_name=a_ext_net1.name, name='pr-1')
prc_ext1 = aim_resource.ExternalNetworkProvidedContract(
tenant_name=a_ext_net1.tenant_name,
l3out_name=a_ext_net1.l3out_name,
ext_net_name=a_ext_net1.name, name=contract)
c1_ext1 = aim_resource.ExternalNetworkConsumedContract(
tenant_name=a_ext_net1.tenant_name,
l3out_name=a_ext_net1.l3out_name,
ext_net_name=a_ext_net1.name, name='co-1')
crc_ext1 = aim_resource.ExternalNetworkConsumedContract(
tenant_name=a_ext_net1.tenant_name,
l3out_name=a_ext_net1.l3out_name,
ext_net_name=a_ext_net1.name, name=contract)
provided = sorted([prc_ext1, p1_ext1], key=lambda x: x.name)
consumed = sorted([crc_ext1, c1_ext1], key=lambda x: x.name)
cv.assert_called_once_with(mock.ANY, a_ext_net1, a_vrf,
provided_contracts=provided, consumed_contracts=consumed)
self.mock_ns.reset_mock()
self._update('routers', router['id'],
@ -8344,39 +8400,58 @@ class TestExternalConnectivityBase(object):
{'external_gateway_info': {'network_id':
ext_net2['id']}}})
a_ext_net2 = aim_resource.ExternalNetwork(
tenant_name=self.t1_aname, l3out_name='l2', name='n2',
provided_contract_names=sorted(['pr-1', contract]),
consumed_contract_names=sorted(['co-1', contract]))
tenant_name=self.t1_aname, l3out_name='l2', name='n2')
p1_ext2 = aim_resource.ExternalNetworkProvidedContract(
tenant_name=a_ext_net2.tenant_name,
l3out_name=a_ext_net2.l3out_name,
ext_net_name=a_ext_net2.name, name='pr-1')
prc_ext2 = aim_resource.ExternalNetworkProvidedContract(
tenant_name=a_ext_net2.tenant_name,
l3out_name=a_ext_net2.l3out_name,
ext_net_name=a_ext_net2.name, name=contract)
c1_ext2 = aim_resource.ExternalNetworkConsumedContract(
tenant_name=a_ext_net2.tenant_name,
l3out_name=a_ext_net2.l3out_name,
ext_net_name=a_ext_net2.name, name='co-1')
c2_ext2 = aim_resource.ExternalNetworkConsumedContract(
tenant_name=a_ext_net2.tenant_name,
l3out_name=a_ext_net2.l3out_name,
ext_net_name=a_ext_net2.name, name='co-2')
crc_ext2 = aim_resource.ExternalNetworkConsumedContract(
tenant_name=a_ext_net2.tenant_name,
l3out_name=a_ext_net2.l3out_name,
ext_net_name=a_ext_net2.name, name=contract)
a_ext_net1.provided_contract_names = []
a_ext_net1.consumed_contract_names = []
dv.assert_called_once_with(mock.ANY, a_ext_net1, a_vrf)
cv.assert_called_once_with(mock.ANY, a_ext_net2, a_vrf)
provided = sorted([prc_ext2, p1_ext2], key=lambda x: x.name)
consumed = sorted([crc_ext2, c1_ext2], key=lambda x: x.name)
cv.assert_called_once_with(mock.ANY, a_ext_net2, a_vrf,
provided_contracts=provided, consumed_contracts=consumed)
self.mock_ns.reset_mock()
self._update('routers', router['id'],
{'router':
{PROV: []}})
a_ext_net2 = aim_resource.ExternalNetwork(
tenant_name=self.t1_aname, l3out_name='l2', name='n2',
provided_contract_names=sorted([contract]),
consumed_contract_names=sorted(['co-1', contract]))
cv.assert_called_once_with(mock.ANY, a_ext_net2, a_vrf)
tenant_name=self.t1_aname, l3out_name='l2', name='n2')
consumed = sorted([crc_ext2, c1_ext2], key=lambda x: x.name)
cv.assert_called_once_with(mock.ANY, a_ext_net2, a_vrf,
provided_contracts=[prc_ext2], consumed_contracts=consumed)
self.mock_ns.reset_mock()
self._update('routers', router['id'],
{'router':
{CONS: ['co-1', 'co-2']}})
a_ext_net2 = aim_resource.ExternalNetwork(
tenant_name=self.t1_aname, l3out_name='l2', name='n2',
provided_contract_names=sorted([contract]),
consumed_contract_names=sorted(['co-1', 'co-2', contract]))
cv.assert_called_once_with(mock.ANY, a_ext_net2, a_vrf)
tenant_name=self.t1_aname, l3out_name='l2', name='n2')
consumed = sorted([crc_ext2, c1_ext2, c2_ext2], key=lambda x: x.name)
cv.assert_called_once_with(mock.ANY, a_ext_net2, a_vrf,
provided_contracts=[prc_ext2], consumed_contracts=consumed)
self.mock_ns.reset_mock()
self._update('routers', router['id'],
{'router': {'external_gateway_info': {}}})
a_ext_net2.provided_contract_names = []
a_ext_net2.consumed_contract_names = []
dv.assert_called_once_with(mock.ANY, a_ext_net2, a_vrf)
def test_router_gateway(self):
@ -8482,40 +8557,62 @@ class TestExternalConnectivityBase(object):
self._validate()
self._add_external_gateway_to_router(routers[0], ext_nets[0])
a_ext_nets[0].provided_contract_names = [contracts[0]]
a_ext_nets[0].consumed_contract_names = [contracts[0]]
cv.assert_called_once_with(mock.ANY, a_ext_nets[0], a_vrf)
prov_ext1 = []
cons_ext1 = []
for con in contracts:
prov_ext1.append(aim_resource.ExternalNetworkProvidedContract(
tenant_name=a_ext_nets[0].tenant_name,
l3out_name=a_ext_nets[0].l3out_name,
ext_net_name=a_ext_nets[0].name, name=con))
cons_ext1.append(aim_resource.ExternalNetworkConsumedContract(
tenant_name=a_ext_nets[0].tenant_name,
l3out_name=a_ext_nets[0].l3out_name,
ext_net_name=a_ext_nets[0].name, name=con))
cv.assert_called_once_with(mock.ANY, a_ext_nets[0], a_vrf,
provided_contracts=[prov_ext1[0]],
consumed_contracts=[cons_ext1[0]])
self._validate()
self.mock_ns.reset_mock()
prov_ext2 = []
cons_ext2 = []
for con in contracts:
prov_ext2.append(aim_resource.ExternalNetworkProvidedContract(
tenant_name=a_ext_nets[1].tenant_name,
l3out_name=a_ext_nets[1].l3out_name,
ext_net_name=a_ext_nets[1].name, name=con))
cons_ext2.append(aim_resource.ExternalNetworkConsumedContract(
tenant_name=a_ext_nets[1].tenant_name,
l3out_name=a_ext_nets[1].l3out_name,
ext_net_name=a_ext_nets[1].name, name=con))
self._add_external_gateway_to_router(routers[1], ext_nets[1])
if shared_l3out:
a_ext_nets[1].provided_contract_names = sorted(contracts)
a_ext_nets[1].consumed_contract_names = sorted(contracts)
provided = sorted(prov_ext2, key=lambda x: x.name)
consumed = sorted(cons_ext2, key=lambda x: x.name)
p_con = provided
c_con = consumed
else:
a_ext_nets[1].provided_contract_names = [contracts[1]]
a_ext_nets[1].consumed_contract_names = [contracts[1]]
cv.assert_called_once_with(mock.ANY, a_ext_nets[1], a_vrf)
p_con = [prov_ext2[1]]
c_con = [cons_ext2[1]]
cv.assert_called_once_with(mock.ANY, a_ext_nets[1], a_vrf,
provided_contracts=p_con,
consumed_contracts=c_con)
self._validate()
self.mock_ns.reset_mock()
self._router_interface_action('remove', routers[0], sub1['id'], None)
if shared_l3out:
a_ext_nets[0].provided_contract_names = [contracts[1]]
a_ext_nets[0].consumed_contract_names = [contracts[1]]
cv.assert_called_once_with(mock.ANY, a_ext_nets[0], a_vrf)
cv.assert_called_once_with(mock.ANY, a_ext_nets[0], a_vrf,
provided_contracts=[prov_ext2[1]],
consumed_contracts=[cons_ext2[1]])
dv.assert_not_called()
else:
a_ext_nets[0].provided_contract_names = []
a_ext_nets[0].consumed_contract_names = []
dv.assert_called_once_with(mock.ANY, a_ext_nets[0], a_vrf)
cv.assert_not_called()
self._validate()
self.mock_ns.reset_mock()
self._router_interface_action('remove', routers[1], sub1['id'], None)
a_ext_nets[1].provided_contract_names = []
a_ext_nets[1].consumed_contract_names = []
dv.assert_called_once_with(mock.ANY, a_ext_nets[1], a_vrf)
self._validate()
@ -8786,9 +8883,15 @@ class TestExternalConnectivityBase(object):
contract = self.name_mapper.router(None, router['id'])
a_ext_net1 = aim_resource.ExternalNetwork(
tenant_name=self.t1_aname, l3out_name='l1', name='n1',
provided_contract_names=[contract],
consumed_contract_names=[contract])
tenant_name=self.t1_aname, l3out_name='l1', name='n1')
prov = aim_resource.ExternalNetworkProvidedContract(
tenant_name=a_ext_net1.tenant_name,
l3out_name=a_ext_net1.l3out_name,
ext_net_name=a_ext_net1.name, name=contract)
cons = aim_resource.ExternalNetworkConsumedContract(
tenant_name=a_ext_net1.tenant_name,
l3out_name=a_ext_net1.l3out_name,
ext_net_name=a_ext_net1.name, name=contract)
a_ext_net1_no_contracts = aim_resource.ExternalNetwork(
tenant_name=self.t1_aname, l3out_name='l1', name='n1')
@ -8802,7 +8905,8 @@ class TestExternalConnectivityBase(object):
a_vrf1 = aim_resource.VRF(
tenant_name=self.name_mapper.project(None, 'tenant_1'),
name='DefaultVRF')
cv.assert_called_once_with(mock.ANY, a_ext_net1, a_vrf1)
cv.assert_called_once_with(mock.ANY, a_ext_net1, a_vrf1,
provided_contracts=[prov], consumed_contracts=[cons])
dv.assert_not_called()
# 2. Create shared network net2 in tenant tenant_2, then connect
@ -8816,7 +8920,8 @@ class TestExternalConnectivityBase(object):
a_vrf2 = aim_resource.VRF(
tenant_name=self.name_mapper.project(None, 'tenant_2'),
name='DefaultVRF')
cv.assert_called_once_with(mock.ANY, a_ext_net1, a_vrf2)
cv.assert_called_once_with(mock.ANY, a_ext_net1, a_vrf2,
provided_contracts=[prov], consumed_contracts=[cons])
dv.assert_called_once_with(mock.ANY, a_ext_net1_no_contracts, a_vrf1)
# 3. Create unshared network net3 in tenant test-tenant, then connect
@ -8839,7 +8944,8 @@ class TestExternalConnectivityBase(object):
# 5. Disconnect net2 from r1
self.mock_ns.reset_mock()
self._router_interface_action('remove', router['id'], sub2['id'], None)
cv.assert_called_once_with(mock.ANY, a_ext_net1, a_vrf1)
cv.assert_called_once_with(mock.ANY, a_ext_net1, a_vrf1,
provided_contracts=[prov], consumed_contracts=[cons])
dv.assert_called_once_with(mock.ANY, a_ext_net1_no_contracts, a_vrf2)
# 6. Disconnect net1 from r1
@ -8881,9 +8987,15 @@ class TestExternalConnectivityBase(object):
contract = self.name_mapper.router(None, router['id'])
a_ext_net1 = aim_resource.ExternalNetwork(
tenant_name=self.t1_aname, l3out_name='l1', name='n1',
provided_contract_names=[contract],
consumed_contract_names=[contract])
tenant_name=self.t1_aname, l3out_name='l1', name='n1')
prov = aim_resource.ExternalNetworkProvidedContract(
tenant_name=a_ext_net1.tenant_name,
l3out_name=a_ext_net1.l3out_name,
ext_net_name=a_ext_net1.name, name=contract)
cons = aim_resource.ExternalNetworkConsumedContract(
tenant_name=a_ext_net1.tenant_name,
l3out_name=a_ext_net1.l3out_name,
ext_net_name=a_ext_net1.name, name=contract)
# create private stuff
net = self._make_network(self.fmt, 'net1', True)['network']
@ -8895,12 +9007,11 @@ class TestExternalConnectivityBase(object):
dv.assert_not_called()
self._router_interface_action('add', router['id'], subnet['id'], None)
cv.assert_called_once_with(mock.ANY, a_ext_net1, vrf)
cv.assert_called_once_with(mock.ANY, a_ext_net1, vrf,
provided_contracts=[prov], consumed_contracts=[cons])
dv.assert_not_called()
self.mock_ns.reset_mock()
a_ext_net1.provided_contract_names = []
a_ext_net1.consumed_contract_names = []
self._router_interface_action('remove', router['id'], subnet['id'],
None)
cv.assert_not_called()

View File

@ -479,10 +479,18 @@ class TestAIMServiceFunctionChainingBase(test_aim_base.AIMBaseTestCase):
self.assertIsNotNone(ext_sub)
self.assertIsNotNone(ext_net)
self.assertTrue(
contract.name in (ext_net.consumed_contract_names if
pref == 'src_' else
ext_net.provided_contract_names),
ext_contract_params = {
'tenant_name': ext_net.tenant_name,
'l3out_name': ext_net.l3out_name,
'ext_net_name': ext_net.name}
if pref == 'src_':
klass = aim_res.ExternalNetworkConsumedContract
else:
klass = aim_res.ExternalNetworkProvidedContract
contracts = self.aim_mgr.find(ctx, klass,
**ext_contract_params)
contract_names = [c.name for c in contracts]
self.assertTrue(contract.name in contract_names,
"%s not in ext net %s" % (contract.name,
ext_net.__dict__))
else:
@ -1390,10 +1398,19 @@ class TestPortChain(TestAIMServiceFunctionChainingBase):
self._aim_context, aim_res.ExternalNetwork,
name=fc['destination_ip_prefix'].replace(
'/', '_') + '_' + 'net_' + dst_net_id)[0]
self.assertEqual(2, len(ext_net.provided_contract_names))
ext_params = {
'tenant_name': ext_net.tenant_name,
'l3out_name': ext_net.l3out_name,
'ext_net_name': ext_net.name}
prov = self.aim_mgr.find(self._aim_context,
aim_res.ExternalNetworkProvidedContract,
**ext_params)
self.assertEqual(2, len(prov))
self.delete_port_chain(pc1['id'])
ext_net = self.aim_mgr.get(self._aim_context, ext_net)
self.assertEqual(1, len(ext_net.provided_contract_names))
prov = self.aim_mgr.find(self._aim_context,
aim_res.ExternalNetworkProvidedContract,
**ext_params)
self.assertEqual(1, len(prov))
self.delete_port_chain(pc2['id'])
self.assertIsNone(self.aim_mgr.get(self._aim_context, ext_net))