[APIC mapping] Support per-tenant NAT EPGs
Adds support for option ('per_tenant_nat_epg') to enable creating a NAT EPG per tenant. The default (i.e. current) behavior is to lump together floating-IPs mappend to endpoints from all tenants into a single, common "NAT EPG" in APIC. When the new option is enabled, instead each tenant gets its own NAT EPG and floating-IPs associated with endpoints of that tenant are placed in that tenant-specific NAT EPG. SNAT endpoints are still put in the common NAT EPG. Changing this option does not affect existing NAT EPG usage. That is, if a tenant was using the common NAT EPG before this option was enabled, then it will continue to use the common NAT EPG until the tenant stops using the external-segment completely. This ensures backwards compatibility during upgrade. Closes-bug: 1595689 Change-Id: I31179f8b3b4a554fdfe85be9adbedb4d92220aca Signed-off-by: Amit Bose <amitbose@gmail.com>
This commit is contained in:
parent
b2d6d07e08
commit
88545a08f7
@ -0,0 +1,43 @@
|
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
"""apic_per-tenant-nat-epg
|
||||||
|
|
||||||
|
Revision ID: 98862f2d814e
|
||||||
|
Revises: 12c1bc8d7026
|
||||||
|
Create Date: 2016-06-22 17:36:28.386526
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision = '98862f2d814e'
|
||||||
|
down_revision = '12c1bc8d7026'
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.create_table(
|
||||||
|
'gp_apic_tenant_specific_nat_epg',
|
||||||
|
sa.Column('external_segment_id', sa.String(36), nullable=False),
|
||||||
|
sa.Column('tenant_id', sa.String(length=36), nullable=False),
|
||||||
|
sa.PrimaryKeyConstraint('external_segment_id', 'tenant_id'),
|
||||||
|
sa.ForeignKeyConstraint(['external_segment_id'],
|
||||||
|
['gp_external_segments.id'],
|
||||||
|
ondelete='CASCADE',
|
||||||
|
name='gp_apic_ptne_fk_es'))
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_table('gp_apic_tenant_specific_nat_epg')
|
@ -1 +1 @@
|
|||||||
12c1bc8d7026
|
98862f2d814e
|
||||||
|
@ -34,6 +34,7 @@ from neutron.common import rpc as n_rpc
|
|||||||
from neutron.common import topics
|
from neutron.common import topics
|
||||||
from neutron import context as nctx
|
from neutron import context as nctx
|
||||||
from neutron.db import db_base_plugin_v2 as n_db
|
from neutron.db import db_base_plugin_v2 as n_db
|
||||||
|
from neutron.db import model_base
|
||||||
from neutron.extensions import portbindings
|
from neutron.extensions import portbindings
|
||||||
from neutron.extensions import providernet
|
from neutron.extensions import providernet
|
||||||
from neutron import manager
|
from neutron import manager
|
||||||
@ -47,6 +48,7 @@ from oslo_concurrency import lockutils
|
|||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
from gbpservice.neutron.db.grouppolicy import group_policy_mapping_db as gpdb
|
from gbpservice.neutron.db.grouppolicy import group_policy_mapping_db as gpdb
|
||||||
from gbpservice.neutron.extensions import driver_proxy_group as proxy_group
|
from gbpservice.neutron.extensions import driver_proxy_group as proxy_group
|
||||||
@ -196,6 +198,16 @@ class ExplicitPortOverlap(gpexc.GroupPolicyBadRequest):
|
|||||||
'%(ip)s has overlapping IP or MAC address with another port '
|
'%(ip)s has overlapping IP or MAC address with another port '
|
||||||
'in network %(net)s')
|
'in network %(net)s')
|
||||||
|
|
||||||
|
|
||||||
|
class TenantSpecificNatEpg(model_base.BASEV2):
|
||||||
|
"""Tenants that use a specific NAT EPG for an external segment."""
|
||||||
|
__tablename__ = 'gp_apic_tenant_specific_nat_epg'
|
||||||
|
external_segment_id = sa.Column(
|
||||||
|
sa.String(36), sa.ForeignKey('gp_external_segments.id',
|
||||||
|
ondelete='CASCADE'),
|
||||||
|
primary_key=True)
|
||||||
|
tenant_id = sa.Column(sa.String(36), primary_key=True)
|
||||||
|
|
||||||
REVERSE_PREFIX = 'reverse-'
|
REVERSE_PREFIX = 'reverse-'
|
||||||
SHADOW_PREFIX = 'Shd-'
|
SHADOW_PREFIX = 'Shd-'
|
||||||
AUTO_PREFIX = 'Auto-'
|
AUTO_PREFIX = 'Auto-'
|
||||||
@ -269,6 +281,7 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
self.enable_dhcp_opt = self.apic_manager.enable_optimized_dhcp
|
self.enable_dhcp_opt = self.apic_manager.enable_optimized_dhcp
|
||||||
self.enable_metadata_opt = self.apic_manager.enable_optimized_metadata
|
self.enable_metadata_opt = self.apic_manager.enable_optimized_metadata
|
||||||
self.nat_enabled = self.apic_manager.use_vmm
|
self.nat_enabled = self.apic_manager.use_vmm
|
||||||
|
self.per_tenant_nat_epg = self.apic_manager.per_tenant_nat_epg
|
||||||
self._gbp_plugin = None
|
self._gbp_plugin = None
|
||||||
self.l3out_vlan_alloc = l3out_vlan_alloc.L3outVlanAlloc()
|
self.l3out_vlan_alloc = l3out_vlan_alloc.L3outVlanAlloc()
|
||||||
self.l3out_vlan_alloc.sync_vlan_allocations(
|
self.l3out_vlan_alloc.sync_vlan_allocations(
|
||||||
@ -596,9 +609,10 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
ext_info = self.apic_manager.ext_net_dict.get(es['name'])
|
ext_info = self.apic_manager.ext_net_dict.get(es['name'])
|
||||||
if ext_info and self._is_edge_nat(ext_info):
|
if ext_info and self._is_edge_nat(ext_info):
|
||||||
continue
|
continue
|
||||||
nat_epg_name = self._get_nat_epg_for_es(context, es)
|
nat_epg_tenant, nat_epg_name = self._determine_nat_epg_for_es(
|
||||||
|
context, es, l3_policy)
|
||||||
nat_epg_tenant = self.apic_manager.apic.fvTenant.name(
|
nat_epg_tenant = self.apic_manager.apic.fvTenant.name(
|
||||||
self._tenant_by_sharing_policy(es))
|
nat_epg_tenant)
|
||||||
fips_in_es = []
|
fips_in_es = []
|
||||||
|
|
||||||
if es['subnet_id']:
|
if es['subnet_id']:
|
||||||
@ -619,7 +633,10 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
if not fips_in_es:
|
if not fips_in_es:
|
||||||
ipms.append({'external_segment_name': es['name'],
|
ipms.append({'external_segment_name': es['name'],
|
||||||
'nat_epg_name': nat_epg_name,
|
'nat_epg_name': nat_epg_name,
|
||||||
'nat_epg_tenant': nat_epg_tenant})
|
'nat_epg_tenant': nat_epg_tenant,
|
||||||
|
'next_hop_ep_tenant': (
|
||||||
|
self.apic_manager.apic.fvTenant.name(
|
||||||
|
self._tenant_by_sharing_policy(es)))})
|
||||||
for f in fips_in_es:
|
for f in fips_in_es:
|
||||||
f['nat_epg_name'] = nat_epg_name
|
f['nat_epg_name'] = nat_epg_name
|
||||||
f['nat_epg_tenant'] = nat_epg_tenant
|
f['nat_epg_tenant'] = nat_epg_tenant
|
||||||
@ -1900,9 +1917,10 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
l3p_id=context.current['id'], es_id=es['id'])
|
l3p_id=context.current['id'], es_id=es['id'])
|
||||||
context.set_external_fixed_ips(es['id'], [ip])
|
context.set_external_fixed_ips(es['id'], [ip])
|
||||||
|
|
||||||
|
is_edge_nat = self._is_edge_nat(ext_info)
|
||||||
es_name = self.name_mapper.external_segment(context, es,
|
es_name = self.name_mapper.external_segment(context, es,
|
||||||
prefix=self._get_shadow_prefix(context,
|
prefix=self._get_shadow_prefix(context,
|
||||||
is_shadow, context.current, self._is_edge_nat(ext_info)))
|
is_shadow, context.current, is_edge_nat))
|
||||||
es_name_pre = self.name_mapper.name_mapper.pre_existing(
|
es_name_pre = self.name_mapper.name_mapper.pre_existing(
|
||||||
context._plugin_context, es['name'])
|
context._plugin_context, es['name'])
|
||||||
es_tenant = self._get_tenant_for_shadow(is_shadow, context.current, es)
|
es_tenant = self._get_tenant_for_shadow(is_shadow, context.current, es)
|
||||||
@ -1917,8 +1935,7 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
# don't need to explicitly create the shadow l3out in this case
|
# don't need to explicitly create the shadow l3out in this case
|
||||||
# because we are going to query APIC then use the pre-existing
|
# because we are going to query APIC then use the pre-existing
|
||||||
# l3out as a template then clone it accordingly
|
# l3out as a template then clone it accordingly
|
||||||
if (is_shadow and self._is_edge_nat(ext_info) and
|
if (is_shadow and is_edge_nat and self._is_pre_existing(es)):
|
||||||
self._is_pre_existing(es)):
|
|
||||||
is_l3out_creation_needed = False
|
is_l3out_creation_needed = False
|
||||||
|
|
||||||
if is_l3out_creation_needed:
|
if is_l3out_creation_needed:
|
||||||
@ -1941,7 +1958,7 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
|
|
||||||
# if its edge nat then we have to flesh
|
# if its edge nat then we have to flesh
|
||||||
# out this shadow L3 out in APIC
|
# out this shadow L3 out in APIC
|
||||||
if is_shadow and self._is_edge_nat(ext_info):
|
if is_shadow and is_edge_nat:
|
||||||
vlan_id = self.l3out_vlan_alloc.reserve_vlan(
|
vlan_id = self.l3out_vlan_alloc.reserve_vlan(
|
||||||
es['name'], context.current['id'])
|
es['name'], context.current['id'])
|
||||||
encap = 'vlan-' + str(vlan_id)
|
encap = 'vlan-' + str(vlan_id)
|
||||||
@ -1978,13 +1995,18 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
self.name_mapper.l2_policy(context, l2p),
|
self.name_mapper.l2_policy(context, l2p),
|
||||||
es_name)
|
es_name)
|
||||||
|
|
||||||
if not is_shadow and nat_enabled:
|
if nat_enabled:
|
||||||
|
if not is_shadow:
|
||||||
# set L3-out for NAT-BD
|
# set L3-out for NAT-BD
|
||||||
self.apic_manager.set_l3out_for_bd(es_tenant,
|
self.apic_manager.set_l3out_for_bd(es_tenant,
|
||||||
self._get_nat_bd_for_es(context, es),
|
self._get_nat_bd_for_es(context, es),
|
||||||
(self.name_mapper.name_mapper.pre_existing(
|
(self.name_mapper.name_mapper.pre_existing(
|
||||||
context, es['name']) if pre_existing else es_name),
|
context, es['name']) if pre_existing else es_name),
|
||||||
transaction=trs)
|
transaction=trs)
|
||||||
|
elif not is_edge_nat:
|
||||||
|
# create tenant-specific NAT EPG if required
|
||||||
|
self._create_tenant_specific_nat_epg(context, es,
|
||||||
|
context.current, transaction=trs)
|
||||||
if not is_shadow:
|
if not is_shadow:
|
||||||
if nat_enabled:
|
if nat_enabled:
|
||||||
# create shadow external-networks
|
# create shadow external-networks
|
||||||
@ -2026,6 +2048,10 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
if nat_enabled:
|
if nat_enabled:
|
||||||
# remove shadow external-networks
|
# remove shadow external-networks
|
||||||
self._unplug_l3p_from_es(context, es, True)
|
self._unplug_l3p_from_es(context, es, True)
|
||||||
|
if not is_edge_nat:
|
||||||
|
# remove tenant-specific NAT EPG if required
|
||||||
|
self._remove_tenant_specific_nat_epg(context, es,
|
||||||
|
context.current)
|
||||||
else:
|
else:
|
||||||
# Dissociate BDs of the VRF from L3-out
|
# Dissociate BDs of the VRF from L3-out
|
||||||
l2ps = self._get_l2_policies(context._plugin_context,
|
l2ps = self._get_l2_policies(context._plugin_context,
|
||||||
@ -2147,13 +2173,14 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
l3policy_obj, transaction=trs)
|
l3policy_obj, transaction=trs)
|
||||||
if is_shadow:
|
if is_shadow:
|
||||||
if not self._is_edge_nat(ext_info):
|
if not self._is_edge_nat(ext_info):
|
||||||
|
nat_epg_tenant, nat_epg_name = (
|
||||||
|
self._determine_nat_epg_for_es(
|
||||||
|
context, es, l3policy_obj))
|
||||||
# set up link to NAT EPG
|
# set up link to NAT EPG
|
||||||
(self.apic_manager.
|
(self.apic_manager.
|
||||||
associate_external_epg_to_nat_epg(
|
associate_external_epg_to_nat_epg(
|
||||||
es_tenant, es_name, ep_name,
|
es_tenant, es_name, ep_name,
|
||||||
self._get_nat_epg_for_es(context, es),
|
nat_epg_name, target_owner=nat_epg_tenant,
|
||||||
target_owner=self._tenant_by_sharing_policy(
|
|
||||||
es),
|
|
||||||
transaction=trs))
|
transaction=trs))
|
||||||
elif nat_enabled:
|
elif nat_enabled:
|
||||||
# 'real' external EPGs provide and consume
|
# 'real' external EPGs provide and consume
|
||||||
@ -3673,3 +3700,98 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
for ip in fixed_ips:
|
for ip in fixed_ips:
|
||||||
ip.pop('subnet_id', None)
|
ip.pop('subnet_id', None)
|
||||||
return fixed_ips
|
return fixed_ips
|
||||||
|
|
||||||
|
def _determine_nat_epg_for_es(self, context, es, tenant_obj):
|
||||||
|
nat_epg_name = self._get_nat_epg_for_es(context, es)
|
||||||
|
nat_epg_tenant = None
|
||||||
|
if (es['shared'] and
|
||||||
|
self._tenant_uses_specific_nat_epg(context, es, tenant_obj)):
|
||||||
|
nat_epg_tenant = self.name_mapper.tenant(tenant_obj)
|
||||||
|
nat_epg_tenant = nat_epg_tenant or self._tenant_by_sharing_policy(es)
|
||||||
|
return nat_epg_tenant, nat_epg_name
|
||||||
|
|
||||||
|
def _tenant_uses_specific_nat_epg(self, context, es, tenant_obj):
|
||||||
|
session = context._plugin_context.session
|
||||||
|
cnt = session.query(TenantSpecificNatEpg).filter_by(
|
||||||
|
external_segment_id = es['id']).filter_by(
|
||||||
|
tenant_id = tenant_obj['tenant_id']).count()
|
||||||
|
return bool(cnt)
|
||||||
|
|
||||||
|
def _create_tenant_specific_nat_epg(self, context, es, l3_policy,
|
||||||
|
transaction=None):
|
||||||
|
if not es['shared']:
|
||||||
|
return
|
||||||
|
|
||||||
|
l3ps = self._get_l3_policies(context._plugin_context.elevated(),
|
||||||
|
filters={'id': [l3p for l3p in es['l3_policies']
|
||||||
|
if l3p != l3_policy['id']],
|
||||||
|
'tenant_id': [l3_policy['tenant_id']]})
|
||||||
|
if l3ps:
|
||||||
|
# there are other L3Ps from this tenant - don't explicitly create
|
||||||
|
# tenant-specific NAT EPG so that we continue using whatever
|
||||||
|
# those L3Ps were using
|
||||||
|
return
|
||||||
|
|
||||||
|
uses_specific_nat_epg = self._tenant_uses_specific_nat_epg(
|
||||||
|
context, es, l3_policy)
|
||||||
|
if uses_specific_nat_epg or not self.per_tenant_nat_epg:
|
||||||
|
return
|
||||||
|
|
||||||
|
nat_bd_name = self._get_nat_bd_for_es(context, es)
|
||||||
|
nat_epg_name = self._get_nat_epg_for_es(context, es)
|
||||||
|
nat_contract = self._get_nat_contract_for_es(context, es)
|
||||||
|
nat_epg_tenant = self.name_mapper.tenant(l3_policy)
|
||||||
|
es_tenant = self._tenant_by_sharing_policy(es)
|
||||||
|
|
||||||
|
with self.apic_manager.apic.transaction(transaction) as trs:
|
||||||
|
self.apic_manager.ensure_epg_created(
|
||||||
|
nat_epg_tenant, nat_epg_name, bd_name=nat_bd_name,
|
||||||
|
bd_owner=es_tenant, transaction=trs)
|
||||||
|
self.apic_manager.set_contract_for_epg(
|
||||||
|
nat_epg_tenant, nat_epg_name, nat_contract,
|
||||||
|
transaction=trs)
|
||||||
|
self.apic_manager.set_contract_for_epg(
|
||||||
|
nat_epg_tenant, nat_epg_name, nat_contract, provider=True,
|
||||||
|
transaction=trs)
|
||||||
|
session = context._plugin_context.session
|
||||||
|
with session.begin(subtransactions=True):
|
||||||
|
db_obj = TenantSpecificNatEpg(
|
||||||
|
external_segment_id=es['id'], tenant_id=l3_policy['tenant_id'])
|
||||||
|
session.add(db_obj)
|
||||||
|
LOG.debug('Created tenant-specific NAT EPG (%(tenant)s, %(epg)s) for '
|
||||||
|
'external segment %(es)s',
|
||||||
|
{'tenant': nat_epg_tenant, 'epg': nat_epg_name,
|
||||||
|
'es': es['id']})
|
||||||
|
|
||||||
|
def _remove_tenant_specific_nat_epg(self, context, es, l3_policy,
|
||||||
|
transaction=None):
|
||||||
|
if not es['shared']:
|
||||||
|
return
|
||||||
|
uses_specific_nat_epg = self._tenant_uses_specific_nat_epg(
|
||||||
|
context, es, l3_policy)
|
||||||
|
if not uses_specific_nat_epg:
|
||||||
|
return
|
||||||
|
|
||||||
|
# remove NAT EPG if this is last L3P from this tenant
|
||||||
|
l3ps = self._get_l3_policies(context._plugin_context.elevated(),
|
||||||
|
filters={'id': [l3p for l3p in es['l3_policies']
|
||||||
|
if l3p != l3_policy['id']],
|
||||||
|
'tenant_id': [l3_policy['tenant_id']]})
|
||||||
|
if not l3ps:
|
||||||
|
session = context._plugin_context.session
|
||||||
|
with session.begin(subtransactions=True):
|
||||||
|
db_obj = session.query(TenantSpecificNatEpg).filter_by(
|
||||||
|
external_segment_id = es['id']).filter_by(
|
||||||
|
tenant_id = l3_policy['tenant_id']).first()
|
||||||
|
if db_obj:
|
||||||
|
session.delete(db_obj)
|
||||||
|
|
||||||
|
nat_epg_name = self._get_nat_epg_for_es(context, es)
|
||||||
|
nat_epg_tenant = self.name_mapper.tenant(l3_policy)
|
||||||
|
self.apic_manager.delete_epg_for_network(
|
||||||
|
nat_epg_tenant, nat_epg_name, transaction=transaction)
|
||||||
|
|
||||||
|
LOG.debug('Removed tenant-specific NAT EPG (%(tenant)s, %(epg)s) '
|
||||||
|
'for external segment %(es)s',
|
||||||
|
{'tenant': nat_epg_tenant, 'epg': nat_epg_name,
|
||||||
|
'es': es['id']})
|
||||||
|
@ -103,7 +103,11 @@ class ApicMappingTestCase(
|
|||||||
config.cfg.CONF.set_override('enable_security_group', False,
|
config.cfg.CONF.set_override('enable_security_group', False,
|
||||||
group='SECURITYGROUP')
|
group='SECURITYGROUP')
|
||||||
n_rpc.create_connection = mock.Mock()
|
n_rpc.create_connection = mock.Mock()
|
||||||
amap.ApicMappingDriver.get_apic_manager = mock.MagicMock()
|
amap.ApicMappingDriver.get_apic_manager = mock.Mock(
|
||||||
|
return_value=mock.MagicMock(
|
||||||
|
name_mapper=mock.Mock(),
|
||||||
|
ext_net_dict={},
|
||||||
|
per_tenant_nat_epg=False))
|
||||||
self.set_up_mocks()
|
self.set_up_mocks()
|
||||||
ml2_opts = ml2_options or {
|
ml2_opts = ml2_options or {
|
||||||
'mechanism_drivers': ['apic_gbp'],
|
'mechanism_drivers': ['apic_gbp'],
|
||||||
@ -143,8 +147,6 @@ class ApicMappingTestCase(
|
|||||||
self.driver.name_mapper.name_mapper.external_policy = echo
|
self.driver.name_mapper.name_mapper.external_policy = echo
|
||||||
self.driver.name_mapper.name_mapper.external_segment = echo
|
self.driver.name_mapper.name_mapper.external_segment = echo
|
||||||
self.driver.name_mapper.name_mapper.pre_existing = echo
|
self.driver.name_mapper.name_mapper.pre_existing = echo
|
||||||
self.driver.apic_manager = mock.Mock(name_mapper=mock.Mock(),
|
|
||||||
ext_net_dict={})
|
|
||||||
self.driver.apic_manager.apic.transaction = self.fake_transaction
|
self.driver.apic_manager.apic.transaction = self.fake_transaction
|
||||||
self.driver.notifier = mock.Mock()
|
self.driver.notifier = mock.Mock()
|
||||||
self.driver.apic_manager.ext_net_dict = {}
|
self.driver.apic_manager.ext_net_dict = {}
|
||||||
@ -393,13 +395,13 @@ class TestPolicyTarget(ApicMappingTestCase):
|
|||||||
self.assertEqual(l3p['tenant_id'], details['vrf_tenant'])
|
self.assertEqual(l3p['tenant_id'], details['vrf_tenant'])
|
||||||
self.assertEqual(l3p['id'], details['vrf_name'])
|
self.assertEqual(l3p['id'], details['vrf_name'])
|
||||||
|
|
||||||
def test_get_gbp_details(self):
|
def _do_test_get_gbp_details(self):
|
||||||
self._mock_external_dict([('supported', '192.168.0.2/24')])
|
self._mock_external_dict([('supported', '192.168.0.2/24')])
|
||||||
self.driver.apic_manager.ext_net_dict[
|
self.driver.apic_manager.ext_net_dict[
|
||||||
'supported']['host_pool_cidr'] = '192.168.200.1/24'
|
'supported']['host_pool_cidr'] = '192.168.200.1/24'
|
||||||
es = self.create_external_segment(name='supported',
|
es = self.create_external_segment(name='supported',
|
||||||
cidr='192.168.0.2/24',
|
cidr='192.168.0.2/24',
|
||||||
expected_res_status=201, shared=False)['external_segment']
|
expected_res_status=201, shared=True)['external_segment']
|
||||||
self.create_nat_pool(external_segment_id=es['id'],
|
self.create_nat_pool(external_segment_id=es['id'],
|
||||||
ip_pool='20.20.20.0/24')
|
ip_pool='20.20.20.0/24')
|
||||||
l3p = self.create_l3_policy(name='myl3',
|
l3p = self.create_l3_policy(name='myl3',
|
||||||
@ -436,7 +438,10 @@ class TestPolicyTarget(ApicMappingTestCase):
|
|||||||
fip = mapping['floating_ip'][0]
|
fip = mapping['floating_ip'][0]
|
||||||
self.assertEqual(pt1['port_id'], fip['port_id'])
|
self.assertEqual(pt1['port_id'], fip['port_id'])
|
||||||
self.assertEqual("NAT-epg-%s" % es['id'], fip['nat_epg_name'])
|
self.assertEqual("NAT-epg-%s" % es['id'], fip['nat_epg_name'])
|
||||||
self.assertEqual(es['tenant_id'], fip['nat_epg_tenant'])
|
self.assertEqual(
|
||||||
|
(es['tenant_id'] if self.driver.per_tenant_nat_epg
|
||||||
|
else self.common_tenant),
|
||||||
|
fip['nat_epg_tenant'])
|
||||||
|
|
||||||
self.assertEqual(l3p['tenant_id'], mapping['vrf_tenant'])
|
self.assertEqual(l3p['tenant_id'], mapping['vrf_tenant'])
|
||||||
self.assertEqual(l3p['id'], mapping['vrf_name'])
|
self.assertEqual(l3p['id'], mapping['vrf_name'])
|
||||||
@ -476,6 +481,13 @@ class TestPolicyTarget(ApicMappingTestCase):
|
|||||||
mapping['host_snat_ips'][0]['host_snat_ip'])
|
mapping['host_snat_ips'][0]['host_snat_ip'])
|
||||||
self.assertEqual(24, mapping['host_snat_ips'][0]['prefixlen'])
|
self.assertEqual(24, mapping['host_snat_ips'][0]['prefixlen'])
|
||||||
|
|
||||||
|
def test_get_gbp_details(self):
|
||||||
|
self._do_test_get_gbp_details()
|
||||||
|
|
||||||
|
def test_get_gbp_details_ptne(self):
|
||||||
|
self.driver.per_tenant_nat_epg = True
|
||||||
|
self._do_test_get_gbp_details()
|
||||||
|
|
||||||
def test_get_snat_ip_for_vrf(self):
|
def test_get_snat_ip_for_vrf(self):
|
||||||
TEST_VRF1 = 'testvrf1'
|
TEST_VRF1 = 'testvrf1'
|
||||||
TEST_VRF2 = 'testvrf2'
|
TEST_VRF2 = 'testvrf2'
|
||||||
@ -2176,8 +2188,12 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
'nexthop': '192.168.0.254'},
|
'nexthop': '192.168.0.254'},
|
||||||
{'destination': '128.0.0.0/16',
|
{'destination': '128.0.0.0/16',
|
||||||
'nexthop': None}])['external_segment']
|
'nexthop': None}])['external_segment']
|
||||||
|
owner = self.common_tenant if shared_es else es['tenant_id']
|
||||||
|
|
||||||
|
mgr = self.driver.apic_manager
|
||||||
|
mgr.ensure_epg_created.reset_mock()
|
||||||
|
mgr.set_contract_for_epg.reset_mock()
|
||||||
|
|
||||||
# Create with explicit address
|
|
||||||
l3p = self.create_l3_policy(
|
l3p = self.create_l3_policy(
|
||||||
name='myl3p',
|
name='myl3p',
|
||||||
shared=shared_l3p,
|
shared=shared_l3p,
|
||||||
@ -2188,15 +2204,37 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
self.assertEqual(1, len(l3p['external_segments'][es['id']]))
|
self.assertEqual(1, len(l3p['external_segments'][es['id']]))
|
||||||
self.assertEqual('169.254.0.2', l3p['external_segments'][es['id']][0])
|
self.assertEqual('169.254.0.2', l3p['external_segments'][es['id']][0])
|
||||||
|
|
||||||
|
expected_epg_calls = []
|
||||||
|
expected_contract_calls = []
|
||||||
|
expected_nat_epg_tenant = owner
|
||||||
|
if self.nat_enabled and shared_es and self.driver.per_tenant_nat_epg:
|
||||||
|
expected_epg_calls.append(
|
||||||
|
mock.call(l3p['tenant_id'], "NAT-epg-%s" % es['id'],
|
||||||
|
bd_name="NAT-bd-%s" % es['id'], bd_owner=owner,
|
||||||
|
transaction=mock.ANY))
|
||||||
|
expected_contract_calls.extend([
|
||||||
|
mock.call(l3p['tenant_id'], "NAT-epg-%s" % es['id'],
|
||||||
|
"NAT-allow-%s" % es['id'], transaction=mock.ANY),
|
||||||
|
mock.call(l3p['tenant_id'], "NAT-epg-%s" % es['id'],
|
||||||
|
"NAT-allow-%s" % es['id'], provider=True,
|
||||||
|
transaction=mock.ANY)])
|
||||||
|
expected_nat_epg_tenant = l3p['tenant_id']
|
||||||
|
self._check_call_list(expected_epg_calls,
|
||||||
|
mgr.ensure_epg_created.call_args_list)
|
||||||
|
self._check_call_list(expected_contract_calls,
|
||||||
|
mgr.set_contract_for_epg.call_args_list)
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
ctx._plugin_context = ctx
|
||||||
|
self.assertEqual((expected_nat_epg_tenant, "NAT-epg-%s" % es['id']),
|
||||||
|
self.driver._determine_nat_epg_for_es(ctx, es, l3p))
|
||||||
|
|
||||||
l2ps = [self.create_l2_policy(name='myl2p-%s' % x,
|
l2ps = [self.create_l2_policy(name='myl2p-%s' % x,
|
||||||
tenant_id=l3p['tenant_id'],
|
tenant_id=l3p['tenant_id'],
|
||||||
shared=shared_l3p,
|
shared=shared_l3p,
|
||||||
l3_policy_id=l3p['id'])['l2_policy']
|
l3_policy_id=l3p['id'])['l2_policy']
|
||||||
for x in range(0, 3)]
|
for x in range(0, 3)]
|
||||||
|
|
||||||
owner = self.common_tenant if shared_es else es['tenant_id']
|
|
||||||
l3p_owner = self.common_tenant if shared_l3p else l3p['tenant_id']
|
l3p_owner = self.common_tenant if shared_l3p else l3p['tenant_id']
|
||||||
mgr = self.driver.apic_manager
|
|
||||||
call_name = mgr.ensure_external_routed_network_created
|
call_name = mgr.ensure_external_routed_network_created
|
||||||
l3out_str = "Shd-%s-%s"
|
l3out_str = "Shd-%s-%s"
|
||||||
if is_edge_nat:
|
if is_edge_nat:
|
||||||
@ -2333,6 +2371,16 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
shared_l3p=False,
|
shared_l3p=False,
|
||||||
is_edge_nat=True)
|
is_edge_nat=True)
|
||||||
|
|
||||||
|
def test_l3p_plugged_to_es_at_creation_ptne_1(self):
|
||||||
|
self.driver.per_tenant_nat_epg = True
|
||||||
|
self._test_l3p_plugged_to_es_at_creation(shared_es=True,
|
||||||
|
shared_l3p=False)
|
||||||
|
|
||||||
|
def test_l3p_plugged_to_es_at_creation_ptne_2(self):
|
||||||
|
self.driver.per_tenant_nat_epg = True
|
||||||
|
self._test_l3p_plugged_to_es_at_creation(shared_es=True,
|
||||||
|
shared_l3p=True)
|
||||||
|
|
||||||
def _test_l3p_plugged_to_es_at_update(self, shared_es,
|
def _test_l3p_plugged_to_es_at_update(self, shared_es,
|
||||||
shared_l3p, is_edge_nat=False):
|
shared_l3p, is_edge_nat=False):
|
||||||
# Verify L3P is correctly plugged to ES on APIC during update
|
# Verify L3P is correctly plugged to ES on APIC during update
|
||||||
@ -2357,6 +2405,10 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
l3_policy_id=l3p['id'])['l2_policy']
|
l3_policy_id=l3p['id'])['l2_policy']
|
||||||
for x in range(0, 3)]
|
for x in range(0, 3)]
|
||||||
|
|
||||||
|
mgr = self.driver.apic_manager
|
||||||
|
mgr.ensure_epg_created.reset_mock()
|
||||||
|
mgr.set_contract_for_epg.reset_mock()
|
||||||
|
|
||||||
# update L3P with ES
|
# update L3P with ES
|
||||||
l3p = self.update_l3_policy(l3p['id'], tenant_id=l3p['tenant_id'],
|
l3p = self.update_l3_policy(l3p['id'], tenant_id=l3p['tenant_id'],
|
||||||
external_segments={es['id']: []},
|
external_segments={es['id']: []},
|
||||||
@ -2364,7 +2416,6 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
self.assertEqual(1, len(l3p['external_segments'][es['id']]))
|
self.assertEqual(1, len(l3p['external_segments'][es['id']]))
|
||||||
self.assertEqual('169.254.0.2', l3p['external_segments'][es['id']][0])
|
self.assertEqual('169.254.0.2', l3p['external_segments'][es['id']][0])
|
||||||
|
|
||||||
mgr = self.driver.apic_manager
|
|
||||||
owner = self.common_tenant if shared_es else es['tenant_id']
|
owner = self.common_tenant if shared_es else es['tenant_id']
|
||||||
l3p_owner = self.common_tenant if shared_l3p else l3p['tenant_id']
|
l3p_owner = self.common_tenant if shared_l3p else l3p['tenant_id']
|
||||||
l3out_str = "Shd-%s-%s"
|
l3out_str = "Shd-%s-%s"
|
||||||
@ -2475,6 +2526,30 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
self._check_call_list(expected_set_l3out_for_bd_calls,
|
self._check_call_list(expected_set_l3out_for_bd_calls,
|
||||||
mgr.set_l3out_for_bd.call_args_list)
|
mgr.set_l3out_for_bd.call_args_list)
|
||||||
|
|
||||||
|
expected_epg_calls = []
|
||||||
|
expected_contract_calls = []
|
||||||
|
expected_nat_epg_tenant = owner
|
||||||
|
if self.nat_enabled and shared_es and self.driver.per_tenant_nat_epg:
|
||||||
|
expected_epg_calls.append(
|
||||||
|
mock.call(l3p['tenant_id'], "NAT-epg-%s" % es['id'],
|
||||||
|
bd_name="NAT-bd-%s" % es['id'], bd_owner=owner,
|
||||||
|
transaction=mock.ANY))
|
||||||
|
expected_contract_calls.extend([
|
||||||
|
mock.call(l3p['tenant_id'], "NAT-epg-%s" % es['id'],
|
||||||
|
"NAT-allow-%s" % es['id'], transaction=mock.ANY),
|
||||||
|
mock.call(l3p['tenant_id'], "NAT-epg-%s" % es['id'],
|
||||||
|
"NAT-allow-%s" % es['id'], provider=True,
|
||||||
|
transaction=mock.ANY)])
|
||||||
|
expected_nat_epg_tenant = l3p['tenant_id']
|
||||||
|
self._check_call_list(expected_epg_calls,
|
||||||
|
mgr.ensure_epg_created.call_args_list)
|
||||||
|
self._check_call_list(expected_contract_calls,
|
||||||
|
mgr.set_contract_for_epg.call_args_list)
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
ctx._plugin_context = ctx
|
||||||
|
self.assertEqual((expected_nat_epg_tenant, "NAT-epg-%s" % es['id']),
|
||||||
|
self.driver._determine_nat_epg_for_es(ctx, es, l3p))
|
||||||
|
|
||||||
# Although the naming convention used here has been chosen poorly,
|
# Although the naming convention used here has been chosen poorly,
|
||||||
# I'm separating the tests in order to get the mock re-set.
|
# I'm separating the tests in order to get the mock re-set.
|
||||||
def test_l3p_plugged_to_es_at_update_1(self):
|
def test_l3p_plugged_to_es_at_update_1(self):
|
||||||
@ -2504,6 +2579,16 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
shared_l3p=False,
|
shared_l3p=False,
|
||||||
is_edge_nat=True)
|
is_edge_nat=True)
|
||||||
|
|
||||||
|
def test_l3p_plugged_to_es_at_update_ptne_1(self):
|
||||||
|
self.driver.per_tenant_nat_epg = True
|
||||||
|
self._test_l3p_plugged_to_es_at_update(shared_es=True,
|
||||||
|
shared_l3p=False)
|
||||||
|
|
||||||
|
def test_l3p_plugged_to_es_at_update_ptne_2(self):
|
||||||
|
self.driver.per_tenant_nat_epg = True
|
||||||
|
self._test_l3p_plugged_to_es_at_update(shared_es=True,
|
||||||
|
shared_l3p=True)
|
||||||
|
|
||||||
def _test_l3p_unplugged_from_es_on_delete(self, shared_es,
|
def _test_l3p_unplugged_from_es_on_delete(self, shared_es,
|
||||||
shared_l3p, is_edge_nat=False):
|
shared_l3p, is_edge_nat=False):
|
||||||
self._mock_external_dict([('supported1', '192.168.0.2/24'),
|
self._mock_external_dict([('supported1', '192.168.0.2/24'),
|
||||||
@ -2564,6 +2649,18 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
mgr.unset_l3out_for_bd.reset_mock()
|
mgr.unset_l3out_for_bd.reset_mock()
|
||||||
self.driver.l3out_vlan_alloc.release_vlan.reset_mock()
|
self.driver.l3out_vlan_alloc.release_vlan.reset_mock()
|
||||||
|
|
||||||
|
expected_epg_calls = []
|
||||||
|
if self.nat_enabled and shared_es and self.driver.per_tenant_nat_epg:
|
||||||
|
expected_epg_calls.append(
|
||||||
|
mock.call(l3p['tenant_id'], "NAT-epg-%s" % es1['id'],
|
||||||
|
transaction=mock.ANY))
|
||||||
|
self._check_call_list(expected_epg_calls,
|
||||||
|
mgr.delete_epg_for_network.call_args_list)
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
ctx._plugin_context = ctx
|
||||||
|
self.assertEqual((owner, "NAT-epg-%s" % es1['id']),
|
||||||
|
self.driver._determine_nat_epg_for_es(ctx, es1, l3p))
|
||||||
|
|
||||||
# Verify correct deletion for 2 ESs
|
# Verify correct deletion for 2 ESs
|
||||||
l3p = self.create_l3_policy(
|
l3p = self.create_l3_policy(
|
||||||
shared=shared_l3p,
|
shared=shared_l3p,
|
||||||
@ -2572,6 +2669,7 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
es2['id']: ['169.254.0.3']},
|
es2['id']: ['169.254.0.3']},
|
||||||
expected_res_status=201)['l3_policy']
|
expected_res_status=201)['l3_policy']
|
||||||
mgr.set_context_for_external_routed_network.reset_mock()
|
mgr.set_context_for_external_routed_network.reset_mock()
|
||||||
|
mgr.delete_epg_for_network.reset_mock()
|
||||||
req = self.new_delete_request('l3_policies', l3p['id'], self.fmt)
|
req = self.new_delete_request('l3_policies', l3p['id'], self.fmt)
|
||||||
res = req.get_response(self.ext_api)
|
res = req.get_response(self.ext_api)
|
||||||
self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
|
self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
|
||||||
@ -2620,6 +2718,15 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
expected_release_vlan_calls,
|
expected_release_vlan_calls,
|
||||||
self.driver.l3out_vlan_alloc.release_vlan.call_args_list)
|
self.driver.l3out_vlan_alloc.release_vlan.call_args_list)
|
||||||
|
|
||||||
|
if self.nat_enabled and shared_es and self.driver.per_tenant_nat_epg:
|
||||||
|
expected_epg_calls.append(
|
||||||
|
mock.call(l3p['tenant_id'], "NAT-epg-%s" % es2['id'],
|
||||||
|
transaction=mock.ANY))
|
||||||
|
self._check_call_list(expected_epg_calls,
|
||||||
|
mgr.delete_epg_for_network.call_args_list)
|
||||||
|
self.assertEqual((owner, "NAT-epg-%s" % es2['id']),
|
||||||
|
self.driver._determine_nat_epg_for_es(ctx, es2, l3p))
|
||||||
|
|
||||||
# Although the naming convention used here has been chosen poorly,
|
# Although the naming convention used here has been chosen poorly,
|
||||||
# I'm separating the tests in order to get the mock re-set.
|
# I'm separating the tests in order to get the mock re-set.
|
||||||
def test_l3p_unplugged_from_es_on_delete_1(self):
|
def test_l3p_unplugged_from_es_on_delete_1(self):
|
||||||
@ -2649,6 +2756,16 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
shared_l3p=False,
|
shared_l3p=False,
|
||||||
is_edge_nat=True)
|
is_edge_nat=True)
|
||||||
|
|
||||||
|
def test_l3p_unplugged_from_es_on_delete_ptne_1(self):
|
||||||
|
self.per_tenant_nat_epg = True
|
||||||
|
self._test_l3p_unplugged_from_es_on_delete(shared_es=True,
|
||||||
|
shared_l3p=False)
|
||||||
|
|
||||||
|
def test_l3p_unplugged_from_es_on_delete_ptne_2(self):
|
||||||
|
self.per_tenant_nat_epg = True
|
||||||
|
self._test_l3p_unplugged_from_es_on_delete(shared_es=True,
|
||||||
|
shared_l3p=True)
|
||||||
|
|
||||||
def _test_l3p_unplugged_from_es_on_update(self, shared_es,
|
def _test_l3p_unplugged_from_es_on_update(self, shared_es,
|
||||||
shared_l3p, is_edge_nat=False):
|
shared_l3p, is_edge_nat=False):
|
||||||
self._mock_external_dict([('supported1', '192.168.0.2/24'),
|
self._mock_external_dict([('supported1', '192.168.0.2/24'),
|
||||||
@ -2818,6 +2935,18 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
self._check_call_list(expected_set_l3out_for_bd_calls,
|
self._check_call_list(expected_set_l3out_for_bd_calls,
|
||||||
mgr.set_l3out_for_bd.call_args_list)
|
mgr.set_l3out_for_bd.call_args_list)
|
||||||
|
|
||||||
|
expected_epg_calls = []
|
||||||
|
if self.nat_enabled and shared_es and self.driver.per_tenant_nat_epg:
|
||||||
|
expected_epg_calls.append(
|
||||||
|
mock.call(l3p['tenant_id'], "NAT-epg-%s" % es1['id'],
|
||||||
|
transaction=mock.ANY))
|
||||||
|
self._check_call_list(expected_epg_calls,
|
||||||
|
mgr.delete_epg_for_network.call_args_list)
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
ctx._plugin_context = ctx
|
||||||
|
self.assertEqual((owner, "NAT-epg-%s" % es1['id']),
|
||||||
|
self.driver._determine_nat_epg_for_es(ctx, es1, l3p))
|
||||||
|
|
||||||
self.driver.l3out_vlan_alloc.release_vlan.reset_mock()
|
self.driver.l3out_vlan_alloc.release_vlan.reset_mock()
|
||||||
mgr.delete_external_routed_network.reset_mock()
|
mgr.delete_external_routed_network.reset_mock()
|
||||||
mgr.unset_l3out_for_bd.reset_mock()
|
mgr.unset_l3out_for_bd.reset_mock()
|
||||||
@ -2826,6 +2955,7 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
external_segments={es1['id']: ['169.254.0.5'],
|
external_segments={es1['id']: ['169.254.0.5'],
|
||||||
es2['id']: ['169.254.0.6']})
|
es2['id']: ['169.254.0.6']})
|
||||||
mgr.set_context_for_external_routed_network.reset_mock()
|
mgr.set_context_for_external_routed_network.reset_mock()
|
||||||
|
mgr.delete_epg_for_network.reset_mock()
|
||||||
self.update_l3_policy(
|
self.update_l3_policy(
|
||||||
l3p['id'], tenant_id=l3p['tenant_id'],
|
l3p['id'], tenant_id=l3p['tenant_id'],
|
||||||
expected_res_status=200, external_segments={})
|
expected_res_status=200, external_segments={})
|
||||||
@ -2891,6 +3021,15 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
expected_release_vlan_calls,
|
expected_release_vlan_calls,
|
||||||
self.driver.l3out_vlan_alloc.release_vlan.call_args_list)
|
self.driver.l3out_vlan_alloc.release_vlan.call_args_list)
|
||||||
|
|
||||||
|
if self.nat_enabled and shared_es and self.driver.per_tenant_nat_epg:
|
||||||
|
expected_epg_calls.append(
|
||||||
|
mock.call(l3p['tenant_id'], "NAT-epg-%s" % es2['id'],
|
||||||
|
transaction=mock.ANY))
|
||||||
|
self._check_call_list(expected_epg_calls,
|
||||||
|
mgr.delete_epg_for_network.call_args_list)
|
||||||
|
self.assertEqual((owner, "NAT-epg-%s" % es2['id']),
|
||||||
|
self.driver._determine_nat_epg_for_es(ctx, es2, l3p))
|
||||||
|
|
||||||
# Although the naming convention used here has been chosen poorly,
|
# Although the naming convention used here has been chosen poorly,
|
||||||
# I'm separating the tests in order to get the mock re-set.
|
# I'm separating the tests in order to get the mock re-set.
|
||||||
def test_l3p_unplugged_from_es_on_update_1(self):
|
def test_l3p_unplugged_from_es_on_update_1(self):
|
||||||
@ -2920,6 +3059,16 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
shared_l3p=False,
|
shared_l3p=False,
|
||||||
is_edge_nat=True)
|
is_edge_nat=True)
|
||||||
|
|
||||||
|
def test_l3p_unplugged_from_es_on_update_ptne_1(self):
|
||||||
|
self.driver.per_tenant_nat_epg = True
|
||||||
|
self._test_l3p_unplugged_from_es_on_update(shared_es=True,
|
||||||
|
shared_l3p=False)
|
||||||
|
|
||||||
|
def test_l3p_unplugged_from_es_on_update_ptne_2(self):
|
||||||
|
self.driver.per_tenant_nat_epg = True
|
||||||
|
self._test_l3p_unplugged_from_es_on_update(shared_es=True,
|
||||||
|
shared_l3p=True)
|
||||||
|
|
||||||
def test_verify_unsupported_es_noop(self):
|
def test_verify_unsupported_es_noop(self):
|
||||||
# Verify L3P is correctly plugged to ES on APIC during update
|
# Verify L3P is correctly plugged to ES on APIC during update
|
||||||
self._mock_external_dict([('supported', '192.168.0.2/24')])
|
self._mock_external_dict([('supported', '192.168.0.2/24')])
|
||||||
@ -2989,6 +3138,107 @@ class TestL3Policy(ApicMappingTestCase):
|
|||||||
def test_multi_es_with_ptg_2(self):
|
def test_multi_es_with_ptg_2(self):
|
||||||
self._test_multi_es_with_ptg(True)
|
self._test_multi_es_with_ptg(True)
|
||||||
|
|
||||||
|
def test_multi_l3p_ptne(self):
|
||||||
|
self.driver.per_tenant_nat_epg = True
|
||||||
|
|
||||||
|
self._mock_external_dict([('supported', '192.168.0.2/24')])
|
||||||
|
es = self.create_external_segment(
|
||||||
|
name='supported', shared=True)['external_segment']
|
||||||
|
|
||||||
|
mgr = self.driver.apic_manager
|
||||||
|
mgr.ensure_epg_created.reset_mock()
|
||||||
|
|
||||||
|
l3ps = []
|
||||||
|
for x in range(0, 3 if self.nat_enabled else 1):
|
||||||
|
l3ps.append(self.create_l3_policy(
|
||||||
|
name='myl3p-%s' % x, tenant_id='another_tenant',
|
||||||
|
external_segments={es['id']: []},
|
||||||
|
expected_res_status=201)['l3_policy'])
|
||||||
|
if self.nat_enabled:
|
||||||
|
mgr.ensure_epg_created.assert_called_once_with(
|
||||||
|
'another_tenant', "NAT-epg-%s" % es['id'],
|
||||||
|
bd_name="NAT-bd-%s" % es['id'],
|
||||||
|
bd_owner=self.common_tenant, transaction=mock.ANY)
|
||||||
|
else:
|
||||||
|
mgr.ensure_epg_created.assert_not_called()
|
||||||
|
|
||||||
|
for l3p in l3ps[:-1]:
|
||||||
|
self.delete_l3_policy(l3p['id'], tenant_id=l3p['tenant_id'])
|
||||||
|
mgr.delete_epg_for_network.assert_not_called()
|
||||||
|
self.delete_l3_policy(l3ps[-1]['id'], tenant_id=l3ps[-1]['tenant_id'])
|
||||||
|
if self.nat_enabled:
|
||||||
|
mgr.delete_epg_for_network.assert_called_once_with(
|
||||||
|
'another_tenant', "NAT-epg-%s" % es['id'],
|
||||||
|
transaction=mock.ANY)
|
||||||
|
else:
|
||||||
|
mgr.delete_epg_for_network.assert_not_called()
|
||||||
|
|
||||||
|
def test_ptne_upgrade(self):
|
||||||
|
# Simulate "upgrade" - tenants existing before upgrade should
|
||||||
|
# continue using non-specific NAT EPG where as new ones use
|
||||||
|
# specific NAT EPGs
|
||||||
|
self._mock_external_dict([('supported', '192.168.0.2/24')])
|
||||||
|
es = self.create_external_segment(
|
||||||
|
name='supported', shared=True)['external_segment']
|
||||||
|
|
||||||
|
mgr = self.driver.apic_manager
|
||||||
|
mgr.ensure_epg_created.reset_mock()
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
ctx._plugin_context = ctx
|
||||||
|
|
||||||
|
l3p_a_1 = self.create_l3_policy(
|
||||||
|
name='myl3p-a-1', tenant_id='tenant_a',
|
||||||
|
external_segments={es['id']: []})['l3_policy']
|
||||||
|
mgr.ensure_epg_created.assert_not_called()
|
||||||
|
self.assertEqual((self.common_tenant, "NAT-epg-%s" % es['id']),
|
||||||
|
self.driver._determine_nat_epg_for_es(ctx, es, l3p_a_1))
|
||||||
|
|
||||||
|
# "Upgrade" and change to per-tenant NAT EPG
|
||||||
|
self.driver.per_tenant_nat_epg = True
|
||||||
|
|
||||||
|
if self.nat_enabled:
|
||||||
|
l3p_a_2 = self.create_l3_policy(
|
||||||
|
name='myl3p-a-2', tenant_id='tenant_a',
|
||||||
|
external_segments={es['id']: []})['l3_policy']
|
||||||
|
mgr.ensure_epg_created.assert_not_called()
|
||||||
|
self.assertEqual((self.common_tenant, "NAT-epg-%s" % es['id']),
|
||||||
|
self.driver._determine_nat_epg_for_es(ctx, es, l3p_a_2))
|
||||||
|
self.delete_l3_policy(l3p_a_2['id'],
|
||||||
|
tenant_id=l3p_a_2['tenant_id'])
|
||||||
|
|
||||||
|
self.assertEqual((self.common_tenant, "NAT-epg-%s" % es['id']),
|
||||||
|
self.driver._determine_nat_epg_for_es(ctx, es, l3p_a_1))
|
||||||
|
self.delete_l3_policy(l3p_a_1['id'], tenant_id=l3p_a_1['tenant_id'])
|
||||||
|
mgr.delete_epg_for_network.assert_not_called()
|
||||||
|
|
||||||
|
l3p_a_3 = self.create_l3_policy(
|
||||||
|
name='myl3p-a-3', tenant_id='tenant_a',
|
||||||
|
external_segments={es['id']: []})['l3_policy']
|
||||||
|
if self.nat_enabled:
|
||||||
|
mgr.ensure_epg_created.assert_called_once_with(
|
||||||
|
'tenant_a', "NAT-epg-%s" % es['id'],
|
||||||
|
bd_name="NAT-bd-%s" % es['id'], bd_owner=self.common_tenant,
|
||||||
|
transaction=mock.ANY)
|
||||||
|
self.assertEqual(('tenant_a', "NAT-epg-%s" % es['id']),
|
||||||
|
self.driver._determine_nat_epg_for_es(ctx, es, l3p_a_3))
|
||||||
|
else:
|
||||||
|
mgr.ensure_epg_created.assert_not_called()
|
||||||
|
self.delete_l3_policy(l3p_a_3['id'], tenant_id=l3p_a_3['tenant_id'])
|
||||||
|
mgr.ensure_epg_created.reset_mock()
|
||||||
|
|
||||||
|
l3p_b_1 = self.create_l3_policy(
|
||||||
|
name='myl3p-b-1', tenant_id='tenant_b',
|
||||||
|
external_segments={es['id']: []})['l3_policy']
|
||||||
|
if self.nat_enabled:
|
||||||
|
mgr.ensure_epg_created.assert_called_once_with(
|
||||||
|
'tenant_b', "NAT-epg-%s" % es['id'],
|
||||||
|
bd_name="NAT-bd-%s" % es['id'], bd_owner=self.common_tenant,
|
||||||
|
transaction=mock.ANY)
|
||||||
|
self.assertEqual(('tenant_b', "NAT-epg-%s" % es['id']),
|
||||||
|
self.driver._determine_nat_epg_for_es(ctx, es, l3p_b_1))
|
||||||
|
else:
|
||||||
|
mgr.ensure_epg_created.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
class TestL3PolicyNoNat(TestL3Policy):
|
class TestL3PolicyNoNat(TestL3Policy):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
@ -3903,7 +4153,7 @@ class TestExternalSegment(ApicMappingTestCase):
|
|||||||
self.assertEqual('169.254.0.2',
|
self.assertEqual('169.254.0.2',
|
||||||
l3p['external_segments'][es['id']][0])
|
l3p['external_segments'][es['id']][0])
|
||||||
|
|
||||||
def test_plug_l3p_to_es_with_multi_ep(self):
|
def _do_test_plug_l3p_to_es_with_multi_ep(self):
|
||||||
tenants = (['tenant_a', 'tenant_b', 'tenant_c']
|
tenants = (['tenant_a', 'tenant_b', 'tenant_c']
|
||||||
if self.nat_enabled else ['tenant_a'])
|
if self.nat_enabled else ['tenant_a'])
|
||||||
|
|
||||||
@ -3962,7 +4212,9 @@ class TestExternalSegment(ApicMappingTestCase):
|
|||||||
"Shd-%s-%s" % (l3p['id'], es['id']),
|
"Shd-%s-%s" % (l3p['id'], es['id']),
|
||||||
"Shd-%s-%s" % (l3p['id'], ep['id']),
|
"Shd-%s-%s" % (l3p['id'], ep['id']),
|
||||||
"NAT-epg-%s" % es['id'],
|
"NAT-epg-%s" % es['id'],
|
||||||
target_owner=self.common_tenant,
|
target_owner=(l3p['tenant_id']
|
||||||
|
if self.driver.per_tenant_nat_epg
|
||||||
|
else self.common_tenant),
|
||||||
transaction=mock.ANY))
|
transaction=mock.ANY))
|
||||||
l3out = es['name' if self.pre_l3out else 'id']
|
l3out = es['name' if self.pre_l3out else 'id']
|
||||||
l3out_owner = (APIC_PRE_L3OUT_TENANT
|
l3out_owner = (APIC_PRE_L3OUT_TENANT
|
||||||
@ -3988,6 +4240,13 @@ class TestExternalSegment(ApicMappingTestCase):
|
|||||||
self._check_call_list(expected_contract_calls,
|
self._check_call_list(expected_contract_calls,
|
||||||
mgr.set_contract_for_external_epg.call_args_list)
|
mgr.set_contract_for_external_epg.call_args_list)
|
||||||
|
|
||||||
|
def test_plug_l3p_to_es_with_multi_ep(self):
|
||||||
|
self._do_test_plug_l3p_to_es_with_multi_ep()
|
||||||
|
|
||||||
|
def test_plug_l3p_to_es_with_multi_ep_ptne(self):
|
||||||
|
self.driver.per_tenant_nat_epg = True
|
||||||
|
self._do_test_plug_l3p_to_es_with_multi_ep()
|
||||||
|
|
||||||
|
|
||||||
class TestExternalSegmentNoNat(TestExternalSegment):
|
class TestExternalSegmentNoNat(TestExternalSegment):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user