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
|
Keystone Extensions Development Guide
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
|
|
||||||
General
|
General
|
||||||
-------
|
=======
|
||||||
|
|
||||||
This Extension Development Guide provides some mocked code to use as an
|
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.
|
||||||
- All Extensions must be created in the `keystone/contrib` folder.
|
- The new Extension code must be contained in a new folder under ``contrib``.
|
||||||
- The new Extension code must be contained in a new folder under `contrib`.
|
|
||||||
- Whenever possible an Extension should follow the following structure
|
- Whenever possible an Extension should follow the following structure
|
||||||
convention:
|
convention::
|
||||||
|
|
||||||
|
|
||||||
keystone
|
keystone
|
||||||
\\\ contrib
|
\\\ contrib
|
||||||
@@ -32,37 +43,38 @@ Extension code base in the `keystone/contrib/example` folder.
|
|||||||
|
|
||||||
\\\ routers.py (mandatory for API Extension)
|
\\\ routers.py (mandatory for API Extension)
|
||||||
|
|
||||||
|
- If the Extension implements an API Extension the ``controllers.py`` and
|
||||||
- If the Extension implements an API Extension the `controllers.py` and
|
``routers.py`` must be present and correctly handle the API Extension
|
||||||
`routers.py` must be present and correctly handle the API Extension requests
|
requests and responses.
|
||||||
and responses.
|
- If the Extension implements backends a ``backends`` folder should exist.
|
||||||
- If the Extension implements backends a `backends` folder should exist.
|
|
||||||
Backends are defined to store data persistently and can use a variety of
|
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.
|
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 the Extension adds data structures, then a ``migrate_repo`` folder should
|
||||||
- If configuration changes are required/introduced in the `keystone.conf.sample`
|
exist.
|
||||||
file, these should be kept disabled as default and have their own element.
|
- If configuration changes are required/introduced in the
|
||||||
- If configuration changes are required/introduced in the `keystone-paste.ini`,
|
``keystone.conf.sample`` file, these should be kept disabled as default and
|
||||||
the new filter must be declared.
|
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
|
- The module may register to listen to events by declaring the corresponding
|
||||||
callbacks in the ``core.py`` file.
|
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
|
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.
|
must follow the config file conventions and introduce a dedicated section.
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
[example]
|
[example]
|
||||||
driver = keystone.contrib.example.backends.sql.mySQLClass
|
driver = keystone.contrib.example.backends.sql.mySQLClass
|
||||||
|
|
||||||
|
[my_other_extension]
|
||||||
[myOtherExtension]
|
|
||||||
extension_flag = False
|
extension_flag = False
|
||||||
|
|
||||||
|
|
||||||
The Extension parameters expressed should be commented out since, by default,
|
The Extension parameters expressed should be commented out since, by default,
|
||||||
extensions are disabled.
|
extensions are disabled.
|
||||||
|
|
||||||
@@ -71,23 +83,21 @@ Example::
|
|||||||
[example]
|
[example]
|
||||||
#driver = keystone.contrib.example.backends.sql.mySQLClass
|
#driver = keystone.contrib.example.backends.sql.mySQLClass
|
||||||
|
|
||||||
|
[my_other_extension]
|
||||||
[myOtherExtension]
|
|
||||||
#extension_flag = False
|
#extension_flag = False
|
||||||
|
|
||||||
|
|
||||||
In case the Extension is overriding or re-implementing an existing portion of
|
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
|
Keystone, the required change should be commented in the ``configuration.rst``
|
||||||
not placed in the `keystone.conf.sample` file to avoid unnecessary confusion.
|
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
|
||||||
In the case an Extension is augmenting a pipeline introducing a new `filter`
|
should declare the filter factory constructor in the ``ini`` file.
|
||||||
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::
|
Example::
|
||||||
|
|
||||||
@@ -95,16 +105,15 @@ Example::
|
|||||||
paste.filter_factory = keystone.contrib.example.routers:ExampleRouter.
|
paste.filter_factory = keystone.contrib.example.routers:ExampleRouter.
|
||||||
factory
|
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
|
How to add the extension in the pipeline should be specified in detail in the
|
||||||
`configuration.rst` file.
|
``configuration.rst`` file.
|
||||||
|
|
||||||
|
|
||||||
Package Constructor File
|
Package Constructor File
|
||||||
------------------------
|
========================
|
||||||
|
|
||||||
The `__init__.py` file represents the package constructor. Extension needs to
|
The ``__init__.py`` file represents the package constructor. Extension needs to
|
||||||
import what is necessary from the `core.py` module.
|
import what is necessary from the ``core.py`` module.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -112,18 +121,18 @@ Example:
|
|||||||
|
|
||||||
from keystone.contrib.example.core import *
|
from keystone.contrib.example.core import *
|
||||||
|
|
||||||
|
|
||||||
Core
|
Core
|
||||||
----
|
====
|
||||||
|
|
||||||
The `core.py` file represents the main module defining the data structure and
|
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`
|
interface. In the ``Model View Control`` (MVC) model it represents the
|
||||||
part and it delegates to the `Backends` the data layer implementation.
|
``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`.
|
|
||||||
|
|
||||||
|
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:
|
Example:
|
||||||
|
|
||||||
@@ -132,14 +141,12 @@ Example:
|
|||||||
@dependency.provider('example_api')
|
@dependency.provider('example_api')
|
||||||
class Manager(manager.Manager):
|
class Manager(manager.Manager):
|
||||||
|
|
||||||
|
|
||||||
Routers
|
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:
|
Example:
|
||||||
|
|
||||||
@@ -159,18 +166,14 @@ Example:
|
|||||||
controller=example_controller,
|
controller=example_controller,
|
||||||
action='do_something',
|
action='do_something',
|
||||||
conditions=dict(method=['GET']))
|
conditions=dict(method=['GET']))
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Controllers
|
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
|
Extension logic. Controllers are consumers of 'Managers' API and must have all
|
||||||
the dependency injections required. `Controllers` are extending the
|
the dependency injections required. ``Controllers`` are extending the
|
||||||
`V3Controller` class.
|
``V3Controller`` class.
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -178,16 +181,14 @@ Example:
|
|||||||
|
|
||||||
@dependency.requires('identity_api', 'example_api')
|
@dependency.requires('identity_api', 'example_api')
|
||||||
class ExampleV3Controller(controller.V3Controller):
|
class ExampleV3Controller(controller.V3Controller):
|
||||||
...
|
pass
|
||||||
|
|
||||||
|
|
||||||
Backends
|
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
|
keystone
|
||||||
\\\ contrib
|
\\\ contrib
|
||||||
@@ -199,16 +200,13 @@ The folder structure must be the following:
|
|||||||
|
|
||||||
\\\ kvs.py (optional)
|
\\\ 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
|
mandatory to define the new table(s) that the Extension introduces and the
|
||||||
attributes they are composed of.
|
attributes they are composed of.
|
||||||
|
|
||||||
|
For more information on backends, refer to the `Keystone Architecture
|
||||||
For more information on Backends please consult the Keystone Architecture
|
<http://docs.openstack.org/developer/keystone/architecture.html>`_
|
||||||
documentation:
|
documentation.
|
||||||
(http://docs.openstack.org/developer/keystone/architecture.html)
|
|
||||||
|
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -224,38 +222,33 @@ Example:
|
|||||||
nullable=False)
|
nullable=False)
|
||||||
...
|
...
|
||||||
|
|
||||||
|
SQL Migration Repository
|
||||||
|
========================
|
||||||
|
|
||||||
|
In case the Extension is adding SQL data structures, these must be stored in
|
||||||
Migrate Repository
|
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
|
||||||
|
|
||||||
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
|
|
||||||
repository.
|
repository.
|
||||||
|
|
||||||
|
In order to create the Extension tables and their attributes, a ``db_sync``
|
||||||
In order to create the Extension tables and its attributes, a db_sync command
|
command must be executed.
|
||||||
must be executed.
|
|
||||||
|
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
./bin/keystone-manage db_sync --extension example
|
./bin/keystone-manage db_sync --extension example
|
||||||
|
|
||||||
|
|
||||||
Event Callbacks
|
Event Callbacks
|
||||||
-----------
|
---------------
|
||||||
|
|
||||||
Extensions may provide callbacks to Keystone (Identity) events.
|
Extensions may provide callbacks to Keystone (Identity) events.
|
||||||
Extensions must provide the list of events of interest and the corresponding
|
Extensions must provide the list of events of interest and the corresponding
|
||||||
callbacks. Events are issued upon successful creation, modification, and
|
callbacks. Events are issued upon successful creation, modification, and
|
||||||
deletion of the following Keystone resources:
|
deletion of the following Keystone resources:
|
||||||
|
|
||||||
* ``group``
|
- ``group``
|
||||||
* ``project``
|
- ``project``
|
||||||
* ``role``
|
- ``role``
|
||||||
* ``user``
|
- ``user``
|
||||||
|
|
||||||
The extension's ``Manager`` class must contain the
|
The extension's ``Manager`` class must contain the
|
||||||
``event_callbacks`` attribute. It is a dictionary listing as keys
|
``event_callbacks`` attribute. It is a dictionary listing as keys
|
||||||
@@ -299,20 +292,20 @@ Example:
|
|||||||
|
|
||||||
A callback must accept the following parameters:
|
A callback must accept the following parameters:
|
||||||
|
|
||||||
* ``service`` - the service information (e.g. identity)
|
- ``service`` - the service information (e.g. identity)
|
||||||
* ``resource_type`` - the resource type (e.g. project)
|
- ``resource_type`` - the resource type (e.g. project)
|
||||||
* ``operation`` - the operation (updated, created, deleted)
|
- ``operation`` - the operation (updated, created, deleted)
|
||||||
* ``payload`` - the actual payload info of the resource that was acted on
|
- ``payload`` - the actual payload info of the resource that was acted on
|
||||||
|
|
||||||
Current callback operations:
|
Current callback operations:
|
||||||
|
|
||||||
* ``created``
|
- ``created``
|
||||||
* ``deleted``
|
- ``deleted``
|
||||||
* ``updated``
|
- ``updated``
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
.. code:: python
|
.. code:: python
|
||||||
|
|
||||||
def project_deleted_callback(self, service, resource_type, operation,
|
def project_deleted_callback(self, service, resource_type, operation,
|
||||||
payload):
|
payload):
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user