From 224e82eb0e35f52bec713dc5986b7b0082403cc8 Mon Sep 17 00:00:00 2001 From: Anton Sidelnikov <53078276+anton-sidelnikov@users.noreply.github.com> Date: Mon, 18 Nov 2024 10:44:04 +0100 Subject: [PATCH] [Feat.] Missing proxies for er, fg and apig (#491) [Feat.] Missing proxies for er, fg and apig Added missing proxies for newest services Closes #469 Closes #468 Closes #450 Reviewed-by: RusselSand Reviewed-by: Vladimir Hasko Reviewed-by: Anton Sidelnikov --- otcextensions/sdk/__init__.py | 15 ++ otcextensions/sdk/apig/__init__.py | 0 otcextensions/sdk/apig/apig_service.py | 22 +++ otcextensions/sdk/apig/v2/__init__.py | 0 otcextensions/sdk/apig/v2/_proxy.py | 18 +++ otcextensions/sdk/er/__init__.py | 0 otcextensions/sdk/er/er_service.py | 23 +++ otcextensions/sdk/er/v3/__init__.py | 0 otcextensions/sdk/er/v3/_proxy.py | 17 ++ otcextensions/sdk/function_graph/__init__.py | 0 .../function_graph/function_graph_service.py | 23 +++ .../sdk/function_graph/v2/__init__.py | 0 otcextensions/sdk/function_graph/v2/_proxy.py | 17 ++ otcextensions/sdk/sdk_make_proxy.py | 148 ++++++++++++++++++ .../tests/functional/sdk/apig/__init__.py | 0 .../tests/functional/sdk/apig/v2/__init__.py | 0 .../functional/sdk/apig/v2/test_service.py | 24 +++ .../tests/functional/sdk/er/__init__.py | 0 .../tests/functional/sdk/er/v3/__init__.py | 0 .../functional/sdk/er/v3/test_service.py | 24 +++ .../functional/sdk/function_graph/__init__.py | 0 .../sdk/function_graph/v2/__init__.py | 0 .../sdk/function_graph/v2/test_service.py | 24 +++ .../proxies-apig-fg-er-f939b4523f23b031.yaml | 8 + 24 files changed, 363 insertions(+) create mode 100644 otcextensions/sdk/apig/__init__.py create mode 100644 otcextensions/sdk/apig/apig_service.py create mode 100644 otcextensions/sdk/apig/v2/__init__.py create mode 100644 otcextensions/sdk/apig/v2/_proxy.py create mode 100644 otcextensions/sdk/er/__init__.py create mode 100644 otcextensions/sdk/er/er_service.py create mode 100644 otcextensions/sdk/er/v3/__init__.py create mode 100644 otcextensions/sdk/er/v3/_proxy.py create mode 100644 otcextensions/sdk/function_graph/__init__.py create mode 100644 otcextensions/sdk/function_graph/function_graph_service.py create mode 100644 otcextensions/sdk/function_graph/v2/__init__.py create mode 100644 otcextensions/sdk/function_graph/v2/_proxy.py create mode 100644 otcextensions/sdk/sdk_make_proxy.py create mode 100644 otcextensions/tests/functional/sdk/apig/__init__.py create mode 100644 otcextensions/tests/functional/sdk/apig/v2/__init__.py create mode 100644 otcextensions/tests/functional/sdk/apig/v2/test_service.py create mode 100644 otcextensions/tests/functional/sdk/er/__init__.py create mode 100644 otcextensions/tests/functional/sdk/er/v3/__init__.py create mode 100644 otcextensions/tests/functional/sdk/er/v3/test_service.py create mode 100644 otcextensions/tests/functional/sdk/function_graph/__init__.py create mode 100644 otcextensions/tests/functional/sdk/function_graph/v2/__init__.py create mode 100644 otcextensions/tests/functional/sdk/function_graph/v2/test_service.py create mode 100644 releasenotes/notes/proxies-apig-fg-er-f939b4523f23b031.yaml diff --git a/otcextensions/sdk/__init__.py b/otcextensions/sdk/__init__.py index 207ca2904..6829b605f 100644 --- a/otcextensions/sdk/__init__.py +++ b/otcextensions/sdk/__init__.py @@ -51,6 +51,11 @@ 'append_project_id': True, 'endpoint_service_type': 'antiddos', }, + 'apig': { + 'service_type': 'apig', + 'append_project_id': True, + 'endpoint_service_type': 'apigv2' + }, 'aomv1': { 'service_type': 'aomv1', 'endpoint_service_type': 'aomv1' @@ -160,6 +165,16 @@ 'service_type': 'enterprise-dashboard-v1', 'endpoint_service_type': 'enterprise-dashboard-v1' }, + 'er': { + 'service_type': 'er', + 'append_project_id': True, + 'endpoint_service_type': 'erv3' + }, + 'function_graph': { + 'service_type': 'function_graph', + 'append_project_id': True, + 'endpoint_service_type': 'functiongraph' + }, 'identity': { 'service_type': 'identity', 'replace_system': True diff --git a/otcextensions/sdk/apig/__init__.py b/otcextensions/sdk/apig/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/apig/apig_service.py b/otcextensions/sdk/apig/apig_service.py new file mode 100644 index 000000000..a42357c04 --- /dev/null +++ b/otcextensions/sdk/apig/apig_service.py @@ -0,0 +1,22 @@ +# 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 openstack import service_description +from otcextensions.sdk.apig.v2 import _proxy + + +class ApigService(service_description.ServiceDescription): + """The APIG service.""" + + supported_versions = { + '2': _proxy.Proxy + } diff --git a/otcextensions/sdk/apig/v2/__init__.py b/otcextensions/sdk/apig/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/apig/v2/_proxy.py b/otcextensions/sdk/apig/v2/_proxy.py new file mode 100644 index 000000000..7a2d49a3c --- /dev/null +++ b/otcextensions/sdk/apig/v2/_proxy.py @@ -0,0 +1,18 @@ +# 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 openstack import proxy + + +class Proxy(proxy.Proxy): + + skip_discovery = True diff --git a/otcextensions/sdk/er/__init__.py b/otcextensions/sdk/er/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/er/er_service.py b/otcextensions/sdk/er/er_service.py new file mode 100644 index 000000000..f3031ee68 --- /dev/null +++ b/otcextensions/sdk/er/er_service.py @@ -0,0 +1,23 @@ +# 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 openstack import service_description + +from otcextensions.sdk.er.v3 import _proxy + + +class ErService(service_description.ServiceDescription): + """The EnterpriseRouter service.""" + + supported_versions = { + '3': _proxy.Proxy + } diff --git a/otcextensions/sdk/er/v3/__init__.py b/otcextensions/sdk/er/v3/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/er/v3/_proxy.py b/otcextensions/sdk/er/v3/_proxy.py new file mode 100644 index 000000000..38cfb42e8 --- /dev/null +++ b/otcextensions/sdk/er/v3/_proxy.py @@ -0,0 +1,17 @@ +# 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 openstack import proxy + + +class Proxy(proxy.Proxy): + + skip_discovery = True diff --git a/otcextensions/sdk/function_graph/__init__.py b/otcextensions/sdk/function_graph/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/function_graph/function_graph_service.py b/otcextensions/sdk/function_graph/function_graph_service.py new file mode 100644 index 000000000..b6cc9c642 --- /dev/null +++ b/otcextensions/sdk/function_graph/function_graph_service.py @@ -0,0 +1,23 @@ +# 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 openstack import service_description + +from otcextensions.sdk.function_graph.v2 import _proxy + + +class FunctionGraphService(service_description.ServiceDescription): + """The FG service.""" + + supported_versions = { + '2': _proxy.Proxy + } diff --git a/otcextensions/sdk/function_graph/v2/__init__.py b/otcextensions/sdk/function_graph/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/function_graph/v2/_proxy.py b/otcextensions/sdk/function_graph/v2/_proxy.py new file mode 100644 index 000000000..38cfb42e8 --- /dev/null +++ b/otcextensions/sdk/function_graph/v2/_proxy.py @@ -0,0 +1,17 @@ +# 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 openstack import proxy + + +class Proxy(proxy.Proxy): + + skip_discovery = True diff --git a/otcextensions/sdk/sdk_make_proxy.py b/otcextensions/sdk/sdk_make_proxy.py new file mode 100644 index 000000000..e7c4d10c3 --- /dev/null +++ b/otcextensions/sdk/sdk_make_proxy.py @@ -0,0 +1,148 @@ +# 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 warnings +from openstack import exceptions +from openstack import warnings as os_warnings + + +class ServiceProxy: + def __init__(self, instance, service_type, supported_versions): + self.instance = instance + self.service_type = service_type + self.supported_versions = supported_versions + + def create_proxy(self, base_service="aomv2", target_service="apig"): + config = self.instance.config + + # Retrieve API version and endpoint configuration + version_string = config.get_api_version(base_service) or '2' + endpoint_override = config.get_endpoint(self.service_type) + + # Fetch service catalog URL and adjust the endpoint if necessary + ep = config.get_service_catalog().url_for( + service_type=base_service, + region_name=config.region_name + ) + epo = f"{ep.replace(base_service.split('v')[0], target_service)}" + + if epo and not endpoint_override: + endpoint_override = epo + + if not version_string and len(self.supported_versions) == 1: + version_string = list(self.supported_versions)[0] + + # Attempt to create a proxy object with the + # specified endpoint and version + proxy_obj = self._get_proxy_object( + config, + version_string, + endpoint_override + ) + if proxy_obj: + return self._handle_discovery(proxy_obj, config) + + # If no specific endpoint or version, + # allow discovery with version constraints + return self._create_discovery_adapter(config, version_string) + + def _get_proxy_object(self, config, version_string, endpoint_override): + proxy_class = None + if endpoint_override and version_string and self.supported_versions: + proxy_class = self.supported_versions.get(version_string[0]) + if proxy_class: + return self._construct_proxy( + config, + proxy_class, + endpoint_override + ) + else: + warnings.warn( + f"The configured version {version_string} " + f"for service {self.service_type} " + f"is not known or supported. The resulting " + f"Proxy object will only have direct " + f"passthrough REST capabilities.", + category=os_warnings.UnsupportedServiceVersion) + elif endpoint_override and self.supported_versions: + temp_adapter = config.get_session_client(self.service_type) + api_version = temp_adapter.get_endpoint_data().api_version + proxy_class = self.supported_versions.get(str(api_version[0])) + if proxy_class: + return self._construct_proxy( + config, + proxy_class, + endpoint_override + ) + else: + warnings.warn( + f"Service {self.service_type} has an " + f"endpoint override set, " + f"but the version discovered ({api_version}) is " + f"not supported. The resulting Proxy object will " + f"only have direct passthrough REST capabilities.", + category=os_warnings.UnsupportedServiceVersion) + + def _construct_proxy(self, config, proxy_class, endpoint_override): + proxy_obj = config.get_session_client( + self.service_type, + constructor=proxy_class, + ) + proxy_obj.endpoint_override = endpoint_override + proxy_obj.additional_headers = {'Content-Type': 'application/json'} + return proxy_obj + + def _handle_discovery(self, proxy_obj, config): + if getattr(proxy_obj, 'skip_discovery', False): + return proxy_obj + + data = proxy_obj.get_endpoint_data() + if data.catalog_url != data.service_url: + ep_key = f'{self.service_type}_endpoint_override' + config.config[ep_key] = data.service_url + proxy_obj = config.get_session_client(self.service_type) + return proxy_obj + + def _create_discovery_adapter(self, config, version_string): + version_kwargs = {} + if version_string: + version_kwargs['version'] = version_string + elif self.supported_versions: + sv = sorted(int(f) for f in self.supported_versions) + version_kwargs['min_version'] = str(sv[0]) + version_kwargs['max_version'] = f"{sv[-1]}.latest" + + temp_adapter = config.get_session_client( + self.service_type, + allow_version_hack=True, + **version_kwargs + ) + found_version = temp_adapter.get_api_major_version() + if found_version is None: + raise exceptions.NotSupported( + f"The {self.service_type} service for " + f"{self.instance.name}:{config.region_name} " + f"exists but does not have any supported versions." + ) + proxy_class = self.supported_versions.get(str(found_version[0])) + if proxy_class: + version_kwargs['constructor'] = proxy_class + else: + warnings.warn( + f"Service {self.service_type} has no discoverable version. " + f"The resulting Proxy object will only have direct" + f" passthrough REST capabilities.", + category=os_warnings.UnsupportedServiceVersion) + return config.get_session_client( + self.service_type, + allow_version_hack=True, **version_kwargs + ) diff --git a/otcextensions/tests/functional/sdk/apig/__init__.py b/otcextensions/tests/functional/sdk/apig/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/apig/v2/__init__.py b/otcextensions/tests/functional/sdk/apig/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/apig/v2/test_service.py b/otcextensions/tests/functional/sdk/apig/v2/test_service.py new file mode 100644 index 000000000..d81929e28 --- /dev/null +++ b/otcextensions/tests/functional/sdk/apig/v2/test_service.py @@ -0,0 +1,24 @@ +# 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 openstack import _log + +from otcextensions.tests.functional import base + +_logger = _log.setup_logging('openstack') + + +class TestService(base.BaseFunctionalTest): + + def test_initialize(self): + client = self.conn.apig + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/functional/sdk/er/__init__.py b/otcextensions/tests/functional/sdk/er/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/er/v3/__init__.py b/otcextensions/tests/functional/sdk/er/v3/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/er/v3/test_service.py b/otcextensions/tests/functional/sdk/er/v3/test_service.py new file mode 100644 index 000000000..ff6f2ec76 --- /dev/null +++ b/otcextensions/tests/functional/sdk/er/v3/test_service.py @@ -0,0 +1,24 @@ +# 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 openstack import _log + +from otcextensions.tests.functional import base + +_logger = _log.setup_logging('openstack') + + +class TestService(base.BaseFunctionalTest): + + def test_initialize(self): + client = self.conn.er + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/functional/sdk/function_graph/__init__.py b/otcextensions/tests/functional/sdk/function_graph/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/function_graph/v2/__init__.py b/otcextensions/tests/functional/sdk/function_graph/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/function_graph/v2/test_service.py b/otcextensions/tests/functional/sdk/function_graph/v2/test_service.py new file mode 100644 index 000000000..a0322374f --- /dev/null +++ b/otcextensions/tests/functional/sdk/function_graph/v2/test_service.py @@ -0,0 +1,24 @@ +# 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 openstack import _log + +from otcextensions.tests.functional import base + +_logger = _log.setup_logging('openstack') + + +class TestService(base.BaseFunctionalTest): + + def test_initialize(self): + client = self.conn.function_graph + + self.assertIsNotNone(client) diff --git a/releasenotes/notes/proxies-apig-fg-er-f939b4523f23b031.yaml b/releasenotes/notes/proxies-apig-fg-er-f939b4523f23b031.yaml new file mode 100644 index 000000000..6486b159b --- /dev/null +++ b/releasenotes/notes/proxies-apig-fg-er-f939b4523f23b031.yaml @@ -0,0 +1,8 @@ +--- +features: + - | + Add APIG v2 proxy + - | + Add EnterpriseRouter v3 proxy + - | + Add FunctionGraph v2 proxy