Merge "cleaned up extension development docs"
This commit is contained in:
		@@ -1,19 +1,30 @@
 | 
			
		||||
..
 | 
			
		||||
      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.
 | 
			
		||||
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`.
 | 
			
		||||
- 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 structure
 | 
			
		||||
  convention:
 | 
			
		||||
 | 
			
		||||
  convention::
 | 
			
		||||
 | 
			
		||||
      keystone
 | 
			
		||||
          \\\  contrib
 | 
			
		||||
@@ -32,37 +43,38 @@ Extension code base in the `keystone/contrib/example` folder.
 | 
			
		||||
 | 
			
		||||
                         \\\  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.
 | 
			
		||||
- 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 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 element.
 | 
			
		||||
- If configuration changes are required/introduced in the `keystone-paste.ini`,
 | 
			
		||||
  the new filter must be declared.
 | 
			
		||||
- 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).
 | 
			
		||||
 | 
			
		||||
`keystone.conf.sample` File
 | 
			
		||||
---------------------------
 | 
			
		||||
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 entry.
 | 
			
		||||
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
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    [myOtherExtension]
 | 
			
		||||
    [my_other_extension]
 | 
			
		||||
    extension_flag = False
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
The Extension parameters expressed should be commented out since, by default,
 | 
			
		||||
extensions are disabled.
 | 
			
		||||
 | 
			
		||||
@@ -71,23 +83,21 @@ Example::
 | 
			
		||||
    [example]
 | 
			
		||||
    #driver = keystone.contrib.example.backends.sql.mySQLClass
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    [myOtherExtension]
 | 
			
		||||
    [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.
 | 
			
		||||
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
 | 
			
		||||
=========================================
 | 
			
		||||
 | 
			
		||||
`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.
 | 
			
		||||
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::
 | 
			
		||||
 | 
			
		||||
@@ -95,16 +105,15 @@ Example::
 | 
			
		||||
    paste.filter_factory = keystone.contrib.example.routers:ExampleRouter.
 | 
			
		||||
    factory
 | 
			
		||||
 | 
			
		||||
The `filter` must not be placed in the `pipeline` and treated as optional.
 | 
			
		||||
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.
 | 
			
		||||
 | 
			
		||||
``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.
 | 
			
		||||
The ``__init__.py`` file represents the package constructor. Extension needs to
 | 
			
		||||
import what is necessary from the ``core.py`` module.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
@@ -112,18 +121,18 @@ Example:
 | 
			
		||||
 | 
			
		||||
   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`.
 | 
			
		||||
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:
 | 
			
		||||
 | 
			
		||||
@@ -132,14 +141,12 @@ Example:
 | 
			
		||||
    @dependency.provider('example_api')
 | 
			
		||||
    class Manager(manager.Manager):
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Routers
 | 
			
		||||
-------
 | 
			
		||||
 | 
			
		||||
`routers.py` have the objective of routing the HTTP requests and direct them to
 | 
			
		||||
the right method within the `Controllers`. Extension routers are extending the
 | 
			
		||||
`wsgi.ExtensionRouter`.
 | 
			
		||||
=======
 | 
			
		||||
 | 
			
		||||
``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:
 | 
			
		||||
 | 
			
		||||
@@ -159,18 +166,14 @@ Example:
 | 
			
		||||
                           controller=example_controller,
 | 
			
		||||
                           action='do_something',
 | 
			
		||||
                           conditions=dict(method=['GET']))
 | 
			
		||||
        ...
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Controllers
 | 
			
		||||
-----------
 | 
			
		||||
===========
 | 
			
		||||
 | 
			
		||||
`controllers.py` have the objective of handing requests and implement the
 | 
			
		||||
``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.
 | 
			
		||||
 | 
			
		||||
the dependency injections required. ``Controllers`` are extending the
 | 
			
		||||
``V3Controller`` class.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
@@ -178,16 +181,14 @@ Example:
 | 
			
		||||
 | 
			
		||||
    @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.
 | 
			
		||||
The folder structure must be the following:
 | 
			
		||||
========
 | 
			
		||||
 | 
			
		||||
The ``backends`` folder provides the model implementations for the different
 | 
			
		||||
backends supported by the Extension. The folder structure must be the
 | 
			
		||||
following::
 | 
			
		||||
 | 
			
		||||
    keystone
 | 
			
		||||
        \\\  contrib
 | 
			
		||||
@@ -199,16 +200,13 @@ The folder structure must be the following:
 | 
			
		||||
 | 
			
		||||
                              \\\   kvs.py            (optional)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
If a SQL backend is provided, in the `sql.py` backend implementation it is
 | 
			
		||||
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 please consult the Keystone Architecture
 | 
			
		||||
documentation:
 | 
			
		||||
(http://docs.openstack.org/developer/keystone/architecture.html)
 | 
			
		||||
 | 
			
		||||
For more information on backends, refer to the `Keystone Architecture
 | 
			
		||||
<http://docs.openstack.org/developer/keystone/architecture.html>`_
 | 
			
		||||
documentation.
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
@@ -224,38 +222,33 @@ Example:
 | 
			
		||||
                                nullable=False)
 | 
			
		||||
        ...
 | 
			
		||||
 | 
			
		||||
SQL Migration Repository
 | 
			
		||||
========================
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Migrate Repository
 | 
			
		||||
------------------
 | 
			
		||||
 | 
			
		||||
In case the Extension is adding data structures, these must be stored in
 | 
			
		||||
separate tables and must not be included in the `migrate_repo` of the core
 | 
			
		||||
Keystone. Please refere to the 'migrate.cfg' file to configure the Extension
 | 
			
		||||
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 its attributes, a db_sync command
 | 
			
		||||
must be executed.
 | 
			
		||||
 | 
			
		||||
In order to create the Extension tables and their attributes, a ``db_sync``
 | 
			
		||||
command must be executed.
 | 
			
		||||
 | 
			
		||||
Example::
 | 
			
		||||
 | 
			
		||||
     ./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``
 | 
			
		||||
- ``group``
 | 
			
		||||
- ``project``
 | 
			
		||||
- ``role``
 | 
			
		||||
- ``user``
 | 
			
		||||
 | 
			
		||||
The extension's ``Manager`` class must contain the
 | 
			
		||||
``event_callbacks`` attribute. It is a dictionary listing as keys
 | 
			
		||||
@@ -299,20 +292,20 @@ Example:
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
- ``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``
 | 
			
		||||
- ``created``
 | 
			
		||||
- ``deleted``
 | 
			
		||||
- ``updated``
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
 | 
			
		||||
.. code:: python
 | 
			
		||||
 | 
			
		||||
      def project_deleted_callback(self, service, resource_type, operation,
 | 
			
		||||
                                   payload):
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user