Represent External Connectivity in GBP: API-DB
Today, the GBP model only represents east-west traffic policies. This new API and reference implementation allows north-south traffic in a GBP enabled cloud partial implements blueprint external-connectivity Change-Id: I9799e6e8ce439bf45d5aef3d800c90df29c06fb3
This commit is contained in:
		@@ -14,6 +14,7 @@ import sqlalchemy as sa
 | 
			
		||||
from sqlalchemy import orm
 | 
			
		||||
from sqlalchemy.orm import exc
 | 
			
		||||
 | 
			
		||||
from neutron.api.v2 import attributes as attr
 | 
			
		||||
from neutron.common import log
 | 
			
		||||
from neutron import context
 | 
			
		||||
from neutron.db import common_db_mixin
 | 
			
		||||
@@ -30,6 +31,18 @@ from gbp.neutron.services.grouppolicy.common import constants as gp_constants
 | 
			
		||||
LOG = logging.getLogger(__name__)
 | 
			
		||||
MAX_IPV4_SUBNET_PREFIX_LENGTH = 31
 | 
			
		||||
MAX_IPV6_SUBNET_PREFIX_LENGTH = 127
 | 
			
		||||
ADDRESS_NOT_SPECIFIED = ''
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class HasNameDescription(object):
 | 
			
		||||
    name = sa.Column(sa.String(50))
 | 
			
		||||
    description = sa.Column(sa.String(255))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BaseSharedGbpResource(models_v2.HasId, models_v2.HasTenant,
 | 
			
		||||
                            HasNameDescription):
 | 
			
		||||
    shared = sa.Column(sa.Boolean)
 | 
			
		||||
    pass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PolicyTarget(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
 | 
			
		||||
@@ -118,6 +131,21 @@ class L2Policy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
 | 
			
		||||
    shared = sa.Column(sa.Boolean)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ESToL3PAssociation(model_base.BASEV2):
 | 
			
		||||
    """Many to many consuming relation between ESs and L3Ps."""
 | 
			
		||||
    __tablename__ = 'gp_es_to_l3p_associations'
 | 
			
		||||
    __table_args__ = (
 | 
			
		||||
        sa.UniqueConstraint('external_segment_id', 'allocated_address'),
 | 
			
		||||
    )
 | 
			
		||||
    l3_policy_id = sa.Column(sa.String(36), sa.ForeignKey('gp_l3_policies.id'),
 | 
			
		||||
                             primary_key=True)
 | 
			
		||||
    external_segment_id = sa.Column(
 | 
			
		||||
        sa.String(36), sa.ForeignKey('gp_external_segments.id'),
 | 
			
		||||
        primary_key=True)
 | 
			
		||||
    allocated_address = sa.Column(sa.String(64), nullable=False,
 | 
			
		||||
                                  primary_key=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class L3Policy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
 | 
			
		||||
    """Represents a L3 Policy with a non-overlapping IP address space."""
 | 
			
		||||
    __tablename__ = 'gp_l3_policies'
 | 
			
		||||
@@ -133,6 +161,9 @@ class L3Policy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
 | 
			
		||||
    subnet_prefix_length = sa.Column(sa.Integer, nullable=False)
 | 
			
		||||
    l2_policies = orm.relationship(L2Policy, backref='l3_policy')
 | 
			
		||||
    shared = sa.Column(sa.Boolean)
 | 
			
		||||
    external_segments = orm.relationship(
 | 
			
		||||
        ESToL3PAssociation, backref='l3_policies',
 | 
			
		||||
        cascade='all, delete-orphan')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NetworkServiceParam(model_base.BASEV2, models_v2.HasId):
 | 
			
		||||
@@ -235,6 +266,28 @@ class PolicyAction(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
 | 
			
		||||
    shared = sa.Column(sa.Boolean)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EPToPRSProvidingAssociation(model_base.BASEV2):
 | 
			
		||||
    """Many to many providing relation between EPs and Policy Rule Sets."""
 | 
			
		||||
    __tablename__ = 'gp_ep_to_prs_providing_associations'
 | 
			
		||||
    policy_rule_set_id = sa.Column(sa.String(36),
 | 
			
		||||
                                   sa.ForeignKey('gp_policy_rule_sets.id'),
 | 
			
		||||
                                   primary_key=True)
 | 
			
		||||
    external_policy_id = sa.Column(
 | 
			
		||||
        sa.String(36), sa.ForeignKey('gp_external_policies.id'),
 | 
			
		||||
        primary_key=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EPToPRSConsumingAssociation(model_base.BASEV2):
 | 
			
		||||
    """Many to many consuming relation between EPs and Policy Rule Sets."""
 | 
			
		||||
    __tablename__ = 'gp_ep_to_prs_consuming_associations'
 | 
			
		||||
    policy_rule_set_id = sa.Column(sa.String(36),
 | 
			
		||||
                                   sa.ForeignKey('gp_policy_rule_sets.id'),
 | 
			
		||||
                                   primary_key=True)
 | 
			
		||||
    external_policy_id = sa.Column(
 | 
			
		||||
        sa.String(36), sa.ForeignKey('gp_external_policies.id'),
 | 
			
		||||
        primary_key=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class PolicyRuleSet(model_base.BASEV2, models_v2.HasTenant):
 | 
			
		||||
    """It is a collection of Policy rules."""
 | 
			
		||||
    __tablename__ = 'gp_policy_rule_sets'
 | 
			
		||||
@@ -256,9 +309,81 @@ class PolicyRuleSet(model_base.BASEV2, models_v2.HasTenant):
 | 
			
		||||
    consuming_policy_target_groups = orm.relationship(
 | 
			
		||||
        PTGToPRSConsumingAssociation,
 | 
			
		||||
        backref='consumed_policy_rule_set', lazy="joined", cascade='all')
 | 
			
		||||
    providing_external_policies = orm.relationship(
 | 
			
		||||
        EPToPRSProvidingAssociation,
 | 
			
		||||
        backref='provided_policy_rule_set', lazy="joined", cascade='all')
 | 
			
		||||
    consuming_external_policies = orm.relationship(
 | 
			
		||||
        EPToPRSConsumingAssociation,
 | 
			
		||||
        backref='consumed_policy_rule_set', lazy="joined", cascade='all')
 | 
			
		||||
    shared = sa.Column(sa.Boolean)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NATPool(model_base.BASEV2, BaseSharedGbpResource):
 | 
			
		||||
    __tablename__ = 'gp_nat_pools'
 | 
			
		||||
    ip_version = sa.Column(sa.Integer, nullable=False)
 | 
			
		||||
    ip_pool = sa.Column(sa.String(64), nullable=False)
 | 
			
		||||
    external_segment_id = sa.Column(
 | 
			
		||||
        sa.String(36), sa.ForeignKey('gp_external_segments.id'))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExternalRoute(model_base.BASEV2):
 | 
			
		||||
    __tablename__ = 'gp_external_routes'
 | 
			
		||||
    external_segment_id = sa.Column(
 | 
			
		||||
        sa.String(36), sa.ForeignKey('gp_external_segments.id',
 | 
			
		||||
                                     ondelete='CASCADE'),
 | 
			
		||||
        primary_key=True)
 | 
			
		||||
    destination = sa.Column(sa.String(64), nullable=False, primary_key=True)
 | 
			
		||||
    nexthop = sa.Column(sa.String(64), primary_key=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class EPToESAssociation(model_base.BASEV2):
 | 
			
		||||
    """Many to many consuming relation between ESs and EPs."""
 | 
			
		||||
    __tablename__ = 'gp_es_to_ep_associations'
 | 
			
		||||
    external_policy_id = sa.Column(
 | 
			
		||||
        sa.String(36), sa.ForeignKey('gp_external_policies.id'),
 | 
			
		||||
        primary_key=True)
 | 
			
		||||
    external_segment_id = sa.Column(
 | 
			
		||||
        sa.String(36), sa.ForeignKey('gp_external_segments.id'),
 | 
			
		||||
        primary_key=True)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExternalSegment(model_base.BASEV2, BaseSharedGbpResource):
 | 
			
		||||
    __tablename__ = 'gp_external_segments'
 | 
			
		||||
    type = sa.Column(sa.String(15))
 | 
			
		||||
    __mapper_args__ = {
 | 
			
		||||
        'polymorphic_on': type,
 | 
			
		||||
        'polymorphic_identity': 'base'
 | 
			
		||||
    }
 | 
			
		||||
    ip_version = sa.Column(sa.Integer, nullable=False)
 | 
			
		||||
    cidr = sa.Column(sa.String(64), nullable=False)
 | 
			
		||||
    port_address_translation = sa.Column(sa.Boolean)
 | 
			
		||||
    nat_pools = orm.relationship(NATPool, backref='external_segment')
 | 
			
		||||
    external_policies = orm.relationship(
 | 
			
		||||
        EPToESAssociation, backref='external_segments',
 | 
			
		||||
        cascade='all, delete-orphan')
 | 
			
		||||
    l3_policies = orm.relationship(
 | 
			
		||||
        ESToL3PAssociation, backref='external_segments',
 | 
			
		||||
        cascade='all, delete-orphan')
 | 
			
		||||
    external_routes = orm.relationship(
 | 
			
		||||
        ExternalRoute, backref='external_segment',
 | 
			
		||||
        cascade='all, delete-orphan')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExternalPolicy(model_base.BASEV2, BaseSharedGbpResource):
 | 
			
		||||
    __tablename__ = 'gp_external_policies'
 | 
			
		||||
    external_segments = orm.relationship(
 | 
			
		||||
        EPToESAssociation,
 | 
			
		||||
        backref='external_policies', cascade='all, delete-orphan')
 | 
			
		||||
    provided_policy_rule_sets = orm.relationship(
 | 
			
		||||
        EPToPRSProvidingAssociation,
 | 
			
		||||
        backref='providing_external_policies',
 | 
			
		||||
        cascade='all, delete-orphan')
 | 
			
		||||
    consumed_policy_rule_sets = orm.relationship(
 | 
			
		||||
        EPToPRSConsumingAssociation,
 | 
			
		||||
        backref='consuming_external_policies',
 | 
			
		||||
        cascade='all, delete-orphan')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
                          common_db_mixin.CommonDbMixin):
 | 
			
		||||
    """GroupPolicy plugin interface implementation using SQLAlchemy models."""
 | 
			
		||||
@@ -271,6 +396,13 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
    def __init__(self, *args, **kwargs):
 | 
			
		||||
        super(GroupPolicyDbPlugin, self).__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def _find_gbp_resource(self, context, type, id, on_fail=None):
 | 
			
		||||
        try:
 | 
			
		||||
            return self._get_by_id(context, type, id)
 | 
			
		||||
        except exc.NoResultFound:
 | 
			
		||||
            if on_fail:
 | 
			
		||||
                raise on_fail(id=id)
 | 
			
		||||
 | 
			
		||||
    def _get_policy_target(self, context, policy_target_id):
 | 
			
		||||
        try:
 | 
			
		||||
            return self._get_by_id(context, PolicyTarget, policy_target_id)
 | 
			
		||||
@@ -341,6 +473,21 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
                policy_rule_set_id=policy_rule_set_id)
 | 
			
		||||
        return policy_rule_set
 | 
			
		||||
 | 
			
		||||
    def _get_external_policy(self, context, external_policy_id):
 | 
			
		||||
        return self._find_gbp_resource(
 | 
			
		||||
            context, ExternalPolicy, external_policy_id,
 | 
			
		||||
            gpolicy.ExternalPolicyNotFound)
 | 
			
		||||
 | 
			
		||||
    def _get_external_segment(self, context, external_segment_id):
 | 
			
		||||
        return self._find_gbp_resource(
 | 
			
		||||
            context, ExternalSegment, external_segment_id,
 | 
			
		||||
            gpolicy.ExternalSegmentNotFound)
 | 
			
		||||
 | 
			
		||||
    def _get_nat_pool(self, context, nat_pool_id):
 | 
			
		||||
        return self._find_gbp_resource(
 | 
			
		||||
            context, NATPool, nat_pool_id,
 | 
			
		||||
            gpolicy.NATPoolNotFound)
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def _get_min_max_ports_from_range(port_range):
 | 
			
		||||
        if not port_range:
 | 
			
		||||
@@ -378,7 +525,7 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
            # New list of actions is valid so we will first reset the existing
 | 
			
		||||
            # list and then add each action in order.
 | 
			
		||||
            # Note that the list could be empty in which case we interpret
 | 
			
		||||
            # it as clearing existing rules.
 | 
			
		||||
            # it as clering existing rules.
 | 
			
		||||
            pr_db.policy_actions = []
 | 
			
		||||
            for action_id in action_id_list:
 | 
			
		||||
                assoc = PolicyRuleActionAssociation(policy_rule_id=pr_db.id,
 | 
			
		||||
@@ -403,14 +550,31 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
 | 
			
		||||
    def _set_providers_or_consumers_for_policy_target_group(
 | 
			
		||||
            self, context, ptg_db, policy_rule_sets_dict, provider=True):
 | 
			
		||||
        assoc_table = (PTGToPRSProvidingAssociation if provider else
 | 
			
		||||
                       PTGToPRSConsumingAssociation)
 | 
			
		||||
        self._set_providers_or_consumers_for_res(
 | 
			
		||||
            context, 'policy_target_group', ptg_db, policy_rule_sets_dict,
 | 
			
		||||
            assoc_table, provider=provider)
 | 
			
		||||
 | 
			
		||||
    def _set_providers_or_consumers_for_ep(
 | 
			
		||||
            self, context, ep_db, policy_rule_sets_dict, provider=True):
 | 
			
		||||
        assoc_table = (EPToPRSProvidingAssociation if provider else
 | 
			
		||||
                       EPToPRSConsumingAssociation)
 | 
			
		||||
        self._set_providers_or_consumers_for_res(
 | 
			
		||||
            context, 'external_policy', ep_db, policy_rule_sets_dict,
 | 
			
		||||
            assoc_table, provider=provider)
 | 
			
		||||
 | 
			
		||||
    def _set_providers_or_consumers_for_res(
 | 
			
		||||
            self, context, type, db_res, policy_rule_sets_dict, assoc_table,
 | 
			
		||||
            provider=True):
 | 
			
		||||
        # TODO(Sumit): Check that the same policy_rule_set ID does not belong
 | 
			
		||||
        # to provider and consumer dicts
 | 
			
		||||
        if not policy_rule_sets_dict:
 | 
			
		||||
            if provider:
 | 
			
		||||
                ptg_db.provided_policy_rule_sets = []
 | 
			
		||||
                db_res.provided_policy_rule_sets = []
 | 
			
		||||
                return
 | 
			
		||||
            else:
 | 
			
		||||
                ptg_db.consumed_policy_rule_sets = []
 | 
			
		||||
                db_res.consumed_policy_rule_sets = []
 | 
			
		||||
                return
 | 
			
		||||
        with context.session.begin(subtransactions=True):
 | 
			
		||||
            policy_rule_sets_id_list = policy_rule_sets_dict.keys()
 | 
			
		||||
@@ -420,22 +584,19 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
            # New list of policy_rule_sets is valid so we will first reset the
 | 
			
		||||
            # existing list and then add each policy_rule_set.
 | 
			
		||||
            # Note that the list could be empty in which case we interpret
 | 
			
		||||
            # it as clearing existing rules.
 | 
			
		||||
            # it as clering existing rules.
 | 
			
		||||
            if provider:
 | 
			
		||||
                ptg_db.provided_policy_rule_sets = []
 | 
			
		||||
                db_res.provided_policy_rule_sets = []
 | 
			
		||||
            else:
 | 
			
		||||
                ptg_db.consumed_policy_rule_sets = []
 | 
			
		||||
                db_res.consumed_policy_rule_sets = []
 | 
			
		||||
            for policy_rule_set_id in policy_rule_sets_id_list:
 | 
			
		||||
                kwargs = {type + '_id': db_res.id,
 | 
			
		||||
                          'policy_rule_set_id': policy_rule_set_id}
 | 
			
		||||
                assoc = assoc_table(**kwargs)
 | 
			
		||||
                if provider:
 | 
			
		||||
                    assoc = PTGToPRSProvidingAssociation(
 | 
			
		||||
                        policy_target_group_id=ptg_db.id,
 | 
			
		||||
                        policy_rule_set_id=policy_rule_set_id)
 | 
			
		||||
                    ptg_db.provided_policy_rule_sets.append(assoc)
 | 
			
		||||
                    db_res.provided_policy_rule_sets.append(assoc)
 | 
			
		||||
                else:
 | 
			
		||||
                    assoc = PTGToPRSConsumingAssociation(
 | 
			
		||||
                        policy_target_group_id=ptg_db.id,
 | 
			
		||||
                        policy_rule_set_id=policy_rule_set_id)
 | 
			
		||||
                    ptg_db.consumed_policy_rule_sets.append(assoc)
 | 
			
		||||
                    db_res.consumed_policy_rule_sets.append(assoc)
 | 
			
		||||
 | 
			
		||||
    def _set_children_for_policy_rule_set(self, context,
 | 
			
		||||
                                          policy_rule_set_db, child_id_list):
 | 
			
		||||
@@ -462,7 +623,7 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
            # New list of child policy_rule_sets is valid so we will first
 | 
			
		||||
            # reset the existing list and then add each policy_rule_set.
 | 
			
		||||
            # Note that the list could be empty in which case we interpret
 | 
			
		||||
            # it as clearing existing child policy_rule_sets.
 | 
			
		||||
            # it as clering existing child policy_rule_sets.
 | 
			
		||||
            policy_rule_set_db.child_policy_rule_sets = []
 | 
			
		||||
            for child in policy_rule_sets_in_db:
 | 
			
		||||
                policy_rule_set_db.child_policy_rule_sets.append(child)
 | 
			
		||||
@@ -487,7 +648,7 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
            # New list of rules is valid so we will first reset the existing
 | 
			
		||||
            # list and then add each rule in order.
 | 
			
		||||
            # Note that the list could be empty in which case we interpret
 | 
			
		||||
            # it as clearing existing rules.
 | 
			
		||||
            # it as clering existing rules.
 | 
			
		||||
            prs_db.policy_rules = []
 | 
			
		||||
            for rule_id in rule_id_list:
 | 
			
		||||
                prs_rule_db = PRSToPRAssociation(
 | 
			
		||||
@@ -495,17 +656,28 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
                    policy_rule_set_id=prs_db.id)
 | 
			
		||||
                prs_db.policy_rules.append(prs_rule_db)
 | 
			
		||||
 | 
			
		||||
    def _process_policy_rule_sets_for_ptg(self, context, ptg_db, ptg):
 | 
			
		||||
    def _process_policy_rule_sets_for_ptg(self, context, db_res, ptg):
 | 
			
		||||
        if 'provided_policy_rule_sets' in ptg:
 | 
			
		||||
            self._set_providers_or_consumers_for_policy_target_group(
 | 
			
		||||
                context, ptg_db, ptg['provided_policy_rule_sets'])
 | 
			
		||||
                context, db_res, ptg['provided_policy_rule_sets'])
 | 
			
		||||
            del ptg['provided_policy_rule_sets']
 | 
			
		||||
        if 'consumed_policy_rule_sets' in ptg:
 | 
			
		||||
            self._set_providers_or_consumers_for_policy_target_group(
 | 
			
		||||
                context, ptg_db, ptg['consumed_policy_rule_sets'], False)
 | 
			
		||||
                context, db_res, ptg['consumed_policy_rule_sets'], False)
 | 
			
		||||
            del ptg['consumed_policy_rule_sets']
 | 
			
		||||
        return ptg
 | 
			
		||||
 | 
			
		||||
    def _process_policy_rule_sets_for_ep(self, context, db_res, res):
 | 
			
		||||
        if 'provided_policy_rule_sets' in res:
 | 
			
		||||
            self._set_providers_or_consumers_for_ep(
 | 
			
		||||
                context, db_res, res['provided_policy_rule_sets'])
 | 
			
		||||
            del res['provided_policy_rule_sets']
 | 
			
		||||
        if 'consumed_policy_rule_sets' in res:
 | 
			
		||||
            self._set_providers_or_consumers_for_ep(
 | 
			
		||||
                context, db_res, res['consumed_policy_rule_sets'], False)
 | 
			
		||||
            del res['consumed_policy_rule_sets']
 | 
			
		||||
        return res
 | 
			
		||||
 | 
			
		||||
    def _set_l3_policy_for_l2_policy(self, context, l2p_id, l3p_id):
 | 
			
		||||
        with context.session.begin(subtransactions=True):
 | 
			
		||||
            l2p_db = self._get_l2_policy(context, l2p_id)
 | 
			
		||||
@@ -539,6 +711,67 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
                nsp_db.network_service_params.append(param_db)
 | 
			
		||||
            del network_service_policy['network_service_params']
 | 
			
		||||
 | 
			
		||||
    def _set_ess_for_ep(self, context, ep_db, es_id_list):
 | 
			
		||||
        if not es_id_list:
 | 
			
		||||
            ep_db.external_segments = []
 | 
			
		||||
            return
 | 
			
		||||
        with context.session.begin(subtransactions=True):
 | 
			
		||||
            filters = {'id': es_id_list}
 | 
			
		||||
            eps_in_db = self._get_collection_query(
 | 
			
		||||
                context, ExternalSegment, filters=filters)
 | 
			
		||||
            not_found = set(es_id_list) - set(ep['id'] for ep in eps_in_db)
 | 
			
		||||
            if not_found:
 | 
			
		||||
                raise gpolicy.ExternalSegmentNotFound(
 | 
			
		||||
                    id=not_found.pop())
 | 
			
		||||
            ep_db.external_segments = []
 | 
			
		||||
            for ep_id in es_id_list:
 | 
			
		||||
                assoc = EPToESAssociation(
 | 
			
		||||
                    external_policy_id=ep_db.id,
 | 
			
		||||
                    external_segment_id=ep_id)
 | 
			
		||||
                ep_db.external_segments.append(assoc)
 | 
			
		||||
 | 
			
		||||
    def _process_segment_ers(self, context, es_db, es):
 | 
			
		||||
        if es['external_routes'] is not attr.ATTR_NOT_SPECIFIED:
 | 
			
		||||
            es_db.external_routes = []
 | 
			
		||||
            for rt in es['external_routes']:
 | 
			
		||||
                target = ExternalRoute(
 | 
			
		||||
                    external_segment_id=es_db.id,
 | 
			
		||||
                    destination=rt['destination'],
 | 
			
		||||
                    nexthop=rt['nexthop'] or ADDRESS_NOT_SPECIFIED)
 | 
			
		||||
                es_db.external_routes.append(target)
 | 
			
		||||
 | 
			
		||||
    def _set_ess_for_l3p(self, context, l3p_db, es_dict):
 | 
			
		||||
        if es_dict is attr.ATTR_NOT_SPECIFIED:
 | 
			
		||||
            return
 | 
			
		||||
        if not es_dict:
 | 
			
		||||
            l3p_db.external_segments = []
 | 
			
		||||
            return
 | 
			
		||||
        with context.session.begin(subtransactions=True):
 | 
			
		||||
            # Validate ESs exist
 | 
			
		||||
            es_set = set(es_dict.keys())
 | 
			
		||||
            filters = {'id': es_set}
 | 
			
		||||
            es_in_db = self._get_collection_query(
 | 
			
		||||
                context, ExternalSegment, filters=filters)
 | 
			
		||||
            not_found = es_set - set(es['id'] for es in es_in_db)
 | 
			
		||||
            if not_found:
 | 
			
		||||
                raise gpolicy.ExternalSegmentNotFound(
 | 
			
		||||
                    id=not_found.pop())
 | 
			
		||||
            l3p_db.external_segments = []
 | 
			
		||||
            for es in es_in_db:
 | 
			
		||||
                if not es_dict[es['id']]:
 | 
			
		||||
                    assoc = ESToL3PAssociation(
 | 
			
		||||
                        external_segment_id=es['id'],
 | 
			
		||||
                        l3_policy_id=l3p_db['id'],
 | 
			
		||||
                        allocated_address=ADDRESS_NOT_SPECIFIED)
 | 
			
		||||
                    l3p_db.external_segments.append(assoc)
 | 
			
		||||
                else:
 | 
			
		||||
                    # Create address allocation
 | 
			
		||||
                    for ip in es_dict[es['id']]:
 | 
			
		||||
                        assoc = ESToL3PAssociation(
 | 
			
		||||
                            external_segment_id=es['id'],
 | 
			
		||||
                            l3_policy_id=l3p_db['id'], allocated_address=ip)
 | 
			
		||||
                        l3p_db.external_segments.append(assoc)
 | 
			
		||||
 | 
			
		||||
    def _make_policy_target_dict(self, pt, fields=None):
 | 
			
		||||
        res = {'id': pt['id'],
 | 
			
		||||
               'tenant_id': pt['tenant_id'],
 | 
			
		||||
@@ -588,6 +821,13 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
               'shared': l3p.get('shared', False), }
 | 
			
		||||
        res['l2_policies'] = [l2p['id']
 | 
			
		||||
                              for l2p in l3p['l2_policies']]
 | 
			
		||||
        es_dict = {}
 | 
			
		||||
        for es in l3p['external_segments']:
 | 
			
		||||
            es_id = es['external_segment_id']
 | 
			
		||||
            if es_id not in es_dict:
 | 
			
		||||
                es_dict[es_id] = []
 | 
			
		||||
            es_dict[es_id].append(es['allocated_address'])
 | 
			
		||||
        res['external_segments'] = es_dict
 | 
			
		||||
        return self._fields(res, fields)
 | 
			
		||||
 | 
			
		||||
    def _make_network_service_policy_dict(self, nsp, fields=None):
 | 
			
		||||
@@ -672,9 +912,67 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
        res['providing_policy_target_groups'] = [
 | 
			
		||||
            ptg['policy_target_group_id']
 | 
			
		||||
            for ptg in prs['providing_policy_target_groups']]
 | 
			
		||||
 | 
			
		||||
        res['consuming_policy_target_groups'] = [
 | 
			
		||||
            ptg['policy_target_group_id']
 | 
			
		||||
            for ptg in prs['consuming_policy_target_groups']]
 | 
			
		||||
 | 
			
		||||
        res['providing_external_policies'] = [
 | 
			
		||||
            ptg['external_policy_id']
 | 
			
		||||
            for ptg in prs['providing_external_policies']]
 | 
			
		||||
 | 
			
		||||
        res['consuming_external_policies'] = [
 | 
			
		||||
            ptg['external_policy_id']
 | 
			
		||||
            for ptg in prs['consuming_external_policies']]
 | 
			
		||||
        return self._fields(res, fields)
 | 
			
		||||
 | 
			
		||||
    def _make_external_segment_dict(self, es, fields=None):
 | 
			
		||||
        res = {'id': es['id'],
 | 
			
		||||
               'tenant_id': es['tenant_id'],
 | 
			
		||||
               'name': es['name'],
 | 
			
		||||
               'description': es['description'],
 | 
			
		||||
               'shared': es.get('shared', False),
 | 
			
		||||
               'ip_version': es['ip_version'],
 | 
			
		||||
               'cidr': es['cidr'],
 | 
			
		||||
               'port_address_translation': es['port_address_translation']}
 | 
			
		||||
        res['external_routes'] = [{'destination': er['destination'],
 | 
			
		||||
                                   'nexthop': er['nexthop']} for er in
 | 
			
		||||
                                  es['external_routes']]
 | 
			
		||||
        res['nat_pools'] = [np['id'] for np in es['nat_pools']]
 | 
			
		||||
        res['external_policies'] = [
 | 
			
		||||
            ep['external_policy_id']
 | 
			
		||||
            for ep in es['external_policies']]
 | 
			
		||||
 | 
			
		||||
        res['l3_policies'] = [
 | 
			
		||||
            l3p['l3_policy_id'] for l3p in es['l3_policies']]
 | 
			
		||||
        return self._fields(res, fields)
 | 
			
		||||
 | 
			
		||||
    def _make_external_policy_dict(self, ep, fields=None):
 | 
			
		||||
        res = {'id': ep['id'],
 | 
			
		||||
               'tenant_id': ep['tenant_id'],
 | 
			
		||||
               'name': ep['name'],
 | 
			
		||||
               'description': ep['description'],
 | 
			
		||||
               'shared': ep.get('shared', False), }
 | 
			
		||||
        res['external_segments'] = [
 | 
			
		||||
            es['external_segment_id']
 | 
			
		||||
            for es in ep['external_segments']]
 | 
			
		||||
        res['provided_policy_rule_sets'] = [
 | 
			
		||||
            pprs['policy_rule_set_id'] for pprs in
 | 
			
		||||
            ep['provided_policy_rule_sets']]
 | 
			
		||||
        res['consumed_policy_rule_sets'] = [
 | 
			
		||||
            cprs['policy_rule_set_id'] for cprs in
 | 
			
		||||
            ep['consumed_policy_rule_sets']]
 | 
			
		||||
        return self._fields(res, fields)
 | 
			
		||||
 | 
			
		||||
    def _make_nat_pool_dict(self, np, fields=None):
 | 
			
		||||
        res = {'id': np['id'],
 | 
			
		||||
               'tenant_id': np['tenant_id'],
 | 
			
		||||
               'name': np['name'],
 | 
			
		||||
               'description': np['description'],
 | 
			
		||||
               'shared': np.get('shared', False),
 | 
			
		||||
               'ip_version': np['ip_version'],
 | 
			
		||||
               'ip_pool': np['ip_pool'],
 | 
			
		||||
               'external_segment_id': np['external_segment_id']}
 | 
			
		||||
        return self._fields(res, fields)
 | 
			
		||||
 | 
			
		||||
    def _get_policy_rule_policy_rule_sets(self, context, policy_rule_id):
 | 
			
		||||
@@ -687,6 +985,17 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
                context.session.query(PolicyRuleActionAssociation).filter_by(
 | 
			
		||||
                    policy_action_id=policy_action_id)]
 | 
			
		||||
 | 
			
		||||
    def _get_external_segment_external_policies(self, context, es_id):
 | 
			
		||||
        return [x['external_policy_id'] for x in
 | 
			
		||||
                context.session.query(EPToESAssociation).filter_by(
 | 
			
		||||
                    external_segment_id=es_id)]
 | 
			
		||||
 | 
			
		||||
    def _get_attribute(self, attrs, key):
 | 
			
		||||
        value = attrs.get(key)
 | 
			
		||||
        if value is attr.ATTR_NOT_SPECIFIED:
 | 
			
		||||
            value = None
 | 
			
		||||
        return value
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
    def validate_subnet_prefix_length(ip_version, new_prefix_length):
 | 
			
		||||
        if (new_prefix_length < 2) or (
 | 
			
		||||
@@ -870,6 +1179,9 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
                ip_pool=l3p['ip_pool'],
 | 
			
		||||
                subnet_prefix_length=l3p['subnet_prefix_length'],
 | 
			
		||||
                shared=l3p.get('shared', False))
 | 
			
		||||
            if 'external_segments' in l3p:
 | 
			
		||||
                self._set_ess_for_l3p(context, l3p_db,
 | 
			
		||||
                                      l3p['external_segments'])
 | 
			
		||||
                context.session.add(l3p_db)
 | 
			
		||||
        return self._make_l3_policy_dict(l3p_db)
 | 
			
		||||
 | 
			
		||||
@@ -882,6 +1194,10 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
                self.validate_subnet_prefix_length(
 | 
			
		||||
                    l3p_db.ip_version,
 | 
			
		||||
                    l3p['subnet_prefix_length'])
 | 
			
		||||
            if 'external_segments' in l3p:
 | 
			
		||||
                self._set_ess_for_l3p(context, l3p_db,
 | 
			
		||||
                                      l3p['external_segments'])
 | 
			
		||||
                del l3p['external_segments']
 | 
			
		||||
            l3p_db.update(l3p)
 | 
			
		||||
        return self._make_l3_policy_dict(l3p_db)
 | 
			
		||||
 | 
			
		||||
@@ -1206,3 +1522,155 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
 | 
			
		||||
    def get_policy_rule_sets_count(self, context, filters=None):
 | 
			
		||||
        return self._get_collection_count(context, PolicyRuleSet,
 | 
			
		||||
                                          filters=filters)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def create_external_policy(self, context, external_policy):
 | 
			
		||||
        ep = external_policy['external_policy']
 | 
			
		||||
        tenant_id = self._get_tenant_id_for_create(context, ep)
 | 
			
		||||
        with context.session.begin(subtransactions=True):
 | 
			
		||||
            ep_db = ExternalPolicy(
 | 
			
		||||
                id=uuidutils.generate_uuid(), tenant_id=tenant_id,
 | 
			
		||||
                name=ep['name'], description=ep['description'],
 | 
			
		||||
                shared=ep.get('shared', False))
 | 
			
		||||
            context.session.add(ep_db)
 | 
			
		||||
            if 'external_segments' in ep:
 | 
			
		||||
                self._set_ess_for_ep(context, ep_db,
 | 
			
		||||
                                     ep['external_segments'])
 | 
			
		||||
            self._process_policy_rule_sets_for_ep(context, ep_db, ep)
 | 
			
		||||
        return self._make_external_policy_dict(ep_db)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def update_external_policy(self, context, external_policy_id,
 | 
			
		||||
                               external_policy):
 | 
			
		||||
        ep = external_policy['external_policy']
 | 
			
		||||
        with context.session.begin(subtransactions=True):
 | 
			
		||||
            ep_db = self._get_external_policy(
 | 
			
		||||
                context, external_policy_id)
 | 
			
		||||
            if 'external_segments' in ep:
 | 
			
		||||
                self._set_ess_for_ep(context, ep_db,
 | 
			
		||||
                                     ep['external_segments'])
 | 
			
		||||
                del ep['external_segments']
 | 
			
		||||
            self._process_policy_rule_sets_for_ep(context, ep_db, ep)
 | 
			
		||||
            ep_db.update(ep)
 | 
			
		||||
        return self._make_external_policy_dict(ep_db)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def get_external_policies(self, context, filters=None, fields=None):
 | 
			
		||||
        return self._get_collection(context, ExternalPolicy,
 | 
			
		||||
                                    self._make_external_policy_dict,
 | 
			
		||||
                                    filters=filters, fields=fields)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def get_external_policies_count(self, context, filters=None):
 | 
			
		||||
        return self._get_collection_count(context, ExternalPolicy,
 | 
			
		||||
                                          filters=filters)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def get_external_policy(self, context, external_policy_id, fields=None):
 | 
			
		||||
        ep = self._get_external_policy(
 | 
			
		||||
            context, external_policy_id)
 | 
			
		||||
        return self._make_external_policy_dict(ep, fields)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def delete_external_policy(self, context, external_policy_id):
 | 
			
		||||
        with context.session.begin(subtransactions=True):
 | 
			
		||||
            ep_db = self._get_external_policy(
 | 
			
		||||
                context, external_policy_id)
 | 
			
		||||
            context.session.delete(ep_db)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def create_external_segment(self, context, external_segment):
 | 
			
		||||
        es = external_segment['external_segment']
 | 
			
		||||
        tenant_id = self._get_tenant_id_for_create(context, es)
 | 
			
		||||
        with context.session.begin(subtransactions=True):
 | 
			
		||||
            es_db = ExternalSegment(
 | 
			
		||||
                id=uuidutils.generate_uuid(), tenant_id=tenant_id,
 | 
			
		||||
                name=es['name'], description=es['description'],
 | 
			
		||||
                shared=es.get('shared', False), ip_version=es['ip_version'],
 | 
			
		||||
                cidr=es['cidr'],
 | 
			
		||||
                port_address_translation=es['port_address_translation'])
 | 
			
		||||
            context.session.add(es_db)
 | 
			
		||||
            if 'external_routes' in es:
 | 
			
		||||
                self._process_segment_ers(context, es_db, es)
 | 
			
		||||
        return self._make_external_segment_dict(es_db)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def update_external_segment(self, context, external_segment_id,
 | 
			
		||||
                                external_segment):
 | 
			
		||||
        es = external_segment['external_segment']
 | 
			
		||||
        with context.session.begin(subtransactions=True):
 | 
			
		||||
            es_db = self._get_external_segment(
 | 
			
		||||
                context, external_segment_id)
 | 
			
		||||
            if 'external_routes' in es:
 | 
			
		||||
                self._process_segment_ers(context, es_db, es)
 | 
			
		||||
                del es['external_routes']
 | 
			
		||||
            es_db.update(es)
 | 
			
		||||
        return self._make_external_segment_dict(es_db)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def get_external_segments(self, context, filters=None, fields=None):
 | 
			
		||||
        return self._get_collection(context, ExternalSegment,
 | 
			
		||||
                                    self._make_external_segment_dict,
 | 
			
		||||
                                    filters=filters, fields=fields)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def get_external_segments_count(self, context, filters=None):
 | 
			
		||||
        return self._get_collection_count(context, ExternalSegment,
 | 
			
		||||
                                          filters=filters)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def get_external_segment(self, context, external_segment_id, fields=None):
 | 
			
		||||
        es = self._get_external_segment(
 | 
			
		||||
            context, external_segment_id)
 | 
			
		||||
        return self._make_external_segment_dict(es, fields)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def delete_external_segment(self, context, external_segment_id):
 | 
			
		||||
        with context.session.begin(subtransactions=True):
 | 
			
		||||
            es_db = self._get_external_segment(
 | 
			
		||||
                context, external_segment_id)
 | 
			
		||||
            context.session.delete(es_db)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def create_nat_pool(self, context, nat_pool):
 | 
			
		||||
        np = nat_pool['nat_pool']
 | 
			
		||||
        tenant_id = self._get_tenant_id_for_create(context, np)
 | 
			
		||||
        with context.session.begin(subtransactions=True):
 | 
			
		||||
            np_db = NATPool(
 | 
			
		||||
                id=uuidutils.generate_uuid(), tenant_id=tenant_id,
 | 
			
		||||
                name=np['name'], description=np['description'],
 | 
			
		||||
                shared=np.get('shared', False), ip_version=np['ip_version'],
 | 
			
		||||
                ip_pool=np['ip_pool'],
 | 
			
		||||
                external_segment_id=np['external_segment_id'])
 | 
			
		||||
            context.session.add(np_db)
 | 
			
		||||
        return self._make_nat_pool_dict(np_db)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def update_nat_pool(self, context, nat_pool_id, nat_pool):
 | 
			
		||||
        np = nat_pool['nat_pool']
 | 
			
		||||
        with context.session.begin(subtransactions=True):
 | 
			
		||||
            np_db = self._get_nat_pool(
 | 
			
		||||
                context, nat_pool_id)
 | 
			
		||||
            np_db.update(np)
 | 
			
		||||
        return self._make_nat_pool_dict(np_db)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def get_nat_pools(self, context, filters=None, fields=None):
 | 
			
		||||
        return self._get_collection(context, NATPool,
 | 
			
		||||
                                    self._make_nat_pool_dict,
 | 
			
		||||
                                    filters=filters, fields=fields)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def get_nat_pools_count(self, context, filters=None):
 | 
			
		||||
        return self._get_collection_count(context, NATPool, filters=filters)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def get_nat_pool(self, context, nat_pool_id, fields=None):
 | 
			
		||||
        np = self._get_nat_pool(context, nat_pool_id)
 | 
			
		||||
        return self._make_nat_pool_dict(np, fields)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
    def delete_nat_pool(self, context, nat_pool_id):
 | 
			
		||||
        with context.session.begin(subtransactions=True):
 | 
			
		||||
            np_db = self._get_nat_pool(context, nat_pool_id)
 | 
			
		||||
            context.session.delete(np_db)
 | 
			
		||||
 
 | 
			
		||||
@@ -241,6 +241,9 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
 | 
			
		||||
                        router_id=router
 | 
			
		||||
                    )
 | 
			
		||||
                    l3p_db.routers.append(assoc)
 | 
			
		||||
            if 'external_segments' in l3p:
 | 
			
		||||
                self._set_ess_for_l3p(context, l3p_db,
 | 
			
		||||
                                      l3p['external_segments'])
 | 
			
		||||
        return self._make_l3_policy_dict(l3p_db)
 | 
			
		||||
 | 
			
		||||
    @log.log
 | 
			
		||||
@@ -269,5 +272,9 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
 | 
			
		||||
                    context.session.delete(assoc)
 | 
			
		||||
                # Don't update l3p_db.routers with router IDs.
 | 
			
		||||
                del l3p['routers']
 | 
			
		||||
            if 'external_segments' in l3p:
 | 
			
		||||
                self._set_ess_for_l3p(context, l3p_db,
 | 
			
		||||
                                      l3p['external_segments'])
 | 
			
		||||
                del l3p['external_segments']
 | 
			
		||||
            l3p_db.update(l3p)
 | 
			
		||||
        return self._make_l3_policy_dict(l3p_db)
 | 
			
		||||
 
 | 
			
		||||
@@ -1 +1 @@
 | 
			
		||||
f4d890a9c126
 | 
			
		||||
f16efdc10a71
 | 
			
		||||
@@ -0,0 +1,151 @@
 | 
			
		||||
# Copyright 2014 OpenStack Foundation
 | 
			
		||||
#
 | 
			
		||||
#    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.
 | 
			
		||||
#
 | 
			
		||||
 | 
			
		||||
""" external_connectivity
 | 
			
		||||
 | 
			
		||||
Revision ID: f16efdc10a71
 | 
			
		||||
"""
 | 
			
		||||
 | 
			
		||||
# revision identifiers, used by Alembic.
 | 
			
		||||
revision = 'f16efdc10a71'
 | 
			
		||||
down_revision = 'f4d890a9c126'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
from alembic import op
 | 
			
		||||
import sqlalchemy as sa
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def upgrade():
 | 
			
		||||
 | 
			
		||||
    op.create_table(
 | 
			
		||||
        'gp_external_segments',
 | 
			
		||||
        sa.Column('id', sa.String(36), nullable=False),
 | 
			
		||||
        sa.Column('tenant_id', sa.String(length=255), nullable=True),
 | 
			
		||||
        sa.Column('name', sa.String(length=50), nullable=True),
 | 
			
		||||
        sa.Column('description', sa.String(length=255), nullable=True),
 | 
			
		||||
        sa.Column('shared', sa.Boolean),
 | 
			
		||||
        sa.Column('ip_version', sa.Integer, nullable=False),
 | 
			
		||||
        sa.Column('cidr', sa.String(64), nullable=False),
 | 
			
		||||
        sa.Column('port_address_translation', sa.Boolean),
 | 
			
		||||
        sa.PrimaryKeyConstraint('id'))
 | 
			
		||||
 | 
			
		||||
    op.create_table(
 | 
			
		||||
        'gp_external_policies',
 | 
			
		||||
        sa.Column('id', sa.String(36), nullable=False),
 | 
			
		||||
        sa.Column('tenant_id', sa.String(length=255), nullable=True),
 | 
			
		||||
        sa.Column('name', sa.String(length=50), nullable=True),
 | 
			
		||||
        sa.Column('description', sa.String(length=255), nullable=True),
 | 
			
		||||
        sa.Column('shared', sa.Boolean),
 | 
			
		||||
        sa.PrimaryKeyConstraint('id'))
 | 
			
		||||
 | 
			
		||||
    op.create_table(
 | 
			
		||||
        'gp_ep_to_prs_providing_associations',
 | 
			
		||||
        sa.Column('policy_rule_set_id', sa.String(length=36), nullable=True),
 | 
			
		||||
        sa.ForeignKeyConstraint(['policy_rule_set_id'],
 | 
			
		||||
                                ['gp_policy_rule_sets.id'],
 | 
			
		||||
                                ondelete='CASCADE'),
 | 
			
		||||
        sa.Column('external_policy_id', sa.String(length=36),
 | 
			
		||||
                  nullable=True),
 | 
			
		||||
        sa.ForeignKeyConstraint(['external_policy_id'],
 | 
			
		||||
                                ['gp_external_policies.id'],
 | 
			
		||||
                                ondelete='CASCADE'),
 | 
			
		||||
        sa.PrimaryKeyConstraint('policy_rule_set_id',
 | 
			
		||||
                                'external_policy_id'))
 | 
			
		||||
 | 
			
		||||
    op.create_table(
 | 
			
		||||
        'gp_ep_to_prs_consuming_associations',
 | 
			
		||||
        sa.Column('policy_rule_set_id', sa.String(length=36), nullable=True),
 | 
			
		||||
        sa.ForeignKeyConstraint(['policy_rule_set_id'],
 | 
			
		||||
                                ['gp_policy_rule_sets.id'],
 | 
			
		||||
                                ondelete='CASCADE'),
 | 
			
		||||
        sa.Column('external_policy_id', sa.String(length=36),
 | 
			
		||||
                  nullable=True),
 | 
			
		||||
        sa.ForeignKeyConstraint(['external_policy_id'],
 | 
			
		||||
                                ['gp_external_policies.id'],
 | 
			
		||||
                                ondelete='CASCADE'),
 | 
			
		||||
        sa.PrimaryKeyConstraint('policy_rule_set_id',
 | 
			
		||||
                                'external_policy_id'))
 | 
			
		||||
 | 
			
		||||
    op.create_table(
 | 
			
		||||
        'gp_es_to_ep_associations',
 | 
			
		||||
        sa.Column('external_policy_id', sa.String(length=36),
 | 
			
		||||
                  nullable=True),
 | 
			
		||||
        sa.ForeignKeyConstraint(['external_policy_id'],
 | 
			
		||||
                                ['gp_external_policies.id'],
 | 
			
		||||
                                ondelete='CASCADE'),
 | 
			
		||||
        sa.Column('external_segment_id', sa.String(length=36),
 | 
			
		||||
                  nullable=True),
 | 
			
		||||
        sa.ForeignKeyConstraint(['external_segment_id'],
 | 
			
		||||
                                ['gp_external_segments.id'],
 | 
			
		||||
                                ondelete='CASCADE'),
 | 
			
		||||
        sa.PrimaryKeyConstraint('external_policy_id',
 | 
			
		||||
                                'external_segment_id'))
 | 
			
		||||
 | 
			
		||||
    op.create_table(
 | 
			
		||||
        'gp_external_routes',
 | 
			
		||||
        sa.Column('destination', sa.String(64)),
 | 
			
		||||
        sa.Column('nexthop', sa.String(64)),
 | 
			
		||||
        sa.Column('external_segment_id', sa.String(length=36),
 | 
			
		||||
                  nullable=True),
 | 
			
		||||
        sa.ForeignKeyConstraint(['external_segment_id'],
 | 
			
		||||
                                ['gp_external_segments.id'],
 | 
			
		||||
                                ondelete='CASCADE'),
 | 
			
		||||
        sa.PrimaryKeyConstraint('external_segment_id',
 | 
			
		||||
                                'destination', 'nexthop'))
 | 
			
		||||
 | 
			
		||||
    op.create_table(
 | 
			
		||||
        'gp_nat_pools',
 | 
			
		||||
        sa.Column('id', sa.String(36), nullable=False),
 | 
			
		||||
        sa.Column('tenant_id', sa.String(length=255), nullable=True),
 | 
			
		||||
        sa.Column('name', sa.String(length=50), nullable=True),
 | 
			
		||||
        sa.Column('description', sa.String(length=255), nullable=True),
 | 
			
		||||
        sa.Column('shared', sa.Boolean),
 | 
			
		||||
        sa.Column('ip_version', sa.Integer, nullable=False),
 | 
			
		||||
        sa.Column('ip_pool', sa.String(64), nullable=False),
 | 
			
		||||
        sa.Column('external_segment_id', sa.String(length=36),
 | 
			
		||||
                  nullable=True),
 | 
			
		||||
        sa.ForeignKeyConstraint(['external_segment_id'],
 | 
			
		||||
                                ['gp_external_segments.id']),
 | 
			
		||||
        sa.PrimaryKeyConstraint('id'))
 | 
			
		||||
 | 
			
		||||
    op.create_table(
 | 
			
		||||
        'gp_es_to_l3p_associations',
 | 
			
		||||
        sa.Column('l3_policy_id', sa.String(length=36), nullable=True),
 | 
			
		||||
        sa.ForeignKeyConstraint(['l3_policy_id'],
 | 
			
		||||
                                ['gp_l3_policies.id'],
 | 
			
		||||
                                ondelete='CASCADE'),
 | 
			
		||||
        sa.Column('external_segment_id', sa.String(length=36),
 | 
			
		||||
                  nullable=True),
 | 
			
		||||
        sa.ForeignKeyConstraint(['external_segment_id'],
 | 
			
		||||
                                ['gp_external_segments.id'],
 | 
			
		||||
                                ondelete='CASCADE'),
 | 
			
		||||
        sa.Column('allocated_address', sa.String(64), nullable=False,
 | 
			
		||||
                  primary_key=True),
 | 
			
		||||
        sa.PrimaryKeyConstraint(
 | 
			
		||||
            'l3_policy_id', 'external_segment_id', 'allocated_address'),
 | 
			
		||||
        sa.UniqueConstraint('external_segment_id', 'allocated_address'),
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def downgrade():
 | 
			
		||||
 | 
			
		||||
    op.drop_table('gp_es_to_l3p_associations')
 | 
			
		||||
    op.drop_table('gp_nat_pools')
 | 
			
		||||
    op.drop_table('gp_external_routes')
 | 
			
		||||
    op.drop_table('gp_es_to_ep_associations')
 | 
			
		||||
    op.drop_table('gp_ep_to_prs_consuming_associations')
 | 
			
		||||
    op.drop_table('gp_ep_to_prs_providing_associations')
 | 
			
		||||
    op.drop_table('gp_external_policies')
 | 
			
		||||
    op.drop_table('gp_external_segments')
 | 
			
		||||
@@ -19,6 +19,7 @@ from neutron.api.v2 import attributes as attr
 | 
			
		||||
from neutron.api.v2 import resource_helper
 | 
			
		||||
from neutron.common import exceptions as nexc
 | 
			
		||||
from neutron.openstack.common import log as logging
 | 
			
		||||
from neutron.openstack.common import uuidutils
 | 
			
		||||
from neutron.plugins.common import constants
 | 
			
		||||
from neutron.services import service_base
 | 
			
		||||
 | 
			
		||||
@@ -83,6 +84,18 @@ class PolicyRuleSetNotFound(nexc.NotFound):
 | 
			
		||||
    message = _("Policy Rule Set %(policy_rule_set_id)s could not be found")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExternalPolicyNotFound(nexc.NotFound):
 | 
			
		||||
    message = _("External Policy %(id)s could not be found")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ExternalSegmentNotFound(nexc.NotFound):
 | 
			
		||||
    message = _("External Segment %(id)s could not be found")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NATPoolNotFound(nexc.NotFound):
 | 
			
		||||
    message = _("NAT Pool %(id)s could not be found")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class BadPolicyRuleSetRelationship(nexc.BadRequest):
 | 
			
		||||
    message = _("Policy Rule Set %(parent_id)s is an invalid parent for "
 | 
			
		||||
                "%(child_id)s, make sure that child policy_rule_set has no "
 | 
			
		||||
@@ -160,6 +173,13 @@ def convert_port_to_string(value):
 | 
			
		||||
        return str(value)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def convert_to_int_if_needed(value):
 | 
			
		||||
    if not value or value is attr.ATTR_NOT_SPECIFIED:
 | 
			
		||||
        return value
 | 
			
		||||
    else:
 | 
			
		||||
        return attr.convert_to_int(value)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _validate_gbp_port_range(data, key_specs=None):
 | 
			
		||||
    if data is None:
 | 
			
		||||
        return
 | 
			
		||||
@@ -226,8 +246,57 @@ def _validate_network_svc_params(data, key_specs=None):
 | 
			
		||||
                return msg
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _validate_external_dict(data, key_specs=None):
 | 
			
		||||
    if data is None:
 | 
			
		||||
        return
 | 
			
		||||
    if not isinstance(data, dict):
 | 
			
		||||
        msg = _("'%s' is not a dictionary") % data
 | 
			
		||||
        LOG.debug(msg)
 | 
			
		||||
        return msg
 | 
			
		||||
    for d in data:
 | 
			
		||||
        if not uuidutils.is_uuid_like(d):
 | 
			
		||||
            msg = _("'%s' is not a valid UUID") % d
 | 
			
		||||
            LOG.debug(msg)
 | 
			
		||||
            return msg
 | 
			
		||||
        if not isinstance(data[d], list):
 | 
			
		||||
            msg = _("'%s' is not a list") % data[d]
 | 
			
		||||
            LOG.debug(msg)
 | 
			
		||||
            return msg
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _validate_gbproutes(data, valid_values=None):
 | 
			
		||||
    # Shamelessly copied from Neutron, will pass even if nexthop is valid
 | 
			
		||||
    if not isinstance(data, list):
 | 
			
		||||
        msg = _("Invalid data format for hostroute: '%s'") % data
 | 
			
		||||
        LOG.debug(msg)
 | 
			
		||||
        return msg
 | 
			
		||||
 | 
			
		||||
    expected_keys = ['destination', 'nexthop']
 | 
			
		||||
    hostroutes = []
 | 
			
		||||
    for hostroute in data:
 | 
			
		||||
        msg = attr._verify_dict_keys(expected_keys, hostroute)
 | 
			
		||||
        if msg:
 | 
			
		||||
            LOG.debug(msg)
 | 
			
		||||
            return msg
 | 
			
		||||
        msg = attr._validate_subnet(hostroute['destination'])
 | 
			
		||||
        if msg:
 | 
			
		||||
            LOG.debug(msg)
 | 
			
		||||
            return msg
 | 
			
		||||
        if hostroute['nexthop'] is not None:
 | 
			
		||||
            msg = attr._validate_ip_address(hostroute['nexthop'])
 | 
			
		||||
        if msg:
 | 
			
		||||
            LOG.debug(msg)
 | 
			
		||||
            return msg
 | 
			
		||||
        if hostroute in hostroutes:
 | 
			
		||||
            msg = _("Duplicate hostroute '%s'") % hostroute
 | 
			
		||||
            LOG.debug(msg)
 | 
			
		||||
            return msg
 | 
			
		||||
        hostroutes.append(hostroute)
 | 
			
		||||
 | 
			
		||||
attr.validators['type:gbp_port_range'] = _validate_gbp_port_range
 | 
			
		||||
attr.validators['type:network_service_params'] = _validate_network_svc_params
 | 
			
		||||
attr.validators['type:external_dict'] = _validate_external_dict
 | 
			
		||||
attr.validators['type:gbproutes'] = _validate_gbproutes
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
POLICY_TARGETS = 'policy_targets'
 | 
			
		||||
@@ -239,7 +308,9 @@ POLICY_ACTIONS = 'policy_actions'
 | 
			
		||||
POLICY_RULES = 'policy_rules'
 | 
			
		||||
POLICY_RULE_SETS = 'policy_rule_sets'
 | 
			
		||||
NETWORK_SERVICE_POLICIES = 'network_service_policies'
 | 
			
		||||
 | 
			
		||||
EXTERNAL_POLICIES = 'external_policies'
 | 
			
		||||
EXTERNAL_SEGMENTS = 'external_segments'
 | 
			
		||||
NAT_POOLS = 'nat_pools'
 | 
			
		||||
 | 
			
		||||
RESOURCE_ATTRIBUTE_MAP = {
 | 
			
		||||
    POLICY_TARGETS: {
 | 
			
		||||
@@ -361,6 +432,10 @@ RESOURCE_ATTRIBUTE_MAP = {
 | 
			
		||||
                      'default': False, 'convert_to': attr.convert_to_boolean,
 | 
			
		||||
                      'is_visible': True, 'required_by_policy': True,
 | 
			
		||||
                      'enforce_policy': True},
 | 
			
		||||
        'external_segments': {
 | 
			
		||||
            'allow_post': True, 'allow_put': True, 'default': None,
 | 
			
		||||
            'validate': {'type:external_dict': None},
 | 
			
		||||
            'convert_to': attr.convert_none_to_empty_dict, 'is_visible': True},
 | 
			
		||||
    },
 | 
			
		||||
    POLICY_CLASSIFIERS: {
 | 
			
		||||
        'id': {'allow_post': False, 'allow_put': False,
 | 
			
		||||
@@ -506,6 +581,109 @@ RESOURCE_ATTRIBUTE_MAP = {
 | 
			
		||||
                      'is_visible': True, 'required_by_policy': True,
 | 
			
		||||
                      'enforce_policy': True},
 | 
			
		||||
    },
 | 
			
		||||
    EXTERNAL_POLICIES: {
 | 
			
		||||
        'id': {'allow_post': False, 'allow_put': False,
 | 
			
		||||
               'validate': {'type:uuid': None},
 | 
			
		||||
               'is_visible': True, 'primary_key': True},
 | 
			
		||||
        'name': {'allow_post': True, 'allow_put': True,
 | 
			
		||||
                 'validate': {'type:string': None},
 | 
			
		||||
                 'default': '', 'is_visible': True},
 | 
			
		||||
        'description': {'allow_post': True, 'allow_put': True,
 | 
			
		||||
                        'validate': {'type:string': None},
 | 
			
		||||
                        'is_visible': True, 'default': ''},
 | 
			
		||||
        'tenant_id': {'allow_post': True, 'allow_put': False,
 | 
			
		||||
                      'validate': {'type:string': None},
 | 
			
		||||
                      'required_by_policy': True, 'is_visible': True},
 | 
			
		||||
        'external_segments': {
 | 
			
		||||
            'allow_post': True, 'allow_put': True, 'default': None,
 | 
			
		||||
            'validate': {'type:uuid_list': None},
 | 
			
		||||
            'convert_to': attr.convert_none_to_empty_list, 'is_visible': True},
 | 
			
		||||
        'provided_policy_rule_sets': {'allow_post': True, 'allow_put': True,
 | 
			
		||||
                                      'validate': {'type:dict_or_none': None},
 | 
			
		||||
                                      'convert_to':
 | 
			
		||||
                                      attr.convert_none_to_empty_dict,
 | 
			
		||||
                                      'default': None, 'is_visible': True},
 | 
			
		||||
        'consumed_policy_rule_sets': {'allow_post': True, 'allow_put': True,
 | 
			
		||||
                                      'validate': {'type:dict_or_none': None},
 | 
			
		||||
                                      'convert_to':
 | 
			
		||||
                                      attr.convert_none_to_empty_dict,
 | 
			
		||||
                                      'default': None, 'is_visible': True},
 | 
			
		||||
        attr.SHARED: {'allow_post': True, 'allow_put': True,
 | 
			
		||||
                      'default': False, 'convert_to': attr.convert_to_boolean,
 | 
			
		||||
                      'is_visible': True, 'required_by_policy': True,
 | 
			
		||||
                      'enforce_policy': True},
 | 
			
		||||
    },
 | 
			
		||||
    EXTERNAL_SEGMENTS: {
 | 
			
		||||
        'id': {'allow_post': False, 'allow_put': False,
 | 
			
		||||
               'validate': {'type:uuid': None},
 | 
			
		||||
               'is_visible': True, 'primary_key': True},
 | 
			
		||||
        'name': {'allow_post': True, 'allow_put': True,
 | 
			
		||||
                 'validate': {'type:string': None},
 | 
			
		||||
                 'default': '', 'is_visible': True},
 | 
			
		||||
        'description': {'allow_post': True, 'allow_put': True,
 | 
			
		||||
                        'validate': {'type:string': None},
 | 
			
		||||
                        'is_visible': True, 'default': ''},
 | 
			
		||||
        'tenant_id': {'allow_post': True, 'allow_put': False,
 | 
			
		||||
                      'validate': {'type:string': None},
 | 
			
		||||
                      'required_by_policy': True, 'is_visible': True},
 | 
			
		||||
        'ip_version': {'allow_post': True, 'allow_put': False,
 | 
			
		||||
                       'convert_to': attr.convert_to_int,
 | 
			
		||||
                       'validate': {'type:values': [4, 6]},
 | 
			
		||||
                       'default': 4, 'is_visible': True},
 | 
			
		||||
        'cidr': {'allow_post': True, 'allow_put': False,
 | 
			
		||||
                 'validate': {'type:subnet': None},
 | 
			
		||||
                 'default': '172.16.0.0/12', 'is_visible': True},
 | 
			
		||||
        'external_policies': {
 | 
			
		||||
            'allow_post': False, 'allow_put': False, 'default': None,
 | 
			
		||||
            'validate': {'type:uuid_list': None},
 | 
			
		||||
            'convert_to': attr.convert_none_to_empty_list, 'is_visible': True},
 | 
			
		||||
        'external_routes': {
 | 
			
		||||
            'allow_post': True, 'allow_put': True,
 | 
			
		||||
            'default': attr.ATTR_NOT_SPECIFIED,
 | 
			
		||||
            'validate': {'type:gbproutes': None},
 | 
			
		||||
            'is_visible': True},
 | 
			
		||||
        'l3_policies': {'allow_post': False, 'allow_put': False,
 | 
			
		||||
                        'validate': {'type:uuid_list': None},
 | 
			
		||||
                        'convert_to': attr.convert_none_to_empty_list,
 | 
			
		||||
                        'default': None, 'is_visible': True},
 | 
			
		||||
        'port_address_translation': {
 | 
			
		||||
            'allow_post': True, 'allow_put': True,
 | 
			
		||||
            'default': False, 'convert_to': attr.convert_to_boolean,
 | 
			
		||||
            'is_visible': True, 'required_by_policy': True,
 | 
			
		||||
            'enforce_policy': True},
 | 
			
		||||
        attr.SHARED: {'allow_post': True, 'allow_put': True,
 | 
			
		||||
                      'default': False, 'convert_to': attr.convert_to_boolean,
 | 
			
		||||
                      'is_visible': True, 'required_by_policy': True,
 | 
			
		||||
                      'enforce_policy': True},
 | 
			
		||||
    },
 | 
			
		||||
    NAT_POOLS: {
 | 
			
		||||
        'id': {'allow_post': False, 'allow_put': False,
 | 
			
		||||
               'validate': {'type:uuid': None},
 | 
			
		||||
               'is_visible': True, 'primary_key': True},
 | 
			
		||||
        'name': {'allow_post': True, 'allow_put': True,
 | 
			
		||||
                 'validate': {'type:string': None},
 | 
			
		||||
                 'default': '', 'is_visible': True},
 | 
			
		||||
        'description': {'allow_post': True, 'allow_put': True,
 | 
			
		||||
                        'validate': {'type:string': None},
 | 
			
		||||
                        'is_visible': True, 'default': ''},
 | 
			
		||||
        'tenant_id': {'allow_post': True, 'allow_put': False,
 | 
			
		||||
                      'validate': {'type:string': None},
 | 
			
		||||
                      'required_by_policy': True, 'is_visible': True},
 | 
			
		||||
        'ip_version': {'allow_post': True, 'allow_put': False,
 | 
			
		||||
                       'convert_to': attr.convert_to_int,
 | 
			
		||||
                       'validate': {'type:values': [4, 6]},
 | 
			
		||||
                       'default': 4, 'is_visible': True},
 | 
			
		||||
        'ip_pool': {'allow_post': True, 'allow_put': False,
 | 
			
		||||
                    'validate': {'type:subnet': None},
 | 
			
		||||
                    'is_visible': True},
 | 
			
		||||
        'external_segment_id': {'allow_post': True, 'allow_put': True,
 | 
			
		||||
                                'validate': {'type:uuid_or_none': None},
 | 
			
		||||
                                'is_visible': True, 'required': True},
 | 
			
		||||
        attr.SHARED: {'allow_post': True, 'allow_put': True,
 | 
			
		||||
                      'default': False, 'convert_to': attr.convert_to_boolean,
 | 
			
		||||
                      'is_visible': True, 'required_by_policy': True,
 | 
			
		||||
                      'enforce_policy': True},
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -535,7 +713,8 @@ class Group_policy(extensions.ExtensionDescriptor):
 | 
			
		||||
    def get_resources(cls):
 | 
			
		||||
        special_mappings = {
 | 
			
		||||
            'l2_policies': 'l2_policy', 'l3_policies': 'l3_policy',
 | 
			
		||||
            'network_service_policies': 'network_service_policy'}
 | 
			
		||||
            'network_service_policies': 'network_service_policy',
 | 
			
		||||
            'external_policies': 'external_policy'}
 | 
			
		||||
        plural_mappings = resource_helper.build_plural_mappings(
 | 
			
		||||
            special_mappings, RESOURCE_ATTRIBUTE_MAP)
 | 
			
		||||
        attr.PLURALS.update(plural_mappings)
 | 
			
		||||
@@ -757,3 +936,66 @@ class GroupPolicyPluginBase(service_base.ServicePluginBase):
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def delete_policy_rule_set(self, context, policy_rule_set_id):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def create_external_policy(self, context, external_policy):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def update_external_policy(self, context, external_policy_id,
 | 
			
		||||
                               external_policy):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def get_external_policies(self, context, filters=None, fields=None):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def get_external_policy(self, context, external_policy_id,
 | 
			
		||||
                            fields=None):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def delete_external_policy(self, context, external_policy_id):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def create_external_segment(self, context, external_segment):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def update_external_segment(self, context, external_segment_id,
 | 
			
		||||
                                external_segment):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def get_external_segments(self, context, filters=None, fields=None):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def get_external_segment(self, context, external_segment_id, fields=None):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def delete_external_segment(self, context, external_segment_id):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def create_nat_pool(self, context, nat_pool):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def update_nat_pool(self, context, nat_pool_id, nat_pool):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def get_nat_pools(self, context, filters=None, fields=None):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def get_nat_pool(self, context, nat_pool_id, fields=None):
 | 
			
		||||
        pass
 | 
			
		||||
 | 
			
		||||
    @abc.abstractmethod
 | 
			
		||||
    def delete_nat_pool(self, context, nat_pool_id):
 | 
			
		||||
        pass
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,8 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
 | 
			
		||||
                   'policy_classifier': {},
 | 
			
		||||
                   'policy_rule_set': {
 | 
			
		||||
                       'parent_id': 'policy_rule_set',
 | 
			
		||||
                       'policy_rules': 'policy_rule'}}
 | 
			
		||||
                       'policy_rules': 'policy_rule'},
 | 
			
		||||
                   }
 | 
			
		||||
    _plurals = None
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
 
 | 
			
		||||
@@ -11,9 +11,11 @@
 | 
			
		||||
# See the License for the specific language governing permissions and
 | 
			
		||||
# limitations under the License.
 | 
			
		||||
 | 
			
		||||
import copy
 | 
			
		||||
import webob.exc
 | 
			
		||||
 | 
			
		||||
from neutron.api import extensions
 | 
			
		||||
from neutron.api.v2 import attributes as nattr
 | 
			
		||||
from neutron import context
 | 
			
		||||
from neutron.openstack.common import importutils
 | 
			
		||||
from neutron.openstack.common import uuidutils
 | 
			
		||||
@@ -94,11 +96,14 @@ class GroupPolicyDBTestBase(object):
 | 
			
		||||
    def _get_test_l3_policy_attrs(self, name='l3p1',
 | 
			
		||||
                                  description='test l3_policy',
 | 
			
		||||
                                  ip_version=4, ip_pool='10.0.0.0/8',
 | 
			
		||||
                                  subnet_prefix_length=24):
 | 
			
		||||
                                  subnet_prefix_length=24,
 | 
			
		||||
                                  external_segments=None):
 | 
			
		||||
        external_segments = external_segments or {}
 | 
			
		||||
        attrs = {'name': name, 'description': description,
 | 
			
		||||
                 'tenant_id': self._tenant_id, 'ip_version': ip_version,
 | 
			
		||||
                 'ip_pool': ip_pool,
 | 
			
		||||
                 'subnet_prefix_length': subnet_prefix_length}
 | 
			
		||||
                 'subnet_prefix_length': subnet_prefix_length,
 | 
			
		||||
                 'external_segments': external_segments}
 | 
			
		||||
 | 
			
		||||
        return attrs
 | 
			
		||||
 | 
			
		||||
@@ -160,6 +165,45 @@ class GroupPolicyDBTestBase(object):
 | 
			
		||||
 | 
			
		||||
        return attrs
 | 
			
		||||
 | 
			
		||||
    def _get_test_ep_attrs(self, name='ep_1', description='test ep',
 | 
			
		||||
                           external_segments=None,
 | 
			
		||||
                           provided_policy_rule_sets=None,
 | 
			
		||||
                           consumed_policy_rule_sets=None):
 | 
			
		||||
        pprs_ids = cprs_ids = es_ids = []
 | 
			
		||||
        if provided_policy_rule_sets:
 | 
			
		||||
            pprs_ids = [pprs_id for pprs_id in provided_policy_rule_sets]
 | 
			
		||||
        if consumed_policy_rule_sets:
 | 
			
		||||
            cprs_ids = [cc_id for cc_id in consumed_policy_rule_sets]
 | 
			
		||||
        if external_segments:
 | 
			
		||||
            es_ids = [es_id for es_id in external_segments]
 | 
			
		||||
        attrs = {'name': name, 'description': description,
 | 
			
		||||
                 'tenant_id': self._tenant_id,
 | 
			
		||||
                 'external_segments': es_ids,
 | 
			
		||||
                 'provided_policy_rule_sets': pprs_ids,
 | 
			
		||||
                 'consumed_policy_rule_sets': cprs_ids}
 | 
			
		||||
        return attrs
 | 
			
		||||
 | 
			
		||||
    def _get_test_es_attrs(self, name='es_1', description='test es',
 | 
			
		||||
                           ip_version=4, cidr='172.0.0.0/8',
 | 
			
		||||
                           external_routes=None,
 | 
			
		||||
                           port_address_translation=False):
 | 
			
		||||
        ear = external_routes or []
 | 
			
		||||
        attrs = {'name': name, 'description': description,
 | 
			
		||||
                 'ip_version': ip_version,
 | 
			
		||||
                 'tenant_id': self._tenant_id, 'cidr': cidr,
 | 
			
		||||
                 'external_routes': ear,
 | 
			
		||||
                 'port_address_translation': port_address_translation}
 | 
			
		||||
        return attrs
 | 
			
		||||
 | 
			
		||||
    def _get_test_np_attrs(self, name='es_1', description='test es',
 | 
			
		||||
                           ip_version=4, ip_pool='10.160.0.0/16',
 | 
			
		||||
                           external_segment_id=None):
 | 
			
		||||
        attrs = {'name': name, 'description': description,
 | 
			
		||||
                 'ip_version': ip_version,
 | 
			
		||||
                 'tenant_id': self._tenant_id, 'ip_pool': ip_pool,
 | 
			
		||||
                 'external_segment_id': external_segment_id}
 | 
			
		||||
        return attrs
 | 
			
		||||
 | 
			
		||||
    def create_policy_target(self, policy_target_group_id=None,
 | 
			
		||||
                             expected_res_status=None, **kwargs):
 | 
			
		||||
        defaults = {'name': 'pt1', 'description': 'test pt'}
 | 
			
		||||
@@ -230,7 +274,7 @@ class GroupPolicyDBTestBase(object):
 | 
			
		||||
    def create_l3_policy(self, expected_res_status=None, **kwargs):
 | 
			
		||||
        defaults = {'name': 'l3p1', 'description': 'test l3_policy',
 | 
			
		||||
                    'ip_version': 4, 'ip_pool': '10.0.0.0/8',
 | 
			
		||||
                    'subnet_prefix_length': 24}
 | 
			
		||||
                    'subnet_prefix_length': 24, 'external_segments': {}}
 | 
			
		||||
        defaults.update(kwargs)
 | 
			
		||||
 | 
			
		||||
        data = {'l3_policy': {'tenant_id': self._tenant_id}}
 | 
			
		||||
@@ -358,6 +402,41 @@ class GroupPolicyDBTestBase(object):
 | 
			
		||||
 | 
			
		||||
        return prs
 | 
			
		||||
 | 
			
		||||
    def _create_gbp_resource(self, type, expected_res_status, body):
 | 
			
		||||
        plural = self._get_resource_plural(type)
 | 
			
		||||
        data = {type: body}
 | 
			
		||||
        req = self.new_create_request(plural, data, self.fmt)
 | 
			
		||||
        res = req.get_response(self.ext_api)
 | 
			
		||||
 | 
			
		||||
        if expected_res_status:
 | 
			
		||||
            self.assertEqual(res.status_int, expected_res_status)
 | 
			
		||||
        elif res.status_int >= webob.exc.HTTPClientError.code:
 | 
			
		||||
            raise webob.exc.HTTPClientError(code=res.status_int)
 | 
			
		||||
        prs = self.deserialize(self.fmt, res)
 | 
			
		||||
        return prs
 | 
			
		||||
 | 
			
		||||
    def create_external_policy(self, expected_res_status=None, **kwargs):
 | 
			
		||||
        defaults = {'name': 'ptg1', 'description': 'test ptg',
 | 
			
		||||
                    'provided_policy_rule_sets': {},
 | 
			
		||||
                    'consumed_policy_rule_sets': {},
 | 
			
		||||
                    'tenant_id': self._tenant_id,
 | 
			
		||||
                    'external_segments': []}
 | 
			
		||||
        defaults.update(kwargs)
 | 
			
		||||
        return self._create_gbp_resource(
 | 
			
		||||
            'external_policy', expected_res_status, defaults)
 | 
			
		||||
 | 
			
		||||
    def create_external_segment(self, expected_res_status=None, **kwargs):
 | 
			
		||||
        body = self._get_test_es_attrs()
 | 
			
		||||
        body.update(kwargs)
 | 
			
		||||
        return self._create_gbp_resource(
 | 
			
		||||
            'external_segment', expected_res_status, body)
 | 
			
		||||
 | 
			
		||||
    def create_nat_pool(self, expected_res_status=None, **kwargs):
 | 
			
		||||
        body = self._get_test_np_attrs()
 | 
			
		||||
        body.update(kwargs)
 | 
			
		||||
        return self._create_gbp_resource(
 | 
			
		||||
            'nat_pool', expected_res_status, body)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GroupPolicyDBTestPlugin(gpdb.GroupPolicyDbPlugin):
 | 
			
		||||
 | 
			
		||||
@@ -379,7 +458,7 @@ class GroupPolicyDbTestCase(GroupPolicyDBTestBase,
 | 
			
		||||
        self.plugin = importutils.import_object(gp_plugin)
 | 
			
		||||
        if not service_plugins:
 | 
			
		||||
            service_plugins = {'gp_plugin_name': gp_plugin}
 | 
			
		||||
 | 
			
		||||
        nattr.PLURALS['nat_pools'] = 'nat_pool'
 | 
			
		||||
        super(GroupPolicyDbTestCase, self).setUp(
 | 
			
		||||
            plugin=core_plugin, ext_mgr=ext_mgr,
 | 
			
		||||
            service_plugins=service_plugins
 | 
			
		||||
@@ -594,19 +673,22 @@ class TestGroupResources(GroupPolicyDbTestCase):
 | 
			
		||||
                          ctx, l2p_id)
 | 
			
		||||
 | 
			
		||||
    def test_create_and_show_l3_policy(self):
 | 
			
		||||
        attrs = self._get_test_l3_policy_attrs()
 | 
			
		||||
        es = self.create_external_segment()['external_segment']
 | 
			
		||||
        es_dict = {es['id']: ['172.0.0.2', '172.0.0.3']}
 | 
			
		||||
        attrs = self._get_test_l3_policy_attrs(
 | 
			
		||||
            external_segments=es_dict)
 | 
			
		||||
 | 
			
		||||
        l3p = self.create_l3_policy()
 | 
			
		||||
        l3p = self.create_l3_policy(external_segments=es_dict)
 | 
			
		||||
 | 
			
		||||
        for k, v in attrs.iteritems():
 | 
			
		||||
            self.assertEqual(l3p['l3_policy'][k], v)
 | 
			
		||||
            self.assertEqual(v, l3p['l3_policy'][k])
 | 
			
		||||
 | 
			
		||||
        req = self.new_show_request('l3_policies', l3p['l3_policy']['id'],
 | 
			
		||||
                                    fmt=self.fmt)
 | 
			
		||||
        res = self.deserialize(self.fmt, req.get_response(self.ext_api))
 | 
			
		||||
 | 
			
		||||
        for k, v in attrs.iteritems():
 | 
			
		||||
            self.assertEqual(res['l3_policy'][k], v)
 | 
			
		||||
            self.assertEqual(v, res['l3_policy'][k])
 | 
			
		||||
 | 
			
		||||
        self._test_show_resource('l3_policy', l3p['l3_policy']['id'], attrs)
 | 
			
		||||
 | 
			
		||||
@@ -630,13 +712,17 @@ class TestGroupResources(GroupPolicyDbTestCase):
 | 
			
		||||
        name = "new_l3_policy"
 | 
			
		||||
        description = 'new desc'
 | 
			
		||||
        prefix_length = 26
 | 
			
		||||
        es = self.create_external_segment()['external_segment']
 | 
			
		||||
        es_dict = {es['id']: ['172.0.0.2', '172.0.0.3']}
 | 
			
		||||
        attrs = self._get_test_l3_policy_attrs(
 | 
			
		||||
            name=name, description=description,
 | 
			
		||||
            subnet_prefix_length=prefix_length)
 | 
			
		||||
            subnet_prefix_length=prefix_length,
 | 
			
		||||
            external_segments=es_dict)
 | 
			
		||||
 | 
			
		||||
        l3p = self.create_l3_policy()
 | 
			
		||||
        data = {'l3_policy': {'name': name, 'description': description,
 | 
			
		||||
                              'subnet_prefix_length': prefix_length}}
 | 
			
		||||
                              'subnet_prefix_length': prefix_length,
 | 
			
		||||
                              'external_segments': es_dict}}
 | 
			
		||||
 | 
			
		||||
        req = self.new_update_request('l3_policies', data,
 | 
			
		||||
                                      l3p['l3_policy']['id'])
 | 
			
		||||
@@ -1080,3 +1166,158 @@ class TestGroupResources(GroupPolicyDbTestCase):
 | 
			
		||||
        req = self.new_update_request('policy_rule_sets', data, prs['id'])
 | 
			
		||||
        res = req.get_response(self.ext_api)
 | 
			
		||||
        self.assertEqual(res.status_int, webob.exc.HTTPBadRequest.code)
 | 
			
		||||
 | 
			
		||||
    def _test_create_and_show(self, type, attrs, expected=None):
 | 
			
		||||
        plural = self._get_resource_plural(type)
 | 
			
		||||
        res = self._create_gbp_resource(type, None, attrs)
 | 
			
		||||
        expected = expected or attrs
 | 
			
		||||
        for k, v in expected.iteritems():
 | 
			
		||||
            self.assertEqual(v, res[type][k])
 | 
			
		||||
 | 
			
		||||
        req = self.new_show_request(plural, res[type]['id'], fmt=self.fmt)
 | 
			
		||||
        res = self.deserialize(self.fmt, req.get_response(self.ext_api))
 | 
			
		||||
        for k, v in expected.iteritems():
 | 
			
		||||
            self.assertEqual(v, res[type][k])
 | 
			
		||||
        self._test_show_resource(type, res[type]['id'], expected)
 | 
			
		||||
 | 
			
		||||
    def test_create_and_show_ep(self):
 | 
			
		||||
        es = self.create_external_segment()['external_segment']
 | 
			
		||||
        prs = self.create_policy_rule_set()['policy_rule_set']
 | 
			
		||||
        attrs = {'external_segments': [es['id']],
 | 
			
		||||
                 'provided_policy_rule_sets': {prs['id']: None},
 | 
			
		||||
                 'consumed_policy_rule_sets': {prs['id']: None}}
 | 
			
		||||
        body = self._get_test_ep_attrs()
 | 
			
		||||
        body.update(attrs)
 | 
			
		||||
        expected = copy.deepcopy(body)
 | 
			
		||||
        expected['provided_policy_rule_sets'] = [prs['id']]
 | 
			
		||||
        expected['consumed_policy_rule_sets'] = [prs['id']]
 | 
			
		||||
        self._test_create_and_show('external_policy', body,
 | 
			
		||||
                                   expected=expected)
 | 
			
		||||
 | 
			
		||||
    def test_create_and_show_es(self):
 | 
			
		||||
        route = {'destination': '0.0.0.0/0', 'nexthop': '172.0.0.1'}
 | 
			
		||||
        attrs = self._get_test_es_attrs(external_routes=[route])
 | 
			
		||||
        self._test_create_and_show('external_segment', attrs)
 | 
			
		||||
 | 
			
		||||
    def test_create_and_show_np(self):
 | 
			
		||||
        es = self.create_external_segment()['external_segment']
 | 
			
		||||
        attrs = self._get_test_np_attrs(external_segment_id=es['id'])
 | 
			
		||||
        self._test_create_and_show('nat_pool', attrs)
 | 
			
		||||
 | 
			
		||||
    def test_list_ep(self):
 | 
			
		||||
        external_policies = [
 | 
			
		||||
            self.create_external_policy(name='ep1', description='ep'),
 | 
			
		||||
            self.create_external_policy(name='ep2', description='ep'),
 | 
			
		||||
            self.create_external_policy(name='ep3', description='ep')]
 | 
			
		||||
        self._test_list_resources('external_policy',
 | 
			
		||||
                                  external_policies,
 | 
			
		||||
                                  query_params='description=ep')
 | 
			
		||||
 | 
			
		||||
    def test_list_es(self):
 | 
			
		||||
        external_segments = [
 | 
			
		||||
            self.create_external_segment(name='es1', description='es'),
 | 
			
		||||
            self.create_external_segment(name='es2', description='es'),
 | 
			
		||||
            self.create_external_segment(name='es3', description='es')]
 | 
			
		||||
        self._test_list_resources('external_segment',
 | 
			
		||||
                                  external_segments,
 | 
			
		||||
                                  query_params='description=es')
 | 
			
		||||
 | 
			
		||||
    def test_update_external_policy(self):
 | 
			
		||||
        name = 'new_ep'
 | 
			
		||||
        description = 'new desc'
 | 
			
		||||
        es = self.create_external_segment()['external_segment']
 | 
			
		||||
        prs = self.create_policy_rule_set()['policy_rule_set']
 | 
			
		||||
        attrs = self._get_test_ep_attrs(
 | 
			
		||||
            name=name, description=description,
 | 
			
		||||
            external_segments=[es['id']],
 | 
			
		||||
            provided_policy_rule_sets={prs['id']: None},
 | 
			
		||||
            consumed_policy_rule_sets={prs['id']: None})
 | 
			
		||||
        ep = self.create_external_policy()['external_policy']
 | 
			
		||||
        data = {'external_policy': {
 | 
			
		||||
            'name': name, 'description': description,
 | 
			
		||||
            'external_segments': [es['id']],
 | 
			
		||||
            'provided_policy_rule_sets': {prs['id']: None},
 | 
			
		||||
            'consumed_policy_rule_sets': {prs['id']: None}}}
 | 
			
		||||
 | 
			
		||||
        req = self.new_update_request('external_policies', data,
 | 
			
		||||
                                      ep['id'])
 | 
			
		||||
        res = self.deserialize(self.fmt, req.get_response(self.ext_api))
 | 
			
		||||
        res = res['external_policy']
 | 
			
		||||
        for k, v in attrs.iteritems():
 | 
			
		||||
            self.assertEqual(v, res[k])
 | 
			
		||||
 | 
			
		||||
        self._test_show_resource('external_policy', ep['id'], attrs)
 | 
			
		||||
 | 
			
		||||
    def test_update_external_segment(self):
 | 
			
		||||
        name = 'new_es'
 | 
			
		||||
        description = 'new desc'
 | 
			
		||||
        route = {'destination': '0.0.0.0/0', 'nexthop': '172.0.0.1'}
 | 
			
		||||
        attrs = self._get_test_es_attrs(name=name, description=description,
 | 
			
		||||
                                        external_routes=[route])
 | 
			
		||||
        es = self.create_external_segment()['external_segment']
 | 
			
		||||
        data = {'external_segment': {
 | 
			
		||||
            'name': name, 'description': description,
 | 
			
		||||
            'external_routes': [route]}}
 | 
			
		||||
 | 
			
		||||
        req = self.new_update_request('external_segments', data,
 | 
			
		||||
                                      es['id'])
 | 
			
		||||
        res = self.deserialize(self.fmt, req.get_response(self.ext_api))
 | 
			
		||||
        res = res['external_segment']
 | 
			
		||||
        for k, v in attrs.iteritems():
 | 
			
		||||
            self.assertEqual(res[k], v)
 | 
			
		||||
 | 
			
		||||
        self._test_show_resource('external_segment', es['id'], attrs)
 | 
			
		||||
 | 
			
		||||
    def test_update_nat_pool(self):
 | 
			
		||||
        name = 'new_np'
 | 
			
		||||
        description = 'new desc'
 | 
			
		||||
        es = self.create_external_segment()['external_segment']
 | 
			
		||||
 | 
			
		||||
        attrs = self._get_test_np_attrs(name=name, description=description,
 | 
			
		||||
                                        external_segment_id=es['id'])
 | 
			
		||||
        np = self.create_nat_pool()['nat_pool']
 | 
			
		||||
        data = {'nat_pool': {
 | 
			
		||||
            'name': name, 'description': description,
 | 
			
		||||
            'external_segment_id': es['id']}}
 | 
			
		||||
 | 
			
		||||
        req = self.new_update_request('nat_pools', data,
 | 
			
		||||
                                      np['id'])
 | 
			
		||||
        res = self.deserialize(self.fmt, req.get_response(self.ext_api))
 | 
			
		||||
        res = res['nat_pool']
 | 
			
		||||
        for k, v in attrs.iteritems():
 | 
			
		||||
            self.assertEqual(v, res[k])
 | 
			
		||||
 | 
			
		||||
        self._test_show_resource('nat_pool', np['id'], attrs)
 | 
			
		||||
 | 
			
		||||
    def test_delete_ep(self):
 | 
			
		||||
        ctx = context.get_admin_context()
 | 
			
		||||
        ep = self.create_external_policy()
 | 
			
		||||
        ep_id = ep['external_policy']['id']
 | 
			
		||||
 | 
			
		||||
        req = self.new_delete_request('external_policies', ep_id)
 | 
			
		||||
        res = req.get_response(self.ext_api)
 | 
			
		||||
        self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
 | 
			
		||||
        self.assertRaises(gpolicy.ExternalPolicyNotFound,
 | 
			
		||||
                          self.plugin.get_external_policy, ctx, ep_id)
 | 
			
		||||
 | 
			
		||||
    def test_delete_es(self):
 | 
			
		||||
        ctx = context.get_admin_context()
 | 
			
		||||
        ep = self.create_external_segment()
 | 
			
		||||
        ep_id = ep['external_segment']['id']
 | 
			
		||||
 | 
			
		||||
        req = self.new_delete_request('external_segments', ep_id)
 | 
			
		||||
        res = req.get_response(self.ext_api)
 | 
			
		||||
        self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
 | 
			
		||||
        self.assertRaises(gpolicy.ExternalSegmentNotFound,
 | 
			
		||||
                          self.plugin.get_external_segment, ctx, ep_id)
 | 
			
		||||
 | 
			
		||||
    def test_delete_np(self):
 | 
			
		||||
        ctx = context.get_admin_context()
 | 
			
		||||
        ep = self.create_nat_pool()
 | 
			
		||||
        ep_id = ep['nat_pool']['id']
 | 
			
		||||
 | 
			
		||||
        req = self.new_delete_request('nat_pools', ep_id)
 | 
			
		||||
        res = req.get_response(self.ext_api)
 | 
			
		||||
        self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
 | 
			
		||||
        self.assertRaises(gpolicy.NATPoolNotFound,
 | 
			
		||||
                          self.plugin.get_nat_pool, ctx, ep_id)
 | 
			
		||||
 
 | 
			
		||||
@@ -84,10 +84,12 @@ class GroupPolicyMappingDbTestCase(tgpdb.GroupPolicyDbTestCase,
 | 
			
		||||
    def _get_test_l3_policy_attrs(self, name='l3p1',
 | 
			
		||||
                                  description='test l3_policy',
 | 
			
		||||
                                  ip_version=4, ip_pool='10.0.0.0/8',
 | 
			
		||||
                                  subnet_prefix_length=24, routers=None):
 | 
			
		||||
                                  subnet_prefix_length=24, routers=None,
 | 
			
		||||
                                  external_segments=None):
 | 
			
		||||
        attrs = (super(GroupPolicyMappingDbTestCase, self).
 | 
			
		||||
                 _get_test_l3_policy_attrs(name, description, ip_version,
 | 
			
		||||
                                           ip_pool, subnet_prefix_length))
 | 
			
		||||
                                           ip_pool, subnet_prefix_length,
 | 
			
		||||
                                           external_segments))
 | 
			
		||||
        attrs.update({'routers': routers or []})
 | 
			
		||||
        return attrs
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -37,6 +37,13 @@ POLICY_CLASSIFIERS_URI = GROUPPOLICY_URI + '/' + 'policy_classifiers'
 | 
			
		||||
POLICY_ACTIONS_URI = GROUPPOLICY_URI + '/' + 'policy_actions'
 | 
			
		||||
POLICY_RULE_SETS_URI = GROUPPOLICY_URI + '/' + 'policy_rule_sets'
 | 
			
		||||
NET_SVC_POLICIES_URI = GROUPPOLICY_URI + '/' + 'network_service_policies'
 | 
			
		||||
EAP_POLICIES_URI = GROUPPOLICY_URI + '/' + 'external_policies'
 | 
			
		||||
EAS_POLICIES_URI = GROUPPOLICY_URI + '/' + 'external_segments'
 | 
			
		||||
NP_POLICIES_URI = GROUPPOLICY_URI + '/' + 'nat_pools'
 | 
			
		||||
 | 
			
		||||
RES_TO_URI = {'external_policy': EAP_POLICIES_URI,
 | 
			
		||||
              'external_segment': EAS_POLICIES_URI,
 | 
			
		||||
              'nat_pool': NP_POLICIES_URI}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class GroupPolicyExtensionTestCase(test_api_v2_extension.ExtensionTestCase):
 | 
			
		||||
@@ -46,7 +53,8 @@ class GroupPolicyExtensionTestCase(test_api_v2_extension.ExtensionTestCase):
 | 
			
		||||
        super(GroupPolicyExtensionTestCase, self).setUp()
 | 
			
		||||
        plural_mappings = {
 | 
			
		||||
            'l2_policy': 'l2_policies', 'l3_policy': 'l3_policies',
 | 
			
		||||
            'network_service_policy': 'network_service_policies'}
 | 
			
		||||
            'network_service_policy': 'network_service_policies',
 | 
			
		||||
            'external_policy': 'external_policies'}
 | 
			
		||||
        self._setUpExtension(
 | 
			
		||||
            GP_PLUGIN_BASE_NAME, constants.GROUP_POLICY,
 | 
			
		||||
            gp.RESOURCE_ATTRIBUTE_MAP, gp.Group_policy, GROUPPOLICY_URI,
 | 
			
		||||
@@ -372,12 +380,13 @@ class GroupPolicyExtensionTestCase(test_api_v2_extension.ExtensionTestCase):
 | 
			
		||||
    def _get_create_l3_policy_default_attrs(self):
 | 
			
		||||
        return {'name': '', 'description': '', 'ip_version': 4,
 | 
			
		||||
                'ip_pool': '10.0.0.0/8', 'subnet_prefix_length': 24,
 | 
			
		||||
                'shared': False}
 | 
			
		||||
                'external_segments': {}, 'shared': False}
 | 
			
		||||
 | 
			
		||||
    def _get_create_l3_policy_attrs(self):
 | 
			
		||||
        return {'name': 'l3p1', 'tenant_id': _uuid(),
 | 
			
		||||
                'description': 'test L3 policy', 'ip_version': 6,
 | 
			
		||||
                'ip_pool': 'fd01:2345:6789::/48',
 | 
			
		||||
                'external_segments': {_uuid(): ['192.168.0.3']},
 | 
			
		||||
                'subnet_prefix_length': 64, 'shared': False}
 | 
			
		||||
 | 
			
		||||
    def _get_update_l3_policy_attrs(self):
 | 
			
		||||
@@ -1016,6 +1025,209 @@ class GroupPolicyExtensionTestCase(test_api_v2_extension.ExtensionTestCase):
 | 
			
		||||
    def test_delete_network_service_policy(self):
 | 
			
		||||
        self._test_entity_delete('network_service_policy')
 | 
			
		||||
 | 
			
		||||
    def _test_entity_create(self, entity, data, expected_value,
 | 
			
		||||
                            default_data=None, non_specified=None):
 | 
			
		||||
        default_data = default_data or data
 | 
			
		||||
        create_method = getattr(self.instance, 'create_%s' % entity)
 | 
			
		||||
        create_method.return_value = expected_value
 | 
			
		||||
        res = self.api.post(_get_path(RES_TO_URI[entity], fmt=self.fmt),
 | 
			
		||||
                            self.serialize(data),
 | 
			
		||||
                            content_type='application/%s' % self.fmt)
 | 
			
		||||
        default_data[entity].update(non_specified or {})
 | 
			
		||||
        kwargs = {entity: default_data}
 | 
			
		||||
        create_method.assert_called_once_with(
 | 
			
		||||
            mock.ANY, **kwargs)
 | 
			
		||||
        self.assertEqual(exc.HTTPCreated.code, res.status_int)
 | 
			
		||||
        res = self.deserialize(res)
 | 
			
		||||
        self.assertIn(entity, res)
 | 
			
		||||
        self.assertEqual(expected_value, res[entity])
 | 
			
		||||
 | 
			
		||||
    def _test_create_entity_with_defaults(self, entity, default_attrs,
 | 
			
		||||
                                          non_specified=None):
 | 
			
		||||
        entity_id = _uuid()
 | 
			
		||||
        data = {entity: {'tenant_id': _uuid()}}
 | 
			
		||||
        default_data = copy.copy(data)
 | 
			
		||||
        default_data[entity].update(default_attrs)
 | 
			
		||||
        expected_value = copy.deepcopy(default_data[entity])
 | 
			
		||||
        expected_value['id'] = entity_id
 | 
			
		||||
        self._test_entity_create(entity, data, expected_value, default_data,
 | 
			
		||||
                                 non_specified)
 | 
			
		||||
 | 
			
		||||
    def _test_create_entity_with_attrs(self, entity, attrs):
 | 
			
		||||
        entity_id = _uuid()
 | 
			
		||||
        data = {entity: attrs}
 | 
			
		||||
        expected_value = copy.deepcopy(data[entity])
 | 
			
		||||
        expected_value['id'] = entity_id
 | 
			
		||||
        self._test_entity_create(entity, data, expected_value)
 | 
			
		||||
 | 
			
		||||
    def _test_get_entity(self, entity, list=False):
 | 
			
		||||
        entity_id = _uuid()
 | 
			
		||||
        value = {'tenant_id': _uuid(), 'id': entity_id}
 | 
			
		||||
        expected_value = value if not list else [value]
 | 
			
		||||
 | 
			
		||||
        resource = entity if not list else self._plural_mappings.get(
 | 
			
		||||
            entity, entity + 's')
 | 
			
		||||
        list_method = getattr(self.instance, 'get_%s' % resource)
 | 
			
		||||
        list_method.return_value = expected_value
 | 
			
		||||
 | 
			
		||||
        kwargs = {'fmt': self.fmt}
 | 
			
		||||
        if not list:
 | 
			
		||||
            kwargs['id'] = entity_id
 | 
			
		||||
        res = self.api.get(_get_path(RES_TO_URI[entity], **kwargs))
 | 
			
		||||
 | 
			
		||||
        if list:
 | 
			
		||||
            list_method.assert_called_once_with(mock.ANY, fields=mock.ANY,
 | 
			
		||||
                                                filters=mock.ANY)
 | 
			
		||||
        else:
 | 
			
		||||
            list_method.assert_called_once_with(mock.ANY, entity_id,
 | 
			
		||||
                                                fields=mock.ANY)
 | 
			
		||||
        self.assertEqual(exc.HTTPOk.code, res.status_int)
 | 
			
		||||
        res = self.deserialize(res)
 | 
			
		||||
        self.assertIn(resource, res)
 | 
			
		||||
        self.assertEqual(expected_value, res[resource])
 | 
			
		||||
 | 
			
		||||
    def _test_update_entity(self, entity, attrs):
 | 
			
		||||
        entity_id = _uuid()
 | 
			
		||||
        update_data = {entity: attrs}
 | 
			
		||||
        expected_value = {'tenant_id': _uuid(), 'id': entity_id}
 | 
			
		||||
 | 
			
		||||
        update_method = getattr(self.instance, 'update_%s' % entity)
 | 
			
		||||
        update_method.return_value = expected_value
 | 
			
		||||
 | 
			
		||||
        res = self.api.put(_get_path(RES_TO_URI[entity], id=entity_id,
 | 
			
		||||
                                     fmt=self.fmt),
 | 
			
		||||
                           self.serialize(update_data))
 | 
			
		||||
 | 
			
		||||
        kwargs = {entity: update_data}
 | 
			
		||||
        update_method.assert_called_once_with(mock.ANY, entity_id, **kwargs)
 | 
			
		||||
        self.assertEqual(exc.HTTPOk.code, res.status_int)
 | 
			
		||||
        res = self.deserialize(res)
 | 
			
		||||
        self.assertIn(entity, res)
 | 
			
		||||
        self.assertEqual(expected_value, res[entity])
 | 
			
		||||
 | 
			
		||||
    def _get_create_external_policy_default_attrs(self):
 | 
			
		||||
        return {'name': '', 'description': '',
 | 
			
		||||
                'external_segments': [],
 | 
			
		||||
                'provided_policy_rule_sets': {},
 | 
			
		||||
                'consumed_policy_rule_sets': {},
 | 
			
		||||
                'shared': False}
 | 
			
		||||
 | 
			
		||||
    def _get_create_external_policy_attrs(self):
 | 
			
		||||
        return {'name': 'ep1', 'tenant_id': _uuid(),
 | 
			
		||||
                'description': 'test ep',
 | 
			
		||||
                'external_segments': [_uuid()],
 | 
			
		||||
                'provided_policy_rule_sets': {_uuid(): None},
 | 
			
		||||
                'consumed_policy_rule_sets': {_uuid(): None},
 | 
			
		||||
                'shared': False}
 | 
			
		||||
 | 
			
		||||
    def _get_update_external_policy_attrs(self):
 | 
			
		||||
        return {'name': 'new_name'}
 | 
			
		||||
 | 
			
		||||
    def test_create_external_policy_with_defaults(self):
 | 
			
		||||
        default_attrs = self._get_create_external_policy_default_attrs()
 | 
			
		||||
        self._test_create_entity_with_defaults('external_policy',
 | 
			
		||||
                                               default_attrs)
 | 
			
		||||
 | 
			
		||||
    def test_create_external_policy(self):
 | 
			
		||||
        attrs = self._get_create_external_policy_attrs()
 | 
			
		||||
        self._test_create_entity_with_attrs('external_policy', attrs)
 | 
			
		||||
 | 
			
		||||
    def test_list_external_policies(self):
 | 
			
		||||
        self._test_get_entity('external_policy', list=True)
 | 
			
		||||
 | 
			
		||||
    def test_get_external_policy(self):
 | 
			
		||||
        self._test_get_entity('external_policy')
 | 
			
		||||
 | 
			
		||||
    def test_update_external_policy(self):
 | 
			
		||||
        update_data = self._get_update_external_policy_attrs()
 | 
			
		||||
        self._test_update_entity('external_policy', update_data)
 | 
			
		||||
 | 
			
		||||
    def test_delete_external_policy_(self):
 | 
			
		||||
        self._test_entity_delete('external_policy')
 | 
			
		||||
 | 
			
		||||
    def _get_create_external_segment_default_attrs(self):
 | 
			
		||||
        return {'name': '', 'description': '',
 | 
			
		||||
                'external_routes': [],
 | 
			
		||||
                'ip_version': 4,
 | 
			
		||||
                'cidr': '172.16.0.0/12',
 | 
			
		||||
                'port_address_translation': False,
 | 
			
		||||
                'shared': False}
 | 
			
		||||
 | 
			
		||||
    def _get_create_external_segment_attrs(self):
 | 
			
		||||
        return {'name': 'es1', 'tenant_id': _uuid(),
 | 
			
		||||
                'description': 'test ep',
 | 
			
		||||
                'external_routes': [{'destination': '0.0.0.0/0',
 | 
			
		||||
                                     'nexthop': '192.168.0.1'}],
 | 
			
		||||
                'cidr': '192.168.0.0/24',
 | 
			
		||||
                'ip_version': 4, 'port_address_translation': True,
 | 
			
		||||
                'shared': False}
 | 
			
		||||
 | 
			
		||||
    def _get_update_external_segment_attrs(self):
 | 
			
		||||
        return {'name': 'new_name'}
 | 
			
		||||
 | 
			
		||||
    def test_create_external_segment_with_defaults(self):
 | 
			
		||||
        default_attrs = (
 | 
			
		||||
            self._get_create_external_segment_default_attrs())
 | 
			
		||||
        self._test_create_entity_with_defaults('external_segment',
 | 
			
		||||
                                               default_attrs)
 | 
			
		||||
 | 
			
		||||
    def test_create_external_segment(self):
 | 
			
		||||
        attrs = self._get_create_external_segment_attrs()
 | 
			
		||||
        self._test_create_entity_with_attrs('external_segment', attrs)
 | 
			
		||||
 | 
			
		||||
    def test_list_external_segments(self):
 | 
			
		||||
        self._test_get_entity('external_segment', list=True)
 | 
			
		||||
 | 
			
		||||
    def test_get_external_segment(self):
 | 
			
		||||
        self._test_get_entity('external_segment')
 | 
			
		||||
 | 
			
		||||
    def test_update_external_segment(self):
 | 
			
		||||
        update_data = self._get_update_external_segment_attrs()
 | 
			
		||||
        self._test_update_entity('external_segment', update_data)
 | 
			
		||||
 | 
			
		||||
    def test_delete_external_segment_(self):
 | 
			
		||||
        self._test_entity_delete('external_segment')
 | 
			
		||||
 | 
			
		||||
    def _get_create_nat_pool_default_attrs(self):
 | 
			
		||||
        return {'name': '', 'description': '',
 | 
			
		||||
                'external_segment_id': None, 'ip_version': 4,
 | 
			
		||||
                'ip_pool': '172.16.0.0/16',
 | 
			
		||||
                'shared': False}
 | 
			
		||||
 | 
			
		||||
    def _get_create_nat_pool_attrs(self):
 | 
			
		||||
        return {'name': 'es1', 'tenant_id': _uuid(),
 | 
			
		||||
                'description': 'test ep',
 | 
			
		||||
                'ip_version': 4,
 | 
			
		||||
                'ip_pool': '172.16.0.0/16',
 | 
			
		||||
                'external_segment_id': _uuid(),
 | 
			
		||||
                'shared': False}
 | 
			
		||||
 | 
			
		||||
    def _get_update_nat_pool_attrs(self):
 | 
			
		||||
        return {'name': 'new_name'}
 | 
			
		||||
 | 
			
		||||
    def test_create_nat_pool_with_defaults(self):
 | 
			
		||||
        default_attrs = (
 | 
			
		||||
            self._get_create_nat_pool_default_attrs())
 | 
			
		||||
        self._test_create_entity_with_defaults('nat_pool',
 | 
			
		||||
                                               default_attrs)
 | 
			
		||||
 | 
			
		||||
    def test_create_nat_pool(self):
 | 
			
		||||
        attrs = self._get_create_nat_pool_attrs()
 | 
			
		||||
        self._test_create_entity_with_attrs('nat_pool', attrs)
 | 
			
		||||
 | 
			
		||||
    def test_list_nat_pools(self):
 | 
			
		||||
        self._test_get_entity('nat_pool', list=True)
 | 
			
		||||
 | 
			
		||||
    def test_get_nat_pool(self):
 | 
			
		||||
        self._test_get_entity('nat_pool')
 | 
			
		||||
 | 
			
		||||
    def test_update_nat_pool(self):
 | 
			
		||||
        update_data = self._get_update_nat_pool_attrs()
 | 
			
		||||
        self._test_update_entity('nat_pool', update_data)
 | 
			
		||||
 | 
			
		||||
    def test_delete_nat_pool_(self):
 | 
			
		||||
        self._test_entity_delete('nat_pool')
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestGroupPolicyAttributeConverters(base.BaseTestCase):
 | 
			
		||||
 | 
			
		||||
@@ -1129,3 +1341,24 @@ class TestGroupPolicyAttributeValidators(base.BaseTestCase):
 | 
			
		||||
        msg = gp._validate_network_svc_params(test_params)
 | 
			
		||||
        self.assertEqual(
 | 
			
		||||
            msg, "Network service param value 'subnet' is not supported")
 | 
			
		||||
 | 
			
		||||
    def test_validate_external_dict(self):
 | 
			
		||||
        self.assertIsNone(gp._validate_external_dict(None))
 | 
			
		||||
        uuid = uuidutils.generate_uuid()
 | 
			
		||||
        uuid_2 = uuidutils.generate_uuid()
 | 
			
		||||
        correct = [{uuid: []}, {}, {uuid: ['192.168.1.1']},
 | 
			
		||||
                   {uuid_2: ['192.168.0.1'], uuid: []}]
 | 
			
		||||
        for x in correct:
 | 
			
		||||
            self.assertIsNone(gp._validate_external_dict(x))
 | 
			
		||||
 | 
			
		||||
        incorrect = 'not_a_dict'
 | 
			
		||||
        self.assertEqual(gp._validate_external_dict(incorrect),
 | 
			
		||||
                         "'%s' is not a dictionary" % incorrect)
 | 
			
		||||
        not_a_uuid = 'not_a_uuid'
 | 
			
		||||
        incorrect = {'not_a_uuid': []}
 | 
			
		||||
        self.assertEqual(gp._validate_external_dict(incorrect),
 | 
			
		||||
                         "'%s' is not a valid UUID" % not_a_uuid)
 | 
			
		||||
        not_a_list = 'not_a_list'
 | 
			
		||||
        incorrect = {uuid: not_a_list}
 | 
			
		||||
        self.assertEqual(gp._validate_external_dict(incorrect),
 | 
			
		||||
                         "'%s' is not a list" % not_a_list)
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,9 @@ class GroupPolicyMappingExtTestCase(tgp.GroupPolicyExtensionTestCase):
 | 
			
		||||
        plural_mappings = {'l2_policy': 'l2_policies',
 | 
			
		||||
                           'l3_policy': 'l3_policies',
 | 
			
		||||
                           'network_service_policy':
 | 
			
		||||
                           'network_service_policies'}
 | 
			
		||||
                           'network_service_policies',
 | 
			
		||||
                           'external_policy':
 | 
			
		||||
                           'external_policies'}
 | 
			
		||||
        self._setUpExtension(
 | 
			
		||||
            tgp.GP_PLUGIN_BASE_NAME, constants.GROUP_POLICY, attr_map,
 | 
			
		||||
            gp.Group_policy, tgp.GROUPPOLICY_URI,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user