Share service chain constructs

Adding 'shared' attribute to the following service chain objects:

- Service Chain Node;
- Service Chain Spec.

As a side effect, REDIRECT rules can now be shared with a
shared SCS value.

implements blueprint share-servicechain-objects

Change-Id: If6cd4072271fdbe9f213aa2922cb918547340cd3
This commit is contained in:
Ivar Lazzaro
2015-03-16 17:24:49 -07:00
parent c66404c4b6
commit c9bfb7b116
14 changed files with 445 additions and 134 deletions

View File

@@ -4,60 +4,87 @@
"admin_only": "rule:context_is_admin", "admin_only": "rule:context_is_admin",
"regular_user": "", "regular_user": "",
"default": "rule:admin_or_owner", "default": "rule:admin_or_owner",
"gbp_shared": "field:policy_target_groups:shared=True", "shared_ptg": "field:policy_target_groups:shared=True",
"shared_pt": "field:policy_targets:shared=True",
"shared_prs": "field:policy_rule_sets:shared=True",
"shared_l3p": "field:l3_policies:shared=True",
"shared_l2p": "field:l2_policies:shared=True",
"shared_es": "field:external_segments:shared=True",
"shared_ep": "field:external_policies:shared=True",
"shared_pc": "field:policy_classifiers:shared=True",
"shared_pa": "field:policy_actions:shared=True",
"shared_pr": "field:policy_rules:shared=True",
"shared_np": "field:nat_pools:shared=True",
"shared_nsp": "field:network_service_policies:shared=True",
"shared_scn": "field:servicechain_nodes:shared=True",
"shared_scs": "field:servicechain_specs:shared=True",
"create_policy_target_group": "", "create_policy_target_group": "",
"create_policy_target_group:shared": "rule:admin_only", "create_policy_target_group:shared": "rule:admin_only",
"get_policy_target_group": "rule:admin_or_owner or rule:gbp_shared", "get_policy_target_group": "rule:admin_or_owner or rule:shared_ptg",
"update_policy_target_group:shared": "rule:admin_only", "update_policy_target_group:shared": "rule:admin_only",
"create_l2_policy": "", "create_l2_policy": "",
"create_l2_policy:shared": "rule:admin_only", "create_l2_policy:shared": "rule:admin_only",
"get_l2_policy": "rule:admin_or_owner or rule:gbp_shared", "get_l2_policy": "rule:admin_or_owner or rule:shared_l2p",
"update_l2_policy:shared": "rule:admin_only", "update_l2_policy:shared": "rule:admin_only",
"create_l3_policy": "", "create_l3_policy": "",
"create_l3_policy:shared": "rule:admin_only", "create_l3_policy:shared": "rule:admin_only",
"get_l3_policy": "rule:admin_or_owner or rule:gbp_shared", "get_l3_policy": "rule:admin_or_owner or rule:shared_l3p",
"update_l3_policy:shared": "rule:admin_only", "update_l3_policy:shared": "rule:admin_only",
"create_policy_classifier": "", "create_policy_classifier": "",
"create_policy_classifier:shared": "rule:admin_only", "create_policy_classifier:shared": "rule:admin_only",
"get_policy_classifier": "rule:admin_or_owner or rule:gbp_shared", "get_policy_classifier": "rule:admin_or_owner or rule:shared_pc",
"update_policy_classifier:shared": "rule:admin_only", "update_policy_classifier:shared": "rule:admin_only",
"create_policy_action": "", "create_policy_action": "",
"create_policy_action:shared": "rule:admin_only", "create_policy_action:shared": "rule:admin_only",
"get_policy_action": "rule:admin_or_owner or rule:gbp_shared", "get_policy_action": "rule:admin_or_owner or rule:shared_pa",
"update_policy_action:shared": "rule:admin_only", "update_policy_action:shared": "rule:admin_only",
"create_policy_rule": "", "create_policy_rule": "",
"create_policy_rule:shared": "rule:admin_only", "create_policy_rule:shared": "rule:admin_only",
"get_policy_rule": "rule:admin_or_owner or rule:gbp_shared", "get_policy_rule": "rule:admin_or_owner or rule:shared_pr",
"update_policy_rule:shared": "rule:admin_only", "update_policy_rule:shared": "rule:admin_only",
"create_policy_rule_set": "", "create_policy_rule_set": "",
"create_policy_rule_set:shared": "rule:admin_only", "create_policy_rule_set:shared": "rule:admin_only",
"get_policy_rule_set": "rule:admin_or_owner or rule:gbp_shared", "get_policy_rule_set": "rule:admin_or_owner or rule:shared_prs",
"update_policy_rule_set:shared": "rule:admin_only", "update_policy_rule_set:shared": "rule:admin_only",
"create_network_service_policy": "", "create_network_service_policy": "",
"create_network_service_policy:shared": "rule:admin_only", "create_network_service_policy:shared": "rule:admin_only",
"get_network_service_policy": "rule:admin_or_owner or rule:gbp_shared", "get_network_service_policy": "rule:admin_or_owner or rule:shared_nsp",
"update_network_service_policy:shared": "rule:admin_only", "update_network_service_policy:shared": "rule:admin_only",
"create_external_segment": "", "create_external_segment": "",
"create_external_segment:shared": "rule:admin_only", "create_external_segment:shared": "rule:admin_only",
"get_external_segment": "rule:admin_or_owner or rule:gbp_shared", "get_external_segment": "rule:admin_or_owner or rule:shared_es",
"update_external_segment:shared": "rule:admin_only", "update_external_segment:shared": "rule:admin_only",
"create_external_policy": "", "create_external_policy": "",
"create_external_policy:shared": "rule:admin_only", "create_external_policy:shared": "rule:admin_only",
"get_external_policy": "rule:admin_or_owner or rule:gbp_shared", "get_external_policy": "rule:admin_or_owner or rule:shared_ep",
"update_external_policy:shared": "rule:admin_only", "update_external_policy:shared": "rule:admin_only",
"create_nat_pool": "", "create_nat_pool": "",
"create_nat_pool:shared": "rule:admin_only", "create_nat_pool:shared": "rule:admin_only",
"get_nat_pool": "rule:admin_or_owner or rule:gbp_shared", "get_nat_pool": "rule:admin_or_owner or rule:shared_np",
"update_nat_pool:shared": "rule:admin_only" "update_nat_pool:shared": "rule:admin_only",
"create_servicechain_node": "",
"create_servicechain_node:shared": "rule:admin_only",
"get_servicechain_node": "rule:admin_or_owner or rule:shared_scn",
"update_servicechain_node:shared": "rule:admin_only",
"create_servicechain_spec": "",
"create_servicechain_spec:shared": "rule:admin_only",
"get_servicechain_spec": "rule:admin_or_owner or rule:shared_scs",
"update_servicechain_spec:shared": "rule:admin_only",
"create_servicechain_instance": "",
"get_servicechain_instance": "rule:admin_or_owner",
"update_servicechain_instance:shared": "rule:admin_only"
} }

View File

@@ -883,6 +883,8 @@ class GroupPolicyDbPlugin(gpolicy.GroupPolicyPluginBase,
'action_type': pa['action_type'], 'action_type': pa['action_type'],
'action_value': pa['action_value'], 'action_value': pa['action_value'],
'shared': pa.get('shared', False), } 'shared': pa.get('shared', False), }
res['policy_rules'] = [pr['policy_rule_id'] for
pr in pa['policy_rules']]
return self._fields(res, fields) return self._fields(res, fields)
def _make_policy_rule_dict(self, pr, fields=None): def _make_policy_rule_dict(self, pr, fields=None):

View File

@@ -0,0 +1,40 @@
# 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.
#
# revision identifiers, used by Alembic.
revision = '3791adbf0045'
down_revision = '2f3834ea746b'
from alembic import op
import sqlalchemy as sa
def upgrade():
op.add_column(
'sc_nodes',
sa.Column('shared', sa.Boolean)
)
op.add_column(
'sc_specs',
sa.Column('shared', sa.Boolean)
)
def downgrade():
op.drop_column('sc_nodes', 'shared')
op.drop_column('sc_specs', 'shared')

View File

@@ -1 +1 @@
2f3834ea746b 3791adbf0045

View File

@@ -68,6 +68,7 @@ class ServiceChainNode(model_base.BASEV2, models_v2.HasId,
specs = orm.relationship(SpecNodeAssociation, specs = orm.relationship(SpecNodeAssociation,
backref="nodes", backref="nodes",
cascade='all, delete, delete-orphan') cascade='all, delete, delete-orphan')
shared = sa.Column(sa.Boolean)
class ServiceChainInstance(model_base.BASEV2, models_v2.HasId, class ServiceChainInstance(model_base.BASEV2, models_v2.HasId,
@@ -111,6 +112,7 @@ class ServiceChainSpec(model_base.BASEV2, models_v2.HasId,
instances = orm.relationship(InstanceSpecAssociation, instances = orm.relationship(InstanceSpecAssociation,
backref="specs", backref="specs",
cascade='all, delete, delete-orphan') cascade='all, delete, delete-orphan')
shared = sa.Column(sa.Boolean)
class ServiceChainDbPlugin(schain.ServiceChainPluginBase, class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
@@ -161,7 +163,10 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
'name': sc_node['name'], 'name': sc_node['name'],
'description': sc_node['description'], 'description': sc_node['description'],
'service_type': sc_node['service_type'], 'service_type': sc_node['service_type'],
'config': sc_node['config']} 'config': sc_node['config'],
'shared': sc_node['shared']}
res['servicechain_specs'] = [sc_spec['servicechain_spec_id']
for sc_spec in sc_node['specs']]
return self._fields(res, fields) return self._fields(res, fields)
def _make_sc_spec_dict(self, spec, fields=None): def _make_sc_spec_dict(self, spec, fields=None):
@@ -169,7 +174,8 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
'tenant_id': spec['tenant_id'], 'tenant_id': spec['tenant_id'],
'name': spec['name'], 'name': spec['name'],
'description': spec['description'], 'description': spec['description'],
'config_param_names': spec.get('config_param_names')} 'config_param_names': spec.get('config_param_names'),
'shared': spec['shared']}
res['nodes'] = [sc_node['node_id'] for sc_node in spec['nodes']] res['nodes'] = [sc_node['node_id'] for sc_node in spec['nodes']]
return self._fields(res, fields) return self._fields(res, fields)
@@ -201,7 +207,8 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
name=node['name'], name=node['name'],
description=node['description'], description=node['description'],
service_type=node['service_type'], service_type=node['service_type'],
config=node['config']) config=node['config'],
shared=node['shared'])
context.session.add(node_db) context.session.add(node_db)
return self._make_sc_node_dict(node_db) return self._make_sc_node_dict(node_db)
@@ -331,7 +338,8 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
spec_db = ServiceChainSpec(id=uuidutils.generate_uuid(), spec_db = ServiceChainSpec(id=uuidutils.generate_uuid(),
tenant_id=tenant_id, tenant_id=tenant_id,
name=spec['name'], name=spec['name'],
description=spec['description']) description=spec['description'],
shared=spec['shared'])
self._process_nodes_for_spec(context, spec_db, spec) self._process_nodes_for_spec(context, spec_db, spec)
context.session.add(spec_db) context.session.add(spec_db)
return self._make_sc_spec_dict(spec_db) return self._make_sc_spec_dict(spec_db)

View File

@@ -115,6 +115,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'config': {'allow_post': True, 'allow_put': False, 'config': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None}, 'validate': {'type:string': None},
'required': True, 'is_visible': True}, 'required': True, '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},
}, },
SERVICECHAIN_SPECS: { SERVICECHAIN_SPECS: {
'id': {'allow_post': False, 'allow_put': False, 'id': {'allow_post': False, 'allow_put': False,
@@ -137,6 +141,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'config_param_names': {'allow_post': False, 'allow_put': False, 'config_param_names': {'allow_post': False, 'allow_put': False,
'validate': {'type:string_list': None}, 'validate': {'type:string_list': None},
'default': [], 'is_visible': True}, 'default': [], '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},
}, },
SERVICECHAIN_INSTANCES: { SERVICECHAIN_INSTANCES: {
'id': {'allow_post': False, 'allow_put': False, 'id': {'allow_post': False, 'allow_put': False,

View File

@@ -77,9 +77,8 @@ class PolicyTargetGroupContext(GroupPolicyContext,
def set_l2_policy_id(self, l2_policy_id): def set_l2_policy_id(self, l2_policy_id):
self._plugin._validate_shared_create( self._plugin._validate_shared_create(
self._plugin_context, self._plugin, self._plugin_context, self._policy_target_group,
self._policy_target_group, 'policy_target_group')
'policy_target_group')
self._plugin._set_l2_policy_for_policy_target_group( self._plugin._set_l2_policy_for_policy_target_group(
self._plugin_context, self._policy_target_group['id'], self._plugin_context, self._policy_target_group['id'],
l2_policy_id) l2_policy_id)
@@ -115,9 +114,7 @@ class L2PolicyContext(GroupPolicyContext, api.L2PolicyContext):
def set_l3_policy_id(self, l3_policy_id): def set_l3_policy_id(self, l3_policy_id):
self._plugin._validate_shared_create( self._plugin._validate_shared_create(
self._plugin_context, self._plugin, self._plugin_context, self._l2_policy, 'l2_policy')
self._l2_policy,
'l2_policy')
self._plugin._set_l3_policy_for_l2_policy( self._plugin._set_l3_policy_for_l2_policy(
self._plugin_context, self._l2_policy['id'], l3_policy_id) self._plugin_context, self._l2_policy['id'], l3_policy_id)
self._l2_policy['l3_policy_id'] = l3_policy_id self._l2_policy['l3_policy_id'] = l3_policy_id

View File

@@ -14,6 +14,8 @@ import netaddr
from neutron.api.v2 import attributes as nattr from neutron.api.v2 import attributes as nattr
from neutron.common import log from neutron.common import log
from neutron import manager as n_manager
from neutron.plugins.common import constants as pconst
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import excutils from oslo_utils import excutils
@@ -26,6 +28,7 @@ from gbpservice.neutron.services.grouppolicy import (
group_policy_context as p_context) group_policy_context as p_context)
from gbpservice.neutron.services.grouppolicy import ( from gbpservice.neutron.services.grouppolicy import (
policy_driver_manager as manager) policy_driver_manager as manager)
from gbpservice.neutron.services.grouppolicy.common import constants as gp_cts
from gbpservice.neutron.services.grouppolicy.common import exceptions as gp_exc from gbpservice.neutron.services.grouppolicy.common import exceptions as gp_exc
@@ -50,6 +53,17 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
self._aliases = aliases self._aliases = aliases
return self._aliases return self._aliases
@property
def servicechain_plugin(self):
# REVISIT(rkukura): Need initialization method after all
# plugins are loaded to grab and store plugin.
plugins = n_manager.NeutronManager.get_service_plugins()
servicechain_plugin = plugins.get(pconst.SERVICECHAIN)
if not servicechain_plugin:
LOG.error(_("No Servicechain service plugin found."))
raise gp_exc.GroupPolicyDeploymentError()
return servicechain_plugin
# Shared attribute validation rules: # Shared attribute validation rules:
# - A shared resource cannot use/link a non-shared resource # - A shared resource cannot use/link a non-shared resource
# - A shared resource cannot be reverted to non-shared if used/linked by # - A shared resource cannot be reverted to non-shared if used/linked by
@@ -96,6 +110,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
self._plurals = dict((nattr.PLURALS[k], k) for k in nattr.PLURALS) self._plurals = dict((nattr.PLURALS[k], k) for k in nattr.PLURALS)
return self._plurals return self._plurals
@staticmethod
def _validate_shared_create(self, context, obj, identity): def _validate_shared_create(self, context, obj, identity):
# REVISIT(ivar): only validate new references # REVISIT(ivar): only validate new references
links = self.usage_graph.get(identity, {}) links = self.usage_graph.get(identity, {})
@@ -111,21 +126,15 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
link_ids = set() link_ids = set()
for linked in linked_objects: for linked in linked_objects:
link_ids.add(linked['id']) link_ids.add(linked['id'])
if not linked.get('shared'): GroupPolicyPlugin._verify_sharing_consistency(
if obj.get('shared'): obj, linked, identity, ref_type)
raise gp_exc.SharedResourceReferenceError(
res_type=identity, res_id=obj['id'],
ref_type=ref_type, ref_id=linked['id'])
if obj.get('tenant_id') != linked.get('tenant_id'):
raise gp_exc.InvalidCrossTenantReference(
res_type=identity, res_id=obj['id'],
ref_type=ref_type, ref_id=linked['id'])
# Check for missing references # Check for missing references
missing = set(ids) - link_ids missing = set(ids) - link_ids
if missing: if missing:
raise gpex.GbpResourceNotFound(identity=ref_type, raise gpex.GbpResourceNotFound(identity=ref_type,
id=str(missing)) id=str(missing))
@staticmethod
def _validate_shared_update(self, context, original, updated, identity): def _validate_shared_update(self, context, original, updated, identity):
# Need admin context to check sharing constraints # Need admin context to check sharing constraints
@@ -133,13 +142,14 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
# it is referring to might. For this reson we run the reference # it is referring to might. For this reson we run the reference
# validation every time a shared resource is updated # validation every time a shared resource is updated
# TODO(ivar): run only when relevant updates happen # TODO(ivar): run only when relevant updates happen
self._validate_shared_create(context, updated, identity) self._validate_shared_create(self, context, updated, identity)
if updated.get('shared') != original.get('shared'): if updated.get('shared') != original.get('shared'):
context = context.elevated() context = context.elevated()
getattr(self, '_validate_%s_unshare' % identity)(context, updated) getattr(self, '_validate_%s_unshare' % identity)(context, updated)
def _check_shared_or_different_tenant(self, context, obj, @staticmethod
method, attr, value=None): def _check_shared_or_different_tenant(context, obj, method, attr,
value=None):
tenant_id = obj['tenant_id'] tenant_id = obj['tenant_id']
refs = method(context, filters={attr: value or [obj['id']]}) refs = method(context, filters={attr: value or [obj['id']]})
for ref in refs: for ref in refs:
@@ -267,6 +277,28 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
ip=addr, es_id=es['id'], l3p_id=current['id'], ip=addr, es_id=es['id'], l3p_id=current['id'],
es_cidr=es['cidr']) es_cidr=es['cidr'])
def _validate_action_value(self, context, action):
if action.get('action_type') == gp_cts.GP_ACTION_REDIRECT:
if action.get('action_value'):
# Verify sc spec existence and visibility
spec = self.servicechain_plugin.get_servicechain_spec(
context, action['action_value'])
GroupPolicyPlugin._verify_sharing_consistency(
action, spec, 'polocy_action', 'servicechain_spec')
@staticmethod
def _verify_sharing_consistency(primary, reference, primary_type,
reference_type):
if not reference.get('shared'):
if primary.get('shared'):
raise gp_exc.SharedResourceReferenceError(
res_type=primary_type, res_id=primary['id'],
ref_type=reference_type, ref_id=reference['id'])
if primary.get('tenant_id') != reference.get('tenant_id'):
raise gp_exc.InvalidCrossTenantReference(
res_type=primary_type, res_id=primary['id'],
ref_type=reference_type, ref_id=reference['id'])
def __init__(self): def __init__(self):
self.extension_manager = ext_manager.ExtensionManager() self.extension_manager = ext_manager.ExtensionManager()
self.policy_driver_manager = manager.PolicyDriverManager() self.policy_driver_manager = manager.PolicyDriverManager()
@@ -282,7 +314,8 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
self).create_policy_target(context, policy_target) self).create_policy_target(context, policy_target)
self.extension_manager.process_create_policy_target( self.extension_manager.process_create_policy_target(
session, policy_target, result) session, policy_target, result)
self._validate_shared_create(context, result, 'policy_target') self._validate_shared_create(
self, context, result, 'policy_target')
policy_context = p_context.PolicyTargetContext(self, context, policy_context = p_context.PolicyTargetContext(self, context,
result) result)
self.policy_driver_manager.create_policy_target_precommit( self.policy_driver_manager.create_policy_target_precommit(
@@ -311,7 +344,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, policy_target_id, policy_target) context, policy_target_id, policy_target)
self.extension_manager.process_update_policy_target( self.extension_manager.process_update_policy_target(
session, policy_target, updated_policy_target) session, policy_target, updated_policy_target)
self._validate_shared_update(context, original_policy_target, self._validate_shared_update(self, context, original_policy_target,
updated_policy_target, updated_policy_target,
'policy_target') 'policy_target')
policy_context = p_context.PolicyTargetContext( policy_context = p_context.PolicyTargetContext(
@@ -373,7 +406,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, policy_target_group) context, policy_target_group)
self.extension_manager.process_create_policy_target_group( self.extension_manager.process_create_policy_target_group(
session, policy_target_group, result) session, policy_target_group, result)
self._validate_shared_create(context, result, self._validate_shared_create(self, context, result,
'policy_target_group') 'policy_target_group')
policy_context = p_context.PolicyTargetGroupContext( policy_context = p_context.PolicyTargetGroupContext(
self, context, result) self, context, result)
@@ -404,9 +437,9 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, policy_target_group_id, policy_target_group) context, policy_target_group_id, policy_target_group)
self.extension_manager.process_update_policy_target_group( self.extension_manager.process_update_policy_target_group(
session, policy_target_group, updated_policy_target_group) session, policy_target_group, updated_policy_target_group)
self._validate_shared_update(context, original_policy_target_group, self._validate_shared_update(
updated_policy_target_group, self, context, original_policy_target_group,
'policy_target_group') updated_policy_target_group, 'policy_target_group')
policy_context = p_context.PolicyTargetGroupContext( policy_context = p_context.PolicyTargetGroupContext(
self, context, updated_policy_target_group, self, context, updated_policy_target_group,
original_policy_target_group=original_policy_target_group) original_policy_target_group=original_policy_target_group)
@@ -482,7 +515,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
self).create_l2_policy(context, l2_policy) self).create_l2_policy(context, l2_policy)
self.extension_manager.process_create_l2_policy( self.extension_manager.process_create_l2_policy(
session, l2_policy, result) session, l2_policy, result)
self._validate_shared_create(context, result, 'l2_policy') self._validate_shared_create(self, context, result, 'l2_policy')
policy_context = p_context.L2PolicyContext(self, context, result) policy_context = p_context.L2PolicyContext(self, context, result)
self.policy_driver_manager.create_l2_policy_precommit( self.policy_driver_manager.create_l2_policy_precommit(
policy_context) policy_context)
@@ -508,7 +541,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, l2_policy_id, l2_policy) context, l2_policy_id, l2_policy)
self.extension_manager.process_update_l2_policy( self.extension_manager.process_update_l2_policy(
session, l2_policy, updated_l2_policy) session, l2_policy, updated_l2_policy)
self._validate_shared_update(context, original_l2_policy, self._validate_shared_update(self, context, original_l2_policy,
updated_l2_policy, 'l2_policy') updated_l2_policy, 'l2_policy')
policy_context = p_context.L2PolicyContext( policy_context = p_context.L2PolicyContext(
self, context, updated_l2_policy, self, context, updated_l2_policy,
@@ -569,7 +602,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, network_service_policy) context, network_service_policy)
self.extension_manager.process_create_network_service_policy( self.extension_manager.process_create_network_service_policy(
session, network_service_policy, result) session, network_service_policy, result)
self._validate_shared_create(context, result, self._validate_shared_create(self, context, result,
'network_service_policy') 'network_service_policy')
policy_context = p_context.NetworkServicePolicyContext( policy_context = p_context.NetworkServicePolicyContext(
self, context, result) self, context, result)
@@ -604,7 +637,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
session, network_service_policy, session, network_service_policy,
updated_network_service_policy) updated_network_service_policy)
self._validate_shared_update( self._validate_shared_update(
context, original_network_service_policy, self, context, original_network_service_policy,
updated_network_service_policy, 'network_service_policy') updated_network_service_policy, 'network_service_policy')
policy_context = p_context.NetworkServicePolicyContext( policy_context = p_context.NetworkServicePolicyContext(
self, context, updated_network_service_policy, self, context, updated_network_service_policy,
@@ -670,7 +703,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
self).create_l3_policy(context, l3_policy) self).create_l3_policy(context, l3_policy)
self.extension_manager.process_create_l3_policy( self.extension_manager.process_create_l3_policy(
session, l3_policy, result) session, l3_policy, result)
self._validate_shared_create(context, result, 'l3_policy') self._validate_shared_create(self, context, result, 'l3_policy')
self._validate_l3p_es(context, result) self._validate_l3p_es(context, result)
policy_context = p_context.L3PolicyContext(self, context, policy_context = p_context.L3PolicyContext(self, context,
result) result)
@@ -698,7 +731,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, l3_policy_id, l3_policy) context, l3_policy_id, l3_policy)
self.extension_manager.process_update_l3_policy( self.extension_manager.process_update_l3_policy(
session, l3_policy, updated_l3_policy) session, l3_policy, updated_l3_policy)
self._validate_shared_update(context, original_l3_policy, self._validate_shared_update(self, context, original_l3_policy,
updated_l3_policy, 'l3_policy') updated_l3_policy, 'l3_policy')
self._validate_l3p_es(context, updated_l3_policy, self._validate_l3p_es(context, updated_l3_policy,
original_l3_policy) original_l3_policy)
@@ -766,7 +799,8 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, policy_classifier) context, policy_classifier)
self.extension_manager.process_create_policy_classifier( self.extension_manager.process_create_policy_classifier(
session, policy_classifier, result) session, policy_classifier, result)
self._validate_shared_create(context, result, 'policy_classifier') self._validate_shared_create(
self, context, result, 'policy_classifier')
policy_context = p_context.PolicyClassifierContext(self, context, policy_context = p_context.PolicyClassifierContext(self, context,
result) result)
self.policy_driver_manager.create_policy_classifier_precommit( self.policy_driver_manager.create_policy_classifier_precommit(
@@ -795,9 +829,9 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, id, policy_classifier) context, id, policy_classifier)
self.extension_manager.process_update_policy_classifier( self.extension_manager.process_update_policy_classifier(
session, policy_classifier, updated_policy_classifier) session, policy_classifier, updated_policy_classifier)
self._validate_shared_update(context, original_policy_classifier, self._validate_shared_update(
updated_policy_classifier, self, context, original_policy_classifier,
'policy_classifier') updated_policy_classifier, 'policy_classifier')
policy_context = p_context.PolicyClassifierContext( policy_context = p_context.PolicyClassifierContext(
self, context, updated_policy_classifier, self, context, updated_policy_classifier,
original_policy_classifier=original_policy_classifier) original_policy_classifier=original_policy_classifier)
@@ -858,7 +892,9 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
self).create_policy_action(context, policy_action) self).create_policy_action(context, policy_action)
self.extension_manager.process_create_policy_action( self.extension_manager.process_create_policy_action(
session, policy_action, result) session, policy_action, result)
self._validate_shared_create(context, result, 'policy_action') self._validate_shared_create(self, context, result,
'policy_action')
self._validate_action_value(context, result)
policy_context = p_context.PolicyActionContext(self, context, policy_context = p_context.PolicyActionContext(self, context,
result) result)
self.policy_driver_manager.create_policy_action_precommit( self.policy_driver_manager.create_policy_action_precommit(
@@ -887,9 +923,10 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
policy_action) policy_action)
self.extension_manager.process_update_policy_action( self.extension_manager.process_update_policy_action(
session, policy_action, updated_policy_action) session, policy_action, updated_policy_action)
self._validate_shared_update(context, original_policy_action, self._validate_shared_update(self, context, original_policy_action,
updated_policy_action, updated_policy_action,
'policy_action') 'policy_action')
self._validate_action_value(context, updated_policy_action)
policy_context = p_context.PolicyActionContext( policy_context = p_context.PolicyActionContext(
self, context, updated_policy_action, self, context, updated_policy_action,
original_policy_action=original_policy_action) original_policy_action=original_policy_action)
@@ -948,7 +985,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, policy_rule) context, policy_rule)
self.extension_manager.process_create_policy_rule( self.extension_manager.process_create_policy_rule(
session, policy_rule, result) session, policy_rule, result)
self._validate_shared_create(context, result, 'policy_rule') self._validate_shared_create(self, context, result, 'policy_rule')
policy_context = p_context.PolicyRuleContext(self, context, policy_context = p_context.PolicyRuleContext(self, context,
result) result)
self.policy_driver_manager.create_policy_rule_precommit( self.policy_driver_manager.create_policy_rule_precommit(
@@ -977,7 +1014,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, id, policy_rule) context, id, policy_rule)
self.extension_manager.process_update_policy_rule( self.extension_manager.process_update_policy_rule(
session, policy_rule, updated_policy_rule) session, policy_rule, updated_policy_rule)
self._validate_shared_update(context, original_policy_rule, self._validate_shared_update(self, context, original_policy_rule,
updated_policy_rule, 'policy_rule') updated_policy_rule, 'policy_rule')
policy_context = p_context.PolicyRuleContext( policy_context = p_context.PolicyRuleContext(
self, context, updated_policy_rule, self, context, updated_policy_rule,
@@ -1038,7 +1075,8 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, policy_rule_set) context, policy_rule_set)
self.extension_manager.process_create_policy_rule_set( self.extension_manager.process_create_policy_rule_set(
session, policy_rule_set, result) session, policy_rule_set, result)
self._validate_shared_create(context, result, 'policy_rule_set') self._validate_shared_create(
self, context, result, 'policy_rule_set')
policy_context = p_context.PolicyRuleSetContext( policy_context = p_context.PolicyRuleSetContext(
self, context, result) self, context, result)
self.policy_driver_manager.create_policy_rule_set_precommit( self.policy_driver_manager.create_policy_rule_set_precommit(
@@ -1067,9 +1105,9 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, id, policy_rule_set) context, id, policy_rule_set)
self.extension_manager.process_update_policy_rule_set( self.extension_manager.process_update_policy_rule_set(
session, policy_rule_set, updated_policy_rule_set) session, policy_rule_set, updated_policy_rule_set)
self._validate_shared_update(context, original_policy_rule_set, self._validate_shared_update(
updated_policy_rule_set, self, context, original_policy_rule_set,
'policy_rule_set') updated_policy_rule_set, 'policy_rule_set')
policy_context = p_context.PolicyRuleSetContext( policy_context = p_context.PolicyRuleSetContext(
self, context, updated_policy_rule_set, self, context, updated_policy_rule_set,
original_policy_rule_set=original_policy_rule_set) original_policy_rule_set=original_policy_rule_set)
@@ -1128,7 +1166,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
external_segment) external_segment)
self.extension_manager.process_create_external_segment( self.extension_manager.process_create_external_segment(
session, external_segment, result) session, external_segment, result)
self._validate_shared_create(context, result, self._validate_shared_create(self, context, result,
'external_segment') 'external_segment')
self._validate_routes(context, result) self._validate_routes(context, result)
policy_context = p_context.ExternalSegmentContext( policy_context = p_context.ExternalSegmentContext(
@@ -1163,7 +1201,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
self.extension_manager.process_update_external_segment( self.extension_manager.process_update_external_segment(
session, external_segment, updated_external_segment) session, external_segment, updated_external_segment)
self._validate_shared_update( self._validate_shared_update(
context, original_external_segment, self, context, original_external_segment,
updated_external_segment, 'external_segment') updated_external_segment, 'external_segment')
self._validate_routes(context, updated_external_segment, self._validate_routes(context, updated_external_segment,
original_external_segment) original_external_segment)
@@ -1231,7 +1269,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, external_policy) context, external_policy)
self.extension_manager.process_create_external_policy( self.extension_manager.process_create_external_policy(
session, external_policy, result) session, external_policy, result)
self._validate_shared_create(context, result, self._validate_shared_create(self, context, result,
'external_policy') 'external_policy')
policy_context = p_context.ExternalPolicyContext( policy_context = p_context.ExternalPolicyContext(
self, context, result) self, context, result)
@@ -1265,7 +1303,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
self.extension_manager.process_update_external_policy( self.extension_manager.process_update_external_policy(
session, external_policy, updated_external_policy) session, external_policy, updated_external_policy)
self._validate_shared_update( self._validate_shared_update(
context, original_external_policy, self, context, original_external_policy,
updated_external_policy, 'external_policy') updated_external_policy, 'external_policy')
policy_context = p_context.ExternalPolicyContext( policy_context = p_context.ExternalPolicyContext(
self, context, updated_external_policy, self, context, updated_external_policy,
@@ -1327,7 +1365,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, nat_pool) context, nat_pool)
self.extension_manager.process_create_nat_pool(session, nat_pool, self.extension_manager.process_create_nat_pool(session, nat_pool,
result) result)
self._validate_shared_create(context, result, 'nat_pool') self._validate_shared_create(self, context, result, 'nat_pool')
policy_context = p_context.NatPoolContext(self, context, result) policy_context = p_context.NatPoolContext(self, context, result)
(self.policy_driver_manager. (self.policy_driver_manager.
create_nat_pool_precommit(policy_context)) create_nat_pool_precommit(policy_context))
@@ -1354,7 +1392,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
nat_pool) nat_pool)
self.extension_manager.process_update_nat_pool( self.extension_manager.process_update_nat_pool(
session, nat_pool, updated_nat_pool) session, nat_pool, updated_nat_pool)
self._validate_shared_update(context, original_nat_pool, self._validate_shared_update(self, context, original_nat_pool,
updated_nat_pool, 'nat_pool') updated_nat_pool, 'nat_pool')
policy_context = p_context.NatPoolContext( policy_context = p_context.NatPoolContext(
self, context, updated_nat_pool, original_nat_pool) self, context, updated_nat_pool, original_nat_pool)

View File

@@ -19,12 +19,14 @@ from gbpservice.neutron.services.servicechain.plugins.msc import (
context as servicechain_context) context as servicechain_context)
from gbpservice.neutron.services.servicechain.plugins.msc import ( from gbpservice.neutron.services.servicechain.plugins.msc import (
driver_manager as manager) driver_manager as manager)
from gbpservice.neutron.services.servicechain.plugins import sharing
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
class ServiceChainPlugin(servicechain_db.ServiceChainDbPlugin): class ServiceChainPlugin(servicechain_db.ServiceChainDbPlugin,
sharing.SharingMixin):
"""Implementation of the Service Chain Plugin. """Implementation of the Service Chain Plugin.
@@ -42,6 +44,7 @@ class ServiceChainPlugin(servicechain_db.ServiceChainDbPlugin):
with session.begin(subtransactions=True): with session.begin(subtransactions=True):
result = super(ServiceChainPlugin, self).create_servicechain_node( result = super(ServiceChainPlugin, self).create_servicechain_node(
context, servicechain_node) context, servicechain_node)
self._validate_shared_create(context, result, 'servicechain_node')
sc_context = servicechain_context.ServiceChainNodeContext( sc_context = servicechain_context.ServiceChainNodeContext(
self, context, result) self, context, result)
self.driver_manager.create_servicechain_node_precommit( self.driver_manager.create_servicechain_node_precommit(
@@ -70,6 +73,8 @@ class ServiceChainPlugin(servicechain_db.ServiceChainDbPlugin):
self).update_servicechain_node( self).update_servicechain_node(
context, servicechain_node_id, context, servicechain_node_id,
servicechain_node) servicechain_node)
self._validate_shared_update(context, original_sc_node,
updated_sc_node, 'servicechain_node')
sc_context = servicechain_context.ServiceChainNodeContext( sc_context = servicechain_context.ServiceChainNodeContext(
self, context, updated_sc_node, self, context, updated_sc_node,
original_sc_node=original_sc_node) original_sc_node=original_sc_node)
@@ -107,6 +112,7 @@ class ServiceChainPlugin(servicechain_db.ServiceChainDbPlugin):
with session.begin(subtransactions=True): with session.begin(subtransactions=True):
result = super(ServiceChainPlugin, self).create_servicechain_spec( result = super(ServiceChainPlugin, self).create_servicechain_spec(
context, servicechain_spec) context, servicechain_spec)
self._validate_shared_create(context, result, 'servicechain_spec')
sc_context = servicechain_context.ServiceChainSpecContext( sc_context = servicechain_context.ServiceChainSpecContext(
self, context, result) self, context, result)
self.driver_manager.create_servicechain_spec_precommit( self.driver_manager.create_servicechain_spec_precommit(
@@ -134,6 +140,8 @@ class ServiceChainPlugin(servicechain_db.ServiceChainDbPlugin):
self).update_servicechain_spec( self).update_servicechain_spec(
context, servicechain_spec_id, context, servicechain_spec_id,
servicechain_spec) servicechain_spec)
self._validate_shared_update(context, original_sc_spec,
updated_sc_spec, 'servicechain_spec')
sc_context = servicechain_context.ServiceChainSpecContext( sc_context = servicechain_context.ServiceChainSpecContext(
self, context, updated_sc_spec, self, context, updated_sc_spec,
original_sc_spec=original_sc_spec) original_sc_spec=original_sc_spec)

View File

@@ -0,0 +1,74 @@
# 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.
from neutron.api.v2 import attributes as nattr
from neutron import manager as n_manager
from neutron.plugins.common import constants as pconst
from oslo_log import log as logging
from gbpservice.neutron.services.grouppolicy.common import exceptions as gp_exc
from gbpservice.neutron.services.grouppolicy import plugin as gbp_plugin
LOG = logging.getLogger(__name__)
class SharingMixin(object):
"""Implementation of the Service Chain Plugin sharing rules.
"""
usage_graph = {'servicechain_spec': {'nodes':
'servicechain_node'},
'servicechain_node': {},
'servicechain_instance': {}}
_plurals = None
@property
def plurals(self):
if not self._plurals:
self._plurals = dict((nattr.PLURALS[k], k) for k in nattr.PLURALS)
return self._plurals
@property
def gbp_plugin(self):
# REVISIT(rkukura): Need initialization method after all
# plugins are loaded to grab and store plugin.
plugins = n_manager.NeutronManager.get_service_plugins()
gbp_plugin = plugins.get(pconst.GROUP_POLICY)
if not gbp_plugin:
LOG.error(_("No group policy service plugin found."))
raise gp_exc.GroupPolicyDeploymentError()
return gbp_plugin
def _validate_shared_create(self, context, obj, identity):
return gbp_plugin.GroupPolicyPlugin._validate_shared_create(
self, context, obj, identity)
def _validate_shared_update(self, context, original, updated, identity):
self._validate_shared_create(context, updated, identity)
if updated.get('shared') != original.get('shared'):
context = context.elevated()
getattr(self, '_validate_%s_unshare' % identity)(context, updated)
def _validate_servicechain_node_unshare(self, context, obj):
# Verify not pointed by shared SCS
gbp_plugin.GroupPolicyPlugin._check_shared_or_different_tenant(
context, obj, self.get_servicechain_specs, 'id',
obj['servicechain_specs'])
def _validate_servicechain_spec_unshare(self, context, obj):
# Verify not pointed by shared policy actions
gbp_plugin.GroupPolicyPlugin._check_shared_or_different_tenant(
context, obj, self.gbp_plugin.get_policy_actions, 'action_value',
[obj['id']])

View File

@@ -5,48 +5,65 @@
"admin_only": "rule:context_is_admin", "admin_only": "rule:context_is_admin",
"regular_user": "", "regular_user": "",
"default": "rule:admin_or_owner", "default": "rule:admin_or_owner",
"gbp_shared": "field:policy_target_groups:shared=True", "shared_ptg": "field:policy_target_groups:shared=True",
"shared_pt": "field:policy_targets:shared=True",
"shared_prs": "field:policy_rule_sets:shared=True",
"shared_l3p": "field:l3_policies:shared=True",
"shared_l2p": "field:l2_policies:shared=True",
"shared_es": "field:external_segments:shared=True",
"shared_ep": "field:external_policies:shared=True",
"shared_pc": "field:policy_classifiers:shared=True",
"shared_pa": "field:policy_actions:shared=True",
"shared_pr": "field:policy_rules:shared=True",
"shared_np": "field:nat_pools:shared=True",
"shared_nsp": "field:network_service_policies:shared=True",
"shared_scn": "field:servicechain_nodes:shared=True",
"shared_scs": "field:servicechain_specs:shared=True",
"create_policy_target_group": "", "create_policy_target_group": "",
"get_policy_target_group": "rule:admin_or_owner or rule:gbp_shared", "get_policy_target_group": "rule:admin_or_owner or rule:shared_ptg",
"gbp_l2p_shared": "field:l2_policies:shared=True",
"create_l2_policy": "", "create_l2_policy": "",
"get_l2_policy": "rule:admin_or_owner or rule:gbp_l2p_shared", "get_l2_policy": "rule:admin_or_owner or rule:shared_l2p",
"gbp_l3p_shared": "field:l3_policies:shared=True",
"create_l3_policy": "", "create_l3_policy": "",
"get_l3_policy": "rule:admin_or_owner or rule:gbp_l3p_shared", "get_l3_policy": "rule:admin_or_owner or rule:shared_l3p",
"gbp_policy_classifier_shared": "field:policy_classifiers:shared=True",
"create_policy_classifier": "", "create_policy_classifier": "",
"get_policy_classifier": "rule:admin_or_owner or rule:gbp_policy_classifier_shared", "get_policy_classifier": "rule:admin_or_owner or rule:shared_pc",
"gbp_policy_action_shared": "field:policy_actions:shared=True",
"create_policy_action": "", "create_policy_action": "",
"get_policy_action": "rule:admin_or_owner or rule:gbp_policy_action_shared", "get_policy_action": "rule:admin_or_owner or rule:shared_pa",
"gbp_policy_rule_shared": "field:policy_rules:shared=True",
"create_policy_rule": "", "create_policy_rule": "",
"get_policy_rule": "rule:admin_or_owner or rule:gbp_policy_rule_shared", "get_policy_rule": "rule:admin_or_owner or rule:shared_pr",
"gbp_policy_rule_set_shared": "field:policy_rule_sets:shared=True",
"create_policy_rule_set": "", "create_policy_rule_set": "",
"get_policy_rule_set": "rule:admin_or_owner or rule:gbp_policy_rule_set_shared", "get_policy_rule_set": "rule:admin_or_owner or rule:shared_prs",
"gbp_nsp_shared": "field:network_service_policies:shared=True",
"create_network_service_policy": "", "create_network_service_policy": "",
"get_network_service_policy": "rule:admin_or_owner or rule:gbp_nsp_shared", "get_network_service_policy": "rule:admin_or_owner or rule:shared_nsp",
"gbp_external_segment_shared": "field:external_segments:shared=True",
"create_external_segment": "", "create_external_segment": "",
"get_external_segment": "rule:admin_or_owner or rule:gbp_external_segment_shared", "get_external_segment": "rule:admin_or_owner or rule:shared_es",
"gbp_external_policy_shared": "field:external_policies:shared=True",
"create_external_policy": "", "create_external_policy": "",
"get_external_policy": "rule:admin_or_owner or rule:gbp_external_policy_shared", "get_external_policy": "rule:admin_or_owner or rule:shared_ep",
"gbp_nat_pool_shared": "field:nat_pools:shared=True",
"create_nat_pool": "", "create_nat_pool": "",
"get_nat_pool": "rule:admin_or_owner or rule:gbp_nat_pool_shared" "get_nat_pool": "rule:admin_or_owner or rule:shared_np",
"create_servicechain_node": "",
"create_servicechain_node:shared": "rule:admin_only",
"get_servicechain_node": "rule:admin_or_owner or rule:shared_scn",
"update_servicechain_node:shared": "rule:admin_only",
"create_servicechain_spec": "",
"create_servicechain_spec:shared": "rule:admin_only",
"get_servicechain_spec": "rule:admin_or_owner or rule:shared_scs",
"update_servicechain_spec:shared": "rule:admin_only",
"create_servicechain_instance": "",
"get_servicechain_instance": "rule:admin_or_owner",
"update_servicechain_instance:shared": "rule:admin_only"
} }

View File

@@ -58,23 +58,24 @@ class ServiceChainDBTestBase(object):
def _get_test_servicechain_node_attrs(self, name='scn1', def _get_test_servicechain_node_attrs(self, name='scn1',
description='test scn', description='test scn',
service_type=constants.FIREWALL, service_type=constants.FIREWALL,
config="{}"): config="{}", shared=False):
attrs = {'name': name, 'description': description, attrs = {'name': name, 'description': description,
'service_type': service_type, 'service_type': service_type,
'config': config, 'config': config,
'tenant_id': self._tenant_id} 'tenant_id': self._tenant_id,
'shared': shared}
return attrs return attrs
def _get_test_servicechain_spec_attrs(self, name='scs1', def _get_test_servicechain_spec_attrs(self, name='scs1',
description='test scs', description='test scs',
nodes=None): nodes=None, shared=False):
node_ids = [] node_ids = []
if nodes: if nodes:
node_ids = [node_id for node_id in nodes] node_ids = [node_id for node_id in nodes]
attrs = {'name': name, 'description': description, attrs = {'name': name, 'description': description,
'tenant_id': self._tenant_id, 'tenant_id': self._tenant_id,
'nodes': node_ids} 'nodes': node_ids, 'shared': shared}
return attrs return attrs
@@ -98,7 +99,7 @@ class ServiceChainDBTestBase(object):
def create_servicechain_node(self, service_type=constants.FIREWALL, def create_servicechain_node(self, service_type=constants.FIREWALL,
config="{}", expected_res_status=None, config="{}", expected_res_status=None,
**kwargs): **kwargs):
defaults = {'name': 'scn1', 'description': 'test scn'} defaults = {'name': 'scn1', 'description': 'test scn', 'shared': False}
defaults.update(kwargs) defaults.update(kwargs)
data = {'servicechain_node': {'service_type': service_type, data = {'servicechain_node': {'service_type': service_type,
@@ -120,7 +121,7 @@ class ServiceChainDBTestBase(object):
def create_servicechain_spec(self, nodes=None, expected_res_status=None, def create_servicechain_spec(self, nodes=None, expected_res_status=None,
**kwargs): **kwargs):
defaults = {'name': 'scs1', 'description': 'test scs'} defaults = {'name': 'scs1', 'description': 'test scs', 'shared': False}
defaults.update(kwargs) defaults.update(kwargs)
data = {'servicechain_spec': {'tenant_id': self._tenant_id, data = {'servicechain_spec': {'tenant_id': self._tenant_id,
@@ -131,7 +132,7 @@ class ServiceChainDBTestBase(object):
scs_res = scs_req.get_response(self.ext_api) scs_res = scs_req.get_response(self.ext_api)
if expected_res_status: if expected_res_status:
self.assertEqual(scs_res.status_int, expected_res_status) self.assertEqual(expected_res_status, scs_res.status_int)
elif scs_res.status_int >= webob.exc.HTTPClientError.code: elif scs_res.status_int >= webob.exc.HTTPClientError.code:
raise webob.exc.HTTPClientError(code=scs_res.status_int) raise webob.exc.HTTPClientError(code=scs_res.status_int)
@@ -150,7 +151,7 @@ class ServiceChainDBTestBase(object):
spec1, spec1,
self.fmt) self.fmt)
spec_res = spec_req.get_response(self.ext_api) spec_res = spec_req.get_response(self.ext_api)
self.assertEqual(spec_res.status_int, webob.exc.HTTPCreated.code) self.assertEqual(webob.exc.HTTPCreated.code, spec_res.status_int)
res = self.deserialize(self.fmt, spec_res) res = self.deserialize(self.fmt, spec_res)
self.assertIn('servicechain_spec', res) self.assertIn('servicechain_spec', res)
self.assertEqual([scn_id], res['servicechain_spec']['nodes']) self.assertEqual([scn_id], res['servicechain_spec']['nodes'])
@@ -161,13 +162,14 @@ class ServiceChainDBTestBase(object):
spec2, spec2,
self.fmt) self.fmt)
spec_res = spec_req.get_response(self.ext_api) spec_res = spec_req.get_response(self.ext_api)
self.assertEqual(spec_res.status_int, webob.exc.HTTPCreated.code) self.assertEqual(webob.exc.HTTPCreated.code, spec_res.status_int)
res = self.deserialize(self.fmt, spec_res) res = self.deserialize(self.fmt, spec_res)
self.assertIn('servicechain_spec', res) self.assertIn('servicechain_spec', res)
self.assertEqual([scn_id], res['servicechain_spec']['nodes']) self.assertEqual([scn_id], res['servicechain_spec']['nodes'])
def create_servicechain_instance(self, servicechain_specs=[], def create_servicechain_instance(self, servicechain_specs=[],
config_param_values="{}", config_param_values=
'{"key": "value"}',
provider_ptg_id=None, provider_ptg_id=None,
consumer_ptg_id=None, consumer_ptg_id=None,
classifier_id=None, classifier_id=None,
@@ -188,7 +190,7 @@ class ServiceChainDBTestBase(object):
sci_res = sci_req.get_response(self.ext_api) sci_res = sci_req.get_response(self.ext_api)
if expected_res_status: if expected_res_status:
self.assertEqual(sci_res.status_int, expected_res_status) self.assertEqual(expected_res_status, sci_res.status_int)
elif sci_res.status_int >= webob.exc.HTTPClientError.code: elif sci_res.status_int >= webob.exc.HTTPClientError.code:
raise webob.exc.HTTPClientError(code=sci_res.status_int) raise webob.exc.HTTPClientError(code=sci_res.status_int)
@@ -240,17 +242,17 @@ class TestServiceChainResources(ServiceChainDbTestCase):
req.get_response(self.ext_api)) req.get_response(self.ext_api))
for k, v in attrs.iteritems(): for k, v in attrs.iteritems():
self.assertEqual(res[resource][k], v) self.assertEqual(v, res[resource][k])
def test_create_and_show_servicechain_node(self): def test_create_and_show_servicechain_node(self):
attrs = self._get_test_servicechain_node_attrs( attrs = self._get_test_servicechain_node_attrs(
service_type=constants.LOADBALANCER, config="config1") service_type=constants.LOADBALANCER)
scn = self.create_servicechain_node( scn = self.create_servicechain_node(
service_type=constants.LOADBALANCER, config="config1") service_type=constants.LOADBALANCER)
for k, v in attrs.iteritems(): for k, v in attrs.iteritems():
self.assertEqual(scn['servicechain_node'][k], v) self.assertEqual(v, scn['servicechain_node'][k])
self._test_show_resource('servicechain_node', self._test_show_resource('servicechain_node',
scn['servicechain_node']['id'], scn['servicechain_node']['id'],
@@ -278,7 +280,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
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['servicechain_node'][k], v) self.assertEqual(v, res['servicechain_node'][k])
self._test_show_resource('servicechain_node', self._test_show_resource('servicechain_node',
scn['servicechain_node']['id'], scn['servicechain_node']['id'],
@@ -304,7 +306,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
# After deleting the Service Chain Spec, node delete should succeed # After deleting the Service Chain Spec, node delete should succeed
req = self.new_delete_request('servicechain_nodes', scn_id) req = self.new_delete_request('servicechain_nodes', scn_id)
res = req.get_response(self.ext_api) res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code) self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
self.assertRaises(service_chain.ServiceChainNodeNotFound, self.assertRaises(service_chain.ServiceChainNodeNotFound,
self.plugin.get_servicechain_node, self.plugin.get_servicechain_node,
ctx, scn_id) ctx, scn_id)
@@ -319,7 +321,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
scs = self.create_servicechain_spec(name=name, nodes=[scn_id]) scs = self.create_servicechain_spec(name=name, nodes=[scn_id])
for k, v in attrs.iteritems(): for k, v in attrs.iteritems():
self.assertEqual(scs['servicechain_spec'][k], v) self.assertEqual(v, scs['servicechain_spec'][k])
self._test_show_resource('servicechain_spec', self._test_show_resource('servicechain_spec',
scs['servicechain_spec']['id'], scs['servicechain_spec']['id'],
@@ -336,7 +338,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
scs = self.create_servicechain_spec( scs = self.create_servicechain_spec(
name=name, nodes=[scn1_id, scn2_id]) name=name, nodes=[scn1_id, scn2_id])
for k, v in attrs.iteritems(): for k, v in attrs.iteritems():
self.assertEqual(scs['servicechain_spec'][k], v) self.assertEqual(v, scs['servicechain_spec'][k])
def test_list_servicechain_specs(self): def test_list_servicechain_specs(self):
scs = [self.create_servicechain_spec(name='scs1', description='scs'), scs = [self.create_servicechain_spec(name='scs1', description='scs'),
@@ -351,27 +353,25 @@ class TestServiceChainResources(ServiceChainDbTestCase):
nodes_list = [scn1_id, scn2_id] nodes_list = [scn1_id, scn2_id]
scs = self.create_servicechain_spec(name='scs1', scs = self.create_servicechain_spec(name='scs1',
nodes=nodes_list) nodes=nodes_list)
self.assertEqual(scs['servicechain_spec']['nodes'], nodes_list) self.assertEqual(nodes_list, scs['servicechain_spec']['nodes'])
res = self._list('servicechain_specs') res = self._list('servicechain_specs')
self.assertEqual(len(res['servicechain_specs']), 1) self.assertEqual(1, len(res['servicechain_specs']))
self.assertEqual(res['servicechain_specs'][0]['nodes'], self.assertEqual(nodes_list, res['servicechain_specs'][0]['nodes'])
nodes_list)
# Delete the service chain spec and create another with nodes in # Delete the service chain spec and create another with nodes in
# reverse order and verify that that proper ordering is maintained # reverse order and verify that that proper ordering is maintained
req = self.new_delete_request('servicechain_specs', req = self.new_delete_request('servicechain_specs',
scs['servicechain_spec']['id']) scs['servicechain_spec']['id'])
res = req.get_response(self.ext_api) res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code) self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
nodes_list.reverse() nodes_list.reverse()
scs = self.create_servicechain_spec(name='scs1', scs = self.create_servicechain_spec(name='scs1',
nodes=nodes_list) nodes=nodes_list)
self.assertEqual(scs['servicechain_spec']['nodes'], nodes_list) self.assertEqual(scs['servicechain_spec']['nodes'], nodes_list)
res = self._list('servicechain_specs') res = self._list('servicechain_specs')
self.assertEqual(len(res['servicechain_specs']), 1) self.assertEqual(1, len(res['servicechain_specs']))
self.assertEqual(res['servicechain_specs'][0]['nodes'], self.assertEqual(nodes_list, res['servicechain_specs'][0]['nodes'])
nodes_list)
def test_update_servicechain_spec(self): def test_update_servicechain_spec(self):
name = "new_servicechain_spec1" name = "new_servicechain_spec1"
@@ -388,7 +388,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
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['servicechain_spec'][k], v) self.assertEqual(v, res['servicechain_spec'][k])
self._test_show_resource('servicechain_spec', self._test_show_resource('servicechain_spec',
scs['servicechain_spec']['id'], attrs) scs['servicechain_spec']['id'], attrs)
@@ -401,7 +401,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
req = self.new_delete_request('servicechain_specs', scs_id) req = self.new_delete_request('servicechain_specs', scs_id)
res = req.get_response(self.ext_api) res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code) self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
self.assertRaises(service_chain.ServiceChainSpecNotFound, self.assertRaises(service_chain.ServiceChainSpecNotFound,
self.plugin.get_servicechain_spec, ctx, scs_id) self.plugin.get_servicechain_spec, ctx, scs_id)
@@ -464,7 +464,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
classifier_id=classifier_id, classifier_id=classifier_id,
config_param_values=config_param_values) config_param_values=config_param_values)
for k, v in attrs.iteritems(): for k, v in attrs.iteritems():
self.assertEqual(sci['servicechain_instance'][k], v) self.assertEqual(v, sci['servicechain_instance'][k])
self._test_show_resource('servicechain_instance', self._test_show_resource('servicechain_instance',
sci['servicechain_instance']['id'], sci['servicechain_instance']['id'],
@@ -488,29 +488,30 @@ class TestServiceChainResources(ServiceChainDbTestCase):
specs_list = [scs1_id, scs2_id] specs_list = [scs1_id, scs2_id]
sci = self.create_servicechain_instance(name='sci1', sci = self.create_servicechain_instance(name='sci1',
servicechain_specs=specs_list) servicechain_specs=specs_list)
self.assertEqual(sci['servicechain_instance']['servicechain_specs'], self.assertEqual(specs_list,
specs_list) sci['servicechain_instance']['servicechain_specs'])
res = self._list('servicechain_instances') res = self._list('servicechain_instances')
self.assertEqual(len(res['servicechain_instances']), 1) self.assertEqual(1, len(res['servicechain_instances']))
result_instance = res['servicechain_instances'][0] result_instance = res['servicechain_instances'][0]
self.assertEqual(result_instance['servicechain_specs'], specs_list) self.assertEqual(specs_list, result_instance['servicechain_specs'])
# Delete the service chain instance and create another with specs in # Delete the service chain instance and create another with specs in
# reverse order and verify that that proper ordering is maintained # reverse order and verify that that proper ordering is maintained
req = self.new_delete_request('servicechain_instances', req = self.new_delete_request('servicechain_instances',
sci['servicechain_instance']['id']) sci['servicechain_instance']['id'])
res = req.get_response(self.ext_api) res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code) self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
specs_list.reverse() specs_list.reverse()
sci = self.create_servicechain_instance(name='sci1', sci = self.create_servicechain_instance(name='sci1',
servicechain_specs=specs_list) servicechain_specs=specs_list)
self.assertEqual(sci['servicechain_instance']['servicechain_specs'], self.assertEqual(specs_list,
specs_list) sci['servicechain_instance']['servicechain_specs'])
res = self._list('servicechain_instances') res = self._list('servicechain_instances')
self.assertEqual(len(res['servicechain_instances']), 1) self.assertEqual(1, len(res['servicechain_instances']))
result_instance = res['servicechain_instances'][0] result_instance = res['servicechain_instances'][0]
self.assertEqual(result_instance['servicechain_specs'], specs_list) self.assertEqual(specs_list,
result_instance['servicechain_specs'])
def test_update_servicechain_instance(self): def test_update_servicechain_instance(self):
name = "new_servicechain_instance" name = "new_servicechain_instance"
@@ -537,7 +538,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
sci['servicechain_instance']['id']) sci['servicechain_instance']['id'])
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['servicechain_instance'][k], v) self.assertEqual(v, res['servicechain_instance'][k])
self._test_show_resource('servicechain_instance', self._test_show_resource('servicechain_instance',
sci['servicechain_instance']['id'], attrs) sci['servicechain_instance']['id'], attrs)
@@ -553,7 +554,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
req = self.new_delete_request('servicechain_instances', sci_id) req = self.new_delete_request('servicechain_instances', sci_id)
res = req.get_response(self.ext_api) res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code) self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
self.assertRaises(service_chain.ServiceChainInstanceNotFound, self.assertRaises(service_chain.ServiceChainInstanceNotFound,
self.plugin.get_servicechain_instance, self.plugin.get_servicechain_instance,
ctx, sci_id) ctx, sci_id)

View File

@@ -29,6 +29,8 @@ cfg.CONF.import_opt('policy_drivers',
GP_PLUGIN_KLASS = ( GP_PLUGIN_KLASS = (
"gbpservice.neutron.services.grouppolicy.plugin.GroupPolicyPlugin" "gbpservice.neutron.services.grouppolicy.plugin.GroupPolicyPlugin"
) )
SERVICECHAIN_SPECS = 'servicechain/servicechain_specs'
SERVICECHAIN_NODES = 'servicechain/servicechain_nodes'
class FakeDriver(object): class FakeDriver(object):
@@ -47,6 +49,8 @@ class GroupPolicyPluginTestCase(tgpmdb.GroupPolicyMappingDbTestCase):
gp_plugin = GP_PLUGIN_KLASS gp_plugin = GP_PLUGIN_KLASS
super(GroupPolicyPluginTestCase, self).setUp(core_plugin=core_plugin, super(GroupPolicyPluginTestCase, self).setUp(core_plugin=core_plugin,
gp_plugin=gp_plugin) gp_plugin=gp_plugin)
cfg.CONF.set_override('servicechain_drivers', ['dummy'],
group='servicechain')
def test_reverse_on_delete(self): def test_reverse_on_delete(self):
manager = self.plugin.policy_driver_manager manager = self.plugin.policy_driver_manager
@@ -105,6 +109,38 @@ class GroupPolicyPluginTestCase(tgpmdb.GroupPolicyMappingDbTestCase):
external_segment_id=es['external_segment']['id'], external_segment_id=es['external_segment']['id'],
**kwargs)['nat_pool'] **kwargs)['nat_pool']
def _create_servicechain_spec(self, node_types=None, shared=False):
node_types = node_types or []
if not node_types:
node_types = ['LOADBALANCER']
node_ids = []
for node_type in node_types:
node_ids.append(self._create_servicechain_node(node_type,
shared=shared))
data = {'servicechain_spec': {'tenant_id': self._tenant_id if not
shared else 'another-tenant',
'nodes': node_ids,
'shared': shared}}
scs_req = self.new_create_request(
SERVICECHAIN_SPECS, data, self.fmt)
spec = self.deserialize(
self.fmt, scs_req.get_response(self.ext_api))
scs_id = spec['servicechain_spec']['id']
return scs_id
def _create_servicechain_node(self, node_type="LOADBALANCER",
shared=False):
config = "{}"
data = {'servicechain_node': {'service_type': node_type,
'tenant_id': self._tenant_id if not
shared else 'another-tenant',
'config': config,
'shared': shared}}
scn_req = self.new_create_request(SERVICECHAIN_NODES, data, self.fmt)
node = self.deserialize(self.fmt, scn_req.get_response(self.ext_api))
scn_id = node['servicechain_node']['id']
return scn_id
class TestL3Policy(GroupPolicyPluginTestCase): class TestL3Policy(GroupPolicyPluginTestCase):
@@ -806,6 +842,57 @@ class TestPolicyTarget(GroupPolicyPluginTestCase):
self._test_cross_tenant_fails(True) self._test_cross_tenant_fails(True)
class TestPolicyAction(GroupPolicyPluginTestCase):
def test_redirect_value_fails(self):
scs_id = self._create_servicechain_spec(
node_types=['FIREWALL_TRANSPARENT'])
res = self.create_policy_action(action_type='redirect',
action_value=scs_id, shared=True,
expected_res_status=400)
self.assertEqual(
'SharedResourceReferenceError', res['NeutronError']['type'])
res = self.create_policy_action(
action_type='redirect', action_value=scs_id, tenant_id='different',
expected_res_status=404)
self.assertEqual(
'ServiceChainSpecNotFound', res['NeutronError']['type'])
res = self.create_policy_action(
action_type='redirect', action_value=scs_id, tenant_id='different',
expected_res_status=400, is_admin_context=True)
self.assertEqual(
'InvalidCrossTenantReference', res['NeutronError']['type'])
res = self.create_policy_action(
action_type='redirect', action_value=scs_id,
expected_res_status=201)['policy_action']
res = self.update_policy_action(
res['id'], shared=True, expected_res_status=400)
self.assertEqual(
'SharedResourceReferenceError', res['NeutronError']['type'])
scs_id = self._create_servicechain_spec(
node_types=['FIREWALL_TRANSPARENT'], shared=True)
self.create_policy_action(
action_type='redirect', action_value=scs_id, shared=True,
expected_res_status=201)['policy_action']
data = {'servicechain_spec': {'shared': False}}
scs_req = self.new_update_request(
SERVICECHAIN_SPECS, data, scs_id, self.fmt)
res = self.deserialize(
self.fmt, scs_req.get_response(self.ext_api))
self.assertEqual(
'InvalidSharedAttributeUpdate', res['NeutronError']['type'])
def test_redirect_shared_create(self):
scs_id = self._create_servicechain_spec(
node_types=['FIREWALL_TRANSPARENT'], shared=True)
self.create_policy_action(action_type='redirect', action_value=scs_id,
shared=True, expected_res_status=201)
class TestGroupPolicyPluginGroupResources( class TestGroupPolicyPluginGroupResources(
GroupPolicyPluginTestCase, tgpdb.TestGroupResources): GroupPolicyPluginTestCase, tgpdb.TestGroupResources):

View File

@@ -66,7 +66,8 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
return { return {
'name': '', 'name': '',
'description': '', 'description': '',
'config': '' 'config': '',
'shared': False
} }
def _get_create_servicechain_node_attrs(self): def _get_create_servicechain_node_attrs(self):
@@ -75,7 +76,8 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
'service_type': 'FIREWALL', 'service_type': 'FIREWALL',
'tenant_id': _uuid(), 'tenant_id': _uuid(),
'description': 'test servicechain node', 'description': 'test servicechain node',
'config': 'test_config' 'config': 'test_config',
'shared': True
} }
def _get_update_servicechain_node_attrs(self): def _get_update_servicechain_node_attrs(self):
@@ -185,7 +187,8 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
return { return {
'name': '', 'name': '',
'description': '', 'description': '',
'nodes': [] 'nodes': [],
'shared': False,
} }
def _get_create_servicechain_spec_attrs(self): def _get_create_servicechain_spec_attrs(self):
@@ -193,7 +196,8 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
'name': 'servicechainspec1', 'name': 'servicechainspec1',
'nodes': [_uuid(), _uuid()], 'nodes': [_uuid(), _uuid()],
'tenant_id': _uuid(), 'tenant_id': _uuid(),
'description': 'test servicechain spec' 'description': 'test servicechain spec',
'shared': True
} }
def _get_update_servicechain_spec_attrs(self): def _get_update_servicechain_spec_attrs(self):