Support Hierarchial Policy Rule Set for Redirects

Change-Id: I5dc4a73c9af82689e4f16a1d07f75b205a354b83
Closes-bug: 1387006
This commit is contained in:
Magesh GV
2014-12-09 15:37:55 +05:30
parent deeaf54d1d
commit 05f5f86279
13 changed files with 425 additions and 149 deletions

View File

@@ -0,0 +1,46 @@
# 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.
#
"""sc_instance_spec_mapping
"""
# revision identifiers, used by Alembic.
revision = '8e14fcb1587e'
down_revision = '64fa77aca090'
from alembic import op
import sqlalchemy as sa
def upgrade(active_plugins=None, options=None):
op.create_table(
'sc_instance_spec_mappings',
sa.Column('servicechain_spec_id',
sa.String(length=36),
nullable=False),
sa.Column('servicechain_instance_id',
sa.String(length=36),
nullable=False),
sa.ForeignKeyConstraint(['servicechain_spec_id'], ['sc_specs.id']),
sa.ForeignKeyConstraint(['servicechain_instance_id'],
['sc_instances.id'],
ondelete='CASCADE'),
sa.PrimaryKeyConstraint('servicechain_instance_id',
'servicechain_spec_id')
)
def downgrade(active_plugins=None, options=None):
op.drop_table('sc_instance_spec_mappings')

View File

@@ -1 +1 @@
64fa77aca090
8e14fcb1587e

View File

@@ -37,8 +37,7 @@ def upgrade(active_plugins=None, options=None):
sa.Column('policy_id',
sa.String(length=36),
nullable=True),
sa.PrimaryKeyConstraint('instance_id'),
sa.PrimaryKeyConstraint('policy_id'))
sa.PrimaryKeyConstraint('instance_id', 'policy_id'))
op.create_table('nvsd_sc_instance_vip_eps',
sa.Column('instance_id',
@@ -50,7 +49,8 @@ def upgrade(active_plugins=None, options=None):
sa.Column('nvsd_ep_id',
sa.String(length=36),
nullable=True),
sa.PrimaryKeyConstraint('instance_id'))
sa.PrimaryKeyConstraint('instance_id', 'vip_port',
'nvsd_ep_id'))
def downgrade(active_plugins=None, options=None):

View File

@@ -63,27 +63,25 @@ def upgrade(active_plugins=None, options=None):
sa.Column('provider_ptg_id', sa.String(length=36), nullable=True),
sa.Column('consumer_ptg_id', sa.String(length=36), nullable=True),
sa.Column('classifier_id', sa.String(length=36), nullable=True),
sa.Column('servicechain_spec', sa.String(length=36), nullable=True),
# FixMe(Magesh) Deletes the instances table itself !!!
# sa.ForeignKeyConstraint(['provider_ptg'],
# FixMe(Magesh) If cascade on delete is used, we lose this info !!!
# sa.ForeignKeyConstraint(['provider_ptg_id'],
# ['gp_policy_target_groups.id'],
# ondelete='CASCADE'),
# sa.ForeignKeyConstraint(['consumer_ptg'],
# sa.ForeignKeyConstraint(['consumer_ptg_id'],
# ['gp_policy_target_groups.id'],
# ondelete='CASCADE'),
# sa.ForeignKeyConstraint(['classifier'], ['gp_policy_classifiers.id'],
# ondelete='CASCADE'),
sa.ForeignKeyConstraint(['servicechain_spec'], ['sc_specs.id']),
sa.PrimaryKeyConstraint('id')
)
op.create_table(
'sc_spec_node_associations',
sa.Column('servicechain_spec', sa.String(length=36), nullable=False),
sa.Column('servicechain_spec_id',
sa.String(length=36),
nullable=False),
sa.Column('node_id', sa.String(length=36), nullable=False),
sa.ForeignKeyConstraint(['servicechain_spec'], ['sc_specs.id']),
sa.ForeignKeyConstraint(['servicechain_spec_id'], ['sc_specs.id']),
sa.ForeignKeyConstraint(['node_id'], ['sc_nodes.id']),
sa.PrimaryKeyConstraint('servicechain_spec', 'node_id')
sa.PrimaryKeyConstraint('servicechain_spec_id', 'node_id')
)

View File

@@ -33,13 +33,23 @@ MAX_IPV6_SUBNET_PREFIX_LENGTH = 127
class SpecNodeAssociation(model_base.BASEV2):
"""Models one to many providing relation between Specs and Nodes."""
__tablename__ = 'sc_spec_node_associations'
servicechain_spec = sa.Column(
servicechain_spec_id = sa.Column(
sa.String(36), sa.ForeignKey('sc_specs.id'), primary_key=True)
node_id = sa.Column(sa.String(36),
sa.ForeignKey('sc_nodes.id'),
primary_key=True)
class InstanceSpecAssociation(model_base.BASEV2):
"""Models one to many providing relation between Instance and Specs."""
__tablename__ = 'sc_instance_spec_mappings'
servicechain_instance_id = sa.Column(
sa.String(36), sa.ForeignKey('sc_instances.id'), primary_key=True)
servicechain_spec_id = sa.Column(sa.String(36),
sa.ForeignKey('sc_specs.id'),
primary_key=True)
class ServiceChainNode(model_base.BASEV2, models_v2.HasId,
models_v2.HasTenant):
"""ServiceChain Node"""
@@ -60,18 +70,19 @@ class ServiceChainInstance(model_base.BASEV2, models_v2.HasId,
name = sa.Column(sa.String(50))
description = sa.Column(sa.String(255))
config_param_values = sa.Column(sa.String(4096))
servicechain_spec = sa.Column(
sa.String(36), sa.ForeignKey('sc_specs.id'), nullable=True)
specs = orm.relationship(InstanceSpecAssociation,
backref='instances',
cascade='all,delete, delete-orphan')
provider_ptg_id = sa.Column(sa.String(36),
# FixMe(Magesh) Deletes the instances table itself
# FixMe(Magesh) Issue with cascade on Delete
# sa.ForeignKey('gp_policy_target_groups.id'),
nullable=True)
consumer_ptg_id = sa.Column(sa.String(36),
# sa.ForeignKey('gp_policy_target_groups.id'),
nullable=True)
classifier_id = sa.Column(sa.String(36),
# sa.ForeignKey('gp_policy_classifiers.id'),
nullable=True)
# sa.ForeignKey('gp_policy_classifiers.id'),
nullable=True)
class ServiceChainSpec(model_base.BASEV2, models_v2.HasId,
@@ -85,8 +96,9 @@ class ServiceChainSpec(model_base.BASEV2, models_v2.HasId,
SpecNodeAssociation,
backref='specs', cascade='all, delete, delete-orphan')
config_param_names = sa.Column(sa.String(4096))
instances = orm.relationship(ServiceChainInstance,
backref="specs")
instances = orm.relationship(InstanceSpecAssociation,
backref="specs",
cascade='all, delete, delete-orphan')
class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
@@ -144,10 +156,11 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
'name': instance['name'],
'description': instance['description'],
'config_param_values': instance['config_param_values'],
'servicechain_spec': instance['servicechain_spec'],
'provider_ptg_id': instance['provider_ptg_id'],
'consumer_ptg_id': instance['consumer_ptg_id'],
'classifier_id': instance['classifier_id']}
res['servicechain_specs'] = [sc_spec['servicechain_spec_id']
for sc_spec in instance['specs']]
return self._fields(res, fields)
@staticmethod
@@ -251,10 +264,39 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
config_param_names.extend(config_params.keys())
spec_db.config_param_names = str(config_param_names)
assoc = SpecNodeAssociation(servicechain_spec=spec_db.id,
assoc = SpecNodeAssociation(servicechain_spec_id=spec_db.id,
node_id=node_id)
spec_db.nodes.append(assoc)
def _process_specs_for_instance(self, context, instance_db, instance):
if 'servicechain_specs' in instance:
self._set_specs_for_instance(context, instance_db,
instance['servicechain_specs'])
del instance['servicechain_specs']
return instance
def _set_specs_for_instance(self, context, instance_db, spec_id_list):
if not spec_id_list:
instance_db.spec_ids = []
return
with context.session.begin(subtransactions=True):
filters = {'id': spec_id_list}
specs_in_db = self._get_collection_query(context, ServiceChainSpec,
filters=filters)
specs_list = set(spec_db['id'] for spec_db in specs_in_db)
for spec_id in spec_id_list:
if spec_id not in specs_list:
# Do not update if spec ID is invalid
raise schain.ServiceChainSpecNotFound(sc_spec_id=spec_id)
# Reset the existing list and then add each spec in order. The list
# could be empty in which case we clear the existing specs.
instance_db.specs = []
for spec_id in spec_id_list:
assoc = InstanceSpecAssociation(
servicechain_instance_id=instance_db.id,
servicechain_spec_id=spec_id)
instance_db.specs.append(assoc)
@log.log
def create_servicechain_spec(self, context, servicechain_spec):
spec = servicechain_spec['servicechain_spec']
@@ -320,10 +362,10 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
tenant_id=tenant_id, name=instance['name'],
description=instance['description'],
config_param_values=instance['config_param_values'],
servicechain_spec=instance['servicechain_spec'],
provider_ptg_id=instance['provider_ptg_id'],
consumer_ptg_id=instance['consumer_ptg_id'],
classifier_id=instance['classifier_id'])
self._process_specs_for_instance(context, instance_db, instance)
context.session.add(instance_db)
return self._make_sc_instance_dict(instance_db)
@@ -334,6 +376,8 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
with context.session.begin(subtransactions=True):
instance_db = self._get_servicechain_instance(
context, servicechain_instance_id)
instance = self._process_specs_for_instance(context, instance_db,
instance)
instance_db.update(instance)
return self._make_sc_instance_dict(instance_db)

View File

@@ -141,8 +141,9 @@ RESOURCE_ATTRIBUTE_MAP = {
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'servicechain_spec': {'allow_post': True, 'allow_put': True,
'validate': {'type:uuid_or_none': None},
'servicechain_specs': {'allow_post': True, 'allow_put': True,
'validate': {'type:uuid_list': None},
'convert_to': attr.convert_none_to_empty_list,
'default': None, 'is_visible': True,
'required': True},
'provider_ptg_id': {'allow_post': True, 'allow_put': False,
@@ -154,9 +155,9 @@ RESOURCE_ATTRIBUTE_MAP = {
'is_visible': True, 'default': None,
'required': True},
'classifier_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:uuid_or_none': None},
'is_visible': True, 'default': None,
'required': True},
'validate': {'type:uuid_or_none': None},
'is_visible': True, 'default': None,
'required': True},
'config_param_values': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'default': "", 'is_visible': True},

View File

@@ -1121,15 +1121,15 @@ class ResourceMappingDriver(api.PolicyDriver):
return
spec = self._servicechain_plugin._get_servicechain_spec(
context._plugin_context, context.original['action_value'])
servicechain_instances = spec.instances
for servicechain_instance in servicechain_instances:
sc_instance_update = {
'servicechain_spec': context.current['action_value']}
self._update_resource(self._servicechain_plugin,
context._plugin_context,
'servicechain_instance',
servicechain_instance['id'],
sc_instance_update)
for servicechain_instance in spec.instances:
sc_instance_update_req = {
'servicechain_specs': [context.current['action_value']]}
self._update_resource(
self._servicechain_plugin,
context._plugin_context,
'servicechain_instance',
servicechain_instance.servicechain_instance_id,
sc_instance_update_req)
def _get_rule_ids_for_actions(self, context, action_id):
policy_rule_qry = context.session.query(
@@ -1137,10 +1137,11 @@ class ResourceMappingDriver(api.PolicyDriver):
policy_rule_qry.filter_by(policy_action_id=action_id)
return policy_rule_qry.all()
def _handle_redirect_action(self, context, policy_rule_sets):
for policy_rule_set_id in policy_rule_sets:
policy_rule_set = context._plugin.get_policy_rule_set(
context._plugin_context, policy_rule_set_id)
def _handle_redirect_action(self, context, policy_rule_set_ids):
policy_rule_sets = context._plugin.get_policy_rule_sets(
context._plugin_context,
filters={'id': policy_rule_set_ids})
for policy_rule_set in policy_rule_sets:
ptgs_consuming_prs = policy_rule_set[
'consuming_policy_target_groups']
ptgs_providing_prs = policy_rule_set[
@@ -1148,42 +1149,60 @@ class ResourceMappingDriver(api.PolicyDriver):
# Create the ServiceChain Instance when we have both Provider and
# consumer PTGs. If Labels are available, they have to be applied
# here. For now we support a single provider
if not ptgs_consuming_prs or not ptgs_providing_prs:
continue
for rule_id in policy_rule_set.get('policy_rules'):
policy_rule = context._plugin.get_policy_rule(
context._plugin_context, rule_id)
parent_classifier_id = None
parent_spec_id = None
if policy_rule_set['parent_id']:
parent = context._plugin.get_policy_rule_set(
context._plugin_context, policy_rule_set['parent_id'])
policy_rules = context._plugin.get_policy_rules(
context._plugin_context,
filters={'id': parent['policy_rules']})
for policy_rule in policy_rules:
policy_actions = context._plugin.get_policy_actions(
context._plugin_context,
filters={'id': policy_rule["policy_actions"],
'action_type': [gconst.GP_ACTION_REDIRECT]})
for policy_action in policy_actions:
parent_classifier_id = policy_rule.get(
"policy_classifier_id")
parent_spec_id = policy_action.get("action_value")
break # One Redirect action per Policy rule set
policy_rules = context._plugin.get_policy_rules(
context._plugin_context,
filters={'id': policy_rule_set['policy_rules']})
for policy_rule in policy_rules:
classifier_id = policy_rule.get("policy_classifier_id")
for action_id in policy_rule.get("policy_actions"):
policy_action = context._plugin.get_policy_action(
context._plugin_context, action_id)
if policy_action['action_type'].upper() == "REDIRECT":
for ptg_consuming_prs in ptgs_consuming_prs:
for ptg_providing_prs in ptgs_providing_prs:
ptg_chain_map = (
if parent_classifier_id and not set(
[parent_classifier_id]) & set([classifier_id]):
continue
policy_actions = context._plugin.get_policy_actions(
context._plugin_context,
filters={'id': policy_rule.get("policy_actions"),
'action_type': [gconst.GP_ACTION_REDIRECT]})
for policy_action in policy_actions:
for ptg_consuming_prs in ptgs_consuming_prs:
for ptg_providing_prs in ptgs_providing_prs:
ptg_chain_map = (
self._get_ptg_servicechain_mapping(
context._plugin_context.session,
ptg_providing_prs,
ptg_consuming_prs))
# REVISIT(Magesh): There may be concurrency
# issues here.
if ptg_chain_map:
continue # one chain between pair of PTGs
sc_instance = (
self._create_servicechain_instance(
context,
policy_action.get("action_value"),
ptg_providing_prs,
ptg_consuming_prs,
classifier_id))
chain_instance_id = sc_instance['id']
self._set_ptg_servicechain_instance_mapping(
context._plugin_context.session,
ptg_providing_prs,
ptg_consuming_prs,
chain_instance_id)
# REVISIT(Magesh): There may be concurrency
# issues here.
if ptg_chain_map:
continue # one chain between pair of PTGs
sc_instance = self._create_servicechain_instance(
context, policy_action.get("action_value"),
parent_spec_id, ptg_providing_prs,
ptg_consuming_prs, classifier_id)
self._set_ptg_servicechain_instance_mapping(
context._plugin_context.session,
ptg_providing_prs, ptg_consuming_prs,
sc_instance['id'])
def _cleanup_redirect_action(self, context):
for ptg_chain in context.ptg_chain_map:
@@ -1339,10 +1358,14 @@ class ResourceMappingDriver(api.PolicyDriver):
return ip_address
def _create_servicechain_instance(self, context, servicechain_spec,
parent_servicechain_spec,
provider_ptg_id, consumer_ptg_id,
classifier_id, config_params=None):
classifier_id,
config_params=None):
sc_spec = [servicechain_spec]
if parent_servicechain_spec:
sc_spec.insert(0, parent_servicechain_spec)
config_param_values = {}
ptg = context._plugin.get_policy_target_group(
context._plugin_context, provider_ptg_id)
network_service_policy_id = ptg.get("network_service_policy_id")
@@ -1362,7 +1385,7 @@ class ResourceMappingDriver(api.PolicyDriver):
attrs = {'tenant_id': context.current['tenant_id'],
'name': 'gbp_' + context.current['name'],
'description': "",
'servicechain_spec': servicechain_spec,
'servicechain_specs': sc_spec,
'provider_ptg_id': provider_ptg_id,
'consumer_ptg_id': consumer_ptg_id,
'classifier_id': classifier_id,
@@ -1784,18 +1807,27 @@ class ResourceMappingDriver(api.PolicyDriver):
for child in children:
child = context._plugin.get_policy_rule_set(
context._plugin_context, child)
child_rules = set(child['policy_rules'])
child_rule_ids = set(child['policy_rules'])
if child['parent_id']:
parent = context._plugin.get_policy_rule_set(
context._plugin_context, child['parent_id'])
parent_rules = set(parent['policy_rules'])
parent_policy_rules = context._plugin.get_policy_rules(
context._plugin_context,
filters={'id': parent['policy_rules']})
child_rules = context._plugin.get_policy_rules(
context._plugin_context,
filters={'id': child['policy_rules']})
parent_classifier_ids = [x['policy_classifier_id']
for x in parent_policy_rules]
delta_rules = [x['id'] for x in child_rules
if x['policy_classifier_id']
not in set(parent_classifier_ids)]
delta_rules = context._plugin.get_policy_rules(
context._plugin_context,
filters={'id': child_rules - parent_rules})
context._plugin_context, {'id': delta_rules})
self._remove_policy_rule_set_rules(context, child, delta_rules)
# Old parent may have filtered some rules, need to add them again
child_rules = context._plugin.get_policy_rules(
context._plugin_context, filters={'id': child_rules})
context._plugin_context, filters={'id': child_rule_ids})
self._apply_policy_rule_set_rules(context, child, child_rules)
def _get_default_security_group(self, plugin_context, ptg_id,
@@ -2020,9 +2052,20 @@ class ResourceMappingDriver(api.PolicyDriver):
if prs['parent_id']:
parent = context._plugin.get_policy_rule_set(
context._plugin_context, prs['parent_id'])
parent_policy_rules = context._plugin.get_policy_rules(
context._plugin_context,
filters={'id': parent['policy_rules']})
subset_rules = context._plugin.get_policy_rules(
context._plugin_context,
filters={'id': subset})
parent_classifier_ids = [x['policy_classifier_id']
for x in parent_policy_rules]
policy_rules = [x['id'] for x in subset_rules
if x['policy_classifier_id']
in set(parent_classifier_ids)]
return context._plugin.get_policy_rules(
context._plugin_context,
{'id': set(subset) & set(parent['policy_rules'])})
{'id': policy_rules})
else:
return context._plugin.get_policy_rules(
context._plugin_context, {'id': set(subset)})

View File

@@ -109,14 +109,15 @@ class OneconvergenceServiceChainDriver(simplechain_driver.SimpleChainDriver):
@log.log
def update_servicechain_instance_postcommit(self, context):
original_spec_id = context._original_sc_instance.get(
'servicechain_spec')
new_spec_id = context._sc_instance.get('servicechain_spec')
if original_spec_id != new_spec_id:
newspec = context._plugin.get_servicechain_spec(
context._plugin_context, new_spec_id)
self._update_servicechain_instance(context, context._sc_instance,
newspec)
original_spec_ids = context._original_sc_instance.get(
'servicechain_specs')
new_spec_ids = context._sc_instance.get('servicechain_specs')
if set(original_spec_ids) != set(new_spec_ids):
for new_spec_id in new_spec_ids:
newspec = context._plugin.get_servicechain_spec(
context._plugin_context, new_spec_id)
self._update_servicechain_instance(context, context.current,
newspec)
@log.log
def delete_servicechain_instance_postcommit(self, context):
@@ -208,12 +209,13 @@ class OneconvergenceServiceChainDriver(simplechain_driver.SimpleChainDriver):
def _create_servicechain_instance_postcommit(self, context):
sc_instance = context.current
sc_spec_id = sc_instance.get('servicechain_spec')
sc_spec = context._plugin.get_servicechain_spec(
context._plugin_context, sc_spec_id)
sc_node_ids = sc_spec.get('nodes')
self._create_servicechain_instance_stacks(context, sc_node_ids,
sc_instance, sc_spec)
sc_spec_ids = sc_instance.get('servicechain_specs')
for sc_spec_id in sc_spec_ids:
sc_spec = context._plugin.get_servicechain_spec(
context._plugin_context, sc_spec_id)
sc_node_ids = sc_spec.get('nodes')
self._create_servicechain_instance_stacks(context, sc_node_ids,
sc_instance, sc_spec)
def _create_port(self, plugin_context, attrs):
return self._create_resource(self._core_plugin, plugin_context, 'port',
@@ -418,8 +420,7 @@ class OneconvergenceServiceChainDriver(simplechain_driver.SimpleChainDriver):
return service_ids
def create_nvsd_action(self, context, action_body):
return self.nvsd_api.create_policy_action(context,
action_body)
return self.nvsd_api.create_policy_action(context, action_body)
def _create_nvsd_services_action(self, context, service_ids):
nvsd_action_list = []
@@ -447,7 +448,7 @@ class OneconvergenceServiceChainDriver(simplechain_driver.SimpleChainDriver):
'tenant_id': context.tenant,
'user_id': context.user,
"action_value": service_id}
#Supporting only one TAP in a chain
# Supporting only one TAP in a chain
if copy_action:
action = self.create_nvsd_action(context, copy_action)
nvsd_action_list.append(action['id'])
@@ -465,12 +466,12 @@ class OneconvergenceServiceChainDriver(simplechain_driver.SimpleChainDriver):
if status == self.CREATE_IN_PROGRESS:
return False
elif status == self.CREATE_FAILED:
#TODO(Magesh): Status has to be added to ServiceChainInstance
#Update the Status to ERROR at this point
# TODO(Magesh): Status has to be added to ServiceChainInstance
# Update the Status to ERROR at this point
return True
#Services are created by now. Determine Service IDs an setup
#Traffic Steering.
# Services are created by now. Determine Service IDs an setup
# Traffic Steering.
service_ids = self._fetch_serviceids_from_stack(context, node_stacks,
chain_instance_id)
nvsd_action_list = self._create_nvsd_services_action(context,
@@ -483,11 +484,10 @@ class OneconvergenceServiceChainDriver(simplechain_driver.SimpleChainDriver):
policy_id = self.create_nvsd_policy(context, left_group,
right_group, classifier_id,
nvsd_action_list)
#TODO(Magesh): Need to store actions and rules also, because
#cleanup will be missed if policy create failed
self._add_chain_policy_map(context.session,
chain_instance_id,
policy_id)
# TODO(Magesh): Need to store actions and rules also, because
# cleanup will be missed if policy create failed
self._add_chain_policy_map(context.session, chain_instance_id,
policy_id, classifier_id)
return True

View File

@@ -110,12 +110,13 @@ class SimpleChainDriver(object):
@log.log
def create_servicechain_instance_postcommit(self, context):
sc_instance = context.current
sc_spec_id = sc_instance.get('servicechain_spec')
sc_spec = context._plugin.get_servicechain_spec(
context._plugin_context, sc_spec_id)
sc_node_ids = sc_spec.get('nodes')
self._create_servicechain_instance_stacks(context, sc_node_ids,
sc_instance, sc_spec)
sc_spec_ids = sc_instance.get('servicechain_specs')
for sc_spec_id in sc_spec_ids:
sc_spec = context._plugin.get_servicechain_spec(
context._plugin_context, sc_spec_id)
sc_node_ids = sc_spec.get('nodes')
self._create_servicechain_instance_stacks(context, sc_node_ids,
sc_instance, sc_spec)
@log.log
def update_servicechain_instance_precommit(self, context):
@@ -123,13 +124,14 @@ class SimpleChainDriver(object):
@log.log
def update_servicechain_instance_postcommit(self, context):
original_spec_id = context.original.get('servicechain_spec')
new_spec_id = context.current.get('servicechain_spec')
if original_spec_id != new_spec_id:
newspec = context._plugin.get_servicechain_spec(
context._plugin_context, new_spec_id)
self._update_servicechain_instance(context, context.current,
newspec)
original_spec_ids = context.original.get('servicechain_specs')
new_spec_ids = context.current.get('servicechain_specs')
if set(original_spec_ids) != set(new_spec_ids):
for new_spec_id in new_spec_ids:
newspec = context._plugin.get_servicechain_spec(
context._plugin_context, new_spec_id)
self._update_servicechain_instance(context, context.current,
newspec)
@log.log
def delete_servicechain_instance_precommit(self, context):

View File

@@ -82,14 +82,14 @@ class ServiceChainDBTestBase(object):
def _get_test_servicechain_instance_attrs(self, name='sci1',
description='test sci',
config_param_values="{}",
servicechain_spec=None,
servicechain_specs=[],
provider_ptg_id=None,
consumer_ptg_id=None,
classifier_id=None):
attrs = {'name': name, 'description': description,
'tenant_id': self._tenant_id,
'config_param_values': config_param_values,
'servicechain_spec': servicechain_spec,
'servicechain_specs': servicechain_specs,
'provider_ptg_id': provider_ptg_id,
'consumer_ptg_id': consumer_ptg_id,
'classifier_id': classifier_id}
@@ -167,7 +167,7 @@ class ServiceChainDBTestBase(object):
self.assertIn('servicechain_spec', res)
self.assertEqual([scn_id], res['servicechain_spec']['nodes'])
def create_servicechain_instance(self, servicechain_spec=None,
def create_servicechain_instance(self, servicechain_specs=[],
config_param_values="{}",
provider_ptg_id=None,
consumer_ptg_id=None,
@@ -177,7 +177,7 @@ class ServiceChainDBTestBase(object):
defaults.update(kwargs)
data = {'servicechain_instance':
{'config_param_values': config_param_values,
'servicechain_spec': servicechain_spec,
'servicechain_specs': servicechain_specs,
'tenant_id': self._tenant_id,
'provider_ptg_id': provider_ptg_id,
'consumer_ptg_id': consumer_ptg_id,
@@ -371,14 +371,14 @@ class TestServiceChainResources(ServiceChainDbTestCase):
classifier_id = uuidutils.generate_uuid()
config_param_values = "{}"
attrs = self._get_test_servicechain_instance_attrs(
servicechain_spec=scs_id,
servicechain_specs=[scs_id],
provider_ptg_id=policy_target_group_id,
consumer_ptg_id=policy_target_group_id,
classifier_id=classifier_id,
config_param_values=config_param_values)
sci = self.create_servicechain_instance(
servicechain_spec=scs_id,
servicechain_specs=[scs_id],
provider_ptg_id=policy_target_group_id,
consumer_ptg_id=policy_target_group_id,
classifier_id=classifier_id,
@@ -411,18 +411,18 @@ class TestServiceChainResources(ServiceChainDbTestCase):
consumer_ptg_id = uuidutils.generate_uuid()
classifier_id = uuidutils.generate_uuid()
attrs = self._get_test_servicechain_instance_attrs(
name=name, description=description, servicechain_spec=scs_id,
name=name, description=description, servicechain_specs=[scs_id],
provider_ptg_id=provider_ptg_id, consumer_ptg_id=consumer_ptg_id,
classifier_id=classifier_id,
config_param_values=config_param_values)
sci = self.create_servicechain_instance(
servicechain_spec=scs_id, provider_ptg_id=provider_ptg_id,
servicechain_specs=[scs_id], provider_ptg_id=provider_ptg_id,
consumer_ptg_id=consumer_ptg_id, classifier_id=classifier_id,
config_param_values=config_param_values)
data = {'servicechain_instance': {'name': name,
'description': description,
'servicechain_spec': scs_id}}
'servicechain_specs': [scs_id]}}
req = self.new_update_request('servicechain_instances', data,
sci['servicechain_instance']['id'])
res = self.deserialize(self.fmt, req.get_response(self.ext_api))

View File

@@ -158,9 +158,21 @@ class ResourceMappingTestCase(
if prs['parent_id']:
parent = self.show_policy_rule_set(
prs['parent_id'])['policy_rule_set']
return [self.show_policy_rule(x)['policy_rule']
for x in prs['policy_rules']
if x in parent['policy_rules']]
parent_policy_rules = [self.show_policy_rule(
policy_rule_id)['policy_rule'] for
policy_rule_id in parent["policy_rules"]]
subset_rules = [self.show_policy_rule(
policy_rule_id)['policy_rule'] for
policy_rule_id in prs['policy_rules']]
parent_classifier_ids = [x['policy_classifier_id']
for x in parent_policy_rules]
policy_rules = [x['id'] for x in subset_rules
if x['policy_classifier_id']
in set(parent_classifier_ids)]
return [self.show_policy_rule(
policy_rule_id)['policy_rule'] for
policy_rule_id in policy_rules]
else:
return [self.show_policy_rule(x)['policy_rule']
for x in prs['policy_rules']]
@@ -1432,7 +1444,7 @@ class TestPolicyRuleSet(ResourceMappingTestCase):
sc_instance = sc_instances['servicechain_instances'][0]
self.assertEqual(sc_instance['provider_ptg_id'], provider_ptg_id)
self.assertEqual(sc_instance['consumer_ptg_id'], consumer_ptg_id)
self.assertEqual(scs_id, sc_instance['servicechain_spec'])
self.assertEqual([scs_id], sc_instance['servicechain_specs'])
data = {'servicechain_node': {'service_type': "FIREWALL",
'tenant_id': self._tenant_id,
@@ -1459,7 +1471,8 @@ class TestPolicyRuleSet(ResourceMappingTestCase):
self.assertEqual(len(new_sc_instances['servicechain_instances']), 1)
new_sc_instance = new_sc_instances['servicechain_instances'][0]
self.assertEqual(sc_instance['id'], new_sc_instance['id'])
self.assertEqual(new_scs_id, new_sc_instance['servicechain_spec'])
self.assertEqual([new_scs_id], new_sc_instance['servicechain_specs'])
req = self.new_delete_request(
'policy_target_groups', consumer_ptg_id)
res = req.get_response(self.ext_api)
@@ -1482,6 +1495,7 @@ class TestPolicyRuleSet(ResourceMappingTestCase):
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']
classifier = self.create_policy_classifier(
name="class1", protocol="tcp", direction="in", port_range="20:90")
classifier_id = classifier['policy_classifier']['id']
@@ -1572,6 +1586,99 @@ class TestPolicyRuleSet(ResourceMappingTestCase):
# No more service chain instances when all the providers are deleted
self.assertEqual(len(sc_instances['servicechain_instances']), 0)
def test_hierarchial_redirect(self):
data = {'servicechain_node': {'service_type': "LOADBALANCER",
'tenant_id': self._tenant_id,
'config': "{}"}}
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']
data = {'servicechain_spec': {'tenant_id': self._tenant_id,
'nodes': [scn_id]}}
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']
classifier1 = self.create_policy_classifier(
name="class1", protocol="tcp", direction="in", port_range="20:90")
classifier1_id = classifier1['policy_classifier']['id']
classifier2 = self.create_policy_classifier(
name="class1", protocol="tcp", direction="in", port_range="80")
classifier2_id = classifier2['policy_classifier']['id']
action = self.create_policy_action(
name="action1", action_type=gconst.GP_ACTION_REDIRECT,
action_value=scs_id)
action_id = action['policy_action']['id']
policy_rule1 = self.create_policy_rule(
name='pr1', policy_classifier_id=classifier1_id,
policy_actions=[action_id])
policy_rule1_id = policy_rule1['policy_rule']['id']
policy_rule2 = self.create_policy_rule(
name='pr2', policy_classifier_id=classifier2_id,
policy_actions=[action_id])
policy_rule2_id = policy_rule2['policy_rule']['id']
policy_rule_set = self.create_policy_rule_set(
name="prs", policy_rules=[policy_rule1_id, policy_rule2_id])
policy_rule_set_id = policy_rule_set['policy_rule_set']['id']
data = {'servicechain_node': {'service_type': "FIREWALL",
'tenant_id': self._tenant_id,
'config': "{}"}}
parent_scn_req = self.new_create_request(SERVICECHAIN_NODES,
data, self.fmt)
parent_sc_node = self.deserialize(
self.fmt, parent_scn_req.get_response(self.ext_api))
parent_scn_id = parent_sc_node['servicechain_node']['id']
data = {'servicechain_spec': {'tenant_id': self._tenant_id,
'nodes': [parent_scn_id]}}
parent_scs_req = self.new_create_request(
SERVICECHAIN_SPECS, data, self.fmt)
parent_spec = self.deserialize(
self.fmt, parent_scs_req.get_response(self.ext_api))
parent_scs_id = parent_spec['servicechain_spec']['id']
parent_action = self.create_policy_action(
name="action2", action_type=gconst.GP_ACTION_REDIRECT,
action_value=parent_scs_id)
parent_action_id = parent_action['policy_action']['id']
parent_policy_rule = self.create_policy_rule(
name='pr1', policy_classifier_id=classifier2_id,
policy_actions=[parent_action_id])
parent_policy_rule_id = parent_policy_rule['policy_rule']['id']
self.create_policy_rule_set(
name="c1", policy_rules=[parent_policy_rule_id],
child_policy_rule_sets=[policy_rule_set_id])
provider_ptg = self.create_policy_target_group(
name="ptg1", provided_policy_rule_sets={policy_rule_set_id: None})
provider_ptg_id = provider_ptg['policy_target_group']['id']
consumer_ptg = self.create_policy_target_group(
name="ptg2",
consumed_policy_rule_sets={policy_rule_set_id: None})
consumer_ptg_id = consumer_ptg['policy_target_group']['id']
sc_node_list_req = self.new_list_request(SERVICECHAIN_INSTANCES)
res = sc_node_list_req.get_response(self.ext_api)
sc_instances = self.deserialize(self.fmt, res)
# We should have one service chain instance created now
self.assertEqual(len(sc_instances['servicechain_instances']), 1)
sc_instance = sc_instances['servicechain_instances'][0]
self.assertEqual(sc_instance['provider_ptg_id'], provider_ptg_id)
self.assertEqual(sc_instance['consumer_ptg_id'], consumer_ptg_id)
self.assertEqual(sc_instance['classifier_id'], classifier2_id)
#REVISIT(Magesh): List api retrieves in different order
#Functionally create/update is working fine
#self.assertEqual(sc_instance['servicechain_spec'],
# [parent_scs_id, scs_id])
req = self.new_delete_request(
'policy_target_groups', consumer_ptg_id)
res = req.get_response(self.ext_api)
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
sc_node_list_req = self.new_list_request(SERVICECHAIN_INSTANCES)
res = sc_node_list_req.get_response(self.ext_api)
sc_instances = self.deserialize(self.fmt, res)
self.assertEqual(len(sc_instances['servicechain_instances']), 0)
def test_shared_policy_rule_set_create_negative(self):
self.create_policy_rule_set(shared=True,
expected_res_status=400)
@@ -1711,6 +1818,41 @@ class TestPolicyRuleSet(ResourceMappingTestCase):
port_range=8080)
self._verify_prs_rules(prs['id'])
def _update_same_classifier_multiple_rules(self):
action = self.create_policy_action(
action_type='allow')['policy_action']
classifier = self.create_policy_classifier(
protocol='TCP', port_range="22",
direction='bi')['policy_classifier']
pr1 = self.create_policy_rule(
policy_classifier_id=classifier['id'],
policy_actions=[action['id']])['policy_rule']
pr2 = self.create_policy_rule(
policy_classifier_id=classifier['id'],
policy_actions=[action['id']])['policy_rule']
prs = self.create_policy_rule_set(
policy_rules=[pr1['id']],
expected_res_status=201)['policy_rule_set']
self.create_policy_rule_set(
policy_rules=[pr2['id']], child_policy_rule_sets=[prs['id']],
expected_res_status=201)
self._verify_prs_rules(prs['id'])
self.create_policy_target_group(
provided_policy_rule_sets={prs['id']: None},
expected_res_status=201)
self.create_policy_target_group(
consumed_policy_rule_sets={prs['id']: None},
expected_res_status=201)
self._verify_prs_rules(prs['id'])
self.update_policy_classifier(
pr1['policy_classifier_id'], expected_res_status=200,
port_range=8080)
self._verify_prs_rules(prs['id'])
def test_delete_policy_rule(self):
pr = self._create_http_allow_rule()
pr2 = self._create_ssh_allow_rule()

View File

@@ -79,10 +79,10 @@ class TestServiceChainInstance(SimpleChainDriverTestCase):
instance1_name = "sc_instance_1"
sc_instance1 = self.create_servicechain_instance(
name=instance1_name,
servicechain_spec=sc_spec_id)
servicechain_specs=[sc_spec_id])
self.assertEqual(
sc_instance1['servicechain_instance']['servicechain_spec'],
sc_spec_id)
sc_instance1['servicechain_instance']['servicechain_specs'],
[sc_spec_id])
stack_name = "stack_" + instance1_name + scn1_name + scn_id[:5]
expected_create_calls.append(
mock.call(stack_name, jsonutils.loads(template1), {}))
@@ -90,10 +90,10 @@ class TestServiceChainInstance(SimpleChainDriverTestCase):
instance2_name = "sc_instance_2"
sc_instance2 = self.create_servicechain_instance(
name=instance2_name,
servicechain_spec=sc_spec_id)
servicechain_specs=[sc_spec_id])
self.assertEqual(
sc_instance2['servicechain_instance']['servicechain_spec'],
sc_spec_id)
sc_instance2['servicechain_instance']['servicechain_specs'],
[sc_spec_id])
stack_name = "stack_" + instance2_name + scn1_name + scn_id[:5]
expected_create_calls.append(
mock.call(stack_name, jsonutils.loads(template1), {}))
@@ -133,10 +133,10 @@ class TestServiceChainInstance(SimpleChainDriverTestCase):
'id': uuidutils.generate_uuid()}}
sc_instance = self.create_servicechain_instance(
name="sc_instance_1",
servicechain_spec=sc_spec_id)
servicechain_specs=[sc_spec_id])
self.assertEqual(
sc_instance['servicechain_instance']['servicechain_spec'],
sc_spec_id)
sc_instance['servicechain_instance']['servicechain_specs'],
[sc_spec_id])
stack_create.assert_called_once_with(mock.ANY, mock.ANY, mock.ANY)
def test_chain_instance_delete(self):
@@ -152,10 +152,10 @@ class TestServiceChainInstance(SimpleChainDriverTestCase):
'id': uuidutils.generate_uuid()}}
sc_instance = self.create_servicechain_instance(
name="sc_instance_1",
servicechain_spec=sc_spec_id)
servicechain_specs=[sc_spec_id])
self.assertEqual(
sc_instance['servicechain_instance']['servicechain_spec'],
sc_spec_id)
sc_instance['servicechain_instance']['servicechain_specs'],
[sc_spec_id])
with mock.patch.object(simplechain_driver.HeatClient,
'delete'):
req = self.new_delete_request(

View File

@@ -304,7 +304,7 @@ class ServiceChainExtensionTestCase(test_api_v2_extension.ExtensionTestCase):
def _get_create_servicechain_instance_attrs(self):
return {
'name': 'servicechaininstance1',
'servicechain_spec': _uuid(),
'servicechain_specs': [_uuid()],
'tenant_id': _uuid(),
'provider_ptg_id': _uuid(),
'consumer_ptg_id': _uuid(),
@@ -316,18 +316,18 @@ class ServiceChainExtensionTestCase(test_api_v2_extension.ExtensionTestCase):
def _get_update_servicechain_instance_attrs(self):
return {
'name': 'new_name',
'servicechain_spec': _uuid()
'servicechain_specs': [_uuid()]
}
def test_create_servicechain_instance_with_defaults(self):
servicechain_instance_id = _uuid()
data = {
'servicechain_instance': {
'servicechain_spec': _uuid(),
'servicechain_specs': [_uuid()],
'tenant_id': _uuid(),
'provider_ptg_id': _uuid(),
'consumer_ptg_id': _uuid(),
'classifier_id': _uuid()
'classifier_id': _uuid(),
}
}
default_attrs = self._get_create_servicechain_instance_default_attrs()