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