aboutsummaryrefslogtreecommitdiffstats
path: root/keystone-moon/doc/source/extension_development.rst
diff options
context:
space:
mode:
Diffstat (limited to 'keystone-moon/doc/source/extension_development.rst')
-rw-r--r--keystone-moon/doc/source/extension_development.rst303
1 files changed, 303 insertions, 0 deletions
diff --git a/keystone-moon/doc/source/extension_development.rst b/keystone-moon/doc/source/extension_development.rst
new file mode 100644
index 00000000..a0248495
--- /dev/null
+++ b/keystone-moon/doc/source/extension_development.rst
@@ -0,0 +1,303 @@
+..
+ Licensed under the Apache License, Version 2.0 (the "License"); you may
+ not use this file except in compliance with the License. You may obtain
+ a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ License for the specific language governing permissions and limitations
+ under the License.
+
+=====================================
+Keystone Extensions Development Guide
+=====================================
+
+General
+=======
+
+This Extension Development Guide provides some mocked code to use as an
+Extension code base in the ``keystone/contrib/example`` folder.
+
+- All Extensions must be created in the ``keystone/contrib`` folder.
+- The new Extension code must be contained in a new folder under ``contrib``.
+- Whenever possible an Extension should follow the following directory
+ structure convention::
+
+ keystone/contrib/
+ └── my_extension
+    ├── backends (optional)
+    │   ├── __init__.py (mandatory)
+    │   └── sql.py (optional)
+    │   └── kvs.py (optional)
+    ├── migrate_repo (optional)
+    │   ├── __init__.py (mandatory)
+    │   ├── migrate.cfg (mandatory)
+    │   └── versions (mandatory)
+ │      ├── 001_create_tables.py (mandatory)
+ │      └── __init__.py (mandatory)
+    ├── __init__.py (mandatory)
+    ├── core.py (mandatory)
+    ├── controllers.py (mandatory for API Extension)
+    └── routers.py (mandatory for API Extension)
+
+- If the Extension implements an API Extension the ``controllers.py`` and
+ ``routers.py`` must be present and correctly handle the API Extension
+ requests and responses.
+- If the Extension implements backends a ``backends`` folder should exist.
+ Backends are defined to store data persistently and can use a variety of
+ technologies. Please see the Backends section in this document for more info.
+- If the Extension adds data structures, then a ``migrate_repo`` folder should
+ exist.
+- If configuration changes are required/introduced in the
+ ``keystone.conf.sample`` file, these should be kept disabled as default and
+ have their own section.
+- If configuration changes are required/introduced in the
+ ``keystone-paste.ini``, the new filter must be declared.
+- The module may register to listen to events by declaring the corresponding
+ callbacks in the ``core.py`` file.
+- The new extension should be disabled by default (it should not affect the
+ default application pipelines).
+
+Modifying the `keystone.conf.sample` File
+=========================================
+
+In the case an Extension needs to change the ``keystone.conf.sample`` file, it
+must follow the config file conventions and introduce a dedicated section.
+
+Example::
+
+ [example]
+ driver = keystone.contrib.example.backends.sql.mySQLClass
+
+ [my_other_extension]
+ extension_flag = False
+
+The Extension parameters expressed should be commented out since, by default,
+extensions are disabled.
+
+Example::
+
+ [example]
+ #driver = keystone.contrib.example.backends.sql.mySQLClass
+
+ [my_other_extension]
+ #extension_flag = False
+
+In case the Extension is overriding or re-implementing an existing portion of
+Keystone, the required change should be commented in the ``configuration.rst``
+but not placed in the `keystone.conf.sample` file to avoid unnecessary
+confusion.
+
+Modifying the ``keystone-paste.ini`` File
+=========================================
+
+In the case an Extension is augmenting a pipeline introducing a new ``filter``
+and/or APIs in the ``OS`` namespace, a corresponding ``filter:`` section is
+necessary to be introduced in the ``keystone-paste.ini`` file. The Extension
+should declare the filter factory constructor in the ``ini`` file.
+
+Example::
+
+ [filter:example]
+ paste.filter_factory = keystone.contrib.example.routers:ExampleRouter.
+ factory
+
+The ``filter`` must not be placed in the ``pipeline`` and treated as optional.
+How to add the extension in the pipeline should be specified in detail in the
+``configuration.rst`` file.
+
+Package Constructor File
+========================
+
+The ``__init__.py`` file represents the package constructor. Extension needs to
+import what is necessary from the ``core.py`` module.
+
+Example:
+
+.. code-block:: python
+
+ from keystone.contrib.example.core import *
+
+Core
+====
+
+The ``core.py`` file represents the main module defining the data structure and
+interface. In the ``Model View Control`` (MVC) model it represents the
+``Model`` part and it delegates to the ``Backends`` the data layer
+implementation.
+
+In case the ``core.py`` file contains a ``Manager`` and a ``Driver`` it must
+provide the dependency injections for the ``Controllers`` and/or other modules
+using the ``Manager``. A good practice is to call the dependency
+``extension_name_api``.
+
+Example:
+
+.. code-block:: python
+
+ @dependency.provider('example_api')
+ class Manager(manager.Manager):
+
+Routers
+=======
+
+``routers.py`` have the objective of routing the HTTP requests and direct them to
+the correct method within the ``Controllers``. Extension routers are extending
+the ``wsgi.ExtensionRouter``.
+
+Example:
+
+.. code-block:: python
+
+ from keystone.common import wsgi
+ from keystone.contrib.example import controllers
+
+
+ class ExampleRouter(wsgi.ExtensionRouter):
+
+ PATH_PREFIX = '/OS-EXAMPLE'
+
+ def add_routes(self, mapper):
+ example_controller = controllers.ExampleV3Controller()
+ mapper.connect(self.PATH_PREFIX + '/example',
+ controller=example_controller,
+ action='do_something',
+ conditions=dict(method=['GET']))
+
+Controllers
+===========
+
+``controllers.py`` have the objective of handing requests and implement the
+Extension logic. Controllers are consumers of 'Managers' API and must have all
+the dependency injections required. ``Controllers`` are extending the
+``V3Controller`` class.
+
+Example:
+
+.. code-block:: python
+
+ @dependency.requires('identity_api', 'example_api')
+ class ExampleV3Controller(controller.V3Controller):
+ pass
+
+Backends
+========
+
+The ``backends`` folder provides the model implementations for the different
+backends supported by the Extension. See General above for an example directory
+structure.
+
+If a SQL backend is provided, in the ``sql.py`` backend implementation it is
+mandatory to define the new table(s) that the Extension introduces and the
+attributes they are composed of.
+
+For more information on backends, refer to the `Keystone Architecture
+<http://docs.openstack.org/developer/keystone/architecture.html>`_
+documentation.
+
+Example:
+
+.. code-block:: python
+
+ class ExampleSQLBackend(sql.ModelBase, sql.DictBase):
+ """example table description."""
+ __tablename__ = 'example_table'
+ attributes = ['id', 'type', 'extra']
+
+ example_id = sql.Column(sql.String(64),
+ primary_key=True,
+ nullable=False)
+ ...
+
+SQL Migration Repository
+========================
+
+In case the Extension is adding SQL data structures, these must be stored in
+separate tables and must not be included in the ``migrate_repo`` of the core
+Keystone. Please refer to the ``migrate.cfg`` file to configure the Extension
+repository.
+
+In order to create the Extension tables and their attributes, a ``db_sync``
+command must be executed.
+
+Example:
+
+.. code-block:: bash
+
+ $ ./bin/keystone-manage db_sync --extension example
+
+Event Callbacks
+---------------
+
+Extensions may provide callbacks to Keystone (Identity) events.
+Extensions must provide the list of events of interest and the corresponding
+callbacks. Events are issued upon successful creation, modification, and
+deletion of the following Keystone resources:
+
+- ``group``
+- ``project``
+- ``role``
+- ``user``
+
+The extension's ``Manager`` class must contain the
+``event_callbacks`` attribute. It is a dictionary listing as keys
+those events that are of interest and the values should be the respective
+callbacks. Event callback registration is done via the
+dependency injection mechanism. During dependency provider registration, the
+``dependency.provider`` decorator looks for the ``event_callbacks``
+class attribute. If it exists the event callbacks are registered
+accordingly. In order to enable event callbacks, the extension's ``Manager``
+class must also be a dependency provider.
+
+Example:
+
+.. code-block:: python
+
+ # Since this is a dependency provider. Any code module using this or any
+ # other dependency provider (uses the dependency.provider decorator)
+ # will be enabled for the attribute based notification
+
+ @dependency.provider('example_api')
+ class ExampleManager(manager.Manager):
+ """Example Manager.
+
+ See :mod:`keystone.common.manager.Manager` for more details on
+ how this dynamically calls the backend.
+
+ """
+
+ def __init__(self):
+ self.event_callbacks = {
+ # Here we add the event_callbacks class attribute that
+ # calls project_deleted_callback when a project is deleted.
+ 'deleted': {
+ 'project': [
+ self.project_deleted_callback]}}
+ super(ExampleManager, self).__init__(
+ 'keystone.contrib.example.core.ExampleDriver')
+
+ def project_deleted_callback(self, context, message):
+ # cleanup data related to the deleted project here
+
+A callback must accept the following parameters:
+
+- ``service`` - the service information (e.g. identity)
+- ``resource_type`` - the resource type (e.g. project)
+- ``operation`` - the operation (updated, created, deleted)
+- ``payload`` - the actual payload info of the resource that was acted on
+
+Current callback operations:
+
+- ``created``
+- ``deleted``
+- ``updated``
+
+Example:
+
+.. code-block:: python
+
+ def project_deleted_callback(self, service, resource_type, operation,
+ payload):