Remove monolithic service chain plugin and drivers
This plugin is subsumed by the Node Composition plugin starting in the liberty cycle. Switching to the NCP as default invalidated some UTs (since NCP does not support more than one service_chain_spec per service_chain_instance). These tests are being skipped. Change-Id: I03383145eaa72681695e12649f731ba1a6b8bad8
This commit is contained in:
parent
10813882d1
commit
1d630b3a4a
@ -1,15 +0,0 @@
|
||||
[simplechain]
|
||||
# Heat server address to create services specified in the service chain
|
||||
# heat_uri = http://localhost:8004/v1
|
||||
|
||||
# CA file for heatclient to verify server certificates
|
||||
# heat_ca_certificates_file =
|
||||
|
||||
# Boolean to control ignoring SSL errors on the heat url
|
||||
# heat_api_insecure = False
|
||||
|
||||
# Number of attempts to retry for stack deletion
|
||||
# stack_delete_retries = 5
|
||||
|
||||
# Wait time between two successive stack delete retries
|
||||
# stack_delete_retry_wait = 3
|
@ -1,6 +0,0 @@
|
||||
[servicechain]
|
||||
|
||||
# An ordered list of service chain drivers entrypoints to be loaded from the
|
||||
# gbpservice.neutron.servicechain.servicechain_drivers namespace.
|
||||
|
||||
# servicechain_drivers=simplechain_driver,oneconvergence_servicechain_driver
|
@ -1,15 +0,0 @@
|
||||
[simplechain]
|
||||
# Heat server address to create services specified in the service chain
|
||||
# heat_uri = http://localhost:8004/v1
|
||||
|
||||
# CA file for heatclient to verify server certificates
|
||||
# heat_ca_certificates_file =
|
||||
|
||||
# Boolean to control ignoring SSL errors on the heat url
|
||||
# heat_api_insecure = False
|
||||
|
||||
# Number of attempts to retry for stack deletion
|
||||
# stack_delete_retries = 5
|
||||
|
||||
# Wait time between two successive stack delete retries
|
||||
# stack_delete_retry_wait = 3
|
@ -1,26 +0,0 @@
|
||||
# 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('servicechain_drivers',
|
||||
default=['dummy'],
|
||||
help=_("An ordered list of service chain drivers "
|
||||
"entrypoints to be loaded from the "
|
||||
"gbpservice.neutron.servicechain.servicechain_drivers "
|
||||
"namespace."))
|
||||
]
|
||||
|
||||
|
||||
cfg.CONF.register_opts(service_chain_opts, "servicechain")
|
@ -1,106 +0,0 @@
|
||||
# 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.
|
||||
|
||||
|
||||
class ServiceChainContext(object):
|
||||
"""ServiceChain context base class."""
|
||||
def __init__(self, plugin, plugin_context):
|
||||
self._plugin = plugin
|
||||
self._plugin_context = plugin_context
|
||||
|
||||
|
||||
class ServiceChainNodeContext(ServiceChainContext):
|
||||
|
||||
def __init__(self, plugin, plugin_context, sc_node,
|
||||
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):
|
||||
return self._sc_node
|
||||
|
||||
@property
|
||||
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):
|
||||
|
||||
def __init__(self, plugin, plugin_context, sc_spec,
|
||||
original_sc_spec=None):
|
||||
super(ServiceChainSpecContext, self).__init__(plugin, plugin_context)
|
||||
self._sc_spec = sc_spec
|
||||
self._original_sc_spec = original_sc_spec
|
||||
|
||||
@property
|
||||
def current(self):
|
||||
return self._sc_spec
|
||||
|
||||
@property
|
||||
def original(self):
|
||||
return self._original_sc_spec
|
||||
|
||||
|
||||
class ServiceChainInstanceContext(ServiceChainContext):
|
||||
|
||||
def __init__(self, plugin, plugin_context, sc_instance,
|
||||
original_sc_instance=None):
|
||||
super(ServiceChainInstanceContext, self).__init__(plugin,
|
||||
plugin_context)
|
||||
self._sc_instance = sc_instance
|
||||
self._original_sc_instance = original_sc_instance
|
||||
|
||||
@property
|
||||
def current(self):
|
||||
return self._sc_instance
|
||||
|
||||
@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
|
@ -1,184 +0,0 @@
|
||||
# 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
|
||||
import stevedore
|
||||
|
||||
from gbpservice._i18n import _LE
|
||||
from gbpservice._i18n import _LI
|
||||
from gbpservice.neutron.services.servicechain.common import (
|
||||
exceptions as sc_exc)
|
||||
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
cfg.CONF.import_opt(
|
||||
'servicechain_drivers',
|
||||
'gbpservice.neutron.services.servicechain.plugins.msc.config',
|
||||
group='servicechain')
|
||||
|
||||
|
||||
class DriverManager(stevedore.named.NamedExtensionManager):
|
||||
"""Route servicechain APIs to servicechain drivers.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
# Registered servicechain drivers, keyed by name.
|
||||
self.drivers = {}
|
||||
# Ordered list of servicechain drivers, defining
|
||||
# the order in which the drivers are called.
|
||||
self.ordered_drivers = []
|
||||
|
||||
LOG.info(_LI("Configured servicechain driver names: %s"),
|
||||
cfg.CONF.servicechain.servicechain_drivers)
|
||||
super(DriverManager,
|
||||
self).__init__(
|
||||
'gbpservice.neutron.servicechain.servicechain_drivers',
|
||||
cfg.CONF.servicechain.servicechain_drivers,
|
||||
invoke_on_load=True, name_order=True)
|
||||
LOG.info(_LI("Loaded servicechain driver names: %s"), self.names())
|
||||
self._register_drivers()
|
||||
|
||||
def _register_drivers(self):
|
||||
"""Register all servicechain drivers.
|
||||
|
||||
This method should only be called once in the DriverManager
|
||||
constructor.
|
||||
"""
|
||||
for ext in self:
|
||||
self.drivers[ext.name] = ext
|
||||
self.ordered_drivers.append(ext)
|
||||
LOG.info(_LI("Registered servicechain drivers: %s"),
|
||||
[driver.name for driver in self.ordered_drivers])
|
||||
|
||||
def initialize(self):
|
||||
# ServiceChain bulk operations requires each driver to support them
|
||||
self.native_bulk_support = True
|
||||
for driver in self.ordered_drivers:
|
||||
LOG.info(_LI("Initializing servicechain driver '%s'"), driver.name)
|
||||
driver.obj.initialize()
|
||||
self.native_bulk_support &= getattr(driver.obj,
|
||||
'native_bulk_support', True)
|
||||
|
||||
def _call_on_drivers(self, method_name, context):
|
||||
"""Helper method for calling a method across all servicechain drivers.
|
||||
|
||||
:param method_name: name of the method to call
|
||||
:param context: context parameter to pass to each method call
|
||||
:param continue_on_failure: whether or not to continue to call
|
||||
all servicechain drivers once one has raised an exception
|
||||
:raises: neutron.services.servicechain.common.ServiceChainDriverError
|
||||
if any servicechain driver call fails.
|
||||
"""
|
||||
error = False
|
||||
for driver in self.ordered_drivers:
|
||||
try:
|
||||
getattr(driver.obj, method_name)(context)
|
||||
except sc_exc.ServiceChainException:
|
||||
# This is an exception for the user.
|
||||
raise
|
||||
except Exception:
|
||||
# This is an internal failure.
|
||||
LOG.exception(
|
||||
_LE("ServiceChain driver '%(name)s' failed in %(method)s"),
|
||||
{'name': driver.name, 'method': method_name}
|
||||
)
|
||||
error = True
|
||||
if error:
|
||||
raise sc_exc.ServiceChainDriverError(
|
||||
method=method_name
|
||||
)
|
||||
|
||||
def create_servicechain_node_precommit(self, context):
|
||||
self._call_on_drivers("create_servicechain_node_precommit", context)
|
||||
|
||||
def create_servicechain_node_postcommit(self, context):
|
||||
self._call_on_drivers("create_servicechain_node_postcommit", context)
|
||||
|
||||
def update_servicechain_node_precommit(self, context):
|
||||
self._call_on_drivers("update_servicechain_node_precommit", context)
|
||||
|
||||
def update_servicechain_node_postcommit(self, context):
|
||||
self._call_on_drivers("update_servicechain_node_postcommit", context)
|
||||
|
||||
def delete_servicechain_node_precommit(self, context):
|
||||
self._call_on_drivers("delete_servicechain_node_precommit", context)
|
||||
|
||||
def delete_servicechain_node_postcommit(self, context):
|
||||
self._call_on_drivers("delete_servicechain_node_postcommit", context)
|
||||
|
||||
def create_servicechain_spec_precommit(self, context):
|
||||
self._call_on_drivers("create_servicechain_spec_precommit", context)
|
||||
|
||||
def create_servicechain_spec_postcommit(self, context):
|
||||
self._call_on_drivers("create_servicechain_spec_postcommit", context)
|
||||
|
||||
def update_servicechain_spec_precommit(self, context):
|
||||
self._call_on_drivers("update_servicechain_spec_precommit", context)
|
||||
|
||||
def update_servicechain_spec_postcommit(self, context):
|
||||
self._call_on_drivers("update_servicechain_spec_postcommit", context)
|
||||
|
||||
def delete_servicechain_spec_precommit(self, context):
|
||||
self._call_on_drivers("delete_servicechain_spec_precommit", context)
|
||||
|
||||
def delete_servicechain_spec_postcommit(self, context):
|
||||
self._call_on_drivers("delete_servicechain_spec_postcommit", context)
|
||||
|
||||
def create_servicechain_instance_precommit(self, context):
|
||||
self._call_on_drivers("create_servicechain_instance_precommit",
|
||||
context)
|
||||
|
||||
def create_servicechain_instance_postcommit(self, context):
|
||||
self._call_on_drivers("create_servicechain_instance_postcommit",
|
||||
context)
|
||||
|
||||
def update_servicechain_instance_precommit(self, context):
|
||||
self._call_on_drivers("update_servicechain_instance_precommit",
|
||||
context)
|
||||
|
||||
def update_servicechain_instance_postcommit(self, context):
|
||||
self._call_on_drivers("update_servicechain_instance_postcommit",
|
||||
context)
|
||||
|
||||
def delete_servicechain_instance_precommit(self, context):
|
||||
self._call_on_drivers("delete_servicechain_instance_precommit",
|
||||
context)
|
||||
|
||||
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)
|
@ -1,116 +0,0 @@
|
||||
# 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 helpers as log
|
||||
|
||||
|
||||
class NoopDriver(object):
|
||||
|
||||
@log.log_method_call
|
||||
def initialize(self):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_node_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_node_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_node_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_node_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_node_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_node_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_spec_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_spec_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_spec_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_spec_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_spec_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_spec_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_instance_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_instance_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_instance_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_instance_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_instance_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_instance_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def create_service_profile_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def create_service_profile_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_service_profile_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_service_profile_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def delete_service_profile_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def delete_service_profile_postcommit(self, context):
|
||||
pass
|
@ -1,482 +0,0 @@
|
||||
# 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 ast
|
||||
import time
|
||||
|
||||
from heatclient import client as heat_client
|
||||
from heatclient import exc as heat_exc
|
||||
from keystoneclient.v2_0 import client as keyclient
|
||||
from neutron import manager
|
||||
from neutron.plugins.common import constants as pconst
|
||||
from neutron_lib.db import model_base
|
||||
from oslo_config import cfg
|
||||
from oslo_log import helpers as log
|
||||
from oslo_log import log as logging
|
||||
from oslo_serialization import jsonutils
|
||||
import sqlalchemy as sa
|
||||
|
||||
from gbpservice._i18n import _LE
|
||||
from gbpservice._i18n import _LW
|
||||
from gbpservice.neutron.services.servicechain.common import exceptions as exc
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
cfg.CONF.import_group('keystone_authtoken', 'keystonemiddleware.auth_token')
|
||||
|
||||
service_chain_opts = [
|
||||
cfg.IntOpt('stack_delete_retries',
|
||||
default=5,
|
||||
help=_("Number of attempts to retry for stack deletion")),
|
||||
cfg.IntOpt('stack_delete_retry_wait',
|
||||
default=3,
|
||||
help=_("Wait time between two successive stack delete "
|
||||
"retries")),
|
||||
cfg.StrOpt('heat_uri',
|
||||
default='http://localhost:8004/v1',
|
||||
help=_("Heat server address to create services "
|
||||
"specified in the service chain.")),
|
||||
cfg.StrOpt('heat_ca_certificates_file', default=None,
|
||||
help=_('CA file for heatclient to verify server certificates')),
|
||||
cfg.BoolOpt('heat_api_insecure', default=False,
|
||||
help=_("If True, ignore any SSL validation issues")),
|
||||
]
|
||||
|
||||
|
||||
cfg.CONF.register_opts(service_chain_opts, "simplechain")
|
||||
|
||||
# Service chain API supported Values
|
||||
sc_supported_type = [pconst.LOADBALANCER, pconst.FIREWALL]
|
||||
STACK_DELETE_RETRIES = cfg.CONF.simplechain.stack_delete_retries
|
||||
STACK_DELETE_RETRY_WAIT = cfg.CONF.simplechain.stack_delete_retry_wait
|
||||
|
||||
|
||||
class ServiceChainInstanceStack(model_base.BASEV2):
|
||||
"""ServiceChainInstance stacks owned by the servicechain driver."""
|
||||
|
||||
__tablename__ = 'sc_instance_stacks'
|
||||
instance_id = sa.Column(sa.String(36),
|
||||
nullable=False, primary_key=True)
|
||||
stack_id = sa.Column(sa.String(36),
|
||||
nullable=False, primary_key=True)
|
||||
|
||||
|
||||
class SimpleChainDriver(object):
|
||||
|
||||
@log.log_method_call
|
||||
def initialize(self):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_node_precommit(self, context):
|
||||
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.warning(_LW('Both service_profile_id and service_type are'
|
||||
'specified, service_type will be ignored.'))
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_node_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_node_precommit(self, context):
|
||||
if (context.original['config'] != context.current['config']):
|
||||
filters = {'servicechain_spec': context.original[
|
||||
'servicechain_specs']}
|
||||
sc_instances = context._plugin.get_servicechain_instances(
|
||||
context._plugin_context, filters)
|
||||
if sc_instances:
|
||||
raise exc.NodeUpdateNotSupported()
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_node_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_node_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_node_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_spec_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_spec_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_spec_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_spec_postcommit(self, context):
|
||||
if context.original['nodes'] != context.current['nodes']:
|
||||
filters = {'servicechain_spec': [context.original['id']]}
|
||||
sc_instances = context._plugin.get_servicechain_instances(
|
||||
context._plugin_context, filters)
|
||||
for sc_instance in sc_instances:
|
||||
self._update_servicechain_instance(context,
|
||||
sc_instance,
|
||||
context._sc_spec)
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_spec_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_spec_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_instance_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_instance_postcommit(self, context):
|
||||
sc_instance = context.current
|
||||
sc_spec_ids = sc_instance.get('servicechain_specs')
|
||||
for sc_spec_id in sc_spec_ids:
|
||||
sc_spec = context._plugin.get_servicechain_spec(
|
||||
context._plugin_context, sc_spec_id)
|
||||
sc_node_ids = sc_spec.get('nodes')
|
||||
self._create_servicechain_instance_stacks(context, sc_node_ids,
|
||||
sc_instance, sc_spec)
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_instance_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_instance_postcommit(self, context):
|
||||
original_spec_ids = context.original.get('servicechain_specs')
|
||||
new_spec_ids = context.current.get('servicechain_specs')
|
||||
if set(original_spec_ids) != set(new_spec_ids):
|
||||
for new_spec_id in new_spec_ids:
|
||||
newspec = context._plugin.get_servicechain_spec(
|
||||
context._plugin_context, new_spec_id)
|
||||
self._update_servicechain_instance(context, context.current,
|
||||
newspec)
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_instance_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_instance_postcommit(self, context):
|
||||
self._delete_servicechain_instance_stacks(context._plugin_context,
|
||||
context.current['id'])
|
||||
|
||||
@log.log_method_call
|
||||
def create_service_profile_precommit(self, context):
|
||||
if context.current['service_type'] not in sc_supported_type:
|
||||
raise exc.InvalidServiceTypeForReferenceDriver()
|
||||
|
||||
@log.log_method_call
|
||||
def create_service_profile_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_service_profile_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def update_service_profile_postcommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
def delete_service_profile_precommit(self, context):
|
||||
pass
|
||||
|
||||
@log.log_method_call
|
||||
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,
|
||||
'policy_target_group',
|
||||
ptg_id)
|
||||
|
||||
def _get_pt(self, context, pt_id):
|
||||
return self._get_resource(self._grouppolicy_plugin,
|
||||
context._plugin_context,
|
||||
'policy_target',
|
||||
pt_id)
|
||||
|
||||
def _get_port(self, context, port_id):
|
||||
return self._get_resource(self._core_plugin,
|
||||
context._plugin_context,
|
||||
'port',
|
||||
port_id)
|
||||
|
||||
def _get_ptg_subnet(self, context, ptg_id):
|
||||
ptg = self._get_ptg(context, ptg_id)
|
||||
return ptg.get("subnets")[0]
|
||||
|
||||
def _get_member_ips(self, context, ptg_id):
|
||||
ptg = self._get_ptg(context, ptg_id)
|
||||
pt_ids = ptg.get("policy_targets")
|
||||
member_addresses = []
|
||||
for pt_id in pt_ids:
|
||||
pt = self._get_pt(context, pt_id)
|
||||
port_id = pt.get("port_id")
|
||||
port = self._get_port(context, port_id)
|
||||
ipAddress = port.get('fixed_ips')[0].get("ip_address")
|
||||
member_addresses.append(ipAddress)
|
||||
return member_addresses
|
||||
|
||||
def _fetch_template_and_params(self, context, sc_instance,
|
||||
sc_spec, sc_node):
|
||||
stack_template = sc_node.get('config')
|
||||
# TODO(magesh):Raise an exception ??
|
||||
if not stack_template:
|
||||
LOG.error(_LE("Service Config is not defined for the service"
|
||||
" chain Node"))
|
||||
return
|
||||
stack_template = jsonutils.loads(stack_template)
|
||||
config_param_values = sc_instance.get('config_param_values', {})
|
||||
stack_params = {}
|
||||
# config_param_values has the parameters for all Nodes. Only apply
|
||||
# the ones relevant for this Node
|
||||
if config_param_values:
|
||||
config_param_values = jsonutils.loads(config_param_values)
|
||||
config_param_names = sc_spec.get('config_param_names', [])
|
||||
if config_param_names:
|
||||
config_param_names = ast.literal_eval(config_param_names)
|
||||
|
||||
# This service chain driver knows how to fill in two parameter values
|
||||
# for the template at present.
|
||||
# 1)Subnet -> Provider PTG subnet is used
|
||||
# 2)PoolMemberIPs -> List of IP Addresses of all PTs in Provider PTG
|
||||
|
||||
# TODO(magesh):Process on the basis of ResourceType rather than Name
|
||||
# eg: Type: OS::Neutron::PoolMember
|
||||
# Variable number of pool members is not handled yet. We may have to
|
||||
# dynamically modify the template json to achieve that
|
||||
member_ips = []
|
||||
provider_ptg_id = sc_instance.get("provider_ptg_id")
|
||||
# If we have the key "PoolMemberIP*" in template input parameters,
|
||||
# fetch the list of IPs of all PTs in the PTG
|
||||
for key in config_param_names or []:
|
||||
if "PoolMemberIP" in key:
|
||||
member_ips = self._get_member_ips(context, provider_ptg_id)
|
||||
break
|
||||
|
||||
member_count = 0
|
||||
for key in config_param_names or []:
|
||||
if "PoolMemberIP" in key:
|
||||
value = (member_ips[member_count]
|
||||
if len(member_ips) > member_count else '0')
|
||||
member_count = member_count + 1
|
||||
config_param_values[key] = value
|
||||
elif key == "Subnet":
|
||||
value = self._get_ptg_subnet(context, provider_ptg_id)
|
||||
config_param_values[key] = value
|
||||
node_params = (stack_template.get('Parameters')
|
||||
or stack_template.get('parameters'))
|
||||
if node_params:
|
||||
for parameter in config_param_values.keys():
|
||||
if parameter in node_params.keys():
|
||||
stack_params[parameter] = config_param_values[parameter]
|
||||
return (stack_template, stack_params)
|
||||
|
||||
def _create_servicechain_instance_stacks(self, context, sc_node_ids,
|
||||
sc_instance, sc_spec):
|
||||
heatclient = HeatClient(context._plugin_context)
|
||||
for sc_node_id in sc_node_ids:
|
||||
sc_node = context._plugin.get_servicechain_node(
|
||||
context._plugin_context, sc_node_id)
|
||||
|
||||
stack_template, stack_params = self._fetch_template_and_params(
|
||||
context, sc_instance, sc_spec, sc_node)
|
||||
|
||||
stack_name = ("stack_" + sc_instance['name'] + sc_node['name'] +
|
||||
sc_instance['id'][:8])
|
||||
stack = heatclient.create(
|
||||
stack_name.replace(" ", ""), stack_template, stack_params)
|
||||
|
||||
self._insert_chain_stack_db(
|
||||
context._plugin_context.session, sc_instance['id'],
|
||||
stack['stack']['id'])
|
||||
|
||||
def _delete_servicechain_instance_stacks(self, context, instance_id):
|
||||
stack_ids = self._get_chain_stacks(context.session, instance_id)
|
||||
heatclient = HeatClient(context)
|
||||
for stack in stack_ids:
|
||||
heatclient.delete(stack.stack_id)
|
||||
for stack in stack_ids:
|
||||
self._wait_for_stack_delete(heatclient, stack.stack_id)
|
||||
self._delete_chain_stacks_db(context.session, instance_id)
|
||||
|
||||
# Wait for the heat stack to be deleted for a maximum of 15 seconds
|
||||
# we check the status every 3 seconds and call sleep again
|
||||
# This is required because cleanup of subnet fails when the stack created
|
||||
# some ports on the subnet and the resource delete is not completed by
|
||||
# the time subnet delete is triggered by Resource Mapping driver
|
||||
def _wait_for_stack_delete(self, heatclient, stack_id):
|
||||
stack_delete_retries = STACK_DELETE_RETRIES
|
||||
while True:
|
||||
try:
|
||||
stack = heatclient.get(stack_id)
|
||||
if stack.stack_status == 'DELETE_COMPLETE':
|
||||
return
|
||||
elif stack.stack_status == 'DELETE_FAILED':
|
||||
heatclient.delete(stack_id)
|
||||
except Exception:
|
||||
LOG.exception(_LE(
|
||||
"Service Chain Instance cleanup may not have "
|
||||
"happened because Heat API request failed "
|
||||
"while waiting for the stack %(stack)s to be "
|
||||
"deleted"), {'stack': stack_id})
|
||||
return
|
||||
else:
|
||||
time.sleep(STACK_DELETE_RETRY_WAIT)
|
||||
stack_delete_retries = stack_delete_retries - 1
|
||||
if stack_delete_retries == 0:
|
||||
LOG.warning(_LW(
|
||||
"Resource cleanup for service chain instance"
|
||||
" is not completed within %(wait)s seconds"
|
||||
" as deletion of Stack %(stack)s is not"
|
||||
" completed"),
|
||||
{'wait': (STACK_DELETE_RETRIES *
|
||||
STACK_DELETE_RETRY_WAIT),
|
||||
'stack': stack_id})
|
||||
return
|
||||
else:
|
||||
continue
|
||||
|
||||
def _get_instance_by_spec_id(self, context, spec_id):
|
||||
filters = {'servicechain_spec': [spec_id]}
|
||||
return context._plugin.get_servicechain_instances(
|
||||
context._plugin_context, filters)
|
||||
|
||||
def _update_servicechain_instance(self, context, sc_instance, newspec):
|
||||
self._delete_servicechain_instance_stacks(context._plugin_context,
|
||||
sc_instance['id'])
|
||||
sc_node_ids = newspec.get('nodes')
|
||||
self._create_servicechain_instance_stacks(context,
|
||||
sc_node_ids,
|
||||
sc_instance,
|
||||
newspec)
|
||||
|
||||
def _delete_chain_stacks_db(self, session, sc_instance_id):
|
||||
with session.begin(subtransactions=True):
|
||||
stacks = session.query(ServiceChainInstanceStack
|
||||
).filter_by(instance_id=sc_instance_id
|
||||
).all()
|
||||
for stack in stacks:
|
||||
session.delete(stack)
|
||||
|
||||
def _insert_chain_stack_db(self, session, sc_instance_id, stack_id):
|
||||
with session.begin(subtransactions=True):
|
||||
chainstack = ServiceChainInstanceStack(
|
||||
instance_id=sc_instance_id,
|
||||
stack_id=stack_id)
|
||||
session.add(chainstack)
|
||||
|
||||
def _get_chain_stacks(self, session, sc_instance_id):
|
||||
with session.begin(subtransactions=True):
|
||||
stack_ids = session.query(ServiceChainInstanceStack.stack_id
|
||||
).filter_by(instance_id=sc_instance_id
|
||||
).all()
|
||||
return stack_ids
|
||||
|
||||
def _get_resource(self, plugin, context, resource, resource_id):
|
||||
obj_getter = getattr(plugin, 'get_' + resource)
|
||||
obj = obj_getter(context, resource_id)
|
||||
return obj
|
||||
|
||||
@property
|
||||
def _core_plugin(self):
|
||||
# REVISIT(Magesh): Need initialization method after all
|
||||
# plugins are loaded to grab and store plugin.
|
||||
return manager.NeutronManager.get_plugin()
|
||||
|
||||
@property
|
||||
def _grouppolicy_plugin(self):
|
||||
# REVISIT(Magesh): Need initialization method after all
|
||||
# plugins are loaded to grab and store plugin.
|
||||
plugins = manager.NeutronManager.get_service_plugins()
|
||||
grouppolicy_plugin = plugins.get(pconst.GROUP_POLICY)
|
||||
if not grouppolicy_plugin:
|
||||
LOG.error(_LE("No Grouppolicy service plugin found."))
|
||||
raise exc.ServiceChainDeploymentError()
|
||||
return grouppolicy_plugin
|
||||
|
||||
|
||||
class HeatClient(object):
|
||||
|
||||
def __init__(self, context, password=None):
|
||||
api_version = "1"
|
||||
self.tenant = context.tenant
|
||||
|
||||
self._keystone = None
|
||||
endpoint = "%s/%s" % (cfg.CONF.simplechain.heat_uri, self.tenant)
|
||||
kwargs = {
|
||||
'token': self._get_auth_token(self.tenant),
|
||||
'username': context.user_name,
|
||||
'password': password,
|
||||
'cacert': cfg.CONF.simplechain.heat_ca_certificates_file,
|
||||
'insecure': cfg.CONF.simplechain.heat_api_insecure
|
||||
}
|
||||
self.client = heat_client.Client(api_version, endpoint, **kwargs)
|
||||
self.stacks = self.client.stacks
|
||||
|
||||
def create(self, name, data, parameters=None):
|
||||
fields = {
|
||||
'stack_name': name,
|
||||
'timeout_mins': 10,
|
||||
'disable_rollback': True,
|
||||
'password': data.get('password')
|
||||
}
|
||||
fields['template'] = data
|
||||
fields['parameters'] = parameters
|
||||
return self.stacks.create(**fields)
|
||||
|
||||
def delete(self, stack_id):
|
||||
try:
|
||||
self.stacks.delete(stack_id)
|
||||
except heat_exc.HTTPNotFound:
|
||||
LOG.warning(_LW(
|
||||
"Stack %(stack)s created by service chain driver is "
|
||||
"not found at cleanup"), {'stack': stack_id})
|
||||
|
||||
def get(self, stack_id):
|
||||
return self.stacks.get(stack_id)
|
||||
|
||||
@property
|
||||
def keystone(self):
|
||||
if not self._keystone:
|
||||
keystone_conf = cfg.CONF.keystone_authtoken
|
||||
if keystone_conf.get('auth_uri'):
|
||||
auth_url = keystone_conf.auth_uri
|
||||
else:
|
||||
auth_url = ('%s://%s:%s/v2.0/' % (
|
||||
keystone_conf.auth_protocol,
|
||||
keystone_conf.auth_host,
|
||||
keystone_conf.auth_port))
|
||||
user = (keystone_conf.get('admin_user') or keystone_conf.username)
|
||||
pw = (keystone_conf.get('admin_password') or
|
||||
keystone_conf.password)
|
||||
self._keystone = keyclient.Client(
|
||||
username=user, password=pw, auth_url=auth_url,
|
||||
tenant_id=self.tenant)
|
||||
return self._keystone
|
||||
|
||||
def _get_auth_token(self, tenant):
|
||||
return self.keystone.get_token(tenant)
|
@ -1,315 +0,0 @@
|
||||
# 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.plugins.common import constants as pconst
|
||||
from oslo_log import helpers as log
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
|
||||
from gbpservice._i18n import _LE
|
||||
import gbpservice.neutron.db.servicechain_db as servicechain_db
|
||||
from gbpservice.neutron.services.grouppolicy.common import constants as gp_cts
|
||||
from gbpservice.neutron.services.servicechain.plugins.msc import (
|
||||
context as servicechain_context)
|
||||
from gbpservice.neutron.services.servicechain.plugins.msc import (
|
||||
driver_manager as manager)
|
||||
from gbpservice.neutron.services.servicechain.plugins import sharing
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ServiceChainPlugin(servicechain_db.ServiceChainDbPlugin,
|
||||
sharing.SharingMixin):
|
||||
|
||||
"""Implementation of the Service Chain Plugin.
|
||||
|
||||
"""
|
||||
supported_extension_aliases = ["servicechain"]
|
||||
path_prefix = gp_cts.GBP_PREFIXES[pconst.SERVICECHAIN]
|
||||
|
||||
def __init__(self):
|
||||
self.driver_manager = manager.DriverManager()
|
||||
super(ServiceChainPlugin, self).__init__()
|
||||
self.driver_manager.initialize()
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_node(self, context, servicechain_node):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
result = super(ServiceChainPlugin, self).create_servicechain_node(
|
||||
context, servicechain_node)
|
||||
self._validate_shared_create(context, result, 'servicechain_node')
|
||||
sc_context = servicechain_context.ServiceChainNodeContext(
|
||||
self, context, result)
|
||||
self.driver_manager.create_servicechain_node_precommit(
|
||||
sc_context)
|
||||
|
||||
try:
|
||||
self.driver_manager.create_servicechain_node_postcommit(
|
||||
sc_context)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE("driver_manager.create_servicechain_postcommit "
|
||||
"failed, deleting servicechain_node %s"),
|
||||
result['id'])
|
||||
self.delete_servicechain_node(context, result['id'])
|
||||
|
||||
return result
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_node(self, context, servicechain_node_id,
|
||||
servicechain_node):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
original_sc_node = self.get_servicechain_node(
|
||||
context, servicechain_node_id)
|
||||
updated_sc_node = super(ServiceChainPlugin,
|
||||
self).update_servicechain_node(
|
||||
context, servicechain_node_id,
|
||||
servicechain_node,
|
||||
set_params=True)
|
||||
self._validate_shared_update(context, original_sc_node,
|
||||
updated_sc_node, 'servicechain_node')
|
||||
sc_context = servicechain_context.ServiceChainNodeContext(
|
||||
self, context, updated_sc_node,
|
||||
original_sc_node=original_sc_node)
|
||||
self.driver_manager.update_servicechain_node_precommit(
|
||||
sc_context)
|
||||
|
||||
self.driver_manager.update_servicechain_node_postcommit(sc_context)
|
||||
|
||||
return updated_sc_node
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_node(self, context, servicechain_node_id):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
sc_node = self.get_servicechain_node(context,
|
||||
servicechain_node_id)
|
||||
sc_context = servicechain_context.ServiceChainNodeContext(
|
||||
self, context, sc_node)
|
||||
self.driver_manager.delete_servicechain_node_precommit(
|
||||
sc_context)
|
||||
super(ServiceChainPlugin, self).delete_servicechain_node(
|
||||
context, servicechain_node_id)
|
||||
|
||||
try:
|
||||
self.driver_manager.delete_servicechain_node_postcommit(
|
||||
sc_context)
|
||||
except Exception:
|
||||
LOG.exception(_LE("delete_servicechain_node_postcommit failed "
|
||||
"for servicechain_node %s"),
|
||||
servicechain_node_id)
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_spec(self, context, servicechain_spec):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
result = super(ServiceChainPlugin, self).create_servicechain_spec(
|
||||
context, servicechain_spec)
|
||||
self._validate_shared_create(context, result, 'servicechain_spec')
|
||||
sc_context = servicechain_context.ServiceChainSpecContext(
|
||||
self, context, result)
|
||||
self.driver_manager.create_servicechain_spec_precommit(
|
||||
sc_context)
|
||||
|
||||
try:
|
||||
self.driver_manager.create_servicechain_spec_postcommit(sc_context)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE("driver_manager.create_servicechain_postcommit "
|
||||
"failed, deleting servicechain_spec %s"),
|
||||
result['id'])
|
||||
self.delete_servicechain_spec(context, result['id'])
|
||||
|
||||
return result
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_spec(self, context, servicechain_spec_id,
|
||||
servicechain_spec):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
original_sc_spec = self.get_servicechain_spec(
|
||||
context, servicechain_spec_id)
|
||||
updated_sc_spec = super(ServiceChainPlugin,
|
||||
self).update_servicechain_spec(
|
||||
context, servicechain_spec_id,
|
||||
servicechain_spec)
|
||||
self._validate_shared_update(context, original_sc_spec,
|
||||
updated_sc_spec, 'servicechain_spec')
|
||||
sc_context = servicechain_context.ServiceChainSpecContext(
|
||||
self, context, updated_sc_spec,
|
||||
original_sc_spec=original_sc_spec)
|
||||
self.driver_manager.update_servicechain_spec_precommit(
|
||||
sc_context)
|
||||
|
||||
self.driver_manager.update_servicechain_spec_postcommit(sc_context)
|
||||
|
||||
return updated_sc_spec
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_spec(self, context, servicechain_spec_id):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
sc_spec = self.get_servicechain_spec(context,
|
||||
servicechain_spec_id)
|
||||
sc_context = servicechain_context.ServiceChainSpecContext(
|
||||
self, context, sc_spec)
|
||||
self.driver_manager.delete_servicechain_spec_precommit(
|
||||
sc_context)
|
||||
super(ServiceChainPlugin, self).delete_servicechain_spec(
|
||||
context, servicechain_spec_id)
|
||||
|
||||
try:
|
||||
self.driver_manager.delete_servicechain_spec_postcommit(sc_context)
|
||||
except Exception:
|
||||
LOG.exception(_LE("delete_servicechain_spec_postcommit failed "
|
||||
"for servicechain_spec %s"),
|
||||
servicechain_spec_id)
|
||||
|
||||
@log.log_method_call
|
||||
def create_servicechain_instance(self, context, servicechain_instance):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
result = super(ServiceChainPlugin,
|
||||
self).create_servicechain_instance(
|
||||
context, servicechain_instance)
|
||||
sc_context = servicechain_context.ServiceChainInstanceContext(
|
||||
self, context, result)
|
||||
self.driver_manager.create_servicechain_instance_precommit(
|
||||
sc_context)
|
||||
|
||||
try:
|
||||
self.driver_manager.create_servicechain_instance_postcommit(
|
||||
sc_context)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE(
|
||||
"driver_manager.create_servicechain_instance_postcommit "
|
||||
"failed, deleting servicechain_instance %s"),
|
||||
result['id'])
|
||||
self.delete_servicechain_instance(context, result['id'])
|
||||
|
||||
return result
|
||||
|
||||
@log.log_method_call
|
||||
def update_servicechain_instance(self, context,
|
||||
servicechain_instance_id,
|
||||
servicechain_instance):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
original_sc_instance = self.get_servicechain_instance(
|
||||
context, servicechain_instance_id)
|
||||
updated_sc_instance = super(ServiceChainPlugin,
|
||||
self).update_servicechain_instance(
|
||||
context, servicechain_instance_id,
|
||||
servicechain_instance)
|
||||
sc_context = servicechain_context.ServiceChainInstanceContext(
|
||||
self, context, updated_sc_instance,
|
||||
original_sc_instance=original_sc_instance)
|
||||
self.driver_manager.update_servicechain_instance_precommit(
|
||||
sc_context)
|
||||
|
||||
self.driver_manager.update_servicechain_instance_postcommit(
|
||||
sc_context)
|
||||
return updated_sc_instance
|
||||
|
||||
@log.log_method_call
|
||||
def delete_servicechain_instance(self, context, servicechain_instance_id):
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
sc_instance = self.get_servicechain_instance(
|
||||
context,
|
||||
servicechain_instance_id)
|
||||
sc_context = servicechain_context.ServiceChainInstanceContext(
|
||||
self, context, sc_instance)
|
||||
self.driver_manager.delete_servicechain_instance_precommit(
|
||||
sc_context)
|
||||
super(ServiceChainPlugin, self).delete_servicechain_instance(
|
||||
context, servicechain_instance_id)
|
||||
|
||||
try:
|
||||
self.driver_manager.delete_servicechain_instance_postcommit(
|
||||
sc_context)
|
||||
except Exception:
|
||||
LOG.exception(_LE("delete_servicechain_instance_postcommit failed "
|
||||
"for servicechain_instance %s"),
|
||||
servicechain_instance_id)
|
||||
|
||||
@log.log_method_call
|
||||
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(_LE(
|
||||
"driver_manager.create_service_profile_postcommit "
|
||||
"failed, deleting service_profile %s"), result['id'])
|
||||
self.delete_service_profile(context, result['id'])
|
||||
|
||||
return result
|
||||
|
||||
@log.log_method_call
|
||||
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_method_call
|
||||
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(_LE("delete_service_profile_postcommit failed "
|
||||
"for service_profile %s"),
|
||||
service_profile_id)
|
@ -35,8 +35,8 @@ DB_GP_PLUGIN_KLASS = (GroupPolicyMappingDBTestPlugin.__module__ + '.' +
|
||||
GroupPolicyMappingDBTestPlugin.__name__)
|
||||
|
||||
SC_PLUGIN_KLASS = (
|
||||
"gbpservice.neutron.services.servicechain.plugins.msc.plugin."
|
||||
"ServiceChainPlugin")
|
||||
"gbpservice.neutron.services.servicechain.plugins.ncp.plugin."
|
||||
"NodeCompositionPlugin")
|
||||
|
||||
|
||||
class GroupPolicyMappingDbTestCase(tgpdb.GroupPolicyDbTestCase,
|
||||
|
@ -20,7 +20,7 @@ from neutron_lib.db import model_base
|
||||
import webob.exc
|
||||
|
||||
from gbpservice.neutron.services.grouppolicy import config
|
||||
from gbpservice.neutron.services.servicechain.plugins.msc import (
|
||||
from gbpservice.neutron.services.servicechain.plugins.ncp import (
|
||||
config as sc_cfg)
|
||||
from gbpservice.neutron.tests.unit.services.grouppolicy import (
|
||||
test_grouppolicy_plugin as test_plugin)
|
||||
@ -40,8 +40,11 @@ class CommonNeutronBaseTestCase(test_plugin.GroupPolicyPluginTestBase):
|
||||
config.cfg.CONF.set_override('policy_drivers',
|
||||
policy_drivers,
|
||||
group='group_policy')
|
||||
sc_cfg.cfg.CONF.set_override('servicechain_drivers',
|
||||
['dummy'], group='servicechain')
|
||||
sc_cfg.cfg.CONF.set_override('node_drivers',
|
||||
['dummy_driver'],
|
||||
group='node_composition_plugin')
|
||||
sc_cfg.cfg.CONF.set_override('node_plumber', 'dummy_plumber',
|
||||
group='node_composition_plugin')
|
||||
config.cfg.CONF.set_override('allow_overlapping_ips', True)
|
||||
super(CommonNeutronBaseTestCase, self).setUp(core_plugin=core_plugin,
|
||||
l3_plugin=l3_plugin,
|
||||
|
@ -31,6 +31,7 @@ from neutron.tests.unit.plugins.ml2 import test_plugin as n_test_plugin
|
||||
from neutron_lib import constants as cst
|
||||
from neutron_lib.db import model_base
|
||||
from oslo_utils import uuidutils
|
||||
import unittest2
|
||||
import webob.exc
|
||||
|
||||
from gbpservice.common import utils
|
||||
@ -43,7 +44,7 @@ from gbpservice.neutron.services.grouppolicy import config
|
||||
from gbpservice.neutron.services.grouppolicy.drivers import chain_mapping
|
||||
from gbpservice.neutron.services.grouppolicy.drivers import nsp_manager
|
||||
from gbpservice.neutron.services.grouppolicy.drivers import resource_mapping
|
||||
from gbpservice.neutron.services.servicechain.plugins.msc import (
|
||||
from gbpservice.neutron.services.servicechain.plugins.ncp import (
|
||||
config as sc_cfg)
|
||||
from gbpservice.neutron.tests.unit.db.grouppolicy import test_group_policy_db
|
||||
from gbpservice.neutron.tests.unit.services.grouppolicy import (
|
||||
@ -81,8 +82,8 @@ class ResourceMappingTestCase(test_plugin.GroupPolicyPluginTestCase):
|
||||
config.cfg.CONF.set_override('policy_drivers',
|
||||
policy_drivers,
|
||||
group='group_policy')
|
||||
sc_cfg.cfg.CONF.set_override('servicechain_drivers',
|
||||
['dummy'], group='servicechain')
|
||||
sc_cfg.cfg.CONF.set_override('node_drivers', ['node_dummy'],
|
||||
group='node_composition_plugin')
|
||||
config.cfg.CONF.set_override('allow_overlapping_ips', True)
|
||||
|
||||
ml2_opts = ml2_options or {
|
||||
@ -2804,6 +2805,9 @@ class TestServiceChain(ResourceMappingTestCase):
|
||||
sc_instances_provider_ptg_ids)
|
||||
self.assertEqual([], sc_instance_update.call_args_list)
|
||||
|
||||
# This test is being skipped because the NCP plugin does not support
|
||||
# multiple servicechain_specs per servicechain_instance
|
||||
@unittest2.skip('skipping')
|
||||
def test_action_spec_value_update(self):
|
||||
scs1_id = self._create_servicechain_spec()
|
||||
action_id, classifier_id, policy_rule_id = (
|
||||
@ -3028,6 +3032,9 @@ class TestServiceChain(ResourceMappingTestCase):
|
||||
self.assertEqual(
|
||||
0, len(sc_instances['servicechain_instances']))
|
||||
|
||||
# This test is being skipped because the NCP plugin does not support
|
||||
# multiple servicechain_specs per servicechain_instance
|
||||
@unittest2.skip('skipping')
|
||||
def test_parent_ruleset_update_for_redirect(self):
|
||||
scs_id = self._create_servicechain_spec()
|
||||
_, classifier_id, policy_rule_id = self._create_tcp_redirect_rule(
|
||||
@ -3078,6 +3085,9 @@ class TestServiceChain(ResourceMappingTestCase):
|
||||
|
||||
self._verify_ptg_delete_cleanup_chain(provider_ptg_id)
|
||||
|
||||
# This test is being skipped because the NCP plugin does not support
|
||||
# multiple servicechain_specs per servicechain_instance
|
||||
@unittest2.skip('skipping')
|
||||
def test_enforce_parent_redirect_after_ptg_create(self):
|
||||
scs_id = self._create_servicechain_spec()
|
||||
_, classifier_id, policy_rule_id = self._create_tcp_redirect_rule(
|
||||
@ -3138,6 +3148,9 @@ class TestServiceChain(ResourceMappingTestCase):
|
||||
|
||||
self._verify_ptg_delete_cleanup_chain(provider_ptg_id)
|
||||
|
||||
# This test is being skipped because the NCP plugin does not support
|
||||
# multiple servicechain_specs per servicechain_instance
|
||||
@unittest2.skip('skipping')
|
||||
def test_hierarchical_redirect(self):
|
||||
scs_id = self._create_servicechain_spec()
|
||||
action_id, classifier_id, policy_rule_id = (
|
||||
@ -3222,6 +3235,9 @@ class TestServiceChain(ResourceMappingTestCase):
|
||||
|
||||
self._verify_ptg_delete_cleanup_chain(provider_ptg2_id)
|
||||
|
||||
# This test is being skipped because the NCP plugin does not support
|
||||
# multiple servicechain_specs per servicechain_instance
|
||||
@unittest2.skip('skipping')
|
||||
def test_rule_update_hierarchial_prs(self):
|
||||
scs_id = self._create_servicechain_spec()
|
||||
action_id, classifier_id, policy_rule_id = (
|
||||
@ -3322,6 +3338,9 @@ class TestServiceChain(ResourceMappingTestCase):
|
||||
[parent_scs_id, scs2_id], classifier_id=classifier_id)
|
||||
self._verify_ptg_delete_cleanup_chain(provider_ptg_id)
|
||||
|
||||
# This test is being skipped because the NCP plugin does not support
|
||||
# multiple servicechain_specs per servicechain_instance
|
||||
@unittest2.skip('skipping')
|
||||
def test_redirect_multiple_ptgs_single_prs(self):
|
||||
scs_id = self._create_servicechain_spec()
|
||||
_, _, policy_rule_id = self._create_tcp_redirect_rule(
|
||||
|
@ -18,28 +18,28 @@ from neutron import context as n_ctx
|
||||
from oslo_config import cfg
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from gbpservice.neutron.services.servicechain.plugins.msc import (
|
||||
plugin as msc_plugin)
|
||||
from gbpservice.neutron.services.servicechain.plugins.msc import context
|
||||
from gbpservice.neutron.services.servicechain.plugins.ncp import (
|
||||
plugin as ncp_plugin)
|
||||
from gbpservice.neutron.services.servicechain.plugins.ncp import context
|
||||
from gbpservice.neutron.tests.unit.db.grouppolicy import (
|
||||
test_servicechain_db as test_servicechain_db)
|
||||
from gbpservice.neutron.tests.unit.db.grouppolicy import test_group_policy_db
|
||||
|
||||
cfg.CONF.import_opt(
|
||||
'servicechain_drivers',
|
||||
'gbpservice.neutron.services.servicechain.plugins.msc.config',
|
||||
group='servicechain')
|
||||
'node_drivers',
|
||||
'gbpservice.neutron.services.servicechain.plugins.ncp.config',
|
||||
group='node_composition_plugin')
|
||||
|
||||
|
||||
class ServiceChainMSCTestPlugin(msc_plugin.ServiceChainPlugin):
|
||||
class ServiceChainNCPTestPlugin(ncp_plugin.NodeCompositionPlugin):
|
||||
|
||||
supported_extension_aliases = ['servicechain'] + (
|
||||
test_group_policy_db.UNSUPPORTED_REQUIRED_EXTS)
|
||||
path_prefix = "/servicechain"
|
||||
|
||||
|
||||
SC_PLUGIN_KLASS = (ServiceChainMSCTestPlugin.__module__ + '.' +
|
||||
ServiceChainMSCTestPlugin.__name__)
|
||||
SC_PLUGIN_KLASS = (ServiceChainNCPTestPlugin.__module__ + '.' +
|
||||
ServiceChainNCPTestPlugin.__name__)
|
||||
|
||||
|
||||
class ServiceChainPluginTestCase(test_servicechain_db.ServiceChainDbTestCase):
|
||||
@ -51,7 +51,7 @@ class ServiceChainPluginTestCase(test_servicechain_db.ServiceChainDbTestCase):
|
||||
gp_plugin=gp_plugin)
|
||||
|
||||
|
||||
class TestGroupPolicyPluginGroupResources(
|
||||
class BaseTestGroupPolicyPluginGroupResources(
|
||||
ServiceChainPluginTestCase,
|
||||
test_servicechain_db.TestServiceChainResources):
|
||||
|
||||
@ -159,13 +159,14 @@ class TestGroupPolicyPluginGroupResources(
|
||||
current = self.create_servicechain_node(
|
||||
service_profile_id=prof['id'],
|
||||
expected_res_status=201)['servicechain_node']
|
||||
ctx = context.ServiceChainNodeContext(self.plugin, plugin_context,
|
||||
current)
|
||||
ctx = context.NodeDriverContext(self.plugin, plugin_context,
|
||||
None, None, current, 0,
|
||||
prof, None)
|
||||
|
||||
self.assertIsNone(ctx.original)
|
||||
self.assertIsNone(ctx.original_node)
|
||||
self.assertIsNone(ctx.original_profile)
|
||||
self.assertEqual(ctx.current['id'], current['id'])
|
||||
self.assertEqual(ctx.current_profile['id'], prof['id'])
|
||||
self.assertEqual(ctx.current_node, current)
|
||||
self.assertEqual(ctx.current_profile, prof)
|
||||
|
||||
# Original node with profile
|
||||
|
||||
@ -174,13 +175,15 @@ class TestGroupPolicyPluginGroupResources(
|
||||
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)
|
||||
ctx = context.NodeDriverContext(
|
||||
self.plugin, plugin_context, None, None, current, 0,
|
||||
prof, None, original_service_chain_node=original,
|
||||
original_service_profile=prof2)
|
||||
|
||||
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'])
|
||||
self.assertEqual(ctx.original_node, original)
|
||||
self.assertEqual(ctx.original_profile, prof2)
|
||||
self.assertEqual(ctx.current_node, current)
|
||||
self.assertEqual(ctx.current_profile, prof)
|
||||
|
||||
def test_node_context_no_profile(self):
|
||||
|
||||
@ -191,23 +194,25 @@ class TestGroupPolicyPluginGroupResources(
|
||||
current = self.create_servicechain_node(
|
||||
service_type='TEST',
|
||||
expected_res_status=201)['servicechain_node']
|
||||
ctx = context.ServiceChainNodeContext(self.plugin, plugin_context,
|
||||
current)
|
||||
ctx = context.NodeDriverContext(self.plugin, plugin_context,
|
||||
None, None, current, 0,
|
||||
None, None)
|
||||
|
||||
self.assertIsNone(ctx.original)
|
||||
self.assertIsNone(ctx.original_node)
|
||||
self.assertIsNone(ctx.original_profile)
|
||||
self.assertEqual(ctx.current['id'], current['id'])
|
||||
self.assertEqual(ctx.current_node, current)
|
||||
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)
|
||||
ctx = context.NodeDriverContext(
|
||||
self.plugin, plugin_context, None, None, current, 0,
|
||||
None, None, original_service_chain_node=original)
|
||||
|
||||
self.assertEqual(ctx.original['id'], original['id'])
|
||||
self.assertEqual(ctx.original_node, original)
|
||||
self.assertIsNone(ctx.original_profile)
|
||||
self.assertEqual(ctx.current['id'], current['id'])
|
||||
self.assertEqual(ctx.current_node, current)
|
||||
self.assertIsNone(ctx.current_profile)
|
||||
|
||||
def test_spec_parameters(self):
|
@ -39,7 +39,7 @@ from gbpservice.neutron.tests.unit.db.grouppolicy import test_group_policy_db
|
||||
from gbpservice.neutron.tests.unit.services.grouppolicy import (
|
||||
test_resource_mapping as test_gp_driver)
|
||||
from gbpservice.neutron.tests.unit.services.servicechain import (
|
||||
test_servicechain_plugin as test_base)
|
||||
base_test_servicechain_plugin as test_base)
|
||||
|
||||
|
||||
class ServiceChainNCPTestPlugin(ncp_plugin.NodeCompositionPlugin):
|
||||
@ -125,7 +125,7 @@ class NodeCompositionPluginTestMixin(object):
|
||||
|
||||
|
||||
class NodeCompositionPluginTestCase(
|
||||
test_base.TestGroupPolicyPluginGroupResources,
|
||||
test_base.BaseTestGroupPolicyPluginGroupResources,
|
||||
NodeCompositionPluginTestMixin):
|
||||
|
||||
def setUp(self, core_plugin=None, gp_plugin=None, node_drivers=None,
|
||||
|
@ -28,7 +28,7 @@ from gbpservice.neutron.tests.unit.db.grouppolicy import test_group_policy_db
|
||||
from gbpservice.neutron.tests.unit.services.grouppolicy import (
|
||||
test_resource_mapping as test_gp_driver)
|
||||
from gbpservice.neutron.tests.unit.services.servicechain import (
|
||||
test_servicechain_plugin as test_base)
|
||||
base_test_servicechain_plugin as test_base)
|
||||
from gbpservice.neutron.tests.unit.services.servicechain.ncp import (
|
||||
test_ncp_plugin as test_ncp_plugin)
|
||||
|
||||
@ -52,7 +52,7 @@ GP_PLUGIN_KLASS = (
|
||||
|
||||
|
||||
class NFPNodeDriverTestCase(
|
||||
test_base.TestGroupPolicyPluginGroupResources,
|
||||
test_base.BaseTestGroupPolicyPluginGroupResources,
|
||||
test_ncp_plugin.NodeCompositionPluginTestMixin):
|
||||
|
||||
DEFAULT_VPN_CONFIG_DICT = {
|
||||
|
@ -1,311 +0,0 @@
|
||||
# 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 heatclient
|
||||
import mock
|
||||
from neutron.plugins.common import constants
|
||||
from oslo_serialization import jsonutils
|
||||
from oslo_utils import uuidutils
|
||||
import webob
|
||||
|
||||
from gbpservice.neutron.services.servicechain.plugins.msc import config
|
||||
from gbpservice.neutron.services.servicechain.plugins.msc.drivers import (
|
||||
simplechain_driver as simplechain_driver)
|
||||
from gbpservice.neutron.tests.unit.services.servicechain import (
|
||||
test_servicechain_plugin as test_servicechain_plugin)
|
||||
|
||||
|
||||
STACK_DELETE_RETRIES = 5
|
||||
STACK_DELETE_RETRY_WAIT = 3
|
||||
|
||||
|
||||
class MockStackObject(object):
|
||||
def __init__(self, status):
|
||||
self.stack_status = status
|
||||
|
||||
|
||||
class MockHeatClientFunctions(object):
|
||||
def delete(self, stack_id):
|
||||
raise heatclient.exc.HTTPNotFound()
|
||||
|
||||
def create(self, **fields):
|
||||
return {'stack': {'id': uuidutils.generate_uuid()}}
|
||||
|
||||
def get(self, stack_id):
|
||||
return MockStackObject('DELETE_COMPLETE')
|
||||
|
||||
def update(self, *args, **fields):
|
||||
return {'stack': {'id': uuidutils.generate_uuid()}}
|
||||
|
||||
|
||||
class MockHeatClient(object):
|
||||
def __init__(self, api_version, endpoint, **kwargs):
|
||||
self.stacks = MockHeatClientFunctions()
|
||||
|
||||
|
||||
class SimpleChainDriverTestCase(
|
||||
test_servicechain_plugin.ServiceChainPluginTestCase):
|
||||
|
||||
def setUp(self):
|
||||
config.cfg.CONF.set_override('servicechain_drivers',
|
||||
['simplechain_driver'],
|
||||
group='servicechain')
|
||||
config.cfg.CONF.set_override('stack_delete_retries',
|
||||
STACK_DELETE_RETRIES,
|
||||
group='simplechain')
|
||||
config.cfg.CONF.set_override('stack_delete_retry_wait',
|
||||
STACK_DELETE_RETRY_WAIT,
|
||||
group='simplechain')
|
||||
super(SimpleChainDriverTestCase, self).setUp()
|
||||
key_client = mock.patch(
|
||||
'gbpservice.neutron.services.servicechain.plugins.msc.drivers.'
|
||||
'simplechain_driver.HeatClient._get_auth_token').start()
|
||||
key_client.return_value = 'mysplendidtoken'
|
||||
|
||||
|
||||
class TestServiceChainInstance(SimpleChainDriverTestCase):
|
||||
|
||||
def test_invalid_service_type_rejected(self):
|
||||
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_profiled_servicechain_node(
|
||||
service_type=constants.FIREWALL, config='{}',
|
||||
expected_res_status=webob.exc.HTTPCreated.code)
|
||||
self.assertEqual('{}', res['servicechain_node']['config'])
|
||||
|
||||
def test_in_use_node_config_update_rejected(self):
|
||||
node = self.create_servicechain_node(
|
||||
service_type=constants.FIREWALL, config='{}',
|
||||
expected_res_status=webob.exc.HTTPCreated.code)[
|
||||
'servicechain_node']
|
||||
self.assertEqual('{}', node['config'])
|
||||
spec = self.create_servicechain_spec(
|
||||
nodes=[node['id']],
|
||||
expected_res_status=webob.exc.HTTPCreated.code)[
|
||||
'servicechain_spec']
|
||||
with mock.patch.object(simplechain_driver.HeatClient,
|
||||
'create') as stack_create:
|
||||
stack_create.return_value = {'stack': {
|
||||
'id': uuidutils.generate_uuid()}}
|
||||
self.create_servicechain_instance(servicechain_specs=[spec['id']])
|
||||
res = self.update_servicechain_node(
|
||||
node['id'],
|
||||
config='{"key": "value"}',
|
||||
expected_res_status=webob.exc.HTTPBadRequest.code)
|
||||
self.assertEqual('NodeUpdateNotSupported',
|
||||
res['NeutronError']['type'])
|
||||
|
||||
def test_chain_spec_update(self):
|
||||
template1 = '{"key1":"value1"}'
|
||||
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_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])
|
||||
sc_spec_id = scs['servicechain_spec']['id']
|
||||
|
||||
stack1 = {'stack': {'id': uuidutils.generate_uuid()}}
|
||||
stack2 = {'stack': {'id': uuidutils.generate_uuid()}}
|
||||
stack3 = {'stack': {'id': uuidutils.generate_uuid()}}
|
||||
expected_create_calls = []
|
||||
expected_delete_calls = []
|
||||
with mock.patch.object(simplechain_driver.HeatClient,
|
||||
'create') as stack_create:
|
||||
with mock.patch.object(simplechain_driver.HeatClient,
|
||||
'delete') as stack_delete:
|
||||
stack_create.return_value = stack1
|
||||
instance1_name = "sc_instance_1"
|
||||
sc_instance1 = self.create_servicechain_instance(
|
||||
name=instance1_name,
|
||||
servicechain_specs=[sc_spec_id])
|
||||
sci1_id = sc_instance1['servicechain_instance']['id']
|
||||
self.assertEqual([sc_spec_id],
|
||||
sc_instance1['servicechain_instance'][
|
||||
'servicechain_specs'])
|
||||
stack_name = ("stack_" + instance1_name + scn1_name +
|
||||
sci1_id[:8])
|
||||
expected_create_calls.append(
|
||||
mock.call(stack_name,
|
||||
jsonutils.loads(template1), {}))
|
||||
stack_create.return_value = stack2
|
||||
instance2_name = "sc_instance_2"
|
||||
sc_instance2 = self.create_servicechain_instance(
|
||||
name=instance2_name,
|
||||
servicechain_specs=[sc_spec_id])
|
||||
sci2_id = sc_instance2['servicechain_instance']['id']
|
||||
self.assertEqual(
|
||||
[sc_spec_id],
|
||||
sc_instance2['servicechain_instance'][
|
||||
'servicechain_specs'])
|
||||
stack_name = ("stack_" + instance2_name + scn1_name +
|
||||
sci2_id[:8])
|
||||
expected_create_calls.append(
|
||||
mock.call(stack_name, jsonutils.loads(template1), {}))
|
||||
|
||||
#Now perform an update of the spec
|
||||
new_spec = {'servicechain_spec': {'nodes': [scn2_id]}}
|
||||
stack_create.return_value = stack3
|
||||
req = self.new_update_request(
|
||||
'servicechain_specs', new_spec, sc_spec_id)
|
||||
res = req.get_response(self.ext_api)
|
||||
self.assertEqual(webob.exc.HTTPOk.code, res.status_int)
|
||||
# The two existing stacks will be deleted and two new stacks
|
||||
# will be created
|
||||
expected_delete_calls.append(mock.call(stack1['stack']['id']))
|
||||
expected_delete_calls.append(mock.call(stack2['stack']['id']))
|
||||
stack_name = ("stack_" + instance1_name + scn2_name +
|
||||
sci1_id[:8])
|
||||
expected_create_calls.append(
|
||||
mock.call(stack_name, jsonutils.loads(template2), {}))
|
||||
stack_name = ("stack_" + instance2_name + scn2_name +
|
||||
sci2_id[:8])
|
||||
expected_create_calls.append(
|
||||
mock.call(stack_name, jsonutils.loads(template2), {}))
|
||||
self.assertEqual(expected_delete_calls,
|
||||
stack_delete.call_args_list)
|
||||
self.assertEqual(expected_create_calls,
|
||||
stack_create.call_args_list)
|
||||
|
||||
def test_chain_instance_create(self):
|
||||
name = "scs1"
|
||||
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']
|
||||
|
||||
with mock.patch.object(simplechain_driver.HeatClient,
|
||||
'create') as stack_create:
|
||||
stack_create.return_value = {'stack': {
|
||||
'id': uuidutils.generate_uuid()}}
|
||||
sc_instance = self.create_servicechain_instance(
|
||||
name="sc_instance_1",
|
||||
servicechain_specs=[sc_spec_id])
|
||||
expected_stack_name = (
|
||||
"stack_" + "sc_instance_1" +
|
||||
scn['servicechain_node']['name'] +
|
||||
sc_instance['servicechain_instance']['id'][:8])
|
||||
self.assertEqual(
|
||||
[sc_spec_id],
|
||||
sc_instance['servicechain_instance']['servicechain_specs'])
|
||||
stack_create.assert_called_once_with(
|
||||
expected_stack_name, mock.ANY, mock.ANY)
|
||||
|
||||
def test_chain_instance_delete(self):
|
||||
name = "scs1"
|
||||
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']
|
||||
|
||||
with mock.patch.object(simplechain_driver.HeatClient,
|
||||
'create') as stack_create:
|
||||
stack_create.return_value = {'stack': {
|
||||
'id': uuidutils.generate_uuid()}}
|
||||
sc_instance = self.create_servicechain_instance(
|
||||
name="sc_instance_1",
|
||||
servicechain_specs=[sc_spec_id])
|
||||
self.assertEqual([sc_spec_id],
|
||||
sc_instance['servicechain_instance']['servicechain_specs'])
|
||||
with mock.patch.object(simplechain_driver.HeatClient,
|
||||
'delete'):
|
||||
req = self.new_delete_request(
|
||||
'servicechain_instances',
|
||||
sc_instance['servicechain_instance']['id'])
|
||||
res = req.get_response(self.ext_api)
|
||||
self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
|
||||
|
||||
def test_wait_stack_delete_for_instance_delete(self):
|
||||
name = "scs1"
|
||||
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']
|
||||
|
||||
with mock.patch.object(simplechain_driver.HeatClient,
|
||||
'create') as stack_create:
|
||||
stack_create.return_value = {'stack': {
|
||||
'id': uuidutils.generate_uuid()}}
|
||||
sc_instance = self.create_servicechain_instance(
|
||||
name="sc_instance_1",
|
||||
servicechain_specs=[sc_spec_id])
|
||||
self.assertEqual([sc_spec_id],
|
||||
sc_instance['servicechain_instance']['servicechain_specs'])
|
||||
|
||||
# Verify that as part of delete service chain instance we call
|
||||
# get method for heat stack 5 times before giving up if the state
|
||||
# does not become DELETE_COMPLETE
|
||||
with mock.patch.object(simplechain_driver.HeatClient,
|
||||
'delete') as stack_delete:
|
||||
with mock.patch.object(simplechain_driver.HeatClient,
|
||||
'get') as stack_get:
|
||||
stack_get.return_value = MockStackObject('PENDING_DELETE')
|
||||
req = self.new_delete_request(
|
||||
'servicechain_instances',
|
||||
sc_instance['servicechain_instance']['id'])
|
||||
res = req.get_response(self.ext_api)
|
||||
self.assertEqual(webob.exc.HTTPNoContent.code,
|
||||
res.status_int)
|
||||
stack_delete.assert_called_once_with(mock.ANY)
|
||||
self.assertEqual(STACK_DELETE_RETRIES,
|
||||
stack_get.call_count)
|
||||
|
||||
# Create and delete another service chain instance and verify that
|
||||
# we call get method for heat stack only once if the stack state
|
||||
# is DELETE_COMPLETE
|
||||
sc_instance = self.create_servicechain_instance(
|
||||
name="sc_instance_1",
|
||||
servicechain_specs=[sc_spec_id])
|
||||
self.assertEqual(
|
||||
[sc_spec_id],
|
||||
sc_instance['servicechain_instance']['servicechain_specs'])
|
||||
with mock.patch.object(simplechain_driver.HeatClient,
|
||||
'delete') as stack_delete:
|
||||
with mock.patch.object(simplechain_driver.HeatClient,
|
||||
'get') as stack_get:
|
||||
stack_get.return_value = MockStackObject(
|
||||
'DELETE_COMPLETE')
|
||||
req = self.new_delete_request(
|
||||
'servicechain_instances',
|
||||
sc_instance['servicechain_instance']['id'])
|
||||
res = req.get_response(self.ext_api)
|
||||
self.assertEqual(webob.exc.HTTPNoContent.code,
|
||||
res.status_int)
|
||||
stack_delete.assert_called_once_with(mock.ANY)
|
||||
self.assertEqual(1, stack_get.call_count)
|
||||
|
||||
def test_stack_not_found_ignored(self):
|
||||
name = "scs1"
|
||||
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']
|
||||
|
||||
mock.patch(heatclient.__name__ + ".client.Client",
|
||||
new=MockHeatClient).start()
|
||||
sc_instance = self.create_servicechain_instance(
|
||||
name="sc_instance_1",
|
||||
servicechain_specs=[sc_spec_id])
|
||||
req = self.new_delete_request(
|
||||
'servicechain_instances',
|
||||
sc_instance['servicechain_instance']['id'])
|
||||
res = req.get_response(self.ext_api)
|
||||
self.assertEqual(webob.exc.HTTPNoContent.code, res.status_int)
|
@ -25,9 +25,6 @@ packages =
|
||||
data_files =
|
||||
etc/group-based-policy/policy.d =
|
||||
etc/policy.json
|
||||
etc/servicechain/plugins/msc =
|
||||
etc/servicechain/plugins/msc/servicechain.ini
|
||||
etc/servicechain/plugins/msc/simplechain.ini
|
||||
etc/group-based-policy/drivers =
|
||||
etc/drivers/implicit_policy.ini
|
||||
etc/drivers/resource_mapping.ini
|
||||
@ -47,8 +44,6 @@ neutron.core_plugins =
|
||||
ml2plus = gbpservice.neutron.plugins.ml2plus.plugin:Ml2PlusPlugin
|
||||
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
|
||||
apic_gbp_l3 = gbpservice.neutron.services.l3_router.l3_apic:ApicGBPL3ServicePlugin
|
||||
nfp_fwaas = gbpservice.contrib.nfp.service_plugins.firewall.nfp_fwaas_plugin:NFPFirewallPlugin
|
||||
@ -77,9 +72,6 @@ neutron.ml2.extension_drivers =
|
||||
apic_aim = gbpservice.neutron.plugins.ml2plus.drivers.apic_aim.extension_driver:ApicExtensionDriver
|
||||
test_ml2plus = gbpservice.neutron.tests.unit.plugins.ml2plus.drivers.extension_test:TestExtensionDriver
|
||||
testdb_ml2plus = gbpservice.neutron.tests.unit.plugins.ml2plus.drivers.extension_test:TestDBExtensionDriver
|
||||
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
|
||||
gbpservice.neutron.servicechain.ncp_drivers =
|
||||
node_dummy = gbpservice.neutron.services.servicechain.plugins.ncp.node_drivers.dummy_driver:NoopNodeDriver
|
||||
heat_node_driver = gbpservice.neutron.services.servicechain.plugins.ncp.node_drivers.heat_node_driver:HeatNodeDriver
|
||||
|
Loading…
Reference in New Issue
Block a user