Merge "Add 2.55 schema & update flavor API in flavors_client"
diff --git a/doc/source/microversion_testing.rst b/doc/source/microversion_testing.rst
index c22888d..325b19f 100644
--- a/doc/source/microversion_testing.rst
+++ b/doc/source/microversion_testing.rst
@@ -354,6 +354,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,