
On 12/24/2013 02:41 AM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
The following functions: get_class_name, internal_redirect, model_fn, parse_request, validate_method, validate_params are used in Resource and Collection classes. Move them to a new module control/utils.py - which will have all common functions to API resources
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- Makefile.am | 1 + src/kimchi/control/__init__.py | 21 ++++++++ src/kimchi/control/utils.py | 103 ++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 71 +-------------------------- 4 files changed, 127 insertions(+), 69 deletions(-) create mode 100644 src/kimchi/control/__init__.py create mode 100644 src/kimchi/control/utils.py You also need update Makefile.am under src/kimchi and add Makefile.am in src/kimchi/control.
Package spec file needs update too.
diff --git a/Makefile.am b/Makefile.am index 0fd92c8..65b39b8 100644 --- a/Makefile.am +++ b/Makefile.am @@ -45,6 +45,7 @@ PEP8_WHITELIST = \ src/kimchi/disks.py \ src/kimchi/root.py \ src/kimchi/server.py \ + src/kimchi/control/utils.py \
all new added python files under src/kimchi/control are pep8 clean, so you can just use a wildcard: src/kimchi/control/*.py \
plugins/__init__.py \ plugins/sample/__init__.py \ plugins/sample/model.py \ diff --git a/src/kimchi/control/__init__.py b/src/kimchi/control/__init__.py new file mode 100644 index 0000000..55cd7bd --- /dev/null +++ b/src/kimchi/control/__init__.py @@ -0,0 +1,21 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA diff --git a/src/kimchi/control/utils.py b/src/kimchi/control/utils.py new file mode 100644 index 0000000..311b5a6 --- /dev/null +++ b/src/kimchi/control/utils.py @@ -0,0 +1,103 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# + +import cherrypy +import json + + +from jsonschema import Draft3Validator, ValidationError + + +from kimchi.exception import InvalidParameter + + +def get_class_name(cls): + try: + sub_class = cls.__subclasses__()[0] + except AttributeError: + sub_class = cls.__class__.__name__ + return sub_class.lower() + + +def model_fn(cls, fn_name): + return '%s_%s' % (get_class_name(cls), fn_name) + + +def validate_method(allowed): + method = cherrypy.request.method.upper() + if method not in allowed: + raise cherrypy.HTTPError(405) + return method + + +def mime_in_header(header, mime): + if not header in cherrypy.request.headers: + accepts = 'application/json' + else: + accepts = cherrypy.request.headers[header] + + if accepts.find(';') != -1: + accepts, _ = accepts.split(';', 1) + + if mime in accepts.split(','): + return True + + return False + + +def parse_request(): + if 'Content-Length' not in cherrypy.request.headers: + return {} + rawbody = cherrypy.request.body.read() + + if mime_in_header('Content-Type', 'application/json'): + try: + return json.loads(rawbody) + except ValueError: + raise cherrypy.HTTPError(400, "Unable to parse JSON request") + else: + raise cherrypy.HTTPError(415, "This API only supports" + " 'application/json'") + + +def internal_redirect(url): + raise cherrypy.InternalRedirect(url.encode("utf-8")) + + +def validate_params(params, instance, action): + root = cherrypy.request.app.root + + if hasattr(root, 'api_schema'): + api_schema = root.api_schema + else: + return + + operation = model_fn(instance, action) + validator = Draft3Validator(api_schema) + request = {operation: params} + + try: + validator.validate(request) + except ValidationError: + raise InvalidParameter('; '.join( + e.message for e in validator.iter_errors(request))) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index ba8b53d..aec1579 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -21,88 +21,21 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
import cherrypy -import json import urllib2
from functools import wraps -from jsonschema import Draft3Validator, ValidationError
import kimchi.template from kimchi import auth +from kimchi.control.utils import get_class_name, internal_redirect, model_fn +from kimchi.control.utils import parse_request, validate_method, validate_params from kimchi.exception import InvalidOperation, InvalidParameter, MissingParameter from kimchi.exception import NotFoundError, OperationFailed from kimchi.model import ISO_POOL_NAME
-def get_class_name(cls): - try: - sub_class = cls.__subclasses__()[0] - except AttributeError: - sub_class = cls.__class__.__name__ - return sub_class.lower() - - -def model_fn(cls, fn_name): - return '%s_%s' % (get_class_name(cls), fn_name) - - -def validate_method(allowed): - method = cherrypy.request.method.upper() - if method not in allowed: - raise cherrypy.HTTPError(405) - return method - - -def mime_in_header(header, mime): - if not header in cherrypy.request.headers: - accepts = 'application/json' - else: - accepts = cherrypy.request.headers[header] - - if accepts.find(';') != -1: - accepts, _ = accepts.split(';', 1) - - if mime in accepts.split(','): - return True - - return False - - -def parse_request(): - if 'Content-Length' not in cherrypy.request.headers: - return {} - rawbody = cherrypy.request.body.read() - - if mime_in_header('Content-Type', 'application/json'): - try: - return json.loads(rawbody) - except ValueError: - raise cherrypy.HTTPError(400, "Unable to parse JSON request") - else: - raise cherrypy.HTTPError(415, "This API only supports" - " 'application/json'") -def internal_redirect(url): - raise cherrypy.InternalRedirect(url.encode("utf-8")) - - -def validate_params(params, instance, action): - root = cherrypy.request.app.root - if hasattr(root, 'api_schema'): - api_schema = root.api_schema - else: - return - operation = model_fn(instance, action) - validator = Draft3Validator(api_schema) - request = {operation: params} - try: - validator.validate(request) - except ValidationError: - raise InvalidParameter('; '.join( - e.message for e in validator.iter_errors(request))) - - class Resource(object): """ A Resource represents a single entity in the API (such as a Virtual Machine)