Merge remote-tracking branch 'docs/master'
This commit is contained in:
commit
f7015de3c6
1
docs/.gitignore
vendored
Normal file
1
docs/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
build/
|
90
docs/Makefile
Normal file
90
docs/Makefile
Normal file
@ -0,0 +1,90 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
SPHINXSOURCE = source
|
||||
PAPER =
|
||||
BUILDDIR = build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SPHINXSOURCE)
|
||||
|
||||
.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/python-keystoneclient.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/python-keystoneclient.qhc"
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
|
||||
"run these through (pdf)latex."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
0
docs/ext/__init__.py
Normal file
0
docs/ext/__init__.py
Normal file
46
docs/ext/apidoc.py
Normal file
46
docs/ext/apidoc.py
Normal file
@ -0,0 +1,46 @@
|
||||
# Copyright 2014 OpenStack Foundation
|
||||
#
|
||||
# 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.
|
||||
|
||||
# NOTE(blk-u): Uncomment the [pbr] section in setup.cfg and remove this
|
||||
# Sphinx extension when https://launchpad.net/bugs/1260495 is fixed.
|
||||
|
||||
import os.path as path
|
||||
|
||||
from sphinx import apidoc
|
||||
|
||||
|
||||
# NOTE(blk-u): pbr will run Sphinx multiple times when it generates
|
||||
# documentation. Once for each builder. To run this extension we use the
|
||||
# 'builder-inited' hook that fires at the beginning of a Sphinx build.
|
||||
# We use ``run_already`` to make sure apidocs are only generated once
|
||||
# even if Sphinx is run multiple times.
|
||||
run_already = False
|
||||
|
||||
|
||||
def run_apidoc(app):
|
||||
global run_already
|
||||
if run_already:
|
||||
return
|
||||
run_already = True
|
||||
|
||||
package_dir = path.abspath(path.join(app.srcdir, '..', '..',
|
||||
'keystoneclient'))
|
||||
source_dir = path.join(app.srcdir, 'api')
|
||||
apidoc.main(['apidoc', package_dir, '-f',
|
||||
'-H', 'keystoneclient Modules',
|
||||
'-o', source_dir])
|
||||
|
||||
|
||||
def setup(app):
|
||||
app.connect('builder-inited', run_apidoc)
|
0
docs/source/_templates/.placeholder
Normal file
0
docs/source/_templates/.placeholder
Normal file
83
docs/source/_theme/layout.html
Normal file
83
docs/source/_theme/layout.html
Normal file
@ -0,0 +1,83 @@
|
||||
{% extends "basic/layout.html" %}
|
||||
{% set css_files = css_files + ['_static/tweaks.css'] %}
|
||||
{% set script_files = script_files + ['_static/jquery.tweet.js'] %}
|
||||
|
||||
{%- macro sidebar() %}
|
||||
{%- if not embedded %}{% if not theme_nosidebar|tobool %}
|
||||
<div class="sphinxsidebar">
|
||||
<div class="sphinxsidebarwrapper">
|
||||
{%- block sidebarlogo %}
|
||||
{%- if logo %}
|
||||
<p class="logo"><a href="{{ pathto(master_doc) }}">
|
||||
<img class="logo" src="{{ pathto('_static/' + logo, 1) }}" alt="Logo"/>
|
||||
</a></p>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
{%- block sidebartoc %}
|
||||
{%- if display_toc %}
|
||||
<h3><a href="{{ pathto(master_doc) }}">{{ _('Table Of Contents') }}</a></h3>
|
||||
{{ toc }}
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
{%- block sidebarrel %}
|
||||
{%- if prev %}
|
||||
<h4>{{ _('Previous topic') }}</h4>
|
||||
<p class="topless"><a href="{{ prev.link|e }}"
|
||||
title="{{ _('previous chapter') }}">{{ prev.title }}</a></p>
|
||||
{%- endif %}
|
||||
{%- if next %}
|
||||
<h4>{{ _('Next topic') }}</h4>
|
||||
<p class="topless"><a href="{{ next.link|e }}"
|
||||
title="{{ _('next chapter') }}">{{ next.title }}</a></p>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
{%- block sidebarsourcelink %}
|
||||
{%- if show_source and has_source and sourcename %}
|
||||
<h3>{{ _('This Page') }}</h3>
|
||||
<ul class="this-page-menu">
|
||||
<li><a href="{{ pathto('_sources/' + sourcename, true)|e }}"
|
||||
rel="nofollow">{{ _('Show Source') }}</a></li>
|
||||
</ul>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
{%- if customsidebar %}
|
||||
{% include customsidebar %}
|
||||
{%- endif %}
|
||||
{%- block sidebarsearch %}
|
||||
{%- if pagename != "search" %}
|
||||
<div id="searchbox" style="display: none">
|
||||
<h3>{{ _('Quick search') }}</h3>
|
||||
<form class="search" action="{{ pathto('search') }}" method="get">
|
||||
<input type="text" name="q" size="18" />
|
||||
<input type="submit" value="{{ _('Go') }}" />
|
||||
<input type="hidden" name="check_keywords" value="yes" />
|
||||
<input type="hidden" name="area" value="default" />
|
||||
</form>
|
||||
<p class="searchtip" style="font-size: 90%">
|
||||
{{ _('Enter search terms or a module, class or function name.') }}
|
||||
</p>
|
||||
</div>
|
||||
<script type="text/javascript">$('#searchbox').show(0);</script>
|
||||
{%- endif %}
|
||||
{%- endblock %}
|
||||
</div>
|
||||
</div>
|
||||
{%- endif %}{% endif %}
|
||||
{%- endmacro %}
|
||||
|
||||
{% block relbar1 %}{% endblock relbar1 %}
|
||||
|
||||
{% block header %}
|
||||
<div id="header">
|
||||
<h1 id="logo"><a href="http://www.openstack.org/">OpenStack</a></h1>
|
||||
<ul id="navigation">
|
||||
<li><a href="http://www.openstack.org/" title="Go to the Home page" class="link">Home</a></li>
|
||||
<li><a href="http://www.openstack.org/projects/" title="Go to the OpenStack Projects page">Projects</a></li>
|
||||
<li><a href="http://www.openstack.org/user-stories/" title="Go to the User Stories page" class="link">User Stories</a></li>
|
||||
<li><a href="http://www.openstack.org/community/" title="Go to the Community page" class="link">Community</a></li>
|
||||
<li><a href="http://www.openstack.org/blog/" title="Go to the OpenStack Blog">Blog</a></li>
|
||||
<li><a href="http://wiki.openstack.org/" title="Go to the OpenStack Wiki">Wiki</a></li>
|
||||
<li><a href="http://docs.openstack.org/" title="Go to OpenStack Documentation" class="current">Documentation</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
{% endblock %}
|
4
docs/source/_theme/theme.conf
Normal file
4
docs/source/_theme/theme.conf
Normal file
@ -0,0 +1,4 @@
|
||||
[theme]
|
||||
inherit = basic
|
||||
stylesheet = nature.css
|
||||
pygments_style = tango
|
241
docs/source/conf.py
Normal file
241
docs/source/conf.py
Normal file
@ -0,0 +1,241 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# python-keystoneclient documentation build configuration file, created by
|
||||
# sphinx-quickstart on Sun Dec 6 14:19:25 2009.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its containing
|
||||
# dir.
|
||||
#
|
||||
# Note that not all possible configuration values are present in this
|
||||
# autogenerated file.
|
||||
#
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import pbr.version
|
||||
|
||||
|
||||
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__),
|
||||
'..', '..')))
|
||||
|
||||
# NOTE(blk-u): Path for our Sphinx extension, remove when
|
||||
# https://launchpad.net/bugs/1260495 is fixed.
|
||||
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
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.append(os.path.abspath('.'))
|
||||
|
||||
# -- General configuration ----------------------------------------------------
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions
|
||||
# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
|
||||
extensions = ['sphinx.ext.autodoc',
|
||||
'sphinx.ext.todo',
|
||||
'sphinx.ext.coverage',
|
||||
'sphinx.ext.intersphinx',
|
||||
# NOTE(blk-u): Uncomment the [pbr] section in setup.cfg and
|
||||
# remove this Sphinx extension when
|
||||
# https://launchpad.net/bugs/1260495 is fixed.
|
||||
'ext.apidoc',
|
||||
]
|
||||
|
||||
todo_include_todos = True
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'python-keystoneclient'
|
||||
copyright = 'OpenStack Contributors'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
version_info = pbr.version.VersionInfo('python-keystoneclient')
|
||||
# The short X.Y version.
|
||||
version = version_info.version_string()
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = version_info.release_string()
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of documents that shouldn't be included in the build.
|
||||
#unused_docs = []
|
||||
|
||||
# List of directories, relative to source directory, that shouldn't be searched
|
||||
# for source files.
|
||||
exclude_trees = []
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
# Grouping the document tree for man pages.
|
||||
# List of tuples 'sourcefile', 'target', 'title', 'Authors name', 'manual'
|
||||
|
||||
man_pages = [
|
||||
('man/keystone', 'keystone', 'Client for OpenStack Identity API',
|
||||
['OpenStack Contributors'], 1),
|
||||
]
|
||||
|
||||
# -- Options for HTML output --------------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. Major themes that come with
|
||||
# Sphinx are currently 'default' and 'sphinxdoc'.
|
||||
html_theme_path = ["."]
|
||||
html_theme = '_theme'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['static']
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
git_cmd = "git log --pretty=format:'%ad, commit %h' --date=local -n1"
|
||||
html_last_updated_fmt = os.popen(git_cmd).read()
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_use_modindex = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = ''
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'python-keystoneclientdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output -------------------------------------------------
|
||||
|
||||
# The paper size ('letter' or 'a4').
|
||||
#latex_paper_size = 'letter'
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#latex_font_size = '10pt'
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual])
|
||||
# .
|
||||
latex_documents = [
|
||||
('index', 'python-keystoneclient.tex',
|
||||
'python-keystoneclient Documentation',
|
||||
'Nebula Inc, based on work by Rackspace and Jacob Kaplan-Moss',
|
||||
'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#latex_preamble = ''
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_use_modindex = True
|
||||
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {'python': ('http://docs.python.org/', None),
|
||||
'nova': ('http://nova.openstack.org', None),
|
||||
'swift': ('http://swift.openstack.org', None),
|
||||
'glance': ('http://glance.openstack.org', None)}
|
48
docs/source/images/graphs_authComp.svg
Normal file
48
docs/source/images/graphs_authComp.svg
Normal file
@ -0,0 +1,48 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.27.20101213.0545 (20101213.0545)
|
||||
-->
|
||||
<!-- Title: AuthComp Pages: 1 -->
|
||||
<svg width="510pt" height="118pt"
|
||||
viewBox="0.00 0.00 510.00 118.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph1" class="graph" transform="scale(1 1) rotate(0) translate(4 114)">
|
||||
<title>AuthComp</title>
|
||||
<polygon fill="white" stroke="white" points="-4,5 -4,-114 507,-114 507,5 -4,5"/>
|
||||
<!-- AuthComp -->
|
||||
<g id="node2" class="node"><title>AuthComp</title>
|
||||
<polygon fill="#fdefe3" stroke="#c00000" points="292,-65 194,-65 194,-25 292,-25 292,-65"/>
|
||||
<text text-anchor="middle" x="243" y="-48.4" font-family="Helvetica,sans-Serif" font-size="14.00">Auth</text>
|
||||
<text text-anchor="middle" x="243" y="-32.4" font-family="Helvetica,sans-Serif" font-size="14.00">Component</text>
|
||||
</g>
|
||||
<!-- Reject -->
|
||||
<!-- AuthComp->Reject -->
|
||||
<g id="edge3" class="edge"><title>AuthComp->Reject</title>
|
||||
<path fill="none" stroke="black" d="M193.933,-51.2787C157.514,-55.939 108.38,-62.2263 73.8172,-66.649"/>
|
||||
<polygon fill="black" stroke="black" points="73.0637,-63.2168 63.5888,-67.9578 73.9522,-70.1602 73.0637,-63.2168"/>
|
||||
<text text-anchor="middle" x="129" y="-97.4" font-family="Times,serif" font-size="14.00">Reject</text>
|
||||
<text text-anchor="middle" x="129" y="-82.4" font-family="Times,serif" font-size="14.00">Unauthenticated</text>
|
||||
<text text-anchor="middle" x="129" y="-67.4" font-family="Times,serif" font-size="14.00">Requests</text>
|
||||
</g>
|
||||
<!-- Service -->
|
||||
<g id="node6" class="node"><title>Service</title>
|
||||
<polygon fill="#d1ebf1" stroke="#1f477d" points="502,-65 408,-65 408,-25 502,-25 502,-65"/>
|
||||
<text text-anchor="middle" x="455" y="-48.4" font-family="Helvetica,sans-Serif" font-size="14.00">OpenStack</text>
|
||||
<text text-anchor="middle" x="455" y="-32.4" font-family="Helvetica,sans-Serif" font-size="14.00">Service</text>
|
||||
</g>
|
||||
<!-- AuthComp->Service -->
|
||||
<g id="edge5" class="edge"><title>AuthComp->Service</title>
|
||||
<path fill="none" stroke="black" d="M292.17,-45C323.626,-45 364.563,-45 397.52,-45"/>
|
||||
<polygon fill="black" stroke="black" points="397.917,-48.5001 407.917,-45 397.917,-41.5001 397.917,-48.5001"/>
|
||||
<text text-anchor="middle" x="350" y="-77.4" font-family="Times,serif" font-size="14.00">Forward</text>
|
||||
<text text-anchor="middle" x="350" y="-62.4" font-family="Times,serif" font-size="14.00">Authenticated</text>
|
||||
<text text-anchor="middle" x="350" y="-47.4" font-family="Times,serif" font-size="14.00">Requests</text>
|
||||
</g>
|
||||
<!-- Start -->
|
||||
<!-- Start->AuthComp -->
|
||||
<g id="edge7" class="edge"><title>Start->AuthComp</title>
|
||||
<path fill="none" stroke="black" d="M59.1526,-21.4745C90.4482,-25.4792 142.816,-32.1802 183.673,-37.4084"/>
|
||||
<polygon fill="black" stroke="black" points="183.43,-40.9057 193.793,-38.7034 184.318,-33.9623 183.43,-40.9057"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.9 KiB |
53
docs/source/images/graphs_authCompDelegate.svg
Normal file
53
docs/source/images/graphs_authCompDelegate.svg
Normal file
@ -0,0 +1,53 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.27.20101213.0545 (20101213.0545)
|
||||
-->
|
||||
<!-- Title: AuthCompDelegate Pages: 1 -->
|
||||
<svg width="588pt" height="104pt"
|
||||
viewBox="0.00 0.00 588.00 104.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph1" class="graph" transform="scale(1 1) rotate(0) translate(4 100)">
|
||||
<title>AuthCompDelegate</title>
|
||||
<polygon fill="white" stroke="white" points="-4,5 -4,-100 585,-100 585,5 -4,5"/>
|
||||
<!-- AuthComp -->
|
||||
<g id="node2" class="node"><title>AuthComp</title>
|
||||
<polygon fill="#fdefe3" stroke="#c00000" points="338,-65 240,-65 240,-25 338,-25 338,-65"/>
|
||||
<text text-anchor="middle" x="289" y="-48.4" font-family="Helvetica,sans-Serif" font-size="14.00">Auth</text>
|
||||
<text text-anchor="middle" x="289" y="-32.4" font-family="Helvetica,sans-Serif" font-size="14.00">Component</text>
|
||||
</g>
|
||||
<!-- Reject -->
|
||||
<!-- AuthComp->Reject -->
|
||||
<g id="edge3" class="edge"><title>AuthComp->Reject</title>
|
||||
<path fill="none" stroke="black" d="M239.6,-50.1899C191.406,-55.2531 118.917,-62.8686 73.5875,-67.6309"/>
|
||||
<polygon fill="black" stroke="black" points="73.0928,-64.1635 63.5132,-68.6893 73.8242,-71.1252 73.0928,-64.1635"/>
|
||||
<text text-anchor="middle" x="152" y="-83.4" font-family="Times,serif" font-size="14.00">Reject Requests</text>
|
||||
<text text-anchor="middle" x="152" y="-68.4" font-family="Times,serif" font-size="14.00">Indicated by the Service</text>
|
||||
</g>
|
||||
<!-- Service -->
|
||||
<g id="node6" class="node"><title>Service</title>
|
||||
<polygon fill="#d1ebf1" stroke="#1f477d" points="580,-65 486,-65 486,-25 580,-25 580,-65"/>
|
||||
<text text-anchor="middle" x="533" y="-48.4" font-family="Helvetica,sans-Serif" font-size="14.00">OpenStack</text>
|
||||
<text text-anchor="middle" x="533" y="-32.4" font-family="Helvetica,sans-Serif" font-size="14.00">Service</text>
|
||||
</g>
|
||||
<!-- AuthComp->Service -->
|
||||
<g id="edge5" class="edge"><title>AuthComp->Service</title>
|
||||
<path fill="none" stroke="black" d="M338.009,-49.0804C344.065,-49.4598 350.172,-49.7828 356,-50 405.743,-51.8535 418.259,-51.9103 468,-50 470.523,-49.9031 473.101,-49.7851 475.704,-49.6504"/>
|
||||
<polygon fill="black" stroke="black" points="476.03,-53.1374 485.807,-49.0576 475.62,-46.1494 476.03,-53.1374"/>
|
||||
<text text-anchor="middle" x="412" y="-68.4" font-family="Times,serif" font-size="14.00">Forward Requests</text>
|
||||
<text text-anchor="middle" x="412" y="-53.4" font-family="Times,serif" font-size="14.00">with Identiy Status</text>
|
||||
</g>
|
||||
<!-- Service->AuthComp -->
|
||||
<g id="edge7" class="edge"><title>Service->AuthComp</title>
|
||||
<path fill="none" stroke="black" d="M495.062,-24.9037C486.397,-21.2187 477.064,-17.9304 468,-16 419.314,-5.63183 404.743,-5.9037 356,-16 349.891,-17.2653 343.655,-19.116 337.566,-21.2803"/>
|
||||
<polygon fill="black" stroke="black" points="336.234,-18.0426 328.158,-24.9003 338.748,-24.5757 336.234,-18.0426"/>
|
||||
<text text-anchor="middle" x="412" y="-33.4" font-family="Times,serif" font-size="14.00">Send Response OR</text>
|
||||
<text text-anchor="middle" x="412" y="-18.4" font-family="Times,serif" font-size="14.00">Reject Message</text>
|
||||
</g>
|
||||
<!-- Start -->
|
||||
<!-- Start->AuthComp -->
|
||||
<g id="edge9" class="edge"><title>Start->AuthComp</title>
|
||||
<path fill="none" stroke="black" d="M59.0178,-20.8384C99.2135,-25.0613 175.782,-33.1055 229.492,-38.7482"/>
|
||||
<polygon fill="black" stroke="black" points="229.265,-42.2435 239.576,-39.8076 229.997,-35.2818 229.265,-42.2435"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.5 KiB |
42
docs/source/index.rst
Normal file
42
docs/source/index.rst
Normal file
@ -0,0 +1,42 @@
|
||||
Python bindings to the OpenStack Identity API (Keystone)
|
||||
========================================================
|
||||
|
||||
This is a client for OpenStack Identity API. There's a Python API for
|
||||
:doc:`Identity API v3 <using-api-v3>` and :doc:`v2 <using-api-v2>` (the
|
||||
:mod:`keystoneclient` modules), and a command-line script (installed as
|
||||
:doc:`keystone <man/keystone>`).
|
||||
|
||||
Contents:
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
man/keystone
|
||||
using-sessions
|
||||
using-api-v2
|
||||
using-api-v3
|
||||
|
||||
middlewarearchitecture
|
||||
|
||||
api/modules
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
Code is hosted `on GitHub`_. Submit bugs to the Keystone project on
|
||||
`Launchpad`_. Submit code to the ``openstack/python-keystoneclient`` project
|
||||
using `Gerrit`_.
|
||||
|
||||
.. _on GitHub: https://github.com/openstack/python-keystoneclient
|
||||
.. _Launchpad: https://launchpad.net/python-keystoneclient
|
||||
.. _Gerrit: http://wiki.openstack.org/GerritWorkflow
|
||||
|
||||
Run tests with ``python setup.py test``.
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
150
docs/source/man/keystone.rst
Normal file
150
docs/source/man/keystone.rst
Normal file
@ -0,0 +1,150 @@
|
||||
========================================
|
||||
:program:`keystone` command line utility
|
||||
========================================
|
||||
|
||||
.. program:: keystone
|
||||
.. highlight:: bash
|
||||
|
||||
SYNOPSIS
|
||||
========
|
||||
|
||||
:program:`keystone` [options] <command> [command-options]
|
||||
|
||||
:program:`keystone help`
|
||||
|
||||
:program:`keystone help` <command>
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
===========
|
||||
|
||||
The :program:`keystone` command line utility interacts with services providing
|
||||
OpenStack Identity API (e.g. Keystone).
|
||||
|
||||
To communicate with the API, you will need to be authenticated - and the
|
||||
:program:`keystone` provides multiple options for this.
|
||||
|
||||
While bootstrapping keystone the authentication is accomplished with a
|
||||
shared secret token and the location of the Identity API endpoint. The
|
||||
shared secret token is configured in keystone.conf as "admin_token".
|
||||
|
||||
You can specify those values on the command line with :option:`--os-token`
|
||||
and :option:`--os-endpoint`, or set them in environment variables:
|
||||
|
||||
.. envvar:: OS_SERVICE_TOKEN
|
||||
|
||||
Your keystone administrative token
|
||||
|
||||
.. envvar:: OS_SERVICE_ENDPOINT
|
||||
|
||||
Your Identity API endpoint
|
||||
|
||||
The command line options will override any environment variables set.
|
||||
|
||||
If you already have accounts, you can use your OpenStack username and
|
||||
password. You can do this with the :option:`--os-username`,
|
||||
:option:`--os-password`.
|
||||
|
||||
Keystone allows a user to be associated with one or more projects which are
|
||||
historically called tenants. To specify the project for which you want to
|
||||
authorize against, you may optionally specify a :option:`--os-tenant-id` or
|
||||
:option:`--os-tenant-name`.
|
||||
|
||||
Instead of using options, it is easier to just set them as environment
|
||||
variables:
|
||||
|
||||
.. envvar:: OS_USERNAME
|
||||
|
||||
Your Keystone username.
|
||||
|
||||
.. envvar:: OS_PASSWORD
|
||||
|
||||
Your Keystone password.
|
||||
|
||||
.. envvar:: OS_TENANT_NAME
|
||||
|
||||
Name of Keystone project.
|
||||
|
||||
.. envvar:: OS_TENANT_ID
|
||||
|
||||
ID of Keystone Tenant.
|
||||
|
||||
.. envvar:: OS_AUTH_URL
|
||||
|
||||
The OpenStack API server URL.
|
||||
|
||||
.. envvar:: OS_IDENTITY_API_VERSION
|
||||
|
||||
The OpenStack Identity API version.
|
||||
|
||||
.. envvar:: OS_CACERT
|
||||
|
||||
The location for the CA truststore (PEM formatted) for this client.
|
||||
|
||||
.. envvar:: OS_CERT
|
||||
|
||||
The location for the keystore (PEM formatted) containing the public
|
||||
key of this client. This keystore can also optionally contain the
|
||||
private key of this client.
|
||||
|
||||
.. envvar:: OS_KEY
|
||||
|
||||
The location for the keystore (PEM formatted) containing the private
|
||||
key of this client. This value can be empty if the private key is
|
||||
included in the OS_CERT file.
|
||||
|
||||
For example, in Bash you'd use::
|
||||
|
||||
export OS_USERNAME=yourname
|
||||
export OS_PASSWORD=yadayadayada
|
||||
export OS_TENANT_NAME=myproject
|
||||
export OS_AUTH_URL=http(s)://example.com:5000/v2.0/
|
||||
export OS_IDENTITY_API_VERSION=2.0
|
||||
export OS_CACERT=/etc/keystone/yourca.pem
|
||||
export OS_CERT=/etc/keystone/yourpublickey.pem
|
||||
export OS_KEY=/etc/keystone/yourprivatekey.pem
|
||||
|
||||
|
||||
OPTIONS
|
||||
=======
|
||||
|
||||
To get a list of available commands and options run::
|
||||
|
||||
keystone help
|
||||
|
||||
To get usage and options of a command::
|
||||
|
||||
keystone help <command>
|
||||
|
||||
|
||||
EXAMPLES
|
||||
========
|
||||
|
||||
Get information about endpoint-create command::
|
||||
|
||||
keystone help endpoint-create
|
||||
|
||||
View endpoints of OpenStack services::
|
||||
|
||||
keystone catalog
|
||||
|
||||
Create a 'service' project::
|
||||
|
||||
keystone tenant-create --name=service
|
||||
|
||||
Create service user for nova::
|
||||
|
||||
keystone user-create --name=nova \
|
||||
--tenant_id=<project ID> \
|
||||
--email=nova@nothing.com
|
||||
|
||||
View roles::
|
||||
|
||||
keystone role-list
|
||||
|
||||
|
||||
BUGS
|
||||
====
|
||||
|
||||
Keystone client is hosted in Launchpad so you can view current bugs at
|
||||
https://bugs.launchpad.net/python-keystoneclient/.
|
428
docs/source/middlewarearchitecture.rst
Normal file
428
docs/source/middlewarearchitecture.rst
Normal file
@ -0,0 +1,428 @@
|
||||
..
|
||||
Copyright 2011-2013 OpenStack Foundation
|
||||
All Rights Reserved.
|
||||
|
||||
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.
|
||||
|
||||
=======================
|
||||
Middleware Architecture
|
||||
=======================
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
The Keystone middleware architecture supports a common authentication protocol
|
||||
in use between the OpenStack projects. By using keystone as a common
|
||||
authentication and authorization mechanism, the OpenStack project can plug in
|
||||
to existing authentication and authorization systems in use by existing
|
||||
environments.
|
||||
|
||||
In this document, we describe the architecture and responsibilities of the
|
||||
authentication middleware which acts as the internal API mechanism for
|
||||
OpenStack projects based on the WSGI standard.
|
||||
|
||||
This documentation describes the implementation in
|
||||
:class:`keystoneclient.middleware.auth_token`
|
||||
|
||||
Specification Overview
|
||||
======================
|
||||
|
||||
'Authentication' is the process of determining that users are who they say they
|
||||
are. Typically, 'authentication protocols' such as HTTP Basic Auth, Digest
|
||||
Access, public key, token, etc, are used to verify a user's identity. In this
|
||||
document, we define an ''authentication component'' as a software module that
|
||||
implements an authentication protocol for an OpenStack service. OpenStack is
|
||||
using a token based mechanism to represent authentication and authorization.
|
||||
|
||||
At a high level, an authentication middleware component is a proxy that
|
||||
intercepts HTTP calls from clients and populates HTTP headers in the request
|
||||
context for other WSGI middleware or applications to use. The general flow
|
||||
of the middleware processing is:
|
||||
|
||||
* clear any existing authorization headers to prevent forgery
|
||||
* collect the token from the existing HTTP request headers
|
||||
* validate the token
|
||||
|
||||
* if valid, populate additional headers representing the identity that has
|
||||
been authenticated and authorized
|
||||
* if invalid, or no token present, reject the request (HTTPUnauthorized)
|
||||
or pass along a header indicating the request is unauthorized (configurable
|
||||
in the middleware)
|
||||
* if the keystone service is unavailable to validate the token, reject
|
||||
the request with HTTPServiceUnavailable.
|
||||
|
||||
.. _authComponent:
|
||||
|
||||
Authentication Component
|
||||
------------------------
|
||||
|
||||
Figure 1. Authentication Component
|
||||
|
||||
.. image:: images/graphs_authComp.svg
|
||||
:width: 100%
|
||||
:height: 180
|
||||
:alt: An Authentication Component
|
||||
|
||||
The middleware may also be configured to operate in a 'delegated mode'.
|
||||
In this mode, the decision to reject an unauthenticated client is delegated to
|
||||
the OpenStack service, as illustrated in :ref:`authComponentDelegated`.
|
||||
|
||||
Here, requests are forwarded to the OpenStack service with an identity status
|
||||
message that indicates whether the client's identity has been confirmed or is
|
||||
indeterminate. It is the OpenStack service that decides whether or not a reject
|
||||
message should be sent to the client.
|
||||
|
||||
.. _authComponentDelegated:
|
||||
|
||||
Authentication Component (Delegated Mode)
|
||||
-----------------------------------------
|
||||
|
||||
Figure 2. Authentication Component (Delegated Mode)
|
||||
|
||||
.. image:: images/graphs_authCompDelegate.svg
|
||||
:width: 100%
|
||||
:height: 180
|
||||
:alt: An Authentication Component (Delegated Mode)
|
||||
|
||||
.. _deployStrategies:
|
||||
|
||||
Deployment Strategy
|
||||
===================
|
||||
|
||||
The middleware is intended to be used inline with OpenStack wsgi components,
|
||||
based on the Oslo WSGI middleware class. It is typically deployed
|
||||
as a configuration element in a paste configuration pipeline of other
|
||||
middleware components, with the pipeline terminating in the service
|
||||
application. The middleware conforms to the python WSGI standard [PEP-333]_.
|
||||
In initializing the middleware, a configuration item (which acts like a python
|
||||
dictionary) is passed to the middleware with relevant configuration options.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
The middleware is configured within the config file of the main application as
|
||||
a WSGI component. Example for the auth_token middleware::
|
||||
|
||||
[app:myService]
|
||||
paste.app_factory = myService:app_factory
|
||||
|
||||
[pipeline:main]
|
||||
pipeline = authtoken myService
|
||||
|
||||
[filter:authtoken]
|
||||
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
|
||||
|
||||
# Prefix to prepend at the beginning of the path (string
|
||||
# value)
|
||||
#auth_admin_prefix=
|
||||
|
||||
# Host providing the admin Identity API endpoint (string
|
||||
# value)
|
||||
auth_host=127.0.0.1
|
||||
|
||||
# Port of the admin Identity API endpoint (integer value)
|
||||
auth_port=35357
|
||||
|
||||
# Protocol of the admin Identity API endpoint(http or https)
|
||||
# (string value)
|
||||
auth_protocol=https
|
||||
|
||||
# Complete public Identity API endpoint (string value)
|
||||
#auth_uri=<None>
|
||||
|
||||
# API version of the admin Identity API endpoint (string
|
||||
# value)
|
||||
#auth_version=<None>
|
||||
|
||||
# Do not handle authorization requests within the middleware,
|
||||
# but delegate the authorization decision to downstream WSGI
|
||||
# components (boolean value)
|
||||
#delay_auth_decision=false
|
||||
|
||||
# Request timeout value for communicating with Identity API
|
||||
# server. (boolean value)
|
||||
#http_connect_timeout=<None>
|
||||
|
||||
# How many times are we trying to reconnect when communicating
|
||||
# with Identity API Server. (integer value)
|
||||
#http_request_max_retries=3
|
||||
|
||||
# Single shared secret with the Keystone configuration used
|
||||
# for bootstrapping a Keystone installation, or otherwise
|
||||
# bypassing the normal authentication process. (string value)
|
||||
#admin_token=<None>
|
||||
|
||||
# Keystone account username (string value)
|
||||
#admin_user=<None>
|
||||
|
||||
# Keystone account password (string value)
|
||||
admin_password=SuperSekretPassword
|
||||
|
||||
# Keystone service account tenant name to validate user tokens
|
||||
# (string value)
|
||||
#admin_tenant_name=admin
|
||||
|
||||
# Env key for the swift cache (string value)
|
||||
#cache=<None>
|
||||
|
||||
# Required if Keystone server requires client certificate
|
||||
# (string value)
|
||||
#certfile=<None>
|
||||
|
||||
# Required if Keystone server requires client certificate
|
||||
# (string value)
|
||||
#keyfile=<None>
|
||||
|
||||
# A PEM encoded Certificate Authority to use when verifying
|
||||
# HTTPs connections. Defaults to system CAs. (string value)
|
||||
#cafile=<None>
|
||||
|
||||
# Verify HTTPS connections. (boolean value)
|
||||
#insecure=false
|
||||
|
||||
# Directory used to cache files related to PKI tokens (string
|
||||
# value)
|
||||
#signing_dir=<None>
|
||||
|
||||
# If defined, the memcache server(s) to use for caching (list
|
||||
# value)
|
||||
# Deprecated group/name - [DEFAULT]/memcache_servers
|
||||
#memcached_servers=<None>
|
||||
|
||||
# In order to prevent excessive requests and validations, the
|
||||
# middleware uses an in-memory cache for the tokens the
|
||||
# Keystone API returns. This is only valid if memcache_servers
|
||||
# is defined. Set to -1 to disable caching completely.
|
||||
# (integer value)
|
||||
#token_cache_time=300
|
||||
|
||||
# Value only used for unit testing (integer value)
|
||||
#revocation_cache_time=1
|
||||
|
||||
# (optional) if defined, indicate whether token data should be
|
||||
# authenticated or authenticated and encrypted. Acceptable
|
||||
# values are MAC or ENCRYPT. If MAC, token data is
|
||||
# authenticated (with HMAC) in the cache. If ENCRYPT, token
|
||||
# data is encrypted and authenticated in the cache. If the
|
||||
# value is not one of these options or empty, auth_token will
|
||||
# raise an exception on initialization. (string value)
|
||||
#memcache_security_strategy=<None>
|
||||
|
||||
# (optional, mandatory if memcache_security_strategy is
|
||||
# defined) this string is used for key derivation. (string
|
||||
# value)
|
||||
#memcache_secret_key=<None>
|
||||
|
||||
# (optional) indicate whether to set the X-Service-Catalog
|
||||
# header. If False, middleware will not ask for service
|
||||
# catalog on token validation and will not set the X-Service-
|
||||
# Catalog header. (boolean value)
|
||||
#include_service_catalog=true
|
||||
|
||||
# Used to control the use and type of token binding. Can be
|
||||
# set to: "disabled" to not check token binding. "permissive"
|
||||
# (default) to validate binding information if the bind type
|
||||
# is of a form known to the server and ignore it if not.
|
||||
# "strict" like "permissive" but if the bind type is unknown
|
||||
# the token will be rejected. "required" any form of token
|
||||
# binding is needed to be allowed. Finally the name of a
|
||||
# binding method that must be present in tokens. (string
|
||||
# value)
|
||||
#enforce_token_bind=permissive
|
||||
|
||||
For services which have a separate paste-deploy ini file, auth_token middleware
|
||||
can be alternatively configured in [keystone_authtoken] section in the main
|
||||
config file. For example in Nova, all middleware parameters can be removed
|
||||
from api-paste.ini::
|
||||
|
||||
[filter:authtoken]
|
||||
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
|
||||
|
||||
and set in nova.conf::
|
||||
|
||||
[DEFAULT]
|
||||
...
|
||||
auth_strategy=keystone
|
||||
|
||||
[keystone_authtoken]
|
||||
auth_host = 127.0.0.1
|
||||
auth_port = 35357
|
||||
auth_protocol = http
|
||||
admin_user = admin
|
||||
admin_password = SuperSekretPassword
|
||||
admin_tenant_name = service
|
||||
# Any of the options that could be set in api-paste.ini can be set here.
|
||||
|
||||
Note that middleware parameters in paste config take priority, they must be
|
||||
removed to use values in [keystone_authtoken] section.
|
||||
|
||||
Configuration Options
|
||||
---------------------
|
||||
|
||||
* ``auth_admin_prefix``: Prefix to prepend at the beginning of the path
|
||||
* ``auth_host``: (required) the host providing the keystone service API endpoint
|
||||
for validating and requesting tokens
|
||||
* ``auth_port``: (optional, default `35357`) the port used to validate tokens
|
||||
* ``auth_protocol``: (optional, default `https`)
|
||||
* ``auth_uri``: (optional, defaults to
|
||||
`auth_protocol`://`auth_host`:`auth_port`)
|
||||
* ``auth_version``: API version of the admin Identity API endpoint
|
||||
* ``delay_auth_decision``: (optional, default `0`) (off). If on, the middleware
|
||||
will not reject invalid auth requests, but will delegate that decision to
|
||||
downstream WSGI components.
|
||||
* ``http_connect_timeout``: (optional) Request timeout value for communicating
|
||||
with Identity API server.
|
||||
* ``http_request_max_retries``: (default 3) How many times are we trying to
|
||||
reconnect when communicating with Identity API Server.
|
||||
* ``http_handler``: (optional) Allows to pass in the name of a fake
|
||||
http_handler callback function used instead of `httplib.HTTPConnection` or
|
||||
`httplib.HTTPSConnection`. Useful for unit testing where network is not
|
||||
available.
|
||||
|
||||
* ``admin_token``: either this or the following three options are required. If
|
||||
set, this is a single shared secret with the keystone configuration used to
|
||||
validate tokens.
|
||||
* ``admin_user``, ``admin_password``, ``admin_tenant_name``: if ``admin_token``
|
||||
is not set, or invalid, then admin_user, admin_password, and
|
||||
admin_tenant_name are defined as a service account which is expected to have
|
||||
been previously configured in Keystone to validate user tokens.
|
||||
|
||||
* ``cache``: (optional) Env key for the swift cache
|
||||
|
||||
* ``certfile``: (required, if Keystone server requires client cert)
|
||||
* ``keyfile``: (required, if Keystone server requires client cert) This can be
|
||||
the same as the certfile if the certfile includes the private key.
|
||||
* ``cafile``: (optional, defaults to use system CA bundle) the path to a PEM
|
||||
encoded CA file/bundle that will be used to verify HTTPS connections.
|
||||
* ``insecure``: (optional, default `False`) Don't verify HTTPS connections
|
||||
(overrides `cafile`).
|
||||
|
||||
* ``signing_dir``: (optional) Directory used to cache files related to PKI
|
||||
tokens
|
||||
|
||||
* ``memcached_servers``: (optional) If defined, the memcache server(s) to use
|
||||
for caching
|
||||
* ``token_cache_time``: (default 300) In order to prevent excessive requests
|
||||
and validations, the middleware uses an in-memory cache for the tokens the
|
||||
Keystone API returns. This is only valid if memcache_servers s defined. Set
|
||||
to -1 to disable caching completely.
|
||||
* ``memcache_security_strategy``: (optional) if defined, indicate whether token
|
||||
data should be authenticated or authenticated and encrypted. Acceptable
|
||||
values are MAC or ENCRYPT. If MAC, token data is authenticated (with HMAC)
|
||||
in the cache. If ENCRYPT, token data is encrypted and authenticated in the
|
||||
cache. If the value is not one of these options or empty, auth_token will
|
||||
raise an exception on initialization.
|
||||
* ``memcache_secret_key``: (mandatory if memcache_security_strategy is defined)
|
||||
this string is used for key derivation.
|
||||
* ``include_service_catalog``: (optional, default `True`) Indicate whether to
|
||||
set the X-Service-Catalog header. If False, middleware will not ask for
|
||||
service catalog on token validation and will not set the X-Service-Catalog
|
||||
header.
|
||||
* ``enforce_token_bind``: (default ``permissive``) Used to control the use and
|
||||
type of token binding. Can be set to: "disabled" to not check token binding.
|
||||
"permissive" (default) to validate binding information if the bind type is of
|
||||
a form known to the server and ignore it if not. "strict" like "permissive"
|
||||
but if the bind type is unknown the token will be rejected. "required" any
|
||||
form of token binding is needed to be allowed. Finally the name of a binding
|
||||
method that must be present in tokens.
|
||||
|
||||
Caching for improved response
|
||||
-----------------------------
|
||||
|
||||
In order to prevent excessive requests and validations, the middleware uses an
|
||||
in-memory cache for the tokens the keystone API returns. Keep in mind that
|
||||
invalidated tokens may continue to work if they are still in the token cache,
|
||||
so token_cache_time is configurable. For larger deployments, the middleware
|
||||
also supports memcache based caching.
|
||||
|
||||
* ``memcached_servers``: (optonal) if defined, the memcache server(s) to use for
|
||||
cacheing. It will be ignored if Swift MemcacheRing is used instead.
|
||||
* ``token_cache_time``: (optional, default 300 seconds) Set to -1 to disable
|
||||
caching completely.
|
||||
|
||||
When deploying auth_token middleware with Swift, user may elect
|
||||
to use Swift MemcacheRing instead of the local Keystone memcache.
|
||||
The Swift MemcacheRing object is passed in from the request environment
|
||||
and it defaults to 'swift.cache'. However it could be
|
||||
different, depending on deployment. To use Swift MemcacheRing, you must
|
||||
provide the ``cache`` option.
|
||||
|
||||
* ``cache``: (optional) if defined, the environment key where the Swift
|
||||
MemcacheRing object is stored.
|
||||
|
||||
Memcached and System Time
|
||||
=========================
|
||||
|
||||
When using `memcached`_ with ``auth_token`` middleware, ensure that the system
|
||||
time of memcached hosts is set to UTC. Memcached uses the host's system
|
||||
time in determining whether a key has expired, whereas Keystone sets
|
||||
key expiry in UTC. The timezone used by Keystone and memcached must
|
||||
match if key expiry is to behave as expected.
|
||||
|
||||
.. _`memcached`: http://memcached.org/
|
||||
|
||||
Memcache Protection
|
||||
===================
|
||||
|
||||
When using memcached, we are storing user tokens and token validation
|
||||
information into the cache as raw data. Which means that anyone who
|
||||
has access to the memcache servers can read and modify data stored
|
||||
there. To mitigate this risk, ``auth_token`` middleware provides an
|
||||
option to authenticate and optionally encrypt the token data stored in
|
||||
the cache.
|
||||
|
||||
* ``memcache_security_strategy``: (optional) if defined, indicate
|
||||
whether token data should be authenticated or authenticated and
|
||||
encrypted. Acceptable values are ``MAC`` or ``ENCRYPT``. If ``MAC``,
|
||||
token data is authenticated (with HMAC) in the cache. If
|
||||
``ENCRYPT``, token data is encrypted and authenticated in the
|
||||
cache. If the value is not one of these options or empty,
|
||||
``auth_token`` will raise an exception on initialization.
|
||||
* ``memcache_secret_key``: (optional, mandatory if
|
||||
``memcache_security_strategy`` is defined) this string is used for
|
||||
key derivation. If ``memcache_security_strategy`` is defined and
|
||||
``memcache_secret_key`` is absent, ``auth_token`` will raise an
|
||||
exception on initialization.
|
||||
|
||||
Exchanging User Information
|
||||
===========================
|
||||
|
||||
The middleware expects to find a token representing the user with the header
|
||||
``X-Auth-Token`` or ``X-Storage-Token``. `X-Storage-Token` is supported for
|
||||
swift/cloud files and for legacy Rackspace use. If the token isn't present and
|
||||
the middleware is configured to not delegate auth responsibility, it will
|
||||
respond to the HTTP request with HTTPUnauthorized, returning the header
|
||||
``WWW-Authenticate`` with the value `Keystone uri='...'` to indicate where to
|
||||
request a token. The auth_uri returned is configured with the middleware.
|
||||
|
||||
The authentication middleware extends the HTTP request with the header
|
||||
``X-Identity-Status``. If a request is successfully authenticated, the value
|
||||
is set to `Confirmed`. If the middleware is delegating the auth decision to the
|
||||
service, then the status is set to `Invalid` if the auth request was
|
||||
unsuccessful.
|
||||
|
||||
Extended the request with additional User Information
|
||||
-----------------------------------------------------
|
||||
|
||||
:py:class:`keystoneclient.middleware.auth_token.AuthProtocol` extends the
|
||||
request with additional information if the user has been authenticated. See the
|
||||
"What we add to the request for use by the OpenStack service" section in
|
||||
:py:mod:`keystoneclient.middleware.auth_token` for the list of fields set by
|
||||
the auth_token middleware.
|
||||
|
||||
|
||||
References
|
||||
==========
|
||||
|
||||
.. [PEP-333] pep0333 Phillip J Eby. 'Python Web Server Gateway Interface
|
||||
v1.0.'' http://www.python.org/dev/peps/pep-0333/.
|
416
docs/source/static/basic.css
Normal file
416
docs/source/static/basic.css
Normal file
@ -0,0 +1,416 @@
|
||||
/**
|
||||
* Sphinx stylesheet -- basic theme
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
|
||||
/* -- main layout ----------------------------------------------------------- */
|
||||
|
||||
div.clearer {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
/* -- relbar ---------------------------------------------------------------- */
|
||||
|
||||
div.related {
|
||||
width: 100%;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.related h3 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.related ul {
|
||||
margin: 0;
|
||||
padding: 0 0 0 10px;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
div.related li {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.related li.right {
|
||||
float: right;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
/* -- sidebar --------------------------------------------------------------- */
|
||||
|
||||
div.sphinxsidebarwrapper {
|
||||
padding: 10px 5px 0 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
float: left;
|
||||
width: 230px;
|
||||
margin-left: -100%;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul,
|
||||
div.sphinxsidebar ul.want-points {
|
||||
margin-left: 20px;
|
||||
list-style: square;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul ul {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar form {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input {
|
||||
border: 1px solid #98dbcc;
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/* -- search page ----------------------------------------------------------- */
|
||||
|
||||
ul.search {
|
||||
margin: 10px 0 0 20px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
ul.search li {
|
||||
padding: 5px 0 5px 20px;
|
||||
background-image: url(file.png);
|
||||
background-repeat: no-repeat;
|
||||
background-position: 0 7px;
|
||||
}
|
||||
|
||||
ul.search li a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul.search li div.context {
|
||||
color: #888;
|
||||
margin: 2px 0 0 30px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
ul.keywordmatches li.goodmatch a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* -- index page ------------------------------------------------------------ */
|
||||
|
||||
table.contentstable {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
table.contentstable p.biglink {
|
||||
line-height: 150%;
|
||||
}
|
||||
|
||||
a.biglink {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
span.linkdescr {
|
||||
font-style: italic;
|
||||
padding-top: 5px;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
/* -- general index --------------------------------------------------------- */
|
||||
|
||||
table.indextable td {
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.indextable dl, table.indextable dd {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
table.indextable tr.pcap {
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
table.indextable tr.cap {
|
||||
margin-top: 10px;
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
img.toggler {
|
||||
margin-right: 3px;
|
||||
margin-top: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* -- general body styles --------------------------------------------------- */
|
||||
|
||||
a.headerlink {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
h1:hover > a.headerlink,
|
||||
h2:hover > a.headerlink,
|
||||
h3:hover > a.headerlink,
|
||||
h4:hover > a.headerlink,
|
||||
h5:hover > a.headerlink,
|
||||
h6:hover > a.headerlink,
|
||||
dt:hover > a.headerlink {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
div.body p.caption {
|
||||
text-align: inherit;
|
||||
}
|
||||
|
||||
div.body td {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.field-list ul {
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.first {
|
||||
}
|
||||
|
||||
p.rubric {
|
||||
margin-top: 30px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* -- sidebars -------------------------------------------------------------- */
|
||||
|
||||
div.sidebar {
|
||||
margin: 0 0 0.5em 1em;
|
||||
border: 1px solid #ddb;
|
||||
padding: 7px 7px 0 7px;
|
||||
background-color: #ffe;
|
||||
width: 40%;
|
||||
float: right;
|
||||
}
|
||||
|
||||
p.sidebar-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* -- topics ---------------------------------------------------------------- */
|
||||
|
||||
div.topic {
|
||||
border: 1px solid #ccc;
|
||||
padding: 7px 7px 0 7px;
|
||||
margin: 10px 0 10px 0;
|
||||
}
|
||||
|
||||
p.topic-title {
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
/* -- admonitions ----------------------------------------------------------- */
|
||||
|
||||
div.admonition {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding: 7px;
|
||||
}
|
||||
|
||||
div.admonition dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.admonition dl {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
p.admonition-title {
|
||||
margin: 0px 10px 5px 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.body p.centered {
|
||||
text-align: center;
|
||||
margin-top: 25px;
|
||||
}
|
||||
|
||||
/* -- tables ---------------------------------------------------------------- */
|
||||
|
||||
table.docutils {
|
||||
border: 0;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table.docutils td, table.docutils th {
|
||||
padding: 1px 8px 1px 0;
|
||||
border-top: 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid #aaa;
|
||||
}
|
||||
|
||||
table.field-list td, table.field-list th {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
table.footnote td, table.footnote th {
|
||||
border: 0 !important;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
padding-right: 5px;
|
||||
}
|
||||
|
||||
/* -- other body styles ----------------------------------------------------- */
|
||||
|
||||
dl {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
dd p {
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
dd ul, dd table {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-top: 3px;
|
||||
margin-bottom: 10px;
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
dt:target, .highlight {
|
||||
background-color: #fbe54e;
|
||||
}
|
||||
|
||||
dl.glossary dt {
|
||||
font-weight: bold;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
.field-list ul {
|
||||
margin: 0;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
.field-list p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.refcount {
|
||||
color: #060;
|
||||
}
|
||||
|
||||
.optional {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.versionmodified {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.system-message {
|
||||
background-color: #fda;
|
||||
padding: 5px;
|
||||
border: 3px solid red;
|
||||
}
|
||||
|
||||
.footnote:target {
|
||||
background-color: #ffa
|
||||
}
|
||||
|
||||
.line-block {
|
||||
display: block;
|
||||
margin-top: 1em;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
.line-block .line-block {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
margin-left: 1.5em;
|
||||
}
|
||||
|
||||
/* -- code displays --------------------------------------------------------- */
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
td.linenos pre {
|
||||
padding: 5px 0px;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
table.highlighttable {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
|
||||
table.highlighttable td {
|
||||
padding: 0 0.5em 0 0.5em;
|
||||
}
|
||||
|
||||
tt.descname {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
tt.descclassname {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
tt.xref, a tt {
|
||||
background-color: transparent;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* -- math display ---------------------------------------------------------- */
|
||||
|
||||
img.math {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.body div.math p {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
span.eqno {
|
||||
float: right;
|
||||
}
|
||||
|
||||
/* -- printout stylesheet --------------------------------------------------- */
|
||||
|
||||
@media print {
|
||||
div.document,
|
||||
div.documentwrapper,
|
||||
div.bodywrapper {
|
||||
margin: 0 !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.sphinxsidebar,
|
||||
div.related,
|
||||
div.footer,
|
||||
#top-link {
|
||||
display: none;
|
||||
}
|
||||
}
|
230
docs/source/static/default.css
Normal file
230
docs/source/static/default.css
Normal file
@ -0,0 +1,230 @@
|
||||
/**
|
||||
* Sphinx stylesheet -- default theme
|
||||
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
*/
|
||||
|
||||
@import url("basic.css");
|
||||
|
||||
/* -- page layout ----------------------------------------------------------- */
|
||||
|
||||
body {
|
||||
font-family: sans-serif;
|
||||
font-size: 100%;
|
||||
background-color: #11303d;
|
||||
color: #000;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.document {
|
||||
background-color: #1c4e63;
|
||||
}
|
||||
|
||||
div.documentwrapper {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.bodywrapper {
|
||||
margin: 0 0 0 230px;
|
||||
}
|
||||
|
||||
div.body {
|
||||
background-color: #ffffff;
|
||||
color: #000000;
|
||||
padding: 0 20px 30px 20px;
|
||||
}
|
||||
|
||||
div.footer {
|
||||
color: #ffffff;
|
||||
width: 100%;
|
||||
padding: 9px 0 9px 0;
|
||||
text-align: center;
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
div.footer a {
|
||||
color: #ffffff;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
div.related {
|
||||
background-color: #133f52;
|
||||
line-height: 30px;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
div.related a {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3 {
|
||||
font-family: 'Trebuchet MS', sans-serif;
|
||||
color: #ffffff;
|
||||
font-size: 1.4em;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3 a {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h4 {
|
||||
font-family: 'Trebuchet MS', sans-serif;
|
||||
color: #ffffff;
|
||||
font-size: 1.3em;
|
||||
font-weight: normal;
|
||||
margin: 5px 0 0 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar p {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
div.sphinxsidebar p.topless {
|
||||
margin: 5px 10px 10px 10px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
margin: 10px;
|
||||
padding: 0;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
div.sphinxsidebar a {
|
||||
color: #98dbcc;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input {
|
||||
border: 1px solid #98dbcc;
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/* -- body styles ----------------------------------------------------------- */
|
||||
|
||||
a {
|
||||
color: #355f7c;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
div.body p, div.body dd, div.body li {
|
||||
text-align: left;
|
||||
line-height: 130%;
|
||||
}
|
||||
|
||||
div.body h1,
|
||||
div.body h2,
|
||||
div.body h3,
|
||||
div.body h4,
|
||||
div.body h5,
|
||||
div.body h6 {
|
||||
font-family: 'Trebuchet MS', sans-serif;
|
||||
background-color: #f2f2f2;
|
||||
font-weight: normal;
|
||||
color: #20435c;
|
||||
border-bottom: 1px solid #ccc;
|
||||
margin: 20px -20px 10px -20px;
|
||||
padding: 3px 0 3px 10px;
|
||||
}
|
||||
|
||||
div.body h1 { margin-top: 0; font-size: 200%; }
|
||||
div.body h2 { font-size: 160%; }
|
||||
div.body h3 { font-size: 140%; }
|
||||
div.body h4 { font-size: 120%; }
|
||||
div.body h5 { font-size: 110%; }
|
||||
div.body h6 { font-size: 100%; }
|
||||
|
||||
a.headerlink {
|
||||
color: #c60f0f;
|
||||
font-size: 0.8em;
|
||||
padding: 0 4px 0 4px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.headerlink:hover {
|
||||
background-color: #c60f0f;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.body p, div.body dd, div.body li {
|
||||
text-align: left;
|
||||
line-height: 130%;
|
||||
}
|
||||
|
||||
div.admonition p.admonition-title + p {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.admonition p {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
div.admonition pre {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
div.admonition ul, div.admonition ol {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
div.note {
|
||||
background-color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.seealso {
|
||||
background-color: #ffc;
|
||||
border: 1px solid #ff6;
|
||||
}
|
||||
|
||||
div.topic {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
div.warning {
|
||||
background-color: #ffe4e4;
|
||||
border: 1px solid #f66;
|
||||
}
|
||||
|
||||
p.admonition-title {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
p.admonition-title:after {
|
||||
content: ":";
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 5px;
|
||||
background-color: #eeffcc;
|
||||
color: #333333;
|
||||
line-height: 120%;
|
||||
border: 1px solid #ac9;
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
}
|
||||
|
||||
tt {
|
||||
background-color: #ecf0f3;
|
||||
padding: 0 1px 0 1px;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.warning tt {
|
||||
background: #efc2c2;
|
||||
}
|
||||
|
||||
.note tt {
|
||||
background: #d6d6d6;
|
||||
}
|
BIN
docs/source/static/header-line.gif
Normal file
BIN
docs/source/static/header-line.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 48 B |
BIN
docs/source/static/header_bg.jpg
Normal file
BIN
docs/source/static/header_bg.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
154
docs/source/static/jquery.tweet.js
Normal file
154
docs/source/static/jquery.tweet.js
Normal file
@ -0,0 +1,154 @@
|
||||
(function($) {
|
||||
|
||||
$.fn.tweet = function(o){
|
||||
var s = {
|
||||
username: ["seaofclouds"], // [string] required, unless you want to display our tweets. :) it can be an array, just do ["username1","username2","etc"]
|
||||
list: null, //[string] optional name of list belonging to username
|
||||
avatar_size: null, // [integer] height and width of avatar if displayed (48px max)
|
||||
count: 3, // [integer] how many tweets to display?
|
||||
intro_text: null, // [string] do you want text BEFORE your your tweets?
|
||||
outro_text: null, // [string] do you want text AFTER your tweets?
|
||||
join_text: null, // [string] optional text in between date and tweet, try setting to "auto"
|
||||
auto_join_text_default: "i said,", // [string] auto text for non verb: "i said" bullocks
|
||||
auto_join_text_ed: "i", // [string] auto text for past tense: "i" surfed
|
||||
auto_join_text_ing: "i am", // [string] auto tense for present tense: "i was" surfing
|
||||
auto_join_text_reply: "i replied to", // [string] auto tense for replies: "i replied to" @someone "with"
|
||||
auto_join_text_url: "i was looking at", // [string] auto tense for urls: "i was looking at" http:...
|
||||
loading_text: null, // [string] optional loading text, displayed while tweets load
|
||||
query: null // [string] optional search query
|
||||
};
|
||||
|
||||
if(o) $.extend(s, o);
|
||||
|
||||
$.fn.extend({
|
||||
linkUrl: function() {
|
||||
var returning = [];
|
||||
var regexp = /((ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?)/gi;
|
||||
this.each(function() {
|
||||
returning.push(this.replace(regexp,"<a href=\"$1\">$1</a>"));
|
||||
});
|
||||
return $(returning);
|
||||
},
|
||||
linkUser: function() {
|
||||
var returning = [];
|
||||
var regexp = /[\@]+([A-Za-z0-9-_]+)/gi;
|
||||
this.each(function() {
|
||||
returning.push(this.replace(regexp,"<a href=\"http://twitter.com/$1\">@$1</a>"));
|
||||
});
|
||||
return $(returning);
|
||||
},
|
||||
linkHash: function() {
|
||||
var returning = [];
|
||||
var regexp = / [\#]+([A-Za-z0-9-_]+)/gi;
|
||||
this.each(function() {
|
||||
returning.push(this.replace(regexp, ' <a href="http://search.twitter.com/search?q=&tag=$1&lang=all&from='+s.username.join("%2BOR%2B")+'">#$1</a>'));
|
||||
});
|
||||
return $(returning);
|
||||
},
|
||||
capAwesome: function() {
|
||||
var returning = [];
|
||||
this.each(function() {
|
||||
returning.push(this.replace(/\b(awesome)\b/gi, '<span class="awesome">$1</span>'));
|
||||
});
|
||||
return $(returning);
|
||||
},
|
||||
capEpic: function() {
|
||||
var returning = [];
|
||||
this.each(function() {
|
||||
returning.push(this.replace(/\b(epic)\b/gi, '<span class="epic">$1</span>'));
|
||||
});
|
||||
return $(returning);
|
||||
},
|
||||
makeHeart: function() {
|
||||
var returning = [];
|
||||
this.each(function() {
|
||||
returning.push(this.replace(/(<)+[3]/gi, "<tt class='heart'>♥</tt>"));
|
||||
});
|
||||
return $(returning);
|
||||
}
|
||||
});
|
||||
|
||||
function relative_time(time_value) {
|
||||
var parsed_date = Date.parse(time_value);
|
||||
var relative_to = (arguments.length > 1) ? arguments[1] : new Date();
|
||||
var delta = parseInt((relative_to.getTime() - parsed_date) / 1000);
|
||||
var pluralize = function (singular, n) {
|
||||
return '' + n + ' ' + singular + (n == 1 ? '' : 's');
|
||||
};
|
||||
if(delta < 60) {
|
||||
return 'less than a minute ago';
|
||||
} else if(delta < (45*60)) {
|
||||
return 'about ' + pluralize("minute", parseInt(delta / 60)) + ' ago';
|
||||
} else if(delta < (24*60*60)) {
|
||||
return 'about ' + pluralize("hour", parseInt(delta / 3600)) + ' ago';
|
||||
} else {
|
||||
return 'about ' + pluralize("day", parseInt(delta / 86400)) + ' ago';
|
||||
}
|
||||
}
|
||||
|
||||
function build_url() {
|
||||
var proto = ('https:' == document.location.protocol ? 'https:' : 'http:');
|
||||
if (s.list) {
|
||||
return proto+"//api.twitter.com/1/"+s.username[0]+"/lists/"+s.list+"/statuses.json?per_page="+s.count+"&callback=?";
|
||||
} else if (s.query == null && s.username.length == 1) {
|
||||
return proto+'//twitter.com/status/user_timeline/'+s.username[0]+'.json?count='+s.count+'&callback=?';
|
||||
} else {
|
||||
var query = (s.query || 'from:'+s.username.join('%20OR%20from:'));
|
||||
return proto+'//search.twitter.com/search.json?&q='+query+'&rpp='+s.count+'&callback=?';
|
||||
}
|
||||
}
|
||||
|
||||
return this.each(function(){
|
||||
var list = $('<ul class="tweet_list">').appendTo(this);
|
||||
var intro = '<p class="tweet_intro">'+s.intro_text+'</p>';
|
||||
var outro = '<p class="tweet_outro">'+s.outro_text+'</p>';
|
||||
var loading = $('<p class="loading">'+s.loading_text+'</p>');
|
||||
|
||||
if(typeof(s.username) == "string"){
|
||||
s.username = [s.username];
|
||||
}
|
||||
|
||||
if (s.loading_text) $(this).append(loading);
|
||||
$.getJSON(build_url(), function(data){
|
||||
if (s.loading_text) loading.remove();
|
||||
if (s.intro_text) list.before(intro);
|
||||
$.each((data.results || data), function(i,item){
|
||||
// auto join text based on verb tense and content
|
||||
if (s.join_text == "auto") {
|
||||
if (item.text.match(/^(@([A-Za-z0-9-_]+)) .*/i)) {
|
||||
var join_text = s.auto_join_text_reply;
|
||||
} else if (item.text.match(/(^\w+:\/\/[A-Za-z0-9-_]+\.[A-Za-z0-9-_:%&\?\/.=]+) .*/i)) {
|
||||
var join_text = s.auto_join_text_url;
|
||||
} else if (item.text.match(/^((\w+ed)|just) .*/im)) {
|
||||
var join_text = s.auto_join_text_ed;
|
||||
} else if (item.text.match(/^(\w*ing) .*/i)) {
|
||||
var join_text = s.auto_join_text_ing;
|
||||
} else {
|
||||
var join_text = s.auto_join_text_default;
|
||||
}
|
||||
} else {
|
||||
var join_text = s.join_text;
|
||||
};
|
||||
|
||||
var from_user = item.from_user || item.user.screen_name;
|
||||
var profile_image_url = item.profile_image_url || item.user.profile_image_url;
|
||||
var join_template = '<span class="tweet_join"> '+join_text+' </span>';
|
||||
var join = ((s.join_text) ? join_template : ' ');
|
||||
var avatar_template = '<a class="tweet_avatar" href="http://twitter.com/'+from_user+'"><img src="'+profile_image_url+'" height="'+s.avatar_size+'" width="'+s.avatar_size+'" alt="'+from_user+'\'s avatar" title="'+from_user+'\'s avatar" border="0"/></a>';
|
||||
var avatar = (s.avatar_size ? avatar_template : '');
|
||||
var date = '<a href="http://twitter.com/'+from_user+'/statuses/'+item.id+'" title="view tweet on twitter">'+relative_time(item.created_at)+'</a>';
|
||||
var text = '<span class="tweet_text">' +$([item.text]).linkUrl().linkUser().linkHash().makeHeart().capAwesome().capEpic()[0]+ '</span>';
|
||||
|
||||
// until we create a template option, arrange the items below to alter a tweet's display.
|
||||
list.append('<li>' + avatar + date + join + text + '</li>');
|
||||
|
||||
list.children('li:first').addClass('tweet_first');
|
||||
list.children('li:odd').addClass('tweet_even');
|
||||
list.children('li:even').addClass('tweet_odd');
|
||||
});
|
||||
if (s.outro_text) list.after(outro);
|
||||
});
|
||||
|
||||
});
|
||||
};
|
||||
})(jQuery);
|
245
docs/source/static/nature.css
Normal file
245
docs/source/static/nature.css
Normal file
@ -0,0 +1,245 @@
|
||||
/*
|
||||
* nature.css_t
|
||||
* ~~~~~~~~~~~~
|
||||
*
|
||||
* Sphinx stylesheet -- nature theme.
|
||||
*
|
||||
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
@import url("basic.css");
|
||||
|
||||
/* -- page layout ----------------------------------------------------------- */
|
||||
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
font-size: 100%;
|
||||
background-color: #111;
|
||||
color: #555;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.documentwrapper {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.bodywrapper {
|
||||
margin: 0 0 0 {{ theme_sidebarwidth|toint }}px;
|
||||
}
|
||||
|
||||
hr {
|
||||
border: 1px solid #B1B4B6;
|
||||
}
|
||||
|
||||
div.document {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
div.body {
|
||||
background-color: #ffffff;
|
||||
color: #3E4349;
|
||||
padding: 0 30px 30px 30px;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
div.footer {
|
||||
color: #555;
|
||||
width: 100%;
|
||||
padding: 13px 0;
|
||||
text-align: center;
|
||||
font-size: 75%;
|
||||
}
|
||||
|
||||
div.footer a {
|
||||
color: #444;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
div.related {
|
||||
background-color: #6BA81E;
|
||||
line-height: 32px;
|
||||
color: #fff;
|
||||
text-shadow: 0px 1px 0 #444;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
div.related a {
|
||||
color: #E2F3CC;
|
||||
}
|
||||
|
||||
div.sphinxsidebar {
|
||||
font-size: 0.75em;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
div.sphinxsidebarwrapper{
|
||||
padding: 20px 0;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3,
|
||||
div.sphinxsidebar h4 {
|
||||
font-family: Arial, sans-serif;
|
||||
color: #222;
|
||||
font-size: 1.2em;
|
||||
font-weight: normal;
|
||||
margin: 0;
|
||||
padding: 5px 10px;
|
||||
background-color: #ddd;
|
||||
text-shadow: 1px 1px 0 white
|
||||
}
|
||||
|
||||
div.sphinxsidebar h4{
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
div.sphinxsidebar h3 a {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
|
||||
div.sphinxsidebar p {
|
||||
color: #888;
|
||||
padding: 5px 20px;
|
||||
}
|
||||
|
||||
div.sphinxsidebar p.topless {
|
||||
}
|
||||
|
||||
div.sphinxsidebar ul {
|
||||
margin: 10px 20px;
|
||||
padding: 0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
div.sphinxsidebar a {
|
||||
color: #444;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input {
|
||||
border: 1px solid #ccc;
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
div.sphinxsidebar input[type=text]{
|
||||
margin-left: 20px;
|
||||
}
|
||||
|
||||
/* -- body styles ----------------------------------------------------------- */
|
||||
|
||||
a {
|
||||
color: #005B81;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #E32E00;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
div.body h1,
|
||||
div.body h2,
|
||||
div.body h3,
|
||||
div.body h4,
|
||||
div.body h5,
|
||||
div.body h6 {
|
||||
font-family: Arial, sans-serif;
|
||||
background-color: #BED4EB;
|
||||
font-weight: normal;
|
||||
color: #212224;
|
||||
margin: 30px 0px 10px 0px;
|
||||
padding: 5px 0 5px 10px;
|
||||
text-shadow: 0px 1px 0 white
|
||||
}
|
||||
|
||||
div.body h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; }
|
||||
div.body h2 { font-size: 150%; background-color: #C8D5E3; }
|
||||
div.body h3 { font-size: 120%; background-color: #D8DEE3; }
|
||||
div.body h4 { font-size: 110%; background-color: #D8DEE3; }
|
||||
div.body h5 { font-size: 100%; background-color: #D8DEE3; }
|
||||
div.body h6 { font-size: 100%; background-color: #D8DEE3; }
|
||||
|
||||
a.headerlink {
|
||||
color: #c60f0f;
|
||||
font-size: 0.8em;
|
||||
padding: 0 4px 0 4px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.headerlink:hover {
|
||||
background-color: #c60f0f;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.body p, div.body dd, div.body li {
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
div.admonition p.admonition-title + p {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
div.highlight{
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
div.note {
|
||||
background-color: #eee;
|
||||
border: 1px solid #ccc;
|
||||
}
|
||||
|
||||
div.seealso {
|
||||
background-color: #ffc;
|
||||
border: 1px solid #ff6;
|
||||
}
|
||||
|
||||
div.topic {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
div.warning {
|
||||
background-color: #ffe4e4;
|
||||
border: 1px solid #f66;
|
||||
}
|
||||
|
||||
p.admonition-title {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
p.admonition-title:after {
|
||||
content: ":";
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 10px;
|
||||
background-color: White;
|
||||
color: #222;
|
||||
line-height: 1.2em;
|
||||
border: 1px solid #C6C9CB;
|
||||
font-size: 1.1em;
|
||||
margin: 1.5em 0 1.5em 0;
|
||||
-webkit-box-shadow: 1px 1px 1px #d8d8d8;
|
||||
-moz-box-shadow: 1px 1px 1px #d8d8d8;
|
||||
}
|
||||
|
||||
tt {
|
||||
background-color: #ecf0f3;
|
||||
color: #222;
|
||||
/* padding: 1px 2px; */
|
||||
font-size: 1.1em;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.viewcode-back {
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
div.viewcode-block:target {
|
||||
background-color: #f4debf;
|
||||
border-top: 1px solid #ac9;
|
||||
border-bottom: 1px solid #ac9;
|
||||
}
|
BIN
docs/source/static/openstack_logo.png
Normal file
BIN
docs/source/static/openstack_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
94
docs/source/static/tweaks.css
Normal file
94
docs/source/static/tweaks.css
Normal file
@ -0,0 +1,94 @@
|
||||
body {
|
||||
background: #fff url(../_static/header_bg.jpg) top left no-repeat;
|
||||
}
|
||||
|
||||
#header {
|
||||
width: 950px;
|
||||
margin: 0 auto;
|
||||
height: 102px;
|
||||
}
|
||||
|
||||
#header h1#logo {
|
||||
background: url(../_static/openstack_logo.png) top left no-repeat;
|
||||
display: block;
|
||||
float: left;
|
||||
text-indent: -9999px;
|
||||
width: 175px;
|
||||
height: 55px;
|
||||
}
|
||||
|
||||
#navigation {
|
||||
background: url(../_static/header-line.gif) repeat-x 0 bottom;
|
||||
display: block;
|
||||
float: left;
|
||||
margin: 27px 0 0 25px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#navigation li{
|
||||
float: left;
|
||||
display: block;
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
#navigation li a {
|
||||
display: block;
|
||||
font-weight: normal;
|
||||
text-decoration: none;
|
||||
background-position: 50% 0;
|
||||
padding: 20px 0 5px;
|
||||
color: #353535;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#navigation li a.current, #navigation li a.section {
|
||||
border-bottom: 3px solid #cf2f19;
|
||||
color: #cf2f19;
|
||||
}
|
||||
|
||||
div.related {
|
||||
background-color: #cde2f8;
|
||||
border: 1px solid #b0d3f8;
|
||||
}
|
||||
|
||||
div.related a {
|
||||
color: #4078ba;
|
||||
text-shadow: none;
|
||||
}
|
||||
|
||||
div.sphinxsidebarwrapper {
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
color: #555;
|
||||
}
|
||||
|
||||
div.documentwrapper h1, div.documentwrapper h2, div.documentwrapper h3, div.documentwrapper h4, div.documentwrapper h5, div.documentwrapper h6 {
|
||||
font-family: 'PT Sans', sans-serif !important;
|
||||
color: #264D69;
|
||||
border-bottom: 1px dotted #C5E2EA;
|
||||
padding: 0;
|
||||
background: none;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
div.documentwrapper h3 {
|
||||
color: #CF2F19;
|
||||
}
|
||||
|
||||
a.headerlink {
|
||||
color: #fff !important;
|
||||
margin-left: 5px;
|
||||
background: #CF2F19 !important;
|
||||
}
|
||||
|
||||
div.body {
|
||||
margin-top: -25px;
|
||||
margin-left: 230px;
|
||||
}
|
||||
|
||||
div.document {
|
||||
width: 960px;
|
||||
margin: 0 auto;
|
||||
}
|
117
docs/source/using-api-v2.rst
Normal file
117
docs/source/using-api-v2.rst
Normal file
@ -0,0 +1,117 @@
|
||||
=================
|
||||
The Client v2 API
|
||||
=================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
The main concepts in the Identity v2 API are:
|
||||
|
||||
* tenants
|
||||
* users
|
||||
* roles
|
||||
* services
|
||||
* endpoints
|
||||
|
||||
The client v2 API lets you query and make changes through
|
||||
managers. For example, to manipulate tenants, you interact with a
|
||||
``keystoneclient.v2_0.tenants.TenantManager`` object.
|
||||
|
||||
You obtain access to managers through via attributes of the
|
||||
``keystoneclient.v2_0.client.Client`` object. For example, the ``tenants``
|
||||
attribute of the ``Client`` class is a tenant manager::
|
||||
|
||||
>>> from keystoneclient.v2_0 import client
|
||||
>>> keystone = client.Client(...)
|
||||
>>> keystone.tenants.list() # List tenants
|
||||
|
||||
You create a valid ``keystoneclient.v2_0.client.Client`` object by passing
|
||||
authentication data to the constructor. Authentication and examples of common
|
||||
tasks are provided below.
|
||||
|
||||
You can generally expect that when the client needs to propagate an exception
|
||||
it will raise an instance of subclass of
|
||||
``keystoneclient.exceptions.ClientException``
|
||||
|
||||
Authenticating
|
||||
==============
|
||||
|
||||
There are two ways to authenticate against Keystone:
|
||||
* against the admin endpoint with the admin token
|
||||
* against the public endpoint with a username and password
|
||||
|
||||
If you are an administrator, you can authenticate by connecting to the admin
|
||||
endpoint and using the admin token (sometimes referred to as the service
|
||||
token). The token is specified as the ``admin_token`` configuration option in
|
||||
your keystone.conf config file, which is typically in /etc/keystone::
|
||||
|
||||
>>> from keystoneclient.v2_0 import client
|
||||
>>> token = '012345SECRET99TOKEN012345'
|
||||
>>> endpoint = 'http://192.168.206.130:35357/v2.0'
|
||||
>>> keystone = client.Client(token=token, endpoint=endpoint)
|
||||
|
||||
If you have a username and password, authentication is done against the
|
||||
public endpoint. You must also specify a tenant that is associated with the
|
||||
user::
|
||||
|
||||
>>> from keystoneclient.v2_0 import client
|
||||
>>> username='adminUser'
|
||||
>>> password='secreetword'
|
||||
>>> tenant_name='openstackDemo'
|
||||
>>> auth_url='http://192.168.206.130:5000/v2.0'
|
||||
>>> keystone = client.Client(username=username, password=password,
|
||||
... tenant_name=tenant_name, auth_url=auth_url)
|
||||
|
||||
Creating tenants
|
||||
================
|
||||
|
||||
This example will create a tenant named *openStackDemo*::
|
||||
|
||||
>>> from keystoneclient.v2_0 import client
|
||||
>>> keystone = client.Client(...)
|
||||
>>> keystone.tenants.create(tenant_name="openstackDemo",
|
||||
... description="Default Tenant", enabled=True)
|
||||
<Tenant {u'id': u'9b7962da6eb04745b477ae920ad55939', u'enabled': True, u'description': u'Default Tenant', u'name': u'openstackDemo'}>
|
||||
|
||||
Creating users
|
||||
==============
|
||||
|
||||
This example will create a user named *adminUser* with a password *secretword*
|
||||
in the opoenstackDemo tenant. We first need to retrieve the tenant::
|
||||
|
||||
>>> from keystoneclient.v2_0 import client
|
||||
>>> keystone = client.Client(...)
|
||||
>>> tenants = keystone.tenants.list()
|
||||
>>> my_tenant = [x for x in tenants if x.name=='openstackDemo'][0]
|
||||
>>> my_user = keystone.users.create(name="adminUser",
|
||||
... password="secretword",
|
||||
... tenant_id=my_tenant.id)
|
||||
|
||||
Creating roles and adding users
|
||||
===============================
|
||||
|
||||
This example will create an admin role and add the *my_user* user to that
|
||||
role, but only for the *my_tenant* tenant:
|
||||
|
||||
>>> from keystoneclient.v2_0 import client
|
||||
>>> keystone = client.Client(...)
|
||||
>>> role = keystone.roles.create('admin')
|
||||
>>> my_tenant = ...
|
||||
>>> my_user = ...
|
||||
>>> keystone.roles.add_user_role(my_user, role, my_tenant)
|
||||
|
||||
Creating services and endpoints
|
||||
===============================
|
||||
|
||||
This example will create the service and corresponding endpoint for the
|
||||
Compute service::
|
||||
|
||||
>>> from keystoneclient.v2_0 import client
|
||||
>>> keystone = client.Client(...)
|
||||
>>> service = keystone.services.create(name="nova", service_type="compute",
|
||||
... description="Nova Compute Service")
|
||||
>>> keystone.endpoints.create(
|
||||
... region="RegionOne", service_id=service.id,
|
||||
... publicurl="http://192.168.206.130:8774/v2/%(tenant_id)s",
|
||||
... adminurl="http://192.168.206.130:8774/v2/%(tenant_id)s",
|
||||
... internalurl="http://192.168.206.130:8774/v2/%(tenant_id)s")
|
113
docs/source/using-api-v3.rst
Normal file
113
docs/source/using-api-v3.rst
Normal file
@ -0,0 +1,113 @@
|
||||
=================
|
||||
The Client v3 API
|
||||
=================
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
The main concepts in the Identity v3 API are:
|
||||
|
||||
* credentials
|
||||
* domains
|
||||
* endpoints
|
||||
* groups
|
||||
* policies
|
||||
* projects
|
||||
* role assignments
|
||||
* roles
|
||||
* services
|
||||
* trusts
|
||||
* users
|
||||
|
||||
The :py:mod:`keystoneclient.v3.client` API lets you query and make changes
|
||||
through ``managers``. For example, to manipulate a project (formerly
|
||||
called tenant), you interact with a
|
||||
:py:class:`keystoneclient.v3.projects.ProjectManager` object.
|
||||
|
||||
You obtain access to managers through attributes of a
|
||||
:py:class:`keystoneclient.v3.client.Client` object. For example, the
|
||||
``projects`` attribute of a ``Client`` object is a projects manager::
|
||||
|
||||
>>> from keystoneclient.v3 import client
|
||||
>>> keystone = client.Client(...)
|
||||
>>> keystone.projects.list() # List projects
|
||||
|
||||
While it is possible to instantiate a
|
||||
:py:class:`keystoneclient.v3.client.Client` object (as done above for
|
||||
clarity), the recommended approach is to use the discovery mechanism
|
||||
provided by the :py:class:`keystoneclient.client.Client` class. The
|
||||
appropriate class will be instantiated depending on the API versions
|
||||
available::
|
||||
|
||||
>>> from keystoneclient import client
|
||||
>>> keystone =
|
||||
... client.Client(auth_url='http://localhost:5000', ...)
|
||||
>>> type(keystone)
|
||||
<class 'keystoneclient.v3.client.Client'>
|
||||
|
||||
One can force the use of a specific version of the API, either by
|
||||
using the ``version`` keyword argument::
|
||||
|
||||
>>> from keystoneclient import client
|
||||
>>> keystone = client.Client(auth_url='http://localhost:5000',
|
||||
version=(2,), ...)
|
||||
>>> type(keystone)
|
||||
<class 'keystoneclient.v2_0.client.Client'>
|
||||
>>> keystone = client.Client(auth_url='http://localhost:5000',
|
||||
version=(3,), ...)
|
||||
>>> type(keystone)
|
||||
<class 'keystoneclient.v3.client.Client'>
|
||||
|
||||
Or by specifying directly the specific API version authentication URL
|
||||
as the auth_url keyword argument::
|
||||
|
||||
>>> from keystoneclient import client
|
||||
>>> keystone =
|
||||
... client.Client(auth_url='http://localhost:5000/v2.0', ...)
|
||||
>>> type(keystone)
|
||||
<class 'keystoneclient.v2_0.client.Client'>
|
||||
>>> keystone =
|
||||
... client.Client(auth_url='http://localhost:5000/v3', ...)
|
||||
>>> type(keystone)
|
||||
<class 'keystoneclient.v3.client.Client'>
|
||||
|
||||
Upon successful authentication, a :py:class:`keystoneclient.v3.client.Client`
|
||||
object is returned (when using the Identity v3 API). Authentication and
|
||||
examples of common tasks are provided below.
|
||||
|
||||
You can generally expect that when the client needs to propagate an
|
||||
exception it will raise an instance of subclass of
|
||||
``keystoneclient.exceptions.ClientException`` (see
|
||||
:py:class:`keystoneclient.openstack.common.apiclient.exceptions.ClientException`)
|
||||
|
||||
Authenticating
|
||||
==============
|
||||
|
||||
You can authenticate against Keystone using a username, a user domain
|
||||
name (which will default to 'Default' if it is not specified) and a
|
||||
password::
|
||||
|
||||
>>> from keystoneclient import client
|
||||
>>> auth_url = 'http://localhost:5000'
|
||||
>>> username = 'adminUser'
|
||||
>>> user_domain_name = 'Default'
|
||||
>>> password = 'secreetword'
|
||||
>>> keystone = client.Client(auth_url=auth_url, version=(3,),
|
||||
... username=username, password=password,
|
||||
... user_domain_name=user_domain_name)
|
||||
|
||||
You may optionally specify a domain or project (along with its project
|
||||
domain name), to obtain a scoped token::
|
||||
|
||||
>>> from keystoneclient import client
|
||||
>>> auth_url = 'http://localhost:5000'
|
||||
>>> username = 'adminUser'
|
||||
>>> user_domain_name = 'Default'
|
||||
>>> project_name = 'demo'
|
||||
>>> project_domain_name = 'Default'
|
||||
>>> password = 'secreetword'
|
||||
>>> keystone = client.Client(auth_url=auth_url, version=(3,),
|
||||
... username=username, password=password,
|
||||
... user_domain_name=user_domain_name,
|
||||
... project_name=project_name,
|
||||
... project_domain_name=project_domain_name)
|
198
docs/source/using-sessions.rst
Normal file
198
docs/source/using-sessions.rst
Normal file
@ -0,0 +1,198 @@
|
||||
==============
|
||||
Using Sessions
|
||||
==============
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
The :py:class:`keystoneclient.session.Session` class was introduced into
|
||||
keystoneclient as an attempt to bring a unified interface to the various
|
||||
OpenStack clients that share common authentication and request parameters
|
||||
between a variety of services.
|
||||
|
||||
The model for using a Session and auth plugin as well as the general terms used
|
||||
have been heavily inspired by the `requests <http://docs.python-requests.org>`_
|
||||
library. However neither the Session class nor any of the authentication
|
||||
plugins rely directly on those concepts from the requests library so you should
|
||||
not expect a direct translation.
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Common client authentication
|
||||
|
||||
Authentication is handled by one of a variety of authentication plugins and
|
||||
then this authentication information is shared between all the services that
|
||||
use the same Session object.
|
||||
|
||||
- Security maintenance
|
||||
|
||||
Security code is maintained in a single place and reused between all
|
||||
clients such that in the event of problems it can be fixed in a single
|
||||
location.
|
||||
|
||||
- Standard discovery mechanisms
|
||||
|
||||
Clients are not expected to have any knowledge of an identity token or any
|
||||
other form of identification credential. Service and endpoint discovery are
|
||||
handled by the Session and plugins.
|
||||
|
||||
|
||||
Sessions for Users
|
||||
==================
|
||||
|
||||
The Session object is the contact point to your OpenStack cloud services. It
|
||||
stores the authentication credentials and connection information required to
|
||||
communicate with OpenStack such that it can be reused to communicate with many
|
||||
services. When creating services this Session object is passed to the client
|
||||
so that it may use this information.
|
||||
|
||||
A Session will authenticate on demand. When a request that requires
|
||||
authentication passes through the Session the authentication plugin will be
|
||||
asked for a valid token. If a valid token is available it will be used
|
||||
otherwise the authentication plugin may attempt to contact the authentication
|
||||
service and fetch a new one.
|
||||
|
||||
An example from keystoneclient::
|
||||
|
||||
>>> from keystoneclient.auth.identity import v3
|
||||
>>> from keystoneclient import session
|
||||
>>> from keystoneclient.v3 import client
|
||||
|
||||
>>> auth = v3.Password(auth_url='https://my.keystone.com:5000/v2.0',
|
||||
... username='myuser',
|
||||
... password='mypassword',
|
||||
... project_id='proj')
|
||||
>>> sess = session.Session(auth=auth,
|
||||
... verify='/path/to/ca.cert')
|
||||
>>> ks = client.Client(session=sess)
|
||||
>>> users = ks.users.list()
|
||||
|
||||
As clients adopt this means of operating they will be created in a similar
|
||||
fashion by passing the Session object to the client's constructor.
|
||||
|
||||
|
||||
Migrating keystoneclient to use a Session
|
||||
-----------------------------------------
|
||||
|
||||
By using a session with a keystonclient Client we define that you have opted in
|
||||
to new behaviour defined by the session. For example authentication is now
|
||||
on-demand rather than on creation. To allow this change in behaviour there are
|
||||
a number of functions that have changed behaviour or are no longer available.
|
||||
|
||||
For example the
|
||||
:py:meth:`keystoneclient.httpclient.HTTPClient.authenticate` command used
|
||||
to be able to always re-authenticate the current client and fetch a new token.
|
||||
As this is now controlled by the Session and not the client this has changed,
|
||||
however the function will still exist to provide compatibility with older
|
||||
clients.
|
||||
|
||||
Likewise certain parameters such as ``user_id`` and ``auth_token`` that used to
|
||||
be available on the client object post authentication will remain
|
||||
uninitialized.
|
||||
|
||||
When converting an application to use a session object with keystoneclient you
|
||||
should be aware of the possibility of changes to authentication and
|
||||
authentication parameters and make sure to test your code thoroughly. It should
|
||||
have no impact on the typical CRUD interaction with the client.
|
||||
|
||||
|
||||
Sharing Authentication Plugins
|
||||
------------------------------
|
||||
|
||||
A session can only contain one authentication plugin however there is nothing
|
||||
that specifically binds the authentication plugin to that session, a new
|
||||
Session can be created that reuses the existing authentication plugin::
|
||||
|
||||
>>> new_sess = session.Session(auth=sess.auth,
|
||||
verify='/path/to/different-cas.cert')
|
||||
|
||||
In this case we cannot know which session object will be used when the plugin
|
||||
performs the authentication call so the command must be able to succeed with
|
||||
either.
|
||||
|
||||
Authentication plugins can also be provided on a per-request basis. This will
|
||||
be beneficial in a situation where a single session is juggling multiple
|
||||
authentication credentials::
|
||||
|
||||
>>> sess.get('https://my.keystone.com:5000/v3',
|
||||
auth=my_auth_plugin)
|
||||
|
||||
If an auth plugin is provided via parameter then it will override any auth
|
||||
plugin on the session.
|
||||
|
||||
Sessions for Client Developers
|
||||
==============================
|
||||
|
||||
Sessions are intended to take away much of the hassle of dealing with
|
||||
authentication data and token formats. Clients should be able to specify filter
|
||||
parameters for selecting the endpoint and have the parsing of the catalog
|
||||
managed for them.
|
||||
|
||||
Authentication
|
||||
--------------
|
||||
|
||||
When making a request with a session object you can simply pass the keyword
|
||||
parameter ``authenticated`` to indicate whether the argument should contain a
|
||||
token, by default a token is included if an authentication plugin is available::
|
||||
|
||||
>>> # In keystone this route is unprotected by default
|
||||
>>> resp = sess.get('https://my.keystone.com:5000/v3',
|
||||
authenticated=False)
|
||||
|
||||
|
||||
Service Discovery
|
||||
-----------------
|
||||
|
||||
In OpenStack the URLs of available services are distributed to the user as a
|
||||
part of the token they receive called the Service Catalog. Clients are expected
|
||||
to use the URLs from the Service Catalog rather than have them provided.
|
||||
|
||||
In general a client does not need to know the full URL for the server that they
|
||||
are communicating with, simply that it should send a request to a path
|
||||
belonging to the correct service.
|
||||
|
||||
This is controlled by the ``endpoint_filter`` parameter to a request which
|
||||
contains all the information an authentication plugin requires to determine the
|
||||
correct URL to which to send a request. When using this mode only the path for
|
||||
the request needs to be specified::
|
||||
|
||||
>>> resp = session.get('/v3/users',
|
||||
endpoint_filter={'service_type': 'identity',
|
||||
'interface': 'public',
|
||||
'region_name': 'myregion'})
|
||||
|
||||
``endpoint_filter`` accepts a number of arguments with which it can determine
|
||||
an endpoint url:
|
||||
|
||||
- ``service_type``: the type of service. For example ``identity``, ``compute``,
|
||||
``volume`` or many other predefined identifiers.
|
||||
|
||||
- ``interface``: the network exposure the interface has. This will be one of:
|
||||
|
||||
- ``public``: An endpoint that is available to the wider internet or network.
|
||||
- ``internal``: An endpoint that is only accessible within the private network.
|
||||
- ``admin``: An endpoint to be used for administrative tasks.
|
||||
|
||||
- ``region_name``: the name of the region where the endpoint resides.
|
||||
|
||||
The endpoint filter is a simple key-value filter and can be provided with any
|
||||
number of arguments. It is then up to the auth plugin to correctly use the
|
||||
parameters it understands.
|
||||
|
||||
The session object determines the URL matching the filter and append to it the
|
||||
provided path and so create a valid request. If multiple URL matches are found
|
||||
then any one may be chosen.
|
||||
|
||||
While authentication plugins will endeavour to maintain a consistent set of
|
||||
arguments for an ``endpoint_filter`` the concept of an authentication plugin is
|
||||
purposefully generic and a specific mechanism may not know how to interpret
|
||||
certain arguments and ignore them. For example the
|
||||
:py:class:`keystoneclient.auth.token_endpoint.Token` plugin (which is used when
|
||||
you want to always use a specific endpoint and token combination) will always
|
||||
return the same endpoint regardless of the parameters to ``endpoint_filter`` or
|
||||
a custom OpenStack authentication mechanism may not have the concept of
|
||||
multiple ``interface`` options and choose to ignore that parameter.
|
||||
|
||||
There is some expectation on the user that they understand the limitations of
|
||||
the authentication system they are using.
|
Loading…
Reference in New Issue
Block a user