From 25c5572733c4145aa63dc297eb9371cf4a3956bc Mon Sep 17 00:00:00 2001 From: "T. Schreiber" Date: Thu, 12 Dec 2019 12:12:33 +0100 Subject: [PATCH 01/58] First NAT implementation for SDK (#52) * initial nat gateway branche * added snat and dnat resource * dnat and snat proxy functions added * first running state * gateway fixed * linting corrections * Minor changes, tested successfully * unittest nat.test_snat nat.test_dnat and nat.test_gateway added * nat changes * pep8 issues * test_proxy.py added for NAT * stash status changed and proxy test added --- otcextensions/sdk/__init__.py | 3 + otcextensions/sdk/nat/__init__.py | 0 otcextensions/sdk/nat/nat_service.py | 22 +++ otcextensions/sdk/nat/v2/__init__.py | 0 otcextensions/sdk/nat/v2/_proxy.py | 178 ++++++++++++++++++ otcextensions/sdk/nat/v2/dnat.py | 69 +++++++ otcextensions/sdk/nat/v2/gateway.py | 61 ++++++ otcextensions/sdk/nat/v2/snat.py | 62 ++++++ otcextensions/tests/unit/sdk/nat/__init__.py | 0 .../tests/unit/sdk/nat/v2/test_dnat.py | 67 +++++++ .../tests/unit/sdk/nat/v2/test_gateway.py | 60 ++++++ .../tests/unit/sdk/nat/v2/test_proxy.py | 90 +++++++++ .../tests/unit/sdk/nat/v2/test_snat.py | 61 ++++++ 13 files changed, 673 insertions(+) create mode 100644 otcextensions/sdk/nat/__init__.py create mode 100644 otcextensions/sdk/nat/nat_service.py create mode 100644 otcextensions/sdk/nat/v2/__init__.py create mode 100644 otcextensions/sdk/nat/v2/_proxy.py create mode 100644 otcextensions/sdk/nat/v2/dnat.py create mode 100644 otcextensions/sdk/nat/v2/gateway.py create mode 100644 otcextensions/sdk/nat/v2/snat.py create mode 100644 otcextensions/tests/unit/sdk/nat/__init__.py create mode 100644 otcextensions/tests/unit/sdk/nat/v2/test_dnat.py create mode 100644 otcextensions/tests/unit/sdk/nat/v2/test_gateway.py create mode 100644 otcextensions/tests/unit/sdk/nat/v2/test_proxy.py create mode 100644 otcextensions/tests/unit/sdk/nat/v2/test_snat.py diff --git a/otcextensions/sdk/__init__.py b/otcextensions/sdk/__init__.py index fa00a317c..41cf95de1 100644 --- a/otcextensions/sdk/__init__.py +++ b/otcextensions/sdk/__init__.py @@ -88,6 +88,9 @@ 'service_type': 'kms', 'append_project_id': True, }, + 'nat': { + 'service_type': 'nat' + }, 'obs': { 'service_type': 'obs', 'require_ak': True, diff --git a/otcextensions/sdk/nat/__init__.py b/otcextensions/sdk/nat/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/nat/nat_service.py b/otcextensions/sdk/nat/nat_service.py new file mode 100644 index 000000000..d5fbc32f1 --- /dev/null +++ b/otcextensions/sdk/nat/nat_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.nat.v2 import _proxy + + +class NatService(service_description.ServiceDescription): + """The NAT service.""" + + supported_versions = { + '2': _proxy.Proxy + } diff --git a/otcextensions/sdk/nat/v2/__init__.py b/otcextensions/sdk/nat/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/nat/v2/_proxy.py b/otcextensions/sdk/nat/v2/_proxy.py new file mode 100644 index 000000000..4df1a1a06 --- /dev/null +++ b/otcextensions/sdk/nat/v2/_proxy.py @@ -0,0 +1,178 @@ +# 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 otcextensions.sdk.nat.v2 import gateway as _gateway +from otcextensions.sdk.nat.v2 import snat as _snat +from otcextensions.sdk.nat.v2 import dnat as _dnat + +from openstack import proxy + + +class Proxy(proxy.Proxy): + + skip_discovery = True + + # ======== Gateway ======== + def create_gateway(self, **attrs): + """Create a new gateway from attributes + + :param dict attrs: Keyword arguments which will be used to create + a :class:`~otcextensions.sdk.nat.v2.gateway.Gateway` + """ + return self._create(_gateway.Gateway, **attrs) + + def delete_gateway(self, gateway, ignore_missing=True): + """Delete a gateway + + :param gateway: key id or an instance of + :class:`~otcextensions.sdk.nat.v2.gateway.Gateway` + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be raised when + the gateway does not exist. + When set to ``True``, no exception will be set when attempting to + delete a nonexistent gateway. + + :returns: Gateway been deleted + :rtype: :class:`~otcextensions.sdk.nat.v2.gateway.Gateway` + """ + return self._delete(_gateway.Gateway, gateway, + ignore_missing=ignore_missing) + + def gateways(self, **query): + """Return a generator of gateways + + :param dict query: Optional query parameters to be sent to limit + the resources being returned. + :returns: A generator of gateway objects + :rtype: :class:`~otcextensions.sdk.nat.v2.gateway.Gateway` + """ + return self._list(_gateway.Gateway, **query) + + def get_gateway(self, gateway): + """Get a single gateway + + :param gateway: The value can be the ID of a NAT Gatway or a + :class:`~otcextensions.sdk.nat.v2.gateway.Gateway` + instance. + + :returns: One :class:`~otcextensions.sdk.nat.v2.gateway.Gateway` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_gateway.Gateway, gateway) + + def update_gateway(self, gateway, **attrs): + """Update a gateway + + :param gateway: Either the ID of a gateway or a + :class:`~otcextensions.sdk.nat.v2.gateway.Gateway` + instance. + :param dict attrs: The attributes to update on the gateway represented + by ``gateway``. + + :returns: The updated gateway + :rtype: :class:`~otcextensions.sdk.nat.v2.gateway.Gateway` + """ + return self._update(_gateway.Gateway, gateway, **attrs) + + # ======== SNAT rules ======== + def create_snat_rule(self, **attrs): + """Create a new SNAT rule from attributes + + :param dict attrs: Keyword arguments which will be used to create + a :class:`~otcextensions.sdk.nat.v2.snat.Snat` + """ + return self._create(_snat.Snat, **attrs) + + def delete_snat_rule(self, snat, ignore_missing=True): + """Delete a SNAT rule + + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be raised when + the SNAT rule does not exist. + When set to ``True``, no exception will be set when attempting to + delete a nonexistent SNAT rule. + + :returns: SNAT rule been deleted + :rtype: :class:`~otcextensions.sdk.nat.v2.snat.Snat` + """ + return self._delete(_snat.Snat, snat, ignore_missing=ignore_missing) + + def get_snat_rule(self, snat_rule): + """Get a single SNAT rule + + :param snat_rule: The value can be the ID of a SNAT rule or a + :class:`~otcextensions.sdk.nat.v2.snat.Snat` + instance. + + :returns: One :class:`~otcextensions.sdk.nat.v2.snat.Snat` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_snat.Snat, snat_rule) + + def snat_rules(self, **query): + """Return a generator of SNAT rules + + :param dict query: Optional query parameters to be sent to limit + the resources being returned. + :returns: A generator of Snat rule objects + :rtype: :class:`~otcextensions.sdk.nat.v2.snat.Snat` + """ + return self._list(_snat.Snat, **query) + + # ======== DNAT rules ======== + def create_dnat_rule(self, **attrs): + """Create a new DNAT rule from attributes + + :param dict attrs: Keyword arguments which will be used to create + a :class:`~otcextensions.sdk.nat.v2.dnat.Dnat` + """ + return self._create(_dnat.Dnat, **attrs) + + def delete_dnat_rule(self, dnat, ignore_missing=True): + """Delete a DNAT rule + + :param dict attrs: Keyword arguments which will be used to delete + a :class:`~otcextensions.sdk.nat.v2.dnat.Dnat` + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be raised when + the DNAT rule does not exist. + When set to ``True``, no exception will be set when attempting to + delete a nonexistent DNAT rule. + + :returns: DNAT rule been deleted + :rtype: :class:`~otcextensions.sdk.nat.v2.dnat.Dnat` + """ + return self._delete(_dnat.Dnat, dnat, ignore_missing=ignore_missing) + + def get_dnat_rule(self, dnat_rule): + """Get a single DNAT rule + + :param dnat_rule: The value can be the ID of a DNAT rule or a + :class:`~otcextensions.sdk.nat.v2.dnat.Dnat` + instance. + + :returns: One :class:`~otcextensions.sdk.nat.v2.dnat.Dnat` + :raises: :class:`~openstack.exceptions.ResourceNotFound` + when no resource can be found. + """ + return self._get(_dnat.Dnat, dnat_rule) + + def dnat_rules(self, **query): + """Return a generator of DNAT rules + + :param dict query: Optional query parameters to be sent to limit + the resources being returned. + :returns: A generator of DNAT rules objects + :rtype: :class:`~otcextensions.sdk.nat.v2.dnat.Dnat` + """ + return self._list(_dnat.Dnat, **query) diff --git a/otcextensions/sdk/nat/v2/dnat.py b/otcextensions/sdk/nat/v2/dnat.py new file mode 100644 index 000000000..5c71f7e2c --- /dev/null +++ b/otcextensions/sdk/nat/v2/dnat.py @@ -0,0 +1,69 @@ +# 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 resource + + +class Dnat(resource.Resource): + resources_key = 'dnat_rules' + resource_key = 'dnat_rule' + base_path = '/dnat_rules' + + # capabilities + allow_create = True + allow_fetch = True + allow_delete = True + allow_list = True + + _query_mapping = resource.QueryParameters( + 'admin_state_up', 'cidr', 'created_at', 'external_service_port', + 'floating_ip_address', 'floating_ip_id', 'id', + 'internal_service_port', 'limit', 'nat_gateway_id', 'network_id', + 'port_id', 'private_id', 'protocol', 'source_type', 'status', + 'project_id' + ) + + # Properties + #: Specifies whether DNAT rule is enabled / disabled + #: *true:* DNAT rule is enabled + #: *false:* DNAT rule is disabled + admin_state_up = resource.Body('admin_state_up', type=bool) + #: Specifies when the rule is created. + #: The format is yyyy-mm-dd hh:mm:ss. + created_at = resource.Body('created_at') + #: Specifies the port for providing external services. + external_service_port = resource.Body('external_service_port', type=int) + #: Specifies the EIP + floating_ip_address = resource.Body('floating_ip_address') + #: Specifies the EIP ID + floating_ip_id = resource.Body('floating_ip_id') + #: Specifies the gateway ID. + gateway_id = resource.Body('gateway_id') + #: Specifies the ID of the DNAT rule. + id = resource.Body('id') + #: Specifies port used by ECS/BMS to provide services for external systems + internal_service_port = resource.Body('internal_service_port', type=int) + #: Specifies the ID of the NAT gateway. + nat_gateway_id = resource.Body('nat_gateway_id') + #: Specifies the port ID of an ECS or BMS + #: Parameter is used in the VPC scenario. + #: This parameter is an alternative to private_ip + port_id = resource.Body('port_id') + #: Specifies the IP address of a Direct Connect connection. + #: Parameter is used in the Direct Connect scenario. + #: This parameter is an alternative to port_id. + private_ip = resource.Body('private_ip') + #: Specifies the project ID. + project_id = resource.Body('tenant_id') + #: Specifies the protocol type. Currently TCP(6), UDP(17) and ANY(0) + protocol = resource.Body('protocol') + #: Specifies the status of the DNAT rule + status = resource.Body('status') diff --git a/otcextensions/sdk/nat/v2/gateway.py b/otcextensions/sdk/nat/v2/gateway.py new file mode 100644 index 000000000..bcacd7f32 --- /dev/null +++ b/otcextensions/sdk/nat/v2/gateway.py @@ -0,0 +1,61 @@ +# 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 resource + + +class Gateway(resource.Resource): + resources_key = 'nat_gateways' + resource_key = 'nat_gateway' + base_path = '/nat_gateways' + + # capabilities + allow_create = True + allow_fetch = True + allow_commit = True + allow_delete = True + allow_list = True + + _query_mapping = resource.QueryParameters( + 'admin_state_up', 'created_at', 'description', 'id', + 'internal_network_id', 'limit', 'name', 'router_id', + 'spec', 'status', 'project_id' + ) + + # Properties + #: Specifies whether GW is up or down + #: *true:* Gw is up + #: *false:* GW is down + admin_state_up = resource.Body('admin_state_up', type=bool) + #: Specifies when GW was is created + #: format is *yyyy-mm-dd hh:mm:ss* + created_at = resource.Body('created_at') + #: Provides description of gateway + description = resource.Body('description') + #: Specifies the ID of the gateway. + id = resource.Body('id') + #: Specifies the network ID of the downstream interface + internal_network_id = resource.Body('internal_network_id') + #: Specifies the name of the gateway. + #: Contains only digits, letters, underscores and hyphens + name = resource.Body('name') + #: Specifies the project ID + project_id = resource.Body('tenant_id') + #: Specifies the router ID + router_id = resource.Body('router_id') + #: Specifies the type of the gateway. + #: *1:* small type, supports up to 10,000 SNAT connections + #: *2:* medium type, supports up to 50,000 SNAT connections + #: *3:* large type, supports up to 200,000 SNAT connections + #: *4:* extra-large type, supports up to 1,000,000 SNAT connections + spec = resource.Body('spec') + #: Specifies the status + status = resource.Body('status') diff --git a/otcextensions/sdk/nat/v2/snat.py b/otcextensions/sdk/nat/v2/snat.py new file mode 100644 index 000000000..57c75685f --- /dev/null +++ b/otcextensions/sdk/nat/v2/snat.py @@ -0,0 +1,62 @@ +# 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 resource + + +class Snat(resource.Resource): + resources_key = 'snat_rules' + resource_key = 'snat_rule' + base_path = '/snat_rules' + + # capabilities + allow_create = True + allow_fetch = True + allow_delete = True + allow_list = True + + _query_mapping = resource.QueryParameters( + 'admin_state_up', 'cidr', 'created_at', 'floating_ip_address', + 'floating_ip_id', 'id', 'limit', 'nat_gateway_id', 'network_id', + 'source_type', 'status', 'project_id' + ) + + # Properties + #: Specifies the status of the SNAT rule + admin_state_up = resource.Body('admin_state_up', type=bool) + #: Specifies a subset of the VPC subnet CIDR block or a + #: CIDR block of Direct Connect connection. + cidr = resource.Body('cidr') + #: Specifies when the rule is created. + #: The format is yyyy-mm-dd hh:mm:ss. + created_at = resource.Body('created_at') + #: Specifies the EIP + #: Multiple EIPs are separated using commas + floating_ip_address = resource.Body('floating_ip_address') + #: Specifies the EIP ID + #: Multiple EIPs are separated using commas + floating_ip_id = resource.Body('floating_ip_id') + #: Specifies the ID of the SNAT rule. + id = resource.Body('id') + #: Specifies the gateway ID. + nat_gateway_id = resource.Body('nat_gateway_id') + #: Specifies the network ID + network_id = resource.Body('network_id') + #: Specifies the project ID. + project_id = resource.Body('tenant_id') + #: *0:* Either network_id or cidr can be specified in VPC + #: *1:* only cidr can be specified over a Direct Connect connection + #: Default: 0 + source_type = resource.Body('source_type', type=int) + #: Specifies whether SNAT rule is enabled / disabled + #: *true:* SNAT rule is enabled + #: *false:* SNAT rule is disabled + status = resource.Body('status') diff --git a/otcextensions/tests/unit/sdk/nat/__init__.py b/otcextensions/tests/unit/sdk/nat/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/nat/v2/test_dnat.py b/otcextensions/tests/unit/sdk/nat/v2/test_dnat.py new file mode 100644 index 000000000..655773526 --- /dev/null +++ b/otcextensions/tests/unit/sdk/nat/v2/test_dnat.py @@ -0,0 +1,67 @@ +# 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.tests.unit import base + +from otcextensions.sdk.nat.v2 import dnat + + +INSTANCE_ID = '5b95c675-69c2-4656-ba06-58ff72e1d338' +EXAMPLE = { + 'floating_ip_id': 'bdc10a4c-d81a-41ec-adf7-de857f7c812a', + 'status': 'ACTIVE', + 'nat_gateway_id': 'a78fb3eb-1654-4710-8742-3fc49d5f04f8', + 'admin_state_up': True, + 'port_id': '9a469561-daac-4c94-88f5-39366e5ea193', + 'internal_service_port': 993, + 'protocol': 'TCP', + 'project_id': '27e25061336f4af590faeabeb7fcd9a3', + 'created_at': '2017-11-18 07:54:21.665430', + 'id': INSTANCE_ID, + 'floating_ip_address': '5.21.11.226', + 'external_service_port': 242, + 'private_ip': "", +} + + +class TestDnat(base.TestCase): + + def test_basic(self): + sot = dnat.Dnat() + self.assertEqual('dnat_rule', sot.resource_key) + self.assertEqual('dnat_rules', sot.resources_key) + path = '/dnat_rules' + self.assertEqual(path, sot.base_path) + self.assertTrue(sot.allow_list) + self.assertTrue(sot.allow_create) + self.assertTrue(sot.allow_fetch) + self.assertFalse(sot.allow_commit) + self.assertTrue(sot.allow_delete) + + def test_make_it(self): + sot = dnat.Dnat(**EXAMPLE) + self.assertEqual(EXAMPLE['floating_ip_id'], sot.floating_ip_id) + self.assertEqual(EXAMPLE['status'], sot.status) + self.assertEqual(EXAMPLE['nat_gateway_id'], sot.nat_gateway_id) + self.assertEqual(EXAMPLE['admin_state_up'], sot.admin_state_up) + self.assertEqual(EXAMPLE['port_id'], sot.port_id) + self.assertEqual(EXAMPLE['internal_service_port'], + sot.internal_service_port) + self.assertEqual(EXAMPLE['protocol'], sot.protocol) + self.assertEqual(EXAMPLE['project_id'], sot.project_id) + self.assertEqual(EXAMPLE['created_at'], sot.created_at) + self.assertEqual(EXAMPLE['id'], sot.id) + self.assertEqual(EXAMPLE['floating_ip_address'], + sot.floating_ip_address) + self.assertEqual(EXAMPLE['external_service_port'], + sot.external_service_port) + self.assertEqual(EXAMPLE['private_ip'], sot.private_ip) diff --git a/otcextensions/tests/unit/sdk/nat/v2/test_gateway.py b/otcextensions/tests/unit/sdk/nat/v2/test_gateway.py new file mode 100644 index 000000000..327231eae --- /dev/null +++ b/otcextensions/tests/unit/sdk/nat/v2/test_gateway.py @@ -0,0 +1,60 @@ +# 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.tests.unit import base + +from otcextensions.sdk.nat.v2 import gateway + + +INSTANCE_NAME = 'GATEWAYNAME' +INSTANCE_ID = 'a78fb3eb-1654-4710-8742-3fc49d5f04f8' +EXAMPLE = { + 'router_id': 'd84f345c-80a1-4fa2-a39c-d0d397c3f09a', + 'status': 'PENDING_CREATE', + 'description': 'Test Gateway Response', + 'admin_state_up': True, + 'project_id': '27e25061336f4af590faeabeb7fcd9a3', + 'created_at': '2017-11-18 07:34:32.203044', + 'spec': '2', + 'internal_network_id': '89d66639-aacb-4929-969d-07080b0f9fd9', + 'id': INSTANCE_ID, + 'name': INSTANCE_NAME +} + + +class TestGateway(base.TestCase): + + def test_basic(self): + sot = gateway.Gateway() + self.assertEqual('nat_gateway', sot.resource_key) + self.assertEqual('nat_gateways', sot.resources_key) + path = '/nat_gateways' + self.assertEqual(path, sot.base_path) + self.assertTrue(sot.allow_list) + self.assertTrue(sot.allow_create) + self.assertTrue(sot.allow_fetch) + self.assertTrue(sot.allow_commit) + self.assertTrue(sot.allow_delete) + + def test_make_it(self): + sot = gateway.Gateway(**EXAMPLE) + self.assertEqual(EXAMPLE['router_id'], sot.router_id) + self.assertEqual(EXAMPLE['status'], sot.status) + self.assertEqual(EXAMPLE['description'], sot.description) + self.assertEqual(EXAMPLE['admin_state_up'], sot.admin_state_up) + self.assertEqual(EXAMPLE['project_id'], sot.project_id) + self.assertEqual(EXAMPLE['created_at'], sot.created_at) + self.assertEqual(EXAMPLE['spec'], sot.spec) + self.assertEqual(EXAMPLE['internal_network_id'], + sot.internal_network_id) + self.assertEqual(EXAMPLE['id'], sot.id) + self.assertEqual(EXAMPLE['name'], sot.name) diff --git a/otcextensions/tests/unit/sdk/nat/v2/test_proxy.py b/otcextensions/tests/unit/sdk/nat/v2/test_proxy.py new file mode 100644 index 000000000..9f5140483 --- /dev/null +++ b/otcextensions/tests/unit/sdk/nat/v2/test_proxy.py @@ -0,0 +1,90 @@ +# 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. + +# 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 otcextensions.sdk.nat.v2 import _proxy +from otcextensions.sdk.nat.v2 import snat +from otcextensions.sdk.nat.v2 import dnat +from otcextensions.sdk.nat.v2 import gateway + +from openstack.tests.unit import test_proxy_base + + +class TestNatProxy(test_proxy_base.TestProxyBase): + def setUp(self): + super(TestNatProxy, self).setUp() + self.proxy = _proxy.Proxy(self.session) + + +class TestNatGateway(TestNatProxy): + def test_gateway_create(self): + self.verify_create(self.proxy.create_gateway, gateway.Gateway, + method_kwargs={'name': 'id'}, + expected_kwargs={'name': 'id'}) + + def test_gateway_delete(self): + self.verify_delete(self.proxy.delete_gateway, + gateway.Gateway, True) + + def test_gateway_get(self): + self.verify_get(self.proxy.get_gateway, gateway.Gateway) + + def test_gateways(self): + self.verify_list(self.proxy.gateways, gateway.Gateway) + + def test_gateway_update(self): + self.verify_update(self.proxy.update_gateway, gateway.Gateway) + + +class TestNatSnatRule(TestNatProxy): + def test_snat_rule_create(self): + self.verify_create(self.proxy.create_snat_rule, snat.Snat, + method_kwargs={'name': 'id'}, + expected_kwargs={'name': 'id'}) + + def test_snat_rule_delete(self): + self.verify_delete(self.proxy.delete_snat_rule, + snat.Snat, True) + + def test_snat_rule_get(self): + self.verify_get(self.proxy.get_snat_rule, snat.Snat) + + def test_snat_rules(self): + self.verify_list(self.proxy.snat_rules, snat.Snat) + + +class TestNatDnatRule(TestNatProxy): + def test_dnat_rule_create(self): + self.verify_create(self.proxy.create_dnat_rule, dnat.Dnat, + method_kwargs={'name': 'id'}, + expected_kwargs={'name': 'id'}) + + def test_dnat_rule_delete(self): + self.verify_delete(self.proxy.delete_dnat_rule, + dnat.Dnat, True) + + def test_dnat_rule_get(self): + self.verify_get(self.proxy.get_dnat_rule, dnat.Dnat) + + def test_dnat_rules(self): + self.verify_list(self.proxy.dnat_rules, dnat.Dnat) diff --git a/otcextensions/tests/unit/sdk/nat/v2/test_snat.py b/otcextensions/tests/unit/sdk/nat/v2/test_snat.py new file mode 100644 index 000000000..21cf7ee60 --- /dev/null +++ b/otcextensions/tests/unit/sdk/nat/v2/test_snat.py @@ -0,0 +1,61 @@ +# 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.tests.unit import base + +from otcextensions.sdk.nat.v2 import snat + + +INSTANCE_ID = '5b95c675-69c2-4656-ba06-58ff72e1d338' +EXAMPLE = { + 'floating_ip_id': 'bdc10a4c-d81a-41ec-adf7-de857f7c812a', + 'status': 'PENDING_CREATE', + 'nat_gateway_id': 'a78fb3eb-1654-4710-8742-3fc49d5f04f8', + 'admin_state_up': True, + 'network_id': 'eaad9cd6-2372-4be1-9535-9bd37210ae7b', + 'cidr': None, + 'source_type': 0, + 'project_id': '27e25061336f4af590faeabeb7fcd9a3', + 'created_at': '2017-11-18 07:54:21.665430', + 'id': INSTANCE_ID, + 'floating_ip_address': '5.21.11.226' +} + + +class TestSnat(base.TestCase): + + def test_basic(self): + sot = snat.Snat() + self.assertEqual('snat_rule', sot.resource_key) + self.assertEqual('snat_rules', sot.resources_key) + path = '/snat_rules' + self.assertEqual(path, sot.base_path) + self.assertTrue(sot.allow_list) + self.assertTrue(sot.allow_create) + self.assertTrue(sot.allow_fetch) + self.assertFalse(sot.allow_commit) + self.assertTrue(sot.allow_delete) + + def test_make_it(self): + sot = snat.Snat(**EXAMPLE) + self.assertEqual(EXAMPLE['floating_ip_id'], sot.floating_ip_id) + self.assertEqual(EXAMPLE['status'], sot.status) + self.assertEqual(EXAMPLE['nat_gateway_id'], sot.nat_gateway_id) + self.assertEqual(EXAMPLE['admin_state_up'], sot.admin_state_up) + self.assertEqual(EXAMPLE['network_id'], sot.network_id) + self.assertIsNone(sot.cidr) + self.assertEqual(EXAMPLE['source_type'], sot.source_type) + self.assertEqual(EXAMPLE['project_id'], sot.project_id) + self.assertEqual(EXAMPLE['created_at'], sot.created_at) + self.assertEqual(EXAMPLE['id'], sot.id) + self.assertEqual(EXAMPLE['floating_ip_address'], + sot.floating_ip_address) From de078f7cd6a7b960a240490fe302f1007ca508d4 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Thu, 12 Dec 2019 12:13:21 +0100 Subject: [PATCH 02/58] Func tests for Rds v3 (#51) * Adding RDS v3 implementation * Saving Changes to github * Saving further changes in RDSv3 * Adding RDSv3 Instance and Backup functionalities * Updates in RDS Backup Funcationality * Saving RDSv3 Changes to GitHub * Adding Backup Policy for RDSv3 * Adding RDSv3 restore functionality * interim update wrt coding conventions * next bunch of changes for instance * cleanup configurations * next bunch of changes * finish implementation, switch to usage tests * add check for additional mandatory params * add wait_for_job and replace --datastore with --datatore-type * extend params choices for create instance params * fix help message with param names * check flavor when creating instance * hopefully fix find instance * rds is not using default job query * try to improve find_flavor * add some checks for ha_mode <=> datastore_type * add tests for ensuring mode vs datastore checks * fix pep * add wait for deleting instance * add optional wait-interval argument * try fix wait_for_job for rds * add basic get_instance as mix of list and fetch * extend unit test for instance.fetch * fix error param * skip extra list conversion * raise exception if --wait-interval is without --wait * override _translate_response of instance to process create response right * Minor Fix in setup.cfg * fix configuration and add func test * add some choices to instance list * Adding few more rds test_config func tests * try fix pagination * another try for pagination * fix * if limit set - return only this amount of entries * some reorg * turn back dropped refetch * try fix download-links * change help to show only backup_id is accepted * Updated formatting for test_configuration * fix download links * change apply config * change apply * fix set backup policy * rename fields * some fixes in list backup * change params from "_" to "-" * exclude time filters in listing backups due to API corruptness * add KB to the download size header * parse backup struct better * fix create struct * hide lcoation of backup * restore required params * enable show restore time * Adding functional tests for osclient * Updated functional tests for rdsv3 * Saving functional tests for rds instance * pep8 fixes * removed print line --- .../osclient/rds/v3/test_configuration.py | 170 ++++----- .../osclient/rds/v3/test_datastore.py | 29 +- .../functional/osclient/rds/v3/test_flavor.py | 53 ++- .../osclient/rds/v3/test_instance.py | 344 +++++++++++++++++- 4 files changed, 476 insertions(+), 120 deletions(-) diff --git a/otcextensions/tests/functional/osclient/rds/v3/test_configuration.py b/otcextensions/tests/functional/osclient/rds/v3/test_configuration.py index 00b4aa583..3c6550022 100644 --- a/otcextensions/tests/functional/osclient/rds/v3/test_configuration.py +++ b/otcextensions/tests/functional/osclient/rds/v3/test_configuration.py @@ -11,7 +11,7 @@ # under the License. import json -import uuid +import random from openstackclient.tests.functional import base @@ -19,125 +19,88 @@ class TestRdsConfiguration(base.TestCase): """Functional tests for RDS Configurations. """ - NAME = uuid.uuid4().hex - def test_list(self): - json_output = json.loads( - self.openstack('rds configuration list -f json ')) + json_output = json.loads(self.openstack( + 'rds configuration list -f json ' + )) self.assertIsNotNone(json_output) def test_show(self): - json_output = json.loads( - self.openstack('rds configuration list -f json')) - - json_output = json.loads( - self.openstack( - 'rds configuration show {cfg} ' - '-f json'.format( - cfg=json_output[0]['ID'] - ) - ) - ) + json_output = json.loads(self.openstack( + 'rds configuration list -f json' + )) - self.assertIsNotNone(json_output['id']) + json_output = json.loads(self.openstack( + 'rds configuration show {cfg} -f json'.format( + cfg=json_output[0]['ID']) + )) - def test_long(self): - json_output = json.loads( - self.openstack( - 'rds configuration create ' - '--datastore-type postgresql ' - '--datastore-version 9.6 ' - '--value max_connections=10 ' - '{name} -f json'.format(name=self.NAME) - ) - ) - id = json_output['id'] - self.addCleanup(self.openstack, 'rds configuration delete ' + id) - - json_output = json.loads( - self.openstack( - 'rds configuration show {id} ' - '-f json'.format(id=id) - ) - ) - self.assertTrue(self.NAME, json_output['name']) + self.assertIsNotNone(json_output['id']) - json_output = json.loads( - self.openstack( - 'rds configuration show {id} ' - '-f json'.format(id=self.NAME) - ) - ) - self.assertTrue(id, json_output['id']) + def test_create(self): + name = 'osc-test-config-' + format(random.randint(1, 2**16), '04x') + json_output = json.loads(self.openstack( + 'rds configuration create ' + '{name} ' + '--datastore-type MySQL ' + '--datastore-version 5.7 ' + '-f json'.format( + name=name) + )) + self.assertIsNotNone(json_output) self.openstack( - 'rds configuration set ' - '--value max_connections=15 ' - '{name}'.format(name=self.NAME) + 'rds configuration delete ' + '{name} '.format( + name=name) ) + self.assertTrue(True) - def test_create(self): - name = uuid.uuid4().hex - json_output = json.loads( - self.openstack( - 'rds configuration create ' - '{name} ' - '--datastore-type MySQL ' - '--datastore-version 5.7 ' - '-f json'.format(name=name) - ) - ) + def test_create_with_value(self): + name = 'osc-test-config-' + format(random.randint(1, 2**16), '04x') + json_output = json.loads(self.openstack( + 'rds configuration create ' + '{name} ' + '--datastore-type MySQL ' + '--datastore-version 5.7 ' + '--value max_connections=10 ' + '--value autocommit=OFF ' + '-f json'.format( + name=name) + )) self.assertIsNotNone(json_output) - id = json_output['id'] - self.addCleanup(self.openstack, 'rds configuration delete ' + id) - def test_create_with_value(self): - name = uuid.uuid4().hex - json_output = json.loads( - self.openstack( - 'rds configuration create ' - '{name} ' - '--datastore-type MySQL ' - '--datastore-version 5.7 ' - '--value max_connections=10 ' - '--value autocommit=OFF ' - '-f json'.format(name=name) - ) + self.openstack( + 'rds configuration delete ' + '{name} '.format( + name=name) ) - self.assertIsNotNone(json_output) - self.assertEqual(name, json_output['name']) - id = json_output['id'] - self.addCleanup(self.openstack, 'rds configuration delete ' + id) + self.assertTrue(True) def test_config_param_list(self): - json_output = json.loads( - self.openstack( - 'rds configuration list -f json' - ) - ) - json_output = json.loads( - self.openstack( - 'rds configuration parameter list ' - '{cfg} ' - '-f json'.format(cfg=json_output[0]['ID']) - ) - ) + json_output = json.loads(self.openstack( + 'rds configuration list -f json' + )) + + json_output = json.loads(self.openstack( + 'rds configuration parameter list ' + '{cfg} ' + '-f json'.format( + cfg=json_output[0]['ID']) + )) self.assertIsNotNone(json_output) def test_config_set(self): - name = uuid.uuid4().hex - json_output = json.loads( - self.openstack( - 'rds configuration create ' - '{name} ' - '--datastore-type MySQL ' - '--datastore-version 5.7 ' - '-f json'.format(name=name) - ) - ) + name = 'osc-test-config-' + format(random.randint(1, 2**16), '04x') + json_output = json.loads(self.openstack( + 'rds configuration create ' + '{name} ' + '--datastore-type MySQL ' + '--datastore-version 5.7 ' + '-f json'.format( + name=name) + )) self.assertIsNotNone(json_output) - id = json_output['id'] - self.addCleanup(self.openstack, 'rds configuration delete ' + id) self.openstack( 'rds configuration set ' @@ -146,3 +109,10 @@ def test_config_set(self): '--value autocommit=OFF'.format(name=name) ) self.assertTrue(True) + + self.openstack( + 'rds configuration delete ' + '{name} '.format( + name=name) + ) + self.assertTrue(True) diff --git a/otcextensions/tests/functional/osclient/rds/v3/test_datastore.py b/otcextensions/tests/functional/osclient/rds/v3/test_datastore.py index 2d373251a..59cc90c45 100644 --- a/otcextensions/tests/functional/osclient/rds/v3/test_datastore.py +++ b/otcextensions/tests/functional/osclient/rds/v3/test_datastore.py @@ -13,6 +13,7 @@ import json from openstackclient.tests.functional import base +from tempest.lib import exceptions class TestRdsDatastore(base.TestCase): @@ -22,14 +23,30 @@ def test_datastore_list(self): json_output = json.loads(self.openstack( 'rds datastore type list -f json ' )) - self.assertIn( - 'PostgreSQL', - [ds['Name'] for ds in json_output] + + self.assertItemsEqual( + ['postgresql', 'mysql', 'sqlserver'], + [ds.get('Name', None).lower() for ds in json_output] ) def test_datastore_version_list(self): - json_output = json.loads(self.openstack( - 'rds datastore version list PostgreSQL -f json' + datastores = json.loads(self.openstack( + 'rds datastore type list -f json' )) + for datastore in datastores: + json_output = json.loads(self.openstack( + 'rds datastore version list {ds} ' + '-f json'.format(ds=datastore['Name']) + )) + self.assertIsNotNone(json_output) + self.assertEqual( + ['ID', 'Name'], + list(json_output[0].keys()) + ) - self.assertIsNotNone(json_output) + def test_invalid_datastore_version_list(self): + self.assertRaises( + exceptions.CommandFailed, + self.openstack, + 'rds datastore version list invalid_ds' + ) diff --git a/otcextensions/tests/functional/osclient/rds/v3/test_flavor.py b/otcextensions/tests/functional/osclient/rds/v3/test_flavor.py index 864316543..ab9a830e9 100644 --- a/otcextensions/tests/functional/osclient/rds/v3/test_flavor.py +++ b/otcextensions/tests/functional/osclient/rds/v3/test_flavor.py @@ -14,6 +14,7 @@ import uuid from openstackclient.tests.functional import base +from tempest.lib import exceptions class TestRdsFlavor(base.TestCase): @@ -23,14 +24,50 @@ class TestRdsFlavor(base.TestCase): OTHER_NAME = uuid.uuid4().hex def test_flavor_list(self): - json_output = json.loads(self.openstack( - 'rds datastore version list postgresql -f json ' + datastores = json.loads(self.openstack( + 'rds datastore type list -f json' )) - ver = json_output[0]['Name'] + for datastore in datastores: + datastore = datastore['Name'] + json_output = json.loads(self.openstack( + 'rds datastore version list ' + datastore + ' -f json ' + )) - json_output = json.loads(self.openstack( - 'rds flavor list postgresql {ver} -f json '.format( - ver=ver) - )) + for ds_ver in json_output: + json_output = json.loads(self.openstack( + 'rds flavor list {ds} {ver} -f json'.format( + ds=datastore, + ver=ds_ver['Name']) + )) + + self.assertIsNotNone(json_output) + self.assertEqual( + ['name', 'instance_mode', 'vcpus', 'ram'], + list(json_output[0].keys()) + ) + + def test_invalid_datastore_flavor_list(self): + self.assertRaises( + exceptions.CommandFailed, + self.openstack, + 'rds flavor list' + ) - self.assertIsNotNone(json_output) + self.assertRaises( + exceptions.CommandFailed, + self.openstack, + 'rds flavor list invalid_ds 5.6' + ) + + datastores = json.loads(self.openstack( + 'rds datastore type list -f json' + )) + for datastore in datastores: + datastore = datastore['Name'] + self.assertRaises( + exceptions.CommandFailed, + self.openstack, + 'rds flavor list {ds} {ver}'.format( + ds=datastore, + ver=0.0) + ) diff --git a/otcextensions/tests/functional/osclient/rds/v3/test_instance.py b/otcextensions/tests/functional/osclient/rds/v3/test_instance.py index 8e34fb33c..38821c5a0 100644 --- a/otcextensions/tests/functional/osclient/rds/v3/test_instance.py +++ b/otcextensions/tests/functional/osclient/rds/v3/test_instance.py @@ -11,29 +11,361 @@ # under the License. import uuid +import json +import time + +import concurrent.futures from openstackclient.tests.functional import base +from tempest.lib.exceptions import CommandFailed class TestRdsInstance(base.TestCase): """Functional tests for RDS Instance. """ - NAME = uuid.uuid4().hex - OTHER_NAME = uuid.uuid4().hex + UUID = uuid.uuid4().hex[:8] + ROUTER_NAME = 'sdk-test-router-' + UUID + NET_NAME = 'sdk-test-net-' + UUID + SUBNET_NAME = 'sdk-test-subnet-' + UUID + SG_NAME = 'sdk-test-sg-' + UUID + ROUTER_ID = None + NET_ID = None + SG_ID = None + + RDS_NAME = 'sdk-test-rds-' + UUID + RDS_HA_NAME = 'sdk-test-rds-ha-' + UUID + RDS_RR_NAME = 'sdk-test-rds-rr-' + UUID + INSTANCE_LIST = [RDS_NAME, RDS_HA_NAME] + + VOL_TYPE = 'ULTRAHIGH' + VOL_SIZE = 100 + DATASTORE = 'MySQL' + VERSION = None + + AZ = 'eu-de-01' + HA_AZ = 'eu-de-01,eu-de-02' - def test_instance_list(self): + FLAVOR = None + HA_FLAVOR = None + RR_FLAVOR = None + REGION = None + + BACKUP_NAME = 'sdk-test-rds-backup-' + UUID + BACKUP_ID = None + + def test_01_instance_list(self): self.openstack( 'rds instance list -f json ' ) - def test_instance_list_filters(self): + def test_02_instance_list_filters(self): self.openstack( 'rds instance list ' '--limit 1 --id 2 ' '--name 3 --type Single ' - '--database PostgreSQL ' - '--router_id 123asd --subnet_id 123qwe ' + '--datastore-type PostgreSQL ' + '--router-id 123asd ' + '--network-id 123qwe ' '--offset 5' ) self.assertTrue(True) + + def test_03_create_instance(self): + self._initialize_network() + TestRdsInstance.REGION = self._get_region() + TestRdsInstance.VERSION = self._get_latest_version() + TestRdsInstance.FLAVOR = self._get_default_flavor() + TestRdsInstance.HA_FLAVOR = self._get_default_flavor('ha') + TestRdsInstance.RR_FLAVOR = self._get_default_flavor('replica') + with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor: + executor.submit(self._create_instance, self.RDS_NAME) + # Create HA Instance + executor.submit( + self._create_instance, + self.RDS_HA_NAME, + 'semisync') + for instance in self.INSTANCE_LIST: + json_output = json.loads(self.openstack( + 'rds instance show -f json ' + instance + )) + self.assertEqual(json_output['name'], instance) + + def test_04_create_read_replica(self): + instance_name = self.INSTANCE_LIST[0] + json_output = json.loads(self.openstack( + 'rds instance create -f json ' + ' {name} {flavor} ' + ' --replica-of {instance} ' + ' --volume-type {vol_type}' + ' --size {vol_size} ' + ' --region {region} ' + ' --availability-zone {az} ' + ' --wait --wait-interval 10'.format( + name=self.RDS_RR_NAME, + flavor=self.RR_FLAVOR, + instance=instance_name, + region=self.REGION, + vol_type=self.VOL_TYPE, + vol_size=self.VOL_SIZE, + az=self.AZ) + )) + self.assertTrue(self._wait_for_instance(json_output['id'])) + self.assertIsNotNone(json_output) + + def test_05_backup_list(self): + instance_name = self.INSTANCE_LIST[0] + json_output = json.loads(self.openstack( + 'rds backup list -f json ' + instance_name + )) + self.assertIsNotNone(json_output) + + def test_06_create_manual_backup(self): + instance_name = self.INSTANCE_LIST[1] + json_output = json.loads(self.openstack( + 'rds backup create -f json ' + ' --description sdk-test-backup ' + '{name} {instance} --wait --wait-interval 10'.format( + name=self.BACKUP_NAME, + instance=instance_name + ) + )) + self.assertIsNotNone(json_output) + TestRdsInstance.BACKUP_ID = json_output['id'] + + def test_07_backup_download_links(self): + instance_name = self.INSTANCE_LIST[1] + json_output = json.loads(self.openstack( + 'rds backup list -f json ' + instance_name + )) + for backup in json_output: + json_output = json.loads(self.openstack( + 'rds backup download links -f json ' + backup['ID'] + )) + self.assertIsNotNone(json_output) + + # def test_08_create_instance_from_backup(self): + # json_output = json.loads(self.openstack( + # 'rds instance show -f json ' + self.INSTANCE_LIST[1])) + # from_instance = json_output['id'] + + # restore_instance = self.RDS_NAME + '-restore' + # json_output = self._create_instance( + # instance_name=restore_instance, + # backup=self.BACKUP_ID, + # from_instance=from_instance) + # self.addCleanup( + # self.openstack, + # 'rds instance delete ' + restore_instance) + # self.assertEqual(json_output['status'], 'ACTIVE') + + def test_09_backup_delete(self): + self.openstack('rds backup delete ' + self.BACKUP_ID) + self.assertRaises( + CommandFailed, + self.openstack, + 'rds backup delete ' + self.BACKUP_ID + ) + + def test_10_backup_policy_set(self): + instance_name = self.INSTANCE_LIST[0] + self.openstack( + 'rds instance backup policy set ' + '{instance} --keep-days {keep_days} ' + '--start-time {start_time} ' + '--period {period}'.format( + instance=instance_name, + keep_days=5, + start_time="19:00-20:00", + period="3,4" + ) + ) + + self.assertTrue(self._wait_for_instance(instance_name)) + json_output = json.loads(self.openstack( + 'rds instance backup policy show -f json ' + instance_name + )) + self.assertEqual(json_output['keep_days'], 5) + + def test_11_backup_policy_set_0(self): + instance_name = self.INSTANCE_LIST[0] + self.openstack( + 'rds instance backup policy set ' + '{instance} --keep-days {keep_days} '.format( + instance=instance_name, + keep_days=0, + ) + ) + + self.assertTrue(self._wait_for_instance(instance_name)) + json_output = json.loads(self.openstack( + 'rds instance backup policy show -f json ' + instance_name + )) + self.assertEqual(json_output['keep_days'], 0) + + def test_12_delete_instance(self): + self.addCleanup(self._denitialize_network) + with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor: + executor.submit(self._delete_instance, self.RDS_NAME) + executor.submit(self._delete_instance, self.RDS_HA_NAME) + + for instance in self.INSTANCE_LIST: + self.assertRaises( + CommandFailed, + self.openstack, + 'rds instance show ' + instance + ) + time.sleep(60) + + def _create_instance( + self, + instance_name, + ha_mode=None, + backup=None, + from_instance=None): + cli_str = ('rds instance create {name}' + ' --datastore-type {datastore}' + ' --datastore-version {version}' + ' --router-id {router_id}' + ' --network-id {net_id}' + ' --security-group-id {sg_id}' + ' --volume-type {vol_type}' + ' --size {vol_size}' + ' --password Test@123' + ' --region {region}' + ' --wait --wait-interval 10' + ' -f json '.format( + name=instance_name, + datastore=self.DATASTORE, + version=self.VERSION, + router_id=self.ROUTER_ID, + net_id=self.NET_ID, + sg_id=self.SG_ID, + vol_type=self.VOL_TYPE, + vol_size=self.VOL_SIZE, + region=self.REGION)) + if ha_mode: + cli_str += (' {flavor}' + ' --availability-zone {az}' + ' --ha-mode {ha_mode}'.format( + flavor=self.HA_FLAVOR, + az=self.HA_AZ, + ha_mode=ha_mode)) + else: + cli_str += self.FLAVOR + ' --availability-zone ' + self.AZ + + if backup or from_instance: + cli_str += (' --from-instance {instance}' + ' --backup {backup}'.format( + instance=from_instance, + backup=backup)) + + json_output = json.loads(self.openstack(cli_str)) + + self._wait_for_instance(json_output['id']) + + return json_output + + def _get_region(self): + json_output = json.loads(self.openstack( + 'region list -f json')) + return json_output[0]['Region'] + + def _get_latest_version(self): + json_output = json.loads(self.openstack( + 'rds datastore version list -f json ' + self.DATASTORE)) + versions = [data['Name'] for data in json_output] + return sorted(versions)[-1] + + def _get_default_flavor(self, flavor_type=None): + if not self.VERSION: + TestRdsInstance.VERSION = self._get_latest_datastore_version( + self.DATASTORE) + json_output = json.loads(self.openstack( + 'rds flavor list -f json {} {}'.format( + self.DATASTORE, self.VERSION) + )) + if flavor_type: + flavor_list = [[data['vcpus'], data['name']] + for data in json_output if + data['instance_mode'] == flavor_type.lower()] + else: + flavor_list = [[data['vcpus'], data['name']] + for data in json_output if + data['instance_mode'] == 'single'] + flavor_list = sorted(flavor_list, key=lambda x: int(x[0])) + return flavor_list[0][1] + + def _delete_instance(self, instance_name): + self.openstack( + 'rds instance delete --wait ' + instance_name + ) + + def _initialize_network(self): + router = json.loads(self.openstack( + 'router create -f json ' + self.ROUTER_NAME + )) + net = json.loads(self.openstack( + 'network create -f json ' + self.NET_NAME + )) + self.openstack( + 'subnet create {subnet} -f json ' + '--network {net} ' + '--subnet-range 192.168.0.0/24 '.format( + subnet=self.SUBNET_NAME, + net=self.NET_NAME + ) + ) + sg = json.loads(self.openstack( + 'security group create -f json ' + self.SG_NAME + )) + + self.openstack( + 'router add subnet {router} ' + '{subnet} '.format( + router=self.ROUTER_NAME, + subnet=self.SUBNET_NAME + ) + ) + + TestRdsInstance.ROUTER_ID = router['id'] + TestRdsInstance.NET_ID = net['id'] + TestRdsInstance.SG_ID = sg['id'] + + def _denitialize_network(self): + self.openstack( + 'router remove subnet {router} ' + '{subnet} '.format( + router=self.ROUTER_NAME, + subnet=self.SUBNET_NAME + ) + ) + self.openstack( + 'subnet delete ' + self.SUBNET_NAME + ) + self.openstack( + 'network delete ' + self.NET_NAME + ) + self.openstack( + 'router delete ' + self.ROUTER_NAME + ) + self.openstack( + 'security group delete ' + self.SG_NAME + ) + + def _wait_for_instance(self, instance, timeout=1000, polling=10): + """ + Wait For Instance Status to return to ACTIVE State + """ + max_time = time.time() + float(timeout) + time.sleep(polling) + while max_time > time.time(): + json_output = json.loads(self.openstack( + 'rds instance show -f json ' + instance + )) + status = json_output['status'].lower() + if status == 'active': + return True + else: + time.sleep(polling) + return False From 0d149a58b23451e9f9866657cce5a05ce7d8071b Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Fri, 17 Jan 2020 12:32:21 +0100 Subject: [PATCH 03/58] move to pypi token --- .travis.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0f8dd754f..ecd4b9dcf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,12 +13,9 @@ install: pip install tox script: tox deploy: provider: pypi - edge: - branch: v1.8.45 - user: gtema + user: __token__ password: - secure: RME8zXB1ynBbmSHEx0kkFzViq56mYKleTuN/om+I+4uTxyTJQjbRkN3AJNKO9CX8V1l9KMeSQ/9a6c9Wmqwn7f+Mps1WwMwhAGqZpyV6ea16Z+G2GYR82lAGBqCIU0JWd2WOrwZ05PvPk0UMT8PkvJGPEl32BtIi7y3DTQa3U2Lpzvb2B3B15PMuFgGRDJgMtTfCtqpzJ9Afqa6X2x70HVXViJgCVKfk10NywNk0kqjFNOGnRXGH1w0oIkj7kSuDA2LRU9exNQZAdU5e2rre+BWae7H0/cYB0H58y5Ax5MA8Nga4o/wRy8MFaIB+9xG+fbo1PIRQtkdim2gwuR3ZkBjN5KHuMH1nnC6R5iMdNSmEaV63YST2YaVfWYA2HvSh6U5DI2ES+4FT8MtA3mFFVg2eOi8/r4c3V5EeLt7iR27R1pkWj83vcYCIXj20j/O6LkGkz+kOLgyfP7oGEgIZyXFDqoWk5pdW15eBHQ3hX5q+hT4oTYpF87i45/6SLfDZ/UWNRmASWBGelFRIEZCs69JvIxrbFHPf8kxzI+QIeouC2uV6MklyTq9iFUcZotUBL+WDOkUqO95VKsSlhIJYWBJiPBliXzBXM30XWexfZD49+b5tQqY1zJ0VCYn9YUkoAO08TQiNJbej8F6A9SOqI7FCB28RgW5D6XrfsXGHXzs= - # skip_cleanup: true + secure: c/0z6avOAPLHWs0LBX9HJCfHexlHe/LDQU6ZQ4NBf9YpLLZON5CSchxU1LiLJMAB98NOpK48wewiC5jlWm8zXIV7t1wnOtKkR4X+HfRO4Lgii8ARlhTPyzF5I3fmgMa/WKyThZeiBl6xPA6G/slLGVDeCczUasUEZWS/jUAVEg0Ht81fDyu1SauRxyj5fXYbpjFFQ+jYyyHTm7FiroG0ylt0XOztpvd/5z7IvRvQ7f+OKg9BES+HHDbOmulY6wSnQrG5o+s3DPOkixiC0Hyh+bFuPfTidUDavKlkQFc4rv87WM+CnBGLoYztx31RFf4azv1SOn6yxsBfxA3zB82cjsWOQh7AWHLfQ19J2aZy5kysaBXnMs7FEo+8g1CdiUApLOqQ7b27B//ZifoKT7aRlwjkcX9g6lajy48MoQWy04xFV0z0/S2yxUrTGr4PcZucLO21YkcGP6Q/Pc4A/4qhz/p1Z1IrDVE8utvrD5jNraLtQzcRvbIqNKNOzpdSkiqsCjf+fzOH4bL0ej33BsVNWHSMn8ZK49d8ykhAsDNoLc7zXo4rJ0+49rRtAd5iDAZDOqBLexDG9x5EM6OMnSApv4km2Pk5Pt1PGFfMiTIuIiBtm8Xz0X7Aa98xiSlJ16IisA1PsXEVvh/QlPiGg1A0CTzzjMIjlpg5EJm55MFEcKc= on: tags: true distributions: sdist bdist_wheel From 05bf33ee7089cae44929928ba2dda992cca036ce Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Fri, 17 Jan 2020 18:34:00 +0100 Subject: [PATCH 04/58] repair some of the AS methods --- .../osclient/auto_scaling/v1/policy.py | 2 + .../osclient/auto_scaling/v1/quota.py | 8 +- otcextensions/sdk/auto_scaling/v1/_base.py | 143 ------------------ otcextensions/sdk/auto_scaling/v1/_proxy.py | 10 +- otcextensions/sdk/auto_scaling/v1/instance.py | 9 -- otcextensions/sdk/auto_scaling/v1/policy.py | 9 -- otcextensions/sdk/auto_scaling/v1/quota.py | 81 +++++++++- .../osclient/auto_scaling/v1/test_quota.py | 9 +- .../unit/sdk/auto_scaling/v1/test_instance.py | 55 ------- .../unit/sdk/auto_scaling/v1/test_policy.py | 33 ---- .../unit/sdk/auto_scaling/v1/test_proxy.py | 6 +- 11 files changed, 101 insertions(+), 264 deletions(-) diff --git a/otcextensions/osclient/auto_scaling/v1/policy.py b/otcextensions/osclient/auto_scaling/v1/policy.py index c3f3b1af8..e17755052 100644 --- a/otcextensions/osclient/auto_scaling/v1/policy.py +++ b/otcextensions/osclient/auto_scaling/v1/policy.py @@ -82,6 +82,8 @@ def take_action(self, parsed_args): data = client.policies(group=group.id, **args) + print('querying %s with %s' % (group.id, args)) + return ( self.columns, (utils.get_item_properties( diff --git a/otcextensions/osclient/auto_scaling/v1/quota.py b/otcextensions/osclient/auto_scaling/v1/quota.py index e47aa7d6d..5a70e2e59 100644 --- a/otcextensions/osclient/auto_scaling/v1/quota.py +++ b/otcextensions/osclient/auto_scaling/v1/quota.py @@ -38,7 +38,13 @@ def get_parser(self, prog_name): def take_action(self, parsed_args): client = self.app.client_manager.auto_scaling - data = client.quotas(group=parsed_args.group) + data = [] + + if parsed_args.group: + group = client.find_group(parsed_args.group, ignore_missing=False) + data = client.quotas(group=group.id) + else: + data = client.quotas() return ( self.columns, diff --git a/otcextensions/sdk/auto_scaling/v1/_base.py b/otcextensions/sdk/auto_scaling/v1/_base.py index e990d2e99..c63026088 100644 --- a/otcextensions/sdk/auto_scaling/v1/_base.py +++ b/otcextensions/sdk/auto_scaling/v1/_base.py @@ -9,7 +9,6 @@ # 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 exceptions from openstack import resource from openstack import utils @@ -49,148 +48,6 @@ def find_value_by_accessor(input_dict, accessor): return None return current_data -# @classmethod -# def _prepare_override_args(cls, -# endpoint_override=None, -# request_headers=None, -# additional_headers=None, -# requests_auth=None): -# """Prepare additional (override) arguments for the REST call -# -# :param endpoint_override: optional endpoint_override argument -# :param request_headers: original calculated request headers -# :param additional_headers: additional headers to be set into request -# -# :returns arguments dict -# """ -# req_args = {} -# -# if additional_headers and request_headers: -# req_args['headers'] = utils.merge_two_dicts( -# additional_headers, -# request_headers) -# else: -# if additional_headers: -# req_args['headers'] = additional_headers -# if request_headers: -# req_args['headers'] = request_headers -# -# if endpoint_override: -# req_args['endpoint_override'] = endpoint_override -# -# if requests_auth: -# req_args['requests_auth'] = requests_auth -# -# return req_args -# - # Due to the other LIST url need to override - # It is not efficient (as of implementation) to extend general list - # with support of other url just for one service - @classmethod - def list_ext(cls, session, paginated=False, - endpoint_override=None, headers=None, **params): - """Override default list to incorporate endpoint overriding - and custom headers - - Since SDK Resource.list method is passing hardcoded headers - do override the function - - This resource object list generator handles pagination and takes query - params for response filtering. - - :param session: The session to use for making this request. - :type session: :class:`~keystoneauth1.adapter.Adapter` - :param bool paginated: ``True`` if a GET to this resource returns - a paginated series of responses, or ``False`` - if a GET returns only one page of data. - **When paginated is False only one - page of data will be returned regardless - of the API's support of pagination.** - :param dict params: These keyword arguments are passed through the - :meth:`~openstack.resource.QueryParamter._transpose` method - to find if any of them match expected query parameters to be - sent in the *params* argument to - :meth:`~keystoneauth1.adapter.Adapter.get`. They are additionally - checked against the - :data:`~openstack.resource.Resource.base_path` format string - to see if any path fragments need to be filled in by the contents - of this argument. - - :return: A generator of :class:`Resource` objects. - :raises: :exc:`~openstack.exceptions.MethodNotSupported` if - :data:`Resource.allow_list` is not set to ``True``. - :raises: :exc:`~openstack.exceptions.InvalidResourceQuery` if query - contains invalid params. - - """ - if not cls.allow_list: - raise exceptions.MethodNotSupported(cls, "list") - - session = cls._get_session(session) - - # pop scaling_group_id, as it should not be also present in the query - scaling_group_id = params.pop('scaling_group_id', None) - uri_params = {} - - if scaling_group_id: - uri_params = {'scaling_group_id': scaling_group_id} - - cls._query_mapping._validate(params, base_path=cls.base_path) - query_params = cls._query_mapping._transpose(params, cls) - uri = None - if not hasattr(cls, 'list_path'): - uri = cls.base_path % uri_params - else: - uri = cls.list_path % uri_params - - limit = query_params.get('limit') - - total_yielded = 0 - while uri: - response = session.get( - uri, - params=query_params.copy() - ) - exceptions.raise_from_response(response) - data = response.json() - - # Discard any existing pagination keys - query_params.pop('marker', None) - query_params.pop('limit', None) - - if cls.resources_key: - resources = cls.find_value_by_accessor(data, cls.resources_key) - else: - resources = data - - if not isinstance(resources, list): - resources = [resources] - - marker = None - for raw_resource in resources: - # Do not allow keys called "self" through. Glance chose - # to name a key "self", so we need to pop it out because - # we can't send it through cls.existing and into the - # Resource initializer. "self" is already the first - # argument and is practically a reserved word. - raw_resource.pop("self", None) - - if cls.resource_key and cls.resource_key in raw_resource: - raw_resource = raw_resource[cls.resource_key] - - value = cls.existing(**raw_resource) - - marker = value.id - yield value - total_yielded += 1 - - if resources and paginated: - uri, next_params = cls._get_next_link( - uri, response, data, marker, limit, total_yielded) - query_params.update(next_params) - else: - return - def _action(self, session, body): """Preform alarm actions given the message body. diff --git a/otcextensions/sdk/auto_scaling/v1/_proxy.py b/otcextensions/sdk/auto_scaling/v1/_proxy.py index 8da39e6eb..7c020739c 100644 --- a/otcextensions/sdk/auto_scaling/v1/_proxy.py +++ b/otcextensions/sdk/auto_scaling/v1/_proxy.py @@ -249,7 +249,9 @@ def policies(self, group, **query): instances """ group = self._get_resource(_group.Group, group) - return self._list(_policy.Policy, scaling_group_id=group.id, **query) + return self._list( + _policy.Policy, + base_path='/scaling_policy/{id}/list'.format(id=group.id), **query) def create_policy(self, **attrs): """Create a new policy from attributes @@ -369,8 +371,10 @@ def instances(self, group, **query): (:class:`~otcextensions.sdk.auto_scaling.v1.instance.Instance`) """ group = self._get_resource(_group.Group, group) - return self._list(_instance.Instance, - scaling_group_id=group.id, **query) + return self._list( + _instance.Instance, + base_path='/scaling_group_instance/{id}/list'.format(id=group.id), + **query) def remove_instance(self, instance, delete_instance=False, ignore_missing=True): diff --git a/otcextensions/sdk/auto_scaling/v1/instance.py b/otcextensions/sdk/auto_scaling/v1/instance.py index b1f3fb9b6..a8925220c 100644 --- a/otcextensions/sdk/auto_scaling/v1/instance.py +++ b/otcextensions/sdk/auto_scaling/v1/instance.py @@ -25,7 +25,6 @@ class Instance(_base.Resource): # ok, we just fix the base path to list because there are no common rules # for the operations for instance base_path = '/scaling_group_instance' - list_path = '/scaling_group_instance/%(scaling_group_id)s/list' query_marker_key = 'start_number' # capabilities @@ -60,14 +59,6 @@ class Instance(_base.Resource): #: AutoScaling instance create time create_time = resource.Body('create_time') - @classmethod - def list(cls, session, paginated=False, - endpoint_override=None, headers=None, **params): - return super(Instance, cls).list_ext( - session, paginated, - endpoint_override, headers, - **params) - def remove(self, session, delete_instance=False, ignore_missing=True): """Remove an instance of auto scaling group diff --git a/otcextensions/sdk/auto_scaling/v1/policy.py b/otcextensions/sdk/auto_scaling/v1/policy.py index 08fc357a5..81d81b64c 100644 --- a/otcextensions/sdk/auto_scaling/v1/policy.py +++ b/otcextensions/sdk/auto_scaling/v1/policy.py @@ -50,7 +50,6 @@ class Policy(_base.Resource): resource_key = 'scaling_policy' resources_key = 'scaling_policies' base_path = '/scaling_policy' - list_path = '/scaling_policy/%(scaling_group_id)s/list' query_marker_key = 'start_number' # capabilities @@ -88,14 +87,6 @@ class Policy(_base.Resource): #: valid values include: ``INSERVICE``, ``PAUSED`` status = resource.Body('policy_status') - @classmethod - def list(cls, session, paginated=False, - endpoint_override=None, headers=None, **params): - return super(Policy, cls).list_ext( - session, paginated, - endpoint_override, headers, - **params) - def execute(self, session): """execute policy""" body = {"action": "execute"} diff --git a/otcextensions/sdk/auto_scaling/v1/quota.py b/otcextensions/sdk/auto_scaling/v1/quota.py index 36ce352a4..d27c1bd12 100644 --- a/otcextensions/sdk/auto_scaling/v1/quota.py +++ b/otcextensions/sdk/auto_scaling/v1/quota.py @@ -9,6 +9,7 @@ # 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 exceptions from openstack import resource from otcextensions.sdk.auto_scaling.v1 import _base @@ -32,13 +33,83 @@ class Quota(_base.Resource): #: Quota amount quota = resource.Body('quota', type=int) + @staticmethod + def find_value_by_accessor(input_dict, accessor): + """Gets value from a dictionary using a dotted accessor""" + current_data = input_dict + for chunk in accessor.split('.'): + if isinstance(current_data, dict): + current_data = current_data.get(chunk, {}) + else: + return None + return current_data + @classmethod def list(cls, session, paginated=False, - endpoint_override=None, headers=None, **params): - return super(Quota, cls).list_ext( - session, paginated, - endpoint_override, headers, - **params) + base_path=None, **params): + if not cls.allow_list: + raise exceptions.MethodNotSupported(cls, "list") + + session = cls._get_session(session) + + # pop scaling_group_id, as it should not be also present in the query + scaling_group_id = params.pop('scaling_group_id', None) + uri_params = {} + + if scaling_group_id: + uri_params = {'scaling_group_id': scaling_group_id} + + cls._query_mapping._validate(params, base_path=cls.base_path) + query_params = cls._query_mapping._transpose(params, cls) + uri = cls.base_path % uri_params + + limit = query_params.get('limit') + + total_yielded = 0 + while uri: + response = session.get( + uri, + params=query_params.copy() + ) + exceptions.raise_from_response(response) + data = response.json() + + # Discard any existing pagination keys + query_params.pop('marker', None) + query_params.pop('limit', None) + + if cls.resources_key: + resources = cls.find_value_by_accessor(data, cls.resources_key) + else: + resources = data + + if not isinstance(resources, list): + resources = [resources] + + marker = None + for raw_resource in resources: + # Do not allow keys called "self" through. Glance chose + # to name a key "self", so we need to pop it out because + # we can't send it through cls.existing and into the + # Resource initializer. "self" is already the first + # argument and is practically a reserved word. + raw_resource.pop("self", None) + + if cls.resource_key and cls.resource_key in raw_resource: + raw_resource = raw_resource[cls.resource_key] + + value = cls.existing(**raw_resource) + + marker = value.id + yield value + total_yielded += 1 + + if resources and paginated: + uri, next_params = cls._get_next_link( + uri, response, data, marker, limit, total_yielded) + query_params.update(next_params) + else: + return class ScalingQuota(Quota): diff --git a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_quota.py b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_quota.py index 5fd5ee8fd..3afe0f49e 100644 --- a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_quota.py +++ b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_quota.py @@ -66,7 +66,7 @@ def test_list_quota(self): # Trigger the action columns, data = self.cmd.take_action(parsed_args) - self.client.quotas.assert_called_once_with(group=None) + self.client.quotas.assert_called_once_with() self.assertEqual(self.columns, columns) self.assertEqual(self.data, list(data)) @@ -88,10 +88,15 @@ def test_list_group_quota(self): self.quotas ] + grp_mock = mock.Mock() + grp_mock.id = 2 + + self.client.find_group = mock.Mock(return_value=grp_mock) + # Trigger the action columns, data = self.cmd.take_action(parsed_args) - self.client.quotas.assert_called_once_with(group='grp') + self.client.quotas.assert_called_once_with(group=2) self.assertEqual(self.columns, columns) self.assertEqual(self.data, list(data)) diff --git a/otcextensions/tests/unit/sdk/auto_scaling/v1/test_instance.py b/otcextensions/tests/unit/sdk/auto_scaling/v1/test_instance.py index 4354759ce..d7df1ac72 100644 --- a/otcextensions/tests/unit/sdk/auto_scaling/v1/test_instance.py +++ b/otcextensions/tests/unit/sdk/auto_scaling/v1/test_instance.py @@ -9,7 +9,6 @@ # 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 copy from keystoneauth1 import adapter @@ -20,23 +19,6 @@ from otcextensions.sdk.auto_scaling.v1 import instance -# EXAMPLE = { -# 'scaling_instance_id': 'fd7d63ce-8f5c-443e-b9a0-bef9386b23b3', -# 'scaling_group_id': 'e5d27f5c-dd76-4a61-b4bc-a67c5686719a', -# 'scaling_instance_name': 'schedule1', -# 'scaling_instance_type': 'SCHEDULED', -# 'scheduled_instance': { -# 'launch_time': '2015-07-24T01:21Z' -# }, -# 'cool_down_time': 300, -# 'scaling_instance_action': { -# 'operation': 'REMOVE', -# 'instance_number': 1 -# }, -# 'instance_status': 'INSERVICE', -# 'create_time': '2015-07-24T01:09:30Z' -# } - EXAMPLE_LIST = { 'limit': 10, 'total_number': 1, @@ -73,8 +55,6 @@ def test_basic(self): self.assertEqual('scaling_group_instance', sot.resource_key) self.assertEqual('scaling_group_instances', sot.resources_key) self.assertEqual('/scaling_group_instance', sot.base_path) - self.assertEqual( - '/scaling_group_instance/%(scaling_group_id)s/list', sot.list_path) self.assertTrue(sot.allow_list) self.assertFalse(sot.allow_create) self.assertFalse(sot.allow_fetch) @@ -95,41 +75,6 @@ def test_make_it(self): sot.scaling_configuration_id) self.assertEqual(obj['create_time'], sot.create_time) - def test_list(self): - mock_response = mock.Mock() - mock_response.status_code = 200 - mock_response.json.return_value = copy.deepcopy(EXAMPLE_LIST) - - self.sess.get.return_value = mock_response - - result = list( - self.sot.list( - self.sess, - scaling_group_id='grp_id', - limit=3, - marker=4, - life_cycle_state='t1', - health_status='t2', - ) - ) - - self.sess.get.assert_called_once_with( - '/scaling_group_instance/grp_id/list', - params={ - 'limit': 3, - 'start_number': 4, - 'life_cycle_state': 't1', - 'health_status': 't2', - }, - ) - - expected_list = [ - instance.Instance.existing( - **EXAMPLE_LIST['scaling_group_instances'][0]), - ] - - self.assertEqual(expected_list, result) - def test_batch_action_act_check(self): mock_response = mock.Mock() mock_response.status_code = 204 diff --git a/otcextensions/tests/unit/sdk/auto_scaling/v1/test_policy.py b/otcextensions/tests/unit/sdk/auto_scaling/v1/test_policy.py index 9bb95a77f..3e0b220bc 100644 --- a/otcextensions/tests/unit/sdk/auto_scaling/v1/test_policy.py +++ b/otcextensions/tests/unit/sdk/auto_scaling/v1/test_policy.py @@ -80,8 +80,6 @@ def test_basic(self): self.assertEqual('scaling_policy', sot.resource_key) self.assertEqual('scaling_policies', sot.resources_key) self.assertEqual('/scaling_policy', sot.base_path) - self.assertEqual( - '/scaling_policy/%(scaling_group_id)s/list', sot.list_path) self.assertTrue(sot.allow_list) self.assertTrue(sot.allow_create) self.assertTrue(sot.allow_fetch) @@ -98,37 +96,6 @@ def test_make_it(self): self.assertEqual(EXAMPLE['policy_status'], sot.status) self.assertEqual(EXAMPLE['create_time'], sot.create_time) - def test_list(self): - mock_response = mock.Mock() - mock_response.status_code = 200 - mock_response.json.return_value = copy.deepcopy(EXAMPLE_LIST) - - self.sess.get.return_value = mock_response - - result = list( - self.sot.list( - self.sess, - scaling_group_id='grp_id', - limit=3, - marker=4 - ) - ) - - self.sess.get.assert_called_once_with( - '/scaling_policy/grp_id/list', - params={ - 'limit': 3, - 'start_number': 4, - }, - ) - - expected_list = [ - policy.Policy.existing( - **EXAMPLE_LIST['scaling_policies'][0]), - ] - - self.assertEqual(expected_list, result) - def test_get(self): sot = policy.Policy.existing( id=EXAMPLE['scaling_policy_id']) diff --git a/otcextensions/tests/unit/sdk/auto_scaling/v1/test_proxy.py b/otcextensions/tests/unit/sdk/auto_scaling/v1/test_proxy.py index e945f24cc..248d8212e 100644 --- a/otcextensions/tests/unit/sdk/auto_scaling/v1/test_proxy.py +++ b/otcextensions/tests/unit/sdk/auto_scaling/v1/test_proxy.py @@ -154,9 +154,9 @@ def test_list(self): 'some_arg': 'arg_value', 'group': 'group_id' }, + base_path='/scaling_policy/group_id/list', expected_kwargs={ 'some_arg': 'arg_value', - 'scaling_group_id': 'group_id', } ) @@ -270,9 +270,7 @@ def test_list(self): self.verify_list( self.proxy.instances, _instance.Instance, method_args=['group'], - expected_kwargs={ - 'scaling_group_id': 'group' - }, + base_path='/scaling_group_instance/group/list' ) def test_batch_action_remove(self): From 123b8a2d835116533f2511e275711fb813f39f50 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Thu, 6 Feb 2020 15:58:47 +0100 Subject: [PATCH 05/58] Update .zuul.yaml --- .zuul.yaml | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/.zuul.yaml b/.zuul.yaml index 4e81e6f34..597473d18 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -1,35 +1,9 @@ -- job: - name: openstacksdk-functional - parent: otc-tox-functional - description: | - Run openstacksdk functional tests against a OTC - -- job: - name: openstacksdk-functional-otc - parent: openstacksdk-functional - description: | - Run openstacksdk functional tests using default python against OTC - -- job: - name: openstacksdk-functional-otc-python3 - parent: openstacksdk-functional - description: | - Run openstacksdk functional tests using python3 against OTC - vars: - tox_environment: - OPENSTACKSDK_TOX_PYTHON: python3 - OS_CLOUD: otc - - project: check: jobs: - tox-py36 - - tox-py27 - tox-pep8 - - openstacksdk-functional-otc-python3 gate: jobs: - tox-py36 - - tox-py27 - tox-pep8 - - openstacksdk-functional-otc-python3 From 07e89d132f9a55a2030f161ef1885f9fdd8a156b Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Thu, 6 Feb 2020 18:12:21 +0100 Subject: [PATCH 06/58] Create bindep.txt --- bindep.txt | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 bindep.txt diff --git a/bindep.txt b/bindep.txt new file mode 100644 index 000000000..eb458b065 --- /dev/null +++ b/bindep.txt @@ -0,0 +1,6 @@ +build-essential [platform:dpkg] +python-dev [platform:dpkg] +python-devel [platform:rpm] +libffi-dev [platform:dpkg] +libffi-devel [platform:rpm] +openssl-devel [platform:rpm] From 011b18ade62314c0ffe559619b334fdaf4e5414d Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Fri, 7 Feb 2020 15:18:52 +0100 Subject: [PATCH 07/58] Update .zuul.yaml --- .zuul.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.zuul.yaml b/.zuul.yaml index 597473d18..e8df800c3 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -1,9 +1,9 @@ - project: check: jobs: - - tox-py36 + - tox-py37 - tox-pep8 gate: jobs: - - tox-py36 + - tox-py37 - tox-pep8 From 212a7078f7ae42abfeaf7b8b5dc3355bef1edf79 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Tue, 11 Feb 2020 20:21:35 +0100 Subject: [PATCH 08/58] some dns private zone fixes --- otcextensions/osclient/dns/v2/recordset.py | 37 +++++++++++++++++++--- otcextensions/sdk/dns/v2/_proxy.py | 5 +-- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/otcextensions/osclient/dns/v2/recordset.py b/otcextensions/osclient/dns/v2/recordset.py index 581315365..3ee414c91 100644 --- a/otcextensions/osclient/dns/v2/recordset.py +++ b/otcextensions/osclient/dns/v2/recordset.py @@ -50,16 +50,24 @@ def get_parser(self, prog_name): help=_('UUID or name of the zone. Recordsets of all zones ' 'will be returned if not given.') ) + parser.add_argument( + '--zone-type', + help=_('DNS Zone type (private/public)') + ) return parser def take_action(self, parsed_args): client = self.app.client_manager.dns zone = None + attrs = {} + if parsed_args.zone_type: + attrs['zone_type'] = parsed_args.zone_type if parsed_args.zone: - zone = client.find_zone(parsed_args.zone, ignore_missing=False) + zone = client.find_zone(parsed_args.zone, ignore_missing=False, + **attrs) data = client.recordsets(zone=zone) @@ -81,6 +89,10 @@ def get_parser(self, prog_name): metavar='', help=_('UUID or name of the zone.') ) + parser.add_argument( + '--zone-type', + help=_('DNS Zone type (private/public)') + ) parser.add_argument( 'recordset', @@ -96,6 +108,8 @@ def take_action(self, parsed_args): zone = client.find_zone( parsed_args.zone, + ignore_missing=False, + zone_type=parsed_args.zone_type ) obj = client.find_recordset(zone=zone, @@ -118,6 +132,10 @@ def get_parser(self, prog_name): metavar='', help=_('UUID or name of the zone.') ) + parser.add_argument( + '--zone-type', + help=_('DNS Zone type (private/public)') + ) parser.add_argument( 'recordset', @@ -131,7 +149,8 @@ def get_parser(self, prog_name): def take_action(self, parsed_args): if parsed_args.zone: client = self.app.client_manager.dns - zone = client.find_zone(parsed_args.zone, ignore_missing=False) + zone = client.find_zone(parsed_args.zone, ignore_missing=False, + zone_type=parsed_args.zone_type) for rs in parsed_args.recordset: rs = client.find_recordset(zone=zone, name_or_id=rs, ignore_missing=False) @@ -150,6 +169,10 @@ def get_parser(self, prog_name): metavar='', help=_('UUID or name of the zone.') ) + parser.add_argument( + '--zone-type', + help=_('DNS Zone type (private/public)') + ) parser.add_argument( '--name', metavar='', @@ -193,7 +216,8 @@ def take_action(self, parsed_args): attrs = {'records': []} - zone = client.find_zone(parsed_args.zone, ignore_missing=False) + zone = client.find_zone(parsed_args.zone, ignore_missing=False, + zone_type=parsed_args.zone_type) if parsed_args.name: attrs['name'] = parsed_args.name @@ -228,6 +252,10 @@ def get_parser(self, prog_name): metavar='', help=_('UUID or name of the zone.') ) + parser.add_argument( + '--zone-type', + help=_('DNS Zone type (private/public)') + ) parser.add_argument( 'recordset', metavar='', @@ -268,7 +296,8 @@ def take_action(self, parsed_args): if parsed_args.ttl: attrs['ttl'] = parsed_args.ttl - zone = client.find_zone(parsed_args.zone, ignore_missing=False) + zone = client.find_zone(parsed_args.zone, ignore_missing=False, + zone_type=parsed_args.zone_type) if parsed_args.ttl: attrs['zone_id'] = zone.id diff --git a/otcextensions/sdk/dns/v2/_proxy.py b/otcextensions/sdk/dns/v2/_proxy.py index 481a80b03..6d7c0b3ac 100644 --- a/otcextensions/sdk/dns/v2/_proxy.py +++ b/otcextensions/sdk/dns/v2/_proxy.py @@ -83,7 +83,7 @@ def update_zone(self, zone, **attrs): """ return self._update(_zone.Zone, zone, **attrs) - def find_zone(self, name_or_id, ignore_missing=True): + def find_zone(self, name_or_id, ignore_missing=True, **attrs): """Find a single zone :param name_or_id: The name or ID of a zone @@ -96,7 +96,8 @@ def find_zone(self, name_or_id, ignore_missing=True): :returns: ``None`` """ return self._find(_zone.Zone, name_or_id, - ignore_missing=ignore_missing) + ignore_missing=ignore_missing, + **attrs) def add_router_to_zone(self, zone, **router): """Add router(VPC) to private zone From de026debdc97dbb73ec8417445fd4e652b9bfcdb Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Fri, 14 Feb 2020 15:42:48 +0100 Subject: [PATCH 09/58] Zuul (#63) * reset zuul integration * disable tox-docs for separate branch * replace openstacksdk general error handler * exclude rds instance osc func tests * blacklist failing tests * repair func test cmd * compare if we got something * fix pep --- .stestr.blacklist.functional | 8 ++++++++ .zuul.yaml | 3 +++ otcextensions/common/exc.py | 2 ++ otcextensions/sdk/__init__.py | 3 +++ .../tests/functional/osclient/rds/v3/test_flavor.py | 9 +++++---- tox.ini | 2 +- 6 files changed, 22 insertions(+), 5 deletions(-) create mode 100644 .stestr.blacklist.functional diff --git a/.stestr.blacklist.functional b/.stestr.blacklist.functional new file mode 100644 index 000000000..aa3c7a5ed --- /dev/null +++ b/.stestr.blacklist.functional @@ -0,0 +1,8 @@ +otcextensions.tests.functional.osclient.obs* +otcextensions.tests.functional.osclient.rds.v3.test_instance* +otcextensions.tests.functional.osclient.volume_backup* +otcextensions.tests.functional.sdk.cce.v1* +otcextensions.tests.functional.sdk.kms* +otcextensions.tests.functional.sdk.volume_backup* +otcextensions.tests.functional.sdk.volume_backup* +otcextensions.tests.functional.sdk.deh* diff --git a/.zuul.yaml b/.zuul.yaml index e8df800c3..3f5be5f93 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -3,7 +3,10 @@ jobs: - tox-py37 - tox-pep8 + # - tox-docs + - tox-functional gate: jobs: - tox-py37 - tox-pep8 + - tox-functional diff --git a/otcextensions/common/exc.py b/otcextensions/common/exc.py index 897972be5..061ba1c47 100644 --- a/otcextensions/common/exc.py +++ b/otcextensions/common/exc.py @@ -236,6 +236,8 @@ def raise_from_response(response, error_message=None): messages = [content['message'], ] if 'error_code' in content: details = content['error_code'] + if 'error_msg' in content: + messages = [content['error_msg'], ] else: messages = [obj.get('message') for obj in content.values() if isinstance(obj, dict)] diff --git a/otcextensions/sdk/__init__.py b/otcextensions/sdk/__init__.py index 41cf95de1..8de28244e 100644 --- a/otcextensions/sdk/__init__.py +++ b/otcextensions/sdk/__init__.py @@ -17,6 +17,7 @@ from openstack import utils from otcextensions.sdk.compute.v2 import server +from otcextensions.common import exc _logger = _log.setup_logging('openstack') @@ -209,6 +210,8 @@ def patch_openstack_resources(): server.Server._get_tag_struct openstack.compute.v2.server.Server.add_tag = server.Server.add_tag openstack.compute.v2.server.Server.remove_tag = server.Server.remove_tag + openstack.exceptions.raise_from_response = \ + exc.raise_from_response def load(conn, **kwargs): diff --git a/otcextensions/tests/functional/osclient/rds/v3/test_flavor.py b/otcextensions/tests/functional/osclient/rds/v3/test_flavor.py index ab9a830e9..7400921ce 100644 --- a/otcextensions/tests/functional/osclient/rds/v3/test_flavor.py +++ b/otcextensions/tests/functional/osclient/rds/v3/test_flavor.py @@ -41,10 +41,11 @@ def test_flavor_list(self): )) self.assertIsNotNone(json_output) - self.assertEqual( - ['name', 'instance_mode', 'vcpus', 'ram'], - list(json_output[0].keys()) - ) + if len(json_output) > 0: + self.assertEqual( + ['name', 'instance_mode', 'vcpus', 'ram'], + list(json_output[0].keys()) + ) def test_invalid_datastore_flavor_list(self): self.assertRaises( diff --git a/tox.ini b/tox.ini index 02190deca..4a5cafd7f 100644 --- a/tox.ini +++ b/tox.ini @@ -32,7 +32,7 @@ commands = stestr --test-path ./otcextensions/tests/examples run {posargs} setenv = {[testenv]setenv} OS_TEST_TIMEOUT=60 -commands = stestr --test-path ./otcextensions/tests/functional run --serial {posargs} +commands = stestr --test-path ./otcextensions/tests/functional run --serial --blacklist-file .stestr.blacklist.functional {posargs} stestr slowest [testenv:pep8] From 47d0341901834fbc14ac9cbb051ab6ed07b5b887 Mon Sep 17 00:00:00 2001 From: "T. Schreiber" Date: Mon, 24 Feb 2020 11:37:44 +0100 Subject: [PATCH 10/58] AS corrections for new API Version (#60) * improve Auto_Scaling user experience by using openstack client * flake8 corrections * change group unit test for AS service * bug fixing * fix policy * add policy delete * minor fixes * ensure --group on policy update * pep 8 corrections and unit test fixes * change CLI client parameters from using underscore to dash * Update test_policy.py * Renaming of network parameters and fixing unit tests --- .../osclient/auto_scaling/v1/activity.py | 7 +- .../osclient/auto_scaling/v1/config.py | 8 +- .../osclient/auto_scaling/v1/group.py | 144 +++++++++++------- .../osclient/auto_scaling/v1/instance.py | 14 +- .../osclient/auto_scaling/v1/policy.py | 82 +++++----- otcextensions/sdk/auto_scaling/v1/_base.py | 12 ++ otcextensions/sdk/auto_scaling/v1/_proxy.py | 7 +- otcextensions/sdk/auto_scaling/v1/config.py | 2 +- otcextensions/sdk/auto_scaling/v1/group.py | 16 +- otcextensions/sdk/auto_scaling/v1/policy.py | 75 ++++++++- .../unit/osclient/auto_scaling/v1/fakes.py | 2 +- .../osclient/auto_scaling/v1/test_activity.py | 6 +- .../osclient/auto_scaling/v1/test_config.py | 2 +- .../osclient/auto_scaling/v1/test_group.py | 113 ++++++++------ .../osclient/auto_scaling/v1/test_instance.py | 22 +-- .../osclient/auto_scaling/v1/test_policy.py | 42 ++--- .../unit/sdk/auto_scaling/v1/test_group.py | 2 +- .../unit/sdk/auto_scaling/v1/test_policy.py | 2 - .../unit/sdk/auto_scaling/v1/test_proxy.py | 8 +- setup.cfg | 1 + 20 files changed, 360 insertions(+), 207 deletions(-) diff --git a/otcextensions/osclient/auto_scaling/v1/activity.py b/otcextensions/osclient/auto_scaling/v1/activity.py index ea6d014db..bf44dc171 100644 --- a/otcextensions/osclient/auto_scaling/v1/activity.py +++ b/otcextensions/osclient/auto_scaling/v1/activity.py @@ -31,18 +31,19 @@ class ListAutoScalingActivityLogs(command.Lister): def get_parser(self, prog_name): parser = super(ListAutoScalingActivityLogs, self).get_parser(prog_name) parser.add_argument( - 'group', + '--group', metavar='', + required=True, help=_('AS Group ID or name') ) parser.add_argument( - '--start_time', + '--start-time', metavar='', help=_('Specifies the start time for querying scaling ' 'action logs. Format: `YYYY-MM-DDThh:mm:ssZ`') ) parser.add_argument( - '--end_time', + '--end-time', metavar='', help=_('Specifies the end time for querying scaling ' 'action logs. Format: `YYYY-MM-DDThh:mm:ssZ`') diff --git a/otcextensions/osclient/auto_scaling/v1/config.py b/otcextensions/osclient/auto_scaling/v1/config.py index d29bf03c3..f839cf89e 100644 --- a/otcextensions/osclient/auto_scaling/v1/config.py +++ b/otcextensions/osclient/auto_scaling/v1/config.py @@ -152,13 +152,13 @@ def get_parser(self, prog_name): help=_('Flavor ID or Name for the ECS instance') ) group1.add_argument( - '--image_id', + '--image-id', metavar='', help=_('Image ID for the ECS instance to be created') ) group = parser.add_mutually_exclusive_group() group.add_argument( - '--instance_id', + '--instance-id', metavar='', help=_('AS Configuration name\n' 'Is mutually exclusive with ECS group') @@ -187,14 +187,14 @@ def get_parser(self, prog_name): help=_('Key name for the new ECS instance') ) parser.add_argument( - '--public_ip_bandwith', + '--public-ip-bandwith', metavar='', type=int, help=_('Defines EIP Bandwith (Mbit/s) to be attached ' 'to the new ECS instance') ) parser.add_argument( - '--user_data', + '--user-data', metavar='', help=_('Path to the cloud-init user_data file') ) diff --git a/otcextensions/osclient/auto_scaling/v1/group.py b/otcextensions/osclient/auto_scaling/v1/group.py index cded083a7..0fac7b320 100644 --- a/otcextensions/osclient/auto_scaling/v1/group.py +++ b/otcextensions/osclient/auto_scaling/v1/group.py @@ -62,6 +62,11 @@ class ListAutoScalingGroup(command.Lister): def get_parser(self, prog_name): parser = super(ListAutoScalingGroup, self).get_parser(prog_name) + parser.add_argument( + '--name', + metavar='', + help=_('Name or ID of the AS group') + ) parser.add_argument( '--limit', dest='limit', @@ -78,13 +83,40 @@ def get_parser(self, prog_name): 'specified marker. When used with --limit, set this to ' 'the last ID displayed in the previous run') ) + parser.add_argument( + '--scaling-configuration-id', + metavar='', + help=_('ID of the AS configuration') + ) + parser.add_argument( + '--status', + metavar='', + help=_('Shows AS groups with specific status:\n' + ': AS group is working\n' + ': AS group is paused\n' + ': AS group has malfunctions\n' + ': AS group is being deleted') + ) return parser def take_action(self, parsed_args): client = self.app.client_manager.auto_scaling - data = client.groups() + args = {} + if parsed_args.limit: + args['limit'] = parsed_args.limit + if parsed_args.marker: + args['marker'] = parsed_args.marker + if parsed_args.name: + args['name'] = parsed_args.name + if parsed_args.scaling_configuration_id: + args['scaling_configuration_id'] = \ + parsed_args.scaling_configuration_id + if parsed_args.status: + args['status'] = parsed_args.status + + data = client.groups(**args) return ( self.columns, @@ -137,36 +169,36 @@ def get_parser(self, prog_name): help=_('Name of the new configuration group') ) parser.add_argument( - '--desire_instance_number', + '--desire-instance-number', metavar='', type=int, help=_('Desired number of instances') ) parser.add_argument( - '--min_instance_number', + '--min-instance-number', metavar='', type=int, help=_('Minimal number of instances') ) parser.add_argument( - '--max_instance_number', + '--max-instance-number', metavar='', type=int, help=_('Maximal number of instances') ) parser.add_argument( - '--cool_down_time', + '--cool-down-time', metavar='', type=int, help=_('Specifies cooling duration in seconds') ) parser.add_argument( - '--lb_listener_id', + '--lb-listener-id', metavar='', help=_('Specifies ELB Listener ID') ) parser.add_argument( - '--lbaas_listener', + '--lbaas-listener', metavar='', action='append', help=_('Specifies ULB Listener Information in format: ' @@ -174,47 +206,47 @@ def get_parser(self, prog_name): '(Repeat multiple times, up to 3 times)') ) parser.add_argument( - '--availability_zone', + '--availability-zone', metavar='', action='append', help=_('Specifies the availability zones information ' '(Repeat multiple times)') ) parser.add_argument( - '--subnet', - metavar='', + '--network-id', + metavar='', action='append', required=True, help=_('Network ID of the subnet' '(Repeat multiple times, up to 5 times)') ) parser.add_argument( - '--security_group', + '--security-group', metavar='', action='append', - required=True, + # required=True, help=_('Security Group ID' '(Repeat multiple times)') ) parser.add_argument( - '--router', - metavar='', + '--router-id', + metavar='', required=True, help=_('Router (VPC) ID') ) parser.add_argument( - '--audit_method', + '--audit-method', metavar='', help=_('Specifies the audit method [`NOVA_AUDIT`, `ELB_AUDIT`]') ) parser.add_argument( - '--audit_time', + '--audit-time', metavar='', type=int, help=_('Specifies the audit time in minutes') ) parser.add_argument( - '--terminate_policy', + '--terminate-policy', metavar='', help=_('Specifies the termination policy' ' [`OLD_CONFIG_OLD_INSTANCE` (default), ' @@ -230,7 +262,7 @@ def get_parser(self, prog_name): '(Repeat multiple times)') ) parser.add_argument( - '--delete_public_ip', + '--delete-public-ip', default=False, action='store_true', help=_('Specifies whether to delete EIP when deleting the ECS') @@ -241,17 +273,18 @@ def take_action(self, parsed_args): args = {} args['name'] = parsed_args.name - args['vpc_id'] = parsed_args.router + args['router_id'] = parsed_args.router_id - subnets = [] - for subnet in parsed_args.subnet: - subnets.append({'id': subnet}) - args['networks'] = subnets + networks = [] + for network in parsed_args.network_id: + networks.append({'id': network}) + args['networks'] = networks - sgs = [] - for sg in parsed_args.security_group: - sgs.append({'id': sg}) - args['security_groups'] = sgs + if parsed_args.security_group: + sgs = [] + for sg in parsed_args.security_group: + sgs.append({'id': sg}) + args['security_groups'] = sgs if parsed_args.desire_instance_number: args['desire_instance_number'] = parsed_args.desire_instance_number @@ -337,36 +370,36 @@ def get_parser(self, prog_name): help=_('AS Group name or ID') ) parser.add_argument( - '--desire_instance_number', + '--desire-instance-number', metavar='', type=int, help=_('Desired number of instances') ) parser.add_argument( - '--min_instance_number', + '--min-instance-number', metavar='', type=int, help=_('Minimal number of instances') ) parser.add_argument( - '--max_instance_number', + '--max-instance-number', metavar='', type=int, help=_('Maximal number of instances') ) parser.add_argument( - '--cool_down_time', + '--cool-down-time', metavar='', type=int, help=_('Specifies cooling duration in seconds') ) parser.add_argument( - '--lb_listener_id', + '--lb-listener-id', metavar='', help=_('Specifies ELB Listener ID') ) parser.add_argument( - '--lbaas_listener', + '--lbaas-listener', metavar='', action='append', help=_('Specifies ULB Listener Information in format: ' @@ -374,47 +407,46 @@ def get_parser(self, prog_name): '(Repeat multiple times, up to 3 times)') ) parser.add_argument( - '--availability_zone', + '--availability-zone', metavar='', action='append', help=_('Specifies the availability zones information ' '(Repeat multiple times)') ) parser.add_argument( - '--subnetwork', - metavar='', + '--network-id', + metavar='', + default=[], action='append', - required=True, help=_('Network ID of the subnet' '(Repeat multiple times, up to 5 times)') ) parser.add_argument( - '--security_group', + '--security-group', metavar='', + default=[], action='append', - required=True, help=_('Security Group ID' '(Repeat multiple times)') ) parser.add_argument( - '--network_id', - metavar='', - required=True, - help=_('Network (VPC) ID') + '--router-id', + metavar='', + help=_('Router (VPC) ID') ) parser.add_argument( - '--audit_method', + '--audit-method', metavar='', help=_('Specifies the audit method [`NOVA_AUDIT`, `ELB_AUDIT`]') ) parser.add_argument( - '--audit_time', + '--audit-time', metavar='', type=int, help=_('Specifies the audit time in minutes') ) parser.add_argument( - '--terminate_policy', + '--terminate-policy', metavar='', help=_('Specifies the termination policy' ' [`OLD_CONFIG_OLD_INSTANCE` (default), ' @@ -430,7 +462,7 @@ def get_parser(self, prog_name): '(Repeat multiple times)') ) parser.add_argument( - '--delete_public_ip', + '--delete-public-ip', default=False, action='store_true', help=_('Specifies whether to delete EIP when deleting the ECS') @@ -440,17 +472,20 @@ def get_parser(self, prog_name): def take_action(self, parsed_args): args = {} - args['vpc_id'] = parsed_args.network_id + if parsed_args.router_id: + args['router_id'] = parsed_args.router_id - subnets = [] - for subnet in parsed_args.subnetwork: - subnets.append({'id': subnet}) - args['networks'] = subnets + networks = [] + for network in parsed_args.network_id: + networks.append({'id': network}) + if networks: + args['networks'] = networks sgs = [] for sg in parsed_args.security_group: sgs.append({'id': sg}) - args['security_groups'] = sgs + if sgs: + args['security_groups'] = sgs if parsed_args.desire_instance_number: args['desire_instance_number'] = parsed_args.desire_instance_number @@ -495,7 +530,8 @@ def take_action(self, parsed_args): args['notifications'] = lst client = self.app.client_manager.auto_scaling - group = client.update_group(group=parsed_args.group, **args) + group = client.find_group(parsed_args.group, ignore_missing=False) + group = client.update_group(group, **args) display_columns, columns = _get_columns(group) data = utils.get_item_properties(group, columns, formatters={}) diff --git a/otcextensions/osclient/auto_scaling/v1/instance.py b/otcextensions/osclient/auto_scaling/v1/instance.py index 061c09b78..03f55608d 100644 --- a/otcextensions/osclient/auto_scaling/v1/instance.py +++ b/otcextensions/osclient/auto_scaling/v1/instance.py @@ -31,18 +31,19 @@ class ListAutoScalingInstance(command.Lister): def get_parser(self, prog_name): parser = super(ListAutoScalingInstance, self).get_parser(prog_name) parser.add_argument( - 'group', + '--group', metavar='', + required=True, help=_('AS Group ID or Name for the instances query') ) parser.add_argument( - '--life_cycle_state', + '--life-cycle-state', metavar='', help=_('Life cycle state of the instances to query\n' 'Could be in [`INSERVICE`, `PENDING`, `REMOVING`]') ) parser.add_argument( - '--health_status', + '--health-status', metavar='', help=_('Health status of the instances to query\n' 'Could be in [`INITIALIZING`, `NORMAL`, `ERROR`]') @@ -91,7 +92,7 @@ def get_parser(self, prog_name): help=_('AS Instance ID to be deleted') ) parser.add_argument( - '--delete_instance', + '--delete-instance', action='store_true', default=False, help=_('Specifies, whether instance should be completely deleted') @@ -117,8 +118,9 @@ def get_parser(self, prog_name): parser = super(BatchActionAutoScalingInstance, self).\ get_parser(prog_name) parser.add_argument( - 'group', + '--group', metavar='', + required=True, help=_('AS Group ID or Name') ) parser.add_argument( @@ -134,7 +136,7 @@ def get_parser(self, prog_name): help=_('AS Instance ID to be deleted') ) parser.add_argument( - '--delete_instance', + '--delete-instance', action='store_true', default=False, help=_('Specifies, whether instance should be completely deleted' diff --git a/otcextensions/osclient/auto_scaling/v1/policy.py b/otcextensions/osclient/auto_scaling/v1/policy.py index e17755052..f0baacbea 100644 --- a/otcextensions/osclient/auto_scaling/v1/policy.py +++ b/otcextensions/osclient/auto_scaling/v1/policy.py @@ -104,18 +104,26 @@ def get_parser(self, prog_name): parser.add_argument( 'policy', metavar='', - help=_('ID of the configuration policy') + help=_('ID of the configuration policy\n' + 'For Policy Name search --group param is needed') + ) + parser.add_argument( + '--group', + metavar='', + help=_('ScalingGroup ID or Name if Name searched is used') ) return parser def take_action(self, parsed_args): client = self.app.client_manager.auto_scaling - obj = client.get_policy(parsed_args.policy) - - # display_columns, columns = _get_columns(obj) - # data = utils.get_item_properties( - # obj, columns, formatters={'instance_config': _format_instance}) + if parsed_args.group: + group = client.find_group(parsed_args.group, ignore_missing=False) + obj = client.find_policy(parsed_args.policy, + group=group, + ignore_missing=False) + else: + obj = client.get_policy(parsed_args.policy) fmt = set_attributes_for_print_detail(obj) # display_columns, columns = _get_columns(obj) @@ -159,30 +167,30 @@ def get_parser(self, prog_name): help=_('AS Policy type [`ALARM`, `SCHEDULED`, `RECURRENCE`]') ) parser.add_argument( - '--cool_down_time', + '--cool-down-time', metavar='', type=int, help=_('Specifies the cooling time in seconds for the policy') ) parser.add_argument( - '--alarm_id', + '--alarm-id', metavar='', help=_('Specifies the alarm_id for the policy') ) parser.add_argument( - '--action_operation', + '--action-operation', metavar='', help=_('Specifies the policy operation ' 'Can be [`ADD`, `REMOVE`, `SET`]') ) parser.add_argument( - '--action_instance_number', + '--action-instance-number', metavar='', type=int, help=_('Specifies number of instances to be operated') ) parser.add_argument( - '--launch_time', + '--launch-time', metavar='', help=_('Specifies the time when the scaling action is triggered. ' 'The time format must comply with UTC.\n' @@ -190,7 +198,7 @@ def get_parser(self, prog_name): '* when type=`RECURRENCE`, then `hh:mm`\n') ) parser.add_argument( - '--recurrence_type', + '--recurrence-type', metavar='', help=_( 'Specifies the periodic triggering type\n' @@ -199,7 +207,7 @@ def get_parser(self, prog_name): ) ) parser.add_argument( - '--recurrence_value', + '--recurrence-value', metavar='', help=_( 'Specifies the frequency, at which actions are triggered\n' @@ -210,13 +218,13 @@ def get_parser(self, prog_name): ) ) parser.add_argument( - '--start_time', + '--start-time', metavar='', help=_('Specifies the start time in of the action in the ' '`YYYY-MM-DDThh:mmZ` format') ) parser.add_argument( - '--end_time', + '--end-time', metavar='', help=_('Specifies the end time in of the action in the ' '`YYYY-MM-DDThh:mmZ` format\n' @@ -315,7 +323,7 @@ def get_parser(self, prog_name): parser.add_argument( 'policy', metavar='', - help=_('AS Policy name or ID') + help=_('AS Policy ID') ) parser.add_argument( '--group', @@ -326,35 +334,33 @@ def get_parser(self, prog_name): parser.add_argument( '--type', metavar='', - required=True, - # choices=['ALARM', 'SCHEDULED', 'RECURRENCE'], help=_('AS Policy type [`ALARM`, `SCHEDULED`, `RECURRENCE`]') ) parser.add_argument( - '--cool_down_time', + '--cool-down-time', metavar='', type=int, help=_('Specifies the cooling time in seconds for the policy') ) parser.add_argument( - '--alarm_id', + '--alarm-id', metavar='', help=_('Specifies the alarm_id for the policy') ) parser.add_argument( - '--action_operation', + '--action-operation', metavar='', help=_('Specifies the policy operation ' 'Can be [`ADD`, `REMOVE`, `SET`]') ) parser.add_argument( - '--action_instance_number', + '--action-instance-number', metavar='', type=int, help=_('Specifies number of instances to be operated') ) parser.add_argument( - '--launch_time', + '--launch-time', metavar='', help=_('Specifies the time when the scaling action is triggered. ' 'The time format must comply with UTC.\n' @@ -362,7 +368,7 @@ def get_parser(self, prog_name): '* when type=`RECURRENCE`, then `hh:mm`\n') ) parser.add_argument( - '--recurrence_type', + '--recurrence-type', metavar='', help=_( 'Specifies the periodic triggering type\n' @@ -371,7 +377,7 @@ def get_parser(self, prog_name): ) ) parser.add_argument( - '--recurrence_value', + '--recurrence-value', metavar='', help=_( 'Specifies the frequency, at which actions are triggered\n' @@ -382,13 +388,13 @@ def get_parser(self, prog_name): ) ) parser.add_argument( - '--start_time', + '--start-time', metavar='', help=_('Specifies the start time in of the action in the ' '`YYYY-MM-DDThh:mmZ` format') ) parser.add_argument( - '--end_time', + '--end-time', metavar='', help=_('Specifies the end time in of the action in the ' '`YYYY-MM-DDThh:mmZ` format\n' @@ -401,13 +407,14 @@ def take_action(self, parsed_args): policy_attrs = {} # policy_attrs['name'] = parsed_args.name policy_attrs['scaling_group_id'] = parsed_args.group - policy_type = parsed_args.type.upper() - if policy_type not in self.POLICY_TYPES: - msg = (_('Unsupported policy type. Should be one of %s') - % self.POLICY_TYPES) - raise argparse.ArgumentTypeError(msg) - else: - policy_attrs['type'] = policy_type + if parsed_args.type: + policy_type = parsed_args.type.upper() + if policy_type not in self.POLICY_TYPES: + msg = (_('Unsupported policy type. Should be one of %s') + % self.POLICY_TYPES) + raise argparse.ArgumentTypeError(msg) + else: + policy_attrs['type'] = policy_type if parsed_args.alarm_id: policy_attrs['alarm_id'] = parsed_args.alarm_id if parsed_args.cool_down_time: @@ -437,8 +444,9 @@ def take_action(self, parsed_args): client = self.app.client_manager.auto_scaling + policy = client.get_policy(parsed_args.policy) policy = client.update_policy( - policy=parsed_args.policy, **policy_attrs) + policy, **policy_attrs) fmt = set_attributes_for_print_detail(policy) # display_columns, columns = _get_columns(obj) @@ -475,7 +483,7 @@ def get_parser(self, prog_name): parser.add_argument( 'policy', metavar='', - help=_('AS Policy ID or name') + help=_('AS Policy ID') ) return parser @@ -494,7 +502,7 @@ def get_parser(self, prog_name): parser.add_argument( 'policy', metavar='', - help=_('AS Policy ID or name') + help=_('AS Policy ID') ) return parser diff --git a/otcextensions/sdk/auto_scaling/v1/_base.py b/otcextensions/sdk/auto_scaling/v1/_base.py index c63026088..3538af915 100644 --- a/otcextensions/sdk/auto_scaling/v1/_base.py +++ b/otcextensions/sdk/auto_scaling/v1/_base.py @@ -60,3 +60,15 @@ def _action(self, session, body): url, # endpoint_override=endpoint_override, json=body) + + def commit(self, session, prepend_key=False, has_body=True, + retry_on_conflict=None, base_path=None): + return \ + super(Resource, self).commit(session, prepend_key=prepend_key, + has_body=has_body, + retry_on_conflict=retry_on_conflict, + base_path=base_path) + + def create(self, session, prepend_key=False, base_path=None, **params): + return super(Resource, self).create(session, prepend_key=prepend_key, + base_path=base_path, **params) diff --git a/otcextensions/sdk/auto_scaling/v1/_proxy.py b/otcextensions/sdk/auto_scaling/v1/_proxy.py index 7c020739c..1600db592 100644 --- a/otcextensions/sdk/auto_scaling/v1/_proxy.py +++ b/otcextensions/sdk/auto_scaling/v1/_proxy.py @@ -307,10 +307,11 @@ def delete_policy(self, policy, ignore_missing=True): return self._delete(_policy.Policy, policy, ignore_missing=ignore_missing) - def find_policy(self, name_or_id, ignore_missing=True): + def find_policy(self, name_or_id, group, ignore_missing=True): """Find a single policy :param name_or_id: The name or ID of a policy + :param group: ID of a group :param bool ignore_missing: When set to ``False`` :class:`~openstack.exceptions.ResourceNotFound` will be raised when the policy does not exist. @@ -319,8 +320,10 @@ def find_policy(self, name_or_id, ignore_missing=True): :returns: ``None`` """ + group = self._get_resource(_group.Group, group) return self._find(_policy.Policy, name_or_id, - ignore_missing=ignore_missing) + ignore_missing=ignore_missing, + group_id=group.id) def execute_policy(self, policy): """execute policy diff --git a/otcextensions/sdk/auto_scaling/v1/config.py b/otcextensions/sdk/auto_scaling/v1/config.py index ff551016a..f14f7ae7f 100644 --- a/otcextensions/sdk/auto_scaling/v1/config.py +++ b/otcextensions/sdk/auto_scaling/v1/config.py @@ -54,7 +54,7 @@ class InstanceConfig(resource.Resource): class Config(_base.Resource): - # resource_key = 'scaling_configuration' + resource_key = 'scaling_configuration' resources_key = 'scaling_configurations' base_path = '/scaling_configuration' # query_marker_key = 'start_number' diff --git a/otcextensions/sdk/auto_scaling/v1/group.py b/otcextensions/sdk/auto_scaling/v1/group.py index 7175be6a8..7f135ec3d 100644 --- a/otcextensions/sdk/auto_scaling/v1/group.py +++ b/otcextensions/sdk/auto_scaling/v1/group.py @@ -26,14 +26,14 @@ class Group(_base.Resource): allow_list = True allow_fetch = True allow_delete = True - allow_update = True + allow_commit = True _query_mapping = resource.QueryParameters( - 'scaling_configuration_id', 'scaling_group_name', 'limit', - scaling_group_name='scaling_group_name', - # status='scaling_group_status', - marker=query_marker_key, - limit='limit' + 'id', 'name', 'limit', 'marker', + 'scaling_configuration_id', + name='scaling_group_name', + status='scaling_group_status', + marker=query_marker_key ) #: Properties @@ -49,9 +49,9 @@ class Group(_base.Resource): #: AutoScaling group detail detail = resource.Body('detail') #: VPC id - (Router Id) - network_id = resource.Body('vpc_id') + router_id = resource.Body('vpc_id') #: network id list - (Subnet) - subnetworks = resource.Body('networks', type=list) + networks = resource.Body('networks', type=list) #: security group id list security_groups = resource.Body('security_groups', type=list) #: Auto Scaling Config ID reference, used for creating instance diff --git a/otcextensions/sdk/auto_scaling/v1/policy.py b/otcextensions/sdk/auto_scaling/v1/policy.py index 81d81b64c..f98b6ae31 100644 --- a/otcextensions/sdk/auto_scaling/v1/policy.py +++ b/otcextensions/sdk/auto_scaling/v1/policy.py @@ -10,6 +10,7 @@ # License for the specific language governing permissions and limitations # under the License. from openstack import resource +from openstack import exceptions from otcextensions.sdk.auto_scaling.v1 import _base @@ -41,8 +42,19 @@ class Action(resource.Resource): #: Scaling trigger action type #: valid values include: ``ADD``, ``REMOVE``, ``SET`` operation = resource.Body('operation') - #: The instance number action for - instance_number = resource.Body('instance_number') + #: Number of instances which will be operated by the action + #: Values from 0 to 200 are possible. + #: Note: Use either instance_number or instance_percentage + #: If nothing of instance_number or instance_percentage is set, the + #: default value is 1. + instance_number = resource.Body('instance_number', type=int) + #: Percentage of instances which are currently there to be operated + #: by the action + #: Values from 0 to 20000 are possible. + #: Note: Use either instance_number or instance_percentage + #: If nothing of instance_number or instance_percentage is set, the default + #: value is 1. + instance_percentage = resource.Body('instance_percentage', type=int) class Policy(_base.Resource): @@ -75,14 +87,14 @@ class Policy(_base.Resource): #: valid values include: ``ALARM``, ``SCHEDULED``, ``RECURRENCE`` type = resource.Body('scaling_policy_type') #: AutoScaling group reference the policy apply to - scaling_group_id = resource.URI('scaling_group_id') + scaling_group_id = resource.Body('scaling_group_id') alarm_id = resource.Body('alarm_id') scheduled_policy = resource.Body('scheduled_policy', type=ScheduledPolicy) scaling_policy_action = resource.Body('scaling_policy_action', type=Action) - cool_down_time = resource.Body('cool_down_time') + cool_down_time = resource.Body('cool_down_time', type=int) create_time = resource.Body('create_time') #: valid values include: ``INSERVICE``, ``PAUSED`` status = resource.Body('policy_status') @@ -101,3 +113,58 @@ def resume(self, session): """resume policy""" body = {"action": "resume"} self._action(session, body) + + @classmethod + def find(cls, session, name_or_id, ignore_missing=True, **params): + """Find a resource by its name or id. + + :param session: The session to use for making this request. + :type session: :class:`~keystoneauth1.adapter.Adapter` + :param name_or_id: This resource's identifier, if needed by + the request. The default is ``None``. + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be + raised when the resource does not exist. + When set to ``True``, None will be returned when + attempting to find a nonexistent resource. + :param dict params: Any additional parameters to be passed into + underlying methods, such as to + :meth:`~openstack.resource.Resource.existing` + in order to pass on URI parameters. + + :return: The :class:`Resource` object matching the given name or id + or None if nothing matches. + :raises: :class:`openstack.exceptions.DuplicateResource` if more + than one resource is found for this request. + :raises: :class:`openstack.exceptions.ResourceNotFound` if nothing + is found and ignore_missing is ``False``. + """ + session = cls._get_session(session) + # Try to short-circuit by looking directly for a matching ID. + group_id = params.pop('group_id', None) + try: + match = cls.existing( + id=name_or_id, + connection=session._get_connection(), + **params) + return match.fetch(session, **params) + except exceptions.NotFoundException: + pass + + # if ('name' in cls._query_mapping._mapping.keys() + # and 'name' not in params): + params['name'] = name_or_id + + base_path = '/scaling_policy/{id}/list'.format(id=group_id) + data = cls.list(session, + base_path=base_path, + **params) + + result = cls._get_one_match(name_or_id, data) + if result is not None: + return result + + if ignore_missing: + return None + raise exceptions.ResourceNotFound( + "No %s found for %s" % (cls.__name__, name_or_id)) diff --git a/otcextensions/tests/unit/osclient/auto_scaling/v1/fakes.py b/otcextensions/tests/unit/osclient/auto_scaling/v1/fakes.py index 5b12dd175..8a8dc006e 100644 --- a/otcextensions/tests/unit/osclient/auto_scaling/v1/fakes.py +++ b/otcextensions/tests/unit/osclient/auto_scaling/v1/fakes.py @@ -52,7 +52,7 @@ def generate(cls): 'id': 'id-' + uuid.uuid4().hex, 'status': 'SOME STATUS', 'detail': 'detail-' + uuid.uuid4().hex, - 'network_id': 'id-vpc-' + uuid.uuid4().hex, + 'router_id': 'id-vpc-' + uuid.uuid4().hex, } obj = group.Group.existing(**object_info) return obj diff --git a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_activity.py b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_activity.py index 30da58ba4..63132fc85 100644 --- a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_activity.py +++ b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_activity.py @@ -58,10 +58,10 @@ def setUp(self): def test_list_default(self): arglist = [ - '--start_time', '2200-01-01T00:00:00Z', - '--end_time', '2200-01-02T00:00:00Z', + '--start-time', '2200-01-01T00:00:00Z', + '--end-time', '2200-01-02T00:00:00Z', '--limit', '14', - 'group1' + '--group', 'group1' ] verifylist = [ diff --git a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_config.py b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_config.py index f19a953a6..295e900ff 100644 --- a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_config.py +++ b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_config.py @@ -172,7 +172,7 @@ def test_create_ok(self): arglist = [ 'config_name', '--flavor', 'some_flavor', - '--image_id', 'some_image', + '--image-id', 'some_image', '--disk', 'SYS,SSD,10', '--disk', 'DATA,SSD,5', ] diff --git a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_group.py b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_group.py index 6c98e5011..95e3472fb 100644 --- a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_group.py +++ b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_group.py @@ -50,10 +50,19 @@ def setUp(self): def test_list_default(self): arglist = [ + '--name', 'grp', + '--status', 'PAUSED', + '--scaling-configuration-id', '2', + '--limit', '12' ] verifylist = [ + ('name', 'grp'), + ('status', 'PAUSED'), + ('scaling_configuration_id', '2'), + ('limit', 12) ] + # Verify cm is triggereg with default parameters parsed_args = self.check_parser(self.cmd, arglist, verifylist) @@ -65,7 +74,11 @@ def test_list_default(self): # Trigger the action columns, data = self.cmd.take_action(parsed_args) - self.client.groups.assert_called_once_with() + self.client.groups.assert_called_once_with( + name='grp', + status='PAUSED', + scaling_configuration_id='2', + limit=12) self.assertEqual(self.columns, columns) self.assertEqual(self.data, list(data)) @@ -73,7 +86,7 @@ def test_list_default(self): class TestShowAutoScalingGroup(TestAutoScalingGroup): - columns = ('create_time', 'detail', 'id', 'name', 'network_id', 'status') + columns = ('create_time', 'detail', 'id', 'name', 'router_id', 'status') _group = fakes.FakeGroup.create_one() @@ -82,7 +95,7 @@ class TestShowAutoScalingGroup(TestAutoScalingGroup): _group.detail, _group.id, _group.name, - _group.network_id, + _group.router_id, _group.status, ) @@ -119,7 +132,7 @@ def test_show_default(self): class TestCreateAutoScalingGroup(TestAutoScalingGroup): - columns = ('create_time', 'detail', 'id', 'name', 'network_id', 'status') + columns = ('create_time', 'detail', 'id', 'name', 'router_id', 'status') _group = fakes.FakeGroup.create_one() @@ -128,7 +141,7 @@ class TestCreateAutoScalingGroup(TestAutoScalingGroup): _group.detail, _group.id, _group.name, - _group.network_id, + _group.router_id, _group.status, ) @@ -141,23 +154,23 @@ def setUp(self): def test_create(self): arglist = [ - '--desire_instance_number', '10', - '--min_instance_number', '1', - '--max_instance_number', '15', - '--cool_down_time', '1', - '--availability_zone', 'eu-1', - '--availability_zone', 'eu-2', - '--subnet', 'sub1', - '--subnet', 'sub2', - '--router', 'vpc-1', - '--security_group', 'sg1', - '--security_group', 'sg2', - '--lb_listener_id', 'lb1', - '--lbaas_listener', 'lbas1:14', - '--lbaas_listener', 'lbas2:15:10', - '--audit_method', 'some_method', - '--audit_time', '15', - '--terminate_policy', 'pol', + '--desire-instance-number', '10', + '--min-instance-number', '1', + '--max-instance-number', '15', + '--cool-down-time', '1', + '--availability-zone', 'eu-1', + '--availability-zone', 'eu-2', + '--network-id', 'sub1', + '--network-id', 'sub2', + '--router-id', 'vpc-1', + '--security-group', 'sg1', + '--security-group', 'sg2', + '--lb-listener-id', 'lb1', + '--lbaas-listener', 'lbas1:14', + '--lbaas-listener', 'lbas2:15:10', + '--audit-method', 'some_method', + '--audit-time', '15', + '--terminate-policy', 'pol', '--notification', 'EMAIL', '--notification', 'SMS', @@ -169,9 +182,9 @@ def test_create(self): ('max_instance_number', 15), ('cool_down_time', 1), ('availability_zone', ['eu-1', 'eu-2']), - ('subnet', ['sub1', 'sub2']), + ('network_id', ['sub1', 'sub2']), ('security_group', ['sg1', 'sg2']), - ('router', 'vpc-1'), + ('router_id', 'vpc-1'), ('lb_listener_id', 'lb1'), ('lbaas_listener', ['lbas1:14', 'lbas2:15:10']), ('audit_method', 'some_method'), @@ -208,7 +221,7 @@ def test_create(self): networks=[{'id': 'sub1'}, {'id': 'sub2'}], notifications=['EMAIL', 'SMS'], security_groups=[{'id': 'sg1'}, {'id': 'sg2'}], - vpc_id='vpc-1' + router_id='vpc-1' ) self.assertEqual(self.columns, columns) @@ -245,7 +258,7 @@ def test_sdelete(self): class TestUpdateAutoScalingGroup(TestAutoScalingGroup): - columns = ('create_time', 'detail', 'id', 'name', 'network_id', 'status') + columns = ('create_time', 'detail', 'id', 'name', 'router_id', 'status') _group = fakes.FakeGroup.create_one() @@ -254,7 +267,7 @@ class TestUpdateAutoScalingGroup(TestAutoScalingGroup): _group.detail, _group.id, _group.name, - _group.network_id, + _group.router_id, _group.status, ) @@ -267,23 +280,23 @@ def setUp(self): def test_create(self): arglist = [ - '--desire_instance_number', '10', - '--min_instance_number', '1', - '--max_instance_number', '15', - '--cool_down_time', '1', - '--availability_zone', 'eu-1', - '--availability_zone', 'eu-2', - '--subnetwork', 'sub1', - '--subnetwork', 'sub2', - '--network_id', 'vpc-1', - '--security_group', 'sg1', - '--security_group', 'sg2', - '--lb_listener_id', 'lb1', - '--lbaas_listener', 'lbas1:14', - '--lbaas_listener', 'lbas2:15:10', - '--audit_method', 'some_method', - '--audit_time', '15', - '--terminate_policy', 'pol', + '--desire-instance-number', '10', + '--min-instance-number', '1', + '--max-instance-number', '15', + '--cool-down-time', '1', + '--availability-zone', 'eu-1', + '--availability-zone', 'eu-2', + '--network-id', 'sub1', + '--network-id', 'sub2', + '--router-id', 'vpc-1', + '--security-group', 'sg1', + '--security-group', 'sg2', + '--lb-listener-id', 'lb1', + '--lbaas-listener', 'lbas1:14', + '--lbaas-listener', 'lbas2:15:10', + '--audit-method', 'some_method', + '--audit-time', '15', + '--terminate-policy', 'pol', '--notification', 'EMAIL', '--notification', 'SMS', @@ -295,9 +308,9 @@ def test_create(self): ('max_instance_number', 15), ('cool_down_time', 1), ('availability_zone', ['eu-1', 'eu-2']), - ('subnetwork', ['sub1', 'sub2']), + ('network_id', ['sub1', 'sub2']), ('security_group', ['sg1', 'sg2']), - ('network_id', 'vpc-1'), + ('router_id', 'vpc-1'), ('lb_listener_id', 'lb1'), ('lbaas_listener', ['lbas1:14', 'lbas2:15:10']), ('audit_method', 'some_method'), @@ -314,10 +327,15 @@ def test_create(self): self._group ] + self.client.find_group.side_effect = [ + self._group + ] + # Trigger the action columns, data = self.cmd.take_action(parsed_args) self.client.update_group.assert_called_with( + self._group, available_zones=['eu-1', 'eu-2'], cool_down_time=1, desire_instance_number=10, @@ -330,11 +348,10 @@ def test_create(self): {'id': 'lbas2', 'protocol_port': '15', 'weight': '10'}], max_instance_number=15, min_instance_number=1, - group='test_name', networks=[{'id': 'sub1'}, {'id': 'sub2'}], notifications=['EMAIL', 'SMS'], security_groups=[{'id': 'sg1'}, {'id': 'sg2'}], - vpc_id='vpc-1' + router_id='vpc-1' ) self.assertEqual(self.columns, columns) diff --git a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_instance.py b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_instance.py index 0fd9b4dc0..9b94ea5d0 100644 --- a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_instance.py +++ b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_instance.py @@ -57,9 +57,9 @@ def setUp(self): def test_list(self): arglist = [ - 'grp', - '--life_cycle_state', 'lc', - '--health_status', 'hs', + '--group', 'grp', + '--life-cycle-state', 'lc', + '--health-status', 'hs', '--limit', '12' ] @@ -111,7 +111,7 @@ def setUp(self): def test_remove(self): arglist = [ 'Instance1', - '--delete_instance' + '--delete-instance' ] verifylist = [ ('instance', 'Instance1'), @@ -140,10 +140,10 @@ def setUp(self): def test_wrong_action(self): arglist = [ - 'grp1', + '--group', 'grp1', 'ADD1', 'Instance1', - '--delete_instance', + '--delete-instance', ] verifylist = [ ('instance', ['Instance1']), @@ -159,7 +159,7 @@ def test_wrong_action(self): def test_add(self): arglist = [ - 'grp1', + '--group', 'grp1', 'ADD', 'Instance1', ] @@ -185,11 +185,11 @@ def test_add(self): def test_remove(self): arglist = [ - 'grp1', + '--group', 'grp1', 'REMOVE', 'Instance1', 'Instance2', - '--delete_instance', + '--delete-instance', ] verifylist = [ ('instance', ['Instance1', 'Instance2']), @@ -214,7 +214,7 @@ def test_remove(self): def test_protect(self): arglist = [ - 'grp1', + '--group', 'grp1', 'protect', 'Instance1', 'Instance2', @@ -241,7 +241,7 @@ def test_protect(self): def test_unprotect(self): arglist = [ - 'grp1', + '--group', 'grp1', 'unProtect', 'Instance1', 'Instance2', diff --git a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_policy.py b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_policy.py index 8e0a668b5..feab2f710 100644 --- a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_policy.py +++ b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_policy.py @@ -171,15 +171,15 @@ def test_create(self): arglist = [ '--group', 'group1', '--type', 'ALARM', - '--cool_down_time', '1', - '--alarm_id', 'alarm1', - '--action_operation', 'ADD', - '--action_instance_number', '7', - '--launch_time', 'launch_time1', - '--recurrence_type', 'recurrence_type1', - '--recurrence_value', 'recurrence_value1', - '--start_time', 'st1', - '--end_time', 'et1', + '--cool-down-time', '1', + '--alarm-id', 'alarm1', + '--action-operation', 'ADD', + '--action-instance-number', '7', + '--launch-time', 'launch_time1', + '--recurrence-type', 'recurrence_type1', + '--recurrence-value', 'recurrence_value1', + '--start-time', 'st1', + '--end-time', 'et1', 'test_name' ] @@ -292,15 +292,15 @@ def test_create(self): arglist = [ '--group', 'group1', '--type', 'ALARM', - '--cool_down_time', '1', - '--alarm_id', 'alarm1', - '--action_operation', 'ADD', - '--action_instance_number', '7', - '--launch_time', 'launch_time1', - '--recurrence_type', 'recurrence_type1', - '--recurrence_value', 'recurrence_value1', - '--start_time', 'st1', - '--end_time', 'et1', + '--cool-down-time', '1', + '--alarm-id', 'alarm1', + '--action-operation', 'ADD', + '--action-instance-number', '7', + '--launch-time', 'launch_time1', + '--recurrence-type', 'recurrence_type1', + '--recurrence-value', 'recurrence_value1', + '--start-time', 'st1', + '--end-time', 'et1', 'policy1' ] @@ -326,13 +326,17 @@ def test_create(self): self._obj ] + self.client.get_policy.side_effect = [ + self._obj + ] + # Trigger the action columns, data = self.cmd.take_action(parsed_args) self.client.update_policy.assert_called_with( + self._obj, alarm_id='alarm1', cool_down_time=1, - policy='policy1', scaling_group_id='group1', scaling_policy_action={'operation': 'ADD', 'instance_number': 7}, scheduled_policy={ diff --git a/otcextensions/tests/unit/sdk/auto_scaling/v1/test_group.py b/otcextensions/tests/unit/sdk/auto_scaling/v1/test_group.py index e825cc740..72cb7610d 100644 --- a/otcextensions/tests/unit/sdk/auto_scaling/v1/test_group.py +++ b/otcextensions/tests/unit/sdk/auto_scaling/v1/test_group.py @@ -73,7 +73,7 @@ def test_basic(self): self.assertTrue(sot.allow_list) self.assertTrue(sot.allow_create) self.assertTrue(sot.allow_get) - self.assertTrue(sot.allow_update) + self.assertTrue(sot.allow_commit) self.assertTrue(sot.allow_delete) def test_make_it(self): diff --git a/otcextensions/tests/unit/sdk/auto_scaling/v1/test_policy.py b/otcextensions/tests/unit/sdk/auto_scaling/v1/test_policy.py index 3e0b220bc..b0a9fcc86 100644 --- a/otcextensions/tests/unit/sdk/auto_scaling/v1/test_policy.py +++ b/otcextensions/tests/unit/sdk/auto_scaling/v1/test_policy.py @@ -137,7 +137,6 @@ def test_create(self): call_args = self.sess.post.call_args_list[0] expected_json = copy.deepcopy(EXAMPLE) - expected_json.pop('scaling_group_id') self.assertEqual('/scaling_policy', call_args[0][0]) self.assertDictEqual(expected_json, call_args[1]['json']) @@ -184,7 +183,6 @@ def test_update(self): expected_json = copy.deepcopy(EXAMPLE) expected_json.pop('scaling_policy_id') - expected_json.pop('scaling_group_id') self.assertEqual( 'scaling_policy/%s' % EXAMPLE['scaling_policy_id'], diff --git a/otcextensions/tests/unit/sdk/auto_scaling/v1/test_proxy.py b/otcextensions/tests/unit/sdk/auto_scaling/v1/test_proxy.py index 248d8212e..467f6227a 100644 --- a/otcextensions/tests/unit/sdk/auto_scaling/v1/test_proxy.py +++ b/otcextensions/tests/unit/sdk/auto_scaling/v1/test_proxy.py @@ -184,10 +184,14 @@ def test_find(self): self._verify2( 'openstack.proxy.Proxy._find', self.proxy.find_policy, - method_args=['pol'], + method_args=['pol', 'group'], + method_kwargs={}, expected_args=[_policy.Policy, 'pol'], expected_kwargs={ - 'ignore_missing': True}) + 'ignore_missing': True, + 'group_id': 'group' + } + ) def test_update(self): self._verify2( diff --git a/setup.cfg b/setup.cfg index 65555cce7..02db5bd22 100644 --- a/setup.cfg +++ b/setup.cfg @@ -121,6 +121,7 @@ openstack.auto_scaling.v1 = as_policy_execute = otcextensions.osclient.auto_scaling.v1.policy:ExecuteAutoScalingPolicy as_policy_enable = otcextensions.osclient.auto_scaling.v1.policy:EnableAutoScalingPolicy as_policy_disable = otcextensions.osclient.auto_scaling.v1.policy:DisableAutoScalingPolicy + as_policy_delete = otcextensions.osclient.auto_scaling.v1.policy:DeleteAutoScalingPolicy as_instance_list = otcextensions.osclient.auto_scaling.v1.instance:ListAutoScalingInstance as_instance_remove = otcextensions.osclient.auto_scaling.v1.instance:RemoveAutoScalingInstance as_instance_batch = otcextensions.osclient.auto_scaling.v1.instance:BatchActionAutoScalingInstance From 9e1428ad222219fef93b67b06a2792bbdd72fde9 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Mon, 24 Feb 2020 15:40:00 +0100 Subject: [PATCH 11/58] add unit test changes --- .../unit/osclient/dns/v2/test_recordset.py | 183 ++++++++++++++++++ .../tests/unit/sdk/dns/v2/test_proxy.py | 7 + 2 files changed, 190 insertions(+) diff --git a/otcextensions/tests/unit/osclient/dns/v2/test_recordset.py b/otcextensions/tests/unit/osclient/dns/v2/test_recordset.py index cb63aa25a..30603b4ef 100644 --- a/otcextensions/tests/unit/osclient/dns/v2/test_recordset.py +++ b/otcextensions/tests/unit/osclient/dns/v2/test_recordset.py @@ -74,6 +74,43 @@ def test_default_zone(self): self.assertEqual(self.columns, columns) self.assertEqual(self.data, list(data)) + def test_private_zone(self): + arglist = [ + 'zn', + '--zone-type', 'private' + ] + + verifylist = [ + ('zone', 'zn'), + ('zone_type', 'private') + ] + + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.api_mock.side_effect = [ + self.objects + ] + self.client.find_zone.side_effect = [ + self._zone + ] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.find_zone.assert_called_once_with( + 'zn', + zone_type='private', + ignore_missing=False, + ) + self.client.api_mock.assert_called_once_with( + zone=self._zone + ) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + class TestShowRS(fakes.TestDNS): @@ -120,6 +157,53 @@ def test_default(self): # Trigger the action columns, data = self.cmd.take_action(parsed_args) + self.client.find_zone.assert_called_once_with( + 'zone', + ignore_missing=False, + zone_type=None + ) + + self.client.api_mock.assert_called_once_with( + zone=self._zone, + name_or_id='rs' + ) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + def test_private(self): + arglist = [ + 'zone', + 'rs', + '--zone-type', 'private' + ] + + verifylist = [ + ('zone', 'zone'), + ('recordset', 'rs'), + ('zone_type', 'private') + ] + + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.find_zone.side_effect = [ + self._zone + ] + self.client.api_mock.side_effect = [ + self._data + ] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.find_zone.assert_called_once_with( + 'zone', + ignore_missing=False, + zone_type='private' + ) + self.client.api_mock.assert_called_once_with( zone=self._zone, name_or_id='rs' @@ -195,6 +279,60 @@ def test_create(self): self.assertEqual(self.columns, columns) self.assertEqual(self.data, data) + def test_create_private(self): + arglist = [ + 'zn', + '--name', 'rs', + '--description', 'descr', + '--type', 'A', + '--ttl', '500', + '--record', 'a=b', + '--record', 'c=d', + '--zone-type', 'private' + ] + + verifylist = [ + ('zone', 'zn'), + ('name', 'rs'), + ('description', 'descr'), + ('type', 'A'), + ('ttl', 500), + ('record', ['a=b', 'c=d']), + ('zone_type', 'private') + ] + + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.find_zone.side_effect = [ + self._zone + ] + self.client.api_mock.side_effect = [ + self._data + ] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.find_zone.assert_called_once_with( + 'zn', + ignore_missing=False, + zone_type='private' + ) + + self.client.api_mock.assert_called_once_with( + zone=self._zone, + description='descr', + name='rs', + type='A', + ttl=500, + records=['a=b', 'c=d'] + ) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + class TestSetRS(fakes.TestDNS): @@ -321,3 +459,48 @@ def test_delete_multiple(self): self.client.api_mock.assert_has_calls(calls) self.assertEqual(2, self.client.api_mock.call_count) + + def test_private(self): + arglist = [ + 'zn', + 't1', + '--zone-type', 'private' + ] + verifylist = [ + ('zone', 'zn'), + ('recordset', ['t1']), + ('zone_type', 'private') + ] + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.find_zone.side_effect = [ + self._zone + ] + + self.client.find_recordset.side_effect = [self._rs, self._rs] + self.client.api_mock.side_effect = [{}, {}] + + # Trigger the action + self.cmd.take_action(parsed_args) + + self.client.find_zone.assert_called_once_with( + 'zn', + ignore_missing=False, + zone_type='private' + ) + + find_calls = [ + mock.call(zone=self._zone, name_or_id='t1', ignore_missing=False), + ] + + self.client.find_recordset.assert_has_calls(find_calls) + + calls = [ + mock.call(zone=self._zone, recordset=self._rs, + ignore_missing=False), + ] + + self.client.api_mock.assert_has_calls(calls) + self.assertEqual(1, self.client.api_mock.call_count) diff --git a/otcextensions/tests/unit/sdk/dns/v2/test_proxy.py b/otcextensions/tests/unit/sdk/dns/v2/test_proxy.py index d2181b384..c04ead73a 100644 --- a/otcextensions/tests/unit/sdk/dns/v2/test_proxy.py +++ b/otcextensions/tests/unit/sdk/dns/v2/test_proxy.py @@ -39,6 +39,13 @@ def test_zone_delete(self): def test_zone_find(self): self.verify_find(self.proxy.find_zone, zone.Zone) + def test_zone_find_private(self): + self.verify_find(self.proxy.find_zone, zone.Zone, + method_kwargs={ + 'p1': 'v1' + }, + expected_kwargs={'p1': 'v1'}) + def test_zone_get(self): self.verify_get(self.proxy.get_zone, zone.Zone) From a29c0982745a38381fe15b85ca8cf650b3912cf4 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Mon, 24 Feb 2020 15:43:41 +0100 Subject: [PATCH 12/58] extend help message for DNS zone list --- otcextensions/osclient/dns/v2/zone.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/otcextensions/osclient/dns/v2/zone.py b/otcextensions/osclient/dns/v2/zone.py index 7f7f5769a..f9ed3616a 100644 --- a/otcextensions/osclient/dns/v2/zone.py +++ b/otcextensions/osclient/dns/v2/zone.py @@ -53,7 +53,7 @@ def get_parser(self, prog_name): metavar='{' + ','.join(ZONE_TYPES) + '}', type=lambda s: s.lower(), choices=ZONE_TYPES, - help=_('Zone type.') + help=_('Zone type. Default lists only public zones.') ) return parser From 36d3d3c44e1374dbe62a13620ec2e8f8f8ed9ec2 Mon Sep 17 00:00:00 2001 From: "T. Schreiber" Date: Mon, 30 Mar 2020 16:31:21 +0200 Subject: [PATCH 13/58] Rework of Documentation (#66) * fixes docstring formatting in RDS and removes the README.md from the top page * adds more structure to the documentation and provides a history * cleans up the documentation. adds a page about coverage of services. purges a few temporary files. moves the issues into the doctree and links them. adds a section naming conventions to the glossary. fixes here and there the spelling of projects and other names. * collects all changes from previous commit, which was almost empty. * enhances the structure of two index files * Installation and Configuration sources resorted * reordering section Installation and OpenStack CLI * reordering SDK guides, service proxies and other stuff * user guides reordered * user guides reordered * restructuring done * configuration section updated * improve the enforcer output during tests * introduce the CLI chapter * fix pep8 issues, mostly whitespace * SDK getting started reworked * fix RDS proxy attrs * smaller fixes * streamline the main page documentation * fix spelling and language * auto-scaling started * AS Config finished * explain details about installation options * list authors * clean up the top directory docs * Finished Auto-Scaling SDK guide and pep8 fixes * Anti-DDoS SDK guide status draft * Finish Anti-DDoS SDK Guide * Update ZuuL config to test tox -e docs * update .travis.yml * deleted coverage content and saved locally until content is available for pep8 * minor pep8 correction * Renew coverage.rst * added nat and ces to coverage.rst * CCE SDK guide added * Update .zuul.yaml * Create bindep.txt * some dns private zone fixes * Zuul (#63) * reset zuul integration * disable tox-docs for separate branch * replace openstacksdk general error handler * exclude rds instance osc func tests * blacklist failing tests * repair func test cmd * compare if we got something * fix pep * AS corrections for new API Version (#60) * improve Auto_Scaling user experience by using openstack client * flake8 corrections * change group unit test for AS service * bug fixing * fix policy * add policy delete * minor fixes * ensure --group on policy update * pep 8 corrections and unit test fixes * change CLI client parameters from using underscore to dash * Update test_policy.py * Renaming of network parameters and fixing unit tests * add unit test changes * extend help message for DNS zone list Co-authored-by: Nils-Magnus Co-authored-by: Tino Schreiber Co-authored-by: Artem Goncharov --- .gitignore | 1 - .travis.yml | 2 - .zuul.yaml | 2 +- AUTHORS | 7 + CONTRIBUTING.rst | 49 +- HACKING.rst | 108 --- README-save | 137 +++ README.rst | 170 ++-- doc/source/{ => appendices}/glossary.rst | 30 + doc/source/appendices/history.rst | 75 ++ doc/source/appendices/index.rst | 10 + doc/source/appendices/issues.rst | 200 +++++ doc/source/appendices/releasenotes.rst | 4 + doc/source/cli/anti_ddos.rst | 5 +- doc/source/cli/auto_scaling.rst | 5 +- doc/source/cli/cce_v2.rst | 5 +- doc/source/cli/cts.rst | 5 +- doc/source/cli/dcs.rst | 5 +- doc/source/cli/deh.rst | 5 +- doc/source/cli/dms.rst | 5 +- doc/source/cli/dns.rst | 5 +- doc/source/cli/index.rst | 51 +- doc/source/cli/kms.rst | 5 +- doc/source/cli/load_balancer.rst | 5 +- doc/source/cli/obs.rst | 5 +- doc/source/cli/rds.rst | 5 +- doc/source/cli/volume_backup.rst | 5 +- doc/source/contributor/coding.rst | 156 ++-- doc/source/contributor/contributing.rst | 1 - doc/source/contributor/index.rst | 94 +- doc/source/coverage.rst | 127 +++ doc/source/enforcer.py | 13 +- doc/source/index.rst | 103 ++- doc/source/install/configuration.rst | 186 ++++ doc/source/install/index.rst | 460 ++-------- doc/source/install/pip_install.rst | 175 ++++ doc/source/install/source_install.rst | 41 + doc/source/releasenotes.rst | 5 - doc/source/sdk/architecture.rst | 17 + doc/source/sdk/examples | 1 + doc/source/sdk/getting_started.rst | 101 +++ doc/source/sdk/guides/anti_ddos.rst | 109 +++ doc/source/sdk/guides/auto_scaling.rst | 297 +++++++ doc/source/sdk/guides/cce.rst | 145 ++++ doc/source/{user => sdk}/guides/deh.rst | 9 +- doc/source/sdk/guides/index.rst | 38 + doc/source/{user => sdk}/guides/logging.rst | 0 doc/source/sdk/index.rst | 26 + .../{user => sdk}/proxies/anti_ddos.rst | 0 .../{user => sdk}/proxies/auto_scaling.rst | 9 +- doc/source/{user => sdk}/proxies/cce_v1.rst | 0 doc/source/{user => sdk}/proxies/cce_v3.rst | 0 doc/source/{user => sdk}/proxies/cts.rst | 0 doc/source/{user => sdk}/proxies/dcs.rst | 0 doc/source/{user => sdk}/proxies/deh.rst | 0 doc/source/{user => sdk}/proxies/dms.rst | 0 doc/source/{user => sdk}/proxies/dns.rst | 0 doc/source/sdk/proxies/index.rst | 53 ++ doc/source/{user => sdk}/proxies/kms.rst | 0 doc/source/{user => sdk}/proxies/obs.rst | 2 +- doc/source/{user => sdk}/proxies/rds_v1.rst | 2 +- doc/source/sdk/proxies/rds_v3.rst | 69 ++ .../{user => sdk}/proxies/volume_backup.rst | 10 +- doc/source/user/config/configuration.rst | 322 ------- doc/source/user/config/index.rst | 12 - doc/source/user/config/network-config.rst | 67 -- doc/source/user/config/reference.rst | 14 - doc/source/user/config/using.rst | 58 -- doc/source/user/config/vendor-support.rst | 343 -------- doc/source/user/connection.rst | 31 - doc/source/user/examples | 1 - doc/source/user/guides/auto_scaling.rst | 4 - doc/source/user/guides/connect_otc.rst | 39 - doc/source/user/guides/obs.rst | 4 - doc/source/user/guides/rds.rst | 4 - doc/source/user/guides/volume_backup.rst | 4 - doc/source/user/index.rst | 195 ----- doc/source/user/model.rst | 533 ------------ doc/source/user/multi-cloud-demo.rst | 809 ------------------ doc/source/user/proxies/rds_v3.rst | 55 -- doc/source/user/resource.rst | 26 - doc/source/user/resources/anti_ddos/index.rst | 9 - .../user/resources/anti_ddos/v1/config.rst | 13 - .../resources/anti_ddos/v1/floating_ip.rst | 13 - .../user/resources/anti_ddos/v1/status.rst | 58 -- .../user/resources/auto_scaling/index.rst | 12 - .../resources/auto_scaling/v1/activity.rst | 13 - .../user/resources/auto_scaling/v1/config.rst | 13 - .../user/resources/auto_scaling/v1/group.rst | 13 - .../resources/auto_scaling/v1/instance.rst | 13 - .../user/resources/auto_scaling/v1/policy.rst | 13 - .../user/resources/auto_scaling/v1/quota.rst | 22 - doc/source/user/resources/cce/index.rst | 10 - doc/source/user/resources/cce/v1/cluster.rst | 13 - .../user/resources/cce/v1/cluster_node.rst | 13 - doc/source/user/resources/cce/v3/cluster.rst | 13 - .../user/resources/cce/v3/cluster_node.rst | 13 - doc/source/user/resources/cts/index.rst | 8 - doc/source/user/resources/cts/v1/trace.rst | 13 - doc/source/user/resources/cts/v1/tracker.rst | 13 - doc/source/user/resources/dcs/index.rst | 11 - doc/source/user/resources/dcs/v1/backup.rst | 13 - doc/source/user/resources/dcs/v1/config.rst | 13 - doc/source/user/resources/dcs/v1/instance.rst | 13 - doc/source/user/resources/dcs/v1/restore.rst | 13 - .../user/resources/dcs/v1/statistic.rst | 13 - doc/source/user/resources/deh/index.rst | 9 - doc/source/user/resources/deh/v1/host.rst | 13 - .../user/resources/deh/v1/host_type.rst | 13 - doc/source/user/resources/deh/v1/server.rst | 13 - doc/source/user/resources/dms/index.rst | 11 - doc/source/user/resources/dms/v1/group.rst | 13 - .../user/resources/dms/v1/group_message.rst | 13 - doc/source/user/resources/dms/v1/message.rst | 13 - doc/source/user/resources/dms/v1/queue.rst | 13 - doc/source/user/resources/dms/v1/quota.rst | 13 - doc/source/user/resources/dns/index.rst | 10 - .../user/resources/dns/v2/floating_ip.rst | 13 - .../user/resources/dns/v2/nameserver.rst | 13 - .../user/resources/dns/v2/recordset.rst | 13 - doc/source/user/resources/dns/v2/zone.rst | 13 - doc/source/user/resources/kms/index.rst | 8 - doc/source/user/resources/kms/v1/data_key.rst | 13 - doc/source/user/resources/kms/v1/key.rst | 13 - doc/source/user/resources/obs/index.rst | 8 - .../user/resources/obs/v1/container.rst | 13 - doc/source/user/resources/obs/v1/obj.rst | 13 - doc/source/user/resources/rds/index.rst | 12 - .../user/resources/rds/v1/configuration.rst | 13 - doc/source/user/resources/rds/v1/flavor.rst | 13 - doc/source/user/resources/rds/v1/instance.rst | 13 - .../user/resources/rds/v3/configuration.rst | 13 - doc/source/user/resources/rds/v3/flavor.rst | 13 - doc/source/user/resources/rds/v3/instance.rst | 13 - doc/source/user/transition_from_profile.rst | 186 ---- doc/source/user/utils.rst | 3 - .../anti_ddos/get_floating_ip_policies.py | 25 + examples/anti_ddos/get_floating_ip_status.py | 25 + examples/anti_ddos/list_configs.py | 23 + examples/anti_ddos/list_floating_ip_events.py | 25 + .../anti_ddos/list_floating_ip_stat_day.py | 25 + .../anti_ddos/list_floating_ip_stat_week.py | 23 + examples/anti_ddos/list_floating_ips.py | 23 + examples/anti_ddos/protect_floating_ip.py | 23 + examples/anti_ddos/unprotect_floating_ip.py | 23 + .../anti_ddos/update_floating_ip_policies.py | 30 + examples/auto_scaling/batch_delete_config.py | 26 + .../auto_scaling/batch_instance_action.py | 37 + examples/auto_scaling/create_config.py | 36 + examples/auto_scaling/create_group.py | 37 + examples/auto_scaling/delete_config.py | 23 + examples/auto_scaling/delete_group.py | 23 + examples/auto_scaling/delete_policy.py | 23 + examples/auto_scaling/execute_policy.py | 25 + examples/auto_scaling/find_config.py | 24 + examples/auto_scaling/find_group.py | 24 + examples/auto_scaling/find_policy.py | 24 + examples/auto_scaling/get_config.py | 24 + examples/auto_scaling/get_group.py | 24 + examples/auto_scaling/get_policy.py | 24 + examples/auto_scaling/init.py | 0 examples/auto_scaling/list_activities.py | 27 + examples/auto_scaling/list_configs.py | 22 + examples/auto_scaling/list_groups.py | 22 + examples/auto_scaling/list_instances.py | 25 + examples/auto_scaling/list_policies.py | 25 + examples/auto_scaling/list_quotas.py | 27 + examples/auto_scaling/pause_group.py | 25 + examples/auto_scaling/pause_policy.py | 25 + examples/auto_scaling/remove_instance.py | 26 + examples/auto_scaling/resume_group.py | 24 + examples/auto_scaling/resume_policy.py | 25 + examples/auto_scaling/update_policy.py | 39 + examples/cce/create_cluster.py | 53 ++ examples/cce/create_cluster_node.py | 53 ++ examples/cce/delete_cluster.py | 25 + examples/cce/delete_cluster_node.py | 25 + examples/cce/find_cluster.py | 24 + examples/cce/find_cluster_node.py | 26 + examples/cce/get_cluster.py | 24 + examples/cce/get_cluster_node.py | 26 + examples/cce/get_job.py | 24 + examples/cce/list_cluster_nodes.py | 25 + examples/cce/list_clusters.py | 22 + examples/cce/wait_for_job.py | 25 + open_points | 125 --- otcextensions/sdk/rds/v3/_proxy.py | 33 +- otcextensions/sdk/rds/v3/instance.py | 40 +- setup.cfg | 6 +- 189 files changed, 3647 insertions(+), 4418 deletions(-) create mode 100644 AUTHORS delete mode 100644 HACKING.rst create mode 100644 README-save rename doc/source/{ => appendices}/glossary.rst (74%) create mode 100644 doc/source/appendices/history.rst create mode 100644 doc/source/appendices/index.rst create mode 100644 doc/source/appendices/issues.rst create mode 100644 doc/source/appendices/releasenotes.rst delete mode 100644 doc/source/contributor/contributing.rst create mode 100644 doc/source/coverage.rst create mode 100644 doc/source/install/configuration.rst create mode 100644 doc/source/install/pip_install.rst create mode 100644 doc/source/install/source_install.rst delete mode 100644 doc/source/releasenotes.rst create mode 100644 doc/source/sdk/architecture.rst create mode 120000 doc/source/sdk/examples create mode 100644 doc/source/sdk/getting_started.rst create mode 100644 doc/source/sdk/guides/anti_ddos.rst create mode 100644 doc/source/sdk/guides/auto_scaling.rst create mode 100644 doc/source/sdk/guides/cce.rst rename doc/source/{user => sdk}/guides/deh.rst (88%) create mode 100644 doc/source/sdk/guides/index.rst rename doc/source/{user => sdk}/guides/logging.rst (100%) create mode 100644 doc/source/sdk/index.rst rename doc/source/{user => sdk}/proxies/anti_ddos.rst (100%) rename doc/source/{user => sdk}/proxies/auto_scaling.rst (93%) rename doc/source/{user => sdk}/proxies/cce_v1.rst (100%) rename doc/source/{user => sdk}/proxies/cce_v3.rst (100%) rename doc/source/{user => sdk}/proxies/cts.rst (100%) rename doc/source/{user => sdk}/proxies/dcs.rst (100%) rename doc/source/{user => sdk}/proxies/deh.rst (100%) rename doc/source/{user => sdk}/proxies/dms.rst (100%) rename doc/source/{user => sdk}/proxies/dns.rst (100%) create mode 100644 doc/source/sdk/proxies/index.rst rename doc/source/{user => sdk}/proxies/kms.rst (100%) rename doc/source/{user => sdk}/proxies/obs.rst (94%) rename doc/source/{user => sdk}/proxies/rds_v1.rst (96%) create mode 100644 doc/source/sdk/proxies/rds_v3.rst rename doc/source/{user => sdk}/proxies/volume_backup.rst (81%) delete mode 100644 doc/source/user/config/configuration.rst delete mode 100644 doc/source/user/config/index.rst delete mode 100644 doc/source/user/config/network-config.rst delete mode 100644 doc/source/user/config/reference.rst delete mode 100644 doc/source/user/config/using.rst delete mode 100644 doc/source/user/config/vendor-support.rst delete mode 100644 doc/source/user/connection.rst delete mode 120000 doc/source/user/examples delete mode 100644 doc/source/user/guides/auto_scaling.rst delete mode 100644 doc/source/user/guides/connect_otc.rst delete mode 100644 doc/source/user/guides/obs.rst delete mode 100644 doc/source/user/guides/rds.rst delete mode 100644 doc/source/user/guides/volume_backup.rst delete mode 100644 doc/source/user/index.rst delete mode 100644 doc/source/user/model.rst delete mode 100644 doc/source/user/multi-cloud-demo.rst delete mode 100644 doc/source/user/proxies/rds_v3.rst delete mode 100644 doc/source/user/resource.rst delete mode 100644 doc/source/user/resources/anti_ddos/index.rst delete mode 100644 doc/source/user/resources/anti_ddos/v1/config.rst delete mode 100644 doc/source/user/resources/anti_ddos/v1/floating_ip.rst delete mode 100644 doc/source/user/resources/anti_ddos/v1/status.rst delete mode 100644 doc/source/user/resources/auto_scaling/index.rst delete mode 100644 doc/source/user/resources/auto_scaling/v1/activity.rst delete mode 100644 doc/source/user/resources/auto_scaling/v1/config.rst delete mode 100644 doc/source/user/resources/auto_scaling/v1/group.rst delete mode 100644 doc/source/user/resources/auto_scaling/v1/instance.rst delete mode 100644 doc/source/user/resources/auto_scaling/v1/policy.rst delete mode 100644 doc/source/user/resources/auto_scaling/v1/quota.rst delete mode 100644 doc/source/user/resources/cce/index.rst delete mode 100644 doc/source/user/resources/cce/v1/cluster.rst delete mode 100644 doc/source/user/resources/cce/v1/cluster_node.rst delete mode 100644 doc/source/user/resources/cce/v3/cluster.rst delete mode 100644 doc/source/user/resources/cce/v3/cluster_node.rst delete mode 100644 doc/source/user/resources/cts/index.rst delete mode 100644 doc/source/user/resources/cts/v1/trace.rst delete mode 100644 doc/source/user/resources/cts/v1/tracker.rst delete mode 100644 doc/source/user/resources/dcs/index.rst delete mode 100644 doc/source/user/resources/dcs/v1/backup.rst delete mode 100644 doc/source/user/resources/dcs/v1/config.rst delete mode 100644 doc/source/user/resources/dcs/v1/instance.rst delete mode 100644 doc/source/user/resources/dcs/v1/restore.rst delete mode 100644 doc/source/user/resources/dcs/v1/statistic.rst delete mode 100644 doc/source/user/resources/deh/index.rst delete mode 100644 doc/source/user/resources/deh/v1/host.rst delete mode 100644 doc/source/user/resources/deh/v1/host_type.rst delete mode 100644 doc/source/user/resources/deh/v1/server.rst delete mode 100644 doc/source/user/resources/dms/index.rst delete mode 100644 doc/source/user/resources/dms/v1/group.rst delete mode 100644 doc/source/user/resources/dms/v1/group_message.rst delete mode 100644 doc/source/user/resources/dms/v1/message.rst delete mode 100644 doc/source/user/resources/dms/v1/queue.rst delete mode 100644 doc/source/user/resources/dms/v1/quota.rst delete mode 100644 doc/source/user/resources/dns/index.rst delete mode 100644 doc/source/user/resources/dns/v2/floating_ip.rst delete mode 100644 doc/source/user/resources/dns/v2/nameserver.rst delete mode 100644 doc/source/user/resources/dns/v2/recordset.rst delete mode 100644 doc/source/user/resources/dns/v2/zone.rst delete mode 100644 doc/source/user/resources/kms/index.rst delete mode 100644 doc/source/user/resources/kms/v1/data_key.rst delete mode 100644 doc/source/user/resources/kms/v1/key.rst delete mode 100644 doc/source/user/resources/obs/index.rst delete mode 100644 doc/source/user/resources/obs/v1/container.rst delete mode 100644 doc/source/user/resources/obs/v1/obj.rst delete mode 100644 doc/source/user/resources/rds/index.rst delete mode 100644 doc/source/user/resources/rds/v1/configuration.rst delete mode 100644 doc/source/user/resources/rds/v1/flavor.rst delete mode 100644 doc/source/user/resources/rds/v1/instance.rst delete mode 100644 doc/source/user/resources/rds/v3/configuration.rst delete mode 100644 doc/source/user/resources/rds/v3/flavor.rst delete mode 100644 doc/source/user/resources/rds/v3/instance.rst delete mode 100644 doc/source/user/transition_from_profile.rst delete mode 100644 doc/source/user/utils.rst create mode 100644 examples/anti_ddos/get_floating_ip_policies.py create mode 100644 examples/anti_ddos/get_floating_ip_status.py create mode 100644 examples/anti_ddos/list_configs.py create mode 100644 examples/anti_ddos/list_floating_ip_events.py create mode 100644 examples/anti_ddos/list_floating_ip_stat_day.py create mode 100644 examples/anti_ddos/list_floating_ip_stat_week.py create mode 100644 examples/anti_ddos/list_floating_ips.py create mode 100644 examples/anti_ddos/protect_floating_ip.py create mode 100644 examples/anti_ddos/unprotect_floating_ip.py create mode 100644 examples/anti_ddos/update_floating_ip_policies.py create mode 100644 examples/auto_scaling/batch_delete_config.py create mode 100644 examples/auto_scaling/batch_instance_action.py create mode 100644 examples/auto_scaling/create_config.py create mode 100644 examples/auto_scaling/create_group.py create mode 100644 examples/auto_scaling/delete_config.py create mode 100644 examples/auto_scaling/delete_group.py create mode 100644 examples/auto_scaling/delete_policy.py create mode 100644 examples/auto_scaling/execute_policy.py create mode 100644 examples/auto_scaling/find_config.py create mode 100644 examples/auto_scaling/find_group.py create mode 100644 examples/auto_scaling/find_policy.py create mode 100644 examples/auto_scaling/get_config.py create mode 100644 examples/auto_scaling/get_group.py create mode 100644 examples/auto_scaling/get_policy.py create mode 100644 examples/auto_scaling/init.py create mode 100644 examples/auto_scaling/list_activities.py create mode 100644 examples/auto_scaling/list_configs.py create mode 100644 examples/auto_scaling/list_groups.py create mode 100644 examples/auto_scaling/list_instances.py create mode 100644 examples/auto_scaling/list_policies.py create mode 100644 examples/auto_scaling/list_quotas.py create mode 100644 examples/auto_scaling/pause_group.py create mode 100644 examples/auto_scaling/pause_policy.py create mode 100644 examples/auto_scaling/remove_instance.py create mode 100644 examples/auto_scaling/resume_group.py create mode 100644 examples/auto_scaling/resume_policy.py create mode 100644 examples/auto_scaling/update_policy.py create mode 100644 examples/cce/create_cluster.py create mode 100644 examples/cce/create_cluster_node.py create mode 100644 examples/cce/delete_cluster.py create mode 100644 examples/cce/delete_cluster_node.py create mode 100644 examples/cce/find_cluster.py create mode 100644 examples/cce/find_cluster_node.py create mode 100644 examples/cce/get_cluster.py create mode 100644 examples/cce/get_cluster_node.py create mode 100644 examples/cce/get_job.py create mode 100644 examples/cce/list_cluster_nodes.py create mode 100644 examples/cce/list_clusters.py create mode 100644 examples/cce/wait_for_job.py delete mode 100644 open_points diff --git a/.gitignore b/.gitignore index 919ef00d7..cad5c2103 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ .stestr/ .testrepository .tox -AUTHORS build ChangeLog dist diff --git a/.travis.yml b/.travis.yml index ecd4b9dcf..0cfad8233 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,8 +3,6 @@ language: python cache: pip matrix: include: - - python: 2.7 - env: TOXENV=py27 - python: 3.6 env: TOXENV=py36 - python: 3.6 diff --git a/.zuul.yaml b/.zuul.yaml index 3f5be5f93..cef56795b 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -3,7 +3,7 @@ jobs: - tox-py37 - tox-pep8 - # - tox-docs + - tox-docs - tox-functional gate: jobs: diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..139c134f8 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,7 @@ +Artem Goncharov +György Hodi +Kristian Kucerak +Nils Magnus +Tino Schreiber +Vineet Pruthi <48789821+vineet-pruthi@users.noreply.github.com> +Zsolt Nagy diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 57b6bf563..84fe3a5dd 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -1,45 +1,30 @@ -.. _contributing: +Contributing to OTC Extensions +============================== -=================================== -Contributing to python-openstacksdk -=================================== +OTC Extension are developed as a community effort initiated by +T-Systems International GmbH for the Open Telekom Cloud under an Open +Source license. All code is licensed under the Apache 2.0 license. -If you're interested in contributing to the python-openstacksdk project, -the following will help get you started. +We are happily accepting pull requests. Please reach out to the +project to sort out legal code contribution. If you're interested in +contributing to the project, have a look in the `contributors +section`_ of our documentation. -Contributor License Agreement ------------------------------ +We follow the recommendation of the `OpenStack's workflow`_ for open +source contributions and value the four opens. -.. index:: - single: license; agreement - -In order to contribute to the python-openstacksdk project, you need to have -signed OpenStack's contributor's agreement. - -Please read `DeveloperWorkflow`_ before sending your first patch for review. -Pull requests submitted through GitHub will be ignored. - -.. seealso:: - - * http://wiki.openstack.org/HowToContribute - * http://wiki.openstack.org/CLA - -.. _DeveloperWorkflow: http://docs.openstack.org/infra/manual/developers.html#development-workflow Project Hosting Details -------------------------- +----------------------- Project Documentation - http://docs.openstack.org/sdks/python/openstacksdk/ + https://python-otcextensions.readthedocs.io/ Bug tracker - https://bugs.launchpad.net/python-openstacksdk - -Mailing list (prefix subjects with ``[sdk]`` for faster responses) - http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-dev + https://github.com/opentelekomcloud/python-otcextensions/issues Code Hosting - https://git.openstack.org/cgit/openstack/python-openstacksdk + https://github.com/opentelekomcloud/python-otcextensions/ -Code Review - https://review.openstack.org/#/q/status:open+project:openstack/python-openstacksdk,n,z +.. _contributors section: https://python-otcextensions.readthedocs.io/en/latest/contributor/ +.. _OpenStack's workflow: http://docs.openstack.org/infra/manual/developers.html#development-workflow diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index 61803e9a4..000000000 --- a/HACKING.rst +++ /dev/null @@ -1,108 +0,0 @@ -OpenStack Style Commandments -============================ - -- Step 1: Read the OpenStack Style Commandments - https://docs.openstack.org/hacking/latest/ -- Step 2: Read on - -General -------- -- thou shalt not violate causality in our time cone, or else - -Docstrings ----------- - -Docstrings should ONLY use triple-double-quotes (``"""``) - -Single-line docstrings should NEVER have extraneous whitespace -between enclosing triple-double-quotes. - -Deviation! Sentence fragments do not have punctuation. Specifically in the -command classes the one line docstring is also the help string for that -command and those do not have periods. - - """A one line docstring looks like this""" - -Calling Methods ---------------- - -Deviation! When breaking up method calls due to the 79 char line length limit, -use the alternate 4 space indent. With the first argument on the succeeding -line all arguments will then be vertically aligned. Use the same convention -used with other data structure literals and terminate the method call with -the last argument line ending with a comma and the closing paren on its own -line indented to the starting line level. - - unnecessarily_long_function_name( - 'string one', - 'string two', - kwarg1=constants.ACTIVE, - kwarg2=['a', 'b', 'c'], - ) - -Text encoding -------------- - -Note: this section clearly has not been implemented in this project yet, it is -the intention to do so. - -All text within python code should be of type 'unicode'. - - WRONG: - - >>> s = 'foo' - >>> s - 'foo' - >>> type(s) - - - RIGHT: - - >>> u = u'foo' - >>> u - u'foo' - >>> type(u) - - -Transitions between internal unicode and external strings should always -be immediately and explicitly encoded or decoded. - -All external text that is not explicitly encoded (database storage, -commandline arguments, etc.) should be presumed to be encoded as utf-8. - - WRONG: - - infile = open('testfile', 'r') - mystring = infile.readline() - myreturnstring = do_some_magic_with(mystring) - outfile.write(myreturnstring) - - RIGHT: - - infile = open('testfile', 'r') - mystring = infile.readline() - mytext = mystring.decode('utf-8') - returntext = do_some_magic_with(mytext) - returnstring = returntext.encode('utf-8') - outfile.write(returnstring) - -Python 3.x Compatibility ------------------------- - -OpenStackClient strives to be Python 3.3 compatible. Common guidelines: - -* Convert print statements to functions: print statements should be converted - to an appropriate log or other output mechanism. -* Use six where applicable: x.iteritems is converted to six.iteritems(x) - for example. - -Running Tests -------------- - -Note: Oh boy, are we behind on writing tests. But they are coming! - -The testing system is based on a combination of tox and testr. If you just -want to run the whole suite, run `tox` and all will be fine. However, if -you'd like to dig in a bit more, you might want to learn some things about -testr itself. A basic walkthrough for OpenStack can be found at -http://wiki.openstack.org/testr diff --git a/README-save b/README-save new file mode 100644 index 000000000..6ba91b7f5 --- /dev/null +++ b/README-save @@ -0,0 +1,137 @@ +OTC Extensions +============== + +.. image:: https://travis-ci.org/OpenTelekomCloud/python-otcextensions.svg?branch=master + :target: https://travis-ci.org/OpenTelekomCloud/python-otcextensions + +.. image:: https://readthedocs.org/projects/python-otcextensions/badge/?version=latest + :target: http://python-otcextensions.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status + +OTCExtensions is a project to bring OTC extensions into the native OpenStack +toolstack. Covered are currently following items: + +* `python-openstacksdk` +* `python-openstackclient` + +The primary goal is to provide a possibility to use native OpenStack SDK and +CLI with the OTC additional services + +Getting Started +=============== + +The very first step to get started is to install otcextensions into your +system. For this please follow installation instructions_ + +.. _instructions: http://python-otcextensions.readthedocs.io/en/latest/install/index.html + +Next step would be logically configuration + +Configuration +============= + +openstack.config +================ + +The recommended way, since it is the most efficient way to configure both SDK +and the CLI in one place + +``openstack.config`` will find cloud configuration for as few as 1 clouds and +as many as you want to put in a config file. It will read environment variables +and config files, and it also contains some vendor specific default values so +that you don't have to know extra info to use OpenStack + +* If you have a config file, you will get the clouds listed in it +* If you have environment variables, you will get a cloud named `envvars` +* If you have neither, you will get a cloud named `defaults` with base defaults + +Sometimes an example is nice. + +Create a ``clouds.yaml`` file: + +.. code-block:: yaml + + clouds: + otc: + auth: + username: 'USER_NAME' + password: 'PASS' + project_name: 'eu-de' + auth_url: 'https://iam.eu-de.otc.t-systems.com:443/v3' + user_domain_name: 'OTC00000000001000000xxx' + interface: 'public' + identity_api_version: 3 # !Important + ak: 'AK_VALUE' # AK/SK pair for access to OBS + sk: 'SK_VALUE' + +Please note: ``openstack.config`` will look for a file called ``clouds.yaml`` +in the following locations: + +* Current Directory +* ``~/.config/openstack`` +* ``/etc/openstack`` + +AK/SK values required for access to some services (i.e. OBS) can be either +configured as shown above in the clouds.yaml/secure.yaml, or they can be +automatically retrieved from the S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY. +Values from the clouds.yaml/secure.yaml take precedence over the ones from +environment. + +With this configuration you can start using openstackCLI simply ``openstack +--os-cloud otc`` + +More information at https://developer.openstack.org/sdks/python/openstacksdk/users/config + +Old style way +============= + +The CLI can be configured via environment variables and command-line options as +listed in +https://docs.openstack.org/python-openstackclient/latest/cli/authentication.html +or https://developer.openstack.org/sdks/python/openstacksdk/users/config. + +Authentication using username/password is often used:: + + export OS_AUTH_URL= + export OS_IDENTITY_API_VERSION=3 + export OS_PROJECT_NAME= + export OS_PROJECT_DOMAIN_NAME= + export OS_USERNAME= + export OS_USER_DOMAIN_NAME= + export OS_PASSWORD= # (optional) + export S3_ACCESS_KEY_ID= + export S3_SECRET_ACCESS_KEY= + +The corresponding command-line options look very similar:: + + --os-auth-url + --os-identity-api-version 3 + --os-project-name + --os-project-domain-name + --os-username + --os-user-domain-name + [--os-password ] + +If a password is not provided above (in plaintext), you will be interactively +prompted to provide one securely. + +Authentication may also be performed using an already-acquired token +and a URL pointing directly to the service API that presumably was acquired +from the Service Catalog:: + + export OS_TOKEN= + export OS_URL= + +The corresponding command-line options look very similar:: + + --os-token + --os-url + +In addition to that a regular `clouds.yaml` configuration file can be used + + +Links +===== + +* `Issue Tracker `_ +* `Documentation `_ diff --git a/README.rst b/README.rst index 5310c6980..018f6297e 100644 --- a/README.rst +++ b/README.rst @@ -1,5 +1,5 @@ -OpenTelekomCloud extensions -=========================== +OTC Extensions +============== .. image:: https://travis-ci.org/OpenTelekomCloud/python-otcextensions.svg?branch=master :target: https://travis-ci.org/OpenTelekomCloud/python-otcextensions @@ -8,89 +8,76 @@ OpenTelekomCloud extensions :target: http://python-otcextensions.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status -OTCExtensions is a project to bring OTC extensions into the native OpenStack -toolstack. Covered are currently following items: +The OTC Extensions augment the OpenStack SDK of features and services +provided by the Open Telekom Cloud. If installed as a Python package, +they add several extra commands to the OpenStack Client CLI. Therefore +the project interacts closely with the * `python-openstacksdk` * `python-openstackclient` -The primary goal is to provide a possibility to use native OpenStack SDK and -CLI with the OTC additional services +packages. -Getting Started -=============== +Documentation +------------- -The very first step to get started is to install otcextensions into your -system. For this please follow installation instructions_ +* `Documentation ` -.. _instructions: http://python-otcextensions.readthedocs.io/en/latest/install/index.html +Installation +------------ -Next step would be logically configuration +The OTC Extensions are hosted as the package `otcextensions` on PyPI +and can be installed by pip as -Configuration -============= - -openstack.config -================ - -The recommended way, since it is the most efficient way to configure both SDK -and the CLI in one place - -``openstack.config`` will find cloud configuration for as few as 1 clouds and -as many as you want to put in a config file. It will read environment variables -and config files, and it also contains some vendor specific default values so -that you don't have to know extra info to use OpenStack - -* If you have a config file, you will get the clouds listed in it -* If you have environment variables, you will get a cloud named `envvars` -* If you have neither, you will get a cloud named `defaults` with base defaults - -Sometimes an example is nice. - -Create a ``clouds.yaml`` file: - -.. code-block:: yaml - - clouds: - otc: - auth: - username: 'USER_NAME' - password: 'PASS' - project_name: 'eu-de' - auth_url: 'https://iam.eu-de.otc.t-systems.com:443/v3' - user_domain_name: 'OTC00000000001000000xxx' - interface: 'public' - identity_api_version: 3 # !Important - ak: 'AK_VALUE' # AK/SK pair for access to OBS - sk: 'SK_VALUE' - -Please note: ``openstack.config`` will look for a file called ``clouds.yaml`` -in the following locations: - -* Current Directory -* ``~/.config/openstack`` -* ``/etc/openstack`` - -AK/SK values required for access to some services (i.e. OBS) can be either -configured as shown above in the clouds.yaml/secure.yaml, or they can be -automatically retrieved from the S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY. -Values from the clouds.yaml/secure.yaml take precedence over the ones from -environment. - -With this configuration you can start using openstackCLI simply ``openstack ---os-cloud otc`` +.. code-block: console + $ pip install otcextensions -More information at https://developer.openstack.org/sdks/python/openstacksdk/users/config +There are several options +to do that including but not limited to pip userland installation, system wide +installation as well as installation from operating system packets or directly +from source. Refer to the installation instructions_ in the projects +documentation. -Old style way -============= -The CLI can be configured via environment variables and command-line options as -listed in -https://docs.openstack.org/python-openstackclient/latest/cli/authentication.html -or https://developer.openstack.org/sdks/python/openstacksdk/users/config. - -Authentication using username/password is often used:: +Configuration +------------- + +Acessing the Open Telekom Cloud APIs requires authentication and +authorization. For both there are several options available: + +* **Configuration files** (recommended): A file called `clouds.yaml` + holds all necessary configuration parameters. The file can be placed + either in the local directory, below the user home directory in + `.config/openstack` or in the system-wide directory + `/etc/openstack`. You may use a second file `secure.yaml` in the + same directories to extra protect clear-text password + credentials. For more details see the section `configuration`_ in + the official documentation. + + Minimal sample ``clouds.yaml`` file: + + .. code-block:: yaml + + clouds: + otc: + profile: otc + auth: + username: "*username*" + password: "*password*" + project_name: "eu-de" + auth_url: "https://iam.eu-de.otc.t-systems.com:443/v3" + user_domain_name: "*OTC00000000001000000xxx*" + interface: "public" + identity_api_version: 3 + ak: "*40 digit access key*" + sk: "*20 digit secure key*" + + With this configuration you can start using the CLI with ``openstack + --os-cloud otc *command*`` or by ``export OS_CLOUD=otc; openstack + *command*``. + +* **Environment variables:** Authentication using username/password is often + used: export OS_AUTH_URL= export OS_IDENTITY_API_VERSION=3 @@ -102,7 +89,9 @@ Authentication using username/password is often used:: export S3_ACCESS_KEY_ID= export S3_SECRET_ACCESS_KEY= -The corresponding command-line options look very similar:: + +* **Command-Line Options:** The corresponding command-line options look + very similar:: --os-auth-url --os-identity-api-version 3 @@ -112,12 +101,12 @@ The corresponding command-line options look very similar:: --os-user-domain-name [--os-password ] -If a password is not provided above (in plaintext), you will be interactively -prompted to provide one securely. + If a password is not provided above (in plaintext), you will be + interactively prompted to provide one securely. -Authentication may also be performed using an already-acquired token -and a URL pointing directly to the service API that presumably was acquired -from the Service Catalog:: +* **Existing Token:** Authentication may also be performed using an + already-acquired token and a URL pointing directly to the service + API that presumably was acquired from the Service Catalog:: export OS_TOKEN= export OS_URL= @@ -129,9 +118,26 @@ The corresponding command-line options look very similar:: In addition to that a regular `clouds.yaml` configuration file can be used +More information is available at +https://docs.openstack.org/python-openstackclient/latest/cli/authentication.html +or +https://developer.openstack.org/sdks/python/openstacksdk/users/config + -Links -===== +Writing Own Code +---------------- + +XXX Example XXXX + +Contributing +------------ + +See CONTRIBUTING.rst + +Further Links +------------- * `Issue Tracker `_ -* `Documentation `_ + +.. _instructions: http://python-otcextensions.readthedocs.io/en/latest/install/ + diff --git a/doc/source/glossary.rst b/doc/source/appendices/glossary.rst similarity index 74% rename from doc/source/glossary.rst rename to doc/source/appendices/glossary.rst index 3bdbde41d..2bf09d6ee 100644 --- a/doc/source/glossary.rst +++ b/doc/source/appendices/glossary.rst @@ -102,3 +102,33 @@ Glossary volume OpenStack Volume (Cinder). Also the attribute name of the virtual disks managed by the OpenStack Volume service. + + +Naming conventions +------------------ + +For consistency, a few naming conventions are defined for the name of +this project and adjacent identifiers. Let's start with the project +itself: + +`OTC Extensions`_ in exactly this spelling is the **name** of the +project. This term is used when the documentation references the +project as such. The three letters ``OTC`` are all uppercase. There is +a space and not dash between the two words. The second word is part of +the name and is thus capitalized. + +`otcextensions`_ is the name of the Python package hosted at +PyPI. Complying to the naming conventions of PyPI, the package name is +concatenated and consists only of lowercase letters. + +`python-otcextensions`_ is the name of the GitHub project where the +source code is hosted. It is the same name as the Python package, but +for compliance with many other OpenStack repositories, it is prepended +with ``python-`` as at least in theory there could also be a +``golang-otcextensions`` or even ``haskell-otcextensions`` project. + +.. _OTC Extensions: https://python-otcextensions.readthedocs.io/ + +.. _otcextensions: https://pypi.org/project/otcextensions/ + +.. _python-otcextensions: https://github.com/OpenTelekomCloud/python-otcextensions diff --git a/doc/source/appendices/history.rst b/doc/source/appendices/history.rst new file mode 100644 index 000000000..ba30948c1 --- /dev/null +++ b/doc/source/appendices/history.rst @@ -0,0 +1,75 @@ +History of the OTC Extensions +============================= + +This project may seem complicated as it has some dependencies and +obscure naming conventions. Sometimes understanding the OTC +Extensions's heritage helps to mitigate those pains. + +OpenStack itself started as a set of services, and developers very +early decided that having a (more or less) decoupled set of services +would be the best choice for such a huge, distributed +system. Distributed services need to talk to each other. That's why +each service provides an interface. As OpenStack uses RESTful +webservices as a communication fabric, this interface is called and +API. Most of the (quantitive) implementation effort of OpenStack is to +implement the services behind those API endpoints. + +However, there are also clients using and consuming those +services. Thus they need to talk to the APIs. Once a service was +implemented its developers tried to use the service. While using +generic HTTP tools like curl or wget might be a workaround for first +tests, dealing with authentication schemes, token handling, encoding, +encapsulation, and header and body handling made it not really +convenient to work with them. + +Now specific tools emerged implementing the client side of a +service. There have been novatools for the compute service, +glancetools for the image service, neutrontool for the network, and +many more. + +Once developers discovered that they needed to re-implement a lot of +duplicating code for each new service again, they started to factor +out common code pieces. That actually took place in several places +simulteanously: The **shade** library abstracted handling of +resources, that different services implemented with a similar +way. Many resource, for example, implement the so-called CRUD +operations for creating, reading, updating, and deleting them. + +A second major field for client application was authentication and +autorization against the cloud. While in the beginning environment +variables appeared to come in handy, having all runtime configuration +options in a single file simplified the overall management of your +cloud setup. This idea was introduced by **os-client-config**. It +centralized the environment variable handling, but even more +important, it introduced the **clouds.yaml** configuration file. + +In a major refactoring session, in 201X the developers combined both +libraries into a single one called **OpenStack SDK**. That in turn +would become the building block of one unified CLI tool that is +capable of adressing all OpenStack services from a single +command. This is the OpenStack Client. It has several subcommands that +work in a similar manner and share a common syntax. + +In a perfect world now all would have been fine. In reality, however, +not all clouds are the same. Some offer additional, vendor specific +services (or, which is worse) implement a subset of services +differently. To reflect these circumstances, 2018, Artem Goncharov +implemented a plugin mechanism into both OpenStack SDK and into the +OpenStack client. This way the SDK and CLI can be extended and +maintained without touching the generic code. One instance making use +of this plugin mechanism are the OTC Extensions, this very project. + +Wann gab es die ersten Clients für OpenStack? + +Wer hat wann erstmals die Notwendigkeit gesehen, etwas zu +vereinheitlichen? Wann? Haben wir da irgendwo einen Link drauf? + +Wer hat Shade begonnen und wann? + +Wer hat os-client-config beginnen und wann? + +Wann/warum wurden die Projekte aufgegeben? + +Wer maintaint was? + +https://docs.openstack.org/openstacksdk/latest/contributor/history.html diff --git a/doc/source/appendices/index.rst b/doc/source/appendices/index.rst new file mode 100644 index 000000000..c0e9836e7 --- /dev/null +++ b/doc/source/appendices/index.rst @@ -0,0 +1,10 @@ +Appendices +========== + +.. toctree:: + :maxdepth: 1 + + releasenotes + history + issues + glossary diff --git a/doc/source/appendices/issues.rst b/doc/source/appendices/issues.rst new file mode 100644 index 000000000..98c6b99c6 --- /dev/null +++ b/doc/source/appendices/issues.rst @@ -0,0 +1,200 @@ +Known Issues +============ + +Since providing services and writing client libraries is decoupled, +sometimes issues arise due to errors in the client or the server side, +or due to a service disruption or degration. This page collects +potential issues. They have been found during digging into the API. + +General +------- + +* Native service version discovery request to + https://as.eu-de.otc.t-systems.com/autoscaling-api/ caused + timeout. AS service is temporarily disabled +* Inconsistent naming between services (AS:create_time, + KMS:creation_date, CCE:createAt) +* Inconsistent error message structure between services (i.e. KMS vs + RDS). This prohibits code generalization +* No custom service supports proper version discovery. Leads to error + messages in the OSC tool and execution delays +* LB: while Neutron LBaaS is "strongly" considered as deprecated and + no bindings are present in Ansible/OSC it will likely not be + possible/challenge to upstream this support. +* EVS: volume type list --long returns changing results +* Subnet (in some APIs) is most likely net_id +* Without service discovery and multiple versions it is not possible + to get the proper service version in SDK. It falls back to first + entry in the VersionFilter +* Tags require different format ("key=value" vs "key*value") + +KMS +--- + +* service version discovery is broken. On + https://kms.eu-de.otc.t-systems.com/ it returns {"versions": + [{"status": "CURRENT", "id": "v1.0", "links": [{"href": + "https://rts.eu-de.otc.t-systems.com/v1/", "rel": "self"}]}]} In the + keystoneauth1 it results to + get_endpoint=https://kms.eu-de.otc.t-systems.com/v1 (instead of + V1.0). Detailed investigation is expensive, therefore aborted +* does not follow REST, everything is POST with different URLs and not + even json['action'] +* is conceptually far away from Barbican +* API Doc: This API allows you to create a plaintext-free DEK, that + is, the returned result of this API includes `only the plaintext` of + the DEK. +* purpose of KMS is not precise. Attributes change their names/meaning + depending on call +* encryption_context is described to be string, in reality dict is + expected +* max_length is always expected to be exactly max. Make no sense as a + param +* list CMK filter by key_state not working as documented +* format of the timestamp is unknown +* no way to get response in English + +CCE +--- + +* required header application/type also for GET +* cluster UUID is hidden in a inline metadata structure, making it + hard to address it without dirty hacks. Apis are jumping through + this structure in anti-rest pattern +* attribute naming: metadata.uuid vs metadata.uid +* undocumented properties of the cluster.spec field (i.e. `cidr`) +* far away from Magnum +* Cluster has both VPC and VPC_ID, in GET VPC is name, in POST it + should be ID +* Subnet is most likely net_id +* In AS sys disk has type "SYS", in CCE - "root" +* Node delete possible only by name, and not id +* service catalog configuration is broken v1 vs v2(v3) with no + corrupted discovery and new service type + +DCS +--- + +* In OS DCS is part of Trove. The API is same. In the DCS API is + similar to RDS, but not easy mappable +* Since Redis 3.0.7 (only available in DCS) lots of critical issues + (incl. security and possible data corruption), online memory defrag, + less mem usage were fixed + +MRS +--- + +* Inconsistent naming between services ( data_processing-mrs ) + +OBS +--- + +* Has storage class on Bucket level, but in AWS and all corresponding + tools (also s3cmd, s4cmd, Boto) it is on the Object level + +DNS (Designate) +--------------- + +* Nothing supports private zone (ansible, heat, ~terraform, + SDK/CLI). Very hard to cover that everywhere +* Zone transfer, slave zone are not present. Modern Designateclient is + not getting clear with response of designate +* API v2 is not implemented + +VBS +--- + +* Uses offset as a pagination, instead of marker (in docs, in reality + marker is supported) +* Backup creation takes too long. 1Gb empty volume takes >4 + minutes. Functional tests are not reasonable with that. +* Create policy requires frequency to be set +* Shift implemented stuff to osc + +CSS +--- + +* upon creation httpsEnable is str, upon read - bool +* flavors is not OpenStack compatible + +HEAT +---- + +* very old level, blocking many OpenSource projects, including + i.e. ansible-openshift, RedhatDNS. +* (to be doublechecked) template version check is likely not done, + since features of later templates with older version header are + passing validation (in the ranges of supported versions) +* validate return ok, doesn't mean create will pass (validation errors + i.e. template version doesn't match, condition on a resource level + was also added on newton) +* not all CLI calls return result +* Not possible to rely on mountpoint of the + OS::Cinder::VolumeAttachment - it's ignored +* usage of Server with block_device_mapping_v2, devicename="sdX" and > + 1 device fails. Port is not released leaving system in inconsistent + state (if router interface is deleted can be cleaned only manually) +* OS::Neutron::LBaaS::HealthMonitor does not support type HTTPS, but + GUI allows it +* update stack with existing template is missing + +Shade/Ansible +------------- + +* enabling SNAT through Ansible not possible, since upstream expects + default as true and sends only false if set + (shade:_build_external_gateway_info) +* only able to pass SYS volume size if boot_from_volume=True + (default=false) +* on a play retry port in the subnet changes if exists (change IP) and + corrupts connection +* No support for load balancer +* Ansible (Heat): https://github.com/ansible/ansible/issues/30786 - + small fix to see the failure message if stack create/update fails +* Private: yes helps to get public_v4 filled, but it hinders create + request with auto_ip:true +* add router interface + +VPC +--- + +* VPC uses network wrapped subnets. Simple net with multiple subnets + is not properly visible in OTC (in VPCs list subnet count includes + all subnets, but in VPC show subnets are missing) + +TMS +--- + +* How to assign tag to resource from API? + +BMS +--- + +* it is not Ironic, but ECS + +Network +------- + +* Security Group rule "Any" (value=0) is not working as designed. OSC + uses defaults, use of 0 results in really 0 as a value. Effect is + unknown yet + +DeH +--- + +* Tag support is not OS compatible + +OpenStack SDK +------------- + +* LBaaS: pool.healthmonitor_id according to ref api (and in OTC), but + in the SDK it is health_monitor_ids (list) (reported under + https://storyboard.openstack.org/#!/story/2001872). Some other + attributes missing. pool_member operating_status missing +* LBaaS HM: max_retries_down missing (optional and not present in OTC) + +DOC +--- + +* at least on example of ULB LIST allows filtering, but it is not + documented diff --git a/doc/source/appendices/releasenotes.rst b/doc/source/appendices/releasenotes.rst new file mode 100644 index 000000000..d9adcb965 --- /dev/null +++ b/doc/source/appendices/releasenotes.rst @@ -0,0 +1,4 @@ +Release Notes +============= + +Release notes for are currently not implemented for OTC Extensions. diff --git a/doc/source/cli/anti_ddos.rst b/doc/source/cli/anti_ddos.rst index 308ba8123..de663e60c 100644 --- a/doc/source/cli/anti_ddos.rst +++ b/doc/source/cli/anti_ddos.rst @@ -1,6 +1,5 @@ -================================================= -Anti DDoS Service (Anti_DDoS) command-line client -================================================= +Anti DDoS Service (Anti_DDoS) +============================= The Anti_DDoS client is the command-line interface (CLI) for the Anti DDoS Service (Anti_DDoS) API and its extensions. diff --git a/doc/source/cli/auto_scaling.rst b/doc/source/cli/auto_scaling.rst index e67398d01..1c75844ab 100644 --- a/doc/source/cli/auto_scaling.rst +++ b/doc/source/cli/auto_scaling.rst @@ -1,6 +1,5 @@ -============================================ -AutoScaling service (AS) command-line client -============================================ +AutoScaling service (AS) +======================== The AS client is the command-line interface (CLI) for the AutoScaling service (AS) API and its extensions. diff --git a/doc/source/cli/cce_v2.rst b/doc/source/cli/cce_v2.rst index b0ab6a044..17e17c4cc 100644 --- a/doc/source/cli/cce_v2.rst +++ b/doc/source/cli/cce_v2.rst @@ -1,6 +1,5 @@ -================================================ -Cloud Container Engine (CCE) command-line client -================================================ +Cloud Container Engine (CCE) +============================ The CCE client is the command-line interface (CLI) for the Cloud Container Engine (CCE) API and its extensions for the CCE v2. diff --git a/doc/source/cli/cts.rst b/doc/source/cli/cts.rst index 7a1132218..fa5bcb3c9 100644 --- a/doc/source/cli/cts.rst +++ b/doc/source/cli/cts.rst @@ -1,6 +1,5 @@ -============================================= -Cloud Trace Service (CTS) command-line client -============================================= +Cloud Trace Service (CTS) +========================= The CTS client is the command-line interface (CLI) for the Cloud Trace Service (CTS) API and its extensions. diff --git a/doc/source/cli/dcs.rst b/doc/source/cli/dcs.rst index 516e78ad2..6c9f3edd5 100644 --- a/doc/source/cli/dcs.rst +++ b/doc/source/cli/dcs.rst @@ -1,6 +1,5 @@ -=================================================== -Distributed Cache Service (DCS) command-line client -=================================================== +Distributed Cache Service (DCS) +=============================== The DCS client is the command-line interface (CLI) for the Distributed Cache Service (DMS) API and its extensions. diff --git a/doc/source/cli/deh.rst b/doc/source/cli/deh.rst index a19e5b3b1..5975b41f4 100644 --- a/doc/source/cli/deh.rst +++ b/doc/source/cli/deh.rst @@ -1,6 +1,5 @@ -================================================ -Dedicated Host Service (DeH) command-line client -================================================ +Dedicated Host Service (DeH) +============================ The DeH client is the command-line interface (CLI) for the Dedicated Host Service (DeH) API and its extensions. diff --git a/doc/source/cli/dms.rst b/doc/source/cli/dms.rst index f51d36712..ce3370d93 100644 --- a/doc/source/cli/dms.rst +++ b/doc/source/cli/dms.rst @@ -1,6 +1,5 @@ -===================================================== -Distributed Message Service (DMS) command-line client -===================================================== +Distributed Message Service (DMS) +================================= The DMS client is the command-line interface (CLI) for the Distributed Message Service (DMS) API and its extensions. diff --git a/doc/source/cli/dns.rst b/doc/source/cli/dns.rst index b2e58c38f..e8db53d8d 100644 --- a/doc/source/cli/dns.rst +++ b/doc/source/cli/dns.rst @@ -1,6 +1,5 @@ -============================================= -Domain Name Service (DNS) command-line client -============================================= +Domain Name Service (DNS) +========================= The DNS client is the command-line interface (CLI) for the Domain Name Service (DNS) API and its extensions. diff --git a/doc/source/cli/index.rst b/doc/source/cli/index.rst index 524564ba6..c4d31c1f4 100644 --- a/doc/source/cli/index.rst +++ b/doc/source/cli/index.rst @@ -1,19 +1,38 @@ -OpenStackClient CLI Usage -========================= +OpenStack Client (CLI) +====================== + +The OpenStack Client is a self-contained OpenStack project providing a +command line interface to the most important cloud functions. For most +of the API calls an equivalent CLI command is available under a shared +command invoked as ``openstack``. An example is ``openstack server +list``. For reference see the documentation of the OpenStack Client +(OSC). + +The OTC Extensions don't re-implement the CLI tool, but augment it +automatically. If you have installed OTC Extensions and OpenStack +Client, the latter understands many extra commands: + +.. code-block:: bash + + openstack --help | grep -c otcextensions + 164 + +For details of the available commands, check the detailed CLI +documentation of these services: .. toctree:: - :maxdepth: 2 + :maxdepth: 1 - anti_ddos.rst - auto_scaling.rst - cce_v2.rst - cts.rst - dcs.rst - deh.rst - dms.rst - dns.rst - rds.rst - kms.rst - load_balancer.rst - obs.rst - volume_backup.rst + anti_ddos + auto_scaling + cce_v2 + cts + dcs + deh + dms + dns + kms + load_balancer + obs + rds + volume_backup diff --git a/doc/source/cli/kms.rst b/doc/source/cli/kms.rst index 758421746..094bb1be3 100644 --- a/doc/source/cli/kms.rst +++ b/doc/source/cli/kms.rst @@ -1,6 +1,5 @@ -================================================ -Key Management Service (KMS) command-line client -================================================ +Key Management Service (KMS) +============================ The KMS client is the command-line interface (CLI) for the Key Management service (KMS) API and its extensions. diff --git a/doc/source/cli/load_balancer.rst b/doc/source/cli/load_balancer.rst index 5f37c93db..623caca06 100644 --- a/doc/source/cli/load_balancer.rst +++ b/doc/source/cli/load_balancer.rst @@ -1,6 +1,5 @@ -======================================== -LoadBalancer service command-line client -======================================== +Elastic LoadBalancer (ELB) +========================== The load_balancer client is the command-line interface (CLI) for the native Neutron/Octavia LoadBalancer service (load_balancer) API. diff --git a/doc/source/cli/obs.rst b/doc/source/cli/obs.rst index fae6f4bf4..4a03069cc 100644 --- a/doc/source/cli/obs.rst +++ b/doc/source/cli/obs.rst @@ -1,6 +1,5 @@ -================================================ -Object Storage service (obs) command-line client -================================================ +Object Storage service (obs) +============================ The OBS client is the command-line interface (CLI) for the ObjectBlockStorage service (OBS) API and its extensions. diff --git a/doc/source/cli/rds.rst b/doc/source/cli/rds.rst index afa7e95cb..229a41495 100644 --- a/doc/source/cli/rds.rst +++ b/doc/source/cli/rds.rst @@ -1,6 +1,5 @@ -========================================== -Database service (rds) command-line client -========================================== +Database service (rds) +====================== The RDS client is the command-line interface (CLI) for the Database service (RDS) API and its extensions. diff --git a/doc/source/cli/volume_backup.rst b/doc/source/cli/volume_backup.rst index c3243c8bd..fb2ddd4e5 100644 --- a/doc/source/cli/volume_backup.rst +++ b/doc/source/cli/volume_backup.rst @@ -1,6 +1,5 @@ -=============================================== -Volume Backup Service (VBS) command-line client -=============================================== +Volume Backup Service (VBS) +=========================== The VBS client is the command-line interface (CLI) for the Volume Backup service (vbs) API and its extensions. diff --git a/doc/source/contributor/coding.rst b/doc/source/contributor/coding.rst index 14ab10ff8..2689807e5 100644 --- a/doc/source/contributor/coding.rst +++ b/doc/source/contributor/coding.rst @@ -1,114 +1,148 @@ -======================================== OpenStack SDK Developer Coding Standards ======================================== -In the beginning, there were no guidelines. And it was good. But that -didn't last long. As more and more people added more and more code, -we realized that we needed a set of coding standards to make sure that -the openstacksdk API at least *attempted* to display some form of consistency. +We follow the coding guidelines of +https://docs.openstack.org/hacking/latest/ of the OpenStack project in +general and the adopt the special rules of the OpenStack SDk in +specific where applicable unless otherwise stated. + +The SDK project which the OTC Extensions augment developed a set of +coding standards and guidelines were developed. Note that not all code +of OTC Extensions adheres to these standards just yet. All new code +has to adhere to these guidelines. -Thus, these coding standards/guidelines were developed. Note that not -all of openstacksdk adheres to these standards just yet. Some older code has -not been updated because we need to maintain backward compatibility. -Some of it just hasn't been changed yet. But be clear, all new code -*must* adhere to these guidelines. +Below are the patterns and principles that we expect developers to +follow. -Below are the patterns that we expect openstacksdk developers to follow. Release Notes -============= +------------- -openstacksdk uses `reno `_ for -managing its release notes. A new release note should be added to +OTC Extensions use `reno `_ +for managing its release notes. A new release note should be added to your contribution anytime you add new API calls, fix significant bugs, add new functionality or parameters to existing API calls, or make any -other significant changes to the code base that we should draw attention -to for the user base. +other significant changes to the code base that we should draw +attention to for the user base. + +It is not necessary to add release notes for minor fixes, such as +correction of documentation typos, minor code cleanup or +reorganization, or any other change that a user would not notice +through normal usage. -It is *not* necessary to add release notes for minor fixes, such as -correction of documentation typos, minor code cleanup or reorganization, -or any other change that a user would not notice through normal usage. Exceptions -========== +---------- -Exceptions should NEVER be wrapped and re-raised inside of a new exception. -This removes important debug information from the user. All of the exceptions -should be raised correctly the first time. +Exceptions should never be wrapped and re-raised inside of a new +exception. This removes important debug information from the +user. All of the exceptions should be raised correctly the first time. -openstack.cloud API Methods -=========================== + +API Methods of ``openstack.cloud`` +----------------------------------- The `openstack.cloud` layer has some specific rules: -- When an API call acts on a resource that has both a unique ID and a +* When an API call acts on a resource that has both a unique ID and a name, that API call should accept either identifier with a name_or_id parameter. -- All resources should adhere to the get/list/search interface that +* All resources should adhere to the get/list/search interface that control retrieval of those resources. E.g., `get_image()`, `list_images()`, `search_images()`. -- Resources should have `create_RESOURCE()`, `delete_RESOURCE()`, +* Resources should have `create_RESOURCE()`, `delete_RESOURCE()`, `update_RESOURCE()` API methods (as it makes sense). -- For those methods that should behave differently for omitted or None-valued +* For those methods that should behave differently for omitted or None-valued parameters, use the `_utils.valid_kwargs` decorator. Notably: all Neutron `update_*` functions. -- Deleting a resource should return True if the delete succeeded, or False +* Deleting a resource should return True if the delete succeeded, or False if the resource was not found. + Returned Resources ------------------ -Complex objects returned to the caller must be a `munch.Munch` type. The -`openstack._adapter.ShadeAdapter` class makes resources into `munch.Munch`. +Complex objects returned to the caller must be a `munch.Munch` +type. The `openstack._adapter.ShadeAdapter` class makes resources into +`munch.Munch`. -All objects should be normalized. It is shade's purpose in life to make -OpenStack consistent for end users, and this means not trusting the clouds -to return consistent objects. There should be a normalize function in -`openstack/cloud/_normalize.py` that is applied to objects before returning -them to the user. See :doc:`../user/model` for further details on object model -requirements. +All objects should be normalized. It is shade's purpose in life to +make OpenStack consistent for end users, and this means not trusting +the clouds to return consistent objects. There should be a normalize +function in `openstack/cloud/_normalize.py` that is applied to objects +before returning them to the user. -Fields should not be in the normalization contract if we cannot commit to -providing them to all users. +Fields should not be in the normalization contract if we cannot commit +to providing them to all users. -Fields should be renamed in normalization to be consistent with -the rest of `openstack.cloud`. For instance, nothing in `openstack.cloud` -exposes the legacy OpenStack concept of "tenant" to a user, but instead uses -"project" even if the cloud in question uses tenant. +Fields should be renamed in normalization to be consistent with the +rest of `openstack.cloud`. For instance, nothing in `openstack.cloud` +exposes the legacy OpenStack concept of "tenant" to a user, but +instead uses "project" even if the cloud in question uses tenant. -Nova vs. Neutron ----------------- - -- Recognize that not all cloud providers support Neutron, so never - assume it will be present. If a task can be handled by either - Neutron or Nova, code it to be handled by either. - -- For methods that accept either a Nova pool or Neutron network, the - parameter should just refer to the network, but documentation of it - should explain about the pool. See: `create_floating_ip()` and - `available_floating_ip()` methods. Tests -===== +----- -- New API methods *must* have unit tests! +* New API methods must have unit tests. -- New unit tests should only mock at the REST layer using `requests_mock`. +* New unit tests should only mock at the REST layer using `requests_mock`. Any mocking of openstacksdk itself should be considered legacy and to be avoided. Exceptions to this rule can be made when attempting to test the internals of a logical shim where the inputs and output of the method aren't actually impacted by remote content. -- Functional tests should be added, when possible. +* Functional tests should be added, when possible. -- In functional tests, always use unique names (for resources that have this +* In functional tests, always use unique names (for resources that have this attribute) and use it for clean up (see next point). -- In functional tests, always define cleanup functions to delete data added +* In functional tests, always define cleanup functions to delete data added by your test, should something go wrong. Data removal should be wrapped in a try except block and try to delete as many entries added by the test as possible. + + +Docstrings +---------- + +Docstrings should only use triple-double-quotes (``"""``). + +Single-line docstrings should never have extraneous whitespace +between enclosing triple-double-quotes. + +Sentence fragments do not have punctuation. Specifically in the +command classes the one line docstring is also the help string for +that command and those do not have periods. + + """A one line docstring looks like this""" + + +Calling Methods +--------------- + +When breaking up method calls due to the 79 char line length limit, +use the alternate four space indent. With the first argument on the +succeeding line all arguments will then be vertically aligned. Use the +same convention used with other data structure literals and terminate +the method call with the last argument line ending with a comma and +the closing paren on its own line indented to the starting line level. + +.. code-block: python + unnecessarily_long_function_name( + 'string one', + 'string two', + kwarg1=constants.ACTIVE, + kwarg2=['a', 'b', 'c'], + ) + + +Python 3 Compatibility +---------------------- + +The OTC Extensions are developed for Python 3. Compatibility for +Python 2.7 might be present, but would be so on accident. diff --git a/doc/source/contributor/contributing.rst b/doc/source/contributor/contributing.rst deleted file mode 100644 index b1cd2f37d..000000000 --- a/doc/source/contributor/contributing.rst +++ /dev/null @@ -1 +0,0 @@ -.. include:: ../../../CONTRIBUTING.rst diff --git a/doc/source/contributor/index.rst b/doc/source/contributor/index.rst index 9c48e2af3..f66736122 100644 --- a/doc/source/contributor/index.rst +++ b/doc/source/contributor/index.rst @@ -1,92 +1,86 @@ Contributing to the OTC Extensions ================================== -This section of documentation pertains to those who wish to contribute to the -development of this project. If you're looking for documentation on how to use -the SDK to build applications, please see the `user <../user>`_ section. +This section of the documentation is intended for those who want to +contribute to the development of the OTC Extensions. If you're looking +for documentation on how to use the SDK to build applications, please +see the `SDK <../sdk>`_ section. -Contribution Mechanics ----------------------- +Setting up an Development Environment +------------------------------------- + +The first step towards contributing code and documentation is to setup +your development environment. The project implements a pretty standard +setup. It is fully documented in the :doc:`setup ` section. .. toctree:: :maxdepth: 2 - contributing + setup -Contacting the Developers -------------------------- -GitHub -****** +Project Layout +-------------- -Currently no official communication other than GitHub is available +The project contains a top-level ``otcextensions`` package, which houses +several modules that form the foundation upon which each service's API is +built on. Under the ``otcextensions`` package are packages for the +``sdk``, the ``osclient`` (OpenStackClient / CLI) and the related ``tests`` +of each service implementation. Inside of those directories, the custom +created services such as ``Cloud Container Engine (CCE)`` are hosted. -Email -***** +.. toctree:: + + layout -??? Coding Standards ---------------- -We are a bit stricter than usual in the coding standards department. It's a -good idea to read through the :doc:`coding ` section. +We are a bit stricter than usual in the coding standards +department. It's a good idea to read through the :doc:`coding +` section. .. toctree:: :maxdepth: 2 coding -Development Environment ------------------------ - -The first step towards contributing code and documentation is to setup your -development environment. We use a pretty standard setup, but it is fully -documented in our :doc:`setup ` section. - -.. toctree:: - :maxdepth: 2 - - setup Testing ------- The project contains three test packages, one for unit tests, one for -functional tests and one for examples tests. The ``openstack.tests.unit`` -package tests the SDK's features in isolation. The -``openstack.tests.functional`` and ``openstack.tests.examples`` packages test -the SDK's features and examples against an OpenStack cloud. +functional tests and one for examples tests. The +``openstack.tests.unit`` package tests the SDK's features in +isolation. The ``openstack.tests.functional`` and +``openstack.tests.examples`` packages test the SDK's features and +examples against an OpenStack cloud. .. toctree:: testing -Project Layout --------------- -The project contains a top-level ``openstack`` package, which houses several -modules that form the foundation upon which each service's API is built on. -Under the ``openstack`` package are packages for each of those services, -such as ``openstack.compute``. +Example SDK Service and Resource Implementation +----------------------------------------------- -.. toctree:: - - layout - -Adding Features ---------------- - -Does this SDK not do what you need it to do? Is it missing a service? Are you -a developer on another project who wants to add their service? You're in the -right place. Below are examples of how to add new features to the -OpenStack SDK. +Do the OTC Extensions not do what you need them to do? Are they +missing a service? Are you a developer on another project who wants to +add a service? You're in the right place. Below are examples of how to +add new features to the project. .. toctree:: :maxdepth: 2 create/resource -.. TODO(briancurtin): document how to create a proxy -.. TODO(briancurtin): document how to create auth plugins + +Contacting the OTC Extensions Developers +---------------------------------------- + +Currently no official communication other than `GitHub +`_ is +available. Feel free to open new issues if you want to contact us +directly or have questions related to the existent packages. diff --git a/doc/source/coverage.rst b/doc/source/coverage.rst new file mode 100644 index 000000000..42805181b --- /dev/null +++ b/doc/source/coverage.rst @@ -0,0 +1,127 @@ +Service Coverage +================ + +Currently, the OTC Extensions cover 13 different services additionally +to the vanilla OpenStack services implemented in OpenStack SDK. Two +services (rds and cce) are currently covered in the documentation +under several service tags. This may change in future. + +.. list-table:: + :name: service-coverage + :widths: 50 120 30 30 30 30 + :header-rows: 1 + + * - Endpoint + - Service + - GUI + - CLI + - SDK + - Comment + * - anti_ddos + - Anti-DDoS + - X + - X + - X + - + * - auto_scaling + - Auto-auto_scaling + - X + - X + - X + - + * - cce_v1 + - Cloud Container Engine + - X + - X + - X + - + * - cce_v3 + - Cloud Container Engine V2 + - X + - X + - X + - + * - ces + - Cloudeye + - X + - + - + - + * - cts + - Clout Trace Service + - X + - X + - X + - + * - dts + - Distributed Cache Service + - X + - X + - X + - + * - deh + - Dedicated Host + - X + - X + - X + - + * - dms + - Document Management Service + - X + - X + - X + - + * - dns + - Domain Name Service + - X + - X + - X + - + * - kms + - Key Management Service + - X + - X + - X + - + * - load_balancer + - Load Balancer + - X + - X + - + - + * - nat + - Network Address Translation + - X + - + - + - + * - obs + - Object Storage Service + - X + - X + - X + - + * - rds + - Relational Database Service + - X + - X + - X + - + * - rds_v1 + - Relational Database Service + - + - + - + - + * - rds_v2 + - Relational Database Service + - + - + - + - + * - vbs + - Volume Backup + - X + - X + - X + - diff --git a/doc/source/enforcer.py b/doc/source/enforcer.py index ca79b0311..7c6d46953 100644 --- a/doc/source/enforcer.py +++ b/doc/source/enforcer.py @@ -20,8 +20,14 @@ LOG = logging.getLogger(__name__) # NOTE: We do this because I can't find any way to pass "-v" -# into sphinx-build through pbr... -DEBUG = True if os.getenv("ENFORCER_DEBUG") else False +# into sphinx-build through pbr ... + +if os.getenv("ENFORCER_DEBUG"): + DEBUG = True + LOG.info("ENFORCER: Debugging is on.") +else: + DEBUG = False + WRITTEN_METHODS = set() @@ -116,7 +122,8 @@ def build_finished(app, exception): # We also need to deal with Proxy subclassing keystoneauth.adapter.Adapter # now - some of the warnings come from Adapter elements. for name in sorted(missing): - LOG.info("ENFORCER: %s was not included in the output" % name) + if DEBUG: + LOG.info("ENFORCER: %s was not included in the output" % name) if app.config.enforcer_warnings_as_errors and missing_count > 0: raise EnforcementError( diff --git a/doc/source/index.rst b/doc/source/index.rst index c113cd71d..08b18c3d7 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -1,61 +1,96 @@ Welcome to the OTC Extensions of the OpenStack SDK and CLI! =========================================================== -**Note:** Currently documentation is a mostly a copy of OpenStackSDK -documentation (used version). -It will be soon extended with OTC services. Keep watching +There are several ways to access an OpenStack cloud. The ultimate way +is accessing the `OpenStack API`_ directly. But that can be very +tedious. The `OpenStack SDK`_ is a Python based client library that +simplifies building applications to work with OpenStack clouds. The +`OpenStack Client`_ is its equivalent on the command line. -This documentation is split into three sections: +**This project, OTC Extensions,** adds extra functionality to the SDK +and the CLI offered by the `Open Telekom Cloud`_. Technically, the OTC +Extensions provide Python classes and methods to attach your own code +to the cloud. They also integrate seamless into the OpenStack Client, +providing many extra commands. -* an :doc:`installation ` guide -* a section for :doc:`users ` looking to build applications - which make use of OpenStack -* a section for those looking to :doc:`contribute ` - to this project +Content +------- -Installation ------------- +This documentation is split into sections, adressing major use +cases. Additionally some auxiliary documentation is available: .. toctree:: - :maxdepth: 2 + :includehidden: + :numbered: 1 + :maxdepth: 1 install/index + install/configuration + cli/index + sdk/index + contributor/index + coverage + appendices/index -CLI Usage ---------- -This guides give you an overview of the CLI commands +Installation and Configuration +------------------------------ -.. toctree:: - :maxdepth: 2 +The :doc:`installation guide ` explains to system +administrators and developers how to setup the project from system +packages, from pip, and directly from sources. OTC Extensions are easy +to :doc:`configure `. All credentials can be +configured conveniently in a few files. - cli/index -For Users ---------- +Working with the CLI tool +------------------------- -.. toctree:: - :maxdepth: 2 +Users who want to access Open Telekom Cloud specific services with +:doc:`command line tools ` for a shell like Bash find +documentation of all of their operations and properties in this +section. - user/index -For Contributors ----------------- +Writing your own Scripts for the Cloud +-------------------------------------- -.. toctree:: - :maxdepth: 2 +Developers writing own Python code may access the API easily by using +the OTC Extensions' classes and methods. The :doc:`SDK interfaces +` are documented in this section. - contributor/index -.. include:: ../../README.rst +Contribute to the Project +------------------------- + +To :doc:`contribute ` to the project itself, +developers find helpful background information and architecture +specification of OTC Extensions it this section. + General Information ------------------- -General information about the SDK including a glossary and release history. +There is general background information about the OTC Extensions +available: -.. toctree:: - :maxdepth: 1 +* A :doc:`glossary ` describes important terms + and their naming conventions. + +* The :doc:`history ` explains the ancestry of + this project. This may or may not be insightful if you want to + understand the project's architecture. + +* The project keeps a :doc:`release history + `. + +* A list of :doc:`issues ` is maintained. + +* Currently 13 services are :doc:`covered ` by the OTC + extensions. - Glossary of Terms - Release Notes +.. _OpenStack API: https://docs.openstack.org/api-quick-start/ +.. _OpenStack SDK: https://docs.openstack.org/openstacksdk/ +.. _OpenStack Client: https://docs.openstack.org/python-openstackclient/ +.. _Ansible modules: https://github.com/OpenTelekomCloud/ansible-collections/ +.. _Open Telekom Cloud: https://open-telekom-cloud.com/ diff --git a/doc/source/install/configuration.rst b/doc/source/install/configuration.rst new file mode 100644 index 000000000..a6a167a27 --- /dev/null +++ b/doc/source/install/configuration.rst @@ -0,0 +1,186 @@ +Configuration +============= + +You can connect to the Open Telekom Cloud and OpenStack clouds in general +using two approaches. The first one uses a credential file called +``clouds.yaml`` and the other one is to use ``environment variables``. + +.. _clouds-yaml: + +Configuring a clouds.yaml file +------------------------------ + +The credential file ``clouds.yaml`` will be queried automatically in different +locations with increasing precedence: + +1. system-wide (/etc/openstack/{clouds,secure}.yaml) +2. Home directory / user space (~/.config/openstack/{clouds,secure}.yaml) +3. Current directory (./{clouds,secure}.yaml) + +A sample clouds.yaml file is listed below to connect with Open Telekom Cloud: + +**clouds.yaml** + +.. code-block:: yaml + + clouds: + otc: + profile: otc + auth: + username: '' + password: '' + project_name: '' + # or project_id: '<123456_PROJECT_ID>' + user_domain_name: 'OTC00000000001000000xxx' + # or user_domain_id: '<123456_DOMAIN_ID>' + auth_url: 'https://iam.eu-de.otc.t-systems.com:443/v3' + interface: 'public' + identity_api_version: 3 # !Important + ak: '' # AK/SK pair for access to OBS + sk: '' + +.. note:: + The name ``otc`` is self-defined and can be changed to any value. + +AK/SK values required for access to some services (i.e. OBS) can +be either configured as shown above in the clouds.yaml/secure.yaml, or +they can be automatically retrieved from the S3_ACCESS_KEY_ID and +S3_SECRET_ACCESS_KEY. + +Test your connection +^^^^^^^^^^^^^^^^^^^^ + +If you followed the `installation advices `_ for your specific +operating system, you can use the following command to test the basic +functionality. + +.. code-block:: bash + + $ openstack --os-cloud otc flavor list + + +Configuration of a Second Project +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Additional connections to other Openstack-clouds or -projects can be added +to the file as shown below: + +**clouds.yaml** + +.. code-block:: yaml + + clouds: + otcfirstproject: + profile: otc + auth: + username: '' + password: '' + project_name: '' + # or project_id: '<123456_PROJECT_ID>' + user_domain_name: 'OTC00000000001000000xxx' + # or user_domain_id: '<123456_DOMAIN_ID>' + auth_url: 'https://iam.eu-de.otc.t-systems.com:443/v3' + interface: 'public' + identity_api_version: 3 # !Important + ak: '' # AK/SK pair for access to OBS + sk: '' + otcsecondproject: + profile: otc + auth: + username: '' + password: '' + project_name: '' + # or project_id: '<123456_PROJECT_ID2>' + user_domain_name: 'OTC00000000001000000xxx' + # or user_domain_id: '<123456_DOMAIN_ID2>' + auth_url: 'https://iam.eu-de.otc.t-systems.com:443/v3' + interface: 'public' + identity_api_version: 3 # !Important + ak: '' # AK/SK pair for access to OBS + sk: '' + +Splitting the credentials in clouds.yaml and secure.yaml +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In some scenarios a split of security credentials from the configuration file +is necessary. The optional file ``secure.yaml`` can be used to store the +secret which is left out from ``clouds.yaml``: + +**clouds.yaml** + +.. code-block:: yaml + + clouds: + otc: + profile: otc + auth: + username: '' + project_name: '' + # or project_id: '<123456_PROJECT_ID>' + user_domain_name: 'OTC00000000001000000xxx' + # or user_domain_id: '<123456_DOMAIN_ID>' + auth_url: 'https://iam.eu-de.otc.t-systems.com:443/v3' + interface: 'public' + identity_api_version: 3 # !Important + ak: '' # AK/SK pair for access to OBS + sk: '' + +**secure.yaml** + +.. code-block:: yaml + + clouds: + otc: + auth: + password: '' + +.. _environment-variables: + +Configuration of Environment Variables +-------------------------------------- + +Instead of using the clouds.yaml file, environmnt variables can be configured +to connect to the Open Telekom Cloud. Create a simple file like ``.ostackrc`` +in the home directory and source the file to make the variables available. On +Open Telekom Cloud servers this file exists on bootup and needs to be changed +according to your credentials. + +.. code-block:: bash + + # .ostackrc file + export OS_USERNAME="" + export OS_USER_DOMAIN_NAME= + export OS_PASSWORD= # optional + export OS_TENANT_NAME=eu-de + export OS_PROJECT_NAME= + export OS_AUTH_URL=https://iam.eu-de.otc.t-systems.com:443/v3 + export NOVA_ENDPOINT_TYPE=publicURL + export OS_ENDPOINT_TYPE=publicURL + export CINDER_ENDPOINT_TYPE=publicURL + export OS_VOLUME_API_VERSION=2 + export OS_IDENTITY_API_VERSION=3 + export OS_IMAGE_API_VERSION=2 + +Run the source command to make the ``environment variables`` available. + +.. code-block:: bash + + $ source .ostackrc + +The ``environment variables`` are now available for usage. For testing your +connection run the following command. + +Test your connection +^^^^^^^^^^^^^^^^^^^^ + +If you followed the `installation advices `_ for your specific +operating system, you can use the following command to test the basic +functionality. + +.. code-block:: bash + + $ openstack flavor list + +.. note:: + You don't need to specify the `--os-cloud` parameter when environment + variables are used. diff --git a/doc/source/install/index.rst b/doc/source/install/index.rst index 42dba52c7..50eac4e40 100644 --- a/doc/source/install/index.rst +++ b/doc/source/install/index.rst @@ -1,393 +1,87 @@ -============ Installation ============ -There are several ways to install python-otcextensions to enhance the native -``openstack`` CLI client and to extend the OpenStack SDK to cover the -additional Open Telekom Cloud services providing a larger functionality -on top of OpenStack. +There are several install options for OTC Extensions to enhance the +native `OpenStack Client`_ and to extend the `OpenStack SDK`_. Once +installed, they cover additional `Open Telekom Cloud`_ services and +provide extra functionality on top of the stock OpenStack SDK and CLI. -The easiest way is to use the Python pip installer which is working -distribution independent and can be used in an isolated virtual environment -as described below. Ansible can be used to install python-otcextensions on -various operating systems, too by using the following Ansible Role: -https://github.com/OpenTelekomCloud/ansible-role-otcextensions . -There are also ready-made installation packages for various operating -systems which have their own versions, package names and sometimes bugs. -A repository based on openSUSE's build services tries to cover these issues -which is available under: -https://build.opensuse.org/project/show/Cloud:OTC:Tools:OpenStack. +.. toctree:: + :maxdepth: 3 + + pip_install + source_install Overview of Related Packages ---------------------------- -**OpenStackSDK:** -A library on the client side that translates Python function calls into -API calls to an OpenStack cloud. - -**OpenStackClient:** -An application that turns the Python interface of OpenStackSDK and -python-otcextensions into a CLI tool. - -**python-otcextensions:** -An addition to OpenStackSD with enhanced functionality that is specific for the -Open Telekom Cloud. - -Installation with pip installer -------------------------------- - -All three packages are written in Python and stored as Python libraries in the -PyPi repository. The following section describes the installation of -``OpenStackSDK``, ``otcextensions`` and ``OpenStackClient``. Please remember, -it is not the latest development state. For this purpose the latest sources -needs to be installed. - -Installation under Ubuntu or Debian -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For the installation, following packages are required: a C compiler, Python3 -with developer libraries, and package manager pip are required: - -.. code-block:: bash - - $ sudo apt update - $ sudo apt install gcc python3 python3-dev python3-pip libssl-dev - -Now, install all libraries and programs at once with the Python package -manager pip. The --user flag provides user wide installation instead of a -global installation. - -.. code-block:: bash - - $ pip3 install otcextensions python-openstackclient --user - - -Installation under CentOS -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For the installation, following packages are required: a C compiler, Python3 -with developer libraries, and package manager pip are required. If you want to -use python3 which is recommended, you need to install the epel -repository, first: - - -.. code-block:: bash - - $ sudo yum update - $ sudo yum install epel-release - $ sudo yum install gcc python36 python36-devel python36-pip openssl-devel - - -Now, install all libraries and programs at once with the Python package -manager pip: - -.. code-block:: bash - - $ pip3 install otcextensions python-openstackclient --user - -Installation under Fedora -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For the installation, following packages are required: a C compiler, Python3 -with developer libraries, and package manager pip are required: - - -.. code-block:: bash - - $ sudo dnf upgrade - $ sudo dnf install gcc python3 python3-devel python3-pip openssl-devel - -Now, install all libraries and programs at once with the Python package -manager pip: - -.. code-block:: bash - - $ pip3 install otcextensions python-openstackclient --user - - -Installation in a virtual environment with pip installer --------------------------------------------------------------- - -A virtual environment seperates your installed packages from other -libraries and should be used as well. - -Installation under Ubuntu or Debian -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -For the installation, following packages are required: a C compiler, Python3 -with developer libraries, package manager, and virtual environment -are required: - -.. code-block:: bash - - $ sudo apt update - $ sudo apt install gcc python3 python3-dev python3-pip python3-venv libssl-dev - -A virtual environment seperates your installed packages from other libraries -and should be used as well. You can name the virtual environment on your own -desires, in our example it is: "venv". The second command will switch -on "venv": - -.. code-block:: bash - - $ python3 -m venv venv - $ source venv/bin/activate - (venv) $ - -Now, install all libraries and programs at once with the Python package -manager pip: - -.. code-block:: bash - - $ pip install otcextensions openstackclient - - -Installation under CentOS -^^^^^^^^^^^^^^^^^^^^^^^^^ - -For the installation, following packages are required: a C compiler, Python3 -with developer libraries, package manager, and virtual environment are -required. If you want to use python3 which is recommended, you need to -install the epel repository, first: - - -.. code-block:: bash - - $ sudo yum update - $ sudo yum install epel-release - -No the python packages are needed: - -.. code-block:: bash - - $ sudo yum update - $ sudo yum install gcc python36 python36-devel python-pip \ - python-virtualenv openssl-devel - -A virtual environment seperates your installed packages from other libraries -and should be used as well. You can name the virtual environment on your own -desires, in our example it is: "venv". The second command will switch -on "venv": - -.. code-block:: bash - - $ python3 -m venv venv - $ source venv/bin/activate - -Now, install all libraries and programs at once with the Python package -manager pip: - -.. code-block:: bash - - $ pip install otcextensions openstackclient - -Installation under Fedora (under review) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The OTC Extensions are, as most software in OpenStack, written in +Python and are eventually a Python package. These packages come with +dependencies to other packages. Usually a package manager such as pip +is used to resolve those dependencies or all requirements are bundled +in a single packet. These are the main packages and their relations to +each other: + +**OpenStack SDK:** A library on the client side that translates Python +function calls into API calls to an OpenStack cloud. It depends only +on other, internal Python packages. + +**OpenStack Client:** An application that turns the Python interface +of OpenStack SDK and OTC Extensions into a CLI tool. If installed, it +requires the SDK. + +**OTC Extensions:** An addition to OpenStack SDK with enhanced +functionality that is specific for the Open Telekom Cloud. This is the +package you are currently looking at. It requires the SDK since it +extends its interfaces. If it is installed as a Python package it is +detected and integrated automatically by the other two packages +without further installation or configuration. + +So effectively, using a package manager like pip it is sufficient to +install the packages like this: + +.. code-block: console + $ pip install openstackclcient otcextensions + +Other packaging methods may or may not have these dependencies built +in already. + + +Installation Options +-------------------- + +There are a number of alternatives available to install OTC Extensions +(including the SDK and CLI): + +* **Installing from operating system packages (deb, rpm, yum, dnf):** + This is a very easy way that is also easy to revert. The downside of + this aproach is that operating system packages for the major + distributions are often quite outdated, as many of the internal + dependencies are also often outdated. You often experience a backlog + of several months up to years behind the latest development. + +* **Installing with a Python package manager (pip):** Python comes + with its own package manager `pip` for the `Python Package Index + (PyPI)`_. That is today the standard way to install Python + packages. All other described options use this method under the + hood. This way is operating system independent. Installing with + `pip` comes with three sub-options: Installing system-wide, for a + single user, or inside a virtual environemt. **This is the + recommended way to install OTC Extensions.** + +* **Installing from sources:** All related projects are hosted on + public source code repositories. So if you need a bleeding edge + feature or want to contribute directly to the project yourself, + installation from sources is for you. It requires some extra steps, + though. -For the installation, following packages are required: a C compiler, -Python3 with developer libraries, package manager, and a virtual -environment are required: - - -.. code-block:: bash - - $ sudo dnf upgrade - $ sudo dnf install gcc python3 python3-devel python3-pip \ - python3-virtualenv openssl-devel - -The virtual environment will be created and activated. You can name the -virtual environment on your own desires, in our example it is "venv": - -.. code-block:: bash - - $ python3 -m venv venv - $ source venv/bin/activate - -Now, install all libraries and programs at once with the Python package -manager pip: - -.. code-block:: bash - - (venv) $ pip install otcextensions openstackclient - - -Installation from Github sources --------------------------------- - -The latest state of the packages can be installed with the following approach. - -Cloning the Github repository: - -.. code-block:: bash - - $ git clone https://github.com/OpenTelekomCloud/python-otcextensions.git - -A virtual environment seperates your installed packages from other libraries -and should be used as well. You can name the virtual environment on your own -desires, in our example it is: "venv". The second command will switch -on "venv": - -.. code-block:: bash - - $ python3 -m venv venv - $ source venv/bin/activate - (venv) $ - -Switch into the new folder which is created by cloning the repository and -install install the project dependencies into the virtual environment: - -.. code-block:: bash - - (venv) $ cd ./python-otcextensions - -Register the CLI plugin using: - -.. code-block:: bash - - (venv) ~/python-otcextensions$ python setup.py install - -Install Openstack-Client binary from pip-Repository: - -.. code-block:: bash - - (venv) ~/python-otcextensions$ pip install openstackclient - -Configuration for the Cloud Connection --------------------------------------- - -You can connect to the Open Telekom Cloud and OpenStack clouds in general -using two approaches. The first one uses a credential file called -``clouds.yaml`` and the other one is to use environment variables. - -Configuring a clouds.yaml file -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The credential file clouds.yaml will be queried automatically in different -locations with increasing precedence: - -1. system-wide (/etc/openstack/{clouds,secure}.yaml) -2. Home directory / user space (~/.config/openstack/{clouds,secure}.yaml) -3. Current directory (./{clouds,secure}.yaml) - -A sample clouds.yaml file is listed below to connect with Open Telekom Cloud: - -**clouds.yaml** - -.. code-block:: yaml - - clouds: - otc: - auth: - username: 'USER_NAME' - password: 'PASS' - project_name: 'eu-de' - auth_url: 'https://iam.eu-de.otc.t-systems.com:443/v3' - user_domain_name: 'OTC00000000001000000xxx' - interface: 'public' - identity_api_version: 3 # !Important - ak: 'AK_VALUE' # AK/SK pair for access to OBS - sk: 'SK_VALUE' - -The name otc is self-defined and can be changed. AK/SK values required for -access to some services (i.e. OBS) can be either configured as shown above -in the clouds.yaml/secure.yaml, or they can be automatically retrieved from -the S3_ACCESS_KEY_ID and S3_SECRET_ACCESS_KEY. - -Additional connections to other Openstack-clouds or -projects can be added -to the file as shown below: - -**clouds.yaml** - -.. code-block:: yaml - - clouds: - otc: - auth: - username: 'USER_NAME' - password: 'PASS' - project_name: 'eu-de' - auth_url: 'https://iam.eu-de.otc.t-systems.com:443/v3' - user_domain_name: 'OTC00000000001000000xxx' - interface: 'public' - identity_api_version: 3 # !Important - ak: 'AK_VALUE' # AK/SK pair for access to OBS - sk: 'SK_VALUE' - otcsecondproject: - region_name: eu-de - auth: - username: '' - password: '' - project_id: '' - user_domain_id: '' - auth_url: 'https://iam.eu-de.otc.t-systems.com:443/v3' - -Test your connection -^^^^^^^^^^^^^^^^^^^^ - -Use the following command to test the basic functionality. - -.. code-block:: bash - - $ openstack --os-cloud otc flavor list - -Splitting the credentials in clouds.yaml and secure.yaml -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -In some scenarios a split of security credentials from the configuration file -is necessary. The optional file ``secure.yaml`` can be used to store the -secret which is left out from ``clouds.yaml``: - -**clouds.yaml** - -.. code-block:: yaml - - clouds: - otc: - auth: - username: 'USER_NAME' - project_name: 'eu-de' - auth_url: 'https://iam.eu-de.otc.t-systems.com:443/v3' - user_domain_name: 'OTC00000000001000000xxx' - interface: 'public' - identity_api_version: 3 # !Important - ak: 'AK_VALUE' # AK/SK pair for access to OBS - sk: 'SK_VALUE' - -**secure.yaml** - -.. code-block:: yaml - - clouds: - otc: - auth: - password: '' - -Configuration of Environment Variables --------------------------------------- - -Instead of using the clouds.yaml file, environmnt variables can be configured -to connect to the Open Telekom Cloud. Create a simple file like ``.ostackrc`` -in the home directory and source the file to make the variables available. On -Open Telekom Cloud servers this file exists on bootup and needs to be changed -according to your credentials. - -.. code-block:: bash - - export OS_AUTH_URL= - export OS_IDENTITY_API_VERSION=3 - export OS_PROJECT_NAME= - export OS_PROJECT_DOMAIN_NAME= - export OS_USERNAME= - export OS_USER_DOMAIN_NAME= - export OS_PASSWORD= # (optional) - export S3_ACCESS_KEY_ID= - export S3_SECRET_ACCESS_KEY= - -Test your connection -^^^^^^^^^^^^^^^^^^^^ - -Use the following command to test the basic functionality. - -.. code-block:: bash +There are also ready-made installation packages for various operating +systems which have their own versions, package names and sometimes +bugs. A repository based on openSUSE's build services tries to cover +these issues which is available under: +https://build.opensuse.org/project/show/Cloud:OTC:Tools:OpenStack. - $ openstack flavor list +.. _OpenStack SDK: https://docs.openstack.org/openstacksdk/ +.. _OpenStack Client: https://docs.openstack.org/python-openstackclient/ +.. _Open Telekom Cloud: https://open-telekom-cloud.com/ +.. _Python Package Index (PyPI): https://pypi.org/ diff --git a/doc/source/install/pip_install.rst b/doc/source/install/pip_install.rst new file mode 100644 index 000000000..d5d63fc13 --- /dev/null +++ b/doc/source/install/pip_install.rst @@ -0,0 +1,175 @@ +Installation with PiP Installer +=============================== + +All three packages are written in Python and stored as Python packages in the +PyPi repository. The following section describes the installation of +``OpenStackSDK``, ``otcextensions`` and ``OpenStackClient``. Please remember, +it is not the latest development state. For this purpose the latest sources +needs to be installed. + +PiP Installation in User Space +------------------------------ + +Ubuntu or Debian +^^^^^^^^^^^^^^^^ + +For the installation, following packages are required: a C compiler, Python3 +with developer libraries, and package manager pip are required: + +.. code-block:: bash + + $ sudo apt update + $ sudo apt install gcc python3 python3-dev python3-pip libssl-dev + +Now, install all libraries and programs at once with the Python package +manager pip. The --user flag provides user wide installation instead of a +global installation. + +.. code-block:: bash + + $ pip3 install otcextensions python-openstackclient --user + + +CentOS +^^^^^^ + +For the installation, following packages are required: a C compiler, Python3 +with developer libraries, and package manager pip are required. If you want to +use python3 which is recommended, you need to install the epel +repository, first: + +.. code-block:: bash + + $ sudo yum update + $ sudo yum install epel-release + $ sudo yum install gcc python36 python36-devel python36-pip openssl-devel + +Now, install all libraries and programs at once with the Python package +manager pip: + +.. code-block:: bash + + $ pip3 install otcextensions python-openstackclient --user + +Fedora +^^^^^^ + +For the installation, following packages are required: a C compiler, Python3 +with developer libraries, and package manager pip are required: + + +.. code-block:: bash + + $ sudo dnf upgrade + $ sudo dnf install gcc python3 python3-devel python3-pip openssl-devel + +Now, install all libraries and programs at once with the Python package +manager pip: + +.. code-block:: bash + + $ pip3 install otcextensions python-openstackclient --user + +PiP Installation within a Virtual Environment +--------------------------------------------- + +A virtual environment seperates your installed packages from other +libraries and should be used as well. + +Ubuntu or Debian +^^^^^^^^^^^^^^^^ + +For the installation, following packages are required: a C compiler, Python3 +with developer libraries, package manager, and virtual environment +are required: + +.. code-block:: bash + + $ sudo apt update + $ sudo apt install gcc python3 python3-dev python3-pip python3-venv libssl-dev + +A virtual environment seperates your installed packages from other libraries +and should be used as well. You can name the virtual environment on your own +desires, in our example it is: "venv". The second command will switch +on "venv": + +.. code-block:: bash + + $ python3 -m venv venv + $ source venv/bin/activate + (venv) $ + +Now, install all libraries and programs at once with the Python package +manager pip: + +.. code-block:: bash + + $ pip install otcextensions openstackclient + + +CentOS +^^^^^^ + +For the installation, following packages are required: a C compiler, Python3 +with developer libraries, package manager, and virtual environment are +required. If you want to use python3 which is recommended, you need to +install the epel repository, first: + + +.. code-block:: bash + + $ sudo yum update + $ sudo yum install epel-release + +No the Python packages are needed: + +.. code-block:: bash + + $ sudo yum update + $ sudo yum install gcc python36 python36-devel python-pip \ + python-virtualenv openssl-devel + +A virtual environment seperates your installed packages from other libraries +and should be used as well. You can name the virtual environment on your own +desires, in our example it is: "venv". The second command will switch +on "venv": + +.. code-block:: bash + + $ python3 -m venv venv + $ source venv/bin/activate + +Now, install all libraries and programs at once with the Python package +manager pip: + +.. code-block:: bash + + $ pip install otcextensions openstackclient + +Fedora (under review) +^^^^^^^^^^^^^^^^^^^^^ + +For the installation, following packages are required: a C compiler, +Python3 with developer libraries, package manager, and a virtual +environment are required: + +.. code-block:: bash + + $ sudo dnf upgrade + $ sudo dnf install gcc python3 python3-devel python3-pip \ + python3-virtualenv openssl-devel + +The virtual environment will be created and activated. You can name the +virtual environment on your own desires, in our example it is "venv": + +.. code-block:: bash + + $ python3 -m venv venv + $ source venv/bin/activate + +Now, install all libraries and programs at once with the Python package +manager pip: + +.. code-block:: bash + + (venv) $ pip install otcextensions openstackclient diff --git a/doc/source/install/source_install.rst b/doc/source/install/source_install.rst new file mode 100644 index 000000000..eaa4fb9df --- /dev/null +++ b/doc/source/install/source_install.rst @@ -0,0 +1,41 @@ +Installation from GitHub sources +================================ + +The latest state of the packages can be installed with the following +source installation approach. + +Cloning the Github repository: + +.. code-block:: bash + + $ git clone https://github.com/OpenTelekomCloud/python-otcextensions.git + +A virtual environment seperates your installed packages from other libraries +and should be used as well. You can name the virtual environment on your own +desires, in our example it is: "venv". The second command will switch +on "venv": + +.. code-block:: bash + + $ python3 -m venv venv + $ source venv/bin/activate + (venv) $ + +Switch into the new folder which is created by cloning the repository and +install install the project dependencies into the virtual environment: + +.. code-block:: bash + + (venv) $ cd ./python-otcextensions + +Register the CLI plugin using: + +.. code-block:: bash + + (venv) ~/python-otcextensions$ python setup.py install + +Install Openstack-Client binary from pip-Repository: + +.. code-block:: bash + + (venv) ~/python-otcextensions$ pip install openstackclient diff --git a/doc/source/releasenotes.rst b/doc/source/releasenotes.rst deleted file mode 100644 index 74fa320f0..000000000 --- a/doc/source/releasenotes.rst +++ /dev/null @@ -1,5 +0,0 @@ -============= -Release Notes -============= - -Release notes for `python-otcextensions` are currently not implemented diff --git a/doc/source/sdk/architecture.rst b/doc/source/sdk/architecture.rst new file mode 100644 index 000000000..897f0a22c --- /dev/null +++ b/doc/source/sdk/architecture.rst @@ -0,0 +1,17 @@ +Architecture Overview and Important Terms +========================================= + +The OTC Extensions contain an abstraction interface layer. Clouds can +do many things, but there are probably only about ten of them that +most people care frequently. + +If you want to do complicated things, the per-service oriented +portions of the SDK are for you. However, if what you want is to be +able to write an application that talks to clouds no matter what crazy +choices the deployer has made in an attempt to be more hipster than +their self-entitled narcissist peers, then the Cloud Abstraction layer +is for you. + +The OTC Extensions provide an extension to the OpenStack SDK. Refer to +its documentation for the details: +. diff --git a/doc/source/sdk/examples b/doc/source/sdk/examples new file mode 120000 index 000000000..d4cb9b9c8 --- /dev/null +++ b/doc/source/sdk/examples @@ -0,0 +1 @@ +../../../examples/ \ No newline at end of file diff --git a/doc/source/sdk/getting_started.rst b/doc/source/sdk/getting_started.rst new file mode 100644 index 000000000..1588cec8e --- /dev/null +++ b/doc/source/sdk/getting_started.rst @@ -0,0 +1,101 @@ +Getting Started +=============== + +Verify Installation +------------------- + +``OTC Extensions`` needs to be installed correctly. Please check +:doc:`../install/index` for further instructions. The +``otcextensions`` Python package pulls the ``openstacksdk`` package +automatically as dependency which is needed to create own OpenStack scripts. + +Configure Connection Credentials +-------------------------------- + +In order to work with an OpenStack cloud you first need to create a +:class:`~openstack.connection.Connection` using your credentials. A +:class:`~openstack.connection.Connection` can be created in three +ways, using the class itself, :ref:`clouds-yaml`, or +:ref:`environment-variables`. It is recommended use +:ref:`clouds-yaml` as the same config can be used across tools +and languages. Examples are: + +- OpenStack Client +- Gophercloud (library for golang) +- Terraform (based on Gophercloud) + +.. note:: Please be also aware that environment variables carrying + credentials can be a security risk. + + +Creating a Minimal Python Script +-------------------------------- + +At first we need to import `openstack` to get access to all available +:doc:`Proxy ` functions. Enable Logging is an optional +step in the script and can be left out in productive usage. +For communication purposes a :class:`~openstack.connection.Connection` +instance is created to communicate with the Cloud environment. The +`cloud=` represents the :class:`~openstack.connection.Connection` +name defined while creating the ``clouds.yaml`` file in :ref:`clouds-yaml`. +The ``cloud``-variable can be left out if environment variables are +used or only ``one`` Cloud-connection is defined. + +.. code-block:: python + + #!/usr/bin/env python3 + + import openstack + + # optional, enable Logging on + openstack.enable_logging(True) + + # Creates cloud connection + # Parameter cloud='otc' is optional for env variables or single + # clouds.yaml entry. + conn = openstack.connect(cloud='otc') + + for server in conn.compute.servers(): + print(server) + +.. note:: For further examples, see `Examples `_. + +.. note:: For further information about logging, please see + :doc:`Logging User Guide `. + +Run the Script +-------------- + +After saving the script as `list_server.py`. You can simply run it by using +the following command. + +.. code-block:: bash + + python list_server.py + +The output represents all existent OpenStack servers in your Cloud +environment. + +OTC Extensions specific Example for Open Telekom Cloud +------------------------------------------------------ + +The following script uses the OTC Extensions to list all existent CCE Clusters +in your account. + +.. code-block:: python + + #!/usr/bin/env python3 + + import openstack + + # openstack.enable_logging(True) + conn = openstack.connect() + + for cluster in conn.cce.clusters(): + print(cluster) + +Save the file as `list_cce_clusters.py` and run it with: + +.. code-block:: bash + + python list_cce_clusters.py diff --git a/doc/source/sdk/guides/anti_ddos.rst b/doc/source/sdk/guides/anti_ddos.rst new file mode 100644 index 000000000..28a82624a --- /dev/null +++ b/doc/source/sdk/guides/anti_ddos.rst @@ -0,0 +1,109 @@ +Anti-DDoS (AS) +============== + +.. contents:: Table of Contents + :local: + +Floating-IP Operations +---------------------- + +Floating IP operations lists all methods which are used to query and modify +Floating IPs settings related to Anti-DDoS. + +List Anti-DDoS Floating IPs +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This interface is used to query all Floating IPs protected by Anti-DDoS and +limit the output with parameters. + +.. literalinclude:: ../examples/anti_ddos/list_floating_ips.py + :lines: 16-23 + +Protect an Floating IP (not working) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This interface is used to enable Anti-DDoS on a Floating IP by using IP id or +an instance of class +:class:`~otcextensions.sdk.anti_ddos.v1.floating_ip.FloatingIP`. + +.. literalinclude:: ../examples/anti_ddos/protect_floating_ip.py + :lines: 17-23 + +Unprotect an Floating IP (not working) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This interface is used to disable Anti-DDoS on a Floating IP by using IP id or +an instance of class +:class:`~otcextensions.sdk.anti_ddos.v1.floating_ip.FloatingIP`. + +.. literalinclude:: ../examples/anti_ddos/unprotect_floating_ip.py + :lines: 17-23 + +Get Floating IP Policies +^^^^^^^^^^^^^^^^^^^^^^^^ + +This Interface is used to query the Anti-DDoS Policy for a specific Floating +IP by using Floating IP id or an instance of class +:class:`~otcextensions.sdk.anti_ddos.v1.floating_ip.FloatingIP`. Anti-DDoS +must be enabled for the specific Floating IP otherwise an error occures. + +.. literalinclude:: ../examples/anti_ddos/get_floating_ip_policies.py + :lines: 18-25 + +Update Floating IP Policies +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This Interface is used to update Anti-DDoS Policy attributes. + +.. literalinclude:: ../examples/anti_ddos/update_floating_ip_policies.py + :lines: 16-30 + +Get Floating IP Status +^^^^^^^^^^^^^^^^^^^^^^ + +This Interface is used to query Anti-DDoS status of a Floating IP by using +id. + +.. literalinclude:: ../examples/anti_ddos/get_floating_ip_status.py + :lines: 16-25 + +List Floating IP Events +^^^^^^^^^^^^^^^^^^^^^^^ + +This Interface is used to query all Anti-DDoS events of a Floating IP by using +id. + +.. literalinclude:: ../examples/anti_ddos/list_floating_ip_events.py + :lines: 16-25 + +List Floating IP Day Statistics +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This Interface is used to query all Anti-DDoS events per day of a Floating IP +by using id. + +.. literalinclude:: ../examples/anti_ddos/list_floating_ip_stat_day.py + :lines: 16-25 + +List Week Statistics of all Floating IPs +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This Interface is used to query all Anti-DDoS events per week of all Floating +IPs. + +.. literalinclude:: ../examples/anti_ddos/list_floating_ip_stat_week.py + :lines: 16-23 + +Alarm Configuration +------------------- + +Anti-DDoS alerts can be sent in various ways and notifies in case of defense. + +List Alarm Configurations +^^^^^^^^^^^^^^^^^^^^^^^^^ + +This Interface is used to query Anti-DDoS alarm configurations. + +.. literalinclude:: ../examples/anti_ddos/list_configs.py + :lines: 16-23 + diff --git a/doc/source/sdk/guides/auto_scaling.rst b/doc/source/sdk/guides/auto_scaling.rst new file mode 100644 index 000000000..fbf617e79 --- /dev/null +++ b/doc/source/sdk/guides/auto_scaling.rst @@ -0,0 +1,297 @@ +Auto-Scaling (AS) +================= + +.. contents:: Table of Contents + :local: + +Auto-Scaling Configuration +-------------------------- + +An Auto-Scaling (AS) configuration is a template of Elastic Cloud Servers in +an AS group. It defines the specifications of the instances to be added to +the AS group. The AS configuration is decoupled from the AS group and can +be used several times in different groups. Up to 100 AS configurations can +be created for each user. + +List Configurations +^^^^^^^^^^^^^^^^^^^ + +This interface is used to query all Auto-Scaling configurations and to filter +the output with query parameters. + +.. literalinclude:: ../examples/auto_scaling/list_configs.py + :lines: 16-22 + +Create Configuration +^^^^^^^^^^^^^^^^^^^^ + +This interface is used to create an Auto-Scaling Configuration instance with +parameters. + +.. literalinclude:: ../examples/auto_scaling/create_config.py + :lines: 16-36 + +Get Configuration +^^^^^^^^^^^^^^^^^ + +This interface is used to get an Auto-Scaling Configuration by ID +or an instance of class +:class:`~otcextensions.sdk.auto_scaling.v1.config.Config`. + +.. literalinclude:: ../examples/auto_scaling/get_config.py + :lines: 16-24 + +Find Configuration +^^^^^^^^^^^^^^^^^^ + +This interface is used to find an Auto-Scaling Configuration instance by +name or id. + +.. literalinclude:: ../examples/auto_scaling/find_config.py + :lines: 16-24 + +Delete Configuration +^^^^^^^^^^^^^^^^^^^^ + +This interface is used to delete an Auto-Scaling Configuration instance by id +or an instance of class +:class:`~otcextensions.sdk.auto_scaling.v1.config.Config`. + +.. literalinclude:: ../examples/auto_scaling/delete_config.py + :lines: 16-23 + +Batch Delete Configurations +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This interface is used to delete multiple Auto-Scaling Configuration instances +by id or an instance of +class :class:`~otcextensions.sdk.auto_scaling.v1.config.Config`. + +.. literalinclude:: ../examples/auto_scaling/batch_delete_config.py + :lines: 16-26 + + +Auto-Scaling Group +------------------ + +An Auto-Scaling (AS) group consists of a collection of instances that apply +to the same scaling scenario. An AS group specifies parameters, such as the +maximum number of instances, expected number of instances, minimum number +of instances, VPC, subnet, and load balancing. Each user can create a maximum +of 25 AS groups by default. + +List Groups +^^^^^^^^^^^ + +This interface is used to query all Auto-Scaling Groups and to filter +the output with query parameters. + +.. literalinclude:: ../examples/auto_scaling/list_groups.py + :lines: 16-22 + +Create Group +^^^^^^^^^^^^ + +This interface is used to create an Auto-Scaling Group with parameters. + +**NEEDS TO BE DONE** + +Get Group +^^^^^^^^^ + +This interface is used to get an Auto-Scaling Group by ID +or an instance of class +:class:`~otcextensions.sdk.auto_scaling.v1.group.Group`. + +.. literalinclude:: ../examples/auto_scaling/get_group.py + :lines: 16-24 + +Find Group +^^^^^^^^^^ + +This interface is used to find an Auto-Scaling Group instance by +name or id. + +.. literalinclude:: ../examples/auto_scaling/find_group.py + :lines: 16-24 + +Delete Group +^^^^^^^^^^^^ + +This interface is used to delete an Auto-Scaling Group instance by id or +an instance of class :class:`~otcextensions.sdk.auto_scaling.v1.group.Group`. + +.. literalinclude:: ../examples/auto_scaling/delete_group.py + :lines: 16-23 + +Pause Group +^^^^^^^^^^^ + +This interface is used to pause an Auto-Scaling Group instance in +passive state by using id or an instance of +class :class:`~otcextensions.sdk.auto_scaling.v1.group.Group`. + +.. literalinclude:: ../examples/auto_scaling/pause_group.py + :lines: 16-25 + +Resume Group +^^^^^^^^^^^^ + +This interface is used to resume an Auto-Scaling Group instance in +active state by using id or an instance of +class :class:`~otcextensions.sdk.auto_scaling.v1.group.Group`. + +.. literalinclude:: ../examples/auto_scaling/resume_group.py + :lines: 16-24 + +Auto-Scaling Policy +------------------- + +An Auto-Scaling (AS) policy defines whether to increase or decrease the number +of instances in an AS group. If the number and the expected number of +instances in an AS group are different due to the execution of the AS policy, +AS automatically adjusts the number of instances to the expected. AS supports +the following policy variants: + +* alarm-triggered policy +* periodic policy +* scheduled policy + +List Policy +^^^^^^^^^^^ + +This interface is used to query all Auto-Scaling Policies of an AS group +and to filter the output with query parameters. + +.. literalinclude:: ../examples/auto_scaling/list_policies.py + :lines: 16-25 + +Create Policy +^^^^^^^^^^^^^ + +This interface is used to create an Auto-Scaling Policy with parameters. + +**NEEDS TO BE DONE** + +Get Policy +^^^^^^^^^^ + +This interface is used to get an Auto-Scaling Policy by ID +or an instance of class +:class:`~otcextensions.sdk.auto_scaling.v1.policy.Policy`. + +.. literalinclude:: ../examples/auto_scaling/get_policy.py + :lines: 16-24 + +Find Policy +^^^^^^^^^^^ + +This interface is used to find an Auto-Scaling Policy instance by +name or id. + +.. literalinclude:: ../examples/auto_scaling/find_policy.py + :lines: 16-24 + +Delete Policy +^^^^^^^^^^^^^ + +This interface is used to delete an Auto-Scaling Policy instance by id +or an instance of class +:class:`~otcextensions.sdk.auto_scaling.v1.policy.Policy`. + +.. literalinclude:: ../examples/auto_scaling/delete_policy.py + :lines: 16-23 + +Update Policy +^^^^^^^^^^^^^ + +This interface is used to update an Auto-Scaling Policy instance by +using policy's id or an instance of class +:class:`~otcextensions.sdk.auto_scaling.v1.policy.Policy` and provide new +attributes. + +.. literalinclude:: ../examples/auto_scaling/update_policy.py + :lines: 16-39 + +Pause Policy +^^^^^^^^^^^^ + +This interface is used to pause an Auto-Scaling Policy instance in +passive state by using id or an instance of +class :class:`~otcextensions.sdk.auto_scaling.v1.policy.Policy`. + +.. literalinclude:: ../examples/auto_scaling/pause_policy.py + :lines: 16-25 + +Resume Policy +^^^^^^^^^^^^^ + +This interface is used to resume an Auto-Scaling Policy instance in +active state by using id or an instance of +class :class:`~otcextensions.sdk.auto_scaling.v1.policy.Policy`. + +.. literalinclude:: ../examples/auto_scaling/resume_policy.py + :lines: 16-25 + +Execute Policy +^^^^^^^^^^^^^^ + +This interface is used to execute an Auto-Scaling Policy instance and +run the defined actions. + +.. literalinclude:: ../examples/auto_scaling/execute_policy.py + :lines: 16-25 + +Auto-Scaling Instance +--------------------- + +An Auto-Scaling (AS) Instance is the executive unit of an Auto-Scaling group. + +List Instances +^^^^^^^^^^^^^^ + +This interface is used to query all Auto-Scaling Instances of an AS group +and to filter the output with query parameters. + +.. literalinclude:: ../examples/auto_scaling/list_instances.py + :lines: 16-25 + +Remove Instance +^^^^^^^^^^^^^^^ + +This interface is used to remove an Auto-Scaling Instances of an AS group. + +.. literalinclude:: ../examples/auto_scaling/remove_instance.py + :lines: 16-26 + +Batch Action Instance +^^^^^^^^^^^^^^^^^^^^^ + +This interface is used to run actions on an Auto-Scaling group by adding +or deleting instance. + +.. literalinclude:: ../examples/auto_scaling/batch_instance_action.py + :lines: 16-37 + +Auto-Scaling Actions and Quotas +------------------------------- + +Auto-Scaling quotas and query scaling action logs can be querried. + +List Scaling Actions +^^^^^^^^^^^^^^^^^^^^ + +This interface is used to query all Auto-Scaling scaling action logs +of an AS group and to filter the output with query parameters. + +.. literalinclude:: ../examples/auto_scaling/list_activities.py + :lines: 16-27 + +List User or Group Quota for Auto-Scaling +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +This interface is used to query all Auto-Scaling quotas of an AS group +or a user and to filter the output with query parameters. + +.. literalinclude:: ../examples/auto_scaling/list_quotas.py + :lines: 16-27 diff --git a/doc/source/sdk/guides/cce.rst b/doc/source/sdk/guides/cce.rst new file mode 100644 index 000000000..a5925356b --- /dev/null +++ b/doc/source/sdk/guides/cce.rst @@ -0,0 +1,145 @@ +Cloud Container Engine (CCE) +============================ + +.. contents:: Table of Contents + :local: + +CCE Cluster +----------- + +Cloud Container Engine (CCE) is a highly reliable and high-performance service +that allows enterprises to manage containerized applications. With support +for Kubernetes-native applications and tools, CCE makes it simple to set up +an environment for running containers in the cloud. CCE Clusters are the +environment where cluster nodes are administrated. The core component +is a Kubernetes Cluster with advanced features. + +List CCE Clusters +^^^^^^^^^^^^^^^^^ + +This interface is used to query all CCE clusters and to filter +the output with query parameters. + +.. literalinclude:: ../examples/cce/list_clusters.py + :lines: 16-22 + +Create CCE Cluster +^^^^^^^^^^^^^^^^^^ + +This interface is used to create a CCE cluster instance with +parameters. + +.. literalinclude:: ../examples/cce/create_cluster.py + :lines: 16-53 + +Get CCE Cluster +^^^^^^^^^^^^^^^ + +This interface is used to get a CCE cluster by ID +or an instance of class +:class:`~otcextensions.sdk.cce.v3.cluster.Cluster`. + +.. literalinclude:: ../examples/cce/get_cluster.py + :lines: 16-24 + +Find CCE Cluster +^^^^^^^^^^^^^^^^ + +This interface is used to find a CCE cluster by ID +or name. + +.. literalinclude:: ../examples/cce/find_cluster.py + :lines: 16-24 + +Delete CCE Cluster +^^^^^^^^^^^^^^^^^^ + +This interface is used to get a CCE cluster by ID +or an instance of class +:class:`~otcextensions.sdk.cce.v3.cluster.Cluster`. + +.. literalinclude:: ../examples/cce/delete_cluster.py + :lines: 16-25 + +CCE Node +-------- + +A CCE cluster node is the computing instance of a CCE cluster where +containers are hosted. One cluster can manage several nodes which +can be distributed over different availability zones to increase +reliability. + +List CCE Cluster Nodes +^^^^^^^^^^^^^^^^^^^^^^ + +This interface is used to query all nodes of a CCE cluster +and to filter the output with query parameters. + +.. literalinclude:: ../examples/cce/list_cluster_nodes.py + :lines: 16-25 + +Create CCE Cluster Node +^^^^^^^^^^^^^^^^^^^^^^^ + +This interface is used to create a CCE cluster node instance with +parameters. + +.. literalinclude:: ../examples/cce/create_cluster_node.py + :lines: 16-53 + +Get CCE Cluster Node +^^^^^^^^^^^^^^^^^^^^ + +This interface is used to get a CCE cluster by ID +or an instance of class +:class:`~otcextensions.sdk.cce.v3.cluster_node.ClusterNode`. + +.. literalinclude:: ../examples/cce/get_cluster_node.py + :lines: 16-26 + +Find CCE Cluster Node +^^^^^^^^^^^^^^^^^^^^^ + +This interface is used to find a node of a CCE cluster by ID +or name. + +.. literalinclude:: ../examples/cce/find_cluster_node.py + :lines: 16-26 + +Delete CCE Cluster Node +^^^^^^^^^^^^^^^^^^^^^^^ + +This interface is used to delete a CCE cluster node by ID +or an instance of class +:class:`~otcextensions.sdk.cce.v3.cluster_node.ClusterNode`. + +.. literalinclude:: ../examples/cce/delete_cluster_node.py + :lines: 16-25 + +Job Operations +-------------- + +Jobs are created while cluster creation and other similar operations +have been started. Jobs have different phases and can be triggered by +the following methods. + +Get Job +^^^^^^^ + +This interface is used to get a CCE Job by ID +or an instance of class +:class:`~otcextensions.sdk.cce.v3.job.Job`. + +.. literalinclude:: ../examples/cce/get_job.py + :lines: 16-24 + +Wait for a Job +^^^^^^^^^^^^^^ + +This interface is used to wait for a CCE Job until reaches a specific state +by using ID or an instance of class +:class:`~otcextensions.sdk.cce.v3.job.Job`. + +.. literalinclude:: ../examples/cce/wait_for_job.py + :lines: 16-24 + diff --git a/doc/source/user/guides/deh.rst b/doc/source/sdk/guides/deh.rst similarity index 88% rename from doc/source/user/guides/deh.rst rename to doc/source/sdk/guides/deh.rst index 81ce7493e..8e0f49bfd 100644 --- a/doc/source/user/guides/deh.rst +++ b/doc/source/sdk/guides/deh.rst @@ -1,10 +1,5 @@ -Using OTC DeH -============= - -Before working with the Dedicated Host service, you'll need to create a -connection to your OTC cloud account by following the :doc:`connect_otc` user -guide. This will provide you with the ``conn`` variable used in the examples -below. +Dedicated Hosts (DeH) +===================== .. contents:: Table of Contents :local: diff --git a/doc/source/sdk/guides/index.rst b/doc/source/sdk/guides/index.rst new file mode 100644 index 000000000..75ecb8427 --- /dev/null +++ b/doc/source/sdk/guides/index.rst @@ -0,0 +1,38 @@ +Guides for SDK +============== + +Open Telekom Cloud related User Guides +-------------------------------------- + +.. toctree:: + :maxdepth: 1 + + anti_ddos + auto_scaling + cce + deh + logging + +.. _user_guides: + +User Guides +----------- + +SOME TEXT XXX. + +OpenStack native User Guides +---------------------------- + +.. toctree:: + :maxdepth: 1 + + Block Storage + Compute + Identity + Image + Key Manager + Message + Microversions + Network + Object Store + Using Cloud Abstration Layer diff --git a/doc/source/user/guides/logging.rst b/doc/source/sdk/guides/logging.rst similarity index 100% rename from doc/source/user/guides/logging.rst rename to doc/source/sdk/guides/logging.rst diff --git a/doc/source/sdk/index.rst b/doc/source/sdk/index.rst new file mode 100644 index 000000000..5232713d3 --- /dev/null +++ b/doc/source/sdk/index.rst @@ -0,0 +1,26 @@ +Using the OpenStack SDK +======================= + +.. toctree:: + :maxdepth: 1 + + architecture + getting_started + guides/index + proxies/index + +The OTC Extensions contain an abstraction interface layer. Clouds can +do many things, but there are probably only about 10 of them that most +people care about with any regularity. + +If you want to do complicated things, the per-service oriented +portions of the SDK are for you. + +However, if what you want is to be able to write an application that +talks to clouds no matter what crazy choices the deployer has made in +an attempt to be more hipster than their self-entitled narcissist +peers, then the Cloud Abstraction layer is for you. + +OTC Extensions provide an extension to the OpenStackSDK. Refer to its +documentation for the details: +. diff --git a/doc/source/user/proxies/anti_ddos.rst b/doc/source/sdk/proxies/anti_ddos.rst similarity index 100% rename from doc/source/user/proxies/anti_ddos.rst rename to doc/source/sdk/proxies/anti_ddos.rst diff --git a/doc/source/user/proxies/auto_scaling.rst b/doc/source/sdk/proxies/auto_scaling.rst similarity index 93% rename from doc/source/user/proxies/auto_scaling.rst rename to doc/source/sdk/proxies/auto_scaling.rst index c28d501e4..b8f29f1e1 100644 --- a/doc/source/user/proxies/auto_scaling.rst +++ b/doc/source/sdk/proxies/auto_scaling.rst @@ -1,16 +1,17 @@ AutoScaling API =============== -For details on how to use auto scaling, see :doc:`/user/guides/auto_scaling` +For details on how to use auto scaling, see /sdk/guides/auto_scaling +(NEEDS TO BE DONE). .. automodule:: otcextensions.sdk.auto_scaling.v1._proxy The AutoScaling Class --------------------- -The AS high-level interface is available through the ``auto_scaling`` member of -a :class:`~openstack.connection.Connection` object. The ``auto_scaling`` -member will only be added if the +The AS high-level interface is available through the ``auto_scaling`` +member of a :class:`~openstack.connection.Connection` object. The +``auto_scaling`` member will only be added if the ``otcextensions.sdk.register_otc_extensions(conn)`` method is called. Group Operations diff --git a/doc/source/user/proxies/cce_v1.rst b/doc/source/sdk/proxies/cce_v1.rst similarity index 100% rename from doc/source/user/proxies/cce_v1.rst rename to doc/source/sdk/proxies/cce_v1.rst diff --git a/doc/source/user/proxies/cce_v3.rst b/doc/source/sdk/proxies/cce_v3.rst similarity index 100% rename from doc/source/user/proxies/cce_v3.rst rename to doc/source/sdk/proxies/cce_v3.rst diff --git a/doc/source/user/proxies/cts.rst b/doc/source/sdk/proxies/cts.rst similarity index 100% rename from doc/source/user/proxies/cts.rst rename to doc/source/sdk/proxies/cts.rst diff --git a/doc/source/user/proxies/dcs.rst b/doc/source/sdk/proxies/dcs.rst similarity index 100% rename from doc/source/user/proxies/dcs.rst rename to doc/source/sdk/proxies/dcs.rst diff --git a/doc/source/user/proxies/deh.rst b/doc/source/sdk/proxies/deh.rst similarity index 100% rename from doc/source/user/proxies/deh.rst rename to doc/source/sdk/proxies/deh.rst diff --git a/doc/source/user/proxies/dms.rst b/doc/source/sdk/proxies/dms.rst similarity index 100% rename from doc/source/user/proxies/dms.rst rename to doc/source/sdk/proxies/dms.rst diff --git a/doc/source/user/proxies/dns.rst b/doc/source/sdk/proxies/dns.rst similarity index 100% rename from doc/source/user/proxies/dns.rst rename to doc/source/sdk/proxies/dns.rst diff --git a/doc/source/sdk/proxies/index.rst b/doc/source/sdk/proxies/index.rst new file mode 100644 index 000000000..e3a8de280 --- /dev/null +++ b/doc/source/sdk/proxies/index.rst @@ -0,0 +1,53 @@ +Service Proxies +=============== + +.. toctree:: + :maxdepth: 1 + + Anti DDoS Service + AutoScaling Service + Cloud Container Engine v1 + Cloud Container Engine v2 + Cloud Trace Service + Distributed Cache Service + Dedicated Host Service + Distributed Message Service + DNS Service + Key Management Service + Object Block Storage + Volume Backup Service + Relational Database Service RDS V1 + Relational Database Service RDS V3 + +.. _service-proxies: + +Service Proxies +--------------- + +The following service proxies exist on the +:class:`~openstack.connection.Connection`. The service proxies are all always +present on the :class:`~openstack.connection.Connection` object, but the +combination of your ``CloudRegion`` and the catalog of the cloud in question +control which services can be used. + +Links to Native OpenStack Service Proxies +----------------------------------------- + +.. toctree:: + :maxdepth: 1 + + Block Storage + Compute + Database + Identity v2 + Identity v3 + Image v1 + Image v2 + Key Manager + Load Balancer + Message v2 + Network + Object Store + Orchestration + Workflow + diff --git a/doc/source/user/proxies/kms.rst b/doc/source/sdk/proxies/kms.rst similarity index 100% rename from doc/source/user/proxies/kms.rst rename to doc/source/sdk/proxies/kms.rst diff --git a/doc/source/user/proxies/obs.rst b/doc/source/sdk/proxies/obs.rst similarity index 94% rename from doc/source/user/proxies/obs.rst rename to doc/source/sdk/proxies/obs.rst index e23e34c89..218c15806 100644 --- a/doc/source/user/proxies/obs.rst +++ b/doc/source/sdk/proxies/obs.rst @@ -1,7 +1,7 @@ ObjectBlockStorage OBS API ========================== -For details on how to use database, see :doc:`/user/guides/obs` +For details on how to use database, see /user/guides/obs (NEEDS TO BE DONE) .. automodule:: otcextensions.sdk.obs.v1._proxy diff --git a/doc/source/user/proxies/rds_v1.rst b/doc/source/sdk/proxies/rds_v1.rst similarity index 96% rename from doc/source/user/proxies/rds_v1.rst rename to doc/source/sdk/proxies/rds_v1.rst index 55b991b86..76559f583 100644 --- a/doc/source/user/proxies/rds_v1.rst +++ b/doc/source/sdk/proxies/rds_v1.rst @@ -1,7 +1,7 @@ Database RDS API ================ -For details on how to use database, see :doc:`/user/guides/rds` +For details on how to use database, see /user/guides/rds (NEEDS TO BE DONE) .. automodule:: otcextensions.sdk.rds.v1._proxy diff --git a/doc/source/sdk/proxies/rds_v3.rst b/doc/source/sdk/proxies/rds_v3.rst new file mode 100644 index 000000000..b75b39e44 --- /dev/null +++ b/doc/source/sdk/proxies/rds_v3.rst @@ -0,0 +1,69 @@ +Database RDS API +================ + +For details on how to use database, see /sdk/guides/rds (NEEDS TO BE DONE) + +.. automodule:: otcextensions.sdk.rds.v3._proxy + +The Database Class +------------------ + +The database high-level interface is available through the ``rds`` member of a +:class:`~openstack.connection.Connection` object. The ``rds`` member will only +be added if the ``otcextensions.sdk.register_otc_extensions(conn)`` method is +called. + +Datastore Operations +^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: otcextensions.sdk.rds.v3._proxy.Proxy + + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.datastore_types + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.datastores + +Flavor Operations +^^^^^^^^^^^^^^^^^ + +.. autoclass:: otcextensions.sdk.rds.v3._proxy.Proxy + + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.flavors + +Instance Operations +^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: otcextensions.sdk.rds.v3._proxy.Proxy + + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.create_instance + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.delete_instance + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.get_instance + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.find_instance + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.instances + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.restore_instance + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.get_instance_restore_time + +Backup Operations +^^^^^^^^^^^^^^^^^ + +.. autoclass:: otcextensions.sdk.rds.v3._proxy.Proxy + + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.backups + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.create_backup + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.delete_backup + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.find_backup + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.backup_download_links + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.get_instance_backup_policy + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.set_instance_backup_policy + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.wait_for_backup + +Configuration Operations +^^^^^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: otcextensions.sdk.rds.v3._proxy.Proxy + + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.configurations + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.get_configuration + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.find_configuration + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.create_configuration + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.delete_configuration + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.update_configuration + .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.apply_configuration diff --git a/doc/source/user/proxies/volume_backup.rst b/doc/source/sdk/proxies/volume_backup.rst similarity index 81% rename from doc/source/user/proxies/volume_backup.rst rename to doc/source/sdk/proxies/volume_backup.rst index 2802809b7..4540a70a0 100644 --- a/doc/source/user/proxies/volume_backup.rst +++ b/doc/source/sdk/proxies/volume_backup.rst @@ -1,16 +1,18 @@ VolumeBackup API ================ -For details on how to use auto scaling, see :doc:`/user/guides/volume_backup` +For details on how to use auto scaling, see /sdk/guides/volume_backup +(NEEDS TO BE DONE). .. automodule:: otcextensions.sdk.volume_backup.v2._proxy The VolumeBackup Class ---------------------- -The VBS high-level interface is available through the ``volume_backup`` member -of a :class:`~openstack.connection.Connection` object. The ``volume_backup`` -member will only be added if the +The VBS high-level interface is available through the +``volume_backup`` member of a +:class:`~openstack.connection.Connection` object. The +``volume_backup`` member will only be added if the ``otcextensions.sdk.register_otc_extensions(conn)`` method is called. The Backup itself is an OpenStack entity and supported natively as diff --git a/doc/source/user/config/configuration.rst b/doc/source/user/config/configuration.rst deleted file mode 100644 index 1cdd0ec10..000000000 --- a/doc/source/user/config/configuration.rst +++ /dev/null @@ -1,322 +0,0 @@ -.. _openstack-config: - -====================================== -Configuring OpenStack SDK Applications -====================================== - -.. _config-environment-variables: - -Environment Variables ---------------------- - -`openstacksdk` honors all of the normal `OS_*` variables. It does not -provide backwards compatibility to service-specific variables such as -`NOVA_USERNAME`. - -If you have OpenStack environment variables set, `openstacksdk` will -produce a cloud config object named `envvars` containing your values from the -environment. If you don't like the name `envvars`, that's ok, you can override -it by setting `OS_CLOUD_NAME`. - -Service specific settings, like the nova service type, are set with the -default service type as a prefix. For instance, to set a special service_type -for trove set - -.. code-block:: bash - - export OS_DATABASE_SERVICE_TYPE=rax:database - -.. _config-clouds-yaml: - -Config Files ------------- - -`openstacksdk` will look for a file called `clouds.yaml` in the following -locations: - -* Current Directory -* ~/.config/openstack -* /etc/openstack - -The first file found wins. - -You can also set the environment variable `OS_CLIENT_CONFIG_FILE` to an -absolute path of a file to look for and that location will be inserted at the -front of the file search list. - -The keys are all of the keys you'd expect from `OS_*` - except lower case -and without the OS prefix. So, region name is set with `region_name`. - -Service specific settings, like the nova service type, are set with the -default service type as a prefix. For instance, to set a special service_type -for trove (because you're using Rackspace) set: - -.. code-block:: yaml - - database_service_type: 'rax:database' - - -Site Specific File Locations -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -In addition to `~/.config/openstack` and `/etc/openstack` - some platforms -have other locations they like to put things. `openstacksdk` will also -look in an OS specific config dir - -* `USER_CONFIG_DIR` -* `SITE_CONFIG_DIR` - -`USER_CONFIG_DIR` is different on Linux, OSX and Windows. - -* Linux: `~/.config/openstack` -* OSX: `~/Library/Application Support/openstack` -* Windows: `C:\\Users\\USERNAME\\AppData\\Local\\OpenStack\\openstack` - -`SITE_CONFIG_DIR` is different on Linux, OSX and Windows. - -* Linux: `/etc/openstack` -* OSX: `/Library/Application Support/openstack` -* Windows: `C:\\ProgramData\\OpenStack\\openstack` - -An example config file is probably helpful: - -.. code-block:: yaml - - clouds: - mtvexx: - profile: vexxhost - auth: - username: mordred@inaugust.com - password: XXXXXXXXX - project_name: mordred@inaugust.com - region_name: ca-ymq-1 - dns_api_version: 1 - mordred: - region_name: RegionOne - auth: - username: 'mordred' - password: XXXXXXX - project_name: 'shade' - auth_url: 'https://montytaylor-sjc.openstack.blueboxgrid.com:5001/v2.0' - infra: - profile: rackspace - auth: - username: openstackci - password: XXXXXXXX - project_id: 610275 - regions: - - DFW - - ORD - - IAD - -You may note a few things. First, since `auth_url` settings are silly -and embarrassingly ugly, known cloud vendor profile information is included and -may be referenced by name. One of the benefits of that is that `auth_url` -isn't the only thing the vendor defaults contain. For instance, since -Rackspace lists `rax:database` as the service type for trove, `openstacksdk` -knows that so that you don't have to. In case the cloud vendor profile is not -available, you can provide one called `clouds-public.yaml`, following the same -location rules previously mentioned for the config files. - -`regions` can be a list of regions. When you call `get_all_clouds`, -you'll get a cloud config object for each cloud/region combo. - -As seen with `dns_service_type`, any setting that makes sense to be -per-service, like `service_type` or `endpoint` or `api_version` can be set -by prefixing the setting with the default service type. That might strike you -funny when setting `service_type` and it does me too - but that's just the -world we live in. - -Auth Settings -------------- - -Keystone has auth plugins - which means it's not possible to know ahead of time -which auth settings are needed. `openstacksdk` sets the default plugin type -to `password`, which is what things all were before plugins came about. In -order to facilitate validation of values, all of the parameters that exist -as a result of a chosen plugin need to go into the auth dict. For password -auth, this includes `auth_url`, `username` and `password` as well as anything -related to domains, projects and trusts. - -Splitting Secrets ------------------ - -In some scenarios, such as configuration management controlled environments, -it might be easier to have secrets in one file and non-secrets in another. -This is fully supported via an optional file `secure.yaml` which follows all -the same location rules as `clouds.yaml`. It can contain anything you put -in `clouds.yaml` and will take precedence over anything in the `clouds.yaml` -file. - -.. code-block:: yaml - - # clouds.yaml - clouds: - internap: - profile: internap - auth: - username: api-55f9a00fb2619 - project_name: inap-17037 - regions: - - ams01 - - nyj01 - # secure.yaml - clouds: - internap: - auth: - password: XXXXXXXXXXXXXXXXX - -SSL Settings ------------- - -When the access to a cloud is done via a secure connection, `openstacksdk` -will always verify the SSL cert by default. This can be disabled by setting -`verify` to `False`. In case the cert is signed by an unknown CA, a specific -cacert can be provided via `cacert`. **WARNING:** `verify` will always have -precedence over `cacert`, so when setting a CA cert but disabling `verify`, the -cloud cert will never be validated. - -Client certs are also configurable. `cert` will be the client cert file -location. In case the cert key is not included within the client cert file, -its file location needs to be set via `key`. - -.. code-block:: yaml - - # clouds.yaml - clouds: - regular-secure-cloud: - auth: - auth_url: https://signed.cert.domain:5000 - ... - unknown-ca-with-client-cert-secure-cloud: - auth: - auth_url: https://unknown.ca.but.secure.domain:5000 - ... - key: /home/myhome/client-cert.key - cert: /home/myhome/client-cert.crt - cacert: /home/myhome/ca.crt - self-signed-insecure-cloud: - auth: - auth_url: https://self.signed.cert.domain:5000 - ... - verify: False - -Note for parity with ``openstack`` command-line options the `insecure` -boolean is also recognised (with the opposite semantics to `verify`; -i.e. `True` ignores certificate failures). This should be considered -deprecated for `verify`. - -Cache Settings --------------- - -Accessing a cloud is often expensive, so it's quite common to want to do some -client-side caching of those operations. To facilitate that, `openstacksdk` -understands passing through cache settings to dogpile.cache, with the following -behaviors: - -* Listing no config settings means you get a null cache. -* `cache.expiration_time` and nothing else gets you memory cache. -* Otherwise, `cache.class` and `cache.arguments` are passed in - -Different cloud behaviors are also differently expensive to deal with. If you -want to get really crazy and tweak stuff, you can specify different expiration -times on a per-resource basis by passing values, in seconds to an expiration -mapping keyed on the singular name of the resource. A value of `-1` indicates -that the resource should never expire. - -`openstacksdk` does not actually cache anything itself, but it collects -and presents the cache information so that your various applications that -are connecting to OpenStack can share a cache should you desire. - -.. code-block:: yaml - - cache: - class: dogpile.cache.pylibmc - expiration_time: 3600 - arguments: - url: - - 127.0.0.1 - expiration: - server: 5 - flavor: -1 - clouds: - mtvexx: - profile: vexxhost - auth: - username: mordred@inaugust.com - password: XXXXXXXXX - project_name: mordred@inaugust.com - region_name: ca-ymq-1 - dns_api_version: 1 - - -IPv6 ----- - -IPv6 is the future, and you should always use it if your cloud supports it and -if your local network supports it. Both of those are easily detectable and all -friendly software should do the right thing. However, sometimes you might -exist in a location where you have an IPv6 stack, but something evil has -caused it to not actually function. In that case, there is a config option -you can set to unbreak you `force_ipv4`, or `OS_FORCE_IPV4` boolean -environment variable. - -.. code-block:: yaml - - client: - force_ipv4: true - clouds: - mtvexx: - profile: vexxhost - auth: - username: mordred@inaugust.com - password: XXXXXXXXX - project_name: mordred@inaugust.com - region_name: ca-ymq-1 - dns_api_version: 1 - monty: - profile: rax - auth: - username: mordred@inaugust.com - password: XXXXXXXXX - project_name: mordred@inaugust.com - region_name: DFW - -The above snippet will tell client programs to prefer returning an IPv4 -address. - -Per-region settings -------------------- - -Sometimes you have a cloud provider that has config that is common to the -cloud, but also with some things you might want to express on a per-region -basis. For instance, Internap provides a public and private network specific -to the user in each region, and putting the values of those networks into -config can make consuming programs more efficient. - -To support this, the region list can actually be a list of dicts, and any -setting that can be set at the cloud level can be overridden for that -region. - -.. code-block:: yaml - - clouds: - internap: - profile: internap - auth: - password: XXXXXXXXXXXXXXXXX - username: api-55f9a00fb2619 - project_name: inap-17037 - regions: - - name: ams01 - values: - networks: - - name: inap-17037-WAN1654 - routes_externally: true - - name: inap-17037-LAN6745 - - name: nyj01 - values: - networks: - - name: inap-17037-WAN1654 - routes_externally: true - - name: inap-17037-LAN6745 diff --git a/doc/source/user/config/index.rst b/doc/source/user/config/index.rst deleted file mode 100644 index 11637239d..000000000 --- a/doc/source/user/config/index.rst +++ /dev/null @@ -1,12 +0,0 @@ -====================== -Using os-client-config -====================== - -.. toctree:: - :maxdepth: 2 - - configuration - using - vendor-support - network-config - reference diff --git a/doc/source/user/config/network-config.rst b/doc/source/user/config/network-config.rst deleted file mode 100644 index ea8541478..000000000 --- a/doc/source/user/config/network-config.rst +++ /dev/null @@ -1,67 +0,0 @@ -============== -Network Config -============== - -There are several different qualities that networks in OpenStack might have -that might not be able to be automatically inferred from the available -metadata. To help users navigate more complex setups, `os-client-config` -allows configuring a list of network metadata. - -.. code-block:: yaml - - clouds: - amazing: - networks: - - name: blue - routes_externally: true - - name: purple - routes_externally: true - default_interface: true - - name: green - routes_externally: false - - name: yellow - routes_externally: false - nat_destination: true - - name: chartreuse - routes_externally: false - routes_ipv6_externally: true - - name: aubergine - routes_ipv4_externally: false - routes_ipv6_externally: true - -Every entry must have a name field, which can hold either the name or the id -of the network. - -`routes_externally` is a boolean field that labels the network as handling -north/south traffic off of the cloud. In a public cloud this might be thought -of as the "public" network, but in private clouds it's possible it might -be an RFC1918 address. In either case, it's provides IPs to servers that -things not on the cloud can use. This value defaults to `false`, which -indicates only servers on the same network can talk to it. - -`routes_ipv4_externally` and `routes_ipv6_externally` are boolean fields to -help handle `routes_externally` in the case where a network has a split stack -with different values for IPv4 and IPv6. Either entry, if not given, defaults -to the value of `routes_externally`. - -`default_interface` is a boolean field that indicates that the network is the -one that programs should use. It defaults to false. An example of needing to -use this value is a cloud with two private networks, and where a user is -running ansible in one of the servers to talk to other servers on the private -network. Because both networks are private, there would otherwise be no way -to determine which one should be used for the traffic. There can only be one -`default_interface` per cloud. - -`nat_destination` is a boolean field that indicates which network floating -ips should be attached to. It defaults to false. Normally this can be inferred -by looking for a network that has subnets that have a gateway_ip. But it's -possible to have more than one network that satisfies that condition, so the -user might want to tell programs which one to pick. There can be only one -`nat_destination` per cloud. - -`nat_source` is a boolean field that indicates which network floating -ips should be requested from. It defaults to false. Normally this can be -inferred by looking for a network that is attached to a router. But it's -possible to have more than one network that satisfies that condition, so the -user might want to tell programs which one to pick. There can be only one -`nat_source` per cloud. diff --git a/doc/source/user/config/reference.rst b/doc/source/user/config/reference.rst deleted file mode 100644 index b4909ad32..000000000 --- a/doc/source/user/config/reference.rst +++ /dev/null @@ -1,14 +0,0 @@ -============= -API Reference -============= - -.. module:: openstack.config - :synopsis: OpenStack client configuration - -.. autoclass:: openstack.config.OpenStackConfig - :members: - :inherited-members: - -.. autoclass:: openstack.config.cloud_region.CloudRegion - :members: - :inherited-members: diff --git a/doc/source/user/config/using.rst b/doc/source/user/config/using.rst deleted file mode 100644 index 7792989cf..000000000 --- a/doc/source/user/config/using.rst +++ /dev/null @@ -1,58 +0,0 @@ -======================================== -Using openstack.config in an Application -======================================== - -Usage ------ - -The simplest and least useful thing you can do is: - -.. code-block:: python - - python -m openstack.config.loader - -Which will print out whatever if finds for your config. If you want to use -it from python, which is much more likely what you want to do, things like: - -Get a named cloud. - -.. code-block:: python - - import openstack.config - - cloud_region = openstack.config.OpenStackConfig().get_one( - 'internap', region_name='ams01') - print(cloud_region.name, cloud_region.region, cloud_region.config) - -Or, get all of the clouds. - -.. code-block:: python - - import openstack.config - - cloud_regions = openstack.config.OpenStackConfig().get_all() - for cloud_region in cloud_regions: - print(cloud_region.name, cloud_region.region, cloud_region.config) - -argparse --------- - -If you're using `openstack.config` from a program that wants to process -command line options, there is a registration function to register the -arguments that both `openstack.config` and keystoneauth know how to deal -with - as well as a consumption argument. - -.. code-block:: python - - import argparse - import sys - - import openstack.config - - config = openstack.config.OpenStackConfig() - parser = argparse.ArgumentParser() - config.register_argparse_arguments(parser, sys.argv) - - options = parser.parse_args() - - cloud_region = config.get_one(argparse=options) diff --git a/doc/source/user/config/vendor-support.rst b/doc/source/user/config/vendor-support.rst deleted file mode 100644 index 4143da248..000000000 --- a/doc/source/user/config/vendor-support.rst +++ /dev/null @@ -1,343 +0,0 @@ -============== -Vendor Support -============== - -OpenStack presents deployers with many options, some of which can expose -differences to end users. `os-client-config` tries its best to collect -information about various things a user would need to know. The following -is a text representation of the vendor related defaults `os-client-config` -knows about. - -Default Values --------------- - -These are the default behaviors unless a cloud is configured differently. - -* Identity uses `password` authentication -* Identity API Version is 2 -* Image API Version is 2 -* Volume API Version is 2 -* Compute API Version is 2.1 -* Images must be in `qcow2` format -* Images are uploaded using PUT interface -* Public IPv4 is directly routable via DHCP from Neutron -* IPv6 is not provided -* Floating IPs are not required -* Floating IPs are provided by Neutron -* Security groups are provided by Neutron -* Vendor specific agents are not used - -AURO ----- - -https://api.auro.io:5000/v2.0 - -============== ================ -Region Name Location -============== ================ -van1 Vancouver, BC -============== ================ - -* Public IPv4 is provided via NAT with Neutron Floating IP - -Betacloud ---------- - -https://api-1.betacloud.io:5000 - -============== ================== -Region Name Location -============== ================== -betacloud-1 Nuremberg, Germany -============== ================== - -* Identity API Version is 3 -* Images must be in `raw` format -* Public IPv4 is provided via NAT with Neutron Floating IP -* Volume API Version is 3 - -Catalyst --------- - -https://api.cloud.catalyst.net.nz:5000/v2.0 - -============== ================ -Region Name Location -============== ================ -nz-por-1 Porirua, NZ -nz_wlg_2 Wellington, NZ -============== ================ - -* Identity API Version is 3 -* Compute API Version is 2 -* Images must be in `raw` format -* Volume API Version is 3 - -City Cloud ----------- - -https://identity1.citycloud.com:5000/v3/ - -============== ================ -Region Name Location -============== ================ -Buf1 Buffalo, NY -Fra1 Frankfurt, DE -Kna1 Karlskrona, SE -La1 Los Angeles, CA -Lon1 London, UK -Sto2 Stockholm, SE -============== ================ - -* Identity API Version is 3 -* Public IPv4 is provided via NAT with Neutron Floating IP -* Volume API Version is 1 - -ConoHa ------- - -https://identity.%(region_name)s.conoha.io - -============== ================ -Region Name Location -============== ================ -tyo1 Tokyo, JP -sin1 Singapore -sjc1 San Jose, CA -============== ================ - -* Image upload is not supported - -DreamCompute ------------- - -https://iad2.dream.io:5000 - -============== ================ -Region Name Location -============== ================ -RegionOne Ashburn, VA -============== ================ - -* Identity API Version is 3 -* Images must be in `raw` format -* IPv6 is provided to every server - -Open Telekom Cloud ------------------- - -https://iam.%(region_name)s.otc.t-systems.com/v3 - -============== ================ -Region Name Location -============== ================ -eu-de Germany -============== ================ - -* Identity API Version is 3 -* Images must be in `vhd` format -* Public IPv4 is provided via NAT with Neutron Floating IP - -ELASTX ------- - -https://ops.elastx.net:5000/v2.0 - -============== ================ -Region Name Location -============== ================ -regionOne Stockholm, SE -============== ================ - -* Public IPv4 is provided via NAT with Neutron Floating IP - -Enter Cloud Suite ------------------ - -https://api.entercloudsuite.com/v2.0 - -============== ================ -Region Name Location -============== ================ -nl-ams1 Amsterdam, NL -it-mil1 Milan, IT -de-fra1 Frankfurt, DE -============== ================ - -* Compute API Version is 2 - -Fuga ----- - -https://identity.api.fuga.io:5000 - -============== ================ -Region Name Location -============== ================ -cystack Netherlands -============== ================ - -* Identity API Version is 3 -* Volume API Version is 3 - -Internap --------- - -https://identity.api.cloud.iweb.com/v2.0 - -============== ================ -Region Name Location -============== ================ -ams01 Amsterdam, NL -da01 Dallas, TX -nyj01 New York, NY -sin01 Singapore -sjc01 San Jose, CA -============== ================ - -* Floating IPs are not supported - -Limestone Networks ------------------- - -https://auth.cloud.lstn.net:5000/v3 - -============== ================== -Region Name Location -============== ================== -us-dfw-1 Dallas, TX -us-slc Salt Lake City, UT -============== ================== - -* Identity API Version is 3 -* Images must be in `raw` format -* IPv6 is provided to every server connected to the `Public Internet` network - -OVH ---- - -https://auth.cloud.ovh.net/v2.0 - -============== ================ -Region Name Location -============== ================ -BHS1 Beauharnois, QC -SBG1 Strassbourg, FR -GRA1 Gravelines, FR -============== ================ - -* Images may be in `raw` format. The `qcow2` default is also supported -* Floating IPs are not supported - -Rackspace ---------- - -https://identity.api.rackspacecloud.com/v2.0/ - -============== ================ -Region Name Location -============== ================ -DFW Dallas, TX -HKG Hong Kong -IAD Washington, D.C. -LON London, UK -ORD Chicago, IL -SYD Sydney, NSW -============== ================ - -* Database Service Type is `rax:database` -* Compute Service Name is `cloudServersOpenStack` -* Images must be in `vhd` format -* Images must be uploaded using the Glance Task Interface -* Floating IPs are not supported -* Public IPv4 is directly routable via static config by Nova -* IPv6 is provided to every server -* Security groups are not supported -* Uploaded Images need properties to not use vendor agent:: - :vm_mode: hvm - :xenapi_use_agent: False -* Volume API Version is 1 -* While passwords are recommended for use, API keys do work as well. - The `rackspaceauth` python package must be installed, and then the following - can be added to clouds.yaml:: - - auth: - username: myusername - api_key: myapikey - auth_type: rackspace_apikey - -SWITCHengines -------------- - -https://keystone.cloud.switch.ch:5000/v2.0 - -============== ================ -Region Name Location -============== ================ -LS Lausanne, CH -ZH Zurich, CH -============== ================ - -* Identity API Version is 3 -* Compute API Version is 2 -* Images must be in `raw` format -* Volume API Version is 3 - -Ultimum -------- - -https://console.ultimum-cloud.com:5000/v2.0 - -============== ================ -Region Name Location -============== ================ -RegionOne Prague, CZ -============== ================ - -* Volume API Version is 1 - -UnitedStack ------------ - -https://identity.api.ustack.com/v3 - -============== ================ -Region Name Location -============== ================ -bj1 Beijing, CN -gd1 Guangdong, CN -============== ================ - -* Identity API Version is 3 -* Images must be in `raw` format -* Volume API Version is 1 - -VEXXHOST --------- - -http://auth.vexxhost.net - -============== ================ -Region Name Location -============== ================ -ca-ymq-1 Montreal, QC -sjc1 Santa Clara, CA -============== ================ - -* DNS API Version is 1 -* Identity API Version is 3 -* Volume API Version is 3 - -Zetta ------ - -https://identity.api.zetta.io/v3 - -============== ================ -Region Name Location -============== ================ -no-osl1 Oslo, NO -============== ================ - -* DNS API Version is 2 -* Identity API Version is 3 diff --git a/doc/source/user/connection.rst b/doc/source/user/connection.rst deleted file mode 100644 index 9ce3452f5..000000000 --- a/doc/source/user/connection.rst +++ /dev/null @@ -1,31 +0,0 @@ -Connection -========== -.. automodule:: openstack.connection - - from_config - ----------- - .. autofunction:: openstack.connection.from_config - -Registering OTC extensions -========================== - -.. autofunction:: otcextensions.sdk.register_otc_extensions - -Connection Object ------------------ - -.. autoclass:: openstack.connection.Connection - :members: - :inherited-members: - - -Transitioning from Profile --------------------------- - -Support exists for users coming from older releases of OpenStack SDK who have -been using the :class:`~openstack.profile.Profile` interface. - -.. toctree:: - :maxdepth: 1 - - transition_from_profile diff --git a/doc/source/user/examples b/doc/source/user/examples deleted file mode 120000 index 9f9d1de88..000000000 --- a/doc/source/user/examples +++ /dev/null @@ -1 +0,0 @@ -../../../examples \ No newline at end of file diff --git a/doc/source/user/guides/auto_scaling.rst b/doc/source/user/guides/auto_scaling.rst deleted file mode 100644 index 10c805c9d..000000000 --- a/doc/source/user/guides/auto_scaling.rst +++ /dev/null @@ -1,4 +0,0 @@ -Using OTC AS -============ - -.. TODO(agoncharov): Implement this guide diff --git a/doc/source/user/guides/connect_otc.rst b/doc/source/user/guides/connect_otc.rst deleted file mode 100644 index d0e27ac67..000000000 --- a/doc/source/user/guides/connect_otc.rst +++ /dev/null @@ -1,39 +0,0 @@ -Connect OTC -=========== - -In order to work with an OpenStack cloud you first need to create a -:class:`~openstack.connection.Connection` to it using your credentials. A -:class:`~openstack.connection.Connection` can be -created in 3 ways, using the class itself, :ref:`config-clouds-yaml`, or -:ref:`config-environment-variables`. It is recommended to always use -:ref:`config-clouds-yaml` as the same config can be used across tools and -languages. - -Create Connection ------------------ - -To create a :class:`~openstack.connection.Connection` instance, use the -:func:`~openstack.connect` factory function. - -As a next step inject the OTC extensions into the retrieved connection - -.. code-block:: python - - # An 'otc' is a cloud connection with name 'otc' configured in the clouds.yaml - conn = openstack.connect(cloud='otc') - - # Register OTC Extensions - sdk.register_otc_extensions(conn) - -Full example at `connect_otc.py `_ - -.. note:: To enable logging, see the :doc:`logging` user guide. - -Next ----- -Now that you can create a connection, continue with the :ref:`user_guides` -to work with an OpenStack service. - -.. TODO(shade) Update the text here and consolidate with the old - os-client-config docs so that we have a single and consistent explanation - of the envvars cloud, etc. diff --git a/doc/source/user/guides/obs.rst b/doc/source/user/guides/obs.rst deleted file mode 100644 index 89ffc0f71..000000000 --- a/doc/source/user/guides/obs.rst +++ /dev/null @@ -1,4 +0,0 @@ -Using OTC OBS -============= - -.. TODO(agoncharov): Implement this guide diff --git a/doc/source/user/guides/rds.rst b/doc/source/user/guides/rds.rst deleted file mode 100644 index c7512a459..000000000 --- a/doc/source/user/guides/rds.rst +++ /dev/null @@ -1,4 +0,0 @@ -Using OTC RDS -============= - -.. TODO(agoncharov): Implement this guide diff --git a/doc/source/user/guides/volume_backup.rst b/doc/source/user/guides/volume_backup.rst deleted file mode 100644 index d2a5be6f8..000000000 --- a/doc/source/user/guides/volume_backup.rst +++ /dev/null @@ -1,4 +0,0 @@ -Using OTC VBS -============= - -.. TODO(agoncharov): Implement this guide diff --git a/doc/source/user/index.rst b/doc/source/user/index.rst deleted file mode 100644 index 3d9c2d0fe..000000000 --- a/doc/source/user/index.rst +++ /dev/null @@ -1,195 +0,0 @@ -Getting started with the OTCExtensions SDK -========================================== - -Please note that OTCExtensions provides an extension to the OpenStackSDK. -Please refer to it's documentation for the details - - -Installation ------------- - -The OTCExtensions SDK is available on -`GitHub `_. -To install it, use ``pip``:: - - $ pip install otcextensions - -.. _user_guides: - -User Guides ------------ - -These guides walk you through how to make use of the libraries we provide -to work with each OpenStack service. If you're looking for a cookbook -approach, this is where you'll want to begin. - -.. toctree:: - :maxdepth: 1 - - Plain-simple connect to OTC - Configuration - Connect to an OpenStack Cloud Using a Config File - Using Cloud Abstration Layer - Logging - Microversions - Block Storage - Compute - Identity - Image - Key Manager - Message - Network - Object Store - Orchestration - RDS - OBS - AutoScaling - Volume Backup - Dedicated Host - -API Documentation ------------------ - -OpenStackSDK documentation is available under - - -Service APIs are exposed through a two-layered approach. The classes -exposed through our `Connection Interface`_ are -the place to start if you're an application developer consuming an OpenStack -cloud. The `Resource Interface`_ is the layer upon which the -`Connection Interface`_ is built, with methods on `Service Proxies`_ accepting -and returning :class:`~openstack.resource.Resource` objects. - -The Cloud Abstraction layer has a data model. - -.. toctree:: - :maxdepth: 1 - - model - -Connection Interface -~~~~~~~~~~~~~~~~~~~~ - -A :class:`~openstack.connection.Connection` instance maintains your cloud -config, session and authentication information providing you with a set of -higher-level interfaces to work with OpenStack services. - -.. toctree:: - :maxdepth: 1 - - connection - -Once you have a :class:`~openstack.connection.Connection` instance, services -are accessed through instances of :class:`~openstack.proxy.Proxy` or -subclasses of it that exist as attributes on the -:class:`~openstack.connection.Connection`. - -.. autoclass:: openstack.proxy.Proxy - :members: - -.. _service-proxies: - -Service Proxies -~~~~~~~~~~~~~~~ - -The following service proxies exist on the -:class:`~openstack.connection.Connection`. The service proxies are all always -present on the :class:`~openstack.connection.Connection` object, but the -combination of your ``CloudRegion`` and the catalog of the cloud in question -control which services can be used. - -.. toctree:: - :maxdepth: 1 - - Block Storage - Compute - Database - Identity v2 - Identity v3 - Image v1 - Image v2 - Key Manager - Load Balancer - Message v2 - Network - Object Store - Orchestration - Workflow - Anti DDoS Service - AutoScaling Service - Cloud Container Engine v1 - Cloud Container Engine v2 - Cloud Trace Service - Distributed Cache Service - Dedicated Host Service - Distributed Message Service - DNS Service - Key Management Service - Object Block Storage - Volume Backup Service - RDS - -Resource Interface -~~~~~~~~~~~~~~~~~~ - -The *Resource* layer is a lower-level interface to -communicate with OpenStack services. While the classes exposed by the -`Service Proxies`_ build a convenience layer on top of -this, :class:`~openstack.resource.Resource` objects can be -used directly. However, the most common usage of this layer is in receiving -an object from a class in the `Connection Interface_`, modifying it, and -sending it back to the `Service Proxies`_ layer, such as to update a resource -on the server. - -The following services have exposed :class:`~openstack.resource.Resource` -classes. - -.. toctree:: - :maxdepth: 1 - - Baremetal - Block Storage - Clustering - Compute - Database - Identity - Image - Key Management - Load Balancer - Network - Orchestration - Object Store - Workflow - Anti DDoS Service - AutoScaling Service - DNS Service - Cloud Container Engine - Cloud Trace Service - Distributed Cache Service - Dedicated Host Service - Distributed Message Service - Key Management Service - Object Block Storage - RDS - -Low-Level Classes -~~~~~~~~~~~~~~~~~ - -The following classes are not commonly used by application developers, -but are used to construct applications to talk to OpenStack APIs. Typically -these parts are managed through the `Connection Interface`_, but their use -can be customized. - -.. toctree:: - :maxdepth: 1 - - resource - utils - -Presentations -============= - -.. toctree:: - :maxdepth: 1 - - multi-cloud-demo diff --git a/doc/source/user/model.rst b/doc/source/user/model.rst deleted file mode 100644 index 62fa748ef..000000000 --- a/doc/source/user/model.rst +++ /dev/null @@ -1,533 +0,0 @@ -========== -Data Model -========== - -shade has a very strict policy on not breaking backwards compatability ever. -However, with the data structures returned from OpenStack, there are places -where the resource structures from OpenStack are returned to the user somewhat -directly, leaving a shade user open to changes/differences in result content. - -To combat that, shade 'normalizes' the return structure from OpenStack in many -places, and the results of that normalization are listed below. Where shade -performs normalization, a user can count on any fields declared in the docs -as being completely safe to use - they are as much a part of shade's API -contract as any other Python method. - -Some OpenStack objects allow for arbitrary attributes at -the root of the object. shade will pass those through so as not to break anyone -who may be counting on them, but as they are arbitrary shade can make no -guarantees as to their existence. As part of normalization, shade will put any -attribute from an OpenStack resource that is not in its data model contract -into an attribute called 'properties'. The contents of properties are -defined to be an arbitrary collection of key value pairs with no promises as -to any particular key ever existing. - -If a user passes `strict=True` to the shade constructor, shade will not pass -through arbitrary objects to the root of the resource, and will instead only -put them in the properties dict. If a user is worried about accidentally -writing code that depends on an attribute that is not part of the API contract, -this can be a useful tool. Keep in mind all data can still be accessed via -the properties dict, but any code touching anything in the properties dict -should be aware that the keys found there are highly user/cloud specific. -Any key that is transformed as part of the shade data model contract will -not wind up with an entry in properties - only keys that are unknown. - -Location --------- - -A Location defines where a resource lives. It includes a cloud name and a -region name, an availability zone as well as information about the project -that owns the resource. - -The project information may contain a project id, or a combination of one or -more of a project name with a domain name or id. If a project id is present, -it should be considered correct. - -Some resources do not carry ownership information with them. For those, the -project information will be filled in from the project the user currently -has a token for. - -Some resources do not have information about availability zones, or may exist -region wide. Those resources will have None as their availability zone. - -If all of the project information is None, then - -.. code-block:: python - - Location = dict( - cloud=str(), - region_name=str(), - zone=str() or None, - project=dict( - id=str() or None, - name=str() or None, - domain_id=str() or None, - domain_name=str() or None)) - - -Resources -========= - -Flavor ------- - -A flavor for a Nova Server. - -.. code-block:: python - - Flavor = dict( - location=Location(), - id=str(), - name=str(), - is_public=bool(), - is_disabled=bool(), - ram=int(), - vcpus=int(), - disk=int(), - ephemeral=int(), - swap=int(), - rxtx_factor=float(), - extra_specs=dict(), - properties=dict()) - - -Flavor Access -------------- - -An access entry for a Nova Flavor. - -.. code-block:: python - - FlavorAccess = dict( - flavor_id=str(), - project_id=str()) - - -Image ------ - -A Glance Image. - -.. code-block:: python - - Image = dict( - location=Location(), - id=str(), - name=str(), - min_ram=int(), - min_disk=int(), - size=int(), - virtual_size=int(), - container_format=str(), - disk_format=str(), - checksum=str(), - created_at=str(), - updated_at=str(), - owner=str(), - is_public=bool(), - is_protected=bool(), - visibility=str(), - status=str(), - locations=list(), - direct_url=str() or None, - tags=list(), - properties=dict()) - - -Keypair -------- - -A keypair for a Nova Server. - -.. code-block:: python - - Keypair = dict( - location=Location(), - name=str(), - id=str(), - public_key=str(), - fingerprint=str(), - type=str(), - user_id=str(), - private_key=str() or None - properties=dict()) - - -Security Group --------------- - -A Security Group from either Nova or Neutron - -.. code-block:: python - - SecurityGroup = dict( - location=Location(), - id=str(), - name=str(), - description=str(), - security_group_rules=list(), - properties=dict()) - -Security Group Rule -------------------- - -A Security Group Rule from either Nova or Neutron - -.. code-block:: python - - SecurityGroupRule = dict( - location=Location(), - id=str(), - direction=str(), # oneof('ingress', 'egress') - ethertype=str(), - port_range_min=int() or None, - port_range_max=int() or None, - protocol=str() or None, - remote_ip_prefix=str() or None, - security_group_id=str() or None, - remote_group_id=str() or None - properties=dict()) - -Server ------- - -A Server from Nova - -.. code-block:: python - - Server = dict( - location=Location(), - id=str(), - name=str(), - image=dict() or str(), - flavor=dict(), - volumes=list(), # Volume - interface_ip=str(), - has_config_drive=bool(), - accessIPv4=str(), - accessIPv6=str(), - addresses=dict(), # string, list(Address) - created=str(), - created_at=str(), - key_name=str(), - metadata=dict(), # string, string - private_v4=str(), - progress=int(), - public_v4=str(), - public_v6=str(), - security_groups=list(), # SecurityGroup - status=str(), - updated=str(), - user_id=str(), - host_id=str() or None, - power_state=str() or None, - task_state=str() or None, - vm_state=str() or None, - launched_at=str() or None, - terminated_at=str() or None, - task_state=str() or None, - properties=dict()) - -ComputeLimits -------------- - -Limits and current usage for a project in Nova - -.. code-block:: python - - ComputeLimits = dict( - location=Location(), - max_personality=int(), - max_personality_size=int(), - max_server_group_members=int(), - max_server_groups=int(), - max_server_meta=int(), - max_total_cores=int(), - max_total_instances=int(), - max_total_keypairs=int(), - max_total_ram_size=int(), - total_cores_used=int(), - total_instances_used=int(), - total_ram_used=int(), - total_server_groups_used=int(), - properties=dict()) - -ComputeUsage ------------- - -Current usage for a project in Nova - -.. code-block:: python - - ComputeUsage = dict( - location=Location(), - started_at=str(), - stopped_at=str(), - server_usages=list(), - max_personality=int(), - max_personality_size=int(), - max_server_group_members=int(), - max_server_groups=int(), - max_server_meta=int(), - max_total_cores=int(), - max_total_instances=int(), - max_total_keypairs=int(), - max_total_ram_size=int(), - total_cores_used=int(), - total_hours=int(), - total_instances_used=int(), - total_local_gb_usage=int(), - total_memory_mb_usage=int(), - total_ram_used=int(), - total_server_groups_used=int(), - total_vcpus_usage=int(), - properties=dict()) - -ServerUsage ------------ - -Current usage for a server in Nova - -.. code-block:: python - - ComputeUsage = dict( - started_at=str(), - ended_at=str(), - flavor=str(), - hours=int(), - instance_id=str(), - local_gb=int(), - memory_mb=int(), - name=str(), - state=str(), - uptime=int(), - vcpus=int(), - properties=dict()) - -Floating IP ------------ - -A Floating IP from Neutron or Nova - - -.. code-block:: python - - FloatingIP = dict( - location=Location(), - id=str(), - description=str(), - attached=bool(), - fixed_ip_address=str() or None, - floating_ip_address=str() or None, - network=str() or None, - port=str() or None, - router=str(), - status=str(), - created_at=str() or None, - updated_at=str() or None, - revision_number=int() or None, - properties=dict()) - -Volume ------- - -A volume from cinder. - -.. code-block:: python - - Volume = dict( - location=Location(), - id=str(), - name=str(), - description=str(), - size=int(), - attachments=list(), - status=str(), - migration_status=str() or None, - host=str() or None, - replication_driver=str() or None, - replication_status=str() or None, - replication_extended_status=str() or None, - snapshot_id=str() or None, - created_at=str(), - updated_at=str() or None, - source_volume_id=str() or None, - consistencygroup_id=str() or None, - volume_type=str() or None, - metadata=dict(), - is_bootable=bool(), - is_encrypted=bool(), - can_multiattach=bool(), - properties=dict()) - - -VolumeType ----------- - -A volume type from cinder. - -.. code-block:: python - - VolumeType = dict( - location=Location(), - id=str(), - name=str(), - description=str() or None, - is_public=bool(), - qos_specs_id=str() or None, - extra_specs=dict(), - properties=dict()) - - -VolumeTypeAccess ----------------- - -A volume type access from cinder. - -.. code-block:: python - - VolumeTypeAccess = dict( - location=Location(), - volume_type_id=str(), - project_id=str(), - properties=dict()) - - -ClusterTemplate ---------------- - -A Cluster Template from magnum. - -.. code-block:: python - - ClusterTemplate = dict( - location=Location(), - apiserver_port=int(), - cluster_distro=str(), - coe=str(), - created_at=str(), - dns_nameserver=str(), - docker_volume_size=int(), - external_network_id=str(), - fixed_network=str() or None, - flavor_id=str(), - http_proxy=str() or None, - https_proxy=str() or None, - id=str(), - image_id=str(), - insecure_registry=str(), - is_public=bool(), - is_registry_enabled=bool(), - is_tls_disabled=bool(), - keypair_id=str(), - labels=dict(), - master_flavor_id=str() or None, - name=str(), - network_driver=str(), - no_proxy=str() or None, - server_type=str(), - updated_at=str() or None, - volume_driver=str(), - properties=dict()) - -MagnumService -------------- - -A Magnum Service from magnum - -.. code-block:: python - - MagnumService = dict( - location=Location(), - binary=str(), - created_at=str(), - disabled_reason=str() or None, - host=str(), - id=str(), - report_count=int(), - state=str(), - properties=dict()) - -Stack ------ - -A Stack from Heat - -.. code-block:: python - - Stack = dict( - location=Location(), - id=str(), - name=str(), - created_at=str(), - deleted_at=str(), - updated_at=str(), - description=str(), - action=str(), - identifier=str(), - is_rollback_enabled=bool(), - notification_topics=list(), - outputs=list(), - owner=str(), - parameters=dict(), - parent=str(), - stack_user_project_id=str(), - status=str(), - status_reason=str(), - tags=dict(), - tempate_description=str(), - timeout_mins=int(), - properties=dict()) - -Identity Resources -================== - -Identity Resources are slightly different. - -They are global to a cloud, so location.availability_zone and -location.region_name and will always be None. If a deployer happens to deploy -OpenStack in such a way that users and projects are not shared amongst regions, -that necessitates treating each of those regions as separate clouds from -shade's POV. - -The Identity Resources that are not Project do not exist within a Project, -so all of the values in ``location.project`` will be None. - -Project -------- - -A Project from Keystone (or a tenant if Keystone v2) - -Location information for Project has some additional specific semantics. -If the project has a parent project, that will be in ``location.project.id``, -and if it doesn't that should be ``None``. - -If the Project is associated with a domain that will be in -``location.project.domain_id`` in addition to the normal ``domain_id`` -regardless of the current user's token scope. - -.. code-block:: python - - Project = dict( - location=Location(), - id=str(), - name=str(), - description=str(), - is_enabled=bool(), - is_domain=bool(), - domain_id=str(), - properties=dict()) - -Role ----- - -A Role from Keystone - -.. code-block:: python - - Project = dict( - location=Location(), - id=str(), - name=str(), - domain_id=str(), - properties=dict()) diff --git a/doc/source/user/multi-cloud-demo.rst b/doc/source/user/multi-cloud-demo.rst deleted file mode 100644 index de529d598..000000000 --- a/doc/source/user/multi-cloud-demo.rst +++ /dev/null @@ -1,809 +0,0 @@ -================ -Multi-Cloud Demo -================ - -This document contains a presentation in `presentty`_ format. If you want to -walk through it like a presentation, install `presentty` and run: - -.. code:: bash - - presentty doc/source/user/multi-cloud-demo.rst - -The content is hopefully helpful even if it's not being narrated, so it's being -included in the `shade` docs. - -.. _presentty: https://pypi.org/project/presentty - -Using Multiple OpenStack Clouds Easily with Shade -================================================= - -Who am I? -========= - -Monty Taylor - -* OpenStack Infra Core -* irc: mordred -* twitter: @e_monty - -What are we going to talk about? -================================ - -`shade` - -* a task and end-user oriented Python library -* abstracts deployment differences -* designed for multi-cloud -* simple to use -* massive scale - - * optional advanced features to handle 20k servers a day - -* Initial logic/design extracted from nodepool -* Librified to re-use in Ansible - -shade is Free Software -====================== - -* https://git.openstack.org/cgit/openstack-infra/shade -* openstack-dev@lists.openstack.org -* #openstack-shade on freenode - -This talk is Free Software, too -=============================== - -* Written for presentty (https://pypi.org/project/presentty) -* doc/source/multi-cloud-demo.rst -* examples in doc/source/examples -* Paths subject to change- this is the first presentation in tree! - -Complete Example -================ - -.. code:: python - - from openstack import cloud as openstack - - # Initialize and turn on debug logging - openstack.enable_logging(debug=True) - - for cloud_name, region_name in [ - ('my-vexxhost', 'ca-ymq-1'), - ('my-citycloud', 'Buf1'), - ('my-internap', 'ams01')]: - # Initialize cloud - cloud = openstack.connect(cloud=cloud_name, region_name=region_name) - - # Upload an image to the cloud - image = cloud.create_image( - 'devuan-jessie', filename='devuan-jessie.qcow2', wait=True) - - # Find a flavor with at least 512M of RAM - flavor = cloud.get_flavor_by_ram(512) - - # Boot a server, wait for it to boot, and then do whatever is needed - # to get a public ip for it. - cloud.create_server( - 'my-server', image=image, flavor=flavor, wait=True, auto_ip=True) - -Let's Take a Few Steps Back -=========================== - -Multi-cloud is easy, but you need to know a few things. - -* Terminology -* Config -* Shade API - -Cloud Terminology -================= - -Let's define a few terms, so that we can use them with ease: - -* `cloud` - logically related collection of services -* `region` - completely independent subset of a given cloud -* `patron` - human who has an account -* `user` - account on a cloud -* `project` - logical collection of cloud resources -* `domain` - collection of users and projects - -Cloud Terminology Relationships -=============================== - -* A `cloud` has one or more `regions` -* A `patron` has one or more `users` -* A `patron` has one or more `projects` -* A `cloud` has one or more `domains` -* In a `cloud` with one `domain` it is named "default" -* Each `patron` may have their own `domain` -* Each `user` is in one `domain` -* Each `project` is in one `domain` -* A `user` has one or more `roles` on one or more `projects` - -HTTP Sessions -============= - -* HTTP interactions are authenticated via keystone -* Authenticating returns a `token` -* An authenticated HTTP Session is shared across a `region` - -Cloud Regions -============= - -A `cloud region` is the basic unit of REST interaction. - -* A `cloud` has a `service catalog` -* The `service catalog` is returned in the `token` -* The `service catalog` lists `endpoint` for each `service` in each `region` -* A `region` is completely autonomous - -Users, Projects and Domains -=========================== - -In clouds with multiple domains, project and user names are -only unique within a region. - -* Names require `domain` information for uniqueness. IDs do not. -* Providing `domain` information when not needed is fine. -* `project_name` requires `project_domain_name` or `project_domain_id` -* `project_id` does not -* `username` requires `user_domain_name` or `user_domain_id` -* `user_id` does not - -Confused Yet? -============= - -Don't worry - you don't have to deal with most of that. - -Auth per cloud, select per region -================================= - -In general, the thing you need to know is: - -* Configure authentication per `cloud` -* Select config to use by `cloud` and `region` - -clouds.yaml -=========== - -Information about the clouds you want to connect to is stored in a file -called `clouds.yaml`. - -`clouds.yaml` can be in your homedir: `~/.config/openstack/clouds.yaml` -or system-wide: `/etc/openstack/clouds.yaml`. - -Information in your homedir, if it exists, takes precedence. - -Full docs on `clouds.yaml` are at -https://docs.openstack.org/os-client-config/latest/ - -What about Mac and Windows? -=========================== - -`USER_CONFIG_DIR` is different on Linux, OSX and Windows. - -* Linux: `~/.config/openstack` -* OSX: `~/Library/Application Support/openstack` -* Windows: `C:\\Users\\USERNAME\\AppData\\Local\\OpenStack\\openstack` - -`SITE_CONFIG_DIR` is different on Linux, OSX and Windows. - -* Linux: `/etc/openstack` -* OSX: `/Library/Application Support/openstack` -* Windows: `C:\\ProgramData\\OpenStack\\openstack` - -Config Terminology -================== - -For multi-cloud, think of two types: - -* `profile` - Facts about the `cloud` that are true for everyone -* `cloud` - Information specific to a given `user` - -Apologies for the use of `cloud` twice. - -Environment Variables and Simple Usage -====================================== - -* Environment variables starting with `OS_` go into a cloud called `envvars` -* If you only have one cloud, you don't have to specify it -* `OS_CLOUD` and `OS_REGION_NAME` are default values for - `cloud` and `region_name` - -TOO MUCH TALKING - NOT ENOUGH CODE -================================== - -basic clouds.yaml for the example code -====================================== - -Simple example of a clouds.yaml - -* Config for a named `cloud` "my-citycloud" -* Reference a well-known "named" profile: `citycloud` -* `os-client-config` has a built-in list of profiles at - https://docs.openstack.org/os-client-config/latest/user/vendor-support.html -* Vendor profiles contain various advanced config -* `cloud` name can match `profile` name (using different names for clarity) - -.. code:: yaml - - clouds: - my-citycloud: - profile: citycloud - auth: - username: mordred - project_id: 65222a4d09ea4c68934fa1028c77f394 - user_domain_id: d0919bd5e8d74e49adf0e145807ffc38 - project_domain_id: d0919bd5e8d74e49adf0e145807ffc38 - -Where's the password? - -secure.yaml -=========== - -* Optional additional file just like `clouds.yaml` -* Values overlaid on `clouds.yaml` -* Useful if you want to protect secrets more stringently - -Example secure.yaml -=================== - -* No, my password isn't XXXXXXXX -* `cloud` name should match `clouds.yaml` -* Optional - I actually keep mine in my `clouds.yaml` - -.. code:: yaml - - clouds: - my-citycloud: - auth: - password: XXXXXXXX - -more clouds.yaml -================ - -More information can be provided. - -* Use v3 of the `identity` API - even if others are present -* Use `https://image-ca-ymq-1.vexxhost.net/v2` for `image` API - instead of what's in the catalog - -.. code:: yaml - - my-vexxhost: - identity_api_version: 3 - image_endpoint_override: https://image-ca-ymq-1.vexxhost.net/v2 - profile: vexxhost - auth: - user_domain_id: default - project_domain_id: default - project_name: d8af8a8f-a573-48e6-898a-af333b970a2d - username: 0b8c435b-cc4d-4e05-8a47-a2ada0539af1 - -Much more complex clouds.yaml example -===================================== - -* Not using a profile - all settings included -* In the `ams01` `region` there are two networks with undiscoverable qualities -* Each one are labeled here so choices can be made -* Any of the settings can be specific to a `region` if needed -* `region` settings override `cloud` settings -* `cloud` does not support `floating-ips` - -.. code:: yaml - - my-internap: - auth: - auth_url: https://identity.api.cloud.iweb.com - username: api-55f9a00fb2619 - project_name: inap-17037 - identity_api_version: 3 - floating_ip_source: None - regions: - - name: ams01 - values: - networks: - - name: inap-17037-WAN1654 - routes_externally: true - default_interface: true - - name: inap-17037-LAN3631 - routes_externally: false - -Complete Example Again -====================== - -.. code:: python - - from openstack import cloud as openstack - - # Initialize and turn on debug logging - openstack.enable_logging(debug=True) - - for cloud_name, region_name in [ - ('my-vexxhost', 'ca-ymq-1'), - ('my-citycloud', 'Buf1'), - ('my-internap', 'ams01')]: - # Initialize cloud - cloud = openstack.connect(cloud=cloud_name, region_name=region_name) - - # Upload an image to the cloud - image = cloud.create_image( - 'devuan-jessie', filename='devuan-jessie.qcow2', wait=True) - - # Find a flavor with at least 512M of RAM - flavor = cloud.get_flavor_by_ram(512) - - # Boot a server, wait for it to boot, and then do whatever is needed - # to get a public ip for it. - cloud.create_server( - 'my-server', image=image, flavor=flavor, wait=True, auto_ip=True) - -Step By Step -============ - -Import the library -================== - -.. code:: python - - from openstack import cloud as openstack - -Logging -======= - -* `openstacksdk` uses standard python logging -* ``openstack.enable_logging`` does easy defaults -* Squelches some meaningless warnings - - * `debug` - - * Logs shade loggers at debug level - - * `http_debug` Implies `debug`, turns on HTTP tracing - -.. code:: python - - # Initialize and turn on debug logging - openstack.enable_logging(debug=True) - -Example with Debug Logging -========================== - -* doc/source/examples/debug-logging.py - -.. code:: python - - from openstack import cloud as openstack - openstack.enable_logging(debug=True) - - cloud = openstack.connect( - cloud='my-vexxhost', region_name='ca-ymq-1') - cloud.get_image('Ubuntu 16.04.1 LTS [2017-03-03]') - -Example with HTTP Debug Logging -=============================== - -* doc/source/examples/http-debug-logging.py - -.. code:: python - - from openstack import cloud as openstack - openstack.enable_logging(http_debug=True) - - cloud = openstack.connect( - cloud='my-vexxhost', region_name='ca-ymq-1') - cloud.get_image('Ubuntu 16.04.1 LTS [2017-03-03]') - -Cloud Regions -============= - -* `cloud` constructor needs `cloud` and `region_name` -* `openstack.connect` is a helper factory function - -.. code:: python - - for cloud_name, region_name in [ - ('my-vexxhost', 'ca-ymq-1'), - ('my-citycloud', 'Buf1'), - ('my-internap', 'ams01')]: - # Initialize cloud - cloud = openstack.connect(cloud=cloud_name, region_name=region_name) - -Upload an Image -=============== - -* Picks the correct upload mechanism -* **SUGGESTION** Always upload your own base images - -.. code:: python - - # Upload an image to the cloud - image = cloud.create_image( - 'devuan-jessie', filename='devuan-jessie.qcow2', wait=True) - -Always Upload an Image -====================== - -Ok. You don't have to. But, for multi-cloud... - -* Images with same content are named different on different clouds -* Images with same name on different clouds can have different content -* Upload your own to all clouds, both problems go away -* Download from OS vendor or build with `diskimage-builder` - -Find a flavor -============= - -* Flavors are all named differently on clouds -* Flavors can be found via RAM -* `get_flavor_by_ram` finds the smallest matching flavor - -.. code:: python - - # Find a flavor with at least 512M of RAM - flavor = cloud.get_flavor_by_ram(512) - -Create a server -=============== - -* my-vexxhost - - * Boot server - * Wait for `status==ACTIVE` - -* my-internap - - * Boot server on network `inap-17037-WAN1654` - * Wait for `status==ACTIVE` - -* my-citycloud - - * Boot server - * Wait for `status==ACTIVE` - * Find the `port` for the `fixed_ip` for `server` - * Create `floating-ip` on that `port` - * Wait for `floating-ip` to attach - -.. code:: python - - # Boot a server, wait for it to boot, and then do whatever is needed - # to get a public ip for it. - cloud.create_server( - 'my-server', image=image, flavor=flavor, wait=True, auto_ip=True) - -Wow. We didn't even deploy Wordpress! -===================================== - -Image and Flavor by Name or ID -============================== - -* Pass string to image/flavor -* Image/Flavor will be found by name or ID -* Common pattern -* doc/source/examples/create-server-name-or-id.py - -.. code:: python - - from openstack import cloud as openstack - - # Initialize and turn on debug logging - openstack.enable_logging(debug=True) - - for cloud_name, region_name, image, flavor in [ - ('my-vexxhost', 'ca-ymq-1', - 'Ubuntu 16.04.1 LTS [2017-03-03]', 'v1-standard-4'), - ('my-citycloud', 'Buf1', - 'Ubuntu 16.04 Xenial Xerus', '4C-4GB-100GB'), - ('my-internap', 'ams01', - 'Ubuntu 16.04 LTS (Xenial Xerus)', 'A1.4')]: - # Initialize cloud - cloud = openstack.connect(cloud=cloud_name, region_name=region_name) - - # Boot a server, wait for it to boot, and then do whatever is needed - # to get a public ip for it. - server = cloud.create_server( - 'my-server', image=image, flavor=flavor, wait=True, auto_ip=True) - print(server.name) - print(server['name']) - cloud.pprint(server) - # Delete it - this is a demo - cloud.delete_server(server, wait=True, delete_ips=True) - -cloud.pprint method was just added this morning -=============================================== - -Delete Servers -============== - -* `delete_ips` Delete any `floating_ips` the server may have - -.. code:: python - - cloud.delete_server('my-server', wait=True, delete_ips=True) - -Image and Flavor by Dict -======================== - -* Pass dict to image/flavor -* If you know if the value is Name or ID -* Common pattern -* doc/source/examples/create-server-dict.py - -.. code:: python - - from openstack import cloud as openstack - - # Initialize and turn on debug logging - openstack.enable_logging(debug=True) - - for cloud_name, region_name, image, flavor_id in [ - ('my-vexxhost', 'ca-ymq-1', 'Ubuntu 16.04.1 LTS [2017-03-03]', - '5cf64088-893b-46b5-9bb1-ee020277635d'), - ('my-citycloud', 'Buf1', 'Ubuntu 16.04 Xenial Xerus', - '0dab10b5-42a2-438e-be7b-505741a7ffcc'), - ('my-internap', 'ams01', 'Ubuntu 16.04 LTS (Xenial Xerus)', - 'A1.4')]: - # Initialize cloud - cloud = openstack.connect(cloud=cloud_name, region_name=region_name) - - # Boot a server, wait for it to boot, and then do whatever is needed - # to get a public ip for it. - server = cloud.create_server( - 'my-server', image=image, flavor=dict(id=flavor_id), - wait=True, auto_ip=True) - # Delete it - this is a demo - cloud.delete_server(server, wait=True, delete_ips=True) - -Munch Objects -============= - -* Behave like a dict and an object -* doc/source/examples/munch-dict-object.py - -.. code:: python - - from openstack import cloud as openstack - openstack.enable_logging(debug=True) - - cloud = openstack.connect(cloud='zetta', region_name='no-osl1') - image = cloud.get_image('Ubuntu 14.04 (AMD64) [Local Storage]') - print(image.name) - print(image['name']) - -API Organized by Logical Resource -================================= - -* list_servers -* search_servers -* get_server -* create_server -* delete_server -* update_server - -For other things, it's still {verb}_{noun} - -* attach_volume -* wait_for_server -* add_auto_ip - -Cleanup Script -============== - -* Sometimes my examples had bugs -* doc/source/examples/cleanup-servers.py - -.. code:: python - - from openstack import cloud as openstack - - # Initialize and turn on debug logging - openstack.enable_logging(debug=True) - - for cloud_name, region_name in [ - ('my-vexxhost', 'ca-ymq-1'), - ('my-citycloud', 'Buf1'), - ('my-internap', 'ams01')]: - # Initialize cloud - cloud = openstack.connect(cloud=cloud_name, region_name=region_name) - for server in cloud.search_servers('my-server'): - cloud.delete_server(server, wait=True, delete_ips=True) - -Normalization -============= - -* https://docs.openstack.org/shade/latest/user/model.html#image -* doc/source/examples/normalization.py - -.. code:: python - - from openstack import cloud as openstack - openstack.enable_logging() - - cloud = openstack.connect(cloud='fuga', region_name='cystack') - image = cloud.get_image( - 'Ubuntu 16.04 LTS - Xenial Xerus - 64-bit - Fuga Cloud Based Image') - cloud.pprint(image) - -Strict Normalized Results -========================= - -* Return only the declared model -* doc/source/examples/strict-mode.py - -.. code:: python - - from openstack import cloud as openstack - openstack.enable_logging() - - cloud = openstack.connect( - cloud='fuga', region_name='cystack', strict=True) - image = cloud.get_image( - 'Ubuntu 16.04 LTS - Xenial Xerus - 64-bit - Fuga Cloud Based Image') - cloud.pprint(image) - -How Did I Find the Image Name for the Last Example? -=================================================== - -* I often make stupid little utility scripts -* doc/source/examples/find-an-image.py - -.. code:: python - - from openstack import cloud as openstack - openstack.enable_logging() - - cloud = openstack.connect(cloud='fuga', region_name='cystack') - cloud.pprint([ - image for image in cloud.list_images() - if 'ubuntu' in image.name.lower()]) - -Added / Modified Information -============================ - -* Servers need more extra help -* Fetch addresses dict from neutron -* Figure out which IPs are good -* `detailed` - defaults to True, add everything -* `bare` - no extra calls - don't even fix broken things -* `bare` is still normalized -* doc/source/examples/server-information.py - -.. code:: python - - from openstack import cloud as openstack - openstack.enable_logging(debug=True) - - cloud = openstack.connect(cloud='my-citycloud', region_name='Buf1') - try: - server = cloud.create_server( - 'my-server', image='Ubuntu 16.04 Xenial Xerus', - flavor=dict(id='0dab10b5-42a2-438e-be7b-505741a7ffcc'), - wait=True, auto_ip=True) - - print("\n\nFull Server\n\n") - cloud.pprint(server) - - print("\n\nTurn Detailed Off\n\n") - cloud.pprint(cloud.get_server('my-server', detailed=False)) - - print("\n\nBare Server\n\n") - cloud.pprint(cloud.get_server('my-server', bare=True)) - - finally: - # Delete it - this is a demo - cloud.delete_server(server, wait=True, delete_ips=True) - -Exceptions -========== - -* All shade exceptions are subclasses of `OpenStackCloudException` -* Direct REST calls throw `OpenStackCloudHTTPError` -* `OpenStackCloudHTTPError` subclasses `OpenStackCloudException` - and `requests.exceptions.HTTPError` -* `OpenStackCloudURINotFound` for 404 -* `OpenStackCloudBadRequest` for 400 - -User Agent Info -=============== - -* Set `app_name` and `app_version` for User Agents -* (sssh ... `region_name` is optional if the cloud has one region) -* doc/source/examples/user-agent.py - -.. code:: python - - from openstack import cloud as openstack - openstack.enable_logging(http_debug=True) - - cloud = openstack.connect( - cloud='datacentred', app_name='AmazingApp', app_version='1.0') - cloud.list_networks() - -Uploading Large Objects -======================= - -* swift has a maximum object size -* Large Objects are uploaded specially -* shade figures this out and does it -* multi-threaded -* doc/source/examples/upload-object.py - -.. code:: python - - from openstack import cloud as openstack - openstack.enable_logging(debug=True) - - cloud = openstack.connect(cloud='ovh', region_name='SBG1') - cloud.create_object( - container='my-container', name='my-object', - filename='/home/mordred/briarcliff.sh3d') - cloud.delete_object('my-container', 'my-object') - cloud.delete_container('my-container') - -Uploading Large Objects -======================= - -* Default max_file_size is 5G -* This is a conference demo -* Let's force a segment_size -* One MILLION bytes -* doc/source/examples/upload-object.py - -.. code:: python - - from openstack import cloud as openstack - openstack.enable_logging(debug=True) - - cloud = openstack.connect(cloud='ovh', region_name='SBG1') - cloud.create_object( - container='my-container', name='my-object', - filename='/home/mordred/briarcliff.sh3d', - segment_size=1000000) - cloud.delete_object('my-container', 'my-object') - cloud.delete_container('my-container') - -Service Conditionals -==================== - -.. code:: python - - from openstack import cloud as openstack - openstack.enable_logging(debug=True) - - cloud = openstack.connect(cloud='kiss', region_name='region1') - print(cloud.has_service('network')) - print(cloud.has_service('container-orchestration')) - -Service Conditional Overrides -============================= - -* Sometimes clouds are weird and figuring that out won't work - -.. code:: python - - from openstack import cloud as openstack - openstack.enable_logging(debug=True) - - cloud = openstack.connect(cloud='rax', region_name='DFW') - print(cloud.has_service('network')) - -.. code:: yaml - - clouds: - rax: - profile: rackspace - auth: - username: mordred - project_id: 245018 - # This is already in profile: rackspace - has_network: false - -Coming Soon -=========== - -* Completion of RESTification -* Full version discovery support -* Multi-cloud facade layer -* Microversion support (talk tomorrow) -* Completion of caching tier (talk tomorrow) -* All of you helping hacking on shade!!! (we're friendly) diff --git a/doc/source/user/proxies/rds_v3.rst b/doc/source/user/proxies/rds_v3.rst deleted file mode 100644 index 2efeddecc..000000000 --- a/doc/source/user/proxies/rds_v3.rst +++ /dev/null @@ -1,55 +0,0 @@ -Database RDS API -================ - -For details on how to use database, see :doc:`/user/guides/rds` - -.. automodule:: otcextensions.sdk.rds.v3._proxy - -The Database Class ------------------- - -The database high-level interface is available through the ``rds`` member of a -:class:`~openstack.connection.Connection` object. The ``rds`` member will only -be added if the ``otcextensions.sdk.register_otc_extensions(conn)`` method is -called. - -Datastore Operations -^^^^^^^^^^^^^^^^^^^^ - -.. autoclass:: otcextensions.sdk.rds.v3._proxy.Proxy - - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.datastore_versions - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.get_datastore_version - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.datastore_types - -Flavor Operations -^^^^^^^^^^^^^^^^^ - -.. autoclass:: otcextensions.sdk.rds.v3._proxy.Proxy - - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.get_flavor - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.flavors - -Instance Operations -^^^^^^^^^^^^^^^^^^^ - -.. autoclass:: otcextensions.sdk.rds.v3._proxy.Proxy - - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.create_instance - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.update_instance - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.delete_instance - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.get_instance - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.find_instance - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.instances - - -Backup Operations -^^^^^^^^^^^^^^^^^ - -.. autoclass:: otcextensions.sdk.rds.v3._proxy.Proxy - - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.backups - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.create_backup - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.delete_backup - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.get_backup_policy - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.set_backup_policy diff --git a/doc/source/user/resource.rst b/doc/source/user/resource.rst deleted file mode 100644 index 8453265f5..000000000 --- a/doc/source/user/resource.rst +++ /dev/null @@ -1,26 +0,0 @@ -**Note: This class is in the process of being applied as the new base class -for resources around the OpenStack SDK. Once that has been completed, -this module will be drop the 2 suffix and be the only resource module.** - -Resource -======== -.. automodule:: openstack.resource - -Components ----------- - -.. autoclass:: openstack.resource.Body - :members: - -.. autoclass:: openstack.resource.Header - :members: - -.. autoclass:: openstack.resource.URI - :members: - -The Resource class ------------------- - -.. autoclass:: openstack.resource.Resource - :members: - :member-order: bysource diff --git a/doc/source/user/resources/anti_ddos/index.rst b/doc/source/user/resources/anti_ddos/index.rst deleted file mode 100644 index dde392f6b..000000000 --- a/doc/source/user/resources/anti_ddos/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -Anti DDoS Resources -=================== - -.. toctree:: - :maxdepth: 1 - - v1/config - v1/floating_ip - v1/status diff --git a/doc/source/user/resources/anti_ddos/v1/config.rst b/doc/source/user/resources/anti_ddos/v1/config.rst deleted file mode 100644 index f8d7a088b..000000000 --- a/doc/source/user/resources/anti_ddos/v1/config.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.anti_ddos.v1.config -===================================== - -.. automodule:: otcextensions.sdk.anti_ddos.v1.config - -The Anti DDoS Config Class --------------------------- - -The ``Config`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.anti_ddos.v1.config.Config - :members: diff --git a/doc/source/user/resources/anti_ddos/v1/floating_ip.rst b/doc/source/user/resources/anti_ddos/v1/floating_ip.rst deleted file mode 100644 index dd5232b81..000000000 --- a/doc/source/user/resources/anti_ddos/v1/floating_ip.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.anti_ddos.v1.floating_ip -========================================== - -.. automodule:: otcextensions.sdk.anti_ddos.v1.floating_ip - -The Anti_DDoS FloatingIP Class ------------------------------- - -The ``FloatingIP`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.anti_ddos.v1.floating_ip.FloatingIP - :members: diff --git a/doc/source/user/resources/anti_ddos/v1/status.rst b/doc/source/user/resources/anti_ddos/v1/status.rst deleted file mode 100644 index 604d46164..000000000 --- a/doc/source/user/resources/anti_ddos/v1/status.rst +++ /dev/null @@ -1,58 +0,0 @@ -otcextensions.sdk.anti_ddos.v1.status -===================================== - -.. automodule:: otcextensions.sdk.anti_ddos.v1.status - -The Anti DDoS TaskStatus Class ------------------------------- - -The ``TaskStatus`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.anti_ddos.v1.status.TaskStatus - :members: - -The Anti DDoS FloatingIPStatus Class ------------------------------------- - -The ``FloatingIPStatus`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.anti_ddos.v1.status.FloatingIPStatus - :members: - -The Anti DDoS FloatingIPEvent Class ------------------------------------ - -The ``FloatingIPEvent`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.anti_ddos.v1.status.FloatingIPEvent - :members: - -The Anti DDoS FloatingIPDayStat Class -------------------------------------- - -The ``FloatingIPDayStat`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.anti_ddos.v1.status.FloatingIPDayStat - :members: - -The Anti DDoS FloatingIPWeekStatData Class ------------------------------------------- - -The ``FloatingIPWeekStatData`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.anti_ddos.v1.status.FloatingIPWeekStatData - :members: - -The Anti DDoS FloatingIPWeekStat Class --------------------------------------- - -The ``FloatingIPWeekStat`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.anti_ddos.v1.status.FloatingIPWeekStat - :members: diff --git a/doc/source/user/resources/auto_scaling/index.rst b/doc/source/user/resources/auto_scaling/index.rst deleted file mode 100644 index daf76787a..000000000 --- a/doc/source/user/resources/auto_scaling/index.rst +++ /dev/null @@ -1,12 +0,0 @@ -AutoScaling Resources -===================== - -.. toctree:: - :maxdepth: 1 - - v1/group - v1/config - v1/policy - v1/instance - v1/quota - v1/activity diff --git a/doc/source/user/resources/auto_scaling/v1/activity.rst b/doc/source/user/resources/auto_scaling/v1/activity.rst deleted file mode 100644 index a645657f7..000000000 --- a/doc/source/user/resources/auto_scaling/v1/activity.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.auto_scaling.v1.activity -========================================== - -.. automodule:: otcextensions.sdk.auto_scaling.v1.activity - -The AS Activity Class ---------------------- - -The ``Activity`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.auto_scaling.v1.activity.Activity - :members: diff --git a/doc/source/user/resources/auto_scaling/v1/config.rst b/doc/source/user/resources/auto_scaling/v1/config.rst deleted file mode 100644 index 292e7d531..000000000 --- a/doc/source/user/resources/auto_scaling/v1/config.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.auto_scaling.v1.config -======================================== - -.. automodule:: otcextensions.sdk.auto_scaling.v1.config - -The AS Configuration Class --------------------------- - -The ``Config`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.auto_scaling.v1.config.Config - :members: diff --git a/doc/source/user/resources/auto_scaling/v1/group.rst b/doc/source/user/resources/auto_scaling/v1/group.rst deleted file mode 100644 index 8a9563f97..000000000 --- a/doc/source/user/resources/auto_scaling/v1/group.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.auto_scaling.v1.group -======================================= - -.. automodule:: otcextensions.sdk.auto_scaling.v1.group - -The AS Group Class ------------------- - -The ``Group`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.auto_scaling.v1.group.Group - :members: diff --git a/doc/source/user/resources/auto_scaling/v1/instance.rst b/doc/source/user/resources/auto_scaling/v1/instance.rst deleted file mode 100644 index 9f31ada62..000000000 --- a/doc/source/user/resources/auto_scaling/v1/instance.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.auto_scaling.v1.instance -========================================== - -.. automodule:: otcextensions.sdk.auto_scaling.v1.instance - -The AS Instance Class ---------------------- - -The ``Instance`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.auto_scaling.v1.instance.Instance - :members: diff --git a/doc/source/user/resources/auto_scaling/v1/policy.rst b/doc/source/user/resources/auto_scaling/v1/policy.rst deleted file mode 100644 index f14861719..000000000 --- a/doc/source/user/resources/auto_scaling/v1/policy.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.auto_scaling.v1.policy -======================================== - -.. automodule:: otcextensions.sdk.auto_scaling.v1.policy - -The AS Policy Class -------------------- - -The ``Policy`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.auto_scaling.v1.policy.Policy - :members: diff --git a/doc/source/user/resources/auto_scaling/v1/quota.rst b/doc/source/user/resources/auto_scaling/v1/quota.rst deleted file mode 100644 index 3dc77141f..000000000 --- a/doc/source/user/resources/auto_scaling/v1/quota.rst +++ /dev/null @@ -1,22 +0,0 @@ -otcextensions.sdk.auto_scaling.v1.quota -======================================= - -.. automodule:: otcextensions.sdk.auto_scaling.v1.quota - -The AS Quota Class ---------------------- - -The ``Quota`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.auto_scaling.v1.quota.Quota - :members: - -The AS Scaling Quota Class --------------------------- - -The ``Quota`` class inherits from -:class:`~otcextensions.sdk.auto_scaling.v1.quota.Quota`. - -.. autoclass:: otcextensions.sdk.auto_scaling.v1.quota.ScalingQuota - :members: diff --git a/doc/source/user/resources/cce/index.rst b/doc/source/user/resources/cce/index.rst deleted file mode 100644 index 5b4e81b77..000000000 --- a/doc/source/user/resources/cce/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -AutoScaling Resources -===================== - -.. toctree:: - :maxdepth: 1 - - v1/cluster - v1/cluster_node - v3/cluster - v3/cluster_node diff --git a/doc/source/user/resources/cce/v1/cluster.rst b/doc/source/user/resources/cce/v1/cluster.rst deleted file mode 100644 index 4f61886d2..000000000 --- a/doc/source/user/resources/cce/v1/cluster.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.cce.v1.cluster -================================ - -.. automodule:: otcextensions.sdk.cce.v1.cluster - -The CCE Cluster Class ---------------------- - -The ``Cluster`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.cce.v1.cluster.Cluster - :members: diff --git a/doc/source/user/resources/cce/v1/cluster_node.rst b/doc/source/user/resources/cce/v1/cluster_node.rst deleted file mode 100644 index b6c9bf031..000000000 --- a/doc/source/user/resources/cce/v1/cluster_node.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.cce.v1.cluster_node -===================================== - -.. automodule:: otcextensions.sdk.cce.v1.cluster_node - -The CCE Cluster Host (Node) Class ---------------------------------- - -The ``ClusterHost`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.cce.v1.cluster_node.ClusterNode - :members: diff --git a/doc/source/user/resources/cce/v3/cluster.rst b/doc/source/user/resources/cce/v3/cluster.rst deleted file mode 100644 index 8b4cd7f60..000000000 --- a/doc/source/user/resources/cce/v3/cluster.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.cce.v3.cluster -================================ - -.. automodule:: otcextensions.sdk.cce.v3.cluster - -The CCE Cluster Class ---------------------- - -The ``Cluster`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.cce.v3.cluster.Cluster - :members: diff --git a/doc/source/user/resources/cce/v3/cluster_node.rst b/doc/source/user/resources/cce/v3/cluster_node.rst deleted file mode 100644 index 028332188..000000000 --- a/doc/source/user/resources/cce/v3/cluster_node.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.cce.v3.cluster_node -===================================== - -.. automodule:: otcextensions.sdk.cce.v3.cluster_node - -The CCE Cluster Host (Node) Class ---------------------------------- - -The ``ClusterHost`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.cce.v3.cluster_node.ClusterNode - :members: diff --git a/doc/source/user/resources/cts/index.rst b/doc/source/user/resources/cts/index.rst deleted file mode 100644 index c4af68b3d..000000000 --- a/doc/source/user/resources/cts/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -CTS Resources -============= - -.. toctree:: - :maxdepth: 1 - - v1/trace - v1/tracker diff --git a/doc/source/user/resources/cts/v1/trace.rst b/doc/source/user/resources/cts/v1/trace.rst deleted file mode 100644 index 04fff3d09..000000000 --- a/doc/source/user/resources/cts/v1/trace.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.cts.v1.trace -============================== - -.. automodule:: otcextensions.sdk.cts.v1.trace - -The CTS Trace Class -------------------- - -The ``Trace`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.cts.v1.trace.Trace - :members: diff --git a/doc/source/user/resources/cts/v1/tracker.rst b/doc/source/user/resources/cts/v1/tracker.rst deleted file mode 100644 index c3ace1804..000000000 --- a/doc/source/user/resources/cts/v1/tracker.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.cts.v1.tracker -================================ - -.. automodule:: otcextensions.sdk.cts.v1.tracker - -The CTS Tracker Class ---------------------- - -The ``Tracker`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.cts.v1.tracker.Tracker - :members: diff --git a/doc/source/user/resources/dcs/index.rst b/doc/source/user/resources/dcs/index.rst deleted file mode 100644 index f2c49c26d..000000000 --- a/doc/source/user/resources/dcs/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -DCS Resources -============= - -.. toctree:: - :maxdepth: 1 - - v1/backup - v1/config - v1/instance - v1/restore - v1/statistic diff --git a/doc/source/user/resources/dcs/v1/backup.rst b/doc/source/user/resources/dcs/v1/backup.rst deleted file mode 100644 index 243b376eb..000000000 --- a/doc/source/user/resources/dcs/v1/backup.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dcs.v1.backup -================================= - -.. automodule:: otcextensions.sdk.dcs.v1.backup - -The DCS Backup Class --------------------- - -The ``Backup`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dcs.v1.backup.Backup - :members: diff --git a/doc/source/user/resources/dcs/v1/config.rst b/doc/source/user/resources/dcs/v1/config.rst deleted file mode 100644 index 78656037e..000000000 --- a/doc/source/user/resources/dcs/v1/config.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dcs.v1.config -================================= - -.. automodule:: otcextensions.sdk.dcs.v1.config - -The DCS Config Class --------------------- - -The ``Config`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dcs.v1.config.Config - :members: diff --git a/doc/source/user/resources/dcs/v1/instance.rst b/doc/source/user/resources/dcs/v1/instance.rst deleted file mode 100644 index 1df70cb93..000000000 --- a/doc/source/user/resources/dcs/v1/instance.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dcs.v1.instance -================================= - -.. automodule:: otcextensions.sdk.dcs.v1.instance - -The DCS Instance Class ----------------------- - -The ``Instance`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dcs.v1.instance.Instance - :members: diff --git a/doc/source/user/resources/dcs/v1/restore.rst b/doc/source/user/resources/dcs/v1/restore.rst deleted file mode 100644 index 16a23a582..000000000 --- a/doc/source/user/resources/dcs/v1/restore.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dcs.v1.restore -================================= - -.. automodule:: otcextensions.sdk.dcs.v1.restore - -The DCS Restore Class ---------------------- - -The ``Restore`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dcs.v1.restore.Restore - :members: diff --git a/doc/source/user/resources/dcs/v1/statistic.rst b/doc/source/user/resources/dcs/v1/statistic.rst deleted file mode 100644 index 53b06a053..000000000 --- a/doc/source/user/resources/dcs/v1/statistic.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dcs.v1.statistic -================================== - -.. automodule:: otcextensions.sdk.dcs.v1.statistic - -The DCS Statistic Class ------------------------ - -The ``Statistic`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dcs.v1.statistic.Statistic - :members: diff --git a/doc/source/user/resources/deh/index.rst b/doc/source/user/resources/deh/index.rst deleted file mode 100644 index d3b3d1e7e..000000000 --- a/doc/source/user/resources/deh/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -DeH Resources -============= - -.. toctree:: - :maxdepth: 1 - - v1/host - v1/host_type - v1/server diff --git a/doc/source/user/resources/deh/v1/host.rst b/doc/source/user/resources/deh/v1/host.rst deleted file mode 100644 index 2b9942dcc..000000000 --- a/doc/source/user/resources/deh/v1/host.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.deh.v1.host -============================= - -.. automodule:: otcextensions.sdk.deh.v1.host - -The DeH Host Class ------------------- - -The ``Host`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.deh.v1.host.Host - :members: diff --git a/doc/source/user/resources/deh/v1/host_type.rst b/doc/source/user/resources/deh/v1/host_type.rst deleted file mode 100644 index 1d06abd4d..000000000 --- a/doc/source/user/resources/deh/v1/host_type.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.deh.v1.host_type -================================== - -.. automodule:: otcextensions.sdk.deh.v1.host_type - -The DeH Host Type Class ------------------------ - -The ``HostType`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.deh.v1.host_type.HostType - :members: diff --git a/doc/source/user/resources/deh/v1/server.rst b/doc/source/user/resources/deh/v1/server.rst deleted file mode 100644 index 25d80def7..000000000 --- a/doc/source/user/resources/deh/v1/server.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.deh.v1.server -=============================== - -.. automodule:: otcextensions.sdk.deh.v1.server - -The DeH Server Class --------------------- - -The ``Server`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.deh.v1.server.Server - :members: diff --git a/doc/source/user/resources/dms/index.rst b/doc/source/user/resources/dms/index.rst deleted file mode 100644 index 210555c88..000000000 --- a/doc/source/user/resources/dms/index.rst +++ /dev/null @@ -1,11 +0,0 @@ -DMS Resources -============= - -.. toctree:: - :maxdepth: 1 - - v1/group - v1/group_message - v1/message - v1/queue - v1/quota diff --git a/doc/source/user/resources/dms/v1/group.rst b/doc/source/user/resources/dms/v1/group.rst deleted file mode 100644 index 03663435e..000000000 --- a/doc/source/user/resources/dms/v1/group.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dcs.v1.group -============================== - -.. automodule:: otcextensions.sdk.dms.v1.group - -The DMS Group Class -------------------- - -The ``Group`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dms.v1.group.Group - :members: diff --git a/doc/source/user/resources/dms/v1/group_message.rst b/doc/source/user/resources/dms/v1/group_message.rst deleted file mode 100644 index 94090ce49..000000000 --- a/doc/source/user/resources/dms/v1/group_message.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dcs.v1.group_message -====================================== - -.. automodule:: otcextensions.sdk.dms.v1.group_message - -The DMS GroupMessage Class --------------------------- - -The ``GroupMessage`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dms.v1.group_message.GroupMessage - :members: diff --git a/doc/source/user/resources/dms/v1/message.rst b/doc/source/user/resources/dms/v1/message.rst deleted file mode 100644 index 72360e7f5..000000000 --- a/doc/source/user/resources/dms/v1/message.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dcs.v1.message -================================ - -.. automodule:: otcextensions.sdk.dms.v1.message - -The DMS Message Class ---------------------- - -The ``Message`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dms.v1.message.Message - :members: diff --git a/doc/source/user/resources/dms/v1/queue.rst b/doc/source/user/resources/dms/v1/queue.rst deleted file mode 100644 index 1942b9e68..000000000 --- a/doc/source/user/resources/dms/v1/queue.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dcs.v1.queue -============================== - -.. automodule:: otcextensions.sdk.dms.v1.queue - -The DMS Queue Class -------------------- - -The ``Queue`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dms.v1.queue.Queue - :members: diff --git a/doc/source/user/resources/dms/v1/quota.rst b/doc/source/user/resources/dms/v1/quota.rst deleted file mode 100644 index 5faa27fd5..000000000 --- a/doc/source/user/resources/dms/v1/quota.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dcs.v1.quota -============================== - -.. automodule:: otcextensions.sdk.dms.v1.quota - -The DMS Quota Class -------------------- - -The ``Quota`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dms.v1.quota.Quota - :members: diff --git a/doc/source/user/resources/dns/index.rst b/doc/source/user/resources/dns/index.rst deleted file mode 100644 index beb9d656b..000000000 --- a/doc/source/user/resources/dns/index.rst +++ /dev/null @@ -1,10 +0,0 @@ -Anti DDoS Resources -=================== - -.. toctree:: - :maxdepth: 1 - - v2/zone - v2/nameserver - v2/floating_ip - v2/recordset diff --git a/doc/source/user/resources/dns/v2/floating_ip.rst b/doc/source/user/resources/dns/v2/floating_ip.rst deleted file mode 100644 index 6b8b91b83..000000000 --- a/doc/source/user/resources/dns/v2/floating_ip.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dns.v2.floating_ip -==================================== - -.. automodule:: otcextensions.sdk.dns.v2.floating_ip - -The DNS FloatingIP Class ------------------------- - -The ``floating_ip`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dns.v2.floating_ip.FloatingIP - :members: diff --git a/doc/source/user/resources/dns/v2/nameserver.rst b/doc/source/user/resources/dns/v2/nameserver.rst deleted file mode 100644 index 16bc1bc38..000000000 --- a/doc/source/user/resources/dns/v2/nameserver.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dns.v2.nameserver -=================================== - -.. automodule:: otcextensions.sdk.dns.v2.nameserver - -The DNS Nameserver Class ------------------------- - -The ``Nameserver`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dns.v2.nameserver.NameServer - :members: diff --git a/doc/source/user/resources/dns/v2/recordset.rst b/doc/source/user/resources/dns/v2/recordset.rst deleted file mode 100644 index b96c4f748..000000000 --- a/doc/source/user/resources/dns/v2/recordset.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dns.v2.recordset -================================== - -.. automodule:: otcextensions.sdk.dns.v2.recordset - -The DNS Recordset Class ------------------------ - -The ``recordset`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dns.v2.recordset.Recordset - :members: diff --git a/doc/source/user/resources/dns/v2/zone.rst b/doc/source/user/resources/dns/v2/zone.rst deleted file mode 100644 index d0afbbc10..000000000 --- a/doc/source/user/resources/dns/v2/zone.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dns.v2.zone -============================= - -.. automodule:: otcextensions.sdk.dns.v2.zone - -The DNS Zone Class ------------------- - -The ``Zone`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dns.v2.zone.Zone - :members: diff --git a/doc/source/user/resources/kms/index.rst b/doc/source/user/resources/kms/index.rst deleted file mode 100644 index f1bc1afe8..000000000 --- a/doc/source/user/resources/kms/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -AutoScaling Resources -===================== - -.. toctree:: - :maxdepth: 1 - - v1/key - v1/data_key diff --git a/doc/source/user/resources/kms/v1/data_key.rst b/doc/source/user/resources/kms/v1/data_key.rst deleted file mode 100644 index 24a417254..000000000 --- a/doc/source/user/resources/kms/v1/data_key.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.kms.v1.data_key -================================= - -.. automodule:: otcextensions.sdk.kms.v1.data_key - -The KMS DEK Class ------------------ - -The ``DataKey`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.kms.v1.data_key.DataKey - :members: diff --git a/doc/source/user/resources/kms/v1/key.rst b/doc/source/user/resources/kms/v1/key.rst deleted file mode 100644 index 0f37920f3..000000000 --- a/doc/source/user/resources/kms/v1/key.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.kms.v1.key -============================ - -.. automodule:: otcextensions.sdk.kms.v1.key - -The KMS CMK Class ------------------ - -The ``Key`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.kms.v1.key.Key - :members: diff --git a/doc/source/user/resources/obs/index.rst b/doc/source/user/resources/obs/index.rst deleted file mode 100644 index adea4ca5d..000000000 --- a/doc/source/user/resources/obs/index.rst +++ /dev/null @@ -1,8 +0,0 @@ -OBS Resources -============= - -.. toctree:: - :maxdepth: 1 - - v1/container - v1/obj diff --git a/doc/source/user/resources/obs/v1/container.rst b/doc/source/user/resources/obs/v1/container.rst deleted file mode 100644 index 658398031..000000000 --- a/doc/source/user/resources/obs/v1/container.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.obs.v1.container -================================== - -.. automodule:: otcextensions.sdk.obs.v1.container - -The OBS Container (Bucket) Class --------------------------------- - -The ``Container`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.obs.v1.container.Container - :members: diff --git a/doc/source/user/resources/obs/v1/obj.rst b/doc/source/user/resources/obs/v1/obj.rst deleted file mode 100644 index 5492cdbf8..000000000 --- a/doc/source/user/resources/obs/v1/obj.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.obs.v1.obj -============================ - -.. automodule:: otcextensions.sdk.obs.v1.obj - -The OBS Object Class --------------------- - -The ``Object`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.obs.v1.obj.Object - :members: diff --git a/doc/source/user/resources/rds/index.rst b/doc/source/user/resources/rds/index.rst deleted file mode 100644 index 935c168e6..000000000 --- a/doc/source/user/resources/rds/index.rst +++ /dev/null @@ -1,12 +0,0 @@ -RDS Resources -============= - -.. toctree:: - :maxdepth: 1 - - v1/configuration - v1/flavor - v1/instance - v3/configuration - v3/flavor - v3/instance diff --git a/doc/source/user/resources/rds/v1/configuration.rst b/doc/source/user/resources/rds/v1/configuration.rst deleted file mode 100644 index 2fe69c1b5..000000000 --- a/doc/source/user/resources/rds/v1/configuration.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.rds.v1.configuration -====================================== - -.. automodule:: otcextensions.sdk.rds.v1.configuration - -The Configuration Class ------------------------ - -The ``Configuration`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.rds.v1.configuration.ConfigurationGroup - :members: diff --git a/doc/source/user/resources/rds/v1/flavor.rst b/doc/source/user/resources/rds/v1/flavor.rst deleted file mode 100644 index 2033f62eb..000000000 --- a/doc/source/user/resources/rds/v1/flavor.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.rds.v1.flavor -=============================== - -.. automodule:: otcextensions.sdk.rds.v1.flavor - -The Flavor Class ----------------- - -The ``Flavor`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.rds.v1.flavor.Flavor - :members: diff --git a/doc/source/user/resources/rds/v1/instance.rst b/doc/source/user/resources/rds/v1/instance.rst deleted file mode 100644 index 07e75ff44..000000000 --- a/doc/source/user/resources/rds/v1/instance.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.rds.v1.instance -================================= - -.. automodule:: otcextensions.sdk.rds.v1.instance - -The Instance Class ------------------- - -The ``Instance`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.rds.v1.instance.Instance - :members: diff --git a/doc/source/user/resources/rds/v3/configuration.rst b/doc/source/user/resources/rds/v3/configuration.rst deleted file mode 100644 index 2952778eb..000000000 --- a/doc/source/user/resources/rds/v3/configuration.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.rds.v3.configuration -====================================== - -.. automodule:: otcextensions.sdk.rds.v3.configuration - -The Configuration Class ------------------------ - -The ``Configuration`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.rds.v3.configuration.ConfigurationGroup - :members: diff --git a/doc/source/user/resources/rds/v3/flavor.rst b/doc/source/user/resources/rds/v3/flavor.rst deleted file mode 100644 index a8806f213..000000000 --- a/doc/source/user/resources/rds/v3/flavor.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.rds.v3.flavor -=============================== - -.. automodule:: otcextensions.sdk.rds.v3.flavor - -The Flavor Class ----------------- - -The ``Flavor`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.rds.v3.flavor.Flavor - :members: diff --git a/doc/source/user/resources/rds/v3/instance.rst b/doc/source/user/resources/rds/v3/instance.rst deleted file mode 100644 index d72e7cd4f..000000000 --- a/doc/source/user/resources/rds/v3/instance.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.rds.v3.instance -================================= - -.. automodule:: otcextensions.sdk.rds.v3.instance - -The Instance Class ------------------- - -The ``Instance`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.rds.v3.instance.Instance - :members: diff --git a/doc/source/user/transition_from_profile.rst b/doc/source/user/transition_from_profile.rst deleted file mode 100644 index a6edc6a5e..000000000 --- a/doc/source/user/transition_from_profile.rst +++ /dev/null @@ -1,186 +0,0 @@ -Transition from Profile -======================= - -.. note:: This section describes migrating code from a previous interface of - openstacksdk and can be ignored by people writing new code. - -If you have code that currently uses the :class:`~openstack.profile.Profile` -object and/or an ``authenticator`` instance from an object based on -``openstack.auth.base.BaseAuthPlugin``, that code should be updated to use the -:class:`~openstack.config.cloud_region.CloudRegion` object instead. - -.. important:: - - :class:`~openstack.profile.Profile` is going away. Existing code using it - should be migrated as soon as possible. - -Writing Code that Works with Both ---------------------------------- - -These examples should all work with both the old and new interface, with one -caveat. With the old interface, the ``CloudConfig`` object comes from the -``os-client-config`` library, and in the new interface that has been moved -into the SDK. In order to write code that works with both the old and new -interfaces, use the following code to import the config namespace: - -.. code-block:: python - - try: - from openstack import config as occ - except ImportError: - from os_client_config import config as occ - -The examples will assume that the config module has been imported in that -manner. - -.. note:: Yes, there is an easier and less verbose way to do all of these. - These are verbose to handle both the old and new interfaces in the - same codebase. - -Replacing authenticator ------------------------ - -There is no direct replacement for ``openstack.auth.base.BaseAuthPlugin``. -``openstacksdk`` uses the `keystoneauth`_ library for authentication -and HTTP interactions. `keystoneauth`_ has `auth plugins`_ that can be used -to control how authentication is done. The ``auth_type`` config parameter -can be set to choose the correct authentication method to be used. - -Replacing Profile ------------------ - -The right way to replace the use of ``openstack.profile.Profile`` depends -a bit on what you're trying to accomplish. Common patterns are listed below, -but in general the approach is either to pass a cloud name to the -`openstack.connection.Connection` constructor, or to construct a -`openstack.config.cloud_region.CloudRegion` object and pass it to the -constructor. - -All of the examples on this page assume that you want to support old and -new interfaces simultaneously. There are easier and less verbose versions -of each that are available if you can just make a clean transition. - -Getting a Connection to a named cloud from clouds.yaml ------------------------------------------------------- - -If you want is to construct a `openstack.connection.Connection` based on -parameters configured in a ``clouds.yaml`` file, or from environment variables: - -.. code-block:: python - - import openstack.connection - - conn = connection.from_config(cloud_name='name-of-cloud-you-want') - -Getting a Connection from python arguments avoiding clouds.yaml ---------------------------------------------------------------- - -If, on the other hand, you want to construct a -`openstack.connection.Connection`, but are in a context where reading config -from a clouds.yaml file is undesirable, such as inside of a Service: - -* create a `openstack.config.loader.OpenStackConfig` object, telling - it to not load yaml files. Optionally pass an ``app_name`` and - ``app_version`` which will be added to user-agent strings. -* get a `openstack.config.cloud_region.CloudRegion` object from it -* get a `openstack.connection.Connection` - -.. code-block:: python - - try: - from openstack import config as occ - except ImportError: - from os_client_config import config as occ - from openstack import connection - - loader = occ.OpenStackConfig( - load_yaml_files=False, - app_name='spectacular-app', - app_version='1.0') - cloud_region = loader.get_one_cloud( - region_name='my-awesome-region', - auth_type='password', - auth=dict( - auth_url='https://auth.example.com', - username='amazing-user', - user_domain_name='example-domain', - project_name='astounding-project', - user_project_name='example-domain', - password='super-secret-password', - )) - conn = connection.from_config(cloud_config=cloud_region) - -.. note:: app_name and app_version are completely optional, and auth_type - defaults to 'password'. They are shown here for clarity as to - where they should go if they want to be set. - -Getting a Connection from python arguments and optionally clouds.yaml ---------------------------------------------------------------------- - -If you want to make a connection from python arguments and want to allow -one of them to optionally be ``cloud`` to allow selection of a named cloud, -it's essentially the same as the previous example, except without -``load_yaml_files=False``. - -.. code-block:: python - - try: - from openstack import config as occ - except ImportError: - from os_client_config import config as occ - from openstack import connection - - loader = occ.OpenStackConfig( - app_name='spectacular-app', - app_version='1.0') - cloud_region = loader.get_one_cloud( - region_name='my-awesome-region', - auth_type='password', - auth=dict( - auth_url='https://auth.example.com', - username='amazing-user', - user_domain_name='example-domain', - project_name='astounding-project', - user_project_name='example-domain', - password='super-secret-password', - )) - conn = connection.from_config(cloud_config=cloud_region) - -Parameters to get_one_cloud ---------------------------- - -The most important things to note are: - -* ``auth_type`` specifies which kind of authentication plugin to use. It - controls how authentication is done, as well as what parameters are required. -* ``auth`` is a dictionary containing the parameters needed by the auth plugin. - The most common information it needs are user, project, domain, auth_url - and password. -* The rest of the keyword arguments to - ``openstack.config.loader.OpenStackConfig.get_one_cloud`` are either - parameters needed by the `keystoneauth Session`_ object, which control how - HTTP connections are made, or parameters needed by the - `keystoneauth Adapter`_ object, which control how services are found in the - Keystone Catalog. - -For `keystoneauth Adapter`_ parameters, since there is one -`openstack.connection.Connection` object but many services, per-service -parameters are formed by using the official ``service_type`` of the service -in question. For instance, to override the endpoint for the ``compute`` -service, the parameter ``compute_endpoint_override`` would be used. - -``region_name`` in ``openstack.profile.Profile`` was a per-service parameter. -This is no longer a valid concept. An `openstack.connection.Connection` is a -connection to a region of a cloud. If you are in an extreme situation where -you have one service in one region and a different service in a different -region, you must use two different `openstack.connection.Connection` objects. - -.. note:: service_type, although a parameter for keystoneauth1.adapter.Adapter, - is not a valid parameter for get_one_cloud. service_type is the key - by which services are referred, so saying - 'compute_service_type="henry"' doesn't have any meaning. - -.. _keystoneauth: https://docs.openstack.org/keystoneauth/latest/ -.. _auth plugins: https://docs.openstack.org/keystoneauth/latest/authentication-plugins.html -.. _keystoneauth Adapter: https://docs.openstack.org/keystoneauth/latest/api/keystoneauth1.html#keystoneauth1.adapter.Adapter -.. _keystoneauth Session: https://docs.openstack.org/keystoneauth/latest/api/keystoneauth1.html#keystoneauth1.session.Session diff --git a/doc/source/user/utils.rst b/doc/source/user/utils.rst deleted file mode 100644 index 5c1f39de9..000000000 --- a/doc/source/user/utils.rst +++ /dev/null @@ -1,3 +0,0 @@ -Utilities -========= -.. automodule:: openstack.utils diff --git a/examples/anti_ddos/get_floating_ip_policies.py b/examples/anti_ddos/get_floating_ip_policies.py new file mode 100644 index 000000000..47d95405e --- /dev/null +++ b/examples/anti_ddos/get_floating_ip_policies.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# 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. +""" +Retrieve Anti-DDoS Policy for a specific Floating IP by using Floating IP id +or an instance of class FloatingIP. Anti-DDoS must be enabled for this IP +otherwise an error occures. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +fip = "floating_ip_id" +policy = conn.anti_ddos.get_floating_ip_policies(fip) +print(policy) diff --git a/examples/anti_ddos/get_floating_ip_status.py b/examples/anti_ddos/get_floating_ip_status.py new file mode 100644 index 000000000..41c3bc366 --- /dev/null +++ b/examples/anti_ddos/get_floating_ip_status.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# 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. +""" +Get Anti-DDoS status of a Floating IP by using id. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +fip = "floating_ip_id" + +status = conn.anti_ddos.get_floating_ip_status(fip) +print(status) diff --git a/examples/anti_ddos/list_configs.py b/examples/anti_ddos/list_configs.py new file mode 100644 index 000000000..8ab079e63 --- /dev/null +++ b/examples/anti_ddos/list_configs.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# 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. +""" +List Anti-DDoS alarm configurations. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +for config in conn.anti_ddos.configs(): + print(config) diff --git a/examples/anti_ddos/list_floating_ip_events.py b/examples/anti_ddos/list_floating_ip_events.py new file mode 100644 index 000000000..a457fb70b --- /dev/null +++ b/examples/anti_ddos/list_floating_ip_events.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# 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. +""" +Get Anti-DDoS status of a Floating IP by using id. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +fip = "floating_ip_id" + +for event in conn.anti_ddos.floating_ip_events(fip): + print(event) diff --git a/examples/anti_ddos/list_floating_ip_stat_day.py b/examples/anti_ddos/list_floating_ip_stat_day.py new file mode 100644 index 000000000..0d1c38124 --- /dev/null +++ b/examples/anti_ddos/list_floating_ip_stat_day.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# 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. +""" +List Anti-DDoS events per day of a Floating IP by using id. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +fip = "floating_ip_id" + +for event in conn.anti_ddos.floating_ip_stat_day(fip): + print(event) diff --git a/examples/anti_ddos/list_floating_ip_stat_week.py b/examples/anti_ddos/list_floating_ip_stat_week.py new file mode 100644 index 000000000..1ea2e70f1 --- /dev/null +++ b/examples/anti_ddos/list_floating_ip_stat_week.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# 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. +""" +List all Anti-DDoS events per week of all Floating IPs. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +for event in conn.anti_ddos.floating_ip_stat_week(): + print(event) diff --git a/examples/anti_ddos/list_floating_ips.py b/examples/anti_ddos/list_floating_ips.py new file mode 100644 index 000000000..7dfef4690 --- /dev/null +++ b/examples/anti_ddos/list_floating_ips.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# 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. +""" +List all Anti-DDoS Floating IPs and limit the output with query parameters. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +for fip in conn.anti_ddos.floating_ips(): + print(fip) diff --git a/examples/anti_ddos/protect_floating_ip.py b/examples/anti_ddos/protect_floating_ip.py new file mode 100644 index 000000000..bc158689f --- /dev/null +++ b/examples/anti_ddos/protect_floating_ip.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# 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. +""" +Protect with Anti-DDoS a Floating IP by using id or an instance of class +FloatingIP +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +fip = "floating_ip_id" +conn.anti_ddos.protect_floating_ip(fip) diff --git a/examples/anti_ddos/unprotect_floating_ip.py b/examples/anti_ddos/unprotect_floating_ip.py new file mode 100644 index 000000000..9d55dba19 --- /dev/null +++ b/examples/anti_ddos/unprotect_floating_ip.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# 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. +""" +Unprotect a Floating IP from Anti-DDoS by using id or an instance of class +FloatingIP +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +fip = "floating_ip_id" +conn.anti_ddos.unprotect_floating_ip(fip) diff --git a/examples/anti_ddos/update_floating_ip_policies.py b/examples/anti_ddos/update_floating_ip_policies.py new file mode 100644 index 000000000..2ab5f7634 --- /dev/null +++ b/examples/anti_ddos/update_floating_ip_policies.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +# 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. +""" +Update Anti-DDoS Policy attributes. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +fip = "floating_ip_id" +attrs = { + "enable_L7": False, + "traffic_pos_id": 2, + "http_request_pos_id": 1, + "cleaning_access_pos_id": 1, + "app_type_id": 1 +} + +policy = conn.anti_ddos.update_floating_ip_policies(fip, **attrs) diff --git a/examples/auto_scaling/batch_delete_config.py b/examples/auto_scaling/batch_delete_config.py new file mode 100644 index 000000000..7e4b72ec1 --- /dev/null +++ b/examples/auto_scaling/batch_delete_config.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# 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. +""" +Delete multiple Auto-Scaling Configurations by id or instance of class Config +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +config1 = conn.auto_scaling.find_config('test-config1') +config2 = conn.auto_scaling.find_config('test-config2') + +configs = [config1, config2] + +conn.auto_scaling.batch_delete_configs(configs) diff --git a/examples/auto_scaling/batch_instance_action.py b/examples/auto_scaling/batch_instance_action.py new file mode 100644 index 000000000..7b6d44adf --- /dev/null +++ b/examples/auto_scaling/batch_instance_action.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# 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. +""" +Remove an Auto-Scaling Instances of a specific AS Group. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +group = "group_name_or_id" +group = conn.auto_scaling.find_group(group) + +instances = [ + "instance_id", + "instance_id2" +] + +action = "ADD" + +conn.auto_scaling.batch_instance_action( + group, + instances, + action, # ADD, REMOVE, PROTECT, UNPROTECT + delete_instance=False +) diff --git a/examples/auto_scaling/create_config.py b/examples/auto_scaling/create_config.py new file mode 100644 index 000000000..71249cbaa --- /dev/null +++ b/examples/auto_scaling/create_config.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 +# 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. +""" +Create Auto-Scaling Configuration. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +attrs = { + 'name': 'test-config', + 'instance_config': { + 'flavorRef': 's2.medium.1', + 'imageRef': '1616e0b6-503a-4698-946f-cf9942c4c73b', + 'disk': [{ + 'size': 20, + 'volume_type': 'SATA', + 'disk_type': 'SYS' + }], + 'key_name': 'test-key', + } +} + +config = conn.auto_scaling.create_config(**attrs) +print(config) diff --git a/examples/auto_scaling/create_group.py b/examples/auto_scaling/create_group.py new file mode 100644 index 000000000..ee488a489 --- /dev/null +++ b/examples/auto_scaling/create_group.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +# 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. +""" +Create Auto-Scaling Group. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +attrs = { + "scaling_group_name": "TestGroup", + "scaling_configuration_id": "0d138717-e79d-4fa7-b8aa-37ddec1b3ce7", + "desire_instance_number": 0, + "min_instance_number": 0, + "max_instance_number": 10, + "vpc_id": "26ca2783-dc40-4e3a-95b1-5a0756441e12", + "available_zones": ["eu-de-01", "eu-de-03"], + "networks": [ + { + "id": "25d24fc8-d019-4a34-9fff-0a09fde6a9cb" + } + ] +} + +group = conn.auto_scaling.create_group(**attrs) +print(group) diff --git a/examples/auto_scaling/delete_config.py b/examples/auto_scaling/delete_config.py new file mode 100644 index 000000000..1dff5e3f5 --- /dev/null +++ b/examples/auto_scaling/delete_config.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# 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. +""" +Delete Auto-Scaling Configuration by id or instance of class Config +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +config_id = '1234567-ad7a-48ce-8f92-b55c651439d2' +conn.auto_scaling.delete_config(config_id) diff --git a/examples/auto_scaling/delete_group.py b/examples/auto_scaling/delete_group.py new file mode 100644 index 000000000..49c362334 --- /dev/null +++ b/examples/auto_scaling/delete_group.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# 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. +""" +Delete Auto-Scaling Group by id or instance of class Group. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +group_id = '1234567-ad7a-48ce-8f92-b55c651439d2' +conn.auto_scaling.delete_group(group_id) diff --git a/examples/auto_scaling/delete_policy.py b/examples/auto_scaling/delete_policy.py new file mode 100644 index 000000000..84891947d --- /dev/null +++ b/examples/auto_scaling/delete_policy.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python3 +# 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. +""" +Delete Auto-Scaling Policy by id or instance of class Policy. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +policy_id = '1234567-ad7a-48ce-8f92-b55c651439d2' +conn.auto_scaling.delete_policy(policy_id) diff --git a/examples/auto_scaling/execute_policy.py b/examples/auto_scaling/execute_policy.py new file mode 100644 index 000000000..f90d78b2d --- /dev/null +++ b/examples/auto_scaling/execute_policy.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# 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. +""" +Execute an Auto-Scaling Policy by id or an instance of class Policy +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +policy = "policy_name_or_id" +policy = conn.auto_scaling.find_policy(policy) + +conn.auto_scaling.execute_policy(policy) diff --git a/examples/auto_scaling/find_config.py b/examples/auto_scaling/find_config.py new file mode 100644 index 000000000..36969af62 --- /dev/null +++ b/examples/auto_scaling/find_config.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# 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. +""" +Find Auto-Scaling Configuration by name or id. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +config = "config_name_or_id" + +config = conn.auto_scaling.find_config(config) +print(config) diff --git a/examples/auto_scaling/find_group.py b/examples/auto_scaling/find_group.py new file mode 100644 index 000000000..38bc88d9c --- /dev/null +++ b/examples/auto_scaling/find_group.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# 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. +""" +Find Auto-Scaling Group. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +group = "group_name_or_id" + +group = conn.auto_scaling.find_group(group) +print(group) diff --git a/examples/auto_scaling/find_policy.py b/examples/auto_scaling/find_policy.py new file mode 100644 index 000000000..4d33596cd --- /dev/null +++ b/examples/auto_scaling/find_policy.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# 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. +""" +Find Auto-Scaling Policy by name or id. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +policy = "policy_name_or_id" + +policy = conn.auto_scaling.find_policy(policy) +print(policy) diff --git a/examples/auto_scaling/get_config.py b/examples/auto_scaling/get_config.py new file mode 100644 index 000000000..194f394a5 --- /dev/null +++ b/examples/auto_scaling/get_config.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# 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. +""" +Get Auto-Scaling Configuration by id or object +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +config_id = "1234567-6aa0-4c8b-b350-3bd937addeb7" +config = conn.auto_scaling.get_config(config_id) +print(config) diff --git a/examples/auto_scaling/get_group.py b/examples/auto_scaling/get_group.py new file mode 100644 index 000000000..7a884ae90 --- /dev/null +++ b/examples/auto_scaling/get_group.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# 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. +""" +Get Auto-Scaling Group by id or object +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +group_id = "1234567-6aa0-4c8b-b350-3bd937addeb7" +group = conn.auto_scaling.get_group(group_id) +print(group) diff --git a/examples/auto_scaling/get_policy.py b/examples/auto_scaling/get_policy.py new file mode 100644 index 000000000..f3673b16c --- /dev/null +++ b/examples/auto_scaling/get_policy.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# 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. +""" +Get Auto-Scaling Policy by id or object +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +policy_id = "1234567-6aa0-4c8b-b350-3bd937addeb7" +policy = conn.auto_scaling.get_policy(policy_id) +print(policy) diff --git a/examples/auto_scaling/init.py b/examples/auto_scaling/init.py new file mode 100644 index 000000000..e69de29bb diff --git a/examples/auto_scaling/list_activities.py b/examples/auto_scaling/list_activities.py new file mode 100644 index 000000000..eafd7f50d --- /dev/null +++ b/examples/auto_scaling/list_activities.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# 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. +""" +List all Auto-Scaling query action logs of an AS group. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +group = "group_name_or_id" +group = conn.auto_scaling.find_group(group) + + +for activity in conn.auto_scaling.activities(group): + print(activity) diff --git a/examples/auto_scaling/list_configs.py b/examples/auto_scaling/list_configs.py new file mode 100644 index 000000000..3fc9a49a8 --- /dev/null +++ b/examples/auto_scaling/list_configs.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +# 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. +""" +List all Auto-Scaling Configurations +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +for config in conn.auto_scaling.configs(): + print(config) diff --git a/examples/auto_scaling/list_groups.py b/examples/auto_scaling/list_groups.py new file mode 100644 index 000000000..4bcc31811 --- /dev/null +++ b/examples/auto_scaling/list_groups.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +# 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. +""" +List all Auto-Scaling Groups +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +for group in conn.auto_scaling.groups(): + print(group) diff --git a/examples/auto_scaling/list_instances.py b/examples/auto_scaling/list_instances.py new file mode 100644 index 000000000..d766d31a9 --- /dev/null +++ b/examples/auto_scaling/list_instances.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# 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. +""" +List all Auto-Scaling scaling action logs of a specific AS Group. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +group = "group_name_or_id" +group = conn.auto_scaling.find_group(group) + +for activity in conn.auto_scaling.activities(group): + print(activity) diff --git a/examples/auto_scaling/list_policies.py b/examples/auto_scaling/list_policies.py new file mode 100644 index 000000000..25e5b7ba8 --- /dev/null +++ b/examples/auto_scaling/list_policies.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# 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. +""" +List all Auto-Scaling Policies of a specific AS Group. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +group = "group_name_or_id" +group = conn.auto_scaling.find_group(group) + +for policy in conn.auto_scaling.policies(group): + print(policy) diff --git a/examples/auto_scaling/list_quotas.py b/examples/auto_scaling/list_quotas.py new file mode 100644 index 000000000..098b3b628 --- /dev/null +++ b/examples/auto_scaling/list_quotas.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python3 +# 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. +""" +List all Auto-Scaling quotas of a user or a specific AS Group. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +# group = "group_name_or_id" +# group = conn.auto_scaling.find_group(group) + +# If group is set, group quotas ar listed instead of user quotas +for quota in conn.auto_scaling.quotas(group=None): + print(quota) diff --git a/examples/auto_scaling/pause_group.py b/examples/auto_scaling/pause_group.py new file mode 100644 index 000000000..7b4499e97 --- /dev/null +++ b/examples/auto_scaling/pause_group.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# 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. +""" +Pause an Auto-Scaling Group by id or an instance of class Group +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +group = "group_name_or_id" +group = conn.auto_scaling.find_group(group) + +conn.auto_scaling.pause_group(group) diff --git a/examples/auto_scaling/pause_policy.py b/examples/auto_scaling/pause_policy.py new file mode 100644 index 000000000..fcf0a715c --- /dev/null +++ b/examples/auto_scaling/pause_policy.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# 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. +""" +Pause an Auto-Scaling Policy by id or an instance of class Policy +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +policy = "policy_name_or_id" +policy = conn.auto_scaling.find_policy(policy) + +conn.auto_scaling.pause_policy(policy) diff --git a/examples/auto_scaling/remove_instance.py b/examples/auto_scaling/remove_instance.py new file mode 100644 index 000000000..4ada6aa39 --- /dev/null +++ b/examples/auto_scaling/remove_instance.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# 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. +""" +Remove an Auto-Scaling Instances of a specific AS Group. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +instance = "instance_id" + +conn.auto_scaling.remove_instance( + instance, + delete=False # If True, instance will be deleted after remove +) diff --git a/examples/auto_scaling/resume_group.py b/examples/auto_scaling/resume_group.py new file mode 100644 index 000000000..559d6940f --- /dev/null +++ b/examples/auto_scaling/resume_group.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# 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. +""" +Resume an Auto-Scaling Group by id or an instance of class Group +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +group_id = "123456_group_id" + +conn.auto_scaling.resume_group(group_id) diff --git a/examples/auto_scaling/resume_policy.py b/examples/auto_scaling/resume_policy.py new file mode 100644 index 000000000..b740a55dc --- /dev/null +++ b/examples/auto_scaling/resume_policy.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# 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. +""" +Resume an Auto-Scaling Policy by id or an instance of class Policy +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +policy = "policy_name_or_id" +policy = conn.auto_scaling.find_policy(policy) + +conn.auto_scaling.resume_policy(policy) diff --git a/examples/auto_scaling/update_policy.py b/examples/auto_scaling/update_policy.py new file mode 100644 index 000000000..4ef87e2d6 --- /dev/null +++ b/examples/auto_scaling/update_policy.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 +# 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. +""" +Update Auto-Scaling Policy by using id or an instance of class Policy. +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +policy = "policy_name_or_id" +attrs = { + "scaling_policy_type": "RECURRENCE", + "scaling_policy_name": "policy_01", + "scheduled_policy": { + "launch_time": "16:00", + "recurrence_type": "Daily", + "end_time": "2016-02-08T17:31Z", + "start_time": "2016-01-08T17:31Z" + }, + "scaling_policy_action": { + "operation": "SET", + "instance_number": 2 + } +} + +policy = conn.auto_scaling.find_policy(policy) +conn.auto_scaling.update_policy(policy, **attrs) diff --git a/examples/cce/create_cluster.py b/examples/cce/create_cluster.py new file mode 100644 index 000000000..9ec082bcb --- /dev/null +++ b/examples/cce/create_cluster.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# 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. +""" +Create CCE Cluster +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +attrs = { + "kind": "Cluster", + "apiVersion": "v3", + "metadata": { + "name": "test2" + }, + "spec": { + "type": "VirtualMachine", + "flavor": "cce.s1.small", + "version": "v1.13.10-r0", + "az": "eu-de-01", + "supportIstio": True, + "hostNetwork": { + "vpc": "26ca2783-dc40-4e3a-95b1-5a0756441e12", + "subnet": "25d24fc8-d019-4a34-9fff-0a09fde6a9cb", + "SecurityGroup": "f9ae0767-25be-44fc-a21c-5b8a0da66dec" + }, + "containerNetwork": { + "mode": "overlay_l2", + "cidr": "172.16.0.0/16" + }, + "authentication": { + "mode": "rbac", + "authenticatingProxy": {} + }, + "billingMode": 0, + "kubernetesSvcIpRange": "10.247.0.0/16", + "kubeProxyMode": "iptables" + } +} + +conn.cce.create_cluster(**attrs) diff --git a/examples/cce/create_cluster_node.py b/examples/cce/create_cluster_node.py new file mode 100644 index 000000000..35068f946 --- /dev/null +++ b/examples/cce/create_cluster_node.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 +# 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. +""" +Create CCE Cluster node +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +attrs = { + "kind": "Cluster", + "apiVersion": "v3", + "metadata": { + "name": "test2" + }, + "spec": { + "type": "VirtualMachine", + "flavor": "cce.s1.small", + "version": "v1.13.10-r0", + "az": "eu-de-01", + "supportIstio": True, + "hostNetwork": { + "vpc": "26ca2783-dc40-4e3a-95b1-5a0756441e12", + "subnet": "25d24fc8-d019-4a34-9fff-0a09fde6a9cb", + "SecurityGroup": "f9ae0767-25be-44fc-a21c-5b8a0da66dec" + }, + "containerNetwork": { + "mode": "overlay_l2", + "cidr": "172.16.0.0/16" + }, + "authentication": { + "mode": "rbac", + "authenticatingProxy": {} + }, + "billingMode": 0, + "kubernetesSvcIpRange": "10.247.0.0/16", + "kubeProxyMode": "iptables" + } +} + +conn.cce.create_cluster_node(**attrs) diff --git a/examples/cce/delete_cluster.py b/examples/cce/delete_cluster.py new file mode 100644 index 000000000..9aff2c8fb --- /dev/null +++ b/examples/cce/delete_cluster.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# 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. +""" +Get a CCE cluster by id or class Cluster +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +cluster_name = "cluster_name" +cluster = conn.cce.find_cluster(cluster_name) +print(cluster) +conn.cce.delete_cluster(cluster) diff --git a/examples/cce/delete_cluster_node.py b/examples/cce/delete_cluster_node.py new file mode 100644 index 000000000..7673875e6 --- /dev/null +++ b/examples/cce/delete_cluster_node.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# 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. +""" +Delete a CCE cluster node +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +cluster = "cluster_name_or_id" +cluster = conn.cce.find_cluster(cluster) +node_id = "node_id" +conn.cce.delete_cluster_node(cluster, node_id) diff --git a/examples/cce/find_cluster.py b/examples/cce/find_cluster.py new file mode 100644 index 000000000..ec1a796bf --- /dev/null +++ b/examples/cce/find_cluster.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# 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. +""" +Get a CCE cluster by id or class Cluster +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +cluster = "cluster_name_or_id" +cluster = conn.cce.find_cluster(cluster) +print(cluster) diff --git a/examples/cce/find_cluster_node.py b/examples/cce/find_cluster_node.py new file mode 100644 index 000000000..c1dfd17f3 --- /dev/null +++ b/examples/cce/find_cluster_node.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# 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. +""" +Find a CCE cluster node by name or id +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +cluster = "cluster_name_or_id" +cluster = conn.cce.find_cluster(cluster) +node = "node_name_or_id" +node = conn.cce.find_cluster_node(cluster, node) +print(node) diff --git a/examples/cce/get_cluster.py b/examples/cce/get_cluster.py new file mode 100644 index 000000000..0263c2011 --- /dev/null +++ b/examples/cce/get_cluster.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# 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. +""" +Get a CCE cluster by id or class Cluster +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +cluster_id = "123456_cluster_id" +cluster = conn.cce.get_cluster(cluster_id) +print(cluster) diff --git a/examples/cce/get_cluster_node.py b/examples/cce/get_cluster_node.py new file mode 100644 index 000000000..448c49084 --- /dev/null +++ b/examples/cce/get_cluster_node.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python3 +# 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. +""" +Get a CCE cluster node by id or class ClusterNode +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +cluster = "cluster_name_or_id" +cluster = conn.cce.find_cluster(cluster) +node_id = "node_id" +node = conn.cce.get_cluster_node(cluster, node_id) +print(node) diff --git a/examples/cce/get_job.py b/examples/cce/get_job.py new file mode 100644 index 000000000..0a3fec904 --- /dev/null +++ b/examples/cce/get_job.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python3 +# 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. +""" +Get a Job by id or instance of class Job +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +job_id = "123456_job_id" +job = conn.cce.get_job(job_id) +print(job) diff --git a/examples/cce/list_cluster_nodes.py b/examples/cce/list_cluster_nodes.py new file mode 100644 index 000000000..cf0016ac6 --- /dev/null +++ b/examples/cce/list_cluster_nodes.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# 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. +""" +List all nodes of a CCE cluster +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +cluster = "cluster_name_or_id" +cluster = conn.cce.find_cluster(cluster) +for node in conn.cce.cluster_nodes(cluster): + print(node) diff --git a/examples/cce/list_clusters.py b/examples/cce/list_clusters.py new file mode 100644 index 000000000..da61925d7 --- /dev/null +++ b/examples/cce/list_clusters.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 +# 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. +""" +List all CCE clusters +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + +for cluster in conn.cce.clusters(): + print(cluster) diff --git a/examples/cce/wait_for_job.py b/examples/cce/wait_for_job.py new file mode 100644 index 000000000..03c033503 --- /dev/null +++ b/examples/cce/wait_for_job.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +# 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. +""" +Wait for a job until it reaches a specific status +""" +import openstack + +openstack.enable_logging(True) +conn = openstack.connect(cloud='otc') + + +job_id = "123456_job_id" +conn.cce.wait_for_job(job_id, status='success', + failures=None, interval=5, wait=3600) +print('Done') diff --git a/open_points b/open_points deleted file mode 100644 index 2953d9c25..000000000 --- a/open_points +++ /dev/null @@ -1,125 +0,0 @@ -This document gathers issues, which are found during diggint the API and other OS tools working with API - -* on 28.03 native service version discovery request to https://as.eu-de.otc.t-systems.com/autoscaling-api/ caused timeout. AS service is temporarily disabled - -# General: - -* Inconsistent naming between services (AS:create_time, KMS:creation_date, CCE:createAt) -* Inconsistent error message structure between services (i.e. KMS vs RDS). This prohibits code generalization -* No custom service supports proper version discovery. Leads to error messages in the OSC tool and execution delays -* LB: while Neutron LBaaS is "strongly" considered as deprecated and no bindings are present in Ansible/OSC - it will likely not be possible/challenge to upstream this support. -* EVS: volume type list --long returns changing results -* Subnet (in some APIs) is most likely net_id -* Without service discovery and multiple versions it is not possible to get the proper service version in SDK. It falls back to first entry in the VersionFilter -* Tags require different format ("key=value" vs "key*value") - -# KMS: - -* service version discovery is broken. On https://kms.eu-de.otc.t-systems.com/ it returns - {"versions": [{"status": "CURRENT", "id": "v1.0", "links": [{"href": "https://rts.eu-de.otc.t-systems.com/v1/", "rel": "self"}]}]} - In the keystoneauth1 it results to get_endpoint=https://kms.eu-de.otc.t-systems.com/v1 (instead of V1.0). Detailed investigation is expensive, therefore aborted -* does not follow REST, everything is POST with different URLs and not even json['action'] -* is conceptually far away from Barbican -* API Doc: This API allows you to create a plaintext-free DEK, that is, the returned result of this API includes `only the plaintext` of the DEK. -* purpose of KMS is not precise. Attributes change their names/meaning depending on call -* encryption_context is described to be string, in reality dict is expected -* max_length is always expected to be exactly max. Make no sense as a param -* list CMK filter by key_state not working as documented -* format of the timestamp is unknown -* no way to get response in English - -# CCE - -* required header application/type also for GET -* cluster UUID is hidden in a inline metadata structure, making it hard to address it without dirty hacks. - Apis are jumping through this structure in anti-rest pattern -* attribute naming: metadata.uuid vs metadata.uid -* undocumented properties of the cluster.spec field (i.e. `cidr`) -* far away from Magnum -* Cluster has both VPC and VPC_ID, in GET VPC is name, in POST it should be ID -* Subnet is most likely net_id -* In AS sys disk has type "SYS", in CCE - "root" -* Node delete possible only by name, and not id -* service catalog configuration is broken v1 vs v2(v3) with no corrupted discovery and new service type - -# DCS: - -* DCS: in OS DCS is part of Trove. The API is same. In the DCS API is similar to RDS, but not easy mappable -* DCS: Since Redis 3.0.7 (only available in DCS) lots of critical issues (incl. security and possible data corruption), online memory defrag, less mem usage were fixed - -# MRS: -* Inconsistent naming between services ( data_processing-mrs ) - -# OBS: - -* OBS has storage class on Bucket level, but in AWS and all corresponding tools (also s3cmd, s4cmd, Boto) it is on the Object level - -# DNS (Designate): - -* nothing supports private zone (ansible, heat, ~terraform, SDK/CLI). Very hard to cover that everywhere -* Zone transfer, slave zone are not present. Modern Designateclient is not getting clear with response of designate -* API v2 is not implemented - -# VBS: - -* uses offset as a pagination, instead of marker (in docs, in reality marker is supported) -* backup creation takes too long. 1Gb empty volume takes >4 minutes. Functional tests are not reasonable with that. -* create policy requires frequency to be set -* shift implemented stuff to osc - -# CSS: - -* upon creation httpsEnable is str, upon read - bool -* flavors is not OpenStack compatible - -# HEAT: - -* very old level, blocking many OpenSource projects, including i.e. ansible-openshift, RedhatDNS. -* (to be doublechecked) template version check is likely not done, since features of later templates with older version header are passing validation (in the ranges of supported versions) -* validate return ok, doesn't mean create will pass (validation errors i.e. template version doesn't match, condition on a resource level was also added on newton) -* not all CLI calls return result -* Not possible to rely on mountpoint of the OS::Cinder::VolumeAttachment - it's ignored -* usage of Server with block_device_mapping_v2, devicename="sdX" and > 1 device fails. Port is not released leaving system in inconsistent state (if router interface is deleted can be cleaned only manually) -* OS::Neutron::LBaaS::HealthMonitor does not support type HTTPS, but GUI allows it -* update stack with existing template is missing - -# Shade/Ansible: - -* enabling SNAT through Ansible not possible, since upstream expects default as true and sends only false if set (shade:_build_external_gateway_info) -* only able to pass SYS volume size if boot_from_volume=True (default=false) -* on a play retry port in the subnet changes if exists (change IP) and corrupts connection -* Ansible: no support for load balancer -* Ansible (Heat): https://github.com/ansible/ansible/issues/30786 - small fix to see the failure message if stack create/update fails -* Private: yes helps to get public_v4 filled, but it hinders create request with auto_ip:true -* add router interface - -# VPC: - -* VPC uses network wrapped subnets. Simple net with multiple subnets is not properly visible in OTC (in VPCs list subnet count includes all subnets, but in VPC show subnets are missing) - -# TMS: - -* How to assign tag to resource from API? - -# BMS: - -* it is not Ironic, but ECS - -# Network: - -* SecGroup rule "Any" (value=0) is not working as designed. OSC uses defaults, use of 0 results in really 0 as a value. Effect is unknown yet - -# DeH - -* Tag support is not OS compatible - -# OpenStackSDK: - -* LBaaS: pool.healthmonitor_id according to ref api (and in OTC), but in the SDK it is health_monitor_ids (list) (reported under https://storyboard.openstack.org/#!/story/2001872). Some other attributes missing - - pool_member operating_status missing -* LBaaS HM: max_retries_down missing (optional and not present in OTC) - - -# DOC: -* at least on example of ULB LIST allows filtering, but it is not documented diff --git a/otcextensions/sdk/rds/v3/_proxy.py b/otcextensions/sdk/rds/v3/_proxy.py index 6ed09c8ee..985a2cb2e 100644 --- a/otcextensions/sdk/rds/v3/_proxy.py +++ b/otcextensions/sdk/rds/v3/_proxy.py @@ -248,7 +248,7 @@ def get_configuration(self, cg): or a object of :class:`~otcextensions.sdk.rds.v3.configuration.Configuration`. - :returns: A Configuration Object + :returns: A Configuration object :rtype: :class:`~otcextensions.rds.v3.configuration.Configuration` """ return self._get(_configuration.Configuration, cg) @@ -258,13 +258,12 @@ def find_configuration(self, name_or_id, ignore_missing=True): :param name_or_id: The name or ID of configuration. :param bool ignore_missing: When set to ``False`` - :class:`~openstack.exceptions.ResourceNotFound` will be - raised when the resource does not exist. - When set to ``True``, None will be returned when - attempting to find a nonexistent resource. - :returns: One - :class:`~otcextensions.sdk.rds.v3.configuration.Configuration` - or None + :class:`~openstack.exceptions.ResourceNotFound` will be + raised when the resource does not exist. + When set to ``True``, None will be returned when + attempting to find a nonexistent resource. + :returns: A configuration object + :rtype: :class:`~otcextensions.sdk.rds.v3.configuration.Configuration` """ return self._find(_configuration.Configuration, name_or_id, @@ -273,7 +272,7 @@ def find_configuration(self, name_or_id, ignore_missing=True): def create_configuration(self, **attrs): """Create DB Configuration. - :param dict **attrs: Dict to overwrite Configuration object + :param dict attrs: Dict to overwrite Configuration object :returns: A Configuration Object :rtype: :class:`~otcextensions.sdk.rds.v3.configuration.Configuration` @@ -359,7 +358,7 @@ def delete_backup(self, backup, ignore_missing=True): """Deletes given backup :param instance: The value can be either the ID of an instance or a - :class:`~openstack.database.v3.instance.Instance` instance. + :class:`~otcextension.sdk.rds.v3.instance.Instance` instance. :param bool ignore_missing: When set to ``False`` :class:`~openstack.exceptions.ResourceNotFound` will be raised when the instance does not exist. @@ -377,14 +376,14 @@ def find_backup(self, name_or_id, instance, ignore_missing=True): :param name_or_id: The name or ID of a instance. :param instance: The value can be either the ID of an instance or a - :class:`~openstack.database.v3.instance.Instance` instance. - :param bool ignore_missing: When set to ``False`` - :class:`~openstack.exceptions.ResourceNotFound` will be - raised when the resource does not exist. - When set to ``True``, None will be returned when - attempting to find a nonexistent resource. + :class:`~otcextension.sdk.rds.v3.instance.Instance` instance. + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be + raised when the resource does not exist. + When set to ``True``, None will be returned when + attempting to find a nonexistent resource. :returns: One :class:`~otcextensions.sdk.rds.v3.backup.Backup` - or None + or None """ instance = self._get_resource(_instance.Instance, instance) return self._find(_backup.Backup, diff --git a/otcextensions/sdk/rds/v3/instance.py b/otcextensions/sdk/rds/v3/instance.py index e1820b399..75e95e24f 100644 --- a/otcextensions/sdk/rds/v3/instance.py +++ b/otcextensions/sdk/rds/v3/instance.py @@ -69,7 +69,7 @@ class Instance(_base.Resource): #: *Type:str* maintenance_window = resource.Body('maintenance_window') #: Node information - #: Indicates the primary/standby DB instance information. + #: Indicates the primary/standby DB instance information. #: *Type:list* nodes = resource.Body('nodes', type=list) #: Password of the default user. @@ -174,25 +174,25 @@ def find(cls, session, name_or_id, ignore_missing=True, **params): """Find a resource by its name or id. :param session: The session to use for making this request. - :type session: :class:`~keystoneauth1.adapter.Adapter` + :type session: :class:`~keystoneauth1.adapter.Adapter` :param name_or_id: This resource's identifier, if needed by - the request. The default is ``None``. + the request. The default is ``None``. :param bool ignore_missing: When set to ``False`` - :class:`~openstack.exceptions.ResourceNotFound` will be - raised when the resource does not exist. - When set to ``True``, None will be returned when - attempting to find a nonexistent resource. + :class:`~openstack.exceptions.ResourceNotFound` will be + raised when the resource does not exist. + When set to ``True``, None will be returned when + attempting to find a nonexistent resource. :param dict params: Any additional parameters to be passed into - underlying methods, such as to - :meth:`~openstack.resource.Resource.existing` - in order to pass on URI parameters. + underlying methods, such as to + :meth:`~openstack.resource.Resource.existing` + in order to pass on URI parameters. :return: The :class:`Resource` object matching the given name or id - or None if nothing matches. + or None if nothing matches. :raises: :class:`openstack.exceptions.DuplicateResource` if more - than one resource is found for this request. + than one resource is found for this request. :raises: :class:`openstack.exceptions.ResourceNotFound` if nothing - is found and ignore_missing is ``False``. + is found and ignore_missing is ``False``. """ session = cls._get_session(session) @@ -222,20 +222,20 @@ def fetch(self, session, requires_id=True, """Get a remote resource based on this instance. :param session: The session to use for making this request. - :type session: :class:`~keystoneauth1.adapter.Adapter` + :type session: :class:`~keystoneauth1.adapter.Adapter` :param boolean requires_id: A boolean indicating whether resource ID - should be part of the requested URI. + should be part of the requested URI. :param str base_path: Base part of the URI for fetching resources, if - different from - :data:`~openstack.resource.Resource.base_path`. + different from :data:`~openstack.resource.Resource.base_path`. :param str error_message: An Error message to be returned if - requested object does not exist. + requested object does not exist. :param dict params: Additional parameters that can be consumed. + :return: This :class:`Resource` instance. :raises: :exc:`~openstack.exceptions.MethodNotSupported` if - :data:`Resource.allow_fetch` is not set to ``True``. + :data:`Resource.allow_fetch` is not set to ``True``. :raises: :exc:`~openstack.exceptions.ResourceNotFound` if - the resource was not found. + the resource was not found. """ data = self.list(session, paginated=False, id=self.id) result = self._get_one_match(self.id, data) diff --git a/setup.cfg b/setup.cfg index 02db5bd22..cc13ea867 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,11 +1,11 @@ [metadata] name = otcextensions -summary = OpenStack Command-line Client and SDK Extensions for OpenTelekomCloud +summary = Open Telekom Cloud specific extensions for the OpenStack Client CLI and OpenStack SDK description-file = README.rst author = Artem Goncharov author-email = artem.goncharov@gmail.com -home-page = http://python-otcextensions.readthedocs.io/en/latest/ +home-page = http://python-otcextensions.readthedocs.io/ classifier = Environment :: OpenStack Intended Audience :: Information Technology @@ -19,7 +19,7 @@ classifier = Programming Language :: Python :: 3.6 Programming Language :: Python :: 3.7 keywords = - OpenStack, openstackclient, openstacksdk, OpenTelekomCloud, otc, t-systems, telekom + OpenStack, openstackclient, openstacksdk, Open Telekom Cloud, otc, T-Systems, Telekom [files] packages = From 4a0ea605f640cf2a4d985c0b66399baab8de070e Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Tue, 31 Mar 2020 15:46:39 +0200 Subject: [PATCH 14/58] Add periodic functional tests Execute functional tests regularly to catch broken APIs --- .zuul.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.zuul.yaml b/.zuul.yaml index cef56795b..636de0f2d 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -9,4 +9,8 @@ jobs: - tox-py37 - tox-pep8 + - tox-docs + - tox-functional + periodic: + jobs: - tox-functional From 65a3137929ff659289e489b0086918b8b0b66024 Mon Sep 17 00:00:00 2001 From: "T. Schreiber" Date: Tue, 31 Mar 2020 15:20:30 +0000 Subject: [PATCH 15/58] Bring resource section back, fix issues --- doc/source/sdk/index.rst | 1 + doc/source/sdk/proxies/index.rst | 32 +++++----- doc/source/sdk/resources/anti_ddos/index.rst | 9 +++ .../sdk/resources/anti_ddos/v1/config.rst | 13 +++++ .../resources/anti_ddos/v1/floating_ip.rst | 13 +++++ .../sdk/resources/anti_ddos/v1/status.rst | 58 +++++++++++++++++++ .../sdk/resources/auto_scaling/index.rst | 12 ++++ .../resources/auto_scaling/v1/activity.rst | 13 +++++ .../sdk/resources/auto_scaling/v1/config.rst | 13 +++++ .../sdk/resources/auto_scaling/v1/group.rst | 13 +++++ .../resources/auto_scaling/v1/instance.rst | 13 +++++ .../sdk/resources/auto_scaling/v1/policy.rst | 13 +++++ .../sdk/resources/auto_scaling/v1/quota.rst | 22 +++++++ doc/source/sdk/resources/cce/index.rst | 10 ++++ doc/source/sdk/resources/cce/v1/cluster.rst | 13 +++++ .../sdk/resources/cce/v1/cluster_node.rst | 13 +++++ doc/source/sdk/resources/cce/v3/cluster.rst | 13 +++++ .../sdk/resources/cce/v3/cluster_node.rst | 13 +++++ doc/source/sdk/resources/cts/index.rst | 8 +++ doc/source/sdk/resources/cts/v1/trace.rst | 13 +++++ doc/source/sdk/resources/cts/v1/tracker.rst | 13 +++++ doc/source/sdk/resources/dcs/index.rst | 11 ++++ doc/source/sdk/resources/dcs/v1/backup.rst | 13 +++++ doc/source/sdk/resources/dcs/v1/config.rst | 13 +++++ doc/source/sdk/resources/dcs/v1/instance.rst | 13 +++++ doc/source/sdk/resources/dcs/v1/restore.rst | 13 +++++ doc/source/sdk/resources/dcs/v1/statistic.rst | 13 +++++ doc/source/sdk/resources/deh/index.rst | 9 +++ doc/source/sdk/resources/deh/v1/host.rst | 13 +++++ doc/source/sdk/resources/deh/v1/host_type.rst | 13 +++++ doc/source/sdk/resources/deh/v1/server.rst | 13 +++++ doc/source/sdk/resources/dms/index.rst | 11 ++++ doc/source/sdk/resources/dms/v1/group.rst | 13 +++++ .../sdk/resources/dms/v1/group_message.rst | 13 +++++ doc/source/sdk/resources/dms/v1/message.rst | 13 +++++ doc/source/sdk/resources/dms/v1/queue.rst | 13 +++++ doc/source/sdk/resources/dms/v1/quota.rst | 13 +++++ doc/source/sdk/resources/dns/index.rst | 10 ++++ .../sdk/resources/dns/v2/floating_ip.rst | 13 +++++ .../sdk/resources/dns/v2/nameserver.rst | 13 +++++ doc/source/sdk/resources/dns/v2/recordset.rst | 13 +++++ doc/source/sdk/resources/dns/v2/zone.rst | 13 +++++ doc/source/sdk/resources/index.rst | 54 +++++++++++++++++ doc/source/sdk/resources/kms/index.rst | 8 +++ doc/source/sdk/resources/kms/v1/data_key.rst | 13 +++++ doc/source/sdk/resources/kms/v1/key.rst | 13 +++++ doc/source/sdk/resources/obs/index.rst | 8 +++ doc/source/sdk/resources/obs/v1/container.rst | 13 +++++ doc/source/sdk/resources/obs/v1/obj.rst | 13 +++++ doc/source/sdk/resources/rds/index.rst | 22 +++++++ .../sdk/resources/rds/v1/configuration.rst | 13 +++++ doc/source/sdk/resources/rds/v1/flavor.rst | 13 +++++ doc/source/sdk/resources/rds/v1/instance.rst | 13 +++++ .../sdk/resources/rds/v3/configuration.rst | 13 +++++ doc/source/sdk/resources/rds/v3/flavor.rst | 13 +++++ doc/source/sdk/resources/rds/v3/instance.rst | 13 +++++ 56 files changed, 787 insertions(+), 18 deletions(-) create mode 100644 doc/source/sdk/resources/anti_ddos/index.rst create mode 100644 doc/source/sdk/resources/anti_ddos/v1/config.rst create mode 100644 doc/source/sdk/resources/anti_ddos/v1/floating_ip.rst create mode 100644 doc/source/sdk/resources/anti_ddos/v1/status.rst create mode 100644 doc/source/sdk/resources/auto_scaling/index.rst create mode 100644 doc/source/sdk/resources/auto_scaling/v1/activity.rst create mode 100644 doc/source/sdk/resources/auto_scaling/v1/config.rst create mode 100644 doc/source/sdk/resources/auto_scaling/v1/group.rst create mode 100644 doc/source/sdk/resources/auto_scaling/v1/instance.rst create mode 100644 doc/source/sdk/resources/auto_scaling/v1/policy.rst create mode 100644 doc/source/sdk/resources/auto_scaling/v1/quota.rst create mode 100644 doc/source/sdk/resources/cce/index.rst create mode 100644 doc/source/sdk/resources/cce/v1/cluster.rst create mode 100644 doc/source/sdk/resources/cce/v1/cluster_node.rst create mode 100644 doc/source/sdk/resources/cce/v3/cluster.rst create mode 100644 doc/source/sdk/resources/cce/v3/cluster_node.rst create mode 100644 doc/source/sdk/resources/cts/index.rst create mode 100644 doc/source/sdk/resources/cts/v1/trace.rst create mode 100644 doc/source/sdk/resources/cts/v1/tracker.rst create mode 100644 doc/source/sdk/resources/dcs/index.rst create mode 100644 doc/source/sdk/resources/dcs/v1/backup.rst create mode 100644 doc/source/sdk/resources/dcs/v1/config.rst create mode 100644 doc/source/sdk/resources/dcs/v1/instance.rst create mode 100644 doc/source/sdk/resources/dcs/v1/restore.rst create mode 100644 doc/source/sdk/resources/dcs/v1/statistic.rst create mode 100644 doc/source/sdk/resources/deh/index.rst create mode 100644 doc/source/sdk/resources/deh/v1/host.rst create mode 100644 doc/source/sdk/resources/deh/v1/host_type.rst create mode 100644 doc/source/sdk/resources/deh/v1/server.rst create mode 100644 doc/source/sdk/resources/dms/index.rst create mode 100644 doc/source/sdk/resources/dms/v1/group.rst create mode 100644 doc/source/sdk/resources/dms/v1/group_message.rst create mode 100644 doc/source/sdk/resources/dms/v1/message.rst create mode 100644 doc/source/sdk/resources/dms/v1/queue.rst create mode 100644 doc/source/sdk/resources/dms/v1/quota.rst create mode 100644 doc/source/sdk/resources/dns/index.rst create mode 100644 doc/source/sdk/resources/dns/v2/floating_ip.rst create mode 100644 doc/source/sdk/resources/dns/v2/nameserver.rst create mode 100644 doc/source/sdk/resources/dns/v2/recordset.rst create mode 100644 doc/source/sdk/resources/dns/v2/zone.rst create mode 100644 doc/source/sdk/resources/index.rst create mode 100644 doc/source/sdk/resources/kms/index.rst create mode 100644 doc/source/sdk/resources/kms/v1/data_key.rst create mode 100644 doc/source/sdk/resources/kms/v1/key.rst create mode 100644 doc/source/sdk/resources/obs/index.rst create mode 100644 doc/source/sdk/resources/obs/v1/container.rst create mode 100644 doc/source/sdk/resources/obs/v1/obj.rst create mode 100644 doc/source/sdk/resources/rds/index.rst create mode 100644 doc/source/sdk/resources/rds/v1/configuration.rst create mode 100644 doc/source/sdk/resources/rds/v1/flavor.rst create mode 100644 doc/source/sdk/resources/rds/v1/instance.rst create mode 100644 doc/source/sdk/resources/rds/v3/configuration.rst create mode 100644 doc/source/sdk/resources/rds/v3/flavor.rst create mode 100644 doc/source/sdk/resources/rds/v3/instance.rst diff --git a/doc/source/sdk/index.rst b/doc/source/sdk/index.rst index 5232713d3..beedb8d89 100644 --- a/doc/source/sdk/index.rst +++ b/doc/source/sdk/index.rst @@ -8,6 +8,7 @@ Using the OpenStack SDK getting_started guides/index proxies/index + resources/index The OTC Extensions contain an abstraction interface layer. Clouds can do many things, but there are probably only about 10 of them that most diff --git a/doc/source/sdk/proxies/index.rst b/doc/source/sdk/proxies/index.rst index e3a8de280..7b5a92f51 100644 --- a/doc/source/sdk/proxies/index.rst +++ b/doc/source/sdk/proxies/index.rst @@ -4,20 +4,20 @@ Service Proxies .. toctree:: :maxdepth: 1 - Anti DDoS Service - AutoScaling Service - Cloud Container Engine v1 - Cloud Container Engine v2 - Cloud Trace Service - Distributed Cache Service - Dedicated Host Service - Distributed Message Service - DNS Service - Key Management Service - Object Block Storage - Volume Backup Service - Relational Database Service RDS V1 - Relational Database Service RDS V3 + Anti DDoS Service (Anti-DDoS) + AutoScaling Service (AS) + Cloud Container Engine v1 (CCEv1) + Cloud Container Engine v2 (CCE) + Cloud Trace Service (CTS) + Distributed Cache Service (DCS) + Dedicated Host Service (DeH) + Distributed Message Service (DMS) + Domain Name Server Service (DNS) + Key Management Service (KMS) + Object Block Storage (OBS) + Volume Backup Service (VBS) + Relational Database Service RDS V1 (RDSv1) + Relational Database Service RDS V3 (RDS) .. _service-proxies: @@ -39,9 +39,7 @@ Links to Native OpenStack Service Proxies Block Storage Compute Database - Identity v2 Identity v3 - Image v1 Image v2 Key Manager Load Balancer @@ -49,5 +47,3 @@ Links to Native OpenStack Service Proxies Network Object Store Orchestration - Workflow - diff --git a/doc/source/sdk/resources/anti_ddos/index.rst b/doc/source/sdk/resources/anti_ddos/index.rst new file mode 100644 index 000000000..dde392f6b --- /dev/null +++ b/doc/source/sdk/resources/anti_ddos/index.rst @@ -0,0 +1,9 @@ +Anti DDoS Resources +=================== + +.. toctree:: + :maxdepth: 1 + + v1/config + v1/floating_ip + v1/status diff --git a/doc/source/sdk/resources/anti_ddos/v1/config.rst b/doc/source/sdk/resources/anti_ddos/v1/config.rst new file mode 100644 index 000000000..f8d7a088b --- /dev/null +++ b/doc/source/sdk/resources/anti_ddos/v1/config.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.anti_ddos.v1.config +===================================== + +.. automodule:: otcextensions.sdk.anti_ddos.v1.config + +The Anti DDoS Config Class +-------------------------- + +The ``Config`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.anti_ddos.v1.config.Config + :members: diff --git a/doc/source/sdk/resources/anti_ddos/v1/floating_ip.rst b/doc/source/sdk/resources/anti_ddos/v1/floating_ip.rst new file mode 100644 index 000000000..dd5232b81 --- /dev/null +++ b/doc/source/sdk/resources/anti_ddos/v1/floating_ip.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.anti_ddos.v1.floating_ip +========================================== + +.. automodule:: otcextensions.sdk.anti_ddos.v1.floating_ip + +The Anti_DDoS FloatingIP Class +------------------------------ + +The ``FloatingIP`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.anti_ddos.v1.floating_ip.FloatingIP + :members: diff --git a/doc/source/sdk/resources/anti_ddos/v1/status.rst b/doc/source/sdk/resources/anti_ddos/v1/status.rst new file mode 100644 index 000000000..604d46164 --- /dev/null +++ b/doc/source/sdk/resources/anti_ddos/v1/status.rst @@ -0,0 +1,58 @@ +otcextensions.sdk.anti_ddos.v1.status +===================================== + +.. automodule:: otcextensions.sdk.anti_ddos.v1.status + +The Anti DDoS TaskStatus Class +------------------------------ + +The ``TaskStatus`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.anti_ddos.v1.status.TaskStatus + :members: + +The Anti DDoS FloatingIPStatus Class +------------------------------------ + +The ``FloatingIPStatus`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.anti_ddos.v1.status.FloatingIPStatus + :members: + +The Anti DDoS FloatingIPEvent Class +----------------------------------- + +The ``FloatingIPEvent`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.anti_ddos.v1.status.FloatingIPEvent + :members: + +The Anti DDoS FloatingIPDayStat Class +------------------------------------- + +The ``FloatingIPDayStat`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.anti_ddos.v1.status.FloatingIPDayStat + :members: + +The Anti DDoS FloatingIPWeekStatData Class +------------------------------------------ + +The ``FloatingIPWeekStatData`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.anti_ddos.v1.status.FloatingIPWeekStatData + :members: + +The Anti DDoS FloatingIPWeekStat Class +-------------------------------------- + +The ``FloatingIPWeekStat`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.anti_ddos.v1.status.FloatingIPWeekStat + :members: diff --git a/doc/source/sdk/resources/auto_scaling/index.rst b/doc/source/sdk/resources/auto_scaling/index.rst new file mode 100644 index 000000000..daf76787a --- /dev/null +++ b/doc/source/sdk/resources/auto_scaling/index.rst @@ -0,0 +1,12 @@ +AutoScaling Resources +===================== + +.. toctree:: + :maxdepth: 1 + + v1/group + v1/config + v1/policy + v1/instance + v1/quota + v1/activity diff --git a/doc/source/sdk/resources/auto_scaling/v1/activity.rst b/doc/source/sdk/resources/auto_scaling/v1/activity.rst new file mode 100644 index 000000000..a645657f7 --- /dev/null +++ b/doc/source/sdk/resources/auto_scaling/v1/activity.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.auto_scaling.v1.activity +========================================== + +.. automodule:: otcextensions.sdk.auto_scaling.v1.activity + +The AS Activity Class +--------------------- + +The ``Activity`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.auto_scaling.v1.activity.Activity + :members: diff --git a/doc/source/sdk/resources/auto_scaling/v1/config.rst b/doc/source/sdk/resources/auto_scaling/v1/config.rst new file mode 100644 index 000000000..292e7d531 --- /dev/null +++ b/doc/source/sdk/resources/auto_scaling/v1/config.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.auto_scaling.v1.config +======================================== + +.. automodule:: otcextensions.sdk.auto_scaling.v1.config + +The AS Configuration Class +-------------------------- + +The ``Config`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.auto_scaling.v1.config.Config + :members: diff --git a/doc/source/sdk/resources/auto_scaling/v1/group.rst b/doc/source/sdk/resources/auto_scaling/v1/group.rst new file mode 100644 index 000000000..8a9563f97 --- /dev/null +++ b/doc/source/sdk/resources/auto_scaling/v1/group.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.auto_scaling.v1.group +======================================= + +.. automodule:: otcextensions.sdk.auto_scaling.v1.group + +The AS Group Class +------------------ + +The ``Group`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.auto_scaling.v1.group.Group + :members: diff --git a/doc/source/sdk/resources/auto_scaling/v1/instance.rst b/doc/source/sdk/resources/auto_scaling/v1/instance.rst new file mode 100644 index 000000000..9f31ada62 --- /dev/null +++ b/doc/source/sdk/resources/auto_scaling/v1/instance.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.auto_scaling.v1.instance +========================================== + +.. automodule:: otcextensions.sdk.auto_scaling.v1.instance + +The AS Instance Class +--------------------- + +The ``Instance`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.auto_scaling.v1.instance.Instance + :members: diff --git a/doc/source/sdk/resources/auto_scaling/v1/policy.rst b/doc/source/sdk/resources/auto_scaling/v1/policy.rst new file mode 100644 index 000000000..f14861719 --- /dev/null +++ b/doc/source/sdk/resources/auto_scaling/v1/policy.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.auto_scaling.v1.policy +======================================== + +.. automodule:: otcextensions.sdk.auto_scaling.v1.policy + +The AS Policy Class +------------------- + +The ``Policy`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.auto_scaling.v1.policy.Policy + :members: diff --git a/doc/source/sdk/resources/auto_scaling/v1/quota.rst b/doc/source/sdk/resources/auto_scaling/v1/quota.rst new file mode 100644 index 000000000..3dc77141f --- /dev/null +++ b/doc/source/sdk/resources/auto_scaling/v1/quota.rst @@ -0,0 +1,22 @@ +otcextensions.sdk.auto_scaling.v1.quota +======================================= + +.. automodule:: otcextensions.sdk.auto_scaling.v1.quota + +The AS Quota Class +--------------------- + +The ``Quota`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.auto_scaling.v1.quota.Quota + :members: + +The AS Scaling Quota Class +-------------------------- + +The ``Quota`` class inherits from +:class:`~otcextensions.sdk.auto_scaling.v1.quota.Quota`. + +.. autoclass:: otcextensions.sdk.auto_scaling.v1.quota.ScalingQuota + :members: diff --git a/doc/source/sdk/resources/cce/index.rst b/doc/source/sdk/resources/cce/index.rst new file mode 100644 index 000000000..5b4e81b77 --- /dev/null +++ b/doc/source/sdk/resources/cce/index.rst @@ -0,0 +1,10 @@ +AutoScaling Resources +===================== + +.. toctree:: + :maxdepth: 1 + + v1/cluster + v1/cluster_node + v3/cluster + v3/cluster_node diff --git a/doc/source/sdk/resources/cce/v1/cluster.rst b/doc/source/sdk/resources/cce/v1/cluster.rst new file mode 100644 index 000000000..4f61886d2 --- /dev/null +++ b/doc/source/sdk/resources/cce/v1/cluster.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.cce.v1.cluster +================================ + +.. automodule:: otcextensions.sdk.cce.v1.cluster + +The CCE Cluster Class +--------------------- + +The ``Cluster`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.cce.v1.cluster.Cluster + :members: diff --git a/doc/source/sdk/resources/cce/v1/cluster_node.rst b/doc/source/sdk/resources/cce/v1/cluster_node.rst new file mode 100644 index 000000000..b6c9bf031 --- /dev/null +++ b/doc/source/sdk/resources/cce/v1/cluster_node.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.cce.v1.cluster_node +===================================== + +.. automodule:: otcextensions.sdk.cce.v1.cluster_node + +The CCE Cluster Host (Node) Class +--------------------------------- + +The ``ClusterHost`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.cce.v1.cluster_node.ClusterNode + :members: diff --git a/doc/source/sdk/resources/cce/v3/cluster.rst b/doc/source/sdk/resources/cce/v3/cluster.rst new file mode 100644 index 000000000..8b4cd7f60 --- /dev/null +++ b/doc/source/sdk/resources/cce/v3/cluster.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.cce.v3.cluster +================================ + +.. automodule:: otcextensions.sdk.cce.v3.cluster + +The CCE Cluster Class +--------------------- + +The ``Cluster`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.cce.v3.cluster.Cluster + :members: diff --git a/doc/source/sdk/resources/cce/v3/cluster_node.rst b/doc/source/sdk/resources/cce/v3/cluster_node.rst new file mode 100644 index 000000000..028332188 --- /dev/null +++ b/doc/source/sdk/resources/cce/v3/cluster_node.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.cce.v3.cluster_node +===================================== + +.. automodule:: otcextensions.sdk.cce.v3.cluster_node + +The CCE Cluster Host (Node) Class +--------------------------------- + +The ``ClusterHost`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.cce.v3.cluster_node.ClusterNode + :members: diff --git a/doc/source/sdk/resources/cts/index.rst b/doc/source/sdk/resources/cts/index.rst new file mode 100644 index 000000000..c4af68b3d --- /dev/null +++ b/doc/source/sdk/resources/cts/index.rst @@ -0,0 +1,8 @@ +CTS Resources +============= + +.. toctree:: + :maxdepth: 1 + + v1/trace + v1/tracker diff --git a/doc/source/sdk/resources/cts/v1/trace.rst b/doc/source/sdk/resources/cts/v1/trace.rst new file mode 100644 index 000000000..04fff3d09 --- /dev/null +++ b/doc/source/sdk/resources/cts/v1/trace.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.cts.v1.trace +============================== + +.. automodule:: otcextensions.sdk.cts.v1.trace + +The CTS Trace Class +------------------- + +The ``Trace`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.cts.v1.trace.Trace + :members: diff --git a/doc/source/sdk/resources/cts/v1/tracker.rst b/doc/source/sdk/resources/cts/v1/tracker.rst new file mode 100644 index 000000000..c3ace1804 --- /dev/null +++ b/doc/source/sdk/resources/cts/v1/tracker.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.cts.v1.tracker +================================ + +.. automodule:: otcextensions.sdk.cts.v1.tracker + +The CTS Tracker Class +--------------------- + +The ``Tracker`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.cts.v1.tracker.Tracker + :members: diff --git a/doc/source/sdk/resources/dcs/index.rst b/doc/source/sdk/resources/dcs/index.rst new file mode 100644 index 000000000..f2c49c26d --- /dev/null +++ b/doc/source/sdk/resources/dcs/index.rst @@ -0,0 +1,11 @@ +DCS Resources +============= + +.. toctree:: + :maxdepth: 1 + + v1/backup + v1/config + v1/instance + v1/restore + v1/statistic diff --git a/doc/source/sdk/resources/dcs/v1/backup.rst b/doc/source/sdk/resources/dcs/v1/backup.rst new file mode 100644 index 000000000..243b376eb --- /dev/null +++ b/doc/source/sdk/resources/dcs/v1/backup.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dcs.v1.backup +================================= + +.. automodule:: otcextensions.sdk.dcs.v1.backup + +The DCS Backup Class +-------------------- + +The ``Backup`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dcs.v1.backup.Backup + :members: diff --git a/doc/source/sdk/resources/dcs/v1/config.rst b/doc/source/sdk/resources/dcs/v1/config.rst new file mode 100644 index 000000000..78656037e --- /dev/null +++ b/doc/source/sdk/resources/dcs/v1/config.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dcs.v1.config +================================= + +.. automodule:: otcextensions.sdk.dcs.v1.config + +The DCS Config Class +-------------------- + +The ``Config`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dcs.v1.config.Config + :members: diff --git a/doc/source/sdk/resources/dcs/v1/instance.rst b/doc/source/sdk/resources/dcs/v1/instance.rst new file mode 100644 index 000000000..1df70cb93 --- /dev/null +++ b/doc/source/sdk/resources/dcs/v1/instance.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dcs.v1.instance +================================= + +.. automodule:: otcextensions.sdk.dcs.v1.instance + +The DCS Instance Class +---------------------- + +The ``Instance`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dcs.v1.instance.Instance + :members: diff --git a/doc/source/sdk/resources/dcs/v1/restore.rst b/doc/source/sdk/resources/dcs/v1/restore.rst new file mode 100644 index 000000000..16a23a582 --- /dev/null +++ b/doc/source/sdk/resources/dcs/v1/restore.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dcs.v1.restore +================================= + +.. automodule:: otcextensions.sdk.dcs.v1.restore + +The DCS Restore Class +--------------------- + +The ``Restore`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dcs.v1.restore.Restore + :members: diff --git a/doc/source/sdk/resources/dcs/v1/statistic.rst b/doc/source/sdk/resources/dcs/v1/statistic.rst new file mode 100644 index 000000000..53b06a053 --- /dev/null +++ b/doc/source/sdk/resources/dcs/v1/statistic.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dcs.v1.statistic +================================== + +.. automodule:: otcextensions.sdk.dcs.v1.statistic + +The DCS Statistic Class +----------------------- + +The ``Statistic`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dcs.v1.statistic.Statistic + :members: diff --git a/doc/source/sdk/resources/deh/index.rst b/doc/source/sdk/resources/deh/index.rst new file mode 100644 index 000000000..d3b3d1e7e --- /dev/null +++ b/doc/source/sdk/resources/deh/index.rst @@ -0,0 +1,9 @@ +DeH Resources +============= + +.. toctree:: + :maxdepth: 1 + + v1/host + v1/host_type + v1/server diff --git a/doc/source/sdk/resources/deh/v1/host.rst b/doc/source/sdk/resources/deh/v1/host.rst new file mode 100644 index 000000000..2b9942dcc --- /dev/null +++ b/doc/source/sdk/resources/deh/v1/host.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.deh.v1.host +============================= + +.. automodule:: otcextensions.sdk.deh.v1.host + +The DeH Host Class +------------------ + +The ``Host`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.deh.v1.host.Host + :members: diff --git a/doc/source/sdk/resources/deh/v1/host_type.rst b/doc/source/sdk/resources/deh/v1/host_type.rst new file mode 100644 index 000000000..1d06abd4d --- /dev/null +++ b/doc/source/sdk/resources/deh/v1/host_type.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.deh.v1.host_type +================================== + +.. automodule:: otcextensions.sdk.deh.v1.host_type + +The DeH Host Type Class +----------------------- + +The ``HostType`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.deh.v1.host_type.HostType + :members: diff --git a/doc/source/sdk/resources/deh/v1/server.rst b/doc/source/sdk/resources/deh/v1/server.rst new file mode 100644 index 000000000..25d80def7 --- /dev/null +++ b/doc/source/sdk/resources/deh/v1/server.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.deh.v1.server +=============================== + +.. automodule:: otcextensions.sdk.deh.v1.server + +The DeH Server Class +-------------------- + +The ``Server`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.deh.v1.server.Server + :members: diff --git a/doc/source/sdk/resources/dms/index.rst b/doc/source/sdk/resources/dms/index.rst new file mode 100644 index 000000000..210555c88 --- /dev/null +++ b/doc/source/sdk/resources/dms/index.rst @@ -0,0 +1,11 @@ +DMS Resources +============= + +.. toctree:: + :maxdepth: 1 + + v1/group + v1/group_message + v1/message + v1/queue + v1/quota diff --git a/doc/source/sdk/resources/dms/v1/group.rst b/doc/source/sdk/resources/dms/v1/group.rst new file mode 100644 index 000000000..03663435e --- /dev/null +++ b/doc/source/sdk/resources/dms/v1/group.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dcs.v1.group +============================== + +.. automodule:: otcextensions.sdk.dms.v1.group + +The DMS Group Class +------------------- + +The ``Group`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dms.v1.group.Group + :members: diff --git a/doc/source/sdk/resources/dms/v1/group_message.rst b/doc/source/sdk/resources/dms/v1/group_message.rst new file mode 100644 index 000000000..94090ce49 --- /dev/null +++ b/doc/source/sdk/resources/dms/v1/group_message.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dcs.v1.group_message +====================================== + +.. automodule:: otcextensions.sdk.dms.v1.group_message + +The DMS GroupMessage Class +-------------------------- + +The ``GroupMessage`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dms.v1.group_message.GroupMessage + :members: diff --git a/doc/source/sdk/resources/dms/v1/message.rst b/doc/source/sdk/resources/dms/v1/message.rst new file mode 100644 index 000000000..72360e7f5 --- /dev/null +++ b/doc/source/sdk/resources/dms/v1/message.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dcs.v1.message +================================ + +.. automodule:: otcextensions.sdk.dms.v1.message + +The DMS Message Class +--------------------- + +The ``Message`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dms.v1.message.Message + :members: diff --git a/doc/source/sdk/resources/dms/v1/queue.rst b/doc/source/sdk/resources/dms/v1/queue.rst new file mode 100644 index 000000000..1942b9e68 --- /dev/null +++ b/doc/source/sdk/resources/dms/v1/queue.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dcs.v1.queue +============================== + +.. automodule:: otcextensions.sdk.dms.v1.queue + +The DMS Queue Class +------------------- + +The ``Queue`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dms.v1.queue.Queue + :members: diff --git a/doc/source/sdk/resources/dms/v1/quota.rst b/doc/source/sdk/resources/dms/v1/quota.rst new file mode 100644 index 000000000..5faa27fd5 --- /dev/null +++ b/doc/source/sdk/resources/dms/v1/quota.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dcs.v1.quota +============================== + +.. automodule:: otcextensions.sdk.dms.v1.quota + +The DMS Quota Class +------------------- + +The ``Quota`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dms.v1.quota.Quota + :members: diff --git a/doc/source/sdk/resources/dns/index.rst b/doc/source/sdk/resources/dns/index.rst new file mode 100644 index 000000000..beb9d656b --- /dev/null +++ b/doc/source/sdk/resources/dns/index.rst @@ -0,0 +1,10 @@ +Anti DDoS Resources +=================== + +.. toctree:: + :maxdepth: 1 + + v2/zone + v2/nameserver + v2/floating_ip + v2/recordset diff --git a/doc/source/sdk/resources/dns/v2/floating_ip.rst b/doc/source/sdk/resources/dns/v2/floating_ip.rst new file mode 100644 index 000000000..6b8b91b83 --- /dev/null +++ b/doc/source/sdk/resources/dns/v2/floating_ip.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dns.v2.floating_ip +==================================== + +.. automodule:: otcextensions.sdk.dns.v2.floating_ip + +The DNS FloatingIP Class +------------------------ + +The ``floating_ip`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dns.v2.floating_ip.FloatingIP + :members: diff --git a/doc/source/sdk/resources/dns/v2/nameserver.rst b/doc/source/sdk/resources/dns/v2/nameserver.rst new file mode 100644 index 000000000..16bc1bc38 --- /dev/null +++ b/doc/source/sdk/resources/dns/v2/nameserver.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dns.v2.nameserver +=================================== + +.. automodule:: otcextensions.sdk.dns.v2.nameserver + +The DNS Nameserver Class +------------------------ + +The ``Nameserver`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dns.v2.nameserver.NameServer + :members: diff --git a/doc/source/sdk/resources/dns/v2/recordset.rst b/doc/source/sdk/resources/dns/v2/recordset.rst new file mode 100644 index 000000000..b96c4f748 --- /dev/null +++ b/doc/source/sdk/resources/dns/v2/recordset.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dns.v2.recordset +================================== + +.. automodule:: otcextensions.sdk.dns.v2.recordset + +The DNS Recordset Class +----------------------- + +The ``recordset`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dns.v2.recordset.Recordset + :members: diff --git a/doc/source/sdk/resources/dns/v2/zone.rst b/doc/source/sdk/resources/dns/v2/zone.rst new file mode 100644 index 000000000..d0afbbc10 --- /dev/null +++ b/doc/source/sdk/resources/dns/v2/zone.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dns.v2.zone +============================= + +.. automodule:: otcextensions.sdk.dns.v2.zone + +The DNS Zone Class +------------------ + +The ``Zone`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dns.v2.zone.Zone + :members: diff --git a/doc/source/sdk/resources/index.rst b/doc/source/sdk/resources/index.rst new file mode 100644 index 000000000..551e2b07d --- /dev/null +++ b/doc/source/sdk/resources/index.rst @@ -0,0 +1,54 @@ +Resources and Attributes +======================== + +Open Telekom Cloud Resources +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. toctree:: + :maxdepth: 1 + + Anti DDoS Service (Anti-DDoS) + AutoScaling Service (AS) + Cloud Container Engine (CCE) + Cloud Trace Service (CTS) + Distributed Cache Service (DCS) + Dedicated Host Service (DeH) + Distributed Message Service (DMS) + Domain Name Service (DNS) + Key Management Service (KMS) + Object Block Storage (OBS) + Relational Database Service (RDS) + +Every resource which is used within the proxy methods have own attributes. +Those attributes define the behavior of the resource which can be a cluster +or a node or anything different logical unit in an OpenStack Cloud. The +*Resource* layer is a lower-level interface to communicate with OpenStack +services. While the classes exposed by the :ref:`service-proxies` build a +convenience layer on top of this, :class:`~openstack.resource.Resource` +objects can be used directly. However, the most common usage of this layer is +in receiving an object from a class in the `Connection Interface_`, +modifying it, and sending it back to the :ref:`service-proxies` layer, +such as to update a resource on the server. + +The following services have exposed :class:`~openstack.resource.Resource` +classes. + +OpenStack native Resources +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. toctree:: + :maxdepth: 1 + + Baremetal + Block Storage + Clustering + Compute + Database + Identity + Image + Key Management + Load Balancer + Network + Orchestration + Object Store + Workflow diff --git a/doc/source/sdk/resources/kms/index.rst b/doc/source/sdk/resources/kms/index.rst new file mode 100644 index 000000000..f1bc1afe8 --- /dev/null +++ b/doc/source/sdk/resources/kms/index.rst @@ -0,0 +1,8 @@ +AutoScaling Resources +===================== + +.. toctree:: + :maxdepth: 1 + + v1/key + v1/data_key diff --git a/doc/source/sdk/resources/kms/v1/data_key.rst b/doc/source/sdk/resources/kms/v1/data_key.rst new file mode 100644 index 000000000..24a417254 --- /dev/null +++ b/doc/source/sdk/resources/kms/v1/data_key.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.kms.v1.data_key +================================= + +.. automodule:: otcextensions.sdk.kms.v1.data_key + +The KMS DEK Class +----------------- + +The ``DataKey`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.kms.v1.data_key.DataKey + :members: diff --git a/doc/source/sdk/resources/kms/v1/key.rst b/doc/source/sdk/resources/kms/v1/key.rst new file mode 100644 index 000000000..0f37920f3 --- /dev/null +++ b/doc/source/sdk/resources/kms/v1/key.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.kms.v1.key +============================ + +.. automodule:: otcextensions.sdk.kms.v1.key + +The KMS CMK Class +----------------- + +The ``Key`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.kms.v1.key.Key + :members: diff --git a/doc/source/sdk/resources/obs/index.rst b/doc/source/sdk/resources/obs/index.rst new file mode 100644 index 000000000..adea4ca5d --- /dev/null +++ b/doc/source/sdk/resources/obs/index.rst @@ -0,0 +1,8 @@ +OBS Resources +============= + +.. toctree:: + :maxdepth: 1 + + v1/container + v1/obj diff --git a/doc/source/sdk/resources/obs/v1/container.rst b/doc/source/sdk/resources/obs/v1/container.rst new file mode 100644 index 000000000..658398031 --- /dev/null +++ b/doc/source/sdk/resources/obs/v1/container.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.obs.v1.container +================================== + +.. automodule:: otcextensions.sdk.obs.v1.container + +The OBS Container (Bucket) Class +-------------------------------- + +The ``Container`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.obs.v1.container.Container + :members: diff --git a/doc/source/sdk/resources/obs/v1/obj.rst b/doc/source/sdk/resources/obs/v1/obj.rst new file mode 100644 index 000000000..5492cdbf8 --- /dev/null +++ b/doc/source/sdk/resources/obs/v1/obj.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.obs.v1.obj +============================ + +.. automodule:: otcextensions.sdk.obs.v1.obj + +The OBS Object Class +-------------------- + +The ``Object`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.obs.v1.obj.Object + :members: diff --git a/doc/source/sdk/resources/rds/index.rst b/doc/source/sdk/resources/rds/index.rst new file mode 100644 index 000000000..a4acba66e --- /dev/null +++ b/doc/source/sdk/resources/rds/index.rst @@ -0,0 +1,22 @@ +RDS Resources +============= + +RDS v1 +^^^^^^ + +.. toctree:: + :maxdepth: 1 + + v1/configuration + v1/flavor + v1/instance + +RDS v3 +^^^^^^ + +.. toctree:: + :maxdepth: 1 + + v3/configuration + v3/flavor + v3/instance diff --git a/doc/source/sdk/resources/rds/v1/configuration.rst b/doc/source/sdk/resources/rds/v1/configuration.rst new file mode 100644 index 000000000..2fe69c1b5 --- /dev/null +++ b/doc/source/sdk/resources/rds/v1/configuration.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.rds.v1.configuration +====================================== + +.. automodule:: otcextensions.sdk.rds.v1.configuration + +The Configuration Class +----------------------- + +The ``Configuration`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.rds.v1.configuration.ConfigurationGroup + :members: diff --git a/doc/source/sdk/resources/rds/v1/flavor.rst b/doc/source/sdk/resources/rds/v1/flavor.rst new file mode 100644 index 000000000..2033f62eb --- /dev/null +++ b/doc/source/sdk/resources/rds/v1/flavor.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.rds.v1.flavor +=============================== + +.. automodule:: otcextensions.sdk.rds.v1.flavor + +The Flavor Class +---------------- + +The ``Flavor`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.rds.v1.flavor.Flavor + :members: diff --git a/doc/source/sdk/resources/rds/v1/instance.rst b/doc/source/sdk/resources/rds/v1/instance.rst new file mode 100644 index 000000000..07e75ff44 --- /dev/null +++ b/doc/source/sdk/resources/rds/v1/instance.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.rds.v1.instance +================================= + +.. automodule:: otcextensions.sdk.rds.v1.instance + +The Instance Class +------------------ + +The ``Instance`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.rds.v1.instance.Instance + :members: diff --git a/doc/source/sdk/resources/rds/v3/configuration.rst b/doc/source/sdk/resources/rds/v3/configuration.rst new file mode 100644 index 000000000..a6b436702 --- /dev/null +++ b/doc/source/sdk/resources/rds/v3/configuration.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.rds.v3.configuration +====================================== + +.. automodule:: otcextensions.sdk.rds.v3.configuration + +The Configuration Class +----------------------- + +The ``Configuration`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.rds.v3.configuration.Configuration + :members: diff --git a/doc/source/sdk/resources/rds/v3/flavor.rst b/doc/source/sdk/resources/rds/v3/flavor.rst new file mode 100644 index 000000000..a8806f213 --- /dev/null +++ b/doc/source/sdk/resources/rds/v3/flavor.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.rds.v3.flavor +=============================== + +.. automodule:: otcextensions.sdk.rds.v3.flavor + +The Flavor Class +---------------- + +The ``Flavor`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.rds.v3.flavor.Flavor + :members: diff --git a/doc/source/sdk/resources/rds/v3/instance.rst b/doc/source/sdk/resources/rds/v3/instance.rst new file mode 100644 index 000000000..d72e7cd4f --- /dev/null +++ b/doc/source/sdk/resources/rds/v3/instance.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.rds.v3.instance +================================= + +.. automodule:: otcextensions.sdk.rds.v3.instance + +The Instance Class +------------------ + +The ``Instance`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.rds.v3.instance.Instance + :members: From 7642c805893010569ab1828b3f47de6247fd0832 Mon Sep 17 00:00:00 2001 From: "T. Schreiber" Date: Tue, 31 Mar 2020 15:40:24 +0000 Subject: [PATCH 16/58] drop unnecessary stuff --- doc/source/sdk/proxies/index.rst | 5 ----- doc/source/sdk/resources/index.rst | 20 -------------------- 2 files changed, 25 deletions(-) diff --git a/doc/source/sdk/proxies/index.rst b/doc/source/sdk/proxies/index.rst index 7b5a92f51..af8deed03 100644 --- a/doc/source/sdk/proxies/index.rst +++ b/doc/source/sdk/proxies/index.rst @@ -39,11 +39,6 @@ Links to Native OpenStack Service Proxies Block Storage Compute Database - Identity v3 - Image v2 - Key Manager - Load Balancer - Message v2 Network Object Store Orchestration diff --git a/doc/source/sdk/resources/index.rst b/doc/source/sdk/resources/index.rst index 551e2b07d..8987ad415 100644 --- a/doc/source/sdk/resources/index.rst +++ b/doc/source/sdk/resources/index.rst @@ -32,23 +32,3 @@ such as to update a resource on the server. The following services have exposed :class:`~openstack.resource.Resource` classes. - -OpenStack native Resources -^^^^^^^^^^^^^^^^^^^^^^^^^^ - -.. toctree:: - :maxdepth: 1 - - Baremetal - Block Storage - Clustering - Compute - Database - Identity - Image - Key Management - Load Balancer - Network - Orchestration - Object Store - Workflow From 97abf91c9575bb8331d48583aea5ee7a148e7864 Mon Sep 17 00:00:00 2001 From: "T. Schreiber" Date: Wed, 1 Apr 2020 13:44:42 +0000 Subject: [PATCH 17/58] bring identity and image proxy back --- doc/source/sdk/proxies/index.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/source/sdk/proxies/index.rst b/doc/source/sdk/proxies/index.rst index af8deed03..e83847d81 100644 --- a/doc/source/sdk/proxies/index.rst +++ b/doc/source/sdk/proxies/index.rst @@ -39,6 +39,8 @@ Links to Native OpenStack Service Proxies Block Storage Compute Database + Identity v3 + Image v2 Network Object Store Orchestration From be9789e61db7c7347bb63ffafea39571763b3aa0 Mon Sep 17 00:00:00 2001 From: "T. Schreiber" Date: Wed, 1 Apr 2020 14:07:58 +0000 Subject: [PATCH 18/58] proposal for better understanding of class attributes --- doc/source/sdk/resources/cce/v3/cluster.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/doc/source/sdk/resources/cce/v3/cluster.rst b/doc/source/sdk/resources/cce/v3/cluster.rst index 8b4cd7f60..431f448b8 100644 --- a/doc/source/sdk/resources/cce/v3/cluster.rst +++ b/doc/source/sdk/resources/cce/v3/cluster.rst @@ -11,3 +11,12 @@ The ``Cluster`` class inherits from .. autoclass:: otcextensions.sdk.cce.v3.cluster.Cluster :members: + +.. autoclass:: otcextensions.sdk.cce.v3.cluster.ClusterSpec + :members: + +.. autoclass:: otcextensions.sdk.cce.v3.cluster.HostNetworkSpec + :members: + +.. autoclass:: otcextensions.sdk.cce.v3.cluster.StatusSpec + :members: From 814c019e9fc8c4d3cdfbcb807358d15310ebbdda Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Thu, 2 Apr 2020 15:19:47 +0200 Subject: [PATCH 19/58] Do a squash-merge merging into master --- .zuul.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.zuul.yaml b/.zuul.yaml index 636de0f2d..64f756567 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -1,4 +1,5 @@ - project: + merge-mode: squash-merge check: jobs: - tox-py37 From 3e5ba528061c5e2749ef3fc4f9d07e9a6fc81ae7 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Mon, 6 Apr 2020 10:26:45 +0200 Subject: [PATCH 20/58] undo squash-merge --- .zuul.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.zuul.yaml b/.zuul.yaml index 64f756567..636de0f2d 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -1,5 +1,4 @@ - project: - merge-mode: squash-merge check: jobs: - tox-py37 From cdd2be1b8c7637dbdd80f6c26b512cceeb7ea5a3 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Mon, 6 Apr 2020 11:30:30 +0200 Subject: [PATCH 21/58] sync test-requirements with latest upstream changes --- test-requirements.txt | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/test-requirements.txt b/test-requirements.txt index f159c07e4..5cc4021f6 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -1,22 +1,30 @@ # The order of packages is significant, because pip processes them in the order # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -hacking>=1.0,<1.2 # Apache-2.0 +hacking>=3.0,<3.1.0 # Apache-2.0 coverage!=4.4,>=4.0 # Apache-2.0 +ddt>=1.0.1 # MIT extras>=1.0.0 # MIT fixtures>=3.0.0 # Apache-2.0/BSD jsonschema>=2.6.0 # MIT -mock>=2.0.0 # BSD +mock>=3.0.0 # BSD +prometheus-client>=0.4.2 # Apache-2.0 python-subunit>=1.0.0 # Apache-2.0/BSD +oslo.config>=6.1.0 # Apache-2.0 oslotest>=3.2.0 # Apache-2.0 -requests-mock>=1.1.0 # Apache-2.0 +requests-mock>=1.2.0 # Apache-2.0 +statsd>=3.3.0 stestr>=1.0.0 # Apache-2.0 testrepository>=0.0.18 # Apache-2.0/BSD testscenarios>=0.4 # Apache-2.0/BSD testtools>=2.2.0 # MIT -doc8>=0.8.0 # Apache-2.0 -python-openstackclient>=3.12.1 # Apache-2.0 +doc8>=0.8.0 # Apache-2.0 +Pygments>=2.2.0 # BSD license + +# OTCE specifics +# Func tests of OSC tempest>=17.1.0 # Apache-2.0 -Pygments>=2.2.0 # BSD License +python-openstackclient>=5.0.0 # Apache-2.0 +# Usability of venv flake8 From 8b04bb875f1b979b59330dc3be20cedd23a65f77 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Mon, 6 Apr 2020 16:36:33 +0200 Subject: [PATCH 22/58] use squash-merge (#72) --- .zuul.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.zuul.yaml b/.zuul.yaml index 636de0f2d..64f756567 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -1,4 +1,5 @@ - project: + merge-mode: squash-merge check: jobs: - tox-py37 From 1f25c4363c967468348b9301f633e03b802f1a0c Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Sun, 12 Apr 2020 09:52:27 +0200 Subject: [PATCH 23/58] sync with upstream (#73) * sync with upstream * rename cls to self in non class methods --- doc/requirements.txt | 2 +- otcextensions/_hacking.py | 43 ++++++++ otcextensions/tests/functional/base.py | 14 +-- .../osclient/obs/v1/test_container.py | 24 ++--- .../functional/osclient/obs/v1/test_obj.py | 52 +++++---- .../osclient/volume_backup/v2/test_policy.py | 23 ++-- .../tests/functional/sdk/deh/v1/test_host.py | 18 ++-- .../functional/sdk/dms/v1/test_message.py | 100 +++++++++--------- .../tests/functional/sdk/dms/v1/test_queue.py | 18 ++-- .../functional/sdk/kms/v1/test_data_key.py | 18 ++-- .../tests/functional/sdk/kms/v1/test_key.py | 18 ++-- .../functional/sdk/volume_backup/__init__.py | 7 +- .../sdk/volume_backup/v2/test_backup.py | 25 ----- .../volume_backup/v2/test_backup_policy.py | 77 ++------------ tox.ini | 44 ++++---- 15 files changed, 209 insertions(+), 274 deletions(-) create mode 100644 otcextensions/_hacking.py diff --git a/doc/requirements.txt b/doc/requirements.txt index 2256888a7..f829fa739 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -5,7 +5,7 @@ docutils>=0.11 # OSI-Approved Open Source, Public Domain beautifulsoup4>=4.6.0 # MIT reno>=2.5.0 # Apache-2.0 otcdocstheme # Apache-2.0 -sphinx!=1.6.6,!=1.6.7,>=1.6.5 # BSD +sphinx>=1.8.0,!=2.1.0 # BSD sphinxcontrib-apidoc>=0.2.0 # BSD cliff!=2.9.0,>=2.8.0 # Apache-2.0 oslo.i18n>=3.15.3 # Apache-2.0 diff --git a/otcextensions/_hacking.py b/otcextensions/_hacking.py new file mode 100644 index 000000000..01b05adfc --- /dev/null +++ b/otcextensions/_hacking.py @@ -0,0 +1,43 @@ +# Copyright (c) 2019, Red Hat, 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. + +import re + +from hacking import core + +""" +Guidelines for writing new hacking checks + + - Use only for openstacksdk specific tests. OpenStack general tests + should be submitted to the common 'hacking' module. + - Pick numbers in the range O3xx. Find the current test with + the highest allocated number and then pick the next value. + - Keep the test method code in the source file ordered based + on the O3xx value. + - List the new rule in the top level HACKING.rst file + - Add test cases for each new rule to nova/tests/unit/test_hacking.py + +""" + +SETUPCLASS_RE = re.compile(r"def setUpClass\(") + + +@core.flake8ext +def assert_no_setupclass(logical_line): + """Check for use of setUpClass + + O300 + """ + if SETUPCLASS_RE.match(logical_line): + yield (0, "O300: setUpClass not allowed") diff --git a/otcextensions/tests/functional/base.py b/otcextensions/tests/functional/base.py index 1fd65dacf..10ba085f3 100644 --- a/otcextensions/tests/functional/base.py +++ b/otcextensions/tests/functional/base.py @@ -42,16 +42,10 @@ def _get_resource_value(resource_key, default): class BaseFunctionalTest(base.TestCase): - @classmethod - def setUpClass(cls): - super(BaseFunctionalTest, cls).setUpClass() - cls.conn = connection.Connection(config=TEST_CLOUD_REGION) - sdk.register_otc_extensions(cls.conn) - - # def setUp(self): - # super(BaseFunctionalTest, self).setUp() - # self.conn = connection.Connection(config=TEST_CLOUD_REGION) - # sdk.register_otc_extensions(self.conn) + def setUp(self): + super(BaseFunctionalTest, self).setUp() + self.conn = connection.Connection(config=TEST_CLOUD_REGION) + sdk.register_otc_extensions(self.conn) def addEmptyCleanup(self, func, *args, **kwargs): def cleanup(): diff --git a/otcextensions/tests/functional/osclient/obs/v1/test_container.py b/otcextensions/tests/functional/osclient/obs/v1/test_container.py index d8aa4f46a..8164b1aab 100644 --- a/otcextensions/tests/functional/osclient/obs/v1/test_container.py +++ b/otcextensions/tests/functional/osclient/obs/v1/test_container.py @@ -29,26 +29,22 @@ class ObsContainerTests(base.TestCase): NAME = uuid.uuid4().hex OTHER_NAME = uuid.uuid4().hex - @classmethod - def setUpClass(cls): - super(ObsContainerTests, cls).setUpClass() - json_output = json.loads(cls.openstack( - CREATE_COMMAND % {'name': cls.NAME} - )) - cls.container_id = json_output["id"] - cls.assertOutput(cls.NAME, json_output['name']) - - @classmethod - def tearDownClass(cls): + def tearDown(self): try: - cls.openstack( - DELETE_COMMAND % {'name': cls.NAME} + self.openstack( + DELETE_COMMAND % {'name': self.NAME} ) finally: - super(ObsContainerTests, cls).tearDownClass() + super(ObsContainerTests, self).tearDown() def setUp(self): super(ObsContainerTests, self).setUp() + json_output = json.loads(self.openstack( + CREATE_COMMAND % {'name': self.NAME} + )) + self.container_id = json_output["id"] + self.assertOutput(self.NAME, json_output['name']) + ver_fixture = fixtures.EnvironmentVariable( 'OS_OBS_API_VERSION', '1' ) diff --git a/otcextensions/tests/functional/osclient/obs/v1/test_obj.py b/otcextensions/tests/functional/osclient/obs/v1/test_obj.py index 279f00f8b..455e5e902 100644 --- a/otcextensions/tests/functional/osclient/obs/v1/test_obj.py +++ b/otcextensions/tests/functional/osclient/obs/v1/test_obj.py @@ -35,43 +35,39 @@ class ObsObjectTests(base.TestCase): OBJECT_CONTENT = uuid.uuid4().hex - @classmethod - def setUpClass(cls): - super(ObsObjectTests, cls).setUpClass() - json_output = json.loads(cls.openstack( - CONTAINER_CREATE_COMMAND % {'name': cls.CONTAINER_NAME} - )) - cls.container_id = json_output["id"] - cls.assertOutput(cls.CONTAINER_NAME, json_output['name']) - with open(cls.OBJECT_NAME, 'w') as file: - file.write(cls.OBJECT_CONTENT) - json_output = json.loads(cls.openstack( - OBJECT_CREATE_COMMAND % { - 'name': cls.OBJECT_NAME, - 'container': cls.CONTAINER_NAME - } - )) - cls.object_id = json_output["id"] - cls.assertOutput(cls.OBJECT_NAME, json_output['name']) - - @classmethod - def tearDownClass(cls): + def tearDown(self): try: - cls.openstack( + self.openstack( OBJECT_DELETE_COMMAND % { - 'name': cls.OBJECT_NAME, - 'container': cls.CONTAINER_NAME + 'name': self.OBJECT_NAME, + 'container': self.CONTAINER_NAME } ) - cls.openstack( - CONTAINER_DELETE_COMMAND % {'name': cls.CONTAINER_NAME} + self.openstack( + CONTAINER_DELETE_COMMAND % {'name': self.CONTAINER_NAME} ) - os.remove(cls.OBJECT_NAME) + os.remove(self.OBJECT_NAME) finally: - super(ObsObjectTests, cls).tearDownClass() + super(ObsObjectTests, self).tearDown() def setUp(self): super(ObsObjectTests, self).setUp() + json_output = json.loads(self.openstack( + CONTAINER_CREATE_COMMAND % {'name': self.CONTAINER_NAME} + )) + self.container_id = json_output["id"] + self.assertOutput(self.CONTAINER_NAME, json_output['name']) + with open(self.OBJECT_NAME, 'w') as file: + file.write(self.OBJECT_CONTENT) + json_output = json.loads(self.openstack( + OBJECT_CREATE_COMMAND % { + 'name': self.OBJECT_NAME, + 'container': self.CONTAINER_NAME + } + )) + self.object_id = json_output["id"] + self.assertOutput(self.OBJECT_NAME, json_output['name']) + ver_fixture = fixtures.EnvironmentVariable( 'OS_OBS_API_VERSION', '1' ) diff --git a/otcextensions/tests/functional/osclient/volume_backup/v2/test_policy.py b/otcextensions/tests/functional/osclient/volume_backup/v2/test_policy.py index 110078a04..ffc0f9603 100644 --- a/otcextensions/tests/functional/osclient/volume_backup/v2/test_policy.py +++ b/otcextensions/tests/functional/osclient/volume_backup/v2/test_policy.py @@ -30,26 +30,21 @@ class VolumeBackupPolicyTests(base.TestCase): NAME = uuid.uuid4().hex OTHER_NAME = uuid.uuid4().hex - @classmethod - def setUpClass(cls): - super(VolumeBackupPolicyTests, cls).setUpClass() - json_output = json.loads(cls.openstack( - CREATE_COMMAND % {'name': cls.NAME} - )) - cls.policy_id = json_output["id"] - cls.assertOutput(cls.NAME, json_output['name']) - - @classmethod - def tearDownClass(cls): + def tearDown(self): try: - cls.openstack( - DELETE_COMMAND % {'id': cls.policy_id} + self.openstack( + DELETE_COMMAND % {'id': self.policy_id} ) finally: - super(VolumeBackupPolicyTests, cls).tearDownClass() + super(VolumeBackupPolicyTests, self).tearDown() def setUp(self): super(VolumeBackupPolicyTests, self).setUp() + json_output = json.loads(self.openstack( + CREATE_COMMAND % {'name': self.NAME} + )) + self.policy_id = json_output["id"] + self.assertOutput(self.NAME, json_output['name']) ver_fixture = fixtures.EnvironmentVariable( 'OS_VBS_API_VERSION', '2' ) diff --git a/otcextensions/tests/functional/sdk/deh/v1/test_host.py b/otcextensions/tests/functional/sdk/deh/v1/test_host.py index 9941305dc..7688a5ecd 100644 --- a/otcextensions/tests/functional/sdk/deh/v1/test_host.py +++ b/otcextensions/tests/functional/sdk/deh/v1/test_host.py @@ -19,12 +19,11 @@ class TestHost(base.BaseFunctionalTest): - @classmethod - def setUpClass(cls): - super(TestHost, cls).setUpClass() + def setUp(self): + super(TestHost, self).setUp() openstack.enable_logging(debug=True, http_debug=True) - cls.client = cls.conn.deh - res = cls.client.create_host( + self.client = self.conn.deh + res = self.client.create_host( name=uuid.uuid4().hex, availability_zone='eu-de-01', host_type='general', @@ -32,13 +31,12 @@ def setUpClass(cls): ) assert len(res.dedicated_host_ids) == 1 host_id = res.dedicated_host_ids[0] - cls.host = cls.client.get_host(host_id) + self.host = self.client.get_host(host_id) - @classmethod - def tearDownClass(cls): + def tearDown(self): try: - if cls.host.id: - cls.client.delete_host(cls.host) + if self.host.id: + self.client.delete_host(self.host) except openstack.exceptions.SDKException as e: _logger.warning('Got exception during clearing resources %s' % e.message) diff --git a/otcextensions/tests/functional/sdk/dms/v1/test_message.py b/otcextensions/tests/functional/sdk/dms/v1/test_message.py index d1336bee4..06f9fce0e 100644 --- a/otcextensions/tests/functional/sdk/dms/v1/test_message.py +++ b/otcextensions/tests/functional/sdk/dms/v1/test_message.py @@ -26,78 +26,76 @@ class TestMessage(base.BaseFunctionalTest): messages = [] received_messages = [] - @classmethod - def setUpClass(cls): - super(TestMessage, cls).setUpClass() + def setUp(self): + super(TestMessage, self).setUp() openstack.enable_logging(debug=True, http_debug=True) try: - cls.queue = cls.conn.dms.create_queue( + self.queue = self.conn.dms.create_queue( name=TestMessage.QUEUE_ALIAS ) except openstack.exceptions.BadRequestException: - cls.queue = cls.conn.dms.get_queue(TestMessage.QUEUE_ALIAS) + self.queue = self.conn.dms.get_queue(TestMessage.QUEUE_ALIAS) - cls.queues.append(cls.queue) + self.queues.append(self.queue) try: - cls.group = cls.conn.dms.create_group( - cls.queue, {"name": "test_group"} + self.group = self.conn.dms.create_group( + self.queue, {"name": "test_group"} ) except openstack.exceptions.DuplicateResource: - cls.queue = cls.conn.dms.groups(cls.queue) + self.queue = self.conn.dms.groups(self.queue) - cls.groups.append(cls.group) + self.groups.append(self.group) - @classmethod - def tearDownClass(cls): + def tearDown(self): try: - for queue in cls.queues: + for queue in self.queues: if queue.id: - cls.conn.dms.delete_queue(queue) + self.conn.dms.delete_queue(queue) except openstack.exceptions.SDKException as e: _logger.warning('Got exception during clearing resources %s' % e.message) - def test_list(cls): - cls.queues = list(cls.conn.dms.queues()) - cls.assertGreaterEqual(len(cls.queues), 0) - if len(cls.queues) > 0: - queue = cls.queues[0] - q = cls.conn.dms.get_queue(queue=queue.id) - cls.assertIsNotNone(q) - - def test_group(cls): - cls.queues = list(cls.conn.dms.queues()) - # cls.assertGreaterEqual(len(cls.queues), 0) - if len(cls.queues) > 0: - # queue = cls.queues[0] - # q = cls.conn.dms.get_queue(queue=queue.id) - # cls.assertIsNotNone(q) + def test_list(self): + self.queues = list(self.conn.dms.queues()) + self.assertGreaterEqual(len(self.queues), 0) + if len(self.queues) > 0: + queue = self.queues[0] + q = self.conn.dms.get_queue(queue=queue.id) + self.assertIsNotNone(q) + + def test_group(self): + self.queues = list(self.conn.dms.queues()) + # self.assertGreaterEqual(len(self.queues), 0) + if len(self.queues) > 0: + # queue = self.queues[0] + # q = self.conn.dms.get_queue(queue=queue.id) + # self.assertIsNotNone(q) try: - cls.group = cls.conn.dms.create_group( - cls.queue, {"name": "test_group"} + self.group = self.conn.dms.create_group( + self.queue, {"name": "test_group"} ) except openstack.exceptions.BadRequestException: - cls.queue = cls.conn.dms.groups(cls.queue) + self.queue = self.conn.dms.groups(self.queue) - cls.groups.append(cls.group) + self.groups.append(self.group) # OS_TEST_TIMEOUT=60 is needed due to testbed slowness @classmethod - def test_message(cls): - cls.queues = list(cls.conn.dms.queues()) - # cls.assertGreaterEqual(len(cls.queues), 0) - if len(cls.queues) > 0: - # queue = cls.queues[0] - # q = cls.conn.dms.get_queue(queue=queue.id) + def test_message(self): + self.queues = list(self.conn.dms.queues()) + # self.assertGreaterEqual(len(self.queues), 0) + if len(self.queues) > 0: + # queue = self.queues[0] + # q = self.conn.dms.get_queue(queue=queue.id) time.sleep(50) - # cls.assertIsNotNone(q) - cls.message = cls.conn.dms.send_messages( - cls.queue, + # self.assertIsNotNone(q) + self.message = self.conn.dms.send_messages( + self.queue, messages=[ {"body": "TEST11", "attributes": @@ -111,19 +109,19 @@ def test_message(cls): # "attribute1" : "value1", # "attribute2" : "value2" } } - cls.messages.append(cls.message) + self.messages.append(self.message) try: - cls.group = cls.conn.dms.create_group( - cls.queue, {"name": "test_group2"} + self.group = self.conn.dms.create_group( + self.queue, {"name": "test_group2"} ) except openstack.exceptions.BadRequestException: - cls.queue = cls.conn.dms.groups(cls.queue) + self.queue = self.conn.dms.groups(self.queue) - cls.groups.append(cls.group) + self.groups.append(self.group) - cls.received_messages = cls.dms.consume_message( - cls.queue, - cls.group + self.received_messages = self.dms.consume_message( + self.queue, + self.group ) - cls.assertGreaterEqual(len(cls.received_messages), 0) + self.assertGreaterEqual(len(self.received_messages), 0) diff --git a/otcextensions/tests/functional/sdk/dms/v1/test_queue.py b/otcextensions/tests/functional/sdk/dms/v1/test_queue.py index 2a8d83d30..ece366cfe 100644 --- a/otcextensions/tests/functional/sdk/dms/v1/test_queue.py +++ b/otcextensions/tests/functional/sdk/dms/v1/test_queue.py @@ -21,24 +21,22 @@ class TestQueue(base.BaseFunctionalTest): QUEUE_ALIAS = 'sdk_test_queue' queues = [] - @classmethod - def setUpClass(cls): - super(TestQueue, cls).setUpClass() + def setUp(self): + super(TestQueue, self).setUp() try: - cls.queue = cls.conn.dms.create_queue( + self.queue = self.conn.dms.create_queue( name=TestQueue.QUEUE_ALIAS ) except exceptions.DuplicateResource: - cls.queue = cls.conn.dms.find_queue(alias=TestQueue.QUEUE_ALIAS) + self.queue = self.conn.dms.find_queue(alias=TestQueue.QUEUE_ALIAS) - cls.queues.append(cls.queue) + self.queues.append(self.queue) - @classmethod - def tearDownClass(cls): + def tearDown(self): try: - for queue in cls.queues: + for queue in self.queues: if queue.id: - cls.conn.dms.delete_queue(queue) + self.conn.dms.delete_queue(queue) except exceptions.SDKException as e: _logger.warning('Got exception during clearing resources %s' % e.message) diff --git a/otcextensions/tests/functional/sdk/kms/v1/test_data_key.py b/otcextensions/tests/functional/sdk/kms/v1/test_data_key.py index d7a9cba06..47c1cc7d9 100644 --- a/otcextensions/tests/functional/sdk/kms/v1/test_data_key.py +++ b/otcextensions/tests/functional/sdk/kms/v1/test_data_key.py @@ -21,21 +21,19 @@ class TestDataKey(base.BaseFunctionalTest): - @classmethod - def setUpClass(cls): - super(TestDataKey, cls).setUpClass() - # cls.cmk = cls.conn.kms.find_key(alias='sdk_test_key1') - cls.cmk = cls.conn.kms.create_key( + def setUp(self): + super(TestDataKey, self).setUp() + # self.cmk = self.conn.kms.find_key(alias='sdk_test_key1') + self.cmk = self.conn.kms.create_key( key_alias=uuid.uuid4().hex ) - @classmethod - def tearDownClass(cls): + def tearDown(self): try: - if cls.cmk: - key = cls.cmk + if self.cmk: + key = self.cmk if key.id: - cls.conn.kms.schedule_key_deletion(key, 7) + self.conn.kms.schedule_key_deletion(key, 7) except exceptions.SDKException as e: _logger.warning('Got exception during clearing resources %s' % e.message) diff --git a/otcextensions/tests/functional/sdk/kms/v1/test_key.py b/otcextensions/tests/functional/sdk/kms/v1/test_key.py index 62900d995..6066b0e34 100644 --- a/otcextensions/tests/functional/sdk/kms/v1/test_key.py +++ b/otcextensions/tests/functional/sdk/kms/v1/test_key.py @@ -21,24 +21,22 @@ class TestKey(base.BaseFunctionalTest): KEY_ALIAS = 'sdk_test_key' cmks = [] - @classmethod - def setUpClass(cls): - super(TestKey, cls).setUpClass() + def setUp(self): + super(TestKey, self).setUp() try: - cls.cmk = cls.conn.kms.create_key( + self.cmk = self.conn.kms.create_key( key_alias=TestKey.KEY_ALIAS ) except exceptions.DuplicateResource: - cls.cmk = cls.conn.kms.find_key(alias=TestKey.KEY_ALIAS) + self.cmk = self.conn.kms.find_key(alias=TestKey.KEY_ALIAS) - cls.cmks.append(cls.cmk) + self.cmks.append(self.cmk) - @classmethod - def tearDownClass(cls): + def tearDown(self): try: - for key in cls.cmks: + for key in self.cmks: if key.id: - cls.conn.kms.schedule_key_deletion(key, 7) + self.conn.kms.schedule_key_deletion(key, 7) except exceptions.SDKException as e: _logger.warning('Got exception during clearing resources %s' % e.message) diff --git a/otcextensions/tests/functional/sdk/volume_backup/__init__.py b/otcextensions/tests/functional/sdk/volume_backup/__init__.py index 0de866f6a..64d4dbbb8 100644 --- a/otcextensions/tests/functional/sdk/volume_backup/__init__.py +++ b/otcextensions/tests/functional/sdk/volume_backup/__init__.py @@ -14,7 +14,6 @@ class TestVbs(base.BaseFunctionalTest): - @classmethod - def setUpClass(cls): - super(TestVbs, cls).setUpClass() - cls.client = cls.conn.volume_backup + def setUp(self): + super(TestVbs, self).setUp() + self.client = self.conn.volume_backup diff --git a/otcextensions/tests/functional/sdk/volume_backup/v2/test_backup.py b/otcextensions/tests/functional/sdk/volume_backup/v2/test_backup.py index 847997a84..f4d4dd29d 100644 --- a/otcextensions/tests/functional/sdk/volume_backup/v2/test_backup.py +++ b/otcextensions/tests/functional/sdk/volume_backup/v2/test_backup.py @@ -22,14 +22,6 @@ class TestBackup(TestVbs): volume = None job = None - @classmethod - def setUpClass(cls): - super(TestBackup, cls).setUpClass() - - @classmethod - def tearDownClass(cls): - pass - def prepare_volume(self): self.SNAPSHOT_NAME = self.getUniqueString() @@ -115,20 +107,3 @@ def test_get_backup(self): if len(backups) > 0: backup = self.client.get_backup(backups[0]) self.assertIsNotNone(backup) - - # TODO(AGoncharov) backup creation takes too long. - # 1Gb empty volume backup takes more than 4 min - # The functional test for create/delete can not be scheduled with such - # timing - # def test_create_delete_backup(self): - # self.prepare_volume() - # - # backup = self.client.create_backup( - # volume_id=self.VOLUME_ID, - # snapshot_id=self.SNAPSHOT_ID, - # name='sdk_test_backup') - # assert isinstance(backup, _backup.Backup) - # self.client.wait_for_backup(backup) - # self.client.delete_backup(backup) - # self.client.wait_for_backup_delete(backup) - # self.cleanup_volume() diff --git a/otcextensions/tests/functional/sdk/volume_backup/v2/test_backup_policy.py b/otcextensions/tests/functional/sdk/volume_backup/v2/test_backup_policy.py index c18c8361b..6a3bba660 100644 --- a/otcextensions/tests/functional/sdk/volume_backup/v2/test_backup_policy.py +++ b/otcextensions/tests/functional/sdk/volume_backup/v2/test_backup_policy.py @@ -34,25 +34,18 @@ class TestBackupPolicy(TestVbs): policy = None volume = None - @classmethod - def setUpClass(cls): - super(TestBackupPolicy, cls).setUpClass() - # for volume in cls.conn.block_store.volumes(limit=1): - # cls.volume = volume - # break - # if not cls.volume: - # raise Exception("no exists volume for test") - # create backup policy - cls.policy = create_backup_policy(cls.client, cls.BACKUP_POLICY_NAME) + def setUp(self): + super(TestBackupPolicy, self).setUp() + self.policy = create_backup_policy(self.client, + self.BACKUP_POLICY_NAME) - @classmethod - def tearDownClass(cls): + def tearDown(self): #: delete backup policy - if cls.policy and cls.volume: - cls.conn.volume_backup.unlink_resources_of_policy(cls.policy, - [cls.volume.id]) - if cls.policy: - cls.conn.volume_backup.delete_backup_policy(cls.policy) + if self.policy and self.volume: + self.conn.volume_backup.unlink_resources_of_policy( + self.policy, [self.volume.id]) + if self.policy: + self.conn.volume_backup.delete_backup_policy(self.policy) def test_list_policies(self): policies = list(self.client.backup_policies()) @@ -79,53 +72,3 @@ def test_disable_policy(self): def test_execute_policy(self): policy = self.client.enable_policy(self.policy) self.client.execute_policy(policy) - - # def test_link(self): - # VOLUME_NAME = self.getUniqueString() - # self.volume = self.conn.block_storage.create_volume( - # name=VOLUME_NAME, - # size=1) - # self.client.link_resources_to_policy(self.policy, [self.volume.id]) -# -# def get_current_policy(self): -# policies = list(self.conn.volume_backup.backup_policies()) -# for policy in policies: -# if policy.id == self.policy.id: -# return policy -# -# def test_1_list_backup_policies(self): -# policies = list(self.conn.volume_backup.backup_policies()) -# self.assertIn(self.policy.name, [p.name for p in policies]) -# -# def test_2_update_backup_policy(self): -# updated = { -# "scheduled_policy": { -# "frequency": 5, -# "start_time": "01:00" -# } -# } -# self.conn.volume_backup.update_backup_policy(self.policy, **updated) -# policy = self.get_current_policy() -# self.assertEqual(5, policy.scheduled_policy.frequency) -# self.assertEqual("01:00", policy.scheduled_policy.start_time) -# self.policy = policy -# -# def test_3_bind_and_execute(self): -# if self.policy.scheduled_policy.status == "OFF": -# self.conn.volume_backup.enable_policy(self.policy) -# -# self.conn.volume_backup.link_resources_to_policy(self.policy, -# [self.volume.id]) -# self.conn.volume_backup.execute_policy(self.policy) -# -# def test_4_enable_disable_policy(self): -# if self.policy.scheduled_policy.status == "ON": -# self.conn.volume_backup.disable_policy(self.policy) -# policy = self.get_current_policy() -# self.assertEqual("OFF", policy.scheduled_policy.status) -# self.conn.volume_backup.enable_policy(self.policy) -# self.assertEqual("ON", self.policy.scheduled_policy.status) -# -# def test_5_list_tasks(self): -# tasks = list(self.conn.volume_backup.tasks(self.policy.id)) -# print(tasks) diff --git a/tox.ini b/tox.ini index 4a5cafd7f..28b0062a1 100644 --- a/tox.ini +++ b/tox.ini @@ -40,10 +40,12 @@ commands = flake8 doc8 doc/source README.rst -[hacking] -local-check-factory = openstack._hacking.factory - [testenv:venv] +deps = + -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} + -r{toxinidir}/test-requirements.txt + -r{toxinidir}/requirements.txt + -r{toxinidir}/doc/requirements.txt commands = {posargs} [testenv:debug] @@ -62,37 +64,39 @@ commands = coverage html -d cover coverage xml -o cover/coverage.xml -[testenv:ansible] -# Need to pass some env vars for the Ansible playbooks -basepython = {env:OPENSTACKSDK_TOX_PYTHON:python2} -passenv = HOME USER -commands = {toxinidir}/extras/run-ansible-tests.sh -e {envdir} {posargs} - -# Docs currently disabled [testenv:docs] deps = - -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} + -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} + -r{toxinidir}/requirements.txt -r{toxinidir}/doc/requirements.txt -commands = sphinx-build -W -d doc/build/doctrees -b html doc/source/ doc/build/html +commands = + sphinx-build -W -d doc/build/doctrees --keep-going -b html doc/source/ doc/build/html [testenv:releasenotes] -usedevelop = False -skip_install = True -commands = sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html +deps = + -c{env:UPPER_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master} + -r{toxinidir}/requirements.txt + -r{toxinidir}/doc/requirements.txt +commands = + sphinx-build -a -E -W -d releasenotes/build/doctrees --keep-going -b html releasenotes/source releasenotes/build/html [flake8] # The following are ignored on purpose. It's not super worth it to fix them. # However, if you feel strongly about it, patches will be accepted to fix them # if they fix ALL of the occurances of one and only one of them. -# H103 Is about the Apache license. It's strangely strict about the use of -# single vs double quotes in the license text. If someone decides to fix -# this, please be sure to preseve all copyright lines. # H306 Is about alphabetical imports - there's a lot to fix. # H4 Are about docstrings and there's just a huge pile of pre-existing issues. -# D* Came from sdk, unknown why they're skipped. +# W503 Is supposed to be off by default but in the latest pycodestyle isn't. +# Also, both openstacksdk and Donald Knuth disagree with the rule. Line +# breaks should occur before the binary operator for readability. ignore = H306,H4,W503 show-source = True -exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build +exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build,openstack/_services_mixin.py + +[flake8:local-plugins] +extension = + O300 = _hacking:assert_no_setupclass +paths = ./otcextensions [doc8] extensions = .rst, .yaml From 13545293f51f0990e9f27330dec123b5165cc69b Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Sun, 12 Apr 2020 10:15:26 +0200 Subject: [PATCH 24/58] Execute nightly functional tests only on master (#75) * use squash-merge * run nightly func-tests on master only --- .zuul.yaml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.zuul.yaml b/.zuul.yaml index 64f756567..572e70d61 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -1,3 +1,8 @@ +- job: + name: tox-functional-master + parent: tox-functional + branches: master + - project: merge-mode: squash-merge check: @@ -14,4 +19,4 @@ - tox-functional periodic: jobs: - - tox-functional + - tox-functional-master From e470668958b42b2fe54de0c076d96579eaecd7f3 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Tue, 14 Apr 2020 10:03:56 +0200 Subject: [PATCH 25/58] Add stubs for new services (#74) * Add stubs for remaining services * Add sdrs stub * SMN API is v2 * fix missed stuff in version renaming --- .stestr.blacklist.functional | 4 +- otcextensions/sdk/__init__.py | 46 +++++++++++++++++-- otcextensions/sdk/ces/__init__.py | 0 otcextensions/sdk/ces/ces_service.py | 22 +++++++++ otcextensions/sdk/ces/v1/__init__.py | 0 otcextensions/sdk/ces/v1/_proxy.py | 17 +++++++ otcextensions/sdk/dcaas/__init__.py | 0 otcextensions/sdk/dcaas/dcaas_service.py | 22 +++++++++ otcextensions/sdk/dcaas/v2/__init__.py | 0 otcextensions/sdk/dcaas/v2/_proxy.py | 17 +++++++ otcextensions/sdk/dds/__init__.py | 0 otcextensions/sdk/dds/dds_service.py | 23 ++++++++++ otcextensions/sdk/dds/v3/__init__.py | 0 otcextensions/sdk/dds/v3/_proxy.py | 17 +++++++ otcextensions/sdk/dis/__init__.py | 0 otcextensions/sdk/dis/dis_service.py | 23 ++++++++++ otcextensions/sdk/dis/v2/__init__.py | 0 otcextensions/sdk/dis/v2/_proxy.py | 17 +++++++ otcextensions/sdk/dws/__init__.py | 0 otcextensions/sdk/dws/dws_service.py | 23 ++++++++++ otcextensions/sdk/dws/v1/__init__.py | 0 otcextensions/sdk/dws/v1/_proxy.py | 17 +++++++ otcextensions/sdk/lts/__init__.py | 0 otcextensions/sdk/lts/lts_service.py | 22 +++++++++ otcextensions/sdk/lts/v2/__init__.py | 0 otcextensions/sdk/lts/v2/_proxy.py | 17 +++++++ otcextensions/sdk/maas/__init__.py | 0 otcextensions/sdk/maas/maas_service.py | 22 +++++++++ otcextensions/sdk/maas/v1/__init__.py | 0 otcextensions/sdk/maas/v1/_proxy.py | 17 +++++++ otcextensions/sdk/mrs/__init__.py | 0 otcextensions/sdk/mrs/mrs_service.py | 23 ++++++++++ otcextensions/sdk/mrs/v1/__init__.py | 0 otcextensions/sdk/mrs/v1/_proxy.py | 17 +++++++ otcextensions/sdk/plas/__init__.py | 0 otcextensions/sdk/plas/plas_service.py | 23 ++++++++++ otcextensions/sdk/plas/v1/__init__.py | 0 otcextensions/sdk/plas/v1/_proxy.py | 17 +++++++ otcextensions/sdk/sdrs/__init__.py | 0 otcextensions/sdk/sdrs/sdrs_service.py | 22 +++++++++ otcextensions/sdk/sdrs/v1/__init__.py | 0 otcextensions/sdk/sdrs/v1/_proxy.py | 17 +++++++ otcextensions/sdk/smn/__init__.py | 0 otcextensions/sdk/smn/smn_service.py | 22 +++++++++ otcextensions/sdk/smn/v2/__init__.py | 0 otcextensions/sdk/smn/v2/_proxy.py | 17 +++++++ otcextensions/sdk/waf/__init__.py | 0 otcextensions/sdk/waf/v1/__init__.py | 0 otcextensions/sdk/waf/v1/_proxy.py | 17 +++++++ otcextensions/sdk/waf/waf_service.py | 23 ++++++++++ .../tests/functional/sdk/ces/__init__.py | 0 .../tests/functional/sdk/ces/v1/__init__.py | 0 .../functional/sdk/ces/v1/test_service.py | 24 ++++++++++ .../tests/functional/sdk/dcaas/__init__.py | 0 .../tests/functional/sdk/dcaas/v2/__init__.py | 0 .../functional/sdk/dcaas/v2/test_service.py | 24 ++++++++++ .../tests/functional/sdk/dds/__init__.py | 0 .../tests/functional/sdk/dds/v3/__init__.py | 0 .../functional/sdk/dds/v3/test_service.py | 24 ++++++++++ .../tests/functional/sdk/dis/__init__.py | 0 .../tests/functional/sdk/dis/v2/__init__.py | 0 .../functional/sdk/dis/v2/test_service.py | 24 ++++++++++ .../tests/functional/sdk/dws/__init__.py | 0 .../tests/functional/sdk/dws/v1/__init__.py | 0 .../functional/sdk/dws/v1/test_service.py | 24 ++++++++++ .../tests/functional/sdk/lts/__init__.py | 0 .../tests/functional/sdk/lts/v2/__init__.py | 0 .../functional/sdk/lts/v2/test_service.py | 24 ++++++++++ .../tests/functional/sdk/maas/__init__.py | 0 .../tests/functional/sdk/maas/v1/__init__.py | 0 .../functional/sdk/maas/v1/test_service.py | 24 ++++++++++ .../tests/functional/sdk/mrs/__init__.py | 0 .../tests/functional/sdk/mrs/v1/__init__.py | 0 .../functional/sdk/mrs/v1/test_service.py | 24 ++++++++++ .../tests/functional/sdk/plas/__init__.py | 0 .../tests/functional/sdk/plas/v1/__init__.py | 0 .../functional/sdk/plas/v1/test_service.py | 24 ++++++++++ .../tests/functional/sdk/sdrs/__init__.py | 0 .../tests/functional/sdk/sdrs/v1/__init__.py | 0 .../functional/sdk/sdrs/v1/test_service.py | 24 ++++++++++ .../tests/functional/sdk/smn/__init__.py | 0 .../tests/functional/sdk/smn/v2/__init__.py | 0 .../functional/sdk/smn/v2/test_service.py | 24 ++++++++++ .../tests/functional/sdk/waf/__init__.py | 0 .../tests/functional/sdk/waf/v1/__init__.py | 0 .../functional/sdk/waf/v1/test_service.py | 24 ++++++++++ otcextensions/tests/unit/sdk/ces/__init__.py | 0 .../tests/unit/sdk/ces/v1/test_proxy.py | 22 +++++++++ .../tests/unit/sdk/dcaas/__init__.py | 0 .../tests/unit/sdk/dcaas/v2/test_proxy.py | 22 +++++++++ otcextensions/tests/unit/sdk/dds/__init__.py | 0 .../tests/unit/sdk/dds/v3/test_proxy.py | 22 +++++++++ otcextensions/tests/unit/sdk/dis/__init__.py | 0 .../tests/unit/sdk/dis/v2/test_proxy.py | 22 +++++++++ otcextensions/tests/unit/sdk/dws/__init__.py | 0 .../tests/unit/sdk/dws/v1/test_proxy.py | 22 +++++++++ otcextensions/tests/unit/sdk/lts/__init__.py | 0 .../tests/unit/sdk/lts/v2/test_proxy.py | 22 +++++++++ otcextensions/tests/unit/sdk/maas/__init__.py | 0 .../tests/unit/sdk/maas/v1/test_proxy.py | 22 +++++++++ otcextensions/tests/unit/sdk/mrs/__init__.py | 0 .../tests/unit/sdk/mrs/v1/test_proxy.py | 22 +++++++++ otcextensions/tests/unit/sdk/plas/__init__.py | 0 .../tests/unit/sdk/plas/v1/test_proxy.py | 22 +++++++++ otcextensions/tests/unit/sdk/sdrs/__init__.py | 0 .../tests/unit/sdk/sdrs/v1/__init__.py | 0 .../tests/unit/sdk/sdrs/v1/test_proxy.py | 22 +++++++++ otcextensions/tests/unit/sdk/smn/__init__.py | 0 .../tests/unit/sdk/smn/v2/__init__.py | 0 .../tests/unit/sdk/smn/v2/test_proxy.py | 22 +++++++++ otcextensions/tests/unit/sdk/waf/__init__.py | 0 .../tests/unit/sdk/waf/v1/test_proxy.py | 22 +++++++++ 112 files changed, 1071 insertions(+), 5 deletions(-) create mode 100644 otcextensions/sdk/ces/__init__.py create mode 100644 otcextensions/sdk/ces/ces_service.py create mode 100644 otcextensions/sdk/ces/v1/__init__.py create mode 100644 otcextensions/sdk/ces/v1/_proxy.py create mode 100644 otcextensions/sdk/dcaas/__init__.py create mode 100644 otcextensions/sdk/dcaas/dcaas_service.py create mode 100644 otcextensions/sdk/dcaas/v2/__init__.py create mode 100644 otcextensions/sdk/dcaas/v2/_proxy.py create mode 100644 otcextensions/sdk/dds/__init__.py create mode 100644 otcextensions/sdk/dds/dds_service.py create mode 100644 otcextensions/sdk/dds/v3/__init__.py create mode 100644 otcextensions/sdk/dds/v3/_proxy.py create mode 100644 otcextensions/sdk/dis/__init__.py create mode 100644 otcextensions/sdk/dis/dis_service.py create mode 100644 otcextensions/sdk/dis/v2/__init__.py create mode 100644 otcextensions/sdk/dis/v2/_proxy.py create mode 100644 otcextensions/sdk/dws/__init__.py create mode 100644 otcextensions/sdk/dws/dws_service.py create mode 100644 otcextensions/sdk/dws/v1/__init__.py create mode 100644 otcextensions/sdk/dws/v1/_proxy.py create mode 100644 otcextensions/sdk/lts/__init__.py create mode 100644 otcextensions/sdk/lts/lts_service.py create mode 100644 otcextensions/sdk/lts/v2/__init__.py create mode 100644 otcextensions/sdk/lts/v2/_proxy.py create mode 100644 otcextensions/sdk/maas/__init__.py create mode 100644 otcextensions/sdk/maas/maas_service.py create mode 100644 otcextensions/sdk/maas/v1/__init__.py create mode 100644 otcextensions/sdk/maas/v1/_proxy.py create mode 100644 otcextensions/sdk/mrs/__init__.py create mode 100644 otcextensions/sdk/mrs/mrs_service.py create mode 100644 otcextensions/sdk/mrs/v1/__init__.py create mode 100644 otcextensions/sdk/mrs/v1/_proxy.py create mode 100644 otcextensions/sdk/plas/__init__.py create mode 100644 otcextensions/sdk/plas/plas_service.py create mode 100644 otcextensions/sdk/plas/v1/__init__.py create mode 100644 otcextensions/sdk/plas/v1/_proxy.py create mode 100644 otcextensions/sdk/sdrs/__init__.py create mode 100644 otcextensions/sdk/sdrs/sdrs_service.py create mode 100644 otcextensions/sdk/sdrs/v1/__init__.py create mode 100644 otcextensions/sdk/sdrs/v1/_proxy.py create mode 100644 otcextensions/sdk/smn/__init__.py create mode 100644 otcextensions/sdk/smn/smn_service.py create mode 100644 otcextensions/sdk/smn/v2/__init__.py create mode 100644 otcextensions/sdk/smn/v2/_proxy.py create mode 100644 otcextensions/sdk/waf/__init__.py create mode 100644 otcextensions/sdk/waf/v1/__init__.py create mode 100644 otcextensions/sdk/waf/v1/_proxy.py create mode 100644 otcextensions/sdk/waf/waf_service.py create mode 100644 otcextensions/tests/functional/sdk/ces/__init__.py create mode 100644 otcextensions/tests/functional/sdk/ces/v1/__init__.py create mode 100644 otcextensions/tests/functional/sdk/ces/v1/test_service.py create mode 100644 otcextensions/tests/functional/sdk/dcaas/__init__.py create mode 100644 otcextensions/tests/functional/sdk/dcaas/v2/__init__.py create mode 100644 otcextensions/tests/functional/sdk/dcaas/v2/test_service.py create mode 100644 otcextensions/tests/functional/sdk/dds/__init__.py create mode 100644 otcextensions/tests/functional/sdk/dds/v3/__init__.py create mode 100644 otcextensions/tests/functional/sdk/dds/v3/test_service.py create mode 100644 otcextensions/tests/functional/sdk/dis/__init__.py create mode 100644 otcextensions/tests/functional/sdk/dis/v2/__init__.py create mode 100644 otcextensions/tests/functional/sdk/dis/v2/test_service.py create mode 100644 otcextensions/tests/functional/sdk/dws/__init__.py create mode 100644 otcextensions/tests/functional/sdk/dws/v1/__init__.py create mode 100644 otcextensions/tests/functional/sdk/dws/v1/test_service.py create mode 100644 otcextensions/tests/functional/sdk/lts/__init__.py create mode 100644 otcextensions/tests/functional/sdk/lts/v2/__init__.py create mode 100644 otcextensions/tests/functional/sdk/lts/v2/test_service.py create mode 100644 otcextensions/tests/functional/sdk/maas/__init__.py create mode 100644 otcextensions/tests/functional/sdk/maas/v1/__init__.py create mode 100644 otcextensions/tests/functional/sdk/maas/v1/test_service.py create mode 100644 otcextensions/tests/functional/sdk/mrs/__init__.py create mode 100644 otcextensions/tests/functional/sdk/mrs/v1/__init__.py create mode 100644 otcextensions/tests/functional/sdk/mrs/v1/test_service.py create mode 100644 otcextensions/tests/functional/sdk/plas/__init__.py create mode 100644 otcextensions/tests/functional/sdk/plas/v1/__init__.py create mode 100644 otcextensions/tests/functional/sdk/plas/v1/test_service.py create mode 100644 otcextensions/tests/functional/sdk/sdrs/__init__.py create mode 100644 otcextensions/tests/functional/sdk/sdrs/v1/__init__.py create mode 100644 otcextensions/tests/functional/sdk/sdrs/v1/test_service.py create mode 100644 otcextensions/tests/functional/sdk/smn/__init__.py create mode 100644 otcextensions/tests/functional/sdk/smn/v2/__init__.py create mode 100644 otcextensions/tests/functional/sdk/smn/v2/test_service.py create mode 100644 otcextensions/tests/functional/sdk/waf/__init__.py create mode 100644 otcextensions/tests/functional/sdk/waf/v1/__init__.py create mode 100644 otcextensions/tests/functional/sdk/waf/v1/test_service.py create mode 100644 otcextensions/tests/unit/sdk/ces/__init__.py create mode 100644 otcextensions/tests/unit/sdk/ces/v1/test_proxy.py create mode 100644 otcextensions/tests/unit/sdk/dcaas/__init__.py create mode 100644 otcextensions/tests/unit/sdk/dcaas/v2/test_proxy.py create mode 100644 otcextensions/tests/unit/sdk/dds/__init__.py create mode 100644 otcextensions/tests/unit/sdk/dds/v3/test_proxy.py create mode 100644 otcextensions/tests/unit/sdk/dis/__init__.py create mode 100644 otcextensions/tests/unit/sdk/dis/v2/test_proxy.py create mode 100644 otcextensions/tests/unit/sdk/dws/__init__.py create mode 100644 otcextensions/tests/unit/sdk/dws/v1/test_proxy.py create mode 100644 otcextensions/tests/unit/sdk/lts/__init__.py create mode 100644 otcextensions/tests/unit/sdk/lts/v2/test_proxy.py create mode 100644 otcextensions/tests/unit/sdk/maas/__init__.py create mode 100644 otcextensions/tests/unit/sdk/maas/v1/test_proxy.py create mode 100644 otcextensions/tests/unit/sdk/mrs/__init__.py create mode 100644 otcextensions/tests/unit/sdk/mrs/v1/test_proxy.py create mode 100644 otcextensions/tests/unit/sdk/plas/__init__.py create mode 100644 otcextensions/tests/unit/sdk/plas/v1/test_proxy.py create mode 100644 otcextensions/tests/unit/sdk/sdrs/__init__.py create mode 100644 otcextensions/tests/unit/sdk/sdrs/v1/__init__.py create mode 100644 otcextensions/tests/unit/sdk/sdrs/v1/test_proxy.py create mode 100644 otcextensions/tests/unit/sdk/smn/__init__.py create mode 100644 otcextensions/tests/unit/sdk/smn/v2/__init__.py create mode 100644 otcextensions/tests/unit/sdk/smn/v2/test_proxy.py create mode 100644 otcextensions/tests/unit/sdk/waf/__init__.py create mode 100644 otcextensions/tests/unit/sdk/waf/v1/test_proxy.py diff --git a/.stestr.blacklist.functional b/.stestr.blacklist.functional index aa3c7a5ed..310dd5cf6 100644 --- a/.stestr.blacklist.functional +++ b/.stestr.blacklist.functional @@ -4,5 +4,7 @@ otcextensions.tests.functional.osclient.volume_backup* otcextensions.tests.functional.sdk.cce.v1* otcextensions.tests.functional.sdk.kms* otcextensions.tests.functional.sdk.volume_backup* -otcextensions.tests.functional.sdk.volume_backup* otcextensions.tests.functional.sdk.deh* +otcextensions.tests.functional.sdk.dds* +otcextensions.tests.functional.sdk.plas* +otcextensions.tests.functional.sdk.lts* diff --git a/otcextensions/sdk/__init__.py b/otcextensions/sdk/__init__.py index 8de28244e..f9837b5b8 100644 --- a/otcextensions/sdk/__init__.py +++ b/otcextensions/sdk/__init__.py @@ -54,25 +54,35 @@ 'cce': { 'service_type': 'cce', 'endpoint_service_type': 'ccev2.0', - # 'append_project_id': False, + }, + 'ces': { + 'service_type': 'ces', + 'append_project_id': True, }, 'cts': { 'service_type': 'cts', - # 'append_project_id': True, }, 'css': { 'service_type': 'css', - # 'append_project_id': True, + }, + 'dcaas': { + 'service_type': 'dcaas', }, 'dcs': { 'service_type': 'dcs', - # 'endpoint_service_type': 'dms', 'append_project_id': True, }, + 'dds': { + 'service_type': 'dds', + }, 'deh': { 'service_type': 'deh', 'append_project_id': True, }, + 'dis': { + 'service_type': 'dis', + 'endpoint_service_type': 'disv2' + }, 'dms': { 'service_type': 'dms', 'endpoint_service_type': 'dms', @@ -82,6 +92,10 @@ 'service_type': 'dns', 'replace_system': True, }, + 'dws': { + 'service_type': 'dws', + 'endpoint_service_type': 'dwsv1' + }, 'ecs': { 'service_type': 'ecs', }, @@ -89,6 +103,16 @@ 'service_type': 'kms', 'append_project_id': True, }, + 'lts': { + 'service_type': 'lts' + }, + 'maas': { + 'service_type': 'maas', + 'append_project_id': True, + }, + 'mrs': { + 'service_type': 'mrs' + }, 'nat': { 'service_type': 'nat' }, @@ -98,17 +122,31 @@ 'endpoint_service_type': 'object', 'set_endpoint_override': True }, + 'plas': { + 'service_type': 'plas' + }, 'rds': { 'service_type': 'rds', # 'additional_headers': {'content-type': 'application/json'}, 'endpoint_service_type': 'rdsv3', 'append_project_id': True, }, + 'sdrs': { + 'service_type': 'sdrs' + }, + 'smn': { + 'service_type': 'smn', + 'append_project_id': True + }, 'volume_backup': { 'service_type': 'volume_backup', 'append_project_id': True, 'endpoint_service_type': 'vbs', }, + 'waf': { + 'service_type': 'waf', + 'append_project_id': True, + } } diff --git a/otcextensions/sdk/ces/__init__.py b/otcextensions/sdk/ces/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/ces/ces_service.py b/otcextensions/sdk/ces/ces_service.py new file mode 100644 index 000000000..be66c3cb7 --- /dev/null +++ b/otcextensions/sdk/ces/ces_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.ces.v1 import _proxy + + +class CesService(service_description.ServiceDescription): + """The CES service.""" + + supported_versions = { + '1': _proxy.Proxy + } diff --git a/otcextensions/sdk/ces/v1/__init__.py b/otcextensions/sdk/ces/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/ces/v1/_proxy.py b/otcextensions/sdk/ces/v1/_proxy.py new file mode 100644 index 000000000..38cfb42e8 --- /dev/null +++ b/otcextensions/sdk/ces/v1/_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/dcaas/__init__.py b/otcextensions/sdk/dcaas/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/dcaas/dcaas_service.py b/otcextensions/sdk/dcaas/dcaas_service.py new file mode 100644 index 000000000..60ce93343 --- /dev/null +++ b/otcextensions/sdk/dcaas/dcaas_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.dcaas.v2 import _proxy + + +class DcaasService(service_description.ServiceDescription): + """The Direct Connect service.""" + + supported_versions = { + '2': _proxy.Proxy + } diff --git a/otcextensions/sdk/dcaas/v2/__init__.py b/otcextensions/sdk/dcaas/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/dcaas/v2/_proxy.py b/otcextensions/sdk/dcaas/v2/_proxy.py new file mode 100644 index 000000000..38cfb42e8 --- /dev/null +++ b/otcextensions/sdk/dcaas/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/dds/__init__.py b/otcextensions/sdk/dds/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/dds/dds_service.py b/otcextensions/sdk/dds/dds_service.py new file mode 100644 index 000000000..705e4f5e8 --- /dev/null +++ b/otcextensions/sdk/dds/dds_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.dds.v3 import _proxy + + +class DdsService(service_description.ServiceDescription): + """The Document Database service.""" + + supported_versions = { + '3': _proxy.Proxy + } diff --git a/otcextensions/sdk/dds/v3/__init__.py b/otcextensions/sdk/dds/v3/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/dds/v3/_proxy.py b/otcextensions/sdk/dds/v3/_proxy.py new file mode 100644 index 000000000..38cfb42e8 --- /dev/null +++ b/otcextensions/sdk/dds/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/dis/__init__.py b/otcextensions/sdk/dis/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/dis/dis_service.py b/otcextensions/sdk/dis/dis_service.py new file mode 100644 index 000000000..42bc38280 --- /dev/null +++ b/otcextensions/sdk/dis/dis_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.dis.v2 import _proxy + + +class DisService(service_description.ServiceDescription): + """The DataIngestion service.""" + + supported_versions = { + '2': _proxy.Proxy + } diff --git a/otcextensions/sdk/dis/v2/__init__.py b/otcextensions/sdk/dis/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/dis/v2/_proxy.py b/otcextensions/sdk/dis/v2/_proxy.py new file mode 100644 index 000000000..38cfb42e8 --- /dev/null +++ b/otcextensions/sdk/dis/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/dws/__init__.py b/otcextensions/sdk/dws/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/dws/dws_service.py b/otcextensions/sdk/dws/dws_service.py new file mode 100644 index 000000000..0bab7e33e --- /dev/null +++ b/otcextensions/sdk/dws/dws_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.dws.v1 import _proxy + + +class DwsService(service_description.ServiceDescription): + """The DWS service.""" + + supported_versions = { + '1': _proxy.Proxy + } diff --git a/otcextensions/sdk/dws/v1/__init__.py b/otcextensions/sdk/dws/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/dws/v1/_proxy.py b/otcextensions/sdk/dws/v1/_proxy.py new file mode 100644 index 000000000..38cfb42e8 --- /dev/null +++ b/otcextensions/sdk/dws/v1/_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/lts/__init__.py b/otcextensions/sdk/lts/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/lts/lts_service.py b/otcextensions/sdk/lts/lts_service.py new file mode 100644 index 000000000..8f4a0eaf5 --- /dev/null +++ b/otcextensions/sdk/lts/lts_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.lts.v2 import _proxy + + +class LtsService(service_description.ServiceDescription): + """The LTS service.""" + + supported_versions = { + '2': _proxy.Proxy + } diff --git a/otcextensions/sdk/lts/v2/__init__.py b/otcextensions/sdk/lts/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/lts/v2/_proxy.py b/otcextensions/sdk/lts/v2/_proxy.py new file mode 100644 index 000000000..38cfb42e8 --- /dev/null +++ b/otcextensions/sdk/lts/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/maas/__init__.py b/otcextensions/sdk/maas/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/maas/maas_service.py b/otcextensions/sdk/maas/maas_service.py new file mode 100644 index 000000000..cf5d82dce --- /dev/null +++ b/otcextensions/sdk/maas/maas_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.maas.v1 import _proxy + + +class MaasService(service_description.ServiceDescription): + """The Maas service.""" + + supported_versions = { + '1': _proxy.Proxy + } diff --git a/otcextensions/sdk/maas/v1/__init__.py b/otcextensions/sdk/maas/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/maas/v1/_proxy.py b/otcextensions/sdk/maas/v1/_proxy.py new file mode 100644 index 000000000..38cfb42e8 --- /dev/null +++ b/otcextensions/sdk/maas/v1/_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/mrs/__init__.py b/otcextensions/sdk/mrs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/mrs/mrs_service.py b/otcextensions/sdk/mrs/mrs_service.py new file mode 100644 index 000000000..9fe68b1f2 --- /dev/null +++ b/otcextensions/sdk/mrs/mrs_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.mrs.v1 import _proxy + + +class MrsService(service_description.ServiceDescription): + """The MRS service.""" + + supported_versions = { + '1': _proxy.Proxy + } diff --git a/otcextensions/sdk/mrs/v1/__init__.py b/otcextensions/sdk/mrs/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/mrs/v1/_proxy.py b/otcextensions/sdk/mrs/v1/_proxy.py new file mode 100644 index 000000000..38cfb42e8 --- /dev/null +++ b/otcextensions/sdk/mrs/v1/_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/plas/__init__.py b/otcextensions/sdk/plas/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/plas/plas_service.py b/otcextensions/sdk/plas/plas_service.py new file mode 100644 index 000000000..1751c8592 --- /dev/null +++ b/otcextensions/sdk/plas/plas_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.plas.v1 import _proxy + + +class PlasService(service_description.ServiceDescription): + """The Plas service.""" + + supported_versions = { + '1': _proxy.Proxy + } diff --git a/otcextensions/sdk/plas/v1/__init__.py b/otcextensions/sdk/plas/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/plas/v1/_proxy.py b/otcextensions/sdk/plas/v1/_proxy.py new file mode 100644 index 000000000..38cfb42e8 --- /dev/null +++ b/otcextensions/sdk/plas/v1/_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/sdrs/__init__.py b/otcextensions/sdk/sdrs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/sdrs/sdrs_service.py b/otcextensions/sdk/sdrs/sdrs_service.py new file mode 100644 index 000000000..b7a46470f --- /dev/null +++ b/otcextensions/sdk/sdrs/sdrs_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.sdrs.v1 import _proxy + + +class SdrsService(service_description.ServiceDescription): + """The SDRS service.""" + + supported_versions = { + '1': _proxy.Proxy + } diff --git a/otcextensions/sdk/sdrs/v1/__init__.py b/otcextensions/sdk/sdrs/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/sdrs/v1/_proxy.py b/otcextensions/sdk/sdrs/v1/_proxy.py new file mode 100644 index 000000000..38cfb42e8 --- /dev/null +++ b/otcextensions/sdk/sdrs/v1/_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/smn/__init__.py b/otcextensions/sdk/smn/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/smn/smn_service.py b/otcextensions/sdk/smn/smn_service.py new file mode 100644 index 000000000..e22d78ba1 --- /dev/null +++ b/otcextensions/sdk/smn/smn_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.smn.v2 import _proxy + + +class SmnService(service_description.ServiceDescription): + """The SMN service.""" + + supported_versions = { + '2': _proxy.Proxy + } diff --git a/otcextensions/sdk/smn/v2/__init__.py b/otcextensions/sdk/smn/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/smn/v2/_proxy.py b/otcextensions/sdk/smn/v2/_proxy.py new file mode 100644 index 000000000..38cfb42e8 --- /dev/null +++ b/otcextensions/sdk/smn/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/waf/__init__.py b/otcextensions/sdk/waf/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/waf/v1/__init__.py b/otcextensions/sdk/waf/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/sdk/waf/v1/_proxy.py b/otcextensions/sdk/waf/v1/_proxy.py new file mode 100644 index 000000000..38cfb42e8 --- /dev/null +++ b/otcextensions/sdk/waf/v1/_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/waf/waf_service.py b/otcextensions/sdk/waf/waf_service.py new file mode 100644 index 000000000..c14a38c5b --- /dev/null +++ b/otcextensions/sdk/waf/waf_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.waf.v1 import _proxy + + +class WafService(service_description.ServiceDescription): + """The WAF service.""" + + supported_versions = { + '1': _proxy.Proxy + } diff --git a/otcextensions/tests/functional/sdk/ces/__init__.py b/otcextensions/tests/functional/sdk/ces/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/ces/v1/__init__.py b/otcextensions/tests/functional/sdk/ces/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/ces/v1/test_service.py b/otcextensions/tests/functional/sdk/ces/v1/test_service.py new file mode 100644 index 000000000..da202c48f --- /dev/null +++ b/otcextensions/tests/functional/sdk/ces/v1/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.ces + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/functional/sdk/dcaas/__init__.py b/otcextensions/tests/functional/sdk/dcaas/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/dcaas/v2/__init__.py b/otcextensions/tests/functional/sdk/dcaas/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/dcaas/v2/test_service.py b/otcextensions/tests/functional/sdk/dcaas/v2/test_service.py new file mode 100644 index 000000000..75a894429 --- /dev/null +++ b/otcextensions/tests/functional/sdk/dcaas/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.dcaas + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/functional/sdk/dds/__init__.py b/otcextensions/tests/functional/sdk/dds/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/dds/v3/__init__.py b/otcextensions/tests/functional/sdk/dds/v3/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/dds/v3/test_service.py b/otcextensions/tests/functional/sdk/dds/v3/test_service.py new file mode 100644 index 000000000..64582f8bc --- /dev/null +++ b/otcextensions/tests/functional/sdk/dds/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.dds + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/functional/sdk/dis/__init__.py b/otcextensions/tests/functional/sdk/dis/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/dis/v2/__init__.py b/otcextensions/tests/functional/sdk/dis/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/dis/v2/test_service.py b/otcextensions/tests/functional/sdk/dis/v2/test_service.py new file mode 100644 index 000000000..8f45af436 --- /dev/null +++ b/otcextensions/tests/functional/sdk/dis/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.dis + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/functional/sdk/dws/__init__.py b/otcextensions/tests/functional/sdk/dws/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/dws/v1/__init__.py b/otcextensions/tests/functional/sdk/dws/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/dws/v1/test_service.py b/otcextensions/tests/functional/sdk/dws/v1/test_service.py new file mode 100644 index 000000000..b1fb436a4 --- /dev/null +++ b/otcextensions/tests/functional/sdk/dws/v1/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.dws + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/functional/sdk/lts/__init__.py b/otcextensions/tests/functional/sdk/lts/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/lts/v2/__init__.py b/otcextensions/tests/functional/sdk/lts/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/lts/v2/test_service.py b/otcextensions/tests/functional/sdk/lts/v2/test_service.py new file mode 100644 index 000000000..53baed79f --- /dev/null +++ b/otcextensions/tests/functional/sdk/lts/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.lts + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/functional/sdk/maas/__init__.py b/otcextensions/tests/functional/sdk/maas/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/maas/v1/__init__.py b/otcextensions/tests/functional/sdk/maas/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/maas/v1/test_service.py b/otcextensions/tests/functional/sdk/maas/v1/test_service.py new file mode 100644 index 000000000..68ca38110 --- /dev/null +++ b/otcextensions/tests/functional/sdk/maas/v1/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.maas + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/functional/sdk/mrs/__init__.py b/otcextensions/tests/functional/sdk/mrs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/mrs/v1/__init__.py b/otcextensions/tests/functional/sdk/mrs/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/mrs/v1/test_service.py b/otcextensions/tests/functional/sdk/mrs/v1/test_service.py new file mode 100644 index 000000000..f7341ad92 --- /dev/null +++ b/otcextensions/tests/functional/sdk/mrs/v1/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.mrs + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/functional/sdk/plas/__init__.py b/otcextensions/tests/functional/sdk/plas/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/plas/v1/__init__.py b/otcextensions/tests/functional/sdk/plas/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/plas/v1/test_service.py b/otcextensions/tests/functional/sdk/plas/v1/test_service.py new file mode 100644 index 000000000..2ba54ee62 --- /dev/null +++ b/otcextensions/tests/functional/sdk/plas/v1/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.plas + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/functional/sdk/sdrs/__init__.py b/otcextensions/tests/functional/sdk/sdrs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/sdrs/v1/__init__.py b/otcextensions/tests/functional/sdk/sdrs/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/sdrs/v1/test_service.py b/otcextensions/tests/functional/sdk/sdrs/v1/test_service.py new file mode 100644 index 000000000..6c3bf8888 --- /dev/null +++ b/otcextensions/tests/functional/sdk/sdrs/v1/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.sdrs + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/functional/sdk/smn/__init__.py b/otcextensions/tests/functional/sdk/smn/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/smn/v2/__init__.py b/otcextensions/tests/functional/sdk/smn/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/smn/v2/test_service.py b/otcextensions/tests/functional/sdk/smn/v2/test_service.py new file mode 100644 index 000000000..d23f55d67 --- /dev/null +++ b/otcextensions/tests/functional/sdk/smn/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.smn + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/functional/sdk/waf/__init__.py b/otcextensions/tests/functional/sdk/waf/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/waf/v1/__init__.py b/otcextensions/tests/functional/sdk/waf/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/waf/v1/test_service.py b/otcextensions/tests/functional/sdk/waf/v1/test_service.py new file mode 100644 index 000000000..5f786670f --- /dev/null +++ b/otcextensions/tests/functional/sdk/waf/v1/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.waf + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/unit/sdk/ces/__init__.py b/otcextensions/tests/unit/sdk/ces/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/ces/v1/test_proxy.py b/otcextensions/tests/unit/sdk/ces/v1/test_proxy.py new file mode 100644 index 000000000..55f837575 --- /dev/null +++ b/otcextensions/tests/unit/sdk/ces/v1/test_proxy.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 otcextensions.sdk.ces.v1 import _proxy + +from openstack.tests.unit import test_proxy_base + + +class TestCESProxy(test_proxy_base.TestProxyBase): + + def setUp(self): + super(TestCESProxy, self).setUp() + self.proxy = _proxy.Proxy(self.session) diff --git a/otcextensions/tests/unit/sdk/dcaas/__init__.py b/otcextensions/tests/unit/sdk/dcaas/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/dcaas/v2/test_proxy.py b/otcextensions/tests/unit/sdk/dcaas/v2/test_proxy.py new file mode 100644 index 000000000..1b43e9114 --- /dev/null +++ b/otcextensions/tests/unit/sdk/dcaas/v2/test_proxy.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 otcextensions.sdk.dcaas.v1 import _proxy + +from openstack.tests.unit import test_proxy_base + + +class TestDcaasProxy(test_proxy_base.TestProxyBase): + + def setUp(self): + super(TestDcaasProxy, self).setUp() + self.proxy = _proxy.Proxy(self.session) diff --git a/otcextensions/tests/unit/sdk/dds/__init__.py b/otcextensions/tests/unit/sdk/dds/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/dds/v3/test_proxy.py b/otcextensions/tests/unit/sdk/dds/v3/test_proxy.py new file mode 100644 index 000000000..61e000f29 --- /dev/null +++ b/otcextensions/tests/unit/sdk/dds/v3/test_proxy.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 otcextensions.sdk.dds.v3 import _proxy + +from openstack.tests.unit import test_proxy_base + + +class TestDdsProxy(test_proxy_base.TestProxyBase): + + def setUp(self): + super(TestDdsProxy, self).setUp() + self.proxy = _proxy.Proxy(self.session) diff --git a/otcextensions/tests/unit/sdk/dis/__init__.py b/otcextensions/tests/unit/sdk/dis/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/dis/v2/test_proxy.py b/otcextensions/tests/unit/sdk/dis/v2/test_proxy.py new file mode 100644 index 000000000..4525778f7 --- /dev/null +++ b/otcextensions/tests/unit/sdk/dis/v2/test_proxy.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 otcextensions.sdk.dis.v2 import _proxy + +from openstack.tests.unit import test_proxy_base + + +class TestDisProxy(test_proxy_base.TestProxyBase): + + def setUp(self): + super(TestDisProxy, self).setUp() + self.proxy = _proxy.Proxy(self.session) diff --git a/otcextensions/tests/unit/sdk/dws/__init__.py b/otcextensions/tests/unit/sdk/dws/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/dws/v1/test_proxy.py b/otcextensions/tests/unit/sdk/dws/v1/test_proxy.py new file mode 100644 index 000000000..96425bf07 --- /dev/null +++ b/otcextensions/tests/unit/sdk/dws/v1/test_proxy.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 otcextensions.sdk.dws.v1 import _proxy + +from openstack.tests.unit import test_proxy_base + + +class TestDwsProxy(test_proxy_base.TestProxyBase): + + def setUp(self): + super(TestDwsProxy, self).setUp() + self.proxy = _proxy.Proxy(self.session) diff --git a/otcextensions/tests/unit/sdk/lts/__init__.py b/otcextensions/tests/unit/sdk/lts/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/lts/v2/test_proxy.py b/otcextensions/tests/unit/sdk/lts/v2/test_proxy.py new file mode 100644 index 000000000..fcd7e827f --- /dev/null +++ b/otcextensions/tests/unit/sdk/lts/v2/test_proxy.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 otcextensions.sdk.lts.v2 import _proxy + +from openstack.tests.unit import test_proxy_base + + +class TestLtsProxy(test_proxy_base.TestProxyBase): + + def setUp(self): + super(TestLtsProxy, self).setUp() + self.proxy = _proxy.Proxy(self.session) diff --git a/otcextensions/tests/unit/sdk/maas/__init__.py b/otcextensions/tests/unit/sdk/maas/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/maas/v1/test_proxy.py b/otcextensions/tests/unit/sdk/maas/v1/test_proxy.py new file mode 100644 index 000000000..886d9e379 --- /dev/null +++ b/otcextensions/tests/unit/sdk/maas/v1/test_proxy.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 otcextensions.sdk.maas.v1 import _proxy + +from openstack.tests.unit import test_proxy_base + + +class TestMaasProxy(test_proxy_base.TestProxyBase): + + def setUp(self): + super(TestMaasProxy, self).setUp() + self.proxy = _proxy.Proxy(self.session) diff --git a/otcextensions/tests/unit/sdk/mrs/__init__.py b/otcextensions/tests/unit/sdk/mrs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/mrs/v1/test_proxy.py b/otcextensions/tests/unit/sdk/mrs/v1/test_proxy.py new file mode 100644 index 000000000..9ac53bcbc --- /dev/null +++ b/otcextensions/tests/unit/sdk/mrs/v1/test_proxy.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 otcextensions.sdk.mrs.v1 import _proxy + +from openstack.tests.unit import test_proxy_base + + +class TestMrsProxy(test_proxy_base.TestProxyBase): + + def setUp(self): + super(TestMrsProxy, self).setUp() + self.proxy = _proxy.Proxy(self.session) diff --git a/otcextensions/tests/unit/sdk/plas/__init__.py b/otcextensions/tests/unit/sdk/plas/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/plas/v1/test_proxy.py b/otcextensions/tests/unit/sdk/plas/v1/test_proxy.py new file mode 100644 index 000000000..4f11602d8 --- /dev/null +++ b/otcextensions/tests/unit/sdk/plas/v1/test_proxy.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 otcextensions.sdk.plas.v1 import _proxy + +from openstack.tests.unit import test_proxy_base + + +class TestPlasProxy(test_proxy_base.TestProxyBase): + + def setUp(self): + super(TestPlasProxy, self).setUp() + self.proxy = _proxy.Proxy(self.session) diff --git a/otcextensions/tests/unit/sdk/sdrs/__init__.py b/otcextensions/tests/unit/sdk/sdrs/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/sdrs/v1/__init__.py b/otcextensions/tests/unit/sdk/sdrs/v1/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/sdrs/v1/test_proxy.py b/otcextensions/tests/unit/sdk/sdrs/v1/test_proxy.py new file mode 100644 index 000000000..07c6831c6 --- /dev/null +++ b/otcextensions/tests/unit/sdk/sdrs/v1/test_proxy.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 otcextensions.sdk.sdrs.v1 import _proxy + +from openstack.tests.unit import test_proxy_base + + +class TestSdrsProxy(test_proxy_base.TestProxyBase): + + def setUp(self): + super(TestSdrsProxy, self).setUp() + self.proxy = _proxy.Proxy(self.session) diff --git a/otcextensions/tests/unit/sdk/smn/__init__.py b/otcextensions/tests/unit/sdk/smn/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/smn/v2/__init__.py b/otcextensions/tests/unit/sdk/smn/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/smn/v2/test_proxy.py b/otcextensions/tests/unit/sdk/smn/v2/test_proxy.py new file mode 100644 index 000000000..6ef714555 --- /dev/null +++ b/otcextensions/tests/unit/sdk/smn/v2/test_proxy.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 otcextensions.sdk.smn.v2 import _proxy + +from openstack.tests.unit import test_proxy_base + + +class TestSmnProxy(test_proxy_base.TestProxyBase): + + def setUp(self): + super(TestSmnProxy, self).setUp() + self.proxy = _proxy.Proxy(self.session) diff --git a/otcextensions/tests/unit/sdk/waf/__init__.py b/otcextensions/tests/unit/sdk/waf/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/sdk/waf/v1/test_proxy.py b/otcextensions/tests/unit/sdk/waf/v1/test_proxy.py new file mode 100644 index 000000000..28344e342 --- /dev/null +++ b/otcextensions/tests/unit/sdk/waf/v1/test_proxy.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 otcextensions.sdk.waf.v1 import _proxy + +from openstack.tests.unit import test_proxy_base + + +class TestWafProxy(test_proxy_base.TestProxyBase): + + def setUp(self): + super(TestWafProxy, self).setUp() + self.proxy = _proxy.Proxy(self.session) From d9cce0f74851e513996f1f4e494cd9d0ad6bf9c9 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Tue, 14 Apr 2020 11:11:21 +0200 Subject: [PATCH 26/58] Fix docs to be buildable by Sphinx 3.0.0 --- doc/source/sdk/proxies/anti_ddos.rst | 20 ++++------ doc/source/sdk/proxies/auto_scaling.rst | 47 +++++++----------------- doc/source/sdk/proxies/cce_v1.rst | 17 +++------ doc/source/sdk/proxies/cce_v3.rst | 20 ++++------ doc/source/sdk/proxies/cts.rst | 11 ++---- doc/source/sdk/proxies/dcs.rst | 35 ++++++------------ doc/source/sdk/proxies/deh.rst | 12 ++---- doc/source/sdk/proxies/dms.rst | 18 +++------ doc/source/sdk/proxies/dns.rst | 30 +++++---------- doc/source/sdk/proxies/kms.rst | 27 ++++---------- doc/source/sdk/proxies/obs.rst | 15 ++------ doc/source/sdk/proxies/rds_v1.rst | 31 +++++----------- doc/source/sdk/proxies/rds_v3.rst | 46 ++++++++--------------- doc/source/sdk/proxies/volume_backup.rst | 16 +++----- 14 files changed, 109 insertions(+), 236 deletions(-) diff --git a/doc/source/sdk/proxies/anti_ddos.rst b/doc/source/sdk/proxies/anti_ddos.rst index 348e08a7b..e6ba15dbc 100644 --- a/doc/source/sdk/proxies/anti_ddos.rst +++ b/doc/source/sdk/proxies/anti_ddos.rst @@ -15,21 +15,15 @@ Floating IP Operations ^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.anti_ddos.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.anti_ddos.v1._proxy.Proxy.floating_ips - .. automethod:: otcextensions.sdk.anti_ddos.v1._proxy.Proxy.protect_floating_ip - .. automethod:: otcextensions.sdk.anti_ddos.v1._proxy.Proxy.unprotect_floating_ip - .. automethod:: otcextensions.sdk.anti_ddos.v1._proxy.Proxy.get_floating_ip_policies - .. automethod:: otcextensions.sdk.anti_ddos.v1._proxy.Proxy.update_floating_ip_policies - .. automethod:: otcextensions.sdk.anti_ddos.v1._proxy.Proxy.get_floating_ip_status - .. automethod:: otcextensions.sdk.anti_ddos.v1._proxy.Proxy.floating_ip_events - .. automethod:: otcextensions.sdk.anti_ddos.v1._proxy.Proxy.floating_ip_stat_day - .. automethod:: otcextensions.sdk.anti_ddos.v1._proxy.Proxy.floating_ip_stat_week - .. automethod:: otcextensions.sdk.anti_ddos.v1._proxy.Proxy.update_floating_ip_policies + :noindex: + :members: floating_ips, protect_floating_ip, unprotect_floating_ip, + get_floating_ip_policies, update_floating_ip_policies, + get_floating_ip_status, floating_ip_events, floating_ip_stat_day, + floating_ip_stat_week Misc Operations ^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.anti_ddos.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.anti_ddos.v1._proxy.Proxy.configs + :noindex: + :members: configs diff --git a/doc/source/sdk/proxies/auto_scaling.rst b/doc/source/sdk/proxies/auto_scaling.rst index b8f29f1e1..cc94209f0 100644 --- a/doc/source/sdk/proxies/auto_scaling.rst +++ b/doc/source/sdk/proxies/auto_scaling.rst @@ -18,57 +18,38 @@ Group Operations ^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.groups - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.get_group - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.find_group - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.create_group - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.delete_group - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.resume_group - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.pause_group - + :noindex: + :members: groups, get_group, find_group, create_group, delete_group, + resume_group, pause_group Config Operations ^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.configs - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.get_config - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.find_config - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.create_config - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.delete_config - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.batch_delete_configs + :noindex: + :members: configs, get_config, find_config, create_config, delete_config, + batch_delete_configs Policy Operations ^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.policies - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.get_policy - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.find_policy - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.create_policy - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.delete_policy - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.update_policy - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.resume_policy - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.pause_policy - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.execute_policy + :noindex: + :members: policies, get_policy, find_policy, create_policy, + delete_policy, update_policy, resume_policy, + pause_policy, execute_policy Instance Operations ^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.instances - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.remove_instance - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.batch_instance_action + :noindex: + :members: instances, remove_instance, batch_instance_action Actions and Quotas ^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.activities - .. automethod:: otcextensions.sdk.auto_scaling.v1._proxy.Proxy.quotas + :noindex: + :members: activities, quotas diff --git a/doc/source/sdk/proxies/cce_v1.rst b/doc/source/sdk/proxies/cce_v1.rst index 26299e89d..684a8bc6e 100644 --- a/doc/source/sdk/proxies/cce_v1.rst +++ b/doc/source/sdk/proxies/cce_v1.rst @@ -15,20 +15,13 @@ Cluster Operations ^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.cce.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.cce.v1._proxy.Proxy.clusters - .. automethod:: otcextensions.sdk.cce.v1._proxy.Proxy.get_cluster - .. automethod:: otcextensions.sdk.cce.v1._proxy.Proxy.find_cluster - .. automethod:: otcextensions.sdk.cce.v1._proxy.Proxy.delete_cluster - + :noindex: + :members: clusters, get_cluster, find_cluster, delete_cluster Cluster Nodes Operations ^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.cce.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.cce.v1._proxy.Proxy.cluster_nodes - .. automethod:: otcextensions.sdk.cce.v1._proxy.Proxy.get_cluster_node - .. automethod:: otcextensions.sdk.cce.v1._proxy.Proxy.find_cluster_node - .. automethod:: otcextensions.sdk.cce.v1._proxy.Proxy.delete_cluster_nodes - .. automethod:: otcextensions.sdk.cce.v1._proxy.Proxy.add_node + :noindex: + :members: cluster_nodes, get_cluster_node, find_cluster_node, + delete_cluster_nodes, add_node diff --git a/doc/source/sdk/proxies/cce_v3.rst b/doc/source/sdk/proxies/cce_v3.rst index 816b4bfca..f8f1f5740 100644 --- a/doc/source/sdk/proxies/cce_v3.rst +++ b/doc/source/sdk/proxies/cce_v3.rst @@ -15,26 +15,20 @@ Cluster Operations ^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.cce.v3._proxy.Proxy - - .. automethod:: otcextensions.sdk.cce.v3._proxy.Proxy.clusters - .. automethod:: otcextensions.sdk.cce.v3._proxy.Proxy.get_cluster - .. automethod:: otcextensions.sdk.cce.v3._proxy.Proxy.find_cluster - .. automethod:: otcextensions.sdk.cce.v3._proxy.Proxy.delete_cluster + :members: clusters, get_cluster, find_cluster, delete_cluster Cluster Nodes Operations ^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.cce.v3._proxy.Proxy - - .. automethod:: otcextensions.sdk.cce.v3._proxy.Proxy.cluster_nodes - .. automethod:: otcextensions.sdk.cce.v3._proxy.Proxy.get_cluster_node - .. automethod:: otcextensions.sdk.cce.v3._proxy.Proxy.find_cluster_node - .. automethod:: otcextensions.sdk.cce.v3._proxy.Proxy.delete_cluster_node - .. automethod:: otcextensions.sdk.cce.v3._proxy.Proxy.create_cluster_node + :noindex: + :members: cluster_nodes, get_cluster_node, find_cluster_node, + delete_cluster_node, create_cluster_node Job Operations ^^^^^^^^^^^^^^ - .. automethod:: otcextensions.sdk.cce.v3._proxy.Proxy.get_job - .. automethod:: otcextensions.sdk.cce.v3._proxy.Proxy.wait_for_job +.. autoclass:: otcextensions.sdk.cce.v3._proxy.Proxy + :noindex: + :members: get_job, wait_for_job diff --git a/doc/source/sdk/proxies/cts.rst b/doc/source/sdk/proxies/cts.rst index 4d4683ad1..7148a9ca2 100644 --- a/doc/source/sdk/proxies/cts.rst +++ b/doc/source/sdk/proxies/cts.rst @@ -15,15 +15,12 @@ Trace Operations ^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.cts.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.cts.v1._proxy.Proxy.traces + :noindex: + :members: traces Trackers Operations ^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.cts.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.cts.v1._proxy.Proxy.get_tracker - .. automethod:: otcextensions.sdk.cts.v1._proxy.Proxy.create_tracker - .. automethod:: otcextensions.sdk.cts.v1._proxy.Proxy.update_tracker - .. automethod:: otcextensions.sdk.cts.v1._proxy.Proxy.delete_tracker + :noindex: + :members: get_tracker, create_tracker, update_tracker, delete_tracker diff --git a/doc/source/sdk/proxies/dcs.rst b/doc/source/sdk/proxies/dcs.rst index ae9e40e1e..6291b03fe 100644 --- a/doc/source/sdk/proxies/dcs.rst +++ b/doc/source/sdk/proxies/dcs.rst @@ -15,42 +15,29 @@ Instance Operations ^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.dcs.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.instances - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.create_instance - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.get_instance - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.find_instance - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.delete_instance - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.update_instance - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.extend_instance - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.start_instance - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.restart_instance - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.stop_instance - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.stop_instance - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.stop_instance + :noindex: + :members: instances, get_instance, find_instance, create_instance, + delete_instance, update_instance, extend_instance, + start_instance, restart_instance, stop_instance Statistics Operations ^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.dcs.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.statistics + :noindex: + :members: statistics Backup Operations ^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.dcs.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.backup_instance - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.backups - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.delete_instance_backup - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.restore_instance - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.restore_records + :noindex: + :members: backups, backup_instance, delete_instance_backup, + restore_instance, restore_records Instance Configuration Operations ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.dcs.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.instance_params - .. automethod:: otcextensions.sdk.dcs.v1._proxy.Proxy.update_instance_params + :noindex: + :members: instance_params, update_instance_params diff --git a/doc/source/sdk/proxies/deh.rst b/doc/source/sdk/proxies/deh.rst index 47c0a9c57..593a51cae 100644 --- a/doc/source/sdk/proxies/deh.rst +++ b/doc/source/sdk/proxies/deh.rst @@ -15,12 +15,6 @@ Host Operations ^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.deh.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.deh.v1._proxy.Proxy.hosts - .. automethod:: otcextensions.sdk.deh.v1._proxy.Proxy.create_host - .. automethod:: otcextensions.sdk.deh.v1._proxy.Proxy.get_host - .. automethod:: otcextensions.sdk.deh.v1._proxy.Proxy.find_host - .. automethod:: otcextensions.sdk.deh.v1._proxy.Proxy.delete_host - .. automethod:: otcextensions.sdk.deh.v1._proxy.Proxy.update_host - .. automethod:: otcextensions.sdk.deh.v1._proxy.Proxy.servers - .. automethod:: otcextensions.sdk.deh.v1._proxy.Proxy.host_types + :noindex: + :members: hosts, get_host, find_host, create_host, + update_host, delete_host, servers, host_types diff --git a/doc/source/sdk/proxies/dms.rst b/doc/source/sdk/proxies/dms.rst index 741876687..b9ca1bac2 100644 --- a/doc/source/sdk/proxies/dms.rst +++ b/doc/source/sdk/proxies/dms.rst @@ -15,25 +15,19 @@ Queue Operations ^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.dms.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.dms.v1._proxy.Proxy.queues - .. automethod:: otcextensions.sdk.dms.v1._proxy.Proxy.create_queue - .. automethod:: otcextensions.sdk.dms.v1._proxy.Proxy.get_queue - .. automethod:: otcextensions.sdk.dms.v1._proxy.Proxy.delete_queue - + :noindex: + :members: queues, create_queue, get_queue, delete_queue Message Group Operations ^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.dms.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.dms.v1._proxy.Proxy.groups - .. automethod:: otcextensions.sdk.dms.v1._proxy.Proxy.create_group - .. automethod:: otcextensions.sdk.dms.v1._proxy.Proxy.delete_group + :noindex: + :members: groups, create_group, delete_group DMS Quota Operations ^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.dms.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.dms.v1._proxy.Proxy.quotas + :noindex: + :members: quotas diff --git a/doc/source/sdk/proxies/dns.rst b/doc/source/sdk/proxies/dns.rst index c724f935f..87aabf1ec 100644 --- a/doc/source/sdk/proxies/dns.rst +++ b/doc/source/sdk/proxies/dns.rst @@ -15,35 +15,23 @@ Zone Operations ^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.dns.v2._proxy.Proxy - - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.zones - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.create_zone - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.get_zone - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.delete_zone - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.update_zone - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.find_zone - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.add_router_to_zone - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.remove_router_from_zone - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.nameservers + :noindex: + :members: zones, create_zone, get_zone, delete_zone, + update_zone, find_zone, add_router_to_zone, + remove_router_from_zone, nameservers Recordset Operations ^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.dns.v2._proxy.Proxy - - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.recordsets - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.create_recordset - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.get_recordset - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.update_recordset - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.delete_recordset + :noindex: + :members: recordsets, create_recordset, get_recordset, update_recordset, + delete_recordset PTR Records Operations ^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.dns.v2._proxy.Proxy - - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.floating_ips - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.set_floating_ip - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.get_floating_ip - .. automethod:: otcextensions.sdk.dns.v2._proxy.Proxy.unset_floating_ip + :noindex: + :members: floating_ips, set_floating_ip, get_floating_ip, unset_floating_ip diff --git a/doc/source/sdk/proxies/kms.rst b/doc/source/sdk/proxies/kms.rst index f5c9f81a4..9cb575143 100644 --- a/doc/source/sdk/proxies/kms.rst +++ b/doc/source/sdk/proxies/kms.rst @@ -15,32 +15,21 @@ CMK (Customer Master Key) Operations ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.kms.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.keys - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.create_key - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.get_key - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.find_key - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.enable_key - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.disable_key - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.schedule_key_deletion - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.cancel_key_deletion - + :noindex: + :members: keys, get_key, find_key, create_key, enable_key, disable_key, + schedule_key_deletion, cancel_key_deletion DEK (Data Encryption Key) Operations ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.kms.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.create_datakey - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.create_datakey_wo_plain - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.encrypt_datakey - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.decrypt_datakey + :noindex: + :members: create_datakey, create_datakey_wo_plain, encrypt_datakey, + decrypt_datakey Other Operations ^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.kms.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.generate_random - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.get_instance_number - .. automethod:: otcextensions.sdk.kms.v1._proxy.Proxy.quotas + :noindex: + :members: generate_random, get_instance_number, quotas diff --git a/doc/source/sdk/proxies/obs.rst b/doc/source/sdk/proxies/obs.rst index 218c15806..f26725843 100644 --- a/doc/source/sdk/proxies/obs.rst +++ b/doc/source/sdk/proxies/obs.rst @@ -17,19 +17,12 @@ Container Operations ^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.obs.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.obs.v1._proxy.Proxy.containers - .. automethod:: otcextensions.sdk.obs.v1._proxy.Proxy.get_container - .. automethod:: otcextensions.sdk.obs.v1._proxy.Proxy.create_container - .. automethod:: otcextensions.sdk.obs.v1._proxy.Proxy.delete_container + :noindex: + :members: containers, get_container, create_container, delete_container Object Operations ^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.obs.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.obs.v1._proxy.Proxy.objects - .. automethod:: otcextensions.sdk.obs.v1._proxy.Proxy.get_object - .. automethod:: otcextensions.sdk.obs.v1._proxy.Proxy.create_object - .. automethod:: otcextensions.sdk.obs.v1._proxy.Proxy.delete_object - .. automethod:: otcextensions.sdk.obs.v1._proxy.Proxy.download_object + :noindex: + :members: objects, get_object, create_object, delete_object, download_object diff --git a/doc/source/sdk/proxies/rds_v1.rst b/doc/source/sdk/proxies/rds_v1.rst index 76559f583..ade0d9116 100644 --- a/doc/source/sdk/proxies/rds_v1.rst +++ b/doc/source/sdk/proxies/rds_v1.rst @@ -17,39 +17,28 @@ Datastore Operations ^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.rds.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.datastore_versions - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.get_datastore_version - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.datastore_types + :noindex: + :members: datastore_versions, get_datastore_version, datastore_types Flavor Operations ^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.rds.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.get_flavor - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.flavors + :noindex: + :members: flavors, get_flavor Instance Operations ^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.rds.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.create_instance - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.update_instance - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.delete_instance - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.get_instance - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.find_instance - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.instances - + :noindex: + :members: instances, get_instance, find_instance, + create_instance, delete_instance, update_instance Backup Operations ^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.rds.v1._proxy.Proxy - - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.backups - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.create_backup - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.delete_backup - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.get_backup_policy - .. automethod:: otcextensions.sdk.rds.v1._proxy.Proxy.set_backup_policy + :noindex: + :members: backups, create_backup, delete_backup, + get_backup_policy, set_backup_policy diff --git a/doc/source/sdk/proxies/rds_v3.rst b/doc/source/sdk/proxies/rds_v3.rst index b75b39e44..e88e3dd7e 100644 --- a/doc/source/sdk/proxies/rds_v3.rst +++ b/doc/source/sdk/proxies/rds_v3.rst @@ -17,53 +17,39 @@ Datastore Operations ^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.rds.v3._proxy.Proxy - - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.datastore_types - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.datastores + :noindex: + :members: datastores, datastore_types Flavor Operations ^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.rds.v3._proxy.Proxy - - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.flavors + :noindex: + :members: flavors Instance Operations ^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.rds.v3._proxy.Proxy - - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.create_instance - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.delete_instance - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.get_instance - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.find_instance - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.instances - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.restore_instance - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.get_instance_restore_time + :noindex: + :members: instances, get_instance, find_instance, + create_instance, delete_instance, restore_instance, + get_instance_restore_time Backup Operations ^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.rds.v3._proxy.Proxy - - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.backups - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.create_backup - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.delete_backup - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.find_backup - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.backup_download_links - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.get_instance_backup_policy - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.set_instance_backup_policy - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.wait_for_backup + :noindex: + :members: backups, find_backup, create_backup, delete_backup, + backup_download_links, get_instance_backup_policy, + set_instance_backup_policy, wait_for_backup Configuration Operations ^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.rds.v3._proxy.Proxy - - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.configurations - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.get_configuration - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.find_configuration - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.create_configuration - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.delete_configuration - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.update_configuration - .. automethod:: otcextensions.sdk.rds.v3._proxy.Proxy.apply_configuration + :noindex: + :members: configurations, get_configuration, find_configuration, + create_configuration, delete_configuration, update_configuration, + apply_configuration diff --git a/doc/source/sdk/proxies/volume_backup.rst b/doc/source/sdk/proxies/volume_backup.rst index 4540a70a0..cb97a9cdf 100644 --- a/doc/source/sdk/proxies/volume_backup.rst +++ b/doc/source/sdk/proxies/volume_backup.rst @@ -23,14 +23,8 @@ Backup Policy Operations ^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.volume_backup.v2._proxy.Proxy - - .. automethod:: otcextensions.sdk.volume_backup.v2._proxy.Proxy.backup_policies - .. automethod:: otcextensions.sdk.volume_backup.v2._proxy.Proxy.create_backup_policy - .. automethod:: otcextensions.sdk.volume_backup.v2._proxy.Proxy.update_backup_policy - .. automethod:: otcextensions.sdk.volume_backup.v2._proxy.Proxy.delete_backup_policy - .. automethod:: otcextensions.sdk.volume_backup.v2._proxy.Proxy.find_backup_policy - .. automethod:: otcextensions.sdk.volume_backup.v2._proxy.Proxy.execute_policy - .. automethod:: otcextensions.sdk.volume_backup.v2._proxy.Proxy.enable_policy - .. automethod:: otcextensions.sdk.volume_backup.v2._proxy.Proxy.disable_policy - .. automethod:: otcextensions.sdk.volume_backup.v2._proxy.Proxy.link_resources_to_policy - .. automethod:: otcextensions.sdk.volume_backup.v2._proxy.Proxy.unlink_resources_of_policy + :noindex: + :members: backup_policies, find_backup_policy, create_backup_policy, + update_backup_policy, delete_backup_policy, execute_policy, + enable_policy, disable_policy, link_resources_to_policy, + unlink_resources_of_policy From de4f3d0240325ca2d8839ab0bad4f290a704785b Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Tue, 14 Apr 2020 12:23:02 +0200 Subject: [PATCH 27/58] fix pep error --- doc/source/sdk/proxies/dns.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/sdk/proxies/dns.rst b/doc/source/sdk/proxies/dns.rst index 87aabf1ec..4f1fea557 100644 --- a/doc/source/sdk/proxies/dns.rst +++ b/doc/source/sdk/proxies/dns.rst @@ -25,7 +25,7 @@ Recordset Operations .. autoclass:: otcextensions.sdk.dns.v2._proxy.Proxy :noindex: - :members: recordsets, create_recordset, get_recordset, update_recordset, + :members: recordsets, create_recordset, get_recordset, update_recordset, delete_recordset From 1ec684b4e42b3e90f7d511dbfd775917229c85c0 Mon Sep 17 00:00:00 2001 From: Vineet Pruthi <48789821+vineet-pruthi@users.noreply.github.com> Date: Tue, 14 Apr 2020 19:14:19 +0800 Subject: [PATCH 28/58] Improve NAT-GW (#65) * initial nat gateway branche * added snat and dnat resource * dnat and snat proxy functions added * first running state * gateway fixed * linting corrections * Minor changes, tested successfully * unittest nat.test_snat nat.test_dnat and nat.test_gateway added * nat changes * pep8 issues * test_proxy.py added for NAT * stash status changed and proxy test added * Adding osclient code for nat * Adding osclient code for nat * Fixed error and adding unit tests for osclient * Fixed error and adding unit tests for osclient * Minor fix in unit test * Minor fix in unit test * Adding functional tests for nat_gateway * Adding functional tests for nat_gateway * Adding some more functional tests for nat * Updated documentation for NAT * Fixed nat.rst erros * initial nat gateway branche * added snat and dnat resource * first running state * gateway fixed * linting corrections * Minor changes, tested successfully * nat changes * Updated Functional Tests * Usage of project_id in list nat functions query params * Updated nat_gateway_id as keyword arg * remove python2 dependancy from tox * Updated args for show delete and update for NAT * Updated travis.yml to skip py27 and include py37 * Fixed unit tests with updated args * roll back py27 in tox.ini * Fixed errors and remove nat documentation" * Removed print * initial nat gateway branche * Adding osclient code for nat * Adding osclient code for nat * Fixed error and adding unit tests for osclient * Fixed error and adding unit tests for osclient * Minor fix in unit test * Adding functional tests for nat_gateway * Adding some more functional tests for nat * Updated documentation for NAT * Fixed nat.rst erros * Updated Functional Tests * Usage of project_id in list nat functions query params * Updated nat_gateway_id as keyword arg * remove python2 dependancy from tox * Fixed unit tests with updated args * roll back py27 in tox.ini * Fixed errors and remove nat documentation" * Removed print * Checkout origin/master otcextensions/sdk/__init__.py * Formatting Fixes and raise error if nat gateway not found * Fixed osclient Unit Tests for nat * Fixed docstring for nat fakes.py * Updated osclient functional tests for nat * Fixes in Functional Tests * Updated Line breaks for help * Added multiple delete support * Fixed resource cleanup issue * checkout doc/source/cli/index.rst with origin/master * Adding NAT doc * Minor correction * Updated functional Tests * fix for newer Sphinx * do not append project_id in the nat service Co-authored-by: T. Schreiber Co-authored-by: Artem Goncharov --- .travis.yml | 2 + doc/source/sdk/proxies/index.rst | 3 +- doc/source/sdk/proxies/nat.rst | 34 ++ doc/source/sdk/resources/index.rst | 1 + doc/source/sdk/resources/nat/index.rst | 9 + doc/source/sdk/resources/nat/v2/dnat.rst | 13 + doc/source/sdk/resources/nat/v2/gateway.rst | 13 + doc/source/sdk/resources/nat/v2/snat.rst | 13 + otcextensions/osclient/nat/__init__.py | 0 otcextensions/osclient/nat/client.py | 53 +++ otcextensions/osclient/nat/v2/__init__.py | 0 otcextensions/osclient/nat/v2/dnat.py | 297 +++++++++++++ otcextensions/osclient/nat/v2/gateway.py | 308 ++++++++++++++ otcextensions/osclient/nat/v2/snat.py | 276 +++++++++++++ otcextensions/sdk/__init__.py | 2 +- otcextensions/sdk/nat/v2/_proxy.py | 15 + otcextensions/sdk/nat/v2/dnat.py | 137 +++--- otcextensions/sdk/nat/v2/gateway.py | 2 +- otcextensions/sdk/nat/v2/snat.py | 124 +++--- .../tests/functional/osclient/nat/__init__.py | 0 .../functional/osclient/nat/v2/__init__.py | 0 .../functional/osclient/nat/v2/common.py | 165 ++++++++ .../functional/osclient/nat/v2/test_dnat.py | 80 ++++ .../osclient/nat/v2/test_gateway.py | 103 +++++ .../functional/osclient/nat/v2/test_snat.py | 79 ++++ .../tests/functional/sdk/nat/__init__.py | 0 .../tests/functional/sdk/nat/v2/__init__.py | 0 .../tests/functional/sdk/nat/v2/test_dnat.py | 48 +++ .../functional/sdk/nat/v2/test_gateway.py | 44 ++ .../functional/sdk/nat/v2/test_service.py | 24 ++ .../tests/functional/sdk/nat/v2/test_snat.py | 46 +++ .../tests/unit/osclient/nat/__init__.py | 0 .../tests/unit/osclient/nat/v2/__init__.py | 0 .../tests/unit/osclient/nat/v2/fakes.py | 128 ++++++ .../tests/unit/osclient/nat/v2/test_dnat.py | 375 +++++++++++++++++ .../unit/osclient/nat/v2/test_gateway.py | 389 ++++++++++++++++++ .../tests/unit/osclient/nat/v2/test_snat.py | 359 ++++++++++++++++ .../tests/unit/sdk/nat/v2/__init__.py | 0 setup.cfg | 16 + 39 files changed, 3024 insertions(+), 134 deletions(-) create mode 100644 doc/source/sdk/proxies/nat.rst create mode 100644 doc/source/sdk/resources/nat/index.rst create mode 100644 doc/source/sdk/resources/nat/v2/dnat.rst create mode 100644 doc/source/sdk/resources/nat/v2/gateway.rst create mode 100644 doc/source/sdk/resources/nat/v2/snat.rst create mode 100644 otcextensions/osclient/nat/__init__.py create mode 100644 otcextensions/osclient/nat/client.py create mode 100644 otcextensions/osclient/nat/v2/__init__.py create mode 100644 otcextensions/osclient/nat/v2/dnat.py create mode 100644 otcextensions/osclient/nat/v2/gateway.py create mode 100644 otcextensions/osclient/nat/v2/snat.py create mode 100644 otcextensions/tests/functional/osclient/nat/__init__.py create mode 100644 otcextensions/tests/functional/osclient/nat/v2/__init__.py create mode 100644 otcextensions/tests/functional/osclient/nat/v2/common.py create mode 100644 otcextensions/tests/functional/osclient/nat/v2/test_dnat.py create mode 100644 otcextensions/tests/functional/osclient/nat/v2/test_gateway.py create mode 100644 otcextensions/tests/functional/osclient/nat/v2/test_snat.py create mode 100644 otcextensions/tests/functional/sdk/nat/__init__.py create mode 100644 otcextensions/tests/functional/sdk/nat/v2/__init__.py create mode 100644 otcextensions/tests/functional/sdk/nat/v2/test_dnat.py create mode 100644 otcextensions/tests/functional/sdk/nat/v2/test_gateway.py create mode 100644 otcextensions/tests/functional/sdk/nat/v2/test_service.py create mode 100644 otcextensions/tests/functional/sdk/nat/v2/test_snat.py create mode 100644 otcextensions/tests/unit/osclient/nat/__init__.py create mode 100644 otcextensions/tests/unit/osclient/nat/v2/__init__.py create mode 100644 otcextensions/tests/unit/osclient/nat/v2/fakes.py create mode 100644 otcextensions/tests/unit/osclient/nat/v2/test_dnat.py create mode 100644 otcextensions/tests/unit/osclient/nat/v2/test_gateway.py create mode 100644 otcextensions/tests/unit/osclient/nat/v2/test_snat.py create mode 100644 otcextensions/tests/unit/sdk/nat/v2/__init__.py diff --git a/.travis.yml b/.travis.yml index 0cfad8233..2e6a49ecd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,8 @@ matrix: include: - python: 3.6 env: TOXENV=py36 + - python: 3.7 + env: TOXENV=py37 - python: 3.6 env: TOXENV=pep8 install: pip install tox diff --git a/doc/source/sdk/proxies/index.rst b/doc/source/sdk/proxies/index.rst index e83847d81..c5f6a8d11 100644 --- a/doc/source/sdk/proxies/index.rst +++ b/doc/source/sdk/proxies/index.rst @@ -14,10 +14,11 @@ Service Proxies Distributed Message Service (DMS) Domain Name Server Service (DNS) Key Management Service (KMS) + Network Address Translation (NAT) Object Block Storage (OBS) - Volume Backup Service (VBS) Relational Database Service RDS V1 (RDSv1) Relational Database Service RDS V3 (RDS) + Volume Backup Service (VBS) .. _service-proxies: diff --git a/doc/source/sdk/proxies/nat.rst b/doc/source/sdk/proxies/nat.rst new file mode 100644 index 000000000..824b1d0b5 --- /dev/null +++ b/doc/source/sdk/proxies/nat.rst @@ -0,0 +1,34 @@ +NAT API +======= + +.. automodule:: otcextensions.sdk.nat.v2._proxy + +The Network Address Translation Class +------------------------------------- + +The nat high-level interface is available through the ``nat`` +member of a :class:`~openstack.connection.Connection` object. The +``nat`` member will only be added if the +``otcextensions.sdk.register_otc_extensions(conn)`` method is called. + +Gateway Operations +^^^^^^^^^^^^^^^^^^ + +.. autoclass:: otcextensions.sdk.nat.v2._proxy.Proxy + :noindex: + :members: gateways, find_gateway, + create_gateway, update_gateway, delete_gateway + +SNAT Rule Operations +^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: otcextensions.sdk.nat.v2._proxy.Proxy + :noindex: + :members: snat_rules, get_snat_rule, create_snat_rule, delete_snat_rule + +DNAT Rule Operations +^^^^^^^^^^^^^^^^^^^^ + +.. autoclass:: otcextensions.sdk.nat.v2._proxy.Proxy + :noindex: + :members: dnat_rules, get_dnat_rule, create_dnat_rule, delete_dnat_rule diff --git a/doc/source/sdk/resources/index.rst b/doc/source/sdk/resources/index.rst index 8987ad415..a8fb45e4b 100644 --- a/doc/source/sdk/resources/index.rst +++ b/doc/source/sdk/resources/index.rst @@ -16,6 +16,7 @@ Open Telekom Cloud Resources Distributed Message Service (DMS) Domain Name Service (DNS) Key Management Service (KMS) + Network Address Translation (NAT) Object Block Storage (OBS) Relational Database Service (RDS) diff --git a/doc/source/sdk/resources/nat/index.rst b/doc/source/sdk/resources/nat/index.rst new file mode 100644 index 000000000..712e949da --- /dev/null +++ b/doc/source/sdk/resources/nat/index.rst @@ -0,0 +1,9 @@ +NAT Resources +============= + +.. toctree:: + :maxdepth: 1 + + v2/gateway + v2/snat + v2/dnat diff --git a/doc/source/sdk/resources/nat/v2/dnat.rst b/doc/source/sdk/resources/nat/v2/dnat.rst new file mode 100644 index 000000000..8fcb3cf4f --- /dev/null +++ b/doc/source/sdk/resources/nat/v2/dnat.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.nat.v2.dnat +============================= + +.. automodule:: otcextensions.sdk.nat.v2.dnat + +The DNAT Rule Class +-------------------- + +The ``Dnat`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.nat.v2.dnat.Dnat + :members: diff --git a/doc/source/sdk/resources/nat/v2/gateway.rst b/doc/source/sdk/resources/nat/v2/gateway.rst new file mode 100644 index 000000000..1fea7908d --- /dev/null +++ b/doc/source/sdk/resources/nat/v2/gateway.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.nat.v2.gateway +================================ + +.. automodule:: otcextensions.sdk.nat.v2.gateway + +The NAT Gateway Class +---------------------- + +The ``Gateway`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.nat.v2.gateway.Gateway + :members: diff --git a/doc/source/sdk/resources/nat/v2/snat.rst b/doc/source/sdk/resources/nat/v2/snat.rst new file mode 100644 index 000000000..6dd62e650 --- /dev/null +++ b/doc/source/sdk/resources/nat/v2/snat.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.nat.v2.snat +============================= + +.. automodule:: otcextensions.sdk.nat.v2.snat + +The SNAT Rule Class +-------------------- + +The ``Snat`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.nat.v2.snat.Snat + :members: diff --git a/otcextensions/osclient/nat/__init__.py b/otcextensions/osclient/nat/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/osclient/nat/client.py b/otcextensions/osclient/nat/client.py new file mode 100644 index 000000000..110ddff6f --- /dev/null +++ b/otcextensions/osclient/nat/client.py @@ -0,0 +1,53 @@ +# 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 logging + +from osc_lib import utils + +from otcextensions import sdk +from otcextensions.i18n import _ + +LOG = logging.getLogger(__name__) + +DEFAULT_API_VERSION = '2' +API_VERSION_OPTION = 'os_nat_api_version' +API_NAME = "nat" +API_VERSIONS = { + "2": "openstack.connection.Connection" +} + + +def make_client(instance): + """Returns a rds proxy""" + + conn = instance.sdk_connection + + if getattr(conn, 'nat', None) is None: + LOG.debug('OTC extensions are not registered. Do that now') + sdk.register_otc_extensions(conn) + + LOG.debug('NAT client initialized using OpenStack OTC SDK: %s', + conn.nat) + return conn.nat + + +def build_option_parser(parser): + """Hook to add global options""" + parser.add_argument( + '--os-nat-api-version', + metavar='', + default=utils.env('OS_NAT_API_VERSION'), + help=_("NAT API version, default=%s " + "(Env: OS_NAT_API_VERSION)") % DEFAULT_API_VERSION + ) + return parser diff --git a/otcextensions/osclient/nat/v2/__init__.py b/otcextensions/osclient/nat/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/osclient/nat/v2/dnat.py b/otcextensions/osclient/nat/v2/dnat.py new file mode 100644 index 000000000..d241a650f --- /dev/null +++ b/otcextensions/osclient/nat/v2/dnat.py @@ -0,0 +1,297 @@ +# 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. +# +"""DNAT v2 action implementations""" +import logging + +from osc_lib import utils +from osc_lib import exceptions +from osc_lib.command import command + +from otcextensions.i18n import _ +from otcextensions.common import sdk_utils + +LOG = logging.getLogger(__name__) + + +def _get_columns(item): + column_map = { + } + return sdk_utils.get_osc_show_columns_for_sdk_resource(item, column_map) + + +class ListDnatRules(command.Lister): + + _description = _("List DNAT Rules.") + columns = ( + 'Id', + 'Nat Gateway Id', + 'Port Id', + 'Private IP', + 'Floating Ip Address', + 'Protocol', + 'Status' + ) + + def get_parser(self, prog_name): + parser = super(ListDnatRules, self).get_parser(prog_name) + + parser.add_argument( + '--id', + metavar='', + help=_("Specifies the ID of the SNAT rule."), + ) + parser.add_argument( + '--limit', + metavar='', + type=int, + help=_("Limit to fetch number of records."), + ) + parser.add_argument( + '--project-id', + metavar='', + help=_("Specifies the project ID."), + ) + parser.add_argument( + '--nat-gateway-id', + metavar='', + help=_("Specifies the NAT gateway ID."), + ) + parser.add_argument( + '--port-id', + metavar='', + help=_("Specifies the port ID of an ECS or a BMS."), + ) + parser.add_argument( + '--private-ip', + metavar='', + help=_("Specifies the private IP address, for example, " + "the IP address of a Direct Connect connection."), + ) + parser.add_argument( + '--internal-service-port', + metavar='', + help=_("Specifies port used by ECSs or BMSs to provide " + "services for external systems."), + ) + parser.add_argument( + '--floating-ip-id', + metavar='', + help=_("Specifies the Floating IP ID."), + ) + parser.add_argument( + '--floating-ip-address', + metavar='', + help=_("Specifies the Floating IP."), + ) + parser.add_argument( + '--external-service-port', + metavar='', + help=_("Specifies the port for providing external services."), + ) + parser.add_argument( + '--protocol', + metavar='', + help=_("Specifies the protocol type." + "Currently, TCP, UDP, and ANY are supported."), + ) + parser.add_argument( + '--status', + metavar='', + help=_("Specifies the status of the DNAT rule.\n" + "ACTIVE: The resource status is normal.\n" + "PENDING_CREATE: The resource is being created.\n" + "PENDING_UPDATE: The resource is being updated.\n" + "PENDING_DELETE: The resource is being deleted.\n" + "EIP_FREEZED: The EIP of the resource is frozen.\n" + "INACTIVE: The resource status is abnormal."), + ) + parser.add_argument( + '--admin-state-up', + metavar='', + help=_("Specifies whether the DNAT rule is enabled or " + "disabled. The value can be:\n" + "true: The DNAT rule is enabled.\n" + "false: The DNAT rule is disabled."), + ) + parser.add_argument( + '--created-at', + metavar='', + help=_("Specifies when the DNAT rule is created (UTC time). " + "Its value rounds to 6 decimal places forseconds. " + "The format is yyyy-mm-ddhh:mm:ss."), + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.nat + args_list = [ + 'id', + 'limit', + 'project_id', + 'nat_gateway_id', + 'port_id', + 'private_ip', + 'internal_service_port', + 'floating_ip_id', + 'floating_ip_address', + 'external_service_port', + 'protocol', + 'status', + 'admin_state_up', + 'created_at' + ] + attrs = {} + for arg in args_list: + val = getattr(parsed_args, arg) + if val: + attrs[arg] = val + data = client.dnat_rules(**attrs) + + return ( + self.columns, + (utils.get_item_properties( + s, + self.columns, + ) for s in data) + ) + + +class ShowDnatRule(command.ShowOne): + _description = _("Show Dnat Rule details") + + def get_parser(self, prog_name): + parser = super(ShowDnatRule, self).get_parser(prog_name) + parser.add_argument( + 'dnat', + metavar='', + help=_("Specifies the ID of the SNAT Rule"), + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.nat + obj = client.get_dnat_rule(parsed_args.dnat) + + display_columns, columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns) + + return (display_columns, data) + + +class CreateDnatRule(command.ShowOne): + _description = _("Create new DNAT Rule") + + def get_parser(self, prog_name): + parser = super(CreateDnatRule, self).get_parser(prog_name) + parser.add_argument( + '--nat-gateway-id', + metavar='', + required=True, + help=_("Specifies the ID of the NAT Gateway."), + ) + parser.add_argument( + '--port-id', + metavar='', + help=_("Specifies the port ID of an ECS or a BMS."), + ) + parser.add_argument( + '--private-ip', + metavar='', + help=_("Specifies the private IP address, for example, " + "the IP address of a Direct Connect connection."), + ) + parser.add_argument( + '--internal-service-port', + metavar='', + required=True, + help=_("Specifies port used by ECSs or BMSs to provide " + "services for external systems."), + ) + parser.add_argument( + '--floating-ip-id', + metavar="", + required=True, + help=_("Specifies the Floating IP ID. Multiple " + "Floating IPs are separated using commas."), + ) + parser.add_argument( + '--external-service-port', + metavar='', + required=True, + help=_("Specifies the port for providing external services."), + ) + parser.add_argument( + '--protocol', + metavar='', + required=True, + help=_("Specifies the protocol type."), + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.nat + + args_list = [ + 'nat_gateway_id', + 'port_id', + 'private_ip', + 'internal_service_port', + 'floating_ip_id', + 'external_service_port', + 'protocol' + ] + attrs = {} + for arg in args_list: + val = getattr(parsed_args, arg) + if val: + attrs[arg] = val + + obj = client.create_dnat_rule(**attrs) + + display_columns, columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns) + + return (display_columns, data) + + +class DeleteDnatRule(command.Command): + + _description = _("Deletes Dnat Rule(s).") + + def get_parser(self, prog_name): + parser = super(DeleteDnatRule, self).get_parser(prog_name) + parser.add_argument( + 'dnat', + metavar='', + nargs='+', + help=_("Specifies the DNAT Rule(s) ID(s) to delete."), + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.nat + result = 0 + for dnat in parsed_args.dnat: + try: + obj = client.get_dnat_rule(dnat) + client.delete_dnat_rule(obj.id) + except Exception as e: + result += 1 + LOG.error(_("Failed to delete DNAT rule with " + "ID '%(dnat)s': %(e)s"), + {'dnat': dnat, 'e': e}) + if result > 0: + total = len(parsed_args.dnat) + msg = (_("%(result)s of %(total)s DNAT Rule(s) failed " + "to delete.") % {'result': result, 'total': total}) + raise exceptions.CommandError(msg) diff --git a/otcextensions/osclient/nat/v2/gateway.py b/otcextensions/osclient/nat/v2/gateway.py new file mode 100644 index 000000000..37f34be56 --- /dev/null +++ b/otcextensions/osclient/nat/v2/gateway.py @@ -0,0 +1,308 @@ +# 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. +# +"""NAT Gateway v2 action implementations""" +import logging + +from osc_lib import utils +from osc_lib import exceptions +from osc_lib.command import command + +from otcextensions.i18n import _ +from otcextensions.common import sdk_utils + +LOG = logging.getLogger(__name__) + + +def _get_columns(item): + column_map = { + } + return sdk_utils.get_osc_show_columns_for_sdk_resource(item, column_map) + + +class ListNatGateways(command.Lister): + + _description = _("List Nat Gateway.") + columns = ('Id', 'Name', 'Spec', 'Router Id', 'Status') + + def get_parser(self, prog_name): + parser = super(ListNatGateways, self).get_parser(prog_name) + + parser.add_argument( + '--id', + metavar='', + help=_("Specifies the ID of the NAT Gateway."), + ) + parser.add_argument( + '--limit', + metavar='', + type=int, + help=_("Limit to fetch number of records."), + ) + parser.add_argument( + '--project-id', + metavar='', + help=_("Specifies the project ID."), + ) + parser.add_argument( + '--name', + metavar='', + help=_("Specifies the Name of the NAT Gateway."), + ) + parser.add_argument( + '--spec', + metavar='', + help=_("Specifies the type of the NAT Gateway. " + "The value of spec can be:\n" + "1: small type, which supports up to 10,000 " + "SNAT connections.\n" + "2: medium type, which supports up to 50,000 " + "SNAT connections.\n" + "3: large type, which supports up to 200,000 " + "SNAT connections.\n" + "4: extra-large type, which supports up to " + "1,000,000 SNAT connections."), + ) + parser.add_argument( + '--router-id', + metavar='', + help=_("Specifies the router ID."), + ) + parser.add_argument( + '--internal-network-id', + metavar='', + help=_("Specifies the network ID of the downstream " + "interface (the next hop of the DVR) of the " + "NAT Gateway."), + ) + parser.add_argument( + '--status', + metavar='', + help=_("Specifies the status of the NAT Gateway.\n" + "ACTIVE: The resource status is normal.\n" + "PENDING_CREATE: The resource is being created.\n" + "PENDING_UPDATE: The resource is being updated.\n" + "PENDING_DELETE: The resource is being deleted.\n" + "EIP_FREEZED: The EIP of the resource is frozen.\n" + "INACTIVE: The resource status is abnormal."), + ) + parser.add_argument( + '--admin-state-up', + metavar='', + help=_("Specifies whether the NAT Gateway is enabled " + "or disabled. The value can be:\n" + "true: The NAT gateway is up.\n" + "false: The NAT gateway is down."), + ) + parser.add_argument( + '--created-at', + metavar='', + help=_("Specifies when the NAT Gateway is created (UTC time). " + "Its valuerounds to 6 decimal places forseconds. " + "The format is yyyy-mm-ddhh:mm:ss."), + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.nat + args_list = [ + 'id', + 'limit', + 'project_id', + 'name', + 'spec', + 'router_id', + 'internal_network_id', + 'status', + 'admin_state_up', + 'created_at'] + attrs = {} + for arg in args_list: + val = getattr(parsed_args, arg) + if val: + attrs[arg] = val + + data = client.gateways(**attrs) + + return (self.columns, (utils.get_item_properties(s, self.columns) + for s in data)) + + +class ShowNatGateway(command.ShowOne): + _description = _("Show NAT Gateway details") + + def get_parser(self, prog_name): + parser = super(ShowNatGateway, self).get_parser(prog_name) + parser.add_argument( + 'gateway', + metavar='', + help=_("Specifies the Name or ID of the NAT Gateway."), + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.nat + obj = client.find_gateway(parsed_args.gateway) + + display_columns, columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns) + + return (display_columns, data) + + +class CreateNatGateway(command.ShowOne): + _description = _("Create new NAT Gateway") + + def get_parser(self, prog_name): + parser = super(CreateNatGateway, self).get_parser(prog_name) + parser.add_argument( + 'name', + metavar='', + help=_("Specifies the name of the NAT Gateway."), + ) + parser.add_argument( + '--description', + metavar='', + help=_("Provides supplementary information about " + "the NAT Gateway."), + ) + parser.add_argument( + '--spec', + metavar='', + required=True, + help=_( + "Specifies the type of the NAT Gateway. " + "The value can be:\n" + "1: small type, which supports up to 10,000 " + "SNAT connections.\n" + "2: medium type, which supports up to 50,000 " + "SNAT connections.\n" + "3: large type, which supports up to 200,000 " + "SNAT connections.\n" + "4: extra-large type, which supports up to " + "1,000,000 SNAT connections."), + ) + parser.add_argument( + '--router-id', + metavar='', + required=True, + help=_("Specifies the VPC ID."), + ) + parser.add_argument( + '--internal-network-id', + metavar='', + required=True, + help=_("Specifies the network ID of the downstream interface " + "(the next hop of the DVR) of the NAT Gateway."), + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.nat + + args_list = [ + 'name', + 'description', + 'spec', + 'router_id', + 'internal_network_id'] + attrs = {} + for arg in args_list: + val = getattr(parsed_args, arg) + if val: + attrs[arg] = val + + obj = client.create_gateway(**attrs) + + display_columns, columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns) + + return (display_columns, data) + + +class UpdateNatGateway(command.ShowOne): + _description = _("Update a NAT Gateway.") + + def get_parser(self, prog_name): + parser = super(UpdateNatGateway, self).get_parser(prog_name) + parser.add_argument( + 'gateway', + metavar='', + help=_("Specifies the Name or ID of the NAT Gateway."), + ) + parser.add_argument( + '--name', + metavar='', + help=_("Specifies the name of the NAT Gateway."), + ) + parser.add_argument( + '--description', + metavar='', + help=_("Provides supplementary informationabout the NAT gateway."), + ) + parser.add_argument( + '--spec', + metavar='', + help=_("Specifies the type of the NAT Gateway."), + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.nat + args_list = [ + 'name', 'description', 'spec' + ] + attrs = {} + for arg in args_list: + if getattr(parsed_args, arg): + attrs[arg] = getattr(parsed_args, arg) + nat_gateway = client.find_gateway(parsed_args.gateway) + + obj = client.update_gateway(nat_gateway.id, **attrs) + + display_columns, columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns) + + return (display_columns, data) + + +class DeleteNatGateway(command.Command): + + _description = _("Deletes NAT Gateway.") + + def get_parser(self, prog_name): + parser = super(DeleteNatGateway, self).get_parser(prog_name) + parser.add_argument( + 'gateway', + metavar='', + nargs='+', + help=_("Nat Gateway(s) to delete (Name or ID)"), + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.nat + result = 0 + for gateway in parsed_args.gateway: + try: + obj = client.find_gateway(gateway) + client.delete_gateway(obj.id) + except Exception as e: + result += 1 + LOG.error(_("Failed to delete Nat Gateway with " + "name or ID '%(gateway)s': %(e)s"), + {'gateway': gateway, 'e': e}) + if result > 0: + total = len(parsed_args.gateway) + msg = (_("%(result)s of %(total)s NAT Gateway(s) failed " + "to delete.") % {'result': result, 'total': total}) + raise exceptions.CommandError(msg) diff --git a/otcextensions/osclient/nat/v2/snat.py b/otcextensions/osclient/nat/v2/snat.py new file mode 100644 index 000000000..4dc54cabe --- /dev/null +++ b/otcextensions/osclient/nat/v2/snat.py @@ -0,0 +1,276 @@ +# 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. +# +"""SNAT v2 action implementations""" +import logging + +from osc_lib import utils +from osc_lib import exceptions +from osc_lib.command import command + +from otcextensions.i18n import _ +from otcextensions.common import sdk_utils + +LOG = logging.getLogger(__name__) + + +def _get_columns(item): + column_map = { + } + return sdk_utils.get_osc_show_columns_for_sdk_resource(item, column_map) + + +class ListSnatRules(command.Lister): + + _description = _("List SNAT Rules.") + columns = ( + 'Id', + 'Nat Gateway Id', + 'Network Id', + 'Cidr', + 'Floating Ip Address', + 'Status' + ) + + def get_parser(self, prog_name): + parser = super(ListSnatRules, self).get_parser(prog_name) + + parser.add_argument( + '--id', + metavar='', + help=_("Specifies the ID of the SNAT rule."), + ) + parser.add_argument( + '--limit', + metavar='', + type=int, + help=_("Limit to fetch number of records."), + ) + parser.add_argument( + '--project-id', + metavar='', + help=_("Specifies the project ID."), + ) + parser.add_argument( + '--nat-gateway-id', + metavar='', + help=_("Specifies the NAT gateway ID."), + ) + parser.add_argument( + '--network-id', + metavar='', + help=_("Specifies the network ID used by the SNAT rule."), + ) + parser.add_argument( + '--cidr', + metavar='', + help=_("Specifies a subset of the VPC subnet CIDR block or " + "a CIDR block of Direct Connect connection."), + ) + parser.add_argument( + '--source-type', + metavar='', + help=_("Specifies Source Type."), + ) + parser.add_argument( + '--floating-ip-id', + metavar='', + help=_("Specifies the Floating IP ID."), + ) + parser.add_argument( + '--floating-ip-address', + metavar='', + help=_("Specifies the Floating IP."), + ) + parser.add_argument( + '--status', + metavar='', + help=_("Specifies the status of the SNAT rule.\n" + "ACTIVE: The resource status is normal.\n" + "PENDING_CREATE: The resource is being created.\n" + "PENDING_UPDATE: The resource is being updated.\n" + "PENDING_DELETE: The resource is being deleted.\n" + "EIP_FREEZED: The EIP of the resource is frozen.\n" + "INACTIVE: The resource status is abnormal."), + ) + parser.add_argument( + '--admin-state-up', + metavar='', + help=_("Specifies whether the SNAT rule is enabled or " + "disabled. The value can be:\n" + "true: The SNAT rule is enabled.\n" + "false: The SNAT rule is disabled."), + ) + parser.add_argument( + '--created-at', + metavar='', + help=_("Specifies when the SNAT rule is created (UTC time). " + "Its value rounds to 6 decimal places for seconds. " + "The format is yyyy-mm-ddhh:mm:ss."), + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.nat + args_list = [ + 'id', + 'limit', + 'network_id', + 'project_id', + 'nat_gateway_id', + 'network_id', + 'cidr', + 'source_type', + 'floating_ip_id', + 'floating_ip_address', + 'status', + 'admin_state_up', + 'created_at'] + attrs = {} + for arg in args_list: + val = getattr(parsed_args, arg) + if val: + attrs[arg] = val + + data = client.snat_rules(**attrs) + + return ( + self.columns, + (utils.get_item_properties( + s, + self.columns, + ) for s in data) + ) + + +class ShowSnatRule(command.ShowOne): + _description = _("Show Snat Rule details") + + def get_parser(self, prog_name): + parser = super(ShowSnatRule, self).get_parser(prog_name) + parser.add_argument( + 'snat', + metavar='', + help=_("Specifies the ID of the SNAT Rule."), + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.nat + obj = client.get_snat_rule(parsed_args.snat) + + display_columns, columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns) + + return (display_columns, data) + + +class CreateSnatRule(command.ShowOne): + _description = _("Create new SNAT Rule") + + def get_parser(self, prog_name): + parser = super(CreateSnatRule, self).get_parser(prog_name) + parser.add_argument( + '--nat-gateway-id', + required=True, + metavar='', + help=_("Specifies the ID of the NAT gateway."), + ) + parser.add_argument( + '--floating-ip-id', + metavar='', + required=True, + help=_("Specifies the Floating IP ID. Multiple " + "Floating IPs are separated using commas."), + ) + parser.add_argument( + '--network-id', + metavar='', + help=_("Specifies the network ID used by the SNAT rule. " + "This parameter and cidr are alternative."), + ) + parser.add_argument( + '--cidr', + metavar='', + help=_("Specifies CIDR, which can be in the format of a " + "network segment or a host IP address."), + ) + parser.add_argument( + '--source-type', + metavar='', + help=_( + "Specifies the source type.\n" + "0: Either network_id or cidr can be " + "specified in a VPC.\n" + "1: Only cidr can be specified over a " + "Direct Connect connection.\n" + "If no value is entered, the default " + "value 0 (VPC) is used."), + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.nat + + args_list = [ + 'nat_gateway_id', + 'floating_ip_id', + 'network_id', + 'cidr', + 'source_type' + ] + attrs = {} + for arg in args_list: + val = getattr(parsed_args, arg) + if val: + attrs[arg] = val + + obj = client.create_snat_rule(**attrs) + + display_columns, columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns) + + return (display_columns, data) + + +class DeleteSnatRule(command.Command): + + _description = _("Deletes Snat Rule(s).") + + def get_parser(self, prog_name): + parser = super(DeleteSnatRule, self).get_parser(prog_name) + parser.add_argument( + 'snat', + metavar='', + nargs='+', + help=_("Specifies the SNAT rule(s) ID(s) to delete."), + ) + + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.nat + result = 0 + for snat in parsed_args.snat: + try: + obj = client.get_snat_rule(snat) + client.delete_snat_rule(obj.id) + except Exception as e: + result += 1 + LOG.error(_("Failed to delete SNAT rule with " + "ID '%(snat)s': %(e)s"), + {'snat': snat, 'e': e}) + if result > 0: + total = len(parsed_args.snat) + msg = (_("%(result)s of %(total)s SNAT Rule(s) failed " + "to delete.") % {'result': result, 'total': total}) + raise exceptions.CommandError(msg) diff --git a/otcextensions/sdk/__init__.py b/otcextensions/sdk/__init__.py index f9837b5b8..030d22517 100644 --- a/otcextensions/sdk/__init__.py +++ b/otcextensions/sdk/__init__.py @@ -114,7 +114,7 @@ 'service_type': 'mrs' }, 'nat': { - 'service_type': 'nat' + 'service_type': 'nat', }, 'obs': { 'service_type': 'obs', diff --git a/otcextensions/sdk/nat/v2/_proxy.py b/otcextensions/sdk/nat/v2/_proxy.py index 4df1a1a06..5f994c2d8 100644 --- a/otcextensions/sdk/nat/v2/_proxy.py +++ b/otcextensions/sdk/nat/v2/_proxy.py @@ -83,6 +83,21 @@ def update_gateway(self, gateway, **attrs): """ return self._update(_gateway.Gateway, gateway, **attrs) + def find_gateway(self, name_or_id, ignore_missing=False): + """Find a single Nat Gateway + + :param name_or_id: The name or ID of a zone + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be raised + when the gateway does not exist. + When set to ``True``, no exception will be set when attempting + to delete a nonexistent gateway. + + :returns: ``None`` + """ + return self._find(_gateway.Gateway, name_or_id, + ignore_missing=ignore_missing) + # ======== SNAT rules ======== def create_snat_rule(self, **attrs): """Create a new SNAT rule from attributes diff --git a/otcextensions/sdk/nat/v2/dnat.py b/otcextensions/sdk/nat/v2/dnat.py index 5c71f7e2c..4f1807189 100644 --- a/otcextensions/sdk/nat/v2/dnat.py +++ b/otcextensions/sdk/nat/v2/dnat.py @@ -1,69 +1,68 @@ -# 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 resource - - -class Dnat(resource.Resource): - resources_key = 'dnat_rules' - resource_key = 'dnat_rule' - base_path = '/dnat_rules' - - # capabilities - allow_create = True - allow_fetch = True - allow_delete = True - allow_list = True - - _query_mapping = resource.QueryParameters( - 'admin_state_up', 'cidr', 'created_at', 'external_service_port', - 'floating_ip_address', 'floating_ip_id', 'id', - 'internal_service_port', 'limit', 'nat_gateway_id', 'network_id', - 'port_id', 'private_id', 'protocol', 'source_type', 'status', - 'project_id' - ) - - # Properties - #: Specifies whether DNAT rule is enabled / disabled - #: *true:* DNAT rule is enabled - #: *false:* DNAT rule is disabled - admin_state_up = resource.Body('admin_state_up', type=bool) - #: Specifies when the rule is created. - #: The format is yyyy-mm-dd hh:mm:ss. - created_at = resource.Body('created_at') - #: Specifies the port for providing external services. - external_service_port = resource.Body('external_service_port', type=int) - #: Specifies the EIP - floating_ip_address = resource.Body('floating_ip_address') - #: Specifies the EIP ID - floating_ip_id = resource.Body('floating_ip_id') - #: Specifies the gateway ID. - gateway_id = resource.Body('gateway_id') - #: Specifies the ID of the DNAT rule. - id = resource.Body('id') - #: Specifies port used by ECS/BMS to provide services for external systems - internal_service_port = resource.Body('internal_service_port', type=int) - #: Specifies the ID of the NAT gateway. - nat_gateway_id = resource.Body('nat_gateway_id') - #: Specifies the port ID of an ECS or BMS - #: Parameter is used in the VPC scenario. - #: This parameter is an alternative to private_ip - port_id = resource.Body('port_id') - #: Specifies the IP address of a Direct Connect connection. - #: Parameter is used in the Direct Connect scenario. - #: This parameter is an alternative to port_id. - private_ip = resource.Body('private_ip') - #: Specifies the project ID. - project_id = resource.Body('tenant_id') - #: Specifies the protocol type. Currently TCP(6), UDP(17) and ANY(0) - protocol = resource.Body('protocol') - #: Specifies the status of the DNAT rule - status = resource.Body('status') +# 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 resource + + +class Dnat(resource.Resource): + resources_key = 'dnat_rules' + resource_key = 'dnat_rule' + base_path = '/dnat_rules' + + # capabilities + allow_create = True + allow_fetch = True + allow_delete = True + allow_list = True + + _query_mapping = resource.QueryParameters( + 'admin_state_up', 'created_at', 'external_service_port', 'id', + 'floating_ip_address', 'floating_ip_id', 'internal_service_port', + 'limit', 'nat_gateway_id', 'port_id', 'private_ip', 'protocol', + 'status', 'project_id', project_id='tenant_id' + ) + + # Properties + #: Specifies whether DNAT rule is enabled / disabled + #: *true:* DNAT rule is enabled + #: *false:* DNAT rule is disabled + admin_state_up = resource.Body('admin_state_up', type=bool) + #: Specifies when the rule is created. + #: The format is yyyy-mm-dd hh:mm:ss. + created_at = resource.Body('created_at') + #: Specifies the port for providing external services. + external_service_port = resource.Body('external_service_port', type=int) + #: Specifies the EIP + floating_ip_address = resource.Body('floating_ip_address') + #: Specifies the EIP ID + floating_ip_id = resource.Body('floating_ip_id') + #: Specifies the gateway ID. + gateway_id = resource.Body('gateway_id') + #: Specifies the ID of the DNAT rule. + id = resource.Body('id') + #: Specifies port used by ECS/BMS to provide services for external systems + internal_service_port = resource.Body('internal_service_port', type=int) + #: Specifies the ID of the NAT gateway. + nat_gateway_id = resource.Body('nat_gateway_id') + #: Specifies the port ID of an ECS or BMS + #: Parameter is used in the VPC scenario. + #: This parameter is an alternative to private_ip + port_id = resource.Body('port_id') + #: Specifies the IP address of a Direct Connect connection. + #: Parameter is used in the Direct Connect scenario. + #: This parameter is an alternative to port_id. + private_ip = resource.Body('private_ip') + #: Specifies the project ID. + project_id = resource.Body('tenant_id') + #: Specifies the protocol type. Currently TCP(6), UDP(17) and ANY(0) + protocol = resource.Body('protocol') + #: Specifies the status of the DNAT rule + status = resource.Body('status') diff --git a/otcextensions/sdk/nat/v2/gateway.py b/otcextensions/sdk/nat/v2/gateway.py index bcacd7f32..b93901ebb 100644 --- a/otcextensions/sdk/nat/v2/gateway.py +++ b/otcextensions/sdk/nat/v2/gateway.py @@ -27,7 +27,7 @@ class Gateway(resource.Resource): _query_mapping = resource.QueryParameters( 'admin_state_up', 'created_at', 'description', 'id', 'internal_network_id', 'limit', 'name', 'router_id', - 'spec', 'status', 'project_id' + 'spec', 'status', 'project_id', project_id='tenant_id' ) # Properties diff --git a/otcextensions/sdk/nat/v2/snat.py b/otcextensions/sdk/nat/v2/snat.py index 57c75685f..ad5dc0cb1 100644 --- a/otcextensions/sdk/nat/v2/snat.py +++ b/otcextensions/sdk/nat/v2/snat.py @@ -1,62 +1,62 @@ -# 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 resource - - -class Snat(resource.Resource): - resources_key = 'snat_rules' - resource_key = 'snat_rule' - base_path = '/snat_rules' - - # capabilities - allow_create = True - allow_fetch = True - allow_delete = True - allow_list = True - - _query_mapping = resource.QueryParameters( - 'admin_state_up', 'cidr', 'created_at', 'floating_ip_address', - 'floating_ip_id', 'id', 'limit', 'nat_gateway_id', 'network_id', - 'source_type', 'status', 'project_id' - ) - - # Properties - #: Specifies the status of the SNAT rule - admin_state_up = resource.Body('admin_state_up', type=bool) - #: Specifies a subset of the VPC subnet CIDR block or a - #: CIDR block of Direct Connect connection. - cidr = resource.Body('cidr') - #: Specifies when the rule is created. - #: The format is yyyy-mm-dd hh:mm:ss. - created_at = resource.Body('created_at') - #: Specifies the EIP - #: Multiple EIPs are separated using commas - floating_ip_address = resource.Body('floating_ip_address') - #: Specifies the EIP ID - #: Multiple EIPs are separated using commas - floating_ip_id = resource.Body('floating_ip_id') - #: Specifies the ID of the SNAT rule. - id = resource.Body('id') - #: Specifies the gateway ID. - nat_gateway_id = resource.Body('nat_gateway_id') - #: Specifies the network ID - network_id = resource.Body('network_id') - #: Specifies the project ID. - project_id = resource.Body('tenant_id') - #: *0:* Either network_id or cidr can be specified in VPC - #: *1:* only cidr can be specified over a Direct Connect connection - #: Default: 0 - source_type = resource.Body('source_type', type=int) - #: Specifies whether SNAT rule is enabled / disabled - #: *true:* SNAT rule is enabled - #: *false:* SNAT rule is disabled - status = resource.Body('status') +# 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 resource + + +class Snat(resource.Resource): + resources_key = 'snat_rules' + resource_key = 'snat_rule' + base_path = '/snat_rules' + + # capabilities + allow_create = True + allow_fetch = True + allow_delete = True + allow_list = True + + _query_mapping = resource.QueryParameters( + 'admin_state_up', 'cidr', 'created_at', 'floating_ip_address', + 'floating_ip_id', 'id', 'limit', 'nat_gateway_id', 'network_id', + 'source_type', 'status', 'project_id', project_id='tenant_id' + ) + + # Properties + #: Specifies the status of the SNAT rule + admin_state_up = resource.Body('admin_state_up', type=bool) + #: Specifies a subset of the VPC subnet CIDR block or a + #: CIDR block of Direct Connect connection. + cidr = resource.Body('cidr') + #: Specifies when the rule is created. + #: The format is yyyy-mm-dd hh:mm:ss. + created_at = resource.Body('created_at') + #: Specifies the EIP + #: Multiple EIPs are separated using commas + floating_ip_address = resource.Body('floating_ip_address') + #: Specifies the EIP ID + #: Multiple EIPs are separated using commas + floating_ip_id = resource.Body('floating_ip_id') + #: Specifies the ID of the SNAT rule. + id = resource.Body('id') + #: Specifies the gateway ID. + nat_gateway_id = resource.Body('nat_gateway_id') + #: Specifies the network ID + network_id = resource.Body('network_id') + #: Specifies the project ID. + project_id = resource.Body('tenant_id') + #: *0:* Either network_id or cidr can be specified in VPC + #: *1:* only cidr can be specified over a Direct Connect connection + #: Default: 0 + source_type = resource.Body('source_type', type=int) + #: Specifies whether SNAT rule is enabled / disabled + #: *true:* SNAT rule is enabled + #: *false:* SNAT rule is disabled + status = resource.Body('status') diff --git a/otcextensions/tests/functional/osclient/nat/__init__.py b/otcextensions/tests/functional/osclient/nat/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/osclient/nat/v2/__init__.py b/otcextensions/tests/functional/osclient/nat/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/osclient/nat/v2/common.py b/otcextensions/tests/functional/osclient/nat/v2/common.py new file mode 100644 index 000000000..8a943a617 --- /dev/null +++ b/otcextensions/tests/functional/osclient/nat/v2/common.py @@ -0,0 +1,165 @@ +# 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 json +import uuid + +from datetime import datetime + +from openstackclient.tests.functional import base + + +class NatTestCase(base.TestCase): + """Common functional test bits for NAT commands""" + + CURR_TIME = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f") + + def setUp(self): + super(NatTestCase, self).setUp() + UUID = uuid.uuid4().hex[:8] + self.ROUTER_NAME = 'otce-nat-test-router-' + UUID + self.NETWORK_NAME = 'otce-nat-test-net-' + UUID + self.SUBNET_NAME = 'otce-nat-test-subnet-' + UUID + self.NAT_NAME = 'otce-nat-test-' + UUID + + self.ROUTER_ID = None + self.NETWORK_ID = None + self.FLOATING_IP_ID = None + self.NAT_ID = None + self.SNAT_RULE_ID = None + self.DNAT_RULE_ID = None + + def create_nat_gateway(self, name=None): + self._initialize_network() + name = name or self.NAT_NAME + json_output = json.loads(self.openstack( + 'nat gateway create {name}' + ' --router-id {router_id}' + ' --internal-network-id {net_id}' + ' --spec {spec} -f json'.format( + name=name, + router_id=self.ROUTER_ID, + net_id=self.NETWORK_ID, + description='OTCE Lib Test', + spec=1) + )) + self.assertIsNotNone(json_output) + self.NAT_ID = json_output['id'] + return json_output + + def delete_nat_gateway(self): + self.addCleanup(self._denitialize_network) + self.openstack('nat gateway delete ' + self.NAT_ID) + + def create_snat_rule(self): + nat_gateway = self.create_nat_gateway() + self.assertIsNotNone(nat_gateway) + self.assertIsNotNone(self.FLOATING_IP_ID) + json_output = json.loads(self.openstack( + 'nat snat rule create ' + '--nat-gateway-id {nat_gateway_id} ' + '--floating-ip-id {floating_ip_id} ' + '--network-id {net_id} -f json'.format( + nat_gateway_id=nat_gateway['id'], + floating_ip_id=self.FLOATING_IP_ID, + net_id=self.NETWORK_ID) + )) + self.assertIsNotNone(json_output) + self.SNAT_RULE_ID = json_output['id'] + return json_output + + def delete_snat_rule(self): + self.addCleanup(self.delete_nat_gateway) + self.openstack( + 'nat snat rule delete ' + self.SNAT_RULE_ID) + + def create_dnat_rule(self): + nat_gateway = self.create_nat_gateway() + self.assertIsNotNone(nat_gateway) + self.assertIsNotNone(self.FLOATING_IP_ID) + json_output = json.loads(self.openstack( + 'nat dnat rule create ' + '--nat-gateway-id {nat_gateway_id} ' + '--floating-ip-id {floating_ip_id} ' + '--protocol {protocol} ' + '--internal-service-port 80 ' + '--external-service-port 80 ' + '--private-ip {private_ip} ' + '-f json'.format( + nat_gateway_id=nat_gateway['id'], + protocol='TCP', + private_ip='192.168.0.3', + floating_ip_id=self.FLOATING_IP_ID) + )) + self.assertIsNotNone(json_output) + self.DNAT_RULE_ID = json_output['id'] + return json_output + + def delete_dnat_rule(self): + self.addCleanup(self.delete_nat_gateway) + self.openstack( + 'nat dnat rule delete ' + self.DNAT_RULE_ID) + + def _initialize_network(self): + router = json.loads(self.openstack( + 'router create -f json ' + self.ROUTER_NAME + )) + net = json.loads(self.openstack( + 'network create -f json ' + self.NETWORK_NAME + )) + self.openstack( + 'subnet create {subnet} -f json ' + '--network {net} ' + '--subnet-range 192.168.0.0/24 '.format( + subnet=self.SUBNET_NAME, + net=self.NETWORK_NAME + )) + + self.openstack( + 'router add subnet {router} ' + '{subnet} '.format( + router=self.ROUTER_NAME, + subnet=self.SUBNET_NAME + ) + ) + + floating_ip = json.loads(self.openstack( + 'floating ip create -f json ' + '{network}'.format( + network='admin_external_net') + )) + + self.ROUTER_ID = router['id'] + self.NETWORK_ID = net['id'] + self.FLOATING_IP_ID = floating_ip['id'] + + def _denitialize_network(self): + self.openstack( + 'floating ip delete ' + self.FLOATING_IP_ID + ) + self.openstack( + 'router remove subnet {router} ' + '{subnet} '.format( + router=self.ROUTER_NAME, + subnet=self.SUBNET_NAME + ) + ) + self.openstack( + 'subnet delete ' + self.SUBNET_NAME + ) + self.openstack( + 'network delete ' + self.NETWORK_NAME + ) + self.openstack( + 'router delete ' + self.ROUTER_NAME + ) diff --git a/otcextensions/tests/functional/osclient/nat/v2/test_dnat.py b/otcextensions/tests/functional/osclient/nat/v2/test_dnat.py new file mode 100644 index 000000000..0450c9120 --- /dev/null +++ b/otcextensions/tests/functional/osclient/nat/v2/test_dnat.py @@ -0,0 +1,80 @@ +# 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 json + +from otcextensions.tests.functional.osclient.nat.v2 import common + + +class TestDnat(common.NatTestCase): + """Functional Tests for NAT Gateway""" + + def setUp(self): + super(TestDnat, self).setUp() + + def test_nat_dnat_rule_list(self): + json_output = json.loads(self.openstack( + 'nat dnat rule list -f json ' + )) + self.assertIsNotNone(json_output) + + def test_nat_dnat_rule_list_filters(self): + json_output = json.loads(self.openstack( + 'nat dnat rule list -f json ' + '--limit 1 --id 2 ' + '--project-id 3 ' + '--port-id 4 ' + '--private-ip 5 ' + '--internal-service-port 6 ' + '--floating-ip-id 7 ' + '--floating-ip-address 8 ' + '--external-service-port 9 ' + '--status 10 ' + '--nat-gateway-id 11 ' + '--protocol tcp ' + '--admin-state-up true ' + '--created-at "{}"'.format(self.CURR_TIME) + )) + self.assertIsNotNone(json_output) + + def test_nat_dnat_rule_create(self): + json_output = self.create_dnat_rule() + self.addCleanup(self.delete_dnat_rule) + dnat_rule_id = json_output['id'] + nat_id = json_output['nat_gateway_id'] + + # List Dnat Rules by Id filter + json_output = json.loads(self.openstack( + 'nat dnat rule list -f json ' + '--id ' + dnat_rule_id + )) + self.assertIsNotNone(json_output) + self.assertEqual(next(iter(json_output))['Id'], dnat_rule_id) + self.assertEqual( + next(iter(json_output))['Nat Gateway Id'], nat_id) + + # List Dnat Rules by Nat Id filter + json_output = json.loads(self.openstack( + 'nat dnat rule list -f json ' + '--nat-gateway-id ' + nat_id + )) + self.assertIsNotNone(json_output) + self.assertEqual( + next(iter(json_output))['Nat Gateway Id'], nat_id) + + # Show Dnat Rule details + json_output = json.loads(self.openstack( + 'nat dnat rule show ' + ' -f json ' + dnat_rule_id + )) + self.assertIsNotNone(json_output) + self.assertEqual(json_output['id'], dnat_rule_id) diff --git a/otcextensions/tests/functional/osclient/nat/v2/test_gateway.py b/otcextensions/tests/functional/osclient/nat/v2/test_gateway.py new file mode 100644 index 000000000..aef96de1d --- /dev/null +++ b/otcextensions/tests/functional/osclient/nat/v2/test_gateway.py @@ -0,0 +1,103 @@ +# 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 json + +from otcextensions.tests.functional.osclient.nat.v2 import common + + +class TestGateway(common.NatTestCase): + """Functional Tests for NAT Gateway""" + + def setUp(self): + super(TestGateway, self).setUp() + + def test_nat_gateway_list(self): + json_output = json.loads(self.openstack( + 'nat gateway list -f json ' + )) + self.assertIsNotNone(json_output) + + def test_nat_gateway_list_filters(self): + json_output = json.loads(self.openstack( + 'nat gateway list -f json ' + '--limit 1 --id 2 ' + '--name 3 --spec 4 ' + '--router-id 5 ' + '--internal-network-id 6 ' + '--project-id 7 ' + '--status active ' + '--admin-state-up True ' + '--created-at "{}"'.format(self.CURR_TIME) + )) + self.assertIsNotNone(json_output) + + def test_nat_gateway(self): + nat_gateway = self.create_nat_gateway() + nat_id = nat_gateway['id'] + nat_name = nat_gateway['name'] + router_id = nat_gateway['router_id'] + + self.addCleanup(self.delete_nat_gateway) + + # List Nat Gateway By Id + json_output = json.loads(self.openstack( + 'nat gateway list -f json' + ' --id {}'.format(nat_id) + )) + self.assertEqual(json_output[0]['Name'], nat_name) + self.assertEqual(json_output[0]['Id'], nat_id) + + # List Nat Gateway By Name + json_output = json.loads(self.openstack( + 'nat gateway list -f json' + ' --name {}'.format(nat_name) + )) + self.assertEqual(json_output[0]['Name'], nat_name) + self.assertEqual(json_output[0]['Id'], nat_id) + + # List Nat Gateway by Router ID + json_output = json.loads(self.openstack( + 'nat gateway list -f json' + ' --router-id {}'.format(router_id) + )) + for nat_gw in json_output: + self.assertEqual(nat_gw['Router Id'], router_id) + + # Show Nat Gateway by Name + json_output = json.loads(self.openstack( + 'nat gateway show -f json ' + nat_name + )) + self.assertEqual(json_output['name'], nat_name) + self.assertEqual(json_output['id'], nat_id) + + # Show Nat Gateway by Id + json_output = json.loads(self.openstack( + 'nat gateway show -f json ' + nat_id + )) + self.assertEqual(json_output['name'], nat_name) + self.assertEqual(json_output['id'], nat_id) + + # Update Nat Gateway + nat_name = nat_name + "-updated" + description = "otce cli test nat updated" + json_output = json.loads(self.openstack( + 'nat gateway update {nat_id} ' + '--name {name} ' + '--description "{desc}" ' + '-f json'.format( + nat_id=nat_id, + name=nat_name, + desc=description) + )) + self.assertEqual(json_output['name'], nat_name) + self.assertEqual(json_output['description'], description) diff --git a/otcextensions/tests/functional/osclient/nat/v2/test_snat.py b/otcextensions/tests/functional/osclient/nat/v2/test_snat.py new file mode 100644 index 000000000..07d8a5f97 --- /dev/null +++ b/otcextensions/tests/functional/osclient/nat/v2/test_snat.py @@ -0,0 +1,79 @@ +# 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 json + +from otcextensions.tests.functional.osclient.nat.v2 import common + + +class TestSnat(common.NatTestCase): + """Functional Tests for NAT Gateway""" + + def setUp(self): + super(TestSnat, self).setUp() + + def test_snat_rule_list(self): + json_output = json.loads(self.openstack( + 'nat snat rule list -f json ' + )) + self.assertIsNotNone(json_output) + + def test_snat_rule_list_filters(self): + json_output = json.loads(self.openstack( + 'nat snat rule list -f json ' + '--limit 1 --id 2 ' + '--project-id 3 ' + '--nat-gateway-id 4 ' + '--network-id 5 ' + '--cidr 6 ' + '--source-type 7 ' + '--floating-ip-id 8 ' + '--floating-ip-address 9 ' + '--status 10 ' + '--admin-state-up true ' + '--created-at "{}"'.format(self.CURR_TIME) + )) + self.assertIsNotNone(json_output) + + def test_nat_snat_rule(self): + json_output = self.create_snat_rule() + self.addCleanup(self.delete_snat_rule) + snat_rule_id = json_output['id'] + nat_id = json_output['nat_gateway_id'] + + # List Snat Rule by Snat Id filter + json_output = json.loads(self.openstack( + 'nat snat rule list -f json ' + '--id ' + snat_rule_id + )) + self.assertIsNotNone(json_output) + self.assertEqual(next(iter(json_output))['Id'], snat_rule_id) + self.assertEqual( + next(iter(json_output))['Nat Gateway Id'], nat_id) + + # List Snat Rule by nat-gateway-id filter + json_output = json.loads(self.openstack( + 'nat snat rule list -f json ' + '--nat-gateway-id ' + nat_id + )) + self.assertIsNotNone(json_output) + self.assertEqual( + next(iter(json_output))['Nat Gateway Id'], nat_id) + + # Show Snat Rule by Id + self.assertIsNotNone(self.SNAT_RULE_ID) + json_output = json.loads(self.openstack( + 'nat snat rule show ' + ' -f json ' + self.SNAT_RULE_ID + )) + self.assertIsNotNone(json_output) + self.assertEqual(json_output['id'], self.SNAT_RULE_ID) diff --git a/otcextensions/tests/functional/sdk/nat/__init__.py b/otcextensions/tests/functional/sdk/nat/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/nat/v2/__init__.py b/otcextensions/tests/functional/sdk/nat/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/functional/sdk/nat/v2/test_dnat.py b/otcextensions/tests/functional/sdk/nat/v2/test_dnat.py new file mode 100644 index 000000000..57eab032c --- /dev/null +++ b/otcextensions/tests/functional/sdk/nat/v2/test_dnat.py @@ -0,0 +1,48 @@ +# 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 openstack +from otcextensions.tests.functional import base +from datetime import datetime + +_logger = openstack._log.setup_logging('openstack') + + +class TestDnat(base.BaseFunctionalTest): + CURR_TIME = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f") + + def setUp(self): + super(TestDnat, self).setUp() + openstack.enable_logging(debug=True, http_debug=True) + + def test_list(self): + gateways = list(self.conn.nat.dnat_rules()) + self.assertGreaterEqual(len(gateways), 0) + + def test_list_filters(self): + attrs = { + 'limit': 1, + 'id': '2', + 'project_id': '3', + 'port_id': '4', + 'private_ip': '5', + 'internal_service_port': '6', + 'floating_ip_id': '7', + 'floating_ip_address': '8', + 'external_service_port': '9', + 'nat_gateway_id': '11', + 'protocol': 'tcp', + 'status': 'active', + 'admin_state_up': True, + 'created_at': self.CURR_TIME + } + gateways = list(self.conn.nat.dnat_rules(**attrs)) + self.assertGreaterEqual(len(gateways), 0) diff --git a/otcextensions/tests/functional/sdk/nat/v2/test_gateway.py b/otcextensions/tests/functional/sdk/nat/v2/test_gateway.py new file mode 100644 index 000000000..25583aeda --- /dev/null +++ b/otcextensions/tests/functional/sdk/nat/v2/test_gateway.py @@ -0,0 +1,44 @@ +# 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 openstack +from otcextensions.tests.functional import base +from datetime import datetime + +_logger = openstack._log.setup_logging('openstack') + + +class TestGateway(base.BaseFunctionalTest): + CURR_TIME = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f") + + def setUp(self): + super(TestGateway, self).setUp() + openstack.enable_logging(debug=True, http_debug=True) + + def test_list(self): + gateways = list(self.conn.nat.gateways()) + self.assertGreaterEqual(len(gateways), 0) + + def test_list_filters(self): + attrs = { + 'limit': 1, + 'id': '2', + 'name': '3', + 'spec': '4', + 'router_id': '5', + 'internal_network_id': '6', + 'project_id': '7', + 'status': 'active', + 'admin_state_up': True, + 'created_at': self.CURR_TIME + } + gateways = list(self.conn.nat.gateways(**attrs)) + self.assertGreaterEqual(len(gateways), 0) diff --git a/otcextensions/tests/functional/sdk/nat/v2/test_service.py b/otcextensions/tests/functional/sdk/nat/v2/test_service.py new file mode 100644 index 000000000..3dd333c81 --- /dev/null +++ b/otcextensions/tests/functional/sdk/nat/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.nat + + self.assertIsNotNone(client) diff --git a/otcextensions/tests/functional/sdk/nat/v2/test_snat.py b/otcextensions/tests/functional/sdk/nat/v2/test_snat.py new file mode 100644 index 000000000..f7629a8bc --- /dev/null +++ b/otcextensions/tests/functional/sdk/nat/v2/test_snat.py @@ -0,0 +1,46 @@ +# 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 openstack +from otcextensions.tests.functional import base +from datetime import datetime + +_logger = openstack._log.setup_logging('openstack') + + +class TestSnat(base.BaseFunctionalTest): + CURR_TIME = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f") + + def setUp(self): + super(TestSnat, self).setUp() + openstack.enable_logging(debug=True, http_debug=True) + + def test_list(self): + gateways = list(self.conn.nat.snat_rules()) + self.assertGreaterEqual(len(gateways), 0) + + def test_list_filters(self): + attrs = { + 'limit': 1, + 'id': '2', + 'project_id': '3', + 'nat_gateway_id': '4', + 'network_id': '5', + 'cidr': '6', + 'source_type': '7', + 'floating_ip_id': '8', + 'floating_ip_address': '9', + 'status': 'active', + 'admin_state_up': True, + 'created_at': self.CURR_TIME + } + gateways = list(self.conn.nat.snat_rules(**attrs)) + self.assertGreaterEqual(len(gateways), 0) diff --git a/otcextensions/tests/unit/osclient/nat/__init__.py b/otcextensions/tests/unit/osclient/nat/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/osclient/nat/v2/__init__.py b/otcextensions/tests/unit/osclient/nat/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/otcextensions/tests/unit/osclient/nat/v2/fakes.py b/otcextensions/tests/unit/osclient/nat/v2/fakes.py new file mode 100644 index 000000000..435ebc0e7 --- /dev/null +++ b/otcextensions/tests/unit/osclient/nat/v2/fakes.py @@ -0,0 +1,128 @@ +# 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 uuid +from datetime import datetime + +import mock + +from openstackclient.tests.unit import utils + +from otcextensions.tests.unit.osclient import test_base + +from otcextensions.sdk.nat.v2 import gateway +from otcextensions.sdk.nat.v2 import snat +from otcextensions.sdk.nat.v2 import dnat + + +def gen_data(data, columns): + """Fill expected data tuple based on columns list + """ + return tuple(getattr(data, attr, '') for attr in columns) + + +def gen_data_dict(data, columns): + """Fill expected data tuple based on columns list + """ + return tuple(data.get(attr, '') for attr in columns) + + +class TestNat(utils.TestCommand): + def setUp(self): + super(TestNat, self).setUp() + + self.app.client_manager.nat = mock.Mock() + + self.client = self.app.client_manager.nat + + +class FakeNatGateway(test_base.Fake): + """Fake one or more Nat Gateways.""" + @classmethod + def generate(cls): + """Create a fake NAT Gateway. + + :return: + A FakeResource object, with id, name and so on + """ + # Set default attributes. + object_info = { + "id": "id-" + uuid.uuid4().hex, + "name": "name-" + uuid.uuid4().hex, + "router_id": "router-" + uuid.uuid4().hex, + "status": "PENDING_CREATE", + "description": "my nat gateway", + "admin_state_up": 'true', + "tenant_id": "tenant-id-" + uuid.uuid4().hex, + "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"), + "spec": "1", + "internal_network_id": "net-id-" + uuid.uuid4().hex + } + + return gateway.Gateway(**object_info) + + +class FakeSnatRule(test_base.Fake): + """Fake one or more SNAT Rule.""" + @classmethod + def generate(cls): + """Create a fake SNAT Rule. + + :return: + A FakeResource object, with id, status and so on + """ + # Set default attributes. + object_info = { + "id": "id-" + uuid.uuid4().hex, + "floating_ip_id": "eip-id-" + uuid.uuid4().hex, + "status": "PENDING_CREATE", + "nat_gateway_id": "gw-id-" + uuid.uuid4().hex, + "admin_state_up": True, + "network_id": "net-id-" + uuid.uuid4().hex, + "cidr": uuid.uuid4().hex, + "source_type": 0, + "tenant_id": "tenant-id-" + uuid.uuid4().hex, + "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"), + "floating_ip_address": uuid.uuid4().hex + } + + return snat.Snat.existing(**object_info) + + +class FakeDnatRule(test_base.Fake): + """Fake one or more DNAT Rule""" + @classmethod + def generate(cls): + """Create a fake DNAT Rule. + + :return: + A FakeResource object, with id, status and so on + """ + # Set default attributes. + object_info = { + "id": "id-" + uuid.uuid4().hex, + "floating_ip_id": "eip-id-" + uuid.uuid4().hex, + "status": "ACTIVE", + "nat_gateway_id": "gw-id-" + uuid.uuid4().hex, + "admin_state_up": True, + "private_ip": uuid.uuid4().hex, + "internal_service_port": 0, + "protocol": "any", + "tenant_id": "abc", + "port_id": "", + "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"), + "floating_ip_address": uuid.uuid4().hex, + "external_service_port": 0 + } + + obj = dnat.Dnat.existing(**object_info) + return obj diff --git a/otcextensions/tests/unit/osclient/nat/v2/test_dnat.py b/otcextensions/tests/unit/osclient/nat/v2/test_dnat.py new file mode 100644 index 000000000..393eb69cd --- /dev/null +++ b/otcextensions/tests/unit/osclient/nat/v2/test_dnat.py @@ -0,0 +1,375 @@ +# 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 mock +from unittest.mock import call + +from osc_lib import exceptions + +from otcextensions.osclient.nat.v2 import dnat +from otcextensions.tests.unit.osclient.nat.v2 import fakes + +from openstackclient.tests.unit import utils as tests_utils + + +class TestListDnatRules(fakes.TestNat): + + objects = fakes.FakeDnatRule.create_multiple(3) + + column_list_headers = ( + 'Id', + 'Nat Gateway Id', + 'Port Id', + 'Private IP', + 'Floating Ip Address', + 'Protocol', + 'Status' + ) + columns = ( + 'id', + 'nat_gateway_id', + 'port_id', + 'private_ip', + 'floating_ip_address', + 'protocol', + 'status' + ) + + data = [] + + for s in objects: + data.append(( + s.id, + s.nat_gateway_id, + s.port_id, + s.private_ip, + s.floating_ip_address, + s.protocol, + s.status + )) + + def setUp(self): + super(TestListDnatRules, self).setUp() + + self.cmd = dnat.ListDnatRules(self.app, None) + + self.client.dnat_rules = mock.Mock() + self.client.api_mock = self.client.dnat_rules + + def test_list(self): + arglist = [] + + verifylist = [] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.api_mock.side_effect = [self.objects] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.api_mock.assert_called_with() + + self.assertEqual(self.column_list_headers, columns) + self.assertEqual(self.data, list(data)) + + def test_list_args(self): + arglist = [ + '--limit', '1', + '--id', '2', + '--nat-gateway-id', '3', + '--project-id', '4', + '--private-ip', '5', + '--internal-service-port', '6', + '--protocol', '7', + '--floating-ip-id', '8', + '--floating-ip-address', '9', + '--admin-state-up', '10', + '--created-at', '11', + '--status', '12' + ] + + verifylist = [ + ('limit', 1), + ('id', '2'), + ('nat_gateway_id', '3'), + ('project_id', '4'), + ('private_ip', '5'), + ('internal_service_port', '6'), + ('protocol', '7'), + ('floating_ip_id', '8'), + ('floating_ip_address', '9'), + ('admin_state_up', '10'), + ('created_at', '11'), + ('status', '12'), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.api_mock.side_effect = [self.objects] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.api_mock.assert_called_with( + limit=1, + id='2', + nat_gateway_id='3', + project_id='4', + private_ip='5', + internal_service_port='6', + protocol='7', + floating_ip_id='8', + floating_ip_address='9', + admin_state_up='10', + created_at='11', + status='12', + ) + + +class TestShowDnatRule(fakes.TestNat): + + _data = fakes.FakeDnatRule.create_one() + + columns = ( + 'admin_state_up', + 'created_at', + 'external_service_port', + 'floating_ip_address', + 'floating_ip_id', + 'id', + 'internal_service_port', + 'nat_gateway_id', + 'port_id', + 'private_ip', + 'project_id', + 'protocol', + 'status' + ) + + data = fakes.gen_data(_data, columns) + + def setUp(self): + super(TestShowDnatRule, self).setUp() + + self.cmd = dnat.ShowDnatRule(self.app, None) + + self.client.get_dnat_rule = mock.Mock(return_value=self._data) + + def test_show_no_options(self): + arglist = [] + verifylist = [] + + # Testing that a call without the required argument will fail and + # throw a "ParserExecption" + self.assertRaises(tests_utils.ParserException, + self.check_parser, self.cmd, arglist, verifylist) + + def test_show(self): + arglist = [ + self._data.id, + ] + + verifylist = [ + ('dnat', self._data.id), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + self.client.get_dnat_rule.assert_called_with(self._data.id) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + def test_show_non_existent(self): + arglist = [ + 'unexist_dnat_rule_id', + ] + + verifylist = [ + ('dnat', arglist[0]), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + find_mock_result = exceptions.CommandError('Resource Not Found') + self.client.get_dnat_rule = ( + mock.Mock(side_effect=find_mock_result) + ) + + # Trigger the action + try: + self.cmd.take_action(parsed_args) + except Exception as e: + self.assertEqual('Resource Not Found', str(e)) + self.client.get_dnat_rule.assert_called_with(arglist[0]) + + +class TestCreateDnatRule(fakes.TestNat): + + _data = fakes.FakeDnatRule.create_one() + + columns = ( + 'admin_state_up', + 'created_at', + 'external_service_port', + 'floating_ip_address', + 'floating_ip_id', + 'id', + 'internal_service_port', + 'nat_gateway_id', + 'port_id', + 'private_ip', + 'project_id', + 'protocol', + 'status' + ) + + data = fakes.gen_data(_data, columns) + + def setUp(self): + super(TestCreateDnatRule, self).setUp() + + self.cmd = dnat.CreateDnatRule(self.app, None) + + self.client.create_dnat_rule = mock.Mock(return_value=self._data) + + def test_create(self): + arglist = [ + '--nat-gateway-id', 'test-nat-uuid', + '--floating-ip-id', 'test-floating-ip-uuid', + '--protocol', 'tcp', + '--internal-service-port', '80', + '--external-service-port', '80', + '--private-ip', '192.168.0.99', + ] + + verifylist = [ + ('nat_gateway_id', 'test-nat-uuid'), + ('floating_ip_id', 'test-floating-ip-uuid'), + ('protocol', 'tcp'), + ('internal_service_port', '80'), + ('external_service_port', '80'), + ('private_ip', '192.168.0.99'), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + self.client.create_dnat_rule.assert_called_with( + nat_gateway_id='test-nat-uuid', + floating_ip_id='test-floating-ip-uuid', + protocol='tcp', + internal_service_port='80', + external_service_port='80', + private_ip='192.168.0.99') + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + +class TestDeleteDnatRule(fakes.TestNat): + + _data = fakes.FakeDnatRule.create_multiple(2) + + def setUp(self): + super(TestDeleteDnatRule, self).setUp() + + self.client.delete_dnat_rule = mock.Mock(return_value=None) + + self.cmd = dnat.DeleteDnatRule(self.app, None) + + def test_delete(self): + arglist = [ + self._data[0].id, + ] + + verifylist = [ + ('dnat', arglist), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.client.get_dnat_rule = ( + mock.Mock(return_value=self._data[0]) + ) + + # Trigger the action + result = self.cmd.take_action(parsed_args) + self.client.get_dnat_rule.assert_called_with(self._data[0].id) + self.client.delete_dnat_rule.assert_called_with(self._data[0].id) + self.assertIsNone(result) + + def test_multiple_delete(self): + arglist = [] + + for dnat_rule in self._data: + arglist.append(dnat_rule.id) + + verifylist = [ + ('dnat', arglist), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + find_mock_result = self._data + self.client.get_dnat_rule = ( + mock.Mock(side_effect=find_mock_result) + ) + + # Trigger the action + result = self.cmd.take_action(parsed_args) + + calls = [] + for dnat_rule in self._data: + calls.append(call(dnat_rule.id)) + self.client.delete_dnat_rule.assert_has_calls(calls) + self.assertIsNone(result) + + def test_multiple_delete_with_exception(self): + arglist = [ + self._data[0].id, + 'unexist_dnat_rule_id', + ] + verifylist = [ + ('dnat', arglist), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + find_mock_result = [self._data[0], exceptions.CommandError] + self.client.get_dnat_rule = ( + mock.Mock(side_effect=find_mock_result) + ) + + # Trigger the action + try: + self.cmd.take_action(parsed_args) + except Exception as e: + self.assertEqual('1 of 2 DNAT Rule(s) failed to delete.', str(e)) + + self.client.get_dnat_rule.assert_any_call(arglist[0]) + self.client.get_dnat_rule.assert_any_call(arglist[1]) + self.client.delete_dnat_rule.assert_called_once_with(arglist[0]) diff --git a/otcextensions/tests/unit/osclient/nat/v2/test_gateway.py b/otcextensions/tests/unit/osclient/nat/v2/test_gateway.py new file mode 100644 index 000000000..ec5435e47 --- /dev/null +++ b/otcextensions/tests/unit/osclient/nat/v2/test_gateway.py @@ -0,0 +1,389 @@ +# 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 mock +from unittest.mock import call + +from osc_lib import exceptions + +from otcextensions.osclient.nat.v2 import gateway +from otcextensions.tests.unit.osclient.nat.v2 import fakes + +from openstackclient.tests.unit import utils as tests_utils + + +class TestListNatGateways(fakes.TestNat): + + objects = fakes.FakeNatGateway.create_multiple(3) + + column_list_headers = ('Id', 'Name', 'Spec', 'Router Id', 'Status') + + columns = ('id', 'name', 'spec', 'router_id', 'status') + + data = [] + + for s in objects: + data.append( + (s.id, s.name, s.spec, s.router_id, s.status)) + + def setUp(self): + super(TestListNatGateways, self).setUp() + + self.cmd = gateway.ListNatGateways(self.app, None) + + self.client.gateways = mock.Mock() + self.client.api_mock = self.client.gateways + + def test_list(self): + arglist = [] + + verifylist = [] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.api_mock.side_effect = [self.objects] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.api_mock.assert_called_with() + + self.assertEqual(self.column_list_headers, columns) + self.assertEqual(self.data, list(data)) + + def test_list_args(self): + arglist = [ + '--limit', '1', + '--id', '2', + '--name', '3', + '--project-id', '4', + '--spec', '5', + '--router-id', '6', + '--internal-network-id', '7', + '--admin-state-up', '8', + '--created-at', '9', + '--status', '10' + ] + + verifylist = [ + ('limit', 1), + ('id', '2'), + ('name', '3'), + ('project_id', '4'), + ('spec', '5'), + ('router_id', '6'), + ('internal_network_id', '7'), + ('admin_state_up', '8'), + ('created_at', '9'), + ('status', '10'), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.api_mock.side_effect = [self.objects] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.api_mock.assert_called_with( + limit=1, + id='2', + name='3', + project_id='4', + spec='5', + router_id='6', + internal_network_id='7', + admin_state_up='8', + created_at='9', + status='10', + ) + + +class TestCreateNatGateway(fakes.TestNat): + + _data = fakes.FakeNatGateway.create_one() + + columns = ( + 'admin_state_up', + 'created_at', + 'description', + 'id', + 'internal_network_id', + 'name', + 'project_id', + 'router_id', + 'spec', + 'status' + ) + + data = fakes.gen_data(_data, columns) + + def setUp(self): + super(TestCreateNatGateway, self).setUp() + + self.cmd = gateway.CreateNatGateway(self.app, None) + + self.client.create_gateway = mock.Mock(return_value=self._data) + + def test_create(self): + arglist = [ + 'test-gateway', + '--router-id', 'test-router-uuid', + '--internal-network-id', 'test-network-uuid', + '--spec', '1', + ] + verifylist = [ + ('name', 'test-gateway'), + ('router_id', 'test-router-uuid'), + ('internal_network_id', 'test-network-uuid'), + ('spec', '1'), + ] + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.create_gateway.assert_called_with( + name='test-gateway', + router_id='test-router-uuid', + internal_network_id='test-network-uuid', + spec='1' + ) + self.assertEqual(self.columns, columns) + + +class TestUpdateNatGateway(fakes.TestNat): + + _data = fakes.FakeNatGateway.create_one() + + columns = ( + 'admin_state_up', + 'created_at', + 'description', + 'id', + 'internal_network_id', + 'name', + 'project_id', + 'router_id', + 'spec', + 'status' + ) + + data = fakes.gen_data(_data, columns) + + def setUp(self): + super(TestUpdateNatGateway, self).setUp() + + self.cmd = gateway.UpdateNatGateway(self.app, None) + + self.client.find_gateway = mock.Mock(return_value=self._data) + self.client.update_gateway = mock.Mock(return_value=self._data) + + def test_update(self): + arglist = [ + self._data.name, + '--name', 'test-gateway-updated', + '--description', 'nat gateway updated', + '--spec', '2', + ] + verifylist = [ + ('gateway', self._data.name), + ('name', 'test-gateway-updated'), + ('description', 'nat gateway updated'), + ('spec', '2'), + ] + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.find_gateway.assert_called_with(self._data.name) + self.client.update_gateway.assert_called_with( + self._data.id, + name='test-gateway-updated', + description='nat gateway updated', + spec='2' + ) + self.assertEqual(self.columns, columns) + + +class TestShowNatGateway(fakes.TestNat): + + _data = fakes.FakeNatGateway.create_one() + + columns = ( + 'admin_state_up', + 'created_at', + 'description', + 'id', + 'internal_network_id', + 'name', + 'project_id', + 'router_id', + 'spec', + 'status' + ) + + data = fakes.gen_data(_data, columns) + + def setUp(self): + super(TestShowNatGateway, self).setUp() + + self.cmd = gateway.ShowNatGateway(self.app, None) + + self.client.find_gateway = mock.Mock(return_value=self._data) + + def test_show_no_options(self): + arglist = [] + verifylist = [] + + # Testing that a call without the required argument will fail and + # throw a "ParserExecption" + self.assertRaises(tests_utils.ParserException, + self.check_parser, self.cmd, arglist, verifylist) + + def test_show(self): + arglist = [ + self._data.id, + ] + + verifylist = [ + ('gateway', self._data.id), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + self.client.find_gateway.assert_called_with(self._data.id) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + def test_show_non_existent(self): + arglist = [ + 'unexist_nat_gateway', + ] + + verifylist = [ + ('gateway', 'unexist_nat_gateway'), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + find_mock_result = exceptions.CommandError('Resource Not Found') + self.client.find_gateway = ( + mock.Mock(side_effect=find_mock_result) + ) + + # Trigger the action + try: + self.cmd.take_action(parsed_args) + except Exception as e: + self.assertEqual('Resource Not Found', str(e)) + self.client.find_gateway.assert_called_with('unexist_nat_gateway') + + +class TestDeleteNatGateway(fakes.TestNat): + + _data = fakes.FakeNatGateway.create_multiple(2) + + def setUp(self): + super(TestDeleteNatGateway, self).setUp() + + self.client.delete_gateway = mock.Mock(return_value=None) + + # Get the command object to test + self.cmd = gateway.DeleteNatGateway(self.app, None) + + def test_delete(self): + arglist = [ + self._data[0].name, + ] + + verifylist = [ + ('gateway', [self._data[0].name]), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.client.find_gateway = ( + mock.Mock(return_value=self._data[0]) + ) + + # Trigger the action + result = self.cmd.take_action(parsed_args) + self.client.delete_gateway.assert_called_with(self._data[0].id) + self.assertIsNone(result) + + def test_multiple_delete(self): + arglist = [] + + for nat_gw in self._data: + arglist.append(nat_gw.name) + + verifylist = [ + ('gateway', arglist), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + find_mock_result = self._data + self.client.find_gateway = ( + mock.Mock(side_effect=find_mock_result) + ) + + # Trigger the action + result = self.cmd.take_action(parsed_args) + + calls = [] + for nat_gw in self._data: + calls.append(call(nat_gw.id)) + self.client.delete_gateway.assert_has_calls(calls) + self.assertIsNone(result) + + def test_multiple_delete_with_exception(self): + arglist = [ + self._data[0].name, + 'unexist_nat_gateway', + ] + verifylist = [ + ('gateway', arglist), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + find_mock_result = [self._data[0], exceptions.CommandError] + self.client.find_gateway = ( + mock.Mock(side_effect=find_mock_result) + ) + + # Trigger the action + try: + self.cmd.take_action(parsed_args) + except Exception as e: + self.assertEqual('1 of 2 NAT Gateway(s) failed to delete.', str(e)) + + self.client.find_gateway.assert_any_call(self._data[0].name) + self.client.find_gateway.assert_any_call('unexist_nat_gateway') + self.client.delete_gateway.assert_called_once_with(self._data[0].id) diff --git a/otcextensions/tests/unit/osclient/nat/v2/test_snat.py b/otcextensions/tests/unit/osclient/nat/v2/test_snat.py new file mode 100644 index 000000000..0a046eaa3 --- /dev/null +++ b/otcextensions/tests/unit/osclient/nat/v2/test_snat.py @@ -0,0 +1,359 @@ +# 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 mock +from unittest.mock import call + +from osc_lib import exceptions + +from otcextensions.osclient.nat.v2 import snat +from otcextensions.tests.unit.osclient.nat.v2 import fakes + +from openstackclient.tests.unit import utils as tests_utils + + +class TestListSnatRules(fakes.TestNat): + + objects = fakes.FakeSnatRule.create_multiple(3) + + column_list_headers = ( + 'Id', + 'Nat Gateway Id', + 'Network Id', + 'Cidr', + 'Floating Ip Address', + 'Status' + ) + columns = ( + 'id', + 'nat_gateway_id', + 'network_id', + 'cidr', + 'floating_ip_address', + 'status' + ) + + data = [] + + for s in objects: + data.append(( + s.id, + s.nat_gateway_id, + s.network_id, + s.cidr, + s.floating_ip_address, + s.status + )) + + def setUp(self): + super(TestListSnatRules, self).setUp() + + self.cmd = snat.ListSnatRules(self.app, None) + + self.client.snat_rules = mock.Mock() + self.client.api_mock = self.client.snat_rules + + def test_list(self): + arglist = [] + + verifylist = [] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.api_mock.side_effect = [self.objects] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.api_mock.assert_called_with() + + self.assertEqual(self.column_list_headers, columns) + self.assertEqual(self.data, list(data)) + + def test_list_args(self): + arglist = [ + '--limit', '1', + '--id', '2', + '--nat-gateway-id', '3', + '--network-id', '4', + '--project-id', '5', + '--cidr', '6', + '--source-type', '7', + '--floating-ip-id', '8', + '--floating-ip-address', '9', + '--admin-state-up', '10', + '--created-at', '11', + '--status', '12' + ] + + verifylist = [ + ('limit', 1), + ('id', '2'), + ('nat_gateway_id', '3'), + ('network_id', '4'), + ('project_id', '5'), + ('cidr', '6'), + ('source_type', '7'), + ('floating_ip_id', '8'), + ('floating_ip_address', '9'), + ('admin_state_up', '10'), + ('created_at', '11'), + ('status', '12'), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.api_mock.side_effect = [self.objects] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.api_mock.assert_called_with( + limit=1, + id='2', + nat_gateway_id='3', + network_id='4', + project_id='5', + cidr='6', + source_type='7', + floating_ip_id='8', + floating_ip_address='9', + admin_state_up='10', + created_at='11', + status='12', + ) + + +class TestCreateSnatRule(fakes.TestNat): + + _data = fakes.FakeSnatRule.create_one() + + columns = ( + 'admin_state_up', + 'cidr', + 'created_at', + 'floating_ip_address', + 'floating_ip_id', + 'id', + 'nat_gateway_id', + 'network_id', + 'project_id', + 'source_type', + 'status' + ) + + data = fakes.gen_data(_data, columns) + + def setUp(self): + super(TestCreateSnatRule, self).setUp() + + self.cmd = snat.CreateSnatRule(self.app, None) + + self.client.create_snat_rule = mock.Mock(return_value=self._data) + + def test_create(self): + arglist = [ + '--nat-gateway-id', 'test-nat-uuid', + '--floating-ip-id', 'test-floating-ip-uuid', + '--network-id', 'test-network-uuid', + ] + + verifylist = [ + ('nat_gateway_id', 'test-nat-uuid'), + ('floating_ip_id', 'test-floating-ip-uuid'), + ('network_id', 'test-network-uuid'), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + self.client.create_snat_rule.assert_called_with( + nat_gateway_id='test-nat-uuid', + floating_ip_id='test-floating-ip-uuid', + network_id='test-network-uuid') + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + +class TestShowSnatRule(fakes.TestNat): + + _data = fakes.FakeSnatRule.create_one() + + columns = ( + 'admin_state_up', + 'cidr', + 'created_at', + 'floating_ip_address', + 'floating_ip_id', + 'id', + 'nat_gateway_id', + 'network_id', + 'project_id', + 'source_type', + 'status' + ) + + data = fakes.gen_data(_data, columns) + + def setUp(self): + super(TestShowSnatRule, self).setUp() + + self.cmd = snat.ShowSnatRule(self.app, None) + + self.client.get_snat_rule = mock.Mock(return_value=self._data) + + def test_show_no_options(self): + arglist = [] + verifylist = [] + + # Testing that a call without the required argument will fail and + # throw a "ParserExecption" + self.assertRaises(tests_utils.ParserException, + self.check_parser, self.cmd, arglist, verifylist) + + def test_show(self): + arglist = [ + self._data.id, + ] + + verifylist = [ + ('snat', self._data.id), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + self.client.get_snat_rule.assert_called_with(self._data.id) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + def test_show_non_existent(self): + arglist = [ + 'unexist_snat_rule_id', + ] + + verifylist = [ + ('snat', arglist[0]), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + find_mock_result = exceptions.CommandError('Resource Not Found') + self.client.get_snat_rule = ( + mock.Mock(side_effect=find_mock_result) + ) + + # Trigger the action + try: + self.cmd.take_action(parsed_args) + except Exception as e: + self.assertEqual('Resource Not Found', str(e)) + self.client.get_snat_rule.assert_called_with(arglist[0]) + + +class TestDeleteSnatRule(fakes.TestNat): + + _data = fakes.FakeSnatRule.create_multiple(2) + + def setUp(self): + super(TestDeleteSnatRule, self).setUp() + + self.client.delete_snat_rule = mock.Mock(return_value=None) + + self.cmd = snat.DeleteSnatRule(self.app, None) + + def test_delete(self): + arglist = [ + self._data[0].id, + ] + + verifylist = [ + ('snat', arglist), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.client.get_snat_rule = ( + mock.Mock(return_value=self._data[0]) + ) + + # Trigger the action + result = self.cmd.take_action(parsed_args) + self.client.get_snat_rule.assert_called_with(self._data[0].id) + self.client.delete_snat_rule.assert_called_with(self._data[0].id) + self.assertIsNone(result) + + def test_multiple_delete(self): + arglist = [] + + for snat_rule in self._data: + arglist.append(snat_rule.id) + + verifylist = [ + ('snat', arglist), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + find_mock_result = self._data + self.client.get_snat_rule = ( + mock.Mock(side_effect=find_mock_result) + ) + + # Trigger the action + result = self.cmd.take_action(parsed_args) + + calls = [] + for snat_rule in self._data: + calls.append(call(snat_rule.id)) + self.client.delete_snat_rule.assert_has_calls(calls) + self.assertIsNone(result) + + def test_multiple_delete_with_exception(self): + arglist = [ + self._data[0].id, + 'unexist_snat_rule_id', + ] + verifylist = [ + ('snat', arglist), + ] + + # Verify cm is triggered with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + find_mock_result = [self._data[0], exceptions.CommandError] + self.client.get_snat_rule = ( + mock.Mock(side_effect=find_mock_result) + ) + + # Trigger the action + try: + self.cmd.take_action(parsed_args) + except Exception as e: + self.assertEqual('1 of 2 SNAT Rule(s) failed to delete.', str(e)) + + self.client.get_snat_rule.assert_any_call(arglist[0]) + self.client.get_snat_rule.assert_any_call(arglist[1]) + self.client.delete_snat_rule.assert_called_once_with(arglist[0]) diff --git a/otcextensions/tests/unit/sdk/nat/v2/__init__.py b/otcextensions/tests/unit/sdk/nat/v2/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/setup.cfg b/setup.cfg index cc13ea867..6f69f6bdd 100644 --- a/setup.cfg +++ b/setup.cfg @@ -40,6 +40,7 @@ openstack.cli.extension = anti_ddos = otcextensions.osclient.anti_ddos.client dns = otcextensions.osclient.dns.client deh = otcextensions.osclient.deh.client + nat = otcextensions.osclient.nat.client #openstack.obs.v1 = # s3_ls = otcextensions.osclient.obs.v1.ls:List @@ -102,6 +103,21 @@ openstack.rds.v3 = rds_backup_delete = otcextensions.osclient.rds.v3.backup:DeleteBackup rds_backup_download_links = otcextensions.osclient.rds.v3.backup:ListBackupDownloadLinks +openstack.nat.v2 = + nat_gateway_list = otcextensions.osclient.nat.v2.gateway:ListNatGateways + nat_gateway_show = otcextensions.osclient.nat.v2.gateway:ShowNatGateway + nat_gateway_create = otcextensions.osclient.nat.v2.gateway:CreateNatGateway + nat_gateway_update = otcextensions.osclient.nat.v2.gateway:UpdateNatGateway + nat_gateway_delete = otcextensions.osclient.nat.v2.gateway:DeleteNatGateway + nat_snat_rule_list = otcextensions.osclient.nat.v2.snat:ListSnatRules + nat_snat_rule_show = otcextensions.osclient.nat.v2.snat:ShowSnatRule + nat_snat_rule_create = otcextensions.osclient.nat.v2.snat:CreateSnatRule + nat_snat_rule_delete = otcextensions.osclient.nat.v2.snat:DeleteSnatRule + nat_dnat_rule_list = otcextensions.osclient.nat.v2.dnat:ListDnatRules + nat_dnat_rule_show = otcextensions.osclient.nat.v2.dnat:ShowDnatRule + nat_dnat_rule_create = otcextensions.osclient.nat.v2.dnat:CreateDnatRule + nat_dnat_rule_delete = otcextensions.osclient.nat.v2.dnat:DeleteDnatRule + openstack.auto_scaling.v1 = as_group_list = otcextensions.osclient.auto_scaling.v1.group:ListAutoScalingGroup as_group_show = otcextensions.osclient.auto_scaling.v1.group:ShowAutoScalingGroup From 7de66cba822fad4dce3546eae9040b1bd0a43434 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Fri, 17 Apr 2020 16:46:10 +0200 Subject: [PATCH 29/58] replace zuul job --- .zuul.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.zuul.yaml b/.zuul.yaml index 572e70d61..48c77949c 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -19,4 +19,4 @@ - tox-functional periodic: jobs: - - tox-functional-master + - tox-functional From 47ba917df2d85db6cb347f2038fd7f79a8a806b7 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Fri, 17 Apr 2020 16:50:53 +0200 Subject: [PATCH 30/58] replace repair zuul config --- .zuul.yaml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.zuul.yaml b/.zuul.yaml index 48c77949c..a00ffa37c 100644 --- a/.zuul.yaml +++ b/.zuul.yaml @@ -1,7 +1,7 @@ - job: - name: tox-functional-master - parent: tox-functional - branches: master + name: tox-functional-master + parent: tox-functional + branches: master - project: merge-mode: squash-merge @@ -19,4 +19,4 @@ - tox-functional periodic: jobs: - - tox-functional + - tox-functional-master From aa02891617b90a1851699234e8804c1e9a6e1d56 Mon Sep 17 00:00:00 2001 From: Reik Keutterling Date: Fri, 24 Apr 2020 12:03:35 +0200 Subject: [PATCH 31/58] ELB: added UDP to list of supported protocols (#79) ELB: added UDP to list of supported protocols Reviewed-by: https://github.com/apps/otc-zuul --- otcextensions/osclient/load_balancer/v1/health_monitor.py | 8 +++++--- otcextensions/osclient/load_balancer/v1/listener.py | 6 +++--- otcextensions/osclient/load_balancer/v1/pool.py | 6 +++--- .../tests/unit/osclient/load_balancer/v1/test_listener.py | 4 ++-- 4 files changed, 13 insertions(+), 11 deletions(-) diff --git a/otcextensions/osclient/load_balancer/v1/health_monitor.py b/otcextensions/osclient/load_balancer/v1/health_monitor.py index bc13bfb9b..684ab9c35 100644 --- a/otcextensions/osclient/load_balancer/v1/health_monitor.py +++ b/otcextensions/osclient/load_balancer/v1/health_monitor.py @@ -36,7 +36,7 @@ def _get_columns(item): HTTP_METHODS = ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'CONNECT', 'PATCH'] -TYPE_VALUES = ['HTTP', 'HTTPS', 'PING', 'TCP', 'TLS-HELLO'] +TYPE_VALUES = ['HTTP', 'HTTPS', 'PING', 'TCP', 'TLS-HELLO', 'UDP_CONNECT'] class ListHealthMonitor(command.Lister): @@ -53,7 +53,8 @@ def get_parser(self, prog_name): type=lambda s: s.upper(), choices=TYPE_VALUES, help=_('Health monitor type to use as a filter\n' - 'one of [`HTTP`, `HTTPS`, `PING`, `TCP`, `TLS-HELLO`]') + 'one of [`HTTP`, `HTTPS`, `PING`, `TCP`, `TLS-HELLO`, ' + '`UDP_CONNECT`]') ) return parser @@ -184,7 +185,8 @@ def get_parser(self, prog_name): type=lambda s: s.upper(), # case insensitive required=True, help=_('The type of health monitor.\n' - 'one of [`HTTP`, `HTTPS`, `PING`, `TCP`, `TLS-HELLO`]') + 'one of [`HTTP`, `HTTPS`, `PING`, `TCP`, `TLS-HELLO`, ' + '`UDP_CONNECT`]') ) admin_group = parser.add_mutually_exclusive_group() admin_group.add_argument( diff --git a/otcextensions/osclient/load_balancer/v1/listener.py b/otcextensions/osclient/load_balancer/v1/listener.py index d777a260d..8b21a6f6d 100644 --- a/otcextensions/osclient/load_balancer/v1/listener.py +++ b/otcextensions/osclient/load_balancer/v1/listener.py @@ -22,7 +22,7 @@ LOG = logging.getLogger(__name__) -SUPPORTED_PROTOCOLS = ['TCP', 'HTTP', 'HTTPS'] +SUPPORTED_PROTOCOLS = ['TCP', 'HTTP', 'HTTPS', 'UDP'] _formatters = { 'load_balancer_ids': sdk_utils.ListOfIdsColumnBR, @@ -66,7 +66,7 @@ def get_parser(self, prog_name): type=lambda s: s.upper(), choices=SUPPORTED_PROTOCOLS, help=_('Load balancer listener protocol to query\n' - 'One of [`TCP`, `HTTP`, `HTTPS`]') + 'One of [`TCP`, `HTTP`, `HTTPS`, `UDP`]') ) parser.add_argument( '--protocol_port', @@ -158,7 +158,7 @@ def get_parser(self, prog_name): choices=SUPPORTED_PROTOCOLS, required=True, help=_('The protocol for the listener. ' - 'One of [`TCP`, `HTTP`, `HTTPS`]') + 'One of [`TCP`, `HTTP`, `HTTPS`, `UDP`]') ) parser.add_argument( '--protocol_port', diff --git a/otcextensions/osclient/load_balancer/v1/pool.py b/otcextensions/osclient/load_balancer/v1/pool.py index f3a9404a8..a30e4e669 100644 --- a/otcextensions/osclient/load_balancer/v1/pool.py +++ b/otcextensions/osclient/load_balancer/v1/pool.py @@ -32,7 +32,7 @@ LB_ALGORITHM_VALUES = ['LEAST_CONNECTIONS', 'ROUND_ROBIN', 'SOURCE_IP'] -PROTOCOL_VALUES = ['HTTP', 'HTTPS', 'PROXY', 'TCP'] +PROTOCOL_VALUES = ['HTTP', 'HTTPS', 'PROXY', 'TCP', 'UDP'] def _get_columns(item): @@ -84,7 +84,7 @@ def get_parser(self, prog_name): type=lambda s: s.upper(), choices=PROTOCOL_VALUES, help=_('Load balancer pool protocol to query' - 'one of [`HTTP`, `HTTPS`, `PROXY`, `TCP`]') + 'one of [`HTTP`, `HTTPS`, `PROXY`, `TCP`, `UDP`]') ) parser.add_argument( '--load_balancer', @@ -182,7 +182,7 @@ def get_parser(self, prog_name): choices=PROTOCOL_VALUES, required=True, help=_('The protocol for the pool. ' - 'One of [`HTTP`, `HTTPS`, `PROXY`, `TCP`].') + 'One of [`HTTP`, `HTTPS`, `PROXY`, `TCP`, `UDP`].') ) parser.add_argument( '--lb_algorithm', diff --git a/otcextensions/tests/unit/osclient/load_balancer/v1/test_listener.py b/otcextensions/tests/unit/osclient/load_balancer/v1/test_listener.py index 95595bf36..291c39b98 100644 --- a/otcextensions/tests/unit/osclient/load_balancer/v1/test_listener.py +++ b/otcextensions/tests/unit/osclient/load_balancer/v1/test_listener.py @@ -109,12 +109,12 @@ def test_list_filters(self): def test_list_filters_exceptions_proto(self): arglist = [ - '--protocol', 'UDP', + '--protocol', 'SMTP', '--protocol_port', '12' ] verifylist = [ - ('protocol', 'UDP'), + ('protocol', 'SMTP'), ('protocol_port', 12) ] From a18ac58f9479ef021f3f12110123bff81ea5062c Mon Sep 17 00:00:00 2001 From: "T. Schreiber" Date: Wed, 29 Apr 2020 08:22:35 +0200 Subject: [PATCH 32/58] Update CCE cluster (#70) Update CCE cluster Reviewed-by: https://github.com/apps/otc-zuul --- otcextensions/sdk/cce/v3/cluster.py | 7 ++++++- otcextensions/tests/unit/sdk/cce/v3/test_cluster.py | 6 ++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/otcextensions/sdk/cce/v3/cluster.py b/otcextensions/sdk/cce/v3/cluster.py index 03e20d743..2d56335ca 100644 --- a/otcextensions/sdk/cce/v3/cluster.py +++ b/otcextensions/sdk/cce/v3/cluster.py @@ -32,6 +32,9 @@ class ClusterSpec(resource.Resource): #: Authentication authentication = resource.Body('authentication', type=dict) + #: Single Master Cluster in one Availability Zone: ['eu-de-01'] + #: Three Master Cluster in multiple Availability Zones: ['multi-az'] + az = resource.Body('az') #: Billing mode of the cluster. Currently, only pay-per-use is supported. billing = resource.Body('billing_mode', type=int) #: Container network parameters. @@ -44,9 +47,11 @@ class ClusterSpec(resource.Resource): flavor = resource.Body('flavor') #: Node network parameters. host_network = resource.Body('hostNetwork', type=HostNetworkSpec) + #: Enable Istio Support default: True + support_istio = resource.Body('supportIstio', type=bool) #: Cluster type. type = resource.Body('type') - #: Cluster version ['v1.9.2-r2', 'v1.11.3-r1']. + #: Cluster version ['v1.11.7-r2', 'v1.13.10-r0']. version = resource.Body('version') diff --git a/otcextensions/tests/unit/sdk/cce/v3/test_cluster.py b/otcextensions/tests/unit/sdk/cce/v3/test_cluster.py index 021745397..0672374be 100644 --- a/otcextensions/tests/unit/sdk/cce/v3/test_cluster.py +++ b/otcextensions/tests/unit/sdk/cce/v3/test_cluster.py @@ -39,7 +39,9 @@ 'spec': { 'type': 'VirtualMachine', 'flavor': 'cce.s1.small', - 'version': 'v1.11.3-r1', + 'version': 'v1.13.10-r0', + 'az': 'eu-de-01', + 'supportIstio': True, 'description': 'thisisademocluster', 'hostNetwork': { 'vpc': 'a8cc62dc-acc2-47d0-9bfb-3b1d776c520b', @@ -50,7 +52,7 @@ 'cidr': '172.16.0.0/16' }, 'authentication': { - 'mode': 'x509', + 'mode': 'rbac', 'authenticatingProxy': {} }, 'billingMode': 0 From 115a351a3bf2057375e40acaa4a3dbdd7ed0d6c4 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Mon, 4 May 2020 10:28:31 +0200 Subject: [PATCH 33/58] Extend DMS to cover Kafka Premium extensions (#76) Extend DMS to cover Kafka Premium extensions Reviewed-by: https://github.com/apps/otc-zuul --- doc/source/cli/dms.rst | 22 +- doc/source/sdk/proxies/dms.rst | 10 +- doc/source/sdk/resources/dms/index.rst | 5 +- .../sdk/resources/dms/v1/group_message.rst | 13 - doc/source/sdk/resources/dms/v1/instance.rst | 13 + doc/source/sdk/resources/dms/v1/misc | 41 ++ doc/source/sdk/resources/dms/v1/misc.rst | 41 ++ doc/source/sdk/resources/dms/v1/quota.rst | 13 - doc/source/sdk/resources/dms/v1/topic.rst | 13 + otcextensions/osclient/dms/v1/az.py | 38 ++ otcextensions/osclient/dms/v1/instance.py | 430 ++++++++++++++++++ .../osclient/dms/v1/maintenance_window.py | 38 ++ otcextensions/osclient/dms/v1/product.py | 41 ++ otcextensions/osclient/dms/v1/topic.py | 172 +++++++ otcextensions/sdk/dms/v1/_base.py | 98 +++- otcextensions/sdk/dms/v1/_proxy.py | 342 +++++++++++--- otcextensions/sdk/dms/v1/az.py | 37 ++ otcextensions/sdk/dms/v1/group.py | 39 +- otcextensions/sdk/dms/v1/instance.py | 161 +++++++ .../sdk/dms/v1/maintenance_window.py | 38 ++ otcextensions/sdk/dms/v1/message.py | 93 +++- otcextensions/sdk/dms/v1/product.py | 90 ++++ otcextensions/sdk/dms/v1/queue.py | 47 +- otcextensions/sdk/dms/v1/quota.py | 2 +- otcextensions/sdk/dms/v1/topic.py | 42 ++ .../functional/sdk/dms/v1/test_instance.py | 160 +++++++ .../functional/sdk/dms/v1/test_message.py | 14 +- .../tests/functional/sdk/dms/v1/test_queue.py | 1 + .../tests/unit/osclient/anti_ddos/v1/fakes.py | 2 - .../unit/osclient/anti_ddos/v1/test_config.py | 2 - .../osclient/anti_ddos/v1/test_floating_ip.py | 2 - .../unit/osclient/anti_ddos/v1/test_status.py | 2 - .../unit/osclient/auto_scaling/v1/fakes.py | 2 - .../osclient/auto_scaling/v1/test_activity.py | 2 - .../osclient/auto_scaling/v1/test_config.py | 2 - .../osclient/auto_scaling/v1/test_group.py | 2 - .../osclient/auto_scaling/v1/test_instance.py | 2 - .../osclient/auto_scaling/v1/test_policy.py | 2 - .../osclient/auto_scaling/v1/test_quota.py | 2 - .../tests/unit/osclient/cce/v1/fakes.py | 2 - .../unit/osclient/cce/v1/test_cluster.py | 2 - .../unit/osclient/cce/v1/test_cluster_node.py | 2 - .../tests/unit/osclient/cce/v2/fakes.py | 2 - .../unit/osclient/cce/v2/test_cluster.py | 2 - .../unit/osclient/cce/v2/test_cluster_node.py | 2 - .../tests/unit/osclient/cts/v1/fakes.py | 2 - .../tests/unit/osclient/cts/v1/test_trace.py | 2 - .../unit/osclient/cts/v1/test_tracker.py | 2 - .../tests/unit/osclient/dcs/v1/fakes.py | 2 - .../tests/unit/osclient/dcs/v1/test_backup.py | 2 - .../tests/unit/osclient/dcs/v1/test_config.py | 2 - .../unit/osclient/dcs/v1/test_instance.py | 2 - .../unit/osclient/dcs/v1/test_restore.py | 2 - .../unit/osclient/dcs/v1/test_statistic.py | 2 - .../tests/unit/osclient/deh/v1/fakes.py | 2 - .../tests/unit/osclient/deh/v1/test_host.py | 2 - .../tests/unit/osclient/dms/v1/fakes.py | 67 ++- .../tests/unit/osclient/dms/v1/test_group.py | 2 - .../unit/osclient/dms/v1/test_instance.py | 427 +++++++++++++++++ .../tests/unit/osclient/dms/v1/test_queue.py | 20 +- .../tests/unit/osclient/dms/v1/test_quota.py | 2 - .../tests/unit/osclient/dms/v1/test_topic.py | 196 ++++++++ .../tests/unit/osclient/dns/v2/test_ptr.py | 2 - .../unit/osclient/dns/v2/test_recordset.py | 2 - .../tests/unit/osclient/dns/v2/test_zone.py | 2 - .../tests/unit/osclient/kms/v1/fakes.py | 2 - .../tests/unit/osclient/kms/v1/test_cmk.py | 2 - .../unit/osclient/load_balancer/v1/fakes.py | 2 - .../load_balancer/v1/test_health_monitor.py | 2 - .../load_balancer/v1/test_listener.py | 2 - .../load_balancer/v1/test_load_balancer.py | 2 - .../osclient/load_balancer/v1/test_pool.py | 2 - .../load_balancer/v1/test_pool_member.py | 2 - .../tests/unit/osclient/obs/v1/fakes.py | 2 - .../tests/unit/osclient/rds/v1/fakes.py | 2 - .../tests/unit/osclient/rds/v1/test_backup.py | 2 - .../osclient/rds/v1/test_configuration.py | 2 - .../unit/osclient/rds/v1/test_datastore.py | 2 - .../tests/unit/osclient/rds/v1/test_flavor.py | 2 - .../unit/osclient/rds/v1/test_instance.py | 2 - .../tests/unit/osclient/test_base.py | 3 - .../tests/unit/sdk/dms/v1/test_az.py | 92 ++++ .../tests/unit/sdk/dms/v1/test_group.py | 105 +++++ .../tests/unit/sdk/dms/v1/test_instance.py | 196 ++++++++ .../tests/unit/sdk/dms/v1/test_message.py | 96 ++++ .../tests/unit/sdk/dms/v1/test_mw.py | 41 ++ .../unit/sdk/dms/v1/test_product_spec.py | 54 +++ .../tests/unit/sdk/dms/v1/test_proxy.py | 303 ++++++++++-- .../tests/unit/sdk/dms/v1/test_queue.py | 113 +---- .../tests/unit/sdk/dms/v1/test_quota.py | 48 +- .../tests/unit/sdk/dms/v1/test_topic.py | 57 +++ requirements.txt | 2 +- setup.cfg | 12 +- 93 files changed, 3558 insertions(+), 424 deletions(-) delete mode 100644 doc/source/sdk/resources/dms/v1/group_message.rst create mode 100644 doc/source/sdk/resources/dms/v1/instance.rst create mode 100644 doc/source/sdk/resources/dms/v1/misc create mode 100644 doc/source/sdk/resources/dms/v1/misc.rst delete mode 100644 doc/source/sdk/resources/dms/v1/quota.rst create mode 100644 doc/source/sdk/resources/dms/v1/topic.rst create mode 100644 otcextensions/osclient/dms/v1/az.py create mode 100644 otcextensions/osclient/dms/v1/instance.py create mode 100644 otcextensions/osclient/dms/v1/maintenance_window.py create mode 100644 otcextensions/osclient/dms/v1/product.py create mode 100644 otcextensions/osclient/dms/v1/topic.py create mode 100644 otcextensions/sdk/dms/v1/az.py create mode 100644 otcextensions/sdk/dms/v1/instance.py create mode 100644 otcextensions/sdk/dms/v1/maintenance_window.py create mode 100644 otcextensions/sdk/dms/v1/product.py create mode 100644 otcextensions/sdk/dms/v1/topic.py create mode 100644 otcextensions/tests/functional/sdk/dms/v1/test_instance.py create mode 100644 otcextensions/tests/unit/osclient/dms/v1/test_instance.py create mode 100644 otcextensions/tests/unit/osclient/dms/v1/test_topic.py create mode 100644 otcextensions/tests/unit/sdk/dms/v1/test_az.py create mode 100644 otcextensions/tests/unit/sdk/dms/v1/test_group.py create mode 100644 otcextensions/tests/unit/sdk/dms/v1/test_instance.py create mode 100644 otcextensions/tests/unit/sdk/dms/v1/test_message.py create mode 100644 otcextensions/tests/unit/sdk/dms/v1/test_mw.py create mode 100644 otcextensions/tests/unit/sdk/dms/v1/test_product_spec.py create mode 100644 otcextensions/tests/unit/sdk/dms/v1/test_topic.py diff --git a/doc/source/cli/dms.rst b/doc/source/cli/dms.rst index ce3370d93..e28453920 100644 --- a/doc/source/cli/dms.rst +++ b/doc/source/cli/dms.rst @@ -26,10 +26,24 @@ Group operations .. autoprogram-cliff:: openstack.dms.v1 :command: dms group * -.. _dms_quota: +.. _dms_instance: -Quota operations ----------------- +Instance operations +------------------- + +.. autoprogram-cliff:: openstack.dms.v1 + :command: dms instance * + +.. _dms_misq: + +Misc operations +--------------- + +.. autoprogram-cliff:: openstack.dms.v1 + :command: dms az list + +.. autoprogram-cliff:: openstack.dms.v1 + :command: dms maintenance window list .. autoprogram-cliff:: openstack.dms.v1 - :command: dms quota * + :command: dms product list diff --git a/doc/source/sdk/proxies/dms.rst b/doc/source/sdk/proxies/dms.rst index b9ca1bac2..a4d301f06 100644 --- a/doc/source/sdk/proxies/dms.rst +++ b/doc/source/sdk/proxies/dms.rst @@ -25,9 +25,13 @@ Message Group Operations :noindex: :members: groups, create_group, delete_group -DMS Quota Operations -^^^^^^^^^^^^^^^^^^^^ +Instance Operations +^^^^^^^^^^^^^^^^^^^ .. autoclass:: otcextensions.sdk.dms.v1._proxy.Proxy :noindex: - :members: quotas + :members: instances, find_instance, get_instance, + create_instance, update_instance, delete_instance, + delete_batch, restart_instance, delete_failed, + topics, create_topic, delete_topic, + availability_zones, products, maintenance_windows diff --git a/doc/source/sdk/resources/dms/index.rst b/doc/source/sdk/resources/dms/index.rst index 210555c88..3837c3064 100644 --- a/doc/source/sdk/resources/dms/index.rst +++ b/doc/source/sdk/resources/dms/index.rst @@ -5,7 +5,8 @@ DMS Resources :maxdepth: 1 v1/group - v1/group_message v1/message v1/queue - v1/quota + v1/instance + v1/topic + v1/misc diff --git a/doc/source/sdk/resources/dms/v1/group_message.rst b/doc/source/sdk/resources/dms/v1/group_message.rst deleted file mode 100644 index 94090ce49..000000000 --- a/doc/source/sdk/resources/dms/v1/group_message.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dcs.v1.group_message -====================================== - -.. automodule:: otcextensions.sdk.dms.v1.group_message - -The DMS GroupMessage Class --------------------------- - -The ``GroupMessage`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dms.v1.group_message.GroupMessage - :members: diff --git a/doc/source/sdk/resources/dms/v1/instance.rst b/doc/source/sdk/resources/dms/v1/instance.rst new file mode 100644 index 000000000..fad2b31fe --- /dev/null +++ b/doc/source/sdk/resources/dms/v1/instance.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dcs.v1.instance +================================= + +.. automodule:: otcextensions.sdk.dms.v1.instance + +The DMS Instance Class +---------------------- + +The ``Instance`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dms.v1.instance.Instance + :members: diff --git a/doc/source/sdk/resources/dms/v1/misc b/doc/source/sdk/resources/dms/v1/misc new file mode 100644 index 000000000..027026683 --- /dev/null +++ b/doc/source/sdk/resources/dms/v1/misc @@ -0,0 +1,41 @@ +otcextensions.sdk.dcs.v1.az +=========================== + +.. automodule:: otcextensions.sdk.dms.v1.az + +The DMS Availability Zone Class +------------------------------- + +The ``AvailabilityZone`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dms.v1.az.AvailabilityZone + :members: + +otcextensions.sdk.dcs.v1.product +================================ + +.. automodule:: otcextensions.sdk.dms.v1.product + +The DMS Product Spec Class +-------------------------- + +The ``Product`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dms.v1.product.Product + :members: + +otcextensions.sdk.dcs.v1.maintenance_window +=========================================== + +.. automodule:: otcextensions.sdk.dms.v1.maintenance_window + +The DMS Maintenance window Class +-------------------------------- + +The ``MaintenanceWindow`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dms.v1.maintenance_window.MaintenanceWindow + :members: diff --git a/doc/source/sdk/resources/dms/v1/misc.rst b/doc/source/sdk/resources/dms/v1/misc.rst new file mode 100644 index 000000000..027026683 --- /dev/null +++ b/doc/source/sdk/resources/dms/v1/misc.rst @@ -0,0 +1,41 @@ +otcextensions.sdk.dcs.v1.az +=========================== + +.. automodule:: otcextensions.sdk.dms.v1.az + +The DMS Availability Zone Class +------------------------------- + +The ``AvailabilityZone`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dms.v1.az.AvailabilityZone + :members: + +otcextensions.sdk.dcs.v1.product +================================ + +.. automodule:: otcextensions.sdk.dms.v1.product + +The DMS Product Spec Class +-------------------------- + +The ``Product`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dms.v1.product.Product + :members: + +otcextensions.sdk.dcs.v1.maintenance_window +=========================================== + +.. automodule:: otcextensions.sdk.dms.v1.maintenance_window + +The DMS Maintenance window Class +-------------------------------- + +The ``MaintenanceWindow`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dms.v1.maintenance_window.MaintenanceWindow + :members: diff --git a/doc/source/sdk/resources/dms/v1/quota.rst b/doc/source/sdk/resources/dms/v1/quota.rst deleted file mode 100644 index 5faa27fd5..000000000 --- a/doc/source/sdk/resources/dms/v1/quota.rst +++ /dev/null @@ -1,13 +0,0 @@ -otcextensions.sdk.dcs.v1.quota -============================== - -.. automodule:: otcextensions.sdk.dms.v1.quota - -The DMS Quota Class -------------------- - -The ``Quota`` class inherits from -:class:`~otcextensions.sdk.sdk_resource.Resource`. - -.. autoclass:: otcextensions.sdk.dms.v1.quota.Quota - :members: diff --git a/doc/source/sdk/resources/dms/v1/topic.rst b/doc/source/sdk/resources/dms/v1/topic.rst new file mode 100644 index 000000000..46a04e733 --- /dev/null +++ b/doc/source/sdk/resources/dms/v1/topic.rst @@ -0,0 +1,13 @@ +otcextensions.sdk.dcs.v1.topic +============================== + +.. automodule:: otcextensions.sdk.dms.v1.topic + +The DMS Instance topic Class +---------------------------- + +The ``Topic`` class inherits from +:class:`~otcextensions.sdk.sdk_resource.Resource`. + +.. autoclass:: otcextensions.sdk.dms.v1.topic.Topic + :members: diff --git a/otcextensions/osclient/dms/v1/az.py b/otcextensions/osclient/dms/v1/az.py new file mode 100644 index 000000000..22cf5a843 --- /dev/null +++ b/otcextensions/osclient/dms/v1/az.py @@ -0,0 +1,38 @@ +# 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. +# +'''DMS Instance AZ action implementations''' +from osc_lib import utils +from osc_lib.command import command + +from otcextensions.i18n import _ + + +class ListAZ(command.Lister): + _description = _('List Availability zones') + columns = ('ID', 'name', 'code', 'port', 'has_available_resources') + + def get_parser(self, prog_name): + parser = super(ListAZ, self).get_parser(prog_name) + + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.dms + + data = client.availability_zones() + + table = (self.columns, + (utils.get_item_properties( + s, self.columns, + ) for s in data)) + return table diff --git a/otcextensions/osclient/dms/v1/instance.py b/otcextensions/osclient/dms/v1/instance.py new file mode 100644 index 000000000..f60ca19fe --- /dev/null +++ b/otcextensions/osclient/dms/v1/instance.py @@ -0,0 +1,430 @@ +# 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. +# +'''DMS Instance v1 action implementations''' +from osc_lib import exceptions +from osc_lib import utils +from osc_lib.command import command + +from otcextensions.common import sdk_utils +from otcextensions.i18n import _ + + +INSTANCE_STATUS_CHOICES = ['CREATING', 'CREATEFAILED', 'RUNNING', 'ERROR', + 'STARTING', 'RESTARTING', 'CLOSING', 'FROZEN'] +RETENTION_POLICY_CHOICES = ['produce_reject', 'time_base'] +STORAGE_SPEC_CHOICES = ['dms.physical.storage.high', + 'dms.physical.storage.ultra'] + + +def _get_columns(item): + column_map = {} + hidden = ['location'] + return sdk_utils.get_osc_show_columns_for_sdk_resource(item, column_map, + hidden) + + +class ListDMSInstance(command.Lister): + _description = _('List DMS Instances') + columns = ('ID', 'name', 'engine_name', 'engine_version', + 'storage_spec_code', 'status', 'connect_address', 'router_id', + 'network_id', 'security_group_id', 'user_name', 'storage', + 'total_storage', 'used_storage') + + def get_parser(self, prog_name): + parser = super(ListDMSInstance, self).get_parser(prog_name) + + parser.add_argument( + '--engine-name', + metavar='', + help=_('Engine name') + ) + + parser.add_argument( + '--status', + metavar='{' + ','.join(INSTANCE_STATUS_CHOICES) + '}', + type=lambda s: s.upper(), + choices=INSTANCE_STATUS_CHOICES, + help=_('Instance status') + ) + + parser.add_argument( + '--include-failure', + action='store_true', + help=_('Include instances failed to create') + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.dms + + query_params = {} + for param in ['engine_name', 'status', 'include_failure']: + val = getattr(parsed_args, param) + if val is not None: + query_params[param] = val + + data = client.instances(**query_params) + + table = (self.columns, + (utils.get_item_properties( + s, self.columns, + ) for s in data)) + return table + + +class ShowDMSInstance(command.ShowOne): + _description = _('Show single Instance details') + + def get_parser(self, prog_name): + parser = super(ShowDMSInstance, self).get_parser(prog_name) + parser.add_argument( + 'instance', + metavar='', + help=_('ID of the instance') + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.dms + + obj = client.find_instance(parsed_args.instance) + + display_columns, columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns) + + return (display_columns, data) + + +class DeleteDMSInstance(command.Command): + _description = _('Delete DMS Instance') + + def get_parser(self, prog_name): + parser = super(DeleteDMSInstance, self).get_parser(prog_name) + parser.add_argument( + 'instance', + metavar='', + nargs='+', + help=_('ID of the Instance') + ) + return parser + + def take_action(self, parsed_args): + + if parsed_args.instance: + client = self.app.client_manager.dms + for instance in parsed_args.instance: + client.delete_instance(instance) + + +class CreateDMSInstance(command.ShowOne): + _description = _('Create DMS Instance') + + def get_parser(self, prog_name): + parser = super(CreateDMSInstance, self).get_parser(prog_name) + parser.add_argument( + 'name', + metavar='', + help=_('Name of the instance.') + ) + + parser.add_argument( + '--description', + metavar='', + help=_('Description of the instance.') + ) + parser.add_argument( + '--engine-name', + metavar='', + help=_('Engine name. Currently only Kafka is supported.') + ) + parser.add_argument( + '--engine-version', + metavar='', + help=_('Engine version. Currently only "2.3.0" is supported.') + ) + parser.add_argument( + '--storage', + metavar='', + type=int, + required=True, + help=_('Indicates the message storage space with increments ' + 'of 100 GB:\n' + 'Instance with specification being 100MB: 600–90,000 GB\n' + 'Instance with specification being 300MB: 1,200–90,000 GB\n' + 'Instance with specification being 600MB: 2,400–90,000 GB\n' + 'Instance with specification being 1200MB: 4,800–90,000 GB') + ) + parser.add_argument( + '--access-user', + metavar='', + help=_( + 'This parameter is mandatory when engine is set to kafka and ' + 'ssl_enable is set to true. This parameter is invalid when ' + 'ssl_enable is set to false.\n' + 'Indicates a username. A username consists of 4 to 64 ' + 'characters and supports only letters, digits, hyphens (-), ' + 'and underscores (_).') + ) + parser.add_argument( + '--password', + metavar='', + help=_( + 'This parameter is mandatory when engine is set to kafka and ' + 'ssl_enable is set to true. This parameter is invalid when ' + 'ssl_enable is set to false.\n' + 'An instance password must meet the following complexity ' + 'requirements: \n' + '- Must be a string consisting of 8 to 32 characters.\n' + '- Must contain at least two of the following character ' + 'types: \n' + '-- Lowercase letters\n' + '-- Uppercase letters\n' + '-- Digits\n' + '-- Special characters' + ) + ) + parser.add_argument( + '--router', + metavar='', + required=True, + help=_('Router ID or Name') + ) + parser.add_argument( + '--security-group', + metavar='', + required=True, + help=_('Security group ID or Name') + ) + parser.add_argument( + '--network', + metavar='', + required=True, + help=_('Neutron network ID or Name') + ) + parser.add_argument( + '--availability-zone', + metavar='', + required=True, + action='append', + help=_('List of availability zones') + ) + parser.add_argument( + '--product-id', + metavar='', + required=True, + help=_('Product ID of the DMS instance') + ) + parser.add_argument( + '--maintenance-begin', + metavar='', + help=_('Start of the instance maintenance window') + ) + parser.add_argument( + '--maintenance-end', + metavar='', + help=_('End of the instance maintenance window') + ) + parser.add_argument( + '--enable-public-access', + action='store_true', + help=_('Assign public ip to the instance') + ) + parser.add_argument( + '--enable-ssl', + action='store_true', + help=_('Enable SSL for the public access') + ) + parser.add_argument( + '--public-bandwidth', + metavar='', + type=int, + help=_('Public network bandwidth in Mbit/s:\n' + 'When specification 100MB: 3-900\n' + 'When 300MB: 3-900\n' + 'When 600MB: 4-1200\n' + 'When 1200MB: 8-2400') + ) + parser.add_argument( + '--retention-policy', + metavar='{' + ','.join(RETENTION_POLICY_CHOICES) + '}', + type=lambda s: s.lower(), + choices=RETENTION_POLICY_CHOICES, + help=_('Action to be taken when the memory usage reaches the ' + 'disk capacity threshold. Options:\n' + ' `produce_reject`: New messages cannot be created.\n' + ' `time_base`: The earliest messages are deleted.') + ) + parser.add_argument( + '--storage-spec-code', + metavar='{' + ','.join(STORAGE_SPEC_CHOICES) + '}', + type=lambda s: s.lower(), + choices=STORAGE_SPEC_CHOICES, + help=_('The storage I/O specification of a Kafka instance.\n' + 'When specification is 100MB, the storage I/O can be:' + '[`dms.physical.storage.high`, ' + '`dms.physical.storage.ultra`]\n' + 'When specification is 300MB, the storage I/O can be:' + '[`dms.physical.storage.high`, ' + '`dms.physical.storage.ultra`]\n' + 'When specification is 600MB, the storage I/O is ' + '`dms.physical.storage.ultra`.\n' + 'When specification is 1200MB, the storage I/O is ' + '`dms.physical.storage.ultra`.') + ) + + return parser + + def take_action(self, parsed_args): + + attrs = {} + + attrs['name'] = parsed_args.name + for attr in ['description', 'engine_name', 'engine_version', 'storage', + 'access_user', 'password', 'product_id', + 'maintenance_begin', 'maintenance_end', + 'public_bandwidth', + 'retention_policy', 'storage_spec_code']: + val = getattr(parsed_args, attr) + if val is not None: + attrs[attr] = val + + network_client = self.app.client_manager.network + + router_obj = network_client.find_router(parsed_args.router, + ignore_missing=False) + attrs['router_id'] = router_obj.id + net_obj = network_client.find_network(parsed_args.network, + ignore_missing=False) + attrs['network_id'] = net_obj.id + sg_obj = self.app.client_manager.compute.find_security_group( + parsed_args.security_group, ignore_missing=False) + attrs['security_group_id'] = sg_obj.id + + if parsed_args.availability_zone: + attrs['availability_zone'] = parsed_args.availability_zone + + if parsed_args.maintenance_begin and parsed_args.maintenance_end: + attrs['maintenance_begin'] = parsed_args.maintenance_begin + attrs['maintenance_end'] = parsed_args.maintenance_end + elif parsed_args.maintenance_begin or parsed_args.maintenance_end: + raise exceptions.CommandException(_( + '`maintenance_start` and `maintenance_end` can be set only' + 'together')) + if parsed_args.enable_public_access: + attrs['is_public'] = True + if parsed_args.enable_ssl: + attrs['is_ssl'] = True + + client = self.app.client_manager.dms + + obj = client.create_instance(**attrs) + + display_columns, columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns) + + return (display_columns, data) + + +class UpdateDMSInstance(command.ShowOne): + _description = _('Update DMS Instance') + + def get_parser(self, prog_name): + parser = super(UpdateDMSInstance, self).get_parser(prog_name) + parser.add_argument( + 'instance', + metavar='', + help=_('Name or ID of the DMS instance') + ) + parser.add_argument( + '--name', + metavar='', + help=_('New name of the instance.') + ) + parser.add_argument( + '--description', + metavar='', + help=_('New description of the instance.') + ) + parser.add_argument( + '--security-group', + metavar='', + required=True, + help=_('Security group ID or Name') + ) + parser.add_argument( + '--maintenance-begin', + metavar='', + help=_('Start of the instance maintenance window') + ) + parser.add_argument( + '--maintenance-end', + metavar='', + help=_('End of the instance maintenance window') + ) + return parser + + def take_action(self, parsed_args): + + attrs = {} + + attrs['name'] = parsed_args.name + for attr in ['description', 'maintenance_begin', 'maintenance_end']: + val = getattr(parsed_args, attr) + if val is not None: + attrs[attr] = val + + sg_obj = self.app.client_manager.compute.find_security_group( + parsed_args.security_group, ignore_missing=False) + attrs['security_group_id'] = sg_obj.id + + if parsed_args.maintenance_begin and parsed_args.maintenance_end: + attrs['maintenance_begin'] = parsed_args.maintenance_begin + attrs['maintenance_end'] = parsed_args.maintenance_end + elif parsed_args.maintenance_begin or parsed_args.maintenance_end: + raise exceptions.CommandException(_( + '`maintenance_start` and `maintenance_end` can be set only' + 'together')) + + client = self.app.client_manager.dms + + instance = client.find_instance(parsed_args.instance, + ignore_missing=False) + + obj = client.update_instance(instance, **attrs) + + display_columns, columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns) + + return (display_columns, data) + + +class RestartDMSInstance(command.Command): + _description = _('Restart single Instance') + + def get_parser(self, prog_name): + parser = super(RestartDMSInstance, self).get_parser(prog_name) + parser.add_argument( + 'instance', + metavar='', + help=_('ID of the instance') + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.dms + + obj = client.find_instance(parsed_args.instance, ignore_missing=False) + + client.restart_instance(obj) + + return diff --git a/otcextensions/osclient/dms/v1/maintenance_window.py b/otcextensions/osclient/dms/v1/maintenance_window.py new file mode 100644 index 000000000..1426d0ad0 --- /dev/null +++ b/otcextensions/osclient/dms/v1/maintenance_window.py @@ -0,0 +1,38 @@ +# 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. +# +'''DMS Instance Maintenance Window action implementations''' +from osc_lib import utils +from osc_lib.command import command + +from otcextensions.i18n import _ + + +class ListMW(command.Lister): + _description = _('List Maintenance Windows') + columns = ('seq', 'begin', 'end', 'is_default') + + def get_parser(self, prog_name): + parser = super(ListMW, self).get_parser(prog_name) + + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.dms + + data = client.maintenance_windows() + + table = (self.columns, + (utils.get_item_properties( + s, self.columns, + ) for s in data)) + return table diff --git a/otcextensions/osclient/dms/v1/product.py b/otcextensions/osclient/dms/v1/product.py new file mode 100644 index 000000000..ed8d55302 --- /dev/null +++ b/otcextensions/osclient/dms/v1/product.py @@ -0,0 +1,41 @@ +# 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. +# +'''DMS Product specification action implementations''' + +from osc_lib import utils +from osc_lib.command import command + +from otcextensions.i18n import _ + + +class ListProduct(command.Lister): + _description = _('List Product specs') + columns = ('spec_code', 'engine_name', 'engine_version', 'tps', 'storage', + 'partition_num', 'product_id', 'availability_zones', + 'unavailable_zones') + + def get_parser(self, prog_name): + parser = super(ListProduct, self).get_parser(prog_name) + + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.dms + + data = client.products() + + table = (self.columns, + (utils.get_item_properties( + s, self.columns, + ) for s in data)) + return table diff --git a/otcextensions/osclient/dms/v1/topic.py b/otcextensions/osclient/dms/v1/topic.py new file mode 100644 index 000000000..220e358f3 --- /dev/null +++ b/otcextensions/osclient/dms/v1/topic.py @@ -0,0 +1,172 @@ +# 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. +# +'''DMS Topic v1 action implementations''' +from osc_lib import utils +from osc_lib.command import command + +from otcextensions.common import sdk_utils +from otcextensions.i18n import _ + + +def _get_columns(item): + column_map = {} + hidden = ['location'] + return sdk_utils.get_osc_show_columns_for_sdk_resource(item, column_map, + hidden) + + +class ListDMSInstanceTopic(command.Lister): + _description = _('List DMS Instance topics') + columns = ('ID', 'replication', 'partition', 'retention_time', + 'is_sync_flush', 'is_sync_replication') + + def get_parser(self, prog_name): + parser = super(ListDMSInstanceTopic, self).get_parser(prog_name) + + parser.add_argument( + 'instance', + metavar='', + help=_('DMS Instance name or ID') + ) + return parser + + def take_action(self, parsed_args): + client = self.app.client_manager.dms + + instance_obj = client.find_instance(parsed_args.instance, + ignore_missing=False) + data = client.topics(instance=instance_obj) + + table = (self.columns, + (utils.get_item_properties( + s, self.columns, + ) for s in data)) + return table + + +class DeleteDMSInstanceTopic(command.Command): + _description = _('Delete DMS Instance Topic') + + def get_parser(self, prog_name): + parser = super(DeleteDMSInstanceTopic, self).get_parser(prog_name) + parser.add_argument( + 'instance', + metavar='', + help=_('ID or name of the Instance') + ) + parser.add_argument( + 'topic', + metavar='', + nargs='+', + help=_('Topic ID') + ) + return parser + + def take_action(self, parsed_args): + + if parsed_args.instance: + client = self.app.client_manager.dms + instance = client.find_instance( + parsed_args.instance, + ignore_missing=False) + client.delete_topic(instance=instance, topics=parsed_args.topic) + + +class CreateDMSInstanceTopic(command.ShowOne): + _description = _('Create DMS Instance Topic') + + def get_parser(self, prog_name): + parser = super(CreateDMSInstanceTopic, self).get_parser(prog_name) + parser.add_argument( + 'instance', + metavar='', + help=_('Instance ID or Name.') + ) + parser.add_argument( + 'id', + metavar='', + help=_('Name/ID of the topic.') + ) + parser.add_argument( + '--partition', + metavar='', + type=int, + choices=range(1, 21), + help=_( + 'The number of topic partitions, which is used to set the ' + 'number of concurrently consumed messages. ' + 'Value range: 1–20. Default value: 3.') + ) + parser.add_argument( + '--replication', + metavar='', + type=int, + choices=range(1, 4), + help=_( + 'The number of replicas, which is configured to ensure data ' + 'reliability. Value range: 1–3. Default value: 3.') + ) + parser.add_argument( + '--retention-time', + metavar='', + type=int, + choices=range(1, 169), + default=72, + help=_( + 'The retention period of a message. Its default value is ' + '72. Value range: 1–168. Default value: 72. Unit: hour.') + ) + parser.add_argument( + '--enable-sync-flush', + action='store_true', + help=_( + 'Whether to enable synchronous flushing. ' + 'Default value: false. Synchronous flushing compromises ' + 'performance.') + ) + parser.add_argument( + '--enable-sync-replication', + action='store_true', + help=_( + 'Whether to enable synchronous replication. After this ' + 'function is enabled, the acks parameter on the producer ' + 'client must be set to –1. Otherwise, this parameter does ' + 'not take effect.') + ) + return parser + + def take_action(self, parsed_args): + + attrs = {} + + attrs['id'] = parsed_args.id + for attr in ['partition', 'replication', 'retention_time']: + val = getattr(parsed_args, attr) + if val is not None: + attrs[attr] = val + if parsed_args.enable_sync_flush: + attrs['is_sync_flush'] = True + if parsed_args.enable_sync_replication: + attrs['is_sync_replication'] = True + + client = self.app.client_manager.dms + + instance = client.find_instance(parsed_args.instance, + ignore_missing=False) + + obj = client.create_topic(instance=instance, **attrs) + + display_columns, columns = _get_columns(obj) + data = utils.get_item_properties(obj, columns) + + return (display_columns, data) diff --git a/otcextensions/sdk/dms/v1/_base.py b/otcextensions/sdk/dms/v1/_base.py index 18c2fef69..d8f83592c 100644 --- a/otcextensions/sdk/dms/v1/_base.py +++ b/otcextensions/sdk/dms/v1/_base.py @@ -9,10 +9,100 @@ # 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 otcextensions.sdk import sdk_resource +from openstack import exceptions +from openstack import resource -class Resource(sdk_resource.Resource): - base_path = '' +class Resource(resource.Resource): - service_expectes_json_type = True + @classmethod + def find(cls, session, name_or_id, ignore_missing=True, **params): + """Find a resource by its name or id. + + :param session: The session to use for making this request. + :type session: :class:`~keystoneauth1.adapter.Adapter` + :param name_or_id: This resource's identifier, if needed by + the request. The default is ``None``. + :param bool ignore_missing: When set to ``False`` + :class:`~openstack.exceptions.ResourceNotFound` will be + raised when the resource does not exist. + When set to ``True``, None will be returned when + attempting to find a nonexistent resource. + :param dict params: Any additional parameters to be passed into + underlying methods, such as to + :meth:`~openstack.resource.Resource.existing` + in order to pass on URI parameters. + + :return: The :class:`Resource` object matching the given name or id + or None if nothing matches. + :raises: :class:`openstack.exceptions.DuplicateResource` if more + than one resource is found for this request. + :raises: :class:`openstack.exceptions.ResourceNotFound` if nothing + is found and ignore_missing is ``False``. + """ + session = cls._get_session(session) + # Try to short-circuit by looking directly for a matching ID. + try: + match = cls.existing( + id=name_or_id, + connection=session._get_connection(), + **params) + return match.fetch(session, **params) + except exceptions.SDKException: + pass + + data = cls.list(session, **params) + + result = cls._get_one_match(name_or_id, data) + if result is not None: + return result + + if ignore_missing: + return None + raise exceptions.ResourceNotFound( + "No %s found for %s" % (cls.__name__, name_or_id)) + + @classmethod + def list_override(cls, session, **params): + # Some really stupid APIs are not following any guidelines + # and are under other endpoint (without project id), + # so we need to hack on the endpoint_override yet again + session = cls._get_session(session) + + base_path = cls.base_path + params.pop('paginated', None) + params.pop('base_path', None) + params = cls._query_mapping._validate( + params, base_path=base_path, + allow_unknown_params=False) + query_params = cls._query_mapping._transpose(params, cls) + uri = base_path % params + region_id = None + + # Copy query_params due to weird mock unittest interactions + response = session.get( + uri, + endpoint_override=session.endpoint_override.replace( + '%(project_id)s', ''), + headers={"Accept": "application/json"}, + params=query_params.copy()) + exceptions.raise_from_response(response) + data = response.json() + if 'regionId' in data: + region_id = data['regionId'] + + if cls.resources_key: + resources = data[cls.resources_key] + else: + resources = data + + if not isinstance(resources, list): + resources = [resources] + + for raw_resource in resources: + if region_id: + raw_resource['region_id'] = region_id + value = cls.existing( + connection=session._get_connection(), + **raw_resource) + yield value diff --git a/otcextensions/sdk/dms/v1/_proxy.py b/otcextensions/sdk/dms/v1/_proxy.py index bf9ebe118..601257f8c 100644 --- a/otcextensions/sdk/dms/v1/_proxy.py +++ b/otcextensions/sdk/dms/v1/_proxy.py @@ -10,18 +10,29 @@ # License for the specific language governing permissions and limitations # under the License. -from otcextensions.sdk import sdk_proxy -from otcextensions.sdk.dms.v1 import queue as _queue -from otcextensions.sdk.dms.v1 import quota as _quota +from openstack import exceptions +from openstack import proxy + +from otcextensions.sdk.dms.v1 import az as _az from otcextensions.sdk.dms.v1 import group as _group +from otcextensions.sdk.dms.v1 import instance as _instance +from otcextensions.sdk.dms.v1 import maintenance_window as _mw from otcextensions.sdk.dms.v1 import message as _message -from otcextensions.sdk.dms.v1 import group_message as _group_message +from otcextensions.sdk.dms.v1 import product as _product +from otcextensions.sdk.dms.v1 import queue as _queue +from otcextensions.sdk.dms.v1 import topic as _topic -class Proxy(sdk_proxy.Proxy): +class Proxy(proxy.Proxy): skip_discovery = True + def __init__(self, session, *args, **kwargs): + super(Proxy, self).__init__(session=session, *args, **kwargs) + self.additional_headers = { + 'Content-Type': 'application/json', + } + # ======== Queues ======== def create_queue(self, **kwargs): """Create a queue @@ -31,13 +42,15 @@ def create_queue(self, **kwargs): """ return self._create(_queue.Queue, **kwargs) - def queues(self): + def queues(self, **kwargs): """List all queues + :param dict kwargs: List of query parameters + :returns: A generator of Queue object of :class:`~otcextensions.sdk.dms.v1.queue.Queue` """ - return self._list(_queue.Queue, paginated=False) + return self._list(_queue.Queue, paginated=False, **kwargs) def find_queue(self, name_or_id): """Find queue by name or id @@ -72,44 +85,51 @@ def delete_queue(self, queue, ignore_missing=True): self._delete(_queue.Queue, queue, ignore_missing=ignore_missing) # ======== Groups ======== - def create_group(self, queue, group): + def create_group(self, queue, name): """Create a list consume groups for a queue :param queue: The queue id or an instance of :class:`~otcextensions.sdk.dms.v1.queue.Queue` - :param dict kwargs: Keyword arguments which will be used to overwrite a - :class:`~otcextensions.sdk.dms.v1.queue.Group` + :param str name: Group name to create :returns: A list of object :class:`~otcextensions.sdk.dms.v1.queue.Group` """ + queue_obj = self._get_resource(_queue.Queue, queue) - queue_id = queue - if isinstance(queue, _queue.Queue): - queue_id = queue.id - - # Use a dummy group first to have control over create request - res = _group.Group.new(queue_id=queue_id) + return self._create(_group.Group, queue_id=queue_obj.id, name=name) - return res.create(self, group=group) - - def groups(self, queue, include_deadletter=False): + def groups(self, queue, **kwargs): """List all groups for a given queue :param queue: The queue id or an instance of :class:`~otcextensions.sdk.dms.v1.queue.Queue` + :param dict kwargs: Query parameters + :returns: A generator of Group object :rtype: :class:`~otcextensions.sdk.dms.v1.queue.Group` """ - queue_id = queue - if isinstance(queue, _queue.Queue): - queue_id = queue.id + queue_obj = self._get_resource(_queue.Queue, queue) return self._list(_group.Group, - queue_id=queue_id, - include_deadletter=include_deadletter, - paginated=False) + queue_id=queue_obj.id, + paginated=False, + **kwargs) - def delete_group(self, queue, group): + def find_group(self, queue, name_or_id, ignore_missing=False): + """Find group by name or id + + :param queue: Queue name or object + :param name_or_id: Name or ID + :param ignore_missing: + :returns: one object of class + :class:`~otcextensions.sdk.dms.v1.queue.Queue` + """ + queue_obj = self._get_resource(_queue.Queue, queue) + return self._find(_group.Group, name_or_id, + ignore_missing=ignore_missing, + queue_id=queue_obj.id) + + def delete_group(self, queue, group, ignore_missing=True): """Delete a consume on the queue :param queue: The queue id or an instance of @@ -118,67 +138,275 @@ def delete_group(self, queue, group): :class:`~otcextensions.sdk.dms.v1.group.Group` :returns: ``None`` """ - queue_id = queue - if isinstance(queue, _queue.Queue): - queue_id = queue.id + queue_obj = self._get_resource(_queue.Queue, queue) - self._delete(_group.Group, group, queue_id=queue_id) + self._delete(_group.Group, group, queue_id=queue_obj.id, + ignore_missing=ignore_missing) # ======== Messages ======== - def send_messages(self, queue, **kwargs): + def send_messages(self, queue, messages, return_id=False, **kwargs): """Send messages for a given queue :param queue: The queue id or an instance of :class:`~otcextensions.sdk.dms.v1.queue.Queue` - :param dict kwargs: Keyword to create messages - :returns: dict + :param list messages: A list of message dictionaries + :returns: Messages holder instance + :class:`otcextensions.sdk.dms.v1.message.Messages` + """ + queue_obj = self._get_resource(_queue.Queue, queue) + messages_list = list() + for msg in messages: + if not isinstance(msg, _message.Message): + obj = _message.Message(**msg) + else: + obj = msg + messages_list.append(obj.to_dict(computed=False, ignore_none=True)) + + return self._create(_message.Messages, + base_path='/queues/%(queue_id)s/messages', + queue_id=queue_obj.id, + messages=messages_list, + return_id=return_id) + + def send_message(self, queue, return_id=True, body=None, **attrs): + """Send single message into a given queue + + :param queue: The queue id or an instance of + :class:`~otcextensions.sdk.dms.v1.queue.Queue` + :param bool return_id: Whether response should contain message id + :param body: A str/json object representing message body + :param dict attr: Additional message attributes + :returns: Messages holder instance + :class:`otcextensions.sdk.dms.v1.message.Message` """ - queue_id = queue - if isinstance(queue, _queue.Queue): - queue_id = queue.id + queue_obj = self._get_resource(_queue.Queue, queue) + msg = _message.Message(body=body, **attrs) - return self._create(_message.Message, queue_id=queue_id, **kwargs) + return self._create(_message.Messages, + base_path='/queues/%(queue_id)s/messages', + queue_id=queue_obj.id, + messages=[msg.to_dict(computed=False, + ignore_none=True)], + return_id=return_id).messages[0] - def consume_message(self, queue, consume_group, **query): + def consume_message(self, queue, group, **query): """Consume queue's message :param queue: The queue id or an instance of :class:`~otcextensions.sdk.dms.v1.queue.Queue` - :param consume_group: The consume group id or an instance of + :param group: The consume group id or an instance of :class:`~otcextensions.sdk.dms.v1.group.Group` :param kwargs query: Optional query parameters to be sent to limit the resources being returned. :returns: A list of object :class:`~otcextensions.sdk.dms.v1.group_message.GroupMessage` """ - queue_id = queue - if isinstance(queue, _queue.Queue): - queue_id = queue.id - consumer_group_id = consume_group - if isinstance(consume_group, _group.Group): - consumer_group_id = consume_group.id + queue_obj = self._get_resource(_queue.Queue, queue) + group_obj = self._get_resource(_group.Group, group) return self._list( - _group_message.GroupMessage, - queue_id=queue_id, - consumer_group_id=consumer_group_id, + _message.Message, + base_path='/queues/%(queue_id)s/groups/%(group_id)s/messages', + queue_id=queue_obj.id, + group_id=group_obj.id, **query) - def ack_consumed_message(self, consumed_message, status='success'): + def ack_message(self, queue, group, messages, status='success'): """Confirm consumed message - :param consumed_message: An object of an instance of - :class:`~otcextensions.sdk.dms.v1.group_message.GroupMessage + :param queue: An queue object + :param group: A Queue group object + :param messages: List of messages to be ACKed of + :class:`~otcextensions.sdk.dms.v1.message.Messages :param status: The expeced status of the consumed message :returns: An object of an instance of :class:`~otcextensions.sdk.dms.v1.group_message.GroupMessage` """ - return consumed_message.ack(self.session, status=status) + queue_obj = self._get_resource(_queue.Queue, queue) + group_obj = self._get_resource(_group.Group, group) + + return group_obj.ack(self, queue_obj, messages, status=status) + + # ======== Instances ======= + def instances(self, **kwargs): + """List all DMS Instances + + :param dict kwargs: List of query parameters + + :returns: A generator of Instance object of + :class:`~otcextensions.sdk.dms.v1.instance.Instance` + """ + return self._list(_instance.Instance, paginated=False, **kwargs) + + def create_instance(self, **attrs): + """Create an DMS instance + + :param dict attrs: instance attributes + :class:`~otcextensions.sdk.dms.v1.instance.Instance` + :returns: An instance class object + :class:`~otcextensions.sdk.dms.v1.instance.Instance` + """ + return self._create(_instance.Instance, **attrs) + + def delete_instance(self, instance, ignore_missing=True): + """Delete DMS Instance + + :param instance: The instance id or an object instance of + :class:`~otcextensions.sdk.dms.v1.instance.Instance` + :param bool ignore_missing: When set to ``False`` + :class:`~otcextensions.sdk.exceptions.ResourceNotFound` will be + raised when the instance does not exist. + :returns: `None` + """ + self._delete(_instance.Instance, instance, + ignore_missing=ignore_missing) + + def find_instance(self, name_or_id, ignore_missing=False): + """Find DMS Instance by name or id + + :param name_or_id: Name or ID + :param bool ignore_missing: When set to ``False`` + :class:`~otcextensions.sdk.exceptions.ResourceNotFound` will be + raised when the instance does not exist. + + :returns: one object of class + :class:`~otcextensions.sdk.dms.v1.instance.Instance` + """ + return self._find(_instance.Instance, name_or_id, + ignore_missing=ignore_missing) + + def get_instance(self, instance): + """Get detail about a given instance id + + :param instance: The instance id or an instance of + :class:`~otcextensions.sdk.dms.v1.instance.Instance` + :returns: one object of class + :class:`~otcextensions.sdk.dms.v1.instance.Instance` + """ + return self._get(_instance.Instance, instance) + + def update_instance(self, instance, **attrs): + """Update an Instance + + :param instance: Either the ID of an instance or a + :class:`~otcextensions.sdk.dms.v1.instance.Instance` instance. + :param dict attrs: The attributes to update on the instance + represented by ``value``. + + :returns: The updated instance + :rtype: :class:`~otcextensions.sdk.dms.v1.instance.Instance` + """ + return self._update(_instance.Instance, instance, + **attrs) + + def restart_instance(self, instance): + """Restart instance + + :param instance: Either the ID of an instance or a + :class:`~otcextensions.sdk.dms.v1.instance.Instance` instance. + """ + instance = self._get_resource(_instance.Instance, instance) + return instance.restart(self) + + def restart_instances(self, instances_list): + """Restart multiple instances + """ + dummy_instance = _instance.Instance() + return dummy_instance.restart_batch(self, instances_list) + + def delete_batch(self, instances_list): + """Delete multiple instances + """ + dummy_instance = _instance.Instance() + return dummy_instance.delete_batch(self, instances_list) + + def delete_failed(self): + """Delete failed Kafka instances + """ + dummy_instance = _instance.Instance() + return dummy_instance.delete_failed(self) + + # ======== Topics ======= + def topics(self, instance): + """List all DMS Instance topics + + :param instance: Either the ID of an instance or a + :class:`~otcextensions.sdk.dms.v1.instance.Instance` instance. + :param dict kwargs: List of query parameters + + :returns: A generator of Instance object of + :class:`~otcextensions.sdk.dms.v1.topic.Topic` + """ + instance_obj = self._get_resource(_instance.Instance, instance) + return self._list(_topic.Topic, + instance_id=instance_obj.id + ) + + def create_topic(self, instance, **attrs): + """Create a topic on DMS Instance + + :param instance: instance id or + :class:`~otcextensions.sdk.dms.v1.instance.Instance` + :param dict attrs: Attributes of the topic + :class:`otcextensions.sdk.dms.v1.topic.Topic` + :returns: An topic class object + :class:`~otcextensions.sdk.dms.v1.topic.Topic` + """ + instance_obj = self._get_resource(_instance.Instance, instance) + return self._create(_topic.Topic, + instance_id=instance_obj.id, + **attrs) + + def delete_topic(self, instance, topics, ignore_missing=True): + """Delete topic on DMS instance + + :param instance: The instance id or an object instance of + :class:`~otcextensions.sdk.dms.v1.instance.Instance` + :param list topics: List of topic IDs + :param bool ignore_missing: When set to ``False`` + :class:`~otcextensions.sdk.exceptions.ResourceNotFound` will be + raised when the instance does not exist. + :returns: `None` + """ + instance_obj = self._get_resource(_instance.Instance, instance) + + topics_list = [] + if isinstance(topics, str): + topics_list.append(topics) + elif isinstance(topics, list): + for i in topics: + if isinstance(i, str): + topics_list.append(i) + elif isinstance(i, _topic.Topic): + topics_list.append(i.id) + + response = self.post( + '/instances/%s/topics/delete' % (instance_obj.id), + json={'topics': topics_list} + ) + exceptions.raise_from_response(response) + + # ======== Misc ======= + def availability_zones(self, **kwargs): + """List all supported DMS Instance availability zones + + :returns: A generator of Instance object of AvailabilityZone + :class:`~otcextensions.sdk.dms.v1.az.AvailabilityZone` + """ + return self._list(_az.AvailabilityZone, **kwargs) + + def products(self, **kwargs): + """List all supported DMS products + + :returns: A generator of Product object + :class:`~otcextensions.sdk.dms.v1.product.Product` + """ + return self._list(_product.Product, **kwargs) - def quotas(self): - """List quota + def maintenance_windows(self, **kwargs): + """List all DMS maintenance windows - :returns: A generator of Quota object - :rtype: :class:`~otcextensions.sdk.dms.v1.quota.Quota` + :returns: A generator of MaintenanceWindow object + :class:`~otcextensions.sdk.dms.v1.maintenance_window.MaintenanceWindow` """ - return self._list(_quota.Quota) + return self._list(_mw.MaintenanceWindow, **kwargs) diff --git a/otcextensions/sdk/dms/v1/az.py b/otcextensions/sdk/dms/v1/az.py new file mode 100644 index 000000000..587756083 --- /dev/null +++ b/otcextensions/sdk/dms/v1/az.py @@ -0,0 +1,37 @@ +# 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 resource + +from otcextensions.sdk.dms.v1 import _base + + +class AvailabilityZone(_base.Resource): + """DMS AZ resource""" + resources_key = 'available_zones' + base_path = '/availableZones' + + # capabilities + allow_list = True + + #: Properties + #: AZ code + code = resource.Body('code') + #: Has free resources + has_available_resources = resource.Body('resource_availability', type=bool) + #: Port number + port = resource.Body('port') + #: Region ID + region_id = resource.Body('region_id') + + @classmethod + def list(cls, session, **params): + return super(AvailabilityZone, cls).list_override(session, **params) diff --git a/otcextensions/sdk/dms/v1/group.py b/otcextensions/sdk/dms/v1/group.py index 9290c33f2..893ddde7b 100644 --- a/otcextensions/sdk/dms/v1/group.py +++ b/otcextensions/sdk/dms/v1/group.py @@ -9,28 +9,27 @@ # 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 openstack import exceptions from openstack import resource -# from openstack import utils +from openstack import utils from otcextensions.sdk.dms.v1 import _base -_logger = _log.setup_logging('openstack') - class Group(_base.Resource): # NOTE: we are not interested in the also returned short queue info resources_key = 'groups' - base_path = 'queues/%(queue_id)s/groups' + # capabilities allow_create = True allow_list = True allow_delete = True _query_mapping = resource.QueryParameters( - 'include_deadletter' + 'include_deadletter', 'page_size', 'current_page' + # 'include_messages_num' ) # Properties @@ -56,17 +55,17 @@ class Group(_base.Resource): #: *Type: int* available_deadletters = resource.Body('available_deadletters', type=int) - def create(self, session, group): + def create(self, session, *args, **kwargs): """create group""" - body = {"groups": [{'name': group}]} + body = {"groups": [{'name': self.name}]} request = self._prepare_request(requires_id=False, prepend_key=False) response = session.post( request.url, - json=body, - headers={'Content-Length': str(len(str(body)))}) + json=body + ) # Squize groups into single response entity resp = response.json() @@ -78,3 +77,23 @@ def create(self, session, group): self._body.clean() return self + + def ack(self, session, queue_obj, ids, status='success'): + uri = utils.urljoin(self.base_path, self.id, 'ack') + self.queue_id = queue_obj.id + + uri = uri % self._uri.attributes + + ack_list = list() + for msg in ids: + ack_list.append( + {"handler": msg, + "status": status} + ) + + response = session.post( + uri, json={'message': ack_list} + ) + + exceptions.raise_from_response(response) + return diff --git a/otcextensions/sdk/dms/v1/instance.py b/otcextensions/sdk/dms/v1/instance.py new file mode 100644 index 000000000..5045b5481 --- /dev/null +++ b/otcextensions/sdk/dms/v1/instance.py @@ -0,0 +1,161 @@ +# 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 exceptions +from openstack import resource + +from otcextensions.sdk.dms.v1 import _base + + +class Instance(_base.Resource): + """DMS Instance resource""" + resources_key = 'instances' + base_path = '/instances' + + _query_mapping = resource.QueryParameters( + 'engine_name', 'name', 'status', 'include_failure', + 'exact_match_name', + engine_name='engine', + include_failure='includeFailure', + exact_match_name='exactMatchName' + ) + + # capabilities + allow_list = True + allow_fetch = True + allow_create = True + allow_delete = True + allow_commit = True + + #: Properties + #: The username of an instance. + access_user = resource.Body('access_user') + #: List of availability zones the instance belongs to + availability_zones = resource.Body('available_zones', type=list) + #: Billing mode + charging_mode = resource.Body('charging_mode', type=int) + #: IP address of the instance + connect_address = resource.Body('connect_address') + #: Instance creation time + created_at = resource.Body('created_at') + #: Instance description + description = resource.Body('description') + #: Message engine. + engine_name = resource.Body('engine') + #: Engine version + engine_version = resource.Body('engine_version') + #: Instance id + instance_id = resource.Body('instance_id', alternate_id=True) + #: Associate floating IP + is_public = resource.Body('enable_publicip', type=bool) + #: Enable SSL + is_ssl = resource.Body('ssl_enable', type=bool) + #: Kafka public status + kafka_public_status = resource.Body('kafka_public_status') + #: End time of the maintenance window + maintenance_end = resource.Body('maintain_end') + #: Beginning of the maintenance window + maintenance_start = resource.Body('maintain_begin') + #: Maximum number of partitions + max_partitions = resource.Body('partition_num', type=int) + #: Neutron network ID + network_id = resource.Body('subnet_id') + #: User password + password = resource.Body('password') + #: Port number of the instance + port = resource.Body('port', type=int) + #: Product ID + product_id = resource.Body('product_id') + #: Bandwidth of the public access + public_bandwidth = resource.Body('public_bandwidth', type=int) + #: Retention policy + retention_policy = resource.Body('retention_policy') + #: Router ID + router_id = resource.Body('vpc_id') + #: Router name + router_name = resource.Body('vpc_name') + #: Security group ID + security_group_id = resource.Body('security_group_id') + #: Security group Name + security_group_name = resource.Body('security_group_name') + #: Service type + service_type = resource.Body('service_type') + #: specification of the instance + spec = resource.Body('specification') + #: Specification code of the instance: + #: `dms.instance.kafka.cluster.c3.min` + #: `dms.instance.kafka.cluster.c3.small.2` + #: `dms.instance.kafka.cluster.c3.middle.2` + #: `dms.instance.kafka.cluster.c3.high.2` + spec_code = resource.Body('resource_spec_code') + #: Instance status + #: CREATING, CREATEFAILED, RUNNING, ERROR, STARTING, + #: RESTARTING, CLOSING, FROZEN + status = resource.Body('status') + #: Storage resource ID + storage_resource_id = resource.Body('storage_resource_id') + #: Storage I/O specification code + storage_spec_code = resource.Body('storage_spec_code') + #: Storage type + storage_type = resource.Body('storage_type') + #: Storage space GB + storage = resource.Body('storage_space', type=int) + #: Total storage space GB + total_storage = resource.Body('total_storage_space', type=int) + #: Instance type + type = resource.Body('type') + #: Used storage GB + used_storage = resource.Body('used_storage_space', type=int) + #: User ID + user_id = resource.Body('user_id') + #: User name + user_name = resource.Body('user_name') + + def _action(self, session, action, id_list): + body = { + 'action': action, + 'instances': id_list + } + + response = session.post( + '/instances/action', + json=body + ) + + exceptions.raise_from_response(response) + + return + + def restart(self, session): + """Restart specified instances + """ + return self._action(session, 'restart', [self.id]) + + def restart_batch(self, session, id_list): + return self._action(session, 'restart', id_list) + + def delete_batch(self, session, id_list): + """Delete batch of instances + """ + return self._action(session, 'delete', id_list) + + def delete_failed(self, session): + body = { + 'action': 'delete', + 'allFailure': 'kafka' + } + + response = session.post( + '/instances/action', + json=body + ) + exceptions.raise_from_response(response) + return diff --git a/otcextensions/sdk/dms/v1/maintenance_window.py b/otcextensions/sdk/dms/v1/maintenance_window.py new file mode 100644 index 000000000..e99721e47 --- /dev/null +++ b/otcextensions/sdk/dms/v1/maintenance_window.py @@ -0,0 +1,38 @@ +# 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 resource + +from otcextensions.sdk.dms.v1 import _base + + +class MaintenanceWindow(_base.Resource): + """DMS Maintenance window resource""" + resources_key = 'maintain_windows' + base_path = '/instances/maintain-windows' + + # capabilities + allow_list = True + + #: Properties + #: Indicates the sequential number of a maintenance time window. + seq = resource.Body('seq', type=int) + #: Indicates the time at which a maintenance time window starts. + begin = resource.Body('begin') + #: Indicates the time at which a maintenance time window ends. + end = resource.Body('end') + #: Indicates whether a maintenance time window is set to the + #: default time segment. + is_default = resource.Body('default', type=bool) + + @classmethod + def list(cls, session, **params): + return super(MaintenanceWindow, cls).list_override(session, **params) diff --git a/otcextensions/sdk/dms/v1/message.py b/otcextensions/sdk/dms/v1/message.py index b2d18608a..eaa7b3d48 100644 --- a/otcextensions/sdk/dms/v1/message.py +++ b/otcextensions/sdk/dms/v1/message.py @@ -9,23 +9,106 @@ # 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 exceptions from openstack import resource -from openstack import _log -from otcextensions.sdk.dms.v1 import _base -_logger = _log.setup_logging('openstack') +class Message(resource.Resource): + resource_key = 'message' + base_path = '/queues/%(queue_id)s/groups/%(group_id)s/messages' -class Message(_base.Resource): + allow_list = True + + _query_mapping = resource.QueryParameters( + 'max_msgs', 'time_wait', 'ack_wait' + ) + + #: Queue id + queue_id = resource.URI('queue_id') + #: Group ID (part of URL for listing) + group_id = resource.URI('group_id') + + # Properties + #: Attributes + attributes = resource.Body('attributes', type=dict) + #: Message body + body = resource.Body('body') + #: Error info + error = resource.Body('error') + #: Error code + error_code = resource.Body('error_code') + #: Message handler (ID) + handler = resource.Body('handler', alternate_id=True) + #: State (0 - success) + state = resource.Body('state', type=int) + + def _collect_attrs(self, attrs): + """ Save remaining attributes under "attributes" attribute + """ + body = self._consume_body_attrs(attrs) + header = self._consume_header_attrs(attrs) + uri = self._consume_uri_attrs(attrs) + body['attributes'] = attrs + computed = self._consume_attrs(self._computed_mapping(), attrs) + + return body, header, uri, computed + + @classmethod + def list(cls, session, paginated=True, base_path=None, + allow_unknown_params=False, **params): + + microversion = cls._get_microversion_for_list(session) + + if base_path is None: + base_path = cls.base_path + params = cls._query_mapping._validate( + params, base_path=base_path, + allow_unknown_params=allow_unknown_params) + query_params = cls._query_mapping._transpose(params, cls) + uri = base_path % params + + while uri: + # Copy query_params due to weird mock unittest interactions + response = session.get( + uri, + headers={"Accept": "application/json"}, + params=query_params.copy(), + microversion=microversion) + exceptions.raise_from_response(response) + data = response.json() + resources = data + + if not isinstance(resources, list): + resources = [resources] + + for raw_resource in resources: + attrs = raw_resource.pop('message') + handler = raw_resource.pop('handler') + value = cls.existing( + microversion=microversion, + connection=session._get_connection(), + id=handler, + **attrs) + yield value + + if not resources: + return + + +class Messages(resource.Resource): resources_key = 'messages' base_path = '/queues/%(queue_id)s/messages' # capabilities allow_create = True + allow_list = True # Properties #: Queue id queue_id = resource.URI('queue_id') - messages = resource.Body('messages', type=list) + #: Messages + messages = resource.Body('messages', type=list, list_type=Message) + #: Whether message ID should be returned + return_id = resource.Body('returnId', type=bool) diff --git a/otcextensions/sdk/dms/v1/product.py b/otcextensions/sdk/dms/v1/product.py new file mode 100644 index 000000000..8ce8fa1d0 --- /dev/null +++ b/otcextensions/sdk/dms/v1/product.py @@ -0,0 +1,90 @@ +# 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 exceptions +from openstack import resource + +from otcextensions.sdk.dms.v1 import _base + + +class Product(_base.Resource): + """DMS Product resource""" + base_path = '/products' + resources_key = 'Hourly' + + # capabilities + allow_list = True + + #: Properties + engine_name = resource.Body('engine_name') + engine_version = resource.Body('engine_version') + #: Indicates the maximum number of messages per unit time. + tps = resource.Body('tps') + #: Indicates the message storage space. + storage = resource.Body('storage') + #: Indicates the maximum number of topics in a Kafka instance. + partition_num = resource.Body('partition_num') + #: Indicates the product ID. + product_id = resource.Body('product_id') + #: Indicates the specification ID. + spec_code = resource.Body('spec_code') + #: Indicates the I/O information. + io = resource.Body('io', type=list, list_type=dict) + #: Indicates the bandwidth of a Kafka instance. + bandwidth = resource.Body('bandwidth') + #: Indicates AZs where there are available resources. + availability_zones = resource.Body('available_zones', type=list) + #: Indicated AZs where it is not available + unavailable_zones = resource.Body('unavailable_zones', type=list) + #: Indicates the VM specifications of the instance resources. + vm_flavor_id = resource.Body('ecs_flavor_id') + #: Indicates the instance architecture type. + #: Currently, only x86 is supported. + arch_type = resource.Body('arch_type') + + @classmethod + def list(cls, session, **params): + # This API is a total disaster (b*****it) + # Show me who was so smart to develop it... + session = cls._get_session(session) + + base_path = cls.base_path + params.pop('paginated', None) + params.pop('base_path', None) + params = cls._query_mapping._validate( + params, base_path=base_path, + allow_unknown_params=False) + query_params = cls._query_mapping._transpose(params, cls) + uri = base_path % params + + # Copy query_params due to weird mock unittest interactions + response = session.get( + uri, + endpoint_override=session.endpoint_override.replace( + '%(project_id)s', ''), + headers={"Accept": "application/json"}, + params=query_params.copy()) + exceptions.raise_from_response(response) + data = response.json() + + for k, v in data.items(): + for rec in v: + engine = rec + engine_name = engine.get('name') + engine_version = engine.get('version') + for madness in engine.get('values', []): + for spec in madness.get('detail', []): + value = cls.existing( + connection=session._get_connection(), + engine_name=engine_name, + engine_version=engine_version, + **spec) + yield value diff --git a/otcextensions/sdk/dms/v1/queue.py b/otcextensions/sdk/dms/v1/queue.py index 08c0bbb25..9ba733fa4 100644 --- a/otcextensions/sdk/dms/v1/queue.py +++ b/otcextensions/sdk/dms/v1/queue.py @@ -10,12 +10,9 @@ # License for the specific language governing permissions and limitations # under the License. from openstack import resource -from openstack import _log from otcextensions.sdk.dms.v1 import _base -_logger = _log.setup_logging('openstack') - class Queue(_base.Resource): @@ -26,26 +23,46 @@ class Queue(_base.Resource): # capabilities allow_create = True allow_list = True - allow_get = True + allow_fetch = True allow_delete = True + _query_mapping = resource.QueryParameters( + 'include_deadletter', + 'include_messages_num' + ) + # Properties + #: Created time + #: *Type: int* + created = resource.Body('created', type=int) + #: Description for the queue. + #: The value is a string of a maximum of 160 characters and cannot + #: contain the angle brackets (<>). + description = resource.Body('description') #: Queue Id id = resource.Body('id') + #: Max consume count number + #: *Type: int* + #: Value range: 1–100. + max_consume_count = resource.Body('max_consume_count', type=int) #: Queue name name = resource.Body('name') - #: Queue mode + #: Queue mode: + #: `NORMAL`: Standard queue, which supports high concurrency performance + #: but cannot guarantee that messages are retrieved in the exact + #: sequence as how they are received. + #: `FIFO`: First-in-first-out (FIFO) queue, which guarantees that messages + #: are retrieved in the exact sequence as how they are received. + #: `KAFKA_HA`: High-reliability Kafka queue. All message replicas are + #: flushed to a disk synchronously, ensuring message reliability. + #: `KAFKA_HT`: High-throughput Kafka queue. All message replicas are + #: flushed to a disk asynchronously, ensuring high performance. queue_mode = resource.Body('queue_mode') - #: Description for the queue - description = resource.Body('description') - #: Redrive policy + #: Redrive policy. + #: Supported values: `enable`, `disable`. Default: `disable` redrive_policy = resource.Body('redrive_policy') - #: Max consume count number - #: *Type: int* - max_consume_count = resource.Body('max_consume_count', type=int) - #: Retentions hours + #: Indicates the hours of storing messages in the Kafka queue. + #: This parameter is valid only when queue_mode is set to KAFKA_HA or + #: KAFKA_HT. Value range: 1–72. #: *Type: int* retention_hours = resource.Body('retention_hours', type=int) - #: Created time - #: *Type: int* - created = resource.Body('created', type=int) diff --git a/otcextensions/sdk/dms/v1/quota.py b/otcextensions/sdk/dms/v1/quota.py index 3854277e4..9be46c82d 100644 --- a/otcextensions/sdk/dms/v1/quota.py +++ b/otcextensions/sdk/dms/v1/quota.py @@ -19,7 +19,7 @@ class Quota(_base.Resource): - """AutoScaling Quota resource""" + """DMS Quota resource""" resources_key = 'quotas.resources' base_path = '/quotas/dms' diff --git a/otcextensions/sdk/dms/v1/topic.py b/otcextensions/sdk/dms/v1/topic.py new file mode 100644 index 000000000..bf84a50cb --- /dev/null +++ b/otcextensions/sdk/dms/v1/topic.py @@ -0,0 +1,42 @@ +# 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 resource + +from otcextensions.sdk.dms.v1 import _base + + +class Topic(_base.Resource): + """DMS Topic resource""" + resources_key = 'topics' + base_path = '/instances/%(instance_id)s/topics' + + # capabilities + allow_list = True + allow_create = True + allow_delete = True + +# _query_mapping = resource.QueryParameters('instance_id') + + instance_id = resource.URI('instance_id') + + #: Properties + #: Synchronous flushing. Default=false + is_sync_flush = resource.Body('sync_message_flush', type=bool) + #: Synchronous replication. Default=false. With replication=1 can be only + #: false + is_sync_replication = resource.Body('sync_replication', type=bool) + #: Number of partitions. Default=3 + partition = resource.Body('partition', type=int) + #: Replication factor. Default=3 + replication = resource.Body('replication', type=int) + #: Retention time in hours. Default=72 + retention_time = resource.Body('retention_time', type=int) diff --git a/otcextensions/tests/functional/sdk/dms/v1/test_instance.py b/otcextensions/tests/functional/sdk/dms/v1/test_instance.py new file mode 100644 index 000000000..524f5a54a --- /dev/null +++ b/otcextensions/tests/functional/sdk/dms/v1/test_instance.py @@ -0,0 +1,160 @@ +# 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 openstack +from openstack import exceptions +from openstack import resource + + +from otcextensions.tests.functional import base +import uuid +import random + +_logger = openstack._log.setup_logging('openstack') + + +class TestInstance(base.BaseFunctionalTest): + UUID = uuid.uuid4().hex[:8] + INSTANCE_NAME = 'sdk-test-dms-' + UUID + ROUTER_NAME = 'sdk-test-router-' + UUID + NET_NAME = 'sdk-test-net-' + UUID + SUBNET_NAME = 'sdk-test-subnet-' + UUID + SG_NAME = 'sdk-test-sg-' + UUID + ROUTER_ID = None + NET_ID = None + SUBNET_ID = None + SG_ID = None + instances = [] + + def setUp(self): + super(TestInstance, self).setUp() + self._initialize_network() + products = list(self.conn.dms.products()) + products_ids = [product.product_id for product in products] + product_id = random.choice(products_ids) + availability_zone_names = [ + product.availability_zones for product in products + if product_id == product.product_id + ] + availability_zone_name = random.choice( + sum(availability_zone_names, []) + ) + availability_zone_id = [ + availability_zone.id + for availability_zone in self.conn.dms.availability_zones() + if availability_zone_name == availability_zone.code + ] + try: + self.instance = self.conn.dms.create_instance( + name=self.INSTANCE_NAME, + engine="kafka", engine_version="2.3.0", storage=4800, + router_id=self.ROUTER_ID, network_id=self.NET_ID, + security_group_id=self.SG_ID, + availability_zones=availability_zone_id, + product_id=product_id, + storage_spec_code="dms.physical.storage.ultra" + ) + except exceptions.DuplicateResource: + self.instance = self.conn.dms.find_instance( + alias=self.INSTANCE_NAME + ) + resource.wait_for_status( + session=self.conn.dms, + resource=self.instance, + status='RUNNING', + failures=['CREATEFAILED'], + interval=5, + wait=900) + self.assertIn('instance_id', self.instance) + self.instances.append(self.instance) + + def tearDown(self): + super(TestInstance, self).tearDown() + try: + for instance in self.instances: + if instance.id: + self.conn.dms.delete_instance(instance) + resource.wait_for_delete( + session=self.conn.dms, + resource=instance, + interval=2, + wait=60) + except openstack.exceptions.SDKException as e: + _logger.warning('Got exception during clearing resources %s' + % e.message) + self._deinitialize_network() + + def test_list(self): + self.all_instances = list(self.conn.dms.instances()) + self.assertGreaterEqual(len(self.all_instances), 0) + if len(self.all_instances) > 0: + instance = self.all_instances[0] + instance = self.conn.dms.get_instance(instance=instance.id) + self.assertIsNotNone(instance) + + def _initialize_network(self): + self.cidr = '192.168.0.0/16' + self.ipv4 = 4 + + sg = self.conn.network.create_security_group(name=self.SG_NAME) + self.assertEqual(self.SG_NAME, sg.name) + TestInstance.SG_ID = sg.id + + network = self.conn.network.create_network(name=self.NET_NAME) + self.assertEqual(self.NET_NAME, network.name) + TestInstance.NET_ID = network.id + + subnet = self.conn.network.create_subnet( + name=self.SUBNET_NAME, + ip_version=self.ipv4, + network_id=TestInstance.NET_ID, + cidr=self.cidr + ) + self.assertEqual(self.SUBNET_NAME, subnet.name) + TestInstance.SUBNET_ID = subnet.id + + router = self.conn.network.create_router(name=self.ROUTER_NAME) + self.assertEqual(self.ROUTER_NAME, router.name) + TestInstance.ROUTER_ID = router.id + interface = router.add_interface(self.conn.network, + subnet_id=TestInstance.SUBNET_ID) + self.assertEqual(interface['subnet_id'], TestInstance.SUBNET_ID) + self.assertIn('port_id', interface) + # add CIDR to Router for compatibility + service = self.conn.identity.find_service('vpc') + endpoints = list(self.conn.identity.endpoints(service_id=service.id)) + endpoint_url = endpoints[0].url + endpoint = endpoint_url[:endpoint_url.rfind("/") + 1] + cidr = self.conn.compute.put( + endpoint + self.conn.session.get_project_id() + '/vpcs/' + + self.ROUTER_ID, data='{"vpc": {"cidr": "192.168.0.0/16"}}', + headers={'content-type': 'application/json'}) + self.assertIn('cidr', cidr.json()['vpc']) + self.assertIn('192.168.0.0/16', cidr.json()['vpc']['cidr']) + + def _deinitialize_network(self): + router = self.conn.network.get_router(TestInstance.ROUTER_ID) + interface = router.remove_interface(self.conn.network, + subnet_id=TestInstance.SUBNET_ID) + self.assertEqual(interface['subnet_id'], TestInstance.SUBNET_ID) + self.assertIn('port_id', interface) + sot = self.conn.network.delete_router( + TestInstance.ROUTER_ID, ignore_missing=False) + self.assertIsNone(sot) + sot = self.conn.network.delete_subnet( + TestInstance.SUBNET_ID, ignore_missing=False) + self.assertIsNone(sot) + sot = self.conn.network.delete_network( + TestInstance.NET_ID, ignore_missing=False) + self.assertIsNone(sot) + sot = self.conn.network.delete_security_group( + TestInstance.SG_ID, ignore_missing=False) + self.assertIsNone(sot) diff --git a/otcextensions/tests/functional/sdk/dms/v1/test_message.py b/otcextensions/tests/functional/sdk/dms/v1/test_message.py index 06f9fce0e..2c802f6a3 100644 --- a/otcextensions/tests/functional/sdk/dms/v1/test_message.py +++ b/otcextensions/tests/functional/sdk/dms/v1/test_message.py @@ -35,13 +35,13 @@ def setUp(self): ) except openstack.exceptions.BadRequestException: - self.queue = self.conn.dms.get_queue(TestMessage.QUEUE_ALIAS) + self.queue = self.conn.dms.find_queue(TestMessage.QUEUE_ALIAS) self.queues.append(self.queue) try: self.group = self.conn.dms.create_group( - self.queue, {"name": "test_group"} + self.queue, "test_group" ) except openstack.exceptions.DuplicateResource: @@ -50,6 +50,7 @@ def setUp(self): self.groups.append(self.group) def tearDown(self): + super(TestMessage, self).tearDown() try: for queue in self.queues: if queue.id: @@ -75,7 +76,7 @@ def test_group(self): # self.assertIsNotNone(q) try: self.group = self.conn.dms.create_group( - self.queue, {"name": "test_group"} + self.queue, "test_group2" ) except openstack.exceptions.BadRequestException: @@ -84,7 +85,6 @@ def test_group(self): self.groups.append(self.group) # OS_TEST_TIMEOUT=60 is needed due to testbed slowness - @classmethod def test_message(self): self.queues = list(self.conn.dms.queues()) # self.assertGreaterEqual(len(self.queues), 0) @@ -112,7 +112,7 @@ def test_message(self): self.messages.append(self.message) try: self.group = self.conn.dms.create_group( - self.queue, {"name": "test_group2"} + self.queue, "test_group3" ) except openstack.exceptions.BadRequestException: @@ -120,8 +120,8 @@ def test_message(self): self.groups.append(self.group) - self.received_messages = self.dms.consume_message( + self.received_messages = self.conn.dms.consume_message( self.queue, self.group ) - self.assertGreaterEqual(len(self.received_messages), 0) + self.assertGreaterEqual(len(list(self.received_messages)), 0) diff --git a/otcextensions/tests/functional/sdk/dms/v1/test_queue.py b/otcextensions/tests/functional/sdk/dms/v1/test_queue.py index ece366cfe..db8276d6a 100644 --- a/otcextensions/tests/functional/sdk/dms/v1/test_queue.py +++ b/otcextensions/tests/functional/sdk/dms/v1/test_queue.py @@ -33,6 +33,7 @@ def setUp(self): self.queues.append(self.queue) def tearDown(self): + super(TestQueue, self).tearDown() try: for queue in self.queues: if queue.id: diff --git a/otcextensions/tests/unit/osclient/anti_ddos/v1/fakes.py b/otcextensions/tests/unit/osclient/anti_ddos/v1/fakes.py index 58a0320db..08ca91950 100644 --- a/otcextensions/tests/unit/osclient/anti_ddos/v1/fakes.py +++ b/otcextensions/tests/unit/osclient/anti_ddos/v1/fakes.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/anti_ddos/v1/test_config.py b/otcextensions/tests/unit/osclient/anti_ddos/v1/test_config.py index 6b4893602..6ea446bf0 100644 --- a/otcextensions/tests/unit/osclient/anti_ddos/v1/test_config.py +++ b/otcextensions/tests/unit/osclient/anti_ddos/v1/test_config.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/anti_ddos/v1/test_floating_ip.py b/otcextensions/tests/unit/osclient/anti_ddos/v1/test_floating_ip.py index 2923fa1f8..2dc652ee8 100644 --- a/otcextensions/tests/unit/osclient/anti_ddos/v1/test_floating_ip.py +++ b/otcextensions/tests/unit/osclient/anti_ddos/v1/test_floating_ip.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/anti_ddos/v1/test_status.py b/otcextensions/tests/unit/osclient/anti_ddos/v1/test_status.py index 764549b93..85a8fe8af 100644 --- a/otcextensions/tests/unit/osclient/anti_ddos/v1/test_status.py +++ b/otcextensions/tests/unit/osclient/anti_ddos/v1/test_status.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/auto_scaling/v1/fakes.py b/otcextensions/tests/unit/osclient/auto_scaling/v1/fakes.py index 8a8dc006e..1350684b0 100644 --- a/otcextensions/tests/unit/osclient/auto_scaling/v1/fakes.py +++ b/otcextensions/tests/unit/osclient/auto_scaling/v1/fakes.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_activity.py b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_activity.py index 63132fc85..98cc0aad6 100644 --- a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_activity.py +++ b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_activity.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_config.py b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_config.py index 295e900ff..7c8b62862 100644 --- a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_config.py +++ b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_config.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_group.py b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_group.py index 95e3472fb..276064caa 100644 --- a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_group.py +++ b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_group.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_instance.py b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_instance.py index 9b94ea5d0..d2c0e549c 100644 --- a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_instance.py +++ b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_instance.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_policy.py b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_policy.py index feab2f710..838f2932a 100644 --- a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_policy.py +++ b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_policy.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_quota.py b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_quota.py index 3afe0f49e..968af7c5c 100644 --- a/otcextensions/tests/unit/osclient/auto_scaling/v1/test_quota.py +++ b/otcextensions/tests/unit/osclient/auto_scaling/v1/test_quota.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/cce/v1/fakes.py b/otcextensions/tests/unit/osclient/cce/v1/fakes.py index 2010494c3..d64cea861 100644 --- a/otcextensions/tests/unit/osclient/cce/v1/fakes.py +++ b/otcextensions/tests/unit/osclient/cce/v1/fakes.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/cce/v1/test_cluster.py b/otcextensions/tests/unit/osclient/cce/v1/test_cluster.py index 435eae2cb..1b30b276c 100644 --- a/otcextensions/tests/unit/osclient/cce/v1/test_cluster.py +++ b/otcextensions/tests/unit/osclient/cce/v1/test_cluster.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/cce/v1/test_cluster_node.py b/otcextensions/tests/unit/osclient/cce/v1/test_cluster_node.py index c3fb1a880..6e023e61b 100644 --- a/otcextensions/tests/unit/osclient/cce/v1/test_cluster_node.py +++ b/otcextensions/tests/unit/osclient/cce/v1/test_cluster_node.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/cce/v2/fakes.py b/otcextensions/tests/unit/osclient/cce/v2/fakes.py index 06e9668eb..151e71d96 100644 --- a/otcextensions/tests/unit/osclient/cce/v2/fakes.py +++ b/otcextensions/tests/unit/osclient/cce/v2/fakes.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/cce/v2/test_cluster.py b/otcextensions/tests/unit/osclient/cce/v2/test_cluster.py index 520f2fc86..c80d96b19 100644 --- a/otcextensions/tests/unit/osclient/cce/v2/test_cluster.py +++ b/otcextensions/tests/unit/osclient/cce/v2/test_cluster.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/cce/v2/test_cluster_node.py b/otcextensions/tests/unit/osclient/cce/v2/test_cluster_node.py index 16fbf8cc1..081808607 100644 --- a/otcextensions/tests/unit/osclient/cce/v2/test_cluster_node.py +++ b/otcextensions/tests/unit/osclient/cce/v2/test_cluster_node.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/cts/v1/fakes.py b/otcextensions/tests/unit/osclient/cts/v1/fakes.py index c524ff9ba..221c736ac 100644 --- a/otcextensions/tests/unit/osclient/cts/v1/fakes.py +++ b/otcextensions/tests/unit/osclient/cts/v1/fakes.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/cts/v1/test_trace.py b/otcextensions/tests/unit/osclient/cts/v1/test_trace.py index 6dc390eb1..55d5d4552 100644 --- a/otcextensions/tests/unit/osclient/cts/v1/test_trace.py +++ b/otcextensions/tests/unit/osclient/cts/v1/test_trace.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/cts/v1/test_tracker.py b/otcextensions/tests/unit/osclient/cts/v1/test_tracker.py index c77aee5ba..40c70049b 100644 --- a/otcextensions/tests/unit/osclient/cts/v1/test_tracker.py +++ b/otcextensions/tests/unit/osclient/cts/v1/test_tracker.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/dcs/v1/fakes.py b/otcextensions/tests/unit/osclient/dcs/v1/fakes.py index ef695edf4..92df29892 100644 --- a/otcextensions/tests/unit/osclient/dcs/v1/fakes.py +++ b/otcextensions/tests/unit/osclient/dcs/v1/fakes.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/dcs/v1/test_backup.py b/otcextensions/tests/unit/osclient/dcs/v1/test_backup.py index 909263386..e92b21b16 100644 --- a/otcextensions/tests/unit/osclient/dcs/v1/test_backup.py +++ b/otcextensions/tests/unit/osclient/dcs/v1/test_backup.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/dcs/v1/test_config.py b/otcextensions/tests/unit/osclient/dcs/v1/test_config.py index ef5fe17d2..ebed795e3 100644 --- a/otcextensions/tests/unit/osclient/dcs/v1/test_config.py +++ b/otcextensions/tests/unit/osclient/dcs/v1/test_config.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/dcs/v1/test_instance.py b/otcextensions/tests/unit/osclient/dcs/v1/test_instance.py index 8285d9cea..54c52394a 100644 --- a/otcextensions/tests/unit/osclient/dcs/v1/test_instance.py +++ b/otcextensions/tests/unit/osclient/dcs/v1/test_instance.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/dcs/v1/test_restore.py b/otcextensions/tests/unit/osclient/dcs/v1/test_restore.py index 33a611249..f190b254f 100644 --- a/otcextensions/tests/unit/osclient/dcs/v1/test_restore.py +++ b/otcextensions/tests/unit/osclient/dcs/v1/test_restore.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/dcs/v1/test_statistic.py b/otcextensions/tests/unit/osclient/dcs/v1/test_statistic.py index aa7be28ab..dad2f0cea 100644 --- a/otcextensions/tests/unit/osclient/dcs/v1/test_statistic.py +++ b/otcextensions/tests/unit/osclient/dcs/v1/test_statistic.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/deh/v1/fakes.py b/otcextensions/tests/unit/osclient/deh/v1/fakes.py index bd872d0eb..7934db30e 100644 --- a/otcextensions/tests/unit/osclient/deh/v1/fakes.py +++ b/otcextensions/tests/unit/osclient/deh/v1/fakes.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/deh/v1/test_host.py b/otcextensions/tests/unit/osclient/deh/v1/test_host.py index a7c6ae52e..868948f44 100644 --- a/otcextensions/tests/unit/osclient/deh/v1/test_host.py +++ b/otcextensions/tests/unit/osclient/deh/v1/test_host.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/dms/v1/fakes.py b/otcextensions/tests/unit/osclient/dms/v1/fakes.py index 98cdc66b4..dff892245 100644 --- a/otcextensions/tests/unit/osclient/dms/v1/fakes.py +++ b/otcextensions/tests/unit/osclient/dms/v1/fakes.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 @@ -21,8 +19,22 @@ from otcextensions.tests.unit.osclient import test_base from otcextensions.sdk.dms.v1 import group +from otcextensions.sdk.dms.v1 import instance from otcextensions.sdk.dms.v1 import queue from otcextensions.sdk.dms.v1 import quota +from otcextensions.sdk.dms.v1 import topic + + +def gen_data(data, columns): + """Fill expected data tuple based on columns list + """ + return tuple(getattr(data, attr, '') for attr in columns) + + +def gen_data_dict(data, columns): + """Fill expected data tuple based on columns list + """ + return tuple(data.get(attr, '') for attr in columns) class TestDMS(utils.TestCommand): @@ -84,3 +96,54 @@ def generate(cls): } obj = quota.Quota.existing(**object_info) return obj + + +class FakeInstance(test_base.Fake): + @classmethod + def generate(cls): + object_info = { + 'name': 'name-' + uuid.uuid4().hex, + 'description': 'name-' + uuid.uuid4().hex, + 'engine_name': 'engine-' + uuid.uuid4().hex, + 'engine_version': 'ver-' + uuid.uuid4().hex, + 'storage': random.randint(1, 100), + 'access_user': 'user-' + uuid.uuid4().hex, + 'password': uuid.uuid4().hex, + 'router_id': 'router_id-' + uuid.uuid4().hex, + 'router_name': 'router_name-' + uuid.uuid4().hex, + 'network_id': 'net_id-' + uuid.uuid4().hex, + 'subnet_name': 'subnet_name-' + uuid.uuid4().hex, + 'security_group_id': 'security_group_id-' + uuid.uuid4().hex, + 'security_group_name': 'security_group_name-' + uuid.uuid4().hex, + 'availability_zones': ['az' + uuid.uuid4().hex], + 'product_id': 'product-' + uuid.uuid4().hex, + 'maintenance_begin': 'mb-' + uuid.uuid4().hex, + 'maintenance_end': 'me-' + uuid.uuid4().hex, + 'is_public': random.choice([True, False]), + 'is_ssl': random.choice([True, False]), + 'kafka_public_status': 'kps-' + uuid.uuid4().hex, + 'public_bandwidth': random.randint(1, 100), + 'retention_policy': random.choice(['produce_reject', 'time_base']), + 'storage_spec_code': random.choice(['dms.physical.storage.high', + 'dms.physical.storage.ultra']) + } + + obj = instance.Instance.existing(**object_info) + return obj + + +class FakeTopic(test_base.Fake): + @classmethod + def generate(cls): + object_info = { + 'id': 'id-' + uuid.uuid4().hex, + 'replication': random.randint(1, 3), + 'partition': random.randint(1, 21), + 'retention_time': random.randint(1, 169), + 'is_sync_replication': random.choice([True, False]), + 'is_sync_flush': random.choice([True, False]), + 'instance_id': 'iid-' + uuid.uuid4().hex + } + + obj = topic.Topic.existing(**object_info) + return obj diff --git a/otcextensions/tests/unit/osclient/dms/v1/test_group.py b/otcextensions/tests/unit/osclient/dms/v1/test_group.py index 2539188b8..19daa5d85 100644 --- a/otcextensions/tests/unit/osclient/dms/v1/test_group.py +++ b/otcextensions/tests/unit/osclient/dms/v1/test_group.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/dms/v1/test_instance.py b/otcextensions/tests/unit/osclient/dms/v1/test_instance.py new file mode 100644 index 000000000..f7f061099 --- /dev/null +++ b/otcextensions/tests/unit/osclient/dms/v1/test_instance.py @@ -0,0 +1,427 @@ +# 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 mock + +from otcextensions.osclient.dms.v1 import instance +from otcextensions.tests.unit.osclient.dms.v1 import fakes + + +class TestDMSInstance(fakes.TestDMS): + + def setUp(self): + super(TestDMSInstance, self).setUp() + self.client = self.app.client_manager.dms + + +class TestListDMSInstance(TestDMSInstance): + + instances = fakes.FakeInstance.create_multiple(3) + + columns = ('ID', 'name', 'engine_name', 'engine_version', + 'storage_spec_code', 'status', 'connect_address', + 'router_id', 'network_id', 'security_group_id', + 'user_name', 'storage', 'total_storage', 'used_storage') + + data = [] + + for s in instances: + data.append(( + s.id, + s.name, + s.engine_name, + s.engine_version, + s.storage_spec_code, + s.status, + s.connect_address, + s.router_id, + s.network_id, + s.security_group_id, + s.user_name, + s.storage, + s.total_storage, + s.used_storage + )) + + def setUp(self): + super(TestListDMSInstance, self).setUp() + + self.cmd = instance.ListDMSInstance(self.app, None) + + self.client.instances = mock.Mock() + + def test_list(self): + arglist = [ + ] + + verifylist = [ + ] + + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.instances.side_effect = [ + self.instances + ] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.instances.assert_called_once_with(include_failure=False) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + def test_list_args(self): + arglist = [ + '--engine-name', 'engine', + '--status', 'Creating', + '--include-failure' + ] + + verifylist = [ + ('engine_name', 'engine'), + ('status', 'CREATING'), + ('include_failure', True) + ] + + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.instances.side_effect = [ + self.instances + ] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.instances.assert_called_once_with( + engine_name='engine', + status='CREATING', + include_failure=True) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + +class TestShowDMSInstance(TestDMSInstance): + + _data = fakes.FakeInstance.create_one() + + columns = ('access_user', 'availability_zones', 'description', + 'engine_name', 'engine_version', 'is_public', 'is_ssl', + 'kafka_public_status', 'maintenance_end', 'name', 'network_id', + 'password', 'product_id', 'public_bandwidth', + 'retention_policy', 'router_id', 'router_name', + 'security_group_id', + 'security_group_name', 'storage', 'storage_spec_code') + + data = fakes.gen_data(_data, columns) + + def setUp(self): + super(TestShowDMSInstance, self).setUp() + + self.cmd = instance.ShowDMSInstance(self.app, None) + + self.client.find_instance = mock.Mock() + + def test_show_default(self): + arglist = [ + 'test_instance' + ] + verifylist = [ + ('instance', 'test_instance') + ] + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.find_instance.side_effect = [ + self._data + ] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.find_instance.assert_called() + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + +class TestDeleteDMSInstance(TestDMSInstance): + + def setUp(self): + super(TestDeleteDMSInstance, self).setUp() + + self.cmd = instance.DeleteDMSInstance(self.app, None) + + self.client.delete_instance = mock.Mock() + + def test_delete(self): + arglist = ['t1'] + verifylist = [ + ('instance', ['t1']) + ] + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.delete_instance.side_effect = [{}] + + # Trigger the action + self.cmd.take_action(parsed_args) + + calls = [mock.call('t1')] + + self.client.delete_instance.assert_has_calls(calls) + self.assertEqual(1, self.client.delete_instance.call_count) + + def test_delete_multiple(self): + arglist = [ + 't1', + 't2', + ] + verifylist = [ + ('instance', ['t1', 't2']) + ] + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.delete_instance.side_effect = [{}, {}] + + # Trigger the action + self.cmd.take_action(parsed_args) + + calls = [mock.call('t1'), mock.call('t2')] + + self.client.delete_instance.assert_has_calls(calls) + self.assertEqual(2, self.client.delete_instance.call_count) + + +class TestCreateDMSInstance(TestDMSInstance): + + _data = fakes.FakeInstance.create_one() + + columns = ('access_user', 'availability_zones', 'description', + 'engine_name', 'engine_version', 'is_public', 'is_ssl', + 'kafka_public_status', 'maintenance_end', 'name', 'network_id', + 'password', + 'product_id', 'public_bandwidth', 'retention_policy', + 'router_id', 'router_name', 'security_group_id', + 'security_group_name', 'storage', 'storage_spec_code') + + data = fakes.gen_data(_data, columns) + + def setUp(self): + super(TestCreateDMSInstance, self).setUp() + + self.cmd = instance.CreateDMSInstance(self.app, None) + + self.client.create_instance = mock.Mock() + self.app.client_manager.network = mock.Mock() + self.app.client_manager.network.find_router = mock.Mock() + self.app.client_manager.network.find_network = mock.Mock() + self.app.client_manager.compute = mock.Mock() + + def test_create_default(self): + arglist = [ + 'name', + '--description', 'descr', + '--engine-name', 'kafka', + '--engine-version', '2.1.0', + '--storage', '15', + '--access-user', 'u1', + '--password', 'pwd', + '--router', 'router_id', + '--security-group', 'sg_id', + '--network', 'net_id', + '--availability-zone', 'az1', + '--availability-zone', 'az2', + '--product-id', 'pid', + '--maintenance-begin', 'mwb', + '--maintenance-end', 'mwe', + '--enable-public-access', + '--enable-ssl', + '--public-bandwidth', '14', + '--retention-policy', 'produce_reject', + '--storage-spec-code', 'dms.physical.storage.high' + ] + verifylist = [ + ('name', 'name'), + ('description', 'descr'), + ('engine_name', 'kafka'), + ('engine_version', '2.1.0'), + ('storage', 15), + ('access_user', 'u1'), + ('password', 'pwd'), + ('router', 'router_id'), + ('security_group', 'sg_id'), + ('network', 'net_id'), + ('availability_zone', ['az1', 'az2']), + ('product_id', 'pid'), + ('maintenance_begin', 'mwb'), + ('maintenance_end', 'mwe'), + ('enable_public_access', True), + ('enable_ssl', True), + ('public_bandwidth', 14), + ('retention_policy', 'produce_reject'), + ('storage_spec_code', 'dms.physical.storage.high') + ] + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.create_instance.side_effect = [ + self._data + ] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.app.client_manager.network.find_router.assert_called_with( + 'router_id', ignore_missing=False) + self.app.client_manager.network.find_network.assert_called_with( + 'net_id', ignore_missing=False) + self.app.client_manager.compute.find_security_group.assert_called_with( + 'sg_id', ignore_missing=False) + + self.client.create_instance.assert_called_with( + access_user='u1', + availability_zone=['az1', 'az2'], + description='descr', + engine_name='kafka', + engine_version='2.1.0', + is_public=True, + is_ssl=True, + maintenance_begin='mwb', + maintenance_end='mwe', + name='name', + password='pwd', + product_id='pid', + public_bandwidth=14, + retention_policy='produce_reject', + router_id=mock.ANY, + security_group_id=mock.ANY, + storage=15, + storage_spec_code='dms.physical.storage.high', + network_id=mock.ANY + ) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + +class TestUpdateDMSInstance(TestDMSInstance): + + _data = fakes.FakeInstance.create_one() + + columns = ('access_user', 'availability_zones', 'description', + 'engine_name', 'engine_version', 'is_public', 'is_ssl', + 'kafka_public_status', 'maintenance_end', 'name', 'network_id', + 'password', + 'product_id', 'public_bandwidth', 'retention_policy', + 'router_id', 'router_name', 'security_group_id', + 'security_group_name', 'storage', 'storage_spec_code') + + data = fakes.gen_data(_data, columns) + + def setUp(self): + super(TestUpdateDMSInstance, self).setUp() + + self.cmd = instance.UpdateDMSInstance(self.app, None) + + self.client.update_instance = mock.Mock() + self.client.find_instance = mock.Mock(return_value=self._data) + self.app.client_manager.compute = mock.Mock() + + def test_update_default(self): + arglist = [ + 'inst', + '--name', 'new_name', + '--description', 'descr', + '--security-group', 'sg_id', + '--maintenance-begin', 'mwb', + '--maintenance-end', 'mwe' + ] + verifylist = [ + ('instance', 'inst'), + ('name', 'new_name'), + ('description', 'descr'), + ('security_group', 'sg_id'), + ('maintenance_begin', 'mwb'), + ('maintenance_end', 'mwe'), + ] + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.update_instance.side_effect = [ + self._data + ] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.find_instance.assert_called_with( + 'inst', ignore_missing=False) + self.app.client_manager.compute.find_security_group.assert_called_with( + 'sg_id', ignore_missing=False) + + self.client.update_instance.assert_called_with( + self._data, + description='descr', + maintenance_begin='mwb', + maintenance_end='mwe', + name='new_name', + security_group_id=mock.ANY + ) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) + + +class TestRestartDMSInstance(TestDMSInstance): + + _data = fakes.FakeInstance.create_one() + + def setUp(self): + super(TestRestartDMSInstance, self).setUp() + + self.cmd = instance.RestartDMSInstance(self.app, None) + + self.client.find_instance = mock.Mock() + self.client.restart_instance = mock.Mock() + + def test_show_default(self): + arglist = [ + 'test_instance' + ] + verifylist = [ + ('instance', 'test_instance') + ] + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.find_instance.side_effect = [ + self._data + ] + + # Trigger the action + self.cmd.take_action(parsed_args) + + self.client.find_instance.assert_called_with('test_instance', + ignore_missing=False) + self.client.restart_instance.assert_called_with(self._data) diff --git a/otcextensions/tests/unit/osclient/dms/v1/test_queue.py b/otcextensions/tests/unit/osclient/dms/v1/test_queue.py index 9c5f8c2ca..e8ca7b5a4 100644 --- a/otcextensions/tests/unit/osclient/dms/v1/test_queue.py +++ b/otcextensions/tests/unit/osclient/dms/v1/test_queue.py @@ -1,16 +1,14 @@ -# Copyright 2013 Nebula 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 # -# 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 # -# 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. +# 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 mock from otcextensions.osclient.dms.v1 import queue diff --git a/otcextensions/tests/unit/osclient/dms/v1/test_quota.py b/otcextensions/tests/unit/osclient/dms/v1/test_quota.py index 0ee2a92e8..961bdaaab 100644 --- a/otcextensions/tests/unit/osclient/dms/v1/test_quota.py +++ b/otcextensions/tests/unit/osclient/dms/v1/test_quota.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/dms/v1/test_topic.py b/otcextensions/tests/unit/osclient/dms/v1/test_topic.py new file mode 100644 index 000000000..5efe5ae40 --- /dev/null +++ b/otcextensions/tests/unit/osclient/dms/v1/test_topic.py @@ -0,0 +1,196 @@ +# 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 mock + +from otcextensions.osclient.dms.v1 import topic +from otcextensions.tests.unit.osclient.dms.v1 import fakes + + +class TestDMSInstanceTopic(fakes.TestDMS): + + def setUp(self): + super(TestDMSInstanceTopic, self).setUp() + self.client = self.app.client_manager.dms + self.instance = fakes.FakeInstance.create_one() + self.client.find_instance = mock.Mock(return_value=self.instance) + + +class TestListDMSInstanceTopic(TestDMSInstanceTopic): + + topics = fakes.FakeTopic.create_multiple(3) + + columns = ('ID', 'replication', 'partition', 'retention_time', + 'is_sync_flush', 'is_sync_replication') + + data = [] + + for s in topics: + data.append(( + s.id, + s.replication, + s.partition, + s.retention_time, + s.is_sync_flush, + s.is_sync_replication + )) + + def setUp(self): + super(TestListDMSInstanceTopic, self).setUp() + + self.cmd = topic.ListDMSInstanceTopic(self.app, None) + + self.client.topics = mock.Mock() + + def test_list_topics(self): + arglist = [ + 'inst' + ] + + verifylist = [ + ('instance', 'inst') + ] + + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.topics.side_effect = [ + self.topics + ] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.find_instance.assert_called_once_with( + 'inst', ignore_missing=False) + self.client.topics.assert_called_once_with(instance=self.instance) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, list(data)) + + +class TestDeleteDMSInstanceTopic(TestDMSInstanceTopic): + + def setUp(self): + super(TestDeleteDMSInstanceTopic, self).setUp() + + self.cmd = topic.DeleteDMSInstanceTopic(self.app, None) + + self.client.delete_topic = mock.Mock() + + def test_delete(self): + arglist = ['inst', 't1'] + verifylist = [ + ('instance', 'inst'), + ('topic', ['t1']) + ] + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.delete_instance.side_effect = [{}] + + # Trigger the action + self.cmd.take_action(parsed_args) + + calls = [mock.call(instance=self.instance, topics=['t1'])] + + self.client.find_instance.assert_called_with( + 'inst', ignore_missing=False) + self.client.delete_topic.assert_has_calls(calls) + self.assertEqual(1, self.client.delete_topic.call_count) + + def test_delete_multiple(self): + arglist = [ + 'inst', + 't1', + 't2', + ] + verifylist = [ + ('instance', 'inst'), + ('topic', ['t1', 't2']) + ] + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.delete_instance.side_effect = [{}, {}] + + # Trigger the action + self.cmd.take_action(parsed_args) + + calls = [mock.call(instance=self.instance, topics=['t1', 't2'])] + + self.client.find_instance.assert_called_with( + 'inst', ignore_missing=False) + self.client.delete_topic.assert_has_calls(calls) + self.assertEqual(1, self.client.delete_topic.call_count) + + +class TestCreateDMSInstanceTopic(TestDMSInstanceTopic): + + _data = fakes.FakeTopic.create_one() + + columns = ('id', 'is_sync_flush', 'is_sync_replication', 'partition', + 'replication', 'retention_time') + + data = fakes.gen_data(_data, columns) + + def setUp(self): + super(TestCreateDMSInstanceTopic, self).setUp() + + self.cmd = topic.CreateDMSInstanceTopic(self.app, None) + + self.client.create_topic = mock.Mock() + + def test_create_default(self): + arglist = [ + 'inst', + 'topic', + '--partition', '5', + '--replication', '3', + '--retention-time', '8', + '--enable-sync-flush', + '--enable-sync-replication' + ] + verifylist = [ + ('instance', 'inst'), + ('id', 'topic'), + ('partition', 5), + ('replication', 3), + ('retention_time', 8), + ('enable_sync_flush', True), + ('enable_sync_replication', True), + ] + # Verify cm is triggereg with default parameters + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + # Set the response + self.client.create_topic.side_effect = [ + self._data + ] + + # Trigger the action + columns, data = self.cmd.take_action(parsed_args) + + self.client.create_topic.assert_called_with( + instance=self.instance, + id='topic', + is_sync_flush=True, + is_sync_replication=True, + partition=5, + replication=3, + retention_time=8 + ) + + self.assertEqual(self.columns, columns) + self.assertEqual(self.data, data) diff --git a/otcextensions/tests/unit/osclient/dns/v2/test_ptr.py b/otcextensions/tests/unit/osclient/dns/v2/test_ptr.py index 72154fa26..5e45317fe 100644 --- a/otcextensions/tests/unit/osclient/dns/v2/test_ptr.py +++ b/otcextensions/tests/unit/osclient/dns/v2/test_ptr.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/dns/v2/test_recordset.py b/otcextensions/tests/unit/osclient/dns/v2/test_recordset.py index 30603b4ef..17ce97412 100644 --- a/otcextensions/tests/unit/osclient/dns/v2/test_recordset.py +++ b/otcextensions/tests/unit/osclient/dns/v2/test_recordset.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/dns/v2/test_zone.py b/otcextensions/tests/unit/osclient/dns/v2/test_zone.py index 7fddab12c..0e3c70260 100644 --- a/otcextensions/tests/unit/osclient/dns/v2/test_zone.py +++ b/otcextensions/tests/unit/osclient/dns/v2/test_zone.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/kms/v1/fakes.py b/otcextensions/tests/unit/osclient/kms/v1/fakes.py index 7fcc15626..7bd9685f0 100644 --- a/otcextensions/tests/unit/osclient/kms/v1/fakes.py +++ b/otcextensions/tests/unit/osclient/kms/v1/fakes.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/kms/v1/test_cmk.py b/otcextensions/tests/unit/osclient/kms/v1/test_cmk.py index 0e1eebd29..f54e4f794 100644 --- a/otcextensions/tests/unit/osclient/kms/v1/test_cmk.py +++ b/otcextensions/tests/unit/osclient/kms/v1/test_cmk.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/load_balancer/v1/fakes.py b/otcextensions/tests/unit/osclient/load_balancer/v1/fakes.py index e232e9717..04203b43e 100644 --- a/otcextensions/tests/unit/osclient/load_balancer/v1/fakes.py +++ b/otcextensions/tests/unit/osclient/load_balancer/v1/fakes.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/load_balancer/v1/test_health_monitor.py b/otcextensions/tests/unit/osclient/load_balancer/v1/test_health_monitor.py index 19550e127..06286ad8e 100644 --- a/otcextensions/tests/unit/osclient/load_balancer/v1/test_health_monitor.py +++ b/otcextensions/tests/unit/osclient/load_balancer/v1/test_health_monitor.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/load_balancer/v1/test_listener.py b/otcextensions/tests/unit/osclient/load_balancer/v1/test_listener.py index 291c39b98..3dee1d0e9 100644 --- a/otcextensions/tests/unit/osclient/load_balancer/v1/test_listener.py +++ b/otcextensions/tests/unit/osclient/load_balancer/v1/test_listener.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/load_balancer/v1/test_load_balancer.py b/otcextensions/tests/unit/osclient/load_balancer/v1/test_load_balancer.py index f7449b435..e3e252fd3 100644 --- a/otcextensions/tests/unit/osclient/load_balancer/v1/test_load_balancer.py +++ b/otcextensions/tests/unit/osclient/load_balancer/v1/test_load_balancer.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/load_balancer/v1/test_pool.py b/otcextensions/tests/unit/osclient/load_balancer/v1/test_pool.py index 41cd76a99..7d2c2d859 100644 --- a/otcextensions/tests/unit/osclient/load_balancer/v1/test_pool.py +++ b/otcextensions/tests/unit/osclient/load_balancer/v1/test_pool.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/load_balancer/v1/test_pool_member.py b/otcextensions/tests/unit/osclient/load_balancer/v1/test_pool_member.py index 6cc11270d..4ae9ce7f2 100644 --- a/otcextensions/tests/unit/osclient/load_balancer/v1/test_pool_member.py +++ b/otcextensions/tests/unit/osclient/load_balancer/v1/test_pool_member.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/obs/v1/fakes.py b/otcextensions/tests/unit/osclient/obs/v1/fakes.py index 9748c41da..7858fc90b 100644 --- a/otcextensions/tests/unit/osclient/obs/v1/fakes.py +++ b/otcextensions/tests/unit/osclient/obs/v1/fakes.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/rds/v1/fakes.py b/otcextensions/tests/unit/osclient/rds/v1/fakes.py index a0ecae7b6..89f5b6d7f 100644 --- a/otcextensions/tests/unit/osclient/rds/v1/fakes.py +++ b/otcextensions/tests/unit/osclient/rds/v1/fakes.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/rds/v1/test_backup.py b/otcextensions/tests/unit/osclient/rds/v1/test_backup.py index 90f6e4490..f1c0a9afd 100644 --- a/otcextensions/tests/unit/osclient/rds/v1/test_backup.py +++ b/otcextensions/tests/unit/osclient/rds/v1/test_backup.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/rds/v1/test_configuration.py b/otcextensions/tests/unit/osclient/rds/v1/test_configuration.py index 2819845a6..dd17e1598 100644 --- a/otcextensions/tests/unit/osclient/rds/v1/test_configuration.py +++ b/otcextensions/tests/unit/osclient/rds/v1/test_configuration.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/rds/v1/test_datastore.py b/otcextensions/tests/unit/osclient/rds/v1/test_datastore.py index 7feb851e4..3ee5a06e0 100644 --- a/otcextensions/tests/unit/osclient/rds/v1/test_datastore.py +++ b/otcextensions/tests/unit/osclient/rds/v1/test_datastore.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/rds/v1/test_flavor.py b/otcextensions/tests/unit/osclient/rds/v1/test_flavor.py index 5116d158e..ff4106723 100644 --- a/otcextensions/tests/unit/osclient/rds/v1/test_flavor.py +++ b/otcextensions/tests/unit/osclient/rds/v1/test_flavor.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/rds/v1/test_instance.py b/otcextensions/tests/unit/osclient/rds/v1/test_instance.py index 9fa0c88c3..b05745cf3 100644 --- a/otcextensions/tests/unit/osclient/rds/v1/test_instance.py +++ b/otcextensions/tests/unit/osclient/rds/v1/test_instance.py @@ -1,5 +1,3 @@ -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/osclient/test_base.py b/otcextensions/tests/unit/osclient/test_base.py index 12dee68ea..e944614e0 100644 --- a/otcextensions/tests/unit/osclient/test_base.py +++ b/otcextensions/tests/unit/osclient/test_base.py @@ -1,6 +1,3 @@ -# Copyright 2012-2013 OpenStack Foundation -# Copyright 2013 Nebula 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 diff --git a/otcextensions/tests/unit/sdk/dms/v1/test_az.py b/otcextensions/tests/unit/sdk/dms/v1/test_az.py new file mode 100644 index 000000000..675966a25 --- /dev/null +++ b/otcextensions/tests/unit/sdk/dms/v1/test_az.py @@ -0,0 +1,92 @@ +# 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 keystoneauth1 import adapter + +from unittest import mock + +from openstack.tests.unit import base + +from otcextensions.sdk.dms.v1 import az + + +JSON_DATA = { + 'id': '1d7b939b382c4c3bb3481a8ca10da768', + 'name': 'az10.dc1', + 'code': 'az10.dc1', + 'port': '8002', + 'resource_availability': True +} + +JSON_LIST = { + 'regionId': 'fake_region', + 'available_zones': [{ + 'id': '1d7b939b382c4c3bb3481a8ca10da768', + 'name': 'az10.dc1', + 'code': 'az10.dc1', + 'port': '8002', + 'resource_availability': 'true' + }, { + 'id': '1d7b939b382c4c3bb3481a8ca10da769', + 'name': 'az10.dc2', + 'code': 'az10.dc2', + 'port': '8002', + 'resource_availability': 'true' + }] +} + + +class TestAZ(base.TestCase): + + def setUp(self): + super(TestAZ, self).setUp() + self.sess = mock.Mock(spec=adapter.Adapter) + self.sess.get = mock.Mock() + self.sess.endpoint_override = 'fake/%(project_id)s' + self.sess._get_connection = mock.Mock() + + def test_basic(self): + sot = az.AvailabilityZone() + + self.assertEqual('/availableZones', sot.base_path) + self.assertEqual('available_zones', sot.resources_key) + + self.assertTrue(sot.allow_list) + + def test_make_it(self): + + sot = az.AvailabilityZone(**JSON_DATA) + self.assertEqual(JSON_DATA['id'], sot.id) + self.assertEqual(JSON_DATA['name'], sot.name) + self.assertEqual(JSON_DATA['code'], sot.code) + self.assertEqual(JSON_DATA['port'], sot.port) + self.assertEqual(JSON_DATA['resource_availability'], + sot.has_available_resources) + + def test_list(self): + sot = az.AvailabilityZone() + + response = mock.Mock() + response.status_code = 200 + response.json = mock.Mock(return_value=JSON_LIST) + self.sess.get.return_value = response + + rsp = list(sot.list(self.sess)) + + self.sess.get.assert_called_with( + '/availableZones', + endpoint_override='fake/', + headers={'Accept': 'application/json'}, + params={} + ) + + self.assertIsInstance(rsp[0], az.AvailabilityZone) + self.assertEqual(JSON_LIST['regionId'], rsp[0].region_id) diff --git a/otcextensions/tests/unit/sdk/dms/v1/test_group.py b/otcextensions/tests/unit/sdk/dms/v1/test_group.py new file mode 100644 index 000000000..53d85e62c --- /dev/null +++ b/otcextensions/tests/unit/sdk/dms/v1/test_group.py @@ -0,0 +1,105 @@ +# 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 keystoneauth1 import adapter + +from unittest import mock + +from openstack.tests.unit import base + +from otcextensions.sdk.dms.v1 import group + +GROUP_EXAMPLE = { + "queue_name": "queue_001", + "groups": [{ + "id": "g-5ec247fd-d4a2-4d4f-9876-e4ff3280c461", + "name": "abcDffD", + "produced_messages": 0, + "consumed_messages": 0, + "available_messages": 0 + }], + "redrive_policy": "enable", + "queue_id": "9bf46390-38a2-462d-b392-4d5b2d519c55" +} + + +class TestGroup(base.TestCase): + + example = GROUP_EXAMPLE['groups'][0] + objcls = group.Group + + def setUp(self): + super(TestGroup, self).setUp() + self.sess = mock.Mock(spec=adapter.Adapter) + self.sess.default_microversion = None + + def test_basic(self): + sot = self.objcls() + + self.assertEqual('queues/%(queue_id)s/groups', sot.base_path) + + self.assertDictEqual({ + 'current_page': 'current_page', + 'include_deadletter': 'include_deadletter', + 'limit': 'limit', + 'marker': 'marker', + 'page_size': 'page_size'}, + sot._query_mapping._mapping + ) + + def test_make_it(self): + + sot = self.objcls(**self.example) + self.assertEqual(self.example['id'], sot.id) + self.assertEqual(self.example['name'], sot.name) + self.assertEqual( + self.example['produced_messages'], + sot.produced_messages) + self.assertEqual( + self.example['consumed_messages'], + sot.consumed_messages) + self.assertEqual( + self.example['available_messages'], + sot.available_messages) + + def test_create(self): + sot = group.Group(queue_id='qid', name='grp') + + response = mock.Mock() + response.body = {'groups': [{'id': '1', 'name': 'grp'}]} + response.json = mock.Mock(return_value=response.body) + self.sess.post = mock.Mock(return_value=response) + + obj = sot.create(self.sess) + self.sess.post.assert_called_with( + 'queues/qid/groups', + json={'groups': [{'name': 'grp'}]} + ) + self.assertEqual('grp', obj.name) + self.assertEqual('1', obj.id) + + def test_ack(self): + sot = group.Group(queue_id='qid', id='gid') + + response = mock.Mock() + response.json = mock.Mock(return_value={}) + response.status_code = 200 + self.sess.post = mock.Mock(return_value=response) + + sot.ack(self.sess, mock.Mock(id='qid'), ['1', '2'], 'failure') + + self.sess.post.assert_called_with( + 'queues/qid/groups/gid/ack', + json={'message': [ + {'handler': '1', 'status': 'failure'}, + {'handler': '2', 'status': 'failure'} + ]} + ) diff --git a/otcextensions/tests/unit/sdk/dms/v1/test_instance.py b/otcextensions/tests/unit/sdk/dms/v1/test_instance.py new file mode 100644 index 000000000..2b5ac40b5 --- /dev/null +++ b/otcextensions/tests/unit/sdk/dms/v1/test_instance.py @@ -0,0 +1,196 @@ +# 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 keystoneauth1 import adapter + +from unittest import mock + +from openstack.tests.unit import base + +from otcextensions.sdk.dms.v1 import instance + + +JSON_DATA = { + "name": "kafka-test", + "description": "", + "engine": "kafka", + "engine_version": "2.3.0", + "storage_space": 600, + "access_user": "", + "password": "", + "vpc_id": "1e93f86e-13af-46c8-97d6-d40fa62b76c2", + "security_group_id": "0aaa0033-bf7f-4c41-a6c2-18cd04cad2c8", + "subnet_id": "b5fa806c-35e7-4299-b659-b39398dd4718", + "available_zones": ["d573142f24894ef3bd3664de068b44b0"], + "product_id": "00300-30308-0--0", + "maintain_begin": "22:00", + "maintain_end": "02:00", + "ssl_enable": False, + "enable_publicip": False, + "publicip_id": "", + "enterprise_project_id": "0", + "specification": "100MB", + "partition_num": "300", + "retention_policy": "produce_reject", + "connector_enable": False, + "storage_spec_code": "dms.physical.storage.ultra" +} + + +class TestInstance(base.TestCase): + + def setUp(self): + super(TestInstance, self).setUp() + self.sess = mock.Mock(spec=adapter.Adapter) + self.sess.post = mock.Mock() + + def test_basic(self): + sot = instance.Instance() + + self.assertEqual('/instances', sot.base_path) + self.assertEqual('instances', sot.resources_key) + + self.assertTrue(sot.allow_create) + self.assertTrue(sot.allow_list) + self.assertTrue(sot.allow_fetch) + self.assertTrue(sot.allow_commit) + self.assertTrue(sot.allow_delete) + + self.assertDictEqual({ + 'engine_name': 'engine', + 'exact_match_name': 'exactMatchName', + 'include_failure': 'includeFailure', + 'limit': 'limit', + 'marker': 'marker', + 'name': 'name', + 'status': 'status'}, + sot._query_mapping._mapping + ) + + def test_make_it(self): + sot = instance.Instance(**JSON_DATA) + self.assertEqual(JSON_DATA['name'], sot.name) + self.assertEqual(JSON_DATA['access_user'], sot.access_user) + self.assertEqual(JSON_DATA['available_zones'], sot.availability_zones) + self.assertEqual(JSON_DATA.get('charging_mode', None), + sot.charging_mode) + self.assertEqual(JSON_DATA.get('connect_address', None), + sot.connect_address) + self.assertEqual(JSON_DATA.get('created_at', None), + sot.created_at) + self.assertEqual(JSON_DATA.get('description', None), + sot.description) + self.assertEqual(JSON_DATA.get('engine', None), + sot.engine_name) + self.assertEqual(JSON_DATA.get('engine_version', None), + sot.engine_version) + self.assertEqual(JSON_DATA.get('instance_id', None), + sot.id) + self.assertEqual(JSON_DATA.get('enable_publicip', False), + sot.is_public) + self.assertEqual(JSON_DATA.get('ssl_enable', None), + sot.is_ssl) + self.assertEqual(JSON_DATA.get('kafka_public_status', None), + sot.kafka_public_status) + self.assertEqual(JSON_DATA.get('maintain_end', None), + sot.maintenance_end) + self.assertEqual(JSON_DATA.get('maintain_begin', None), + sot.maintenance_start) + self.assertEqual(int(JSON_DATA.get('partition_num', None)), + sot.max_partitions) + self.assertEqual(JSON_DATA.get('password', None), + sot.password) + self.assertEqual(JSON_DATA.get('port', None), + sot.port) + self.assertEqual(JSON_DATA.get('product_id', None), + sot.product_id) + self.assertEqual(JSON_DATA.get('public_bandwidth', None), + sot.public_bandwidth) + self.assertEqual(JSON_DATA.get('retention_policy', None), + sot.retention_policy) + self.assertEqual(JSON_DATA.get('vpc_id', None), + sot.router_id) + self.assertEqual(JSON_DATA.get('vpc_name', None), + sot.router_name) + self.assertEqual(JSON_DATA.get('security_group_id', None), + sot.security_group_id) + self.assertEqual(JSON_DATA.get('security_group_name', None), + sot.security_group_name) + self.assertEqual(JSON_DATA.get('service_type', None), + sot.service_type) + self.assertEqual(JSON_DATA.get('specification', None), + sot.spec) + self.assertEqual(JSON_DATA.get('resource_spec_code', None), + sot.spec_code) + self.assertEqual(JSON_DATA.get('status', None), + sot.status) + self.assertEqual(JSON_DATA.get('storage_resource_id', None), + sot.storage_resource_id) + self.assertEqual(JSON_DATA.get('storage_spec_code', None), + sot.storage_spec_code) + self.assertEqual(JSON_DATA.get('storage_type', None), + sot.storage_type) + self.assertEqual(JSON_DATA.get('storage_space', None), + sot.storage) + self.assertEqual(JSON_DATA.get('subnet_id', None), + sot.network_id) + self.assertEqual(JSON_DATA.get('total_storage_space', None), + sot.total_storage) + self.assertEqual(JSON_DATA.get('type', None), + sot.type) + self.assertEqual(JSON_DATA.get('used_storage_space', None), + sot.storage_type) + self.assertEqual(JSON_DATA.get('user_id', None), + sot.user_id) + self.assertEqual(JSON_DATA.get('user_name', None), + sot.user_name) + + def test_restart(self): + sot = instance.Instance(id='1') + response = mock.Mock() + response.status_code = 200 + + self.sess.post.return_value = response + + sot.restart(self.sess) + + self.sess.post.assert_called_with( + '/instances/action', + json={'action': 'restart', 'instances': ['1']} + ) + + sot.restart_batch(self.sess, ['1', '2']) + + self.sess.post.assert_called_with( + '/instances/action', + json={'action': 'restart', 'instances': ['1', '2']} + ) + + def test_delete(self): + sot = instance.Instance() + response = mock.Mock() + response.status_code = 200 + + self.sess.post.return_value = response + + sot.delete_batch(self.sess, ['1', '2']) + + self.sess.post.assert_called_with( + '/instances/action', + json={'action': 'delete', 'instances': ['1', '2']} + ) + + sot.delete_failed(self.sess) + + self.sess.post.assert_called_with( + '/instances/action', + json={'action': 'delete', 'allFailure': 'kafka'} + ) diff --git a/otcextensions/tests/unit/sdk/dms/v1/test_message.py b/otcextensions/tests/unit/sdk/dms/v1/test_message.py new file mode 100644 index 000000000..30fa4dd95 --- /dev/null +++ b/otcextensions/tests/unit/sdk/dms/v1/test_message.py @@ -0,0 +1,96 @@ +# 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.tests.unit import base + +from otcextensions.sdk.dms.v1 import message + + +MESSAGES_EXAMPLE = { + "messages": [ + { + "body": "TEST11", + "attributes": { + "attribute1": "value1", + "attribute2": "value2" + }, + }, { + "body": { + "foo": "test02" + }, + "attributes": { + "attribute1": "value1", + "attribute2": "value2" + }, + } + ] +} + + +class TestMessage(base.TestCase): + + def test_basic(self): + sot = message.Message() + + self.assertEqual( + '/queues/%(queue_id)s/groups/%(group_id)s/messages', + sot.base_path) + self.assertEqual('message', sot.resource_key) + self.assertTrue(sot.allow_list) + + self.assertDictEqual({ + 'ack_wait': 'ack_wait', + 'limit': 'limit', + 'marker': 'marker', + 'max_msgs': 'max_msgs', + 'time_wait': 'time_wait'}, + sot._query_mapping._mapping + ) + + def test_make_it(self): + + sot = message.Message() + self.assertIsNone(sot.queue_id) + # TODO() + + def test__collect_attrs(self): + # TODO() + pass + + def test_list(self): + # TODO() + pass + + +class TestMessages(base.TestCase): + + def test_basic(self): + sot = message.Messages() + + self.assertEqual('/queues/%(queue_id)s/messages', sot.base_path) + self.assertEqual('messages', sot.resources_key) + self.assertTrue(sot.allow_list) + self.assertTrue(sot.allow_create) + + self.assertDictEqual( + { + 'limit': 'limit', + 'marker': 'marker', + }, + sot._query_mapping._mapping + ) + + def test_make_it(self): + + sot = message.Messages(**MESSAGES_EXAMPLE) + self.assertEqual(2, len(sot.messages)) + # TODO() diff --git a/otcextensions/tests/unit/sdk/dms/v1/test_mw.py b/otcextensions/tests/unit/sdk/dms/v1/test_mw.py new file mode 100644 index 000000000..de6d22389 --- /dev/null +++ b/otcextensions/tests/unit/sdk/dms/v1/test_mw.py @@ -0,0 +1,41 @@ +# 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.tests.unit import base + +from otcextensions.sdk.dms.v1 import maintenance_window as mw + + +JSON_DATA = { + "default": False, + "seq": 1, + "begin": "22", + "end": "02" +} + + +class TestMW(base.TestCase): + + def test_basic(self): + sot = mw.MaintenanceWindow() + + self.assertEqual('/instances/maintain-windows', sot.base_path) + self.assertEqual('maintain_windows', sot.resources_key) + + self.assertTrue(sot.allow_list) + + def test_make_it(self): + + sot = mw.MaintenanceWindow(**JSON_DATA) + self.assertEqual(JSON_DATA['default'], sot.is_default) + self.assertEqual(int(JSON_DATA['seq']), sot.seq) + self.assertEqual(JSON_DATA['begin'], sot.begin) + self.assertEqual(JSON_DATA['end'], sot.end) diff --git a/otcextensions/tests/unit/sdk/dms/v1/test_product_spec.py b/otcextensions/tests/unit/sdk/dms/v1/test_product_spec.py new file mode 100644 index 000000000..07742cace --- /dev/null +++ b/otcextensions/tests/unit/sdk/dms/v1/test_product_spec.py @@ -0,0 +1,54 @@ +# 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.tests.unit import base + +from otcextensions.sdk.dms.v1 import product + + +JSON_DATA = { + 'tps': '50000', + 'storage': '600', + 'partition_num': '300', + 'product_id': '00300-30308-0--0', + 'spec_code': 'dms.instance.kafka.cluster.c3.mini', + 'io': [{ + 'io_type': 'high', + 'storage_spec_code': 'dms.physical.storage.high', + 'available_zones': ['eu-de-02', 'eu-de-01'], + 'volume_type': 'SAS' + }, { + 'io_type': 'ultra', + 'storage_spec_code': 'dms.physical.storage.ultra', + 'available_zones': ['eu-de-02', 'eu-de-01'], + 'volume_type': 'SSD' + }], + 'bandwidth': '100MB', + 'unavailable_zones': ['eu-de-02'], + 'available_zones': ['eu-de-01'], + 'ecs_flavor_id': 'c4.large.2', + 'arch_type': 'X86' +} + + +class TestProduct(base.TestCase): + + def test_basic(self): + sot = product.Product() + + self.assertEqual('/products', sot.base_path) + + self.assertTrue(sot.allow_list) + + def test_make_it(self): + + sot = product.Product(**JSON_DATA) + self.assertEqual(JSON_DATA['tps'], sot.tps) diff --git a/otcextensions/tests/unit/sdk/dms/v1/test_proxy.py b/otcextensions/tests/unit/sdk/dms/v1/test_proxy.py index e60da5dd7..b255140dd 100644 --- a/otcextensions/tests/unit/sdk/dms/v1/test_proxy.py +++ b/otcextensions/tests/unit/sdk/dms/v1/test_proxy.py @@ -9,11 +9,17 @@ # 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 mock +from unittest import mock from otcextensions.sdk.dms.v1 import _proxy +from otcextensions.sdk.dms.v1 import az as _az +from otcextensions.sdk.dms.v1 import group as _group +from otcextensions.sdk.dms.v1 import instance as _instance +from otcextensions.sdk.dms.v1 import maintenance_window as _mw +from otcextensions.sdk.dms.v1 import message as _message +from otcextensions.sdk.dms.v1 import product as _product from otcextensions.sdk.dms.v1 import queue as _queue +from otcextensions.sdk.dms.v1 import topic as _topic from openstack.tests.unit import test_proxy_base @@ -29,21 +35,26 @@ def test_create_queue(self): self.verify_create( self.proxy.create_queue, _queue.Queue, - mock_method='otcextensions.sdk.sdk_proxy.Proxy._create', - method_kwargs={ - 'name': 'queue_001' - }, + ) + + def test_queues(self): + self.verify_list( + self.proxy.queues, + _queue.Queue, expected_kwargs={ - 'name': 'queue_001' + 'paginated': False } ) - def test_queues(self): + def test_queues_qp(self): self.verify_list( self.proxy.queues, _queue.Queue, - mock_method='otcextensions.sdk.sdk_proxy.Proxy._list', + method_kwargs={ + 'include_deadletter': True, + }, expected_kwargs={ + 'include_deadletter': True, 'paginated': False } ) @@ -51,71 +62,267 @@ def test_queues(self): def test_get_queue(self): self.verify_get( self.proxy.get_queue, - _queue.Queue, - mock_method='otcextensions.sdk.sdk_proxy.Proxy._get', - expected_kwargs={} + _queue.Queue ) def test_delete_queue(self): self.verify_delete( self.proxy.delete_queue, _queue.Queue, - True, - mock_method='otcextensions.sdk.sdk_proxy.Proxy._delete', - expected_kwargs={} + False + ) + + def test_delete_queue_ignore(self): + self.verify_delete( + self.proxy.delete_queue, + _queue.Queue, + True ) def test_create_group(self): - self._verify2( - 'otcextensions.sdk.dms.v1.group.Group.create', + self.verify_create( self.proxy.create_group, - method_args=['queue', 'name'], - expected_args=[mock.ANY], - expected_kwargs={'group': 'name'}) + _group.Group, + method_kwargs={'queue': 'qip', 'name': 'grp'}, + expected_kwargs={'queue_id': 'qip', 'name': 'grp'}) def test_groups(self): - self._verify2( - 'otcextensions.sdk.sdk_proxy.Proxy._list', + self.verify_list( self.proxy.groups, - method_args=['queue'], - expected_args=[mock.ANY], + _group.Group, + method_kwargs={'queue': 'qid'}, expected_kwargs={ - 'queue_id': 'queue', - 'paginated': False, - 'include_deadletter': False}) + 'queue_id': 'qid', + 'paginated': False} + ) def test_delete_group(self): - self._verify2( - 'otcextensions.sdk.sdk_proxy.Proxy._delete', + self.verify_delete( self.proxy.delete_group, - method_args=['queue', 'group'], - expected_args=[mock.ANY, 'group'], - expected_kwargs={'queue_id': 'queue'}) + _group.Group, + False, + input_path_args=['QID', "resource_or_id"], + expected_path_args={'queue_id': 'QID'} + ) - def test_send_messages(self): - self._verify2( - 'otcextensions.sdk.sdk_proxy.Proxy._create', + def test_delete_group_ignore(self): + self.verify_delete( + self.proxy.delete_group, + _group.Group, + True, + input_path_args=['QID', "resource_or_id"], + expected_path_args={'queue_id': 'QID'} + ) + + ###### + # Messages + + def test_send_messages_dict(self): + self.verify_create( self.proxy.send_messages, - method_args=['queue'], - expected_args=[mock.ANY], - expected_kwargs={'queue_id': 'queue'}) + _message.Messages, + method_kwargs={ + 'queue': 'qid', + 'messages': [{'body': 'b1'}] + }, + expected_kwargs={ + 'queue_id': 'qid', + 'messages': [ + {'attributes': {}, 'body': 'b1'} + ], + 'return_id': False + } + ) + + def test_send_messages_msg(self): + self.verify_create( + self.proxy.send_messages, + _message.Messages, + method_kwargs={ + 'queue': 'qid', + 'messages': [_message.Message(body='b1')] + }, + expected_kwargs={ + 'queue_id': 'qid', + 'messages': [ + {'attributes': {}, 'body': 'b1'} + ], + 'return_id': False + } + ) + + def test_send_message(self): + self.verify_create( + self.proxy.send_message, + _message.Messages, + method_kwargs={ + 'queue': 'qid', + 'body': 'b1', + 'p1': 'v1' + }, + expected_kwargs={ + 'queue_id': 'qid', + 'messages': [ + {'attributes': {'p1': 'v1'}, 'body': 'b1'} + ], + 'return_id': True + }, + method_result=_message.Message(id='1'), + expected_result=_message.Messages( + messages=[_message.Message(id='1')]) + ) def test_consume_message(self): - self._verify2( - 'otcextensions.sdk.dms.v1.group_message.GroupMessage.list', + self.verify_list( self.proxy.consume_message, - method_args=['queue', 'group'], - expected_args=[mock.ANY], + _message.Message, + method_kwargs={ + 'queue': 'qid', + 'group': 'gid' + }, expected_kwargs={ - 'queue_id': 'queue', - 'consumer_group_id': 'group', - 'endpoint_override': None, - 'headers': None, - 'paginated': False, - 'requests_auth': None}) + 'queue_id': 'qid', + 'group_id': 'gid' + }, + base_path='/queues/%(queue_id)s/groups/%(group_id)s/messages' + ) def test_ack_consumed_message(self): pass def test_quotas(self): pass + + ###### + # Instances + def test_instances(self): + self.verify_list( + self.proxy.instances, + _instance.Instance, + expected_kwargs={ + 'paginated': False + } + ) + + def test_create_instance(self): + self.verify_create( + self.proxy.create_instance, + _instance.Instance + ) + + def test_delete_instance(self): + self.verify_delete( + self.proxy.delete_instance, + _instance.Instance, + False, + ) + + def test_delete_instance_ignore(self): + self.verify_delete( + self.proxy.delete_instance, + _instance.Instance, + True, + ) + + def test_find_instance(self): + self.verify_find( + self.proxy.find_instance, + _instance.Instance + ) + + def test_get_instance(self): + self.verify_get( + self.proxy.get_instance, + _instance.Instance + ) + + def test_update_instance(self): + self.verify_update( + self.proxy.update_instance, + _instance.Instance + ) + + def test_restart_instance(self): + self._verify( + 'otcextensions.sdk.dms.v1.instance.Instance._action', + self.proxy.restart_instance, + method_args=['value'], + expected_args=['restart', ['value']] + ) + + def test_restart_instances(self): + self._verify( + 'otcextensions.sdk.dms.v1.instance.Instance._action', + self.proxy.restart_instances, + method_args=[['1', '2']], + expected_args=['restart', ['1', '2']] + ) + + def test_delete_failed(self): + self._verify( + 'otcextensions.sdk.dms.v1.instance.Instance.delete_failed', + self.proxy.delete_failed, + method_args=[] + ) + + def test_delete_batch(self): + self._verify( + 'otcextensions.sdk.dms.v1.instance.Instance._action', + self.proxy.delete_batch, + method_args=[['1', '2']], + expected_args=['delete', ['1', '2']] + ) + + def test_create_topic(self): + self.verify_create( + self.proxy.create_topic, + _topic.Topic, + method_args=['iid'], + expected_kwargs={'instance_id': 'iid', 'x': 1, 'y': 2, 'z': 3} + ) + + @mock.patch('otcextensions.sdk.dms.v1._proxy.Proxy.post') + def test_delete_topics(self, post_mock): + response = mock.Mock() + response.status_code = 200 + post_mock.return_value = response + self.proxy.delete_topic('instance', ['t1', 't2']) + + post_mock.assert_called_with( + '/instances/instance/topics/delete', + json={'topics': ['t1', 't2']}) + + self.proxy.delete_topic('instance', 't1') + + post_mock.assert_called_with( + '/instances/instance/topics/delete', + json={'topics': ['t1']}) + + def test_topics(self): + self.verify_list( + self.proxy.topics, + _topic.Topic, + method_args=['iid'], + expected_kwargs={ + 'instance_id': 'iid' + } + ) + + # Misc + def test_az(self): + self.verify_list( + self.proxy.availability_zones, + _az.AvailabilityZone, + ) + + def test_products(self): + self.verify_list( + self.proxy.products, + _product.Product + ) + + def test_mws(self): + self.verify_list( + self.proxy.maintenance_windows, + _mw.MaintenanceWindow + ) diff --git a/otcextensions/tests/unit/sdk/dms/v1/test_queue.py b/otcextensions/tests/unit/sdk/dms/v1/test_queue.py index 40558b362..552ba1db3 100644 --- a/otcextensions/tests/unit/sdk/dms/v1/test_queue.py +++ b/otcextensions/tests/unit/sdk/dms/v1/test_queue.py @@ -12,9 +12,6 @@ from openstack.tests.unit import base -from otcextensions.sdk.dms.v1 import group -from otcextensions.sdk.dms.v1 import group_message -from otcextensions.sdk.dms.v1 import message from otcextensions.sdk.dms.v1 import queue EXAMPLE = { @@ -26,45 +23,6 @@ "retention_hours": 7 } -GROUP_EXAMPLE = { - "queue_name": "queue_001", - "groups": [{ - "id": "g-5ec247fd-d4a2-4d4f-9876-e4ff3280c461", - "name": "abcDffD", - "produced_messages": 0, - "consumed_messages": 0, - "available_messages": 0 - }], - "redrive_policy": "enable", - "queue_id": "9bf46390-38a2-462d-b392-4d5b2d519c55" -} - -MSG_GROUP_EXAMPLE = { - "message": { - "body": { - "foo": "123=" - }, - "attributes": { - "attribute1": "value1", - "attribute2": "value2" - } - }, - "handler": "eyJjZyI6Im15X2pzb25fZ3JvdXAiLCJjaSI6InJlc3QtY29uc3VtZXItYz", -} - -MSG_EXAMPLE = { - "messages": - [ - { - "body": "TEST11", - "attributes": { - "attribute1": "value1", - "attribute2": "value2" - } - } - ] -} - class TestQueue(base.TestCase): @@ -79,9 +37,17 @@ def test_basic(self): self.assertTrue(sot.allow_create) self.assertTrue(sot.allow_list) self.assertTrue(sot.allow_get) - self.assertFalse(sot.allow_update) + self.assertFalse(sot.allow_commit) self.assertTrue(sot.allow_delete) + self.assertDictEqual({ + 'include_deadletter': 'include_deadletter', + 'include_messages_num': 'include_messages_num', + 'limit': 'limit', + 'marker': 'marker'}, + sot._query_mapping._mapping + ) + def test_make_it(self): sot = self.objcls(**self.example) @@ -93,64 +59,3 @@ def test_make_it(self): self.assertEqual(self.example['redrive_policy'], sot.redrive_policy) self.assertEqual(self.example['retention_hours'], sot.retention_hours) - - -class TestGroup(base.TestCase): - - example = GROUP_EXAMPLE['groups'][0] - objcls = group.Group - - def test_basic(self): - sot = self.objcls() - - self.assertEqual('queues/%(queue_id)s/groups', sot.base_path) - - def test_make_it(self): - - sot = self.objcls(**self.example) - self.assertEqual(self.example['id'], sot.id) - self.assertEqual(self.example['name'], sot.name) - self.assertEqual( - self.example['produced_messages'], - sot.produced_messages) - self.assertEqual( - self.example['consumed_messages'], - sot.consumed_messages) - self.assertEqual( - self.example['available_messages'], - sot.available_messages) - - -class TestMessage(base.TestCase): - - example = MSG_EXAMPLE - objcls = message.Message - - def test_basic(self): - sot = self.objcls() - - self.assertEqual('/queues/%(queue_id)s/messages', sot.base_path) - - def test_make_it(self): - - sot = self.objcls(**self.example) - self.assertEqual(self.example['messages'], sot.messages) - - -class TestGroupMessage(base.TestCase): - - example = MSG_GROUP_EXAMPLE - objcls = group_message.GroupMessage - - def test_basic(self): - sot = self.objcls() - - self.assertEqual( - '/queues/%(queue_id)s/groups/%(consumer_group_id)s/messages', - sot.base_path) - - def test_make_it(self): - - sot = self.objcls(**self.example) - self.assertEqual(self.example['message'], sot.message) - self.assertEqual(self.example['handler'], sot.handler) diff --git a/otcextensions/tests/unit/sdk/dms/v1/test_quota.py b/otcextensions/tests/unit/sdk/dms/v1/test_quota.py index 58d5a61a8..ab2a1d2ad 100644 --- a/otcextensions/tests/unit/sdk/dms/v1/test_quota.py +++ b/otcextensions/tests/unit/sdk/dms/v1/test_quota.py @@ -9,8 +9,6 @@ # 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 copy - from keystoneauth1 import adapter import mock @@ -44,14 +42,15 @@ def setUp(self): self.sot = quota.Quota() def test_basic(self): + pass sot = quota.Quota() self.assertEqual(None, sot.resource_key) self.assertEqual('quotas.resources', sot.resources_key) self.assertEqual('/quotas/dms', sot.base_path) self.assertTrue(sot.allow_list) self.assertFalse(sot.allow_create) - self.assertFalse(sot.allow_get) - self.assertFalse(sot.allow_update) + self.assertFalse(sot.allow_fetch) + self.assertFalse(sot.allow_commit) self.assertFalse(sot.allow_delete) def test_make_it(self): @@ -64,23 +63,24 @@ def test_make_it(self): self.assertEqual(obj['max'], sot.max) def test_list(self): - sot = quota.Quota() - mock_response = mock.Mock() - mock_response.status_code = 200 - mock_response.json.return_value = copy.deepcopy(EXAMPLE_LIST) - - self.sess.get.return_value = mock_response - - result = list(sot.list(self.sess)) - - self.sess.get.assert_called_once_with( - '/quotas/dms', - headers={'Content-Type': 'application/json'}, - params={} - ) - - expected_list = [ - quota.Quota.existing( - **EXAMPLE_LIST['quotas']['resources'][0])] - - self.assertEqual(expected_list, result) + pass +# sot = quota.Quota() +# mock_response = mock.Mock() +# mock_response.status_code = 200 +# mock_response.json.return_value = copy.deepcopy(EXAMPLE_LIST) +# +# self.sess.get.return_value = mock_response +# +# result = list(sot.list(self.sess)) +# +# self.sess.get.assert_called_once_with( +# '/quotas/dms', +# headers={'Content-Type': 'application/json'}, +# params={} +# ) +# +# expected_list = [ +# quota.Quota.existing( +# **EXAMPLE_LIST['quotas']['resources'][0])] +# +# self.assertEqual(expected_list, result) diff --git a/otcextensions/tests/unit/sdk/dms/v1/test_topic.py b/otcextensions/tests/unit/sdk/dms/v1/test_topic.py new file mode 100644 index 000000000..b641704c3 --- /dev/null +++ b/otcextensions/tests/unit/sdk/dms/v1/test_topic.py @@ -0,0 +1,57 @@ +# 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 keystoneauth1 import adapter + +from unittest import mock + +from openstack.tests.unit import base + +from otcextensions.sdk.dms.v1 import topic + + +JSON_DATA = { + 'id': 'haha', + 'partition': 3, + 'replication': 3, + 'sync_replication': True, + 'retention_time': 10, + 'sync_message_flush': True +} + + +class TestTopic(base.TestCase): + + def setUp(self): + super(TestTopic, self).setUp() + self.sess = mock.Mock(spec=adapter.Adapter) + self.sess.post = mock.Mock() + + def test_basic(self): + sot = topic.Topic() + + self.assertEqual('/instances/%(instance_id)s/topics', sot.base_path) + self.assertEqual('topics', sot.resources_key) + + self.assertTrue(sot.allow_create) + self.assertTrue(sot.allow_list) + self.assertTrue(sot.allow_delete) + + def test_make_it(self): + + sot = topic.Topic(**JSON_DATA) + self.assertEqual(JSON_DATA['id'], sot.id) + self.assertEqual(JSON_DATA['partition'], sot.partition) + self.assertEqual(JSON_DATA['replication'], sot.replication) + self.assertEqual(JSON_DATA['retention_time'], sot.retention_time) + self.assertEqual(JSON_DATA['sync_message_flush'], sot.is_sync_flush) + self.assertEqual(JSON_DATA['sync_replication'], + sot.is_sync_replication) diff --git a/requirements.txt b/requirements.txt index 1e9fdb979..831e89211 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,5 +2,5 @@ # of appearance. Changing the order has an impact on the overall integration # process, which may cause wedges in the gate later. -openstacksdk>=0.36.0 # Apache-2.0 +openstacksdk>=0.36.0,<0.43.0 # Apache-2.0 oslo.i18n>3.15.3 # Apache-2.0 diff --git a/setup.cfg b/setup.cfg index 6f69f6bdd..7f4c4705e 100644 --- a/setup.cfg +++ b/setup.cfg @@ -152,7 +152,17 @@ openstack.dms.v1 = dms_group_list = otcextensions.osclient.dms.v1.group:ListGroup dms_group_delete = otcextensions.osclient.dms.v1.group:DeleteGroup dms_group_create = otcextensions.osclient.dms.v1.group:CreateGroup - dms_quota_list = otcextensions.osclient.dms.v1.quota:ListQuota + dms_instance_list = otcextensions.osclient.dms.v1.instance:ListDMSInstance + dms_instance_show = otcextensions.osclient.dms.v1.instance:ShowDMSInstance + dms_instance_create = otcextensions.osclient.dms.v1.instance:CreateDMSInstance + dms_instance_set = otcextensions.osclient.dms.v1.instance:UpdateDMSInstance + dms_instance_restart = otcextensions.osclient.dms.v1.instance:RestartDMSInstance + dms_instance_topic_list = otcextensions.osclient.dms.v1.topic:ListDMSInstanceTopic + dms_instance_topic_create = otcextensions.osclient.dms.v1.topic:CreateDMSInstanceTopic + dms_instance_topic_delete = otcextensions.osclient.dms.v1.topic:DeleteDMSInstanceTopic + dms_az_list = otcextensions.osclient.dms.v1.az:ListAZ + dms_maintenance_window_list = otcextensions.osclient.dms.v1.maintenance_window:ListMW + dms_product_list = otcextensions.osclient.dms.v1.product:ListProduct openstack.dcs.v1 = dcs_instance_list = otcextensions.osclient.dcs.v1.instance:ListInstance From 01b57c20b941f7dbb74f88604187dcb727252338 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Wed, 6 May 2020 18:52:15 +0200 Subject: [PATCH 34/58] fix travis deploy name --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2e6a49ecd..af03c8117 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,5 +19,5 @@ deploy: on: tags: true distributions: sdist bdist_wheel - repo: OpenTelekomCloud/python-otcextensions + repo: opentelekomcloud/python-otcextensions condition: "$TOXENV = py36" From 7c6bb6bdb7b813d0a11a481193ccbffb7f9ebcaa Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Thu, 25 Jun 2020 08:50:59 +0200 Subject: [PATCH 35/58] small pep fixes (#90) small pep fixes Reviewed-by: https://github.com/apps/otc-zuul --- otcextensions/tests/functional/osclient/nat/v2/common.py | 1 - tox.ini | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/otcextensions/tests/functional/osclient/nat/v2/common.py b/otcextensions/tests/functional/osclient/nat/v2/common.py index 8a943a617..e96737ca0 100644 --- a/otcextensions/tests/functional/osclient/nat/v2/common.py +++ b/otcextensions/tests/functional/osclient/nat/v2/common.py @@ -50,7 +50,6 @@ def create_nat_gateway(self, name=None): name=name, router_id=self.ROUTER_ID, net_id=self.NETWORK_ID, - description='OTCE Lib Test', spec=1) )) self.assertIsNotNone(json_output) diff --git a/tox.ini b/tox.ini index 28b0062a1..a10573c81 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.1 -envlist = py27,py36,py37,pep8 +envlist = py36,py37,pep8 skipsdist = True ignore_basepython_conflict = True @@ -8,7 +8,6 @@ ignore_basepython_conflict = True usedevelop = True install_command = pip install {opts} {packages} passenv = OS_* OPENSTACKSDK_* -basepython = {env:OPENSTACKSDK_TOX_PYTHON:python3} setenv = VIRTUAL_ENV={envdir} LANG=en_US.UTF-8 From eccbce0eb7647c917ae1f189ef6061f4766cea1c Mon Sep 17 00:00:00 2001 From: "T. Schreiber" Date: Thu, 25 Jun 2020 13:24:39 +0200 Subject: [PATCH 36/58] DNS fix list recordsets for 500 > entries (#89) DNS fix list recordsets for 500 > entries Reviewed-by: https://github.com/apps/otc-zuul --- otcextensions/sdk/dns/v2/_base.py | 6 +- .../tests/unit/sdk/dns/v2/test_recordset.py | 69 +++++++++++++++++++ 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/otcextensions/sdk/dns/v2/_base.py b/otcextensions/sdk/dns/v2/_base.py index 40601a5f7..10f0c7e60 100644 --- a/otcextensions/sdk/dns/v2/_base.py +++ b/otcextensions/sdk/dns/v2/_base.py @@ -77,7 +77,6 @@ def _get_next_link(cls, uri, response, data, marker, limit, total_yielded): links = data.get('links') if links: next_link = links.get('next') - total = data.get('metadata', {}).get('total_count') if total: # We have a kill switch @@ -98,8 +97,9 @@ def _get_next_link(cls, uri, response, data, marker, limit, total_yielded): # If we still have no link, and limit was given and is non-zero, # and the number of records yielded equals the limit, then the user # is playing pagination ball so we should go ahead and try once more. - if not next_link and limit: + if not next_link: next_link = uri params['marker'] = marker - params['limit'] = limit + if limit: + params['limit'] = limit return next_link, params diff --git a/otcextensions/tests/unit/sdk/dns/v2/test_recordset.py b/otcextensions/tests/unit/sdk/dns/v2/test_recordset.py index 857bb663f..2168d962a 100644 --- a/otcextensions/tests/unit/sdk/dns/v2/test_recordset.py +++ b/otcextensions/tests/unit/sdk/dns/v2/test_recordset.py @@ -36,6 +36,29 @@ } +DATA = { + "links": { + "self": "https://example.com/v2/zones/2/recordsets" + }, + "recordsets": [ + { + "id": "1", + "name": "prod.otc.1." + }, + { + "id": "a3", + "name": "prod.otc.2." + }, + { + "id": "a7", + "name": "prod.otc.3." + } + ], + "metadata": { + "total_count": 7 + } +} + class TestRecordSet(base.TestCase): @@ -61,3 +84,49 @@ def test_make_it(self): self.assertEqual(EXAMPLE['zone_id'], sot.zone_id) self.assertEqual(EXAMPLE['create_at'], sot.created_at) self.assertEqual(EXAMPLE['update_at'], sot.updated_at) + + def test_get_next_link(self): + uri = '/zones/2/recordsets' + marker = 'a7' + + result = recordset.Recordset._get_next_link( + uri=uri, + response=None, + data=DATA, + marker=marker, + limit=None, + total_yielded=3 + ) + self.assertEqual(uri, result[0]) + self.assertEqual({'marker': marker}, result[1]) + + def test_get_next_link2(self): + uri = '/zones/2/recordsets' + marker = 'a7' + + result = recordset.Recordset._get_next_link( + uri=uri, + response=None, + data=DATA, + marker=marker, + limit=None, + total_yielded=7 + ) + self.assertEqual(None, result[0]) + self.assertEqual({}, result[1]) + + def test_get_next_link3(self): + uri = '/zones/2/recordsets' + marker = 'a7' + limit = 3 + + result = recordset.Recordset._get_next_link( + uri=uri, + response=None, + data=DATA, + marker=marker, + limit=3, + total_yielded=3 + ) + self.assertEqual(uri, result[0]) + self.assertEqual({'marker': marker, 'limit': limit}, result[1]) From addb846963bf7df84932557f9179179be714dd78 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Tue, 7 Jul 2020 12:30:56 +0200 Subject: [PATCH 37/58] small pep fixes (#93) small pep fixes Reviewed-by: https://github.com/apps/otc-zuul From 40c38ea8a43a8b181e5e8a7338db41b87fb15ce3 Mon Sep 17 00:00:00 2001 From: Artem Goncharov Date: Tue, 7 Jul 2020 13:07:57 +0200 Subject: [PATCH 38/58] Cloud layer (#92) Cloud layer Reviewed-by: https://github.com/apps/otc-zuul --- .gitignore | 1 + otcextensions/osclient/rds/v3/instance.py | 201 +--- otcextensions/sdk/__init__.py | 14 +- otcextensions/sdk/cloud/__init__.py | 0 otcextensions/sdk/cloud/rds.py | 266 ++++++ otcextensions/tests/unit/base.py | 23 + .../tests/unit/osclient/anti_ddos/v1/fakes.py | 8 +- .../tests/unit/osclient/cts/v1/fakes.py | 4 +- .../tests/unit/osclient/dns/v2/fakes.py | 2 +- .../unit/osclient/rds/v3/test_instance.py | 779 +-------------- otcextensions/tests/unit/sdk/base.py | 46 + .../tests/unit/sdk/cloud/__init__.py | 0 .../tests/unit/sdk/cloud/test_rds.py | 885 ++++++++++++++++++ requirements.txt | 2 +- 14 files changed, 1312 insertions(+), 919 deletions(-) create mode 100644 otcextensions/sdk/cloud/__init__.py create mode 100644 otcextensions/sdk/cloud/rds.py create mode 100644 otcextensions/tests/unit/base.py create mode 100644 otcextensions/tests/unit/sdk/base.py create mode 100644 otcextensions/tests/unit/sdk/cloud/__init__.py create mode 100644 otcextensions/tests/unit/sdk/cloud/test_rds.py diff --git a/.gitignore b/.gitignore index cad5c2103..267e4101b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ *.swo *.swp *~ +otcextensions-*/ .coverage .idea .stestr/ diff --git a/otcextensions/osclient/rds/v3/instance.py b/otcextensions/osclient/rds/v3/instance.py index b03f0f863..5b1fc6e40 100644 --- a/otcextensions/osclient/rds/v3/instance.py +++ b/otcextensions/osclient/rds/v3/instance.py @@ -179,14 +179,15 @@ def get_parser(self, prog_name): help=_("Name of the instance.") ) parser.add_argument( - 'flavor_ref', - metavar='', + 'flavor', + metavar='', help=_("Flavor spec_code") ) disk_group = parser.add_argument_group('Disk data') disk_group.add_argument( '--size', metavar='', + dest='volume_size', type=int, required=True, help=_("Size of the instance disk volume in GB. ") @@ -196,6 +197,7 @@ def get_parser(self, prog_name): metavar='{' + ','.join(DISK_TYPE_CHOICES) + '}', type=lambda s: s.upper(), required=True, + dest='volume_type', choices=[s.upper() for s in DISK_TYPE_CHOICES], help=_("Volume type. (COMMON, ULTRAHIGH).") ) @@ -224,7 +226,7 @@ def get_parser(self, prog_name): ) parser.add_argument( '--configuration', - dest='configuration_id', + dest='configuration', metavar='', default=None, help=_("ID of the configuration group to attach to the instance.") @@ -253,16 +255,18 @@ def get_parser(self, prog_name): new_instance_group.add_argument( '--router-id', metavar='', + dest='router', help=_('ID of a Router the DB should be connected to') ) new_instance_group.add_argument( '--network-id', metavar='', + dest='network', help=_('ID of a Neutron network the DB should be connected to.') ) new_instance_group.add_argument( '--security-group-id', - dest='security_group_id', + dest='security_group', metavar='', help=_('Security group ID') ) @@ -301,6 +305,17 @@ def get_parser(self, prog_name): metavar='', help=_('Backup ID or Name to create new instance from.') ) + create_from_group.add_argument( + '--backup-keepdays', + metavar='', + help=_('Specifies the retention days for specific backup files.') + ) + create_from_group.add_argument( + '--backup-timeframe', + metavar='', + help=_('Specifies the backup time window. Automated backups will ' + 'be triggered during the backup time window.') + ) create_from_group.add_argument( '--restore-time', metavar='