group-based-policy/gbpservice/neutron/extensions/servicechain.py

458 lines
18 KiB
Python

# 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
from neutron.api import extensions as neutron_extensions
from neutron.api.v2 import attributes as attr
from neutron.api.v2 import resource_helper
from neutron.plugins.common import constants
from neutron_lib.api import converters as conv
from neutron_lib.api import extensions
from neutron_lib.api import validators as valid
from neutron_lib import exceptions as nexc
from neutron_lib.services import base as service_base
from oslo_config import cfg
from oslo_log import log as logging
import six
from gbpservice.neutron import extensions as gbp_extensions
import gbpservice.neutron.extensions.group_policy # noqa
from gbpservice.neutron.services.servicechain.common import constants as scc
# The code below is a monkey patch of key Neutron's modules. This is needed for
# the GBP service to be loaded correctly. GBP extensions' path is added
# to Neutron's so that it's found at extension scanning time.
neutron_extensions.append_api_extensions_path(gbp_extensions.__path__)
LOG = logging.getLogger(__name__)
# Service Chain Exceptions
class ServiceProfileNotFound(nexc.NotFound):
message = _("ServiceProfile %(profile_id)s could not be found")
class ServiceProfileInUse(nexc.NotFound):
message = _("Unable to complete operation, ServiceProfile "
"%(profile_id)s is in use")
class ServiceChainNodeNotFound(nexc.NotFound):
message = _("ServiceChainNode %(sc_node_id)s could not be found")
class ServiceChainSpecNotFound(nexc.NotFound):
message = _("ServiceChainSpec %(sc_spec_id)s could not be found")
class ServiceChainInstanceNotFound(nexc.NotFound):
message = _("ServiceChainInstance %(sc_instance_id)s could not be found")
class ServiceChainNodeInUse(nexc.InUse):
message = _("Unable to complete operation, ServiceChainNode "
"%(node_id)s is in use")
class ServiceChainSpecInUse(nexc.InUse):
message = _("Unable to complete operation, ServiceChainSpec "
"%(spec_id)s is in use")
class ServiceTypeNotFound(nexc.NotFound):
message = _("ServiceType %(service_type_id) could not be found")
class ServiceTypeNotSupported(nexc.NotFound):
message = _("ServiceType %(service_type_id) not supported")
class PortNotFound(nexc.NotFound):
message = _("Port %(port_id)s could not be found")
def _validate_str_list(data, valid_values=None):
if not isinstance(data, list):
msg = _("'%s' is not a list") % data
LOG.debug(msg)
return msg
for item in data:
msg = valid.validate_string(item)
if msg:
LOG.debug(msg)
return msg
if len(set(data)) != len(data):
msg = _("Duplicate items in the list: '%s'") % ', '.join(data)
LOG.debug(msg)
return msg
valid.validators['type:string_list'] = _validate_str_list
SERVICECHAIN_NODES = 'servicechain_nodes'
SERVICECHAIN_SPECS = 'servicechain_specs'
SERVICECHAIN_INSTANCES = 'servicechain_instances'
SERVICE_PROFILES = 'service_profiles'
RESOURCE_ATTRIBUTE_MAP = {
SERVICECHAIN_NODES: {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None}, 'is_visible': True,
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True,
'validate': {'type:gbp_resource_name': None}, 'default': '',
'is_visible': True},
'description': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'service_type': {'allow_post': True, 'allow_put': False,
'validate': {'type:string_or_none': None},
'is_visible': True, 'default': None},
'service_profile_id': {'allow_post': True, 'allow_put': True,
'validate': {'type:uuid_or_none': None},
'is_visible': True, 'default': None},
'config': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'required': True, 'is_visible': True},
attr.SHARED: {'allow_post': True, 'allow_put': True,
'default': False, 'convert_to': conv.convert_to_boolean,
'is_visible': True, 'required_by_policy': True,
'enforce_policy': True},
},
SERVICECHAIN_SPECS: {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None}, 'is_visible': True,
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True,
'validate': {'type:gbp_resource_name': None},
'default': '', 'is_visible': True},
'description': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'nodes': {'allow_post': True, 'allow_put': True,
'validate': {'type:uuid_list': None},
'convert_to': conv.convert_none_to_empty_list,
'default': None, 'is_visible': True,
'required': True},
'config_param_names': {'allow_post': False, 'allow_put': False,
'validate': {'type:string_list': None},
'default': [], 'is_visible': True},
attr.SHARED: {'allow_post': True, 'allow_put': True,
'default': False, 'convert_to': conv.convert_to_boolean,
'is_visible': True, 'required_by_policy': True,
'enforce_policy': True},
},
SERVICECHAIN_INSTANCES: {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None}, 'is_visible': True,
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True,
'validate': {'type:gbp_resource_name': None},
'default': '', 'is_visible': True},
'description': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'servicechain_specs': {'allow_post': True, 'allow_put': True,
'validate': {'type:uuid_list': None},
'convert_to': conv.convert_none_to_empty_list,
'default': None, 'is_visible': True,
'required': True},
'provider_ptg_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:uuid_or_none': None},
'is_visible': True, 'default': None,
'required': True},
'consumer_ptg_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string_or_none': None},
'is_visible': True, 'default': None,
'required': True},
'management_ptg_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:uuid_or_none': None},
'is_visible': True, 'default': None,
'required': True},
'classifier_id': {'allow_post': True, 'allow_put': True,
'validate': {'type:uuid_or_none': None},
'is_visible': True, 'default': None,
'required': True},
'config_param_values': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'default': "", 'is_visible': True},
},
SERVICE_PROFILES: {
'id': {'allow_post': False, 'allow_put': False,
'validate': {'type:uuid': None}, 'is_visible': True,
'primary_key': True},
'name': {'allow_post': True, 'allow_put': True,
'validate': {'type:gbp_resource_name': None},
'default': '', 'is_visible': True},
'description': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'tenant_id': {'allow_post': True, 'allow_put': False,
'validate': {'type:string': None},
'required_by_policy': True, 'is_visible': True},
'status': {'allow_post': False, 'allow_put': False,
'is_visible': True},
'status_details': {'allow_post': False, 'allow_put': False,
'is_visible': True},
attr.SHARED: {'allow_post': True, 'allow_put': True,
'default': False, 'convert_to': conv.convert_to_boolean,
'is_visible': True, 'required_by_policy': True,
'enforce_policy': True},
'vendor': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'default': ''},
'insertion_mode': {'allow_post': True, 'allow_put': True,
'validate': {'type:values':
scc.VALID_INSERTION_MODES},
'is_visible': True, 'default': None},
'service_type': {'allow_post': True, 'allow_put': True,
'validate': {'type:string': None},
'is_visible': True, 'required': True},
'service_flavor': {'allow_post': True, 'allow_put': True,
'validate': {'type:string_or_none': None},
'is_visible': True, 'default': None},
},
}
service_chain_quota_opts = [
cfg.IntOpt('quota_servicechain_node',
default=-1,
help=_('Number of Service Chain Nodes allowed per tenant. '
'A negative value means unlimited.')),
cfg.IntOpt('quota_servicechain_spec',
default=-1,
help=_('Number of Service Chain Specs allowed per tenant. '
'A negative value means unlimited.')),
cfg.IntOpt('quota_servicechain_instance',
default=-1,
help=_('Number of Service Chain Instances allowed per tenant. '
'A negative value means unlimited.')),
cfg.IntOpt('quota_service_profile',
default=-1,
help=_('Number of Service Profiles allowed per tenant. '
'A negative value means unlimited.')),
]
cfg.CONF.register_opts(service_chain_quota_opts, 'QUOTAS')
class Servicechain(extensions.ExtensionDescriptor):
@classmethod
def get_name(cls):
return "Service Chain Abstraction"
@classmethod
def get_alias(cls):
return "servicechain"
@classmethod
def get_description(cls):
return "Extension for Service Chain Abstraction"
@classmethod
def get_namespace(cls):
return "https://wiki.openstack.org/wiki/Neutron/sc/v2.0/"
@classmethod
def get_updated(cls):
return "2014-08-03T12:00:00-00:00"
@classmethod
def get_resources(cls):
plural_mappings = resource_helper.build_plural_mappings(
{}, RESOURCE_ATTRIBUTE_MAP)
gbp_extensions.register_plurals(plural_mappings)
return resource_helper.build_resource_info(plural_mappings,
RESOURCE_ATTRIBUTE_MAP,
constants.SERVICECHAIN,
register_quota=True)
@classmethod
def get_plugin_interface(cls):
return ServiceChainPluginBase
def update_attributes_map(self, attributes):
super(Servicechain, self).update_attributes_map(
attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP)
def get_extended_resources(self, version):
if version == "2.0":
return RESOURCE_ATTRIBUTE_MAP
else:
return {}
@six.add_metaclass(abc.ABCMeta)
class ServiceChainPluginBase(service_base.ServicePluginBase):
def get_plugin_name(self):
return constants.SERVICECHAIN
def get_plugin_type(self):
return constants.SERVICECHAIN
def get_plugin_description(self):
return 'Service Chain plugin'
def update_chains_pt_added(self, context, policy_target, instance_id):
""" Auto scaling function.
Override this method to react to policy target creation.
"""
pass
def update_chains_pt_removed(self, context, policy_target, instance_id):
""" Auto scaling function.
Override this method to react to policy target deletion.
"""
pass
def update_chains_consumer_added(self, context, policy_target_group,
instance_id):
""" Auto scaling function.
Override this method to react to policy target group addition as
a consumer of a chain.
"""
pass
def update_chains_consumer_removed(self, context, policy_target_group,
instance_id):
""" Auto scaling function.
Override this method to react to policy target group removed as a
consumer of a chain
"""
pass
def policy_target_group_updated(self, context, old_policy_target_group,
current_policy_target_group,
instance_id):
""" Utility function.
Override this method to react to policy target group update
"""
pass
@abc.abstractmethod
def get_servicechain_nodes(self, context, filters=None, fields=None):
pass
@abc.abstractmethod
def get_servicechain_node(self, context, servicechain_node_id,
fields=None):
pass
@abc.abstractmethod
def create_servicechain_node(self, context, servicechain_node):
pass
@abc.abstractmethod
def update_servicechain_node(self, context, servicechain_node_id,
servicechain_node):
pass
@abc.abstractmethod
def delete_servicechain_node(self, context, servicechain_node_id):
pass
@abc.abstractmethod
def get_servicechain_specs(self, context, filters=None, fields=None):
pass
@abc.abstractmethod
def get_servicechain_spec(self, context, servicechain_spec_id,
fields=None):
pass
@abc.abstractmethod
def create_servicechain_spec(self, context, servicechain_spec):
pass
@abc.abstractmethod
def update_servicechain_spec(self, context, servicechain_spec_id,
servicechain_spec):
pass
@abc.abstractmethod
def delete_servicechain_spec(self, context, servicechain_spec_id):
pass
@abc.abstractmethod
def get_servicechain_instances(self, context, filters=None, fields=None):
pass
@abc.abstractmethod
def get_servicechain_instance(self, context, servicechain_instance_id,
fields=None):
pass
@abc.abstractmethod
def create_servicechain_instance(self, context, servicechain_instance):
pass
@abc.abstractmethod
def update_servicechain_instance(self, context, servicechain_instance_id,
servicechain_instance):
pass
@abc.abstractmethod
def delete_servicechain_instance(self, context, servicechain_instance_id):
pass
@abc.abstractmethod
def create_service_profile(self, context, service_profile):
pass
@abc.abstractmethod
def update_service_profile(self, context, service_profile_id,
service_profile):
pass
@abc.abstractmethod
def delete_service_profile(self, context, service_profile_id):
pass
@abc.abstractmethod
def get_service_profile(self, context, service_profile_id, fields=None):
pass
@abc.abstractmethod
def get_service_profiles(self, context, filters=None, fields=None):
pass