Merge "Add microversion to support extra_specs in flavor API."
This commit is contained in:
commit
c6d7d92c93
@ -105,11 +105,12 @@ Response
|
||||
- swap: flavor_swap
|
||||
- rxtx_factor: flavor_rxtx_factor
|
||||
- os-flavor-access:is_public: flavor_is_public
|
||||
- extra_specs: extra_specs_2_61
|
||||
|
||||
|
||||
**Example Create Flavor (v2.55)**
|
||||
**Example Create Flavor (v2.61)**
|
||||
|
||||
.. literalinclude:: ../../doc/api_samples/flavor-manage/v2.55/flavor-create-post-resp.json
|
||||
.. literalinclude:: ../../doc/api_samples/flavor-manage/v2.61/flavor-create-post-resp.json
|
||||
:language: javascript
|
||||
|
||||
List Flavors With Details
|
||||
@ -155,10 +156,11 @@ Response
|
||||
- swap: flavor_swap
|
||||
- rxtx_factor: flavor_rxtx_factor
|
||||
- os-flavor-access:is_public: flavor_is_public
|
||||
- extra_specs: extra_specs_2_61
|
||||
|
||||
**Example List Flavors With Details (v2.55)**
|
||||
**Example List Flavors With Details (v2.61)**
|
||||
|
||||
.. literalinclude:: ../../doc/api_samples/flavors/v2.55/flavors-detail-resp.json
|
||||
.. literalinclude:: ../../doc/api_samples/flavors/v2.61/flavors-detail-resp.json
|
||||
:language: javascript
|
||||
|
||||
Show Flavor Details
|
||||
@ -197,10 +199,11 @@ Response
|
||||
- swap: flavor_swap
|
||||
- rxtx_factor: flavor_rxtx_factor
|
||||
- os-flavor-access:is_public: flavor_is_public
|
||||
- extra_specs: extra_specs_2_61
|
||||
|
||||
**Example Show Flavor Details (v2.55)**
|
||||
**Example Show Flavor Details (v2.61)**
|
||||
|
||||
.. literalinclude:: ../../doc/api_samples/flavors/v2.55/flavor-get-resp.json
|
||||
.. literalinclude:: ../../doc/api_samples/flavors/v2.61/flavor-get-resp.json
|
||||
:language: javascript
|
||||
|
||||
Update Flavor Description
|
||||
@ -252,11 +255,12 @@ Response
|
||||
- swap: flavor_swap
|
||||
- rxtx_factor: flavor_rxtx_factor
|
||||
- os-flavor-access:is_public: flavor_is_public
|
||||
- extra_specs: extra_specs_2_61
|
||||
|
||||
|
||||
**Example Update Flavor Description (v2.55)**
|
||||
**Example Update Flavor Description (v2.61)**
|
||||
|
||||
.. literalinclude:: ../../doc/api_samples/flavor-manage/v2.55/flavor-update-resp.json
|
||||
.. literalinclude:: ../../doc/api_samples/flavor-manage/v2.61/flavor-update-resp.json
|
||||
:language: javascript
|
||||
|
||||
Delete Flavor
|
||||
|
@ -2463,6 +2463,15 @@ extra_specs_2_47:
|
||||
in: body
|
||||
required: false
|
||||
type: object
|
||||
extra_specs_2_61:
|
||||
min_version: 2.61
|
||||
description: |
|
||||
A dictionary of the flavor's extra-specs key-and-value pairs. This will
|
||||
only be included if the user is allowed by policy to index flavor
|
||||
extra_specs.
|
||||
in: body
|
||||
required: false
|
||||
type: object
|
||||
fault:
|
||||
description: |
|
||||
A fault object. Only displayed when the server status is ``ERROR`` or
|
||||
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"flavor": {
|
||||
"name": "test_flavor",
|
||||
"ram": 1024,
|
||||
"vcpus": 2,
|
||||
"disk": 10,
|
||||
"id": "10",
|
||||
"rxtx_factor": 2.0,
|
||||
"description": "test description"
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
{
|
||||
"flavor": {
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 10,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"os-flavor-access:is_public": true,
|
||||
"id": "10",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/10",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/10",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "test_flavor",
|
||||
"ram": 1024,
|
||||
"swap": "",
|
||||
"rxtx_factor": 2.0,
|
||||
"vcpus": 2,
|
||||
"description": "test description",
|
||||
"extra_specs": {}
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"flavor": {
|
||||
"description": "updated description"
|
||||
}
|
||||
}
|
26
doc/api_samples/flavor-manage/v2.61/flavor-update-resp.json
Normal file
26
doc/api_samples/flavor-manage/v2.61/flavor-update-resp.json
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"flavor": {
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 1,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"os-flavor-access:is_public": true,
|
||||
"id": "1",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/1",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/1",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.tiny",
|
||||
"ram": 512,
|
||||
"swap": "",
|
||||
"vcpus": 1,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": "updated description",
|
||||
"extra_specs": {}
|
||||
}
|
||||
}
|
29
doc/api_samples/flavors/v2.61/flavor-get-resp.json
Normal file
29
doc/api_samples/flavors/v2.61/flavor-get-resp.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"flavor": {
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 20,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"os-flavor-access:is_public": true,
|
||||
"id": "7",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/7",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/7",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.small.description",
|
||||
"ram": 2048,
|
||||
"swap": "",
|
||||
"vcpus": 1,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": "test description",
|
||||
"extra_specs": {
|
||||
"key1": "value1",
|
||||
"key2": "value2"
|
||||
}
|
||||
}
|
||||
}
|
179
doc/api_samples/flavors/v2.61/flavors-detail-resp.json
Normal file
179
doc/api_samples/flavors/v2.61/flavors-detail-resp.json
Normal file
@ -0,0 +1,179 @@
|
||||
{
|
||||
"flavors": [
|
||||
{
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 1,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"os-flavor-access:is_public": true,
|
||||
"id": "1",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/1",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/1",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.tiny",
|
||||
"ram": 512,
|
||||
"swap": "",
|
||||
"vcpus": 1,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": null,
|
||||
"extra_specs": {}
|
||||
},
|
||||
{
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 20,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"os-flavor-access:is_public": true,
|
||||
"id": "2",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/2",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/2",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.small",
|
||||
"ram": 2048,
|
||||
"swap": "",
|
||||
"vcpus": 1,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": null,
|
||||
"extra_specs": {}
|
||||
},
|
||||
{
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 40,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"os-flavor-access:is_public": true,
|
||||
"id": "3",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/3",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/3",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.medium",
|
||||
"ram": 4096,
|
||||
"swap": "",
|
||||
"vcpus": 2,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": null,
|
||||
"extra_specs": {}
|
||||
},
|
||||
{
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 80,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"os-flavor-access:is_public": true,
|
||||
"id": "4",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/4",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/4",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.large",
|
||||
"ram": 8192,
|
||||
"swap": "",
|
||||
"vcpus": 4,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": null,
|
||||
"extra_specs": {}
|
||||
},
|
||||
{
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 160,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"os-flavor-access:is_public": true,
|
||||
"id": "5",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/5",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/5",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.xlarge",
|
||||
"ram": 16384,
|
||||
"swap": "",
|
||||
"vcpus": 8,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": null,
|
||||
"extra_specs": {}
|
||||
},
|
||||
{
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 1,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"os-flavor-access:is_public": true,
|
||||
"id": "6",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/6",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/6",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.tiny.specs",
|
||||
"ram": 512,
|
||||
"swap": "",
|
||||
"vcpus": 1,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": null,
|
||||
"extra_specs": {
|
||||
"hw:cpu_model": "SandyBridge",
|
||||
"hw:mem_page_size": "2048",
|
||||
"hw:cpu_policy": "dedicated"
|
||||
}
|
||||
},
|
||||
{
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 20,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"os-flavor-access:is_public": true,
|
||||
"id": "7",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/7",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/7",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.small.description",
|
||||
"ram": 2048,
|
||||
"swap": "",
|
||||
"vcpus": 1,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": "test description",
|
||||
"extra_specs": {
|
||||
"key1": "value1",
|
||||
"key2": "value2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
109
doc/api_samples/flavors/v2.61/flavors-list-resp.json
Normal file
109
doc/api_samples/flavors/v2.61/flavors-list-resp.json
Normal file
@ -0,0 +1,109 @@
|
||||
{
|
||||
"flavors": [
|
||||
{
|
||||
"id": "1",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/1",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/1",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.tiny",
|
||||
"description": null
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/2",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/2",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.small",
|
||||
"description": null
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/3",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/3",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.medium",
|
||||
"description": null
|
||||
},
|
||||
{
|
||||
"id": "4",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/4",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/4",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.large",
|
||||
"description": null
|
||||
},
|
||||
{
|
||||
"id": "5",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/5",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/5",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.xlarge",
|
||||
"description": null
|
||||
},
|
||||
{
|
||||
"id": "6",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/6",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/6",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.tiny.specs",
|
||||
"description": null
|
||||
},
|
||||
{
|
||||
"id": "7",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2/6f70656e737461636b20342065766572/flavors/7",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/7",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.small.description",
|
||||
"description": "test description"
|
||||
}
|
||||
]
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.60",
|
||||
"version": "2.61",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.60",
|
||||
"version": "2.61",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@ -143,6 +143,9 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
API. And the os-migrations API now returns both the id and the
|
||||
uuid in response.
|
||||
* 2.60 - Add support for attaching a single volume to multiple instances.
|
||||
* 2.61 - Exposes flavor extra_specs in the flavor representation. Flavor
|
||||
extra_specs will be included in Response body of GET, POST, PUT
|
||||
/flavors APIs.
|
||||
"""
|
||||
|
||||
# The minimum and maximum versions of the API supported
|
||||
@ -151,7 +154,7 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
# Note(cyeoh): This only applies for the v2.1 API once microversions
|
||||
# support is fully merged. It does not affect the V2 API.
|
||||
_MIN_API_VERSION = "2.1"
|
||||
_MAX_API_VERSION = "2.60"
|
||||
_MAX_API_VERSION = "2.61"
|
||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||
|
||||
# Almost all proxy APIs which are related to network, images and baremetal
|
||||
|
@ -21,6 +21,7 @@ from nova.compute import flavors
|
||||
from nova import exception
|
||||
from nova import objects
|
||||
from nova.policies import base
|
||||
from nova.policies import flavor_extra_specs as fes_policies
|
||||
from nova.policies import flavor_manage as fm_policies
|
||||
from nova import policy
|
||||
|
||||
@ -110,7 +111,17 @@ class FlavorManageController(wsgi.Controller):
|
||||
exception.FlavorIdExists) as err:
|
||||
raise webob.exc.HTTPConflict(explanation=err.format_message())
|
||||
|
||||
return self._view_builder.show(req, flavor, include_description)
|
||||
include_extra_specs = False
|
||||
if api_version_request.is_supported(
|
||||
req, flavors_view.FLAVOR_EXTRA_SPECS_MICROVERSION):
|
||||
include_extra_specs = context.can(
|
||||
fes_policies.POLICY_ROOT % 'index', fatal=False)
|
||||
# NOTE(yikun): This empty extra_spec only for keeping consistent
|
||||
# with other related flavor api.
|
||||
flavor.extra_specs = {}
|
||||
|
||||
return self._view_builder.show(req, flavor, include_description,
|
||||
include_extra_specs=include_extra_specs)
|
||||
|
||||
@wsgi.Controller.api_version(flavors_view.FLAVOR_DESCRIPTION_MICROVERSION)
|
||||
@wsgi.action('update')
|
||||
@ -133,4 +144,10 @@ class FlavorManageController(wsgi.Controller):
|
||||
# Cache the flavor so the flavor_access and flavor_rxtx extensions
|
||||
# can add stuff to the response.
|
||||
req.cache_db_flavor(flavor)
|
||||
return self._view_builder.show(req, flavor, include_description=True)
|
||||
include_extra_specs = False
|
||||
if api_version_request.is_supported(
|
||||
req, flavors_view.FLAVOR_EXTRA_SPECS_MICROVERSION):
|
||||
include_extra_specs = context.can(
|
||||
fes_policies.POLICY_ROOT % 'index', fatal=False)
|
||||
return self._view_builder.show(req, flavor, include_description=True,
|
||||
include_extra_specs=include_extra_specs)
|
||||
|
@ -26,6 +26,7 @@ from nova.compute import flavors
|
||||
from nova import exception
|
||||
from nova.i18n import _
|
||||
from nova import objects
|
||||
from nova.policies import flavor_extra_specs as fes_policies
|
||||
from nova import utils
|
||||
|
||||
ALIAS = 'flavors'
|
||||
@ -47,9 +48,16 @@ class FlavorsController(wsgi.Controller):
|
||||
@wsgi.expected_errors(400)
|
||||
def detail(self, req):
|
||||
"""Return all flavors in detail."""
|
||||
context = req.environ['nova.context']
|
||||
limited_flavors = self._get_flavors(req)
|
||||
req.cache_db_flavors(limited_flavors)
|
||||
return self._view_builder.detail(req, limited_flavors)
|
||||
include_extra_specs = False
|
||||
if api_version_request.is_supported(
|
||||
req, flavors_view.FLAVOR_EXTRA_SPECS_MICROVERSION):
|
||||
include_extra_specs = context.can(
|
||||
fes_policies.POLICY_ROOT % 'index', fatal=False)
|
||||
return self._view_builder.detail(
|
||||
req, limited_flavors, include_extra_specs=include_extra_specs)
|
||||
|
||||
@wsgi.expected_errors(404)
|
||||
def show(self, req, id):
|
||||
@ -61,9 +69,16 @@ class FlavorsController(wsgi.Controller):
|
||||
except exception.FlavorNotFound as e:
|
||||
raise webob.exc.HTTPNotFound(explanation=e.format_message())
|
||||
|
||||
include_extra_specs = False
|
||||
if api_version_request.is_supported(
|
||||
req, flavors_view.FLAVOR_EXTRA_SPECS_MICROVERSION):
|
||||
include_extra_specs = context.can(
|
||||
fes_policies.POLICY_ROOT % 'index', fatal=False)
|
||||
include_description = api_version_request.is_supported(
|
||||
req, flavors_view.FLAVOR_DESCRIPTION_MICROVERSION)
|
||||
return self._view_builder.show(req, flavor, include_description)
|
||||
return self._view_builder.show(
|
||||
req, flavor, include_description=include_description,
|
||||
include_extra_specs=include_extra_specs)
|
||||
|
||||
def _parse_is_public(self, is_public):
|
||||
"""Parse is_public into something usable."""
|
||||
|
@ -765,3 +765,18 @@ From this version of the API users can attach a ``multiattach`` capable volume
|
||||
to multiple instances. The API request for creating the additional attachments
|
||||
is the same. The chosen virt driver and the volume back end has to support the
|
||||
functionality as well.
|
||||
|
||||
2.61
|
||||
----
|
||||
|
||||
Exposes flavor extra_specs in the flavor representation. Now users can see the
|
||||
flavor extra-specs in flavor APIs response and do not need to call
|
||||
``GET /flavors/{flavor_id}/os-extra_specs`` API. If the user is prevented by
|
||||
policy from indexing extra-specs, then the ``extra_specs`` field will not be
|
||||
included in the flavor information. Flavor extra_specs will be included in
|
||||
Response body of the following APIs:
|
||||
|
||||
* ``GET /flavors/detail``
|
||||
* ``GET /flavors/{flavor_id}``
|
||||
* ``POST /flavors``
|
||||
* ``PUT /flavors/{flavor_id}``
|
||||
|
@ -19,6 +19,7 @@ from nova.policies import flavor_access as fa_policies
|
||||
from nova.policies import flavor_rxtx as fr_policies
|
||||
|
||||
FLAVOR_DESCRIPTION_MICROVERSION = '2.55'
|
||||
FLAVOR_EXTRA_SPECS_MICROVERSION = '2.61'
|
||||
|
||||
|
||||
class ViewBuilder(common.ViewBuilder):
|
||||
@ -26,10 +27,12 @@ class ViewBuilder(common.ViewBuilder):
|
||||
_collection_name = "flavors"
|
||||
|
||||
def basic(self, request, flavor, include_description=False,
|
||||
update_is_public=None, update_rxtx_factor=None):
|
||||
# update_is_public & update_rxtx_factor are placeholder param
|
||||
# which are not used in this method as basic() method is used by
|
||||
# index() (GET /flavors) which does not return those keys in response.
|
||||
update_is_public=None, update_rxtx_factor=None,
|
||||
include_extra_specs=False):
|
||||
# include_extra_specs & update_is_public & update_rxtx_factor are
|
||||
# placeholder param which are not used in this method as basic() method
|
||||
# is used by index() (GET /flavors) which does not return those keys in
|
||||
# response.
|
||||
flavor_dict = {
|
||||
"flavor": {
|
||||
"id": flavor["flavorid"],
|
||||
@ -46,7 +49,8 @@ class ViewBuilder(common.ViewBuilder):
|
||||
return flavor_dict
|
||||
|
||||
def show(self, request, flavor, include_description=False,
|
||||
update_is_public=None, update_rxtx_factor=None):
|
||||
update_is_public=None, update_rxtx_factor=None,
|
||||
include_extra_specs=False):
|
||||
flavor_dict = {
|
||||
"flavor": {
|
||||
"id": flavor["flavorid"],
|
||||
@ -66,6 +70,9 @@ class ViewBuilder(common.ViewBuilder):
|
||||
if include_description:
|
||||
flavor_dict['flavor']['description'] = flavor.description
|
||||
|
||||
if include_extra_specs:
|
||||
flavor_dict['flavor']['extra_specs'] = flavor.extra_specs
|
||||
|
||||
# TODO(gmann): 'update_is_public' & 'update_rxtx_factor' are policies
|
||||
# checks. Once os-flavor-access & os-flavor-rxtx policies are
|
||||
# removed, 'os-flavor-access:is_public' and 'rxtx_factor' need to be
|
||||
@ -96,7 +103,7 @@ class ViewBuilder(common.ViewBuilder):
|
||||
return self._list_view(self.basic, request, flavors, coll_name,
|
||||
include_description=include_description)
|
||||
|
||||
def detail(self, request, flavors):
|
||||
def detail(self, request, flavors, include_extra_specs=False):
|
||||
"""Return the 'detail' view of flavors."""
|
||||
coll_name = self._collection_name + '/detail'
|
||||
include_description = api_version_request.is_supported(
|
||||
@ -109,11 +116,12 @@ class ViewBuilder(common.ViewBuilder):
|
||||
return self._list_view(self.show, request, flavors, coll_name,
|
||||
include_description=include_description,
|
||||
update_is_public=update_is_public,
|
||||
update_rxtx_factor=update_rxtx_factor)
|
||||
update_rxtx_factor=update_rxtx_factor,
|
||||
include_extra_specs=include_extra_specs)
|
||||
|
||||
def _list_view(self, func, request, flavors, coll_name,
|
||||
include_description=False, update_is_public=None,
|
||||
update_rxtx_factor=None):
|
||||
update_rxtx_factor=None, include_extra_specs=False):
|
||||
"""Provide a view for a list of flavors.
|
||||
|
||||
:param func: Function used to format the flavor data
|
||||
@ -127,11 +135,14 @@ class ViewBuilder(common.ViewBuilder):
|
||||
included in the response dict.
|
||||
:param update_rxtx_factor: If the flavor.rxtx_factor field should be
|
||||
included in the response dict.
|
||||
:param include_extra_specs: If the flavor.extra_specs should be
|
||||
included in the response dict.
|
||||
|
||||
:returns: Flavor reply data in dictionary format
|
||||
"""
|
||||
flavor_list = [func(request, flavor, include_description,
|
||||
update_is_public, update_rxtx_factor)["flavor"]
|
||||
update_is_public, update_rxtx_factor,
|
||||
include_extra_specs)["flavor"]
|
||||
for flavor in flavors]
|
||||
flavors_links = self._get_collection_links(request,
|
||||
flavors,
|
||||
|
@ -0,0 +1,11 @@
|
||||
{
|
||||
"flavor": {
|
||||
"name": "%(flavor_name)s",
|
||||
"ram": 1024,
|
||||
"vcpus": 2,
|
||||
"disk": 10,
|
||||
"id": "%(flavor_id)s",
|
||||
"rxtx_factor": 2.0,
|
||||
"description": "test description"
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
{
|
||||
"flavor": {
|
||||
"disk": 10,
|
||||
"id": "%(flavor_id)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/%(flavor_id)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/%(flavor_id)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "%(flavor_name)s",
|
||||
"os-flavor-access:is_public": true,
|
||||
"ram": 1024,
|
||||
"vcpus": 2,
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"swap": "",
|
||||
"rxtx_factor": 2.0,
|
||||
"description": "test description",
|
||||
"extra_specs": {}
|
||||
}
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
{
|
||||
"flavor": {
|
||||
"description": "updated description"
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
{
|
||||
"flavor": {
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 1,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"os-flavor-access:is_public": true,
|
||||
"id": "1",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/flavors/1",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/flavors/1",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.tiny",
|
||||
"ram": 512,
|
||||
"swap": "",
|
||||
"vcpus": 1,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": "updated description",
|
||||
"extra_specs": {}
|
||||
}
|
||||
}
|
@ -0,0 +1,29 @@
|
||||
{
|
||||
"flavor": {
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 20,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"id": "%(flavorid)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/%(flavorid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/%(flavorid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.small.description",
|
||||
"os-flavor-access:is_public": true,
|
||||
"ram": 2048,
|
||||
"swap": "",
|
||||
"vcpus": 1,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": "test description",
|
||||
"extra_specs": {
|
||||
"key1": "value1",
|
||||
"key2": "value2"
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
{
|
||||
"flavors": [
|
||||
{
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 1,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"id": "1",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/1",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/1",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.tiny",
|
||||
"os-flavor-access:is_public": true,
|
||||
"ram": 512,
|
||||
"swap": "",
|
||||
"vcpus": 1,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": null,
|
||||
"extra_specs": {}
|
||||
},
|
||||
{
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 20,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"id": "2",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/2",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/2",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.small",
|
||||
"os-flavor-access:is_public": true,
|
||||
"ram": 2048,
|
||||
"swap": "",
|
||||
"vcpus": 1,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": null,
|
||||
"extra_specs": {}
|
||||
},
|
||||
{
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 40,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"id": "3",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/3",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/3",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.medium",
|
||||
"os-flavor-access:is_public": true,
|
||||
"ram": 4096,
|
||||
"swap": "",
|
||||
"vcpus": 2,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": null,
|
||||
"extra_specs": {}
|
||||
},
|
||||
{
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 80,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"id": "4",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/4",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/4",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.large",
|
||||
"os-flavor-access:is_public": true,
|
||||
"ram": 8192,
|
||||
"swap": "",
|
||||
"vcpus": 4,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": null,
|
||||
"extra_specs": {}
|
||||
},
|
||||
{
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 160,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"id": "5",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/5",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/5",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.xlarge",
|
||||
"os-flavor-access:is_public": true,
|
||||
"ram": 16384,
|
||||
"swap": "",
|
||||
"vcpus": 8,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": null,
|
||||
"extra_specs": {}
|
||||
},
|
||||
{
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 1,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"id": "6",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/6",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/6",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.tiny.specs",
|
||||
"os-flavor-access:is_public": true,
|
||||
"ram": 512,
|
||||
"swap": "",
|
||||
"vcpus": 1,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": null,
|
||||
"extra_specs": {
|
||||
"hw:cpu_model": "SandyBridge",
|
||||
"hw:mem_page_size": "2048",
|
||||
"hw:cpu_policy": "dedicated"
|
||||
}
|
||||
},
|
||||
{
|
||||
"OS-FLV-DISABLED:disabled": false,
|
||||
"disk": 20,
|
||||
"OS-FLV-EXT-DATA:ephemeral": 0,
|
||||
"id": "%(flavorid)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/%(flavorid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/%(flavorid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.small.description",
|
||||
"os-flavor-access:is_public": true,
|
||||
"ram": 2048,
|
||||
"swap": "",
|
||||
"vcpus": 1,
|
||||
"rxtx_factor": 1.0,
|
||||
"description": "test description",
|
||||
"extra_specs": {
|
||||
"key1": "value1",
|
||||
"key2": "value2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,109 @@
|
||||
{
|
||||
"flavors": [
|
||||
{
|
||||
"id": "1",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/1",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/1",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.tiny",
|
||||
"description": null
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/2",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/2",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.small",
|
||||
"description": null
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/3",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/3",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.medium",
|
||||
"description": null
|
||||
},
|
||||
{
|
||||
"id": "4",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/4",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/4",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.large",
|
||||
"description": null
|
||||
},
|
||||
{
|
||||
"id": "5",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/5",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/5",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.xlarge",
|
||||
"description": null
|
||||
},
|
||||
{
|
||||
"id": "6",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/6",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/6",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.tiny.specs",
|
||||
"description": null
|
||||
},
|
||||
{
|
||||
"id": "%(flavorid)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(versioned_compute_endpoint)s/flavors/%(flavorid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(compute_endpoint)s/flavors/%(flavorid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"name": "m1.small.description",
|
||||
"description": "test description"
|
||||
}
|
||||
]
|
||||
}
|
@ -57,3 +57,26 @@ class FlavorsSampleJsonTest2_55(FlavorsSampleJsonTest):
|
||||
new_flavor.create()
|
||||
self.flavor_show_id = new_flavor_id
|
||||
self.subs = {'flavorid': new_flavor_id}
|
||||
|
||||
|
||||
class FlavorsSampleJsonTest2_61(FlavorsSampleJsonTest):
|
||||
microversion = '2.61'
|
||||
scenarios = [('v2_61', {'api_major_version': 'v2.1'})]
|
||||
|
||||
def setUp(self):
|
||||
super(FlavorsSampleJsonTest2_61, self).setUp()
|
||||
# Get the existing flavors created by DefaultFlavorsFixture.
|
||||
ctxt = nova_context.get_admin_context()
|
||||
flavors = objects.FlavorList.get_all(ctxt)
|
||||
# Flavors are sorted by flavorid in ascending order by default, so
|
||||
# get the last flavor in the list and create a new flavor with an
|
||||
# incremental flavorid so we have a predictable sort order for the
|
||||
# sample response.
|
||||
new_flavor_id = int(flavors[-1].flavorid) + 1
|
||||
new_flavor = objects.Flavor(
|
||||
ctxt, memory_mb=2048, vcpus=1, root_gb=20, flavorid=new_flavor_id,
|
||||
name='m1.small.description', description='test description',
|
||||
extra_specs={"key1": "value1", "key2": "value2"})
|
||||
new_flavor.create()
|
||||
self.flavor_show_id = new_flavor_id
|
||||
self.subs = {'flavorid': new_flavor_id}
|
||||
|
@ -52,6 +52,8 @@ class FlavorsTestV21(test.TestCase):
|
||||
microversion = '2.1'
|
||||
# Flag to tell the test if a description should be expected in a response.
|
||||
expect_description = False
|
||||
# Flag to tell the test if a extra_specs should be expected in a response.
|
||||
expect_extra_specs = False
|
||||
|
||||
def setUp(self):
|
||||
super(FlavorsTestV21, self).setUp()
|
||||
@ -73,6 +75,8 @@ class FlavorsTestV21(test.TestCase):
|
||||
expected['swap'] = flavor.swap
|
||||
if self.expect_description:
|
||||
expected['description'] = flavor.description
|
||||
if self.expect_extra_specs:
|
||||
expected['extra_specs'] = flavor.extra_specs
|
||||
|
||||
@mock.patch('nova.objects.Flavor.get_by_flavor_id',
|
||||
side_effect=return_flavor_not_found)
|
||||
@ -769,6 +773,12 @@ class FlavorsTestV2_55(FlavorsTestV21):
|
||||
expect_description = True
|
||||
|
||||
|
||||
class FlavorsTestV2_61(FlavorsTestV2_55):
|
||||
"""Run the same tests as we would for v2.55 but with a extra_specs."""
|
||||
microversion = '2.61'
|
||||
expect_extra_specs = True
|
||||
|
||||
|
||||
class FlavorsPolicyEnforcementV21(test.NoDBTestCase):
|
||||
|
||||
def setUp(self):
|
||||
|
@ -705,7 +705,8 @@ FLAVORS = {
|
||||
vcpu_weight=None,
|
||||
disabled=False,
|
||||
is_public=True,
|
||||
description=None
|
||||
description=None,
|
||||
extra_specs={"key1": "value1", "key2": "value2"}
|
||||
),
|
||||
'2': objects.Flavor(
|
||||
id=2,
|
||||
@ -720,7 +721,8 @@ FLAVORS = {
|
||||
vcpu_weight=None,
|
||||
disabled=True,
|
||||
is_public=True,
|
||||
description='flavor 2 description'
|
||||
description='flavor 2 description',
|
||||
extra_specs={}
|
||||
),
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,18 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Exposes flavor extra_specs in the flavor representation since microversion
|
||||
2.61. Flavor extra_specs will be included in Response body of the
|
||||
following APIs:
|
||||
|
||||
* ``GET /flavors/detail``
|
||||
* ``GET /flavors/{flavor_id}``
|
||||
* ``POST /flavors``
|
||||
* ``PUT /flavors/{flavor_id}``
|
||||
|
||||
Now users can see the flavor extra-specs in flavor APIs response and do
|
||||
not need to call ``GET /flavors/{flavor_id}/os-extra_specs`` API. The
|
||||
visibility of the flavor extra_specs within the flavor resource will be
|
||||
controlled by the same policy rules as are used for showing the flavor
|
||||
extra_specs. If the user has no access to query extra_specs, the
|
||||
``flavor.extra_specs`` will not be included.
|
Loading…
Reference in New Issue
Block a user