From 053eae0c8b04b9586884b5cfb0844a381cc801bc Mon Sep 17 00:00:00 2001 From: Cao Xuan Hoang Date: Wed, 8 Mar 2017 13:40:39 +0700 Subject: [PATCH] Migrate neutron-vpnaas API definitions to neutron-lib Neutron-vpnaas is intending to bring back into the stadium. So, neutron-vpnaas must migrate it's API definition to neutron-lib. Co-Authored-By: Anh Tran Co-Authored-By: Hunt Xu Change-Id: I06760fbbbc87570412a21364fba58efe880a907b --- neutron_lib/api/definitions/__init__.py | 8 +- neutron_lib/api/definitions/base.py | 5 + neutron_lib/api/definitions/vpn.py | 407 ++++++++++++++++++ .../api/definitions/vpn_endpoint_groups.py | 69 +++ neutron_lib/api/definitions/vpn_flavors.py | 41 ++ neutron_lib/api/validators/__init__.py | 16 +- neutron_lib/exceptions/vpn.py | 187 ++++++++ .../tests/unit/api/definitions/test_vpn.py | 30 ++ .../definitions/test_vpn_endpoint_groups.py | 20 + .../unit/api/definitions/test_vpn_flavors.py | 20 + .../notes/vpn-api-def-52970461fac0f7d2.yaml | 8 + 11 files changed, 809 insertions(+), 2 deletions(-) create mode 100644 neutron_lib/api/definitions/vpn.py create mode 100644 neutron_lib/api/definitions/vpn_endpoint_groups.py create mode 100644 neutron_lib/api/definitions/vpn_flavors.py create mode 100644 neutron_lib/exceptions/vpn.py create mode 100644 neutron_lib/tests/unit/api/definitions/test_vpn.py create mode 100644 neutron_lib/tests/unit/api/definitions/test_vpn_endpoint_groups.py create mode 100644 neutron_lib/tests/unit/api/definitions/test_vpn_flavors.py create mode 100644 releasenotes/notes/vpn-api-def-52970461fac0f7d2.yaml diff --git a/neutron_lib/api/definitions/__init__.py b/neutron_lib/api/definitions/__init__.py index 80d05d308..57eb547f7 100644 --- a/neutron_lib/api/definitions/__init__.py +++ b/neutron_lib/api/definitions/__init__.py @@ -64,6 +64,9 @@ from neutron_lib.api.definitions import subnetpool from neutron_lib.api.definitions import trunk from neutron_lib.api.definitions import trunk_details from neutron_lib.api.definitions import vlantransparent +from neutron_lib.api.definitions import vpn +from neutron_lib.api.definitions import vpn_endpoint_groups +from neutron_lib.api.definitions import vpn_flavors _ALL_API_DEFINITIONS = { @@ -120,5 +123,8 @@ _ALL_API_DEFINITIONS = { subnetpool, trunk, trunk_details, - vlantransparent + vlantransparent, + vpn, + vpn_endpoint_groups, + vpn_flavors, } diff --git a/neutron_lib/api/definitions/base.py b/neutron_lib/api/definitions/base.py index 77a9929e7..be1db0082 100644 --- a/neutron_lib/api/definitions/base.py +++ b/neutron_lib/api/definitions/base.py @@ -126,6 +126,11 @@ KNOWN_EXTENSIONS = ( 'bgpvpn', # https://git.openstack.org/cgit/openstack/networking-bgpvpn 'bgpvpn-routes-control', 'bgpvpn-vni', + + # git.openstack.org/cgit/openstack/neutron-vpnaas + 'vpnaas', + 'vpn-endpoint-groups', + 'vpn-flavors', ) KNOWN_KEYWORDS = ( diff --git a/neutron_lib/api/definitions/vpn.py b/neutron_lib/api/definitions/vpn.py new file mode 100644 index 000000000..3367be726 --- /dev/null +++ b/neutron_lib/api/definitions/vpn.py @@ -0,0 +1,407 @@ +# (c) Copyright 2013 Hewlett-Packard Development Company, L.P. +# 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. + +from neutron_lib.api import converters +from neutron_lib.api.definitions import l3 +from neutron_lib.api import validators +from neutron_lib.db import constants as db_const + +# Resource constants +VPNSERVICE = 'vpnservice' +VPNSERVICES = 'vpnservices' +IPSEC_SITE_CONNECTION = 'ipsec_site_connection' +IPSEC_SITE_CONNECTIONS = 'ipsec_site_connections' +IPSEC_POLICY = 'ipsecpolicy' +IPSEC_POLICIES = 'ipsecpolicies' +IKE_POLICY = 'ikepolicy' +IKE_POLICIES = 'ikepolicies' + +# VPN initiator constants +VPN_INITIATOR_BI_DIRECTIONAL = 'bi-directional' +VPN_INITIATOR_RESPONSE_ONLY = 'response-only' + +VPN_SUPPORTED_INITIATORS = [ + VPN_INITIATOR_BI_DIRECTIONAL, VPN_INITIATOR_RESPONSE_ONLY, +] + +# VPN encryption algorithm constants +VPN_ENCRYPTION_ALGORITHM_3DES = '3des' +VPN_ENCRYPTION_ALGORITHM_AES_128 = 'aes-128' +VPN_ENCRYPTION_ALGORITHM_AES_192 = 'aes-192' +VPN_ENCRYPTION_ALGORITHM_AES_256 = 'aes-256' + +VPN_SUPPORTED_ENCRYPTION_ALGORITHMS = [ + VPN_ENCRYPTION_ALGORITHM_3DES, VPN_ENCRYPTION_ALGORITHM_AES_128, + VPN_ENCRYPTION_ALGORITHM_AES_192, VPN_ENCRYPTION_ALGORITHM_AES_256, +] + +# VPN DPD action constants +VPN_DPD_ACTION_CLEAR = 'clear' +VPN_DPD_ACTION_DISABLED = 'disabled' +VPN_DPD_ACTION_HOLD = 'hold' +VPN_DPD_ACTION_RESTART = 'restart' +VPN_DPD_ACTION_RESTART_BY_PEER = 'restart-by-peer' + +VPN_SUPPORTED_DPD_ACTIONS = [ + VPN_DPD_ACTION_CLEAR, VPN_DPD_ACTION_DISABLED, VPN_DPD_ACTION_HOLD, + VPN_DPD_ACTION_RESTART, VPN_DPD_ACTION_RESTART_BY_PEER, +] + +# VPN transform protocol constants +VPN_TRANSFORM_PROTOCOL_AH = 'ah' +VPN_TRANSFORM_PROTOCOL_AH_ESP = 'ah-esp' +VPN_TRANSFORM_PROTOCOL_ESP = 'esp' + +VPN_SUPPORTED_TRANSFORM_PROTOCOLS = [ + VPN_TRANSFORM_PROTOCOL_AH, VPN_TRANSFORM_PROTOCOL_AH_ESP, + VPN_TRANSFORM_PROTOCOL_ESP, +] + +# VPN encapsulation mode constants +VPN_ENCAPSULATION_MODE_TRANSPORT = 'transport' +VPN_ENCAPSULATION_MODE_TUNNEL = 'tunnel' + +VPN_SUPPORTED_ENCAPSULATION_MODES = [ + VPN_ENCAPSULATION_MODE_TRANSPORT, VPN_ENCAPSULATION_MODE_TUNNEL, +] + +# VPN lifetime unit constants +VPN_LIFETIME_UNIT_SECONDS = 'seconds' + +VPN_SUPPORTED_LIFETIME_UNITS = [ + VPN_LIFETIME_UNIT_SECONDS, +] + +# VPN PFS group constants +VPN_PFS_GROUP2 = 'group2' +VPN_PFS_GROUP5 = 'group5' +VPN_PFS_GROUP14 = 'group14' + +VPN_SUPPORTED_PFSES = [ + VPN_PFS_GROUP2, VPN_PFS_GROUP5, VPN_PFS_GROUP14, +] + +# VPN IKE version constants +VPN_IKE_VERSION_V1 = 'v1' +VPN_IKE_VERSION_V2 = 'v2' + +VPN_SUPPORTED_IKE_VERSIONS = [ + VPN_IKE_VERSION_V1, VPN_IKE_VERSION_V2, +] + +# VPN auth mode constants +VPN_AUTH_MODE_PSK = 'psk' + +VPN_SUPPORTED_AUTH_MODES = [ + VPN_AUTH_MODE_PSK, +] + +# VPN auth algorithm constants +VPN_AUTH_ALGORITHM_SHA1 = 'sha1' +VPN_AUTH_ALGORITHM_SHA256 = 'sha256' +VPN_AUTH_ALGORITHM_SHA384 = 'sha384' +VPN_AUTH_ALGORITHM_SHA512 = 'sha512' + +VPN_SUPPORTED_AUTH_ALGORITHMS = [ + VPN_AUTH_ALGORITHM_SHA1, VPN_AUTH_ALGORITHM_SHA256, + VPN_AUTH_ALGORITHM_SHA384, VPN_AUTH_ALGORITHM_SHA512, +] + +# VPN phase1 negotiation mode constants +VPN_PHASE1_NEGOTIATION_MODE_MAIN = 'main' + +VPN_SUPPORTED_PHASE1_NEGOTIATION_MODES = [ + VPN_PHASE1_NEGOTIATION_MODE_MAIN, +] + +# The alias of the extension. +ALIAS = 'vpnaas' + +# Whether or not this extension is simply signaling behavior to the user +# or it actively modifies the attribute map. +IS_SHIM_EXTENSION = False + +# Whether the extension is marking the adoption of standardattr model for +# legacy resources, or introducing new standardattr attributes. False or +# None if the standardattr model is adopted since the introduction of +# resource extension. +# If this is True, the alias for the extension should be prefixed with +# 'standard-attr-'. +IS_STANDARD_ATTR_EXTENSION = False + +# The name of the extension. +NAME = 'VPN service' + +# The description of the extension. +DESCRIPTION = "Extension for VPN service" + +# A timestamp of when the extension was introduced. +UPDATED_TIMESTAMP = "2013-05-29T10:00:00-00:00" + +# Base for the API calls +API_PREFIX = '/vpn' + +_vpn_lifetime_limits = (60, validators.UNLIMITED) + +RESOURCE_ATTRIBUTE_MAP = { + + VPNSERVICES: { + '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': db_const.PROJECT_ID_FIELD_SIZE}, + 'required_by_policy': True, + 'is_visible': True}, + 'name': {'allow_post': True, 'allow_put': True, + 'validate': {'type:string': db_const.NAME_FIELD_SIZE}, + 'is_visible': True, 'default': ''}, + 'description': {'allow_post': True, 'allow_put': True, + 'validate': { + 'type:string': db_const.DESCRIPTION_FIELD_SIZE}, + 'is_visible': True, 'default': ''}, + 'subnet_id': {'allow_post': True, 'allow_put': False, + 'validate': {'type:uuid_or_none': None}, + 'is_visible': True, 'default': None}, + 'router_id': {'allow_post': True, 'allow_put': False, + 'validate': {'type:uuid': None}, + 'is_visible': True}, + 'admin_state_up': {'allow_post': True, 'allow_put': True, + 'default': True, + 'convert_to': converters.convert_to_boolean, + 'is_visible': True}, + 'external_v4_ip': {'allow_post': False, 'allow_put': False, + 'is_visible': True}, + 'external_v6_ip': {'allow_post': False, 'allow_put': False, + 'is_visible': True}, + 'status': {'allow_post': False, 'allow_put': False, + 'is_visible': True}, + }, + + IPSEC_SITE_CONNECTIONS: { + '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': db_const.PROJECT_ID_FIELD_SIZE}, + 'required_by_policy': True, + 'is_visible': True}, + 'name': {'allow_post': True, 'allow_put': True, + 'validate': {'type:string': db_const.NAME_FIELD_SIZE}, + 'is_visible': True, 'default': ''}, + 'description': {'allow_post': True, 'allow_put': True, + 'validate': { + 'type:string': db_const.DESCRIPTION_FIELD_SIZE}, + 'is_visible': True, 'default': ''}, + 'local_id': {'allow_post': True, 'allow_put': True, + 'validate': {'type:string': None}, + 'is_visible': True, 'default': ''}, + 'peer_address': {'allow_post': True, 'allow_put': True, + 'validate': {'type:string': None}, + 'is_visible': True}, + 'peer_id': {'allow_post': True, 'allow_put': True, + 'validate': {'type:string': None}, + 'is_visible': True}, + 'peer_cidrs': {'allow_post': True, 'allow_put': True, + 'convert_to': converters.convert_to_list, + 'validate': {'type:subnet_list_or_none': None}, + 'is_visible': True, + 'default': None}, + 'local_ep_group_id': {'allow_post': True, 'allow_put': True, + 'validate': {'type:uuid_or_none': None}, + 'is_visible': True, 'default': None}, + 'peer_ep_group_id': {'allow_post': True, 'allow_put': True, + 'validate': {'type:uuid_or_none': None}, + 'is_visible': True, 'default': None}, + 'route_mode': {'allow_post': False, 'allow_put': False, + 'is_visible': True}, + 'mtu': {'allow_post': True, 'allow_put': True, + 'default': 1500, + 'validate': {'type:non_negative': None}, + 'convert_to': converters.convert_to_int, + 'is_visible': True}, + 'initiator': {'allow_post': True, 'allow_put': True, + 'default': VPN_INITIATOR_BI_DIRECTIONAL, + 'validate': {'type:values': VPN_SUPPORTED_INITIATORS}, + 'is_visible': True}, + 'auth_mode': {'allow_post': False, 'allow_put': False, + 'default': VPN_AUTH_MODE_PSK, + 'validate': {'type:values': VPN_SUPPORTED_AUTH_MODES}, + 'is_visible': True}, + 'psk': {'allow_post': True, 'allow_put': True, + 'validate': {'type:string': None}, + 'is_visible': True}, + 'dpd': { + 'allow_post': True, 'allow_put': True, + 'convert_to': converters.convert_none_to_empty_dict, + 'is_visible': True, + 'default': {}, + 'validate': { + 'type:dict_or_empty': { + 'action': {'type:values': VPN_SUPPORTED_DPD_ACTIONS}, + 'interval': {'type:non_negative': None}, + 'timeout': {'type:non_negative': None}}}}, + 'admin_state_up': {'allow_post': True, 'allow_put': True, + 'default': True, + 'convert_to': converters.convert_to_boolean, + 'is_visible': True}, + 'status': {'allow_post': False, 'allow_put': False, + 'is_visible': True}, + 'vpnservice_id': {'allow_post': True, 'allow_put': False, + 'validate': {'type:uuid': None}, + 'is_visible': True}, + 'ikepolicy_id': {'allow_post': True, 'allow_put': False, + 'validate': {'type:uuid': None}, + 'is_visible': True}, + 'ipsecpolicy_id': {'allow_post': True, 'allow_put': False, + 'validate': {'type:uuid': None}, + 'is_visible': True}, + }, + + IPSEC_POLICIES: { + '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': db_const.PROJECT_ID_FIELD_SIZE}, + 'required_by_policy': True, + 'is_visible': True}, + 'name': {'allow_post': True, 'allow_put': True, + 'validate': {'type:string': db_const.NAME_FIELD_SIZE}, + 'is_visible': True, 'default': ''}, + 'description': {'allow_post': True, 'allow_put': True, + 'validate': { + 'type:string': db_const.DESCRIPTION_FIELD_SIZE}, + 'is_visible': True, 'default': ''}, + 'transform_protocol': { + 'allow_post': True, + 'allow_put': True, + 'default': VPN_TRANSFORM_PROTOCOL_ESP, + 'validate': {'type:values': VPN_SUPPORTED_TRANSFORM_PROTOCOLS}, + 'is_visible': True}, + 'auth_algorithm': { + 'allow_post': True, + 'allow_put': True, + 'default': VPN_AUTH_ALGORITHM_SHA1, + 'validate': {'type:values': VPN_SUPPORTED_AUTH_ALGORITHMS}, + 'is_visible': True}, + 'encryption_algorithm': { + 'allow_post': True, + 'allow_put': True, + 'default': VPN_ENCRYPTION_ALGORITHM_AES_128, + 'validate': {'type:values': VPN_SUPPORTED_ENCRYPTION_ALGORITHMS}, + 'is_visible': True}, + 'encapsulation_mode': { + 'allow_post': True, + 'allow_put': True, + 'default': VPN_ENCAPSULATION_MODE_TUNNEL, + 'validate': {'type:values': VPN_SUPPORTED_ENCAPSULATION_MODES}, + 'is_visible': True}, + 'lifetime': { + 'allow_post': True, 'allow_put': True, + 'convert_to': converters.convert_none_to_empty_dict, + 'default': {}, + 'validate': { + 'type:dict_or_empty': { + 'units': {'type:values': VPN_SUPPORTED_LIFETIME_UNITS}, + 'value': {'type:range': _vpn_lifetime_limits}}}, + 'is_visible': True}, + 'pfs': {'allow_post': True, 'allow_put': True, + 'default': VPN_PFS_GROUP5, + 'validate': {'type:values': VPN_SUPPORTED_PFSES}, + 'is_visible': True}, + }, + + IKE_POLICIES: { + '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': db_const.PROJECT_ID_FIELD_SIZE}, + 'required_by_policy': True, + 'is_visible': True}, + 'name': {'allow_post': True, 'allow_put': True, + 'validate': {'type:string': db_const.NAME_FIELD_SIZE}, + 'is_visible': True, 'default': ''}, + 'description': {'allow_post': True, 'allow_put': True, + 'validate': { + 'type:string': db_const.DESCRIPTION_FIELD_SIZE}, + 'is_visible': True, 'default': ''}, + 'auth_algorithm': { + 'allow_post': True, 'allow_put': True, + 'default': VPN_AUTH_ALGORITHM_SHA1, + 'validate': {'type:values': VPN_SUPPORTED_AUTH_ALGORITHMS}, + 'is_visible': True}, + 'encryption_algorithm': { + 'allow_post': True, 'allow_put': True, + 'default': VPN_ENCRYPTION_ALGORITHM_AES_128, + 'validate': {'type:values': VPN_SUPPORTED_ENCRYPTION_ALGORITHMS}, + 'is_visible': True}, + 'phase1_negotiation_mode': { + 'allow_post': True, 'allow_put': True, + 'default': VPN_PHASE1_NEGOTIATION_MODE_MAIN, + 'validate': { + 'type:values': VPN_SUPPORTED_PHASE1_NEGOTIATION_MODES}, + 'is_visible': True}, + 'lifetime': { + 'allow_post': True, 'allow_put': True, + 'convert_to': converters.convert_none_to_empty_dict, + 'default': {}, + 'validate': { + 'type:dict_or_empty': { + 'units': {'type:values': VPN_SUPPORTED_LIFETIME_UNITS}, + 'value': {'type:range': _vpn_lifetime_limits}}}, + 'is_visible': True}, + 'ike_version': { + 'allow_post': True, 'allow_put': True, + 'default': VPN_IKE_VERSION_V1, + 'validate': {'type:values': VPN_SUPPORTED_IKE_VERSIONS}, + 'is_visible': True}, + 'pfs': {'allow_post': True, 'allow_put': True, + 'default': VPN_PFS_GROUP5, + 'validate': {'type:values': VPN_SUPPORTED_PFSES}, + 'is_visible': True}, + }, +} + +# The subresource attribute map for the extension. This extension has only +# top level resources, not child resources, so this is set to an empty dict. +SUB_RESOURCE_ATTRIBUTE_MAP = { +} + +# The action map. +ACTION_MAP = { +} + +# The action status. +ACTION_STATUS = { +} + +# The list of required extensions. +REQUIRED_EXTENSIONS = [ + l3.ALIAS, +] + +# The list of optional extensions. +OPTIONAL_EXTENSIONS = [ +] diff --git a/neutron_lib/api/definitions/vpn_endpoint_groups.py b/neutron_lib/api/definitions/vpn_endpoint_groups.py new file mode 100644 index 000000000..41f29f4b8 --- /dev/null +++ b/neutron_lib/api/definitions/vpn_endpoint_groups.py @@ -0,0 +1,69 @@ +# (c) Copyright 2015 NEC 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. + +from neutron_lib.api import converters +from neutron_lib.api.definitions import vpn +from neutron_lib.db import constants as db_const + +# VPN Endpoint type constants +VPN_ENDPOINT_TYPE_CIDR = 'cidr' +VPN_ENDPOINT_TYPE_NETWORK = 'network' +VPN_ENDPOINT_TYPE_ROUTER = 'router' +VPN_ENDPOINT_TYPE_SUBNET = 'subnet' +VPN_ENDPOINT_TYPE_VLAN = 'vlan' + +VPN_SUPPORTED_ENDPOINT_TYPES = [ + VPN_ENDPOINT_TYPE_CIDR, VPN_ENDPOINT_TYPE_NETWORK, + VPN_ENDPOINT_TYPE_ROUTER, VPN_ENDPOINT_TYPE_SUBNET, VPN_ENDPOINT_TYPE_VLAN, +] + +ALIAS = 'vpn-endpoint-groups' +IS_SHIM_EXTENSION = False +IS_STANDARD_ATTR_EXTENSION = False +NAME = 'VPN Endpoint Groups' +DESCRIPTION = 'VPN endpoint groups support' +UPDATED_TIMESTAMP = '2015-08-04T10:00:00-00:00' +API_PREFIX = '/vpn' +RESOURCE_ATTRIBUTE_MAP = { + 'endpoint_groups': { + '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': db_const.PROJECT_ID_FIELD_SIZE}, + 'required_by_policy': True, + 'is_visible': True}, + 'name': {'allow_post': True, 'allow_put': True, + 'validate': {'type:string': db_const.NAME_FIELD_SIZE}, + 'is_visible': True, 'default': ''}, + 'description': {'allow_post': True, 'allow_put': True, + 'validate': { + 'type:string': db_const.DESCRIPTION_FIELD_SIZE}, + 'is_visible': True, 'default': ''}, + 'type': {'allow_post': True, 'allow_put': False, + 'validate': {'type:values': VPN_SUPPORTED_ENDPOINT_TYPES}, + 'is_visible': True}, + 'endpoints': {'allow_post': True, 'allow_put': False, + 'convert_to': converters.convert_to_list, + 'is_visible': True, + 'default': []}, + }, +} +SUB_RESOURCE_ATTRIBUTE_MAP = {} +ACTION_MAP = {} +REQUIRED_EXTENSIONS = [vpn.ALIAS] +OPTIONAL_EXTENSIONS = [] +ACTION_STATUS = {} diff --git a/neutron_lib/api/definitions/vpn_flavors.py b/neutron_lib/api/definitions/vpn_flavors.py new file mode 100644 index 000000000..72ad39c72 --- /dev/null +++ b/neutron_lib/api/definitions/vpn_flavors.py @@ -0,0 +1,41 @@ +# Copyright 2017 Eayun, Inc. +# +# 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_lib.api.definitions import flavors +from neutron_lib.api.definitions import vpn + +FLAVOR_ID = 'flavor_id' + +ALIAS = 'vpn-flavors' +IS_SHIM_EXTENSION = False +IS_STANDARD_ATTR_EXTENSION = False +NAME = 'VPN Service Falvor Extension' +DESCRIPTION = 'Flavor support for vpnservices.' +UPDATED_TIMESTAMP = '2017-04-19T00:00:00-00:00' +API_PREFIX = '/vpn' +RESOURCE_NAME = vpn.VPNSERVICE +COLLECTION_NAME = vpn.VPNSERVICES +RESOURCE_ATTRIBUTE_MAP = { + COLLECTION_NAME: { + FLAVOR_ID: {'allow_post': True, 'allow_put': False, + 'validate': {'type:uuid_or_none': None}, + 'is_visible': True, 'default': None} + }, +} +SUB_RESOURCE_ATTRIBUTE_MAP = {} +ACTION_MAP = {} +REQUIRED_EXTENSIONS = [vpn.ALIAS] +OPTIONAL_EXTENSIONS = [flavors.ALIAS] +ACTION_STATUS = {} diff --git a/neutron_lib/api/validators/__init__.py b/neutron_lib/api/validators/__init__.py index 5432d8efd..d9b5c7b48 100644 --- a/neutron_lib/api/validators/__init__.py +++ b/neutron_lib/api/validators/__init__.py @@ -681,6 +681,18 @@ def validate_subnet_list(data, valid_values=None): return _validate_subnet_list(data, valid_values) +def validate_subnet_list_or_none(data, key_specs=None): + """Validate data is a list of subnet dicts or None. + + :param data: The data to validate. + :param key_specs: Not used! + :returns: None if data is None or a valid list of subnet dicts, otherwise + a human readable message as to why the data is invalid. + """ + if data is not None: + return validate_subnet_list(data, key_specs) + + def validate_regex(data, valid_values=None): """Validate data is matched against a regex. @@ -1073,7 +1085,9 @@ validators = {'type:dict': validate_dict, 'type:list_of_unique_strings': validate_list_of_unique_strings, 'type:list_of_any_key_specs_or_none': validate_any_key_specs_or_none, - 'type:service_plugin_type': validate_service_plugin_type} + 'type:service_plugin_type': validate_service_plugin_type, + 'type:subnet_list_or_none': validate_subnet_list_or_none, + } def _to_validation_type(validation_type): diff --git a/neutron_lib/exceptions/vpn.py b/neutron_lib/exceptions/vpn.py new file mode 100644 index 000000000..be7ce8599 --- /dev/null +++ b/neutron_lib/exceptions/vpn.py @@ -0,0 +1,187 @@ +# 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_lib._i18n import _ +from neutron_lib import exceptions + + +# VPNaaS Exceptions +class VPNServiceNotFound(exceptions.NotFound): + message = _("VPNService %(vpnservice_id)s could not be found") + + +class IPsecSiteConnectionNotFound(exceptions.NotFound): + message = _("ipsec_site_connection %(ipsec_site_conn_id)s not found") + + +class IPsecSiteConnectionDpdIntervalValueError(exceptions.InvalidInput): + message = _("ipsec_site_connection %(attr)s is " + "equal to or less than dpd_interval") + + +class IPsecSiteConnectionMtuError(exceptions.InvalidInput): + message = _("ipsec_site_connection MTU %(mtu)d is too small " + "for ipv%(version)s") + + +class IPsecSiteConnectionPeerCidrError(exceptions.InvalidInput): + message = _("ipsec_site_connection peer cidr %(peer_cidr)s is " + "invalid CIDR") + + +class IKEPolicyNotFound(exceptions.NotFound): + message = _("IKEPolicy %(ikepolicy_id)s could not be found") + + +class IPsecPolicyNotFound(exceptions.NotFound): + message = _("IPsecPolicy %(ipsecpolicy_id)s could not be found") + + +class IKEPolicyInUse(exceptions.InUse): + message = _("IKEPolicy %(ikepolicy_id)s is in use by existing " + "IPsecSiteConnection and can't be updated or deleted") + + +class VPNServiceInUse(exceptions.InUse): + message = _("VPNService %(vpnservice_id)s is still in use") + + +class SubnetInUseByVPNService(exceptions.InUse): + message = _("Subnet %(subnet_id)s is used by VPNService %(vpnservice_id)s") + + +class SubnetInUseByEndpointGroup(exceptions.InUse): + message = _("Subnet %(subnet_id)s is used by endpoint group %(group_id)s") + + +class VPNStateInvalidToUpdate(exceptions.BadRequest): + message = _("Invalid state %(state)s of vpnaas resource %(id)s " + "for updating") + + +class IPsecPolicyInUse(exceptions.InUse): + message = _("IPsecPolicy %(ipsecpolicy_id)s is in use by existing " + "IPsecSiteConnection and can't be updated or deleted") + + +class DeviceDriverImportError(exceptions.NeutronException): + message = _("Can not load driver :%(device_driver)s") + + +class SubnetIsNotConnectedToRouter(exceptions.BadRequest): + message = _("Subnet %(subnet_id)s is not " + "connected to Router %(router_id)s") + + +class RouterIsNotExternal(exceptions.BadRequest): + message = _("Router %(router_id)s has no external network gateway set") + + +class VPNPeerAddressNotResolved(exceptions.InvalidInput): + message = _("Peer address %(peer_address)s cannot be resolved") + + +class ExternalNetworkHasNoSubnet(exceptions.BadRequest): + message = _("Router's %(router_id)s external network has " + "no %(ip_version)s subnet") + + +# VPN Endpoint Group Exceptions +class VPNEndpointGroupNotFound(exceptions.NotFound): + message = _("Endpoint group %(endpoint_group_id)s could not be found") + + +class InvalidEndpointInEndpointGroup(exceptions.InvalidInput): + message = _("Endpoint '%(endpoint)s' is invalid for group " + "type '%(group_type)s': %(why)s") + + +class MissingEndpointForEndpointGroup(exceptions.BadRequest): + message = _("No endpoints specified for endpoint group '%(group)s'") + + +class NonExistingSubnetInEndpointGroup(exceptions.InvalidInput): + message = _("Subnet %(subnet)s in endpoint group does not exist") + + +class MixedIPVersionsForIPSecEndpoints(exceptions.BadRequest): + message = _("Endpoints in group %(group)s do not have the same IP " + "version, as required for IPSec site-to-site connection") + + +class MixedIPVersionsForPeerCidrs(exceptions.BadRequest): + message = _("Peer CIDRs do not have the same IP version, as required " + "for IPSec site-to-site connection") + + +class MixedIPVersionsForIPSecConnection(exceptions.BadRequest): + message = _("IP versions are not compatible between peer and local " + "endpoints") + + +class InvalidEndpointGroup(exceptions.BadRequest): + message = _("Endpoint group%(suffix)s %(which)s cannot be specified, " + "when VPN Service has subnet specified") + + +class WrongEndpointGroupType(exceptions.BadRequest): + message = _("Endpoint group %(which)s type is '%(group_type)s' and " + "should be '%(expected)s'") + + +class PeerCidrsInvalid(exceptions.BadRequest): + message = _("Peer CIDRs cannot be specified, when using endpoint " + "groups") + + +class MissingPeerCidrs(exceptions.BadRequest): + message = _("Missing peer CIDRs for IPsec site-to-site connection") + + +class MissingRequiredEndpointGroup(exceptions.BadRequest): + message = _("Missing endpoint group%(suffix)s %(which)s for IPSec " + "site-to-site connection") + + +class EndpointGroupInUse(exceptions.BadRequest): + message = _("Endpoint group %(group_id)s is in use and cannot be deleted") + + +# VPN Flavors Exceptions +class FlavorsPluginNotLoaded(exceptions.NotFound): + message = _("Flavors plugin not found") + + +class NoProviderFoundForFlavor(exceptions.NotFound): + message = _("No service provider found for flavor %(flavor_id)s") + + +# IPsec Service Driver Validator Exceptions +class IpsecValidationFailure(exceptions.BadRequest): + message = _("IPSec does not support %(resource)s attribute %(key)s " + "with value '%(value)s'") + + +class IkeValidationFailure(exceptions.BadRequest): + message = _("IKE does not support %(resource)s attribute %(key)s " + "with value '%(value)s'") + + +# Cisco Csr Driver Exceptions +class CsrInternalError(exceptions.NeutronException): + message = _("Fatal - %(reason)s") + + +# Cisco CSR Driver Validator Exceptions +class CsrValidationFailure(exceptions.BadRequest): + message = _("Cisco CSR does not support %(resource)s attribute %(key)s " + "with value '%(value)s'") diff --git a/neutron_lib/tests/unit/api/definitions/test_vpn.py b/neutron_lib/tests/unit/api/definitions/test_vpn.py new file mode 100644 index 000000000..aeb2584a1 --- /dev/null +++ b/neutron_lib/tests/unit/api/definitions/test_vpn.py @@ -0,0 +1,30 @@ +# 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_lib.api.definitions import vpn +from neutron_lib.tests.unit.api.definitions import base + + +class VPNDefinitionTestCase(base.DefinitionBaseTestCase): + extension_module = vpn + extension_resources = ('vpnservices', 'ipsec_site_connections', + 'ipsecpolicies', 'ikepolicies',) + extension_attributes = ('auth_algorithm', 'auth_mode', 'dpd', + 'encapsulation_mode', 'encryption_algorithm', + 'external_v4_ip', 'external_v6_ip', + 'ike_version', 'ikepolicy_id', 'initiator', + 'ipsecpolicy_id', 'lifetime', 'local_ep_group_id', + 'local_id', 'mtu', 'peer_address', 'peer_cidrs', + 'peer_ep_group_id', 'peer_id', 'pfs', + 'phase1_negotiation_mode', 'psk', 'route_mode', + 'router_id', 'subnet_id', 'transform_protocol', + 'vpnservice_id',) diff --git a/neutron_lib/tests/unit/api/definitions/test_vpn_endpoint_groups.py b/neutron_lib/tests/unit/api/definitions/test_vpn_endpoint_groups.py new file mode 100644 index 000000000..ea2c9762c --- /dev/null +++ b/neutron_lib/tests/unit/api/definitions/test_vpn_endpoint_groups.py @@ -0,0 +1,20 @@ +# 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_lib.api.definitions import vpn_endpoint_groups +from neutron_lib.tests.unit.api.definitions import base + + +class VPNEndpointGroupsDefinitionTestCase(base.DefinitionBaseTestCase): + extension_module = vpn_endpoint_groups + extension_resources = ('endpoint_groups',) + extension_attributes = ('type', 'endpoints',) diff --git a/neutron_lib/tests/unit/api/definitions/test_vpn_flavors.py b/neutron_lib/tests/unit/api/definitions/test_vpn_flavors.py new file mode 100644 index 000000000..f27f48213 --- /dev/null +++ b/neutron_lib/tests/unit/api/definitions/test_vpn_flavors.py @@ -0,0 +1,20 @@ +# 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_lib.api.definitions import vpn_flavors +from neutron_lib.tests.unit.api.definitions import base + + +class VPNFlavorsDefinitionTestCase(base.DefinitionBaseTestCase): + extension_module = vpn_flavors + extension_resources = (vpn_flavors.COLLECTION_NAME,) + extension_attributes = (vpn_flavors.FLAVOR_ID,) diff --git a/releasenotes/notes/vpn-api-def-52970461fac0f7d2.yaml b/releasenotes/notes/vpn-api-def-52970461fac0f7d2.yaml new file mode 100644 index 000000000..8f1d3b217 --- /dev/null +++ b/releasenotes/notes/vpn-api-def-52970461fac0f7d2.yaml @@ -0,0 +1,8 @@ +--- +features: + - Adds ``neutron-vpnaas`` API definitions to neutron-lib, including + ``vpnaas``, ``vpn-endpoint-groups`` and ``vpn-flavors``. + - Migrate user facing exceptions into neutron-lib along with the API + definitions. + - A new validator for type ``type:subnet_list_or_none`` to validate + data is a list of subnet dicts or ``None`` is added too.