AIM Policy Driver - Part 5 - L3 Policies (implicit)
L3 Policy is mapped to Address Scope and Subnetpool. This patch implements the implicit workflow to create these mapped resources. Implements blueprint: address-scope-mapping Change-Id: I4309ada6f26c23a11232a858ff4e36bd5d03e25a
This commit is contained in:
parent
7b00c95f56
commit
dd5eb2f3aa
|
@ -284,35 +284,38 @@ class LocalAPI(object):
|
|||
except n_exc.NetworkNotFound:
|
||||
LOG.warning(_LW('Network %s already deleted'), network_id)
|
||||
|
||||
def _get_router(self, plugin_context, router_id):
|
||||
def _get_router(self, plugin_context, router_id, clean_session=True):
|
||||
return self._get_resource(self._l3_plugin, plugin_context, 'router',
|
||||
router_id)
|
||||
router_id, clean_session=clean_session)
|
||||
|
||||
def _get_routers(self, plugin_context, filters=None):
|
||||
def _get_routers(self, plugin_context, filters=None, clean_session=True):
|
||||
filters = filters or {}
|
||||
return self._get_resources(self._l3_plugin, plugin_context, 'routers',
|
||||
filters)
|
||||
filters, clean_session=clean_session)
|
||||
|
||||
def _create_router(self, plugin_context, attrs):
|
||||
def _create_router(self, plugin_context, attrs, clean_session=True):
|
||||
return self._create_resource(self._l3_plugin, plugin_context, 'router',
|
||||
attrs)
|
||||
attrs, clean_session=clean_session)
|
||||
|
||||
def _update_router(self, plugin_context, router_id, attrs):
|
||||
def _update_router(self, plugin_context, router_id, attrs,
|
||||
clean_session=True):
|
||||
return self._update_resource(self._l3_plugin, plugin_context, 'router',
|
||||
router_id, attrs)
|
||||
router_id, attrs,
|
||||
clean_session=clean_session)
|
||||
|
||||
def _add_router_interface(self, plugin_context, router_id, interface_info):
|
||||
self._l3_plugin.add_router_interface(plugin_context,
|
||||
router_id, interface_info)
|
||||
|
||||
def _remove_router_interface(self, plugin_context, router_id,
|
||||
interface_info):
|
||||
interface_info, clean_session=True):
|
||||
# To detach Router interface either port ID or Subnet ID is mandatory
|
||||
key = 'port_id' if 'port_id' in interface_info else 'subnet_id'
|
||||
fixed_ips_filter = {key: [interface_info.get(key)]}
|
||||
filters = {'device_id': [router_id],
|
||||
'fixed_ips': fixed_ips_filter}
|
||||
ports = self._get_ports(plugin_context, filters=filters)
|
||||
ports = self._get_ports(plugin_context, filters=filters,
|
||||
clean_session=clean_session)
|
||||
|
||||
try:
|
||||
self._l3_plugin.remove_router_interface(plugin_context, router_id,
|
||||
|
@ -330,21 +333,22 @@ class LocalAPI(object):
|
|||
{'port': ports[0]},
|
||||
'port' + '.delete.end')
|
||||
|
||||
def _add_router_gw_interface(self, plugin_context, router_id, gw_info):
|
||||
def _add_router_gw_interface(self, plugin_context, router_id, gw_info,
|
||||
clean_session=True):
|
||||
return self._l3_plugin.update_router(
|
||||
plugin_context, router_id,
|
||||
{'router': {'external_gateway_info': gw_info}})
|
||||
|
||||
def _remove_router_gw_interface(self, plugin_context, router_id,
|
||||
interface_info):
|
||||
interface_info, clean_session=True):
|
||||
self._l3_plugin.update_router(
|
||||
plugin_context, router_id,
|
||||
{'router': {'external_gateway_info': None}})
|
||||
|
||||
def _delete_router(self, plugin_context, router_id):
|
||||
def _delete_router(self, plugin_context, router_id, clean_session=True):
|
||||
try:
|
||||
self._delete_resource(self._l3_plugin, plugin_context, 'router',
|
||||
router_id)
|
||||
router_id, clean_session=clean_session)
|
||||
except l3.RouterNotFound:
|
||||
LOG.warning(_LW('Router %s already deleted'), router_id)
|
||||
|
||||
|
@ -436,6 +440,75 @@ class LocalAPI(object):
|
|||
except l3.FloatingIPNotFound:
|
||||
LOG.warning(_LW('Floating IP %s Already deleted'), fip_id)
|
||||
|
||||
def _get_address_scope(self, plugin_context, address_scope_id,
|
||||
clean_session=True):
|
||||
return self._get_resource(self._core_plugin, plugin_context,
|
||||
'address_scope', address_scope_id,
|
||||
clean_session=clean_session)
|
||||
|
||||
def _get_address_scopes(self, plugin_context, filters=None,
|
||||
clean_session=True):
|
||||
filters = filters or {}
|
||||
return self._get_resources(self._core_plugin, plugin_context,
|
||||
'address_scopes', filters,
|
||||
clean_session=clean_session)
|
||||
|
||||
def _create_address_scope(self, plugin_context, attrs,
|
||||
clean_session=True):
|
||||
return self._create_resource(self._core_plugin, plugin_context,
|
||||
'address_scope', attrs,
|
||||
clean_session=clean_session)
|
||||
|
||||
def _update_address_scope(self, plugin_context, address_scope_id, attrs,
|
||||
clean_session=True):
|
||||
return self._update_resource(self._core_plugin, plugin_context,
|
||||
'address_scope', address_scope_id, attrs,
|
||||
clean_session=clean_session)
|
||||
|
||||
def _delete_address_scope(self, plugin_context, address_scope_id,
|
||||
clean_session=True):
|
||||
try:
|
||||
self._delete_resource(self._core_plugin, plugin_context,
|
||||
'address_scope', address_scope_id,
|
||||
clean_session=clean_session)
|
||||
except n_exc.AddressScopeNotFound:
|
||||
LOG.warning(_LW('Address Scope %s already deleted'),
|
||||
address_scope_id)
|
||||
|
||||
def _get_subnetpool(self, plugin_context, subnetpool_id,
|
||||
clean_session=True):
|
||||
return self._get_resource(self._core_plugin, plugin_context,
|
||||
'subnetpool', subnetpool_id,
|
||||
clean_session=clean_session)
|
||||
|
||||
def _get_subnetpools(self, plugin_context, filters=None,
|
||||
clean_session=True):
|
||||
filters = filters or {}
|
||||
return self._get_resources(self._core_plugin, plugin_context,
|
||||
'subnetpools', filters,
|
||||
clean_session=clean_session)
|
||||
|
||||
def _create_subnetpool(self, plugin_context, attrs,
|
||||
clean_session=True):
|
||||
return self._create_resource(self._core_plugin, plugin_context,
|
||||
'subnetpool', attrs,
|
||||
clean_session=clean_session)
|
||||
|
||||
def _update_subnetpool(self, plugin_context, subnetpool_id, attrs,
|
||||
clean_session=True):
|
||||
return self._update_resource(self._core_plugin, plugin_context,
|
||||
'subnetpool', subnetpool_id, attrs,
|
||||
clean_session=clean_session)
|
||||
|
||||
def _delete_subnetpool(self, plugin_context, subnetpool_id,
|
||||
clean_session=True):
|
||||
try:
|
||||
self._delete_resource(self._core_plugin, plugin_context,
|
||||
'subnetpool', subnetpool_id,
|
||||
clean_session=clean_session)
|
||||
except n_exc.SubnetpoolNotFound:
|
||||
LOG.warning(_LW('Subnetpool %s already deleted'), subnetpool_id)
|
||||
|
||||
def _get_l2_policy(self, plugin_context, l2p_id, clean_session=True):
|
||||
return self._get_resource(self._group_policy_plugin, plugin_context,
|
||||
'l2_policy', l2p_id,
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from neutron.common import exceptions as nexc
|
||||
from neutron.db import model_base
|
||||
from oslo_log import helpers as log
|
||||
from oslo_log import log as logging
|
||||
|
@ -25,6 +26,10 @@ from gbpservice.neutron.services.grouppolicy.common import exceptions
|
|||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class AddressScopeUpdateForL3PNotSupported(nexc.BadRequest):
|
||||
message = _("Address Scope update for L3 Policy is not supported.")
|
||||
|
||||
|
||||
class PolicyTargetMapping(gpdb.PolicyTarget):
|
||||
"""Mapping of PolicyTarget to Neutron Port."""
|
||||
__table_args__ = {'extend_existing': True}
|
||||
|
@ -71,12 +76,40 @@ class L3PolicyRouterAssociation(model_base.BASEV2):
|
|||
primary_key=True)
|
||||
|
||||
|
||||
class L3PolicySubnetpoolV4Association(model_base.BASEV2):
|
||||
"""Models one to many relation between a L3Policy and v4 Subnetpools."""
|
||||
__tablename__ = 'gp_l3_policy_subnetpool_v4_associations'
|
||||
l3_policy_id = sa.Column(sa.String(36), sa.ForeignKey('gp_l3_policies.id'),
|
||||
primary_key=True)
|
||||
subnetpool_id = sa.Column(
|
||||
sa.String(36), sa.ForeignKey('subnetpools.id'), primary_key=True)
|
||||
|
||||
|
||||
class L3PolicySubnetpoolV6Association(model_base.BASEV2):
|
||||
"""Models one to many relation between a L3Policy and v6 Subnetpools."""
|
||||
__tablename__ = 'gp_l3_policy_subnetpool_v6_associations'
|
||||
l3_policy_id = sa.Column(sa.String(36), sa.ForeignKey('gp_l3_policies.id'),
|
||||
primary_key=True)
|
||||
subnetpool_id = sa.Column(
|
||||
sa.String(36), sa.ForeignKey('subnetpools.id'), primary_key=True)
|
||||
|
||||
|
||||
class L3PolicyMapping(gpdb.L3Policy):
|
||||
"""Mapping of L3Policy to set of Neutron Routers."""
|
||||
"""Mapping of L3Policy to set of Neutron Resources."""
|
||||
__table_args__ = {'extend_existing': True}
|
||||
__mapper_args__ = {'polymorphic_identity': 'mapping'}
|
||||
routers = orm.relationship(L3PolicyRouterAssociation,
|
||||
cascade='all', lazy="joined")
|
||||
address_scope_v4_id = sa.Column(
|
||||
sa.String(36), sa.ForeignKey('address_scopes.id'),
|
||||
nullable=True, unique=True)
|
||||
address_scope_v6_id = sa.Column(
|
||||
sa.String(36), sa.ForeignKey('address_scopes.id'),
|
||||
nullable=True, unique=True)
|
||||
subnetpools_v4 = orm.relationship(L3PolicySubnetpoolV4Association,
|
||||
cascade='all', lazy="joined")
|
||||
subnetpools_v6 = orm.relationship(L3PolicySubnetpoolV6Association,
|
||||
cascade='all', lazy="joined")
|
||||
|
||||
|
||||
class ExternalSegmentMapping(gpdb.ExternalSegment):
|
||||
|
@ -122,6 +155,10 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
|
|||
res = super(GroupPolicyMappingDbPlugin,
|
||||
self)._make_l3_policy_dict(l3p)
|
||||
res['routers'] = [router.router_id for router in l3p.routers]
|
||||
res['address_scope_v4_id'] = l3p.address_scope_v4_id
|
||||
res['address_scope_v6_id'] = l3p.address_scope_v6_id
|
||||
res['subnetpools_v4'] = [sp.subnetpool_id for sp in l3p.subnetpools_v4]
|
||||
res['subnetpools_v6'] = [sp.subnetpool_id for sp in l3p.subnetpools_v6]
|
||||
return self._fields(res, fields)
|
||||
|
||||
def _make_external_segment_dict(self, es, fields=None):
|
||||
|
@ -171,6 +208,98 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
|
|||
l2p_db = self._get_l2_policy(context, l2p_id)
|
||||
l2p_db.network_id = network_id
|
||||
|
||||
def _set_address_scope_for_l3_policy(self, context, l3p_id,
|
||||
address_scope_id, ip_version=4):
|
||||
if not address_scope_id:
|
||||
return
|
||||
# TODO(Sumit): address_scope_id validation
|
||||
with context.session.begin(subtransactions=True):
|
||||
l3p_db = self._get_l3_policy(context, l3p_id)
|
||||
if ip_version == 4:
|
||||
l3p_db.address_scope_v4_id = address_scope_id
|
||||
else:
|
||||
l3p_db.address_scope_v6_id = address_scope_id
|
||||
|
||||
def _add_subnetpool_to_l3_policy(self, context, l3p_id,
|
||||
subnetpool_id, ip_version=4):
|
||||
# TODO(Sumit): subnetpool_id validation
|
||||
with context.session.begin(subtransactions=True):
|
||||
l3p_db = self._get_l3_policy(context, l3p_id)
|
||||
if ip_version == 4:
|
||||
assoc = L3PolicySubnetpoolV4Association(
|
||||
l3_policy_id=l3p_id, subnetpool_id=subnetpool_id)
|
||||
l3p_db.subnetpools_v4.append(assoc)
|
||||
else:
|
||||
assoc = L3PolicySubnetpoolV6Association(
|
||||
l3_policy_id=l3p_id, subnetpool_id=subnetpool_id)
|
||||
l3p_db.subnetpools_v6.append(assoc)
|
||||
return {4: [sp.subnetpool_id for sp in l3p_db.subnetpools_v4],
|
||||
6: [sp.subnetpool_id for sp in l3p_db.subnetpools_v6]}
|
||||
|
||||
def _add_subnetpools_to_l3_policy(self, context, l3p_id,
|
||||
subnetpools, ip_version=4):
|
||||
for sp in subnetpools or []:
|
||||
self._add_subnetpool_to_l3_policy(
|
||||
context, l3p_id, sp, ip_version=ip_version)
|
||||
|
||||
def _remove_subnetpool_from_l3_policy(self, context, l3p_id,
|
||||
subnetpool_id, ip_version=4):
|
||||
with context.session.begin(subtransactions=True):
|
||||
l3p_db = self._get_l3_policy(context, l3p_id)
|
||||
if ip_version == 4:
|
||||
assoc = (context.session.query(
|
||||
L3PolicySubnetpoolV4Association).filter_by(
|
||||
l3_policy_id=l3p_id,
|
||||
subnetpool_id=subnetpool_id).one())
|
||||
l3p_db.subnetpools_v4.remove(assoc)
|
||||
else:
|
||||
assoc = (context.session.query(
|
||||
L3PolicySubnetpoolV6Association).filter_by(
|
||||
l3_policy_id=l3p_id,
|
||||
subnetpool_id=subnetpool_id).one())
|
||||
l3p_db.subnetpools_v6.remove(assoc)
|
||||
context.session.delete(assoc)
|
||||
return {4: [sp.subnetpool_id for sp in l3p_db.subnetpools_v4],
|
||||
6: [sp.subnetpool_id for sp in l3p_db.subnetpools_v6]}
|
||||
|
||||
def _update_subnetpools_for_l3_policy(self, context, l3p_id,
|
||||
subnetpools, ip_version=4):
|
||||
# Add/remove associations for changes in subnetpools
|
||||
# TODO(Sumit): Before disassociating a subnetpool, check that
|
||||
# there is no PT present on a subnet which belongs to that subnetpool
|
||||
if not subnetpools:
|
||||
return
|
||||
with context.session.begin(subtransactions=True):
|
||||
l3p_db = self._get_l3_policy(context, l3p_id)
|
||||
new_subnetpools = set(subnetpools)
|
||||
if ip_version == 4:
|
||||
old_subnetpools = set(sp.subnetpool_id
|
||||
for sp in l3p_db.subnetpools_v4)
|
||||
else:
|
||||
old_subnetpools = set(sp.subnetpool_id
|
||||
for sp in l3p_db.subnetpools_v6)
|
||||
for sp in new_subnetpools - old_subnetpools:
|
||||
if ip_version == 4:
|
||||
assoc = L3PolicySubnetpoolV4Association(
|
||||
l3_policy_id=l3p_id, subnetpool_id=sp)
|
||||
l3p_db.subnetpools_v4.append(assoc)
|
||||
else:
|
||||
assoc = L3PolicySubnetpoolV6Association(
|
||||
l3_policy_id=l3p_id, subnetpool_id=sp)
|
||||
l3p_db.subnetpools_v6.append(assoc)
|
||||
for sp in old_subnetpools - new_subnetpools:
|
||||
if ip_version == 4:
|
||||
assoc = (context.session.query(
|
||||
L3PolicySubnetpoolV4Association).filter_by(
|
||||
l3_policy_id=l3p_id, subnetpool_id=sp).one())
|
||||
l3p_db.subnetpools_v4.remove(assoc)
|
||||
else:
|
||||
assoc = (context.session.query(
|
||||
L3PolicySubnetpoolV6Association).filter_by(
|
||||
l3_policy_id=l3p_id, subnetpool_id=sp).one())
|
||||
l3p_db.subnetpools_v6.remove(assoc)
|
||||
context.session.delete(assoc)
|
||||
|
||||
def _add_router_to_l3_policy(self, context, l3p_id, router_id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
l3p_db = self._get_l3_policy(context, l3p_id)
|
||||
|
@ -424,6 +553,18 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
|
|||
l3p['subnet_prefix_length'],
|
||||
description=l3p['description'],
|
||||
shared=l3p.get('shared', False))
|
||||
|
||||
self._set_address_scope_for_l3_policy(
|
||||
context, l3p_db['id'], l3p.get('address_scope_v4_id'),
|
||||
ip_version=4)
|
||||
self._set_address_scope_for_l3_policy(
|
||||
context, l3p_db['id'], l3p.get('address_scope_v6_id'),
|
||||
ip_version=6)
|
||||
self._add_subnetpools_to_l3_policy(
|
||||
context, l3p_db['id'], l3p.get('subnetpools_v4'), ip_version=4)
|
||||
self._add_subnetpools_to_l3_policy(
|
||||
context, l3p_db['id'], l3p.get('subnetpools_v6'), ip_version=6)
|
||||
|
||||
if 'routers' in l3p:
|
||||
for router in l3p['routers']:
|
||||
assoc = L3PolicyRouterAssociation(
|
||||
|
@ -440,12 +581,27 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
|
|||
@log.log_method_call
|
||||
def update_l3_policy(self, context, l3_policy_id, l3_policy):
|
||||
l3p = l3_policy['l3_policy']
|
||||
|
||||
if 'address_scope_v4_id' in l3p or 'address_scope_v6_id' in l3p:
|
||||
raise AddressScopeUpdateForL3PNotSupported()
|
||||
|
||||
with context.session.begin(subtransactions=True):
|
||||
l3p_db = self._get_l3_policy(context, l3_policy_id)
|
||||
|
||||
self._update_subnetpools_for_l3_policy(context, l3_policy_id,
|
||||
l3p.get('subnetpools_v4'),
|
||||
ip_version=4)
|
||||
l3p.pop('subnetpools_v4', None)
|
||||
self._update_subnetpools_for_l3_policy(context, l3_policy_id,
|
||||
l3p.get('subnetpools_v6'),
|
||||
ip_version=4)
|
||||
l3p.pop('subnetpools_v6', None)
|
||||
|
||||
if 'subnet_prefix_length' in l3p:
|
||||
self.validate_subnet_prefix_length(l3p_db.ip_version,
|
||||
l3p['subnet_prefix_length'],
|
||||
l3p_db.ip_pool)
|
||||
|
||||
if 'routers' in l3p:
|
||||
# Add/remove associations for changes in routers.
|
||||
new_routers = set(l3p['routers'])
|
||||
|
|
|
@ -1 +1 @@
|
|||
7afacef00d31
|
||||
d4bb487a81b8
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""address_scope and subnetpool mapping for l3_policies
|
||||
|
||||
Revision ID: d4bb487a81b8
|
||||
Revises: c1aab79622fe
|
||||
Create Date: 2016-08-28 11:35:32.724952
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = 'd4bb487a81b8'
|
||||
down_revision = '7afacef00d31'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
|
||||
op.create_table(
|
||||
'gp_l3_policy_subnetpool_v4_associations',
|
||||
sa.Column('l3_policy_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('subnetpool_id', sa.String(length=36), nullable=False),
|
||||
sa.ForeignKeyConstraint(['l3_policy_id'], ['gp_l3_policies.id'],
|
||||
name='gpm_l3p_subnetpool_v4_assoc_fk_l3pid'),
|
||||
sa.ForeignKeyConstraint(['subnetpool_id'], ['subnetpools.id'],
|
||||
name='gpm_l3p_subnetpool_v4_assoc_fk_spid'),
|
||||
sa.PrimaryKeyConstraint('l3_policy_id', 'subnetpool_id')
|
||||
)
|
||||
|
||||
op.create_table(
|
||||
'gp_l3_policy_subnetpool_v6_associations',
|
||||
sa.Column('l3_policy_id', sa.String(length=36), nullable=False),
|
||||
sa.Column('subnetpool_id', sa.String(length=36), nullable=False),
|
||||
sa.ForeignKeyConstraint(['l3_policy_id'], ['gp_l3_policies.id'],
|
||||
name='gpm_l3p_subnetpool_v6_assoc_fk_l3pid'),
|
||||
sa.ForeignKeyConstraint(['subnetpool_id'], ['subnetpools.id'],
|
||||
name='gpm_l3p_subnetpool_v6_assoc_fk_spid'),
|
||||
sa.PrimaryKeyConstraint('l3_policy_id', 'subnetpool_id')
|
||||
)
|
||||
|
||||
op.add_column(
|
||||
'gp_l3_policies',
|
||||
sa.Column('address_scope_v4_id', sa.String(length=36), nullable=True),
|
||||
)
|
||||
|
||||
op.add_column(
|
||||
'gp_l3_policies',
|
||||
sa.Column('address_scope_v6_id', sa.String(length=36), nullable=True),
|
||||
)
|
||||
|
||||
op.create_unique_constraint('gpm_l3p_addr_scope_v4_uq',
|
||||
'gp_l3_policies', ['address_scope_v4_id'])
|
||||
op.create_unique_constraint('gpm_l3p_addr_scope_v6_uq',
|
||||
'gp_l3_policies', ['address_scope_v6_id'])
|
||||
op.create_foreign_key('gpm_l3p_addr_scope_v4_fk',
|
||||
source='gp_l3_policies', referent='address_scopes',
|
||||
local_cols=['address_scope_v4_id'],
|
||||
remote_cols=['id'])
|
||||
op.create_foreign_key('gpm_l3p_addr_scope_v6_fk',
|
||||
source='gp_l3_policies', referent='address_scopes',
|
||||
local_cols=['address_scope_v6_id'],
|
||||
remote_cols=['id'])
|
||||
|
||||
op.create_table(
|
||||
'gpm_owned_address_scopes',
|
||||
sa.Column('address_scope_id', sa.String(length=36), nullable=False),
|
||||
sa.ForeignKeyConstraint(
|
||||
['address_scope_id'], ['address_scopes.id'],
|
||||
name='rmd_addr_scope_owned_fk', ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('address_scope_id')
|
||||
)
|
||||
|
||||
op.create_table(
|
||||
'gpm_owned_subnetpools',
|
||||
sa.Column('subnetpool_id', sa.String(length=36), nullable=False),
|
||||
sa.ForeignKeyConstraint(['subnetpool_id'], ['subnetpools.id'],
|
||||
name='rmd_subnetpool_owned_fk',
|
||||
ondelete='CASCADE'),
|
||||
sa.PrimaryKeyConstraint('subnetpool_id')
|
||||
)
|
||||
|
||||
|
||||
def downgrade():
|
||||
pass
|
|
@ -41,6 +41,20 @@ EXTENDED_ATTRIBUTES_2_0 = {
|
|||
'is_visible': True, 'default': None},
|
||||
},
|
||||
gp.L3_POLICIES: {
|
||||
'address_scope_v4_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:uuid_or_none': None},
|
||||
'is_visible': True, 'default': None},
|
||||
'address_scope_v6_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:uuid_or_none': None},
|
||||
'is_visible': True, 'default': None},
|
||||
'subnetpools_v4': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:uuid_list': None},
|
||||
'convert_to': attr.convert_none_to_empty_list,
|
||||
'is_visible': True, 'default': None},
|
||||
'subnetpools_v6': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:uuid_list': None},
|
||||
'convert_to': attr.convert_none_to_empty_list,
|
||||
'is_visible': True, 'default': None},
|
||||
'routers': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:uuid_list': None},
|
||||
'convert_to': attr.convert_none_to_empty_list,
|
||||
|
|
|
@ -28,6 +28,7 @@ from gbpservice.neutron.plugins.ml2plus.drivers.apic_aim import model
|
|||
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.drivers import (
|
||||
neutron_resources as nrd)
|
||||
from gbpservice.neutron.services.grouppolicy.drivers.cisco.apic import (
|
||||
|
@ -41,6 +42,7 @@ 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']
|
||||
|
||||
# Definitions duplicated from apicapi lib
|
||||
APIC_OWNED = 'apic_owned_'
|
||||
|
@ -82,6 +84,76 @@ class AIMMappingDriver(nrd.CommonNeutronBase):
|
|||
def aim_display_name(self, name):
|
||||
return name
|
||||
|
||||
@log.log_method_call
|
||||
def create_l3_policy_precommit(self, context):
|
||||
l3p = context.current
|
||||
l3p_db = context._plugin._get_l3_policy(
|
||||
context._plugin_context, l3p['id'])
|
||||
ascp = 'address_scope_v4_id' if l3p['ip_version'] == 4 else (
|
||||
'address_scope_v6_id')
|
||||
if not l3p[ascp]:
|
||||
# REVISIT: For dual stack.
|
||||
# This logic assumes either 4 or 6 but not both
|
||||
self._use_implicit_address_scope(context, clean_session=False)
|
||||
l3p_db[ascp] = l3p[ascp]
|
||||
subpool = 'subnetpools_v4' if l3p['ip_version'] == 4 else (
|
||||
'subnetpools_v6')
|
||||
if not l3p[subpool]:
|
||||
# REVISIT: For dual stack.
|
||||
# This logic assumes either 4 or 6 but not both
|
||||
self._use_implicit_subnetpool(
|
||||
context, address_scope_id=l3p_db[ascp],
|
||||
ip_version=l3p['ip_version'], clean_session=False)
|
||||
# REVISIT: Check if the following constraint still holds
|
||||
if len(l3p['routers']) > 1:
|
||||
raise exc.L3PolicyMultipleRoutersNotSupported()
|
||||
# REVISIT: Validate non overlapping IPs in the same tenant.
|
||||
# Currently this validation is not required for the
|
||||
# AIM driver, and since the AIM driver is the only
|
||||
# driver inheriting from this driver, we are okay
|
||||
# without the check.
|
||||
self._reject_invalid_router_access(context, clean_session=False)
|
||||
if not l3p['routers']:
|
||||
self._use_implicit_router(context, clean_session=False)
|
||||
|
||||
@log.log_method_call
|
||||
def update_l3_policy_precommit(self, context):
|
||||
if context.current['routers'] != context.original['routers']:
|
||||
raise exc.L3PolicyRoutersUpdateNotSupported()
|
||||
# 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, clean_session=False)
|
||||
# TODO(Sumit): For extra safety add validation for address_scope change
|
||||
|
||||
@log.log_method_call
|
||||
def delete_l3_policy_precommit(self, context):
|
||||
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 v4v6subpools.iteritems():
|
||||
subpools = [sp.subnetpool_id for sp in v]
|
||||
for sp_id in subpools:
|
||||
self._db_plugin(
|
||||
context._plugin)._remove_subnetpool_from_l3_policy(
|
||||
context._plugin_context, l3p_db['id'], sp_id,
|
||||
ip_version=k)
|
||||
self._cleanup_subnetpool(context._plugin_context, sp_id,
|
||||
clean_session=False)
|
||||
for ascp in ADDR_SCOPE_KEYS:
|
||||
if l3p_db[ascp]:
|
||||
ascp_id = l3p_db[ascp]
|
||||
l3p_db.update({ascp: None})
|
||||
self._cleanup_address_scope(context._plugin_context, ascp_id,
|
||||
clean_session=False)
|
||||
routers = [router.router_id for router in l3p_db.routers]
|
||||
for router_id in routers:
|
||||
self._db_plugin(context._plugin)._remove_router_from_l3_policy(
|
||||
context._plugin_context, l3p_db['id'], router_id)
|
||||
self._cleanup_router(context._plugin_context, router_id,
|
||||
clean_session=False)
|
||||
|
||||
# TODO(Sumit): Implement get_l3_policy_status()
|
||||
|
||||
@log.log_method_call
|
||||
def create_l2_policy_precommit(self, context):
|
||||
super(AIMMappingDriver, self).create_l2_policy_precommit(context)
|
||||
|
@ -117,6 +189,8 @@ class AIMMappingDriver(nrd.CommonNeutronBase):
|
|||
context, context.current, default_epg_dn)
|
||||
super(AIMMappingDriver, self).delete_l2_policy_precommit(context)
|
||||
|
||||
# TODO(Sumit): Implement get_l2_policy_status()
|
||||
|
||||
@log.log_method_call
|
||||
def create_policy_target_group_precommit(self, context):
|
||||
if context.current['subnets']:
|
||||
|
@ -208,6 +282,7 @@ class AIMMappingDriver(nrd.CommonNeutronBase):
|
|||
for subnet_id in subnet_ids:
|
||||
if not context._plugin._get_ptgs_for_subnet(
|
||||
context._plugin_context, subnet_id):
|
||||
# TODO(Sumit): pass router_id of default router
|
||||
self._cleanup_subnet(plugin_context, subnet_id,
|
||||
clean_session=False)
|
||||
|
||||
|
@ -258,11 +333,6 @@ class AIMMappingDriver(nrd.CommonNeutronBase):
|
|||
if pt_db['port_id']:
|
||||
self._cleanup_port(context._plugin_context, pt_db['port_id'])
|
||||
|
||||
@log.log_method_call
|
||||
def delete_l3_policy_precommit(self, context):
|
||||
# TODO(Sumit): Implement
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_policy_classifier_precommit(self, context):
|
||||
o_dir = context.original['direction']
|
||||
|
@ -694,12 +764,14 @@ class AIMMappingDriver(nrd.CommonNeutronBase):
|
|||
context._plugin_context, l2p_id)
|
||||
name = APIC_OWNED + l2p['name']
|
||||
added = super(
|
||||
AIMMappingDriver, self)._use_implicit_subnet(
|
||||
AIMMappingDriver,
|
||||
self)._use_implicit_subnet_from_subnetpool(
|
||||
context, subnet_specifics={'name': name},
|
||||
is_proxy=False, clean_session=clean_session)
|
||||
clean_session=clean_session)
|
||||
context.add_subnets(subs - set(context.current['subnets']))
|
||||
for subnet in added:
|
||||
self._sync_ptg_subnets(context, l2p)
|
||||
# TODO(Sumit): This subnet needs to added to the default router
|
||||
|
||||
def _create_implicit_contracts_and_configure_default_epg(
|
||||
self, context, l2p, epg_dn):
|
||||
|
|
|
@ -44,8 +44,13 @@ class CommonNeutronBase(ipd.ImplicitPolicyBase, rmd.OwnedResourcesOperations,
|
|||
if not context.current['l3_policy_id']:
|
||||
self._create_implicit_l3_policy(context, clean_session=False)
|
||||
l2p_db['l3_policy_id'] = context.current['l3_policy_id']
|
||||
l3p_db = context._plugin._get_l3_policy(
|
||||
context._plugin_context, l2p_db['l3_policy_id'])
|
||||
if not context.current['network_id']:
|
||||
self._use_implicit_network(context, clean_session=False)
|
||||
self._use_implicit_network(
|
||||
context, address_scope_v4=l3p_db['address_scope_v4_id'],
|
||||
address_scope_v6=l3p_db['address_scope_v6_id'],
|
||||
clean_session=False)
|
||||
l2p_db['network_id'] = context.current['network_id']
|
||||
|
||||
@log.log_method_call
|
||||
|
|
|
@ -85,6 +85,26 @@ class OwnedNetwork(model_base.BASEV2):
|
|||
nullable=False, primary_key=True)
|
||||
|
||||
|
||||
class OwnedAddressScope(model_base.BASEV2):
|
||||
"""An Address Scope owned by the resource_mapping driver."""
|
||||
|
||||
__tablename__ = 'gpm_owned_address_scopes'
|
||||
address_scope_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('address_scopes.id',
|
||||
ondelete='CASCADE'),
|
||||
nullable=False, primary_key=True)
|
||||
|
||||
|
||||
class OwnedSubnetpool(model_base.BASEV2):
|
||||
"""A Subnetpool owned by the resource_mapping driver."""
|
||||
|
||||
__tablename__ = 'gpm_owned_subnetpools'
|
||||
subnetpool_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey('subnetpools.id',
|
||||
ondelete='CASCADE'),
|
||||
nullable=False, primary_key=True)
|
||||
|
||||
|
||||
class OwnedRouter(model_base.BASEV2):
|
||||
"""A Router owned by the resource_mapping driver."""
|
||||
|
||||
|
@ -115,6 +135,10 @@ class CidrInUse(exc.GroupPolicyInternalError):
|
|||
|
||||
class OwnedResourcesOperations(object):
|
||||
|
||||
# TODO(Sumit): All the following operations can be condensed into
|
||||
# a single _mark_resource_owned() and _resource_is_owned() method,
|
||||
# by creating a resource to DB class name mapping.
|
||||
|
||||
def _mark_port_owned(self, session, port_id):
|
||||
with session.begin(subtransactions=True):
|
||||
owned = OwnedPort(port_id=port_id)
|
||||
|
@ -159,9 +183,89 @@ class OwnedResourcesOperations(object):
|
|||
filter_by(router_id=router_id).
|
||||
first() is not None)
|
||||
|
||||
def _mark_address_scope_owned(self, session, address_scope_id):
|
||||
with session.begin(subtransactions=True):
|
||||
owned = OwnedAddressScope(address_scope_id=address_scope_id)
|
||||
session.add(owned)
|
||||
|
||||
def _address_scope_is_owned(self, session, address_scope_id):
|
||||
with session.begin(subtransactions=True):
|
||||
return (session.query(OwnedAddressScope).
|
||||
filter_by(address_scope_id=address_scope_id).
|
||||
first() is not None)
|
||||
|
||||
def _mark_subnetpool_owned(self, session, subnetpool_id):
|
||||
with session.begin(subtransactions=True):
|
||||
owned = OwnedSubnetpool(subnetpool_id=subnetpool_id)
|
||||
session.add(owned)
|
||||
|
||||
def _subnetpool_is_owned(self, session, subnetpool_id):
|
||||
with session.begin(subtransactions=True):
|
||||
return (session.query(OwnedSubnetpool).
|
||||
filter_by(subnetpool_id=subnetpool_id).
|
||||
first() is not None)
|
||||
|
||||
|
||||
class ImplicitResourceOperations(local_api.LocalAPI):
|
||||
|
||||
def _create_implicit_address_scope(self, context, clean_session=True,
|
||||
**kwargs):
|
||||
attrs = {'tenant_id': context.current['tenant_id'],
|
||||
'name': context.current['name'], 'ip_version':
|
||||
context.current['ip_version'],
|
||||
'shared': context.current.get('shared', False)}
|
||||
attrs.update(**kwargs)
|
||||
address_scope = self._create_address_scope(
|
||||
context._plugin_context, attrs, clean_session)
|
||||
as_id = address_scope['id']
|
||||
self._mark_address_scope_owned(context._plugin_context.session, as_id)
|
||||
return address_scope
|
||||
|
||||
def _use_implicit_address_scope(self, context, clean_session=True):
|
||||
address_scope = self._create_implicit_address_scope(
|
||||
context, clean_session, name='l3p_' + context.current['name'])
|
||||
context.set_address_scope_id(address_scope['id'])
|
||||
|
||||
def _cleanup_address_scope(self, plugin_context, address_scope_id,
|
||||
clean_session=True):
|
||||
if self._address_scope_is_owned(plugin_context.session,
|
||||
address_scope_id):
|
||||
self._delete_address_scope(plugin_context, address_scope_id,
|
||||
clean_session)
|
||||
|
||||
def _create_implicit_subnetpool(self, context, clean_session=True,
|
||||
**kwargs):
|
||||
attrs = {'tenant_id': context.current['tenant_id'],
|
||||
'name': context.current['name'], 'ip_version':
|
||||
context.current['ip_version'],
|
||||
'default_prefixlen': context.current['subnet_prefix_length'],
|
||||
'prefixes': [context.current['ip_pool']],
|
||||
'shared': context.current.get('shared', False),
|
||||
# Per current understanding, is_default is used for
|
||||
# auto_allocation and is a per-tenant setting.
|
||||
'is_default': False}
|
||||
attrs.update(**kwargs)
|
||||
subnetpool = self._create_subnetpool(
|
||||
context._plugin_context, attrs, clean_session)
|
||||
sp_id = subnetpool['id']
|
||||
self._mark_subnetpool_owned(context._plugin_context.session, sp_id)
|
||||
return subnetpool
|
||||
|
||||
def _use_implicit_subnetpool(self, context, address_scope_id, ip_version,
|
||||
clean_session=True):
|
||||
subnetpool = self._create_implicit_subnetpool(
|
||||
context, clean_session, name='l3p_' + context.current['name'],
|
||||
address_scope_id=address_scope_id)
|
||||
context.add_subnetpool(subnetpool_id=subnetpool['id'],
|
||||
ip_version=ip_version)
|
||||
|
||||
def _cleanup_subnetpool(self, plugin_context, subnetpool_id,
|
||||
clean_session=True):
|
||||
if self._subnetpool_is_owned(plugin_context.session,
|
||||
subnetpool_id):
|
||||
self._delete_subnetpool(plugin_context, subnetpool_id,
|
||||
clean_session)
|
||||
|
||||
def _create_implicit_network(self, context, clean_session=True, **kwargs):
|
||||
attrs = {'tenant_id': context.current['tenant_id'],
|
||||
'name': context.current['name'], 'admin_state_up': True,
|
||||
|
@ -173,9 +277,12 @@ class ImplicitResourceOperations(local_api.LocalAPI):
|
|||
self._mark_network_owned(context._plugin_context.session, network_id)
|
||||
return network
|
||||
|
||||
def _use_implicit_network(self, context, clean_session=True):
|
||||
def _use_implicit_network(self, context, address_scope_v4=None,
|
||||
address_scope_v6=None, clean_session=True):
|
||||
network = self._create_implicit_network(
|
||||
context, clean_session, name='l2p_' + context.current['name'])
|
||||
context, clean_session, name='l2p_' + context.current['name'],
|
||||
ipv4_address_scope=address_scope_v4,
|
||||
ipv6_address_scope=address_scope_v6)
|
||||
context.set_network_id(network['id'])
|
||||
|
||||
def _cleanup_network(self, plugin_context, network_id, clean_session=True):
|
||||
|
@ -363,6 +470,53 @@ class ImplicitResourceOperations(local_api.LocalAPI):
|
|||
context, is_proxy, prefix_len, subnet_specifics, l2p, l3p,
|
||||
clean_session=clean_session)
|
||||
|
||||
def _use_implicit_subnet_from_subnetpool(
|
||||
self, context, subnet_specifics=None, clean_session=True):
|
||||
# If a subnet needs to be created with a prefix_length other than
|
||||
# the subnet_prefix_length set for the l3_policy, a 'prefixlen' can be
|
||||
# passed explicitly in the subnet_specifics dict.
|
||||
# If a subnet with a specific CIDR needs to be created, the 'cidr' can
|
||||
# be passed explicitly in the subnet_specifics dict.
|
||||
# Note that either 'prefixlen' or 'cidr' can be requested, not both.
|
||||
# If a 'subnetpool_id' other than the one considered default is to be
|
||||
# used, it can be passed explicitly in the subnet_specifics dict.
|
||||
subnet_specifics = subnet_specifics or {}
|
||||
l2p_id = context.current['l2_policy_id']
|
||||
l2p = context._plugin.get_l2_policy(context._plugin_context, l2p_id)
|
||||
l3p_id = l2p['l3_policy_id']
|
||||
l3p_db = context._plugin.get_l3_policy(context._plugin_context, l3p_id)
|
||||
# REVISIT: For dual stack
|
||||
# Current assumption is that either v4 or v6 subnet needs to be
|
||||
# allocated, but not both
|
||||
if l3p_db['address_scope_v4_id']:
|
||||
# Since this is implicit assignment, the first subnetpool
|
||||
# is considered as the default and always used (here and in
|
||||
# the v6 case below)
|
||||
subnetpool_id = l3p_db['subnetpools_v4'][0]
|
||||
ip_version = 4
|
||||
else:
|
||||
subnetpool_id = l3p_db['subnetpools_v6'][0]
|
||||
ip_version = 6
|
||||
attrs = {'tenant_id': context.current['tenant_id'],
|
||||
'name': 'ptg_' + context.current['name'],
|
||||
'network_id': l2p['network_id'],
|
||||
'ip_version': ip_version,
|
||||
'subnetpool_id': subnetpool_id,
|
||||
'cidr': attributes.ATTR_NOT_SPECIFIED,
|
||||
'prefixlen': attributes.ATTR_NOT_SPECIFIED,
|
||||
'enable_dhcp': True,
|
||||
'gateway_ip': attributes.ATTR_NOT_SPECIFIED,
|
||||
'allocation_pools': attributes.ATTR_NOT_SPECIFIED,
|
||||
'dns_nameservers': (
|
||||
cfg.CONF.resource_mapping.dns_nameservers or
|
||||
attributes.ATTR_NOT_SPECIFIED),
|
||||
'host_routes': attributes.ATTR_NOT_SPECIFIED}
|
||||
attrs.update(subnet_specifics)
|
||||
subnet = self._create_subnet(context._plugin_context, attrs,
|
||||
clean_session=clean_session)
|
||||
self._mark_subnet_owned(context._plugin_context.session, subnet['id'])
|
||||
return [subnet]
|
||||
|
||||
def _cleanup_subnet(self, plugin_context, subnet_id, router_id=None,
|
||||
clean_session=True):
|
||||
interface_info = {'subnet_id': subnet_id}
|
||||
|
@ -431,6 +585,48 @@ class ImplicitResourceOperations(local_api.LocalAPI):
|
|||
except n_exc.PortNotFound:
|
||||
LOG.warning(_LW("Port %s is missing") % port_id)
|
||||
|
||||
def _reject_invalid_router_access(self, context, clean_session=True):
|
||||
# Validate if the explicit router(s) belong to the tenant.
|
||||
# Are routers shared across tenants ??
|
||||
# How to check if admin and if admin can access all routers ??
|
||||
for router_id in context.current['routers']:
|
||||
router = None
|
||||
try:
|
||||
router = self._get_router(context._plugin_context, router_id,
|
||||
clean_session=clean_session)
|
||||
except n_exc.NotFound:
|
||||
raise exc.InvalidRouterAccess(
|
||||
msg="Can't access other tenants router",
|
||||
router_id=router_id,
|
||||
tenant_id=context.current['tenant_id'])
|
||||
|
||||
if router:
|
||||
tenant_id_of_explicit_router = router['tenant_id']
|
||||
curr_tenant_id = context.current['tenant_id']
|
||||
if tenant_id_of_explicit_router != curr_tenant_id:
|
||||
raise exc.InvalidRouterAccess(
|
||||
msg="Can't access other tenants router",
|
||||
router_id=router_id,
|
||||
tenant_id=context.current['tenant_id'])
|
||||
|
||||
def _use_implicit_router(self, context, router_name=None,
|
||||
clean_session=True):
|
||||
attrs = {'tenant_id': context.current['tenant_id'],
|
||||
'name': router_name or ('l3p_' + context.current['name']),
|
||||
'external_gateway_info': None,
|
||||
'admin_state_up': True}
|
||||
router = self._create_router(context._plugin_context, attrs,
|
||||
clean_session=clean_session)
|
||||
router_id = router['id']
|
||||
self._mark_router_owned(context._plugin_context.session, router_id)
|
||||
context.add_router(router_id)
|
||||
return router_id
|
||||
|
||||
def _cleanup_router(self, plugin_context, router_id, clean_session=True):
|
||||
if self._router_is_owned(plugin_context.session, router_id):
|
||||
self._delete_router(plugin_context, router_id,
|
||||
clean_session=clean_session)
|
||||
|
||||
|
||||
class ResourceMappingDriver(api.PolicyDriver, ImplicitResourceOperations,
|
||||
nsp_manager.NetworkServicePolicyMappingMixin,
|
||||
|
@ -531,29 +727,6 @@ class ResourceMappingDriver(api.PolicyDriver, ImplicitResourceOperations,
|
|||
network_id=context.current['network_id'],
|
||||
tenant_id=context.current['tenant_id'])
|
||||
|
||||
def _reject_invalid_router_access(self, context):
|
||||
# Validate if the explicit router(s) belong to the tenant.
|
||||
# Are routers shared across tenants ??
|
||||
# How to check if admin and if admin can access all routers ??
|
||||
for router_id in context.current['routers']:
|
||||
router = None
|
||||
try:
|
||||
router = self._get_router(context._plugin_context, router_id)
|
||||
except n_exc.NotFound:
|
||||
raise exc.InvalidRouterAccess(
|
||||
msg="Can't access other tenants router",
|
||||
router_id=router_id,
|
||||
tenant_id=context.current['tenant_id'])
|
||||
|
||||
if router:
|
||||
tenant_id_of_explicit_router = router['tenant_id']
|
||||
curr_tenant_id = context.current['tenant_id']
|
||||
if tenant_id_of_explicit_router != curr_tenant_id:
|
||||
raise exc.InvalidRouterAccess(
|
||||
msg="Can't access other tenants router",
|
||||
router_id=router_id,
|
||||
tenant_id=context.current['tenant_id'])
|
||||
|
||||
@log.log_method_call
|
||||
def create_policy_target_precommit(self, context):
|
||||
self._check_create_policy_target(context)
|
||||
|
@ -1794,21 +1967,6 @@ class ResourceMappingDriver(api.PolicyDriver, ImplicitResourceOperations,
|
|||
self._delete_subnet(context._plugin_context, subnet_id)
|
||||
raise exc.GroupPolicyInternalError()
|
||||
|
||||
def _use_implicit_router(self, context, router_name=None):
|
||||
attrs = {'tenant_id': context.current['tenant_id'],
|
||||
'name': router_name or ('l3p_' + context.current['name']),
|
||||
'external_gateway_info': None,
|
||||
'admin_state_up': True}
|
||||
router = self._create_router(context._plugin_context, attrs)
|
||||
router_id = router['id']
|
||||
self._mark_router_owned(context._plugin_context.session, router_id)
|
||||
context.add_router(router_id)
|
||||
return router_id
|
||||
|
||||
def _cleanup_router(self, plugin_context, router_id):
|
||||
if self._router_is_owned(plugin_context.session, router_id):
|
||||
self._delete_router(plugin_context, router_id)
|
||||
|
||||
def _create_policy_rule_set_sg(self, context, sg_name_prefix):
|
||||
return self._create_gbp_sg(
|
||||
context._plugin_context, context.current['tenant_id'],
|
||||
|
|
|
@ -130,6 +130,29 @@ class L3PolicyContext(GroupPolicyContext, api.L3PolicyContext):
|
|||
def original(self):
|
||||
return self._original_l3_policy
|
||||
|
||||
def set_address_scope_id(self, address_scope_id, version=4):
|
||||
self._plugin._set_address_scope_for_l3_policy(
|
||||
self._plugin_context, self._l3_policy['id'], address_scope_id,
|
||||
ip_version=version)
|
||||
if version == 4:
|
||||
self._l3_policy['address_scope_v4_id'] = address_scope_id
|
||||
else:
|
||||
self._l3_policy['address_scope_v6_id'] = address_scope_id
|
||||
|
||||
def add_subnetpool(self, subnetpool_id, ip_version=4):
|
||||
subnetpools = self._plugin._add_subnetpool_to_l3_policy(
|
||||
self._plugin_context, self._l3_policy['id'], subnetpool_id,
|
||||
ip_version=ip_version)
|
||||
self._l3_policy['subnetpools_v4'] = subnetpools[4]
|
||||
self._l3_policy['subnetpools_v6'] = subnetpools[6]
|
||||
|
||||
def remove_subnetpool(self, subnetpool_id, ip_version=4):
|
||||
subnetpools = self._plugin._remove_subnetpool_to_l3_policy(
|
||||
self._plugin_context, self._l3_policy['id'], subnetpool_id,
|
||||
ip_version=ip_version)
|
||||
self._l3_policy['subnetpools_v4'] = subnetpools[4]
|
||||
self._l3_policy['subnetpools_v6'] = subnetpools[6]
|
||||
|
||||
def add_router(self, router_id):
|
||||
routers = self._plugin._add_router_to_l3_policy(
|
||||
self._plugin_context, self._l3_policy['id'], router_id)
|
||||
|
|
|
@ -346,6 +346,7 @@ class GroupPolicyDbTestCase(GroupPolicyDBTestBase,
|
|||
plugins = manager.NeutronManager.get_service_plugins()
|
||||
self._gbp_plugin = plugins.get(constants.GROUP_POLICY)
|
||||
self._sc_plugin = plugins.get(constants.SERVICECHAIN)
|
||||
self._l3_plugin = plugins.get(constants.L3_ROUTER_NAT)
|
||||
|
||||
|
||||
class TestGroupResources(GroupPolicyDbTestCase):
|
||||
|
|
|
@ -220,6 +220,99 @@ class TestAIMStatus(AIMBaseTestCase):
|
|||
self.aim_mgr.get_status = orig_get_status
|
||||
|
||||
|
||||
class TestL3Policy(AIMBaseTestCase):
|
||||
|
||||
def test_create_l3_policy_lifecycle_implicit_address_scope(self):
|
||||
# Create L3 policy with implicit router.
|
||||
l3p = self.create_l3_policy(name="l3p1")['l3_policy']
|
||||
l3p_id = l3p['id']
|
||||
self.assertIsNone(l3p['address_scope_v6_id'])
|
||||
ascp_id = l3p['address_scope_v4_id']
|
||||
self.assertEqual(len(l3p['subnetpools_v4']), 1)
|
||||
sp_id = l3p['subnetpools_v4'][0]
|
||||
self.assertIsNotNone(ascp_id)
|
||||
routers = l3p['routers']
|
||||
self.assertIsNotNone(routers)
|
||||
self.assertEqual(len(routers), 1)
|
||||
router_id = routers[0]
|
||||
"""
|
||||
# TODO(Sumit): Address-scope retrieval is creating issues, requires
|
||||
# some fixing in the UT setup
|
||||
req = self.new_show_request('address-scopes', ascp_id, fmt=self.fmt)
|
||||
res = self.deserialize(self.fmt, req.get_response(self.api))
|
||||
ascope = res['address_scope']
|
||||
"""
|
||||
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.assertEqual(l3p['ip_pool'], subpool['prefixes'][0])
|
||||
self.assertEqual(l3p['subnet_prefix_length'],
|
||||
int(subpool['default_prefixlen']))
|
||||
self.assertEqual(l3p['ip_version'],
|
||||
subpool['ip_version'])
|
||||
router = self._get_object('routers', router_id, self.ext_api)['router']
|
||||
self.assertEqual('l3p_l3p1', router['name'])
|
||||
|
||||
# TODO(Sumit): Test update of relevant attributes
|
||||
|
||||
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)
|
||||
req = self.new_show_request('subnetpools', sp_id, fmt=self.fmt)
|
||||
res = req.get_response(self.api)
|
||||
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
|
||||
req = self.new_show_request('address_scopes', ascp_id, fmt=self.fmt)
|
||||
res = req.get_response(self.api)
|
||||
self.assertEqual(webob.exc.HTTPNotFound.code, res.status_int)
|
||||
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)
|
||||
|
||||
|
||||
class TestL3PolicyRollback(AIMBaseTestCase):
|
||||
|
||||
def test_l3_policy_create_fail(self):
|
||||
orig_func = self.dummy.create_l3_policy_precommit
|
||||
self.dummy.create_l3_policy_precommit = mock.Mock(
|
||||
side_effect=Exception)
|
||||
self.create_l3_policy(name="l3p1", expected_res_status=500)
|
||||
self.assertEqual([], self._plugin.get_address_scopes(self._context))
|
||||
self.assertEqual([], self._plugin.get_subnetpools(self._context))
|
||||
self.assertEqual([], self._l3_plugin.get_routers(self._context))
|
||||
self.assertEqual([], self._gbp_plugin.get_l3_policies(self._context))
|
||||
# restore mock
|
||||
self.dummy.create_l3_policy_precommit = orig_func
|
||||
|
||||
def test_l3_policy_update_fail(self):
|
||||
orig_func = self.dummy.update_l3_policy_precommit
|
||||
self.dummy.update_l3_policy_precommit = mock.Mock(
|
||||
side_effect=Exception)
|
||||
l3p = self.create_l3_policy(name="l3p1")['l3_policy']
|
||||
l3p_id = l3p['id']
|
||||
self.update_l3_policy(l3p_id, expected_res_status=500,
|
||||
name="new name")
|
||||
new_l3p = self.show_l3_policy(l3p_id, expected_res_status=200)
|
||||
self.assertEqual(l3p['name'],
|
||||
new_l3p['l3_policy']['name'])
|
||||
# restore mock
|
||||
self.dummy.update_l3_policy_precommit = orig_func
|
||||
|
||||
def test_l3_policy_delete_fail(self):
|
||||
orig_func = self.dummy.delete_l3_policy_precommit
|
||||
self.dummy.delete_l3_policy_precommit = mock.Mock(
|
||||
side_effect=Exception)
|
||||
l3p = self.create_l3_policy(name="l3p1")['l3_policy']
|
||||
l3p_id = l3p['id']
|
||||
self.delete_l3_policy(l3p_id, expected_res_status=500)
|
||||
self.show_l3_policy(l3p_id, expected_res_status=200)
|
||||
self.assertEqual(
|
||||
1, len(self._plugin.get_address_scopes(self._context)))
|
||||
self.assertEqual(1, len(self._plugin.get_subnetpools(self._context)))
|
||||
self.assertEqual(1, len(self._l3_plugin.get_routers(self._context)))
|
||||
# restore mock
|
||||
self.dummy.delete_l3_policy_precommit = orig_func
|
||||
|
||||
|
||||
class TestL2PolicyBase(test_nr_base.TestL2Policy, AIMBaseTestCase):
|
||||
|
||||
def _validate_implicit_contracts_exist(self, l2p):
|
||||
|
@ -366,7 +459,7 @@ class TestL2Policy(TestL2PolicyBase):
|
|||
class TestL2PolicyRollback(TestL2PolicyBase):
|
||||
|
||||
def test_l2_policy_create_fail(self):
|
||||
orig_func = self.dummy.create_policy_target_group_precommit
|
||||
orig_func = self.dummy.create_l2_policy_precommit
|
||||
self.dummy.create_l2_policy_precommit = mock.Mock(
|
||||
side_effect=Exception)
|
||||
self.create_l2_policy(name="l2p1", expected_res_status=500)
|
||||
|
@ -474,9 +567,14 @@ class TestPolicyTargetGroup(AIMBaseTestCase):
|
|||
|
||||
l2p = self.show_l2_policy(ptg['l2_policy_id'],
|
||||
expected_res_status=200)['l2_policy']
|
||||
l3p = self.show_l3_policy(l2p['l3_policy_id'],
|
||||
expected_res_status=200)['l3_policy']
|
||||
req = self.new_show_request('subnets', ptg['subnets'][0], fmt=self.fmt)
|
||||
res = self.deserialize(self.fmt, req.get_response(self.api))
|
||||
self.assertIsNotNone(res['subnet']['id'])
|
||||
subnet = self.deserialize(self.fmt,
|
||||
req.get_response(self.api))['subnet']
|
||||
self.assertIsNotNone(subnet['id'])
|
||||
self.assertEqual(l3p['subnetpools_v4'][0],
|
||||
subnet['subnetpool_id'])
|
||||
ptg_name = ptg['name']
|
||||
aim_epg_name = str(self.name_mapper.policy_target_group(
|
||||
self._neutron_context.session, ptg_id, ptg_name))
|
||||
|
@ -602,6 +700,17 @@ class TestPolicyTargetGroup(AIMBaseTestCase):
|
|||
self.assertIsNotNone(res['subnet']['id'])
|
||||
|
||||
|
||||
# TODO(Sumit): Add tests here which tests different scenarios for subnet
|
||||
# allocation for PTGs
|
||||
# 1. Multiple PTGs share the subnets associated with the l2_policy
|
||||
# 2. Associated subnets are correctly used for IP address allocation
|
||||
# 3. New subnets are created when the last available is exhausted
|
||||
# 4. If multiple subnets are present, all are deleted at the time of
|
||||
# l2_policy deletion
|
||||
# 5. 'prefixlen', 'cidr', and 'subnetpool_id' overrides as a part of
|
||||
# the subnet_specifics dictionary
|
||||
|
||||
|
||||
class TestPolicyTargetGroupRollback(AIMBaseTestCase):
|
||||
|
||||
def test_policy_target_group_create_fail(self):
|
||||
|
|
|
@ -103,16 +103,26 @@ class GroupPolicyMappingExtTestCase(tgp.GroupPolicyExtensionTestCase):
|
|||
|
||||
def get_create_l3_policy_default_attrs(self):
|
||||
attrs = cm.get_create_l3_policy_default_attrs()
|
||||
attrs.update({'address_scope_v4_id': None})
|
||||
attrs.update({'address_scope_v6_id': None})
|
||||
attrs.update({'subnetpools_v4': []})
|
||||
attrs.update({'subnetpools_v6': []})
|
||||
attrs.update({'routers': []})
|
||||
return attrs
|
||||
|
||||
def get_create_l3_policy_attrs(self):
|
||||
attrs = cm.get_create_l3_policy_attrs()
|
||||
attrs.update({'address_scope_v4_id': tgp._uuid()})
|
||||
attrs.update({'address_scope_v6_id': tgp._uuid()})
|
||||
attrs.update({'subnetpools_v4': [tgp._uuid(), tgp._uuid()]})
|
||||
attrs.update({'subnetpools_v6': [tgp._uuid(), tgp._uuid()]})
|
||||
attrs.update({'routers': [tgp._uuid(), tgp._uuid()]})
|
||||
return attrs
|
||||
|
||||
def get_update_l3_policy_attrs(self):
|
||||
attrs = cm.get_update_l3_policy_attrs()
|
||||
attrs.update({'subnetpools_v4': [tgp._uuid(), tgp._uuid()]})
|
||||
attrs.update({'subnetpools_v6': [tgp._uuid(), tgp._uuid()]})
|
||||
attrs.update({'routers': [tgp._uuid(), tgp._uuid()]})
|
||||
return attrs
|
||||
|
||||
|
|
Loading…
Reference in New Issue