node composition plugin architecture
The Node Composition Plugin (NCP) is introduced here in its most simple form: The interaction with the Node Drivers is still completely missing. This patch is intended to collect the whole internal API between the NCP and the Node Drivers, taking also into account the new NodeDriverContext. Partially implements blueprint node-centric-chain-plugin Change-Id: I0f791d2be8b5ef5d9bf7a297e0dbdc0248350edd
This commit is contained in:
parent
2527cdd688
commit
657306d199
@ -85,8 +85,8 @@ class PolicyTargetGroupInUse(GroupPolicyBadRequest):
|
||||
|
||||
class InvalidPortForPTG(GroupPolicyBadRequest):
|
||||
message = _("Subnet %(port_subnet_id)s of port %(port_id)s does not "
|
||||
"match subnet %(ptg_subnet_id)s of Policy Target Group "
|
||||
"%(policy_target_group_id)s.")
|
||||
"match subnet %(ptg_subnet_id)s of Policy Target Group "
|
||||
"%(policy_target_group_id)s.")
|
||||
|
||||
|
||||
class InvalidSubnetForPTG(GroupPolicyBadRequest):
|
||||
|
@ -461,10 +461,22 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
|
||||
context, policy_target_group_id)
|
||||
pt_ids = policy_target_group['policy_targets']
|
||||
for pt in self.get_policy_targets(context, {'id': pt_ids}):
|
||||
if pt['port_id']:
|
||||
if self._is_port_bound(pt['port_id']):
|
||||
if pt['port_id'] and self._is_port_bound(pt['port_id']):
|
||||
raise gp_exc.PolicyTargetGroupInUse(
|
||||
policy_target_group=policy_target_group_id)
|
||||
policy_context = p_context.PolicyTargetGroupContext(
|
||||
self, context, policy_target_group)
|
||||
self.policy_driver_manager.delete_policy_target_group_precommit(
|
||||
policy_context)
|
||||
|
||||
# Disassociate all the PRSs first, this will trigger service chains
|
||||
# deletion.
|
||||
self.update_policy_target_group(
|
||||
context, policy_target_group_id,
|
||||
{'policy_target_group': {'provided_policy_rule_sets': {},
|
||||
'consumed_policy_rule_sets': {}}})
|
||||
|
||||
with session.begin(subtransactions=True):
|
||||
for pt_id in pt_ids:
|
||||
# We will allow PTG deletion if all PTs are unused.
|
||||
# We could have cleaned these opportunistically in
|
||||
@ -472,10 +484,6 @@ class GroupPolicyPlugin(group_policy_mapping_db.GroupPolicyMappingDbPlugin):
|
||||
# such that either all unused PTs are deleted
|
||||
# or nothing is.
|
||||
self.delete_policy_target(context, pt_id)
|
||||
policy_context = p_context.PolicyTargetGroupContext(
|
||||
self, context, policy_target_group)
|
||||
self.policy_driver_manager.delete_policy_target_group_precommit(
|
||||
policy_context)
|
||||
super(GroupPolicyPlugin, self).delete_policy_target_group(
|
||||
context, policy_target_group_id)
|
||||
|
||||
|
@ -0,0 +1,26 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_config import cfg
|
||||
|
||||
|
||||
service_chain_opts = [
|
||||
cfg.ListOpt('node_drivers',
|
||||
default=['node_dummy'],
|
||||
help=_("An ordered list of service chain node drivers "
|
||||
"entrypoints to be loaded from the "
|
||||
"gbpservice.neutron.servicechain.ncp_drivers "
|
||||
"namespace."))
|
||||
]
|
||||
|
||||
|
||||
cfg.CONF.register_opts(service_chain_opts, "node_composition_plugin")
|
177
gbpservice/neutron/services/servicechain/plugins/ncp/context.py
Normal file
177
gbpservice/neutron/services/servicechain/plugins/ncp/context.py
Normal file
@ -0,0 +1,177 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from neutron import context as n_context
|
||||
from neutron import manager
|
||||
from neutron.plugins.common import constants as pconst
|
||||
|
||||
from gbpservice.neutron.extensions import group_policy
|
||||
|
||||
|
||||
def get_gbp_plugin():
|
||||
return manager.NeutronManager.get_service_plugins().get("GROUP_POLICY")
|
||||
|
||||
|
||||
def get_node_driver_context(sc_plugin, context, sc_instance,
|
||||
current_node, original_node=None,
|
||||
management_group=None, service_targets=None):
|
||||
specs = sc_plugin.get_servicechain_specs(
|
||||
context, filters={'id': sc_instance['servicechain_specs']})
|
||||
provider = _ptg_or_ep(context, sc_instance['provider_ptg_id'])
|
||||
consumer = _ptg_or_ep(context, sc_instance['consumer_ptg_id'])
|
||||
current_profile = sc_plugin.get_service_profile(
|
||||
context, current_node['service_profile_id'])
|
||||
original_profile = sc_plugin.get_service_profile(
|
||||
context,
|
||||
original_node['service_profile_id']) if original_node else None
|
||||
return NodeDriverContext(sc_plugin=sc_plugin,
|
||||
context=context,
|
||||
service_chain_instance=sc_instance,
|
||||
service_chain_specs=specs,
|
||||
current_service_chain_node=current_node,
|
||||
current_service_profile=current_profile,
|
||||
provider_group=provider,
|
||||
consumer_group=consumer,
|
||||
management_group=management_group,
|
||||
original_service_chain_node=original_node,
|
||||
original_service_profile=original_profile,
|
||||
service_targets=service_targets)
|
||||
|
||||
|
||||
def _ptg_or_ep(context, group_id):
|
||||
group = None
|
||||
if group_id:
|
||||
try:
|
||||
group = get_gbp_plugin().get_policy_target_group(context, group_id)
|
||||
except group_policy.PolicyTargetGroupNotFound:
|
||||
# Could be EP
|
||||
context.session.rollback()
|
||||
group = get_gbp_plugin().get_external_policy(context, group_id)
|
||||
return group
|
||||
|
||||
|
||||
class NodeDriverContext(object):
|
||||
""" Context passed down to NCC Node Drivers."""
|
||||
|
||||
def __init__(self, sc_plugin, context, service_chain_instance,
|
||||
service_chain_specs, current_service_chain_node,
|
||||
current_service_profile, provider_group, consumer_group=None,
|
||||
management_group=None, original_service_chain_node=None,
|
||||
original_service_profile=None, service_targets=None):
|
||||
self._gbp_plugin = get_gbp_plugin()
|
||||
self._sc_plugin = sc_plugin
|
||||
self._plugin_context = context
|
||||
self._admin_context = None
|
||||
self._service_chain_instance = service_chain_instance
|
||||
self._current_service_chain_node = current_service_chain_node
|
||||
self._current_service_profile = current_service_profile
|
||||
self._original_service_chain_node = original_service_chain_node
|
||||
self._original_service_profile = original_service_profile
|
||||
self._service_targets = service_targets
|
||||
self._service_chain_specs = service_chain_specs
|
||||
self._provider_group = provider_group
|
||||
self._consumer_group = consumer_group
|
||||
self._management_group = management_group
|
||||
self._relevant_specs = None
|
||||
self._core_plugin = manager.NeutronManager.get_plugin()
|
||||
self._l3_plugin = manager.NeutronManager.get_service_plugins().get(
|
||||
pconst.L3_ROUTER_NAT)
|
||||
|
||||
@property
|
||||
def gbp_plugin(self):
|
||||
return self._gbp_plugin
|
||||
|
||||
@property
|
||||
def sc_plugin(self):
|
||||
return self._sc_plugin
|
||||
|
||||
@property
|
||||
def core_plugin(self):
|
||||
return self._core_plugin
|
||||
|
||||
@property
|
||||
def l3_plugin(self):
|
||||
return self._l3_plugin
|
||||
|
||||
@property
|
||||
def plugin_context(self):
|
||||
return self._plugin_context
|
||||
|
||||
@property
|
||||
def plugin_session(self):
|
||||
return self._plugin_context.session
|
||||
|
||||
@property
|
||||
def session(self):
|
||||
return self.plugin_session
|
||||
|
||||
@property
|
||||
def admin_context(self):
|
||||
if not self._admin_context:
|
||||
self._admin_context = n_context.get_admin_context()
|
||||
return self._admin_context
|
||||
|
||||
@property
|
||||
def admin_session(self):
|
||||
return self.admin_context.session
|
||||
|
||||
@property
|
||||
def instance(self):
|
||||
return self._service_chain_instance
|
||||
|
||||
@property
|
||||
def current_node(self):
|
||||
return self._current_service_chain_node
|
||||
|
||||
@property
|
||||
def current_profile(self):
|
||||
return self._current_service_profile
|
||||
|
||||
@property
|
||||
def original_node(self):
|
||||
return self._original_service_chain_node
|
||||
|
||||
@property
|
||||
def original_profile(self):
|
||||
return self._original_service_profile
|
||||
|
||||
@property
|
||||
def relevant_specs(self):
|
||||
"""Get specs on the SCI containing this particular Node."""
|
||||
if not self._relevant_specs:
|
||||
self._relevant_specs = [x for x in self._service_chain_specs if
|
||||
self.current_node['id'] in x['nodes']]
|
||||
return self._relevant_specs
|
||||
|
||||
@property
|
||||
def service_targets(self):
|
||||
""" Returns the service targets assigned for this service if any.
|
||||
The result looks like the following:
|
||||
{
|
||||
"provider": [pt_uuids],
|
||||
"consumer": [pt_uuids],
|
||||
"management": [pt_uuids],
|
||||
}
|
||||
"""
|
||||
return self._service_targets
|
||||
|
||||
@property
|
||||
def provider(self):
|
||||
return self._provider_group
|
||||
|
||||
@property
|
||||
def consumer(self):
|
||||
return self._consumer_group
|
||||
|
||||
@property
|
||||
def management(self):
|
||||
return self._management_group
|
@ -0,0 +1,145 @@
|
||||
# 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.
|
||||
|
||||
import abc
|
||||
import six
|
||||
|
||||
|
||||
@six.add_metaclass(abc.ABCMeta)
|
||||
class NodeDriverBase(object):
|
||||
"""Node Driver Base class for Node Composition Plugin (NCP).
|
||||
|
||||
A Node Driver is the fundamental unit of the NCP service chain plugin.
|
||||
It is invoked every time an operation has to be executed on Service Node
|
||||
instances (eg. services that are part of a deployed chain)
|
||||
which the Node Driver is capable of deploy, destroy and update.
|
||||
The Node Driver may expose resource needs to the NCP plugin, that will
|
||||
make sure that the NodeDriverContext is enriched with all that's needed by
|
||||
the driver.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def initialize(self):
|
||||
"""Perform driver initialization.
|
||||
|
||||
Called after all drivers have been loaded and the database has
|
||||
been initialized. No abstract methods defined below will be
|
||||
called prior to this method being called.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_plumbing_info(self, context):
|
||||
""" Tells the NCP Plugin which kind of plumbing is needed by the Node.
|
||||
|
||||
The plumbing info is defined as a collection of needed policy targets
|
||||
on a specific role, this may vary based on the node
|
||||
(obtained from the NodeDriverContext) that the specific driver is asked
|
||||
to deploy. An example of plumbing info is the following:
|
||||
|
||||
{
|
||||
"management": <list of updated PT body dicts, one for each needed>,
|
||||
"provider": <list of updated PT body dicts, one for each needed>,
|
||||
"consumer": <list of updated PT body dicts, one for each needed>
|
||||
}
|
||||
|
||||
The role (key of the above dictionary) specifies in which "side" the
|
||||
policy target has to exist. Depending on the kind of chaining the
|
||||
Neutron port could actually be placed somewhere else! The value
|
||||
is a list of attributes intended to override the PT body. This could
|
||||
be used, for example, for providing explicit Neutron Ports when the
|
||||
driver requires it or for establishing a naming convention for the PTs.
|
||||
An empty dictionary will be mostly used in this case, which will
|
||||
indicate a basic PT creation:
|
||||
|
||||
{
|
||||
"management": [{}], # One PT needed in the management
|
||||
"provider": [{}, {port_id: 'a'}], # Two PT needed in the provider
|
||||
"consumer": [] # Zero PT needed in the consumer
|
||||
}
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def validate_create(self, context):
|
||||
"""Validate whether a SCN can be processed or not for creation.
|
||||
|
||||
This method is intended as a indicative measure of whether the NCP
|
||||
plugin should use this specific driver for scheduling a given node.
|
||||
A successful validation is a prerequisite but doesn't guarantee that
|
||||
this driver will ultimately be chosen.
|
||||
|
||||
:param context: NodeDriverContext instance describing the service chain
|
||||
and the specific node to be processed by this driver.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def validate_update(self, context):
|
||||
"""Validate whether a SCN can be processed or not.
|
||||
|
||||
This method will be called whenever a specific Node owned by this
|
||||
driver needs to be updated. It should be used to verify whether the
|
||||
Driver is capable of enforcing the update or not.
|
||||
|
||||
:param context: NodeDriverContext instance describing the service chain
|
||||
and the specific node to be processed by this driver.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def create(self, context):
|
||||
"""Instantiate a Service Chain Node based on the chain context.
|
||||
|
||||
This method will be called at Service Chain instantiation time by the
|
||||
NCP plugin. Every scheduled Node Driver will be assigned a Node of the
|
||||
chain that has to be deployed based on the node definition and the
|
||||
service chain context. The same driver could be called multiple times
|
||||
on different nodes of the same chain.
|
||||
The datapath is expected to work according to the user intent at the
|
||||
end of the chain instantiation.
|
||||
|
||||
:param context: NodeDriverContext instance describing the service chain
|
||||
and the specific node to be processed by this driver.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete(self, context):
|
||||
"""Destroy a deployed Service Chain Node.
|
||||
|
||||
This method will be called when a Service Chain Instance is destroyed
|
||||
or in case of node rescheduling. The driver is expected to undeploy the
|
||||
specific node and free the owned resources. Freeing the resources
|
||||
created by the NCP plugin as a consequence of the plumbing_info
|
||||
method belongs to the NCP plugin, and it is in charge of disposing
|
||||
them if needed.
|
||||
|
||||
:param context: NodeDriverContext instance describing the service chain
|
||||
and the specific node to be processed by this driver.
|
||||
"""
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update(self, context):
|
||||
"""Update a deployed Service Chain Node.
|
||||
|
||||
Some changes in the Service Chain Node could need modifications in all
|
||||
its instances. This method will be used in order to synchronize the
|
||||
service configuration with the user expectation.
|
||||
The original node definition is provided in the context in order to
|
||||
calculate the difference if needed.
|
||||
|
||||
:param context: NodeDriverContext instance describing the service chain
|
||||
and the specific node to be processed by this driver.
|
||||
"""
|
||||
pass
|
@ -0,0 +1,57 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
import stevedore
|
||||
|
||||
from gbpservice.neutron.services.servicechain.plugins.ncp import config # noqa
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NodeDriverManager(stevedore.named.NamedExtensionManager):
|
||||
"""Route servicechain APIs to servicechain node drivers.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# Registered node drivers, keyed by name.
|
||||
self.drivers = {}
|
||||
# Ordered list of node drivers.
|
||||
self.ordered_drivers = []
|
||||
names = cfg.CONF.node_composition_plugin.node_drivers
|
||||
LOG.info(_("Configured service chain node driver names: %s"), names)
|
||||
super(NodeDriverManager,
|
||||
self).__init__(
|
||||
'gbpservice.neutron.servicechain.ncp_drivers', names,
|
||||
invoke_on_load=True, name_order=True)
|
||||
LOG.info(_("Loaded service chain node driver names: %s"), self.names())
|
||||
self._register_drivers()
|
||||
|
||||
def _register_drivers(self):
|
||||
"""Register all service chain node drivers."""
|
||||
for ext in self:
|
||||
self.drivers[ext.name] = ext
|
||||
self.ordered_drivers.append(ext)
|
||||
LOG.info(_("Registered service chain node drivers: %s"),
|
||||
[driver.name for driver in self.ordered_drivers])
|
||||
|
||||
def initialize(self):
|
||||
"""Initialize all the service chain node drivers."""
|
||||
self.native_bulk_support = True
|
||||
for driver in self.ordered_drivers:
|
||||
LOG.info(_("Initializing service chain node drivers '%s'"),
|
||||
driver.name)
|
||||
driver.obj.initialize()
|
||||
self.native_bulk_support &= getattr(driver.obj,
|
||||
'native_bulk_support', True)
|
@ -0,0 +1,48 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from neutron.common import log
|
||||
|
||||
from gbpservice.neutron.services.servicechain.plugins.ncp import driver_base
|
||||
|
||||
|
||||
class NoopNodeDriver(driver_base.NodeDriverBase):
|
||||
|
||||
initialized = False
|
||||
|
||||
@log.log
|
||||
def initialize(self):
|
||||
self.initialized = True
|
||||
|
||||
@log.log
|
||||
def get_plumbing_info(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def validate_create(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def validate_update(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def create(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def delete(self, context):
|
||||
pass
|
||||
|
||||
@log.log
|
||||
def update(self, context):
|
||||
pass
|
@ -0,0 +1,32 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from gbpservice.neutron.db import servicechain_db
|
||||
from gbpservice.neutron.services.servicechain.plugins.ncp import (
|
||||
node_driver_manager as manager)
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class NodeCompositionPlugin(servicechain_db.ServiceChainDbPlugin):
|
||||
|
||||
"""Implementation of the Service Chain Plugin.
|
||||
|
||||
"""
|
||||
supported_extension_aliases = ["servicechain"]
|
||||
|
||||
def __init__(self):
|
||||
self.driver_manager = manager.NodeDriverManager()
|
||||
super(NodeCompositionPlugin, self).__init__()
|
||||
self.driver_manager.initialize()
|
@ -293,6 +293,7 @@ def get_update_nat_pool_attrs():
|
||||
return {'name': 'new_name'}
|
||||
|
||||
|
||||
# Service Chain
|
||||
@gbp_attributes
|
||||
def get_create_service_profile_default_attrs():
|
||||
return {'name': '', 'description': ''}
|
||||
@ -314,6 +315,92 @@ def get_update_service_profile_attrs():
|
||||
}
|
||||
|
||||
|
||||
@gbp_attributes
|
||||
def get_create_servicechain_node_default_attrs():
|
||||
return {
|
||||
'name': '',
|
||||
'description': '',
|
||||
'config': '{}',
|
||||
'service_type': None,
|
||||
'shared': False,
|
||||
}
|
||||
|
||||
|
||||
@gbp_attributes
|
||||
def get_create_servicechain_node_attrs():
|
||||
return {
|
||||
'name': 'servicechain1',
|
||||
'service_profile_id': _uuid(),
|
||||
'tenant_id': _uuid(),
|
||||
'description': 'test servicechain node',
|
||||
'config': '{}',
|
||||
'service_type': None,
|
||||
'shared': True,
|
||||
}
|
||||
|
||||
|
||||
@gbp_attributes
|
||||
def get_update_servicechain_node_attrs():
|
||||
return {
|
||||
'name': 'new_name',
|
||||
}
|
||||
|
||||
|
||||
@gbp_attributes
|
||||
def get_create_servicechain_spec_default_attrs():
|
||||
return {
|
||||
'name': '',
|
||||
'description': '',
|
||||
'nodes': [],
|
||||
'shared': False,
|
||||
}
|
||||
|
||||
|
||||
@gbp_attributes
|
||||
def get_create_servicechain_spec_attrs():
|
||||
return {
|
||||
'name': 'servicechainspec1',
|
||||
'nodes': [_uuid(), _uuid()],
|
||||
'tenant_id': _uuid(),
|
||||
'description': 'test servicechain spec',
|
||||
'shared': True,
|
||||
}
|
||||
|
||||
|
||||
@gbp_attributes
|
||||
def get_update_servicechain_spec_attrs():
|
||||
return {
|
||||
'name': 'new_name',
|
||||
'nodes': [_uuid()]
|
||||
}
|
||||
|
||||
|
||||
@gbp_attributes
|
||||
def get_create_servicechain_instance_default_attrs():
|
||||
return {'name': '', 'description': '', 'config_param_values': "{}"}
|
||||
|
||||
|
||||
@gbp_attributes
|
||||
def get_create_servicechain_instance_attrs():
|
||||
return {
|
||||
'name': 'servicechaininstance1',
|
||||
'servicechain_specs': [_uuid()],
|
||||
'tenant_id': _uuid(),
|
||||
'provider_ptg_id': _uuid(),
|
||||
'consumer_ptg_id': _uuid(),
|
||||
'classifier_id': _uuid(),
|
||||
'config_param_values': "{}",
|
||||
'description': 'test servicechain instance'
|
||||
}
|
||||
|
||||
|
||||
def get_update_servicechain_instance_attrs():
|
||||
return {
|
||||
'name': 'new_name',
|
||||
'servicechain_specs': [_uuid()]
|
||||
}
|
||||
|
||||
|
||||
def get_resource_plural(resource):
|
||||
if resource.endswith('y'):
|
||||
resource_plural = resource.replace('y', 'ies')
|
||||
|
@ -37,52 +37,7 @@ TESTDIR = os.path.dirname(os.path.abspath(gbpservice.neutron.tests.__file__))
|
||||
ETCDIR = os.path.join(TESTDIR, 'etc')
|
||||
|
||||
|
||||
class GroupPolicyDBTestBase(object):
|
||||
resource_prefix_map = dict(
|
||||
(k, constants.COMMON_PREFIXES[constants.GROUP_POLICY])
|
||||
for k in gpolicy.RESOURCE_ATTRIBUTE_MAP.keys()
|
||||
)
|
||||
|
||||
fmt = JSON_FORMAT
|
||||
|
||||
def __getattr__(self, item):
|
||||
# Verify is an update of a proper GBP object
|
||||
def _is_gbp_resource(plural):
|
||||
return plural in gpolicy.RESOURCE_ATTRIBUTE_MAP
|
||||
# Update Method
|
||||
if item.startswith('update_'):
|
||||
resource = item[len('update_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_gbp_resource(plural):
|
||||
def update_wrapper(id, **kwargs):
|
||||
return self._update_gbp_resource(id, resource, **kwargs)
|
||||
return update_wrapper
|
||||
# Show Method
|
||||
if item.startswith('show_'):
|
||||
resource = item[len('show_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_gbp_resource(plural):
|
||||
def show_wrapper(id, **kwargs):
|
||||
return self._show_gbp_resource(id, plural, **kwargs)
|
||||
return show_wrapper
|
||||
# Create Method
|
||||
if item.startswith('create_'):
|
||||
resource = item[len('create_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_gbp_resource(plural):
|
||||
def create_wrapper(**kwargs):
|
||||
return self._create_gbp_resource(resource, **kwargs)
|
||||
return create_wrapper
|
||||
# Delete Method
|
||||
if item.startswith('delete_'):
|
||||
resource = item[len('delete_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_gbp_resource(plural):
|
||||
def delete_wrapper(id, **kwargs):
|
||||
return self._delete_gbp_resource(id, plural, **kwargs)
|
||||
return delete_wrapper
|
||||
|
||||
raise AttributeError
|
||||
class ApiManagerMixin(object):
|
||||
|
||||
def _test_list_resources(self, resource, items,
|
||||
neutron_context=None,
|
||||
@ -96,8 +51,8 @@ class GroupPolicyDBTestBase(object):
|
||||
self.assertEqual(sorted([i['id'] for i in res[resource_plural]]),
|
||||
sorted([i[resource]['id'] for i in items]))
|
||||
|
||||
def _create_gbp_resource(self, type, expected_res_status=None,
|
||||
is_admin_context=False, **kwargs):
|
||||
def _create_resource(self, type, expected_res_status=None,
|
||||
is_admin_context=False, **kwargs):
|
||||
plural = cm.get_resource_plural(type)
|
||||
defaults = getattr(cm,
|
||||
'get_create_%s_default_attrs' % type)()
|
||||
@ -119,7 +74,7 @@ class GroupPolicyDBTestBase(object):
|
||||
|
||||
return self.deserialize(self.fmt, res)
|
||||
|
||||
def _update_gbp_resource(
|
||||
def _update_resource(
|
||||
self, id, type, expected_res_status=None, is_admin_context=False,
|
||||
**kwargs):
|
||||
plural = cm.get_resource_plural(type)
|
||||
@ -138,8 +93,8 @@ class GroupPolicyDBTestBase(object):
|
||||
raise webob.exc.HTTPClientError(code=res.status_int)
|
||||
return self.deserialize(self.fmt, res)
|
||||
|
||||
def _show_gbp_resource(self, id, plural, expected_res_status=None,
|
||||
is_admin_context=False, tenant_id=None):
|
||||
def _show_resource(self, id, plural, expected_res_status=None,
|
||||
is_admin_context=False, tenant_id=None):
|
||||
req = self.new_show_request(plural, id, fmt=self.fmt)
|
||||
req.environ['neutron.context'] = context.Context(
|
||||
'', tenant_id or self._tenant_id, is_admin_context)
|
||||
@ -151,8 +106,8 @@ class GroupPolicyDBTestBase(object):
|
||||
raise webob.exc.HTTPClientError(code=res.status_int)
|
||||
return self.deserialize(self.fmt, res)
|
||||
|
||||
def _delete_gbp_resource(self, id, plural, is_admin_context=False,
|
||||
expected_res_status=None, tenant_id=None):
|
||||
def _delete_resource(self, id, plural, is_admin_context=False,
|
||||
expected_res_status=None, tenant_id=None):
|
||||
req = self.new_delete_request(plural, id)
|
||||
req.environ['neutron.context'] = context.Context(
|
||||
'', tenant_id or self._tenant_id, is_admin_context)
|
||||
@ -161,6 +116,56 @@ class GroupPolicyDBTestBase(object):
|
||||
self.assertEqual(res.status_int, expected_res_status)
|
||||
elif res.status_int >= webob.exc.HTTPClientError.code:
|
||||
raise webob.exc.HTTPClientError(code=res.status_int)
|
||||
if res.status_int != 204:
|
||||
return self.deserialize(self.fmt, res)
|
||||
|
||||
|
||||
class GroupPolicyDBTestBase(ApiManagerMixin):
|
||||
resource_prefix_map = dict(
|
||||
(k, constants.COMMON_PREFIXES[constants.GROUP_POLICY])
|
||||
for k in gpolicy.RESOURCE_ATTRIBUTE_MAP.keys()
|
||||
)
|
||||
|
||||
fmt = JSON_FORMAT
|
||||
|
||||
def __getattr__(self, item):
|
||||
# Verify is an update of a proper GBP object
|
||||
def _is_gbp_resource(plural):
|
||||
return plural in gpolicy.RESOURCE_ATTRIBUTE_MAP
|
||||
# Update Method
|
||||
if item.startswith('update_'):
|
||||
resource = item[len('update_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_gbp_resource(plural):
|
||||
def update_wrapper(id, **kwargs):
|
||||
return self._update_resource(id, resource, **kwargs)
|
||||
return update_wrapper
|
||||
# Show Method
|
||||
if item.startswith('show_'):
|
||||
resource = item[len('show_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_gbp_resource(plural):
|
||||
def show_wrapper(id, **kwargs):
|
||||
return self._show_resource(id, plural, **kwargs)
|
||||
return show_wrapper
|
||||
# Create Method
|
||||
if item.startswith('create_'):
|
||||
resource = item[len('create_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_gbp_resource(plural):
|
||||
def create_wrapper(**kwargs):
|
||||
return self._create_resource(resource, **kwargs)
|
||||
return create_wrapper
|
||||
# Delete Method
|
||||
if item.startswith('delete_'):
|
||||
resource = item[len('delete_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_gbp_resource(plural):
|
||||
def delete_wrapper(id, **kwargs):
|
||||
return self._delete_resource(id, plural, **kwargs)
|
||||
return delete_wrapper
|
||||
|
||||
raise AttributeError
|
||||
|
||||
|
||||
class GroupPolicyDBTestPlugin(gpdb.GroupPolicyDbPlugin):
|
||||
@ -1115,7 +1120,7 @@ class TestGroupResources(GroupPolicyDbTestCase):
|
||||
|
||||
def _test_create_and_show(self, type, attrs, expected=None):
|
||||
plural = cm.get_resource_plural(type)
|
||||
res = self._create_gbp_resource(type, None, False, **attrs)
|
||||
res = self._create_resource(type, None, False, **attrs)
|
||||
expected = expected or attrs
|
||||
for k, v in expected.iteritems():
|
||||
self.assertEqual(v, res[type][k])
|
||||
|
@ -24,20 +24,71 @@ from neutron.tests.unit.db import test_db_base_plugin_v2
|
||||
from oslo_utils import importutils
|
||||
|
||||
from gbpservice.neutron.db import servicechain_db as svcchain_db
|
||||
from gbpservice.neutron.extensions import group_policy as gpolicy
|
||||
from gbpservice.neutron.extensions import servicechain as service_chain
|
||||
from gbpservice.neutron.services.servicechain.common import constants as sccon
|
||||
from gbpservice.neutron.tests.unit import common as cm
|
||||
from gbpservice.neutron.tests.unit.db.grouppolicy import test_group_policy_db
|
||||
|
||||
JSON_FORMAT = 'json'
|
||||
|
||||
|
||||
class ServiceChainDBTestBase(object):
|
||||
class ServiceChainDBTestBase(test_group_policy_db.ApiManagerMixin):
|
||||
resource_prefix_map = dict(
|
||||
(k, constants.COMMON_PREFIXES[constants.SERVICECHAIN])
|
||||
for k in service_chain.RESOURCE_ATTRIBUTE_MAP.keys()
|
||||
)
|
||||
for k in service_chain.RESOURCE_ATTRIBUTE_MAP.keys())
|
||||
resource_prefix_map.update(dict(
|
||||
(k, constants.COMMON_PREFIXES[constants.GROUP_POLICY])
|
||||
for k in gpolicy.RESOURCE_ATTRIBUTE_MAP.keys()
|
||||
))
|
||||
|
||||
fmt = JSON_FORMAT
|
||||
|
||||
def __getattr__(self, item):
|
||||
# Verify is an update of a proper GBP object
|
||||
|
||||
def _is_sc_resource(plural):
|
||||
return plural in service_chain.RESOURCE_ATTRIBUTE_MAP
|
||||
|
||||
def _is_gbp_resource(plural):
|
||||
return plural in gpolicy.RESOURCE_ATTRIBUTE_MAP
|
||||
|
||||
def _is_valid_resource(plural):
|
||||
return _is_gbp_resource(plural) or _is_sc_resource(plural)
|
||||
# Update Method
|
||||
if item.startswith('update_'):
|
||||
resource = item[len('update_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_valid_resource(plural):
|
||||
def update_wrapper(id, **kwargs):
|
||||
return self._update_resource(id, resource, **kwargs)
|
||||
return update_wrapper
|
||||
# Show Method
|
||||
if item.startswith('show_'):
|
||||
resource = item[len('show_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_valid_resource(plural):
|
||||
def show_wrapper(id, **kwargs):
|
||||
return self._show_resource(id, plural, **kwargs)
|
||||
return show_wrapper
|
||||
# Create Method
|
||||
if item.startswith('create_'):
|
||||
resource = item[len('create_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_valid_resource(plural):
|
||||
def create_wrapper(**kwargs):
|
||||
return self._create_resource(resource, **kwargs)
|
||||
return create_wrapper
|
||||
# Delete Method
|
||||
if item.startswith('delete_'):
|
||||
resource = item[len('delete_'):]
|
||||
plural = cm.get_resource_plural(resource)
|
||||
if _is_valid_resource(plural):
|
||||
def delete_wrapper(id, **kwargs):
|
||||
return self._delete_resource(id, plural, **kwargs)
|
||||
return delete_wrapper
|
||||
|
||||
raise AttributeError
|
||||
|
||||
def _get_resource_plural(self, resource):
|
||||
if resource.endswith('y'):
|
||||
resource_plural = resource.replace('y', 'ies')
|
||||
@ -58,188 +109,6 @@ 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_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}
|
||||
|
||||
return attrs
|
||||
|
||||
def _get_test_servicechain_spec_attrs(self, name='scs1',
|
||||
description='test scs',
|
||||
nodes=None, shared=False):
|
||||
node_ids = []
|
||||
if nodes:
|
||||
node_ids = [node_id for node_id in nodes]
|
||||
attrs = {'name': name, 'description': description,
|
||||
'tenant_id': self._tenant_id,
|
||||
'nodes': node_ids, 'shared': shared}
|
||||
|
||||
return attrs
|
||||
|
||||
def _get_test_servicechain_instance_attrs(self, name='sci1',
|
||||
description='test sci',
|
||||
config_param_values="{}",
|
||||
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_specs': servicechain_specs,
|
||||
'provider_ptg_id': provider_ptg_id,
|
||||
'consumer_ptg_id': consumer_ptg_id,
|
||||
'classifier_id': classifier_id}
|
||||
|
||||
return attrs
|
||||
|
||||
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_profile_id': service_profile_id,
|
||||
'tenant_id': self._tenant_id,
|
||||
'config': config}}
|
||||
data['servicechain_node'].update(defaults)
|
||||
|
||||
scn_req = self.new_create_request('servicechain_nodes', 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_spec(self, nodes=None, expected_res_status=None,
|
||||
**kwargs):
|
||||
defaults = {'name': 'scs1', 'description': 'test scs', 'shared': False}
|
||||
defaults.update(kwargs)
|
||||
|
||||
data = {'servicechain_spec': {'tenant_id': self._tenant_id,
|
||||
'nodes': nodes}}
|
||||
data['servicechain_spec'].update(defaults)
|
||||
|
||||
scs_req = self.new_create_request('servicechain_specs', data, self.fmt)
|
||||
scs_res = scs_req.get_response(self.ext_api)
|
||||
|
||||
if expected_res_status:
|
||||
self.assertEqual(expected_res_status, scs_res.status_int)
|
||||
elif scs_res.status_int >= webob.exc.HTTPClientError.code:
|
||||
raise webob.exc.HTTPClientError(code=scs_res.status_int)
|
||||
|
||||
scs = self.deserialize(self.fmt, scs_res)
|
||||
|
||||
return scs
|
||||
|
||||
def test_create_servicechain_specs_same_node(self):
|
||||
template1 = '{"key1":"value1"}'
|
||||
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,
|
||||
'nodes': [scn_id]}}
|
||||
spec_req = self.new_create_request('servicechain_specs',
|
||||
spec1,
|
||||
self.fmt)
|
||||
spec_res = spec_req.get_response(self.ext_api)
|
||||
self.assertEqual(webob.exc.HTTPCreated.code, spec_res.status_int)
|
||||
res = self.deserialize(self.fmt, spec_res)
|
||||
self.assertIn('servicechain_spec', res)
|
||||
self.assertEqual([scn_id], res['servicechain_spec']['nodes'])
|
||||
spec2 = {"servicechain_spec": {'name': 'scs2',
|
||||
'tenant_id': self._tenant_id,
|
||||
'nodes': [scn_id]}}
|
||||
spec_req = self.new_create_request('servicechain_specs',
|
||||
spec2,
|
||||
self.fmt)
|
||||
spec_res = spec_req.get_response(self.ext_api)
|
||||
self.assertEqual(webob.exc.HTTPCreated.code, spec_res.status_int)
|
||||
res = self.deserialize(self.fmt, spec_res)
|
||||
self.assertIn('servicechain_spec', res)
|
||||
self.assertEqual([scn_id], res['servicechain_spec']['nodes'])
|
||||
|
||||
def create_servicechain_instance(self, servicechain_specs=[],
|
||||
config_param_values=
|
||||
'{"key": "value"}',
|
||||
provider_ptg_id=None,
|
||||
consumer_ptg_id=None,
|
||||
classifier_id=None,
|
||||
expected_res_status=None, **kwargs):
|
||||
defaults = {'name': 'sci1', 'description': 'test sci'}
|
||||
defaults.update(kwargs)
|
||||
data = {'servicechain_instance':
|
||||
{'config_param_values': config_param_values,
|
||||
'servicechain_specs': servicechain_specs,
|
||||
'tenant_id': self._tenant_id,
|
||||
'provider_ptg_id': provider_ptg_id,
|
||||
'consumer_ptg_id': consumer_ptg_id,
|
||||
'classifier_id': classifier_id}}
|
||||
data['servicechain_instance'].update(defaults)
|
||||
|
||||
sci_req = self.new_create_request('servicechain_instances',
|
||||
data, self.fmt)
|
||||
sci_res = sci_req.get_response(self.ext_api)
|
||||
|
||||
if expected_res_status:
|
||||
self.assertEqual(expected_res_status, sci_res.status_int)
|
||||
elif sci_res.status_int >= webob.exc.HTTPClientError.code:
|
||||
raise webob.exc.HTTPClientError(code=sci_res.status_int)
|
||||
|
||||
sci = self.deserialize(self.fmt, sci_res)
|
||||
|
||||
return sci
|
||||
|
||||
def _create_profiled_servicechain_node(
|
||||
self, service_type=constants.LOADBALANCER, shared_profile=False,
|
||||
profile_tenant_id=None, **kwargs):
|
||||
@ -267,11 +136,11 @@ class ServiceChainDbTestCase(ServiceChainDBTestBase,
|
||||
test_db_base_plugin_v2.NeutronDbPluginV2TestCase):
|
||||
|
||||
def setUp(self, core_plugin=None, sc_plugin=None, service_plugins=None,
|
||||
ext_mgr=None):
|
||||
ext_mgr=None, gp_plugin=None):
|
||||
if not sc_plugin:
|
||||
sc_plugin = DB_GP_PLUGIN_KLASS
|
||||
if not service_plugins:
|
||||
service_plugins = {'gp_plugin_name': GP_PLUGIN_KLASS,
|
||||
service_plugins = {'gp_plugin_name': gp_plugin or GP_PLUGIN_KLASS,
|
||||
'sc_plugin_name': sc_plugin}
|
||||
|
||||
super(ServiceChainDbTestCase, self).setUp(
|
||||
@ -285,6 +154,36 @@ class ServiceChainDbTestCase(ServiceChainDBTestBase,
|
||||
engine = db_api.get_engine()
|
||||
model_base.BASEV2.metadata.create_all(engine)
|
||||
|
||||
def test_create_servicechain_specs_same_node(self):
|
||||
template1 = '{"key1":"value1"}'
|
||||
sp = self.create_service_profile(
|
||||
service_type=constants.FIREWALL)['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,
|
||||
'nodes': [scn_id]}}
|
||||
spec_req = self.new_create_request('servicechain_specs',
|
||||
spec1,
|
||||
self.fmt)
|
||||
spec_res = spec_req.get_response(self.ext_api)
|
||||
self.assertEqual(webob.exc.HTTPCreated.code, spec_res.status_int)
|
||||
res = self.deserialize(self.fmt, spec_res)
|
||||
self.assertIn('servicechain_spec', res)
|
||||
self.assertEqual([scn_id], res['servicechain_spec']['nodes'])
|
||||
spec2 = {"servicechain_spec": {'name': 'scs2',
|
||||
'tenant_id': self._tenant_id,
|
||||
'nodes': [scn_id]}}
|
||||
spec_req = self.new_create_request('servicechain_specs',
|
||||
spec2,
|
||||
self.fmt)
|
||||
spec_res = spec_req.get_response(self.ext_api)
|
||||
self.assertEqual(webob.exc.HTTPCreated.code, spec_res.status_int)
|
||||
res = self.deserialize(self.fmt, spec_res)
|
||||
self.assertIn('servicechain_spec', res)
|
||||
self.assertEqual([scn_id], res['servicechain_spec']['nodes'])
|
||||
|
||||
|
||||
class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
|
||||
@ -299,8 +198,8 @@ 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(
|
||||
profile = self.create_service_profile(service_type=constants.FIREWALL)
|
||||
attrs = cm.get_create_servicechain_node_default_attrs(
|
||||
service_profile_id=profile['service_profile']['id'],
|
||||
config="config1")
|
||||
|
||||
@ -329,8 +228,8 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
def test_update_servicechain_node(self):
|
||||
name = 'new_servicechain_node'
|
||||
description = 'new desc'
|
||||
profile = self.create_service_profile()
|
||||
attrs = self._get_test_servicechain_node_attrs(
|
||||
profile = self.create_service_profile(service_type=constants.FIREWALL)
|
||||
attrs = cm.get_create_servicechain_node_default_attrs(
|
||||
name=name, description=description,
|
||||
service_profile_id=profile['service_profile']['id'])
|
||||
|
||||
@ -380,7 +279,8 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
scn = self._create_profiled_servicechain_node()
|
||||
scn_id = scn['servicechain_node']['id']
|
||||
|
||||
attrs = self._get_test_servicechain_spec_attrs(name, nodes=[scn_id])
|
||||
attrs = cm.get_create_servicechain_spec_default_attrs(
|
||||
name=name, nodes=[scn_id])
|
||||
|
||||
scs = self.create_servicechain_spec(name=name, nodes=[scn_id])
|
||||
|
||||
@ -397,10 +297,10 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
scn1_id = scn1['servicechain_node']['id']
|
||||
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])
|
||||
attrs = cm.get_create_servicechain_spec_default_attrs(
|
||||
name=name, nodes=[scn1_id, scn2_id])
|
||||
scs = self.create_servicechain_spec(
|
||||
name=name, nodes=[scn1_id, scn2_id])
|
||||
name=name, nodes=[scn1_id, scn2_id])
|
||||
for k, v in attrs.iteritems():
|
||||
self.assertEqual(v, scs['servicechain_spec'][k])
|
||||
|
||||
@ -444,9 +344,8 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
description = 'new desc'
|
||||
scn_id = self._create_profiled_servicechain_node()[
|
||||
'servicechain_node']['id']
|
||||
attrs = self._get_test_servicechain_spec_attrs(name=name,
|
||||
description=description,
|
||||
nodes=[scn_id])
|
||||
attrs = cm.get_create_servicechain_spec_default_attrs(
|
||||
name=name, description=description, nodes=[scn_id])
|
||||
scs = self.create_servicechain_spec()
|
||||
data = {'servicechain_spec': {'name': name, 'description': description,
|
||||
'nodes': [scn_id]}}
|
||||
@ -517,7 +416,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
policy_target_group_id = uuidutils.generate_uuid()
|
||||
classifier_id = uuidutils.generate_uuid()
|
||||
config_param_values = "{}"
|
||||
attrs = self._get_test_servicechain_instance_attrs(
|
||||
attrs = cm.get_create_servicechain_instance_default_attrs(
|
||||
servicechain_specs=[scs_id],
|
||||
provider_ptg_id=policy_target_group_id,
|
||||
consumer_ptg_id=policy_target_group_id,
|
||||
@ -588,7 +487,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
provider_ptg_id = uuidutils.generate_uuid()
|
||||
consumer_ptg_id = uuidutils.generate_uuid()
|
||||
classifier_id = uuidutils.generate_uuid()
|
||||
attrs = self._get_test_servicechain_instance_attrs(
|
||||
attrs = cm.get_create_servicechain_instance_default_attrs(
|
||||
name=name, description=description, servicechain_specs=[scs_id],
|
||||
provider_ptg_id=provider_ptg_id, consumer_ptg_id=consumer_ptg_id,
|
||||
classifier_id=classifier_id,
|
||||
@ -627,7 +526,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
ctx, sci_id)
|
||||
|
||||
def test_create_and_show_service_profile(self):
|
||||
attrs = self._get_test_service_profile_attrs(
|
||||
attrs = cm.get_create_service_profile_default_attrs(
|
||||
service_type=constants.FIREWALL, vendor="vendor1")
|
||||
|
||||
scn = self.create_service_profile(
|
||||
@ -640,20 +539,23 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
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')]
|
||||
scns = [self.create_service_profile(name='sp1', description='sp',
|
||||
service_type='LOADBALANCER'),
|
||||
self.create_service_profile(name='sp2', description='sp',
|
||||
service_type='LOADBALANCER'),
|
||||
self.create_service_profile(name='sp3', description='sp',
|
||||
service_type='LOADBALANCER')]
|
||||
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(
|
||||
attrs = cm.get_create_service_profile_default_attrs(
|
||||
name=name, description=description,
|
||||
service_type=constants.FIREWALL)
|
||||
|
||||
scn = self.create_service_profile()
|
||||
scn = self.create_service_profile(service_type=constants.FIREWALL)
|
||||
|
||||
data = {'service_profile': {'name': name,
|
||||
'description': description}}
|
||||
@ -670,7 +572,7 @@ class TestServiceChainResources(ServiceChainDbTestCase):
|
||||
def test_delete_service_profile(self):
|
||||
ctx = context.get_admin_context()
|
||||
|
||||
sp = self.create_service_profile()
|
||||
sp = self.create_service_profile(service_type='LOADBALANCER')
|
||||
sp_id = sp['service_profile']['id']
|
||||
|
||||
scn = self.create_servicechain_node(service_profile_id=sp_id)
|
||||
|
@ -0,0 +1,131 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from neutron import context as n_context
|
||||
from neutron.db import api as db_api
|
||||
from neutron.db import model_base
|
||||
from oslo_config import cfg
|
||||
|
||||
from gbpservice.neutron.services.servicechain.plugins.ncp import (
|
||||
context as ncp_context)
|
||||
import gbpservice.neutron.services.servicechain.plugins.ncp.config # noqa
|
||||
from gbpservice.neutron.services.servicechain.plugins.ncp.node_drivers import (
|
||||
dummy_driver as dummy_driver)
|
||||
from gbpservice.neutron.tests.unit.services.servicechain import (
|
||||
test_servicechain_plugin as test_base)
|
||||
|
||||
SC_PLUGIN_KLASS = (
|
||||
"gbpservice.neutron.services.servicechain.plugins.ncp.plugin."
|
||||
"NodeCompositionPlugin")
|
||||
CORE_PLUGIN = ('gbpservice.neutron.tests.unit.services.grouppolicy.'
|
||||
'test_resource_mapping.NoL3NatSGTestPlugin')
|
||||
GP_PLUGIN_KLASS = (
|
||||
"gbpservice.neutron.services.grouppolicy.plugin.GroupPolicyPlugin"
|
||||
)
|
||||
|
||||
|
||||
class NodeCompositionPluginTestCase(
|
||||
test_base.TestGroupPolicyPluginGroupResources):
|
||||
|
||||
def setUp(self, core_plugin=None, gp_plugin=None, node_drivers=None):
|
||||
if node_drivers:
|
||||
cfg.CONF.set_override('node_drivers', node_drivers,
|
||||
group='node_composition_chain')
|
||||
super(NodeCompositionPluginTestCase, self).setUp(
|
||||
core_plugin=core_plugin or CORE_PLUGIN,
|
||||
gp_plugin=gp_plugin or GP_PLUGIN_KLASS,
|
||||
sc_plugin=SC_PLUGIN_KLASS)
|
||||
engine = db_api.get_engine()
|
||||
model_base.BASEV2.metadata.create_all(engine)
|
||||
|
||||
def test_node_shared(self):
|
||||
pass
|
||||
|
||||
def test_profile_shared(self):
|
||||
pass
|
||||
|
||||
def test_spec_shared(self):
|
||||
pass
|
||||
|
||||
def test_context_attributes(self):
|
||||
# Verify Context attributes for simple config
|
||||
plugin_context = n_context.get_admin_context()
|
||||
profile = self.create_service_profile(
|
||||
service_type="TYPE")['service_profile']
|
||||
node = self.create_servicechain_node(
|
||||
service_profile_id=profile['id'], config='{}')['servicechain_node']
|
||||
spec = self.create_servicechain_spec(
|
||||
nodes=[node['id']])['servicechain_spec']
|
||||
provider = self.create_policy_target_group()['policy_target_group']
|
||||
consumer = self.create_policy_target_group()['policy_target_group']
|
||||
management = self.create_policy_target_group()['policy_target_group']
|
||||
instance = self.create_servicechain_instance(
|
||||
provider_ptg_id=provider['id'], consumer_ptg_id=consumer['id'],
|
||||
servicechain_specs=[spec['id']])['servicechain_instance']
|
||||
|
||||
# Verify created without errors
|
||||
ctx = ncp_context.get_node_driver_context(
|
||||
self.plugin, plugin_context, instance, node,
|
||||
management_group=management)
|
||||
|
||||
self.assertIsNotNone(ctx.gbp_plugin)
|
||||
self.assertIsNotNone(ctx.sc_plugin)
|
||||
self.assertIsNotNone(ctx.core_plugin)
|
||||
self.assertIsNotNone(ctx.plugin_context)
|
||||
self.assertIsNotNone(ctx.plugin_session)
|
||||
self.assertIsNotNone(ctx.session)
|
||||
self.assertIsNotNone(ctx.admin_context)
|
||||
self.assertIsNotNone(ctx.admin_session)
|
||||
self.assertEqual(ctx.instance, instance)
|
||||
self.assertEqual(ctx.provider, provider)
|
||||
self.assertEqual(ctx.consumer, consumer)
|
||||
self.assertEqual(ctx.management, management)
|
||||
self.assertEqual(ctx.management, management)
|
||||
self.assertEqual(ctx.relevant_specs, [spec])
|
||||
del ctx.current_profile['nodes']
|
||||
self.assertEqual(ctx.current_profile, profile)
|
||||
self.assertIsNone(ctx.original_node)
|
||||
self.assertIsNone(ctx.service_targets)
|
||||
|
||||
def test_context_relevant_specs(self):
|
||||
plugin_context = n_context.get_admin_context()
|
||||
node_used = self._create_profiled_servicechain_node(
|
||||
service_type="TYPE", config='{}')['servicechain_node']
|
||||
spec_used = self.create_servicechain_spec(
|
||||
nodes=[node_used['id']])['servicechain_spec']
|
||||
|
||||
node_unused = self._create_profiled_servicechain_node(
|
||||
service_type="TYPE", config='{}')['servicechain_node']
|
||||
spec_unused = self.create_servicechain_spec(
|
||||
nodes=[node_unused['id']])['servicechain_spec']
|
||||
|
||||
provider = self.create_policy_target_group()['policy_target_group']
|
||||
instance = self.create_servicechain_instance(
|
||||
provider_ptg_id=provider['id'],
|
||||
servicechain_specs=[spec_used['id'],
|
||||
spec_unused['id']])['servicechain_instance']
|
||||
self.assertEqual(len(instance['servicechain_specs']), 2)
|
||||
|
||||
ctx = ncp_context.get_node_driver_context(
|
||||
self.plugin, plugin_context, instance, node_used)
|
||||
self.assertEqual(ctx.relevant_specs, [spec_used])
|
||||
|
||||
|
||||
class TestNcpNodeDriverManager(NodeCompositionPluginTestCase):
|
||||
|
||||
def test_manager_initialized(self):
|
||||
mgr = self.plugin.driver_manager
|
||||
self.assertIsInstance(mgr.ordered_drivers[0].obj,
|
||||
dummy_driver.NoopNodeDriver)
|
||||
for driver in mgr.ordered_drivers:
|
||||
self.assertTrue(driver.obj.initialized)
|
@ -29,16 +29,17 @@ SC_PLUGIN_KLASS = (
|
||||
|
||||
class ServiceChainPluginTestCase(test_servicechain_db.ServiceChainDbTestCase):
|
||||
|
||||
def setUp(self, core_plugin=None, sc_plugin=None):
|
||||
def setUp(self, core_plugin=None, sc_plugin=None, gp_plugin=None):
|
||||
if not sc_plugin:
|
||||
sc_plugin = SC_PLUGIN_KLASS
|
||||
super(ServiceChainPluginTestCase, self).setUp(core_plugin=core_plugin,
|
||||
sc_plugin=sc_plugin)
|
||||
sc_plugin=sc_plugin,
|
||||
gp_plugin=gp_plugin)
|
||||
|
||||
|
||||
class TestGroupPolicyPluginGroupResources(
|
||||
ServiceChainPluginTestCase,
|
||||
test_servicechain_db.TestServiceChainResources):
|
||||
ServiceChainPluginTestCase,
|
||||
test_servicechain_db.TestServiceChainResources):
|
||||
|
||||
def test_spec_shared(self):
|
||||
# Shared spec can only point shared nodes
|
||||
@ -55,7 +56,7 @@ class TestGroupPolicyPluginGroupResources(
|
||||
'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)
|
||||
expected_res_status=404)
|
||||
self.create_servicechain_spec(nodes=[node['id']], shared=True,
|
||||
tenant_id='nonadmin',
|
||||
expected_res_status=400)
|
||||
@ -80,7 +81,7 @@ class TestGroupPolicyPluginGroupResources(
|
||||
tenant_id='admin')['service_profile']
|
||||
self.create_servicechain_node(
|
||||
service_profile_id=prof['id'], shared=True,
|
||||
expected_res_status=400)
|
||||
expected_res_status=404)
|
||||
self.create_servicechain_node(
|
||||
service_profile_id=prof['id'], shared=True,
|
||||
tenant_id='admin', expected_res_status=400)
|
||||
|
@ -20,6 +20,7 @@ from neutron.tests.unit.extensions import base as test_extensions_base
|
||||
from webob import exc
|
||||
|
||||
from gbpservice.neutron.extensions import servicechain
|
||||
from gbpservice.neutron.tests.unit import common as cm
|
||||
|
||||
|
||||
_uuid = uuidutils.generate_uuid
|
||||
@ -63,30 +64,6 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
self.assertIn('servicechain_node', res)
|
||||
self.assertEqual(expected_value, res['servicechain_node'])
|
||||
|
||||
def _get_create_servicechain_node_default_attrs(self):
|
||||
return {
|
||||
'name': '',
|
||||
'description': '',
|
||||
'config': '',
|
||||
'shared': False
|
||||
}
|
||||
|
||||
def _get_create_servicechain_node_attrs(self):
|
||||
return {
|
||||
'name': 'servicechain1',
|
||||
'service_profile_id': _uuid(),
|
||||
'tenant_id': _uuid(),
|
||||
'description': 'test servicechain node',
|
||||
'config': 'test_config',
|
||||
'shared': True,
|
||||
'service_type': None,
|
||||
}
|
||||
|
||||
def _get_update_servicechain_node_attrs(self):
|
||||
return {
|
||||
'name': 'new_name',
|
||||
}
|
||||
|
||||
def test_create_servicechain_node_with_defaults(self):
|
||||
servicechain_node_id = _uuid()
|
||||
data = {
|
||||
@ -97,7 +74,7 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
'service_type': None,
|
||||
}
|
||||
}
|
||||
default_attrs = self._get_create_servicechain_node_default_attrs()
|
||||
default_attrs = cm.get_create_servicechain_node_default_attrs()
|
||||
default_data = copy.copy(data)
|
||||
default_data['servicechain_node'].update(default_attrs)
|
||||
expected_value = dict(default_data['servicechain_node'])
|
||||
@ -108,7 +85,7 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
def test_create_servicechain_node(self):
|
||||
servicechain_node_id = _uuid()
|
||||
data = {
|
||||
'servicechain_node': self._get_create_servicechain_node_attrs()
|
||||
'servicechain_node': cm.get_create_servicechain_node_attrs()
|
||||
}
|
||||
expected_value = dict(data['servicechain_node'])
|
||||
expected_value['id'] = servicechain_node_id
|
||||
@ -149,7 +126,7 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
def test_update_servicechain_node(self):
|
||||
servicechain_node_id = _uuid()
|
||||
update_data = {
|
||||
'servicechain_node': self._get_update_servicechain_node_attrs()
|
||||
'servicechain_node': cm.get_update_servicechain_node_attrs()
|
||||
}
|
||||
expected_value = {'tenant_id': _uuid(), 'id': servicechain_node_id}
|
||||
self.instance.update_servicechain_node.return_value = expected_value
|
||||
@ -186,29 +163,6 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
self.assertIn('servicechain_spec', res)
|
||||
self.assertEqual(expected_value, res['servicechain_spec'])
|
||||
|
||||
def _get_create_servicechain_spec_default_attrs(self):
|
||||
return {
|
||||
'name': '',
|
||||
'description': '',
|
||||
'nodes': [],
|
||||
'shared': False,
|
||||
}
|
||||
|
||||
def _get_create_servicechain_spec_attrs(self):
|
||||
return {
|
||||
'name': 'servicechainspec1',
|
||||
'nodes': [_uuid(), _uuid()],
|
||||
'tenant_id': _uuid(),
|
||||
'description': 'test servicechain spec',
|
||||
'shared': True
|
||||
}
|
||||
|
||||
def _get_update_servicechain_spec_attrs(self):
|
||||
return {
|
||||
'name': 'new_name',
|
||||
'nodes': [_uuid()]
|
||||
}
|
||||
|
||||
def test_create_servicechain_spec_with_defaults(self):
|
||||
servicechain_spec_id = _uuid()
|
||||
data = {
|
||||
@ -216,7 +170,7 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
'nodes': [_uuid(), _uuid()], 'tenant_id': _uuid()
|
||||
}
|
||||
}
|
||||
default_attrs = self._get_create_servicechain_spec_default_attrs()
|
||||
default_attrs = cm.get_create_servicechain_spec_default_attrs()
|
||||
default_data = copy.copy(data)
|
||||
default_data['servicechain_spec'].update(default_attrs)
|
||||
expected_value = dict(default_data['servicechain_spec'])
|
||||
@ -227,7 +181,7 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
def test_create_servicechain_spec(self):
|
||||
servicechain_spec_id = _uuid()
|
||||
data = {
|
||||
'servicechain_spec': self._get_create_servicechain_spec_attrs()
|
||||
'servicechain_spec': cm.get_create_servicechain_spec_attrs()
|
||||
}
|
||||
expected_value = dict(data['servicechain_spec'])
|
||||
expected_value['id'] = servicechain_spec_id
|
||||
@ -267,7 +221,7 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
def test_update_servicechain_spec(self):
|
||||
servicechain_spec_id = _uuid()
|
||||
update_data = {
|
||||
'servicechain_spec': self._get_update_servicechain_spec_attrs()
|
||||
'servicechain_spec': cm.get_update_servicechain_spec_attrs()
|
||||
}
|
||||
expected_value = {'tenant_id': _uuid(), 'id': servicechain_spec_id}
|
||||
self.instance.update_servicechain_spec.return_value = expected_value
|
||||
@ -305,27 +259,6 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
self.assertIn('servicechain_instance', res)
|
||||
self.assertEqual(expected_value, res['servicechain_instance'])
|
||||
|
||||
def _get_create_servicechain_instance_default_attrs(self):
|
||||
return {'name': '', 'description': '', 'config_param_values': "{}"}
|
||||
|
||||
def _get_create_servicechain_instance_attrs(self):
|
||||
return {
|
||||
'name': 'servicechaininstance1',
|
||||
'servicechain_specs': [_uuid()],
|
||||
'tenant_id': _uuid(),
|
||||
'provider_ptg_id': _uuid(),
|
||||
'consumer_ptg_id': _uuid(),
|
||||
'classifier_id': _uuid(),
|
||||
'config_param_values': "{}",
|
||||
'description': 'test servicechain instance'
|
||||
}
|
||||
|
||||
def _get_update_servicechain_instance_attrs(self):
|
||||
return {
|
||||
'name': 'new_name',
|
||||
'servicechain_specs': [_uuid()]
|
||||
}
|
||||
|
||||
def test_create_servicechain_instance_with_defaults(self):
|
||||
servicechain_instance_id = _uuid()
|
||||
data = {
|
||||
@ -337,7 +270,7 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
'classifier_id': _uuid(),
|
||||
}
|
||||
}
|
||||
default_attrs = self._get_create_servicechain_instance_default_attrs()
|
||||
default_attrs = cm.get_create_servicechain_instance_default_attrs()
|
||||
default_data = copy.copy(data)
|
||||
default_data['servicechain_instance'].update(default_attrs)
|
||||
expected_value = dict(default_data['servicechain_instance'])
|
||||
@ -349,7 +282,7 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
def test_create_servicechain_instance(self):
|
||||
servicechain_instance_id = _uuid()
|
||||
data = {'servicechain_instance':
|
||||
self._get_create_servicechain_instance_attrs()}
|
||||
cm.get_create_servicechain_instance_attrs()}
|
||||
expected_value = dict(data['servicechain_instance'])
|
||||
expected_value['id'] = servicechain_instance_id
|
||||
|
||||
@ -389,7 +322,7 @@ class ServiceChainExtensionTestCase(test_extensions_base.ExtensionTestCase):
|
||||
def test_update_servicechain_instance(self):
|
||||
servicechain_instance_id = _uuid()
|
||||
update_data = {'servicechain_instance':
|
||||
self._get_update_servicechain_instance_attrs()}
|
||||
cm.get_update_servicechain_instance_attrs()}
|
||||
expected_value = {'tenant_id': _uuid(), 'id': servicechain_instance_id}
|
||||
self.instance.update_servicechain_instance.return_value = (
|
||||
expected_value)
|
||||
|
@ -38,6 +38,7 @@ neutron.service_plugins =
|
||||
group_policy = gbpservice.neutron.services.grouppolicy.plugin:GroupPolicyPlugin
|
||||
servicechain = gbpservice.neutron.services.servicechain.plugins.msc.plugin:ServiceChainPlugin
|
||||
msc = gbpservice.neutron.services.servicechain.plugins.msc.plugin:ServiceChainPlugin
|
||||
ncp = gbpservice.neutron.services.servicechain.plugins.ncp.plugin:NodeCompositionPlugin
|
||||
gbpservice.neutron.group_policy.extension_drivers =
|
||||
test = gbpservice.neutron.tests.unit.services.grouppolicy.test_extension_driver_api:TestExtensionDriver
|
||||
gbpservice.neutron.group_policy.policy_drivers =
|
||||
@ -56,6 +57,8 @@ gbpservice.neutron.servicechain.servicechain_drivers =
|
||||
dummy = gbpservice.neutron.services.servicechain.plugins.msc.drivers.dummy_driver:NoopDriver
|
||||
simplechain_driver = gbpservice.neutron.services.servicechain.plugins.msc.drivers.simplechain_driver:SimpleChainDriver
|
||||
oneconvergence_servicechain_driver = gbpservice.neutron.services.servicechain.plugins.msc.drivers.oneconvergence_servicechain_driver:OneconvergenceServiceChainDriver
|
||||
gbpservice.neutron.servicechain.ncp_drivers =
|
||||
node_dummy = gbpservice.neutron.services.servicechain.plugins.ncp.node_drivers.dummy_driver:NoopNodeDriver
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
|
Loading…
Reference in New Issue
Block a user