introduce service profile model
Partially implements blueprint node-centric-chain-plugin Change-Id: I2403e35d49a1e100f292f82082c7dad96d79fc29
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
"shared_nsp": "field:network_service_policies:shared=True",
|
||||
"shared_scn": "field:servicechain_nodes:shared=True",
|
||||
"shared_scs": "field:servicechain_specs:shared=True",
|
||||
"shared_sp": "field:service_profiles:shared=True",
|
||||
|
||||
"create_policy_target_group": "",
|
||||
"create_policy_target_group:shared": "rule:admin_only",
|
||||
@@ -86,5 +87,10 @@
|
||||
|
||||
"create_servicechain_instance": "",
|
||||
"get_servicechain_instance": "rule:admin_or_owner",
|
||||
"update_servicechain_instance:shared": "rule:admin_only"
|
||||
"update_servicechain_instance:shared": "rule:admin_only",
|
||||
|
||||
"create_service_profile": "",
|
||||
"create_service_profile:shared": "rule:admin_only",
|
||||
"get_service_profile": "rule:admin_or_owner or rule:shared_sp",
|
||||
"update_service_profile:shared": "rule:admin_only"
|
||||
}
|
||||
|
@@ -0,0 +1,56 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""service_profile
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '9744740aa75c'
|
||||
down_revision = 'fd98aa15958d'
|
||||
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table(
|
||||
'service_profiles',
|
||||
sa.Column('id', sa.String(36), nullable=False),
|
||||
sa.Column('tenant_id', sa.String(length=255), nullable=True),
|
||||
sa.Column('name', sa.String(length=50), nullable=True),
|
||||
sa.Column('vendor', sa.String(length=50), nullable=True),
|
||||
sa.Column('description', sa.String(length=255), nullable=True),
|
||||
sa.Column('shared', sa.Boolean),
|
||||
sa.Column('insertion_mode', sa.String(length=50), nullable=True),
|
||||
sa.Column('service_type', sa.String(length=50), nullable=True),
|
||||
sa.Column('service_flavor', sa.String(length=1024), nullable=True),
|
||||
sa.PrimaryKeyConstraint('id'),
|
||||
)
|
||||
|
||||
op.add_column(
|
||||
'sc_nodes',
|
||||
sa.Column('service_profile_id', sa.String(36), nullable=True)
|
||||
)
|
||||
|
||||
op.create_foreign_key('sc_nodes_ibfk_profile', source='sc_nodes',
|
||||
referent='service_profiles',
|
||||
local_cols=['service_profile_id'],
|
||||
remote_cols=['id'])
|
||||
|
||||
op.alter_column("sc_nodes", "service_type",
|
||||
existing_type=sa.String(length=50), nullable=True)
|
||||
|
||||
|
||||
def downgrade():
|
||||
pass
|
@@ -1 +1 @@
|
||||
fd98aa15958d
|
||||
9744740aa75c
|
@@ -63,12 +63,15 @@ class ServiceChainNode(model_base.BASEV2, models_v2.HasId,
|
||||
__tablename__ = 'sc_nodes'
|
||||
name = sa.Column(sa.String(50))
|
||||
description = sa.Column(sa.String(255))
|
||||
service_type = sa.Column(sa.String(50))
|
||||
config = sa.Column(sa.String(4096))
|
||||
specs = orm.relationship(SpecNodeAssociation,
|
||||
backref="nodes",
|
||||
cascade='all, delete, delete-orphan')
|
||||
shared = sa.Column(sa.Boolean)
|
||||
service_type = sa.Column(sa.String(50), nullable=True)
|
||||
service_profile_id = sa.Column(
|
||||
sa.String(36), sa.ForeignKey('service_profiles.id'),
|
||||
nullable=True)
|
||||
|
||||
|
||||
class ServiceChainInstance(model_base.BASEV2, models_v2.HasId,
|
||||
@@ -115,6 +118,23 @@ class ServiceChainSpec(model_base.BASEV2, models_v2.HasId,
|
||||
shared = sa.Column(sa.Boolean)
|
||||
|
||||
|
||||
class ServiceProfile(model_base.BASEV2, models_v2.HasId,
|
||||
models_v2.HasTenant):
|
||||
""" Service Profile
|
||||
"""
|
||||
__tablename__ = 'service_profiles'
|
||||
name = sa.Column(sa.String(50))
|
||||
description = sa.Column(sa.String(255))
|
||||
vendor = sa.Column(sa.String(50))
|
||||
shared = sa.Column(sa.Boolean)
|
||||
# Not using ENUM for less painful upgrades. Validation will happen at the
|
||||
# API level
|
||||
insertion_mode = sa.Column(sa.String(50))
|
||||
service_type = sa.Column(sa.String(50))
|
||||
service_flavor = sa.Column(sa.String(1024))
|
||||
nodes = orm.relationship(ServiceChainNode, backref="service_profile")
|
||||
|
||||
|
||||
class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
|
||||
common_db_mixin.CommonDbMixin):
|
||||
"""ServiceChain plugin interface implementation using SQLAlchemy models."""
|
||||
@@ -157,11 +177,19 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
|
||||
raise schain.ServiceChainInstanceNotFound(
|
||||
sc_instance_id=instance_id)
|
||||
|
||||
def _get_service_profile(self, context, profile_id):
|
||||
try:
|
||||
return self._get_by_id(context, ServiceProfile, profile_id)
|
||||
except exc.NoResultFound:
|
||||
raise schain.ServiceProfileNotFound(
|
||||
profile_id=profile_id)
|
||||
|
||||
def _make_sc_node_dict(self, sc_node, fields=None):
|
||||
res = {'id': sc_node['id'],
|
||||
'tenant_id': sc_node['tenant_id'],
|
||||
'name': sc_node['name'],
|
||||
'description': sc_node['description'],
|
||||
'service_profile_id': sc_node['service_profile_id'],
|
||||
'service_type': sc_node['service_type'],
|
||||
'config': sc_node['config'],
|
||||
'shared': sc_node['shared']}
|
||||
@@ -192,6 +220,19 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
|
||||
for sc_spec in instance['specs']]
|
||||
return self._fields(res, fields)
|
||||
|
||||
def _make_service_profile_dict(self, profile, fields=None):
|
||||
res = {'id': profile['id'],
|
||||
'tenant_id': profile['tenant_id'],
|
||||
'name': profile['name'],
|
||||
'description': profile['description'],
|
||||
'shared': profile['shared'],
|
||||
'service_type': profile['service_type'],
|
||||
'service_flavor': profile['service_flavor'],
|
||||
'vendor': profile['vendor'],
|
||||
'insertion_mode': profile['insertion_mode']}
|
||||
res['nodes'] = [node['id'] for node in profile['nodes']]
|
||||
return self._fields(res, fields)
|
||||
|
||||
@staticmethod
|
||||
def validate_service_type(service_type):
|
||||
if service_type not in schain.sc_supported_type:
|
||||
@@ -202,13 +243,12 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
|
||||
node = servicechain_node['servicechain_node']
|
||||
tenant_id = self._get_tenant_id_for_create(context, node)
|
||||
with context.session.begin(subtransactions=True):
|
||||
node_db = ServiceChainNode(id=uuidutils.generate_uuid(),
|
||||
tenant_id=tenant_id,
|
||||
name=node['name'],
|
||||
description=node['description'],
|
||||
service_type=node['service_type'],
|
||||
config=node['config'],
|
||||
shared=node['shared'])
|
||||
node_db = ServiceChainNode(
|
||||
id=uuidutils.generate_uuid(), tenant_id=tenant_id,
|
||||
name=node['name'], description=node['description'],
|
||||
service_profile_id=node['service_profile_id'],
|
||||
service_type=node['service_type'],
|
||||
config=node['config'], shared=node['shared'])
|
||||
context.session.add(node_db)
|
||||
return self._make_sc_node_dict(node_db)
|
||||
|
||||
@@ -447,6 +487,61 @@ class ServiceChainDbPlugin(schain.ServiceChainPluginBase,
|
||||
page_reverse=page_reverse)
|
||||
|
||||
@log.log
|
||||
def get_servicechain_instances_count(self, context, filters=None):
|
||||
return self._get_collection_count(context, ServiceChainInstance,
|
||||
def get_service_profile_count(self, context, filters=None):
|
||||
return self._get_collection_count(context, ServiceProfile,
|
||||
filters=filters)
|
||||
|
||||
@log.log
|
||||
def create_service_profile(self, context, service_profile):
|
||||
profile = service_profile['service_profile']
|
||||
tenant_id = self._get_tenant_id_for_create(context, profile)
|
||||
with context.session.begin(subtransactions=True):
|
||||
profile_db = ServiceProfile(
|
||||
id=uuidutils.generate_uuid(), tenant_id=tenant_id,
|
||||
name=profile['name'], description=profile['description'],
|
||||
service_type=profile['service_type'],
|
||||
insertion_mode=profile['insertion_mode'],
|
||||
vendor=profile['vendor'],
|
||||
service_flavor=profile['service_flavor'],
|
||||
shared=profile['shared'])
|
||||
context.session.add(profile_db)
|
||||
return self._make_service_profile_dict(profile_db)
|
||||
|
||||
@log.log
|
||||
def update_service_profile(self, context, service_profile_id,
|
||||
service_profile):
|
||||
profile = service_profile['service_profile']
|
||||
with context.session.begin(subtransactions=True):
|
||||
profile_db = self._get_service_profile(context,
|
||||
service_profile_id)
|
||||
profile_db.update(profile)
|
||||
return self._make_service_profile_dict(profile_db)
|
||||
|
||||
@log.log
|
||||
def delete_service_profile(self, context, service_profile_id):
|
||||
with context.session.begin(subtransactions=True):
|
||||
profile_db = self._get_service_profile(context,
|
||||
service_profile_id)
|
||||
if profile_db.nodes:
|
||||
raise schain.ServiceProfileInUse(
|
||||
profile_id=service_profile_id)
|
||||
context.session.delete(profile_db)
|
||||
|
||||
@log.log
|
||||
def get_service_profile(self, context, service_profile_id, fields=None):
|
||||
profile_db = self._get_service_profile(
|
||||
context, service_profile_id)
|
||||
return self._make_service_profile_dict(profile_db, fields)
|
||||
|
||||
@log.log
|
||||
def get_service_profiles(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None, marker=None,
|
||||
page_reverse=False):
|
||||
marker_obj = self._get_marker_obj(context, 'service_profile',
|
||||
limit, marker)
|
||||
return self._get_collection(context, ServiceProfile,
|
||||
self._make_service_profile_dict,
|
||||
filters=filters, fields=fields,
|
||||
sorts=sorts, limit=limit,
|
||||
marker_obj=marker_obj,
|
||||
page_reverse=page_reverse)
|
||||
|
@@ -23,6 +23,7 @@ from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
import gbpservice.neutron.extensions
|
||||
from gbpservice.neutron.services.servicechain.common import constants as scc
|
||||
|
||||
|
||||
# The code below is a monkey patch of key Neutron's modules. This is needed for
|
||||
@@ -37,6 +38,15 @@ LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# Service Chain Exceptions
|
||||
class ServiceProfileNotFound(nexc.NotFound):
|
||||
message = _("ServiceProfile %(profile_id)s could not be found")
|
||||
|
||||
|
||||
class ServiceProfileInUse(nexc.NotFound):
|
||||
message = _("Unable to complete operation, ServiceProfile "
|
||||
"%(profile_id)s is in use")
|
||||
|
||||
|
||||
class ServiceChainNodeNotFound(nexc.NotFound):
|
||||
message = _("ServiceChainNode %(sc_node_id)s could not be found")
|
||||
|
||||
@@ -94,6 +104,7 @@ attr.validators['type:string_list'] = _validate_str_list
|
||||
SERVICECHAIN_NODES = 'servicechain_nodes'
|
||||
SERVICECHAIN_SPECS = 'servicechain_specs'
|
||||
SERVICECHAIN_INSTANCES = 'servicechain_instances'
|
||||
SERVICE_PROFILES = 'service_profiles'
|
||||
|
||||
RESOURCE_ATTRIBUTE_MAP = {
|
||||
SERVICECHAIN_NODES: {
|
||||
@@ -110,8 +121,11 @@ RESOURCE_ATTRIBUTE_MAP = {
|
||||
'validate': {'type:string': None},
|
||||
'required_by_policy': True, 'is_visible': True},
|
||||
'service_type': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:string': None},
|
||||
'required': True, 'is_visible': True},
|
||||
'validate': {'type:string_or_none': None},
|
||||
'is_visible': True, 'default': None},
|
||||
'service_profile_id': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:uuid_or_none': None},
|
||||
'is_visible': True, 'default': None},
|
||||
'config': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:string': None},
|
||||
'required': True, 'is_visible': True},
|
||||
@@ -180,6 +194,37 @@ RESOURCE_ATTRIBUTE_MAP = {
|
||||
'validate': {'type:string': None},
|
||||
'default': "", 'is_visible': True},
|
||||
},
|
||||
SERVICE_PROFILES: {
|
||||
'id': {'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None}, 'is_visible': True,
|
||||
'primary_key': True},
|
||||
'name': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'default': '', 'is_visible': True},
|
||||
'description': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {'type:string': None},
|
||||
'required_by_policy': True, 'is_visible': True},
|
||||
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},
|
||||
'vendor': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'default': ''},
|
||||
'insertion_mode': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:values':
|
||||
scc.VALID_INSERTION_MODES},
|
||||
'is_visible': True, 'default': None},
|
||||
'service_type': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string': None},
|
||||
'is_visible': True, 'required': True},
|
||||
'service_flavor': {'allow_post': True, 'allow_put': True,
|
||||
'validate': {'type:string_or_none': None},
|
||||
'is_visible': True, 'default': None},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -321,3 +366,34 @@ class ServiceChainPluginBase(service_base.ServicePluginBase):
|
||||
@log.log
|
||||
def delete_servicechain_instance(self, context, servicechain_instance_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
@log.log
|
||||
def get_service_profile_count(self, context, filters=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
@log.log
|
||||
def create_service_profile(self, context, service_profile):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
@log.log
|
||||
def update_service_profile(self, context, service_profile_id,
|
||||
service_profile):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
@log.log
|
||||
def delete_service_profile(self, context, service_profile_id):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
@log.log
|
||||
def get_service_profile(self, context, service_profile_id, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
@log.log
|
||||
def get_service_profiles(self, context, filters=None, fields=None):
|
||||
pass
|
||||
|
@@ -125,7 +125,7 @@ class NonSharedNetworkOnSharedL2PolicyNotSupported(GroupPolicyBadRequest):
|
||||
|
||||
|
||||
class InvalidSharedAttributeUpdate(GroupPolicyBadRequest):
|
||||
message = _("Invalid shared attribute update. Shared resource %(id)s is"
|
||||
message = _("Invalid shared attribute update. Shared resource %(id)s is "
|
||||
"referenced by %(rid)s, which is either shared or owned by a "
|
||||
"different tenant.")
|
||||
|
||||
|
23
gbpservice/neutron/services/servicechain/common/constants.py
Normal file
23
gbpservice/neutron/services/servicechain/common/constants.py
Normal file
@@ -0,0 +1,23 @@
|
||||
# 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.
|
||||
|
||||
INSERTION_MODE_L2 = 'l2'
|
||||
INSERTION_MODE_L3 = 'l3'
|
||||
INSERTION_MODE_BITW = 'bitw'
|
||||
INSERTION_MODE_TAP = 'tap'
|
||||
INSERTION_MODE_NONE = None
|
||||
|
||||
VALID_INSERTION_MODES = [INSERTION_MODE_L2,
|
||||
INSERTION_MODE_L3,
|
||||
INSERTION_MODE_BITW,
|
||||
INSERTION_MODE_TAP,
|
||||
INSERTION_MODE_NONE]
|
@@ -24,7 +24,18 @@ class ServiceChainNodeContext(ServiceChainContext):
|
||||
original_sc_node=None):
|
||||
super(ServiceChainNodeContext, self).__init__(plugin, plugin_context)
|
||||
self._sc_node = sc_node
|
||||
self._profile = None
|
||||
if self._sc_node['service_profile_id']:
|
||||
self._profile = self._plugin.get_service_profile(
|
||||
self._plugin_context, self._sc_node['service_profile_id'])
|
||||
|
||||
self._original_sc_node = original_sc_node
|
||||
self._original_profile = None
|
||||
if (self._original_sc_node and
|
||||
self._original_sc_node['service_profile_id']):
|
||||
self._original_profile = self._plugin.get_service_profile(
|
||||
self._plugin_context,
|
||||
self._original_sc_node['service_profile_id'])
|
||||
|
||||
@property
|
||||
def current(self):
|
||||
@@ -34,6 +45,14 @@ class ServiceChainNodeContext(ServiceChainContext):
|
||||
def original(self):
|
||||
return self._original_sc_node
|
||||
|
||||
@property
|
||||
def current_profile(self):
|
||||
return self._profile
|
||||
|
||||
@property
|
||||
def original_profile(self):
|
||||
return self._original_profile
|
||||
|
||||
|
||||
class ServiceChainSpecContext(ServiceChainContext):
|
||||
|
||||
@@ -68,3 +87,20 @@ class ServiceChainInstanceContext(ServiceChainContext):
|
||||
@property
|
||||
def original(self):
|
||||
return self._original_sc_instance
|
||||
|
||||
|
||||
class ServiceProfileContext(ServiceChainContext):
|
||||
|
||||
def __init__(self, plugin, plugin_context, profile,
|
||||
original_profile=None):
|
||||
super(ServiceProfileContext, self).__init__(plugin, plugin_context)
|
||||
self._profile = profile
|
||||
self._original_profile = original_profile
|
||||
|
||||
@property
|
||||
def current(self):
|
||||
return self._profile
|
||||
|
||||
@property
|
||||
def original(self):
|
||||
return self._original_profile
|
||||
|
@@ -156,3 +156,27 @@ class DriverManager(stevedore.named.NamedExtensionManager):
|
||||
def delete_servicechain_instance_postcommit(self, context):
|
||||
self._call_on_drivers("delete_servicechain_instance_postcommit",
|
||||
context)
|
||||
|
||||
def create_service_profile_precommit(self, context):
|
||||
self._call_on_drivers("create_service_profile_precommit",
|
||||
context)
|
||||
|
||||
def create_service_profile_postcommit(self, context):
|
||||
self._call_on_drivers("create_service_profile_postcommit",
|
||||
context)
|
||||
|
||||
def update_service_profile_precommit(self, context):
|
||||
self._call_on_drivers("update_service_profile_precommit",
|
||||
context)
|
||||
|
||||
def update_service_profile_postcommit(self, context):
|
||||
self._call_on_drivers("update_service_profile_postcommit",
|
||||
context)
|
||||
|
||||
def delete_service_profile_precommit(self, context):
|
||||
self._call_on_drivers("delete_service_profile_precommit",
|
||||
context)
|
||||
|
||||
def delete_service_profile_postcommit(self, context):
|
||||
self._call_on_drivers("delete_service_profile_postcommit",
|
||||
context)
|
||||
|
@@ -90,3 +90,27 @@ class NoopDriver(object):
|
||||
@log.log
|
||||
def delete_servicechain_instance_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def create_service_profile_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def create_service_profile_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def update_service_profile_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def update_service_profile_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def delete_service_profile_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def delete_service_profile_postcommit(self, context):
|
||||
pass
|
@@ -14,7 +14,6 @@ import ast
|
||||
import time
|
||||
|
||||
from heatclient import client as heat_client
|
||||
|
||||
from heatclient import exc as heat_exc
|
||||
from neutron.common import log
|
||||
from neutron.db import model_base
|
||||
@@ -75,8 +74,12 @@ class SimpleChainDriver(object):
|
||||
|
||||
@log.log
|
||||
def create_servicechain_node_precommit(self, context):
|
||||
if context.current['service_type'] not in sc_supported_type:
|
||||
raise exc.InvalidServiceTypeForReferenceDriver()
|
||||
if context.current['service_profile_id'] is None:
|
||||
if context.current['service_type'] not in sc_supported_type:
|
||||
raise exc.InvalidServiceTypeForReferenceDriver()
|
||||
elif context.current['service_type']:
|
||||
LOG.warn(_('Both service_profile_id and service_type are'
|
||||
'specified, service_type will be ignored.'))
|
||||
|
||||
@log.log
|
||||
def create_servicechain_node_postcommit(self, context):
|
||||
@@ -168,6 +171,31 @@ class SimpleChainDriver(object):
|
||||
self._delete_servicechain_instance_stacks(context._plugin_context,
|
||||
context.current['id'])
|
||||
|
||||
@log.log
|
||||
def create_service_profile_precommit(self, context):
|
||||
if context.current['service_type'] not in sc_supported_type:
|
||||
raise exc.InvalidServiceTypeForReferenceDriver()
|
||||
|
||||
@log.log
|
||||
def create_service_profile_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def update_service_profile_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def update_service_profile_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def delete_service_profile_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def delete_service_profile_postcommit(self, context):
|
||||
pass
|
||||
|
||||
def _get_ptg(self, context, ptg_id):
|
||||
return self._get_resource(self._grouppolicy_plugin,
|
||||
context._plugin_context,
|
||||
|
@@ -240,3 +240,72 @@ class ServiceChainPlugin(servicechain_db.ServiceChainDbPlugin,
|
||||
LOG.exception(_("delete_servicechain_instance_postcommit failed "
|
||||
"for servicechain_instance %s"),
|
||||
servicechain_instance_id)
|
||||
|
||||
@log.log
|
||||
def create_service_profile(self, context, service_profile):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
result = super(ServiceChainPlugin,
|
||||
self).create_service_profile(
|
||||
context, service_profile)
|
||||
self._validate_shared_create(context, result, 'service_profile')
|
||||
sc_context = servicechain_context.ServiceProfileContext(
|
||||
self, context, result)
|
||||
self.driver_manager.create_service_profile_precommit(
|
||||
sc_context)
|
||||
|
||||
try:
|
||||
self.driver_manager.create_service_profile_postcommit(
|
||||
sc_context)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_(
|
||||
"driver_manager.create_service_profile_postcommit "
|
||||
"failed, deleting service_profile %s"),
|
||||
result['id'])
|
||||
self.delete_service_profile(context, result['id'])
|
||||
|
||||
return result
|
||||
|
||||
@log.log
|
||||
def update_service_profile(self, context, service_profile_id,
|
||||
service_profile):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
original_profile = self.get_service_profile(
|
||||
context, service_profile_id)
|
||||
updated_profile = super(ServiceChainPlugin,
|
||||
self).update_service_profile(
|
||||
context, service_profile_id, service_profile)
|
||||
self._validate_shared_update(context, original_profile,
|
||||
updated_profile, 'service_profile')
|
||||
sc_context = servicechain_context.ServiceProfileContext(
|
||||
self, context, updated_profile,
|
||||
original_profile=original_profile)
|
||||
self.driver_manager.update_service_profile_precommit(
|
||||
sc_context)
|
||||
|
||||
self.driver_manager.update_service_profile_postcommit(
|
||||
sc_context)
|
||||
return updated_profile
|
||||
|
||||
@log.log
|
||||
def delete_service_profile(self, context, service_profile_id):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
profile = self.get_service_profile(
|
||||
context, service_profile_id)
|
||||
sc_context = servicechain_context.ServiceProfileContext(
|
||||
self, context, profile)
|
||||
self.driver_manager.delete_service_profile_precommit(
|
||||
sc_context)
|
||||
super(ServiceChainPlugin, self).delete_service_profile(
|
||||
context, service_profile_id)
|
||||
|
||||
try:
|
||||
self.driver_manager.delete_service_profile_postcommit(
|
||||
sc_context)
|
||||
except Exception:
|
||||
LOG.exception(_("delete_service_profile_postcommit failed "
|
||||
"for service_profile %s"),
|
||||
service_profile_id)
|
||||
|
@@ -30,8 +30,11 @@ class SharingMixin(object):
|
||||
|
||||
usage_graph = {'servicechain_spec': {'nodes':
|
||||
'servicechain_node'},
|
||||
'servicechain_node': {},
|
||||
'servicechain_instance': {}}
|
||||
'servicechain_node': {'service_profile_id':
|
||||
'service_profile'},
|
||||
'servicechain_instance': {},
|
||||
'service_profile': {},
|
||||
}
|
||||
_plurals = None
|
||||
|
||||
@property
|
||||
@@ -72,3 +75,7 @@ class SharingMixin(object):
|
||||
gbp_plugin.GroupPolicyPlugin._check_shared_or_different_tenant(
|
||||
context, obj, self.gbp_plugin.get_policy_actions, 'action_value',
|
||||
[obj['id']])
|
||||
|
||||
def _validate_service_profile_unshare(self, context, obj):
|
||||
gbp_plugin.GroupPolicyPlugin._check_shared_or_different_tenant(
|
||||
context, obj, self.get_servicechain_nodes, 'service_profile_id')
|
||||
|
@@ -19,6 +19,7 @@
|
||||
"shared_nsp": "field:network_service_policies:shared=True",
|
||||
"shared_scn": "field:servicechain_nodes:shared=True",
|
||||
"shared_scs": "field:servicechain_specs:shared=True",
|
||||
"shared_sp": "field:service_profiles:shared=True",
|
||||
|
||||
"create_policy_target_group": "",
|
||||
"get_policy_target_group": "rule:admin_or_owner or rule:shared_ptg",
|
||||
@@ -65,5 +66,10 @@
|
||||
|
||||
"create_servicechain_instance": "",
|
||||
"get_servicechain_instance": "rule:admin_or_owner",
|
||||
"update_servicechain_instance:shared": "rule:admin_only"
|
||||
"update_servicechain_instance:shared": "rule:admin_only",
|
||||
|
||||
"create_service_profile": "",
|
||||
"create_service_profile:shared": "rule:admin_only",
|
||||
"get_service_profile": "rule:admin_or_owner or rule:shared_sp",
|
||||
"update_service_profile:shared": "rule:admin_only"
|
||||
}
|
||||
|
@@ -293,6 +293,27 @@ def get_update_nat_pool_attrs():
|
||||
return {'name': 'new_name'}
|
||||
|
||||
|
||||
@gbp_attributes
|
||||
def get_create_service_profile_default_attrs():
|
||||
return {'name': '', 'description': ''}
|
||||
|
||||
|
||||
@gbp_attributes
|
||||
def get_create_service_profile_attrs():
|
||||
return {
|
||||
'name': 'serviceprofile1',
|
||||
'service_type': 'FIREWALL',
|
||||
'description': 'test service profile',
|
||||
}
|
||||
|
||||
|
||||
@gbp_attributes
|
||||
def get_update_service_profile_attrs():
|
||||
return {
|
||||
'name': 'new_name',
|
||||
}
|
||||
|
||||
|
||||
def get_resource_plural(resource):
|
||||
if resource.endswith('y'):
|
||||
resource_plural = resource.replace('y', 'ies')
|
||||
|
@@ -15,6 +15,8 @@ import webob.exc
|
||||
|
||||
from neutron.api import extensions
|
||||
from neutron import context
|
||||
from neutron.db import api as db_api
|
||||
from neutron.db import model_base
|
||||
from neutron.openstack.common import uuidutils
|
||||
from neutron.plugins.common import constants
|
||||
from neutron.tests.unit.api import test_extensions
|
||||
@@ -23,6 +25,7 @@ from oslo_utils import importutils
|
||||
|
||||
from gbpservice.neutron.db import servicechain_db as svcchain_db
|
||||
from gbpservice.neutron.extensions import servicechain as service_chain
|
||||
from gbpservice.neutron.services.servicechain.common import constants as sccon
|
||||
|
||||
JSON_FORMAT = 'json'
|
||||
|
||||
@@ -55,12 +58,24 @@ class ServiceChainDBTestBase(object):
|
||||
self.assertEqual(sorted([i['id'] for i in res[resource_plural]]),
|
||||
sorted([i[resource]['id'] for i in items]))
|
||||
|
||||
def _get_test_servicechain_node_attrs(self, name='scn1',
|
||||
description='test scn',
|
||||
service_type=constants.FIREWALL,
|
||||
config="{}", shared=False):
|
||||
def _get_test_service_profile_attrs(
|
||||
self, name='sp1', description='test sp',
|
||||
service_type=constants.LOADBALANCER, vendor='',
|
||||
insertion_mode=sccon.INSERTION_MODE_L3, service_flavor=''):
|
||||
attrs = {'name': name, 'description': description,
|
||||
'service_type': service_type,
|
||||
'vendor': vendor, 'insertion_mode': insertion_mode,
|
||||
'service_flavor': service_flavor,
|
||||
'tenant_id': self._tenant_id}
|
||||
|
||||
return attrs
|
||||
|
||||
def _get_test_servicechain_node_attrs(self, name='scn1',
|
||||
description='test scn',
|
||||
service_profile_id=None,
|
||||
config="{}", shared=False):
|
||||
attrs = {'name': name, 'description': description,
|
||||
'service_profile_id': service_profile_id,
|
||||
'config': config,
|
||||
'tenant_id': self._tenant_id,
|
||||
'shared': shared}
|
||||
@@ -96,13 +111,38 @@ class ServiceChainDBTestBase(object):
|
||||
|
||||
return attrs
|
||||
|
||||
def create_servicechain_node(self, service_type=constants.FIREWALL,
|
||||
def create_service_profile(self, service_type=constants.FIREWALL,
|
||||
insertion_mode=sccon.INSERTION_MODE_L3,
|
||||
vendor='', service_flavor='',
|
||||
expected_res_status=None, **kwargs):
|
||||
defaults = {'name': 'sp1', 'description': 'test sp'}
|
||||
defaults.update(kwargs)
|
||||
data = {'service_profile': {'service_type': service_type,
|
||||
'service_flavor': service_flavor,
|
||||
'tenant_id': self._tenant_id,
|
||||
'insertion_mode': insertion_mode,
|
||||
'vendor': vendor}}
|
||||
data['service_profile'].update(defaults)
|
||||
|
||||
scn_req = self.new_create_request('service_profiles', data, self.fmt)
|
||||
scn_res = scn_req.get_response(self.ext_api)
|
||||
|
||||
if expected_res_status:
|
||||
self.assertEqual(scn_res.status_int, expected_res_status)
|
||||
elif scn_res.status_int >= webob.exc.HTTPClientError.code:
|
||||
raise webob.exc.HTTPClientError(code=scn_res.status_int)
|
||||
|
||||
scn = self.deserialize(self.fmt, scn_res)
|
||||
|
||||
return scn
|
||||
|
||||
def create_servicechain_node(self, service_profile_id=None,
|
||||
config="{}", expected_res_status=None,
|
||||
**kwargs):
|
||||
defaults = {'name': 'scn1', 'description': 'test scn', 'shared': False}
|
||||
defaults.update(kwargs)
|
||||
|
||||
data = {'servicechain_node': {'service_type': service_type,
|
||||
data = {'servicechain_node': {'service_profile_id': service_profile_id,
|
||||
'tenant_id': self._tenant_id,
|
||||
'config': config}}
|
||||
data['servicechain_node'].update(defaults)
|
||||
@@ -142,7 +182,9 @@ class ServiceChainDBTestBase(object):
|
||||
|
||||
def test_create_servicechain_specs_same_node(self):
|
||||
template1 = '{"key1":"value1"}'
|
||||
scn = self.create_servicechain_node(config=template1)
|
||||
sp = self.create_service_profile()['service_profile']
|
||||
scn = self.create_servicechain_node(
|
||||
config=template1, service_profile_id=sp['id'])
|
||||
scn_id = scn['servicechain_node']['id']
|
||||
spec1 = {"servicechain_spec": {'name': 'scs1',
|
||||
'tenant_id': self._tenant_id,
|
||||
@@ -198,6 +240,16 @@ class ServiceChainDBTestBase(object):
|
||||
|
||||
return sci
|
||||
|
||||
def _create_profiled_servicechain_node(
|
||||
self, service_type=constants.LOADBALANCER, shared_profile=False,
|
||||
profile_tenant_id=None, **kwargs):
|
||||
prof = self.create_service_profile(
|
||||
service_type=service_type,
|
||||
shared=shared_profile,
|
||||
tenant_id=profile_tenant_id or self._tenant_id)['service_profile']
|
||||
return self.create_servicechain_node(
|
||||
service_profile_id=prof['id'], **kwargs)
|
||||
|
||||
|
||||
class ServiceChainDBTestPlugin(svcchain_db.ServiceChainDbPlugin):
|
||||
|
||||
@@ -230,6 +282,8 @@ class ServiceChainDbTestCase(ServiceChainDBTestBase,
|
||||
if not ext_mgr:
|
||||
ext_mgr = extensions.PluginAwareExtensionManager.get_instance()
|
||||
self.ext_api = test_extensions.setup_extensions_middleware(ext_mgr)
|
||||
engine = db_api.get_engine()
|
||||
model_base.BASEV2.metadata.create_all(engine)
|
||||
|
||||
|
||||
class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
@@ -245,11 +299,14 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
self.assertEqual(v, res[resource][k])
|
||||
|
||||
def test_create_and_show_servicechain_node(self):
|
||||
profile = self.create_service_profile()
|
||||
attrs = self._get_test_servicechain_node_attrs(
|
||||
service_type=constants.LOADBALANCER)
|
||||
service_profile_id=profile['service_profile']['id'],
|
||||
config="config1")
|
||||
|
||||
scn = self.create_servicechain_node(
|
||||
service_type=constants.LOADBALANCER)
|
||||
service_profile_id=profile['service_profile']['id'],
|
||||
config="config1")
|
||||
|
||||
for k, v in attrs.iteritems():
|
||||
self.assertEqual(v, scn['servicechain_node'][k])
|
||||
@@ -259,19 +316,26 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
attrs)
|
||||
|
||||
def test_list_servicechain_nodes(self):
|
||||
scns = [self.create_servicechain_node(name='scn1', description='scn'),
|
||||
self.create_servicechain_node(name='scn2', description='scn'),
|
||||
self.create_servicechain_node(name='scn3', description='scn')]
|
||||
scns = [
|
||||
self._create_profiled_servicechain_node(name='scn1',
|
||||
description='scn'),
|
||||
self._create_profiled_servicechain_node(name='scn2',
|
||||
description='scn'),
|
||||
self._create_profiled_servicechain_node(name='scn3',
|
||||
description='scn')]
|
||||
self._test_list_resources('servicechain_node', scns,
|
||||
query_params='description=scn')
|
||||
|
||||
def test_update_servicechain_node(self):
|
||||
name = 'new_servicechain_node'
|
||||
description = 'new desc'
|
||||
attrs = self._get_test_servicechain_node_attrs(name=name,
|
||||
description=description)
|
||||
profile = self.create_service_profile()
|
||||
attrs = self._get_test_servicechain_node_attrs(
|
||||
name=name, description=description,
|
||||
service_profile_id=profile['service_profile']['id'])
|
||||
|
||||
scn = self.create_servicechain_node()
|
||||
scn = self.create_servicechain_node(
|
||||
service_profile_id=profile['service_profile']['id'])
|
||||
|
||||
data = {'servicechain_node': {'name': name,
|
||||
'description': description}}
|
||||
@@ -289,7 +353,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
def test_delete_servicechain_node(self):
|
||||
ctx = context.get_admin_context()
|
||||
|
||||
scn = self.create_servicechain_node()
|
||||
scn = self._create_profiled_servicechain_node()
|
||||
scn_id = scn['servicechain_node']['id']
|
||||
|
||||
scs = self.create_servicechain_spec(nodes=[scn_id])
|
||||
@@ -313,7 +377,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
|
||||
def test_create_and_show_servicechain_spec(self):
|
||||
name = "scs1"
|
||||
scn = self.create_servicechain_node()
|
||||
scn = self._create_profiled_servicechain_node()
|
||||
scn_id = scn['servicechain_node']['id']
|
||||
|
||||
attrs = self._get_test_servicechain_spec_attrs(name, nodes=[scn_id])
|
||||
@@ -329,9 +393,9 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
|
||||
def test_create_spec_multiple_nodes(self):
|
||||
name = "scs1"
|
||||
scn1 = self.create_servicechain_node()
|
||||
scn1 = self._create_profiled_servicechain_node()
|
||||
scn1_id = scn1['servicechain_node']['id']
|
||||
scn2 = self.create_servicechain_node()
|
||||
scn2 = self._create_profiled_servicechain_node()
|
||||
scn2_id = scn2['servicechain_node']['id']
|
||||
attrs = self._get_test_servicechain_spec_attrs(
|
||||
name, nodes=[scn1_id, scn2_id])
|
||||
@@ -348,8 +412,10 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
query_params='description=scs')
|
||||
|
||||
def test_node_ordering_list_servicechain_specs(self):
|
||||
scn1_id = self.create_servicechain_node()['servicechain_node']['id']
|
||||
scn2_id = self.create_servicechain_node()['servicechain_node']['id']
|
||||
scn1_id = self._create_profiled_servicechain_node()[
|
||||
'servicechain_node']['id']
|
||||
scn2_id = self._create_profiled_servicechain_node()[
|
||||
'servicechain_node']['id']
|
||||
nodes_list = [scn1_id, scn2_id]
|
||||
scs = self.create_servicechain_spec(name='scs1',
|
||||
nodes=nodes_list)
|
||||
@@ -376,7 +442,8 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
def test_update_servicechain_spec(self):
|
||||
name = "new_servicechain_spec1"
|
||||
description = 'new desc'
|
||||
scn_id = self.create_servicechain_node()['servicechain_node']['id']
|
||||
scn_id = self._create_profiled_servicechain_node()[
|
||||
'servicechain_node']['id']
|
||||
attrs = self._get_test_servicechain_spec_attrs(name=name,
|
||||
description=description,
|
||||
nodes=[scn_id])
|
||||
@@ -558,3 +625,69 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
self.assertRaises(service_chain.ServiceChainInstanceNotFound,
|
||||
self.plugin.get_servicechain_instance,
|
||||
ctx, sci_id)
|
||||
|
||||
def test_create_and_show_service_profile(self):
|
||||
attrs = self._get_test_service_profile_attrs(
|
||||
service_type=constants.FIREWALL, vendor="vendor1")
|
||||
|
||||
scn = self.create_service_profile(
|
||||
service_type=constants.FIREWALL, vendor="vendor1")
|
||||
|
||||
for k, v in attrs.iteritems():
|
||||
self.assertEqual(scn['service_profile'][k], v)
|
||||
|
||||
self._test_show_resource('service_profile',
|
||||
scn['service_profile']['id'], attrs)
|
||||
|
||||
def test_list_service_profile(self):
|
||||
scns = [self.create_service_profile(name='sp1', description='sp'),
|
||||
self.create_service_profile(name='sp2', description='sp'),
|
||||
self.create_service_profile(name='sp3', description='sp')]
|
||||
self._test_list_resources('service_profile', scns,
|
||||
query_params='description=sp')
|
||||
|
||||
def test_update_service_profile(self):
|
||||
name = 'new_service_profile'
|
||||
description = 'new desc'
|
||||
attrs = self._get_test_service_profile_attrs(
|
||||
name=name, description=description,
|
||||
service_type=constants.FIREWALL)
|
||||
|
||||
scn = self.create_service_profile()
|
||||
|
||||
data = {'service_profile': {'name': name,
|
||||
'description': description}}
|
||||
req = self.new_update_request('service_profiles', data,
|
||||
scn['service_profile']['id'])
|
||||
res = self.deserialize(self.fmt, req.get_response(self.ext_api))
|
||||
|
||||
for k, v in attrs.iteritems():
|
||||
self.assertEqual(res['service_profile'][k], v)
|
||||
|
||||
self._test_show_resource('service_profile',
|
||||
scn['service_profile']['id'], attrs)
|
||||
|
||||
def test_delete_service_profile(self):
|
||||
ctx = context.get_admin_context()
|
||||
|
||||
sp = self.create_service_profile()
|
||||
sp_id = sp['service_profile']['id']
|
||||
|
||||
scn = self.create_servicechain_node(service_profile_id=sp_id)
|
||||
scn_id = scn['servicechain_node']['id']
|
||||
|
||||
# Deleting Service Chain Node in use by a Spec should fail
|
||||
self.assertRaises(service_chain.ServiceProfileInUse,
|
||||
self.plugin.delete_service_profile, ctx, sp_id)
|
||||
|
||||
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)
|
||||
|
||||
# After deleting the Service Chain Spec, node delete should succeed
|
||||
req = self.new_delete_request('service_profiles', sp_id)
|
||||
res = req.get_response(self.ext_api)
|
||||
self.assertEqual(res.status_int, webob.exc.HTTPNoContent.code)
|
||||
self.assertRaises(service_chain.ServiceProfileNotFound,
|
||||
self.plugin.get_service_profile,
|
||||
ctx, sp_id)
|
||||
|
@@ -42,6 +42,7 @@ from gbpservice.neutron.tests.unit.services.grouppolicy import (
|
||||
test_grouppolicy_plugin as test_plugin)
|
||||
|
||||
|
||||
SERVICE_PROFILES = 'servicechain/service_profiles'
|
||||
SERVICECHAIN_NODES = 'servicechain/servicechain_nodes'
|
||||
SERVICECHAIN_SPECS = 'servicechain/servicechain_specs'
|
||||
SERVICECHAIN_INSTANCES = 'servicechain/servicechain_instances'
|
||||
@@ -1479,8 +1480,17 @@ class TestPolicyRuleSet(ResourceMappingTestCase):
|
||||
|
||||
self._verify_prs_rules(policy_rule_set_id)
|
||||
|
||||
def _create_service_profile(self, node_type='LOADBALANCER'):
|
||||
data = {'service_profile': {'service_type': node_type,
|
||||
'tenant_id': self._tenant_id}}
|
||||
scn_req = self.new_create_request(SERVICE_PROFILES, data, self.fmt)
|
||||
node = self.deserialize(self.fmt, scn_req.get_response(self.ext_api))
|
||||
scn_id = node['service_profile']['id']
|
||||
return scn_id
|
||||
|
||||
def _create_servicechain_node(self, node_type="LOADBALANCER"):
|
||||
data = {'servicechain_node': {'service_type': node_type,
|
||||
profile_id = self._create_service_profile(node_type)
|
||||
data = {'servicechain_node': {'service_profile_id': profile_id,
|
||||
'tenant_id': self._tenant_id,
|
||||
'config': "{}"}}
|
||||
scn_req = self.new_create_request(SERVICECHAIN_NODES, data, self.fmt)
|
||||
@@ -1623,12 +1633,19 @@ class TestPolicyRuleSet(ResourceMappingTestCase):
|
||||
self._assert_proper_chain_instance(sc_instance, provider_ptg_id,
|
||||
consumer_ptg_id, [scs_id])
|
||||
|
||||
data = {'servicechain_node': {'service_type': "FIREWALL",
|
||||
data = {'service_profile': {'service_type': "FIREWALL",
|
||||
'tenant_id': self._tenant_id}}
|
||||
service_profile = self.new_create_request(SERVICE_PROFILES,
|
||||
data, self.fmt)
|
||||
service_profile = self.deserialize(
|
||||
self.fmt, service_profile.get_response(self.ext_api))
|
||||
sp_id = service_profile['service_profile']['id']
|
||||
data = {'servicechain_node': {'service_profile_id': sp_id,
|
||||
'tenant_id': self._tenant_id,
|
||||
'config': "{}"}}
|
||||
scn_req = self.new_create_request(SERVICECHAIN_NODES, data, self.fmt)
|
||||
new_node = self.deserialize(
|
||||
self.fmt, scn_req.get_response(self.ext_api))
|
||||
self.fmt, scn_req.get_response(self.ext_api))
|
||||
new_scn_id = new_node['servicechain_node']['id']
|
||||
data = {'servicechain_spec': {'tenant_id': self._tenant_id,
|
||||
'nodes': [new_scn_id]}}
|
||||
@@ -1856,7 +1873,14 @@ class TestPolicyRuleSet(ResourceMappingTestCase):
|
||||
child_prs_id = child_prs['policy_rule_set']['id']
|
||||
|
||||
self._verify_prs_rules(child_prs_id)
|
||||
data = {'servicechain_node': {'service_type': "FIREWALL",
|
||||
data = {'service_profile': {'service_type': "FIREWALL",
|
||||
'tenant_id': self._tenant_id}}
|
||||
service_profile = self.new_create_request(SERVICE_PROFILES,
|
||||
data, self.fmt)
|
||||
service_profile = self.deserialize(
|
||||
self.fmt, service_profile.get_response(self.ext_api))
|
||||
sp_id = service_profile['service_profile']['id']
|
||||
data = {'servicechain_node': {'service_profile_id': sp_id,
|
||||
'tenant_id': self._tenant_id,
|
||||
'config': "{}"}}
|
||||
parent_scn_req = self.new_create_request(SERVICECHAIN_NODES,
|
||||
|
@@ -11,8 +11,10 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from neutron import context as n_ctx
|
||||
from oslo_config import cfg
|
||||
|
||||
from gbpservice.neutron.services.servicechain.plugins.msc import context
|
||||
from gbpservice.neutron.tests.unit.db.grouppolicy import (
|
||||
test_servicechain_db as test_servicechain_db)
|
||||
|
||||
@@ -37,4 +39,158 @@ class ServiceChainPluginTestCase(test_servicechain_db.ServiceChainDbTestCase):
|
||||
class TestGroupPolicyPluginGroupResources(
|
||||
ServiceChainPluginTestCase,
|
||||
test_servicechain_db.TestServiceChainResources):
|
||||
pass
|
||||
|
||||
def test_spec_shared(self):
|
||||
# Shared spec can only point shared nodes
|
||||
node = self._create_profiled_servicechain_node(
|
||||
'LOADBALANCER', shared=True, shared_profile=True,
|
||||
profile_tenant_id='admin', tenant_id='admin')['servicechain_node']
|
||||
self.create_servicechain_spec(nodes=[node['id']], shared=True,
|
||||
expected_res_status=201)
|
||||
self.create_servicechain_spec(nodes=[node['id']], shared=False,
|
||||
tenant_id='admin',
|
||||
expected_res_status=201)
|
||||
|
||||
node = self._create_profiled_servicechain_node(
|
||||
'LOADBALANCER', shared=False, profile_tenant_id='nonadmin',
|
||||
tenant_id='nonadmin')['servicechain_node']
|
||||
self.create_servicechain_spec(nodes=[node['id']], shared=True,
|
||||
expected_res_status=400)
|
||||
self.create_servicechain_spec(nodes=[node['id']], shared=True,
|
||||
tenant_id='nonadmin',
|
||||
expected_res_status=400)
|
||||
self.create_servicechain_spec(nodes=[node['id']], shared=False,
|
||||
tenant_id='nonadmin',
|
||||
expected_res_status=201)
|
||||
|
||||
def test_node_shared(self):
|
||||
# Shared node can only point shared profile
|
||||
prof = self.create_service_profile(
|
||||
service_type='LOADBALANCER', shared=True,
|
||||
tenant_id='admin')['service_profile']
|
||||
to_update = self.create_servicechain_node(
|
||||
service_profile_id=prof['id'], shared=True,
|
||||
expected_res_status=201)['servicechain_node']
|
||||
self.create_servicechain_node(
|
||||
service_profile_id=prof['id'], shared=False, tenant_id='admin',
|
||||
expected_res_status=201)
|
||||
|
||||
prof = self.create_service_profile(
|
||||
service_type='LOADBALANCER', shared=False,
|
||||
tenant_id='admin')['service_profile']
|
||||
self.create_servicechain_node(
|
||||
service_profile_id=prof['id'], shared=True,
|
||||
expected_res_status=400)
|
||||
self.create_servicechain_node(
|
||||
service_profile_id=prof['id'], shared=True,
|
||||
tenant_id='admin', expected_res_status=400)
|
||||
self.create_servicechain_node(
|
||||
service_profile_id=prof['id'], shared=False,
|
||||
tenant_id='admin', expected_res_status=201)
|
||||
|
||||
self.create_servicechain_spec(nodes=[to_update['id']], shared=True,
|
||||
tenant_id='nonadmin',
|
||||
expected_res_status=201)
|
||||
|
||||
data = {'servicechain_node': {'shared': False}}
|
||||
req = self.new_update_request('servicechain_nodes', data,
|
||||
to_update['id'])
|
||||
res = req.get_response(self.ext_api)
|
||||
self.assertEqual(400, res.status_int)
|
||||
res = self.deserialize(self.fmt, res)
|
||||
self.assertEqual('InvalidSharedAttributeUpdate',
|
||||
res['NeutronError']['type'])
|
||||
|
||||
def test_profile_shared(self):
|
||||
prof = self.create_service_profile(
|
||||
service_type='LOADBALANCER', shared=True,
|
||||
tenant_id='admin')['service_profile']
|
||||
self.create_servicechain_node(
|
||||
service_profile_id=prof['id'], shared=True,
|
||||
expected_res_status=201)
|
||||
|
||||
data = {'service_profile': {'shared': False}}
|
||||
req = self.new_update_request('service_profiles', data,
|
||||
prof['id'])
|
||||
res = req.get_response(self.ext_api)
|
||||
self.assertEqual(400, res.status_int)
|
||||
res = self.deserialize(self.fmt, res)
|
||||
self.assertEqual('InvalidSharedAttributeUpdate',
|
||||
res['NeutronError']['type'])
|
||||
|
||||
prof = self.create_service_profile(
|
||||
service_type='LOADBALANCER', shared=False)['service_profile']
|
||||
self.create_servicechain_node(
|
||||
service_profile_id=prof['id'], shared=False,
|
||||
expected_res_status=201)
|
||||
|
||||
data = {'service_profile': {'shared': True}}
|
||||
req = self.new_update_request('service_profiles', data,
|
||||
prof['id'])
|
||||
res = req.get_response(self.ext_api)
|
||||
self.assertEqual(200, res.status_int)
|
||||
res = self.deserialize(self.fmt, res)
|
||||
self.assertTrue(res['service_profile']['shared'])
|
||||
|
||||
def test_node_context_profile(self):
|
||||
|
||||
# Current node with profile
|
||||
plugin_context = n_ctx.get_admin_context()
|
||||
plugin_context.is_admin = plugin_context.is_advsvc = False
|
||||
plugin_context.tenant_id = 'test-tenant'
|
||||
|
||||
prof = self.create_service_profile(
|
||||
service_type='LOADBALANCER')['service_profile']
|
||||
current = self.create_servicechain_node(
|
||||
service_profile_id=prof['id'],
|
||||
expected_res_status=201)['servicechain_node']
|
||||
ctx = context.ServiceChainNodeContext(self.plugin, plugin_context,
|
||||
current)
|
||||
|
||||
self.assertIsNone(ctx.original)
|
||||
self.assertIsNone(ctx.original_profile)
|
||||
self.assertEqual(ctx.current['id'], current['id'])
|
||||
self.assertEqual(ctx.current_profile['id'], prof['id'])
|
||||
|
||||
# Original node with profile
|
||||
|
||||
prof2 = self.create_service_profile(
|
||||
service_type='LOADBALANCER')['service_profile']
|
||||
original = self.create_servicechain_node(
|
||||
service_profile_id=prof2['id'],
|
||||
expected_res_status=201)['servicechain_node']
|
||||
ctx = context.ServiceChainNodeContext(self.plugin, plugin_context,
|
||||
current, original)
|
||||
|
||||
self.assertEqual(ctx.original['id'], original['id'])
|
||||
self.assertEqual(ctx.original_profile['id'], prof2['id'])
|
||||
self.assertEqual(ctx.current['id'], current['id'])
|
||||
self.assertEqual(ctx.current_profile['id'], prof['id'])
|
||||
|
||||
def test_node_context_no_profile(self):
|
||||
|
||||
plugin_context = n_ctx.get_admin_context()
|
||||
plugin_context.is_admin = plugin_context.is_advsvc = False
|
||||
plugin_context.tenant_id = 'test_tenant'
|
||||
|
||||
current = self.create_servicechain_node(
|
||||
service_type='TEST',
|
||||
expected_res_status=201)['servicechain_node']
|
||||
ctx = context.ServiceChainNodeContext(self.plugin, plugin_context,
|
||||
current)
|
||||
|
||||
self.assertIsNone(ctx.original)
|
||||
self.assertIsNone(ctx.original_profile)
|
||||
self.assertEqual(ctx.current['id'], current['id'])
|
||||
self.assertIsNone(ctx.current_profile)
|
||||
|
||||
original = self.create_servicechain_node(
|
||||
service_type='TEST',
|
||||
expected_res_status=201)['servicechain_node']
|
||||
ctx = context.ServiceChainNodeContext(self.plugin, plugin_context,
|
||||
current, original)
|
||||
|
||||
self.assertEqual(ctx.original['id'], original['id'])
|
||||
self.assertIsNone(ctx.original_profile)
|
||||
self.assertEqual(ctx.current['id'], current['id'])
|
||||
self.assertIsNone(ctx.current_profile)
|
||||
|
@@ -69,27 +69,32 @@ class SimpleChainDriverTestCase(
|
||||
class TestServiceChainInstance(SimpleChainDriverTestCase):
|
||||
|
||||
def test_invalid_service_type_rejected(self):
|
||||
res = self.create_servicechain_node(
|
||||
service_type="test", config='{}',
|
||||
res = self.create_service_profile(
|
||||
service_type="test",
|
||||
expected_res_status=webob.exc.HTTPBadRequest.code)
|
||||
self.assertEqual('InvalidServiceTypeForReferenceDriver',
|
||||
res['NeutronError']['type'])
|
||||
|
||||
def test_chain_node_create_success(self):
|
||||
res = self.create_servicechain_node(
|
||||
res = self._create_profiled_servicechain_node(
|
||||
service_type=constants.FIREWALL, config='{}',
|
||||
expected_res_status=webob.exc.HTTPCreated.code)
|
||||
self.assertEqual(constants.FIREWALL,
|
||||
res['servicechain_node']['service_type'])
|
||||
self.assertEqual('{}', res['servicechain_node']['config'])
|
||||
|
||||
def test_chain_node_create_success_service_type(self):
|
||||
res = self.create_servicechain_node(
|
||||
service_type=constants.FIREWALL, config='{}',
|
||||
expected_res_status=webob.exc.HTTPCreated.code)
|
||||
self.assertEqual('{}', res['servicechain_node']['config'])
|
||||
|
||||
def test_chain_spec_update(self):
|
||||
template1 = '{"key1":"value1"}'
|
||||
scn = self.create_servicechain_node(config=template1)
|
||||
scn = self._create_profiled_servicechain_node(config=template1)
|
||||
scn1_name = scn['servicechain_node']['name']
|
||||
scn_id = scn['servicechain_node']['id']
|
||||
name = "scs1"
|
||||
template2 = '{"key2":"value2"}'
|
||||
scn2 = self.create_servicechain_node(config=template2)
|
||||
scn2 = self._create_profiled_servicechain_node(config=template2)
|
||||
scn2_id = scn2['servicechain_node']['id']
|
||||
scn2_name = scn2['servicechain_node']['name']
|
||||
scs = self.create_servicechain_spec(name=name, nodes=[scn_id])
|
||||
@@ -159,7 +164,7 @@ class TestServiceChainInstance(SimpleChainDriverTestCase):
|
||||
|
||||
def test_chain_instance_create(self):
|
||||
name = "scs1"
|
||||
scn = self.create_servicechain_node()
|
||||
scn = self._create_profiled_servicechain_node()
|
||||
scn_id = scn['servicechain_node']['id']
|
||||
scs = self.create_servicechain_spec(name=name, nodes=[scn_id])
|
||||
sc_spec_id = scs['servicechain_spec']['id']
|
||||
@@ -183,7 +188,7 @@ class TestServiceChainInstance(SimpleChainDriverTestCase):
|
||||
|
||||
def test_chain_instance_delete(self):
|
||||
name = "scs1"
|
||||
scn = self.create_servicechain_node()
|
||||
scn = self._create_profiled_servicechain_node()
|
||||
scn_id = scn['servicechain_node']['id']
|
||||
scs = self.create_servicechain_spec(name=name, nodes=[scn_id])
|
||||
sc_spec_id = scs['servicechain_spec']['id']
|
||||
@@ -207,7 +212,7 @@ class TestServiceChainInstance(SimpleChainDriverTestCase):
|
||||
|
||||
def test_wait_stack_delete_for_instance_delete(self):
|
||||
name = "scs1"
|
||||
scn = self.create_servicechain_node()
|
||||
scn = self._create_profiled_servicechain_node()
|
||||
scn_id = scn['servicechain_node']['id']
|
||||
scs = self.create_servicechain_spec(name=name, nodes=[scn_id])
|
||||
sc_spec_id = scs['servicechain_spec']['id']
|
||||
@@ -266,7 +271,7 @@ class TestServiceChainInstance(SimpleChainDriverTestCase):
|
||||
|
||||
def test_stack_not_found_ignored(self):
|
||||
name = "scs1"
|
||||
scn = self.create_servicechain_node()
|
||||
scn = self._create_profiled_servicechain_node()
|
||||
scn_id = scn['servicechain_node']['id']
|
||||
scs = self.create_servicechain_spec(name=name, nodes=[scn_id])
|
||||
sc_spec_id = scs['servicechain_spec']['id']
|
||||
|
@@ -31,6 +31,7 @@ SERVICECHAIN_URI = 'servicechain'
|
||||
SERVICECHAIN_NODES_URI = SERVICECHAIN_URI + '/' + 'servicechain_nodes'
|
||||
SERVICECHAIN_SPECS_URI = SERVICECHAIN_URI + '/' + 'servicechain_specs'
|
||||
SERVICECHAIN_INSTANCES_URI = SERVICECHAIN_URI + '/' + 'servicechain_instances'
|
||||
SERVICE_PROFILE_URI = SERVICECHAIN_URI + '/' + 'service_profiles'
|
||||
|
||||
|
||||
class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
@@ -73,11 +74,12 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
def _get_create_servicechain_node_attrs(self):
|
||||
return {
|
||||
'name': 'servicechain1',
|
||||
'service_type': 'FIREWALL',
|
||||
'service_profile_id': _uuid(),
|
||||
'tenant_id': _uuid(),
|
||||
'description': 'test servicechain node',
|
||||
'config': 'test_config',
|
||||
'shared': True
|
||||
'shared': True,
|
||||
'service_type': None,
|
||||
}
|
||||
|
||||
def _get_update_servicechain_node_attrs(self):
|
||||
@@ -89,9 +91,10 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
servicechain_node_id = _uuid()
|
||||
data = {
|
||||
'servicechain_node': {
|
||||
'service_type': 'FIREWALL',
|
||||
'service_profile_id': _uuid(),
|
||||
'tenant_id': _uuid(),
|
||||
'config': 'test_config'
|
||||
'config': 'test_config',
|
||||
'service_type': None,
|
||||
}
|
||||
}
|
||||
default_attrs = self._get_create_servicechain_node_default_attrs()
|
||||
|
Reference in New Issue
Block a user