From d75fba70b197f024d8a1f1ba9510477157dc1b78 Mon Sep 17 00:00:00 2001 From: chenying Date: Fri, 15 Dec 2017 15:16:47 +0800 Subject: [PATCH] Add jsonschema validation for karbor triggers API Change-Id: I1213d465ad89447ac61ba8f4ff1899152f0407d9 Partial-Implements: bp karbor-json-schema-validation --- karbor/api/schemas/triggers.py | 78 +++++++++++++++++++ karbor/api/v1/triggers.py | 4 + .../unit/api/v1/test_scheduled_operation.py | 2 +- karbor/tests/unit/api/v1/test_triggers.py | 23 +++--- 4 files changed, 96 insertions(+), 11 deletions(-) create mode 100644 karbor/api/schemas/triggers.py diff --git a/karbor/api/schemas/triggers.py b/karbor/api/schemas/triggers.py new file mode 100644 index 00000000..4a3c2fc8 --- /dev/null +++ b/karbor/api/schemas/triggers.py @@ -0,0 +1,78 @@ +# 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 Karbor V1 Triggers API. + +""" + + +create = { + 'type': 'object', + 'properties': { + 'type': 'object', + 'trigger_info': { + 'type': 'object', + 'properties': { + 'name': {'type': 'string'}, + 'type': {'type': 'string'}, + 'properties': { + 'type': 'object', + 'properties': { + 'format': {'type': 'string'}, + 'pattern': {'type': 'string'}, + 'start_time': {'type': 'string'}, + 'end_time': {'type': 'string'}, + 'window': {'type': 'integer'}, + }, + 'required': ['format', 'pattern'], + 'additionalProperties': False, + }, + }, + 'required': ['name', 'type', 'properties'], + 'additionalProperties': False, + }, + }, + 'required': ['trigger_info'], + 'additionalProperties': False, +} + + +update = { + 'type': 'object', + 'properties': { + 'type': 'object', + 'trigger_info': { + 'type': 'object', + 'properties': { + 'name': {'type': 'string'}, + 'type': {'type': 'string'}, + 'properties': { + 'type': 'object', + 'properties': { + 'format': {'type': 'string'}, + 'pattern': {'type': 'string'}, + 'start_time': {'type': 'string'}, + 'end_time': {'type': 'string'}, + 'window': {'type': 'integer'}, + }, + 'required': [], + 'additionalProperties': False, + }, + }, + 'required': [], + 'additionalProperties': False, + }, + }, + 'required': ['trigger_info'], + 'additionalProperties': False, +} diff --git a/karbor/api/v1/triggers.py b/karbor/api/v1/triggers.py index 7d21cde0..87be728d 100644 --- a/karbor/api/v1/triggers.py +++ b/karbor/api/v1/triggers.py @@ -21,6 +21,8 @@ from webob import exc from karbor.api import common from karbor.api.openstack import wsgi +from karbor.api.schemas import triggers as trigger_schema +from karbor.api import validation from karbor import exception from karbor.i18n import _ from karbor import objects @@ -78,6 +80,7 @@ class TriggersController(wsgi.Controller): self.operationengine_api = operationengine_api.API() super(TriggersController, self).__init__() + @validation.schema(trigger_schema.create) def create(self, req, body): """Creates a new trigger.""" @@ -159,6 +162,7 @@ class TriggersController(wsgi.Controller): trigger.destroy() + @validation.schema(trigger_schema.update) def update(self, req, id, body): """Update a trigger""" diff --git a/karbor/tests/unit/api/v1/test_scheduled_operation.py b/karbor/tests/unit/api/v1/test_scheduled_operation.py index a8d3ce07..7ae466a5 100644 --- a/karbor/tests/unit/api/v1/test_scheduled_operation.py +++ b/karbor/tests/unit/api/v1/test_scheduled_operation.py @@ -187,7 +187,7 @@ class ScheduledOperationApiTest(base.TestCase): controller = trigger_api.TriggersController() controller.operationengine_api = test_triggers.FakeRemoteOperationApi() req = fakes.HTTPRequest.blank('/v1/triggers') - return controller.create(req, create_trigger_param) + return controller.create(req, body=create_trigger_param) @mock.patch( 'karbor.context.RequestContext.can') diff --git a/karbor/tests/unit/api/v1/test_triggers.py b/karbor/tests/unit/api/v1/test_triggers.py index 2c090b35..df778941 100644 --- a/karbor/tests/unit/api/v1/test_triggers.py +++ b/karbor/tests/unit/api/v1/test_triggers.py @@ -9,6 +9,8 @@ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. +from datetime import datetime + from oslo_config import cfg from webob import exc @@ -52,20 +54,21 @@ class TriggerApiTest(base.TestCase): "type": "time", "properties": { "format": "crontab", - "pattern": "* * * * *" + "pattern": "* * * * *", + 'start_time': datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'), }, } def test_create_trigger_InvalidBody(self): - self.assertRaises(exc.HTTPUnprocessableEntity, + self.assertRaises(exception.ValidationError, self.controller.create, - self.req, {}) + self.req, body={}) def test_create_trigger_InvalidName(self): body = self._get_create_trigger_request_body() - self.assertRaises(exc.HTTPBadRequest, + self.assertRaises(exception.ValidationError, self.controller.create, - self.req, body) + self.req, body=body) def test_create_trigger_invalid_trigger_type(self): param = self.default_create_trigger_param.copy() @@ -73,7 +76,7 @@ class TriggerApiTest(base.TestCase): body = self._get_create_trigger_request_body(param) self.assertRaises(exc.HTTPBadRequest, self.controller.create, - self.req, body) + self.req, body=body) def test_create_trigger_invalid_trigger_formt_type(self): param = self.default_create_trigger_param.copy() @@ -81,14 +84,14 @@ class TriggerApiTest(base.TestCase): body = self._get_create_trigger_request_body(param) self.assertRaises(exc.HTTPBadRequest, self.controller.create, - self.req, body) + self.req, body=body) def test_create_trigger(self): name = 'every minutes' param = self.default_create_trigger_param.copy() param['name'] = name body = self._get_create_trigger_request_body(param) - trigger = self.controller.create(self.req, body) + trigger = self.controller.create(self.req, body=body) self.assertEqual(name, trigger['trigger_info']['name']) def test_delete_trigger_binded_with_operation(self): @@ -118,7 +121,7 @@ class TriggerApiTest(base.TestCase): param['properties']['window'] = 10 body = self._get_create_trigger_request_body(param) trigger1 = self.controller.update( - self.req, trigger['trigger_info']['id'], body) + self.req, trigger['trigger_info']['id'], body=body) self.assertEqual(name, trigger1['trigger_info']['name']) self.assertEqual(10, int( @@ -154,7 +157,7 @@ class TriggerApiTest(base.TestCase): def _create_one_trigger(self): param = self.default_create_trigger_param.copy() body = self._get_create_trigger_request_body(param) - return self.controller.create(self.req, body) + return self.controller.create(self.req, body=body) def _get_create_trigger_request_body(self, param={}): return {"trigger_info": param}