[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:
@@ -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):
|
||||
|
||||
@@ -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):
|
||||
|
||||
Reference in New Issue
Block a user