Merge "Add api validation schema for image_metadata"

This commit is contained in:
Jenkins 2014-12-02 00:57:38 +00:00 committed by Gerrit Code Review
commit 9eddbace68
3 changed files with 83 additions and 32 deletions

View File

@ -16,8 +16,10 @@
from webob import exc
from nova.api.openstack import common
from nova.api.openstack.compute.schemas.v3 import image_metadata
from nova.api.openstack import extensions
from nova.api.openstack import wsgi
from nova.api import validation
from nova import exception
from nova.i18n import _
import nova.image
@ -57,12 +59,12 @@ class ImageMetadataController(wsgi.Controller):
raise exc.HTTPNotFound()
@extensions.expected_errors((400, 403, 404, 413))
@validation.schema(image_metadata.create)
def create(self, req, image_id, body):
context = req.environ['nova.context']
image = self._get_image(context, image_id)
if 'metadata' in body:
for key, value in body['metadata'].iteritems():
image['properties'][key] = value
for key, value in body['metadata'].iteritems():
image['properties'][key] = value
common.check_img_metadata_properties_quota(context,
image['properties'])
try:
@ -73,21 +75,15 @@ class ImageMetadataController(wsgi.Controller):
return dict(metadata=image['properties'])
@extensions.expected_errors((400, 403, 404, 413))
@validation.schema(image_metadata.update)
def update(self, req, image_id, id, body):
context = req.environ['nova.context']
try:
meta = body['meta']
except KeyError:
expl = _('Incorrect request body format')
raise exc.HTTPBadRequest(explanation=expl)
meta = body['meta']
if id not in meta:
expl = _('Request body and URI mismatch')
raise exc.HTTPBadRequest(explanation=expl)
if len(meta) > 1:
expl = _('Request body contains too many items')
raise exc.HTTPBadRequest(explanation=expl)
image = self._get_image(context, image_id)
image['properties'][id] = meta[id]
@ -101,10 +97,11 @@ class ImageMetadataController(wsgi.Controller):
return dict(meta=meta)
@extensions.expected_errors((400, 403, 404, 413))
@validation.schema(image_metadata.update_all)
def update_all(self, req, image_id, body):
context = req.environ['nova.context']
image = self._get_image(context, image_id)
metadata = body.get('metadata', {})
metadata = body['metadata']
common.check_img_metadata_properties_quota(context, metadata)
image['properties'] = metadata
try:

View File

@ -0,0 +1,44 @@
# Copyright 2014 IBM 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.
import copy
from nova.api.validation import parameter_types
create = {
'type': 'object',
'properties': {
'metadata': parameter_types.metadata
},
'required': ['metadata'],
'additionalProperties': False,
}
single_metadata = copy.deepcopy(parameter_types.metadata)
single_metadata.update({
'minProperties': 1,
'maxProperties': 1
})
update = {
'type': 'object',
'properties': {
'meta': single_metadata
},
'required': ['meta'],
'additionalProperties': False,
}
update_all = create

View File

@ -37,6 +37,7 @@ def get_image_123():
class ImageMetaDataTestV21(test.NoDBTestCase):
controller_class = image_metadata_v21.ImageMetadataController
invalid_request = exception.ValidationError
def setUp(self):
super(ImageMetaDataTestV21, self).setUp()
@ -84,7 +85,7 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
body = {"metadata": {"key7": "value7"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
res = self.controller.create(req, '123', body)
res = self.controller.create(req, '123', body=body)
get_mocked.assert_called_once_with(mock.ANY, '123')
expected = copy.deepcopy(get_image_123())
expected['properties'] = {
@ -111,7 +112,7 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.create, req, '100', body)
self.controller.create, req, '100', body=body)
self.assertFalse(quota_mocked.called)
self.assertFalse(update_mocked.called)
@ -124,7 +125,7 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
body = {"metadata": {"key9": "value9"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
res = self.controller.update_all(req, '123', body)
res = self.controller.update_all(req, '123', body=body)
get_mocked.assert_called_once_with(mock.ANY, '123')
expected = copy.deepcopy(get_image_123())
expected['properties'] = {
@ -148,7 +149,7 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.update_all, req, '100', body)
self.controller.update_all, req, '100', body=body)
self.assertFalse(quota_mocked.called)
@mock.patch(CHK_QUOTA_STR)
@ -160,7 +161,7 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
body = {"meta": {"key1": "zz"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
res = self.controller.update(req, '123', 'key1', body)
res = self.controller.update(req, '123', 'key1', body=body)
expected = copy.deepcopy(get_image_123())
expected['properties'] = {
'key1': 'zz' # changed meta
@ -183,7 +184,8 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPNotFound,
self.controller.update, req, '100', 'key1', body)
self.controller.update, req, '100', 'key1',
body=body)
self.assertFalse(quota_mocked.called)
@mock.patch(CHK_QUOTA_STR)
@ -197,8 +199,9 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
req.body = ''
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, '123', 'key1', body)
self.assertRaises(self.invalid_request,
self.controller.update, req, '123', 'key1',
body=body)
self.assertFalse(get_mocked.called)
self.assertFalse(quota_mocked.called)
self.assertFalse(update_mocked.called)
@ -212,12 +215,13 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
_quota_mocked):
req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata/key1')
req.method = 'PUT'
body = {"metadata": {"foo": "bar"}}
body = {"meta": {"foo": "bar"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, '123', 'key1', body)
self.controller.update, req, '123', 'key1',
body=body)
self.assertFalse(get_mocked.called)
self.assertFalse(update_mocked.called)
@ -233,7 +237,8 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPBadRequest,
self.controller.update, req, '123', 'bad', body)
self.controller.update, req, '123', 'bad',
body=body)
self.assertFalse(quota_mocked.called)
self.assertFalse(update_mocked.called)
@ -281,7 +286,7 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPForbidden,
self.controller.create, req, '123', body)
self.controller.create, req, '123', body=body)
self.assertFalse(update_mocked.called)
@mock.patch(CHK_QUOTA_STR,
@ -294,12 +299,13 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
body = {"metadata": {"foo": "bar"}}
req = fakes.HTTPRequest.blank('/v2/fake/images/123/metadata/blah')
req.method = 'PUT'
body = {"meta": {"blah": "blah"}}
body = {"meta": {"blah": "blah", "blah1": "blah1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPForbidden,
self.controller.update, req, '123', 'blah', body)
self.assertRaises(self.invalid_request,
self.controller.update, req, '123', 'blah',
body=body)
self.assertFalse(update_mocked.called)
@mock.patch('nova.image.api.API.get',
@ -312,7 +318,8 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPForbidden,
self.controller.update, req, '123', 'key1', body)
self.controller.update, req, '123', 'key1',
body=body)
@mock.patch('nova.image.api.API.get',
side_effect=exception.ImageNotAuthorized(image_id='123'))
@ -323,12 +330,13 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
req = fakes.HTTPRequest.blank('/v2/fake/images/%s/metadata/key1'
% image_id)
req.method = 'PUT'
body = {"meta": {"key1": "value1"}}
body = {"metadata": {"key1": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPForbidden,
self.controller.update_all, req, image_id, body)
self.controller.update_all, req, image_id,
body=body)
@mock.patch('nova.image.api.API.get',
side_effect=exception.ImageNotAuthorized(image_id='123'))
@ -339,16 +347,18 @@ class ImageMetaDataTestV21(test.NoDBTestCase):
req = fakes.HTTPRequest.blank('/v2/fake/images/%s/metadata/key1'
% image_id)
req.method = 'POST'
body = {"meta": {"key1": "value1"}}
body = {"metadata": {"key1": "value1"}}
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
self.assertRaises(webob.exc.HTTPForbidden,
self.controller.create, req, image_id, body)
self.controller.create, req, image_id,
body=body)
class ImageMetaDataTestV2(ImageMetaDataTestV21):
controller_class = image_metadata.Controller
invalid_request = webob.exc.HTTPBadRequest
# NOTE(cyeoh): This duplicate unittest is necessary for a race condition
# with the V21 unittests. It's mock issue.