V3 jsonschema validation: snapshot_actions
This patch adds jsonschema validation for below snapshot_actions API * POST /v3/{project_id}/snapshots/{snapshot_id}/action Change-Id: I810f72777864947e7e44ddf668732e06db68c1f3 Partial-Implements: bp json-schema-validation
This commit is contained in:
parent
04847c42c7
commit
417f3b7331
|
@ -18,6 +18,8 @@ import webob
|
|||
|
||||
from cinder.api import extensions
|
||||
from cinder.api.openstack import wsgi
|
||||
from cinder.api.schemas import snapshot_actions
|
||||
from cinder.api import validation
|
||||
from cinder.i18n import _
|
||||
from cinder import objects
|
||||
from cinder.objects import fields
|
||||
|
@ -31,6 +33,7 @@ class SnapshotActionsController(wsgi.Controller):
|
|||
LOG.debug("SnapshotActionsController initialized")
|
||||
|
||||
@wsgi.action('os-update_snapshot_status')
|
||||
@validation.schema(snapshot_actions.update_snapshot_status)
|
||||
def _update_snapshot_status(self, req, id, body):
|
||||
"""Update database fields related to status of a snapshot.
|
||||
|
||||
|
@ -41,11 +44,8 @@ class SnapshotActionsController(wsgi.Controller):
|
|||
|
||||
context = req.environ['cinder.context']
|
||||
LOG.debug("body: %s", body)
|
||||
try:
|
||||
status = body['os-update_snapshot_status']['status']
|
||||
except KeyError:
|
||||
msg = _("'status' must be specified.")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
status = body['os-update_snapshot_status']['status']
|
||||
|
||||
# Allowed state transitions
|
||||
status_map = {fields.SnapshotStatus.CREATING:
|
||||
|
@ -78,15 +78,6 @@ class SnapshotActionsController(wsgi.Controller):
|
|||
|
||||
progress = body['os-update_snapshot_status'].get('progress', None)
|
||||
if progress:
|
||||
# This is expected to be a string like '73%'
|
||||
msg = _('progress must be an integer percentage')
|
||||
try:
|
||||
integer = int(progress[:-1])
|
||||
except ValueError:
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
if integer < 0 or integer > 100 or progress[-1] != '%':
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
update_dict.update({'progress': progress})
|
||||
|
||||
LOG.info("Updating snapshot %(id)s with info %(dict)s",
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
# Copyright (C) 2018 NTT DATA
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Schema for V3 snapshot actions API.
|
||||
|
||||
"""
|
||||
|
||||
update_snapshot_status = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'os-update_snapshot_status': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'status': {'type': 'string'},
|
||||
'progress': {'format': 'progress'},
|
||||
},
|
||||
'required': ['status'],
|
||||
'additionalProperties': False,
|
||||
},
|
||||
},
|
||||
'required': ['os-update_snapshot_status'],
|
||||
'additionalProperties': False,
|
||||
}
|
|
@ -171,6 +171,21 @@ def _validate_status(param_value):
|
|||
return True
|
||||
|
||||
|
||||
@jsonschema.FormatChecker.cls_checks('progress')
|
||||
def _validate_progress(progress):
|
||||
if progress:
|
||||
try:
|
||||
integer = int(progress[:-1])
|
||||
except ValueError:
|
||||
msg = _('progress must be an integer percentage')
|
||||
raise exception.InvalidInput(reason=msg)
|
||||
if integer < 0 or integer > 100 or progress[-1] != '%':
|
||||
msg = _('progress must be an integer percentage between'
|
||||
' 0 and 100')
|
||||
raise exception.InvalidInput(reason=msg)
|
||||
return True
|
||||
|
||||
|
||||
@jsonschema.FormatChecker.cls_checks('base64')
|
||||
def _validate_base64_format(instance):
|
||||
try:
|
||||
|
|
|
@ -12,13 +12,17 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
from oslo_serialization import jsonutils
|
||||
from six.moves import http_client
|
||||
import webob
|
||||
|
||||
from cinder.api.contrib import snapshot_actions
|
||||
from cinder.api import microversions as mv
|
||||
from cinder import context
|
||||
from cinder import db
|
||||
from cinder import exception
|
||||
from cinder.objects import fields
|
||||
from cinder import test
|
||||
from cinder.tests.unit.api import fakes
|
||||
|
@ -36,12 +40,14 @@ def fake_snapshot_get(context, snapshot_id):
|
|||
return snapshot
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class SnapshotActionsTest(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(SnapshotActionsTest, self).setUp()
|
||||
self.user_ctxt = context.RequestContext(
|
||||
fake.USER_ID, fake.PROJECT_ID, auth_token=True)
|
||||
self.controller = snapshot_actions.SnapshotActionsController()
|
||||
|
||||
@mock.patch('cinder.db.snapshot_update', autospec=True)
|
||||
@mock.patch('cinder.db.sqlalchemy.api._snapshot_get',
|
||||
|
@ -88,3 +94,42 @@ class SnapshotActionsTest(test.TestCase):
|
|||
res = req.get_response(fakes.wsgi_app(
|
||||
fake_auth_context=self.user_ctxt))
|
||||
self.assertEqual(http_client.BAD_REQUEST, res.status_int)
|
||||
|
||||
@mock.patch('cinder.db.snapshot_update', autospec=True)
|
||||
@mock.patch('cinder.db.sqlalchemy.api._snapshot_get',
|
||||
side_effect=fake_snapshot_get)
|
||||
@mock.patch('cinder.db.snapshot_metadata_get', return_value=dict())
|
||||
def test_update_snapshot_valid_progress(self, metadata_get, *args):
|
||||
body = {'os-update_snapshot_status':
|
||||
{'status': fields.SnapshotStatus.AVAILABLE,
|
||||
'progress': '50%'}}
|
||||
req = webob.Request.blank('/v2/%s/snapshots/%s/action' % (
|
||||
fake.PROJECT_ID, fake.SNAPSHOT_ID))
|
||||
req.method = "POST"
|
||||
req.body = jsonutils.dump_as_bytes(body)
|
||||
req.headers["content-type"] = "application/json"
|
||||
|
||||
res = req.get_response(fakes.wsgi_app(
|
||||
fake_auth_context=self.user_ctxt))
|
||||
self.assertEqual(http_client.ACCEPTED, res.status_int)
|
||||
|
||||
@ddt.data(({'os-update_snapshot_status':
|
||||
{'status': fields.SnapshotStatus.AVAILABLE,
|
||||
'progress': '50'}}, exception.InvalidInput),
|
||||
({'os-update_snapshot_status':
|
||||
{'status': fields.SnapshotStatus.AVAILABLE,
|
||||
'progress': '103%'}}, exception.InvalidInput),
|
||||
({'os-update_snapshot_status':
|
||||
{'status': fields.SnapshotStatus.AVAILABLE,
|
||||
'progress': " "}}, exception.InvalidInput),
|
||||
({'os-update_snapshot_status':
|
||||
{'status': fields.SnapshotStatus.AVAILABLE,
|
||||
'progress': 50}}, exception.ValidationError))
|
||||
@ddt.unpack
|
||||
def test_update_snapshot_invalid_progress(self, body, exception_class):
|
||||
req = webob.Request.blank('/v3/%s/snapshots/%s/action' % (
|
||||
fake.PROJECT_ID, fake.SNAPSHOT_ID))
|
||||
req.api_version_request = mv.get_api_version(mv.BASE_VERSION)
|
||||
self.assertRaises(exception_class,
|
||||
self.controller._update_snapshot_status,
|
||||
req, body=body)
|
||||
|
|
Loading…
Reference in New Issue