]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard_v2: Refactor controller base class
authorVolker Theile <vtheile@suse.com>
Tue, 30 Jan 2018 10:58:46 +0000 (11:58 +0100)
committerRicardo Dias <rdias@suse.com>
Mon, 5 Mar 2018 13:07:03 +0000 (13:07 +0000)
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>
src/pybind/mgr/dashboard_v2/.gitignore
src/pybind/mgr/dashboard_v2/README.rst
src/pybind/mgr/dashboard_v2/controllers/ping.py
src/pybind/mgr/dashboard_v2/tools.py

index 6274710671afa39d340fe1546b22a1a257f7a233..15922e4b09fd3492ef5041b6fe27a2215ddc4662 100644 (file)
@@ -9,6 +9,7 @@ __pycache__
 # IDE
 .vscode
 .idea
+*.egg
 
 # virtualenv
 venv
index 280d30df3d89e2cdff169a7dfe98b2da2afa2a72..5e40d34493152ca4649555bff960070a6d324600 100644 (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?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
index 71fa743b963115d74f7b30972bfecda186049bad..d4a419a259ee0232e8725300ee90d61a8644285d 100644 (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'
index 6cc8688db6d2a3cc8cb50891b64348e1ab835e01..7a7f397331ef127e3608dd45e56a2b08a9334a52 100644 (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.