Merge "[apic-mapping] Explicit end of the chain for ptgs"
This commit is contained in:
@@ -51,7 +51,6 @@ from oslo_serialization import jsonutils
|
|||||||
import sqlalchemy as sa
|
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 group_policy as gpolicy
|
from gbpservice.neutron.extensions import group_policy as gpolicy
|
||||||
from gbpservice.neutron.services.grouppolicy.common import constants as g_const
|
from gbpservice.neutron.services.grouppolicy.common import constants as g_const
|
||||||
from gbpservice.neutron.services.grouppolicy.common import exceptions as gpexc
|
from gbpservice.neutron.services.grouppolicy.common import exceptions as gpexc
|
||||||
@@ -199,6 +198,10 @@ class ExplicitPortOverlap(gpexc.GroupPolicyBadRequest):
|
|||||||
'in network %(net)s')
|
'in network %(net)s')
|
||||||
|
|
||||||
|
|
||||||
|
class AdminOnlyOperation(gpexc.GroupPolicyBadRequest):
|
||||||
|
message = _("This operation is reserved to admins")
|
||||||
|
|
||||||
|
|
||||||
class TenantSpecificNatEpg(model_base.BASEV2):
|
class TenantSpecificNatEpg(model_base.BASEV2):
|
||||||
"""Tenants that use a specific NAT EPG for an external segment."""
|
"""Tenants that use a specific NAT EPG for an external segment."""
|
||||||
__tablename__ = 'gp_apic_tenant_specific_nat_epg'
|
__tablename__ = 'gp_apic_tenant_specific_nat_epg'
|
||||||
@@ -208,6 +211,7 @@ class TenantSpecificNatEpg(model_base.BASEV2):
|
|||||||
primary_key=True)
|
primary_key=True)
|
||||||
tenant_id = sa.Column(sa.String(36), 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-'
|
||||||
@@ -224,6 +228,7 @@ REVERTIBLE_PROTOCOLS = [n_constants.PROTO_NAME_TCP.lower(),
|
|||||||
n_constants.PROTO_NAME_UDP.lower(),
|
n_constants.PROTO_NAME_UDP.lower(),
|
||||||
n_constants.PROTO_NAME_ICMP.lower()]
|
n_constants.PROTO_NAME_ICMP.lower()]
|
||||||
PROXY_PORT_PREFIX = "opflex_proxy:"
|
PROXY_PORT_PREFIX = "opflex_proxy:"
|
||||||
|
EOC_PREFIX = "opflex_eoc:"
|
||||||
ICMP_REPLY_TYPES = ['echo-rep', 'dst-unreach', 'src-quench', 'time-exceeded']
|
ICMP_REPLY_TYPES = ['echo-rep', 'dst-unreach', 'src-quench', 'time-exceeded']
|
||||||
|
|
||||||
|
|
||||||
@@ -430,22 +435,36 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
owned=own_addr, inject_default_route=
|
owned=own_addr, inject_default_route=
|
||||||
l2p['inject_default_route'])
|
l2p['inject_default_route'])
|
||||||
self._add_vrf_details(context, details)
|
self._add_vrf_details(context, details)
|
||||||
if self._is_pt_chain_head(context, pt, ptg, owned_ips=own_addr):
|
if self._is_pt_chain_head(context, pt, ptg, owned_ips=own_addr,
|
||||||
|
port_id=port_id):
|
||||||
# is a relevant proxy_gateway, push all the addresses from this
|
# is a relevant proxy_gateway, push all the addresses from this
|
||||||
# chain to this PT
|
# chain to this PT
|
||||||
extra_map = details
|
extra_map = details
|
||||||
master_mac = self._is_master_owner(context, pt,
|
master_port = self._is_master_owner(context, pt,
|
||||||
owned_ips=own_addr)
|
owned_ips=own_addr)
|
||||||
if master_mac:
|
if master_port:
|
||||||
extra_map = details['extra_details'].setdefault(
|
extra_map = details['extra_details'].setdefault(
|
||||||
master_mac, {'extra_ips': [], 'floating_ip': [],
|
master_port['mac_address'],
|
||||||
'ip_mapping': [], 'host_snat_ips': []})
|
{'extra_ips': [], 'floating_ip': [],
|
||||||
if bool(master_mac) == bool(pt['cluster_id']):
|
'ip_mapping': [], 'host_snat_ips': []})
|
||||||
|
if bool(master_port) == bool(pt['cluster_id']):
|
||||||
l3_policy = context._plugin.get_l3_policy(
|
l3_policy = context._plugin.get_l3_policy(
|
||||||
context, l2p['l3_policy_id'])
|
context, l2p['l3_policy_id'])
|
||||||
while ptg['proxied_group_id']:
|
proxied_ptgs = []
|
||||||
|
while ptg.get('proxied_group_id'):
|
||||||
proxied = self.gbp_plugin.get_policy_target_group(
|
proxied = self.gbp_plugin.get_policy_target_group(
|
||||||
context, ptg['proxied_group_id'])
|
context, ptg['proxied_group_id'])
|
||||||
|
proxied_ptgs.append(proxied)
|
||||||
|
ptg = proxied
|
||||||
|
# Retrieve PTGs explicitly proxied
|
||||||
|
descriptions = [EOC_PREFIX + port_id]
|
||||||
|
if master_port:
|
||||||
|
# Also retrieve groups proxied by master of the cluster
|
||||||
|
descriptions.append(EOC_PREFIX + master_port['id'])
|
||||||
|
proxied_ptgs.extend(
|
||||||
|
self._get_policy_target_groups(
|
||||||
|
context, filters={'description': descriptions}))
|
||||||
|
for proxied in proxied_ptgs:
|
||||||
for port in self._get_ptg_ports(proxied):
|
for port in self._get_ptg_ports(proxied):
|
||||||
extra_map['extra_ips'].extend(
|
extra_map['extra_ips'].extend(
|
||||||
[x['ip_address'] for x in port['fixed_ips'] +
|
[x['ip_address'] for x in port['fixed_ips'] +
|
||||||
@@ -460,7 +479,6 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
if not extra_map['host_snat_ips']:
|
if not extra_map['host_snat_ips']:
|
||||||
extra_map['host_snat_ips'].extend(
|
extra_map['host_snat_ips'].extend(
|
||||||
host_snat_ips)
|
host_snat_ips)
|
||||||
ptg = proxied
|
|
||||||
else:
|
else:
|
||||||
LOG.info(_LI("Active master has changed for PT %s"),
|
LOG.info(_LI("Active master has changed for PT %s"),
|
||||||
pt['id'])
|
pt['id'])
|
||||||
@@ -858,6 +876,10 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
context._plugin_context, context.current['id'])
|
context._plugin_context, context.current['id'])
|
||||||
db_group.l2_policy_id = proxied['l2_policy_id']
|
db_group.l2_policy_id = proxied['l2_policy_id']
|
||||||
context.current['l2_policy_id'] = proxied['l2_policy_id']
|
context.current['l2_policy_id'] = proxied['l2_policy_id']
|
||||||
|
if context.current['description']:
|
||||||
|
if (EOC_PREFIX in context.current['description']
|
||||||
|
and not context._plugin_context.is_admin):
|
||||||
|
raise AdminOnlyOperation()
|
||||||
else:
|
else:
|
||||||
self.name_mapper.has_valid_name(context.current)
|
self.name_mapper.has_valid_name(context.current)
|
||||||
|
|
||||||
@@ -1192,6 +1214,11 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
context.current['subnets']):
|
context.current['subnets']):
|
||||||
raise ExplicitSubnetAssociationNotSupported()
|
raise ExplicitSubnetAssociationNotSupported()
|
||||||
self._reject_shared_update(context, 'policy_target_group')
|
self._reject_shared_update(context, 'policy_target_group')
|
||||||
|
if (context.current['description'] !=
|
||||||
|
context.original['description']):
|
||||||
|
if (EOC_PREFIX in context.current['description']
|
||||||
|
and not context._plugin_context.is_admin):
|
||||||
|
raise AdminOnlyOperation()
|
||||||
|
|
||||||
def update_policy_target_group_postcommit(self, context):
|
def update_policy_target_group_postcommit(self, context):
|
||||||
if not self.name_mapper._is_apic_reference(context.current):
|
if not self.name_mapper._is_apic_reference(context.current):
|
||||||
@@ -2420,13 +2447,15 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
object):
|
object):
|
||||||
return apic_manager.TENANT_COMMON
|
return apic_manager.TENANT_COMMON
|
||||||
else:
|
else:
|
||||||
if object.get('proxied_group_id'): # Then it's a proxy PTG
|
if object.get('proxied_group_id') or object.get(
|
||||||
# Even though they may belong to a different tenant,
|
'enforce_service_chains') is False:
|
||||||
|
# Then it's a proxy
|
||||||
|
# PTG Even though they may belong to a different tenant,
|
||||||
# the proxy PTGs will be created on the L2P's tenant to
|
# the proxy PTGs will be created on the L2P's tenant to
|
||||||
# make APIC happy
|
# make APIC happy
|
||||||
l2p = self.gbp_plugin.get_l2_policy(
|
l2p = self.gbp_plugin.get_l2_policy(
|
||||||
nctx.get_admin_context(), object['l2_policy_id'])
|
nctx.get_admin_context(), object['l2_policy_id'])
|
||||||
return self.name_mapper.tenant(l2p)
|
return self._tenant_by_sharing_policy(l2p)
|
||||||
else:
|
else:
|
||||||
return self.name_mapper.tenant(object)
|
return self.name_mapper.tenant(object)
|
||||||
|
|
||||||
@@ -2545,12 +2574,11 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
bd_name = self.name_mapper.policy_target_group(
|
bd_name = self.name_mapper.policy_target_group(
|
||||||
context, proxied, prefix=SHADOW_PREFIX)
|
context, proxied, prefix=SHADOW_PREFIX)
|
||||||
ptg_name = self.name_mapper.policy_target_group(context, proxied)
|
ptg_name = self.name_mapper.policy_target_group(context, proxied)
|
||||||
is_l2 = context.current['proxy_type'] == proxy_group.PROXY_TYPE_L2
|
|
||||||
with self.apic_manager.apic.transaction(None) as trs:
|
with self.apic_manager.apic.transaction(None) as trs:
|
||||||
# Create shadow BD to host the proxied EPG
|
# Create shadow BD to host the proxied EPG
|
||||||
self.apic_manager.ensure_bd_created_on_apic(
|
self.apic_manager.ensure_bd_created_on_apic(
|
||||||
tenant, bd_name, ctx_owner=ctx_owner, ctx_name=l3_policy_name,
|
tenant, bd_name, ctx_owner=ctx_owner, ctx_name=l3_policy_name,
|
||||||
allow_broadcast=is_l2, unicast_route=False, transaction=trs,
|
allow_broadcast=True, unicast_route=False, transaction=trs,
|
||||||
enforce_subnet_check=False)
|
enforce_subnet_check=False)
|
||||||
# Move current PTG to different BD
|
# Move current PTG to different BD
|
||||||
self.apic_manager.ensure_epg_created(
|
self.apic_manager.ensure_epg_created(
|
||||||
@@ -3175,6 +3203,17 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
def _notify_head_chain_ports(self, ptg_id):
|
def _notify_head_chain_ports(self, ptg_id):
|
||||||
context = nctx.get_admin_context()
|
context = nctx.get_admin_context()
|
||||||
ptg = self.gbp_plugin.get_policy_target_group(context, ptg_id)
|
ptg = self.gbp_plugin.get_policy_target_group(context, ptg_id)
|
||||||
|
explicit_eoc_id = self._extract_ptg_explicit_eoc(context, ptg)
|
||||||
|
if explicit_eoc_id:
|
||||||
|
# Could be a cluster master
|
||||||
|
updates = [explicit_eoc_id]
|
||||||
|
eoc_pt = self._port_id_to_pt(context, explicit_eoc_id)
|
||||||
|
if eoc_pt:
|
||||||
|
updates.extend(
|
||||||
|
x['port_id'] for x in self.gbp_plugin.get_policy_targets(
|
||||||
|
context, {'cluster_id': [eoc_pt['id']]}))
|
||||||
|
for update in updates:
|
||||||
|
self._notify_port_update(context, update)
|
||||||
# to avoid useless double notification exit now if no proxy
|
# to avoid useless double notification exit now if no proxy
|
||||||
if not ptg.get('proxy_group_id'):
|
if not ptg.get('proxy_group_id'):
|
||||||
return
|
return
|
||||||
@@ -3281,33 +3320,48 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
return opt.lower() in ['true', 'yes', '1']
|
return opt.lower() in ['true', 'yes', '1']
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def _is_pt_chain_head(self, plugin_context, pt, ptg=None, owned_ips=None):
|
def _is_pt_chain_head(self, plugin_context, pt, ptg=None, owned_ips=None,
|
||||||
if pt:
|
port_id=None):
|
||||||
ptg = ptg or self._get_policy_target_group(
|
if not pt:
|
||||||
plugin_context, pt['policy_target_group_id'])
|
return False
|
||||||
# Check whenther PTG is the end of a chain
|
|
||||||
chain_end = bool(ptg.get('proxied_group_id') and
|
|
||||||
not ptg.get('proxy_group'))
|
|
||||||
if chain_end:
|
|
||||||
cluster_id = pt['cluster_id']
|
|
||||||
if cluster_id:
|
|
||||||
# The master PT must be a proxy gateway for this to be
|
|
||||||
# eligible as the chain head
|
|
||||||
master_pt = self._get_pt_cluster_master(plugin_context, pt)
|
|
||||||
|
|
||||||
# Verify whether this is the active PT
|
master_pt = None
|
||||||
return bool(master_pt['proxy_gateway'] and
|
if port_id or pt.get('cluster_id'):
|
||||||
self._is_master_owner(plugin_context, pt,
|
descr = []
|
||||||
master_pt=master_pt,
|
if port_id:
|
||||||
owned_ips=owned_ips))
|
descr.append(EOC_PREFIX + port_id)
|
||||||
# regular PT not part of a cluster, return if proxy gateway
|
if pt.get('cluster_id'):
|
||||||
return bool(pt['proxy_gateway'])
|
master_pt = self._get_pt_cluster_master(plugin_context, pt)
|
||||||
|
descr.append(EOC_PREFIX + master_pt['port_id'])
|
||||||
|
if bool(self._get_policy_target_groups(
|
||||||
|
plugin_context, filters={'description': descr})):
|
||||||
|
return True
|
||||||
|
|
||||||
|
ptg = ptg or self._get_policy_target_group(
|
||||||
|
plugin_context, pt['policy_target_group_id'])
|
||||||
|
# Check whether PTG is the end of a chain
|
||||||
|
chain_end = bool(ptg.get('proxied_group_id') and
|
||||||
|
not ptg.get('proxy_group'))
|
||||||
|
if chain_end:
|
||||||
|
cluster_id = pt['cluster_id']
|
||||||
|
if cluster_id:
|
||||||
|
# The master PT must be a proxy gateway for this to be
|
||||||
|
# eligible as the chain head
|
||||||
|
master_pt = master_pt or self._get_pt_cluster_master(
|
||||||
|
plugin_context, pt)
|
||||||
|
# Verify whether this is the active PT
|
||||||
|
return bool(master_pt['proxy_gateway'] and
|
||||||
|
self._is_master_owner(plugin_context, pt,
|
||||||
|
master_pt=master_pt,
|
||||||
|
owned_ips=owned_ips))
|
||||||
|
# regular PT not part of a cluster, return if proxy gateway
|
||||||
|
return bool(pt['proxy_gateway'])
|
||||||
|
|
||||||
def _is_master_owner(self, plugin_context, pt, master_pt=None,
|
def _is_master_owner(self, plugin_context, pt, master_pt=None,
|
||||||
owned_ips=None):
|
owned_ips=None):
|
||||||
"""Verifies if the port owns the master address.
|
"""Verifies if the port owns the master address.
|
||||||
|
|
||||||
Returns the master MAC address or False
|
Returns the master port address or False
|
||||||
"""
|
"""
|
||||||
if pt['cluster_id']:
|
if pt['cluster_id']:
|
||||||
master_pt = master_pt or self._get_pt_cluster_master(
|
master_pt = master_pt or self._get_pt_cluster_master(
|
||||||
@@ -3319,10 +3373,9 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
master_port = self._get_port(plugin_context, master_pt['port_id'])
|
master_port = self._get_port(plugin_context, master_pt['port_id'])
|
||||||
master_addresses = set([x['ip_address'] for x in
|
master_addresses = set([x['ip_address'] for x in
|
||||||
master_port['fixed_ips']])
|
master_port['fixed_ips']])
|
||||||
master_mac = master_port['mac_address']
|
|
||||||
if bool(owned_addresses & master_addresses):
|
if bool(owned_addresses & master_addresses):
|
||||||
return master_mac
|
return master_port
|
||||||
return False
|
return None
|
||||||
|
|
||||||
def _get_owned_addresses(self, plugin_context, port_id):
|
def _get_owned_addresses(self, plugin_context, port_id):
|
||||||
return set(self.ha_ip_handler.get_ha_ipaddresses_for_port(port_id))
|
return set(self.ha_ip_handler.get_ha_ipaddresses_for_port(port_id))
|
||||||
@@ -3807,3 +3860,13 @@ class ApicMappingDriver(api.ResourceMappingDriver,
|
|||||||
'for external segment %(es)s',
|
'for external segment %(es)s',
|
||||||
{'tenant': nat_epg_tenant, 'epg': nat_epg_name,
|
{'tenant': nat_epg_tenant, 'epg': nat_epg_name,
|
||||||
'es': es['id']})
|
'es': es['id']})
|
||||||
|
|
||||||
|
def _extract_ptg_explicit_eoc(self, plugin_context, ptg):
|
||||||
|
"""Extract PTG End of Chain
|
||||||
|
|
||||||
|
Given a PTG, retrieves the explicit End of the Chain from its
|
||||||
|
description and returns a Neutron port
|
||||||
|
:return: Neutron port or None
|
||||||
|
"""
|
||||||
|
if EOC_PREFIX in ptg.get('description', ''):
|
||||||
|
return ptg['description'][len(EOC_PREFIX):]
|
||||||
|
@@ -244,6 +244,13 @@ class ApicMappingTestCase(
|
|||||||
sys.modules["apicapi"] = self.saved_apicapi
|
sys.modules["apicapi"] = self.saved_apicapi
|
||||||
super(ApicMappingTestCase, self).tearDown()
|
super(ApicMappingTestCase, self).tearDown()
|
||||||
|
|
||||||
|
def _get_pts_addresses(self, pts):
|
||||||
|
addresses = []
|
||||||
|
for pt in pts:
|
||||||
|
port = self._get_object('ports', pt['port_id'], self.api)['port']
|
||||||
|
addresses.extend([x['ip_address'] for x in port['fixed_ips']])
|
||||||
|
return addresses
|
||||||
|
|
||||||
def _build_external_dict(self, name, cidr_exposed, is_edge_nat=False):
|
def _build_external_dict(self, name, cidr_exposed, is_edge_nat=False):
|
||||||
ext_info = {
|
ext_info = {
|
||||||
'enable_nat': 'True' if self.nat_enabled else 'False'
|
'enable_nat': 'True' if self.nat_enabled else 'False'
|
||||||
@@ -553,6 +560,24 @@ class TestPolicyTarget(ApicMappingTestCase):
|
|||||||
details['host_snat_ip'])
|
details['host_snat_ip'])
|
||||||
self.assertEqual(24, details['prefixlen'])
|
self.assertEqual(24, details['prefixlen'])
|
||||||
|
|
||||||
|
def test_get_gbp_details_extra_ips_explicit_eoc(self):
|
||||||
|
ptg = self.create_policy_target_group(
|
||||||
|
name="ptg1")['policy_target_group']
|
||||||
|
pt1 = self.create_policy_target(
|
||||||
|
policy_target_group_id=ptg['id'])['policy_target']
|
||||||
|
ptg2 = self.create_policy_target_group(
|
||||||
|
name="ptg2",
|
||||||
|
description='opflex_eoc:' + pt1['port_id'],
|
||||||
|
is_admin_context=True)['policy_target_group']
|
||||||
|
pt2 = self.create_policy_target(
|
||||||
|
policy_target_group_id=ptg2['id'])['policy_target']
|
||||||
|
mapping = self.driver.get_gbp_details(context.get_admin_context(),
|
||||||
|
device='tap%s' % pt1['port_id'], host='h2')
|
||||||
|
|
||||||
|
# Extra ip set for pt2
|
||||||
|
ips = self._get_pts_addresses([pt2])
|
||||||
|
self.assertEqual(set(ips), set(mapping['extra_ips']))
|
||||||
|
|
||||||
def test_snat_pool_subnet_deletion(self):
|
def test_snat_pool_subnet_deletion(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[
|
||||||
@@ -1100,6 +1125,55 @@ class TestPolicyTarget(ApicMappingTestCase):
|
|||||||
self.assertEqual('1.1.1.1', entries[0].ha_ip_address)
|
self.assertEqual('1.1.1.1', entries[0].ha_ip_address)
|
||||||
self.assertEqual('1.1.1.1', entries[1].ha_ip_address)
|
self.assertEqual('1.1.1.1', entries[1].ha_ip_address)
|
||||||
|
|
||||||
|
def test_explicit_end_of_chain(self):
|
||||||
|
self.driver._notify_port_update = mock.Mock()
|
||||||
|
ptg = self.create_policy_target_group(
|
||||||
|
name="ptg1")['policy_target_group']
|
||||||
|
pt1 = self.create_policy_target(
|
||||||
|
policy_target_group_id=ptg['id'])['policy_target']
|
||||||
|
ptg2 = self.create_policy_target_group(
|
||||||
|
name="ptg2",
|
||||||
|
description='opflex_eoc:' + pt1['port_id'],
|
||||||
|
is_admin_context=True)['policy_target_group']
|
||||||
|
self.create_policy_target(policy_target_group_id=ptg2['id'])
|
||||||
|
# pt1 notified
|
||||||
|
self.driver._notify_port_update.assert_called_once_with(
|
||||||
|
mock.ANY, pt1['port_id'])
|
||||||
|
|
||||||
|
def test_explicit_end_of_chain_cluster(self):
|
||||||
|
self.driver._notify_port_update = mock.Mock()
|
||||||
|
ptg = self.create_policy_target_group(
|
||||||
|
name="ptg1")['policy_target_group']
|
||||||
|
pt1 = self.create_policy_target(
|
||||||
|
policy_target_group_id=ptg['id'])['policy_target']
|
||||||
|
# Same cluster
|
||||||
|
pt2 = self.create_policy_target(
|
||||||
|
policy_target_group_id=ptg['id'],
|
||||||
|
cluster_id=pt1['id'])['policy_target']
|
||||||
|
pt3 = self.create_policy_target(
|
||||||
|
policy_target_group_id=ptg['id'],
|
||||||
|
cluster_id=pt1['id'])['policy_target']
|
||||||
|
ptg2 = self.create_policy_target_group(
|
||||||
|
name="ptg2",
|
||||||
|
description='opflex_eoc:' + pt1['port_id'],
|
||||||
|
is_admin_context=True)['policy_target_group']
|
||||||
|
self.create_policy_target(policy_target_group_id=ptg2['id'])
|
||||||
|
# pt1, 2 and 3 notified
|
||||||
|
expected_calls = [
|
||||||
|
mock.call(mock.ANY, pt1['port_id']),
|
||||||
|
mock.call(mock.ANY, pt2['port_id']),
|
||||||
|
mock.call(mock.ANY, pt3['port_id'])]
|
||||||
|
self._check_call_list(
|
||||||
|
expected_calls, self.driver._notify_port_update.call_args_list)
|
||||||
|
|
||||||
|
def test_explicit_eoc_raises(self):
|
||||||
|
ptg = self.create_policy_target_group(
|
||||||
|
name="ptg1")['policy_target_group']
|
||||||
|
self.create_policy_target_group(
|
||||||
|
name="ptg2", description='opflex_eoc:', expected_res_status=400)
|
||||||
|
self.update_policy_target_group(
|
||||||
|
ptg['id'], description='opflex_eoc:', expected_res_status=400)
|
||||||
|
|
||||||
|
|
||||||
class TestPolicyTargetVlanNetwork(ApicMappingVlanTestCase,
|
class TestPolicyTargetVlanNetwork(ApicMappingVlanTestCase,
|
||||||
TestPolicyTarget):
|
TestPolicyTarget):
|
||||||
|
@@ -809,13 +809,6 @@ class TestApicChains(ApicMappingStitchingPlumberGBPTestCase,
|
|||||||
|
|
||||||
class TestProxyGroup(ApicMappingStitchingPlumberGBPTestCase):
|
class TestProxyGroup(ApicMappingStitchingPlumberGBPTestCase):
|
||||||
|
|
||||||
def _get_pts_addresses(self, pts):
|
|
||||||
addresses = []
|
|
||||||
for pt in pts:
|
|
||||||
port = self._get_object('ports', pt['port_id'], self.api)['port']
|
|
||||||
addresses.extend([x['ip_address'] for x in port['fixed_ips']])
|
|
||||||
return addresses
|
|
||||||
|
|
||||||
def _proxy_tenant(self, ptg, admin_proxy):
|
def _proxy_tenant(self, ptg, admin_proxy):
|
||||||
return 'admin' if admin_proxy else ptg['tenant_id']
|
return 'admin' if admin_proxy else ptg['tenant_id']
|
||||||
|
|
||||||
@@ -926,7 +919,7 @@ class TestProxyGroup(ApicMappingStitchingPlumberGBPTestCase):
|
|||||||
# Shadow BD created
|
# Shadow BD created
|
||||||
self.mgr.ensure_bd_created_on_apic.assert_called_once_with(
|
self.mgr.ensure_bd_created_on_apic.assert_called_once_with(
|
||||||
ptg['tenant_id'], 'Shd-' + ptg['id'], ctx_owner=l3p['tenant_id'],
|
ptg['tenant_id'], 'Shd-' + ptg['id'], ctx_owner=l3p['tenant_id'],
|
||||||
ctx_name=l3p['id'], allow_broadcast=False, unicast_route=False,
|
ctx_name=l3p['id'], allow_broadcast=True, unicast_route=False,
|
||||||
transaction=mock.ANY, enforce_subnet_check=False)
|
transaction=mock.ANY, enforce_subnet_check=False)
|
||||||
# Proxied PTG moved
|
# Proxied PTG moved
|
||||||
expected_calls = [
|
expected_calls = [
|
||||||
@@ -1217,7 +1210,7 @@ class TestProxyGroup(ApicMappingStitchingPlumberGBPTestCase):
|
|||||||
# Shadow BD created in non-admin tenant
|
# Shadow BD created in non-admin tenant
|
||||||
self.mgr.ensure_bd_created_on_apic.assert_called_once_with(
|
self.mgr.ensure_bd_created_on_apic.assert_called_once_with(
|
||||||
'non-admin', 'Shd-' + ptg['id'], ctx_owner=l3p['tenant_id'],
|
'non-admin', 'Shd-' + ptg['id'], ctx_owner=l3p['tenant_id'],
|
||||||
ctx_name=l3p['id'], allow_broadcast=False, unicast_route=False,
|
ctx_name=l3p['id'], allow_broadcast=True, unicast_route=False,
|
||||||
transaction=mock.ANY, enforce_subnet_check=False)
|
transaction=mock.ANY, enforce_subnet_check=False)
|
||||||
# Proxied PTG moved
|
# Proxied PTG moved
|
||||||
expected_calls = [
|
expected_calls = [
|
||||||
|
Reference in New Issue
Block a user