From 14bb8ff2373536fa0df24bb4f7198c14d58d8e2f Mon Sep 17 00:00:00 2001 From: Stephen Finucane Date: Fri, 22 Nov 2024 15:31:41 +0000 Subject: [PATCH] api: Add response body schemas for host aggregate APIs We already tackled the action APIs for this resource. Now tackle the remaining APIs. Change-Id: I62de0e325d86f761a09c5a70e80d8d8209ed4bf1 Signed-off-by: Stephen Finucane --- nova/api/openstack/compute/aggregates.py | 13 +- .../compute/schemas/aggregate_images.py | 6 +- .../openstack/compute/schemas/aggregates.py | 154 ++++++++++++------ .../api/openstack/compute/test_aggregates.py | 16 +- 4 files changed, 122 insertions(+), 67 deletions(-) diff --git a/nova/api/openstack/compute/aggregates.py b/nova/api/openstack/compute/aggregates.py index 70d685eee1..6c93b0498a 100644 --- a/nova/api/openstack/compute/aggregates.py +++ b/nova/api/openstack/compute/aggregates.py @@ -50,6 +50,8 @@ class AggregateController(wsgi.Controller): @wsgi.expected_errors(()) @validation.query_schema(schema.index_query) + @validation.response_body_schema(schema.index_response, '2.1', '2.40') + @validation.response_body_schema(schema.index_response_v241, '2.41') def index(self, req): """Returns a list a host aggregate's id, name, availability_zone.""" context = _get_context(req) @@ -63,6 +65,8 @@ class AggregateController(wsgi.Controller): @wsgi.expected_errors((400, 409)) @validation.schema(schema.create_v20, '2.0', '2.0') @validation.schema(schema.create, '2.1') + @validation.response_body_schema(schema.create_response, '2.1', '2.40') + @validation.response_body_schema(schema.create_response_v241, '2.41') def create(self, req, body): """Creates an aggregate, given its name and optional availability zone. @@ -96,6 +100,8 @@ class AggregateController(wsgi.Controller): @wsgi.expected_errors((400, 404)) @validation.query_schema(schema.show_query) + @validation.response_body_schema(schema.show_response, '2.1', '2.40') + @validation.response_body_schema(schema.show_response_v241, '2.41') def show(self, req, id): """Shows the details of an aggregate, hosts and metadata included.""" context = _get_context(req) @@ -115,6 +121,8 @@ class AggregateController(wsgi.Controller): @wsgi.expected_errors((400, 404, 409)) @validation.schema(schema.update_v20, '2.0', '2.0') @validation.schema(schema.update, '2.1') + @validation.response_body_schema(schema.update_response, '2.1', '2.40') + @validation.response_body_schema(schema.update_response_v241, '2.41') def update(self, req, id, body): """Updates the name and/or availability_zone of given aggregate.""" context = _get_context(req) @@ -143,6 +151,7 @@ class AggregateController(wsgi.Controller): # as this operation complete the deletion of aggregate resource and return # no response body. @wsgi.expected_errors((400, 404)) + @validation.response_body_schema(schema.delete_response) def delete(self, req, id): """Removes an aggregate by id.""" context = _get_context(req) @@ -280,7 +289,9 @@ class AggregateController(wsgi.Controller): @wsgi.Controller.api_version('2.81') @wsgi.response(202) @wsgi.expected_errors((400, 404)) - @validation.schema(aggregate_images.aggregate_images_v2_81) + @validation.schema(aggregate_images.aggregate_images) + @validation.response_body_schema( + aggregate_images.aggregate_images_response) def images(self, req, id, body): """Allows image cache management requests.""" context = _get_context(req) diff --git a/nova/api/openstack/compute/schemas/aggregate_images.py b/nova/api/openstack/compute/schemas/aggregate_images.py index b1b0cf84da..8a026f1fa6 100644 --- a/nova/api/openstack/compute/schemas/aggregate_images.py +++ b/nova/api/openstack/compute/schemas/aggregate_images.py @@ -13,7 +13,7 @@ from nova.api.validation import parameter_types -aggregate_images_v2_81 = { +aggregate_images = { 'type': 'object', 'properties': { 'cache': { @@ -32,3 +32,7 @@ aggregate_images_v2_81 = { 'required': ['cache'], 'additionalProperties': False, } + +aggregate_images_response = { + 'type': 'null', +} diff --git a/nova/api/openstack/compute/schemas/aggregates.py b/nova/api/openstack/compute/schemas/aggregates.py index db0e36faf7..b2f247f9d2 100644 --- a/nova/api/openstack/compute/schemas/aggregates.py +++ b/nova/api/openstack/compute/schemas/aggregates.py @@ -140,68 +140,116 @@ show_query = { _aggregate_response = { 'type': 'object', 'properties': { - 'aggregate': { - 'type': 'object', - 'properties': { - 'availability_zone': {'type': ['null', 'string']}, - 'created_at': {'type': 'string', 'format': 'date-time'}, - 'deleted': {'type': 'boolean'}, - 'deleted_at': { - 'oneOf': [ - {'type': 'null'}, - {'type': 'string', 'format': 'date-time'}, - ], - }, - 'hosts': { - 'type': ['array', 'null'], - 'items': { - 'type': 'string', - }, - }, - 'id': {'type': 'integer'}, - # TODO(stephenfin): This should be stricter - 'metadata': { - 'type': ['null', 'object'], - 'properties': {}, - 'additionalProperties': True, - }, - 'name': {'type': 'string'}, - 'updated_at': { - 'oneOf': [ - {'type': 'null'}, - {'type': 'string', 'format': 'date-time'}, - ], - }, - }, - 'required': [ - 'availability_zone', - 'created_at', - 'deleted', - 'deleted_at', - 'hosts', - 'id', - 'metadata', - 'name', - 'updated_at', + 'availability_zone': {'type': ['null', 'string']}, + 'created_at': {'type': 'string', 'format': 'date-time'}, + 'deleted': {'type': 'boolean'}, + 'deleted_at': { + 'oneOf': [ + {'type': 'null'}, + {'type': 'string', 'format': 'date-time'}, + ], + }, + 'hosts': { + 'type': ['array', 'null'], + 'items': { + 'type': 'string', + }, + }, + 'id': {'type': 'integer'}, + # TODO(stephenfin): This could be stricter + 'metadata': { + 'type': ['null', 'object'], + 'properties': {}, + 'additionalProperties': True, + }, + 'name': {'type': 'string'}, + 'updated_at': { + 'oneOf': [ + {'type': 'null'}, + {'type': 'string', 'format': 'date-time'}, ], - 'additionalProperties': False, }, }, - 'required': ['aggregate'], + 'required': [ + 'availability_zone', + 'created_at', + 'deleted', + 'deleted_at', + 'hosts', + 'id', + 'metadata', + 'name', + 'updated_at', + ], 'additionalProperties': False, } _aggregate_response_v241 = copy.deepcopy(_aggregate_response) -_aggregate_response_v241['properties']['aggregate']['properties'].update( +_aggregate_response_v241['properties'].update( {'uuid': {'type': 'string', 'format': 'uuid'}}, ) -_aggregate_response_v241['properties']['aggregate']['required'].append('uuid') +_aggregate_response_v241['required'].append('uuid') -add_host_response = copy.deepcopy(_aggregate_response) -add_host_response_v241 = copy.deepcopy(_aggregate_response_v241) +index_response = { + 'type': 'object', + 'properties': { + 'aggregates': { + 'type': 'array', + 'items': copy.deepcopy(_aggregate_response), + }, + }, + 'required': ['aggregates'], + 'additionalProperties': False, +} +index_response_v241 = copy.deepcopy(index_response) +index_response_v241['properties']['aggregates']['items'] = copy.deepcopy( + _aggregate_response_v241 +) -remove_host_response = copy.deepcopy(_aggregate_response) -remove_host_response_v241 = copy.deepcopy(_aggregate_response_v241) +create_response = { + 'type': 'object', + 'properties': { + 'aggregate': copy.deepcopy(_aggregate_response), + }, + 'required': ['aggregate'], + 'additionalProperties': False, +} +del create_response['properties']['aggregate']['properties']['hosts'] +del create_response['properties']['aggregate']['properties']['metadata'] +create_response['properties']['aggregate']['required'].remove('hosts') +create_response['properties']['aggregate']['required'].remove('metadata') +create_response_v241 = copy.deepcopy(create_response) +create_response_v241['properties']['aggregate'] = copy.deepcopy( + _aggregate_response_v241 +) +del create_response_v241['properties']['aggregate']['properties']['hosts'] +del create_response_v241['properties']['aggregate']['properties']['metadata'] +create_response_v241['properties']['aggregate']['required'].remove('hosts') +create_response_v241['properties']['aggregate']['required'].remove('metadata') -set_metadata_response = copy.deepcopy(_aggregate_response) -set_metadata_response_v241 = copy.deepcopy(_aggregate_response_v241) +show_response = { + 'type': 'object', + 'properties': { + 'aggregate': copy.deepcopy(_aggregate_response), + }, + 'required': ['aggregate'], + 'additionalProperties': False, +} +show_response_v241 = copy.deepcopy(show_response) +show_response_v241['properties']['aggregate'] = copy.deepcopy( + _aggregate_response_v241 +) + +update_response = copy.deepcopy(show_response) +update_response_v241 = copy.deepcopy(show_response_v241) + +delete_response = {'type': 'null'} + +add_host_response = copy.deepcopy(show_response) +add_host_response_v241 = copy.deepcopy(show_response_v241) + +remove_host_response = copy.deepcopy(show_response) +remove_host_response_v241 = copy.deepcopy(show_response_v241) + +set_metadata_response = copy.deepcopy(show_response) +set_metadata_response_v241 = copy.deepcopy(show_response_v241) diff --git a/nova/tests/unit/api/openstack/compute/test_aggregates.py b/nova/tests/unit/api/openstack/compute/test_aggregates.py index b9c7ac34b3..72e00392f3 100644 --- a/nova/tests/unit/api/openstack/compute/test_aggregates.py +++ b/nova/tests/unit/api/openstack/compute/test_aggregates.py @@ -272,12 +272,8 @@ class AggregateTestCaseV21(test.NoDBTestCase): @mock.patch('nova.compute.api.AggregateAPI.create_aggregate') def test_create_with_none_availability_zone(self, mock_create_agg): - mock_create_agg.return_value = objects.Aggregate( - self.context, - name='test', - uuid=uuidsentinel.aggregate, - hosts=[], - metadata={}) + mock_create_agg.return_value = _make_agg_obj( + {'name': 'test', 'metadata': {}}) body = {"aggregate": {"name": "test", "availability_zone": None}} result = self.controller.create(self.req, body=body) @@ -388,12 +384,8 @@ class AggregateTestCaseV21(test.NoDBTestCase): @mock.patch('nova.compute.api.AggregateAPI.update_aggregate') def test_update_with_none_availability_zone(self, mock_update_agg): agg_id = 173 - mock_update_agg.return_value = objects.Aggregate(self.context, - name='test', - uuid=uuidsentinel.agg, - id=agg_id, - hosts=[], - metadata={}) + mock_update_agg.return_value = _make_agg_obj( + {'name': 'test', 'metadata': {}}) body = {"aggregate": {"name": "test", "availability_zone": None}} result = self.controller.update(self.req, agg_id, body=body)