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",
"regular_user": "",
"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: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",
"create_l2_policy": "",
"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",
"create_l3_policy": "",
"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",
"create_policy_classifier": "",
"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",
"create_policy_action": "",
"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",
"create_policy_rule": "",
"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",
"create_policy_rule_set": "",
"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",
"create_network_service_policy": "",
"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",
"create_external_segment": "",
"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",
"create_external_policy": "",
"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",
"create_nat_pool": "",
"create_nat_pool:shared": "rule:admin_only",
"get_nat_pool": "rule:admin_or_owner or rule:gbp_shared",
"update_nat_pool:shared": "rule:admin_only"
"get_nat_pool": "rule:admin_or_owner or rule:shared_np",
"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_value': pa['action_value'],
'shared': pa.get('shared', False), }
res['policy_rules'] = [pr['policy_rule_id'] for
pr in pa['policy_rules']]
return self._fields(res, fields)
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,
backref="nodes",
cascade='all, delete, delete-orphan')
shared = sa.Column(sa.Boolean)
class ServiceChainInstance(model_base.BASEV2, models_v2.HasId,
@ -111,6 +112,7 @@ class ServiceChainSpec(model_base.BASEV2, models_v2.HasId,
instances = orm.relationship(InstanceSpecAssociation,
backref="specs",
cascade='all, delete, delete-orphan')
shared = sa.Column(sa.Boolean)
class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
@ -161,7 +163,10 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
'name': sc_node['name'],
'description': sc_node['description'],
'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)
def _make_sc_spec_dict(self, spec, fields=None):
@ -169,7 +174,8 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
'tenant_id': spec['tenant_id'],
'name': spec['name'],
'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']]
return self._fields(res, fields)
@ -201,7 +207,8 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
name=node['name'],
description=node['description'],
service_type=node['service_type'],
config=node['config'])
config=node['config'],
shared=node['shared'])
context.session.add(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(),
tenant_id=tenant_id,
name=spec['name'],
description=spec['description'])
description=spec['description'],
shared=spec['shared'])
self._process_nodes_for_spec(context, spec_db, spec)
context.session.add(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,
'validate': {'type:string': None},
'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: {
'id': {'allow_post': False, 'allow_put': False,
@ -137,6 +141,10 @@ RESOURCE_ATTRIBUTE_MAP = {
'config_param_names': {'allow_post': False, 'allow_put': False,
'validate': {'type:string_list': None},
'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: {
'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):
self._plugin._validate_shared_create(
self._plugin_context,
self._policy_target_group,
'policy_target_group')
self._plugin, self._plugin_context, self._policy_target_group,
'policy_target_group')
self._plugin._set_l2_policy_for_policy_target_group(
self._plugin_context, self._policy_target_group['id'],
l2_policy_id)
@ -115,9 +114,7 @@ class L2PolicyContext(GroupPolicyContext, api.L2PolicyContext):
def set_l3_policy_id(self, l3_policy_id):
self._plugin._validate_shared_create(
self._plugin_context,
self._l2_policy,
'l2_policy')
self._plugin, self._plugin_context, self._l2_policy, 'l2_policy')
self._plugin._set_l3_policy_for_l2_policy(
self._plugin_context, self._l2_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.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_utils import excutils
@ -26,6 +28,7 @@ from gbpservice.neutron.services.grouppolicy import (
group_policy_context as p_context)
from gbpservice.neutron.services.grouppolicy import (
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
@ -50,6 +53,17 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
self._aliases = 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:
# - A shared resource cannot use/link a non-shared resource
# - 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)
return self._plurals
@staticmethod
def _validate_shared_create(self, context, obj, identity):
# REVISIT(ivar): only validate new references
links = self.usage_graph.get(identity, {})
@ -111,21 +126,15 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
link_ids = set()
for linked in linked_objects:
link_ids.add(linked['id'])
if not linked.get('shared'):
if obj.get('shared'):
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'])
GroupPolicyPlugin._verify_sharing_consistency(
obj, linked, identity, ref_type)
# Check for missing references
missing = set(ids) - link_ids
if missing:
raise gpex.GbpResourceNotFound(identity=ref_type,
id=str(missing))
@staticmethod
def _validate_shared_update(self, context, original, updated, identity):
# 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
# validation every time a shared resource is updated
# 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'):
context = context.elevated()
getattr(self, '_validate_%s_unshare' % identity)(context, updated)
def _check_shared_or_different_tenant(self, context, obj,
method, attr, value=None):
@staticmethod
def _check_shared_or_different_tenant(context, obj, method, attr,
value=None):
tenant_id = obj['tenant_id']
refs = method(context, filters={attr: value or [obj['id']]})
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'],
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):
self.extension_manager = ext_manager.ExtensionManager()
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.extension_manager.process_create_policy_target(
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,
result)
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)
self.extension_manager.process_update_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,
'policy_target')
policy_context = p_context.PolicyTargetContext(
@ -373,7 +406,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, policy_target_group)
self.extension_manager.process_create_policy_target_group(
session, policy_target_group, result)
self._validate_shared_create(context, result,
self._validate_shared_create(self, context, result,
'policy_target_group')
policy_context = p_context.PolicyTargetGroupContext(
self, context, result)
@ -404,9 +437,9 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, policy_target_group_id, policy_target_group)
self.extension_manager.process_update_policy_target_group(
session, policy_target_group, updated_policy_target_group)
self._validate_shared_update(context, original_policy_target_group,
updated_policy_target_group,
'policy_target_group')
self._validate_shared_update(
self, context, original_policy_target_group,
updated_policy_target_group, 'policy_target_group')
policy_context = p_context.PolicyTargetGroupContext(
self, context, updated_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.extension_manager.process_create_l2_policy(
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)
self.policy_driver_manager.create_l2_policy_precommit(
policy_context)
@ -508,7 +541,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, l2_policy_id, l2_policy)
self.extension_manager.process_update_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')
policy_context = p_context.L2PolicyContext(
self, context, updated_l2_policy,
@ -569,7 +602,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, network_service_policy)
self.extension_manager.process_create_network_service_policy(
session, network_service_policy, result)
self._validate_shared_create(context, result,
self._validate_shared_create(self, context, result,
'network_service_policy')
policy_context = p_context.NetworkServicePolicyContext(
self, context, result)
@ -604,7 +637,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
session, network_service_policy,
updated_network_service_policy)
self._validate_shared_update(
context, original_network_service_policy,
self, context, original_network_service_policy,
updated_network_service_policy, 'network_service_policy')
policy_context = p_context.NetworkServicePolicyContext(
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.extension_manager.process_create_l3_policy(
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)
policy_context = p_context.L3PolicyContext(self, context,
result)
@ -698,7 +731,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, l3_policy_id, l3_policy)
self.extension_manager.process_update_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')
self._validate_l3p_es(context, updated_l3_policy,
original_l3_policy)
@ -766,7 +799,8 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, policy_classifier)
self.extension_manager.process_create_policy_classifier(
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,
result)
self.policy_driver_manager.create_policy_classifier_precommit(
@ -795,9 +829,9 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, id, policy_classifier)
self.extension_manager.process_update_policy_classifier(
session, policy_classifier, updated_policy_classifier)
self._validate_shared_update(context, original_policy_classifier,
updated_policy_classifier,
'policy_classifier')
self._validate_shared_update(
self, context, original_policy_classifier,
updated_policy_classifier, 'policy_classifier')
policy_context = p_context.PolicyClassifierContext(
self, context, updated_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.extension_manager.process_create_policy_action(
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,
result)
self.policy_driver_manager.create_policy_action_precommit(
@ -887,9 +923,10 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
policy_action)
self.extension_manager.process_update_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,
'policy_action')
self._validate_action_value(context, updated_policy_action)
policy_context = p_context.PolicyActionContext(
self, context, updated_policy_action,
original_policy_action=original_policy_action)
@ -948,7 +985,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, policy_rule)
self.extension_manager.process_create_policy_rule(
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,
result)
self.policy_driver_manager.create_policy_rule_precommit(
@ -977,7 +1014,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, id, policy_rule)
self.extension_manager.process_update_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')
policy_context = p_context.PolicyRuleContext(
self, context, updated_policy_rule,
@ -1038,7 +1075,8 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, policy_rule_set)
self.extension_manager.process_create_policy_rule_set(
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(
self, context, result)
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)
self.extension_manager.process_update_policy_rule_set(
session, policy_rule_set, updated_policy_rule_set)
self._validate_shared_update(context, original_policy_rule_set,
updated_policy_rule_set,
'policy_rule_set')
self._validate_shared_update(
self, context, original_policy_rule_set,
updated_policy_rule_set, 'policy_rule_set')
policy_context = p_context.PolicyRuleSetContext(
self, context, updated_policy_rule_set,
original_policy_rule_set=original_policy_rule_set)
@ -1128,7 +1166,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
external_segment)
self.extension_manager.process_create_external_segment(
session, external_segment, result)
self._validate_shared_create(context, result,
self._validate_shared_create(self, context, result,
'external_segment')
self._validate_routes(context, result)
policy_context = p_context.ExternalSegmentContext(
@ -1163,7 +1201,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
self.extension_manager.process_update_external_segment(
session, external_segment, updated_external_segment)
self._validate_shared_update(
context, original_external_segment,
self, context, original_external_segment,
updated_external_segment, 'external_segment')
self._validate_routes(context, updated_external_segment,
original_external_segment)
@ -1231,7 +1269,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, external_policy)
self.extension_manager.process_create_external_policy(
session, external_policy, result)
self._validate_shared_create(context, result,
self._validate_shared_create(self, context, result,
'external_policy')
policy_context = p_context.ExternalPolicyContext(
self, context, result)
@ -1265,7 +1303,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
self.extension_manager.process_update_external_policy(
session, external_policy, updated_external_policy)
self._validate_shared_update(
context, original_external_policy,
self, context, original_external_policy,
updated_external_policy, 'external_policy')
policy_context = p_context.ExternalPolicyContext(
self, context, updated_external_policy,
@ -1327,7 +1365,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
context, nat_pool)
self.extension_manager.process_create_nat_pool(session, nat_pool,
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)
(self.policy_driver_manager.
create_nat_pool_precommit(policy_context))
@ -1354,7 +1392,7 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
nat_pool)
self.extension_manager.process_update_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')
policy_context = p_context.NatPoolContext(
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)
from gbpservice.neutron.services.servicechain.plugins.msc import (
driver_manager as manager)
from gbpservice.neutron.services.servicechain.plugins import sharing
LOG = logging.getLogger(__name__)
class ServiceChainPlugin(servicechain_db.ServiceChainDbPlugin):
class ServiceChainPlugin(servicechain_db.ServiceChainDbPlugin,
sharing.SharingMixin):
"""Implementation of the Service Chain Plugin.
@ -42,6 +44,7 @@ class ServiceChainPlugin(servicechain_db.ServiceChainDbPlugin):
with session.begin(subtransactions=True):
result = super(ServiceChainPlugin, self).create_servicechain_node(
context, servicechain_node)
self._validate_shared_create(context, result, 'servicechain_node')
sc_context = servicechain_context.ServiceChainNodeContext(
self, context, result)
self.driver_manager.create_servicechain_node_precommit(
@ -70,6 +73,8 @@ class ServiceChainPlugin(servicechain_db.ServiceChainDbPlugin):
self).update_servicechain_node(
context, servicechain_node_id,
servicechain_node)
self._validate_shared_update(context, original_sc_node,
updated_sc_node, 'servicechain_node')
sc_context = servicechain_context.ServiceChainNodeContext(
self, context, updated_sc_node,
original_sc_node=original_sc_node)
@ -107,6 +112,7 @@ class ServiceChainPlugin(servicechain_db.ServiceChainDbPlugin):
with session.begin(subtransactions=True):
result = super(ServiceChainPlugin, self).create_servicechain_spec(
context, servicechain_spec)
self._validate_shared_create(context, result, 'servicechain_spec')
sc_context = servicechain_context.ServiceChainSpecContext(
self, context, result)
self.driver_manager.create_servicechain_spec_precommit(
@ -134,6 +140,8 @@ class ServiceChainPlugin(servicechain_db.ServiceChainDbPlugin):
self).update_servicechain_spec(
context, servicechain_spec_id,
servicechain_spec)
self._validate_shared_update(context, original_sc_spec,
updated_sc_spec, 'servicechain_spec')
sc_context = servicechain_context.ServiceChainSpecContext(
self, context, updated_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",
"regular_user": "",
"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": "",
"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": "",
"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": "",
"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": "",
"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": "",
"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": "",
"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": "",
"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": "",
"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": "",
"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": "",
"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": "",
"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',
description='test scn',
service_type=constants.FIREWALL,
config="{}"):
config="{}", shared=False):
attrs = {'name': name, 'description': description,
'service_type': service_type,
'config': config,
'tenant_id': self._tenant_id}
'tenant_id': self._tenant_id,
'shared': shared}
return attrs
def _get_test_servicechain_spec_attrs(self, name='scs1',
description='test scs',
nodes=None):
nodes=None, shared=False):
node_ids = []
if nodes:
node_ids = [node_id for node_id in nodes]
attrs = {'name': name, 'description': description,
'tenant_id': self._tenant_id,
'nodes': node_ids}
'nodes': node_ids, 'shared': shared}
return attrs
@ -98,7 +99,7 @@ class ServiceChainDBTestBase(object):
def create_servicechain_node(self, service_type=constants.FIREWALL,
config="{}", expected_res_status=None,
**kwargs):
defaults = {'name': 'scn1', 'description': 'test scn'}
defaults = {'name': 'scn1', 'description': 'test scn', 'shared': False}
defaults.update(kwargs)
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,
**kwargs):
defaults = {'name': 'scs1', 'description': 'test scs'}
defaults = {'name': 'scs1', 'description': 'test scs', 'shared': False}
defaults.update(kwargs)
data = {'servicechain_spec': {'tenant_id': self._tenant_id,
@ -131,7 +132,7 @@ class ServiceChainDBTestBase(object):
scs_res = scs_req.get_response(self.ext_api)
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:
raise webob.exc.HTTPClientError(code=scs_res.status_int)
@ -150,7 +151,7 @@ class ServiceChainDBTestBase(object):
spec1,
self.fmt)
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)
self.assertIn('servicechain_spec', res)
self.assertEqual([scn_id], res['servicechain_spec']['nodes'])
@ -161,13 +162,14 @@ class ServiceChainDBTestBase(object):
spec2,
self.fmt)
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)
self.assertIn('servicechain_spec', res)
self.assertEqual([scn_id], res['servicechain_spec']['nodes'])
def create_servicechain_instance(self, servicechain_specs=[],
config_param_values="{}",
config_param_values=
'{"key": "value"}',
provider_ptg_id=None,
consumer_ptg_id=None,
classifier_id=None,
@ -188,7 +190,7 @@ class ServiceChainDBTestBase(object):
sci_res = sci_req.get_response(self.ext_api)
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:
raise webob.exc.HTTPClientError(code=sci_res.status_int)
@ -240,17 +242,17 @@ class TestServiceChainResources(ServiceChainDbTestCase):
req.get_response(self.ext_api))
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):
attrs = self._get_test_servicechain_node_attrs(
service_type=constants.LOADBALANCER, config="config1")
service_type=constants.LOADBALANCER)
scn = self.create_servicechain_node(
service_type=constants.LOADBALANCER, config="config1")
service_type=constants.LOADBALANCER)
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',
scn['servicechain_node']['id'],
@ -278,7 +280,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
res = self.deserialize(self.fmt, req.get_response(self.ext_api))
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',
scn['servicechain_node']['id'],
@ -304,7 +306,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
# After deleting the Service Chain Spec, node delete should succeed
req = self.new_delete_request('servicechain_nodes', scn_id)
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.plugin.get_servicechain_node,
ctx, scn_id)
@ -319,7 +321,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
scs = self.create_servicechain_spec(name=name, nodes=[scn_id])
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',
scs['servicechain_spec']['id'],
@ -336,7 +338,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
scs = self.create_servicechain_spec(
name=name, nodes=[scn1_id, scn2_id])
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):
scs = [self.create_servicechain_spec(name='scs1', description='scs'),
@ -351,27 +353,25 @@ class TestServiceChainResources(ServiceChainDbTestCase):
nodes_list = [scn1_id, scn2_id]
scs = self.create_servicechain_spec(name='scs1',
nodes=nodes_list)
self.assertEqual(scs['servicechain_spec']['nodes'], nodes_list)
self.assertEqual(nodes_list, scs['servicechain_spec']['nodes'])
res = self._list('servicechain_specs')
self.assertEqual(len(res['servicechain_specs']), 1)
self.assertEqual(res['servicechain_specs'][0]['nodes'],
nodes_list)
self.assertEqual(1, len(res['servicechain_specs']))
self.assertEqual(nodes_list, res['servicechain_specs'][0]['nodes'])
# Delete the service chain spec and create another with nodes in
# reverse order and verify that that proper ordering is maintained
req = self.new_delete_request('servicechain_specs',
scs['servicechain_spec']['id'])
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()
scs = self.create_servicechain_spec(name='scs1',
nodes=nodes_list)
self.assertEqual(scs['servicechain_spec']['nodes'], nodes_list)
res = self._list('servicechain_specs')
self.assertEqual(len(res['servicechain_specs']), 1)
self.assertEqual(res['servicechain_specs'][0]['nodes'],
nodes_list)
self.assertEqual(1, len(res['servicechain_specs']))
self.assertEqual(nodes_list, res['servicechain_specs'][0]['nodes'])
def test_update_servicechain_spec(self):
name = "new_servicechain_spec1"
@ -388,7 +388,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
res = self.deserialize(self.fmt, req.get_response(self.ext_api))
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',
scs['servicechain_spec']['id'], attrs)
@ -401,7 +401,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
req = self.new_delete_request('servicechain_specs', scs_id)
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.plugin.get_servicechain_spec, ctx, scs_id)
@ -464,7 +464,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
classifier_id=classifier_id,
config_param_values=config_param_values)
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',
sci['servicechain_instance']['id'],
@ -488,29 +488,30 @@ class TestServiceChainResources(ServiceChainDbTestCase):
specs_list = [scs1_id, scs2_id]
sci = self.create_servicechain_instance(name='sci1',
servicechain_specs=specs_list)
self.assertEqual(sci['servicechain_instance']['servicechain_specs'],
specs_list)
self.assertEqual(specs_list,
sci['servicechain_instance']['servicechain_specs'])
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]
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
# reverse order and verify that that proper ordering is maintained
req = self.new_delete_request('servicechain_instances',
sci['servicechain_instance']['id'])
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()
sci = self.create_servicechain_instance(name='sci1',
servicechain_specs=specs_list)
self.assertEqual(sci['servicechain_instance']['servicechain_specs'],
specs_list)
self.assertEqual(specs_list,
sci['servicechain_instance']['servicechain_specs'])
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]
self.assertEqual(result_instance['servicechain_specs'], specs_list)
self.assertEqual(specs_list,
result_instance['servicechain_specs'])
def test_update_servicechain_instance(self):
name = "new_servicechain_instance"
@ -537,7 +538,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
sci['servicechain_instance']['id'])
res = self.deserialize(self.fmt, req.get_response(self.ext_api))
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',
sci['servicechain_instance']['id'], attrs)
@ -553,7 +554,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
req = self.new_delete_request('servicechain_instances', sci_id)
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.plugin.get_servicechain_instance,
ctx, sci_id)

View File

@ -29,6 +29,8 @@ cfg.CONF.import_opt('policy_drivers',
GP_PLUGIN_KLASS = (
"gbpservice.neutron.services.grouppolicy.plugin.GroupPolicyPlugin"
)
SERVICECHAIN_SPECS = 'servicechain/servicechain_specs'
SERVICECHAIN_NODES = 'servicechain/servicechain_nodes'
class FakeDriver(object):
@ -47,6 +49,8 @@ class GroupPolicyPluginTestCase(tgpmdb.GroupPolicyMappingDbTestCase):
gp_plugin = GP_PLUGIN_KLASS
super(GroupPolicyPluginTestCase, self).setUp(core_plugin=core_plugin,
gp_plugin=gp_plugin)
cfg.CONF.set_override('servicechain_drivers', ['dummy'],
group='servicechain')
def test_reverse_on_delete(self):
manager = self.plugin.policy_driver_manager
@ -105,6 +109,38 @@ class GroupPolicyPluginTestCase(tgpmdb.GroupPolicyMappingDbTestCase):
external_segment_id=es['external_segment']['id'],
**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):
@ -806,6 +842,57 @@ class TestPolicyTarget(GroupPolicyPluginTestCase):
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(
GroupPolicyPluginTestCase, tgpdb.TestGroupResources):

View File

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