Merge "Use subnetpools in resource mapping driver"
This commit is contained in:
commit
45c7c2ee0c
@ -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")
|
||||
|
@ -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 (
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user