Merge "api: Add response body schemas for image metadata APIs"

This commit is contained in:
Zuul
2025-06-26 11:35:06 +00:00
committed by Gerrit Code Review
3 changed files with 68 additions and 19 deletions
+24 -19
View File
@@ -16,10 +16,8 @@
from webob import exc
from nova.api.openstack.api_version_request import \
MAX_IMAGE_META_PROXY_API_VERSION
from nova.api.openstack import common
from nova.api.openstack.compute.schemas import image_metadata
from nova.api.openstack.compute.schemas import image_metadata as schema
from nova.api.openstack import wsgi
from nova.api import validation
from nova import exception
@@ -27,11 +25,12 @@ from nova.i18n import _
from nova.image import glance
@validation.validated
class ImageMetadataController(wsgi.Controller):
"""The image metadata API controller for the OpenStack API."""
def __init__(self):
super(ImageMetadataController, self).__init__()
super().__init__()
self.image_api = glance.API()
def _get_image(self, context, image_id):
@@ -43,18 +42,20 @@ class ImageMetadataController(wsgi.Controller):
msg = _("Image not found.")
raise exc.HTTPNotFound(explanation=msg)
@wsgi.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
@wsgi.api_version('2.1', '2.38')
@wsgi.expected_errors((403, 404))
@validation.query_schema(image_metadata.index_query)
@validation.query_schema(schema.index_query)
@validation.response_body_schema(schema.index_response)
def index(self, req, image_id):
"""Returns the list of metadata for a given instance."""
context = req.environ['nova.context']
metadata = self._get_image(context, image_id)['properties']
return dict(metadata=metadata)
return {'metadata': metadata}
@wsgi.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
@wsgi.api_version('2.1', '2.38')
@wsgi.expected_errors((403, 404))
@validation.query_schema(image_metadata.show_query)
@validation.query_schema(schema.show_query)
@validation.response_body_schema(schema.show_response)
def show(self, req, image_id, id):
context = req.environ['nova.context']
metadata = self._get_image(context, image_id)['properties']
@@ -63,9 +64,10 @@ class ImageMetadataController(wsgi.Controller):
else:
raise exc.HTTPNotFound()
@wsgi.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
@wsgi.api_version('2.1', '2.38')
@wsgi.expected_errors((400, 403, 404))
@validation.schema(image_metadata.create)
@validation.schema(schema.create)
@validation.response_body_schema(schema.create_response)
def create(self, req, image_id, body):
context = req.environ['nova.context']
image = self._get_image(context, image_id)
@@ -78,11 +80,12 @@ class ImageMetadataController(wsgi.Controller):
purge_props=True)
except exception.ImageNotAuthorized as e:
raise exc.HTTPForbidden(explanation=e.format_message())
return dict(metadata=image['properties'])
return {'metadata': image['properties']}
@wsgi.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
@wsgi.api_version('2.1', '2.38')
@wsgi.expected_errors((400, 403, 404))
@validation.schema(image_metadata.update)
@validation.schema(schema.update)
@validation.response_body_schema(schema.update_response)
def update(self, req, image_id, id, body):
context = req.environ['nova.context']
@@ -101,11 +104,12 @@ class ImageMetadataController(wsgi.Controller):
purge_props=True)
except exception.ImageNotAuthorized as e:
raise exc.HTTPForbidden(explanation=e.format_message())
return dict(meta=meta)
return {'meta': meta}
@wsgi.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
@wsgi.api_version('2.1', '2.38')
@wsgi.expected_errors((400, 403, 404))
@validation.schema(image_metadata.update_all)
@validation.schema(schema.update_all)
@validation.response_body_schema(schema.update_all_response)
def update_all(self, req, image_id, body):
context = req.environ['nova.context']
image = self._get_image(context, image_id)
@@ -117,11 +121,12 @@ class ImageMetadataController(wsgi.Controller):
purge_props=True)
except exception.ImageNotAuthorized as e:
raise exc.HTTPForbidden(explanation=e.format_message())
return dict(metadata=metadata)
return {'metadata': metadata}
@wsgi.api_version("2.1", MAX_IMAGE_META_PROXY_API_VERSION)
@wsgi.api_version('2.1', '2.38')
@wsgi.expected_errors((403, 404))
@wsgi.response(204)
@validation.response_body_schema(schema.delete_response)
def delete(self, req, image_id, id):
context = req.environ['nova.context']
image = self._get_image(context, image_id)
@@ -15,6 +15,7 @@
import copy
from nova.api.validation import parameter_types
from nova.api.validation import response_types
create = {
@@ -48,3 +49,29 @@ update_all = create
index_query = {}
show_query = {}
index_response = {
'type': 'object',
'properties': {
'metadata': response_types.metadata,
},
'required': ['metadata'],
'additionalProperties': False,
}
show_response = {
'type': 'object',
'properties': {
'meta': response_types.meta,
},
'required': ['meta'],
'additionalProperties': False,
}
create_response = copy.deepcopy(index_response)
update_response = copy.deepcopy(show_response)
update_all_response = copy.deepcopy(index_response)
delete_response = {'type': 'null'}
+17
View File
@@ -12,6 +12,23 @@
"""Common field types for validating API responses."""
import copy
metadata = {
'type': 'object',
'patternProperties': {
'^[a-zA-Z0-9-_:. ]{1,255}$': {
'type': 'string', 'maxLength': 255,
}
},
'additionalProperties': False,
}
meta = copy.deepcopy(metadata)
meta['minProperties'] = 1
meta['maxProperties'] = 1
links = {
'type': 'array',
'items': {