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
This commit is contained in:
parent
52d0c059ab
commit
52c5d28190
@ -342,6 +342,10 @@ Microversion tests implemented in Tempest
|
|||||||
|
|
||||||
.. _2.48: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id43
|
.. _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`_
|
||||||
|
|
||||||
.. _2.60: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id54
|
.. _2.60: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id54
|
||||||
|
@ -0,0 +1,4 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Add update flavor API to compute flavors_client library.
|
43
tempest/api/compute/admin/test_flavors_microversions.py
Normal file
43
tempest/api/compute/admin/test_flavors_microversions.py
Normal file
@ -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']
|
@ -86,7 +86,7 @@ unset_flavor_extra_specs = {
|
|||||||
'status_code': [200]
|
'status_code': [200]
|
||||||
}
|
}
|
||||||
|
|
||||||
create_get_flavor_details = {
|
create_update_get_flavor_details = {
|
||||||
'status_code': [200],
|
'status_code': [200],
|
||||||
'response_body': {
|
'response_body': {
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
|
112
tempest/lib/api_schema/response/compute/v2_55/flavors.py
Normal file
112
tempest/lib/api_schema/response/compute/v2_55/flavors.py
Normal file
@ -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']
|
||||||
|
}
|
||||||
|
}
|
@ -21,12 +21,18 @@ from tempest.lib.api_schema.response.compute.v2_1 import flavors_access \
|
|||||||
as schema_access
|
as schema_access
|
||||||
from tempest.lib.api_schema.response.compute.v2_1 import flavors_extra_specs \
|
from tempest.lib.api_schema.response.compute.v2_1 import flavors_extra_specs \
|
||||||
as schema_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.common import rest_client
|
||||||
from tempest.lib.services.compute import base_compute_client
|
from tempest.lib.services.compute import base_compute_client
|
||||||
|
|
||||||
|
|
||||||
class FlavorsClient(base_compute_client.BaseComputeClient):
|
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):
|
def list_flavors(self, detail=False, **params):
|
||||||
"""Lists flavors.
|
"""Lists flavors.
|
||||||
|
|
||||||
@ -36,11 +42,12 @@ class FlavorsClient(base_compute_client.BaseComputeClient):
|
|||||||
https://developer.openstack.org/api-ref/compute/#list-flavors-with-details
|
https://developer.openstack.org/api-ref/compute/#list-flavors-with-details
|
||||||
"""
|
"""
|
||||||
url = 'flavors'
|
url = 'flavors'
|
||||||
_schema = schema.list_flavors
|
schema = self.get_schema(self.schema_versions_info)
|
||||||
|
|
||||||
if detail:
|
if detail:
|
||||||
url += '/detail'
|
url += '/detail'
|
||||||
_schema = schema.list_flavors_details
|
_schema = schema.list_flavors_details
|
||||||
|
else:
|
||||||
|
_schema = schema.list_flavors
|
||||||
if params:
|
if params:
|
||||||
url += '?%s' % urllib.urlencode(params)
|
url += '?%s' % urllib.urlencode(params)
|
||||||
|
|
||||||
@ -58,7 +65,9 @@ class FlavorsClient(base_compute_client.BaseComputeClient):
|
|||||||
"""
|
"""
|
||||||
resp, body = self.get("flavors/%s" % flavor_id)
|
resp, body = self.get("flavors/%s" % flavor_id)
|
||||||
body = json.loads(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)
|
return rest_client.ResponseBody(resp, body)
|
||||||
|
|
||||||
def create_flavor(self, **kwargs):
|
def create_flavor(self, **kwargs):
|
||||||
@ -77,7 +86,25 @@ class FlavorsClient(base_compute_client.BaseComputeClient):
|
|||||||
resp, body = self.post('flavors', post_body)
|
resp, body = self.post('flavors', post_body)
|
||||||
|
|
||||||
body = json.loads(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)
|
return rest_client.ResponseBody(resp, body)
|
||||||
|
|
||||||
def delete_flavor(self, flavor_id):
|
def delete_flavor(self, flavor_id):
|
||||||
|
@ -17,6 +17,7 @@ import copy
|
|||||||
import fixtures
|
import fixtures
|
||||||
from oslo_serialization import jsonutils as json
|
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.lib.services.compute import flavors_client
|
||||||
from tempest.tests.lib import fake_auth_provider
|
from tempest.tests.lib import fake_auth_provider
|
||||||
from tempest.tests.lib import fake_http
|
from tempest.tests.lib import fake_http
|
||||||
@ -39,6 +40,21 @@ class TestFlavorsClient(base.BaseServiceTest):
|
|||||||
"vcpus": 1
|
"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": {
|
EXTRA_SPECS = {"extra_specs": {
|
||||||
"key1": "value1",
|
"key1": "value1",
|
||||||
"key2": "value2"}
|
"key2": "value2"}
|
||||||
@ -106,6 +122,25 @@ class TestFlavorsClient(base.BaseServiceTest):
|
|||||||
def test_create_flavor__byte_body(self):
|
def test_create_flavor__byte_body(self):
|
||||||
self._test_create_flavor(bytes_body=True)
|
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):
|
def test_delete_flavor(self):
|
||||||
self.check_service_client_function(
|
self.check_service_client_function(
|
||||||
self.client.delete_flavor,
|
self.client.delete_flavor,
|
||||||
|
Loading…
Reference in New Issue
Block a user