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:
Ivar Lazzaro
2014-11-26 18:41:48 -08:00
parent 0ff6e01eee
commit 672f53f1b4
10 changed files with 1386 additions and 39 deletions

View File

@@ -14,6 +14,7 @@ import sqlalchemy as sa
from sqlalchemy import orm from sqlalchemy import orm
from sqlalchemy.orm import exc from sqlalchemy.orm import exc
from neutron.api.v2 import attributes as attr
from neutron.common import log from neutron.common import log
from neutron import context from neutron import context
from neutron.db import common_db_mixin 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__) LOG = logging.getLogger(__name__)
MAX_IPV4_SUBNET_PREFIX_LENGTH = 31 MAX_IPV4_SUBNET_PREFIX_LENGTH = 31
MAX_IPV6_SUBNET_PREFIX_LENGTH = 127 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): 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) 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): class L3Policy(model_base.BASEV2, models_v2.HasId, models_v2.HasTenant):
"""Represents a L3 Policy with a non-overlapping IP address space.""" """Represents a L3 Policy with a non-overlapping IP address space."""
__tablename__ = 'gp_l3_policies' __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) subnet_prefix_length = sa.Column(sa.Integer, nullable=False)
l2_policies = orm.relationship(L2Policy, backref='l3_policy') l2_policies = orm.relationship(L2Policy, backref='l3_policy')
shared = sa.Column(sa.Boolean) 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): 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) 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): class PolicyRuleSet(model_base.BASEV2, models_v2.HasTenant):
"""It is a collection of Policy rules.""" """It is a collection of Policy rules."""
__tablename__ = 'gp_policy_rule_sets' __tablename__ = 'gp_policy_rule_sets'
@@ -256,9 +309,81 @@ class PolicyRuleSet(model_base.BASEV2, models_v2.HasTenant):
consuming_policy_target_groups = orm.relationship( consuming_policy_target_groups = orm.relationship(
PTGToPRSConsumingAssociation, PTGToPRSConsumingAssociation,
backref='consumed_policy_rule_set', lazy="joined", cascade='all') 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) 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, class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
common_db_mixin.CommonDbMixin): common_db_mixin.CommonDbMixin):
"""GroupPolicy plugin interface implementation using SQLAlchemy models.""" """GroupPolicy plugin interface implementation using SQLAlchemy models."""
@@ -271,6 +396,13 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(GroupPolicyDbPlugin, self).__init__(*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): def _get_policy_target(self, context, policy_target_id):
try: try:
return self._get_by_id(context, PolicyTarget, policy_target_id) 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) policy_rule_set_id=policy_rule_set_id)
return policy_rule_set 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 @staticmethod
def _get_min_max_ports_from_range(port_range): def _get_min_max_ports_from_range(port_range):
if not 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 # New list of actions is valid so we will first reset the existing
# list and then add each action in order. # list and then add each action in order.
# Note that the list could be empty in which case we interpret # 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 = [] pr_db.policy_actions = []
for action_id in action_id_list: for action_id in action_id_list:
assoc = PolicyRuleActionAssociation(policy_rule_id=pr_db.id, 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( def _set_providers_or_consumers_for_policy_target_group(
self, context, ptg_db, policy_rule_sets_dict, provider=True): 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 # TODO(Sumit): Check that the same policy_rule_set ID does not belong
# to provider and consumer dicts # to provider and consumer dicts
if not policy_rule_sets_dict: if not policy_rule_sets_dict:
if provider: if provider:
ptg_db.provided_policy_rule_sets = [] db_res.provided_policy_rule_sets = []
return return
else: else:
ptg_db.consumed_policy_rule_sets = [] db_res.consumed_policy_rule_sets = []
return return
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
policy_rule_sets_id_list = policy_rule_sets_dict.keys() 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 # New list of policy_rule_sets is valid so we will first reset the
# existing list and then add each policy_rule_set. # existing list and then add each policy_rule_set.
# Note that the list could be empty in which case we interpret # Note that the list could be empty in which case we interpret
# it as clearing existing rules. # it as clering existing rules.
if provider: if provider:
ptg_db.provided_policy_rule_sets = [] db_res.provided_policy_rule_sets = []
else: else:
ptg_db.consumed_policy_rule_sets = [] db_res.consumed_policy_rule_sets = []
for policy_rule_set_id in policy_rule_sets_id_list: 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: if provider:
assoc = PTGToPRSProvidingAssociation( db_res.provided_policy_rule_sets.append(assoc)
policy_target_group_id=ptg_db.id,
policy_rule_set_id=policy_rule_set_id)
ptg_db.provided_policy_rule_sets.append(assoc)
else: else:
assoc = PTGToPRSConsumingAssociation( db_res.consumed_policy_rule_sets.append(assoc)
policy_target_group_id=ptg_db.id,
policy_rule_set_id=policy_rule_set_id)
ptg_db.consumed_policy_rule_sets.append(assoc)
def _set_children_for_policy_rule_set(self, context, def _set_children_for_policy_rule_set(self, context,
policy_rule_set_db, child_id_list): 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 # New list of child policy_rule_sets is valid so we will first
# reset the existing list and then add each policy_rule_set. # reset the existing list and then add each policy_rule_set.
# Note that the list could be empty in which case we interpret # 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 = [] policy_rule_set_db.child_policy_rule_sets = []
for child in policy_rule_sets_in_db: for child in policy_rule_sets_in_db:
policy_rule_set_db.child_policy_rule_sets.append(child) 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 # New list of rules is valid so we will first reset the existing
# list and then add each rule in order. # list and then add each rule in order.
# Note that the list could be empty in which case we interpret # 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 = [] prs_db.policy_rules = []
for rule_id in rule_id_list: for rule_id in rule_id_list:
prs_rule_db = PRSToPRAssociation( prs_rule_db = PRSToPRAssociation(
@@ -495,17 +656,28 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
policy_rule_set_id=prs_db.id) policy_rule_set_id=prs_db.id)
prs_db.policy_rules.append(prs_rule_db) 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: if 'provided_policy_rule_sets' in ptg:
self._set_providers_or_consumers_for_policy_target_group( 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'] del ptg['provided_policy_rule_sets']
if 'consumed_policy_rule_sets' in ptg: if 'consumed_policy_rule_sets' in ptg:
self._set_providers_or_consumers_for_policy_target_group( 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'] del ptg['consumed_policy_rule_sets']
return ptg 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): def _set_l3_policy_for_l2_policy(self, context, l2p_id, l3p_id):
with context.session.begin(subtransactions=True): with context.session.begin(subtransactions=True):
l2p_db = self._get_l2_policy(context, l2p_id) 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) nsp_db.network_service_params.append(param_db)
del network_service_policy['network_service_params'] 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): def _make_policy_target_dict(self, pt, fields=None):
res = {'id': pt['id'], res = {'id': pt['id'],
'tenant_id': pt['tenant_id'], 'tenant_id': pt['tenant_id'],
@@ -588,6 +821,13 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
'shared': l3p.get('shared', False), } 'shared': l3p.get('shared', False), }
res['l2_policies'] = [l2p['id'] res['l2_policies'] = [l2p['id']
for l2p in l3p['l2_policies']] 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) return self._fields(res, fields)
def _make_network_service_policy_dict(self, nsp, fields=None): def _make_network_service_policy_dict(self, nsp, fields=None):
@@ -672,9 +912,67 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
res['providing_policy_target_groups'] = [ res['providing_policy_target_groups'] = [
ptg['policy_target_group_id'] ptg['policy_target_group_id']
for ptg in prs['providing_policy_target_groups']] for ptg in prs['providing_policy_target_groups']]
res['consuming_policy_target_groups'] = [ res['consuming_policy_target_groups'] = [
ptg['policy_target_group_id'] ptg['policy_target_group_id']
for ptg in prs['consuming_policy_target_groups']] 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) return self._fields(res, fields)
def _get_policy_rule_policy_rule_sets(self, context, policy_rule_id): 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( context.session.query(PolicyRuleActionAssociation).filter_by(
policy_action_id=policy_action_id)] 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 @staticmethod
def validate_subnet_prefix_length(ip_version, new_prefix_length): def validate_subnet_prefix_length(ip_version, new_prefix_length):
if (new_prefix_length < 2) or ( if (new_prefix_length < 2) or (
@@ -870,7 +1179,10 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
ip_pool=l3p['ip_pool'], ip_pool=l3p['ip_pool'],
subnet_prefix_length=l3p['subnet_prefix_length'], subnet_prefix_length=l3p['subnet_prefix_length'],
shared=l3p.get('shared', False)) shared=l3p.get('shared', False))
context.session.add(l3p_db) 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) return self._make_l3_policy_dict(l3p_db)
@log.log @log.log
@@ -882,6 +1194,10 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
self.validate_subnet_prefix_length( self.validate_subnet_prefix_length(
l3p_db.ip_version, l3p_db.ip_version,
l3p['subnet_prefix_length']) 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) l3p_db.update(l3p)
return self._make_l3_policy_dict(l3p_db) 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): def get_policy_rule_sets_count(self, context, filters=None):
return self._get_collection_count(context, PolicyRuleSet, return self._get_collection_count(context, PolicyRuleSet,
filters=filters) 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)

View File

@@ -241,6 +241,9 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
router_id=router router_id=router
) )
l3p_db.routers.append(assoc) 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) return self._make_l3_policy_dict(l3p_db)
@log.log @log.log
@@ -269,5 +272,9 @@ class GroupPolicyMappingDbPlugin(gpdb.GroupPolicyDbPlugin):
context.session.delete(assoc) context.session.delete(assoc)
# Don't update l3p_db.routers with router IDs. # Don't update l3p_db.routers with router IDs.
del l3p['routers'] 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) l3p_db.update(l3p)
return self._make_l3_policy_dict(l3p_db) return self._make_l3_policy_dict(l3p_db)

View File

@@ -1 +1 @@
f4d890a9c126 f16efdc10a71

View File

@@ -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')

View File

@@ -19,6 +19,7 @@ from neutron.api.v2 import attributes as attr
from neutron.api.v2 import resource_helper from neutron.api.v2 import resource_helper
from neutron.common import exceptions as nexc from neutron.common import exceptions as nexc
from neutron.openstack.common import log as logging from neutron.openstack.common import log as logging
from neutron.openstack.common import uuidutils
from neutron.plugins.common import constants from neutron.plugins.common import constants
from neutron.services import service_base 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") 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): class BadPolicyRuleSetRelationship(nexc.BadRequest):
message = _("Policy Rule Set %(parent_id)s is an invalid parent for " message = _("Policy Rule Set %(parent_id)s is an invalid parent for "
"%(child_id)s, make sure that child policy_rule_set has no " "%(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) 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): def _validate_gbp_port_range(data, key_specs=None):
if data is None: if data is None:
return return
@@ -226,8 +246,57 @@ def _validate_network_svc_params(data, key_specs=None):
return msg 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:gbp_port_range'] = _validate_gbp_port_range
attr.validators['type:network_service_params'] = _validate_network_svc_params 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' POLICY_TARGETS = 'policy_targets'
@@ -239,7 +308,9 @@ POLICY_ACTIONS = 'policy_actions'
POLICY_RULES = 'policy_rules' POLICY_RULES = 'policy_rules'
POLICY_RULE_SETS = 'policy_rule_sets' POLICY_RULE_SETS = 'policy_rule_sets'
NETWORK_SERVICE_POLICIES = 'network_service_policies' NETWORK_SERVICE_POLICIES = 'network_service_policies'
EXTERNAL_POLICIES = 'external_policies'
EXTERNAL_SEGMENTS = 'external_segments'
NAT_POOLS = 'nat_pools'
RESOURCE_ATTRIBUTE_MAP = { RESOURCE_ATTRIBUTE_MAP = {
POLICY_TARGETS: { POLICY_TARGETS: {
@@ -361,6 +432,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'default': False, 'convert_to': attr.convert_to_boolean, 'default': False, 'convert_to': attr.convert_to_boolean,
'is_visible': True, 'required_by_policy': True, 'is_visible': True, 'required_by_policy': True,
'enforce_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: { POLICY_CLASSIFIERS: {
'id': {'allow_post': False, 'allow_put': False, 'id': {'allow_post': False, 'allow_put': False,
@@ -506,6 +581,109 @@ RESOURCE_ATTRIBUTE_MAP = {
'is_visible': True, 'required_by_policy': True, 'is_visible': True, 'required_by_policy': True,
'enforce_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): def get_resources(cls):
special_mappings = { special_mappings = {
'l2_policies': 'l2_policy', 'l3_policies': 'l3_policy', '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( plural_mappings = resource_helper.build_plural_mappings(
special_mappings, RESOURCE_ATTRIBUTE_MAP) special_mappings, RESOURCE_ATTRIBUTE_MAP)
attr.PLURALS.update(plural_mappings) attr.PLURALS.update(plural_mappings)
@@ -757,3 +936,66 @@ class GroupPolicyPluginBase(service_base.ServicePluginBase):
@abc.abstractmethod @abc.abstractmethod
def delete_policy_rule_set(self, context, policy_rule_set_id): def delete_policy_rule_set(self, context, policy_rule_set_id):
pass 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

View File

@@ -69,7 +69,8 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
'policy_classifier': {}, 'policy_classifier': {},
'policy_rule_set': { 'policy_rule_set': {
'parent_id': 'policy_rule_set', 'parent_id': 'policy_rule_set',
'policy_rules': 'policy_rule'}} 'policy_rules': 'policy_rule'},
}
_plurals = None _plurals = None
@property @property

View File

@@ -11,9 +11,11 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import copy
import webob.exc import webob.exc
from neutron.api import extensions from neutron.api import extensions
from neutron.api.v2 import attributes as nattr
from neutron import context from neutron import context
from neutron.openstack.common import importutils from neutron.openstack.common import importutils
from neutron.openstack.common import uuidutils from neutron.openstack.common import uuidutils
@@ -94,11 +96,14 @@ class GroupPolicyDBTestBase(object):
def _get_test_l3_policy_attrs(self, name='l3p1', def _get_test_l3_policy_attrs(self, name='l3p1',
description='test l3_policy', description='test l3_policy',
ip_version=4, ip_pool='10.0.0.0/8', 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, attrs = {'name': name, 'description': description,
'tenant_id': self._tenant_id, 'ip_version': ip_version, 'tenant_id': self._tenant_id, 'ip_version': ip_version,
'ip_pool': ip_pool, 'ip_pool': ip_pool,
'subnet_prefix_length': subnet_prefix_length} 'subnet_prefix_length': subnet_prefix_length,
'external_segments': external_segments}
return attrs return attrs
@@ -160,6 +165,45 @@ class GroupPolicyDBTestBase(object):
return attrs 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, def create_policy_target(self, policy_target_group_id=None,
expected_res_status=None, **kwargs): expected_res_status=None, **kwargs):
defaults = {'name': 'pt1', 'description': 'test pt'} defaults = {'name': 'pt1', 'description': 'test pt'}
@@ -230,7 +274,7 @@ class GroupPolicyDBTestBase(object):
def create_l3_policy(self, expected_res_status=None, **kwargs): def create_l3_policy(self, expected_res_status=None, **kwargs):
defaults = {'name': 'l3p1', 'description': 'test l3_policy', defaults = {'name': 'l3p1', 'description': 'test l3_policy',
'ip_version': 4, 'ip_pool': '10.0.0.0/8', 'ip_version': 4, 'ip_pool': '10.0.0.0/8',
'subnet_prefix_length': 24} 'subnet_prefix_length': 24, 'external_segments': {}}
defaults.update(kwargs) defaults.update(kwargs)
data = {'l3_policy': {'tenant_id': self._tenant_id}} data = {'l3_policy': {'tenant_id': self._tenant_id}}
@@ -358,6 +402,41 @@ class GroupPolicyDBTestBase(object):
return prs 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): class GroupPolicyDBTestPlugin(gpdb.GroupPolicyDbPlugin):
@@ -379,7 +458,7 @@ class GroupPolicyDbTestCase(GroupPolicyDBTestBase,
self.plugin = importutils.import_object(gp_plugin) self.plugin = importutils.import_object(gp_plugin)
if not service_plugins: if not service_plugins:
service_plugins = {'gp_plugin_name': gp_plugin} service_plugins = {'gp_plugin_name': gp_plugin}
nattr.PLURALS['nat_pools'] = 'nat_pool'
super(GroupPolicyDbTestCase, self).setUp( super(GroupPolicyDbTestCase, self).setUp(
plugin=core_plugin, ext_mgr=ext_mgr, plugin=core_plugin, ext_mgr=ext_mgr,
service_plugins=service_plugins service_plugins=service_plugins
@@ -594,19 +673,22 @@ class TestGroupResources(GroupPolicyDbTestCase):
ctx, l2p_id) ctx, l2p_id)
def test_create_and_show_l3_policy(self): 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(): 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'], req = self.new_show_request('l3_policies', l3p['l3_policy']['id'],
fmt=self.fmt) fmt=self.fmt)
res = self.deserialize(self.fmt, req.get_response(self.ext_api)) res = self.deserialize(self.fmt, req.get_response(self.ext_api))
for k, v in attrs.iteritems(): 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) self._test_show_resource('l3_policy', l3p['l3_policy']['id'], attrs)
@@ -630,13 +712,17 @@ class TestGroupResources(GroupPolicyDbTestCase):
name = "new_l3_policy" name = "new_l3_policy"
description = 'new desc' description = 'new desc'
prefix_length = 26 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( attrs = self._get_test_l3_policy_attrs(
name=name, description=description, name=name, description=description,
subnet_prefix_length=prefix_length) subnet_prefix_length=prefix_length,
external_segments=es_dict)
l3p = self.create_l3_policy() l3p = self.create_l3_policy()
data = {'l3_policy': {'name': name, 'description': description, 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, req = self.new_update_request('l3_policies', data,
l3p['l3_policy']['id']) l3p['l3_policy']['id'])
@@ -1080,3 +1166,158 @@ class TestGroupResources(GroupPolicyDbTestCase):
req = self.new_update_request('policy_rule_sets', data, prs['id']) req = self.new_update_request('policy_rule_sets', data, prs['id'])
res = req.get_response(self.ext_api) res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, webob.exc.HTTPBadRequest.code) 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)

View File

@@ -84,10 +84,12 @@ class GroupPolicyMappingDbTestCase(tgpdb.GroupPolicyDbTestCase,
def _get_test_l3_policy_attrs(self, name='l3p1', def _get_test_l3_policy_attrs(self, name='l3p1',
description='test l3_policy', description='test l3_policy',
ip_version=4, ip_pool='10.0.0.0/8', 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). attrs = (super(GroupPolicyMappingDbTestCase, self).
_get_test_l3_policy_attrs(name, description, ip_version, _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 []}) attrs.update({'routers': routers or []})
return attrs return attrs

View File

@@ -37,6 +37,13 @@ POLICY_CLASSIFIERS_URI = GROUPPOLICY_URI + '/' + 'policy_classifiers'
POLICY_ACTIONS_URI = GROUPPOLICY_URI + '/' + 'policy_actions' POLICY_ACTIONS_URI = GROUPPOLICY_URI + '/' + 'policy_actions'
POLICY_RULE_SETS_URI = GROUPPOLICY_URI + '/' + 'policy_rule_sets' POLICY_RULE_SETS_URI = GROUPPOLICY_URI + '/' + 'policy_rule_sets'
NET_SVC_POLICIES_URI = GROUPPOLICY_URI + '/' + 'network_service_policies' 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): class GroupPolicyExtensionTestCase(test_api_v2_extension.ExtensionTestCase):
@@ -46,7 +53,8 @@ class GroupPolicyExtensionTestCase(test_api_v2_extension.ExtensionTestCase):
super(GroupPolicyExtensionTestCase, self).setUp() super(GroupPolicyExtensionTestCase, self).setUp()
plural_mappings = { plural_mappings = {
'l2_policy': 'l2_policies', 'l3_policy': 'l3_policies', '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( self._setUpExtension(
GP_PLUGIN_BASE_NAME, constants.GROUP_POLICY, GP_PLUGIN_BASE_NAME, constants.GROUP_POLICY,
gp.RESOURCE_ATTRIBUTE_MAP, gp.Group_policy, GROUPPOLICY_URI, 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): def _get_create_l3_policy_default_attrs(self):
return {'name': '', 'description': '', 'ip_version': 4, return {'name': '', 'description': '', 'ip_version': 4,
'ip_pool': '10.0.0.0/8', 'subnet_prefix_length': 24, 'ip_pool': '10.0.0.0/8', 'subnet_prefix_length': 24,
'shared': False} 'external_segments': {}, 'shared': False}
def _get_create_l3_policy_attrs(self): def _get_create_l3_policy_attrs(self):
return {'name': 'l3p1', 'tenant_id': _uuid(), return {'name': 'l3p1', 'tenant_id': _uuid(),
'description': 'test L3 policy', 'ip_version': 6, 'description': 'test L3 policy', 'ip_version': 6,
'ip_pool': 'fd01:2345:6789::/48', 'ip_pool': 'fd01:2345:6789::/48',
'external_segments': {_uuid(): ['192.168.0.3']},
'subnet_prefix_length': 64, 'shared': False} 'subnet_prefix_length': 64, 'shared': False}
def _get_update_l3_policy_attrs(self): 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): def test_delete_network_service_policy(self):
self._test_entity_delete('network_service_policy') 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): class TestGroupPolicyAttributeConverters(base.BaseTestCase):
@@ -1129,3 +1341,24 @@ class TestGroupPolicyAttributeValidators(base.BaseTestCase):
msg = gp._validate_network_svc_params(test_params) msg = gp._validate_network_svc_params(test_params)
self.assertEqual( self.assertEqual(
msg, "Network service param value 'subnet' is not supported") 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)

View File

@@ -38,7 +38,9 @@ class GroupPolicyMappingExtTestCase(tgp.GroupPolicyExtensionTestCase):
plural_mappings = {'l2_policy': 'l2_policies', plural_mappings = {'l2_policy': 'l2_policies',
'l3_policy': 'l3_policies', 'l3_policy': 'l3_policies',
'network_service_policy': 'network_service_policy':
'network_service_policies'} 'network_service_policies',
'external_policy':
'external_policies'}
self._setUpExtension( self._setUpExtension(
tgp.GP_PLUGIN_BASE_NAME, constants.GROUP_POLICY, attr_map, tgp.GP_PLUGIN_BASE_NAME, constants.GROUP_POLICY, attr_map,
gp.Group_policy, tgp.GROUPPOLICY_URI, gp.Group_policy, tgp.GROUPPOLICY_URI,