Merge "Return uuid attribute for aggregates"
This commit is contained in:
commit
9b918199d8
|
@ -34,6 +34,7 @@ Response
|
|||
- metadata: aggregate_metadata
|
||||
- name: aggregate_name
|
||||
- updated_at: updated_consider_null
|
||||
- uuid: aggregate_uuid
|
||||
|
||||
**Example List Aggregates: JSON response**
|
||||
|
||||
|
@ -79,6 +80,7 @@ Response
|
|||
- id: aggregate_id_body
|
||||
- name: aggregate_name
|
||||
- updated_at: updated_consider_null
|
||||
- uuid: aggregate_uuid
|
||||
|
||||
**Example Create Aggregate: JSON response**
|
||||
|
||||
|
@ -118,6 +120,7 @@ Response
|
|||
- metadata: aggregate_metadata
|
||||
- name: aggregate_name
|
||||
- updated_at: updated_consider_null
|
||||
- uuid: aggregate_uuid
|
||||
|
||||
**Example Show Aggregate Details: JSON response**
|
||||
|
||||
|
@ -168,6 +171,7 @@ Response
|
|||
- metadata: aggregate_metadata
|
||||
- name: aggregate_name
|
||||
- updated_at: updated_consider_null
|
||||
- uuid: aggregate_uuid
|
||||
|
||||
**Example Update Aggregate: JSON response**
|
||||
|
||||
|
@ -240,6 +244,7 @@ Response
|
|||
- metadata: aggregate_metadata
|
||||
- name: aggregate_name
|
||||
- updated_at: updated_consider_null
|
||||
- uuid: aggregate_uuid
|
||||
|
||||
**Example Add Host: JSON response**
|
||||
|
||||
|
@ -289,6 +294,7 @@ Response
|
|||
- metadata: aggregate_metadata
|
||||
- name: aggregate_name
|
||||
- updated_at: updated_consider_null
|
||||
- uuid: aggregate_uuid
|
||||
|
||||
**Example Remove Host: JSON response**
|
||||
|
||||
|
@ -338,6 +344,7 @@ Response
|
|||
- metadata: aggregate_metadata
|
||||
- name: aggregate_name
|
||||
- updated_at: updated_consider_null
|
||||
- uuid: aggregate_uuid
|
||||
|
||||
**Example Create Or Update Aggregate Metadata: JSON response**
|
||||
|
||||
|
|
|
@ -967,6 +967,12 @@ aggregate_remove_host:
|
|||
in: body
|
||||
required: true
|
||||
type: object
|
||||
aggregate_uuid:
|
||||
description: |
|
||||
The UUID of the host aggregate.
|
||||
in: body
|
||||
type: string
|
||||
min_version: 2.41
|
||||
aggregates:
|
||||
description: |
|
||||
The list of existing aggregates.
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"add_host": {
|
||||
"host": "compute"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"set_metadata":
|
||||
{
|
||||
"metadata":
|
||||
{
|
||||
"key": "value"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"aggregate":
|
||||
{
|
||||
"name": "name",
|
||||
"availability_zone": "nova"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2016-12-27T22:51:32.877711",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"id": 1,
|
||||
"name": "name",
|
||||
"updated_at": null,
|
||||
"uuid": "86a0da0e-9f0c-4f51-a1e0-3c25edab3783"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"remove_host": {
|
||||
"host": "compute"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"aggregate":
|
||||
{
|
||||
"name": "newname",
|
||||
"availability_zone": "nova2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova2",
|
||||
"created_at": "2016-12-27T23:47:32.897139",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {
|
||||
"availability_zone": "nova2"
|
||||
},
|
||||
"name": "newname",
|
||||
"updated_at": "2016-12-27T23:47:33.067180",
|
||||
"uuid": "6f74e3f3-df28-48f3-98e1-ac941b1c5e43"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2016-12-27T23:47:30.594805",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [
|
||||
"compute"
|
||||
],
|
||||
"id": 1,
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null,
|
||||
"uuid": "d1842372-89c5-4fbd-ad5a-5d2e16c85456"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2016-12-27T23:47:30.563527",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null,
|
||||
"uuid": "fd0a5b12-7e8d-469d-bfd5-64a6823e7407"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"aggregates": [
|
||||
{
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2016-12-27T23:47:32.911515",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [
|
||||
"compute"
|
||||
],
|
||||
"id": 1,
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null,
|
||||
"uuid": "6ba28ba7-f29b-45cc-a30b-6e3a40c2fb14"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2016-12-27T23:59:18.623100",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {
|
||||
"availability_zone": "nova",
|
||||
"key": "value"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": "2016-12-27T23:59:18.723348",
|
||||
"uuid": "26002bdb-62cc-41bd-813a-0ad22db32625"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova",
|
||||
"created_at": "2016-12-27T23:47:30.594805",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null,
|
||||
"uuid": "d1842372-89c5-4fbd-ad5a-5d2e16c85456"
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@
|
|||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.40",
|
||||
"version": "2.41",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.40",
|
||||
"version": "2.41",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
|
|
@ -97,6 +97,7 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
|||
provided for listing servers.
|
||||
* 2.39 - Deprecates image-metadata proxy API
|
||||
* 2.40 - Adds simple tenant usage pagination support.
|
||||
* 2.41 - Return uuid attribute for aggregates.
|
||||
"""
|
||||
|
||||
# The minimum and maximum versions of the API supported
|
||||
|
@ -105,7 +106,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.40"
|
||||
_MAX_API_VERSION = "2.41"
|
||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||
|
||||
# Almost all proxy APIs which related to network, images and baremetal
|
||||
|
|
|
@ -19,6 +19,7 @@ import datetime
|
|||
|
||||
from webob import exc
|
||||
|
||||
from nova.api.openstack import api_version_request
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack.compute.schemas import aggregates
|
||||
from nova.api.openstack import extensions
|
||||
|
@ -47,7 +48,7 @@ class AggregateController(wsgi.Controller):
|
|||
context = _get_context(req)
|
||||
context.can(aggr_policies.POLICY_ROOT % 'index')
|
||||
aggregates = self.api.get_aggregate_list(context)
|
||||
return {'aggregates': [self._marshall_aggregate(a)['aggregate']
|
||||
return {'aggregates': [self._marshall_aggregate(req, a)['aggregate']
|
||||
for a in aggregates]}
|
||||
|
||||
# NOTE(gmann): Returns 200 for backwards compatibility but should be 201
|
||||
|
@ -77,7 +78,7 @@ class AggregateController(wsgi.Controller):
|
|||
except exception.InvalidAggregateAction as e:
|
||||
raise exc.HTTPBadRequest(explanation=e.format_message())
|
||||
|
||||
agg = self._marshall_aggregate(aggregate)
|
||||
agg = self._marshall_aggregate(req, aggregate)
|
||||
|
||||
# To maintain the same API result as before the changes for returning
|
||||
# nova objects were made.
|
||||
|
@ -95,7 +96,7 @@ class AggregateController(wsgi.Controller):
|
|||
aggregate = self.api.get_aggregate(context, id)
|
||||
except exception.AggregateNotFound as e:
|
||||
raise exc.HTTPNotFound(explanation=e.format_message())
|
||||
return self._marshall_aggregate(aggregate)
|
||||
return self._marshall_aggregate(req, aggregate)
|
||||
|
||||
@extensions.expected_errors((400, 404, 409))
|
||||
@validation.schema(aggregates.update_v20, '2.0', '2.0')
|
||||
|
@ -117,7 +118,7 @@ class AggregateController(wsgi.Controller):
|
|||
except exception.InvalidAggregateAction as e:
|
||||
raise exc.HTTPBadRequest(explanation=e.format_message())
|
||||
|
||||
return self._marshall_aggregate(aggregate)
|
||||
return self._marshall_aggregate(req, aggregate)
|
||||
|
||||
# NOTE(gmann): Returns 200 for backwards compatibility but should be 204
|
||||
# as this operation complete the deletion of aggregate resource and return
|
||||
|
@ -154,7 +155,7 @@ class AggregateController(wsgi.Controller):
|
|||
except (exception.AggregateHostExists,
|
||||
exception.InvalidAggregateAction) as e:
|
||||
raise exc.HTTPConflict(explanation=e.format_message())
|
||||
return self._marshall_aggregate(aggregate)
|
||||
return self._marshall_aggregate(req, aggregate)
|
||||
|
||||
# NOTE(gmann): Returns 200 for backwards compatibility but should be 202
|
||||
# for representing async API as this API just accepts the request and
|
||||
|
@ -179,7 +180,7 @@ class AggregateController(wsgi.Controller):
|
|||
msg = _('Cannot remove host %(host)s in aggregate %(id)s') % {
|
||||
'host': host, 'id': id}
|
||||
raise exc.HTTPConflict(explanation=msg)
|
||||
return self._marshall_aggregate(aggregate)
|
||||
return self._marshall_aggregate(req, aggregate)
|
||||
|
||||
@extensions.expected_errors((400, 404))
|
||||
@wsgi.action('set_metadata')
|
||||
|
@ -198,18 +199,19 @@ class AggregateController(wsgi.Controller):
|
|||
except exception.InvalidAggregateAction as e:
|
||||
raise exc.HTTPBadRequest(explanation=e.format_message())
|
||||
|
||||
return self._marshall_aggregate(aggregate)
|
||||
return self._marshall_aggregate(req, aggregate)
|
||||
|
||||
def _marshall_aggregate(self, aggregate):
|
||||
def _marshall_aggregate(self, req, aggregate):
|
||||
_aggregate = {}
|
||||
for key, value in self._build_aggregate_items(aggregate):
|
||||
for key, value in self._build_aggregate_items(req, aggregate):
|
||||
# NOTE(danms): The original API specified non-TZ-aware timestamps
|
||||
if isinstance(value, datetime.datetime):
|
||||
value = value.replace(tzinfo=None)
|
||||
_aggregate[key] = value
|
||||
return {"aggregate": _aggregate}
|
||||
|
||||
def _build_aggregate_items(self, aggregate):
|
||||
def _build_aggregate_items(self, req, aggregate):
|
||||
show_uuid = api_version_request.is_supported(req, min_version="2.41")
|
||||
keys = aggregate.obj_fields
|
||||
# NOTE(rlrossit): Within the compute API, metadata will always be
|
||||
# set on the aggregate object (at a minimum to {}). Because of this,
|
||||
|
@ -217,11 +219,9 @@ class AggregateController(wsgi.Controller):
|
|||
# case it is only ['availability_zone']) without worrying about
|
||||
# lazy-loading an unset variable
|
||||
for key in keys:
|
||||
# NOTE(danms): Skip the uuid field because we have no microversion
|
||||
# to expose it
|
||||
if ((aggregate.obj_attr_is_set(key)
|
||||
or key in aggregate.obj_extra_fields) and
|
||||
key != 'uuid'):
|
||||
(show_uuid or key != 'uuid')):
|
||||
yield key, getattr(aggregate, key)
|
||||
|
||||
|
||||
|
|
|
@ -445,3 +445,11 @@ user documentation.
|
|||
`CONF.api.max_limit` to encourage the adoption of this new microversion,
|
||||
and circumvent the existing possibility DoS-like usage requests on systems
|
||||
with thousands of instances.
|
||||
|
||||
2.41
|
||||
----
|
||||
|
||||
The 'uuid' attribute of an aggregate is now returned from calls to the
|
||||
`/os-aggregates` endpoint. This attribute is auto-generated upon creation of
|
||||
an aggregate. The `os-aggregates` API resource endpoint remains an
|
||||
administrator-only API.
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"add_host": {
|
||||
"host": "%(host_name)s"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"set_metadata":
|
||||
{
|
||||
"metadata":
|
||||
{
|
||||
"key": "value"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"aggregate":
|
||||
{
|
||||
"name": "name",
|
||||
"availability_zone": "nova"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova",
|
||||
"created_at": "%(strtime)s",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"id": %(aggregate_id)s,
|
||||
"name": "name",
|
||||
"updated_at": null,
|
||||
"uuid": "%(uuid)s"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"remove_host": {
|
||||
"host": "%(host_name)s"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"aggregate":
|
||||
{
|
||||
"name": "newname",
|
||||
"availability_zone": "nova2"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova2",
|
||||
"created_at": "%(strtime)s",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {
|
||||
"availability_zone": "nova2"
|
||||
},
|
||||
"name": "newname",
|
||||
"updated_at": "%(strtime)s",
|
||||
"uuid": "%(uuid)s"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova",
|
||||
"created_at": "%(strtime)s",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [
|
||||
"%(compute_host)s"
|
||||
],
|
||||
"id": 1,
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null,
|
||||
"uuid": "%(uuid)s"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova",
|
||||
"created_at": "%(strtime)s",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null,
|
||||
"uuid": "%(uuid)s"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"aggregates": [
|
||||
{
|
||||
"availability_zone": "nova",
|
||||
"created_at": "%(strtime)s",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [
|
||||
"%(compute_host)s"
|
||||
],
|
||||
"id": 1,
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null,
|
||||
"uuid": "%(uuid)s"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova",
|
||||
"created_at": "%(strtime)s",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {
|
||||
"availability_zone": "nova",
|
||||
"key": "value"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": %(strtime)s,
|
||||
"uuid": "%(uuid)s"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"aggregate": {
|
||||
"availability_zone": "nova",
|
||||
"created_at": "%(strtime)s",
|
||||
"deleted": false,
|
||||
"deleted_at": null,
|
||||
"hosts": [],
|
||||
"id": 1,
|
||||
"metadata": {
|
||||
"availability_zone": "nova"
|
||||
},
|
||||
"name": "name",
|
||||
"updated_at": null,
|
||||
"uuid": "%(uuid)s"
|
||||
}
|
||||
}
|
|
@ -13,12 +13,18 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
|
||||
from nova.tests.functional.api_sample_tests import api_sample_base
|
||||
|
||||
|
||||
class AggregatesSampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
|
||||
ADMIN_API = True
|
||||
sample_dir = "os-aggregates"
|
||||
# extra_subs is a noop in the base v2.1 test class; it's used to sub in
|
||||
# additional details for response verification of actions performed on an
|
||||
# existing aggregate.
|
||||
extra_subs = {}
|
||||
|
||||
def _test_aggregate_create(self):
|
||||
subs = {
|
||||
|
@ -37,6 +43,7 @@ class AggregatesSampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
|
|||
}
|
||||
response = self._do_post('os-aggregates/%s/action' % aggregate_id,
|
||||
'aggregate-add-host-post-req', subs)
|
||||
subs.update(self.extra_subs)
|
||||
self._verify_response('aggregates-add-host-post-resp', subs,
|
||||
response, 200)
|
||||
|
||||
|
@ -49,14 +56,15 @@ class AggregatesSampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
|
|||
def test_aggregate_get(self):
|
||||
agg_id = self._test_aggregate_create()
|
||||
response = self._do_get('os-aggregates/%s' % agg_id)
|
||||
self._verify_response('aggregates-get-resp', {}, response, 200)
|
||||
self._verify_response('aggregates-get-resp', self.extra_subs,
|
||||
response, 200)
|
||||
|
||||
def test_add_metadata(self):
|
||||
agg_id = self._test_aggregate_create()
|
||||
response = self._do_post('os-aggregates/%s/action' % agg_id,
|
||||
'aggregate-metadata-post-req',
|
||||
{'action': 'set_metadata'})
|
||||
self._verify_response('aggregates-metadata-post-resp', {},
|
||||
self._verify_response('aggregates-metadata-post-resp', self.extra_subs,
|
||||
response, 200)
|
||||
|
||||
def test_add_host(self):
|
||||
|
@ -70,6 +78,7 @@ class AggregatesSampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
|
|||
}
|
||||
response = self._do_post('os-aggregates/1/action',
|
||||
'aggregate-remove-host-post-req', subs)
|
||||
subs.update(self.extra_subs)
|
||||
self._verify_response('aggregates-remove-host-post-resp',
|
||||
subs, response, 200)
|
||||
|
||||
|
@ -78,4 +87,33 @@ class AggregatesSampleJsonTest(api_sample_base.ApiSampleTestBaseV21):
|
|||
response = self._do_put('os-aggregates/%s' % aggregate_id,
|
||||
'aggregate-update-post-req', {})
|
||||
self._verify_response('aggregate-update-post-resp',
|
||||
{}, response, 200)
|
||||
self.extra_subs, response, 200)
|
||||
|
||||
|
||||
class AggregatesV2_41_SampleJsonTest(AggregatesSampleJsonTest):
|
||||
microversion = '2.41'
|
||||
scenarios = [
|
||||
(
|
||||
"v2_41", {
|
||||
'api_major_version': 'v2.1',
|
||||
},
|
||||
)
|
||||
]
|
||||
|
||||
def _test_aggregate_create(self):
|
||||
subs = {
|
||||
"aggregate_id": '(?P<id>\d+)',
|
||||
}
|
||||
response = self._do_post('os-aggregates', 'aggregate-post-req', subs)
|
||||
# This feels like cheating since we're getting the uuid from the
|
||||
# response before we even validate that it exists in the response based
|
||||
# on the sample, but we'll fail with a KeyError if it doesn't which is
|
||||
# maybe good enough. Alternatively we have to mock out the DB API
|
||||
# to return a fake aggregate with a hard-coded uuid that matches the
|
||||
# API sample which isn't fun either.
|
||||
subs['uuid'] = jsonutils.loads(response.content)['aggregate']['uuid']
|
||||
# save off the uuid for subs validation on other actions performed
|
||||
# on this aggregate
|
||||
self.extra_subs['uuid'] = subs['uuid']
|
||||
return self._verify_response('aggregate-post-resp',
|
||||
subs, response, 200)
|
||||
|
|
|
@ -89,6 +89,9 @@ class _IntegratedTestBase(test.TestCase):
|
|||
else:
|
||||
self.api = self.api_fixture.api
|
||||
|
||||
if hasattr(self, 'microversion'):
|
||||
self.api.microversion = self.microversion
|
||||
|
||||
self.useFixture(cast_as_call.CastAsCall(self.stubs))
|
||||
|
||||
self.addCleanup(nova.tests.unit.image.fake.FakeImageService_reset)
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
import mock
|
||||
from webob import exc
|
||||
|
||||
from nova.api.openstack import api_version_request
|
||||
from nova.api.openstack.compute import aggregates as aggregates_v21
|
||||
from nova.compute import api as compute_api
|
||||
from nova import context
|
||||
|
@ -743,11 +744,23 @@ class AggregateTestCaseV21(test.NoDBTestCase):
|
|||
'metadata': {'foo': 'bar', 'availability_zone': 'nova'},
|
||||
'hosts': ['host1', 'host2']}
|
||||
agg_obj = _make_agg_obj(agg)
|
||||
marshalled_agg = self.controller._marshall_aggregate(agg_obj)
|
||||
|
||||
# _marshall_aggregate() puts all fields and obj_extra_fields in the
|
||||
# top-level dict, so we need to put availability_zone at the top also
|
||||
agg['availability_zone'] = 'nova'
|
||||
|
||||
avr_v240 = api_version_request.APIVersionRequest("2.40")
|
||||
avr_v241 = api_version_request.APIVersionRequest("2.41")
|
||||
|
||||
req = mock.MagicMock(api_version_request=avr_v241)
|
||||
marshalled_agg = self.controller._marshall_aggregate(req, agg_obj)
|
||||
|
||||
self.assertEqual(agg, marshalled_agg['aggregate'])
|
||||
|
||||
req = mock.MagicMock(api_version_request=avr_v240)
|
||||
marshalled_agg = self.controller._marshall_aggregate(req, agg_obj)
|
||||
|
||||
# UUID isn't in microversion 2.40 and before
|
||||
del agg['uuid']
|
||||
self.assertEqual(agg, marshalled_agg['aggregate'])
|
||||
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
features:
|
||||
- A new 2.41 microversion was added to the Compute API. Users specifying this
|
||||
microversion will now see the 'uuid' attribute of aggregates when calling
|
||||
the `os-aggregates` REST API endpoint.
|
Loading…
Reference in New Issue