diff --git a/releasenotes/notes/new-placement-client-methods-e35c473e29494928.yaml b/releasenotes/notes/new-placement-client-methods-e35c473e29494928.yaml new file mode 100644 index 0000000000..9e6d49a192 --- /dev/null +++ b/releasenotes/notes/new-placement-client-methods-e35c473e29494928.yaml @@ -0,0 +1,11 @@ +--- +features: + - | + Add ``placement`` API methods for testing Routed Provider Networks feature. + The following API calls are available for tempest from now in the new + resource_providers_client: + + * GET /resource_providers + * GET /resource_providers/{uuid} + * GET /resource_providers/{uuid}/inventories + * GET /resource_providers/{uuid}/aggregates diff --git a/tempest/clients.py b/tempest/clients.py index 8363a8d6ca..6d19a0c742 100644 --- a/tempest/clients.py +++ b/tempest/clients.py @@ -44,7 +44,7 @@ class Manager(clients.ServiceClients): self._set_object_storage_clients() self._set_image_clients() self._set_network_clients() - self.placement_client = self.placement.PlacementClient() + self._set_placement_clients() # TODO(andreaf) This is maintained for backward compatibility # with plugins, but it should removed eventually, since it was # never a stable interface and it's not useful anyways @@ -139,6 +139,11 @@ class Manager(clients.ServiceClients): self.snapshots_extensions_client = self.compute.SnapshotsClient( **params_volume) + def _set_placement_clients(self): + self.placement_client = self.placement.PlacementClient() + self.resource_providers_client = \ + self.placement.ResourceProvidersClient() + def _set_identity_clients(self): # Clients below use the admin endpoint type of Keystone API v2 params_v2_admin = { diff --git a/tempest/lib/services/placement/__init__.py b/tempest/lib/services/placement/__init__.py index 5c20c57cfd..daeaeabac7 100644 --- a/tempest/lib/services/placement/__init__.py +++ b/tempest/lib/services/placement/__init__.py @@ -14,5 +14,7 @@ from tempest.lib.services.placement.placement_client import \ PlacementClient +from tempest.lib.services.placement.resource_providers_client import \ + ResourceProvidersClient -__all__ = ['PlacementClient'] +__all__ = ['PlacementClient', 'ResourceProvidersClient'] diff --git a/tempest/lib/services/placement/resource_providers_client.py b/tempest/lib/services/placement/resource_providers_client.py new file mode 100644 index 0000000000..56f6409002 --- /dev/null +++ b/tempest/lib/services/placement/resource_providers_client.py @@ -0,0 +1,82 @@ +# 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 oslo_serialization import jsonutils as json +from six.moves.urllib import parse as urllib + +from tempest.lib.common import rest_client +from tempest.lib.services.placement import base_placement_client + + +class ResourceProvidersClient(base_placement_client.BasePlacementClient): + """Client class for resource provider related methods + + This client class aims to support read-only API operations for resource + providers. The following resources are supported: + * resource providers + * resource provider inventories + * resource provider aggregates + """ + + def list_resource_providers(self, **params): + """List resource providers. + + For full list of available parameters, please refer to the official + API reference: + https://docs.openstack.org/api-ref/placement/#list-resource-providers + """ + url = '/resource_providers' + if params: + url += '?%s' % urllib.urlencode(params) + resp, body = self.get(url) + self.expected_success(200, resp.status) + body = json.loads(body) + return rest_client.ResponseBody(resp, body) + + def show_resource_provider(self, rp_uuid): + """Show resource provider. + + For full list of available parameters, please refer to the official + API reference: + https://docs.openstack.org/api-ref/placement/#show-resource-provider + """ + url = '/resource_providers/%s' % rp_uuid + resp, body = self.get(url) + self.expected_success(200, resp.status) + body = json.loads(body) + return rest_client.ResponseBody(resp, body) + + def list_resource_provider_inventories(self, rp_uuid): + """List resource provider inventories. + + For full list of available parameters, please refer to the official + API reference: + https://docs.openstack.org/api-ref/placement/#list-resource-provider-inventories + """ + url = '/resource_providers/%s/inventories' % rp_uuid + resp, body = self.get(url) + self.expected_success(200, resp.status) + body = json.loads(body) + return rest_client.ResponseBody(resp, body) + + def list_resource_provider_aggregates(self, rp_uuid): + """List resource provider aggregates. + + For full list of available parameters, please refer to the official + API reference: + https://docs.openstack.org/api-ref/placement/#list-resource-provider-aggregates + """ + url = '/resource_providers/%s/aggregates' % rp_uuid + resp, body = self.get(url) + self.expected_success(200, resp.status) + body = json.loads(body) + return rest_client.ResponseBody(resp, body) diff --git a/tempest/tests/lib/services/placement/test_resource_providers_client.py b/tempest/tests/lib/services/placement/test_resource_providers_client.py new file mode 100644 index 0000000000..11aeaf2ae3 --- /dev/null +++ b/tempest/tests/lib/services/placement/test_resource_providers_client.py @@ -0,0 +1,119 @@ +# 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 tempest.lib.services.placement import resource_providers_client +from tempest.tests.lib import fake_auth_provider +from tempest.tests.lib.services import base + + +class TestResourceProvidersClient(base.BaseServiceTest): + FAKE_RESOURCE_PROVIDER_UUID = '3722a86e-a563-11e9-9abb-c3d41b6d3abf' + FAKE_ROOT_PROVIDER_UUID = '4a6a57c8-a563-11e9-914e-f3e0478fce53' + FAKE_RESOURCE_PROVIDER = { + 'generation': 0, + 'name': 'Ceph Storage Pool', + 'uuid': FAKE_RESOURCE_PROVIDER_UUID, + 'parent_provider_uuid': FAKE_ROOT_PROVIDER_UUID, + 'root_provider_uuid': FAKE_ROOT_PROVIDER_UUID + } + + FAKE_RESOURCE_PROVIDERS = { + 'resource_providers': [FAKE_RESOURCE_PROVIDER] + } + + FAKE_RESOURCE_PROVIDER_INVENTORIES = { + 'inventories': { + 'DISK_GB': { + 'allocation_ratio': 1.0, + 'max_unit': 35, + 'min_unit': 1, + 'reserved': 0, + 'step_size': 1, + 'total': 35 + } + }, + 'resource_provider_generation': 7 + } + + FAKE_AGGREGATE_UUID = '1166be40-a567-11e9-9f2a-53827f9311fa' + FAKE_RESOURCE_PROVIDER_AGGREGATES = { + 'aggregates': [FAKE_AGGREGATE_UUID] + } + + def setUp(self): + super(TestResourceProvidersClient, self).setUp() + fake_auth = fake_auth_provider.FakeAuthProvider() + self.client = resource_providers_client.ResourceProvidersClient( + fake_auth, 'placement', 'regionOne') + + def _test_list_resource_providers(self, bytes_body=False): + self.check_service_client_function( + self.client.list_resource_providers, + 'tempest.lib.common.rest_client.RestClient.get', + self.FAKE_RESOURCE_PROVIDERS, + to_utf=bytes_body, + status=200 + ) + + def test_list_resource_providers_with_bytes_body(self): + self._test_list_resource_providers() + + def test_list_resource_providers_with_str_body(self): + self._test_list_resource_providers(bytes_body=True) + + def _test_show_resource_provider(self, bytes_body=False): + self.check_service_client_function( + self.client.show_resource_provider, + 'tempest.lib.common.rest_client.RestClient.get', + self.FAKE_RESOURCE_PROVIDER, + to_utf=bytes_body, + status=200, + rp_uuid=self.FAKE_RESOURCE_PROVIDER_UUID + ) + + def test_show_resource_provider_with_str_body(self): + self._test_show_resource_provider() + + def test_show_resource_provider_with_bytes_body(self): + self._test_show_resource_provider(bytes_body=True) + + def _test_list_resource_provider_inventories(self, bytes_body=False): + self.check_service_client_function( + self.client.list_resource_provider_inventories, + 'tempest.lib.common.rest_client.RestClient.get', + self.FAKE_RESOURCE_PROVIDER_INVENTORIES, + to_utf=bytes_body, + status=200, + rp_uuid=self.FAKE_RESOURCE_PROVIDER_UUID + ) + + def test_list_resource_provider_inventories_with_str_body(self): + self._test_list_resource_provider_inventories() + + def test_list_resource_provider_inventories_with_bytes_body(self): + self._test_list_resource_provider_inventories(bytes_body=True) + + def _test_list_resource_provider_aggregates(self, bytes_body=False): + self.check_service_client_function( + self.client.list_resource_provider_aggregates, + 'tempest.lib.common.rest_client.RestClient.get', + self.FAKE_RESOURCE_PROVIDER_AGGREGATES, + to_utf=bytes_body, + status=200, + rp_uuid=self.FAKE_RESOURCE_PROVIDER_UUID + ) + + def test_list_resource_provider_aggregates_with_str_body(self): + self._test_list_resource_provider_aggregates() + + def test_list_resource_provider_aggregates_with_bytes_body(self): + self._test_list_resource_provider_aggregates(bytes_body=True)