Merge "Use subnetpools in resource mapping driver"

This commit is contained in:
Jenkins 2017-08-25 21:30:09 +00:00 committed by Gerrit Code Review
commit 45c7c2ee0c
6 changed files with 806 additions and 236 deletions

View File

@ -329,3 +329,23 @@ class IdenticalExternalRoute(GroupPolicyBadRequest):
message = _("External segments %(es1)s and %(es2)s cannot have "
"identical external route CIDR %(cidr)s if associated "
"with a common L3 policy.")
class NoValidAddressScope(GroupPolicyBadRequest):
message = _("No address scope was either provided, could be "
"determined, or could be created for a l3_policy.")
class NoAddressScopeForSubnetpool(GroupPolicyBadRequest):
message = _("Subnetpool does not have an associated address scope.")
class InconsistentAddressScopeSubnetpool(GroupPolicyBadRequest):
message = _("Subnetpool is not associated with the address "
"scope for a l3_policy.")
class IncorrectSubnetpoolUpdate(GroupPolicyBadRequest):
message = _("Subnetpool %(subnetpool_id)s cannot be disassociated "
"from L3 Policy %(l3p_id)s since it has allocated subnet(s) "
"associated with that L3 Policy")

View File

@ -11,7 +11,6 @@
# under the License.
import hashlib
import netaddr
import re
import six
@ -21,7 +20,6 @@ from aim import context as aim_context
from aim import utils as aim_utils
from neutron.agent.linux import dhcp
from neutron import context as n_context
from neutron.db import models_v2
from neutron import policy
from neutron_lib import constants as n_constants
from neutron_lib import exceptions as n_exc
@ -48,7 +46,6 @@ from gbpservice.neutron.services.grouppolicy.common import (
constants as gp_const)
from gbpservice.neutron.services.grouppolicy.common import constants as g_const
from gbpservice.neutron.services.grouppolicy.common import exceptions as exc
from gbpservice.neutron.services.grouppolicy.common import utils
from gbpservice.neutron.services.grouppolicy.drivers import (
neutron_resources as nrd)
from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import (
@ -65,7 +62,6 @@ REVERSE = 'Reverse'
FILTER_DIRECTIONS = {FORWARD: False, REVERSE: True}
FORWARD_FILTER_ENTRIES = 'Forward-FilterEntries'
REVERSE_FILTER_ENTRIES = 'Reverse-FilterEntries'
ADDR_SCOPE_KEYS = ['address_scope_v4_id', 'address_scope_v6_id']
AUTO_PTG_NAME_PREFIX = 'ptg-for-l2p-%s'
# Note that this prefix should not exceede 4 characters
AUTO_PTG_PREFIX = 'auto'
@ -124,25 +120,11 @@ opts = [
cfg.CONF.register_opts(opts, "aim_mapping")
class NoValidAddressScope(exc.GroupPolicyBadRequest):
message = _("No address scope was either provided, could be "
"determined, or could be created for a l3_policy.")
class InvalidVrfForDualStackAddressScopes(exc.GroupPolicyBadRequest):
message = _("User-specified address scopes for both address families, "
"(IPv4 and IPv6) must use the same ACI VRF.")
class InconsistentAddressScopeSubnetpool(exc.GroupPolicyBadRequest):
message = _("Subnetpool is not associated with the address "
"scope for a l3_policy.")
class NoAddressScopeForSubnetpool(exc.GroupPolicyBadRequest):
message = _("Subnetpool does not have an associated address scope.")
class AutoPTGDeleteNotSupported(exc.GroupPolicyBadRequest):
message = _("Auto PTG %(id)s cannot be deleted.")
@ -250,11 +232,25 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
def aim_display_name(self, name):
return aim_utils.sanitize_display_name(name)
def _use_implicit_address_scope(self, context, ip_version, **kwargs):
# Ensure ipv4 and ipv6 address scope have same vrf
kwargs = {}
if context.saved_scope_vrf:
kwargs.update({cisco_apic.DIST_NAMES: context.saved_scope_vrf})
address_scope = super(AIMMappingDriver,
self)._use_implicit_address_scope(context,
ip_version,
**kwargs)
context.saved_scope_vrf = address_scope[cisco_apic.DIST_NAMES]
return address_scope
# TODO(tbachman): remove once non-isomorphic address scopes
# are supported
def _validate_address_scopes(self, context, ip_dict):
v4_scope_id = ip_dict.get(4, {}).get('address_scope')
v6_scope_id = ip_dict.get(6, {}).get('address_scope')
def _validate_address_scopes(self, context):
l3p_db = context._plugin._get_l3_policy(
context._plugin_context, context.current['id'])
v4_scope_id = l3p_db['address_scope_v4_id']
v6_scope_id = l3p_db['address_scope_v6_id']
if v4_scope_id and v6_scope_id:
v4_scope = self._get_address_scope(
context._plugin_context, v4_scope_id)
@ -268,98 +264,16 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
def create_l3_policy_precommit(self, context):
l3p_req = context.current
self._check_l3policy_ext_segment(context, l3p_req)
l3p_db = context._plugin._get_l3_policy(
context._plugin_context, l3p_req['id'])
# The ip_version tells us what should be supported
ip_version = l3p_req['ip_version']
l3p_db['ip_version'] = ip_version
# First determine the address scope for the address
# families specified in ip_version. We look first at
# explicitly passed address scopes, then the address
# scopes of the subnetpools, then the address scopes
# of default defined subnetpool (via that extension),
# or just create one if none are present
ip_dict = {}
ascp = None
if ip_version == 4 or ip_version == 46:
ip_dict[4] = {'address_scope_key': 'address_scope_v4_id',
'subnetpools_key': 'subnetpools_v4'}
if ip_version == 6 or ip_version == 46:
ip_dict[6] = {'address_scope_key': 'address_scope_v6_id',
'subnetpools_key': 'subnetpools_v6'}
# save VRF DN from v4 family address scope, if implicitly created,
# as we will need to reuse it if we also implicitly create a v6
# address scopes
saved_scope_vrf = None
for family in ip_dict.keys():
explicit_scope = l3p_req[ip_dict[family]['address_scope_key']]
explicit_pools = l3p_req[ip_dict[family]['subnetpools_key']]
default_pool = self._core_plugin.get_default_subnetpool(
context._plugin_context.elevated(), ip_version=family)
ip_pool = utils.convert_ip_pool_string_to_list(l3p_req['ip_pool'])
family_prefixes = [prefix for prefix in ip_pool
if netaddr.IPNetwork(prefix).version == family]
if explicit_scope:
ascp = ip_dict[family]['address_scope'] = explicit_scope
elif explicit_pools:
ascp, _ = self._check_subnetpools_for_same_scope(context,
explicit_pools, None)
ip_dict[family]['address_scope'] = ascp
l3p_db[ip_dict[family]['address_scope_key']] = ascp
elif family_prefixes:
kwargs = {}
if saved_scope_vrf:
kwargs.update({cisco_apic.DIST_NAMES: saved_scope_vrf})
address_scope = self._use_implicit_address_scope(context,
ip_version=family, **kwargs)
ip_dict[family]['address_scope'] = (
l3p_req[ip_dict[family]['address_scope_key']])
saved_scope_vrf = address_scope[
cisco_apic.DIST_NAMES]
elif default_pool and default_pool.get('address_scope_id'):
ip_dict[family]['address_scope'] = (
default_pool['address_scope_id'])
else:
raise NoValidAddressScope()
context.saved_scope_vrf = None
self._create_l3p_subnetpools(context)
# reset the temporarily saved scope
context.saved_scope_vrf = None
if explicit_scope or explicit_pools:
# In the case of explicitly provided address_scope or
# subnetpools, set shared flag of L3P to the address_scope
ascp_db = self._get_address_scope(
context._plugin_context, ascp)
l3p_db['shared'] = ascp_db['shared']
context.current['shared'] = l3p_db['shared']
if not explicit_pools and family_prefixes:
# for pools that need to be created, we
# want to use subnet_prefix_length as the
# default for v4 subnets, and /64 for v6
# subnets. If a subnet_prefix_length wasn't
# provided, we use the implict default
if family == 4:
default_prefixlen = l3p_req['subnet_prefix_length'] or 24
else:
default_prefixlen = 64
if family_prefixes:
self._use_implicit_subnetpool(context,
address_scope_id=ip_dict[family]['address_scope'],
ip_version=family, prefixes=family_prefixes,
default_prefixlen=default_prefixlen)
elif not explicit_pools and default_pool:
l3p_req[ip_dict[family]['subnetpools_key']] = [
default_pool['id']]
context._plugin._add_subnetpools_to_l3_policy(
context._plugin_context, l3p_db, [default_pool['id']],
ip_version=family)
# TODO(Sumit): check that l3p['ip_pool'] does not overlap with an
# existing subnetpool associated with the explicit address_scope
self._configure_l3p_for_multiple_subnetpools(context,
l3p_db, ip_version=family,
address_scope_id=ip_dict[family]['address_scope'])
self._validate_address_scopes(context, ip_dict)
self._validate_address_scopes(context)
# REVISIT: Check if the following constraint still holds
if len(l3p_req['routers']) > 1:
@ -390,34 +304,11 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
self._reject_invalid_router_access(context)
self._validate_in_use_by_nsp(context)
ip_dict = {4: {'address_scope_key': 'address_scope_v4_id',
'subnetpools_key': 'subnetpools_v4'},
6: {'address_scope_key': 'address_scope_v6_id',
'subnetpools_key': 'subnetpools_v6'}}
l3p_orig = context.original
l3p_curr = context.current
for family in ip_dict.keys():
ip_info = ip_dict[family]
if (l3p_curr[ip_info['subnetpools_key']] and (
l3p_curr[ip_info['subnetpools_key']] !=
l3p_orig[ip_info['subnetpools_key']])):
l3p_db = context._plugin._get_l3_policy(
context._plugin_context, l3p_curr['id'])
self._configure_l3p_for_multiple_subnetpools(context,
l3p_db, ip_version=family,
address_scope_id=l3p_db[ip_info['address_scope_key']])
removed = list(set(l3p_orig[ip_info['subnetpools_key']]) -
set(l3p_curr[ip_info['subnetpools_key']]))
for sp_id in removed:
if sp_id in self._get_in_use_subnetpools_for_l3p(context):
raise IncorrectSubnetpoolUpdate(
subnetpool_id=sp_id, l3p_id=l3p_curr['id'])
# If an implicitly created subnetpool is being
# disassocaited we try to delete it
self._cleanup_subnetpool(context._plugin_context, sp_id)
self._update_l3p_subnetpools(context)
# TODO(Sumit): For extra safety add validation for address_scope change
l3p_orig = context.original
l3p_curr = context.current
self._check_l3policy_ext_segment(context, l3p_curr)
old_segment_dict = l3p_orig['external_segments']
new_segment_dict = l3p_curr['external_segments']
@ -444,7 +335,9 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
context.current, external_segments.keys())
l3p_db = context._plugin._get_l3_policy(
context._plugin_context, context.current['id'])
v4v6subpools = {4: l3p_db.subnetpools_v4, 6: l3p_db.subnetpools_v6}
for k, v in six.iteritems(v4v6subpools):
subpools = [sp.subnetpool_id for sp in v]
for sp_id in subpools:
@ -453,11 +346,13 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
context._plugin_context, l3p_db['id'], sp_id,
ip_version=k)
self._cleanup_subnetpool(context._plugin_context, sp_id)
for ascp in ADDR_SCOPE_KEYS:
for ascp in self.L3P_ADDRESS_SCOPE_KEYS.values():
if l3p_db[ascp]:
ascp_id = l3p_db[ascp]
l3p_db.update({ascp: None})
self._cleanup_address_scope(context._plugin_context, ascp_id)
for router_id in context.current['routers']:
self._db_plugin(context._plugin)._remove_router_from_l3_policy(
context._plugin_context, l3p_db['id'], router_id)
@ -477,7 +372,7 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
# considered for deriving the status
mapped_status = []
for ascp in ADDR_SCOPE_KEYS:
for ascp in self.L3P_ADDRESS_SCOPE_KEYS.values():
if l3p_db[ascp]:
ascp_id = l3p_db[ascp]
ascope = self._get_address_scope(
@ -1183,58 +1078,6 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
if context.original.get('shared') != context.current.get('shared'):
raise SharedAttributeUpdateNotSupported(type=type)
def _check_subnetpools_for_same_scope(self, context, subnetpools,
ascp, prefixes=None):
sp_ascp = None
for sp_id in subnetpools:
sp = self._get_subnetpool(
# admin context to retrieve subnetpools from
# other tenants
context._plugin_context.elevated(), sp_id)
if not sp['address_scope_id']:
raise NoAddressScopeForSubnetpool()
if not sp_ascp:
if ascp:
# This is the case where the address_scope
# was explicitly set for the l3p and we need to
# check if it conflicts with the address_scope of
# the first subnetpool
if sp['address_scope_id'] != ascp:
raise InconsistentAddressScopeSubnetpool()
else:
# No address_scope was explicitly set for the l3p,
# so set it to that of the first subnetpool
ascp = sp['address_scope_id']
sp_ascp = sp['address_scope_id']
elif sp_ascp != sp['address_scope_id']:
# all subnetpools do not have the same address_scope
raise InconsistentAddressScopeSubnetpool()
# aggregate subnetpool prefixes
sp_prefixlist = [prefix for prefix in sp['prefixes']]
if prefixes:
stripped = [prefix.strip() for prefix in prefixes.split(',')]
prefixes = ', '.join(stripped + sp_prefixlist)
else:
prefixes = ', '.join(sp_prefixlist)
return ascp, prefixes
def _configure_l3p_for_multiple_subnetpools(self, context,
l3p_db, ip_version=4,
address_scope_id=None):
l3p_req = context.current
ascp_id_key = 'address_scope_v4_id' if ip_version == 4 else (
'address_scope_v6_id')
subpool_ids_key = 'subnetpools_v4' if ip_version == 4 else (
'subnetpools_v6')
# admin context to retrieve subnetpools from a different tenant
address_scope_id, prefixes = self._check_subnetpools_for_same_scope(
context, l3p_req[subpool_ids_key], address_scope_id,
prefixes=l3p_db['ip_pool'])
l3p_db[ascp_id_key] = address_scope_id
l3p_db['ip_pool'] = prefixes
if l3p_req['subnet_prefix_length']:
l3p_db['subnet_prefix_length'] = l3p_req['subnet_prefix_length']
def _aim_tenant_name(self, session, tenant_id, aim_resource_class=None,
gbp_resource=None, gbp_obj=None):
if aim_resource_class and (
@ -2480,20 +2323,6 @@ class AIMMappingDriver(nrd.CommonNeutronBase, aim_rpc.AIMMappingRPCMixin):
self._validate_nat_pool_for_nsp(context)
self._handle_network_service_policy(context)
def _get_in_use_subnetpools_for_l3p(self, context):
return [x.subnetpool_id for x in
context._plugin_context.session.query(models_v2.Subnet).join(
gpmdb.PTGToSubnetAssociation,
gpmdb.PTGToSubnetAssociation.subnet_id ==
models_v2.Subnet.id
).join(gpmdb.PolicyTargetGroupMapping,
gpmdb.PTGToSubnetAssociation.policy_target_group_id ==
gpmdb.PolicyTargetGroupMapping.id).join(
gpmdb.L2PolicyMapping).join(
gpmdb.L3PolicyMapping).filter(
gpmdb.L2PolicyMapping.l3_policy_id ==
context.current['id']).all()]
def _get_prss_for_policy_rules(self, context, pr_ids):
return [self._get_policy_rule_set(
context._plugin_context, x['id']) for x in (

View File

@ -12,6 +12,10 @@
from neutron_lib.api import validators
from oslo_config import cfg
from oslo_log import log as logging
from gbpservice._i18n import _LW
from gbpservice.neutron.db.grouppolicy.extensions import group_proxy_db as db
from gbpservice.neutron.db.grouppolicy import group_policy_db as gp_db
from gbpservice.neutron.extensions import driver_proxy_group
@ -19,6 +23,9 @@ from gbpservice.neutron.services.grouppolicy import (
group_policy_driver_api as api)
LOG = logging.getLogger(__name__)
class ProxyGroupDriver(api.ExtensionDriver):
_supported_extension_alias = 'proxy_group'
_extension_dict = driver_proxy_group.EXTENDED_ATTRIBUTES_2_0
@ -99,11 +106,26 @@ class ProxyGroupDriver(api.ExtensionDriver):
@api.default_extension_behavior(db.ProxyIPPoolMapping)
def process_create_l3_policy(self, session, data, result):
data = data['l3_policy']
gp_db.GroupPolicyDbPlugin.validate_ip_pool(
data['proxy_ip_pool'], data['ip_version'])
gp_db.GroupPolicyDbPlugin.validate_subnet_prefix_length(
data['ip_version'], data['proxy_subnet_prefix_length'],
data['proxy_ip_pool'])
if cfg.CONF.resource_mapping.use_subnetpools:
# With subnetpools, proxy ips are allocated from regular ip_pool
# (since neutron does not allow mixed subnetpools on same
# network). But proxy_subnet_prefix_length is still used to
# determine size of proxy ip pool.
gp_db.GroupPolicyDbPlugin.validate_subnet_prefix_length(
data['ip_version'], data['proxy_subnet_prefix_length'],
data['ip_pool'])
if data['proxy_ip_pool']:
LOG.warning(_LW("Since use_subnetpools setting is turned on, "
"proxy_ip_pool %s will be ignored. "
"Proxy subnets will be allocated from same "
"subnetpool as group subnets"),
data['proxy_ip_pool'])
else:
gp_db.GroupPolicyDbPlugin.validate_ip_pool(
data['proxy_ip_pool'], data['ip_version'])
gp_db.GroupPolicyDbPlugin.validate_subnet_prefix_length(
data['ip_version'], data['proxy_subnet_prefix_length'],
data['proxy_ip_pool'])
@api.default_extension_behavior(db.ProxyIPPoolMapping)
def process_update_l3_policy(self, session, data, result):

View File

@ -16,6 +16,7 @@ import operator
from keystoneclient import exceptions as k_exceptions
from keystoneclient.v2_0 import client as k_client
from neutron.api.v2 import attributes
from neutron.common import exceptions as neutron_exc
from neutron import context as n_context
from neutron.db import models_v2
from neutron.extensions import l3 as ext_l3
@ -38,6 +39,7 @@ from gbpservice._i18n import _LW
from gbpservice.common import utils
from gbpservice.network.neutronv2 import local_api
from gbpservice.neutron.db.grouppolicy import group_policy_db as gpdb
from gbpservice.neutron.db.grouppolicy import group_policy_mapping_db as gpmdb
from gbpservice.neutron.db import servicechain_db # noqa
from gbpservice.neutron.extensions import driver_proxy_group as proxy_ext
from gbpservice.neutron.extensions import group_policy as gp_ext
@ -68,6 +70,10 @@ opts = [
help=_("default IPv6 address assignment mode for subnets "
"created implicitly for L3 policies. Valid values are "
"'slaac', 'dhcpv6-stateful', and 'dhcpv6-stateless'")),
cfg.BoolOpt('use_subnetpools',
default=True,
help=_("make use of neutron subnet pools and address scopes "
"as L3 policy resource")),
]
cfg.CONF.register_opts(opts, "resource_mapping")
@ -227,6 +233,11 @@ class OwnedResourcesOperations(object):
class ImplicitResourceOperations(local_api.LocalAPI,
nsp_manager.NetworkServicePolicyMappingMixin):
L3P_ADDRESS_SCOPE_KEYS = {4: 'address_scope_v4_id',
6: 'address_scope_v6_id'}
L3P_SUBNETPOOLS_KEYS = {4: 'subnetpools_v4',
6: 'subnetpools_v6'}
def _sg_rule(self, plugin_context, tenant_id, sg_id, direction,
protocol=None, port_range=None, cidr=None,
ethertype=n_const.IPv4, unset=False):
@ -526,6 +537,7 @@ class ImplicitResourceOperations(local_api.LocalAPI,
self._delete_subnet(context._plugin_context,
subnet['id'])
raise exc.GroupPolicyInternalError()
raise exc.NoSubnetAvailable()
def _use_implicit_subnet(self, context, is_proxy=False, prefix_len=None,
@ -561,17 +573,14 @@ class ImplicitResourceOperations(local_api.LocalAPI,
l3p_id = l2p['l3_policy_id']
l3p_db = context._plugin.get_l3_policy(context._plugin_context, l3p_id)
# Only allocate from subnetpools that belong to this tenant
ip_dict = {}
if l3p_db['address_scope_v4_id']:
ip_dict[4] = {'address_scope_key': 'address_scope_v4_id',
'subnetpools_key': 'subnetpools_v4'}
if l3p_db['address_scope_v6_id']:
ip_dict[6] = {'address_scope_key': 'address_scope_v6_id',
'subnetpools_key': 'subnetpools_v6'}
subnets = []
for ip_version in ip_dict.keys():
for ip_version in (4, 6):
# continue if no address scope defined for this ip version
if not l3p_db[self.L3P_ADDRESS_SCOPE_KEYS[ip_version]]:
continue
filters = {'tenant_id': [context.current['tenant_id']],
'id': l3p_db[ip_dict[ip_version]['subnetpools_key']]}
'id': l3p_db[self.L3P_SUBNETPOOLS_KEYS[ip_version]]}
# All relevant subnetpools owned by this tenant
candidate_subpools = self._get_subnetpools(
context._plugin_context, filters) or []
@ -1368,6 +1377,184 @@ class ImplicitResourceOperations(local_api.LocalAPI,
ip_address = ip_range['last_ip']
return ip_address
def _get_in_use_subnetpools_for_l3p(self, context):
return [x.subnetpool_id for x in
context._plugin_context.session.query(models_v2.Subnet).join(
gpmdb.PTGToSubnetAssociation,
gpmdb.PTGToSubnetAssociation.subnet_id ==
models_v2.Subnet.id
).join(gpmdb.PolicyTargetGroupMapping,
gpmdb.PTGToSubnetAssociation.policy_target_group_id ==
gpmdb.PolicyTargetGroupMapping.id).join(
gpmdb.L2PolicyMapping).join(
gpmdb.L3PolicyMapping).filter(
gpmdb.L2PolicyMapping.l3_policy_id ==
context.current['id']).all()]
def _check_subnetpools_for_same_scope(self, context, subnetpools,
ascp, prefixes=None):
sp_ascp = None
for sp_id in subnetpools:
sp = self._get_subnetpool(
# admin context to retrieve subnetpools from
# other tenants
context._plugin_context.elevated(), sp_id)
if not sp['address_scope_id']:
raise exc.NoAddressScopeForSubnetpool()
if not sp_ascp:
if ascp:
# This is the case where the address_scope
# was explicitly set for the l3p and we need to
# check if it conflicts with the address_scope of
# the first subnetpool
if sp['address_scope_id'] != ascp:
raise exc.InconsistentAddressScopeSubnetpool()
else:
# No address_scope was explicitly set for the l3p,
# so set it to that of the first subnetpool
ascp = sp['address_scope_id']
sp_ascp = sp['address_scope_id']
elif sp_ascp != sp['address_scope_id']:
# all subnetpools do not have the same address_scope
raise exc.InconsistentAddressScopeSubnetpool()
# aggregate subnetpool prefixes
sp_prefixlist = [prefix for prefix in sp['prefixes']]
if prefixes:
stripped = [prefix.strip() for prefix in prefixes.split(',')]
prefixes = ', '.join(stripped + sp_prefixlist)
else:
prefixes = ', '.join(sp_prefixlist)
return ascp, prefixes
def _configure_l3p_for_multiple_subnetpools(self, context,
l3p_db, ip_version=4,
address_scope_id=None):
l3p_req = context.current
ascp_id_key = 'address_scope_v4_id' if ip_version == 4 else (
'address_scope_v6_id')
subpool_ids_key = 'subnetpools_v4' if ip_version == 4 else (
'subnetpools_v6')
# admin context to retrieve subnetpools from a different tenant
address_scope_id, prefixes = self._check_subnetpools_for_same_scope(
context, l3p_req[subpool_ids_key], address_scope_id,
prefixes=l3p_db['ip_pool'])
l3p_db[ascp_id_key] = address_scope_id
l3p_db['ip_pool'] = prefixes
if l3p_req['subnet_prefix_length']:
l3p_db['subnet_prefix_length'] = l3p_req['subnet_prefix_length']
def _create_l3p_subnetpools(self, context):
l3p_req = context.current
l3p_db = context._plugin._get_l3_policy(
context._plugin_context, l3p_req['id'])
# The ip_version tells us what should be supported
ip_version = l3p_req['ip_version']
l3p_db['ip_version'] = ip_version
# First determine the address scope for the address
# families specified in ip_version. We look first at
# explicitly passed address scopes, then the address
# scopes of the subnetpools, then the address scopes
# of default defined subnetpool (via that extension),
# or just create one if none are present
ip_dict = {}
ascp = None
# for pools that need to be created, we
# want to use subnet_prefix_length as the
# default for v4 subnets, and /64 for v6
# subnets. If a subnet_prefix_length wasn't
# provided, we use the implict default
if ip_version == 4 or ip_version == 46:
ip_dict[4] = {'default_prefixlen':
l3p_req['subnet_prefix_length'] or 24}
if ip_version == 6 or ip_version == 46:
ip_dict[6] = {'default_prefixlen': 64}
for family in ip_dict.keys():
explicit_scope = l3p_req[self.L3P_ADDRESS_SCOPE_KEYS[family]]
explicit_pools = l3p_req[self.L3P_SUBNETPOOLS_KEYS[family]]
default_pool = self._core_plugin.get_default_subnetpool(
context._plugin_context.elevated(), ip_version=family)
ip_pool = gbp_utils.convert_ip_pool_string_to_list(
l3p_req['ip_pool'])
family_prefixes = [prefix for prefix in ip_pool
if netaddr.IPNetwork(prefix).version == family]
if explicit_scope:
ascp = explicit_scope
elif explicit_pools:
ascp, _ = self._check_subnetpools_for_same_scope(context,
explicit_pools, None)
l3p_db[self.L3P_ADDRESS_SCOPE_KEYS[family]] = ascp
elif family_prefixes:
ascp = self._use_implicit_address_scope(
context, ip_version=family)['id']
elif default_pool and default_pool.get('address_scope_id'):
ascp = default_pool['address_scope_id']
else:
raise exc.NoValidAddressScope()
if explicit_scope or explicit_pools:
# In the case of explicitly provided address_scope or
# subnetpools, set shared flag of L3P to the address_scope
ascp_db = self._get_address_scope(
context._plugin_context, ascp)
l3p_db['shared'] = ascp_db['shared']
context.current['shared'] = l3p_db['shared']
if not explicit_pools and family_prefixes:
self._use_implicit_subnetpool(context,
address_scope_id=ascp,
ip_version=family, prefixes=family_prefixes,
default_prefixlen=ip_dict[family]['default_prefixlen'])
elif not explicit_pools and default_pool:
l3p_req[self.L3P_SUBNETPOOLS_KEYS[family]] = [
default_pool['id']]
context._plugin._add_subnetpools_to_l3_policy(
context._plugin_context, l3p_db, [default_pool['id']],
ip_version=family)
# TODO(Sumit): check that l3p['ip_pool'] does not overlap with an
# existing subnetpool associated with the explicit address_scope
self._configure_l3p_for_multiple_subnetpools(context,
l3p_db, ip_version=family,
address_scope_id=ascp)
def _update_l3p_subnetpools(self, context):
l3p_orig = context.original
l3p_curr = context.current
for family in (4, 6):
subnetpools_key = self.L3P_SUBNETPOOLS_KEYS[family]
address_scope_key = self.L3P_ADDRESS_SCOPE_KEYS[family]
if (l3p_curr[subnetpools_key] and (
l3p_curr[subnetpools_key] != l3p_orig[subnetpools_key])):
l3p_db = context._plugin._get_l3_policy(
context._plugin_context, l3p_curr['id'])
self._configure_l3p_for_multiple_subnetpools(context,
l3p_db, ip_version=family,
address_scope_id=l3p_db[address_scope_key])
removed = list(set(l3p_orig[subnetpools_key]) -
set(l3p_curr[subnetpools_key]))
for sp_id in removed:
if sp_id in self._get_in_use_subnetpools_for_l3p(context):
raise exc.IncorrectSubnetpoolUpdate(
subnetpool_id=sp_id, l3p_id=l3p_curr['id'])
# If an implicitly created subnetpool is being
# disassocaited we try to delete it
self._cleanup_subnetpool(context._plugin_context, sp_id)
def _delete_l3p_subnetpools(self, context):
subpools = []
for sp_key in self.L3P_SUBNETPOOLS_KEYS.values():
subpools += context.current[sp_key]
for sp_id in subpools:
self._cleanup_subnetpool(context._plugin_context, sp_id)
for ascp_key in self.L3P_ADDRESS_SCOPE_KEYS.values():
if context.current[ascp_key]:
self._cleanup_address_scope(context._plugin_context,
context.current[ascp_key])
class ResourceMappingDriver(api.PolicyDriver, ImplicitResourceOperations,
OwnedResourcesOperations):
@ -1619,12 +1806,7 @@ class ResourceMappingDriver(api.PolicyDriver, ImplicitResourceOperations,
# REVISIT(ivar) this validates the PTG L2P after the IPD creates it
# (which happens in the postcommit phase)
self._validate_proxy_ptg(context)
subnets = context.current['subnets']
if not subnets:
self._use_implicit_subnet(
context,
is_proxy=bool(context.current.get('proxied_group_id')))
subnets = context.current['subnets']
# connect router to subnets of the PTG
l2p_id = context.current['l2_policy_id']
l2p = context._plugin.get_l2_policy(context._plugin_context,
@ -1632,7 +1814,31 @@ class ResourceMappingDriver(api.PolicyDriver, ImplicitResourceOperations,
l3p_id = l2p['l3_policy_id']
l3p = context._plugin.get_l3_policy(context._plugin_context,
l3p_id)
self._stitch_ptg_to_l3p(context, context.current, l3p, subnets)
if not context.current['subnets']:
is_proxy = bool(context.current.get('proxied_group_id'))
if (not MAPPING_CFG.use_subnetpools or
(is_proxy and
context.current.get('proxy_type') == proxy_ext.PROXY_TYPE_L2)):
self._use_implicit_subnet(context, is_proxy=is_proxy)
else:
try:
subnet_specifics = {}
if context.current.get('proxied_group_id'):
# Since this is proxy group, we need to allocate
# subnet with proxy-specific prefix len
subnet_specifics = {
'prefixlen': l3p['proxy_subnet_prefix_length']}
subnets = self._use_implicit_subnet_from_subnetpool(
context, subnet_specifics)
context.add_subnets([sub['id'] for sub in subnets])
except neutron_exc.SubnetAllocationError:
# Translate to GBP exception
raise exc.NoSubnetAvailable()
self._stitch_ptg_to_l3p(context, context.current, l3p,
context.current['subnets'])
self._handle_network_service_policy(context)
self._handle_policy_rule_sets(context)
@ -1836,14 +2042,19 @@ class ResourceMappingDriver(api.PolicyDriver, ImplicitResourceOperations,
@log.log_method_call
def create_l3_policy_postcommit(self, context):
if not context.current['routers']:
self._use_implicit_router(context)
if MAPPING_CFG.use_subnetpools:
self._create_l3p_subnetpools(context)
l3p = context.current
if not l3p['routers']:
self._use_implicit_router(context)
if l3p['external_segments']:
self._plug_router_to_external_segment(
context, l3p['external_segments'])
self._set_l3p_external_routes(context)
self._process_new_l3p_ip_pool(context, context.current['ip_pool'])
if not MAPPING_CFG.use_subnetpools:
self._process_new_l3p_ip_pool(context, context.current['ip_pool'])
@log.log_method_call
def update_l3_policy_precommit(self, context):
@ -1851,6 +2062,10 @@ class ResourceMappingDriver(api.PolicyDriver, ImplicitResourceOperations,
raise exc.L3PolicyRoutersUpdateNotSupported()
if len(context.current['external_segments']) > 1:
raise exc.MultipleESPerL3PolicyNotSupported()
if MAPPING_CFG.use_subnetpools:
self._update_l3p_subnetpools(context)
# Currently there is no support for router update in l3p update.
# Added this check just in case it is supported in future.
self._reject_invalid_router_access(context)
@ -1883,7 +2098,12 @@ class ResourceMappingDriver(api.PolicyDriver, ImplicitResourceOperations,
def delete_l3_policy_postcommit(self, context):
for router_id in context.current['routers']:
self._cleanup_router(context._plugin_context, router_id)
self._process_remove_l3p_ip_pool(context, context.current['ip_pool'])
if MAPPING_CFG.use_subnetpools:
self._delete_l3p_subnetpools(context)
else:
self._process_remove_l3p_ip_pool(context,
context.current['ip_pool'])
@log.log_method_call
def create_policy_classifier_precommit(self, context):

View File

@ -11,6 +11,7 @@
# under the License.
from neutron import context as n_ctx
from oslo_config import cfg
from sqlalchemy.orm import exc as orm_exc
from gbpservice.neutron.db.grouppolicy.extensions import group_proxy_db
@ -182,8 +183,13 @@ class ExtensionDriverTestCaseMixin(object):
self.assertEqual('InvalidDefaultSubnetPrefixLength',
res['NeutronError']['type'])
def test_proxy_pool_invalid_version(self):
# proxy_ip_pool is of a different version
def test_proxy_pool_legacy_invalid_version(self):
cfg.CONF.set_override('use_subnetpools',
False,
group='resource_mapping')
# without subnetpools, proxy_ip_pool of a different version
# should fail
res = self.create_l3_policy(ip_version=6, ip_pool='1::1/16',
proxy_ip_pool='192.168.0.0/16',
expected_res_status=400)

View File

@ -24,6 +24,7 @@ from neutron.db.qos import models as qos_models
from neutron.extensions import external_net as external_net
from neutron.extensions import securitygroup as ext_sg
from neutron.plugins.common import constants as pconst
from neutron.tests.unit.extensions import test_address_scope
from neutron.tests.unit.extensions import test_l3
from neutron.tests.unit.extensions import test_securitygroup
from neutron.tests.unit.plugins.ml2 import test_plugin as n_test_plugin
@ -42,6 +43,7 @@ from gbpservice.neutron.services.grouppolicy import (
policy_driver_manager as pdm)
from gbpservice.neutron.services.grouppolicy.common import constants as gconst
from gbpservice.neutron.services.grouppolicy.common import exceptions as gpexc
from gbpservice.neutron.services.grouppolicy.common import utils as gp_utils
from gbpservice.neutron.services.grouppolicy import config
from gbpservice.neutron.services.grouppolicy.drivers import chain_mapping
from gbpservice.neutron.services.grouppolicy.drivers import nsp_manager
@ -62,9 +64,12 @@ CHAIN_TENANT_ID = 'chain_owner'
class NoL3NatSGTestPlugin(
test_l3.TestNoL3NatPlugin,
test_securitygroup.SecurityGroupTestPlugin):
test_securitygroup.SecurityGroupTestPlugin,
test_address_scope.AddressScopeTestPlugin):
supported_extension_aliases = ["external-net", "security-group"] + (
supported_extension_aliases = ["external-net",
"security-group",
"address-scope"] + (
test_group_policy_db.UNSUPPORTED_REQUIRED_EXTS)
@ -1002,7 +1007,12 @@ class TestPolicyTargetGroupWithoutDNSConfiguration(ResourceMappingTestCase):
class TestPolicyTargetGroup(ResourceMappingTestCase):
def _test_implicit_subnet_lifecycle(self, shared=False):
def _test_implicit_subnet_lifecycle(self, shared=False,
disable_subnetpools=False):
config.cfg.CONF.set_override('use_subnetpools',
not disable_subnetpools,
group='resource_mapping')
# Use explicit L2 policy so network and subnet not deleted
# with policy_target group.
l2p = self.create_l2_policy(shared=shared)
@ -1036,6 +1046,9 @@ class TestPolicyTargetGroup(ResourceMappingTestCase):
def test_implicit_subnet_lifecycle(self):
self._test_implicit_subnet_lifecycle()
def test_implicit_subnet_lifecycle_legacy(self):
self._test_implicit_subnet_lifecycle(disable_subnetpools=True)
def test_implicit_subnet_lifecycle_shared(self):
self._test_implicit_subnet_lifecycle(True)
@ -1295,7 +1308,15 @@ class TestPolicyTargetGroup(ResourceMappingTestCase):
def test_default_security_group_allows_intra_ptg_update(self):
# Create ptg and retrieve subnet and network
ptg = self.create_policy_target_group()['policy_target_group']
l3p = self.create_l3_policy(name="l3p1",
ip_pool='10.0.0.0/24, 10.1.0.0/24')
l3p_id = l3p['l3_policy']['id']
# Create L2 policy.
l2p = self.create_l2_policy(name="l2p1", l3_policy_id=l3p_id)
l2p_id = l2p['l2_policy']['id']
ptg = self.create_policy_target_group(
l2_policy_id=l2p_id)['policy_target_group']
subnets = ptg['subnets']
req = self.new_show_request('subnets', subnets[0], fmt=self.fmt)
subnet1 = self.deserialize(self.fmt,
@ -1304,7 +1325,9 @@ class TestPolicyTargetGroup(ResourceMappingTestCase):
fmt=self.fmt)
network = self.deserialize(self.fmt,
req.get_response(self.api))
with self.subnet(network=network, cidr='192.168.0.0/24') as subnet2:
with self.subnet(network=network,
cidr='10.1.0.0/24',
subnetpool_id=subnet1['subnetpool_id']) as subnet2:
# Add subnet
subnet2 = subnet2['subnet']
subnets = [subnet1['id'], subnet2['id']]
@ -1636,7 +1659,8 @@ class TestL2Policy(ResourceMappingTestCase):
data['NeutronError']['type'])
class TestL3Policy(ResourceMappingTestCase):
class TestL3Policy(ResourceMappingTestCase,
test_address_scope.AddressScopeTestCase):
def test_implicit_router_lifecycle(self):
# Create L3 policy with implicit router.
@ -1910,6 +1934,455 @@ class TestL3Policy(ResourceMappingTestCase):
self.assertEqual('InvalidRouterAccess',
res['NeutronError']['type'])
def _show_subnetpool(self, id):
req = self.new_show_request('subnetpools', id, fmt=self.fmt)
return self.deserialize(self.fmt,
req.get_response(self.api))['subnetpool']
def _extend_subnet_prefixes(self, prefixes, l3p, subnetpools_version):
if subnetpools_version:
for spool_id in l3p[subnetpools_version]:
prefixes.extend(self._show_subnetpool(spool_id)['prefixes'])
def _validate_create_l3_policy(self, l3p, subnetpool_prefixes=None,
compare_subnetpool_shared_attr=True):
# subnetpool_prefixes should be set only when the l3p has only
# one subnetpool configured; if not, the default None value should
# be used and the subnetpools should be validated in the calling test
# function.
# compare_subnetpool_shared_attr is set to False in the case explicit
# unshared subnetpool is created on shared address_scope.
prefixes_list = []
ascp_ids = []
ip_versions = []
subnetpools_versions = []
ip_version = l3p['ip_version']
if ip_version == 4 or ip_version == 46:
subnetpools_versions.append('subnetpools_v4')
ascp_ids.append(l3p['address_scope_v4_id'])
ip_versions.append(4)
if ip_version == 6 or ip_version == 46:
subnetpools_versions.append('subnetpools_v6')
ascp_ids.append(l3p['address_scope_v6_id'])
ip_versions.append(6)
if subnetpool_prefixes:
for version in subnetpools_versions:
self._extend_subnet_prefixes(prefixes_list, l3p, version)
self.assertItemsEqual(subnetpool_prefixes, prefixes_list)
params = {'ids': ascp_ids}
req = self.new_list_request('address-scopes',
params=params, fmt=self.fmt)
res = self.deserialize(self.fmt, req.get_response(self.ext_api))
ascopes = res['address_scopes']
for ascope in ascopes:
self.assertIn(ascope['ip_version'], ip_versions)
self.assertEqual(l3p['shared'], ascope['shared'])
self.assertIsNotNone(ascp_ids)
routers = l3p['routers']
self.assertIsNotNone(routers)
self.assertEqual(len(routers), 1)
router_id = routers[0]
for version in subnetpools_versions:
sp_id = l3p[version][0]
subpool = self._show_subnetpool(sp_id)
req = self.new_show_request('subnetpools', sp_id, fmt=self.fmt)
res = self.deserialize(self.fmt, req.get_response(self.api))
subpool = res['subnetpool']
self.assertIn(subpool['prefixes'][0], l3p['ip_pool'])
self.assertIn(subpool['ip_version'], ip_versions)
if compare_subnetpool_shared_attr:
self.assertEqual(l3p['shared'], subpool['shared'])
router = self._get_object('routers', router_id, self.ext_api)['router']
self.assertEqual('l3p_l3p1', router['name'])
def _validate_delete_l3_policy(self, l3p,
explicit_address_scope=False,
explicit_subnetpool=False,
v4_default=False, v6_default=False):
ascp_ids = []
subnetpools_versions = []
ip_version = l3p['ip_version']
if ip_version == 4 or ip_version == 46:
subnetpools_versions.append('subnetpools_v4')
ascp_ids.append(l3p['address_scope_v4_id'])
if ip_version == 6 or ip_version == 46:
subnetpools_versions.append('subnetpools_v6')
ascp_ids.append(l3p['address_scope_v6_id'])
router_id = l3p['routers'][0]
req = self.new_delete_request('l3_policies', l3p['id'])
res = req.get_response(self.ext_api)
self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
for version in subnetpools_versions:
sp_id = l3p[version][0]
req = self.new_show_request('subnetpools', sp_id, fmt=self.fmt)
res = req.get_response(self.api)
if explicit_subnetpool or (
version == 'subnetpools_v4' and v4_default) or (
version == 'subnetpools_v6' and v6_default):
self.assertEqual(webob.exc.HTTPOk.code, res.status_int)
else:
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
params = {'ids': ascp_ids}
req = self.new_list_request('address-scopes',
params=params, fmt=self.fmt)
res = req.get_response(self.ext_api)
if explicit_address_scope or v4_default or v6_default:
self.assertEqual(webob.exc.HTTPOk.code, res.status_int)
else:
res = self.deserialize(self.fmt, req.get_response(self.ext_api))
self.assertEqual(res['address_scopes'], [])
req = self.new_show_request('routers', router_id, fmt=self.fmt)
res = req.get_response(self.ext_api)
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
# TODO(Sumit): Add test for implicit address_scope not deleted
# when it has associated subnetpools
def _test_update_l3_policy_subnetpool(
self, l3p, prefixes, ip_version=4, implicit_pool=True, shared=False,
tenant_id=None, subnet_prefix_length=24):
if ip_version == 4 or ip_version == 46:
subnetpools_version = 'subnetpools_v4'
ascp_id = l3p['address_scope_v4_id']
if ip_version == 6 or ip_version == 46:
subnetpools_version = 'subnetpools_v6'
ascp_id = l3p['address_scope_v6_id']
implicit_subpool = []
if implicit_pool:
implicit_subpool = l3p['subnetpools_v4'] if ip_version == 4 else (
l3p['subnetpools_v6'])
if not tenant_id:
tenant_id = self._tenant_id
sp2 = self._make_subnetpool(
self.fmt, prefixes, name='sp2', address_scope_id=ascp_id,
tenant_id=tenant_id, shared=shared)['subnetpool']
self.assertEqual(ascp_id, sp2['address_scope_id'])
self.assertEqual(prefixes, sp2['prefixes'])
implicit_ip_pool = l3p['ip_pool']
implicit_subnet_prefix_length = l3p['subnet_prefix_length']
# Preserve existing subnetpools including implicitly created subnetpool
new_subnetpools = implicit_subpool + [sp2['id']]
attrs = {'id': l3p['id'], subnetpools_version: new_subnetpools}
l3p = self.update_l3_policy(**attrs)['l3_policy']
prefixlist = [prefix.strip() for prefix in l3p['ip_pool'].split(',')]
implicitlist = [prefix.strip()
for prefix in implicit_ip_pool.split(',')]
for prefix in prefixlist:
self.assertIn(prefix, prefixes + implicitlist)
self.assertEqual(l3p['subnet_prefix_length'], subnet_prefix_length)
self.assertItemsEqual(new_subnetpools, l3p[subnetpools_version])
attrs = {'id': l3p['id'], subnetpools_version: implicit_subpool}
l3p = self.update_l3_policy(**attrs)['l3_policy']
self.assertEqual(implicit_ip_pool, l3p['ip_pool'])
self.assertEqual(implicit_subnet_prefix_length,
l3p['subnet_prefix_length'])
self.assertItemsEqual(implicit_subpool, l3p[subnetpools_version])
req = self.new_delete_request('subnetpools', sp2['id'])
res = req.get_response(self.api)
self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
def _extend_ip_pool(self, ip_pool, prefixes):
if ip_pool:
return ','.join(ip_pool.split(',') + prefixes.split(','))
else:
return prefixes
def _create_l3_policy_for_lifecycle_tests(
self, explicit_address_scope=False, explicit_subnetpool=False,
ip_version=4, ip_pool=None, subnet_prefix_length=24,
tenant_id=None, shared=False, v4_default=False,
v6_default=False,
no_address_scopes=False):
if not tenant_id:
tenant_id = self._tenant_id
attrs = {'name': 'l3p1', 'ip_version': ip_version, 'shared': shared,
'ip_pool': ip_pool,
'subnet_prefix_length': subnet_prefix_length}
address_scope_v4 = address_scope_v6 = None
if explicit_address_scope or v4_default or v6_default:
if ip_version == 4 or ip_version == 46:
address_scope_v4 = self._make_address_scope(
self.fmt, 4, name='as1v4',
shared=shared)['address_scope']
if not v4_default:
attrs['address_scope_v4_id'] = address_scope_v4['id']
if ip_version == 6 or ip_version == 46:
address_scope_v6 = self._make_address_scope(
self.fmt, 6, name='as1v6',
shared=shared)['address_scope']
if not v6_default:
attrs['address_scope_v6_id'] = address_scope_v6['id']
ip_pool_v4 = ip_pool_v6 = None
if ip_version == 4 or ip_version == 46:
if not ip_pool:
ip_pool_v4 = '192.168.0.0/16'
if explicit_subnetpool or v4_default:
sp = self._make_subnetpool(
self.fmt, [ip_pool_v4], name='sp1v4',
is_default=v4_default,
address_scope_id=address_scope_v4['id'],
tenant_id=tenant_id, shared=shared)['subnetpool']
if explicit_subnetpool:
attrs['subnetpools_v4'] = [sp['id']]
if ip_version == 6 or ip_version == 46:
if not ip_pool:
ip_pool_v6 = 'fd6d:8d64:af0c::/64'
if explicit_subnetpool or v6_default:
sp = self._make_subnetpool(
self.fmt, [ip_pool_v6], name='sp1v6',
is_default=v6_default,
address_scope_id=address_scope_v6['id'],
tenant_id=tenant_id, shared=shared)['subnetpool']
if explicit_subnetpool:
attrs['subnetpools_v6'] = [sp['id']]
if ip_pool_v4 and not v4_default and not no_address_scopes:
attrs['ip_pool'] = self._extend_ip_pool(attrs['ip_pool'],
ip_pool_v4)
if ip_pool_v6 and not v6_default and not no_address_scopes:
attrs['ip_pool'] = self._extend_ip_pool(attrs['ip_pool'],
ip_pool_v6)
# Create L3 policy with implicit address_scope, subnetpool and router
l3p = self.create_l3_policy(**attrs)['l3_policy']
self._validate_create_l3_policy(l3p,
gp_utils.convert_ip_pool_string_to_list(l3p['ip_pool']))
return l3p
def _test_l3_policy_lifecycle(self, explicit_address_scope=False,
explicit_subnetpool=False,
ip_version=4, ip_pool=None,
subnet_prefix_length=24, tenant_id=None,
shared=False, v4_default=False,
v6_default=False,
no_address_scopes=False):
l3p = self._create_l3_policy_for_lifecycle_tests(
explicit_address_scope=explicit_address_scope,
explicit_subnetpool=explicit_subnetpool, ip_version=ip_version,
ip_pool=ip_pool, subnet_prefix_length=subnet_prefix_length,
tenant_id=tenant_id, shared=shared,
v4_default=v4_default,
v6_default=v6_default,
no_address_scopes=no_address_scopes)
if not tenant_id:
tenant_id = l3p['tenant_id']
if ip_version == 4 or ip_version == 46:
self._test_update_l3_policy_subnetpool(
l3p, prefixes=['10.0.0.0/8'], ip_version=4, shared=shared,
tenant_id=tenant_id)
if ip_version == 6 or ip_version == 46:
self._test_update_l3_policy_subnetpool(
l3p, prefixes=['fd6d:8d64:af0c:1::/64'], ip_version=6,
shared=shared, tenant_id=tenant_id)
# TODO(Sumit): Test update of other relevant attributes
self._validate_delete_l3_policy(
l3p, explicit_address_scope=explicit_address_scope,
explicit_subnetpool=explicit_subnetpool,
v4_default=v4_default, v6_default=v6_default)
def test_unshared_l3_policy_v4_lifecycle_implicit_address_scope(self):
self._test_l3_policy_lifecycle()
def test_shared_l3_policy_v4_lifecycle_implicit_address_scope(self):
self._test_l3_policy_lifecycle(shared=True)
def test_unshared_l3_policy_v6_lifecycle_implicit_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=6)
def test_shared_l3_policy_v6_lifecycle_implicit_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=6, shared=True)
def test_unshared_l3_policy_dual_lifecycle_implicit_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46)
def test_unshared_l3_policy_dual_lifecycle_implicit_2_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46,
v4_default=True, v6_default=True)
def test_unshared_l3_policy_dual_lifecycle_implicit_3_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46, v4_default=True)
def test_unshared_l3_policy_dual_lifecycle_implicit_4_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46, v6_default=True)
def test_shared_l3_policy_dual_lifecycle_implicit_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46, shared=True)
def test_shared_l3_policy_dual_lifecycle_implicit_2_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46, shared=True,
v4_default=True, v6_default=True)
def test_shared_l3_policy_dual_lifecycle_implicit_3_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46, shared=True,
v4_default=True)
def test_shared_l3_policy_dual_lifecycle_implicit_4_address_scope(self):
self._test_l3_policy_lifecycle(ip_version=46, shared=True,
v6_default=True)
def test_unshared_l3_policy_lifecycle_explicit_address_scope_v4(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True)
def test_shared_l3_policy_lifecycle_explicit_address_scope_v4(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
shared=True)
def test_unshared_l3_policy_lifecycle_explicit_address_scope_v6(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
ip_version=6)
def test_shared_l3_policy_lifecycle_explicit_address_scope_v6(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
ip_version=6, shared=True)
def test_unshared_l3_policy_lifecycle_explicit_address_scope_dual(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
ip_version=46)
def test_shared_l3_policy_lifecycle_explicit_address_scope_dual(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
ip_version=46, shared=True)
def test_unshared_create_l3_policy_explicit_subnetpool_v4(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
explicit_subnetpool=True)
def test_shared_create_l3_policy_explicit_subnetpool_v4(self):
self._test_l3_policy_lifecycle(explicit_address_scope=True,
explicit_subnetpool=True, shared=True)
def test_unshared_create_l3_policy_explicit_subnetpool_v6(self):
self._test_l3_policy_lifecycle(
explicit_address_scope=True, explicit_subnetpool=True,
ip_version=6)
def test_shared_create_l3_policy_explicit_subnetpool_v6(self):
self._test_l3_policy_lifecycle(
explicit_address_scope=True, explicit_subnetpool=True,
ip_version=6, shared=True)
def test_unshared_create_l3_policy_explicit_subnetpool_dual(self):
self._test_l3_policy_lifecycle(
explicit_address_scope=True, explicit_subnetpool=True,
ip_version=46, ip_pool=None)
def test_shared_create_l3_policy_explicit_subnetpool_dual(self):
self._test_l3_policy_lifecycle(
explicit_address_scope=True, explicit_subnetpool=True,
ip_version=46, shared=True)
def test_unshared_l3_policy_lifecycle_no_address_scope(self):
self.assertRaises(webob.exc.HTTPClientError,
self._test_l3_policy_lifecycle,
no_address_scopes=True)
def test_l3_policy_lifecycle_dual_address_scope(self):
with self.address_scope(ip_version=4, shared=True) as ascpv4:
ascpv4 = ascpv4['address_scope']
with self.address_scope(ip_version=6, shared=True) as ascpv6:
ascpv6 = ascpv6['address_scope']
l3p = self.create_l3_policy(
ip_version=46,
address_scope_v4_id=ascpv4['id'],
address_scope_v6_id=ascpv6['id'])['l3_policy']
self.assertEqual(ascpv4['id'], l3p['address_scope_v4_id'])
self.assertEqual(ascpv6['id'], l3p['address_scope_v6_id'])
def test_create_l3p_shared_addr_scp_explicit_unshared_subnetpools(self):
with self.address_scope(ip_version=4, shared=True) as ascpv4:
ascpv4 = ascpv4['address_scope']
with self.subnetpool(
name='sp1v4', prefixes=['192.168.0.0/16'],
tenant_id=ascpv4['tenant_id'], default_prefixlen=24,
address_scope_id=ascpv4['id'], shared=False) as sp1v4:
sp1v4 = sp1v4['subnetpool']
# As admin, create a subnetpool in a different tenant
# but associated with the same address_scope
sp2v4 = self._make_subnetpool(
self.fmt, ['10.1.0.0/16'], name='sp2v4',
tenant_id='test-tenant-2', address_scope_id=ascpv4['id'],
default_prefixlen=24, shared=False,
admin=True)['subnetpool']
l3p = self.create_l3_policy(
name="l3p1", subnetpools_v4=[sp1v4['id'], sp2v4['id']]
)['l3_policy']
self.assertEqual(ascpv4['id'], sp1v4['address_scope_id'])
self.assertEqual(ascpv4['id'], l3p['address_scope_v4_id'])
for prefix in sp1v4['prefixes'] + sp2v4['prefixes']:
self.assertIn(prefix, l3p['ip_pool'])
self.assertEqual(24, l3p['subnet_prefix_length'])
self._validate_create_l3_policy(
l3p, compare_subnetpool_shared_attr=False)
self.assertEqual(2, len(l3p['subnetpools_v4']))
sp3v4 = self._make_subnetpool(
self.fmt, ['10.2.0.0/16'], name='sp3v4',
tenant_id='test-tenant-3', address_scope_id=ascpv4['id'],
default_prefixlen=24, shared=False,
admin=True)['subnetpool']
l3p = self.update_l3_policy(
l3p['id'],
subnetpools_v4=[sp1v4['id'], sp2v4['id'], sp3v4['id']])[
'l3_policy']
self.assertEqual(3, len(l3p['subnetpools_v4']))
self._validate_create_l3_policy(
l3p, compare_subnetpool_shared_attr=False)
self._validate_delete_l3_policy(
l3p, explicit_address_scope=True, explicit_subnetpool=True)
def _test_update_l3_policy_replace_implicit_subnetpool(
self, shared=False):
l3p = self._create_l3_policy_for_lifecycle_tests(shared=shared)
ascp_id = l3p['address_scope_v4_id']
implicit_ip_pool = l3p['ip_pool']
implicit_subnet_prefix_length = l3p['subnet_prefix_length']
implicit_subpool_id = l3p['subnetpools_v4'][0]
# if address_scope is shared, use a different tenant for subnetpool
# to simulate cross-tenant scenario
sp_tenant_id = 'test-tenant-2' if shared else self._tenant_id
new_prefixes = ['10.0.0.0/16']
# if address_scope is shared, subnetpool is created in a different
# tenant, so use admin role
sp2 = self._make_subnetpool(
self.fmt, new_prefixes, name='sp2', address_scope_id=ascp_id,
tenant_id=sp_tenant_id, admin=shared)['subnetpool']
self.assertEqual(ascp_id, sp2['address_scope_id'])
self.assertEqual(new_prefixes, sp2['prefixes'])
attrs = {'id': l3p['id'], 'subnetpools_v4': [sp2['id']]}
l3p = self.update_l3_policy(**attrs)['l3_policy']
self.assertEqual(sp2['id'], l3p['subnetpools_v4'][0])
for prefix in sp2['prefixes']:
self.assertIn(prefix, l3p['ip_pool'])
self.assertNotEqual(implicit_ip_pool, l3p['ip_pool'])
if implicit_subnet_prefix_length:
self.assertEqual(implicit_subnet_prefix_length,
l3p['subnet_prefix_length'])
# implicit subnetpool is deleted
req = self.new_show_request('subnetpools', implicit_subpool_id,
fmt=self.fmt)
res = req.get_response(self.api)
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
def test_update_unshared_l3_policy_replace_implicit_subnetpool(self):
self._test_update_l3_policy_replace_implicit_subnetpool()
def test_update_shared_l3_policy_replace_implicit_subnetpool(self):
self._test_update_l3_policy_replace_implicit_subnetpool(shared=True)
# TODO(ivar): We need a UT that verifies that the PT's ports have the default
# SG when there are no policy_rule_sets involved, that the default SG is