Add 2.55 schema & update flavor API in flavors_client
Compute microversion 2.55 adds 'description' in
flavor APIs response and new API to update the same.
This commit fill the schema gap for that and also
add new updte flavor API in flavors_client lib.
Change-Id: I91c049c3aa9dab5a272369edd18f2c5890d1e5b0
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index 942f969..535dfc6 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -342,6 +342,10 @@
.. _2.48: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id43
+ * `2.55`_
+
+ .. _2.55: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id49
+
* `2.60`_
.. _2.60: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id54
diff --git a/releasenotes/notes/add-update-flavor--api-to-flavors-client-a859542fe54aab7c.yaml b/releasenotes/notes/add-update-flavor--api-to-flavors-client-a859542fe54aab7c.yaml
new file mode 100644
index 0000000..222a99f
--- /dev/null
+++ b/releasenotes/notes/add-update-flavor--api-to-flavors-client-a859542fe54aab7c.yaml
@@ -0,0 +1,4 @@
+---
+features:
+ - |
+ Add update flavor API to compute flavors_client library.
diff --git a/tempest/api/compute/admin/test_flavors_microversions.py b/tempest/api/compute/admin/test_flavors_microversions.py
new file mode 100644
index 0000000..027af25
--- /dev/null
+++ b/tempest/api/compute/admin/test_flavors_microversions.py
@@ -0,0 +1,43 @@
+# Copyright 2018 NEC Corporation.
+# All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+from tempest.api.compute import base
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+
+
+class FlavorsV255TestJSON(base.BaseV2ComputeAdminTest):
+ min_microversion = '2.55'
+ max_microversion = 'latest'
+
+ # NOTE(gmann): This class tests the flavors APIs
+ # response schema for the 2.55 microversion.
+
+ @decorators.idempotent_id('61976b25-488d-41dc-9dcb-cb9693a7b075')
+ def test_crud_flavor(self):
+ flavor_id = data_utils.rand_int_id(start=1000)
+ # Checking create API response schema
+ new_flavor_id = self.create_flavor(ram=512,
+ vcpus=1,
+ disk=10,
+ id=flavor_id)['id']
+ # Checking show API response schema
+ self.flavors_client.show_flavor(new_flavor_id)['flavor']
+ # Checking update API response schema
+ self.admin_flavors_client.update_flavor(new_flavor_id,
+ description='new')['flavor']
+ # Checking list details API response schema
+ self.flavors_client.list_flavors(detail=True)['flavors']
+ # Checking list API response schema
+ self.flavors_client.list_flavors()['flavors']
diff --git a/tempest/lib/api_schema/response/compute/v2_1/flavors.py b/tempest/lib/api_schema/response/compute/v2_1/flavors.py
index 547d94d..af5e67f 100644
--- a/tempest/lib/api_schema/response/compute/v2_1/flavors.py
+++ b/tempest/lib/api_schema/response/compute/v2_1/flavors.py
@@ -86,7 +86,7 @@
'status_code': [200]
}
-create_get_flavor_details = {
+create_update_get_flavor_details = {
'status_code': [200],
'response_body': {
'type': 'object',
diff --git a/tempest/lib/api_schema/response/compute/v2_55/__init__.py b/tempest/lib/api_schema/response/compute/v2_55/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_55/__init__.py
diff --git a/tempest/lib/api_schema/response/compute/v2_55/flavors.py b/tempest/lib/api_schema/response/compute/v2_55/flavors.py
new file mode 100644
index 0000000..823190a
--- /dev/null
+++ b/tempest/lib/api_schema/response/compute/v2_55/flavors.py
@@ -0,0 +1,112 @@
+# Copyright 2018 NEC Corporation. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+from tempest.lib.api_schema.response.compute.v2_1 import parameter_types
+
+# Note(gmann): This is schema for microversion 2.55 which includes the
+# following changes:
+# Add new PUT API
+# Adds a ``description`` field to the following APIs response:
+# - ``GET /flavors``
+# - ``GET /flavors/detail``
+# - ``GET /flavors/{flavor_id}``
+# - ``POST /flavors``
+
+flavor_description = {
+ 'type': ['string', 'null'],
+ 'minLength': 0, 'maxLength': 65535
+}
+
+list_flavors = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'flavors': {
+ 'type': 'array',
+ 'items': {
+ 'type': 'object',
+ 'properties': {
+ 'name': {'type': 'string'},
+ 'links': parameter_types.links,
+ 'id': {'type': 'string'},
+ 'description': flavor_description
+ },
+ 'additionalProperties': False,
+ 'required': ['name', 'links', 'id', 'description']
+ }
+ },
+ 'flavors_links': parameter_types.links
+ },
+ 'additionalProperties': False,
+ # NOTE(gmann): flavors_links attribute is not necessary
+ # to be present always So it is not 'required'.
+ 'required': ['flavors']
+ }
+}
+
+common_flavor_info = {
+ 'type': 'object',
+ 'properties': {
+ 'name': {'type': 'string'},
+ 'links': parameter_types.links,
+ 'ram': {'type': 'integer'},
+ 'vcpus': {'type': 'integer'},
+ # 'swap' attributes comes as integer value but if it is empty
+ # it comes as "". So defining type of as string and integer.
+ 'swap': {'type': ['integer', 'string']},
+ 'disk': {'type': 'integer'},
+ 'id': {'type': 'string'},
+ 'OS-FLV-DISABLED:disabled': {'type': 'boolean'},
+ 'os-flavor-access:is_public': {'type': 'boolean'},
+ 'rxtx_factor': {'type': 'number'},
+ 'OS-FLV-EXT-DATA:ephemeral': {'type': 'integer'},
+ 'description': flavor_description
+ },
+ 'additionalProperties': False,
+ # 'OS-FLV-DISABLED', 'os-flavor-access', 'rxtx_factor' and
+ # 'OS-FLV-EXT-DATA' are API extensions. So they are not 'required'.
+ 'required': ['name', 'links', 'ram', 'vcpus', 'swap', 'disk', 'id',
+ 'description']
+}
+
+list_flavors_details = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'flavors': {
+ 'type': 'array',
+ 'items': common_flavor_info
+ },
+ # NOTE(gmann): flavors_links attribute is not necessary
+ # to be present always So it is not 'required'.
+ 'flavors_links': parameter_types.links
+ },
+ 'additionalProperties': False,
+ 'required': ['flavors']
+ }
+}
+
+create_update_get_flavor_details = {
+ 'status_code': [200],
+ 'response_body': {
+ 'type': 'object',
+ 'properties': {
+ 'flavor': common_flavor_info
+ },
+ 'additionalProperties': False,
+ 'required': ['flavor']
+ }
+}
diff --git a/tempest/lib/services/compute/flavors_client.py b/tempest/lib/services/compute/flavors_client.py
index 0fb1991..4923d7e 100644
--- a/tempest/lib/services/compute/flavors_client.py
+++ b/tempest/lib/services/compute/flavors_client.py
@@ -21,12 +21,18 @@
as schema_access
from tempest.lib.api_schema.response.compute.v2_1 import flavors_extra_specs \
as schema_extra_specs
+from tempest.lib.api_schema.response.compute.v2_55 import flavors \
+ as schemav255
from tempest.lib.common import rest_client
from tempest.lib.services.compute import base_compute_client
class FlavorsClient(base_compute_client.BaseComputeClient):
+ schema_versions_info = [
+ {'min': None, 'max': '2.54', 'schema': schema},
+ {'min': '2.55', 'max': None, 'schema': schemav255}]
+
def list_flavors(self, detail=False, **params):
"""Lists flavors.
@@ -36,11 +42,12 @@
https://developer.openstack.org/api-ref/compute/#list-flavors-with-details
"""
url = 'flavors'
- _schema = schema.list_flavors
-
+ schema = self.get_schema(self.schema_versions_info)
if detail:
url += '/detail'
_schema = schema.list_flavors_details
+ else:
+ _schema = schema.list_flavors
if params:
url += '?%s' % urllib.urlencode(params)
@@ -58,7 +65,9 @@
"""
resp, body = self.get("flavors/%s" % flavor_id)
body = json.loads(body)
- self.validate_response(schema.create_get_flavor_details, resp, body)
+ schema = self.get_schema(self.schema_versions_info)
+ self.validate_response(schema.create_update_get_flavor_details,
+ resp, body)
return rest_client.ResponseBody(resp, body)
def create_flavor(self, **kwargs):
@@ -77,7 +86,25 @@
resp, body = self.post('flavors', post_body)
body = json.loads(body)
- self.validate_response(schema.create_get_flavor_details, resp, body)
+ schema = self.get_schema(self.schema_versions_info)
+ self.validate_response(schema.create_update_get_flavor_details,
+ resp, body)
+ return rest_client.ResponseBody(resp, body)
+
+ def update_flavor(self, flavor_id, **kwargs):
+ """Uodate the flavor or instance type.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://developer.openstack.org/api-ref/compute/#update-flavor-description
+ """
+ put_body = json.dumps({'flavor': kwargs})
+ resp, body = self.put("flavors/%s" % flavor_id, put_body)
+
+ body = json.loads(body)
+ schema = self.get_schema(self.schema_versions_info)
+ self.validate_response(schema.create_update_get_flavor_details,
+ resp, body)
return rest_client.ResponseBody(resp, body)
def delete_flavor(self, flavor_id):
diff --git a/tempest/tests/lib/services/compute/test_flavors_client.py b/tempest/tests/lib/services/compute/test_flavors_client.py
index cbd17c6..5325036 100644
--- a/tempest/tests/lib/services/compute/test_flavors_client.py
+++ b/tempest/tests/lib/services/compute/test_flavors_client.py
@@ -17,6 +17,7 @@
import fixtures
from oslo_serialization import jsonutils as json
+from tempest.api.compute import api_microversion_fixture
from tempest.lib.services.compute import flavors_client
from tempest.tests.lib import fake_auth_provider
from tempest.tests.lib import fake_http
@@ -39,6 +40,21 @@
"vcpus": 1
}
+ FAKE_FLAVOR_UPDATE = {
+ "disk": 1,
+ "id": "1",
+ "links": [{
+ "href": "http://openstack.example.com/v2/openstack/flavors/1",
+ "rel": "self"}, {
+ "href": "http://openstack.example.com/openstack/flavors/1",
+ "rel": "bookmark"}],
+ "name": "m1.tiny",
+ "ram": 512,
+ "swap": 1,
+ "vcpus": 1,
+ "description": 'new'
+ }
+
EXTRA_SPECS = {"extra_specs": {
"key1": "value1",
"key2": "value2"}
@@ -106,6 +122,25 @@
def test_create_flavor__byte_body(self):
self._test_create_flavor(bytes_body=True)
+ def _test_update_flavor(self, bytes_body=False):
+ self.useFixture(api_microversion_fixture.APIMicroversionFixture(
+ '2.55'))
+ expected = {"flavor": TestFlavorsClient.FAKE_FLAVOR_UPDATE}
+ request = {"flavor": {"description": "updated description"}}
+ self.check_service_client_function(
+ self.client.update_flavor,
+ 'tempest.lib.common.rest_client.RestClient.put',
+ expected,
+ bytes_body,
+ flavor_id='8c7aae5a-d315-4216-875b-ed9b6a5bcfc6',
+ **request)
+
+ def test_update_flavor_str_body(self):
+ self._test_update_flavor(bytes_body=False)
+
+ def test_update_flavor__byte_body(self):
+ self._test_update_flavor(bytes_body=True)
+
def test_delete_flavor(self):
self.check_service_client_function(
self.client.delete_flavor,