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,7 +1179,10 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
|
||||
ip_pool=l3p['ip_pool'],
|
||||
subnet_prefix_length=l3p['subnet_prefix_length'],
|
||||
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)
|
||||
|
||||
@log.log
|
||||
@@ -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