This patch adds openid token auth support when calling k8s APIs. Openid token auth of k8s relies on an external openid provider, and Keycloak acts as the openid provider in this implementation. Implements: blueprint support-openid-k8s-vim Change-Id: Ie5e080a20cba3ba0ed514ede7955eb16729d797c
714 lines
21 KiB
Python
714 lines
21 KiB
Python
# Copyright 2015 Intel Corporation..
|
|
# All Rights Reserved.
|
|
#
|
|
# 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 oslo_log import log as logging
|
|
|
|
from tacker._i18n import _
|
|
from tacker.api import extensions
|
|
from tacker.api.v1 import attributes as attr
|
|
from tacker.api.v1 import base
|
|
from tacker.api.v1 import resource_helper
|
|
from tacker.common import exceptions
|
|
from tacker import manager
|
|
from tacker.plugins.common import constants
|
|
from tacker.services import service_base
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class MultipleMGMTDriversSpecified(exceptions.InvalidInput):
|
|
message = _('More than one MGMT Driver per vnfd is not supported')
|
|
|
|
|
|
class ServiceTypesNotSpecified(exceptions.InvalidInput):
|
|
message = _('service types are not specified')
|
|
|
|
|
|
class VNFDInUse(exceptions.InUse):
|
|
message = _('VNFD %(vnfd_id)s is still in use')
|
|
|
|
|
|
class VNFInUse(exceptions.InUse):
|
|
message = _('VNF %(vnf_id)s is still in use')
|
|
|
|
|
|
class InvalidMgmtDriver(exceptions.InvalidInput):
|
|
message = _('Invalid Mgmt driver %(mgmt_driver_name)s.')
|
|
|
|
|
|
class InvalidInfraDriver(exceptions.InvalidInput):
|
|
message = _('VIM type %(vim_name)s is not supported as an infra driver')
|
|
|
|
|
|
class InvalidAPIAttributeType(exceptions.InvalidInput):
|
|
message = _('Expecting dict type for API attribute instead of %(atype)s ')
|
|
|
|
|
|
class VNFCreateFailed(exceptions.TackerException):
|
|
message = _('creating VNF based on %(vnfd_id)s failed')
|
|
|
|
|
|
class VNFUpdateInvalidInput(exceptions.TackerException):
|
|
message = _('VNF Update Invalid Input %(reason)s')
|
|
|
|
|
|
class VNFUpdateWaitFailed(exceptions.TackerException):
|
|
message = _('VNF Update %(reason)s')
|
|
|
|
|
|
class VNFCreateWaitFailed(exceptions.TackerException):
|
|
message = _('VNF Create %(reason)s')
|
|
|
|
|
|
class VNFScaleWaitFailed(exceptions.TackerException):
|
|
message = _('%(reason)s')
|
|
|
|
|
|
class VNFDeleteWaitFailed(exceptions.TackerException):
|
|
message = _('VNF Delete %(reason)s')
|
|
|
|
|
|
class VNFHealWaitFailed(exceptions.TackerException):
|
|
message = _('VNF Heal %(reason)s')
|
|
|
|
|
|
class VNFChangeExtConnWaitFailed(exceptions.TackerException):
|
|
message = _('VNF ChangeExtConn %(reason)s')
|
|
|
|
|
|
class VNFDeleteFailed(exceptions.TackerException):
|
|
message = _('%(reason)s')
|
|
|
|
|
|
class VNFHealFailed(exceptions.TackerException):
|
|
message = _('VNF %(vnf_id)s failed to heal')
|
|
|
|
|
|
class VNFDNotFound(exceptions.NotFound):
|
|
message = _('VNFD %(vnfd_id)s could not be found')
|
|
|
|
|
|
class CnfDefinitionNotFound(exceptions.NotFound):
|
|
message = _(
|
|
"CNF definition file with path %(path)s "
|
|
"is not found in vnf_artifacts.")
|
|
|
|
|
|
class CNFCreateWaitFailed(exceptions.TackerException):
|
|
message = _('CNF Create Failed with reason: %(reason)s')
|
|
|
|
|
|
class CNFScaleFailed(exceptions.TackerException):
|
|
message = _('CNF Scale Failed with reason: %(reason)s')
|
|
|
|
|
|
class CNFScaleWaitFailed(exceptions.TackerException):
|
|
message = _('CNF Scale Wait Failed with reason: %(reason)s')
|
|
|
|
|
|
class CNFHealFailed(exceptions.TackerException):
|
|
message = _('%(reason)s')
|
|
|
|
|
|
class CNFHealWaitFailed(exceptions.TackerException):
|
|
message = _('%(reason)s')
|
|
|
|
|
|
class InvalidVimConnectionInfo(exceptions.TackerException):
|
|
message = _('Invalid vim_connection_info: %(reason)s')
|
|
|
|
|
|
class HelmClientRemoteCommandError(exceptions.TackerException):
|
|
message = _('Failed to execute remote command.')
|
|
|
|
|
|
class HelmClientMissingParamsError(exceptions.TackerException):
|
|
message = _('The specified value %(value)s was not found.')
|
|
|
|
|
|
class HelmClientOtherError(exceptions.TackerException):
|
|
message = _('An error occurred in HelmClient: %(error_message)s.')
|
|
|
|
|
|
class ServiceTypeNotFound(exceptions.NotFound):
|
|
message = _('service type %(service_type_id)s could not be found')
|
|
|
|
|
|
class VNFNotFound(exceptions.NotFound):
|
|
message = _('VNF %(vnf_id)s could not be found')
|
|
|
|
|
|
class LCMUserDataFailed(exceptions.TackerException):
|
|
message = _('LCM user data %(reason)s')
|
|
|
|
|
|
class ParamYAMLNotWellFormed(exceptions.InvalidInput):
|
|
message = _("Parameter YAML not well formed - %(error_msg_details)s")
|
|
|
|
|
|
class ToscaParserFailed(exceptions.InvalidInput):
|
|
message = _("tosca-parser failed: - %(error_msg_details)s")
|
|
|
|
|
|
class HeatTranslatorFailed(exceptions.InvalidInput):
|
|
message = _("heat-translator failed: - %(error_msg_details)s")
|
|
|
|
|
|
class HeatClientException(exceptions.TackerException):
|
|
message = _("%(msg)s")
|
|
|
|
|
|
class IPAddrInvalidInput(exceptions.InvalidInput):
|
|
message = _("IP Address input values should be in a list format")
|
|
|
|
|
|
class HugePageSizeInvalidInput(exceptions.InvalidInput):
|
|
message = _("Value specified for mem_page_size is invalid: "
|
|
"%(error_msg_details)s. The valid values are 'small', 'large',"
|
|
" 'any' or an integer value in MB")
|
|
|
|
|
|
class CpuAllocationInvalidKeys(exceptions.InvalidInput):
|
|
message = _("Invalid keys specified in VNFD - %(error_msg_details)s."
|
|
"Supported keys are: %(valid_keys)s")
|
|
|
|
|
|
class CpuAllocationInvalidValues(exceptions.InvalidInput):
|
|
message = _("Invalid values specified in VNFD - %(error_msg_details)s."
|
|
"Supported Values are: %(valid_values)s")
|
|
|
|
|
|
class NumaNodesInvalidKeys(exceptions.InvalidInput):
|
|
message = _("Invalid keys specified in VNFD - %(error_msg_details)s."
|
|
"Supported keys are: %(valid_keys)s")
|
|
|
|
|
|
class FilePathMissing(exceptions.InvalidInput):
|
|
message = _("'file' attribute is missing for "
|
|
"tosca.artifacts.Deployment.Image.VM artifact type")
|
|
|
|
|
|
class InfraDriverUnreachable(exceptions.ServiceUnavailable):
|
|
message = _("Could not retrieve VNF resource IDs and"
|
|
" types. Please check %(service)s status.")
|
|
|
|
|
|
class VNFInactive(exceptions.InvalidInput):
|
|
message = _("VNF %(vnf_id)s is not in Active state: %(message)s")
|
|
|
|
|
|
class MetadataNotMatched(exceptions.InvalidInput):
|
|
message = _("Metadata for alarm policy is not matched")
|
|
|
|
|
|
class InvalidResourceType(exceptions.InvalidInput):
|
|
message = _("Resource type %(resource_type)s for alarm policy "
|
|
"is not supported")
|
|
|
|
|
|
class InvalidSubstitutionMapping(exceptions.InvalidInput):
|
|
message = _("Input for substitution mapping requirements are not"
|
|
" valid for %(requirement)s. They must be in the form"
|
|
" of list with two entries")
|
|
|
|
|
|
class SMRequirementMissing(exceptions.InvalidInput):
|
|
message = _("All the requirements for substitution_mappings are not"
|
|
" provided. Missing requirement for %(requirement)s")
|
|
|
|
|
|
class InvalidParamsForSM(exceptions.InvalidInput):
|
|
message = _("Please provide parameters for substitution mappings")
|
|
|
|
|
|
class InvalidKubernetesScalingPolicyNumber(exceptions.InvalidInput):
|
|
message = _("Please provide only one Scaling policy")
|
|
|
|
|
|
class InvalidKubernetesNetworkNumber(exceptions.InvalidInput):
|
|
message = _("Please provide one network for all vdus")
|
|
|
|
|
|
class InvalidKubernetesInputParameter(exceptions.InvalidInput):
|
|
message = _("Found unsupported keys for %(found_keys)s ")
|
|
|
|
|
|
class InvalidInstReqInfoForScaling(exceptions.InvalidInput):
|
|
message = _("Scaling resource cannot be set to "
|
|
"fixed ip_address or mac_address.")
|
|
|
|
|
|
class InvalidMaintenanceParameter(exceptions.InvalidInput):
|
|
message = _("Could not find the required params for maintenance")
|
|
|
|
|
|
class OIDCAuthFailed(exceptions.InvalidInput):
|
|
message = _("OIDC authentication and authorization failed."
|
|
" Detail: %(detail)s")
|
|
|
|
|
|
def _validate_service_type_list(data, valid_values=None):
|
|
if not isinstance(data, list):
|
|
msg = _("Invalid data format for service list: '%s'") % data
|
|
LOG.debug(msg)
|
|
return msg
|
|
if not data:
|
|
msg = _("Empty list is not allowed for service list. '%s'") % data
|
|
LOG.debug(msg)
|
|
return msg
|
|
key_specs = {
|
|
'service_type': {
|
|
'type:string': None,
|
|
}
|
|
}
|
|
for service in data:
|
|
msg = attr._validate_dict(service, key_specs)
|
|
if msg:
|
|
LOG.debug(msg)
|
|
return msg
|
|
|
|
|
|
attr.validators['type:service_type_list'] = _validate_service_type_list
|
|
|
|
NAME_MAX_LEN = 255
|
|
|
|
RESOURCE_ATTRIBUTE_MAP = {
|
|
|
|
'vnfds': {
|
|
'id': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'validate': {'type:uuid': None},
|
|
'is_visible': True,
|
|
'primary_key': True,
|
|
},
|
|
'tenant_id': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'required_by_policy': True,
|
|
'is_visible': True,
|
|
},
|
|
'name': {
|
|
'allow_post': True,
|
|
'allow_put': True,
|
|
'validate': {'type:string': NAME_MAX_LEN},
|
|
'is_visible': True,
|
|
},
|
|
'description': {
|
|
'allow_post': True,
|
|
'allow_put': True,
|
|
'validate': {'type:string': None},
|
|
'is_visible': True,
|
|
'default': '',
|
|
},
|
|
'service_types': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'convert_to': attr.convert_to_list,
|
|
'validate': {'type:service_type_list': None},
|
|
'is_visible': True,
|
|
'default': attr.ATTR_NOT_SPECIFIED,
|
|
},
|
|
'attributes': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'convert_to': attr.convert_none_to_empty_dict,
|
|
'validate': {'type:dict_or_nodata': None},
|
|
'is_visible': True,
|
|
'default': None,
|
|
},
|
|
'created_at': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
},
|
|
'updated_at': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
},
|
|
'template_source': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
'default': 'onboarded'
|
|
},
|
|
},
|
|
|
|
'vnfs': {
|
|
'id': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'validate': {'type:uuid': None},
|
|
'is_visible': True,
|
|
'primary_key': True
|
|
},
|
|
'tenant_id': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'required_by_policy': True,
|
|
'is_visible': True
|
|
},
|
|
'vnfd_id': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'validate': {'type:uuid': None},
|
|
'is_visible': True,
|
|
'default': None
|
|
},
|
|
'vim_id': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'is_visible': True,
|
|
'default': '',
|
|
},
|
|
'name': {
|
|
'allow_post': True,
|
|
'allow_put': True,
|
|
'validate': {'type:string': NAME_MAX_LEN},
|
|
'is_visible': True,
|
|
},
|
|
'description': {
|
|
'allow_post': True,
|
|
'allow_put': True,
|
|
'validate': {'type:string': None},
|
|
'is_visible': True,
|
|
'default': '',
|
|
},
|
|
'instance_id': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'is_visible': True,
|
|
},
|
|
'mgmt_ip_address': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'is_visible': True,
|
|
},
|
|
'attributes': {
|
|
'allow_post': True,
|
|
'allow_put': True,
|
|
'validate': {'type:dict_or_none': None},
|
|
'is_visible': True,
|
|
'default': {},
|
|
},
|
|
'placement_attr': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'validate': {'type:dict_or_none': None},
|
|
'is_visible': True,
|
|
'default': {},
|
|
},
|
|
'status': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
},
|
|
'error_reason': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
},
|
|
'created_at': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
},
|
|
'updated_at': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
},
|
|
'vnfd_template': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'validate': {'type:dict_or_none': None},
|
|
'is_visible': True,
|
|
'default': None,
|
|
},
|
|
},
|
|
}
|
|
|
|
|
|
SUB_RESOURCE_ATTRIBUTE_MAP = {
|
|
'actions': {
|
|
'parent': {
|
|
'collection_name': 'vnfs',
|
|
'member_name': 'vnf'
|
|
},
|
|
'members': {
|
|
'scale': {
|
|
'parameters': {
|
|
'policy': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
'validate': {'type:string': None}
|
|
},
|
|
'type': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
'validate': {'type:string': None}
|
|
},
|
|
'tenant_id': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'required_by_policy': False,
|
|
'is_visible': False
|
|
},
|
|
}
|
|
},
|
|
}
|
|
},
|
|
'triggers': {
|
|
'parent': {
|
|
'collection_name': 'vnfs',
|
|
'member_name': 'vnf'
|
|
},
|
|
'members': {
|
|
'trigger': {
|
|
'parameters': {
|
|
'policy_name': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
'validate': {'type:string': None}
|
|
},
|
|
'action_name': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
'validate': {'type:string': None}
|
|
},
|
|
'params': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
'validate': {'type:dict_or_none': None}
|
|
},
|
|
'tenant_id': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'required_by_policy': False,
|
|
'is_visible': False
|
|
}
|
|
}
|
|
},
|
|
}
|
|
},
|
|
'resources': {
|
|
'parent': {
|
|
'collection_name': 'vnfs',
|
|
'member_name': 'vnf'
|
|
},
|
|
'members': {
|
|
'resource': {
|
|
'parameters': {
|
|
'name': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
},
|
|
'type': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
},
|
|
'id': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
},
|
|
}
|
|
}
|
|
}
|
|
},
|
|
'maintenances': {
|
|
'parent': {
|
|
'collection_name': 'vnfs',
|
|
'member_name': 'vnf'
|
|
},
|
|
'members': {
|
|
'maintenance': {
|
|
'parameters': {
|
|
'params': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'is_visible': True,
|
|
'validate': {'type:dict_or_none': None}
|
|
},
|
|
'tenant_id': {
|
|
'allow_post': True,
|
|
'allow_put': False,
|
|
'validate': {'type:string': None},
|
|
'required_by_policy': False,
|
|
'is_visible': False
|
|
},
|
|
'response': {
|
|
'allow_post': False,
|
|
'allow_put': False,
|
|
'validate': {'type:dict_or_none': None},
|
|
'is_visible': True
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
class Vnfm(extensions.ExtensionDescriptor):
|
|
@classmethod
|
|
def get_name(cls):
|
|
return 'VNF Manager'
|
|
|
|
@classmethod
|
|
def get_alias(cls):
|
|
return 'VNFM'
|
|
|
|
@classmethod
|
|
def get_description(cls):
|
|
return "Extension for VNF Manager"
|
|
|
|
@classmethod
|
|
def get_namespace(cls):
|
|
return 'https://wiki.openstack.org/Tacker'
|
|
|
|
@classmethod
|
|
def get_updated(cls):
|
|
return "2013-11-19T10:00:00-00:00"
|
|
|
|
@classmethod
|
|
def get_resources(cls):
|
|
special_mappings = {}
|
|
plural_mappings = resource_helper.build_plural_mappings(
|
|
special_mappings, RESOURCE_ATTRIBUTE_MAP)
|
|
plural_mappings['service_types'] = 'service_type'
|
|
attr.PLURALS.update(plural_mappings)
|
|
resources = resource_helper.build_resource_info(
|
|
plural_mappings, RESOURCE_ATTRIBUTE_MAP, constants.VNFM,
|
|
translate_name=True)
|
|
plugin = manager.TackerManager.get_service_plugins()[
|
|
constants.VNFM]
|
|
for collection_name in SUB_RESOURCE_ATTRIBUTE_MAP:
|
|
parent = SUB_RESOURCE_ATTRIBUTE_MAP[collection_name]['parent']
|
|
|
|
for resource_name in SUB_RESOURCE_ATTRIBUTE_MAP[
|
|
collection_name]['members']:
|
|
params = SUB_RESOURCE_ATTRIBUTE_MAP[
|
|
collection_name]['members'][resource_name]['parameters']
|
|
|
|
controller = base.create_resource(collection_name,
|
|
resource_name,
|
|
plugin, params,
|
|
allow_bulk=True,
|
|
parent=parent)
|
|
|
|
resource = extensions.ResourceExtension(
|
|
collection_name,
|
|
controller, parent,
|
|
attr_map=params)
|
|
resources.append(resource)
|
|
return resources
|
|
|
|
@classmethod
|
|
def get_plugin_interface(cls):
|
|
return VNFMPluginBase
|
|
|
|
def update_attributes_map(self, attributes):
|
|
super(Vnfm, self).update_attributes_map(
|
|
attributes, extension_attrs_map=RESOURCE_ATTRIBUTE_MAP)
|
|
|
|
def get_extended_resources(self, version):
|
|
version_map = {'1.0': RESOURCE_ATTRIBUTE_MAP}
|
|
return version_map.get(version, {})
|
|
|
|
|
|
class VNFMPluginBase(service_base.NFVPluginBase, metaclass=abc.ABCMeta):
|
|
def get_plugin_name(self):
|
|
return constants.VNFM
|
|
|
|
def get_plugin_type(self):
|
|
return constants.VNFM
|
|
|
|
def get_plugin_description(self):
|
|
return 'Tacker VNF Manager plugin'
|
|
|
|
@abc.abstractmethod
|
|
def create_vnfd(self, context, vnfd):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def delete_vnfd(self, context, vnfd_id):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def get_vnfd(self, context, vnfd_id, fields=None):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def get_vnfds(self, context, filters=None, fields=None):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def get_vnfs(self, context, filters=None, fields=None):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def get_vnf(self, context, vnf_id, fields=None):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def get_vnf_resources(self, context, vnf_id, fields=None, filters=None):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def create_vnf(self, context, vnf):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def update_vnf(
|
|
self, context, vnf_id, vnf):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def delete_vnf(self, context, vnf_id):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def create_vnf_scale(
|
|
self, context, vnf_id, scale):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def create_vnf_trigger(
|
|
self, context, vnf_id, trigger):
|
|
pass
|
|
|
|
@abc.abstractmethod
|
|
def create_vnf_maintenance(self, context, vnf_id, maintenance):
|
|
pass
|