diff options
| author | Joe Heck <heckj@mac.com> | 2012-01-19 17:30:27 -0800 |
|---|---|---|
| committer | Joe Heck <heckj@mac.com> | 2012-01-19 17:30:40 -0800 |
| commit | f40198dece0b3729e6eb70abaa972bd73ee827da (patch) | |
| tree | 737b41d3e0867134b143644f30bed12ddab4491f /docs | |
| parent | ffeb0e558ca1108df02c53c9170e73020e57e67c (diff) | |
| download | keystone-f40198dece0b3729e6eb70abaa972bd73ee827da.tar.gz keystone-f40198dece0b3729e6eb70abaa972bd73ee827da.tar.xz keystone-f40198dece0b3729e6eb70abaa972bd73ee827da.zip | |
shimming in basics from original keystone
Diffstat (limited to 'docs')
| -rwxr-xr-x | docs/generate_autodoc_index.py | 76 | ||||
| -rw-r--r-- | docs/source/_static/basic.css | 416 | ||||
| -rw-r--r-- | docs/source/_static/default.css | 230 | ||||
| -rw-r--r-- | docs/source/_static/jquery.tweet.js | 154 | ||||
| -rw-r--r-- | docs/source/_static/tweaks.css | 65 | ||||
| -rw-r--r-- | docs/source/_templates/.placeholder | 0 | ||||
| -rw-r--r-- | docs/source/_theme/layout.html | 86 | ||||
| -rw-r--r-- | docs/source/_theme/theme.conf | 5 | ||||
| -rw-r--r-- | docs/source/community.rst | 93 | ||||
| -rw-r--r-- | docs/source/conf.py | 12 | ||||
| -rw-r--r-- | docs/source/developing.rst | 135 | ||||
| -rw-r--r-- | docs/source/index.rst | 58 | ||||
| -rw-r--r-- | docs/source/man/keystone-manage.rst | 192 | ||||
| -rw-r--r-- | docs/source/man/keystone.rst | 90 | ||||
| -rw-r--r-- | docs/source/setup.rst | 151 | ||||
| -rw-r--r-- | docs/source/testing.rst | 77 |
16 files changed, 1832 insertions, 8 deletions
diff --git a/docs/generate_autodoc_index.py b/docs/generate_autodoc_index.py new file mode 100755 index 00000000..993369b0 --- /dev/null +++ b/docs/generate_autodoc_index.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +"""Generates files for sphinx documentation using a simple Autodoc based +template. + +To use, just run as a script: + $ python doc/generate_autodoc_index.py +""" + +import os + + +base_dir = os.path.dirname(os.path.abspath(__file__)) +RSTDIR=os.path.join(base_dir, "source", "sourcecode") +SOURCEDIR=os.path.join(base_dir, "..") + +# Exclude these modules from the autodoc results +EXCLUDE_MODULES = ['keystone.backends.sqlalchemy.migrate_repo'] + +def in_exclude_list(module_name): + """Compares a module to the list of excluded modules + + Returns true if the provided module resides in or matches + an excluded module, false otherwise. + """ + for excluded_module in EXCLUDE_MODULES: + if module_name.startswith(excluded_module): + return True + return False + +def find_autodoc_modules(module_name, sourcedir): + """returns a list of modules in the SOURCE directory""" + modlist = [] + os.chdir(os.path.join(sourcedir, module_name)) + for root, dirs, files in os.walk("."): + for filename in files: + if filename.endswith(".py"): + # root = ./keystone/test/unit + # filename = base.py + elements = root.split(os.path.sep) + # replace the leading "." with the module name + elements[0] = module_name + # and get the base module name + base, extension = os.path.splitext(filename) + if not (base == "__init__"): + elements.append(base) + result = (".".join(elements)) + if not in_exclude_list(result): + modlist.append(result) + return modlist + +if not(os.path.exists(RSTDIR)): + os.mkdir(RSTDIR) + +INDEXOUT = open("%s/autoindex.rst" % RSTDIR, "w") +INDEXOUT.write("Source Code Index\n") +INDEXOUT.write("=================\n") +INDEXOUT.write(".. toctree::\n") +INDEXOUT.write(" :maxdepth: 1\n") +INDEXOUT.write("\n") + +for module in find_autodoc_modules('keystone', SOURCEDIR): + generated_file = "%s/%s.rst" % (RSTDIR, module) + + INDEXOUT.write(" %s\n" % module) + FILEOUT = open(generated_file, "w") + FILEOUT.write("The :mod:`%s` Module\n" % module) + FILEOUT.write("==============================" + "==============================" + "==============================\n") + FILEOUT.write(".. automodule:: %s\n" % module) + FILEOUT.write(" :members:\n") + FILEOUT.write(" :undoc-members:\n") + FILEOUT.write(" :show-inheritance:\n") + FILEOUT.close() + +INDEXOUT.close() diff --git a/docs/source/_static/basic.css b/docs/source/_static/basic.css new file mode 100644 index 00000000..d909ce37 --- /dev/null +++ b/docs/source/_static/basic.css @@ -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; + } +} diff --git a/docs/source/_static/default.css b/docs/source/_static/default.css new file mode 100644 index 00000000..c8091ecb --- /dev/null +++ b/docs/source/_static/default.css @@ -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; +} diff --git a/docs/source/_static/jquery.tweet.js b/docs/source/_static/jquery.tweet.js new file mode 100644 index 00000000..c93fea87 --- /dev/null +++ b/docs/source/_static/jquery.tweet.js @@ -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);
\ No newline at end of file diff --git a/docs/source/_static/tweaks.css b/docs/source/_static/tweaks.css new file mode 100644 index 00000000..16cd6e76 --- /dev/null +++ b/docs/source/_static/tweaks.css @@ -0,0 +1,65 @@ +ul.todo_list { + list-style-type: none; + margin: 0; + padding: 0; +} + +ul.todo_list li { + display: block; + margin: 0; + padding: 7px 0; + border-top: 1px solid #eee; +} + +ul.todo_list li p { + display: inline; +} + +ul.todo_list li p.link { + font-weight: bold; +} + +ul.todo_list li p.details { + font-style: italic; +} + +ul.todo_list li { +} + +div.admonition { + border: 1px solid #8F1000; +} + +div.admonition p.admonition-title { + background-color: #8F1000; + border-bottom: 1px solid #8E8E8E; +} + +a { + color: #CF2F19; +} + +div.related ul li a { + color: #CF2F19; +} + +div.sphinxsidebar h4 { + background-color:#8E8E8E; + border:1px solid #255E6E; + color:white; + font-size:1em; + margin:1em 0 0.5em; + padding:0.1em 0 0.1em 0.5em; +} + +em { + font-style: normal; +} + +table.docutils { + font-size: 11px; +} + +a tt { + color:#CF2F19; +}
\ No newline at end of file diff --git a/docs/source/_templates/.placeholder b/docs/source/_templates/.placeholder new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/docs/source/_templates/.placeholder diff --git a/docs/source/_theme/layout.html b/docs/source/_theme/layout.html new file mode 100644 index 00000000..e3eb54b7 --- /dev/null +++ b/docs/source/_theme/layout.html @@ -0,0 +1,86 @@ +{% extends "sphinxdoc/layout.html" %} +{% set css_files = css_files + ['_static/tweaks.css'] %} +{% set script_files = script_files + ['_static/jquery.tweet.js'] %} +{% block extrahead %} + <script type='text/javascript'> + $(document).ready(function(){ + $("#twitter_feed").tweet({ + username: "openstack", + query: "from:openstack", + avatar_size: 32, + count: 10, + loading_text: "loading tweets..." + }); + }); + </script> +{% endblock %} + +{%- 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 %} + + {%- if pagename == "index" %} + <h3>{{ _('Twitter Feed') }}</h3> + <div id="twitter_feed" class='twitter_feed'></div> + {%- endif %} + + + {%- endblock %} + </div> + </div> + {%- endif %}{% endif %} +{%- endmacro %} diff --git a/docs/source/_theme/theme.conf b/docs/source/_theme/theme.conf new file mode 100644 index 00000000..e039fe01 --- /dev/null +++ b/docs/source/_theme/theme.conf @@ -0,0 +1,5 @@ +[theme] +inherit = sphinxdoc +stylesheet = sphinxdoc.css +pygments_style = friendly + diff --git a/docs/source/community.rst b/docs/source/community.rst new file mode 100644 index 00000000..bbad2421 --- /dev/null +++ b/docs/source/community.rst @@ -0,0 +1,93 @@ +.. + Copyright 2011 OpenStack, LLC + 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. + +================ +Getting Involved +================ + +The OpenStack community is a very friendly group and there are places online to join in with the +community. Feel free to ask questions. This document points you to some of the places where you can +communicate with people. + +How to Join the Community +========================= + +Our community welcomes all people interested in open source cloud computing, and there are no formal +membership requirements. The best way to join the community is to talk with others online or at a meetup +and offer contributions through Launchpad_, the wiki_, or blogs. We welcome all types of contributions, +from blueprint designs to documentation to testing to deployment scripts. + +.. _Launchpad: https://launchpad.net/keystone +.. _wiki: http://wiki.openstack.org/ + + + +Contributing Code +----------------- + +To contribute code, sign up for a Launchpad account and sign a contributor license agreement, +available on the `<http://wiki.openstack.org/CLA>`_. Once the CLA is signed you +can contribute code through the Gerrit version control system which is related to your Launchpad account. + +To contribute tests, docs, code, etc, refer to our `Gerrit-Jenkins-Github Workflow`_. + +.. _`Gerrit-Jenkins-Github Workflow`: http://wiki.openstack.org/GerritJenkinsGithub + + +#openstack on Freenode IRC Network +---------------------------------- + +There is a very active chat channel at `<irc://freenode.net/#openstack>`_. This +is usually the best place to ask questions and find your way around. IRC stands for Internet Relay +Chat and it is a way to chat online in real time. You can also ask a question and come back to the +log files to read the answer later. Logs for the #openstack IRC channel are stored at +`<http://eavesdrop.openstack.org/irclogs/>`_. + +OpenStack Wiki +-------------- + +The wiki is a living source of knowledge. It is edited by the community, and +has collections of links and other sources of information. Typically the pages are a good place +to write drafts for specs or documentation, describe a blueprint, or collaborate with others. + +`OpenStack Wiki <http://wiki.openstack.org/>`_ + +Keystone on Launchpad +--------------------- + +Launchpad is a code hosting service that hosts the Keystone source code. From +Launchpad you can report bugs, ask questions, and register blueprints (feature requests). + +* `Launchpad Keystone Page <http://launchpad.net/keystone>`_ + +OpenStack Blog +-------------- + +The OpenStack blog includes a weekly newsletter that aggregates OpenStack news +from around the internet, as well as providing inside information on upcoming +events and posts from OpenStack contributors. + +`OpenStack Blog <http://openstack.org/blog>`_ + +See also: `Planet OpenStack <http://planet.openstack.org/>`_, aggregating blogs +about OpenStack from around the internet into a single feed. If you'd like to contribute to this blog +aggregation with your blog posts, there are instructions for `adding your blog <http://wiki.openstack.org/AddingYourBlog>`_. + +Twitter +------- + +Because all the cool kids do it: `@openstack <http://twitter.com/openstack>`_. Also follow the +`#openstack <http://search.twitter.com/search?q=%23openstack>`_ tag for relevant tweets. diff --git a/docs/source/conf.py b/docs/source/conf.py index 11c8adb0..63515726 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -97,6 +97,18 @@ pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. modindex_common_prefix = ['keystone.'] +# -- Options for man page output -------------------------------------------- + +# Grouping the document tree for man pages. +# List of tuples 'sourcefile', 'target', u'title', u'Authors name', 'manual' + +man_pages = [ + ('man/keystone-manage', 'keystone-manage', u'Keystone Management Utility', + [u'OpenStack'], 1), + ('man/keystone', 'keystone', u'Keystone Startup Command', + [u'OpenStack'], 1), + ] + # -- Options for HTML output --------------------------------------------------- diff --git a/docs/source/developing.rst b/docs/source/developing.rst new file mode 100644 index 00000000..acd22730 --- /dev/null +++ b/docs/source/developing.rst @@ -0,0 +1,135 @@ +.. + Copyright 2011 OpenStack, LLC + 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. + +======================== +Developing with Keystone +======================== + +Get your development environment set up according to :doc:`setup`. + +Running a development instance +============================== + +Setting up a virtualenv +----------------------- + +We recommend establishing a virtualenv to run keystone within. To establish +this environment, use the command:: + + $ python tools/install_venv.py + +This will create a local virtual environment in the directory ``.venv``. +Once created, you can activate this virtualenv for your current shell using:: + + $ source .venv/bin/activate + +The virtual environment can be disabled using the command:: + + $ deactivate + +You can also use ``tools\with_venv.sh`` to prefix commands so that they run +within the virtual environment. For more information on virtual environments, +see virtualenv_. + +.. _virtualenv: http://www.virtualenv.org/ + +Running Keystone +---------------- + +To run the keystone Admin and API server instances, use:: + + $ tools/with_venv.sh bin/keystone + +Running a demo service that uses Keystone +----------------------------------------- + +To run client demo (with all auth middleware running locally on sample service):: + + $ tools/with_venv.sh examples/echo/bin/echod + +which spins up a simple "echo" service on port 8090. To use a simple echo client:: + + $ python examples/echo/echo_client.py + +Interacting with Keystone +========================= + +You can interact with Keystone through the command line using :doc:`man/keystone-manage` +which allows you to establish tenants, users, etc. + +You can also interact with Keystone through it's REST API. There is a python +keystone client library python-keystoneclient_ which interacts exclusively through +the REST API. + +.. _python-keystoneclient: https://github.com/4P/python-keystoneclient + +The easiest way to establish some base information in Keystone to interact with is +to invoke:: + + $ tools/with_venv.sh bin/sampledata + +You can see the details of what that creates in ``keystone/test/sampledata.py`` + +Enabling debugging middleware +----------------------------- + +You can enable a huge amount of additional data (debugging information) about +the request and repsonse objects flowing through Keystone using the debugging +WSGI middleware. + +To enable this, just modify the pipelines in ``etc/keystone.conf``, from:: + + [pipeline:admin] + pipeline = + urlnormalizer + admin_api + + [pipeline:keystone-legacy-auth] + pipeline = + urlnormalizer + legacy_auth + d5_compat + service_api + +... to:: + + [pipeline:admin] + pipeline = + debug + urlnormalizer + d5_compat + admin_api + + [pipeline:keystone-legacy-auth] + pipeline = + debug + urlnormalizer + legacy_auth + d5_compat + service_api + +Two simple and easy debugging tools are using the ``-d`` when you start keystone:: + + $ ./keystone -d + +and the `--trace-calls` flag:: + + $ ./keystone -trace-calls + +The ``-d`` flag outputs debug information to the console. The ``--trace-calls`` flag +outputs extensive, nested trace calls to the console and highlights any errors +in red. + diff --git a/docs/source/index.rst b/docs/source/index.rst index cd7c96a8..4270033a 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,17 +1,59 @@ -.. keystone documentation master file, created by - sphinx-quickstart on Mon Jan 9 12:02:59 2012. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. +.. + Copyright 2011 OpenStack, LLC + All Rights Reserved. -Welcome to keystone's documentation! -==================================== + 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 -Contents: + 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. + +==================================================== +Welcome to Keystone, the OpenStack Identity Service! +==================================================== + +Keystone is a cloud identity service written in Python, which provides +authentication, authorization, and an OpenStack service catalog. It +implements `OpenStack's Identity API`_. + +This document describes Keystone for contributors of the project, and assumes +that you are already familiar with Keystone from an `end-user perspective`_. + +.. _`OpenStack's Identity API`: http://docs.openstack.org/api/openstack-identity-service/2.0/content/ +.. _`end-user perspective`: http://docs.openstack.org/ + +This documentation is generated by the Sphinx toolkit and lives in the source +tree. Additional documentation on Keystone and other components of OpenStack can +be found on the `OpenStack wiki`_. Also see the :doc:`community` page for +other ways to interact with the community. + +.. _`OpenStack wiki`: http://wiki.openstack.org + +Getting Started +=============== .. toctree:: - :maxdepth: 2 + :maxdepth: 1 + + setup + community + testing +Developers Documentation +======================== +.. toctree:: + :maxdepth: 1 + + developing + architecture + sourcecode/autoindex Indices and tables ================== diff --git a/docs/source/man/keystone-manage.rst b/docs/source/man/keystone-manage.rst new file mode 100644 index 00000000..9e9304f0 --- /dev/null +++ b/docs/source/man/keystone-manage.rst @@ -0,0 +1,192 @@ +=============== +keystone-manage +=============== + +--------------------------- +Keystone Management Utility +--------------------------- + +:Author: keystone@lists.launchpad.net +:Date: 2010-11-16 +:Copyright: OpenStack LLC +:Version: 0.1.2 +:Manual section: 1 +:Manual group: cloud computing + +SYNOPSIS +======== + + keystone-manage [options] + +DESCRIPTION +=========== + +keystone-manage is the command line tool that interacts with the keystone +service to configure Keystone + +USAGE +===== + + ``keystone-manage [options] type action [additional args]`` + +user +---- + +* **user add** [username] [password] + + adds a user to Keystone's data store + +* **user list** + + lists all users + +* **user disable** [username] + + disables the user *username* + +tenant +------ + +* **tenant add** [tenant_name] + + adds a tenant to Keystone's data store + +* **tenant list** + + lists all users + +* **tenant disable** [tenant_name] + +role +---- + +Roles are used to associated users to tenants. Two roles are defined related +to the Keystone service in it's configuration file :doc:`../keystone.conf` + +* **role add** [role_name] + + adds a role + +* **role list** ([tenant_name]) + + lists all roles, or all roles for tenant, if tenant_name is provided + +* **role grant** [role_name] [username] ([tenant]) + + grants a role to a specific user. Granted globally if tenant_name is not + provided or granted for a specific tenant if tenant_name is provided. + +service +------- + +* **service add** [name] [type] [description] [owner_id] + + adds a service + +* **service list** + + lists all services with id, name, and type + +endpointTemplate +---------------- + +* **endpointTemplate add** [region] [service_name] [public_url] [admin_url] [internal_url] [enabled] [is_global] + + Add a service endpoint for keystone. + + example:: + + keystone-manage endpointTemplates add RegionOne \ + keystone \ + http://keystone_host:5000/v2.0 \ + http://keystone_host:35357/v2.0 \ + http://keystone_host:5000/v2.0 \ + 1 1 + +* **endpointTemplate list** ([tenant_name]) + + lists endpoint templates with service, region, and public_url. Restricted to + tenant endpoints if tenant_name is provided. + +token +----- + +* **token add** [token] [username] [tenant] [expiration] + + adds a token for a given user and tenant with an expiration + +* **token list** + + lists all tokens + +* **token delete** [token] + + deletes the identified token + +endpoint +-------- + +* **endpoint add** [tenant_name] [endpoint_template] + + adds a tenant-specific endpoint + +credentials +----------- + +* **credentials add** [username] [type] [key] [password] ([tenant_name]) + +OPTIONS +======= + + --version show program's version number and exit + -h, --help show this help message and exit + -v, --verbose Print more verbose output + -d, --debug Print debugging output to console + -c PATH, --config-file=PATH Path to the config file to use. When not + specified (the default), we generally look at + the first argument specified to be a config + file, and if that is also missing, we search + standard directories for a config file. + -p BIND_PORT, --port=BIND_PORT, --bind-port=BIND_PORT + specifies port to listen on (default is 5000) + --host=BIND_HOST, --bind-host=BIND_HOST + specifies host address to listen on (default + is all or 0.0.0.0) + -t, --trace-calls Turns on call tracing for troubleshooting + -a PORT, --admin-port=PORT Specifies port for Admin API to listen on + (default is 35357) + +Logging Options: +================ + +The following configuration options are specific to logging +functionality for this program. + + --log-config=PATH If this option is specified, the logging + configuration file specified is used and + overrides any other logging options specified. + Please see the Python logging module + documentation for details on logging + configuration files. + --log-date-format=FORMAT Format string for %(asctime)s in log records. + Default: %Y-%m-%d %H:%M:%S + --log-file=PATH (Optional) Name of log file to output to. If + not set, logging will go to stdout. + --log-dir=LOG_DIR (Optional) The directory to keep log files in + (will be prepended to --logfile) + +FILES +===== + +None + +SEE ALSO +======== + +* `Keystone <http://github.com/openstack/keystone>`__ + +SOURCE +====== + +* Keystone is sourced in GitHub `Keystone <http://github.com/openstack/keystone>`__ +* Keystone bugs are managed at Launchpad `Launchpad Keystone <https://bugs.launchpad.net/keystone>`__ diff --git a/docs/source/man/keystone.rst b/docs/source/man/keystone.rst new file mode 100644 index 00000000..48e062e4 --- /dev/null +++ b/docs/source/man/keystone.rst @@ -0,0 +1,90 @@ +======== +keystone +======== + +--------------------------- +Keystone Management Utility +--------------------------- + +:Author: keystone@lists.launchpad.net +:Date: 2010-11-16 +:Copyright: OpenStack LLC +:Version: 0.1.2 +:Manual section: 1 +:Manual group: cloud computing + +SYNOPSIS +======== + + keystone [options] + +DESCRIPTION +=========== + +keystone starts both the service and administrative API servers for Keystone. +Use :doc:`keystone-control` to stop/start/restart and manage those services +once started. + +USAGE +===== + + keystone ``keystone [options]`` + +Common Options: +^^^^^^^^^^^^^^^ + --version show program's version number and exit + -h, --help show this help message and exit + +The following configuration options are common to all keystone +programs.:: + + -v, --verbose Print more verbose output + -d, --debug Print debugging output to console + -c PATH, --config-file=PATH Path to the config file to use. When not + specified (the default), we generally look at + the first argument specified to be a config + file, and if that is also missing, we search + standard directories for a config file. + -p BIND_PORT, --port=BIND_PORT, --bind-port=BIND_PORT + specifies port to listen on (default is 5000) + --host=BIND_HOST, --bind-host=BIND_HOST + specifies host address to listen on (default + is all or 0.0.0.0) + -t, --trace-calls Turns on call tracing for troubleshooting + -a PORT, --admin-port=PORT Specifies port for Admin API to listen on + (default is 35357) + +Logging Options: +^^^^^^^^^^^^^^^^ + +The following configuration options are specific to logging +functionality for this program.:: + + --log-config=PATH If this option is specified, the logging + configuration file specified is used and + overrides any other logging options specified. + Please see the Python logging module + documentation for details on logging + configuration files. + --log-date-format=FORMAT Format string for %(asctime)s in log records. + Default: %Y-%m-%d %H:%M:%S + --log-file=PATH (Optional) Name of log file to output to. If + not set, logging will go to stdout. + --log-dir=LOG_DIR (Optional) The directory to keep log files in + (will be prepended to --logfile) + +FILES +===== + +None + +SEE ALSO +======== + +* `Keystone <http://github.com/openstack/keystone>`__ + +SOURCE +====== + +* Keystone is sourced in GitHub `Keystone <http://github.com/openstack/keystone>`__ +* Keystone bugs are managed at Launchpad `Launchpad Keystone <https://bugs.launchpad.net/keystone>`__ diff --git a/docs/source/setup.rst b/docs/source/setup.rst new file mode 100644 index 00000000..e608f09e --- /dev/null +++ b/docs/source/setup.rst @@ -0,0 +1,151 @@ +.. + Copyright 2011 OpenStack, LLC + 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. + +============================================= +Setting up a Keystone development environment +============================================= + +This document describes setting up keystone directly from GitHub_ +for development purposes. + +To install keystone from packaging, refer instead to Keystone's `User Documentation`_. + +.. _GitHub: http://github.com/openstack/keystone +.. _`User Documentation`: http://docs.openstack.org/ + +Prerequisites +============= + +This document assumes you are using: + +- Ubuntu 11.10, Fedora 15, or Mac OS X Lion +- `Python 2.7`_ + +.. _`Python 2.7`: http://www.python.org/ + +And that you have the following tools available on your system: + +- git_ +- setuptools_ +- pip_ + +**Reminder**: If you're successfully using a different platform, or a +different version of the above, please document your configuration here! + +.. _git: http://git-scm.com/ +.. _setuptools: http://pypi.python.org/pypi/setuptools + +Getting the latest code +======================= + +You can clone our latest code from our `Github repository`:: + + $ git clone https://github.com/openstack/keystone.git + +When that is complete, you can:: + + $ cd keystone + +.. _`Github repository`: https://github.com/openstack/keystone + +Installing dependencies +======================= + +Keystone maintains a list of PyPi_ dependencies, designed for use by +pip_. + +.. _PyPi: http://pypi.python.org/ +.. _pip: http://pypi.python.org/pypi/pip + +However, your system *may* need additional dependencies that `pip` (and by +extension, PyPi) cannot satisfy. These dependencies should be installed +prior to using `pip`, and the installation method may vary depending on +your platform. + +Ubuntu 11.10:: + + $ sudo apt-get install python-dev libxml2-dev libxslt1-dev libsasl2-dev libsqlite3-dev libssl-dev libldap2-dev + +Fedora 15:: + + $ sudo yum install python-sqlite2 python-lxml python-greenlet-devel python-ldap + +Mac OS X Lion (requires MacPorts_):: + + $ sudo port install py-ldap + +.. _MacPorts: http://www.macports.org/ + +PyPi Packages +------------- + +Assuming you have any necessary binary packages & header files available +on your system, you can then install PyPi dependencies. + +You may also need to prefix `pip install` with `sudo`, depending on your +environment:: + + # Describe dependencies (including non-PyPi dependencies) + $ cat tools/pip-requires + + # Install all PyPi dependencies (for production, testing, and development) + $ pip install -r tools/pip-requires + +Updating your PYTHONPATH +======================== + +There are a number of methods for getting Keystone into your PYTHON PATH, +the easiest of which is:: + + # Fake-install the project by symlinking Keystone into your Python site-packages + $ python setup.py develop + +You should then be able to `import keystone` from your Python shell +without issue:: + + >>> import keystone.version + >>> + +If you want to check the version of Keystone you are running: + + >>> print keystone.version.version() + 2012.1-dev + + +If you can import keystone successfully, you should be ready to move on to :doc:`testing`. + +Troubleshooting +=============== + +Eventlet segfaults on RedHat / Fedora +------------------------------------- + +[*If this is no longer an issue, please remove this section, thanks!*] + +On some OSes, specifically Fedora 15, the current versions of +greenlet/eventlet segfault when running keystone. To fix this, install +the development versions of greenlet and eventlet:: + + $ pip uninstall greenlet eventlet + $ cd <appropriate working directory> + $ hg clone https://bitbucket.org/ambroff/greenlet + $ cd greenlet + $ sudo python setup.py install + + $ cd <appropriate working directory> + $ hg clone https://bitbucket.org/which_linden/eventlet + $ cd greenlet + $ sudo python setup.py install diff --git a/docs/source/testing.rst b/docs/source/testing.rst new file mode 100644 index 00000000..82a33604 --- /dev/null +++ b/docs/source/testing.rst @@ -0,0 +1,77 @@ +================ +Testing Keystone +================ + +Keystone uses a number of testing methodologies to ensure correctness. + +Running Built-In Tests +====================== + +To run the full suites of tests maintained within Keystone, run:: + + $ ./run_tests.sh --with-progress + +This shows realtime feedback during test execution, and iterates over +multiple configuration variations. + +This differs from how tests are executed from the continuous integration +environment. Specifically, Jenkins doesn't care about realtime progress, +and aborts after the first test failure (a fail-fast behavior):: + + $ ./run_tests.sh + +Testing Schema Migrations +========================= + +The application of schema migrations can be tested using SQLAlchemy Migrate’s built-in test runner, one migration at a time. + +.. WARNING:: + + This may leave your database in an inconsistent state; attempt this in non-production environments only! + +This is useful for testing the *next* migration in sequence (both forward & backward) in a database under version control:: + + $ python keystone/backends/sqlalchemy/migrate_repo/manage.py test --url=sqlite:///test.db --repository=keystone/backends/sqlalchemy/migrate_repo/ + +This command refers to a SQLite database used for testing purposes. Depending on the migration, this command alone does not make assertions as to the integrity of your data during migration. + +Writing Tests +============= + +Tests are maintained in the ``keystone.test`` module. Unit tests are +isolated from functional tests. + +Functional Tests +---------------- + +The ``keystone.test.functional.common`` module provides a ``unittest``-based +``httplib`` client which you can extend and use for your own tests. +Generally, functional tests should serve to illustrate intended use cases +and API behaviors. To help make your tests easier to read, the test client: + +- Authenticates with a known user name and password combination +- Asserts 2xx HTTP status codes (unless told otherwise) +- Abstracts keystone REST verbs & resources into single function calls + +Testing Multiple Configurations +------------------------------- + +Several variations of the default configuration are iterated over to +ensure test coverage of mutually exclusive featuresets, such as the +various backend options. + +These configuration templates are maintained in ``keystone/test/etc`` and +are iterated over by ``run_tests.py``. + +Further Testing +=============== + +devstack_ is the *best* way to quickly deploy keystone with the rest of the +OpenStack universe and should be critical step in your development workflow! + +You may also be interested in either the `OpenStack Continuous Integration Project`_ +or the `OpenStack Integration Testing Project`_. + +.. _devstack: http://devstack.org/ +.. _OpenStack Continuous Integration Project: https://github.com/openstack/openstack-ci +.. _OpenStack Integration Testing Project: https://github.com/openstack/openstack-integration-tests |
