[PATCH 00/15 V2] Reorganize controller module

From: Aline Manera <alinefm@br.ibm.com> V1 -> V2: - Remove 'instance' parameter from generate_action_handler() - Update Makefile and spec files - Remove controller content when it is moved to new files - Update authors in new files - Fix identation error while using pep8 1.4 - Other minor fixes Aline Manera (15): Move generate_action_handler() function to Resource() class Move common functions for Resource and Collection to control/utils.py Move login() and logout() functions from controller.py to root.py Move basic controller resources to control/base.py Move all resources related to vms to control/vms.py Move all resources related to templates to control/templates.py Move all resources related to debug reports to control/debugreports.py Move all resources related to storage pools to control/storagepools.py Move all resources related to storage volume to control/storagevolumes.py Move all resources related to interfaces to control/interfaces.py Move all resources related to networks to control/networks.py Move all resources related to config to control/config.py Move all resources related to host to control/host.py Move all resources related to plugins to control/plugins.py Move all resources related to tasks to control/tasks.py Makefile.am | 1 + configure.ac | 1 + contrib/kimchi.spec.fedora.in | 1 + contrib/kimchi.spec.suse.in | 1 + plugins/sample/__init__.py | 2 +- src/kimchi/Makefile.am | 3 +- src/kimchi/control/Makefile.am | 28 ++ src/kimchi/control/__init__.py | 21 + src/kimchi/control/base.py | 292 +++++++++++++ src/kimchi/control/config.py | 69 ++++ src/kimchi/control/debugreports.py | 52 +++ src/kimchi/control/host.py | 63 +++ src/kimchi/control/interfaces.py | 45 ++ src/kimchi/control/networks.py | 48 +++ src/kimchi/control/plugins.py | 45 ++ src/kimchi/control/storagepools.py | 127 ++++++ src/kimchi/control/storagevolumes.py | 81 ++++ src/kimchi/control/tasks.py | 41 ++ src/kimchi/control/templates.py | 52 +++ src/kimchi/control/utils.py | 105 +++++ src/kimchi/control/vms.py | 65 +++ src/kimchi/controller.py | 755 ---------------------------------- src/kimchi/root.py | 62 ++- tests/test_mockmodel.py | 6 +- 24 files changed, 1191 insertions(+), 775 deletions(-) create mode 100644 src/kimchi/control/Makefile.am create mode 100644 src/kimchi/control/__init__.py create mode 100644 src/kimchi/control/base.py create mode 100644 src/kimchi/control/config.py create mode 100644 src/kimchi/control/debugreports.py create mode 100644 src/kimchi/control/host.py create mode 100644 src/kimchi/control/interfaces.py create mode 100644 src/kimchi/control/networks.py create mode 100644 src/kimchi/control/plugins.py create mode 100644 src/kimchi/control/storagepools.py create mode 100644 src/kimchi/control/storagevolumes.py create mode 100644 src/kimchi/control/tasks.py create mode 100644 src/kimchi/control/templates.py create mode 100644 src/kimchi/control/utils.py create mode 100644 src/kimchi/control/vms.py delete mode 100644 src/kimchi/controller.py -- 1.7.10.4

From: Aline Manera <alinefm@br.ibm.com> generate_action_handler() function is only used by Resources instances so move it to Resource() Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/controller.py | 75 +++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 2940278..293b588 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -103,33 +103,6 @@ def validate_params(params, instance, action): e.message for e in validator.iter_errors(request))) -def generate_action_handler(instance, action_name, action_args=None): - def wrapper(*args, **kwargs): - validate_method(('POST')) - try: - model_args = list(instance.model_args) - if action_args is not None: - model_args.extend(parse_request()[key] for key in action_args) - fn = getattr(instance.model, model_fn(instance, action_name)) - fn(*model_args) - raise internal_redirect(instance.uri_fmt % - tuple(instance.model_args)) - except MissingParameter, param: - raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % param) - except InvalidParameter, param: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % param) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - - wrapper.__name__ = action_name - wrapper.exposed = True - return wrapper - - class Resource(object): """ A Resource represents a single entity in the API (such as a Virtual Machine) @@ -153,6 +126,32 @@ class Resource(object): self.model_args = (ident,) self.update_params = [] + def generate_action_handler(self, action_name, action_args=None): + def wrapper(*args, **kwargs): + validate_method(('POST')) + try: + model_args = list(self.model_args) + if action_args is not None: + model_args.extend(parse_request()[key] for key in action_args) + fn = getattr(self.model, model_fn(self, action_name)) + fn(*model_args) + raise internal_redirect(self.uri_fmt % + tuple(self.model_args)) + except MissingParameter, param: + raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % param) + except InvalidParameter, param: + raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % param) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except OperationFailed, msg: + raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + + wrapper.__name__ = action_name + wrapper.exposed = True + return wrapper + def lookup(self): try: lookup = getattr(self.model, model_fn(self, 'lookup')) @@ -369,9 +368,9 @@ class VM(Resource): self.update_params = ["name"] self.screenshot = VMScreenShot(model, ident) self.uri_fmt = '/vms/%s' - self.start = generate_action_handler(self, 'start') - self.stop = generate_action_handler(self, 'stop') - self.connect = generate_action_handler(self, 'connect') + self.start = self.generate_action_handler('start') + self.stop = self.generate_action_handler('stop') + self.connect = self.generate_action_handler('connect') @property def data(self): @@ -453,8 +452,8 @@ class Network(Resource): def __init__(self, model, ident): super(Network, self).__init__(model, ident) self.uri_fmt = "/networks/%s" - self.activate = generate_action_handler(self, 'activate') - self.deactivate = generate_action_handler(self, 'deactivate') + self.activate = self.generate_action_handler('activate') + self.deactivate = self.generate_action_handler('deactivate') @property def data(self): @@ -475,8 +474,8 @@ class StorageVolume(Resource): self.info = {} self.model_args = [self.pool, self.ident] self.uri_fmt = '/storagepools/%s/storagevolumes/%s' - self.resize = generate_action_handler(self, 'resize', ['size']) - self.wipe = generate_action_handler(self, 'wipe') + self.resize = self.generate_action_handler('resize', ['size']) + self.wipe = self.generate_action_handler('wipe') @property def data(self): @@ -522,8 +521,8 @@ class StoragePool(Resource): super(StoragePool, self).__init__(model, ident) self.update_params = ["autostart"] self.uri_fmt = "/storagepools/%s" - self.activate = generate_action_handler(self, 'activate') - self.deactivate = generate_action_handler(self, 'deactivate') + self.activate = self.generate_action_handler('activate') + self.deactivate = self.generate_action_handler('deactivate') @property def data(self): @@ -689,8 +688,8 @@ class Host(Resource): self.stats = HostStats(self.model) self.stats.exposed = True self.uri_fmt = '/host/%s' - self.reboot = generate_action_handler(self, 'reboot') - self.shutdown = generate_action_handler(self, 'shutdown') + self.reboot = self.generate_action_handler('reboot') + self.shutdown = self.generate_action_handler('shutdown') self.partitions = Partitions(self.model) self.partitions.exposed = True -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
generate_action_handler() function is only used by Resources instances so move it to Resource()
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/controller.py | 75 +++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 38 deletions(-)
diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 2940278..293b588 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -103,33 +103,6 @@ def validate_params(params, instance, action): e.message for e in validator.iter_errors(request)))
-def generate_action_handler(instance, action_name, action_args=None): - def wrapper(*args, **kwargs): - validate_method(('POST')) - try: - model_args = list(instance.model_args) - if action_args is not None: - model_args.extend(parse_request()[key] for key in action_args) - fn = getattr(instance.model, model_fn(instance, action_name)) - fn(*model_args) - raise internal_redirect(instance.uri_fmt % - tuple(instance.model_args)) - except MissingParameter, param: - raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % param) - except InvalidParameter, param: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % param) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - - wrapper.__name__ = action_name - wrapper.exposed = True - return wrapper - - class Resource(object): """ A Resource represents a single entity in the API (such as a Virtual Machine) @@ -153,6 +126,32 @@ class Resource(object): self.model_args = (ident,) self.update_params = []
+ def generate_action_handler(self, action_name, action_args=None): + def wrapper(*args, **kwargs): + validate_method(('POST')) + try: + model_args = list(self.model_args) + if action_args is not None: + model_args.extend(parse_request()[key] for key in action_args) + fn = getattr(self.model, model_fn(self, action_name)) + fn(*model_args) + raise internal_redirect(self.uri_fmt % + tuple(self.model_args)) + except MissingParameter, param: + raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % param) + except InvalidParameter, param: + raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % param) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except OperationFailed, msg: + raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + + wrapper.__name__ = action_name + wrapper.exposed = True + return wrapper + def lookup(self): try: lookup = getattr(self.model, model_fn(self, 'lookup')) @@ -369,9 +368,9 @@ class VM(Resource): self.update_params = ["name"] self.screenshot = VMScreenShot(model, ident) self.uri_fmt = '/vms/%s' - self.start = generate_action_handler(self, 'start') - self.stop = generate_action_handler(self, 'stop') - self.connect = generate_action_handler(self, 'connect') + self.start = self.generate_action_handler('start') + self.stop = self.generate_action_handler('stop') + self.connect = self.generate_action_handler('connect')
@property def data(self): @@ -453,8 +452,8 @@ class Network(Resource): def __init__(self, model, ident): super(Network, self).__init__(model, ident) self.uri_fmt = "/networks/%s" - self.activate = generate_action_handler(self, 'activate') - self.deactivate = generate_action_handler(self, 'deactivate') + self.activate = self.generate_action_handler('activate') + self.deactivate = self.generate_action_handler('deactivate')
@property def data(self): @@ -475,8 +474,8 @@ class StorageVolume(Resource): self.info = {} self.model_args = [self.pool, self.ident] self.uri_fmt = '/storagepools/%s/storagevolumes/%s' - self.resize = generate_action_handler(self, 'resize', ['size']) - self.wipe = generate_action_handler(self, 'wipe') + self.resize = self.generate_action_handler('resize', ['size']) + self.wipe = self.generate_action_handler('wipe')
@property def data(self): @@ -522,8 +521,8 @@ class StoragePool(Resource): super(StoragePool, self).__init__(model, ident) self.update_params = ["autostart"] self.uri_fmt = "/storagepools/%s" - self.activate = generate_action_handler(self, 'activate') - self.deactivate = generate_action_handler(self, 'deactivate') + self.activate = self.generate_action_handler('activate') + self.deactivate = self.generate_action_handler('deactivate')
@property def data(self): @@ -689,8 +688,8 @@ class Host(Resource): self.stats = HostStats(self.model) self.stats.exposed = True self.uri_fmt = '/host/%s' - self.reboot = generate_action_handler(self, 'reboot') - self.shutdown = generate_action_handler(self, 'shutdown') + self.reboot = self.generate_action_handler('reboot') + self.shutdown = self.generate_action_handler('shutdown') self.partitions = Partitions(self.model) self.partitions.exposed = True

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
generate_action_handler() function is only used by Resources instances so move it to Resource()
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/controller.py | 75 +++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 38 deletions(-)
diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 2940278..293b588 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -103,33 +103,6 @@ def validate_params(params, instance, action): e.message for e in validator.iter_errors(request)))
-def generate_action_handler(instance, action_name, action_args=None): - def wrapper(*args, **kwargs): - validate_method(('POST')) - try: - model_args = list(instance.model_args) - if action_args is not None: - model_args.extend(parse_request()[key] for key in action_args) - fn = getattr(instance.model, model_fn(instance, action_name)) - fn(*model_args) - raise internal_redirect(instance.uri_fmt % - tuple(instance.model_args)) - except MissingParameter, param: - raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % param) - except InvalidParameter, param: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % param) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - - wrapper.__name__ = action_name - wrapper.exposed = True - return wrapper - - class Resource(object): """ A Resource represents a single entity in the API (such as a Virtual Machine) @@ -153,6 +126,32 @@ class Resource(object): self.model_args = (ident,) self.update_params = []
+ def generate_action_handler(self, action_name, action_args=None): + def wrapper(*args, **kwargs): + validate_method(('POST')) + try: + model_args = list(self.model_args) + if action_args is not None: + model_args.extend(parse_request()[key] for key in action_args) + fn = getattr(self.model, model_fn(self, action_name)) + fn(*model_args) + raise internal_redirect(self.uri_fmt % + tuple(self.model_args)) + except MissingParameter, param: + raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % param) + except InvalidParameter, param: + raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % param) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except OperationFailed, msg: + raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + + wrapper.__name__ = action_name + wrapper.exposed = True + return wrapper + def lookup(self): try: lookup = getattr(self.model, model_fn(self, 'lookup')) @@ -369,9 +368,9 @@ class VM(Resource): self.update_params = ["name"] self.screenshot = VMScreenShot(model, ident) self.uri_fmt = '/vms/%s' - self.start = generate_action_handler(self, 'start') - self.stop = generate_action_handler(self, 'stop') - self.connect = generate_action_handler(self, 'connect') + self.start = self.generate_action_handler('start') + self.stop = self.generate_action_handler('stop') + self.connect = self.generate_action_handler('connect')
@property def data(self): @@ -453,8 +452,8 @@ class Network(Resource): def __init__(self, model, ident): super(Network, self).__init__(model, ident) self.uri_fmt = "/networks/%s" - self.activate = generate_action_handler(self, 'activate') - self.deactivate = generate_action_handler(self, 'deactivate') + self.activate = self.generate_action_handler('activate') + self.deactivate = self.generate_action_handler('deactivate')
@property def data(self): @@ -475,8 +474,8 @@ class StorageVolume(Resource): self.info = {} self.model_args = [self.pool, self.ident] self.uri_fmt = '/storagepools/%s/storagevolumes/%s' - self.resize = generate_action_handler(self, 'resize', ['size']) - self.wipe = generate_action_handler(self, 'wipe') + self.resize = self.generate_action_handler('resize', ['size']) + self.wipe = self.generate_action_handler('wipe')
@property def data(self): @@ -522,8 +521,8 @@ class StoragePool(Resource): super(StoragePool, self).__init__(model, ident) self.update_params = ["autostart"] self.uri_fmt = "/storagepools/%s" - self.activate = generate_action_handler(self, 'activate') - self.deactivate = generate_action_handler(self, 'deactivate') + self.activate = self.generate_action_handler('activate') + self.deactivate = self.generate_action_handler('deactivate')
@property def data(self): @@ -689,8 +688,8 @@ class Host(Resource): self.stats = HostStats(self.model) self.stats.exposed = True self.uri_fmt = '/host/%s' - self.reboot = generate_action_handler(self, 'reboot') - self.shutdown = generate_action_handler(self, 'shutdown') + self.reboot = self.generate_action_handler('reboot') + self.shutdown = self.generate_action_handler('shutdown') self.partitions = Partitions(self.model) self.partitions.exposed = True

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 Also update Makefile and spec files in order to package new files under /control Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- Makefile.am | 1 + configure.ac | 1 + contrib/kimchi.spec.fedora.in | 1 + contrib/kimchi.spec.suse.in | 1 + src/kimchi/Makefile.am | 2 + src/kimchi/control/Makefile.am | 28 +++++++++++ src/kimchi/control/__init__.py | 21 ++++++++ src/kimchi/control/utils.py | 105 ++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 71 +-------------------------- 9 files changed, 162 insertions(+), 69 deletions(-) create mode 100644 src/kimchi/control/Makefile.am create mode 100644 src/kimchi/control/__init__.py create mode 100644 src/kimchi/control/utils.py diff --git a/Makefile.am b/Makefile.am index 0fd92c8..1d4ed7d 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/*.py \ plugins/__init__.py \ plugins/sample/__init__.py \ plugins/sample/model.py \ diff --git a/configure.ac b/configure.ac index 0d04d51..e4ccb83 100644 --- a/configure.ac +++ b/configure.ac @@ -53,6 +53,7 @@ AC_CONFIG_FILES([ src/Makefile src/distros.d/Makefile src/kimchi/Makefile + src/kimchi/control/Makefile plugins/Makefile plugins/sample/Makefile plugins/sample/ui/Makefile diff --git a/contrib/kimchi.spec.fedora.in b/contrib/kimchi.spec.fedora.in index 577516c..3044fc8 100644 --- a/contrib/kimchi.spec.fedora.in +++ b/contrib/kimchi.spec.fedora.in @@ -110,6 +110,7 @@ rm -rf $RPM_BUILD_ROOT %attr(-,root,root) %{_bindir}/kimchid %{python_sitelib}/kimchi/*.py* +%{python_sitelib}/kimchi/control/*.py* %{python_sitelib}/kimchi/API.json %{_datadir}/kimchi/doc/API.md %{_datadir}/kimchi/doc/README.md diff --git a/contrib/kimchi.spec.suse.in b/contrib/kimchi.spec.suse.in index 12d02ec..190b2be 100644 --- a/contrib/kimchi.spec.suse.in +++ b/contrib/kimchi.spec.suse.in @@ -57,6 +57,7 @@ rm -rf $RPM_BUILD_ROOT %attr(-,root,root) %{_bindir}/kimchid %{python_sitelib}/kimchi/*.py* +%{python_sitelib}/kimchi/control/*.py* %{python_sitelib}/kimchi/API.json %{_datadir}/kimchi/doc/API.md %{_datadir}/kimchi/doc/README.md diff --git a/src/kimchi/Makefile.am b/src/kimchi/Makefile.am index 47a3bd2..78af50f 100644 --- a/src/kimchi/Makefile.am +++ b/src/kimchi/Makefile.am @@ -20,6 +20,8 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +SUBDIRS = control + kimchi_PYTHON = \ asynctask.py \ auth.py \ diff --git a/src/kimchi/control/Makefile.am b/src/kimchi/control/Makefile.am new file mode 100644 index 0000000..925c593 --- /dev/null +++ b/src/kimchi/control/Makefile.am @@ -0,0 +1,28 @@ +# +# 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 + +control_PYTHON = *.py + +controldir = $(pythondir)/kimchi/control + +install-data-local: + $(MKDIR_P) $(DESTDIR)$(controldir) diff --git a/src/kimchi/control/__init__.py b/src/kimchi/control/__init__.py new file mode 100644 index 0000000..8a37cc4 --- /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..c3c5f8e --- /dev/null +++ b/src/kimchi/control/utils.py @@ -0,0 +1,105 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Mark Wu <wudxw@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 293b588..13b394e 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) -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, 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
Also update Makefile and spec files in order to package new files under /control
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- Makefile.am | 1 + configure.ac | 1 + contrib/kimchi.spec.fedora.in | 1 + contrib/kimchi.spec.suse.in | 1 + src/kimchi/Makefile.am | 2 + src/kimchi/control/Makefile.am | 28 +++++++++++ src/kimchi/control/__init__.py | 21 ++++++++ src/kimchi/control/utils.py | 105 ++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 71 +-------------------------- 9 files changed, 162 insertions(+), 69 deletions(-) create mode 100644 src/kimchi/control/Makefile.am create mode 100644 src/kimchi/control/__init__.py create mode 100644 src/kimchi/control/utils.py
diff --git a/Makefile.am b/Makefile.am index 0fd92c8..1d4ed7d 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/*.py \ plugins/__init__.py \ plugins/sample/__init__.py \ plugins/sample/model.py \ diff --git a/configure.ac b/configure.ac index 0d04d51..e4ccb83 100644 --- a/configure.ac +++ b/configure.ac @@ -53,6 +53,7 @@ AC_CONFIG_FILES([ src/Makefile src/distros.d/Makefile src/kimchi/Makefile + src/kimchi/control/Makefile plugins/Makefile plugins/sample/Makefile plugins/sample/ui/Makefile diff --git a/contrib/kimchi.spec.fedora.in b/contrib/kimchi.spec.fedora.in index 577516c..3044fc8 100644 --- a/contrib/kimchi.spec.fedora.in +++ b/contrib/kimchi.spec.fedora.in @@ -110,6 +110,7 @@ rm -rf $RPM_BUILD_ROOT %attr(-,root,root) %{_bindir}/kimchid %{python_sitelib}/kimchi/*.py* +%{python_sitelib}/kimchi/control/*.py* %{python_sitelib}/kimchi/API.json %{_datadir}/kimchi/doc/API.md %{_datadir}/kimchi/doc/README.md diff --git a/contrib/kimchi.spec.suse.in b/contrib/kimchi.spec.suse.in index 12d02ec..190b2be 100644 --- a/contrib/kimchi.spec.suse.in +++ b/contrib/kimchi.spec.suse.in @@ -57,6 +57,7 @@ rm -rf $RPM_BUILD_ROOT %attr(-,root,root) %{_bindir}/kimchid %{python_sitelib}/kimchi/*.py* +%{python_sitelib}/kimchi/control/*.py* %{python_sitelib}/kimchi/API.json %{_datadir}/kimchi/doc/API.md %{_datadir}/kimchi/doc/README.md diff --git a/src/kimchi/Makefile.am b/src/kimchi/Makefile.am index 47a3bd2..78af50f 100644 --- a/src/kimchi/Makefile.am +++ b/src/kimchi/Makefile.am @@ -20,6 +20,8 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+SUBDIRS = control + kimchi_PYTHON = \ asynctask.py \ auth.py \ diff --git a/src/kimchi/control/Makefile.am b/src/kimchi/control/Makefile.am new file mode 100644 index 0000000..925c593 --- /dev/null +++ b/src/kimchi/control/Makefile.am @@ -0,0 +1,28 @@ +# +# 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 + +control_PYTHON = *.py + +controldir = $(pythondir)/kimchi/control + +install-data-local: + $(MKDIR_P) $(DESTDIR)$(controldir) diff --git a/src/kimchi/control/__init__.py b/src/kimchi/control/__init__.py new file mode 100644 index 0000000..8a37cc4 --- /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..c3c5f8e --- /dev/null +++ b/src/kimchi/control/utils.py @@ -0,0 +1,105 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Mark Wu <wudxw@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 293b588..13b394e 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)

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, 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
Also update Makefile and spec files in order to package new files under /control
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- Makefile.am | 1 + configure.ac | 1 + contrib/kimchi.spec.fedora.in | 1 + contrib/kimchi.spec.suse.in | 1 + src/kimchi/Makefile.am | 2 + src/kimchi/control/Makefile.am | 28 +++++++++++ src/kimchi/control/__init__.py | 21 ++++++++ src/kimchi/control/utils.py | 105 ++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 71 +-------------------------- 9 files changed, 162 insertions(+), 69 deletions(-) create mode 100644 src/kimchi/control/Makefile.am create mode 100644 src/kimchi/control/__init__.py create mode 100644 src/kimchi/control/utils.py
diff --git a/Makefile.am b/Makefile.am index 0fd92c8..1d4ed7d 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/*.py \ plugins/__init__.py \ plugins/sample/__init__.py \ plugins/sample/model.py \ diff --git a/configure.ac b/configure.ac index 0d04d51..e4ccb83 100644 --- a/configure.ac +++ b/configure.ac @@ -53,6 +53,7 @@ AC_CONFIG_FILES([ src/Makefile src/distros.d/Makefile src/kimchi/Makefile + src/kimchi/control/Makefile plugins/Makefile plugins/sample/Makefile plugins/sample/ui/Makefile diff --git a/contrib/kimchi.spec.fedora.in b/contrib/kimchi.spec.fedora.in index 577516c..3044fc8 100644 --- a/contrib/kimchi.spec.fedora.in +++ b/contrib/kimchi.spec.fedora.in @@ -110,6 +110,7 @@ rm -rf $RPM_BUILD_ROOT %attr(-,root,root) %{_bindir}/kimchid %{python_sitelib}/kimchi/*.py* +%{python_sitelib}/kimchi/control/*.py* %{python_sitelib}/kimchi/API.json %{_datadir}/kimchi/doc/API.md %{_datadir}/kimchi/doc/README.md diff --git a/contrib/kimchi.spec.suse.in b/contrib/kimchi.spec.suse.in index 12d02ec..190b2be 100644 --- a/contrib/kimchi.spec.suse.in +++ b/contrib/kimchi.spec.suse.in @@ -57,6 +57,7 @@ rm -rf $RPM_BUILD_ROOT %attr(-,root,root) %{_bindir}/kimchid %{python_sitelib}/kimchi/*.py* +%{python_sitelib}/kimchi/control/*.py* %{python_sitelib}/kimchi/API.json %{_datadir}/kimchi/doc/API.md %{_datadir}/kimchi/doc/README.md diff --git a/src/kimchi/Makefile.am b/src/kimchi/Makefile.am index 47a3bd2..78af50f 100644 --- a/src/kimchi/Makefile.am +++ b/src/kimchi/Makefile.am @@ -20,6 +20,8 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+SUBDIRS = control + kimchi_PYTHON = \ asynctask.py \ auth.py \ diff --git a/src/kimchi/control/Makefile.am b/src/kimchi/control/Makefile.am new file mode 100644 index 0000000..925c593 --- /dev/null +++ b/src/kimchi/control/Makefile.am @@ -0,0 +1,28 @@ +# +# 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 + +control_PYTHON = *.py + +controldir = $(pythondir)/kimchi/control + +install-data-local: + $(MKDIR_P) $(DESTDIR)$(controldir) diff --git a/src/kimchi/control/__init__.py b/src/kimchi/control/__init__.py new file mode 100644 index 0000000..8a37cc4 --- /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..c3c5f8e --- /dev/null +++ b/src/kimchi/control/utils.py @@ -0,0 +1,105 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Mark Wu <wudxw@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 293b588..13b394e 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)

From: Aline Manera <alinefm@br.ibm.com> controller.py file must contain all related to Kimchi API resources Common cherrypy functions must be in root.py Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/controller.py | 20 -------------------- src/kimchi/root.py | 26 ++++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 13b394e..af30118 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -28,7 +28,6 @@ from functools import wraps 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 @@ -649,25 +648,6 @@ class Partition(Resource): def data(self): return self.info -@cherrypy.expose -def login(*args): - params = parse_request() - try: - userid = params['userid'] - password = params['password'] - except KeyError, key: - raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % key) - try: - auth.login(userid, password) - except OperationFailed: - raise cherrypy.HTTPError(401) - return '{}' - -@cherrypy.expose -def logout(): - auth.logout() - return '{}' - class Plugins(Collection): def __init__(self, model): super(Plugins, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 46403ab..21950bc 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -25,9 +25,12 @@ import cherrypy import json +from kimchi import auth from kimchi import controller from kimchi import template from kimchi.config import get_api_schema_file +from kimchi.control.utils import parse_request +from kimchi.exception import OperationFailed class Root(controller.Resource): @@ -52,8 +55,6 @@ class Root(controller.Resource): self.tasks = controller.Tasks(model) self.config = controller.Config(model) self.host = controller.Host(model) - self.login = controller.login - self.logout = controller.logout self.debugreports = controller.DebugReports(model) self.plugins = controller.Plugins(model) self.api_schema = json.load(open(get_api_schema_file())) @@ -87,3 +88,24 @@ class Root(controller.Resource): if page.endswith('.html'): return template.render('tabs/' + page, None) raise cherrypy.HTTPError(404) + + @cherrypy.expose + def login(self, *args): + params = parse_request() + try: + userid = params['userid'] + password = params['password'] + except KeyError, key: + raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % key) + + try: + auth.login(userid, password) + except OperationFailed: + raise cherrypy.HTTPError(401) + + return '{}' + + @cherrypy.expose + def logout(self): + auth.logout() + return '{}' -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
controller.py file must contain all related to Kimchi API resources Common cherrypy functions must be in root.py
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/controller.py | 20 -------------------- src/kimchi/root.py | 26 ++++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 13b394e..af30118 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -28,7 +28,6 @@ from functools import wraps
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 @@ -649,25 +648,6 @@ class Partition(Resource): def data(self): return self.info
-@cherrypy.expose -def login(*args): - params = parse_request() - try: - userid = params['userid'] - password = params['password'] - except KeyError, key: - raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % key) - try: - auth.login(userid, password) - except OperationFailed: - raise cherrypy.HTTPError(401) - return '{}' - -@cherrypy.expose -def logout(): - auth.logout() - return '{}' - class Plugins(Collection): def __init__(self, model): super(Plugins, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 46403ab..21950bc 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -25,9 +25,12 @@ import cherrypy import json
+from kimchi import auth from kimchi import controller from kimchi import template from kimchi.config import get_api_schema_file +from kimchi.control.utils import parse_request +from kimchi.exception import OperationFailed
class Root(controller.Resource): @@ -52,8 +55,6 @@ class Root(controller.Resource): self.tasks = controller.Tasks(model) self.config = controller.Config(model) self.host = controller.Host(model) - self.login = controller.login - self.logout = controller.logout self.debugreports = controller.DebugReports(model) self.plugins = controller.Plugins(model) self.api_schema = json.load(open(get_api_schema_file())) @@ -87,3 +88,24 @@ class Root(controller.Resource): if page.endswith('.html'): return template.render('tabs/' + page, None) raise cherrypy.HTTPError(404) + + @cherrypy.expose + def login(self, *args): + params = parse_request() + try: + userid = params['userid'] + password = params['password'] + except KeyError, key: + raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % key) + + try: + auth.login(userid, password) + except OperationFailed: + raise cherrypy.HTTPError(401) + + return '{}' + + @cherrypy.expose + def logout(self): + auth.logout() + return '{}'

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
controller.py file must contain all related to Kimchi API resources Common cherrypy functions must be in root.py
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/controller.py | 20 -------------------- src/kimchi/root.py | 26 ++++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 13b394e..af30118 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -28,7 +28,6 @@ from functools import wraps
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 @@ -649,25 +648,6 @@ class Partition(Resource): def data(self): return self.info
-@cherrypy.expose -def login(*args): - params = parse_request() - try: - userid = params['userid'] - password = params['password'] - except KeyError, key: - raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % key) - try: - auth.login(userid, password) - except OperationFailed: - raise cherrypy.HTTPError(401) - return '{}' - -@cherrypy.expose -def logout(): - auth.logout() - return '{}' - class Plugins(Collection): def __init__(self, model): super(Plugins, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 46403ab..21950bc 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -25,9 +25,12 @@ import cherrypy import json
+from kimchi import auth from kimchi import controller from kimchi import template from kimchi.config import get_api_schema_file +from kimchi.control.utils import parse_request +from kimchi.exception import OperationFailed
class Root(controller.Resource): @@ -52,8 +55,6 @@ class Root(controller.Resource): self.tasks = controller.Tasks(model) self.config = controller.Config(model) self.host = controller.Host(model) - self.login = controller.login - self.logout = controller.logout self.debugreports = controller.DebugReports(model) self.plugins = controller.Plugins(model) self.api_schema = json.load(open(get_api_schema_file())) @@ -87,3 +88,24 @@ class Root(controller.Resource): if page.endswith('.html'): return template.render('tabs/' + page, None) raise cherrypy.HTTPError(404) + + @cherrypy.expose + def login(self, *args): + params = parse_request() + try: + userid = params['userid'] + password = params['password'] + except KeyError, key: + raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % key) + + try: + auth.login(userid, password) + except OperationFailed: + raise cherrypy.HTTPError(401) + + return '{}' + + @cherrypy.expose + def logout(self): + auth.logout() + return '{}'

From: Aline Manera <alinefm@br.ibm.com> Resource(), Collection() and AsyncCollection classes are base for all Kimchi resources. Move them to a separated file as they should not be changed with high frequency Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/__init__.py | 2 +- src/kimchi/control/base.py | 292 ++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 244 ------------------------------------ src/kimchi/root.py | 5 +- tests/test_mockmodel.py | 6 +- 5 files changed, 299 insertions(+), 250 deletions(-) create mode 100644 src/kimchi/control/base.py diff --git a/plugins/sample/__init__.py b/plugins/sample/__init__.py index 25014cb..a1fe44e 100644 --- a/plugins/sample/__init__.py +++ b/plugins/sample/__init__.py @@ -27,7 +27,7 @@ import os from cherrypy import expose -from kimchi.controller import Collection, Resource +from kimchi.control.base import Collection, Resource from model import Model diff --git a/src/kimchi/control/base.py b/src/kimchi/control/base.py new file mode 100644 index 0000000..185c8d8 --- /dev/null +++ b/src/kimchi/control/base.py @@ -0,0 +1,292 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linix.vnet.ibm.com> +# Shu Ming <shuming@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 urllib2 + + +import kimchi.template +from kimchi.control.utils import get_class_name, internal_redirect, model_fn +from kimchi.control.utils import parse_request, validate_method +from kimchi.control.utils import validate_params +from kimchi.exception import InvalidOperation, InvalidParameter +from kimchi.exception import MissingParameter, NotFoundError, OperationFailed + + +class Resource(object): + """ + A Resource represents a single entity in the API (such as a Virtual + Machine) + + To create new Resource types, subclass this and change the following things + in the child class: + + - If the Resource requires more than one identifier set self.model_args as + appropriate. This should only be necessary if this Resource is logically + nested. For example: A Storage Volume belongs to a Storage Pool so the + Storage Volume would set model args to (pool_ident, volume_ident). + + - Implement the base operations of 'lookup' and 'delete' in the model(s). + + - Set the 'data' property to a JSON-serializable representation of the + Resource. + """ + def __init__(self, model, ident=None): + self.model = model + self.ident = ident + self.model_args = (ident,) + self.update_params = [] + + def generate_action_handler(self, action_name, action_args=None): + def wrapper(*args, **kwargs): + validate_method(('POST')) + try: + model_args = list(self.model_args) + if action_args is not None: + model_args.extend(parse_request()[key] + for key in action_args) + fn = getattr(self.model, model_fn(self, action_name)) + fn(*model_args) + uri_params = tuple(self.model_args) + raise internal_redirect(self.uri_fmt % uri_params) + except MissingParameter, param: + error = "Missing parameter: '%s'" % param + raise cherrypy.HTTPError(400, error) + except InvalidParameter, param: + error = "Invalid parameter: '%s'" % param + raise cherrypy.HTTPError(400, error) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except OperationFailed, msg: + raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + + wrapper.__name__ = action_name + wrapper.exposed = True + return wrapper + + def lookup(self): + try: + lookup = getattr(self.model, model_fn(self, 'lookup')) + self.info = lookup(*self.model_args) + except AttributeError: + self.info = {} + + def delete(self): + try: + fn = getattr(self.model, model_fn(self, 'delete')) + fn(*self.model_args) + cherrypy.response.status = 204 + except AttributeError: + error = "Delete is not allowed for %s" % get_class_name(self) + raise cherrypy.HTTPError(405, error) + except OperationFailed, msg: + raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + + @cherrypy.expose + def index(self): + method = validate_method(('GET', 'DELETE', 'PUT')) + if method == 'GET': + try: + return self.get() + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except OperationFailed, msg: + raise cherrypy.HTTPError(406, "Operation failed: '%s'" % msg) + elif method == 'DELETE': + try: + return self.delete() + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + elif method == 'PUT': + try: + return self.update() + except InvalidParameter, msg: + raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % msg) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + + def update(self): + try: + update = getattr(self.model, model_fn(self, 'update')) + except AttributeError: + error = "%s does not implement update method" + raise cherrypy.HTTPError(405, error % get_class_name(self)) + + params = parse_request() + validate_params(params, self, 'update') + + if self.update_params is not None: + invalids = [v for v in params.keys() if + v not in self.update_params] + if invalids: + error = "%s are not allowed to be updated" % invalids + raise cherrypy.HTTPError(405, error) + + ident = update(self.ident, params) + if ident != self.ident: + uri_params = list(self.model_args[:-1]) + uri_params += [urllib2.quote(ident.encode('utf8'))] + raise cherrypy.HTTPRedirect(self.uri_fmt % tuple(uri_params), 303) + + return self.get() + + def get(self): + self.lookup() + return kimchi.template.render(get_class_name(self), self.data) + + @property + def data(self): + """ + Override this in inherited classes to provide the Resource + representation as a python dictionary. + """ + return {} + + +class Collection(object): + """ + A Collection is a container for Resource objects. To create a new + Collection type, subclass this and make the following changes to the child + class: + + - Set self.resource to the type of Resource that this Collection contains + + - Set self.resource_args. This can remain an empty list if the Resources + can be initialized with only one identifier. Otherwise, include + additional values as needed (eg. to identify a parent resource). + + - Set self.model_args. Similar to above, this is needed only if the model + needs additional information to identify this Collection. + + - Implement the base operations of 'create' and 'get_list' in the model. + """ + def __init__(self, model): + self.model = model + self.resource = Resource + self.resource_args = [] + self.model_args = [] + + def create(self, *args): + try: + create = getattr(self.model, model_fn(self, 'create')) + except AttributeError: + error = 'Create is not allowed for %s' % get_class_name(self) + raise cherrypy.HTTPError(405, error) + + params = parse_request() + validate_params(params, self, 'create') + args = self.model_args + [params] + name = create(*args) + cherrypy.response.status = 201 + args = self.resource_args + [name] + res = self.resource(self.model, *args) + + return res.get() + + def _get_resources(self): + try: + get_list = getattr(self.model, model_fn(self, 'get_list')) + idents = get_list(*self.model_args) + res_list = [] + for ident in idents: + # internal text, get_list changes ident to unicode for sorted + args = self.resource_args + [ident] + res = self.resource(self.model, *args) + res.lookup() + res_list.append(res) + return res_list + except AttributeError: + return [] + + def _cp_dispatch(self, vpath): + if vpath: + ident = vpath.pop(0) + # incoming text, from URL, is not unicode, need decode + args = self.resource_args + [ident.decode("utf-8")] + return self.resource(self.model, *args) + + def get(self): + resources = self._get_resources() + data = [] + for res in resources: + data.append(res.data) + return kimchi.template.render(get_class_name(self), data) + + @cherrypy.expose + def index(self, *args): + method = validate_method(('GET', 'POST')) + if method == 'GET': + try: + return self.get() + except InvalidOperation, param: + error = "Invalid operation: '%s'" % param + raise cherrypy.HTTPError(400, error) + except NotFoundError, param: + raise cherrypy.HTTPError(404, "Not found: '%s'" % param) + + elif method == 'POST': + try: + return self.create(*args) + except MissingParameter, param: + error = "Missing parameter: '%s'" % param + raise cherrypy.HTTPError(400, error) + except InvalidParameter, param: + error = "Invalid parameter: '%s'" % param + raise cherrypy.HTTPError(400, error) + except OperationFailed, param: + raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % param) + except InvalidOperation, param: + error = "Invalid operation: '%s'" % param + raise cherrypy.HTTPError(400, error) + except NotFoundError, param: + raise cherrypy.HTTPError(404, "Not found: '%s'" % param) + + +class AsyncCollection(Collection): + """ + A Collection to create it's resource by asynchronous task + """ + def __init__(self, model): + super(AsyncCollection, self).__init__(model) + + def create(self, *args): + try: + create = getattr(self.model, model_fn(self, 'create')) + except AttributeError: + error = 'Create is not allowed for %s' % get_class_name(self) + raise cherrypy.HTTPError(405, error) + + params = parse_request() + args = self.model_args + [params] + task = create(*args) + cherrypy.response.status = 202 + return kimchi.template.render("Task", task) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index af30118..fade825 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -35,250 +35,6 @@ from kimchi.exception import NotFoundError, OperationFailed from kimchi.model import ISO_POOL_NAME -class Resource(object): - """ - A Resource represents a single entity in the API (such as a Virtual Machine) - - To create new Resource types, subclass this and change the following things - in the child class: - - - If the Resource requires more than one identifier set self.model_args as - appropriate. This should only be necessary if this Resource is logically - nested. For example: A Storage Volume belongs to a Storage Pool so the - Storage Volume would set model args to (pool_ident, volume_ident). - - - Implement the base operations of 'lookup' and 'delete' in the model(s). - - - Set the 'data' property to a JSON-serializable representation of the - Resource. - """ - def __init__(self, model, ident=None): - self.model = model - self.ident = ident - self.model_args = (ident,) - self.update_params = [] - - def generate_action_handler(self, action_name, action_args=None): - def wrapper(*args, **kwargs): - validate_method(('POST')) - try: - model_args = list(self.model_args) - if action_args is not None: - model_args.extend(parse_request()[key] for key in action_args) - fn = getattr(self.model, model_fn(self, action_name)) - fn(*model_args) - raise internal_redirect(self.uri_fmt % - tuple(self.model_args)) - except MissingParameter, param: - raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % param) - except InvalidParameter, param: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % param) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - - wrapper.__name__ = action_name - wrapper.exposed = True - return wrapper - - def lookup(self): - try: - lookup = getattr(self.model, model_fn(self, 'lookup')) - self.info = lookup(*self.model_args) - except AttributeError: - self.info = {} - - def delete(self): - try: - fn = getattr(self.model, model_fn(self, 'delete')) - fn(*self.model_args) - cherrypy.response.status = 204 - except AttributeError: - raise cherrypy.HTTPError(405, 'Delete is not allowed for %s' % get_class_name(self)) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - - @cherrypy.expose - def index(self): - method = validate_method(('GET', 'DELETE', 'PUT')) - if method == 'GET': - try: - return self.get() - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(406, "Operation failed: '%s'" % msg) - elif method == 'DELETE': - try: - return self.delete() - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - elif method == 'PUT': - try: - return self.update() - except InvalidParameter, msg: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - - def update(self): - try: - update = getattr(self.model, model_fn(self, 'update')) - except AttributeError: - raise cherrypy.HTTPError(405, "%s does not implement update " - "method" % get_class_name(self)) - params = parse_request() - validate_params(params, self, 'update') - if self.update_params != None: - invalids = [v for v in params.keys() if - v not in self.update_params] - if invalids: - raise cherrypy.HTTPError(405, "%s are not allowed to be updated" % - invalids) - ident = update(self.ident, params) - if ident != self.ident: - raise cherrypy.HTTPRedirect(self.uri_fmt % - tuple(list(self.model_args[:-1]) + [urllib2.quote(ident.encode('utf8'))]), - 303) - return self.get() - - - def get(self): - self.lookup() - return kimchi.template.render(get_class_name(self), self.data) - - @property - def data(self): - """ - Override this in inherited classes to provide the Resource - representation as a python dictionary. - """ - return {} - - -class Collection(object): - """ - A Collection is a container for Resource objects. To create a new - Collection type, subclass this and make the following changes to the child - class: - - - Set self.resource to the type of Resource that this Collection contains - - - Set self.resource_args. This can remain an empty list if the Resources - can be initialized with only one identifier. Otherwise, include - additional values as needed (eg. to identify a parent resource). - - - Set self.model_args. Similar to above, this is needed only if the model - needs additional information to identify this Collection. - - - Implement the base operations of 'create' and 'get_list' in the model. - """ - def __init__(self, model): - self.model = model - self.resource = Resource - self.resource_args = [] - self.model_args = [] - - def create(self, *args): - try: - create = getattr(self.model, model_fn(self, 'create')) - except AttributeError: - raise cherrypy.HTTPError(405, - 'Create is not allowed for %s' % get_class_name(self)) - params = parse_request() - validate_params(params, self, 'create') - args = self.model_args + [params] - name = create(*args) - cherrypy.response.status = 201 - args = self.resource_args + [name] - res = self.resource(self.model, *args) - return res.get() - - def _get_resources(self): - try: - get_list = getattr(self.model, model_fn(self, 'get_list')) - idents = get_list(*self.model_args) - res_list = [] - for ident in idents: - # internal text, get_list changes ident to unicode for sorted - args = self.resource_args + [ident] - res = self.resource(self.model, *args) - res.lookup() - res_list.append(res) - return res_list - except AttributeError: - return [] - - def _cp_dispatch(self, vpath): - if vpath: - ident = vpath.pop(0) - # incoming text, from URL, is not unicode, need decode - args = self.resource_args + [ident.decode("utf-8")] - return self.resource(self.model, *args) - - def get(self): - resources = self._get_resources() - data = [] - for res in resources: - data.append(res.data) - return kimchi.template.render(get_class_name(self), data) - - @cherrypy.expose - def index(self, *args): - method = validate_method(('GET', 'POST')) - if method == 'GET': - try: - return self.get() - except InvalidOperation, param: - raise cherrypy.HTTPError(400, - "Invalid operation: '%s'" % param) - except NotFoundError, param: - raise cherrypy.HTTPError(404, "Not found: '%s'" % param) - elif method == 'POST': - try: - return self.create(*args) - except MissingParameter, param: - raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % param) - except InvalidParameter, param: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % param) - except OperationFailed, param: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % param) - except InvalidOperation, param: - raise cherrypy.HTTPError(400, - "Invalid operation: '%s'" % param) - except NotFoundError, param: - raise cherrypy.HTTPError(404, "Not found: '%s'" % param) - - -class AsyncCollection(Collection): - """ - A Collection to create it's resource by asynchronous task - """ - def __init__(self, model): - super(AsyncCollection, self).__init__(model) - - def create(self, *args): - try: - create = getattr(self.model, model_fn(self, 'create')) - except AttributeError: - raise cherrypy.HTTPError(405, - 'Create is not allowed for %s' % get_class_name(self)) - params = parse_request() - args = self.model_args + [params] - task = create(*args) - cherrypy.response.status = 202 - return kimchi.template.render("Task", task) - - class DebugReportContent(Resource): def __init__(self, model, ident): super(DebugReportContent, self).__init__(model, ident) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 21950bc..2af2cf6 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -30,10 +30,11 @@ from kimchi import controller from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request +from kimchi.control.base import Resource from kimchi.exception import OperationFailed -class Root(controller.Resource): +class Root(Resource): def __init__(self, model, dev_env): self._handled_error = ['error_page.400', 'error_page.404', 'error_page.405', 'error_page.406', @@ -46,7 +47,7 @@ class Root(controller.Resource): self._cp_config = dict([(key, self.error_development_handler) for key in self._handled_error]) - controller.Resource.__init__(self, model) + Resource.__init__(self, model) self.vms = controller.VMs(model) self.templates = controller.Templates(model) self.storagepools = controller.StoragePools(model) diff --git a/tests/test_mockmodel.py b/tests/test_mockmodel.py index 5a3c73e..c47e062 100644 --- a/tests/test_mockmodel.py +++ b/tests/test_mockmodel.py @@ -28,7 +28,7 @@ import unittest import kimchi.mockmodel -import kimchi.controller +from kimchi.control.base import Collection, Resource from utils import get_free_port, patch_auth, request, run_server @@ -53,7 +53,7 @@ class MockModelTests(unittest.TestCase): os.unlink('/tmp/obj-store-test') def test_collection(self): - c = kimchi.controller.Collection(model) + c = Collection(model) # The base Collection is always empty cherrypy.request.method = 'GET' @@ -70,7 +70,7 @@ class MockModelTests(unittest.TestCase): self.fail("Expected exception not raised") def test_resource(self): - r = kimchi.controller.Resource(model) + r = Resource(model) # Test the base Resource representation cherrypy.request.method = 'GET' -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Resource(), Collection() and AsyncCollection classes are base for all Kimchi resources. Move them to a separated file as they should not be changed with high frequency
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/__init__.py | 2 +- src/kimchi/control/base.py | 292 ++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 244 ------------------------------------ src/kimchi/root.py | 5 +- tests/test_mockmodel.py | 6 +- 5 files changed, 299 insertions(+), 250 deletions(-) create mode 100644 src/kimchi/control/base.py
diff --git a/plugins/sample/__init__.py b/plugins/sample/__init__.py index 25014cb..a1fe44e 100644 --- a/plugins/sample/__init__.py +++ b/plugins/sample/__init__.py @@ -27,7 +27,7 @@ import os from cherrypy import expose
-from kimchi.controller import Collection, Resource +from kimchi.control.base import Collection, Resource from model import Model
diff --git a/src/kimchi/control/base.py b/src/kimchi/control/base.py new file mode 100644 index 0000000..185c8d8 --- /dev/null +++ b/src/kimchi/control/base.py @@ -0,0 +1,292 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linix.vnet.ibm.com> +# Shu Ming <shuming@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 urllib2 + + +import kimchi.template +from kimchi.control.utils import get_class_name, internal_redirect, model_fn +from kimchi.control.utils import parse_request, validate_method +from kimchi.control.utils import validate_params +from kimchi.exception import InvalidOperation, InvalidParameter +from kimchi.exception import MissingParameter, NotFoundError, OperationFailed + + +class Resource(object): + """ + A Resource represents a single entity in the API (such as a Virtual + Machine) + + To create new Resource types, subclass this and change the following things + in the child class: + + - If the Resource requires more than one identifier set self.model_args as + appropriate. This should only be necessary if this Resource is logically + nested. For example: A Storage Volume belongs to a Storage Pool so the + Storage Volume would set model args to (pool_ident, volume_ident). + + - Implement the base operations of 'lookup' and 'delete' in the model(s). + + - Set the 'data' property to a JSON-serializable representation of the + Resource. + """ + def __init__(self, model, ident=None): + self.model = model + self.ident = ident + self.model_args = (ident,) + self.update_params = [] + + def generate_action_handler(self, action_name, action_args=None): + def wrapper(*args, **kwargs): + validate_method(('POST')) + try: + model_args = list(self.model_args) + if action_args is not None: + model_args.extend(parse_request()[key] + for key in action_args) + fn = getattr(self.model, model_fn(self, action_name)) + fn(*model_args) + uri_params = tuple(self.model_args) + raise internal_redirect(self.uri_fmt % uri_params) + except MissingParameter, param: + error = "Missing parameter: '%s'" % param + raise cherrypy.HTTPError(400, error) + except InvalidParameter, param: + error = "Invalid parameter: '%s'" % param + raise cherrypy.HTTPError(400, error) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except OperationFailed, msg: + raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + + wrapper.__name__ = action_name + wrapper.exposed = True + return wrapper + + def lookup(self): + try: + lookup = getattr(self.model, model_fn(self, 'lookup')) + self.info = lookup(*self.model_args) + except AttributeError: + self.info = {} + + def delete(self): + try: + fn = getattr(self.model, model_fn(self, 'delete')) + fn(*self.model_args) + cherrypy.response.status = 204 + except AttributeError: + error = "Delete is not allowed for %s" % get_class_name(self) + raise cherrypy.HTTPError(405, error) + except OperationFailed, msg: + raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + + @cherrypy.expose + def index(self): + method = validate_method(('GET', 'DELETE', 'PUT')) + if method == 'GET': + try: + return self.get() + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except OperationFailed, msg: + raise cherrypy.HTTPError(406, "Operation failed: '%s'" % msg) + elif method == 'DELETE': + try: + return self.delete() + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + elif method == 'PUT': + try: + return self.update() + except InvalidParameter, msg: + raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % msg) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + + def update(self): + try: + update = getattr(self.model, model_fn(self, 'update')) + except AttributeError: + error = "%s does not implement update method" + raise cherrypy.HTTPError(405, error % get_class_name(self)) + + params = parse_request() + validate_params(params, self, 'update') + + if self.update_params is not None: + invalids = [v for v in params.keys() if + v not in self.update_params] + if invalids: + error = "%s are not allowed to be updated" % invalids + raise cherrypy.HTTPError(405, error) + + ident = update(self.ident, params) + if ident != self.ident: + uri_params = list(self.model_args[:-1]) + uri_params += [urllib2.quote(ident.encode('utf8'))] + raise cherrypy.HTTPRedirect(self.uri_fmt % tuple(uri_params), 303) + + return self.get() + + def get(self): + self.lookup() + return kimchi.template.render(get_class_name(self), self.data) + + @property + def data(self): + """ + Override this in inherited classes to provide the Resource + representation as a python dictionary. + """ + return {} + + +class Collection(object): + """ + A Collection is a container for Resource objects. To create a new + Collection type, subclass this and make the following changes to the child + class: + + - Set self.resource to the type of Resource that this Collection contains + + - Set self.resource_args. This can remain an empty list if the Resources + can be initialized with only one identifier. Otherwise, include + additional values as needed (eg. to identify a parent resource). + + - Set self.model_args. Similar to above, this is needed only if the model + needs additional information to identify this Collection. + + - Implement the base operations of 'create' and 'get_list' in the model. + """ + def __init__(self, model): + self.model = model + self.resource = Resource + self.resource_args = [] + self.model_args = [] + + def create(self, *args): + try: + create = getattr(self.model, model_fn(self, 'create')) + except AttributeError: + error = 'Create is not allowed for %s' % get_class_name(self) + raise cherrypy.HTTPError(405, error) + + params = parse_request() + validate_params(params, self, 'create') + args = self.model_args + [params] + name = create(*args) + cherrypy.response.status = 201 + args = self.resource_args + [name] + res = self.resource(self.model, *args) + + return res.get() + + def _get_resources(self): + try: + get_list = getattr(self.model, model_fn(self, 'get_list')) + idents = get_list(*self.model_args) + res_list = [] + for ident in idents: + # internal text, get_list changes ident to unicode for sorted + args = self.resource_args + [ident] + res = self.resource(self.model, *args) + res.lookup() + res_list.append(res) + return res_list + except AttributeError: + return [] + + def _cp_dispatch(self, vpath): + if vpath: + ident = vpath.pop(0) + # incoming text, from URL, is not unicode, need decode + args = self.resource_args + [ident.decode("utf-8")] + return self.resource(self.model, *args) + + def get(self): + resources = self._get_resources() + data = [] + for res in resources: + data.append(res.data) + return kimchi.template.render(get_class_name(self), data) + + @cherrypy.expose + def index(self, *args): + method = validate_method(('GET', 'POST')) + if method == 'GET': + try: + return self.get() + except InvalidOperation, param: + error = "Invalid operation: '%s'" % param + raise cherrypy.HTTPError(400, error) + except NotFoundError, param: + raise cherrypy.HTTPError(404, "Not found: '%s'" % param) + + elif method == 'POST': + try: + return self.create(*args) + except MissingParameter, param: + error = "Missing parameter: '%s'" % param + raise cherrypy.HTTPError(400, error) + except InvalidParameter, param: + error = "Invalid parameter: '%s'" % param + raise cherrypy.HTTPError(400, error) + except OperationFailed, param: + raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % param) + except InvalidOperation, param: + error = "Invalid operation: '%s'" % param + raise cherrypy.HTTPError(400, error) + except NotFoundError, param: + raise cherrypy.HTTPError(404, "Not found: '%s'" % param) + + +class AsyncCollection(Collection): + """ + A Collection to create it's resource by asynchronous task + """ + def __init__(self, model): + super(AsyncCollection, self).__init__(model) + + def create(self, *args): + try: + create = getattr(self.model, model_fn(self, 'create')) + except AttributeError: + error = 'Create is not allowed for %s' % get_class_name(self) + raise cherrypy.HTTPError(405, error) + + params = parse_request() + args = self.model_args + [params] + task = create(*args) + cherrypy.response.status = 202 + return kimchi.template.render("Task", task) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index af30118..fade825 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -35,250 +35,6 @@ from kimchi.exception import NotFoundError, OperationFailed from kimchi.model import ISO_POOL_NAME
-class Resource(object): - """ - A Resource represents a single entity in the API (such as a Virtual Machine) - - To create new Resource types, subclass this and change the following things - in the child class: - - - If the Resource requires more than one identifier set self.model_args as - appropriate. This should only be necessary if this Resource is logically - nested. For example: A Storage Volume belongs to a Storage Pool so the - Storage Volume would set model args to (pool_ident, volume_ident). - - - Implement the base operations of 'lookup' and 'delete' in the model(s). - - - Set the 'data' property to a JSON-serializable representation of the - Resource. - """ - def __init__(self, model, ident=None): - self.model = model - self.ident = ident - self.model_args = (ident,) - self.update_params = [] - - def generate_action_handler(self, action_name, action_args=None): - def wrapper(*args, **kwargs): - validate_method(('POST')) - try: - model_args = list(self.model_args) - if action_args is not None: - model_args.extend(parse_request()[key] for key in action_args) - fn = getattr(self.model, model_fn(self, action_name)) - fn(*model_args) - raise internal_redirect(self.uri_fmt % - tuple(self.model_args)) - except MissingParameter, param: - raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % param) - except InvalidParameter, param: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % param) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - - wrapper.__name__ = action_name - wrapper.exposed = True - return wrapper - - def lookup(self): - try: - lookup = getattr(self.model, model_fn(self, 'lookup')) - self.info = lookup(*self.model_args) - except AttributeError: - self.info = {} - - def delete(self): - try: - fn = getattr(self.model, model_fn(self, 'delete')) - fn(*self.model_args) - cherrypy.response.status = 204 - except AttributeError: - raise cherrypy.HTTPError(405, 'Delete is not allowed for %s' % get_class_name(self)) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - - @cherrypy.expose - def index(self): - method = validate_method(('GET', 'DELETE', 'PUT')) - if method == 'GET': - try: - return self.get() - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(406, "Operation failed: '%s'" % msg) - elif method == 'DELETE': - try: - return self.delete() - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - elif method == 'PUT': - try: - return self.update() - except InvalidParameter, msg: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - - def update(self): - try: - update = getattr(self.model, model_fn(self, 'update')) - except AttributeError: - raise cherrypy.HTTPError(405, "%s does not implement update " - "method" % get_class_name(self)) - params = parse_request() - validate_params(params, self, 'update') - if self.update_params != None: - invalids = [v for v in params.keys() if - v not in self.update_params] - if invalids: - raise cherrypy.HTTPError(405, "%s are not allowed to be updated" % - invalids) - ident = update(self.ident, params) - if ident != self.ident: - raise cherrypy.HTTPRedirect(self.uri_fmt % - tuple(list(self.model_args[:-1]) + [urllib2.quote(ident.encode('utf8'))]), - 303) - return self.get() - - - def get(self): - self.lookup() - return kimchi.template.render(get_class_name(self), self.data) - - @property - def data(self): - """ - Override this in inherited classes to provide the Resource - representation as a python dictionary. - """ - return {} - - -class Collection(object): - """ - A Collection is a container for Resource objects. To create a new - Collection type, subclass this and make the following changes to the child - class: - - - Set self.resource to the type of Resource that this Collection contains - - - Set self.resource_args. This can remain an empty list if the Resources - can be initialized with only one identifier. Otherwise, include - additional values as needed (eg. to identify a parent resource). - - - Set self.model_args. Similar to above, this is needed only if the model - needs additional information to identify this Collection. - - - Implement the base operations of 'create' and 'get_list' in the model. - """ - def __init__(self, model): - self.model = model - self.resource = Resource - self.resource_args = [] - self.model_args = [] - - def create(self, *args): - try: - create = getattr(self.model, model_fn(self, 'create')) - except AttributeError: - raise cherrypy.HTTPError(405, - 'Create is not allowed for %s' % get_class_name(self)) - params = parse_request() - validate_params(params, self, 'create') - args = self.model_args + [params] - name = create(*args) - cherrypy.response.status = 201 - args = self.resource_args + [name] - res = self.resource(self.model, *args) - return res.get() - - def _get_resources(self): - try: - get_list = getattr(self.model, model_fn(self, 'get_list')) - idents = get_list(*self.model_args) - res_list = [] - for ident in idents: - # internal text, get_list changes ident to unicode for sorted - args = self.resource_args + [ident] - res = self.resource(self.model, *args) - res.lookup() - res_list.append(res) - return res_list - except AttributeError: - return [] - - def _cp_dispatch(self, vpath): - if vpath: - ident = vpath.pop(0) - # incoming text, from URL, is not unicode, need decode - args = self.resource_args + [ident.decode("utf-8")] - return self.resource(self.model, *args) - - def get(self): - resources = self._get_resources() - data = [] - for res in resources: - data.append(res.data) - return kimchi.template.render(get_class_name(self), data) - - @cherrypy.expose - def index(self, *args): - method = validate_method(('GET', 'POST')) - if method == 'GET': - try: - return self.get() - except InvalidOperation, param: - raise cherrypy.HTTPError(400, - "Invalid operation: '%s'" % param) - except NotFoundError, param: - raise cherrypy.HTTPError(404, "Not found: '%s'" % param) - elif method == 'POST': - try: - return self.create(*args) - except MissingParameter, param: - raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % param) - except InvalidParameter, param: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % param) - except OperationFailed, param: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % param) - except InvalidOperation, param: - raise cherrypy.HTTPError(400, - "Invalid operation: '%s'" % param) - except NotFoundError, param: - raise cherrypy.HTTPError(404, "Not found: '%s'" % param) - - -class AsyncCollection(Collection): - """ - A Collection to create it's resource by asynchronous task - """ - def __init__(self, model): - super(AsyncCollection, self).__init__(model) - - def create(self, *args): - try: - create = getattr(self.model, model_fn(self, 'create')) - except AttributeError: - raise cherrypy.HTTPError(405, - 'Create is not allowed for %s' % get_class_name(self)) - params = parse_request() - args = self.model_args + [params] - task = create(*args) - cherrypy.response.status = 202 - return kimchi.template.render("Task", task) - - class DebugReportContent(Resource): def __init__(self, model, ident): super(DebugReportContent, self).__init__(model, ident) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 21950bc..2af2cf6 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -30,10 +30,11 @@ from kimchi import controller from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request +from kimchi.control.base import Resource from kimchi.exception import OperationFailed
-class Root(controller.Resource): +class Root(Resource): def __init__(self, model, dev_env): self._handled_error = ['error_page.400', 'error_page.404', 'error_page.405', 'error_page.406', @@ -46,7 +47,7 @@ class Root(controller.Resource): self._cp_config = dict([(key, self.error_development_handler) for key in self._handled_error])
- controller.Resource.__init__(self, model) + Resource.__init__(self, model) self.vms = controller.VMs(model) self.templates = controller.Templates(model) self.storagepools = controller.StoragePools(model) diff --git a/tests/test_mockmodel.py b/tests/test_mockmodel.py index 5a3c73e..c47e062 100644 --- a/tests/test_mockmodel.py +++ b/tests/test_mockmodel.py @@ -28,7 +28,7 @@ import unittest
import kimchi.mockmodel -import kimchi.controller +from kimchi.control.base import Collection, Resource from utils import get_free_port, patch_auth, request, run_server
@@ -53,7 +53,7 @@ class MockModelTests(unittest.TestCase): os.unlink('/tmp/obj-store-test')
def test_collection(self): - c = kimchi.controller.Collection(model) + c = Collection(model)
# The base Collection is always empty cherrypy.request.method = 'GET' @@ -70,7 +70,7 @@ class MockModelTests(unittest.TestCase): self.fail("Expected exception not raised")
def test_resource(self): - r = kimchi.controller.Resource(model) + r = Resource(model)
# Test the base Resource representation cherrypy.request.method = 'GET'

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Resource(), Collection() and AsyncCollection classes are base for all Kimchi resources. Move them to a separated file as they should not be changed with high frequency
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- plugins/sample/__init__.py | 2 +- src/kimchi/control/base.py | 292 ++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 244 ------------------------------------ src/kimchi/root.py | 5 +- tests/test_mockmodel.py | 6 +- 5 files changed, 299 insertions(+), 250 deletions(-) create mode 100644 src/kimchi/control/base.py
diff --git a/plugins/sample/__init__.py b/plugins/sample/__init__.py index 25014cb..a1fe44e 100644 --- a/plugins/sample/__init__.py +++ b/plugins/sample/__init__.py @@ -27,7 +27,7 @@ import os from cherrypy import expose
-from kimchi.controller import Collection, Resource +from kimchi.control.base import Collection, Resource from model import Model
diff --git a/src/kimchi/control/base.py b/src/kimchi/control/base.py new file mode 100644 index 0000000..185c8d8 --- /dev/null +++ b/src/kimchi/control/base.py @@ -0,0 +1,292 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linix.vnet.ibm.com> +# Shu Ming <shuming@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 urllib2 + + +import kimchi.template +from kimchi.control.utils import get_class_name, internal_redirect, model_fn +from kimchi.control.utils import parse_request, validate_method +from kimchi.control.utils import validate_params +from kimchi.exception import InvalidOperation, InvalidParameter +from kimchi.exception import MissingParameter, NotFoundError, OperationFailed + + +class Resource(object): + """ + A Resource represents a single entity in the API (such as a Virtual + Machine) + + To create new Resource types, subclass this and change the following things + in the child class: + + - If the Resource requires more than one identifier set self.model_args as + appropriate. This should only be necessary if this Resource is logically + nested. For example: A Storage Volume belongs to a Storage Pool so the + Storage Volume would set model args to (pool_ident, volume_ident). + + - Implement the base operations of 'lookup' and 'delete' in the model(s). + + - Set the 'data' property to a JSON-serializable representation of the + Resource. + """ + def __init__(self, model, ident=None): + self.model = model + self.ident = ident + self.model_args = (ident,) + self.update_params = [] + + def generate_action_handler(self, action_name, action_args=None): + def wrapper(*args, **kwargs): + validate_method(('POST')) + try: + model_args = list(self.model_args) + if action_args is not None: + model_args.extend(parse_request()[key] + for key in action_args) + fn = getattr(self.model, model_fn(self, action_name)) + fn(*model_args) + uri_params = tuple(self.model_args) + raise internal_redirect(self.uri_fmt % uri_params) + except MissingParameter, param: + error = "Missing parameter: '%s'" % param + raise cherrypy.HTTPError(400, error) + except InvalidParameter, param: + error = "Invalid parameter: '%s'" % param + raise cherrypy.HTTPError(400, error) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except OperationFailed, msg: + raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + + wrapper.__name__ = action_name + wrapper.exposed = True + return wrapper + + def lookup(self): + try: + lookup = getattr(self.model, model_fn(self, 'lookup')) + self.info = lookup(*self.model_args) + except AttributeError: + self.info = {} + + def delete(self): + try: + fn = getattr(self.model, model_fn(self, 'delete')) + fn(*self.model_args) + cherrypy.response.status = 204 + except AttributeError: + error = "Delete is not allowed for %s" % get_class_name(self) + raise cherrypy.HTTPError(405, error) + except OperationFailed, msg: + raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + + @cherrypy.expose + def index(self): + method = validate_method(('GET', 'DELETE', 'PUT')) + if method == 'GET': + try: + return self.get() + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except OperationFailed, msg: + raise cherrypy.HTTPError(406, "Operation failed: '%s'" % msg) + elif method == 'DELETE': + try: + return self.delete() + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + elif method == 'PUT': + try: + return self.update() + except InvalidParameter, msg: + raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % msg) + except InvalidOperation, msg: + raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) + except NotFoundError, msg: + raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) + + def update(self): + try: + update = getattr(self.model, model_fn(self, 'update')) + except AttributeError: + error = "%s does not implement update method" + raise cherrypy.HTTPError(405, error % get_class_name(self)) + + params = parse_request() + validate_params(params, self, 'update') + + if self.update_params is not None: + invalids = [v for v in params.keys() if + v not in self.update_params] + if invalids: + error = "%s are not allowed to be updated" % invalids + raise cherrypy.HTTPError(405, error) + + ident = update(self.ident, params) + if ident != self.ident: + uri_params = list(self.model_args[:-1]) + uri_params += [urllib2.quote(ident.encode('utf8'))] + raise cherrypy.HTTPRedirect(self.uri_fmt % tuple(uri_params), 303) + + return self.get() + + def get(self): + self.lookup() + return kimchi.template.render(get_class_name(self), self.data) + + @property + def data(self): + """ + Override this in inherited classes to provide the Resource + representation as a python dictionary. + """ + return {} + + +class Collection(object): + """ + A Collection is a container for Resource objects. To create a new + Collection type, subclass this and make the following changes to the child + class: + + - Set self.resource to the type of Resource that this Collection contains + + - Set self.resource_args. This can remain an empty list if the Resources + can be initialized with only one identifier. Otherwise, include + additional values as needed (eg. to identify a parent resource). + + - Set self.model_args. Similar to above, this is needed only if the model + needs additional information to identify this Collection. + + - Implement the base operations of 'create' and 'get_list' in the model. + """ + def __init__(self, model): + self.model = model + self.resource = Resource + self.resource_args = [] + self.model_args = [] + + def create(self, *args): + try: + create = getattr(self.model, model_fn(self, 'create')) + except AttributeError: + error = 'Create is not allowed for %s' % get_class_name(self) + raise cherrypy.HTTPError(405, error) + + params = parse_request() + validate_params(params, self, 'create') + args = self.model_args + [params] + name = create(*args) + cherrypy.response.status = 201 + args = self.resource_args + [name] + res = self.resource(self.model, *args) + + return res.get() + + def _get_resources(self): + try: + get_list = getattr(self.model, model_fn(self, 'get_list')) + idents = get_list(*self.model_args) + res_list = [] + for ident in idents: + # internal text, get_list changes ident to unicode for sorted + args = self.resource_args + [ident] + res = self.resource(self.model, *args) + res.lookup() + res_list.append(res) + return res_list + except AttributeError: + return [] + + def _cp_dispatch(self, vpath): + if vpath: + ident = vpath.pop(0) + # incoming text, from URL, is not unicode, need decode + args = self.resource_args + [ident.decode("utf-8")] + return self.resource(self.model, *args) + + def get(self): + resources = self._get_resources() + data = [] + for res in resources: + data.append(res.data) + return kimchi.template.render(get_class_name(self), data) + + @cherrypy.expose + def index(self, *args): + method = validate_method(('GET', 'POST')) + if method == 'GET': + try: + return self.get() + except InvalidOperation, param: + error = "Invalid operation: '%s'" % param + raise cherrypy.HTTPError(400, error) + except NotFoundError, param: + raise cherrypy.HTTPError(404, "Not found: '%s'" % param) + + elif method == 'POST': + try: + return self.create(*args) + except MissingParameter, param: + error = "Missing parameter: '%s'" % param + raise cherrypy.HTTPError(400, error) + except InvalidParameter, param: + error = "Invalid parameter: '%s'" % param + raise cherrypy.HTTPError(400, error) + except OperationFailed, param: + raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % param) + except InvalidOperation, param: + error = "Invalid operation: '%s'" % param + raise cherrypy.HTTPError(400, error) + except NotFoundError, param: + raise cherrypy.HTTPError(404, "Not found: '%s'" % param) + + +class AsyncCollection(Collection): + """ + A Collection to create it's resource by asynchronous task + """ + def __init__(self, model): + super(AsyncCollection, self).__init__(model) + + def create(self, *args): + try: + create = getattr(self.model, model_fn(self, 'create')) + except AttributeError: + error = 'Create is not allowed for %s' % get_class_name(self) + raise cherrypy.HTTPError(405, error) + + params = parse_request() + args = self.model_args + [params] + task = create(*args) + cherrypy.response.status = 202 + return kimchi.template.render("Task", task) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index af30118..fade825 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -35,250 +35,6 @@ from kimchi.exception import NotFoundError, OperationFailed from kimchi.model import ISO_POOL_NAME
-class Resource(object): - """ - A Resource represents a single entity in the API (such as a Virtual Machine) - - To create new Resource types, subclass this and change the following things - in the child class: - - - If the Resource requires more than one identifier set self.model_args as - appropriate. This should only be necessary if this Resource is logically - nested. For example: A Storage Volume belongs to a Storage Pool so the - Storage Volume would set model args to (pool_ident, volume_ident). - - - Implement the base operations of 'lookup' and 'delete' in the model(s). - - - Set the 'data' property to a JSON-serializable representation of the - Resource. - """ - def __init__(self, model, ident=None): - self.model = model - self.ident = ident - self.model_args = (ident,) - self.update_params = [] - - def generate_action_handler(self, action_name, action_args=None): - def wrapper(*args, **kwargs): - validate_method(('POST')) - try: - model_args = list(self.model_args) - if action_args is not None: - model_args.extend(parse_request()[key] for key in action_args) - fn = getattr(self.model, model_fn(self, action_name)) - fn(*model_args) - raise internal_redirect(self.uri_fmt % - tuple(self.model_args)) - except MissingParameter, param: - raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % param) - except InvalidParameter, param: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % param) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - - wrapper.__name__ = action_name - wrapper.exposed = True - return wrapper - - def lookup(self): - try: - lookup = getattr(self.model, model_fn(self, 'lookup')) - self.info = lookup(*self.model_args) - except AttributeError: - self.info = {} - - def delete(self): - try: - fn = getattr(self.model, model_fn(self, 'delete')) - fn(*self.model_args) - cherrypy.response.status = 204 - except AttributeError: - raise cherrypy.HTTPError(405, 'Delete is not allowed for %s' % get_class_name(self)) - except OperationFailed, msg: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - - @cherrypy.expose - def index(self): - method = validate_method(('GET', 'DELETE', 'PUT')) - if method == 'GET': - try: - return self.get() - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except OperationFailed, msg: - raise cherrypy.HTTPError(406, "Operation failed: '%s'" % msg) - elif method == 'DELETE': - try: - return self.delete() - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - elif method == 'PUT': - try: - return self.update() - except InvalidParameter, msg: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % msg) - except InvalidOperation, msg: - raise cherrypy.HTTPError(400, "Invalid operation: '%s'" % msg) - except NotFoundError, msg: - raise cherrypy.HTTPError(404, "Not found: '%s'" % msg) - - def update(self): - try: - update = getattr(self.model, model_fn(self, 'update')) - except AttributeError: - raise cherrypy.HTTPError(405, "%s does not implement update " - "method" % get_class_name(self)) - params = parse_request() - validate_params(params, self, 'update') - if self.update_params != None: - invalids = [v for v in params.keys() if - v not in self.update_params] - if invalids: - raise cherrypy.HTTPError(405, "%s are not allowed to be updated" % - invalids) - ident = update(self.ident, params) - if ident != self.ident: - raise cherrypy.HTTPRedirect(self.uri_fmt % - tuple(list(self.model_args[:-1]) + [urllib2.quote(ident.encode('utf8'))]), - 303) - return self.get() - - - def get(self): - self.lookup() - return kimchi.template.render(get_class_name(self), self.data) - - @property - def data(self): - """ - Override this in inherited classes to provide the Resource - representation as a python dictionary. - """ - return {} - - -class Collection(object): - """ - A Collection is a container for Resource objects. To create a new - Collection type, subclass this and make the following changes to the child - class: - - - Set self.resource to the type of Resource that this Collection contains - - - Set self.resource_args. This can remain an empty list if the Resources - can be initialized with only one identifier. Otherwise, include - additional values as needed (eg. to identify a parent resource). - - - Set self.model_args. Similar to above, this is needed only if the model - needs additional information to identify this Collection. - - - Implement the base operations of 'create' and 'get_list' in the model. - """ - def __init__(self, model): - self.model = model - self.resource = Resource - self.resource_args = [] - self.model_args = [] - - def create(self, *args): - try: - create = getattr(self.model, model_fn(self, 'create')) - except AttributeError: - raise cherrypy.HTTPError(405, - 'Create is not allowed for %s' % get_class_name(self)) - params = parse_request() - validate_params(params, self, 'create') - args = self.model_args + [params] - name = create(*args) - cherrypy.response.status = 201 - args = self.resource_args + [name] - res = self.resource(self.model, *args) - return res.get() - - def _get_resources(self): - try: - get_list = getattr(self.model, model_fn(self, 'get_list')) - idents = get_list(*self.model_args) - res_list = [] - for ident in idents: - # internal text, get_list changes ident to unicode for sorted - args = self.resource_args + [ident] - res = self.resource(self.model, *args) - res.lookup() - res_list.append(res) - return res_list - except AttributeError: - return [] - - def _cp_dispatch(self, vpath): - if vpath: - ident = vpath.pop(0) - # incoming text, from URL, is not unicode, need decode - args = self.resource_args + [ident.decode("utf-8")] - return self.resource(self.model, *args) - - def get(self): - resources = self._get_resources() - data = [] - for res in resources: - data.append(res.data) - return kimchi.template.render(get_class_name(self), data) - - @cherrypy.expose - def index(self, *args): - method = validate_method(('GET', 'POST')) - if method == 'GET': - try: - return self.get() - except InvalidOperation, param: - raise cherrypy.HTTPError(400, - "Invalid operation: '%s'" % param) - except NotFoundError, param: - raise cherrypy.HTTPError(404, "Not found: '%s'" % param) - elif method == 'POST': - try: - return self.create(*args) - except MissingParameter, param: - raise cherrypy.HTTPError(400, "Missing parameter: '%s'" % param) - except InvalidParameter, param: - raise cherrypy.HTTPError(400, "Invalid parameter: '%s'" % param) - except OperationFailed, param: - raise cherrypy.HTTPError(500, "Operation Failed: '%s'" % param) - except InvalidOperation, param: - raise cherrypy.HTTPError(400, - "Invalid operation: '%s'" % param) - except NotFoundError, param: - raise cherrypy.HTTPError(404, "Not found: '%s'" % param) - - -class AsyncCollection(Collection): - """ - A Collection to create it's resource by asynchronous task - """ - def __init__(self, model): - super(AsyncCollection, self).__init__(model) - - def create(self, *args): - try: - create = getattr(self.model, model_fn(self, 'create')) - except AttributeError: - raise cherrypy.HTTPError(405, - 'Create is not allowed for %s' % get_class_name(self)) - params = parse_request() - args = self.model_args + [params] - task = create(*args) - cherrypy.response.status = 202 - return kimchi.template.render("Task", task) - - class DebugReportContent(Resource): def __init__(self, model, ident): super(DebugReportContent, self).__init__(model, ident) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 21950bc..2af2cf6 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -30,10 +30,11 @@ from kimchi import controller from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request +from kimchi.control.base import Resource from kimchi.exception import OperationFailed
-class Root(controller.Resource): +class Root(Resource): def __init__(self, model, dev_env): self._handled_error = ['error_page.400', 'error_page.404', 'error_page.405', 'error_page.406', @@ -46,7 +47,7 @@ class Root(controller.Resource): self._cp_config = dict([(key, self.error_development_handler) for key in self._handled_error])
- controller.Resource.__init__(self, model) + Resource.__init__(self, model) self.vms = controller.VMs(model) self.templates = controller.Templates(model) self.storagepools = controller.StoragePools(model) diff --git a/tests/test_mockmodel.py b/tests/test_mockmodel.py index 5a3c73e..c47e062 100644 --- a/tests/test_mockmodel.py +++ b/tests/test_mockmodel.py @@ -28,7 +28,7 @@ import unittest
import kimchi.mockmodel -import kimchi.controller +from kimchi.control.base import Collection, Resource from utils import get_free_port, patch_auth, request, run_server
@@ -53,7 +53,7 @@ class MockModelTests(unittest.TestCase): os.unlink('/tmp/obj-store-test')
def test_collection(self): - c = kimchi.controller.Collection(model) + c = Collection(model)
# The base Collection is always empty cherrypy.request.method = 'GET' @@ -70,7 +70,7 @@ class MockModelTests(unittest.TestCase): self.fail("Expected exception not raised")
def test_resource(self): - r = kimchi.controller.Resource(model) + r = Resource(model)
# Test the base Resource representation cherrypy.request.method = 'GET'

From: Aline Manera <alinefm@br.ibm.com> VMs(Collection), VM(Resource) and VMScreenshot(Resource) were moved to a new - control/vms.py That way we can easily know where vm resource is implemented. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 38 -------------------------- src/kimchi/root.py | 3 ++- 3 files changed, 67 insertions(+), 39 deletions(-) create mode 100644 src/kimchi/control/vms.py diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py new file mode 100644 index 0000000..d722920 --- /dev/null +++ b/src/kimchi/control/vms.py @@ -0,0 +1,65 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Royce Lv <lvroyce@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 + +from kimchi.control.base import Collection, Resource +from kimchi.control.utils import internal_redirect + + +class VMs(Collection): + def __init__(self, model): + super(VMs, self).__init__(model) + self.resource = VM + + +class VM(Resource): + def __init__(self, model, ident): + super(VM, self).__init__(model, ident) + self.update_params = ["name"] + self.screenshot = VMScreenShot(model, ident) + self.uri_fmt = '/vms/%s' + self.start = self.generate_action_handler('start') + self.stop = self.generate_action_handler('stop') + self.connect = self.generate_action_handler('connect') + + @property + def data(self): + return {'name': self.ident, + 'uuid': self.info['uuid'], + 'stats': self.info['stats'], + 'memory': self.info['memory'], + 'cpus': self.info['cpus'], + 'state': self.info['state'], + 'screenshot': self.info['screenshot'], + 'icon': self.info['icon'], + 'graphics': {'type': self.info['graphics']['type'], + 'port': self.info['graphics']['port']}} + + +class VMScreenShot(Resource): + def __init__(self, model, ident): + super(VMScreenShot, self).__init__(model, ident) + + def get(self): + self.lookup() + raise internal_redirect(self.info) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index fade825..cca2b57 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -44,44 +44,6 @@ class DebugReportContent(Resource): raise internal_redirect(self.info['file']) -class VMs(Collection): - def __init__(self, model): - super(VMs, self).__init__(model) - self.resource = VM - - -class VM(Resource): - def __init__(self, model, ident): - super(VM, self).__init__(model, ident) - self.update_params = ["name"] - self.screenshot = VMScreenShot(model, ident) - self.uri_fmt = '/vms/%s' - self.start = self.generate_action_handler('start') - self.stop = self.generate_action_handler('stop') - self.connect = self.generate_action_handler('connect') - - @property - def data(self): - return {'name': self.ident, - 'uuid': self.info['uuid'], - 'stats': self.info['stats'], - 'memory': self.info['memory'], - 'cpus': self.info['cpus'], - 'state': self.info['state'], - 'screenshot': self.info['screenshot'], - 'icon': self.info['icon'], - 'graphics': {'type': self.info['graphics']['type'], - 'port': self.info['graphics']['port']}} - - -class VMScreenShot(Resource): - def __init__(self, model, ident): - super(VMScreenShot, self).__init__(model, ident) - - def get(self): - self.lookup() - raise internal_redirect(self.info) - class Templates(Collection): def __init__(self, model): super(Templates, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 2af2cf6..99185eb 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -31,6 +31,7 @@ from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource +from kimchi.control.vms import VMs from kimchi.exception import OperationFailed @@ -48,7 +49,7 @@ class Root(Resource): for key in self._handled_error]) Resource.__init__(self, model) - self.vms = controller.VMs(model) + self.vms = VMs(model) self.templates = controller.Templates(model) self.storagepools = controller.StoragePools(model) self.interfaces = controller.Interfaces(model) -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
VMs(Collection), VM(Resource) and VMScreenshot(Resource) were moved to a new - control/vms.py That way we can easily know where vm resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 38 -------------------------- src/kimchi/root.py | 3 ++- 3 files changed, 67 insertions(+), 39 deletions(-) create mode 100644 src/kimchi/control/vms.py
diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py new file mode 100644 index 0000000..d722920 --- /dev/null +++ b/src/kimchi/control/vms.py @@ -0,0 +1,65 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Royce Lv <lvroyce@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 + +from kimchi.control.base import Collection, Resource +from kimchi.control.utils import internal_redirect + + +class VMs(Collection): + def __init__(self, model): + super(VMs, self).__init__(model) + self.resource = VM + + +class VM(Resource): + def __init__(self, model, ident): + super(VM, self).__init__(model, ident) + self.update_params = ["name"] + self.screenshot = VMScreenShot(model, ident) + self.uri_fmt = '/vms/%s' + self.start = self.generate_action_handler('start') + self.stop = self.generate_action_handler('stop') + self.connect = self.generate_action_handler('connect') + + @property + def data(self): + return {'name': self.ident, + 'uuid': self.info['uuid'], + 'stats': self.info['stats'], + 'memory': self.info['memory'], + 'cpus': self.info['cpus'], + 'state': self.info['state'], + 'screenshot': self.info['screenshot'], + 'icon': self.info['icon'], + 'graphics': {'type': self.info['graphics']['type'], + 'port': self.info['graphics']['port']}} + + +class VMScreenShot(Resource): + def __init__(self, model, ident): + super(VMScreenShot, self).__init__(model, ident) + + def get(self): + self.lookup() + raise internal_redirect(self.info) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index fade825..cca2b57 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -44,44 +44,6 @@ class DebugReportContent(Resource): raise internal_redirect(self.info['file'])
-class VMs(Collection): - def __init__(self, model): - super(VMs, self).__init__(model) - self.resource = VM - - -class VM(Resource): - def __init__(self, model, ident): - super(VM, self).__init__(model, ident) - self.update_params = ["name"] - self.screenshot = VMScreenShot(model, ident) - self.uri_fmt = '/vms/%s' - self.start = self.generate_action_handler('start') - self.stop = self.generate_action_handler('stop') - self.connect = self.generate_action_handler('connect') - - @property - def data(self): - return {'name': self.ident, - 'uuid': self.info['uuid'], - 'stats': self.info['stats'], - 'memory': self.info['memory'], - 'cpus': self.info['cpus'], - 'state': self.info['state'], - 'screenshot': self.info['screenshot'], - 'icon': self.info['icon'], - 'graphics': {'type': self.info['graphics']['type'], - 'port': self.info['graphics']['port']}} - - -class VMScreenShot(Resource): - def __init__(self, model, ident): - super(VMScreenShot, self).__init__(model, ident) - - def get(self): - self.lookup() - raise internal_redirect(self.info) - class Templates(Collection): def __init__(self, model): super(Templates, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 2af2cf6..99185eb 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -31,6 +31,7 @@ from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource +from kimchi.control.vms import VMs from kimchi.exception import OperationFailed
@@ -48,7 +49,7 @@ class Root(Resource): for key in self._handled_error])
Resource.__init__(self, model) - self.vms = controller.VMs(model) + self.vms = VMs(model) self.templates = controller.Templates(model) self.storagepools = controller.StoragePools(model) self.interfaces = controller.Interfaces(model)

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
VMs(Collection), VM(Resource) and VMScreenshot(Resource) were moved to a new - control/vms.py That way we can easily know where vm resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/vms.py | 65 +++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 38 -------------------------- src/kimchi/root.py | 3 ++- 3 files changed, 67 insertions(+), 39 deletions(-) create mode 100644 src/kimchi/control/vms.py
diff --git a/src/kimchi/control/vms.py b/src/kimchi/control/vms.py new file mode 100644 index 0000000..d722920 --- /dev/null +++ b/src/kimchi/control/vms.py @@ -0,0 +1,65 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Royce Lv <lvroyce@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 + +from kimchi.control.base import Collection, Resource +from kimchi.control.utils import internal_redirect + + +class VMs(Collection): + def __init__(self, model): + super(VMs, self).__init__(model) + self.resource = VM + + +class VM(Resource): + def __init__(self, model, ident): + super(VM, self).__init__(model, ident) + self.update_params = ["name"] + self.screenshot = VMScreenShot(model, ident) + self.uri_fmt = '/vms/%s' + self.start = self.generate_action_handler('start') + self.stop = self.generate_action_handler('stop') + self.connect = self.generate_action_handler('connect') + + @property + def data(self): + return {'name': self.ident, + 'uuid': self.info['uuid'], + 'stats': self.info['stats'], + 'memory': self.info['memory'], + 'cpus': self.info['cpus'], + 'state': self.info['state'], + 'screenshot': self.info['screenshot'], + 'icon': self.info['icon'], + 'graphics': {'type': self.info['graphics']['type'], + 'port': self.info['graphics']['port']}} + + +class VMScreenShot(Resource): + def __init__(self, model, ident): + super(VMScreenShot, self).__init__(model, ident) + + def get(self): + self.lookup() + raise internal_redirect(self.info) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index fade825..cca2b57 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -44,44 +44,6 @@ class DebugReportContent(Resource): raise internal_redirect(self.info['file'])
-class VMs(Collection): - def __init__(self, model): - super(VMs, self).__init__(model) - self.resource = VM - - -class VM(Resource): - def __init__(self, model, ident): - super(VM, self).__init__(model, ident) - self.update_params = ["name"] - self.screenshot = VMScreenShot(model, ident) - self.uri_fmt = '/vms/%s' - self.start = self.generate_action_handler('start') - self.stop = self.generate_action_handler('stop') - self.connect = self.generate_action_handler('connect') - - @property - def data(self): - return {'name': self.ident, - 'uuid': self.info['uuid'], - 'stats': self.info['stats'], - 'memory': self.info['memory'], - 'cpus': self.info['cpus'], - 'state': self.info['state'], - 'screenshot': self.info['screenshot'], - 'icon': self.info['icon'], - 'graphics': {'type': self.info['graphics']['type'], - 'port': self.info['graphics']['port']}} - - -class VMScreenShot(Resource): - def __init__(self, model, ident): - super(VMScreenShot, self).__init__(model, ident) - - def get(self): - self.lookup() - raise internal_redirect(self.info) - class Templates(Collection): def __init__(self, model): super(Templates, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 2af2cf6..99185eb 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -31,6 +31,7 @@ from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource +from kimchi.control.vms import VMs from kimchi.exception import OperationFailed
@@ -48,7 +49,7 @@ class Root(Resource): for key in self._handled_error])
Resource.__init__(self, model) - self.vms = controller.VMs(model) + self.vms = VMs(model) self.templates = controller.Templates(model) self.storagepools = controller.StoragePools(model) self.interfaces = controller.Interfaces(model)

From: Aline Manera <alinefm@br.ibm.com> Templates(Collection) and Template(Resource) were moved to a new - control/templates.py That way we can easily know where template resource is implemented. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/templates.py | 52 +++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 28 --------------------- src/kimchi/root.py | 3 ++- 3 files changed, 54 insertions(+), 29 deletions(-) create mode 100644 src/kimchi/control/templates.py diff --git a/src/kimchi/control/templates.py b/src/kimchi/control/templates.py new file mode 100644 index 0000000..30875cd --- /dev/null +++ b/src/kimchi/control/templates.py @@ -0,0 +1,52 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# 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 + +from kimchi.control.base import Collection, Resource + + +class Templates(Collection): + def __init__(self, model): + super(Templates, self).__init__(model) + self.resource = Template + + +class Template(Resource): + def __init__(self, model, ident): + super(Template, self).__init__(model, ident) + self.update_params = ["name", "folder", "icon", "os_distro", + "storagepool", "os_version", "cpus", + "memory", "cdrom", "disks"] + self.uri_fmt = "/templates/%s" + + @property + def data(self): + return {'name': self.ident, + 'icon': self.info['icon'], + 'os_distro': self.info['os_distro'], + 'os_version': self.info['os_version'], + 'cpus': self.info['cpus'], + 'memory': self.info['memory'], + 'cdrom': self.info['cdrom'], + 'disks': self.info['disks'], + 'storagepool': self.info['storagepool'], + 'folder': self.info.get('folder', [])} diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index cca2b57..38ccb7b 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -44,34 +44,6 @@ class DebugReportContent(Resource): raise internal_redirect(self.info['file']) -class Templates(Collection): - def __init__(self, model): - super(Templates, self).__init__(model) - self.resource = Template - - -class Template(Resource): - def __init__(self, model, ident): - super(Template, self).__init__(model, ident) - self.update_params = ["name", "folder", "icon", "os_distro", - "storagepool", "os_version", "cpus", - "memory", "cdrom", "disks"] - self.uri_fmt = "/templates/%s" - - @property - def data(self): - return {'name': self.ident, - 'icon': self.info['icon'], - 'os_distro': self.info['os_distro'], - 'os_version': self.info['os_version'], - 'cpus': self.info['cpus'], - 'memory': self.info['memory'], - 'cdrom': self.info['cdrom'], - 'disks': self.info['disks'], - 'storagepool': self.info['storagepool'], - 'folder': self.info.get('folder', [])} - - class Interfaces(Collection): def __init__(self, model): super(Interfaces, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 99185eb..cd4a11f 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -31,6 +31,7 @@ from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource +from kimchi.control.templates import Templates from kimchi.control.vms import VMs from kimchi.exception import OperationFailed @@ -50,7 +51,7 @@ class Root(Resource): Resource.__init__(self, model) self.vms = VMs(model) - self.templates = controller.Templates(model) + self.templates = Templates(model) self.storagepools = controller.StoragePools(model) self.interfaces = controller.Interfaces(model) self.networks = controller.Networks(model) -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Templates(Collection) and Template(Resource) were moved to a new - control/templates.py That way we can easily know where template resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/templates.py | 52 +++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 28 --------------------- src/kimchi/root.py | 3 ++- 3 files changed, 54 insertions(+), 29 deletions(-) create mode 100644 src/kimchi/control/templates.py
diff --git a/src/kimchi/control/templates.py b/src/kimchi/control/templates.py new file mode 100644 index 0000000..30875cd --- /dev/null +++ b/src/kimchi/control/templates.py @@ -0,0 +1,52 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# 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 + +from kimchi.control.base import Collection, Resource + + +class Templates(Collection): + def __init__(self, model): + super(Templates, self).__init__(model) + self.resource = Template + + +class Template(Resource): + def __init__(self, model, ident): + super(Template, self).__init__(model, ident) + self.update_params = ["name", "folder", "icon", "os_distro", + "storagepool", "os_version", "cpus", + "memory", "cdrom", "disks"] + self.uri_fmt = "/templates/%s" + + @property + def data(self): + return {'name': self.ident, + 'icon': self.info['icon'], + 'os_distro': self.info['os_distro'], + 'os_version': self.info['os_version'], + 'cpus': self.info['cpus'], + 'memory': self.info['memory'], + 'cdrom': self.info['cdrom'], + 'disks': self.info['disks'], + 'storagepool': self.info['storagepool'], + 'folder': self.info.get('folder', [])} diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index cca2b57..38ccb7b 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -44,34 +44,6 @@ class DebugReportContent(Resource): raise internal_redirect(self.info['file'])
-class Templates(Collection): - def __init__(self, model): - super(Templates, self).__init__(model) - self.resource = Template - - -class Template(Resource): - def __init__(self, model, ident): - super(Template, self).__init__(model, ident) - self.update_params = ["name", "folder", "icon", "os_distro", - "storagepool", "os_version", "cpus", - "memory", "cdrom", "disks"] - self.uri_fmt = "/templates/%s" - - @property - def data(self): - return {'name': self.ident, - 'icon': self.info['icon'], - 'os_distro': self.info['os_distro'], - 'os_version': self.info['os_version'], - 'cpus': self.info['cpus'], - 'memory': self.info['memory'], - 'cdrom': self.info['cdrom'], - 'disks': self.info['disks'], - 'storagepool': self.info['storagepool'], - 'folder': self.info.get('folder', [])} - - class Interfaces(Collection): def __init__(self, model): super(Interfaces, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 99185eb..cd4a11f 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -31,6 +31,7 @@ from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource +from kimchi.control.templates import Templates from kimchi.control.vms import VMs from kimchi.exception import OperationFailed
@@ -50,7 +51,7 @@ class Root(Resource):
Resource.__init__(self, model) self.vms = VMs(model) - self.templates = controller.Templates(model) + self.templates = Templates(model) self.storagepools = controller.StoragePools(model) self.interfaces = controller.Interfaces(model) self.networks = controller.Networks(model)

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Templates(Collection) and Template(Resource) were moved to a new - control/templates.py That way we can easily know where template resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/templates.py | 52 +++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 28 --------------------- src/kimchi/root.py | 3 ++- 3 files changed, 54 insertions(+), 29 deletions(-) create mode 100644 src/kimchi/control/templates.py
diff --git a/src/kimchi/control/templates.py b/src/kimchi/control/templates.py new file mode 100644 index 0000000..30875cd --- /dev/null +++ b/src/kimchi/control/templates.py @@ -0,0 +1,52 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# 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 + +from kimchi.control.base import Collection, Resource + + +class Templates(Collection): + def __init__(self, model): + super(Templates, self).__init__(model) + self.resource = Template + + +class Template(Resource): + def __init__(self, model, ident): + super(Template, self).__init__(model, ident) + self.update_params = ["name", "folder", "icon", "os_distro", + "storagepool", "os_version", "cpus", + "memory", "cdrom", "disks"] + self.uri_fmt = "/templates/%s" + + @property + def data(self): + return {'name': self.ident, + 'icon': self.info['icon'], + 'os_distro': self.info['os_distro'], + 'os_version': self.info['os_version'], + 'cpus': self.info['cpus'], + 'memory': self.info['memory'], + 'cdrom': self.info['cdrom'], + 'disks': self.info['disks'], + 'storagepool': self.info['storagepool'], + 'folder': self.info.get('folder', [])} diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index cca2b57..38ccb7b 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -44,34 +44,6 @@ class DebugReportContent(Resource): raise internal_redirect(self.info['file'])
-class Templates(Collection): - def __init__(self, model): - super(Templates, self).__init__(model) - self.resource = Template - - -class Template(Resource): - def __init__(self, model, ident): - super(Template, self).__init__(model, ident) - self.update_params = ["name", "folder", "icon", "os_distro", - "storagepool", "os_version", "cpus", - "memory", "cdrom", "disks"] - self.uri_fmt = "/templates/%s" - - @property - def data(self): - return {'name': self.ident, - 'icon': self.info['icon'], - 'os_distro': self.info['os_distro'], - 'os_version': self.info['os_version'], - 'cpus': self.info['cpus'], - 'memory': self.info['memory'], - 'cdrom': self.info['cdrom'], - 'disks': self.info['disks'], - 'storagepool': self.info['storagepool'], - 'folder': self.info.get('folder', [])} - - class Interfaces(Collection): def __init__(self, model): super(Interfaces, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 99185eb..cd4a11f 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -31,6 +31,7 @@ from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource +from kimchi.control.templates import Templates from kimchi.control.vms import VMs from kimchi.exception import OperationFailed
@@ -50,7 +51,7 @@ class Root(Resource):
Resource.__init__(self, model) self.vms = VMs(model) - self.templates = controller.Templates(model) + self.templates = Templates(model) self.storagepools = controller.StoragePools(model) self.interfaces = controller.Interfaces(model) self.networks = controller.Networks(model)

From: Aline Manera <alinefm@br.ibm.com> DebugReports(Collection), DebugReport(Resource) and DebugReportContent(Resource) were moved to a new - control/debugreports.py That way we can easily know where debug report resource is implemented. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/debugreports.py | 52 ++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 28 ------------------- src/kimchi/root.py | 3 ++- 3 files changed, 54 insertions(+), 29 deletions(-) create mode 100644 src/kimchi/control/debugreports.py diff --git a/src/kimchi/control/debugreports.py b/src/kimchi/control/debugreports.py new file mode 100644 index 0000000..a55ba38 --- /dev/null +++ b/src/kimchi/control/debugreports.py @@ -0,0 +1,52 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Shu Ming <shuming@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 + +from kimchi.control.base import AsyncCollection, Resource +from kimchi.control.utils import internal_redirect + + +class DebugReports(AsyncCollection): + def __init__(self, model): + super(DebugReports, self).__init__(model) + self.resource = DebugReport + + +class DebugReport(Resource): + def __init__(self, model, ident): + super(DebugReport, self).__init__(model, ident) + self.content = DebugReportContent(model, ident) + + @property + def data(self): + return {'name': self.ident, + 'file': self.info['file'], + 'time': self.info['ctime']} + + +class DebugReportContent(Resource): + def __init__(self, model, ident): + super(DebugReportContent, self).__init__(model, ident) + + def get(self): + self.lookup() + raise internal_redirect(self.info['file']) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 38ccb7b..a856efd 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -35,15 +35,6 @@ from kimchi.exception import NotFoundError, OperationFailed from kimchi.model import ISO_POOL_NAME -class DebugReportContent(Resource): - def __init__(self, model, ident): - super(DebugReportContent, self).__init__(model, ident) - - def get(self): - self.lookup() - raise internal_redirect(self.info['file']) - - class Interfaces(Collection): def __init__(self, model): super(Interfaces, self).__init__(model) @@ -244,25 +235,6 @@ class Tasks(Collection): self.resource = Task -class DebugReports(AsyncCollection): - def __init__(self, model): - super(DebugReports, self).__init__(model) - self.resource = DebugReport - - -class DebugReport(Resource): - def __init__(self, model, ident): - super(DebugReport, self).__init__(model, ident) - self.ident = ident - self.content = DebugReportContent(model, ident) - - @property - def data(self): - return {'name': self.ident, - 'file': self.info['file'], - 'time': self.info['ctime']} - - class Config(Resource): def __init__(self, model, id=None): super(Config, self).__init__(model, id) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index cd4a11f..d2aeb9f 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -31,6 +31,7 @@ from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource +from kimchi.control.debugreports import DebugReports from kimchi.control.templates import Templates from kimchi.control.vms import VMs from kimchi.exception import OperationFailed @@ -58,7 +59,7 @@ class Root(Resource): self.tasks = controller.Tasks(model) self.config = controller.Config(model) self.host = controller.Host(model) - self.debugreports = controller.DebugReports(model) + self.debugreports = DebugReports(model) self.plugins = controller.Plugins(model) self.api_schema = json.load(open(get_api_schema_file())) -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
DebugReports(Collection), DebugReport(Resource) and DebugReportContent(Resource) were moved to a new - control/debugreports.py That way we can easily know where debug report resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/debugreports.py | 52 ++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 28 ------------------- src/kimchi/root.py | 3 ++- 3 files changed, 54 insertions(+), 29 deletions(-) create mode 100644 src/kimchi/control/debugreports.py
diff --git a/src/kimchi/control/debugreports.py b/src/kimchi/control/debugreports.py new file mode 100644 index 0000000..a55ba38 --- /dev/null +++ b/src/kimchi/control/debugreports.py @@ -0,0 +1,52 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Shu Ming <shuming@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 + +from kimchi.control.base import AsyncCollection, Resource +from kimchi.control.utils import internal_redirect + + +class DebugReports(AsyncCollection): + def __init__(self, model): + super(DebugReports, self).__init__(model) + self.resource = DebugReport + + +class DebugReport(Resource): + def __init__(self, model, ident): + super(DebugReport, self).__init__(model, ident) + self.content = DebugReportContent(model, ident) + + @property + def data(self): + return {'name': self.ident, + 'file': self.info['file'], + 'time': self.info['ctime']} + + +class DebugReportContent(Resource): + def __init__(self, model, ident): + super(DebugReportContent, self).__init__(model, ident) + + def get(self): + self.lookup() + raise internal_redirect(self.info['file']) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 38ccb7b..a856efd 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -35,15 +35,6 @@ from kimchi.exception import NotFoundError, OperationFailed from kimchi.model import ISO_POOL_NAME
-class DebugReportContent(Resource): - def __init__(self, model, ident): - super(DebugReportContent, self).__init__(model, ident) - - def get(self): - self.lookup() - raise internal_redirect(self.info['file']) - - class Interfaces(Collection): def __init__(self, model): super(Interfaces, self).__init__(model) @@ -244,25 +235,6 @@ class Tasks(Collection): self.resource = Task
-class DebugReports(AsyncCollection): - def __init__(self, model): - super(DebugReports, self).__init__(model) - self.resource = DebugReport - - -class DebugReport(Resource): - def __init__(self, model, ident): - super(DebugReport, self).__init__(model, ident) - self.ident = ident - self.content = DebugReportContent(model, ident) - - @property - def data(self): - return {'name': self.ident, - 'file': self.info['file'], - 'time': self.info['ctime']} - - class Config(Resource): def __init__(self, model, id=None): super(Config, self).__init__(model, id) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index cd4a11f..d2aeb9f 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -31,6 +31,7 @@ from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource +from kimchi.control.debugreports import DebugReports from kimchi.control.templates import Templates from kimchi.control.vms import VMs from kimchi.exception import OperationFailed @@ -58,7 +59,7 @@ class Root(Resource): self.tasks = controller.Tasks(model) self.config = controller.Config(model) self.host = controller.Host(model) - self.debugreports = controller.DebugReports(model) + self.debugreports = DebugReports(model) self.plugins = controller.Plugins(model) self.api_schema = json.load(open(get_api_schema_file()))

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
DebugReports(Collection), DebugReport(Resource) and DebugReportContent(Resource) were moved to a new - control/debugreports.py That way we can easily know where debug report resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/debugreports.py | 52 ++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 28 ------------------- src/kimchi/root.py | 3 ++- 3 files changed, 54 insertions(+), 29 deletions(-) create mode 100644 src/kimchi/control/debugreports.py
diff --git a/src/kimchi/control/debugreports.py b/src/kimchi/control/debugreports.py new file mode 100644 index 0000000..a55ba38 --- /dev/null +++ b/src/kimchi/control/debugreports.py @@ -0,0 +1,52 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Shu Ming <shuming@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 + +from kimchi.control.base import AsyncCollection, Resource +from kimchi.control.utils import internal_redirect + + +class DebugReports(AsyncCollection): + def __init__(self, model): + super(DebugReports, self).__init__(model) + self.resource = DebugReport + + +class DebugReport(Resource): + def __init__(self, model, ident): + super(DebugReport, self).__init__(model, ident) + self.content = DebugReportContent(model, ident) + + @property + def data(self): + return {'name': self.ident, + 'file': self.info['file'], + 'time': self.info['ctime']} + + +class DebugReportContent(Resource): + def __init__(self, model, ident): + super(DebugReportContent, self).__init__(model, ident) + + def get(self): + self.lookup() + raise internal_redirect(self.info['file']) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 38ccb7b..a856efd 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -35,15 +35,6 @@ from kimchi.exception import NotFoundError, OperationFailed from kimchi.model import ISO_POOL_NAME
-class DebugReportContent(Resource): - def __init__(self, model, ident): - super(DebugReportContent, self).__init__(model, ident) - - def get(self): - self.lookup() - raise internal_redirect(self.info['file']) - - class Interfaces(Collection): def __init__(self, model): super(Interfaces, self).__init__(model) @@ -244,25 +235,6 @@ class Tasks(Collection): self.resource = Task
-class DebugReports(AsyncCollection): - def __init__(self, model): - super(DebugReports, self).__init__(model) - self.resource = DebugReport - - -class DebugReport(Resource): - def __init__(self, model, ident): - super(DebugReport, self).__init__(model, ident) - self.ident = ident - self.content = DebugReportContent(model, ident) - - @property - def data(self): - return {'name': self.ident, - 'file': self.info['file'], - 'time': self.info['ctime']} - - class Config(Resource): def __init__(self, model, id=None): super(Config, self).__init__(model, id) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index cd4a11f..d2aeb9f 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -31,6 +31,7 @@ from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource +from kimchi.control.debugreports import DebugReports from kimchi.control.templates import Templates from kimchi.control.vms import VMs from kimchi.exception import OperationFailed @@ -58,7 +59,7 @@ class Root(Resource): self.tasks = controller.Tasks(model) self.config = controller.Config(model) self.host = controller.Host(model) - self.debugreports = controller.DebugReports(model) + self.debugreports = DebugReports(model) self.plugins = controller.Plugins(model) self.api_schema = json.load(open(get_api_schema_file()))

From: Aline Manera <alinefm@br.ibm.com> StoragePools(Collection), StoragePool(Resource) and IsoPool(Resource) were moved to a new - control/storagepools.py That way we can easily know where storage pool resource is implemented. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/storagepools.py | 127 ++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 89 ------------------------- src/kimchi/root.py | 3 +- 3 files changed, 129 insertions(+), 90 deletions(-) create mode 100644 src/kimchi/control/storagepools.py diff --git a/src/kimchi/control/storagepools.py b/src/kimchi/control/storagepools.py new file mode 100644 index 0000000..466b4b6 --- /dev/null +++ b/src/kimchi/control/storagepools.py @@ -0,0 +1,127 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Bing Bu Cao <mars@linux.vnet.ibm.com> +# Royce Lv <lvroyce@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 + + +from kimchi.control.base import Collection, Resource +from kimchi.control.storagevolumes import IsoVolumes, StorageVolumes +from kimchi.control.utils import get_class_name, model_fn, parse_request +from kimchi.model import ISO_POOL_NAME + + +class StoragePools(Collection): + def __init__(self, model): + super(StoragePools, self).__init__(model) + self.resource = StoragePool + isos = IsoPool(model) + isos.exposed = True + setattr(self, ISO_POOL_NAME, isos) + + def create(self, *args): + try: + create = getattr(self.model, model_fn(self, 'create')) + except AttributeError: + error = 'Create is not allowed for %s' % get_class_name(self) + raise cherrypy.HTTPError(405, error) + + params = parse_request() + args = self.model_args + [params] + name = create(*args) + args = self.resource_args + [name] + res = self.resource(self.model, *args) + resp = res.get() + + if 'task_id' in res.data: + cherrypy.response.status = 202 + else: + cherrypy.response.status = 201 + + return resp + + def _get_resources(self): + try: + res_list = super(StoragePools, self)._get_resources() + # Append reserved pools + isos = getattr(self, ISO_POOL_NAME) + isos.lookup() + res_list.append(isos) + except AttributeError: + pass + + return res_list + + +class StoragePool(Resource): + def __init__(self, model, ident): + super(StoragePool, self).__init__(model, ident) + self.update_params = ["autostart"] + self.uri_fmt = "/storagepools/%s" + self.activate = self.generate_action_handler('activate') + self.deactivate = self.generate_action_handler('deactivate') + + @property + def data(self): + res = {'name': self.ident, + 'state': self.info['state'], + 'capacity': self.info['capacity'], + 'allocated': self.info['allocated'], + 'available': self.info['available'], + 'path': self.info['path'], + 'source': self.info['source'], + 'type': self.info['type'], + 'nr_volumes': self.info['nr_volumes'], + 'autostart': self.info['autostart']} + + val = self.info.get('task_id') + if val: + res['task_id'] = val + + return res + + def _cp_dispatch(self, vpath): + if vpath: + subcollection = vpath.pop(0) + if subcollection == 'storagevolumes': + # incoming text, from URL, is not unicode, need decode + return StorageVolumes(self.model, self.ident.decode("utf-8")) + + +class IsoPool(Resource): + def __init__(self, model): + super(IsoPool, self).__init__(model, ISO_POOL_NAME) + + @property + def data(self): + return {'name': self.ident, + 'state': self.info['state'], + 'type': self.info['type']} + + def _cp_dispatch(self, vpath): + if vpath: + subcollection = vpath.pop(0) + if subcollection == 'storagevolumes': + # incoming text, from URL, is not unicode, need decode + return IsoVolumes(self.model, self.ident.decode("utf-8")) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index a856efd..535f816 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -129,95 +129,6 @@ class StorageVolumes(Collection): self.model_args = [self.pool, ] -class StoragePool(Resource): - def __init__(self, model, ident): - super(StoragePool, self).__init__(model, ident) - self.update_params = ["autostart"] - self.uri_fmt = "/storagepools/%s" - self.activate = self.generate_action_handler('activate') - self.deactivate = self.generate_action_handler('deactivate') - - @property - def data(self): - res = {'name': self.ident, - 'state': self.info['state'], - 'capacity': self.info['capacity'], - 'allocated': self.info['allocated'], - 'available': self.info['available'], - 'path': self.info['path'], - 'source': self.info['source'], - 'type': self.info['type'], - 'nr_volumes': self.info['nr_volumes'], - 'autostart': self.info['autostart']} - val = self.info.get('task_id') - if val: - res['task_id'] = val - return res - - - def _cp_dispatch(self, vpath): - if vpath: - subcollection = vpath.pop(0) - if subcollection == 'storagevolumes': - # incoming text, from URL, is not unicode, need decode - return StorageVolumes(self.model, self.ident.decode("utf-8")) - - -class IsoPool(Resource): - def __init__(self, model): - super(IsoPool, self).__init__(model, ISO_POOL_NAME) - - @property - def data(self): - return {'name': self.ident, - 'state': self.info['state'], - 'type': self.info['type']} - - def _cp_dispatch(self, vpath): - if vpath: - subcollection = vpath.pop(0) - if subcollection == 'storagevolumes': - # incoming text, from URL, is not unicode, need decode - return IsoVolumes(self.model, self.ident.decode("utf-8")) - - -class StoragePools(Collection): - def __init__(self, model): - super(StoragePools, self).__init__(model) - self.resource = StoragePool - isos = IsoPool(model) - isos.exposed = True - setattr(self, ISO_POOL_NAME, isos) - - def create(self, *args): - try: - create = getattr(self.model, model_fn(self, 'create')) - except AttributeError: - raise cherrypy.HTTPError(405, - 'Create is not allowed for %s' % get_class_name(self)) - params = parse_request() - args = self.model_args + [params] - name = create(*args) - args = self.resource_args + [name] - res = self.resource(self.model, *args) - resp = res.get() - if 'task_id' in res.data: - cherrypy.response.status = 202 - else: - cherrypy.response.status = 201 - return resp - - def _get_resources(self): - try: - res_list = super(StoragePools, self)._get_resources() - # Append reserved pools - isos = getattr(self, ISO_POOL_NAME) - isos.lookup() - res_list.append(isos) - except AttributeError: - pass - return res_list - class Task(Resource): def __init__(self, model, id): super(Task, self).__init__(model, id) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index d2aeb9f..6e41190 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -32,6 +32,7 @@ from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource from kimchi.control.debugreports import DebugReports +from kimchi.control.storagepools import StoragePools from kimchi.control.templates import Templates from kimchi.control.vms import VMs from kimchi.exception import OperationFailed @@ -53,7 +54,7 @@ class Root(Resource): Resource.__init__(self, model) self.vms = VMs(model) self.templates = Templates(model) - self.storagepools = controller.StoragePools(model) + self.storagepools = StoragePools(model) self.interfaces = controller.Interfaces(model) self.networks = controller.Networks(model) self.tasks = controller.Tasks(model) -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
StoragePools(Collection), StoragePool(Resource) and IsoPool(Resource) were moved to a new - control/storagepools.py That way we can easily know where storage pool resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/storagepools.py | 127 ++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 89 ------------------------- src/kimchi/root.py | 3 +- 3 files changed, 129 insertions(+), 90 deletions(-) create mode 100644 src/kimchi/control/storagepools.py
diff --git a/src/kimchi/control/storagepools.py b/src/kimchi/control/storagepools.py new file mode 100644 index 0000000..466b4b6 --- /dev/null +++ b/src/kimchi/control/storagepools.py @@ -0,0 +1,127 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Bing Bu Cao <mars@linux.vnet.ibm.com> +# Royce Lv <lvroyce@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 + + +from kimchi.control.base import Collection, Resource +from kimchi.control.storagevolumes import IsoVolumes, StorageVolumes +from kimchi.control.utils import get_class_name, model_fn, parse_request +from kimchi.model import ISO_POOL_NAME + + +class StoragePools(Collection): + def __init__(self, model): + super(StoragePools, self).__init__(model) + self.resource = StoragePool + isos = IsoPool(model) + isos.exposed = True + setattr(self, ISO_POOL_NAME, isos) + + def create(self, *args): + try: + create = getattr(self.model, model_fn(self, 'create')) + except AttributeError: + error = 'Create is not allowed for %s' % get_class_name(self) + raise cherrypy.HTTPError(405, error) + + params = parse_request() + args = self.model_args + [params] + name = create(*args) + args = self.resource_args + [name] + res = self.resource(self.model, *args) + resp = res.get() + + if 'task_id' in res.data: + cherrypy.response.status = 202 + else: + cherrypy.response.status = 201 + + return resp + + def _get_resources(self): + try: + res_list = super(StoragePools, self)._get_resources() + # Append reserved pools + isos = getattr(self, ISO_POOL_NAME) + isos.lookup() + res_list.append(isos) + except AttributeError: + pass + + return res_list + + +class StoragePool(Resource): + def __init__(self, model, ident): + super(StoragePool, self).__init__(model, ident) + self.update_params = ["autostart"] + self.uri_fmt = "/storagepools/%s" + self.activate = self.generate_action_handler('activate') + self.deactivate = self.generate_action_handler('deactivate') + + @property + def data(self): + res = {'name': self.ident, + 'state': self.info['state'], + 'capacity': self.info['capacity'], + 'allocated': self.info['allocated'], + 'available': self.info['available'], + 'path': self.info['path'], + 'source': self.info['source'], + 'type': self.info['type'], + 'nr_volumes': self.info['nr_volumes'], + 'autostart': self.info['autostart']} + + val = self.info.get('task_id') + if val: + res['task_id'] = val + + return res + + def _cp_dispatch(self, vpath): + if vpath: + subcollection = vpath.pop(0) + if subcollection == 'storagevolumes': + # incoming text, from URL, is not unicode, need decode + return StorageVolumes(self.model, self.ident.decode("utf-8")) + + +class IsoPool(Resource): + def __init__(self, model): + super(IsoPool, self).__init__(model, ISO_POOL_NAME) + + @property + def data(self): + return {'name': self.ident, + 'state': self.info['state'], + 'type': self.info['type']} + + def _cp_dispatch(self, vpath): + if vpath: + subcollection = vpath.pop(0) + if subcollection == 'storagevolumes': + # incoming text, from URL, is not unicode, need decode + return IsoVolumes(self.model, self.ident.decode("utf-8")) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index a856efd..535f816 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -129,95 +129,6 @@ class StorageVolumes(Collection): self.model_args = [self.pool, ]
-class StoragePool(Resource): - def __init__(self, model, ident): - super(StoragePool, self).__init__(model, ident) - self.update_params = ["autostart"] - self.uri_fmt = "/storagepools/%s" - self.activate = self.generate_action_handler('activate') - self.deactivate = self.generate_action_handler('deactivate') - - @property - def data(self): - res = {'name': self.ident, - 'state': self.info['state'], - 'capacity': self.info['capacity'], - 'allocated': self.info['allocated'], - 'available': self.info['available'], - 'path': self.info['path'], - 'source': self.info['source'], - 'type': self.info['type'], - 'nr_volumes': self.info['nr_volumes'], - 'autostart': self.info['autostart']} - val = self.info.get('task_id') - if val: - res['task_id'] = val - return res - - - def _cp_dispatch(self, vpath): - if vpath: - subcollection = vpath.pop(0) - if subcollection == 'storagevolumes': - # incoming text, from URL, is not unicode, need decode - return StorageVolumes(self.model, self.ident.decode("utf-8")) - - -class IsoPool(Resource): - def __init__(self, model): - super(IsoPool, self).__init__(model, ISO_POOL_NAME) - - @property - def data(self): - return {'name': self.ident, - 'state': self.info['state'], - 'type': self.info['type']} - - def _cp_dispatch(self, vpath): - if vpath: - subcollection = vpath.pop(0) - if subcollection == 'storagevolumes': - # incoming text, from URL, is not unicode, need decode - return IsoVolumes(self.model, self.ident.decode("utf-8")) - - -class StoragePools(Collection): - def __init__(self, model): - super(StoragePools, self).__init__(model) - self.resource = StoragePool - isos = IsoPool(model) - isos.exposed = True - setattr(self, ISO_POOL_NAME, isos) - - def create(self, *args): - try: - create = getattr(self.model, model_fn(self, 'create')) - except AttributeError: - raise cherrypy.HTTPError(405, - 'Create is not allowed for %s' % get_class_name(self)) - params = parse_request() - args = self.model_args + [params] - name = create(*args) - args = self.resource_args + [name] - res = self.resource(self.model, *args) - resp = res.get() - if 'task_id' in res.data: - cherrypy.response.status = 202 - else: - cherrypy.response.status = 201 - return resp - - def _get_resources(self): - try: - res_list = super(StoragePools, self)._get_resources() - # Append reserved pools - isos = getattr(self, ISO_POOL_NAME) - isos.lookup() - res_list.append(isos) - except AttributeError: - pass - return res_list - class Task(Resource): def __init__(self, model, id): super(Task, self).__init__(model, id) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index d2aeb9f..6e41190 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -32,6 +32,7 @@ from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource from kimchi.control.debugreports import DebugReports +from kimchi.control.storagepools import StoragePools from kimchi.control.templates import Templates from kimchi.control.vms import VMs from kimchi.exception import OperationFailed @@ -53,7 +54,7 @@ class Root(Resource): Resource.__init__(self, model) self.vms = VMs(model) self.templates = Templates(model) - self.storagepools = controller.StoragePools(model) + self.storagepools = StoragePools(model) self.interfaces = controller.Interfaces(model) self.networks = controller.Networks(model) self.tasks = controller.Tasks(model)

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
StoragePools(Collection), StoragePool(Resource) and IsoPool(Resource) were moved to a new - control/storagepools.py That way we can easily know where storage pool resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/storagepools.py | 127 ++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 89 ------------------------- src/kimchi/root.py | 3 +- 3 files changed, 129 insertions(+), 90 deletions(-) create mode 100644 src/kimchi/control/storagepools.py
diff --git a/src/kimchi/control/storagepools.py b/src/kimchi/control/storagepools.py new file mode 100644 index 0000000..466b4b6 --- /dev/null +++ b/src/kimchi/control/storagepools.py @@ -0,0 +1,127 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Bing Bu Cao <mars@linux.vnet.ibm.com> +# Royce Lv <lvroyce@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 + + +from kimchi.control.base import Collection, Resource +from kimchi.control.storagevolumes import IsoVolumes, StorageVolumes +from kimchi.control.utils import get_class_name, model_fn, parse_request +from kimchi.model import ISO_POOL_NAME + + +class StoragePools(Collection): + def __init__(self, model): + super(StoragePools, self).__init__(model) + self.resource = StoragePool + isos = IsoPool(model) + isos.exposed = True + setattr(self, ISO_POOL_NAME, isos) + + def create(self, *args): + try: + create = getattr(self.model, model_fn(self, 'create')) + except AttributeError: + error = 'Create is not allowed for %s' % get_class_name(self) + raise cherrypy.HTTPError(405, error) + + params = parse_request() + args = self.model_args + [params] + name = create(*args) + args = self.resource_args + [name] + res = self.resource(self.model, *args) + resp = res.get() + + if 'task_id' in res.data: + cherrypy.response.status = 202 + else: + cherrypy.response.status = 201 + + return resp + + def _get_resources(self): + try: + res_list = super(StoragePools, self)._get_resources() + # Append reserved pools + isos = getattr(self, ISO_POOL_NAME) + isos.lookup() + res_list.append(isos) + except AttributeError: + pass + + return res_list + + +class StoragePool(Resource): + def __init__(self, model, ident): + super(StoragePool, self).__init__(model, ident) + self.update_params = ["autostart"] + self.uri_fmt = "/storagepools/%s" + self.activate = self.generate_action_handler('activate') + self.deactivate = self.generate_action_handler('deactivate') + + @property + def data(self): + res = {'name': self.ident, + 'state': self.info['state'], + 'capacity': self.info['capacity'], + 'allocated': self.info['allocated'], + 'available': self.info['available'], + 'path': self.info['path'], + 'source': self.info['source'], + 'type': self.info['type'], + 'nr_volumes': self.info['nr_volumes'], + 'autostart': self.info['autostart']} + + val = self.info.get('task_id') + if val: + res['task_id'] = val + + return res + + def _cp_dispatch(self, vpath): + if vpath: + subcollection = vpath.pop(0) + if subcollection == 'storagevolumes': + # incoming text, from URL, is not unicode, need decode + return StorageVolumes(self.model, self.ident.decode("utf-8")) + + +class IsoPool(Resource): + def __init__(self, model): + super(IsoPool, self).__init__(model, ISO_POOL_NAME) + + @property + def data(self): + return {'name': self.ident, + 'state': self.info['state'], + 'type': self.info['type']} + + def _cp_dispatch(self, vpath): + if vpath: + subcollection = vpath.pop(0) + if subcollection == 'storagevolumes': + # incoming text, from URL, is not unicode, need decode + return IsoVolumes(self.model, self.ident.decode("utf-8")) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index a856efd..535f816 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -129,95 +129,6 @@ class StorageVolumes(Collection): self.model_args = [self.pool, ]
-class StoragePool(Resource): - def __init__(self, model, ident): - super(StoragePool, self).__init__(model, ident) - self.update_params = ["autostart"] - self.uri_fmt = "/storagepools/%s" - self.activate = self.generate_action_handler('activate') - self.deactivate = self.generate_action_handler('deactivate') - - @property - def data(self): - res = {'name': self.ident, - 'state': self.info['state'], - 'capacity': self.info['capacity'], - 'allocated': self.info['allocated'], - 'available': self.info['available'], - 'path': self.info['path'], - 'source': self.info['source'], - 'type': self.info['type'], - 'nr_volumes': self.info['nr_volumes'], - 'autostart': self.info['autostart']} - val = self.info.get('task_id') - if val: - res['task_id'] = val - return res - - - def _cp_dispatch(self, vpath): - if vpath: - subcollection = vpath.pop(0) - if subcollection == 'storagevolumes': - # incoming text, from URL, is not unicode, need decode - return StorageVolumes(self.model, self.ident.decode("utf-8")) - - -class IsoPool(Resource): - def __init__(self, model): - super(IsoPool, self).__init__(model, ISO_POOL_NAME) - - @property - def data(self): - return {'name': self.ident, - 'state': self.info['state'], - 'type': self.info['type']} - - def _cp_dispatch(self, vpath): - if vpath: - subcollection = vpath.pop(0) - if subcollection == 'storagevolumes': - # incoming text, from URL, is not unicode, need decode - return IsoVolumes(self.model, self.ident.decode("utf-8")) - - -class StoragePools(Collection): - def __init__(self, model): - super(StoragePools, self).__init__(model) - self.resource = StoragePool - isos = IsoPool(model) - isos.exposed = True - setattr(self, ISO_POOL_NAME, isos) - - def create(self, *args): - try: - create = getattr(self.model, model_fn(self, 'create')) - except AttributeError: - raise cherrypy.HTTPError(405, - 'Create is not allowed for %s' % get_class_name(self)) - params = parse_request() - args = self.model_args + [params] - name = create(*args) - args = self.resource_args + [name] - res = self.resource(self.model, *args) - resp = res.get() - if 'task_id' in res.data: - cherrypy.response.status = 202 - else: - cherrypy.response.status = 201 - return resp - - def _get_resources(self): - try: - res_list = super(StoragePools, self)._get_resources() - # Append reserved pools - isos = getattr(self, ISO_POOL_NAME) - isos.lookup() - res_list.append(isos) - except AttributeError: - pass - return res_list - class Task(Resource): def __init__(self, model, id): super(Task, self).__init__(model, id) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index d2aeb9f..6e41190 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -32,6 +32,7 @@ from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource from kimchi.control.debugreports import DebugReports +from kimchi.control.storagepools import StoragePools from kimchi.control.templates import Templates from kimchi.control.vms import VMs from kimchi.exception import OperationFailed @@ -53,7 +54,7 @@ class Root(Resource): Resource.__init__(self, model) self.vms = VMs(model) self.templates = Templates(model) - self.storagepools = controller.StoragePools(model) + self.storagepools = StoragePools(model) self.interfaces = controller.Interfaces(model) self.networks = controller.Networks(model) self.tasks = controller.Tasks(model)

From: Aline Manera <alinefm@br.ibm.com> StorageVolumes(Collection), StorageVolume(Resource) and IsoVolumes(Collection) were moved to a new - control/storagevolumes.py That way we can easily know where storage volume resource is implemented. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/storagevolumes.py | 81 ++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 50 --------------------- 2 files changed, 81 insertions(+), 50 deletions(-) create mode 100644 src/kimchi/control/storagevolumes.py diff --git a/src/kimchi/control/storagevolumes.py b/src/kimchi/control/storagevolumes.py new file mode 100644 index 0000000..d541807 --- /dev/null +++ b/src/kimchi/control/storagevolumes.py @@ -0,0 +1,81 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Bing Bu Cao <mars@linux.vnet.ibm.com> +# Royce Lv <lvroyce@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 kimchi.template +from kimchi.control.base import Collection, Resource +from kimchi.control.utils import get_class_name, model_fn + + +class StorageVolumes(Collection): + def __init__(self, model, pool): + super(StorageVolumes, self).__init__(model) + self.resource = StorageVolume + self.pool = pool + self.resource_args = [self.pool, ] + self.model_args = [self.pool, ] + + +class StorageVolume(Resource): + def __init__(self, model, pool, ident): + super(StorageVolume, self).__init__(model, ident) + self.pool = pool + self.ident = ident + self.info = {} + self.model_args = [self.pool, self.ident] + self.uri_fmt = '/storagepools/%s/storagevolumes/%s' + self.resize = self.generate_action_handler('resize', ['size']) + self.wipe = self.generate_action_handler('wipe') + + @property + def data(self): + res = {'name': self.ident, + 'type': self.info['type'], + 'capacity': self.info['capacity'], + 'allocation': self.info['allocation'], + 'path': self.info['path'], + 'format': self.info['format']} + + for key in ('os_version', 'os_distro', 'bootable'): + val = self.info.get(key) + if val: + res[key] = val + + return res + + +class IsoVolumes(Collection): + def __init__(self, model, pool): + super(IsoVolumes, self).__init__(model) + self.pool = pool + + def get(self): + res_list = [] + try: + get_list = getattr(self.model, model_fn(self, 'get_list')) + res_list = get_list(*self.model_args) + except AttributeError: + pass + + return kimchi.template.render(get_class_name(self), res_list) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 535f816..b691842 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -79,56 +79,6 @@ class Network(Resource): 'state': self.info['state']} -class StorageVolume(Resource): - def __init__(self, model, pool, ident): - super(StorageVolume, self).__init__(model, ident) - self.pool = pool - self.ident = ident - self.info = {} - self.model_args = [self.pool, self.ident] - self.uri_fmt = '/storagepools/%s/storagevolumes/%s' - self.resize = self.generate_action_handler('resize', ['size']) - self.wipe = self.generate_action_handler('wipe') - - @property - def data(self): - res = {'name': self.ident, - 'type': self.info['type'], - 'capacity': self.info['capacity'], - 'allocation': self.info['allocation'], - 'path': self.info['path'], - 'format': self.info['format']} - for key in ('os_version', 'os_distro', 'bootable'): - val = self.info.get(key) - if val: - res[key] = val - return res - - -class IsoVolumes(Collection): - def __init__(self, model, pool): - super(IsoVolumes, self).__init__(model) - self.pool = pool - - def get(self): - res_list = [] - try: - get_list = getattr(self.model, model_fn(self, 'get_list')) - res_list = get_list(*self.model_args) - except AttributeError: - pass - return kimchi.template.render(get_class_name(self), res_list) - - -class StorageVolumes(Collection): - def __init__(self, model, pool): - super(StorageVolumes, self).__init__(model) - self.resource = StorageVolume - self.pool = pool - self.resource_args = [self.pool, ] - self.model_args = [self.pool, ] - - class Task(Resource): def __init__(self, model, id): super(Task, self).__init__(model, id) -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
StorageVolumes(Collection), StorageVolume(Resource) and IsoVolumes(Collection) were moved to a new - control/storagevolumes.py That way we can easily know where storage volume resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/storagevolumes.py | 81 ++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 50 --------------------- 2 files changed, 81 insertions(+), 50 deletions(-) create mode 100644 src/kimchi/control/storagevolumes.py
diff --git a/src/kimchi/control/storagevolumes.py b/src/kimchi/control/storagevolumes.py new file mode 100644 index 0000000..d541807 --- /dev/null +++ b/src/kimchi/control/storagevolumes.py @@ -0,0 +1,81 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Bing Bu Cao <mars@linux.vnet.ibm.com> +# Royce Lv <lvroyce@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 kimchi.template +from kimchi.control.base import Collection, Resource +from kimchi.control.utils import get_class_name, model_fn + + +class StorageVolumes(Collection): + def __init__(self, model, pool): + super(StorageVolumes, self).__init__(model) + self.resource = StorageVolume + self.pool = pool + self.resource_args = [self.pool, ] + self.model_args = [self.pool, ] + + +class StorageVolume(Resource): + def __init__(self, model, pool, ident): + super(StorageVolume, self).__init__(model, ident) + self.pool = pool + self.ident = ident + self.info = {} + self.model_args = [self.pool, self.ident] + self.uri_fmt = '/storagepools/%s/storagevolumes/%s' + self.resize = self.generate_action_handler('resize', ['size']) + self.wipe = self.generate_action_handler('wipe') + + @property + def data(self): + res = {'name': self.ident, + 'type': self.info['type'], + 'capacity': self.info['capacity'], + 'allocation': self.info['allocation'], + 'path': self.info['path'], + 'format': self.info['format']} + + for key in ('os_version', 'os_distro', 'bootable'): + val = self.info.get(key) + if val: + res[key] = val + + return res + + +class IsoVolumes(Collection): + def __init__(self, model, pool): + super(IsoVolumes, self).__init__(model) + self.pool = pool + + def get(self): + res_list = [] + try: + get_list = getattr(self.model, model_fn(self, 'get_list')) + res_list = get_list(*self.model_args) + except AttributeError: + pass + + return kimchi.template.render(get_class_name(self), res_list) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 535f816..b691842 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -79,56 +79,6 @@ class Network(Resource): 'state': self.info['state']}
-class StorageVolume(Resource): - def __init__(self, model, pool, ident): - super(StorageVolume, self).__init__(model, ident) - self.pool = pool - self.ident = ident - self.info = {} - self.model_args = [self.pool, self.ident] - self.uri_fmt = '/storagepools/%s/storagevolumes/%s' - self.resize = self.generate_action_handler('resize', ['size']) - self.wipe = self.generate_action_handler('wipe') - - @property - def data(self): - res = {'name': self.ident, - 'type': self.info['type'], - 'capacity': self.info['capacity'], - 'allocation': self.info['allocation'], - 'path': self.info['path'], - 'format': self.info['format']} - for key in ('os_version', 'os_distro', 'bootable'): - val = self.info.get(key) - if val: - res[key] = val - return res - - -class IsoVolumes(Collection): - def __init__(self, model, pool): - super(IsoVolumes, self).__init__(model) - self.pool = pool - - def get(self): - res_list = [] - try: - get_list = getattr(self.model, model_fn(self, 'get_list')) - res_list = get_list(*self.model_args) - except AttributeError: - pass - return kimchi.template.render(get_class_name(self), res_list) - - -class StorageVolumes(Collection): - def __init__(self, model, pool): - super(StorageVolumes, self).__init__(model) - self.resource = StorageVolume - self.pool = pool - self.resource_args = [self.pool, ] - self.model_args = [self.pool, ] - - class Task(Resource): def __init__(self, model, id): super(Task, self).__init__(model, id)

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
StorageVolumes(Collection), StorageVolume(Resource) and IsoVolumes(Collection) were moved to a new - control/storagevolumes.py That way we can easily know where storage volume resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/storagevolumes.py | 81 ++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 50 --------------------- 2 files changed, 81 insertions(+), 50 deletions(-) create mode 100644 src/kimchi/control/storagevolumes.py
diff --git a/src/kimchi/control/storagevolumes.py b/src/kimchi/control/storagevolumes.py new file mode 100644 index 0000000..d541807 --- /dev/null +++ b/src/kimchi/control/storagevolumes.py @@ -0,0 +1,81 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Bing Bu Cao <mars@linux.vnet.ibm.com> +# Royce Lv <lvroyce@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 kimchi.template +from kimchi.control.base import Collection, Resource +from kimchi.control.utils import get_class_name, model_fn + + +class StorageVolumes(Collection): + def __init__(self, model, pool): + super(StorageVolumes, self).__init__(model) + self.resource = StorageVolume + self.pool = pool + self.resource_args = [self.pool, ] + self.model_args = [self.pool, ] + + +class StorageVolume(Resource): + def __init__(self, model, pool, ident): + super(StorageVolume, self).__init__(model, ident) + self.pool = pool + self.ident = ident + self.info = {} + self.model_args = [self.pool, self.ident] + self.uri_fmt = '/storagepools/%s/storagevolumes/%s' + self.resize = self.generate_action_handler('resize', ['size']) + self.wipe = self.generate_action_handler('wipe') + + @property + def data(self): + res = {'name': self.ident, + 'type': self.info['type'], + 'capacity': self.info['capacity'], + 'allocation': self.info['allocation'], + 'path': self.info['path'], + 'format': self.info['format']} + + for key in ('os_version', 'os_distro', 'bootable'): + val = self.info.get(key) + if val: + res[key] = val + + return res + + +class IsoVolumes(Collection): + def __init__(self, model, pool): + super(IsoVolumes, self).__init__(model) + self.pool = pool + + def get(self): + res_list = [] + try: + get_list = getattr(self.model, model_fn(self, 'get_list')) + res_list = get_list(*self.model_args) + except AttributeError: + pass + + return kimchi.template.render(get_class_name(self), res_list) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 535f816..b691842 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -79,56 +79,6 @@ class Network(Resource): 'state': self.info['state']}
-class StorageVolume(Resource): - def __init__(self, model, pool, ident): - super(StorageVolume, self).__init__(model, ident) - self.pool = pool - self.ident = ident - self.info = {} - self.model_args = [self.pool, self.ident] - self.uri_fmt = '/storagepools/%s/storagevolumes/%s' - self.resize = self.generate_action_handler('resize', ['size']) - self.wipe = self.generate_action_handler('wipe') - - @property - def data(self): - res = {'name': self.ident, - 'type': self.info['type'], - 'capacity': self.info['capacity'], - 'allocation': self.info['allocation'], - 'path': self.info['path'], - 'format': self.info['format']} - for key in ('os_version', 'os_distro', 'bootable'): - val = self.info.get(key) - if val: - res[key] = val - return res - - -class IsoVolumes(Collection): - def __init__(self, model, pool): - super(IsoVolumes, self).__init__(model) - self.pool = pool - - def get(self): - res_list = [] - try: - get_list = getattr(self.model, model_fn(self, 'get_list')) - res_list = get_list(*self.model_args) - except AttributeError: - pass - return kimchi.template.render(get_class_name(self), res_list) - - -class StorageVolumes(Collection): - def __init__(self, model, pool): - super(StorageVolumes, self).__init__(model) - self.resource = StorageVolume - self.pool = pool - self.resource_args = [self.pool, ] - self.model_args = [self.pool, ] - - class Task(Resource): def __init__(self, model, id): super(Task, self).__init__(model, id)

From: Aline Manera <alinefm@br.ibm.com> Interfaces(Collection) and Interface(Resource) were moved to a new - control/interfaces.py That way we can easily know where interface resource is implemented. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/interfaces.py | 45 ++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 20 ----------------- src/kimchi/root.py | 3 ++- 3 files changed, 47 insertions(+), 21 deletions(-) create mode 100644 src/kimchi/control/interfaces.py diff --git a/src/kimchi/control/interfaces.py b/src/kimchi/control/interfaces.py new file mode 100644 index 0000000..28be26e --- /dev/null +++ b/src/kimchi/control/interfaces.py @@ -0,0 +1,45 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@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 + +from kimchi.control.base import Collection, Resource + + +class Interfaces(Collection): + def __init__(self, model): + super(Interfaces, self).__init__(model) + self.resource = Interface + + +class Interface(Resource): + def __init__(self, model, ident): + super(Interface, self).__init__(model, ident) + self.uri_fmt = "/interfaces/%s" + + @property + def data(self): + return {'name': self.ident, + 'type': self.info['type'], + 'ipaddr': self.info['ipaddr'], + 'netmask': self.info['netmask'], + 'status': self.info['status']} diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index b691842..2a888a4 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -35,26 +35,6 @@ from kimchi.exception import NotFoundError, OperationFailed from kimchi.model import ISO_POOL_NAME -class Interfaces(Collection): - def __init__(self, model): - super(Interfaces, self).__init__(model) - self.resource = Interface - - -class Interface(Resource): - def __init__(self, model, ident): - super(Interface, self).__init__(model, ident) - self.uri_fmt = "/interfaces/%s" - - @property - def data(self): - return {'name': self.ident, - 'type': self.info['type'], - 'ipaddr': self.info['ipaddr'], - 'netmask': self.info['netmask'], - 'status': self.info['status']} - - class Networks(Collection): def __init__(self, model): super(Networks, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 6e41190..982c7ea 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -32,6 +32,7 @@ from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource from kimchi.control.debugreports import DebugReports +from kimchi.control.interfaces import Interfaces from kimchi.control.storagepools import StoragePools from kimchi.control.templates import Templates from kimchi.control.vms import VMs @@ -55,7 +56,7 @@ class Root(Resource): self.vms = VMs(model) self.templates = Templates(model) self.storagepools = StoragePools(model) - self.interfaces = controller.Interfaces(model) + self.interfaces = Interfaces(model) self.networks = controller.Networks(model) self.tasks = controller.Tasks(model) self.config = controller.Config(model) -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Interfaces(Collection) and Interface(Resource) were moved to a new - control/interfaces.py That way we can easily know where interface resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/interfaces.py | 45 ++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 20 ----------------- src/kimchi/root.py | 3 ++- 3 files changed, 47 insertions(+), 21 deletions(-) create mode 100644 src/kimchi/control/interfaces.py
diff --git a/src/kimchi/control/interfaces.py b/src/kimchi/control/interfaces.py new file mode 100644 index 0000000..28be26e --- /dev/null +++ b/src/kimchi/control/interfaces.py @@ -0,0 +1,45 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@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 + +from kimchi.control.base import Collection, Resource + + +class Interfaces(Collection): + def __init__(self, model): + super(Interfaces, self).__init__(model) + self.resource = Interface + + +class Interface(Resource): + def __init__(self, model, ident): + super(Interface, self).__init__(model, ident) + self.uri_fmt = "/interfaces/%s" + + @property + def data(self): + return {'name': self.ident, + 'type': self.info['type'], + 'ipaddr': self.info['ipaddr'], + 'netmask': self.info['netmask'], + 'status': self.info['status']} diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index b691842..2a888a4 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -35,26 +35,6 @@ from kimchi.exception import NotFoundError, OperationFailed from kimchi.model import ISO_POOL_NAME
-class Interfaces(Collection): - def __init__(self, model): - super(Interfaces, self).__init__(model) - self.resource = Interface - - -class Interface(Resource): - def __init__(self, model, ident): - super(Interface, self).__init__(model, ident) - self.uri_fmt = "/interfaces/%s" - - @property - def data(self): - return {'name': self.ident, - 'type': self.info['type'], - 'ipaddr': self.info['ipaddr'], - 'netmask': self.info['netmask'], - 'status': self.info['status']} - - class Networks(Collection): def __init__(self, model): super(Networks, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 6e41190..982c7ea 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -32,6 +32,7 @@ from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource from kimchi.control.debugreports import DebugReports +from kimchi.control.interfaces import Interfaces from kimchi.control.storagepools import StoragePools from kimchi.control.templates import Templates from kimchi.control.vms import VMs @@ -55,7 +56,7 @@ class Root(Resource): self.vms = VMs(model) self.templates = Templates(model) self.storagepools = StoragePools(model) - self.interfaces = controller.Interfaces(model) + self.interfaces = Interfaces(model) self.networks = controller.Networks(model) self.tasks = controller.Tasks(model) self.config = controller.Config(model)

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Interfaces(Collection) and Interface(Resource) were moved to a new - control/interfaces.py That way we can easily know where interface resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/interfaces.py | 45 ++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 20 ----------------- src/kimchi/root.py | 3 ++- 3 files changed, 47 insertions(+), 21 deletions(-) create mode 100644 src/kimchi/control/interfaces.py
diff --git a/src/kimchi/control/interfaces.py b/src/kimchi/control/interfaces.py new file mode 100644 index 0000000..28be26e --- /dev/null +++ b/src/kimchi/control/interfaces.py @@ -0,0 +1,45 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@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 + +from kimchi.control.base import Collection, Resource + + +class Interfaces(Collection): + def __init__(self, model): + super(Interfaces, self).__init__(model) + self.resource = Interface + + +class Interface(Resource): + def __init__(self, model, ident): + super(Interface, self).__init__(model, ident) + self.uri_fmt = "/interfaces/%s" + + @property + def data(self): + return {'name': self.ident, + 'type': self.info['type'], + 'ipaddr': self.info['ipaddr'], + 'netmask': self.info['netmask'], + 'status': self.info['status']} diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index b691842..2a888a4 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -35,26 +35,6 @@ from kimchi.exception import NotFoundError, OperationFailed from kimchi.model import ISO_POOL_NAME
-class Interfaces(Collection): - def __init__(self, model): - super(Interfaces, self).__init__(model) - self.resource = Interface - - -class Interface(Resource): - def __init__(self, model, ident): - super(Interface, self).__init__(model, ident) - self.uri_fmt = "/interfaces/%s" - - @property - def data(self): - return {'name': self.ident, - 'type': self.info['type'], - 'ipaddr': self.info['ipaddr'], - 'netmask': self.info['netmask'], - 'status': self.info['status']} - - class Networks(Collection): def __init__(self, model): super(Networks, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 6e41190..982c7ea 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -32,6 +32,7 @@ from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource from kimchi.control.debugreports import DebugReports +from kimchi.control.interfaces import Interfaces from kimchi.control.storagepools import StoragePools from kimchi.control.templates import Templates from kimchi.control.vms import VMs @@ -55,7 +56,7 @@ class Root(Resource): self.vms = VMs(model) self.templates = Templates(model) self.storagepools = StoragePools(model) - self.interfaces = controller.Interfaces(model) + self.interfaces = Interfaces(model) self.networks = controller.Networks(model) self.tasks = controller.Tasks(model) self.config = controller.Config(model)

From: Aline Manera <alinefm@br.ibm.com> Networks(Collection) and Network(Resource) were moved to a new - control/networks.py That way we can easily know where network resource is implemented. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/networks.py | 48 ++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 24 -------------------- src/kimchi/root.py | 3 ++- 3 files changed, 50 insertions(+), 25 deletions(-) create mode 100644 src/kimchi/control/networks.py diff --git a/src/kimchi/control/networks.py b/src/kimchi/control/networks.py new file mode 100644 index 0000000..ad95d69 --- /dev/null +++ b/src/kimchi/control/networks.py @@ -0,0 +1,48 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@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 + +from kimchi.control.base import Collection, Resource + + +class Networks(Collection): + def __init__(self, model): + super(Networks, self).__init__(model) + self.resource = Network + + +class Network(Resource): + def __init__(self, model, ident): + super(Network, self).__init__(model, ident) + self.uri_fmt = "/networks/%s" + self.activate = self.generate_action_handler('activate') + self.deactivate = self.generate_action_handler('deactivate') + + @property + def data(self): + return {'name': self.ident, + 'autostart': self.info['autostart'], + 'connection': self.info['connection'], + 'interface': self.info['interface'], + 'subnet': self.info['subnet'], + 'dhcp': self.info['dhcp'], + 'state': self.info['state']} diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 2a888a4..8f21bfd 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -35,30 +35,6 @@ from kimchi.exception import NotFoundError, OperationFailed from kimchi.model import ISO_POOL_NAME -class Networks(Collection): - def __init__(self, model): - super(Networks, self).__init__(model) - self.resource = Network - - -class Network(Resource): - def __init__(self, model, ident): - super(Network, self).__init__(model, ident) - self.uri_fmt = "/networks/%s" - self.activate = self.generate_action_handler('activate') - self.deactivate = self.generate_action_handler('deactivate') - - @property - def data(self): - return {'name': self.ident, - 'autostart': self.info['autostart'], - 'connection': self.info['connection'], - 'interface': self.info['interface'], - 'subnet': self.info['subnet'], - 'dhcp': self.info['dhcp'], - 'state': self.info['state']} - - class Task(Resource): def __init__(self, model, id): super(Task, self).__init__(model, id) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 982c7ea..ebcd062 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -33,6 +33,7 @@ from kimchi.control.utils import parse_request from kimchi.control.base import Resource from kimchi.control.debugreports import DebugReports from kimchi.control.interfaces import Interfaces +from kimchi.control.networks import Networks from kimchi.control.storagepools import StoragePools from kimchi.control.templates import Templates from kimchi.control.vms import VMs @@ -57,7 +58,7 @@ class Root(Resource): self.templates = Templates(model) self.storagepools = StoragePools(model) self.interfaces = Interfaces(model) - self.networks = controller.Networks(model) + self.networks = Networks(model) self.tasks = controller.Tasks(model) self.config = controller.Config(model) self.host = controller.Host(model) -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Networks(Collection) and Network(Resource) were moved to a new - control/networks.py That way we can easily know where network resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/networks.py | 48 ++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 24 -------------------- src/kimchi/root.py | 3 ++- 3 files changed, 50 insertions(+), 25 deletions(-) create mode 100644 src/kimchi/control/networks.py
diff --git a/src/kimchi/control/networks.py b/src/kimchi/control/networks.py new file mode 100644 index 0000000..ad95d69 --- /dev/null +++ b/src/kimchi/control/networks.py @@ -0,0 +1,48 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@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 + +from kimchi.control.base import Collection, Resource + + +class Networks(Collection): + def __init__(self, model): + super(Networks, self).__init__(model) + self.resource = Network + + +class Network(Resource): + def __init__(self, model, ident): + super(Network, self).__init__(model, ident) + self.uri_fmt = "/networks/%s" + self.activate = self.generate_action_handler('activate') + self.deactivate = self.generate_action_handler('deactivate') + + @property + def data(self): + return {'name': self.ident, + 'autostart': self.info['autostart'], + 'connection': self.info['connection'], + 'interface': self.info['interface'], + 'subnet': self.info['subnet'], + 'dhcp': self.info['dhcp'], + 'state': self.info['state']} diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 2a888a4..8f21bfd 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -35,30 +35,6 @@ from kimchi.exception import NotFoundError, OperationFailed from kimchi.model import ISO_POOL_NAME
-class Networks(Collection): - def __init__(self, model): - super(Networks, self).__init__(model) - self.resource = Network - - -class Network(Resource): - def __init__(self, model, ident): - super(Network, self).__init__(model, ident) - self.uri_fmt = "/networks/%s" - self.activate = self.generate_action_handler('activate') - self.deactivate = self.generate_action_handler('deactivate') - - @property - def data(self): - return {'name': self.ident, - 'autostart': self.info['autostart'], - 'connection': self.info['connection'], - 'interface': self.info['interface'], - 'subnet': self.info['subnet'], - 'dhcp': self.info['dhcp'], - 'state': self.info['state']} - - class Task(Resource): def __init__(self, model, id): super(Task, self).__init__(model, id) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 982c7ea..ebcd062 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -33,6 +33,7 @@ from kimchi.control.utils import parse_request from kimchi.control.base import Resource from kimchi.control.debugreports import DebugReports from kimchi.control.interfaces import Interfaces +from kimchi.control.networks import Networks from kimchi.control.storagepools import StoragePools from kimchi.control.templates import Templates from kimchi.control.vms import VMs @@ -57,7 +58,7 @@ class Root(Resource): self.templates = Templates(model) self.storagepools = StoragePools(model) self.interfaces = Interfaces(model) - self.networks = controller.Networks(model) + self.networks = Networks(model) self.tasks = controller.Tasks(model) self.config = controller.Config(model) self.host = controller.Host(model)

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:48 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Networks(Collection) and Network(Resource) were moved to a new - control/networks.py That way we can easily know where network resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/networks.py | 48 ++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 24 -------------------- src/kimchi/root.py | 3 ++- 3 files changed, 50 insertions(+), 25 deletions(-) create mode 100644 src/kimchi/control/networks.py
diff --git a/src/kimchi/control/networks.py b/src/kimchi/control/networks.py new file mode 100644 index 0000000..ad95d69 --- /dev/null +++ b/src/kimchi/control/networks.py @@ -0,0 +1,48 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@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 + +from kimchi.control.base import Collection, Resource + + +class Networks(Collection): + def __init__(self, model): + super(Networks, self).__init__(model) + self.resource = Network + + +class Network(Resource): + def __init__(self, model, ident): + super(Network, self).__init__(model, ident) + self.uri_fmt = "/networks/%s" + self.activate = self.generate_action_handler('activate') + self.deactivate = self.generate_action_handler('deactivate') + + @property + def data(self): + return {'name': self.ident, + 'autostart': self.info['autostart'], + 'connection': self.info['connection'], + 'interface': self.info['interface'], + 'subnet': self.info['subnet'], + 'dhcp': self.info['dhcp'], + 'state': self.info['state']} diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 2a888a4..8f21bfd 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -35,30 +35,6 @@ from kimchi.exception import NotFoundError, OperationFailed from kimchi.model import ISO_POOL_NAME
-class Networks(Collection): - def __init__(self, model): - super(Networks, self).__init__(model) - self.resource = Network - - -class Network(Resource): - def __init__(self, model, ident): - super(Network, self).__init__(model, ident) - self.uri_fmt = "/networks/%s" - self.activate = self.generate_action_handler('activate') - self.deactivate = self.generate_action_handler('deactivate') - - @property - def data(self): - return {'name': self.ident, - 'autostart': self.info['autostart'], - 'connection': self.info['connection'], - 'interface': self.info['interface'], - 'subnet': self.info['subnet'], - 'dhcp': self.info['dhcp'], - 'state': self.info['state']} - - class Task(Resource): def __init__(self, model, id): super(Task, self).__init__(model, id) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 982c7ea..ebcd062 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -33,6 +33,7 @@ from kimchi.control.utils import parse_request from kimchi.control.base import Resource from kimchi.control.debugreports import DebugReports from kimchi.control.interfaces import Interfaces +from kimchi.control.networks import Networks from kimchi.control.storagepools import StoragePools from kimchi.control.templates import Templates from kimchi.control.vms import VMs @@ -57,7 +58,7 @@ class Root(Resource): self.templates = Templates(model) self.storagepools = StoragePools(model) self.interfaces = Interfaces(model) - self.networks = controller.Networks(model) + self.networks = Networks(model) self.tasks = controller.Tasks(model) self.config = controller.Config(model) self.host = controller.Host(model)

From: Aline Manera <alinefm@br.ibm.com> Config(Resource), Capabilities(Resource), Distros(Collection) and Distro(Resource) were moved to a new - control/config.py That way we can easily know where config resource is implemented. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/config.py | 69 ++++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 41 ------------------------- src/kimchi/root.py | 3 +- 3 files changed, 71 insertions(+), 42 deletions(-) create mode 100644 src/kimchi/control/config.py diff --git a/src/kimchi/control/config.py b/src/kimchi/control/config.py new file mode 100644 index 0000000..3630172 --- /dev/null +++ b/src/kimchi/control/config.py @@ -0,0 +1,69 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@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 + + +from kimchi.control.base import Collection, Resource + + +class Config(Resource): + def __init__(self, model, id=None): + super(Config, self).__init__(model, id) + self.capabilities = Capabilities(self.model) + self.capabilities.exposed = True + self.distros = Distros(model) + self.distros.exposed = True + + @property + def data(self): + return {'http_port': cherrypy.server.socket_port} + + +class Capabilities(Resource): + def __init__(self, model, id=None): + super(Capabilities, self).__init__(model, id) + + @property + def data(self): + caps = ['libvirt_stream_protocols', 'qemu_stream', + 'screenshot', 'system_report_tool'] + ret = dict([(x, None) for x in caps]) + ret.update(self.model.get_capabilities()) + return ret + + +class Distros(Collection): + def __init__(self, model): + super(Distros, self).__init__(model) + self.resource = Distro + + +class Distro(Resource): + def __init__(self, model, ident): + super(Distro, self).__init__(model, ident) + + @property + def data(self): + return self.info diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 8f21bfd..0ec0c6f 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -52,47 +52,6 @@ class Tasks(Collection): self.resource = Task -class Config(Resource): - def __init__(self, model, id=None): - super(Config, self).__init__(model, id) - self.capabilities = Capabilities(self.model) - self.capabilities.exposed = True - self.distros = Distros(model) - self.distros.exposed = True - - @property - def data(self): - return {'http_port': cherrypy.server.socket_port} - -class Capabilities(Resource): - def __init__(self, model, id=None): - super(Capabilities, self).__init__(model, id) - self.model = model - - @property - def data(self): - caps = ['libvirt_stream_protocols', 'qemu_stream', - 'screenshot', 'system_report_tool'] - ret = dict([(x, None) for x in caps]) - ret.update(self.model.get_capabilities()) - return ret - - -class Distro(Resource): - def __init__(self, model, ident): - super(Distro, self).__init__(model, ident) - - @property - def data(self): - return self.info - - -class Distros(Collection): - def __init__(self, model): - super(Distros, self).__init__(model) - self.resource = Distro - - class Host(Resource): def __init__(self, model, id=None): super(Host, self).__init__(model, id) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index ebcd062..c4f795b 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -31,6 +31,7 @@ from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource +from kimchi.control.config import Config from kimchi.control.debugreports import DebugReports from kimchi.control.interfaces import Interfaces from kimchi.control.networks import Networks @@ -60,7 +61,7 @@ class Root(Resource): self.interfaces = Interfaces(model) self.networks = Networks(model) self.tasks = controller.Tasks(model) - self.config = controller.Config(model) + self.config = Config(model) self.host = controller.Host(model) self.debugreports = DebugReports(model) self.plugins = controller.Plugins(model) -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:49 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Config(Resource), Capabilities(Resource), Distros(Collection) and Distro(Resource) were moved to a new - control/config.py That way we can easily know where config resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/config.py | 69 ++++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 41 ------------------------- src/kimchi/root.py | 3 +- 3 files changed, 71 insertions(+), 42 deletions(-) create mode 100644 src/kimchi/control/config.py
diff --git a/src/kimchi/control/config.py b/src/kimchi/control/config.py new file mode 100644 index 0000000..3630172 --- /dev/null +++ b/src/kimchi/control/config.py @@ -0,0 +1,69 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@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 + + +from kimchi.control.base import Collection, Resource + + +class Config(Resource): + def __init__(self, model, id=None): + super(Config, self).__init__(model, id) + self.capabilities = Capabilities(self.model) + self.capabilities.exposed = True + self.distros = Distros(model) + self.distros.exposed = True + + @property + def data(self): + return {'http_port': cherrypy.server.socket_port} + + +class Capabilities(Resource): + def __init__(self, model, id=None): + super(Capabilities, self).__init__(model, id) + + @property + def data(self): + caps = ['libvirt_stream_protocols', 'qemu_stream', + 'screenshot', 'system_report_tool'] + ret = dict([(x, None) for x in caps]) + ret.update(self.model.get_capabilities()) + return ret + + +class Distros(Collection): + def __init__(self, model): + super(Distros, self).__init__(model) + self.resource = Distro + + +class Distro(Resource): + def __init__(self, model, ident): + super(Distro, self).__init__(model, ident) + + @property + def data(self): + return self.info diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 8f21bfd..0ec0c6f 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -52,47 +52,6 @@ class Tasks(Collection): self.resource = Task
-class Config(Resource): - def __init__(self, model, id=None): - super(Config, self).__init__(model, id) - self.capabilities = Capabilities(self.model) - self.capabilities.exposed = True - self.distros = Distros(model) - self.distros.exposed = True - - @property - def data(self): - return {'http_port': cherrypy.server.socket_port} - -class Capabilities(Resource): - def __init__(self, model, id=None): - super(Capabilities, self).__init__(model, id) - self.model = model - - @property - def data(self): - caps = ['libvirt_stream_protocols', 'qemu_stream', - 'screenshot', 'system_report_tool'] - ret = dict([(x, None) for x in caps]) - ret.update(self.model.get_capabilities()) - return ret - - -class Distro(Resource): - def __init__(self, model, ident): - super(Distro, self).__init__(model, ident) - - @property - def data(self): - return self.info - - -class Distros(Collection): - def __init__(self, model): - super(Distros, self).__init__(model) - self.resource = Distro - - class Host(Resource): def __init__(self, model, id=None): super(Host, self).__init__(model, id) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index ebcd062..c4f795b 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -31,6 +31,7 @@ from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource +from kimchi.control.config import Config from kimchi.control.debugreports import DebugReports from kimchi.control.interfaces import Interfaces from kimchi.control.networks import Networks @@ -60,7 +61,7 @@ class Root(Resource): self.interfaces = Interfaces(model) self.networks = Networks(model) self.tasks = controller.Tasks(model) - self.config = controller.Config(model) + self.config = Config(model) self.host = controller.Host(model) self.debugreports = DebugReports(model) self.plugins = controller.Plugins(model)

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:49 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Config(Resource), Capabilities(Resource), Distros(Collection) and Distro(Resource) were moved to a new - control/config.py That way we can easily know where config resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/config.py | 69 ++++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 41 ------------------------- src/kimchi/root.py | 3 +- 3 files changed, 71 insertions(+), 42 deletions(-) create mode 100644 src/kimchi/control/config.py
diff --git a/src/kimchi/control/config.py b/src/kimchi/control/config.py new file mode 100644 index 0000000..3630172 --- /dev/null +++ b/src/kimchi/control/config.py @@ -0,0 +1,69 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@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 + + +from kimchi.control.base import Collection, Resource + + +class Config(Resource): + def __init__(self, model, id=None): + super(Config, self).__init__(model, id) + self.capabilities = Capabilities(self.model) + self.capabilities.exposed = True + self.distros = Distros(model) + self.distros.exposed = True + + @property + def data(self): + return {'http_port': cherrypy.server.socket_port} + + +class Capabilities(Resource): + def __init__(self, model, id=None): + super(Capabilities, self).__init__(model, id) + + @property + def data(self): + caps = ['libvirt_stream_protocols', 'qemu_stream', + 'screenshot', 'system_report_tool'] + ret = dict([(x, None) for x in caps]) + ret.update(self.model.get_capabilities()) + return ret + + +class Distros(Collection): + def __init__(self, model): + super(Distros, self).__init__(model) + self.resource = Distro + + +class Distro(Resource): + def __init__(self, model, ident): + super(Distro, self).__init__(model, ident) + + @property + def data(self): + return self.info diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 8f21bfd..0ec0c6f 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -52,47 +52,6 @@ class Tasks(Collection): self.resource = Task
-class Config(Resource): - def __init__(self, model, id=None): - super(Config, self).__init__(model, id) - self.capabilities = Capabilities(self.model) - self.capabilities.exposed = True - self.distros = Distros(model) - self.distros.exposed = True - - @property - def data(self): - return {'http_port': cherrypy.server.socket_port} - -class Capabilities(Resource): - def __init__(self, model, id=None): - super(Capabilities, self).__init__(model, id) - self.model = model - - @property - def data(self): - caps = ['libvirt_stream_protocols', 'qemu_stream', - 'screenshot', 'system_report_tool'] - ret = dict([(x, None) for x in caps]) - ret.update(self.model.get_capabilities()) - return ret - - -class Distro(Resource): - def __init__(self, model, ident): - super(Distro, self).__init__(model, ident) - - @property - def data(self): - return self.info - - -class Distros(Collection): - def __init__(self, model): - super(Distros, self).__init__(model) - self.resource = Distro - - class Host(Resource): def __init__(self, model, id=None): super(Host, self).__init__(model, id) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index ebcd062..c4f795b 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -31,6 +31,7 @@ from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request from kimchi.control.base import Resource +from kimchi.control.config import Config from kimchi.control.debugreports import DebugReports from kimchi.control.interfaces import Interfaces from kimchi.control.networks import Networks @@ -60,7 +61,7 @@ class Root(Resource): self.interfaces = Interfaces(model) self.networks = Networks(model) self.tasks = controller.Tasks(model) - self.config = controller.Config(model) + self.config = Config(model) self.host = controller.Host(model) self.debugreports = DebugReports(model) self.plugins = controller.Plugins(model)

From: Aline Manera <alinefm@br.ibm.com> Host(Resource), HostStats(Resource), Partitions(Collection) and Partition(Resource) were moved to a new - control/host.py That way we can easily know where host resource is implemented. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/host.py | 63 ++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 34 ------------------------ src/kimchi/root.py | 3 ++- 3 files changed, 65 insertions(+), 35 deletions(-) create mode 100644 src/kimchi/control/host.py diff --git a/src/kimchi/control/host.py b/src/kimchi/control/host.py new file mode 100644 index 0000000..9b19577 --- /dev/null +++ b/src/kimchi/control/host.py @@ -0,0 +1,63 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@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 + +from kimchi.control.base import Collection, Resource + + +class Host(Resource): + def __init__(self, model, id=None): + super(Host, self).__init__(model, id) + self.uri_fmt = '/host/%s' + self.reboot = self.generate_action_handler('reboot') + self.shutdown = self.generate_action_handler('shutdown') + self.stats = HostStats(self.model) + self.stats.exposed = True + self.partitions = Partitions(self.model) + self.partitions.exposed = True + + @property + def data(self): + return self.info + + +class HostStats(Resource): + @property + def data(self): + return self.info + + +class Partitions(Collection): + def __init__(self, model): + super(Partitions, self).__init__(model) + self.resource = Partition + + +class Partition(Resource): + def __init__(self, model, id): + super(Partition, self).__init__(model, id) + + @property + def data(self): + return self.info diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 0ec0c6f..aca54f2 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -52,40 +52,6 @@ class Tasks(Collection): self.resource = Task -class Host(Resource): - def __init__(self, model, id=None): - super(Host, self).__init__(model, id) - self.stats = HostStats(self.model) - self.stats.exposed = True - self.uri_fmt = '/host/%s' - self.reboot = self.generate_action_handler('reboot') - self.shutdown = self.generate_action_handler('shutdown') - self.partitions = Partitions(self.model) - self.partitions.exposed = True - - @property - def data(self): - return self.info - -class HostStats(Resource): - @property - def data(self): - return self.info - -class Partitions(Collection): - def __init__(self, model): - super(Partitions, self).__init__(model) - self.resource = Partition - - -class Partition(Resource): - def __init__(self, model,id): - super(Partition, self).__init__(model,id) - - @property - def data(self): - return self.info - class Plugins(Collection): def __init__(self, model): super(Plugins, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index c4f795b..6e5f282 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -33,6 +33,7 @@ from kimchi.control.utils import parse_request from kimchi.control.base import Resource from kimchi.control.config import Config from kimchi.control.debugreports import DebugReports +from kimchi.control.host import Host from kimchi.control.interfaces import Interfaces from kimchi.control.networks import Networks from kimchi.control.storagepools import StoragePools @@ -62,7 +63,7 @@ class Root(Resource): self.networks = Networks(model) self.tasks = controller.Tasks(model) self.config = Config(model) - self.host = controller.Host(model) + self.host = Host(model) self.debugreports = DebugReports(model) self.plugins = controller.Plugins(model) self.api_schema = json.load(open(get_api_schema_file())) -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:49 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Host(Resource), HostStats(Resource), Partitions(Collection) and Partition(Resource) were moved to a new - control/host.py That way we can easily know where host resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/host.py | 63 ++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 34 ------------------------ src/kimchi/root.py | 3 ++- 3 files changed, 65 insertions(+), 35 deletions(-) create mode 100644 src/kimchi/control/host.py
diff --git a/src/kimchi/control/host.py b/src/kimchi/control/host.py new file mode 100644 index 0000000..9b19577 --- /dev/null +++ b/src/kimchi/control/host.py @@ -0,0 +1,63 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@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 + +from kimchi.control.base import Collection, Resource + + +class Host(Resource): + def __init__(self, model, id=None): + super(Host, self).__init__(model, id) + self.uri_fmt = '/host/%s' + self.reboot = self.generate_action_handler('reboot') + self.shutdown = self.generate_action_handler('shutdown') + self.stats = HostStats(self.model) + self.stats.exposed = True + self.partitions = Partitions(self.model) + self.partitions.exposed = True + + @property + def data(self): + return self.info + + +class HostStats(Resource): + @property + def data(self): + return self.info + + +class Partitions(Collection): + def __init__(self, model): + super(Partitions, self).__init__(model) + self.resource = Partition + + +class Partition(Resource): + def __init__(self, model, id): + super(Partition, self).__init__(model, id) + + @property + def data(self): + return self.info diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 0ec0c6f..aca54f2 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -52,40 +52,6 @@ class Tasks(Collection): self.resource = Task
-class Host(Resource): - def __init__(self, model, id=None): - super(Host, self).__init__(model, id) - self.stats = HostStats(self.model) - self.stats.exposed = True - self.uri_fmt = '/host/%s' - self.reboot = self.generate_action_handler('reboot') - self.shutdown = self.generate_action_handler('shutdown') - self.partitions = Partitions(self.model) - self.partitions.exposed = True - - @property - def data(self): - return self.info - -class HostStats(Resource): - @property - def data(self): - return self.info - -class Partitions(Collection): - def __init__(self, model): - super(Partitions, self).__init__(model) - self.resource = Partition - - -class Partition(Resource): - def __init__(self, model,id): - super(Partition, self).__init__(model,id) - - @property - def data(self): - return self.info - class Plugins(Collection): def __init__(self, model): super(Plugins, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index c4f795b..6e5f282 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -33,6 +33,7 @@ from kimchi.control.utils import parse_request from kimchi.control.base import Resource from kimchi.control.config import Config from kimchi.control.debugreports import DebugReports +from kimchi.control.host import Host from kimchi.control.interfaces import Interfaces from kimchi.control.networks import Networks from kimchi.control.storagepools import StoragePools @@ -62,7 +63,7 @@ class Root(Resource): self.networks = Networks(model) self.tasks = controller.Tasks(model) self.config = Config(model) - self.host = controller.Host(model) + self.host = Host(model) self.debugreports = DebugReports(model) self.plugins = controller.Plugins(model) self.api_schema = json.load(open(get_api_schema_file()))

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:49 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Host(Resource), HostStats(Resource), Partitions(Collection) and Partition(Resource) were moved to a new - control/host.py That way we can easily know where host resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/host.py | 63 ++++++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 34 ------------------------ src/kimchi/root.py | 3 ++- 3 files changed, 65 insertions(+), 35 deletions(-) create mode 100644 src/kimchi/control/host.py
diff --git a/src/kimchi/control/host.py b/src/kimchi/control/host.py new file mode 100644 index 0000000..9b19577 --- /dev/null +++ b/src/kimchi/control/host.py @@ -0,0 +1,63 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Adam Litke <agl@linux.vnet.ibm.com> +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Daniel Henrique Barboza <danielhb@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@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 + +from kimchi.control.base import Collection, Resource + + +class Host(Resource): + def __init__(self, model, id=None): + super(Host, self).__init__(model, id) + self.uri_fmt = '/host/%s' + self.reboot = self.generate_action_handler('reboot') + self.shutdown = self.generate_action_handler('shutdown') + self.stats = HostStats(self.model) + self.stats.exposed = True + self.partitions = Partitions(self.model) + self.partitions.exposed = True + + @property + def data(self): + return self.info + + +class HostStats(Resource): + @property + def data(self): + return self.info + + +class Partitions(Collection): + def __init__(self, model): + super(Partitions, self).__init__(model) + self.resource = Partition + + +class Partition(Resource): + def __init__(self, model, id): + super(Partition, self).__init__(model, id) + + @property + def data(self): + return self.info diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index 0ec0c6f..aca54f2 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -52,40 +52,6 @@ class Tasks(Collection): self.resource = Task
-class Host(Resource): - def __init__(self, model, id=None): - super(Host, self).__init__(model, id) - self.stats = HostStats(self.model) - self.stats.exposed = True - self.uri_fmt = '/host/%s' - self.reboot = self.generate_action_handler('reboot') - self.shutdown = self.generate_action_handler('shutdown') - self.partitions = Partitions(self.model) - self.partitions.exposed = True - - @property - def data(self): - return self.info - -class HostStats(Resource): - @property - def data(self): - return self.info - -class Partitions(Collection): - def __init__(self, model): - super(Partitions, self).__init__(model) - self.resource = Partition - - -class Partition(Resource): - def __init__(self, model,id): - super(Partition, self).__init__(model,id) - - @property - def data(self): - return self.info - class Plugins(Collection): def __init__(self, model): super(Plugins, self).__init__(model) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index c4f795b..6e5f282 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -33,6 +33,7 @@ from kimchi.control.utils import parse_request from kimchi.control.base import Resource from kimchi.control.config import Config from kimchi.control.debugreports import DebugReports +from kimchi.control.host import Host from kimchi.control.interfaces import Interfaces from kimchi.control.networks import Networks from kimchi.control.storagepools import StoragePools @@ -62,7 +63,7 @@ class Root(Resource): self.networks = Networks(model) self.tasks = controller.Tasks(model) self.config = Config(model) - self.host = controller.Host(model) + self.host = Host(model) self.debugreports = DebugReports(model) self.plugins = controller.Plugins(model) self.api_schema = json.load(open(get_api_schema_file()))

From: Aline Manera <alinefm@br.ibm.com> Plugins(Collection) was moved to a new - control/plugins.py That way we can easily know where plugins resource is implemented. Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/plugins.py | 45 +++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 19 ----------------- src/kimchi/root.py | 3 ++- 3 files changed, 47 insertions(+), 20 deletions(-) create mode 100644 src/kimchi/control/plugins.py diff --git a/src/kimchi/control/plugins.py b/src/kimchi/control/plugins.py new file mode 100644 index 0000000..af32709 --- /dev/null +++ b/src/kimchi/control/plugins.py @@ -0,0 +1,45 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@linux.vnet.ibm.com> +# zhoumeina <zhoumein@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 kimchi.template +from kimchi.control.base import Collection, Resource +from kimchi.control.utils import get_class_name, model_fn + + +class Plugins(Collection): + def __init__(self, model): + super(Plugins, self).__init__(model) + + @property + def data(self): + return self.info + + def get(self): + res_list = [] + try: + get_list = getattr(self.model, model_fn(self, 'get_list')) + res_list = get_list(*self.model_args) + except AttributeError: + pass + return kimchi.template.render(get_class_name(self), res_list) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index aca54f2..4684e11 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -50,22 +50,3 @@ class Tasks(Collection): def __init__(self, model): super(Tasks, self).__init__(model) self.resource = Task - - -class Plugins(Collection): - def __init__(self, model): - super(Plugins, self).__init__(model) - self.model = model - - @property - def data(self): - return self.info - - def get(self): - res_list = [] - try: - get_list = getattr(self.model, model_fn(self, 'get_list')) - res_list = get_list(*self.model_args) - except AttributeError: - pass - return kimchi.template.render(get_class_name(self), res_list) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 6e5f282..8ea15d8 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -36,6 +36,7 @@ from kimchi.control.debugreports import DebugReports from kimchi.control.host import Host from kimchi.control.interfaces import Interfaces from kimchi.control.networks import Networks +from kimchi.control.plugins import Plugins from kimchi.control.storagepools import StoragePools from kimchi.control.templates import Templates from kimchi.control.vms import VMs @@ -65,7 +66,7 @@ class Root(Resource): self.config = Config(model) self.host = Host(model) self.debugreports = DebugReports(model) - self.plugins = controller.Plugins(model) + self.plugins = Plugins(model) self.api_schema = json.load(open(get_api_schema_file())) def error_production_handler(self, status, message, traceback, version): -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:49 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Plugins(Collection) was moved to a new - control/plugins.py That way we can easily know where plugins resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/plugins.py | 45 +++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 19 ----------------- src/kimchi/root.py | 3 ++- 3 files changed, 47 insertions(+), 20 deletions(-) create mode 100644 src/kimchi/control/plugins.py
diff --git a/src/kimchi/control/plugins.py b/src/kimchi/control/plugins.py new file mode 100644 index 0000000..af32709 --- /dev/null +++ b/src/kimchi/control/plugins.py @@ -0,0 +1,45 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@linux.vnet.ibm.com> +# zhoumeina <zhoumein@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 kimchi.template +from kimchi.control.base import Collection, Resource +from kimchi.control.utils import get_class_name, model_fn + + +class Plugins(Collection): + def __init__(self, model): + super(Plugins, self).__init__(model) + + @property + def data(self): + return self.info + + def get(self): + res_list = [] + try: + get_list = getattr(self.model, model_fn(self, 'get_list')) + res_list = get_list(*self.model_args) + except AttributeError: + pass + return kimchi.template.render(get_class_name(self), res_list) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index aca54f2..4684e11 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -50,22 +50,3 @@ class Tasks(Collection): def __init__(self, model): super(Tasks, self).__init__(model) self.resource = Task - - -class Plugins(Collection): - def __init__(self, model): - super(Plugins, self).__init__(model) - self.model = model - - @property - def data(self): - return self.info - - def get(self): - res_list = [] - try: - get_list = getattr(self.model, model_fn(self, 'get_list')) - res_list = get_list(*self.model_args) - except AttributeError: - pass - return kimchi.template.render(get_class_name(self), res_list) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 6e5f282..8ea15d8 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -36,6 +36,7 @@ from kimchi.control.debugreports import DebugReports from kimchi.control.host import Host from kimchi.control.interfaces import Interfaces from kimchi.control.networks import Networks +from kimchi.control.plugins import Plugins from kimchi.control.storagepools import StoragePools from kimchi.control.templates import Templates from kimchi.control.vms import VMs @@ -65,7 +66,7 @@ class Root(Resource): self.config = Config(model) self.host = Host(model) self.debugreports = DebugReports(model) - self.plugins = controller.Plugins(model) + self.plugins = Plugins(model) self.api_schema = json.load(open(get_api_schema_file()))
def error_production_handler(self, status, message, traceback, version):

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:49 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Plugins(Collection) was moved to a new - control/plugins.py That way we can easily know where plugins resource is implemented.
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/control/plugins.py | 45 +++++++++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 19 ----------------- src/kimchi/root.py | 3 ++- 3 files changed, 47 insertions(+), 20 deletions(-) create mode 100644 src/kimchi/control/plugins.py
diff --git a/src/kimchi/control/plugins.py b/src/kimchi/control/plugins.py new file mode 100644 index 0000000..af32709 --- /dev/null +++ b/src/kimchi/control/plugins.py @@ -0,0 +1,45 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# ShaoHe Feng <shaohef@linux.vnet.ibm.com> +# zhoumeina <zhoumein@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 kimchi.template +from kimchi.control.base import Collection, Resource +from kimchi.control.utils import get_class_name, model_fn + + +class Plugins(Collection): + def __init__(self, model): + super(Plugins, self).__init__(model) + + @property + def data(self): + return self.info + + def get(self): + res_list = [] + try: + get_list = getattr(self.model, model_fn(self, 'get_list')) + res_list = get_list(*self.model_args) + except AttributeError: + pass + return kimchi.template.render(get_class_name(self), res_list) diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py index aca54f2..4684e11 100644 --- a/src/kimchi/controller.py +++ b/src/kimchi/controller.py @@ -50,22 +50,3 @@ class Tasks(Collection): def __init__(self, model): super(Tasks, self).__init__(model) self.resource = Task - - -class Plugins(Collection): - def __init__(self, model): - super(Plugins, self).__init__(model) - self.model = model - - @property - def data(self): - return self.info - - def get(self): - res_list = [] - try: - get_list = getattr(self.model, model_fn(self, 'get_list')) - res_list = get_list(*self.model_args) - except AttributeError: - pass - return kimchi.template.render(get_class_name(self), res_list) diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 6e5f282..8ea15d8 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -36,6 +36,7 @@ from kimchi.control.debugreports import DebugReports from kimchi.control.host import Host from kimchi.control.interfaces import Interfaces from kimchi.control.networks import Networks +from kimchi.control.plugins import Plugins from kimchi.control.storagepools import StoragePools from kimchi.control.templates import Templates from kimchi.control.vms import VMs @@ -65,7 +66,7 @@ class Root(Resource): self.config = Config(model) self.host = Host(model) self.debugreports = DebugReports(model) - self.plugins = controller.Plugins(model) + self.plugins = Plugins(model) self.api_schema = json.load(open(get_api_schema_file()))
def error_production_handler(self, status, message, traceback, version):

From: Aline Manera <alinefm@br.ibm.com> Tasks(Collection) and Task(Resource) were moved to a new - control/tasks.py That way we can easily know where task resource is implemented. Also remove former controller.py Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/Makefile.am | 1 - src/kimchi/control/tasks.py | 41 ++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 52 ------------------------------------------- src/kimchi/root.py | 4 ++-- 4 files changed, 43 insertions(+), 55 deletions(-) create mode 100644 src/kimchi/control/tasks.py delete mode 100644 src/kimchi/controller.py diff --git a/src/kimchi/Makefile.am b/src/kimchi/Makefile.am index 78af50f..955e63c 100644 --- a/src/kimchi/Makefile.am +++ b/src/kimchi/Makefile.am @@ -25,7 +25,6 @@ SUBDIRS = control kimchi_PYTHON = \ asynctask.py \ auth.py \ - controller.py \ disks.py \ distroloader.py \ exception.py \ diff --git a/src/kimchi/control/tasks.py b/src/kimchi/control/tasks.py new file mode 100644 index 0000000..b799422 --- /dev/null +++ b/src/kimchi/control/tasks.py @@ -0,0 +1,41 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Shu Ming <shuming@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 + +from kimchi.control.base import Collection, Resource + + +class Tasks(Collection): + def __init__(self, model): + super(Tasks, self).__init__(model) + self.resource = Task + + +class Task(Resource): + def __init__(self, model, id): + super(Task, self).__init__(model, id) + + @property + def data(self): + return {'id': self.ident, + 'status': self.info['status'], + 'message': self.info['message']} diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py deleted file mode 100644 index 4684e11..0000000 --- a/src/kimchi/controller.py +++ /dev/null @@ -1,52 +0,0 @@ -# -# 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 urllib2 - - -from functools import wraps - - -import kimchi.template -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 - - -class Task(Resource): - def __init__(self, model, id): - super(Task, self).__init__(model, id) - - @property - def data(self): - return {'id': self.ident, - 'status': self.info['status'], - 'message': self.info['message']} - - -class Tasks(Collection): - def __init__(self, model): - super(Tasks, self).__init__(model) - self.resource = Task diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 8ea15d8..1750014 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -26,7 +26,6 @@ import json from kimchi import auth -from kimchi import controller from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request @@ -38,6 +37,7 @@ from kimchi.control.interfaces import Interfaces from kimchi.control.networks import Networks from kimchi.control.plugins import Plugins from kimchi.control.storagepools import StoragePools +from kimchi.control.tasks import Tasks from kimchi.control.templates import Templates from kimchi.control.vms import VMs from kimchi.exception import OperationFailed @@ -62,7 +62,7 @@ class Root(Resource): self.storagepools = StoragePools(model) self.interfaces = Interfaces(model) self.networks = Networks(model) - self.tasks = controller.Tasks(model) + self.tasks = Tasks(model) self.config = Config(model) self.host = Host(model) self.debugreports = DebugReports(model) -- 1.7.10.4

Reviewed-by: Daniel Barboza <danielhb@linux.vnet.ibm.com> On 12/26/2013 07:49 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Tasks(Collection) and Task(Resource) were moved to a new - control/tasks.py That way we can easily know where task resource is implemented. Also remove former controller.py
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/Makefile.am | 1 - src/kimchi/control/tasks.py | 41 ++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 52 ------------------------------------------- src/kimchi/root.py | 4 ++-- 4 files changed, 43 insertions(+), 55 deletions(-) create mode 100644 src/kimchi/control/tasks.py delete mode 100644 src/kimchi/controller.py
diff --git a/src/kimchi/Makefile.am b/src/kimchi/Makefile.am index 78af50f..955e63c 100644 --- a/src/kimchi/Makefile.am +++ b/src/kimchi/Makefile.am @@ -25,7 +25,6 @@ SUBDIRS = control kimchi_PYTHON = \ asynctask.py \ auth.py \ - controller.py \ disks.py \ distroloader.py \ exception.py \ diff --git a/src/kimchi/control/tasks.py b/src/kimchi/control/tasks.py new file mode 100644 index 0000000..b799422 --- /dev/null +++ b/src/kimchi/control/tasks.py @@ -0,0 +1,41 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Shu Ming <shuming@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 + +from kimchi.control.base import Collection, Resource + + +class Tasks(Collection): + def __init__(self, model): + super(Tasks, self).__init__(model) + self.resource = Task + + +class Task(Resource): + def __init__(self, model, id): + super(Task, self).__init__(model, id) + + @property + def data(self): + return {'id': self.ident, + 'status': self.info['status'], + 'message': self.info['message']} diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py deleted file mode 100644 index 4684e11..0000000 --- a/src/kimchi/controller.py +++ /dev/null @@ -1,52 +0,0 @@ -# -# 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 urllib2 - - -from functools import wraps - - -import kimchi.template -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 - - -class Task(Resource): - def __init__(self, model, id): - super(Task, self).__init__(model, id) - - @property - def data(self): - return {'id': self.ident, - 'status': self.info['status'], - 'message': self.info['message']} - - -class Tasks(Collection): - def __init__(self, model): - super(Tasks, self).__init__(model) - self.resource = Task diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 8ea15d8..1750014 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -26,7 +26,6 @@ import json
from kimchi import auth -from kimchi import controller from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request @@ -38,6 +37,7 @@ from kimchi.control.interfaces import Interfaces from kimchi.control.networks import Networks from kimchi.control.plugins import Plugins from kimchi.control.storagepools import StoragePools +from kimchi.control.tasks import Tasks from kimchi.control.templates import Templates from kimchi.control.vms import VMs from kimchi.exception import OperationFailed @@ -62,7 +62,7 @@ class Root(Resource): self.storagepools = StoragePools(model) self.interfaces = Interfaces(model) self.networks = Networks(model) - self.tasks = controller.Tasks(model) + self.tasks = Tasks(model) self.config = Config(model) self.host = Host(model) self.debugreports = DebugReports(model)

Reviewed-by: Rodrigo Trujillo <rodrigo.trujillo@linux.vnet.ibm.com> On 12/26/2013 07:49 PM, Aline Manera wrote:
From: Aline Manera <alinefm@br.ibm.com>
Tasks(Collection) and Task(Resource) were moved to a new - control/tasks.py That way we can easily know where task resource is implemented. Also remove former controller.py
Signed-off-by: Aline Manera <alinefm@br.ibm.com> --- src/kimchi/Makefile.am | 1 - src/kimchi/control/tasks.py | 41 ++++++++++++++++++++++++++++++++++ src/kimchi/controller.py | 52 ------------------------------------------- src/kimchi/root.py | 4 ++-- 4 files changed, 43 insertions(+), 55 deletions(-) create mode 100644 src/kimchi/control/tasks.py delete mode 100644 src/kimchi/controller.py
diff --git a/src/kimchi/Makefile.am b/src/kimchi/Makefile.am index 78af50f..955e63c 100644 --- a/src/kimchi/Makefile.am +++ b/src/kimchi/Makefile.am @@ -25,7 +25,6 @@ SUBDIRS = control kimchi_PYTHON = \ asynctask.py \ auth.py \ - controller.py \ disks.py \ distroloader.py \ exception.py \ diff --git a/src/kimchi/control/tasks.py b/src/kimchi/control/tasks.py new file mode 100644 index 0000000..b799422 --- /dev/null +++ b/src/kimchi/control/tasks.py @@ -0,0 +1,41 @@ +# +# Project Kimchi +# +# Copyright IBM, Corp. 2013 +# +# Authors: +# Aline Manera <alinefm@linux.vnet.ibm.com> +# Shu Ming <shuming@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 + +from kimchi.control.base import Collection, Resource + + +class Tasks(Collection): + def __init__(self, model): + super(Tasks, self).__init__(model) + self.resource = Task + + +class Task(Resource): + def __init__(self, model, id): + super(Task, self).__init__(model, id) + + @property + def data(self): + return {'id': self.ident, + 'status': self.info['status'], + 'message': self.info['message']} diff --git a/src/kimchi/controller.py b/src/kimchi/controller.py deleted file mode 100644 index 4684e11..0000000 --- a/src/kimchi/controller.py +++ /dev/null @@ -1,52 +0,0 @@ -# -# 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 urllib2 - - -from functools import wraps - - -import kimchi.template -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 - - -class Task(Resource): - def __init__(self, model, id): - super(Task, self).__init__(model, id) - - @property - def data(self): - return {'id': self.ident, - 'status': self.info['status'], - 'message': self.info['message']} - - -class Tasks(Collection): - def __init__(self, model): - super(Tasks, self).__init__(model) - self.resource = Task diff --git a/src/kimchi/root.py b/src/kimchi/root.py index 8ea15d8..1750014 100644 --- a/src/kimchi/root.py +++ b/src/kimchi/root.py @@ -26,7 +26,6 @@ import json
from kimchi import auth -from kimchi import controller from kimchi import template from kimchi.config import get_api_schema_file from kimchi.control.utils import parse_request @@ -38,6 +37,7 @@ from kimchi.control.interfaces import Interfaces from kimchi.control.networks import Networks from kimchi.control.plugins import Plugins from kimchi.control.storagepools import StoragePools +from kimchi.control.tasks import Tasks from kimchi.control.templates import Templates from kimchi.control.vms import VMs from kimchi.exception import OperationFailed @@ -62,7 +62,7 @@ class Root(Resource): self.storagepools = StoragePools(model) self.interfaces = Interfaces(model) self.networks = Networks(model) - self.tasks = controller.Tasks(model) + self.tasks = Tasks(model) self.config = Config(model) self.host = Host(model) self.debugreports = DebugReports(model)
participants (3)
-
Aline Manera
-
Daniel H Barboza
-
Rodrigo Trujillo