[APIC mapping] Fix contract association for pre-existing external EPG

When any tenant that uses a pre-existing L3Out (and external EPG),
either deletes its external policy (or detaches it from
external-segment), we were removing the provide/consume
relationship for the external EPG to NAT-allow contract.
This breaks NAT connectivity for the other tenants. This
fix removes the relationship only if there are no other
external policy objects mapping to the same external EPG.

Closes-Bug: 1527763

Change-Id: I74858c83b111b1fb223e4cd6af87e3625c64ec49
Signed-off-by: Amit Bose <bose@noironetworks.com>
This commit is contained in:
Amit Bose
2015-12-18 14:05:24 -08:00
parent e6a416b783
commit 1105a01346
2 changed files with 82 additions and 10 deletions

View File

@@ -1856,16 +1856,23 @@ class ApicMappingDriver(api.ResourceMappingDriver,
self.apic_manager.ensure_external_epg_deleted(
es_name, external_epg=ep_name, owner=es_tenant)
elif pre_existing_epg and nat_enabled:
nat_contract = self._get_nat_contract_for_es(context, es)
with self.apic_manager.apic.transaction() as trs:
self.apic_manager.unset_contract_for_external_epg(
es_name, nat_contract,
external_epg=ep_name, owner=es_tenant,
provided=True, transaction=trs)
self.apic_manager.unset_contract_for_external_epg(
es_name, nat_contract,
external_epg=ep_name, owner=es_tenant,
provided=False, transaction=trs)
pre_epgs = context._plugin.get_external_policies(
context._plugin_context.elevated(),
filters={'id': es['external_policies'],
'name': [ep['name']]})
# Unset contracts if there are no other pre-existing EPGs
if not [x for x in pre_epgs if x['id'] != ep['id']]:
nat_contract = self._get_nat_contract_for_es(
context, es)
with self.apic_manager.apic.transaction() as trs:
self.apic_manager.unset_contract_for_external_epg(
es_name, nat_contract,
external_epg=ep_name, owner=es_tenant,
provided=True, transaction=trs)
self.apic_manager.unset_contract_for_external_epg(
es_name, nat_contract,
external_epg=ep_name, owner=es_tenant,
provided=False, transaction=trs)
def _do_external_segment_update(self, context, ext_info,
l3policy_obj=None):

View File

@@ -3228,6 +3228,71 @@ class TestExternalPolicyPreL3Out(TestExternalPolicy):
super(TestExternalPolicyPreL3Out, self).setUp(
pre_existing_l3out=True)
def test_multi_tenant_delete(self):
self._mock_external_dict([('supported', '192.168.0.2/24')])
es = self.create_external_segment(
name='supported', cidr='192.168.0.0/24', shared=True,
expected_res_status=201)['external_segment']
ep_list = [
self.create_external_policy(
name=APIC_EXTERNAL_EPG,
external_segments=[es['id']],
tenant_id=tnnt,
expected_res_status=201)['external_policy']
for tnnt in ['tenant_a', 'tenant_b', 'tenant_c']]
for ep in ep_list:
self.delete_external_policy(
ep['id'], tenant_id=ep['tenant_id'],
expected_res_status=webob.exc.HTTPNoContent.code)
nat_contract = "NAT-allow-%s" % es['id']
expected_calls = [
mock.call(es['name'], nat_contract,
external_epg=APIC_EXTERNAL_EPG,
provided=True, owner=APIC_PRE_L3OUT_TENANT,
transaction=mock.ANY),
mock.call(es['name'], nat_contract,
external_epg=APIC_EXTERNAL_EPG,
provided=False, owner=APIC_PRE_L3OUT_TENANT,
transaction=mock.ANY)
]
mgr = self.driver.apic_manager
self._check_call_list(expected_calls,
mgr.unset_contract_for_external_epg.call_args_list)
def test_multi_tenant_update_dissociate(self):
self._mock_external_dict([('supported', '192.168.0.2/24')])
es = self.create_external_segment(
name='supported', cidr='192.168.0.0/24', shared=True,
expected_res_status=201)['external_segment']
ep_list = [
self.create_external_policy(
name=APIC_EXTERNAL_EPG,
external_segments=[es['id']],
tenant_id=tnnt,
expected_res_status=201)['external_policy']
for tnnt in ['tenant_a', 'tenant_b', 'tenant_c']]
for ep in ep_list:
self.update_external_policy(
ep['id'], tenant_id=ep['tenant_id'],
external_segments=[],
expected_res_status=200)
nat_contract = "NAT-allow-%s" % es['id']
expected_calls = [
mock.call(es['name'], nat_contract,
external_epg=APIC_EXTERNAL_EPG,
provided=True, owner=APIC_PRE_L3OUT_TENANT,
transaction=mock.ANY),
mock.call(es['name'], nat_contract,
external_epg=APIC_EXTERNAL_EPG,
provided=False, owner=APIC_PRE_L3OUT_TENANT,
transaction=mock.ANY)
]
mgr = self.driver.apic_manager
self._check_call_list(expected_calls,
mgr.unset_contract_for_external_epg.call_args_list)
class TestExternalPolicyNoNatPreL3Out(TestExternalPolicy):
def setUp(self):