Merge "Add 2.55 schema & update flavor API in flavors_client"

This commit is contained in:
Zuul 2018-05-16 05:35:28 +00:00 committed by Gerrit Code Review
commit e4f4d8bee1
8 changed files with 230 additions and 5 deletions

View File

@ -354,6 +354,10 @@ Microversion tests implemented in Tempest
.. _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

View File

@ -0,0 +1,4 @@
---
features:
- |
Add update flavor API to compute flavors_client library.

View 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']

View File

@ -86,7 +86,7 @@ unset_flavor_extra_specs = {
'status_code': [200]
}
create_get_flavor_details = {
create_update_get_flavor_details = {
'status_code': [200],
'response_body': {
'type': 'object',

View 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']
}
}

View File

@ -21,12 +21,18 @@ from tempest.lib.api_schema.response.compute.v2_1 import flavors_access \
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 @@ class FlavorsClient(base_compute_client.BaseComputeClient):
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 @@ class FlavorsClient(base_compute_client.BaseComputeClient):
"""
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 @@ class FlavorsClient(base_compute_client.BaseComputeClient):
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):

View File

@ -17,6 +17,7 @@ import copy
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 @@ class TestFlavorsClient(base.BaseServiceTest):
"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 @@ class TestFlavorsClient(base.BaseServiceTest):
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,