mgr/dashboard_v2: Refactor controller base class

Make it a little bit more OO. This way the mgr and logger properties are well
designed and documented which should help contributors to understand the code.

Signed-off-by: Volker Theile <vtheile@suse.com>
This commit is contained in:
Volker Theile 2018-01-30 11:58:46 +01:00 committed by Ricardo Dias
parent d0b166cfe8
commit f416efcf8c
No known key found for this signature in database
GPG Key ID: 74390C579BD37B68
4 changed files with 63 additions and 20 deletions

View File

@ -9,6 +9,7 @@ __pycache__
# IDE
.vscode
.idea
*.egg
# virtualenv
venv

View File

@ -98,25 +98,25 @@ Developer Notes
How to add a new controller?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
If you want to add a new endpoint to the backend, you just need to add
a class decorated with ``ApiController`` in a python file located under the
``controllers`` directory. The dashboard plugin will automatically load your
new controller upon start.
If you want to add a new endpoint to the backend, you just need to add a
class derived from ``BaseController`` decorated with ``ApiController`` in a
Python file located under the ``controllers`` directory. The Dashboard module
will automatically load your new controller upon start.
For example create a file ``ping2.py`` under ``controllers`` directory with the
following code::
import cherrypy
from ..tools import ApiController
from ..tools import ApiController, BaseController
@ApiController('ping2')
class Ping2(object):
class Ping2(BaseController):
@cherrypy.expose
def default(self, *args):
return "Hello"
Reload the dashboard plugin, and then you can access the above controller
from the web browser using the URL http://mgr_hostname:8080/api/ping2
Reload the Dashboard module and then you can access the above controller from
the web browser using the URL http://mgr_hostname:8080/api/ping2.
We also provide a simple mechanism to create REST based controllers using the
``RESTController`` class.
@ -156,9 +156,9 @@ Now only authenticated users will be able to "ping" your controller.
How to access the manager module instance from a controller?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Each controller class annoted with the ``ApiController`` decorator is injected
with a class property that points to the manager module global instance. The
property is named ``mgr``.
Each controller class derived from ``BaseController``has a class property that
points to the manager module global instance. The property is named ``mgr``.
There is another class property called ``logger`` to easily add log messages.
Example::
@ -171,9 +171,6 @@ Example::
self.logger.debug('Listing available servers')
return {'servers': self.mgr.list_servers()}
We also inject a class property ``logger`` that is provided by the module class
to easily add log messages.
How to write a unit test for a controller?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -3,12 +3,12 @@ from __future__ import absolute_import
import cherrypy
from ..tools import ApiController, AuthRequired, RESTController
from ..tools import ApiController, AuthRequired, RESTController, BaseController
@ApiController('ping')
@AuthRequired()
class Ping(object):
class Ping(BaseController):
@cherrypy.expose
def default(self):
return 'pong'

View File

@ -9,6 +9,7 @@ import os
import pkgutil
import sys
import six
import cherrypy
@ -55,10 +56,10 @@ def load_controllers(mgrmodule):
mod = importlib.import_module('.controllers.{}'.format(mod_name),
package='dashboard_v2')
for _, cls in mod.__dict__.items():
if isinstance(cls, type) and hasattr(cls, '_cp_controller_'):
# found controller
# Controllers MUST be derived from the class BaseController.
if isinstance(cls, BaseControllerMeta) and \
hasattr(cls, '_cp_controller_'):
cls.mgr = mgrmodule
cls.logger = mgrmodule.log
controllers.append(cls)
return controllers
@ -69,7 +70,51 @@ def _json_error_page(status, message, traceback, version):
version=version))
class RESTController(object):
class BaseControllerMeta(type):
@property
def mgr(cls):
"""
:return: Returns the MgrModule instance of this Ceph dashboard module.
"""
return cls._mgr_module
@mgr.setter
def mgr(cls, value):
"""
:param value: The MgrModule instance of the Ceph dashboard module.
"""
cls._mgr_module = value
@property
def logger(cls):
"""
:return: Returns the logger belonging to the Ceph dashboard module.
"""
return cls.mgr.log
class BaseController(six.with_metaclass(BaseControllerMeta, object)):
"""
Base class for all controllers providing API endpoints.
"""
_mgr_module = None
@property
def mgr(self):
"""
:return: Returns the MgrModule instance of this Ceph module.
"""
return self._mgr_module
@property
def logger(self):
"""
:return: Returns the logger belonging to the Ceph dashboard module.
"""
return self.mgr.log
class RESTController(BaseController):
"""
Base class for providing a RESTful interface to a resource.