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:
		@@ -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
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user