diff --git a/doc/ext/__init__.py b/doc/ext/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/doc/ext/list_plugins.py b/doc/ext/list_plugins.py new file mode 100644 index 00000000..96268804 --- /dev/null +++ b/doc/ext/list_plugins.py @@ -0,0 +1,93 @@ +# 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. + +import inspect + +from docutils import nodes +from docutils.parsers import rst +from docutils.parsers.rst import directives +from docutils.statemachine import ViewList +from sphinx.util.nodes import nested_parse_with_titles + +from stevedore import extension + + +class ListAuthPluginsDirective(rst.Directive): + """Present a simple list of the plugins in a namespace.""" + + option_spec = { + 'class': directives.class_option, + 'overline-style': directives.single_char_or_unicode, + 'underline-style': directives.single_char_or_unicode, + } + + has_content = True + + @property + def app(self): + return self.state.document.settings.env.app + + def report_load_failure(mgr, ep, err): + self.app.warn(u'Failed to load %s: %s' % (ep.module_name, err)) + + def display_plugin(self, ext): + overline_style = self.options.get('overline-style', '') + underline_style = self.options.get('underline-style', '=') + + if overline_style: + yield overline_style * len(ext.name) + + yield ext.name + + if underline_style: + yield underline_style * len(ext.name) + + yield "\n" + + doc = inspect.getdoc(ext.obj) + if doc: + yield doc + yield "\n" + yield "------" + + yield "\n" + + for opt in ext.obj.get_options(): + yield ":%s: %s" % (opt.name, opt.help) + + yield "\n" + + def run(self): + mgr = extension.ExtensionManager( + 'keystoneauth1.plugin', + on_load_failure_callback=self.report_load_failure, + invoke_on_load=True, + ) + + result = ViewList() + + for name in sorted(mgr.names()): + for line in self.display_plugin(mgr[name]): + for l in line.splitlines(): + result.append(l, mgr[name].entry_point.module_name) + + # Parse what we have into a new section. + node = nodes.section() + node.document = self.state.document + nested_parse_with_titles(self.state, result, node) + + return node.children + + +def setup(app): + app.info('loading keystoneauth1 plugins') + app.add_directive('list-auth-plugins', ListAuthPluginsDirective) diff --git a/doc/source/conf.py b/doc/source/conf.py index 9be29ee6..d6e4a195 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -24,6 +24,8 @@ import pbr.version sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..', '..'))) +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), + '..'))) # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -40,6 +42,7 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.coverage', 'sphinx.ext.intersphinx', 'oslosphinx', + 'ext.list_plugins', ] todo_include_todos = True diff --git a/doc/source/index.rst b/doc/source/index.rst index 47538725..8c433ecf 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -13,6 +13,7 @@ Contents: using-sessions authentication-plugins + plugin-options extras migrating diff --git a/doc/source/plugin-options.rst b/doc/source/plugin-options.rst new file mode 100644 index 00000000..4417f81b --- /dev/null +++ b/doc/source/plugin-options.rst @@ -0,0 +1,92 @@ +============== +Plugin Options +============== + +Using plugins via config file +----------------------------- + +When using the plugins via config file you define the plugin name as +``auth_type``. The options of the plugin are then specified while replacing +``-`` with ``_`` to be valid in configuration. + +For example to use the password_ plugin in a config file you would specify: + +.. code-block:: ini + + [section] + auth_url = http://keystone.example.com:5000/ + auth_type = password + username = myuser + password = mypassword + project_name = myproject + default_domain_name = mydomain + + +Using plugins via CLI +--------------------- + +When using auth plugins via CLI via ``os-client-config`` or ``shade`` you can +specify parameters via environment configuration by using the pattern ``OS_`` +followed by the uppercase parameter name replacing ``-`` with ``_``. + +For example to use the password_ plugin via environment variable you specify: + +.. code-block:: bash + + export OS_AUTH_TYPE=password + export OS_AUTH_URL=http://keystone.example.com:5000/ + export OS_USERNAME=myuser + export OS_PASSWORD=mypassword + export OS_PROJECT_NAME=myproject + export OS_DEFAULT_DOMAIN_NAME=mydomain + +Specifying operations via CLI parameter will override the environment +parameter. These are specified with the pattern ``--os-`` and the parameter +name. Using the password_ example again: + +.. code-block:: bash + + openstack --os-auth-type password \ + --os-auth-url http://keystone.example.com:5000/ \ + --os-username myuser \ + --os-password mypassword \ + --os-project-name myproject \ + --os-default-domain-name mydomain \ + operation + +Additional loaders +------------------ + +The configuration and CLI loaders are quite commonly used however similar +concepts are found in other situations such as ``os-client-config`` in which +you specify authentication and other cloud parameters in a ``clouds.yaml`` +file. + +Loaders such as these use the same plugin options listed below, but via their +own mechanism. In ``os-client-config`` the password_ plugin looks like: + +.. code-block:: yaml + + clouds: + mycloud: + auth_type: password + auth: + auth_url: http://keystone.example.com:5000/ + auth_type: password + username: myuser + password: mypassword + project_name: myproject + default_domain_name: mydomain + +However different services may implement loaders in their own way and you +should consult their relevant documentation. The same auth options will be +available. + + +Available Plugins +----------------- + +This is a listing of all included plugins and the options that they accept. +Plugins are listed alphabetically and not in any order of priority. + +.. list-auth-plugins:: diff --git a/keystoneauth1/loading/_plugins/admin_token.py b/keystoneauth1/loading/_plugins/admin_token.py index abffdc2c..3aba63d3 100644 --- a/keystoneauth1/loading/_plugins/admin_token.py +++ b/keystoneauth1/loading/_plugins/admin_token.py @@ -15,6 +15,17 @@ from keystoneauth1 import token_endpoint class AdminToken(loading.BaseLoader): + """Use an existing token and a known endpoint to perform requests. + + This plugin is primarily useful for development or for use with identity + service ADMIN tokens. Because this token is used directly there is no + fetching a service catalog or determining scope information and so it + cannot be used by clients that expect use this scope information. + + Because there is no service catalog the endpoint that is supplied with + initialization is used for all operations performed with this plugin so + must be the full base URL to an actual service. + """ @property def plugin_class(self): diff --git a/keystoneauth1/loading/_plugins/identity/generic.py b/keystoneauth1/loading/_plugins/identity/generic.py index ab9b547e..b6c139c7 100644 --- a/keystoneauth1/loading/_plugins/identity/generic.py +++ b/keystoneauth1/loading/_plugins/identity/generic.py @@ -15,6 +15,18 @@ from keystoneauth1 import loading class Token(loading.BaseGenericLoader): + """Given an existing token rescope it to another target. + + This plugin uses the Identity service's rescope mechanism to get a new + token based upon an existing token. Because an auth plugin requires a + service catalog and scope information it is often easier to fetch a new + token based on an existing one than validate and reuse the one you already + have. + + As a generic plugin this plugin is identity version independent and will + discover available versions before use. This means it expects to be + providen an unversioned URL to operate against. + """ @property def plugin_class(self): @@ -32,6 +44,15 @@ class Token(loading.BaseGenericLoader): class Password(loading.BaseGenericLoader): + """Authenticate via a username and password. + + Authenticate to the identity service using an inbuilt username and + password. This is the standard and most common form of authentication. + + As a generic plugin this plugin is identity version independent and will + discover available versions before use. This means it expects to be + providen an unversioned URL to operate against. + """ @property def plugin_class(self):