Merge "[Fedora] Install dnsmasq on n-cpu less host"
diff --git a/.gitignore b/.gitignore
index 1840352..b80b476 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,23 +1,23 @@
-proto
*~
.*.sw?
*.log
*.log.[1-9]
-src
-localrc
-local.sh
+*.pem
+.localrc.auto
+.prereqs
+.stackenv
+accrc
+docs/files
+docs/html
files/*.gz
files/*.qcow2
files/images
files/pip-*
files/get-pip.py
-stack-screenrc
-*.pem
-accrc
-.stackenv
-.prereqs
-devstack-docs-*
-docs/
-docs-files
-.localrc.auto
local.conf
+local.sh
+localrc
+proto
+shocco
+src
+stack-screenrc
diff --git a/AUTHORS b/AUTHORS
index c6b40d8..04bff48 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -48,3 +48,4 @@
Yun Mao <yunmao@gmail.com>
Yong Sheng Gong <gongysh@cn.ibm.com>
Zhongyue Luo <lzyeval@gmail.com>
+Zhenguo Niu <niu.zglinux@gmail.com>
diff --git a/HACKING.rst b/HACKING.rst
index 83455e3..d69bb49 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -17,7 +17,7 @@
Contributing code to DevStack follows the usual OpenStack process as described
in `How To Contribute`__ in the OpenStack wiki. `DevStack's LaunchPad project`__
-contains the usual links for blueprints, bugs, tec.
+contains the usual links for blueprints, bugs, etc.
__ contribute_
.. _contribute: http://wiki.openstack.org/HowToContribute
diff --git a/README.md b/README.md
index f0406c6..7eacebd 100644
--- a/README.md
+++ b/README.md
@@ -133,11 +133,25 @@
# Apache Frontend
-Apache web server is enabled for wsgi services by setting
-`APACHE_ENABLED_SERVICES` in your ``localrc`` section. Remember to
-enable these services at first as above.
+Apache web server can be enabled for wsgi services that support being deployed
+under HTTPD + mod_wsgi. By default, services that recommend running under
+HTTPD + mod_wsgi are deployed under Apache. To use an alternative deployment
+strategy (e.g. eventlet) for services that support an alternative to HTTPD +
+mod_wsgi set ``ENABLE_HTTPD_MOD_WSGI_SERVICES`` to ``False`` in your
+``local.conf``.
- APACHE_ENABLED_SERVICES+=key,swift
+Each service that can be run under HTTPD + mod_wsgi also has an override
+toggle available that can be set in your ``local.conf``.
+
+Keystone is run under HTTPD + mod_wsgi by default.
+
+Example (Keystone):
+
+ KEYSTONE_USE_MOD_WSGI="True"
+
+Example (Swift):
+
+ SWIFT_USE_MOD_WSGI="True"
# Swift
@@ -330,6 +344,25 @@
Q_HOST=$SERVICE_HOST
MATCHMAKER_REDIS_HOST=$SERVICE_HOST
+# Multi-Region Setup
+
+We want to setup two devstack (RegionOne and RegionTwo) with shared keystone
+(same users and services) and horizon.
+Keystone and Horizon will be located in RegionOne.
+Full spec is available at:
+https://wiki.openstack.org/wiki/Heat/Blueprints/Multi_Region_Support_for_Heat.
+
+In RegionOne:
+
+ REGION_NAME=RegionOne
+
+In RegionTwo:
+
+ disable_service horizon
+ KEYSTONE_SERVICE_HOST=<KEYSTONE_IP_ADDRESS_FROM_REGION_ONE>
+ KEYSTONE_AUTH_HOST=<KEYSTONE_IP_ADDRESS_FROM_REGION_ONE>
+ REGION_NAME=RegionTwo
+
# Cells
Cells is a new scaling option with a full spec at:
diff --git a/clean.sh b/clean.sh
index 7851da3..e2374e7 100755
--- a/clean.sh
+++ b/clean.sh
@@ -120,9 +120,9 @@
# Clean up files
-FILES_TO_CLEAN=".localrc.auto docs-files docs/ shocco/ stack-screenrc test*.conf* test.ini*"
+FILES_TO_CLEAN=".localrc.auto docs/files docs/html shocco/ stack-screenrc test*.conf* test.ini*"
FILES_TO_CLEAN+=".stackenv .prereqs"
for file in $FILES_TO_CLEAN; do
- rm -f $TOP_DIR/$file
+ rm -rf $TOP_DIR/$file
done
diff --git a/docs/source/assets/css/bootstrap.css b/docs/source/assets/css/bootstrap.css
new file mode 100644
index 0000000..5fd10bc
--- /dev/null
+++ b/docs/source/assets/css/bootstrap.css
@@ -0,0 +1,616 @@
+article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
+audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
+audio:not([controls]){display:none;}
+html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}
+a:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
+a:hover,a:active{outline:0;}
+sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}
+sup{top:-0.5em;}
+sub{bottom:-0.25em;}
+img{max-width:100%;height:auto;border:0;-ms-interpolation-mode:bicubic;}
+button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}
+button,input{*overflow:visible;line-height:normal;}
+button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}
+button,input[type="button"],input[type="reset"],input[type="submit"]{cursor:pointer;-webkit-appearance:button;}
+input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;}
+input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;}
+textarea{overflow:auto;vertical-align:top;}
+body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;color:#333333;background-color:#ffffff;}
+a{color:#0088cc;text-decoration:none;}
+a:hover{color:#005580;text-decoration:underline;}
+.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";}
+.row:after{clear:both;}
+[class*="span"]{float:left;margin-left:20px;}
+.span1{width:60px;}
+.span2{width:140px;}
+.span3{width:220px;}
+.span4{width:300px;}
+.span5{width:380px;}
+.span6{width:460px;}
+.span7{width:540px;}
+.span8{width:620px;}
+.span9{width:700px;}
+.span10{width:780px;}
+.span11{width:860px;}
+.span12,.container{width:940px;}
+.offset1{margin-left:100px;}
+.offset2{margin-left:180px;}
+.offset3{margin-left:260px;}
+.offset4{margin-left:340px;}
+.offset5{margin-left:420px;}
+.offset6{margin-left:500px;}
+.offset7{margin-left:580px;}
+.offset8{margin-left:660px;}
+.offset9{margin-left:740px;}
+.offset10{margin-left:820px;}
+.offset11{margin-left:900px;}
+.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";}
+.row-fluid:after{clear:both;}
+.row-fluid>[class*="span"]{float:left;margin-left:2.127659574%;}
+.row-fluid>[class*="span"]:first-child{margin-left:0;}
+.row-fluid .span1{width:6.382978723%;}
+.row-fluid .span2{width:14.89361702%;}
+.row-fluid .span3{width:23.404255317%;}
+.row-fluid .span4{width:31.914893614%;}
+.row-fluid .span5{width:40.425531911%;}
+.row-fluid .span6{width:48.93617020799999%;}
+.row-fluid .span7{width:57.446808505%;}
+.row-fluid .span8{width:65.95744680199999%;}
+.row-fluid .span9{width:74.468085099%;}
+.row-fluid .span10{width:82.97872339599999%;}
+.row-fluid .span11{width:91.489361693%;}
+.row-fluid .span12{width:99.99999998999999%;}
+.container{width:940px;margin-left:auto;margin-right:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";}
+.container:after{clear:both;}
+.container-fluid{padding-left:20px;padding-right:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";}
+.container-fluid:after{clear:both;}
+p{margin:0 0 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;line-height:18px;}p small{font-size:11px;color:#999999;}
+.lead{margin-bottom:18px;font-size:20px;font-weight:200;line-height:27px;}
+h1,h2,h3,h4,h5,h6{margin:0;font-weight:bold;color:#333333;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;color:#999999;}
+h1{font-size:30px;line-height:36px;}h1 small{font-size:18px;}
+h2{font-size:24px;line-height:36px;}h2 small{font-size:18px;}
+h3{line-height:27px;font-size:18px;}h3 small{font-size:14px;}
+h4,h5,h6{line-height:18px;}
+h4{font-size:14px;}h4 small{font-size:12px;}
+h5{font-size:12px;}
+h6{font-size:11px;color:#999999;text-transform:uppercase;}
+.page-header{padding-bottom:17px;margin:18px 0;border-bottom:1px solid #eeeeee;}
+.page-header h1{line-height:1;}
+ul,ol{padding:0;margin:0 0 9px 25px;}
+ul ul,ul ol,ol ol,ol ul{margin-bottom:0;}
+ul{list-style:disc;}
+ol{list-style:decimal;}
+li{line-height:18px;}
+ul.unstyled{margin-left:0;list-style:none;}
+dl{margin-bottom:18px;}
+dt,dd{line-height:18px;}
+dt{font-weight:bold;}
+dd{margin-left:9px;}
+hr{margin:18px 0;border:0;border-top:1px solid #e5e5e5;border-bottom:1px solid #ffffff;}
+strong{font-weight:bold;}
+em{font-style:italic;}
+.muted{color:#999999;}
+abbr{font-size:90%;text-transform:uppercase;border-bottom:1px dotted #ddd;cursor:help;}
+blockquote{padding:0 0 0 15px;margin:0 0 18px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:22.5px;}
+blockquote small{display:block;line-height:18px;color:#999999;}blockquote small:before{content:'\2014 \00A0';}
+blockquote.pull-right{float:right;padding-left:0;padding-right:15px;border-left:0;border-right:5px solid #eeeeee;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;}
+q:before,q:after,blockquote:before,blockquote:after{content:"";}
+address{display:block;margin-bottom:18px;line-height:18px;font-style:normal;}
+small{font-size:100%;}
+cite{font-style:normal;}
+code,pre{padding:0 3px 2px;font-family:Menlo,Monaco,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+code{padding:3px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;}
+pre{display:block;padding:8.5px;margin:0 0 9px;font-size:12px;line-height:18px;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;white-space:pre;white-space:pre-wrap;word-break:break-all;}pre.prettyprint{margin-bottom:18px;}
+pre code{padding:0;background-color:transparent;}
+form{margin:0 0 18px;}
+fieldset{padding:0;margin:0;border:0;}
+legend{display:block;width:100%;padding:0;margin-bottom:27px;font-size:19.5px;line-height:36px;color:#333333;border:0;border-bottom:1px solid #eee;}
+label,input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:18px;}
+label{display:block;margin-bottom:5px;color:#333333;}
+input,textarea,select,.uneditable-input{display:inline-block;width:210px;height:18px;padding:4px;margin-bottom:9px;font-size:13px;line-height:18px;color:#555555;border:1px solid #ccc;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+.uneditable-textarea{width:auto;height:auto;}
+label input,label textarea,label select{display:block;}
+input[type="image"],input[type="checkbox"],input[type="radio"]{width:auto;height:auto;padding:0;margin:3px 0;*margin-top:0;line-height:normal;border:0;cursor:pointer;border-radius:0 \0/;}
+input[type="file"]{padding:initial;line-height:initial;border:initial;background-color:#ffffff;background-color:initial;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
+input[type="button"],input[type="reset"],input[type="submit"]{width:auto;height:auto;}
+select,input[type="file"]{height:28px;*margin-top:4px;line-height:28px;}
+select{width:220px;background-color:#ffffff;}
+select[multiple],select[size]{height:auto;}
+input[type="image"]{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
+textarea{height:auto;}
+input[type="hidden"]{display:none;}
+.radio,.checkbox{padding-left:18px;}
+.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-18px;}
+.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;}
+.radio.inline,.checkbox.inline{display:inline-block;margin-bottom:0;vertical-align:middle;}
+.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;}
+.controls>.radio.inline:first-child,.controls>.checkbox.inline:first-child{padding-top:0;}
+input,textarea{-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear 0.2s,box-shadow linear 0.2s;-moz-transition:border linear 0.2s,box-shadow linear 0.2s;-ms-transition:border linear 0.2s,box-shadow linear 0.2s;-o-transition:border linear 0.2s,box-shadow linear 0.2s;transition:border linear 0.2s,box-shadow linear 0.2s;}
+input:focus,textarea:focus{border-color:rgba(82, 168, 236, 0.8);-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 8px rgba(82, 168, 236, 0.6);outline:0;outline:thin dotted \9;}
+input[type="file"]:focus,input[type="checkbox"]:focus,select:focus{-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
+.input-mini{width:60px;}
+.input-small{width:90px;}
+.input-medium{width:150px;}
+.input-large{width:210px;}
+.input-xlarge{width:270px;}
+.input-xxlarge{width:530px;}
+input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{float:none;margin-left:0;}
+input.span1,textarea.span1,.uneditable-input.span1{width:50px;}
+input.span2,textarea.span2,.uneditable-input.span2{width:130px;}
+input.span3,textarea.span3,.uneditable-input.span3{width:210px;}
+input.span4,textarea.span4,.uneditable-input.span4{width:290px;}
+input.span5,textarea.span5,.uneditable-input.span5{width:370px;}
+input.span6,textarea.span6,.uneditable-input.span6{width:450px;}
+input.span7,textarea.span7,.uneditable-input.span7{width:530px;}
+input.span8,textarea.span8,.uneditable-input.span8{width:610px;}
+input.span9,textarea.span9,.uneditable-input.span9{width:690px;}
+input.span10,textarea.span10,.uneditable-input.span10{width:770px;}
+input.span11,textarea.span11,.uneditable-input.span11{width:850px;}
+input.span12,textarea.span12,.uneditable-input.span12{width:930px;}
+input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{background-color:#f5f5f5;border-color:#ddd;cursor:not-allowed;}
+.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;}
+.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;border-color:#c09853;}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:0 0 6px #dbc59e;-moz-box-shadow:0 0 6px #dbc59e;box-shadow:0 0 6px #dbc59e;}
+.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;}
+.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;}
+.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;border-color:#b94a48;}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:0 0 6px #d59392;-moz-box-shadow:0 0 6px #d59392;box-shadow:0 0 6px #d59392;}
+.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;}
+.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;}
+.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;border-color:#468847;}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:0 0 6px #7aba7b;-moz-box-shadow:0 0 6px #7aba7b;box-shadow:0 0 6px #7aba7b;}
+.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;}
+input:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;}
+.form-actions{padding:17px 20px 18px;margin-top:18px;margin-bottom:18px;background-color:#f5f5f5;border-top:1px solid #ddd;}
+.uneditable-input{display:block;background-color:#ffffff;border-color:#eee;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;}
+:-moz-placeholder{color:#999999;}
+::-webkit-input-placeholder{color:#999999;}
+.help-block{margin-top:5px;margin-bottom:0;color:#999999;}
+.help-inline{display:inline-block;*display:inline;*zoom:1;margin-bottom:9px;vertical-align:middle;padding-left:5px;}
+.input-prepend,.input-append{margin-bottom:5px;*zoom:1;}.input-prepend:before,.input-append:before,.input-prepend:after,.input-append:after{display:table;content:"";}
+.input-prepend:after,.input-append:after{clear:both;}
+.input-prepend input,.input-append input,.input-prepend .uneditable-input,.input-append .uneditable-input{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}.input-prepend input:focus,.input-append input:focus,.input-prepend .uneditable-input:focus,.input-append .uneditable-input:focus{position:relative;z-index:2;}
+.input-prepend .uneditable-input,.input-append .uneditable-input{border-left-color:#ccc;}
+.input-prepend .add-on,.input-append .add-on{float:left;display:block;width:auto;min-width:16px;height:18px;margin-right:-1px;padding:4px 5px;font-weight:normal;line-height:18px;color:#999999;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#f5f5f5;border:1px solid #ccc;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
+.input-prepend .active,.input-append .active{background-color:#a9dba9;border-color:#46a546;}
+.input-prepend .add-on{*margin-top:1px;}
+.input-append input,.input-append .uneditable-input{float:left;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
+.input-append .uneditable-input{border-right-color:#ccc;}
+.input-append .add-on{margin-right:0;margin-left:-1px;-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
+.input-append input:first-child{*margin-left:-160px;}.input-append input:first-child+.add-on{*margin-left:-21px;}
+.search-query{padding-left:14px;padding-right:14px;margin-bottom:0;-webkit-border-radius:14px;-moz-border-radius:14px;border-radius:14px;}
+.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input{display:inline-block;margin-bottom:0;}
+.form-search label,.form-inline label,.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{display:inline-block;}
+.form-search .input-append .add-on,.form-inline .input-prepend .add-on,.form-search .input-append .add-on,.form-inline .input-prepend .add-on{vertical-align:middle;}
+.control-group{margin-bottom:9px;}
+.form-horizontal legend+.control-group{margin-top:18px;-webkit-margin-top-collapse:separate;}
+.form-horizontal .control-group{margin-bottom:18px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";}
+.form-horizontal .control-group:after{clear:both;}
+.form-horizontal .control-group>label{float:left;width:140px;padding-top:5px;text-align:right;}
+.form-horizontal .controls{margin-left:160px;}
+.form-horizontal .form-actions{padding-left:160px;}
+table{max-width:100%;border-collapse:collapse;border-spacing:0;}
+.table{width:100%;margin-bottom:18px;}.table th,.table td{padding:8px;line-height:18px;text-align:left;border-top:1px solid #ddd;}
+.table th{font-weight:bold;vertical-align:bottom;}
+.table td{vertical-align:top;}
+.table thead:first-child tr th,.table thead:first-child tr td{border-top:0;}
+.table tbody+tbody{border-top:2px solid #ddd;}
+.table-condensed th,.table-condensed td{padding:4px 5px;}
+.table-bordered{border:1px solid #ddd;border-collapse:separate;*border-collapse:collapsed;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th+th,.table-bordered td+td,.table-bordered th+td,.table-bordered td+th{border-left:1px solid #ddd;}
+.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;}
+.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-radius:4px 0 0 0;-moz-border-radius:4px 0 0 0;border-radius:4px 0 0 0;}
+.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-radius:0 4px 0 0;-moz-border-radius:0 4px 0 0;border-radius:0 4px 0 0;}
+.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;}
+.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child{-webkit-border-radius:0 0 4px 0;-moz-border-radius:0 0 4px 0;border-radius:0 0 4px 0;}
+.table-striped tbody tr:nth-child(even) td,.table-striped tbody tr:nth-child(even) th{background-color:#f1f1f1;}
+table .span1{float:none;width:44px;margin-left:0;}
+table .span2{float:none;width:124px;margin-left:0;}
+table .span3{float:none;width:204px;margin-left:0;}
+table .span4{float:none;width:284px;margin-left:0;}
+table .span5{float:none;width:364px;margin-left:0;}
+table .span6{float:none;width:444px;margin-left:0;}
+table .span7{float:none;width:524px;margin-left:0;}
+table .span8{float:none;width:604px;margin-left:0;}
+table .span9{float:none;width:684px;margin-left:0;}
+table .span10{float:none;width:764px;margin-left:0;}
+table .span11{float:none;width:844px;margin-left:0;}
+table .span12{float:none;width:924px;margin-left:0;}
+[class^="icon-"]{display:inline-block;width:14px;height:14px;vertical-align:text-top;background-image:url(../img/glyphicons-halflings.png);background-position:14px 14px;background-repeat:no-repeat;*margin-right:.3em;}[class^="icon-"]:last-child{*margin-left:0;}
+.icon-white{background-image:url(../img/glyphicons-halflings-white.png);}
+.icon-glass{background-position:0 0;}
+.icon-music{background-position:-24px 0;}
+.icon-search{background-position:-48px 0;}
+.icon-envelope{background-position:-72px 0;}
+.icon-heart{background-position:-96px 0;}
+.icon-star{background-position:-120px 0;}
+.icon-star-empty{background-position:-144px 0;}
+.icon-user{background-position:-168px 0;}
+.icon-film{background-position:-192px 0;}
+.icon-th-large{background-position:-216px 0;}
+.icon-th{background-position:-240px 0;}
+.icon-th-list{background-position:-264px 0;}
+.icon-ok{background-position:-288px 0;}
+.icon-remove{background-position:-312px 0;}
+.icon-zoom-in{background-position:-336px 0;}
+.icon-zoom-out{background-position:-360px 0;}
+.icon-off{background-position:-384px 0;}
+.icon-signal{background-position:-408px 0;}
+.icon-cog{background-position:-432px 0;}
+.icon-trash{background-position:-456px 0;}
+.icon-home{background-position:0 -24px;}
+.icon-file{background-position:-24px -24px;}
+.icon-time{background-position:-48px -24px;}
+.icon-road{background-position:-72px -24px;}
+.icon-download-alt{background-position:-96px -24px;}
+.icon-download{background-position:-120px -24px;}
+.icon-upload{background-position:-144px -24px;}
+.icon-inbox{background-position:-168px -24px;}
+.icon-play-circle{background-position:-192px -24px;}
+.icon-repeat{background-position:-216px -24px;}
+.icon-refresh{background-position:-240px -24px;}
+.icon-list-alt{background-position:-264px -24px;}
+.icon-lock{background-position:-287px -24px;}
+.icon-flag{background-position:-312px -24px;}
+.icon-headphones{background-position:-336px -24px;}
+.icon-volume-off{background-position:-360px -24px;}
+.icon-volume-down{background-position:-384px -24px;}
+.icon-volume-up{background-position:-408px -24px;}
+.icon-qrcode{background-position:-432px -24px;}
+.icon-barcode{background-position:-456px -24px;}
+.icon-tag{background-position:0 -48px;}
+.icon-tags{background-position:-25px -48px;}
+.icon-book{background-position:-48px -48px;}
+.icon-bookmark{background-position:-72px -48px;}
+.icon-print{background-position:-96px -48px;}
+.icon-camera{background-position:-120px -48px;}
+.icon-font{background-position:-144px -48px;}
+.icon-bold{background-position:-167px -48px;}
+.icon-italic{background-position:-192px -48px;}
+.icon-text-height{background-position:-216px -48px;}
+.icon-text-width{background-position:-240px -48px;}
+.icon-align-left{background-position:-264px -48px;}
+.icon-align-center{background-position:-288px -48px;}
+.icon-align-right{background-position:-312px -48px;}
+.icon-align-justify{background-position:-336px -48px;}
+.icon-list{background-position:-360px -48px;}
+.icon-indent-left{background-position:-384px -48px;}
+.icon-indent-right{background-position:-408px -48px;}
+.icon-facetime-video{background-position:-432px -48px;}
+.icon-picture{background-position:-456px -48px;}
+.icon-pencil{background-position:0 -72px;}
+.icon-map-marker{background-position:-24px -72px;}
+.icon-adjust{background-position:-48px -72px;}
+.icon-tint{background-position:-72px -72px;}
+.icon-edit{background-position:-96px -72px;}
+.icon-share{background-position:-120px -72px;}
+.icon-check{background-position:-144px -72px;}
+.icon-move{background-position:-168px -72px;}
+.icon-step-backward{background-position:-192px -72px;}
+.icon-fast-backward{background-position:-216px -72px;}
+.icon-backward{background-position:-240px -72px;}
+.icon-play{background-position:-264px -72px;}
+.icon-pause{background-position:-288px -72px;}
+.icon-stop{background-position:-312px -72px;}
+.icon-forward{background-position:-336px -72px;}
+.icon-fast-forward{background-position:-360px -72px;}
+.icon-step-forward{background-position:-384px -72px;}
+.icon-eject{background-position:-408px -72px;}
+.icon-chevron-left{background-position:-432px -72px;}
+.icon-chevron-right{background-position:-456px -72px;}
+.icon-plus-sign{background-position:0 -96px;}
+.icon-minus-sign{background-position:-24px -96px;}
+.icon-remove-sign{background-position:-48px -96px;}
+.icon-ok-sign{background-position:-72px -96px;}
+.icon-question-sign{background-position:-96px -96px;}
+.icon-info-sign{background-position:-120px -96px;}
+.icon-screenshot{background-position:-144px -96px;}
+.icon-remove-circle{background-position:-168px -96px;}
+.icon-ok-circle{background-position:-192px -96px;}
+.icon-ban-circle{background-position:-216px -96px;}
+.icon-arrow-left{background-position:-240px -96px;}
+.icon-arrow-right{background-position:-264px -96px;}
+.icon-arrow-up{background-position:-289px -96px;}
+.icon-arrow-down{background-position:-312px -96px;}
+.icon-share-alt{background-position:-336px -96px;}
+.icon-resize-full{background-position:-360px -96px;}
+.icon-resize-small{background-position:-384px -96px;}
+.icon-plus{background-position:-408px -96px;}
+.icon-minus{background-position:-433px -96px;}
+.icon-asterisk{background-position:-456px -96px;}
+.icon-exclamation-sign{background-position:0 -120px;}
+.icon-gift{background-position:-24px -120px;}
+.icon-leaf{background-position:-48px -120px;}
+.icon-fire{background-position:-72px -120px;}
+.icon-eye-open{background-position:-96px -120px;}
+.icon-eye-close{background-position:-120px -120px;}
+.icon-warning-sign{background-position:-144px -120px;}
+.icon-plane{background-position:-168px -120px;}
+.icon-calendar{background-position:-192px -120px;}
+.icon-random{background-position:-216px -120px;}
+.icon-comment{background-position:-240px -120px;}
+.icon-magnet{background-position:-264px -120px;}
+.icon-chevron-up{background-position:-288px -120px;}
+.icon-chevron-down{background-position:-313px -119px;}
+.icon-retweet{background-position:-336px -120px;}
+.icon-shopping-cart{background-position:-360px -120px;}
+.icon-folder-close{background-position:-384px -120px;}
+.icon-folder-open{background-position:-408px -120px;}
+.icon-resize-vertical{background-position:-432px -119px;}
+.icon-resize-horizontal{background-position:-456px -118px;}
+.dropdown{position:relative;}
+.dropdown-toggle{*margin-bottom:-3px;}
+.dropdown-toggle:active,.open .dropdown-toggle{outline:0;}
+.caret{display:inline-block;width:0;height:0;text-indent:-99999px;*text-indent:0;vertical-align:top;border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid #000000;opacity:0.3;filter:alpha(opacity=30);content:"\2193";}
+.dropdown .caret{margin-top:8px;margin-left:2px;}
+.dropdown:hover .caret,.open.dropdown .caret{opacity:1;filter:alpha(opacity=100);}
+.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;float:left;display:none;min-width:160px;max-width:220px;_width:160px;padding:4px 0;margin:0;list-style:none;background-color:#ffffff;border-color:#ccc;border-color:rgba(0, 0, 0, 0.2);border-style:solid;border-width:1px;-webkit-border-radius:0 0 5px 5px;-moz-border-radius:0 0 5px 5px;border-radius:0 0 5px 5px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;*border-right-width:2px;*border-bottom-width:2px;}.dropdown-menu.bottom-up{top:auto;bottom:100%;margin-bottom:2px;}
+.dropdown-menu .divider{height:1px;margin:5px 1px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;*width:100%;*margin:-5px 0 5px;}
+.dropdown-menu a{display:block;padding:3px 15px;clear:both;font-weight:normal;line-height:18px;color:#555555;white-space:nowrap;}
+.dropdown-menu li>a:hover,.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#ffffff;text-decoration:none;background-color:#0088cc;}
+.dropdown.open{*z-index:1000;}.dropdown.open .dropdown-toggle{color:#ffffff;background:#ccc;background:rgba(0, 0, 0, 0.3);}
+.dropdown.open .dropdown-menu{display:block;}
+.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #eee;border:1px solid rgba(0, 0, 0, 0.05);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);}
+.fade{-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-ms-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;opacity:0;}.fade.in{opacity:1;}
+.collapse{-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-ms-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;position:relative;overflow:hidden;height:0;}.collapse.in{height:auto;}
+.close{float:right;font-size:20px;font-weight:bold;line-height:18px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;opacity:0.4;filter:alpha(opacity=40);cursor:pointer;}
+.btn{display:inline-block;padding:4px 10px 4px;font-size:13px;line-height:18px;color:#333333;text-align:center;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#fafafa;background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), color-stop(25%, #ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-moz-linear-gradient(top, #ffffff, #ffffff 25%, #e6e6e6);background-image:-ms-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:-o-linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-image:linear-gradient(#ffffff, #ffffff 25%, #e6e6e6);background-repeat:no-repeat;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);border:1px solid #ccc;border-bottom-color:#bbb;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);cursor:pointer;*margin-left:.3em;}.btn:first-child{*margin-left:0;}
+.btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-ms-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;}
+.btn:focus{outline:thin dotted;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}
+.btn.active,.btn:active{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);background-color:#e6e6e6;background-color:#d9d9d9 \9;color:rgba(0, 0, 0, 0.5);outline:0;}
+.btn.disabled,.btn[disabled]{cursor:default;background-image:none;background-color:#e6e6e6;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}
+.btn-large{padding:9px 14px;font-size:15px;line-height:normal;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
+.btn-large .icon{margin-top:1px;}
+.btn-small{padding:5px 9px;font-size:11px;line-height:16px;}
+.btn-small .icon{margin-top:-1px;}
+.btn-primary,.btn-primary:hover,.btn-warning,.btn-warning:hover,.btn-danger,.btn-danger:hover,.btn-success,.btn-success:hover,.btn-info,.btn-info:hover{text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);color:#ffffff;}
+.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active{color:rgba(255, 255, 255, 0.75);}
+.btn-primary{background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-ms-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(top, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#0088cc', endColorstr='#0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{background-color:#0044cc;}
+.btn-primary:active,.btn-primary.active{background-color:#003399 \9;}
+.btn-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-ms-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(top, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fbb450', endColorstr='#f89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{background-color:#f89406;}
+.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;}
+.btn-danger{background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-ms-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(top, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#bd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{background-color:#bd362f;}
+.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;}
+.btn-success{background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-ms-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(top, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{background-color:#51a351;}
+.btn-success:active,.btn-success.active{background-color:#408140 \9;}
+.btn-info{background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-ms-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(top, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{background-color:#2f96b4;}
+.btn-info:active,.btn-info.active{background-color:#24748c \9;}
+button.btn,input[type="submit"].btn{*padding-top:2px;*padding-bottom:2px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;}
+button.btn.large,input[type="submit"].btn.large{*padding-top:7px;*padding-bottom:7px;}
+button.btn.small,input[type="submit"].btn.small{*padding-top:3px;*padding-bottom:3px;}
+.btn-group{position:relative;*zoom:1;*margin-left:.3em;}.btn-group:before,.btn-group:after{display:table;content:"";}
+.btn-group:after{clear:both;}
+.btn-group:first-child{*margin-left:0;}
+.btn-group+.btn-group{margin-left:5px;}
+.btn-toolbar{margin-top:9px;margin-bottom:9px;}.btn-toolbar .btn-group{display:inline-block;*display:inline;*zoom:1;}
+.btn-group .btn{position:relative;float:left;margin-left:-1px;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.btn-group .btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}
+.btn-group .btn:last-child,.btn-group .dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}
+.btn-group .btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;}
+.btn-group .btn.large:last-child,.btn-group .large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;}
+.btn-group .btn:hover,.btn-group .btn:focus,.btn-group .btn:active,.btn-group .btn.active{z-index:2;}
+.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;}
+.btn-group .dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 1px 0 0 rgba(255, 255, 255, 0.125),inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);*padding-top:5px;*padding-bottom:5px;}
+.btn-group.open{*z-index:1000;}.btn-group.open .dropdown-menu{display:block;margin-top:1px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
+.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 6px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);}
+.btn .caret{margin-top:7px;margin-left:0;}
+.btn:hover .caret,.open.btn-group .caret{opacity:1;filter:alpha(opacity=100);}
+.btn-primary .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret{border-top-color:#ffffff;opacity:0.75;filter:alpha(opacity=75);}
+.btn-small .caret{margin-top:4px;}
+.alert{padding:8px 35px 8px 14px;margin-bottom:18px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.alert,.alert-heading{color:#c09853;}
+.alert .close{position:relative;top:-2px;right:-21px;line-height:18px;}
+.alert-success{background-color:#dff0d8;border-color:#d6e9c6;}
+.alert-success,.alert-success .alert-heading{color:#468847;}
+.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;}
+.alert-danger,.alert-error,.alert-danger .alert-heading,.alert-error .alert-heading{color:#b94a48;}
+.alert-info{background-color:#d9edf7;border-color:#bce8f1;}
+.alert-info,.alert-info .alert-heading{color:#3a87ad;}
+.alert-block{padding-top:14px;padding-bottom:14px;}
+.alert-block>p,.alert-block>ul{margin-bottom:0;}
+.alert-block p+p{margin-top:5px;}
+.nav{margin-left:0;margin-bottom:18px;list-style:none;}
+.nav>li>a{display:block;}
+.nav>li>a:hover{text-decoration:none;background-color:#eeeeee;}
+.nav-list{padding-left:14px;padding-right:14px;margin-bottom:0;}
+.nav-list>li>a,.nav-list .nav-header{display:block;padding:3px 15px;margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}
+.nav-list .nav-header{font-size:11px;font-weight:bold;line-height:18px;color:#999999;text-transform:uppercase;}
+.nav-list>li+.nav-header{margin-top:9px;}
+.nav-list .active>a{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;}
+.nav-list .icon{margin-right:2px;}
+.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";}
+.nav-tabs:after,.nav-pills:after{clear:both;}
+.nav-tabs>li,.nav-pills>li{float:left;}
+.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;}
+.nav-tabs{border-bottom:1px solid #ddd;}
+.nav-tabs>li{margin-bottom:-1px;}
+.nav-tabs>li>a{padding-top:9px;padding-bottom:9px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;}
+.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;}
+.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}
+.nav-pills .active>a,.nav-pills .active>a:hover{color:#ffffff;background-color:#0088cc;}
+.nav-stacked>li{float:none;}
+.nav-stacked>li>a{margin-right:0;}
+.nav-tabs.nav-stacked{border-bottom:0;}
+.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}
+.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}
+.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;}
+.nav-pills.nav-stacked>li>a{margin-bottom:3px;}
+.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;}
+.nav-tabs .dropdown-menu,.nav-pills .dropdown-menu{margin-top:1px;border-width:1px;}
+.nav-pills .dropdown-menu{-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.nav-tabs .dropdown-toggle .caret,.nav-pills .dropdown-toggle .caret{border-top-color:#0088cc;margin-top:6px;}
+.nav-tabs .dropdown-toggle:hover .caret,.nav-pills .dropdown-toggle:hover .caret{border-top-color:#005580;}
+.nav-tabs .active .dropdown-toggle .caret,.nav-pills .active .dropdown-toggle .caret{border-top-color:#333333;}
+.nav>.dropdown.active>a:hover{color:#000000;cursor:pointer;}
+.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;}
+.nav .open .caret,.nav .open.active .caret,.nav .open a:hover .caret{border-top-color:#ffffff;opacity:1;filter:alpha(opacity=100);}
+.tabs-stacked .open>a:hover{border-color:#999999;}
+.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";}
+.tabbable:after{clear:both;}
+.tabs-below .nav-tabs,.tabs-right .nav-tabs,.tabs-left .nav-tabs{border-bottom:0;}
+.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;}
+.tab-content>.active,.pill-content>.active{display:block;}
+.tabs-below .nav-tabs{border-top:1px solid #ddd;}
+.tabs-below .nav-tabs>li{margin-top:-1px;margin-bottom:0;}
+.tabs-below .nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below .nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;}
+.tabs-below .nav-tabs .active>a,.tabs-below .nav-tabs .active>a:hover{border-color:transparent #ddd #ddd #ddd;}
+.tabs-left .nav-tabs>li,.tabs-right .nav-tabs>li{float:none;}
+.tabs-left .nav-tabs>li>a,.tabs-right .nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;}
+.tabs-left .nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;}
+.tabs-left .nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}
+.tabs-left .nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;}
+.tabs-left .nav-tabs .active>a,.tabs-left .nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;}
+.tabs-right .nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;}
+.tabs-right .nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}
+.tabs-right .nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;}
+.tabs-right .nav-tabs .active>a,.tabs-right .nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;}
+.navbar{overflow:visible;margin-bottom:18px;}
+.navbar-inner{padding-left:20px;padding-right:20px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.25),inset 0 -1px 0 rgba(0, 0, 0, 0.1);}
+.btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;background-color:#2c2c2c;background-image:-moz-linear-gradient(top, #333333, #222222);background-image:-ms-linear-gradient(top, #333333, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#333333), to(#222222));background-image:-webkit-linear-gradient(top, #333333, #222222);background-image:-o-linear-gradient(top, #333333, #222222);background-image:linear-gradient(top, #333333, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#333333', endColorstr='#222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.075);}.btn-navbar:hover,.btn-navbar:active,.btn-navbar.active,.btn-navbar.disabled,.btn-navbar[disabled]{background-color:#222222;}
+.btn-navbar:active,.btn-navbar.active{background-color:#080808 \9;}
+.btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);}
+.btn-navbar .icon-bar+.icon-bar{margin-top:3px;}
+.nav-collapse.collapse{height:auto;}
+.navbar .brand:hover{text-decoration:none;}
+.navbar .brand{float:left;display:block;padding:8px 20px 12px;margin-left:-20px;font-size:20px;font-weight:200;line-height:1;color:#ffffff;}
+.navbar .navbar-text{margin-bottom:0;line-height:40px;color:#999999;}.navbar .navbar-text a:hover{color:#ffffff;background-color:transparent;}
+.navbar .btn,.navbar .btn-group{margin-top:5px;}
+.navbar .btn-group .btn{margin-top:0;}
+.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";}
+.navbar-form:after{clear:both;}
+.navbar-form input,.navbar-form select{display:inline-block;margin-top:5px;margin-bottom:0;}
+.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;}
+.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;}
+.navbar-search{position:relative;float:left;margin-top:6px;margin-bottom:0;}.navbar-search .search-query{padding:4px 9px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;color:#ffffff;color:rgba(255, 255, 255, 0.75);background:#666;background:rgba(255, 255, 255, 0.3);border:1px solid #111;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1),0 1px 0px rgba(255, 255, 255, 0.15);-webkit-transition:none;-moz-transition:none;-ms-transition:none;-o-transition:none;transition:none;}.navbar-search .search-query :-moz-placeholder{color:#eeeeee;}
+.navbar-search .search-query::-webkit-input-placeholder{color:#eeeeee;}
+.navbar-search .search-query:hover{color:#ffffff;background-color:#999999;background-color:rgba(255, 255, 255, 0.5);}
+.navbar-search .search-query:focus,.navbar-search .search-query.focused{padding:5px 10px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;}
+.navbar-fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030;}
+.navbar-fixed-top .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}
+.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;}
+.navbar .nav.pull-right{float:right;}
+.navbar .nav>li{display:block;float:left;}
+.navbar .nav>li>a{float:none;padding:10px 10px 11px;line-height:19px;color:#999999;text-decoration:none;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}
+.navbar .nav>li>a:hover{background-color:transparent;color:#ffffff;text-decoration:none;}
+.navbar .nav .active>a,.navbar .nav .active>a:hover{color:#ffffff;text-decoration:none;background-color:#222222;background-color:rgba(0, 0, 0, 0.5);}
+.navbar .divider-vertical{height:40px;width:1px;margin:0 9px;overflow:hidden;background-color:#222222;border-right:1px solid #333333;}
+.navbar .nav.pull-right{margin-left:10px;margin-right:0;}
+.navbar .dropdown-menu{margin-top:1px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.navbar .dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;}
+.navbar .dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;}
+.navbar .nav .dropdown-toggle .caret,.navbar .nav .open.dropdown .caret{border-top-color:#ffffff;}
+.navbar .nav .active .caret{opacity:1;filter:alpha(opacity=100);}
+.navbar .nav .open>.dropdown-toggle,.navbar .nav .active>.dropdown-toggle,.navbar .nav .open.active>.dropdown-toggle{background-color:transparent;}
+.navbar .nav .active>.dropdown-toggle:hover{color:#ffffff;}
+.navbar .nav.pull-right .dropdown-menu{left:auto;right:0;}.navbar .nav.pull-right .dropdown-menu:before{left:auto;right:12px;}
+.navbar .nav.pull-right .dropdown-menu:after{left:auto;right:13px;}
+.breadcrumb{padding:7px 14px;margin:0 0 18px;background-color:#fbfbfb;background-image:-moz-linear-gradient(top, #ffffff, #f5f5f5);background-image:-ms-linear-gradient(top, #ffffff, #f5f5f5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f5f5f5));background-image:-webkit-linear-gradient(top, #ffffff, #f5f5f5);background-image:-o-linear-gradient(top, #ffffff, #f5f5f5);background-image:linear-gradient(top, #ffffff, #f5f5f5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#f5f5f5', GradientType=0);border:1px solid #ddd;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;}.breadcrumb li{display:inline;text-shadow:0 1px 0 #ffffff;}
+.breadcrumb .divider{padding:0 5px;color:#999999;}
+.breadcrumb .active a{color:#333333;}
+.pagination{height:36px;margin:18px 0;}
+.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);}
+.pagination li{display:inline;}
+.pagination a{float:left;padding:0 14px;line-height:34px;text-decoration:none;border:1px solid #ddd;border-left-width:0;}
+.pagination a:hover,.pagination .active a{background-color:#f5f5f5;}
+.pagination .active a{color:#999999;cursor:default;}
+.pagination .disabled a,.pagination .disabled a:hover{color:#999999;background-color:transparent;cursor:default;}
+.pagination li:first-child a{border-left-width:1px;-webkit-border-radius:3px 0 0 3px;-moz-border-radius:3px 0 0 3px;border-radius:3px 0 0 3px;}
+.pagination li:last-child a{-webkit-border-radius:0 3px 3px 0;-moz-border-radius:0 3px 3px 0;border-radius:0 3px 3px 0;}
+.pagination-centered{text-align:center;}
+.pagination-right{text-align:right;}
+.pager{margin-left:0;margin-bottom:18px;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";}
+.pager:after{clear:both;}
+.pager li{display:inline;}
+.pager a{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}
+.pager a:hover{text-decoration:none;background-color:#f5f5f5;}
+.pager .next a{float:right;}
+.pager .previous a{float:left;}
+.modal-open .dropdown-menu{z-index:2050;}
+.modal-open .dropdown.open{*z-index:2050;}
+.modal-open .popover{z-index:2060;}
+.modal-open .tooltip{z-index:2070;}
+.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;}
+.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);}
+.modal{position:fixed;top:50%;left:50%;z-index:1050;max-height:500px;overflow:auto;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-ms-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;}
+.modal.fade.in{top:50%;}
+.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;}
+.modal-body{padding:15px;}
+.modal-footer{padding:14px 15px 15px;margin-bottom:0;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";}
+.modal-footer:after{clear:both;}
+.modal-footer .btn{float:right;margin-left:5px;margin-bottom:0;}
+.tooltip{position:absolute;z-index:1020;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);}
+.tooltip.top{margin-top:-2px;}
+.tooltip.right{margin-left:2px;}
+.tooltip.bottom{margin-top:2px;}
+.tooltip.left{margin-left:-2px;}
+.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
+.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;}
+.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;}
+.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;}
+.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.tooltip-arrow{position:absolute;width:0;height:0;}
+.popover{position:absolute;top:0;left:0;z-index:1010;display:none;padding:5px;}.popover.top{margin-top:-5px;}
+.popover.right{margin-left:5px;}
+.popover.bottom{margin-top:5px;}
+.popover.left{margin-left:-5px;}
+.popover.top .arrow{bottom:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-top:5px solid #000000;}
+.popover.right .arrow{top:50%;left:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-right:5px solid #000000;}
+.popover.bottom .arrow{top:0;left:50%;margin-left:-5px;border-left:5px solid transparent;border-right:5px solid transparent;border-bottom:5px solid #000000;}
+.popover.left .arrow{top:50%;right:0;margin-top:-5px;border-top:5px solid transparent;border-bottom:5px solid transparent;border-left:5px solid #000000;}
+.popover .arrow{position:absolute;width:0;height:0;}
+.popover-inner{padding:3px;width:280px;overflow:hidden;background:#000000;background:rgba(0, 0, 0, 0.8);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);}
+.popover-title{padding:9px 15px;line-height:1;background-color:#f5f5f5;border-bottom:1px solid #eee;-webkit-border-radius:3px 3px 0 0;-moz-border-radius:3px 3px 0 0;border-radius:3px 3px 0 0;}
+.popover-content{padding:14px;background-color:#ffffff;-webkit-border-radius:0 0 3px 3px;-moz-border-radius:0 0 3px 3px;border-radius:0 0 3px 3px;-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0;}
+.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";}
+.thumbnails:after{clear:both;}
+.thumbnails>li{float:left;margin:0 0 18px 20px;}
+.thumbnail{display:block;padding:4px;line-height:1;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:0 1px 1px rgba(0, 0, 0, 0.075);}
+a.thumbnail:hover{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);}
+.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;}
+.thumbnail .caption{padding:9px;}
+.label{padding:1px 3px 2px;font-size:9.75px;font-weight:bold;color:#ffffff;text-transform:uppercase;background-color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}
+.label-important{background-color:#b94a48;}
+.label-warning{background-color:#f89406;}
+.label-success{background-color:#468847;}
+.label-info{background-color:#3a87ad;}
+@-webkit-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}.progress{overflow:hidden;height:18px;margin-bottom:18px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-ms-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(top, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#f5f5f5', endColorstr='#f9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.progress .bar{width:0%;height:18px;color:#ffffff;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-ms-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(top, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#149bdf', endColorstr='#0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-ms-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;}
+.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;}
+.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;}
+.progress-danger .bar{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-ms-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(top, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ee5f5b', endColorstr='#c43c35', GradientType=0);}
+.progress-danger.progress-striped .bar{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
+.progress-success .bar{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-ms-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(top, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#62c462', endColorstr='#57a957', GradientType=0);}
+.progress-success.progress-striped .bar{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
+.progress-info .bar{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-ms-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(top, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#5bc0de', endColorstr='#339bb9', GradientType=0);}
+.progress-info.progress-striped .bar{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-ms-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(-45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}
+.accordion{margin-bottom:18px;}
+.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}
+.accordion-heading{border-bottom:0;}
+.accordion-heading .accordion-toggle{display:block;padding:8px 15px;}
+.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;}
+.carousel{position:relative;margin-bottom:18px;line-height:1;}
+.carousel-inner{overflow:hidden;width:100%;position:relative;}
+.carousel .item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-ms-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;}
+.carousel .item>img{display:block;line-height:1;}
+.carousel .active,.carousel .next,.carousel .prev{display:block;}
+.carousel .active{left:0;}
+.carousel .next,.carousel .prev{position:absolute;top:0;width:100%;}
+.carousel .next{left:100%;}
+.carousel .prev{left:-100%;}
+.carousel .next.left,.carousel .prev.right{left:0;}
+.carousel .active.left{left:-100%;}
+.carousel .active.right{left:100%;}
+.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;}
+.carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);}
+.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:10px 15px 5px;background:#333333;background:rgba(0, 0, 0, 0.75);}
+.carousel-caption h4,.carousel-caption p{color:#ffffff;}
+.hero-unit{padding:60px;margin-bottom:30px;background-color:#f5f5f5;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;letter-spacing:-1px;}
+.hero-unit p{font-size:18px;font-weight:200;line-height:27px;}
+.pull-right{float:right;}
+.pull-left{float:left;}
+.hide{display:none;}
+.show{display:block;}
+.invisible{visibility:hidden;}
+
+
+/* Responsive css */
+
+/*.hidden{display:none;visibility:hidden;}*/
+/*@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0);} .page-header h1 small{display:block;line-height:18px;} input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;height:28px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;-ms-box-sizing:border-box;box-sizing:border-box;} .input-prepend input[class*="span"],.input-append input[class*="span"]{width:auto;} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc;} .form-horizontal .control-group>label{float:none;width:auto;padding-top:0;text-align:left;} .form-horizontal .controls{margin-left:0;} .form-horizontal .control-list{padding-top:0;} .form-horizontal .form-actions{padding-left:10px;padding-right:10px;} .modal{position:absolute;top:10px;left:10px;right:10px;width:auto;margin:0;}.modal.fade.in{top:auto;} .modal-header .close{padding:10px;margin:-10px;} .carousel-caption{position:static;}}@media (max-width:768px){.container{width:auto;padding:0 20px;} .row-fluid{width:100%;} .row{margin-left:0;} .row>[class*="span"],.row-fluid>[class*="span"]{float:none;display:block;width:auto;margin:0;}}@media (min-width:768px) and (max-width:980px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:20px;} .span1{width:42px;} .span2{width:104px;} .span3{width:166px;} .span4{width:228px;} .span5{width:290px;} .span6{width:352px;} .span7{width:414px;} .span8{width:476px;} .span9{width:538px;} .span10{width:600px;} .span11{width:662px;} .span12,.container{width:724px;} .offset1{margin-left:82px;} .offset2{margin-left:144px;} .offset3{margin-left:206px;} .offset4{margin-left:268px;} .offset5{margin-left:330px;} .offset6{margin-left:392px;} .offset7{margin-left:454px;} .offset8{margin-left:516px;} .offset9{margin-left:578px;} .offset10{margin-left:640px;} .offset11{margin-left:702px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.762430939%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid .span1{width:5.801104972%;} .row-fluid .span2{width:14.364640883%;} .row-fluid .span3{width:22.928176794%;} .row-fluid .span4{width:31.491712705%;} .row-fluid .span5{width:40.055248616%;} .row-fluid .span6{width:48.618784527%;} .row-fluid .span7{width:57.182320438000005%;} .row-fluid .span8{width:65.74585634900001%;} .row-fluid .span9{width:74.30939226%;} .row-fluid .span10{width:82.87292817100001%;} .row-fluid .span11{width:91.436464082%;} .row-fluid .span12{width:99.999999993%;} input.span1,textarea.span1,.uneditable-input.span1{width:32px;} input.span2,textarea.span2,.uneditable-input.span2{width:94px;} input.span3,textarea.span3,.uneditable-input.span3{width:156px;} input.span4,textarea.span4,.uneditable-input.span4{width:218px;} input.span5,textarea.span5,.uneditable-input.span5{width:280px;} input.span6,textarea.span6,.uneditable-input.span6{width:342px;} input.span7,textarea.span7,.uneditable-input.span7{width:404px;} input.span8,textarea.span8,.uneditable-input.span8{width:466px;} input.span9,textarea.span9,.uneditable-input.span9{width:528px;} input.span10,textarea.span10,.uneditable-input.span10{width:590px;} input.span11,textarea.span11,.uneditable-input.span11{width:652px;} input.span12,textarea.span12,.uneditable-input.span12{width:714px;}}@media (max-width:980px){body{padding-top:0;} .navbar-fixed-top{position:static;margin-bottom:18px;} .navbar-fixed-top .navbar-inner{padding:5px;} .navbar .container{width:auto;padding:0;} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px;} .navbar .nav-collapse{clear:left;} .navbar .nav{float:none;margin:0 0 9px;} .navbar .nav>li{float:none;} .navbar .nav>li>a{margin-bottom:2px;} .navbar .nav>.divider-vertical{display:none;} .navbar .nav>li>a,.navbar .dropdown-menu a{padding:6px 15px;font-weight:bold;color:#999999;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .navbar .dropdown-menu li+li a{margin-bottom:2px;} .navbar .nav>li>a:hover,.navbar .dropdown-menu a:hover{background-color:#222222;} .navbar .dropdown-menu{position:static;top:auto;left:auto;float:none;display:block;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .navbar .dropdown-menu:before,.navbar .dropdown-menu:after{display:none;} .navbar .dropdown-menu .divider{display:none;} .navbar-form,.navbar-search{float:none;padding:9px 15px;margin:9px 0;border-top:1px solid #222222;border-bottom:1px solid #222222;-webkit-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);-moz-box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);box-shadow:inset 0 1px 0 rgba(255, 255, 255, 0.1),0 1px 0 rgba(255, 255, 255, 0.1);} .navbar .nav.pull-right{float:none;margin-left:0;} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px;} .btn-navbar{display:block;} .nav-collapse{overflow:hidden;height:0;}}@media (min-width:980px){.nav-collapse.collapse{height:auto !important;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:"";} .row:after{clear:both;} [class*="span"]{float:left;margin-left:30px;} .span1{width:70px;} .span2{width:170px;} .span3{width:270px;} .span4{width:370px;} .span5{width:470px;} .span6{width:570px;} .span7{width:670px;} .span8{width:770px;} .span9{width:870px;} .span10{width:970px;} .span11{width:1070px;} .span12,.container{width:1170px;} .offset1{margin-left:130px;} .offset2{margin-left:230px;} .offset3{margin-left:330px;} .offset4{margin-left:430px;} .offset5{margin-left:530px;} .offset6{margin-left:630px;} .offset7{margin-left:730px;} .offset8{margin-left:830px;} .offset9{margin-left:930px;} .offset10{margin-left:1030px;} .offset11{margin-left:1130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";} .row-fluid:after{clear:both;} .row-fluid>[class*="span"]{float:left;margin-left:2.564102564%;} .row-fluid>[class*="span"]:first-child{margin-left:0;} .row-fluid .span1{width:5.982905983%;} .row-fluid .span2{width:14.529914530000001%;} .row-fluid .span3{width:23.076923077%;} .row-fluid .span4{width:31.623931624%;} .row-fluid .span5{width:40.170940171000005%;} .row-fluid .span6{width:48.717948718%;} .row-fluid .span7{width:57.264957265%;} .row-fluid .span8{width:65.81196581200001%;} .row-fluid .span9{width:74.358974359%;} .row-fluid .span10{width:82.905982906%;} .row-fluid .span11{width:91.45299145300001%;} .row-fluid .span12{width:100%;} input.span1,textarea.span1,.uneditable-input.span1{width:60px;} input.span2,textarea.span2,.uneditable-input.span2{width:160px;} input.span3,textarea.span3,.uneditable-input.span3{width:260px;} input.span4,textarea.span4,.uneditable-input.span4{width:360px;} input.span5,textarea.span5,.uneditable-input.span5{width:460px;} input.span6,textarea.span6,.uneditable-input.span6{width:560px;} input.span7,textarea.span7,.uneditable-input.span7{width:660px;} input.span8,textarea.span8,.uneditable-input.span8{width:760px;} input.span9,textarea.span9,.uneditable-input.span9{width:860px;} input.span10,textarea.span10,.uneditable-input.span10{width:960px;} input.span11,textarea.span11,.uneditable-input.span11{width:1060px;} input.span12,textarea.span12,.uneditable-input.span12{width:1160px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;}}*/
diff --git a/docs/source/assets/css/local.css b/docs/source/assets/css/local.css
new file mode 100644
index 0000000..5c703af
--- /dev/null
+++ b/docs/source/assets/css/local.css
@@ -0,0 +1,122 @@
+
+a.brand {
+ background: url(../images/small_logo.png) no-repeat left 6px;
+ width: 166px;
+ text-indent: -9999px;
+}
+
+code {
+ background-color: #ffffff;
+}
+
+#home .hero-unit {
+ background: url(../images/header_bg.png) top left repeat-x;
+ color: #fff;
+ padding-left: 25px;
+ padding-right: 25px;
+ height: 161px;
+}
+
+#home .hero-unit {
+ margin-right: ;
+}
+
+h1#main_header {
+ background: url(../images/logo.png) top left no-repeat;
+ text-indent: -9999px;
+}
+
+.sub_header {
+ font-size: 12px;
+ font-family: "anivers";
+ font-weight: normal;
+ width: 420px;
+}
+
+#home .hero-unit a {
+ color: #fff;
+ text-decoration: underline;
+}
+
+.clear {
+ clear: both;
+}
+
+ol#getting_started {
+ list-style: none;
+ width: 396px;
+ margin-top: -45px;
+ margin-right: 0;
+ margin-left: 72px;
+}
+
+ol#getting_started li {
+ background: url(../images/quickstart.png) top left no-repeat;
+}
+
+ol#getting_started li pre {
+ font-size: 11px;
+ padding: 5px;
+ background: #4d7ead;
+ border-color: #2c5d8d;
+ color: #fff;
+ overflow: auto;
+}
+
+li#ubuntu {
+ height: 46px;
+ padding: ;
+ padding-left: 82px;
+ padding-top: 27px;
+ margin-bottom: 14px;
+}
+
+li#github {
+ background-position: left -70px !important;
+ height: 61px;
+ padding: ;
+ padding-left: 82px;
+ padding-top: 4px;
+ margin-bottom: 25px;
+}
+
+
+li#install {
+ background-position: left bottom !important;
+ height: 61px;
+ padding: ;
+ padding-left: 82px;
+ padding-top: 4px;
+ margin-bottom: 25px;
+}
+
+h2 small {
+ font-size: 12px;
+ font-style: italic;
+}
+
+.container section {
+ margin-bottom: 25px;
+}
+
+
+thead, tfoot{
+ background: #ededed;
+ color: #444444;
+}
+
+table {
+ color: #444;
+}
+a.table-action {
+ display: block;
+ width: 45px;
+}
+
+footer {
+ clear: both;
+}
+
+.wat {
+ margin-top: 33px;
+}
\ No newline at end of file
diff --git a/docs/source/assets/images/devstack.png b/docs/source/assets/images/devstack.png
new file mode 100644
index 0000000..ca6297e
--- /dev/null
+++ b/docs/source/assets/images/devstack.png
Binary files differ
diff --git a/docs/source/assets/images/header_bg.png b/docs/source/assets/images/header_bg.png
new file mode 100644
index 0000000..4e6b2b8
--- /dev/null
+++ b/docs/source/assets/images/header_bg.png
Binary files differ
diff --git a/docs/source/assets/images/logo.png b/docs/source/assets/images/logo.png
new file mode 100644
index 0000000..9c2087e
--- /dev/null
+++ b/docs/source/assets/images/logo.png
Binary files differ
diff --git a/docs/source/assets/images/quickstart.png b/docs/source/assets/images/quickstart.png
new file mode 100644
index 0000000..5f01bac
--- /dev/null
+++ b/docs/source/assets/images/quickstart.png
Binary files differ
diff --git a/docs/source/assets/images/small_logo.png b/docs/source/assets/images/small_logo.png
new file mode 100644
index 0000000..181459f
--- /dev/null
+++ b/docs/source/assets/images/small_logo.png
Binary files differ
diff --git a/docs/source/assets/js/bootstrap.js b/docs/source/assets/js/bootstrap.js
new file mode 100644
index 0000000..c832ccb
--- /dev/null
+++ b/docs/source/assets/js/bootstrap.js
@@ -0,0 +1,1722 @@
+/* ===================================================
+ * bootstrap-transition.js v2.0.0
+ * http://twitter.github.com/bootstrap/javascript.html#transitions
+ * ===================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ========================================================== */
+
+!function( $ ) {
+
+ $(function () {
+
+ "use strict"
+
+ /* CSS TRANSITION SUPPORT (https://gist.github.com/373874)
+ * ======================================================= */
+
+ $.support.transition = (function () {
+ var thisBody = document.body || document.documentElement
+ , thisStyle = thisBody.style
+ , support = thisStyle.transition !== undefined || thisStyle.WebkitTransition !== undefined || thisStyle.MozTransition !== undefined || thisStyle.MsTransition !== undefined || thisStyle.OTransition !== undefined
+
+ return support && {
+ end: (function () {
+ var transitionEnd = "TransitionEnd"
+ if ( $.browser.webkit ) {
+ transitionEnd = "webkitTransitionEnd"
+ } else if ( $.browser.mozilla ) {
+ transitionEnd = "transitionend"
+ } else if ( $.browser.opera ) {
+ transitionEnd = "oTransitionEnd"
+ }
+ return transitionEnd
+ }())
+ }
+ })()
+
+ })
+
+}( window.jQuery )
+/* ==========================================================
+ * bootstrap-alert.js v2.0.0
+ * http://twitter.github.com/bootstrap/javascript.html#alerts
+ * ==========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ========================================================== */
+
+
+!function( $ ){
+
+ "use strict"
+
+ /* ALERT CLASS DEFINITION
+ * ====================== */
+
+ var dismiss = '[data-dismiss="alert"]'
+ , Alert = function ( el ) {
+ $(el).on('click', dismiss, this.close)
+ }
+
+ Alert.prototype = {
+
+ constructor: Alert
+
+ , close: function ( e ) {
+ var $this = $(this)
+ , selector = $this.attr('data-target')
+ , $parent
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ $parent = $(selector)
+ $parent.trigger('close')
+
+ e && e.preventDefault()
+
+ $parent.length || ($parent = $this.hasClass('alert') ? $this : $this.parent())
+
+ $parent.removeClass('in')
+
+ function removeElement() {
+ $parent.remove()
+ $parent.trigger('closed')
+ }
+
+ $.support.transition && $parent.hasClass('fade') ?
+ $parent.on($.support.transition.end, removeElement) :
+ removeElement()
+ }
+
+ }
+
+
+ /* ALERT PLUGIN DEFINITION
+ * ======================= */
+
+ $.fn.alert = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('alert')
+ if (!data) $this.data('alert', (data = new Alert(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ $.fn.alert.Constructor = Alert
+
+
+ /* ALERT DATA-API
+ * ============== */
+
+ $(function () {
+ $('body').on('click.alert.data-api', dismiss, Alert.prototype.close)
+ })
+
+}( window.jQuery )
+/* ============================================================
+ * bootstrap-button.js v2.0.0
+ * http://twitter.github.com/bootstrap/javascript.html#buttons
+ * ============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ============================================================ */
+
+!function( $ ){
+
+ "use strict"
+
+ /* BUTTON PUBLIC CLASS DEFINITION
+ * ============================== */
+
+ var Button = function ( element, options ) {
+ this.$element = $(element)
+ this.options = $.extend({}, $.fn.button.defaults, options)
+ }
+
+ Button.prototype = {
+
+ constructor: Button
+
+ , setState: function ( state ) {
+ var d = 'disabled'
+ , $el = this.$element
+ , data = $el.data()
+ , val = $el.is('input') ? 'val' : 'html'
+
+ state = state + 'Text'
+ data.resetText || $el.data('resetText', $el[val]())
+
+ $el[val](data[state] || this.options[state])
+
+ // push to event loop to allow forms to submit
+ setTimeout(function () {
+ state == 'loadingText' ?
+ $el.addClass(d).attr(d, d) :
+ $el.removeClass(d).removeAttr(d)
+ }, 0)
+ }
+
+ , toggle: function () {
+ var $parent = this.$element.parent('[data-toggle="buttons-radio"]')
+
+ $parent && $parent
+ .find('.active')
+ .removeClass('active')
+
+ this.$element.toggleClass('active')
+ }
+
+ }
+
+
+ /* BUTTON PLUGIN DEFINITION
+ * ======================== */
+
+ $.fn.button = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('button')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('button', (data = new Button(this, options)))
+ if (option == 'toggle') data.toggle()
+ else if (option) data.setState(option)
+ })
+ }
+
+ $.fn.button.defaults = {
+ loadingText: 'loading...'
+ }
+
+ $.fn.button.Constructor = Button
+
+
+ /* BUTTON DATA-API
+ * =============== */
+
+ $(function () {
+ $('body').on('click.button.data-api', '[data-toggle^=button]', function ( e ) {
+ $(e.target).button('toggle')
+ })
+ })
+
+}( window.jQuery )
+/* ==========================================================
+ * bootstrap-carousel.js v2.0.0
+ * http://twitter.github.com/bootstrap/javascript.html#carousel
+ * ==========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ========================================================== */
+
+
+!function( $ ){
+
+ "use strict"
+
+ /* CAROUSEL CLASS DEFINITION
+ * ========================= */
+
+ var Carousel = function (element, options) {
+ this.$element = $(element)
+ this.options = $.extend({}, $.fn.carousel.defaults, options)
+ this.options.slide && this.slide(this.options.slide)
+ }
+
+ Carousel.prototype = {
+
+ cycle: function () {
+ this.interval = setInterval($.proxy(this.next, this), this.options.interval)
+ return this
+ }
+
+ , to: function (pos) {
+ var $active = this.$element.find('.active')
+ , children = $active.parent().children()
+ , activePos = children.index($active)
+ , that = this
+
+ if (pos > (children.length - 1) || pos < 0) return
+
+ if (this.sliding) {
+ return this.$element.one('slid', function () {
+ that.to(pos)
+ })
+ }
+
+ if (activePos == pos) {
+ return this.pause().cycle()
+ }
+
+ return this.slide(pos > activePos ? 'next' : 'prev', $(children[pos]))
+ }
+
+ , pause: function () {
+ clearInterval(this.interval)
+ return this
+ }
+
+ , next: function () {
+ if (this.sliding) return
+ return this.slide('next')
+ }
+
+ , prev: function () {
+ if (this.sliding) return
+ return this.slide('prev')
+ }
+
+ , slide: function (type, next) {
+ var $active = this.$element.find('.active')
+ , $next = next || $active[type]()
+ , isCycling = this.interval
+ , direction = type == 'next' ? 'left' : 'right'
+ , fallback = type == 'next' ? 'first' : 'last'
+ , that = this
+
+ this.sliding = true
+
+ isCycling && this.pause()
+
+ $next = $next.length ? $next : this.$element.find('.item')[fallback]()
+
+ if (!$.support.transition && this.$element.hasClass('slide')) {
+ this.$element.trigger('slide')
+ $active.removeClass('active')
+ $next.addClass('active')
+ this.sliding = false
+ this.$element.trigger('slid')
+ } else {
+ $next.addClass(type)
+ $next[0].offsetWidth // force reflow
+ $active.addClass(direction)
+ $next.addClass(direction)
+ this.$element.trigger('slide')
+ this.$element.one($.support.transition.end, function () {
+ $next.removeClass([type, direction].join(' ')).addClass('active')
+ $active.removeClass(['active', direction].join(' '))
+ that.sliding = false
+ setTimeout(function () { that.$element.trigger('slid') }, 0)
+ })
+ }
+
+ isCycling && this.cycle()
+
+ return this
+ }
+
+ }
+
+
+ /* CAROUSEL PLUGIN DEFINITION
+ * ========================== */
+
+ $.fn.carousel = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('carousel')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('carousel', (data = new Carousel(this, options)))
+ if (typeof option == 'number') data.to(option)
+ else if (typeof option == 'string' || (option = options.slide)) data[option]()
+ else data.cycle()
+ })
+ }
+
+ $.fn.carousel.defaults = {
+ interval: 5000
+ }
+
+ $.fn.carousel.Constructor = Carousel
+
+
+ /* CAROUSEL DATA-API
+ * ================= */
+
+ $(function () {
+ $('body').on('click.carousel.data-api', '[data-slide]', function ( e ) {
+ var $this = $(this), href
+ , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
+ , options = !$target.data('modal') && $.extend({}, $target.data(), $this.data())
+ $target.carousel(options)
+ e.preventDefault()
+ })
+ })
+
+}( window.jQuery )
+/* =============================================================
+ * bootstrap-collapse.js v2.0.0
+ * http://twitter.github.com/bootstrap/javascript.html#collapse
+ * =============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ============================================================ */
+
+!function( $ ){
+
+ "use strict"
+
+ var Collapse = function ( element, options ) {
+ this.$element = $(element)
+ this.options = $.extend({}, $.fn.collapse.defaults, options)
+
+ if (this.options["parent"]) {
+ this.$parent = $(this.options["parent"])
+ }
+
+ this.options.toggle && this.toggle()
+ }
+
+ Collapse.prototype = {
+
+ constructor: Collapse
+
+ , dimension: function () {
+ var hasWidth = this.$element.hasClass('width')
+ return hasWidth ? 'width' : 'height'
+ }
+
+ , show: function () {
+ var dimension = this.dimension()
+ , scroll = $.camelCase(['scroll', dimension].join('-'))
+ , actives = this.$parent && this.$parent.find('.in')
+ , hasData
+
+ if (actives && actives.length) {
+ hasData = actives.data('collapse')
+ actives.collapse('hide')
+ hasData || actives.data('collapse', null)
+ }
+
+ this.$element[dimension](0)
+ this.transition('addClass', 'show', 'shown')
+ this.$element[dimension](this.$element[0][scroll])
+
+ }
+
+ , hide: function () {
+ var dimension = this.dimension()
+ this.reset(this.$element[dimension]())
+ this.transition('removeClass', 'hide', 'hidden')
+ this.$element[dimension](0)
+ }
+
+ , reset: function ( size ) {
+ var dimension = this.dimension()
+
+ this.$element
+ .removeClass('collapse')
+ [dimension](size || 'auto')
+ [0].offsetWidth
+
+ this.$element.addClass('collapse')
+ }
+
+ , transition: function ( method, startEvent, completeEvent ) {
+ var that = this
+ , complete = function () {
+ if (startEvent == 'show') that.reset()
+ that.$element.trigger(completeEvent)
+ }
+
+ this.$element
+ .trigger(startEvent)
+ [method]('in')
+
+ $.support.transition && this.$element.hasClass('collapse') ?
+ this.$element.one($.support.transition.end, complete) :
+ complete()
+ }
+
+ , toggle: function () {
+ this[this.$element.hasClass('in') ? 'hide' : 'show']()
+ }
+
+ }
+
+ /* COLLAPSIBLE PLUGIN DEFINITION
+ * ============================== */
+
+ $.fn.collapse = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('collapse')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('collapse', (data = new Collapse(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.collapse.defaults = {
+ toggle: true
+ }
+
+ $.fn.collapse.Constructor = Collapse
+
+
+ /* COLLAPSIBLE DATA-API
+ * ==================== */
+
+ $(function () {
+ $('body').on('click.collapse.data-api', '[data-toggle=collapse]', function ( e ) {
+ var $this = $(this), href
+ , target = $this.attr('data-target')
+ || e.preventDefault()
+ || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') //strip for ie7
+ , option = $(target).data('collapse') ? 'toggle' : $this.data()
+ $(target).collapse(option)
+ })
+ })
+
+}( window.jQuery )
+/* ============================================================
+ * bootstrap-dropdown.js v2.0.0
+ * http://twitter.github.com/bootstrap/javascript.html#dropdowns
+ * ============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ============================================================ */
+
+
+!function( $ ){
+
+ "use strict"
+
+ /* DROPDOWN CLASS DEFINITION
+ * ========================= */
+
+ var toggle = '[data-toggle="dropdown"]'
+ , Dropdown = function ( element ) {
+ var $el = $(element).on('click.dropdown.data-api', this.toggle)
+ $('html').on('click.dropdown.data-api', function () {
+ $el.parent().removeClass('open')
+ })
+ }
+
+ Dropdown.prototype = {
+
+ constructor: Dropdown
+
+ , toggle: function ( e ) {
+ var $this = $(this)
+ , selector = $this.attr('data-target')
+ , $parent
+ , isActive
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ $parent = $(selector)
+ $parent.length || ($parent = $this.parent())
+
+ isActive = $parent.hasClass('open')
+
+ clearMenus()
+ !isActive && $parent.toggleClass('open')
+
+ return false
+ }
+
+ }
+
+ function clearMenus() {
+ $(toggle).parent().removeClass('open')
+ }
+
+
+ /* DROPDOWN PLUGIN DEFINITION
+ * ========================== */
+
+ $.fn.dropdown = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('dropdown')
+ if (!data) $this.data('dropdown', (data = new Dropdown(this)))
+ if (typeof option == 'string') data[option].call($this)
+ })
+ }
+
+ $.fn.dropdown.Constructor = Dropdown
+
+
+ /* APPLY TO STANDARD DROPDOWN ELEMENTS
+ * =================================== */
+
+ $(function () {
+ $('html').on('click.dropdown.data-api', clearMenus)
+ $('body').on('click.dropdown.data-api', toggle, Dropdown.prototype.toggle)
+ })
+
+}( window.jQuery )
+/* =========================================================
+ * bootstrap-modal.js v2.0.0
+ * http://twitter.github.com/bootstrap/javascript.html#modals
+ * =========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ========================================================= */
+
+
+!function( $ ){
+
+ "use strict"
+
+ /* MODAL CLASS DEFINITION
+ * ====================== */
+
+ var Modal = function ( content, options ) {
+ this.options = $.extend({}, $.fn.modal.defaults, options)
+ this.$element = $(content)
+ .delegate('[data-dismiss="modal"]', 'click.dismiss.modal', $.proxy(this.hide, this))
+ }
+
+ Modal.prototype = {
+
+ constructor: Modal
+
+ , toggle: function () {
+ return this[!this.isShown ? 'show' : 'hide']()
+ }
+
+ , show: function () {
+ var that = this
+
+ if (this.isShown) return
+
+ $('body').addClass('modal-open')
+
+ this.isShown = true
+ this.$element.trigger('show')
+
+ escape.call(this)
+ backdrop.call(this, function () {
+ var transition = $.support.transition && that.$element.hasClass('fade')
+
+ !that.$element.parent().length && that.$element.appendTo(document.body) //don't move modals dom position
+
+ that.$element
+ .show()
+
+ if (transition) {
+ that.$element[0].offsetWidth // force reflow
+ }
+
+ that.$element.addClass('in')
+
+ transition ?
+ that.$element.one($.support.transition.end, function () { that.$element.trigger('shown') }) :
+ that.$element.trigger('shown')
+
+ })
+ }
+
+ , hide: function ( e ) {
+ e && e.preventDefault()
+
+ if (!this.isShown) return
+
+ var that = this
+ this.isShown = false
+
+ $('body').removeClass('modal-open')
+
+ escape.call(this)
+
+ this.$element
+ .trigger('hide')
+ .removeClass('in')
+
+ $.support.transition && this.$element.hasClass('fade') ?
+ hideWithTransition.call(this) :
+ hideModal.call(this)
+ }
+
+ }
+
+
+ /* MODAL PRIVATE METHODS
+ * ===================== */
+
+ function hideWithTransition() {
+ var that = this
+ , timeout = setTimeout(function () {
+ that.$element.off($.support.transition.end)
+ hideModal.call(that)
+ }, 500)
+
+ this.$element.one($.support.transition.end, function () {
+ clearTimeout(timeout)
+ hideModal.call(that)
+ })
+ }
+
+ function hideModal( that ) {
+ this.$element
+ .hide()
+ .trigger('hidden')
+
+ backdrop.call(this)
+ }
+
+ function backdrop( callback ) {
+ var that = this
+ , animate = this.$element.hasClass('fade') ? 'fade' : ''
+
+ if (this.isShown && this.options.backdrop) {
+ var doAnimate = $.support.transition && animate
+
+ this.$backdrop = $('<div class="modal-backdrop ' + animate + '" />')
+ .appendTo(document.body)
+
+ if (this.options.backdrop != 'static') {
+ this.$backdrop.click($.proxy(this.hide, this))
+ }
+
+ if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
+
+ this.$backdrop.addClass('in')
+
+ doAnimate ?
+ this.$backdrop.one($.support.transition.end, callback) :
+ callback()
+
+ } else if (!this.isShown && this.$backdrop) {
+ this.$backdrop.removeClass('in')
+
+ $.support.transition && this.$element.hasClass('fade')?
+ this.$backdrop.one($.support.transition.end, $.proxy(removeBackdrop, this)) :
+ removeBackdrop.call(this)
+
+ } else if (callback) {
+ callback()
+ }
+ }
+
+ function removeBackdrop() {
+ this.$backdrop.remove()
+ this.$backdrop = null
+ }
+
+ function escape() {
+ var that = this
+ if (this.isShown && this.options.keyboard) {
+ $(document).on('keyup.dismiss.modal', function ( e ) {
+ e.which == 27 && that.hide()
+ })
+ } else if (!this.isShown) {
+ $(document).off('keyup.dismiss.modal')
+ }
+ }
+
+
+ /* MODAL PLUGIN DEFINITION
+ * ======================= */
+
+ $.fn.modal = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('modal')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('modal', (data = new Modal(this, options)))
+ if (typeof option == 'string') data[option]()
+ else data.show()
+ })
+ }
+
+ $.fn.modal.defaults = {
+ backdrop: true
+ , keyboard: true
+ }
+
+ $.fn.modal.Constructor = Modal
+
+
+ /* MODAL DATA-API
+ * ============== */
+
+ $(function () {
+ $('body').on('click.modal.data-api', '[data-toggle="modal"]', function ( e ) {
+ var $this = $(this), href
+ , $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
+ , option = $target.data('modal') ? 'toggle' : $.extend({}, $target.data(), $this.data())
+
+ e.preventDefault()
+ $target.modal(option)
+ })
+ })
+
+}( window.jQuery )
+/* ===========================================================
+ * bootstrap-tooltip.js v2.0.0
+ * http://twitter.github.com/bootstrap/javascript.html#tooltips
+ * Inspired by the original jQuery.tipsy by Jason Frame
+ * ===========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ========================================================== */
+
+!function( $ ) {
+
+ "use strict"
+
+ /* TOOLTIP PUBLIC CLASS DEFINITION
+ * =============================== */
+
+ var Tooltip = function ( element, options ) {
+ this.init('tooltip', element, options)
+ }
+
+ Tooltip.prototype = {
+
+ constructor: Tooltip
+
+ , init: function ( type, element, options ) {
+ var eventIn
+ , eventOut
+
+ this.type = type
+ this.$element = $(element)
+ this.options = this.getOptions(options)
+ this.enabled = true
+
+ if (this.options.trigger != 'manual') {
+ eventIn = this.options.trigger == 'hover' ? 'mouseenter' : 'focus'
+ eventOut = this.options.trigger == 'hover' ? 'mouseleave' : 'blur'
+ this.$element.on(eventIn, this.options.selector, $.proxy(this.enter, this))
+ this.$element.on(eventOut, this.options.selector, $.proxy(this.leave, this))
+ }
+
+ this.options.selector ?
+ (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
+ this.fixTitle()
+ }
+
+ , getOptions: function ( options ) {
+ options = $.extend({}, $.fn[this.type].defaults, options, this.$element.data())
+
+ if (options.delay && typeof options.delay == 'number') {
+ options.delay = {
+ show: options.delay
+ , hide: options.delay
+ }
+ }
+
+ return options
+ }
+
+ , enter: function ( e ) {
+ var self = $(e.currentTarget)[this.type](this._options).data(this.type)
+
+ if (!self.options.delay || !self.options.delay.show) {
+ self.show()
+ } else {
+ self.hoverState = 'in'
+ setTimeout(function() {
+ if (self.hoverState == 'in') {
+ self.show()
+ }
+ }, self.options.delay.show)
+ }
+ }
+
+ , leave: function ( e ) {
+ var self = $(e.currentTarget)[this.type](this._options).data(this.type)
+
+ if (!self.options.delay || !self.options.delay.hide) {
+ self.hide()
+ } else {
+ self.hoverState = 'out'
+ setTimeout(function() {
+ if (self.hoverState == 'out') {
+ self.hide()
+ }
+ }, self.options.delay.hide)
+ }
+ }
+
+ , show: function () {
+ var $tip
+ , inside
+ , pos
+ , actualWidth
+ , actualHeight
+ , placement
+ , tp
+
+ if (this.hasContent() && this.enabled) {
+ $tip = this.tip()
+ this.setContent()
+
+ if (this.options.animation) {
+ $tip.addClass('fade')
+ }
+
+ placement = typeof this.options.placement == 'function' ?
+ this.options.placement.call(this, $tip[0], this.$element[0]) :
+ this.options.placement
+
+ inside = /in/.test(placement)
+
+ $tip
+ .remove()
+ .css({ top: 0, left: 0, display: 'block' })
+ .appendTo(inside ? this.$element : document.body)
+
+ pos = this.getPosition(inside)
+
+ actualWidth = $tip[0].offsetWidth
+ actualHeight = $tip[0].offsetHeight
+
+ switch (inside ? placement.split(' ')[1] : placement) {
+ case 'bottom':
+ tp = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2}
+ break
+ case 'top':
+ tp = {top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2}
+ break
+ case 'left':
+ tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth}
+ break
+ case 'right':
+ tp = {top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width}
+ break
+ }
+
+ $tip
+ .css(tp)
+ .addClass(placement)
+ .addClass('in')
+ }
+ }
+
+ , setContent: function () {
+ var $tip = this.tip()
+ $tip.find('.tooltip-inner').html(this.getTitle())
+ $tip.removeClass('fade in top bottom left right')
+ }
+
+ , hide: function () {
+ var that = this
+ , $tip = this.tip()
+
+ $tip.removeClass('in')
+
+ function removeWithAnimation() {
+ var timeout = setTimeout(function () {
+ $tip.off($.support.transition.end).remove()
+ }, 500)
+
+ $tip.one($.support.transition.end, function () {
+ clearTimeout(timeout)
+ $tip.remove()
+ })
+ }
+
+ $.support.transition && this.$tip.hasClass('fade') ?
+ removeWithAnimation() :
+ $tip.remove()
+ }
+
+ , fixTitle: function () {
+ var $e = this.$element
+ if ($e.attr('title') || typeof($e.attr('data-original-title')) != 'string') {
+ $e.attr('data-original-title', $e.attr('title') || '').removeAttr('title')
+ }
+ }
+
+ , hasContent: function () {
+ return this.getTitle()
+ }
+
+ , getPosition: function (inside) {
+ return $.extend({}, (inside ? {top: 0, left: 0} : this.$element.offset()), {
+ width: this.$element[0].offsetWidth
+ , height: this.$element[0].offsetHeight
+ })
+ }
+
+ , getTitle: function () {
+ var title
+ , $e = this.$element
+ , o = this.options
+
+ title = $e.attr('data-original-title')
+ || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
+
+ title = title.toString().replace(/(^\s*|\s*$)/, "")
+
+ return title
+ }
+
+ , tip: function () {
+ return this.$tip = this.$tip || $(this.options.template)
+ }
+
+ , validate: function () {
+ if (!this.$element[0].parentNode) {
+ this.hide()
+ this.$element = null
+ this.options = null
+ }
+ }
+
+ , enable: function () {
+ this.enabled = true
+ }
+
+ , disable: function () {
+ this.enabled = false
+ }
+
+ , toggleEnabled: function () {
+ this.enabled = !this.enabled
+ }
+
+ , toggle: function () {
+ this[this.tip().hasClass('in') ? 'hide' : 'show']()
+ }
+
+ }
+
+
+ /* TOOLTIP PLUGIN DEFINITION
+ * ========================= */
+
+ $.fn.tooltip = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('tooltip')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('tooltip', (data = new Tooltip(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.tooltip.Constructor = Tooltip
+
+ $.fn.tooltip.defaults = {
+ animation: true
+ , delay: 0
+ , selector: false
+ , placement: 'top'
+ , trigger: 'hover'
+ , title: ''
+ , template: '<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'
+ }
+
+}( window.jQuery )
+/* ===========================================================
+ * bootstrap-popover.js v2.0.0
+ * http://twitter.github.com/bootstrap/javascript.html#popovers
+ * ===========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * =========================================================== */
+
+
+!function( $ ) {
+
+ "use strict"
+
+ var Popover = function ( element, options ) {
+ this.init('popover', element, options)
+ }
+
+ /* NOTE: POPOVER EXTENDS BOOTSTRAP-TOOLTIP.js
+ ========================================== */
+
+ Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype, {
+
+ constructor: Popover
+
+ , setContent: function () {
+ var $tip = this.tip()
+ , title = this.getTitle()
+ , content = this.getContent()
+
+ $tip.find('.popover-title')[ $.type(title) == 'object' ? 'append' : 'html' ](title)
+ $tip.find('.popover-content > *')[ $.type(content) == 'object' ? 'append' : 'html' ](content)
+
+ $tip.removeClass('fade top bottom left right in')
+ }
+
+ , hasContent: function () {
+ return this.getTitle() || this.getContent()
+ }
+
+ , getContent: function () {
+ var content
+ , $e = this.$element
+ , o = this.options
+
+ content = $e.attr('data-content')
+ || (typeof o.content == 'function' ? o.content.call($e[0]) : o.content)
+
+ content = content.toString().replace(/(^\s*|\s*$)/, "")
+
+ return content
+ }
+
+ , tip: function() {
+ if (!this.$tip) {
+ this.$tip = $(this.options.template)
+ }
+ return this.$tip
+ }
+
+ })
+
+
+ /* POPOVER PLUGIN DEFINITION
+ * ======================= */
+
+ $.fn.popover = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('popover')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('popover', (data = new Popover(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.popover.Constructor = Popover
+
+ $.fn.popover.defaults = $.extend({} , $.fn.tooltip.defaults, {
+ placement: 'right'
+ , content: ''
+ , template: '<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'
+ })
+
+}( window.jQuery )
+/* =============================================================
+ * bootstrap-scrollspy.js v2.0.0
+ * http://twitter.github.com/bootstrap/javascript.html#scrollspy
+ * =============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ============================================================== */
+
+!function ( $ ) {
+
+ "use strict"
+
+ /* SCROLLSPY CLASS DEFINITION
+ * ========================== */
+
+ function ScrollSpy( element, options) {
+ var process = $.proxy(this.process, this)
+ , $element = $(element).is('body') ? $(window) : $(element)
+ , href
+ this.options = $.extend({}, $.fn.scrollspy.defaults, options)
+ this.$scrollElement = $element.on('scroll.scroll.data-api', process)
+ this.selector = (this.options.target
+ || ((href = $(element).attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '')) //strip for ie7
+ || '') + ' .nav li > a'
+ this.$body = $('body').on('click.scroll.data-api', this.selector, process)
+ this.refresh()
+ this.process()
+ }
+
+ ScrollSpy.prototype = {
+
+ constructor: ScrollSpy
+
+ , refresh: function () {
+ this.targets = this.$body
+ .find(this.selector)
+ .map(function () {
+ var href = $(this).attr('href')
+ return /^#\w/.test(href) && $(href).length ? href : null
+ })
+
+ this.offsets = $.map(this.targets, function (id) {
+ return $(id).position().top
+ })
+ }
+
+ , process: function () {
+ var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
+ , offsets = this.offsets
+ , targets = this.targets
+ , activeTarget = this.activeTarget
+ , i
+
+ for (i = offsets.length; i--;) {
+ activeTarget != targets[i]
+ && scrollTop >= offsets[i]
+ && (!offsets[i + 1] || scrollTop <= offsets[i + 1])
+ && this.activate( targets[i] )
+ }
+ }
+
+ , activate: function (target) {
+ var active
+
+ this.activeTarget = target
+
+ this.$body
+ .find(this.selector).parent('.active')
+ .removeClass('active')
+
+ active = this.$body
+ .find(this.selector + '[href="' + target + '"]')
+ .parent('li')
+ .addClass('active')
+
+ if ( active.parent('.dropdown-menu') ) {
+ active.closest('li.dropdown').addClass('active')
+ }
+ }
+
+ }
+
+
+ /* SCROLLSPY PLUGIN DEFINITION
+ * =========================== */
+
+ $.fn.scrollspy = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('scrollspy')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('scrollspy', (data = new ScrollSpy(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.scrollspy.Constructor = ScrollSpy
+
+ $.fn.scrollspy.defaults = {
+ offset: 10
+ }
+
+
+ /* SCROLLSPY DATA-API
+ * ================== */
+
+ $(function () {
+ $('[data-spy="scroll"]').each(function () {
+ var $spy = $(this)
+ $spy.scrollspy($spy.data())
+ })
+ })
+
+}( window.jQuery )
+/* ========================================================
+ * bootstrap-tab.js v2.0.0
+ * http://twitter.github.com/bootstrap/javascript.html#tabs
+ * ========================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ======================================================== */
+
+
+!function( $ ){
+
+ "use strict"
+
+ /* TAB CLASS DEFINITION
+ * ==================== */
+
+ var Tab = function ( element ) {
+ this.element = $(element)
+ }
+
+ Tab.prototype = {
+
+ constructor: Tab
+
+ , show: function () {
+ var $this = this.element
+ , $ul = $this.closest('ul:not(.dropdown-menu)')
+ , selector = $this.attr('data-target')
+ , previous
+ , $target
+
+ if (!selector) {
+ selector = $this.attr('href')
+ selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') //strip for ie7
+ }
+
+ if ( $this.parent('li').hasClass('active') ) return
+
+ previous = $ul.find('.active a').last()[0]
+
+ $this.trigger({
+ type: 'show'
+ , relatedTarget: previous
+ })
+
+ $target = $(selector)
+
+ this.activate($this.parent('li'), $ul)
+ this.activate($target, $target.parent(), function () {
+ $this.trigger({
+ type: 'shown'
+ , relatedTarget: previous
+ })
+ })
+ }
+
+ , activate: function ( element, container, callback) {
+ var $active = container.find('> .active')
+ , transition = callback
+ && $.support.transition
+ && $active.hasClass('fade')
+
+ function next() {
+ $active
+ .removeClass('active')
+ .find('> .dropdown-menu > .active')
+ .removeClass('active')
+
+ element.addClass('active')
+
+ if (transition) {
+ element[0].offsetWidth // reflow for transition
+ element.addClass('in')
+ } else {
+ element.removeClass('fade')
+ }
+
+ if ( element.parent('.dropdown-menu') ) {
+ element.closest('li.dropdown').addClass('active')
+ }
+
+ callback && callback()
+ }
+
+ transition ?
+ $active.one($.support.transition.end, next) :
+ next()
+
+ $active.removeClass('in')
+ }
+ }
+
+
+ /* TAB PLUGIN DEFINITION
+ * ===================== */
+
+ $.fn.tab = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('tab')
+ if (!data) $this.data('tab', (data = new Tab(this)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.tab.Constructor = Tab
+
+
+ /* TAB DATA-API
+ * ============ */
+
+ $(function () {
+ $('body').on('click.tab.data-api', '[data-toggle="tab"], [data-toggle="pill"]', function (e) {
+ e.preventDefault()
+ $(this).tab('show')
+ })
+ })
+
+}( window.jQuery )
+/* =============================================================
+ * bootstrap-typeahead.js v2.0.0
+ * http://twitter.github.com/bootstrap/javascript.html#typeahead
+ * =============================================================
+ * Copyright 2012 Twitter, Inc.
+ *
+ * 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.
+ * ============================================================ */
+
+!function( $ ){
+
+ "use strict"
+
+ var Typeahead = function ( element, options ) {
+ this.$element = $(element)
+ this.options = $.extend({}, $.fn.typeahead.defaults, options)
+ this.matcher = this.options.matcher || this.matcher
+ this.sorter = this.options.sorter || this.sorter
+ this.highlighter = this.options.highlighter || this.highlighter
+ this.$menu = $(this.options.menu).appendTo('body')
+ this.source = this.options.source
+ this.shown = false
+ this.listen()
+ }
+
+ Typeahead.prototype = {
+
+ constructor: Typeahead
+
+ , select: function () {
+ var val = this.$menu.find('.active').attr('data-value')
+ this.$element.val(val)
+ return this.hide()
+ }
+
+ , show: function () {
+ var pos = $.extend({}, this.$element.offset(), {
+ height: this.$element[0].offsetHeight
+ })
+
+ this.$menu.css({
+ top: pos.top + pos.height
+ , left: pos.left
+ })
+
+ this.$menu.show()
+ this.shown = true
+ return this
+ }
+
+ , hide: function () {
+ this.$menu.hide()
+ this.shown = false
+ return this
+ }
+
+ , lookup: function (event) {
+ var that = this
+ , items
+ , q
+
+ this.query = this.$element.val()
+
+ if (!this.query) {
+ return this.shown ? this.hide() : this
+ }
+
+ items = $.grep(this.source, function (item) {
+ if (that.matcher(item)) return item
+ })
+
+ items = this.sorter(items)
+
+ if (!items.length) {
+ return this.shown ? this.hide() : this
+ }
+
+ return this.render(items.slice(0, this.options.items)).show()
+ }
+
+ , matcher: function (item) {
+ return ~item.toLowerCase().indexOf(this.query.toLowerCase())
+ }
+
+ , sorter: function (items) {
+ var beginswith = []
+ , caseSensitive = []
+ , caseInsensitive = []
+ , item
+
+ while (item = items.shift()) {
+ if (!item.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item)
+ else if (~item.indexOf(this.query)) caseSensitive.push(item)
+ else caseInsensitive.push(item)
+ }
+
+ return beginswith.concat(caseSensitive, caseInsensitive)
+ }
+
+ , highlighter: function (item) {
+ return item.replace(new RegExp('(' + this.query + ')', 'ig'), function ($1, match) {
+ return '<strong>' + match + '</strong>'
+ })
+ }
+
+ , render: function (items) {
+ var that = this
+
+ items = $(items).map(function (i, item) {
+ i = $(that.options.item).attr('data-value', item)
+ i.find('a').html(that.highlighter(item))
+ return i[0]
+ })
+
+ items.first().addClass('active')
+ this.$menu.html(items)
+ return this
+ }
+
+ , next: function (event) {
+ var active = this.$menu.find('.active').removeClass('active')
+ , next = active.next()
+
+ if (!next.length) {
+ next = $(this.$menu.find('li')[0])
+ }
+
+ next.addClass('active')
+ }
+
+ , prev: function (event) {
+ var active = this.$menu.find('.active').removeClass('active')
+ , prev = active.prev()
+
+ if (!prev.length) {
+ prev = this.$menu.find('li').last()
+ }
+
+ prev.addClass('active')
+ }
+
+ , listen: function () {
+ this.$element
+ .on('blur', $.proxy(this.blur, this))
+ .on('keypress', $.proxy(this.keypress, this))
+ .on('keyup', $.proxy(this.keyup, this))
+
+ if ($.browser.webkit || $.browser.msie) {
+ this.$element.on('keydown', $.proxy(this.keypress, this))
+ }
+
+ this.$menu
+ .on('click', $.proxy(this.click, this))
+ .on('mouseenter', 'li', $.proxy(this.mouseenter, this))
+ }
+
+ , keyup: function (e) {
+ e.stopPropagation()
+ e.preventDefault()
+
+ switch(e.keyCode) {
+ case 40: // down arrow
+ case 38: // up arrow
+ break
+
+ case 9: // tab
+ case 13: // enter
+ if (!this.shown) return
+ this.select()
+ break
+
+ case 27: // escape
+ this.hide()
+ break
+
+ default:
+ this.lookup()
+ }
+
+ }
+
+ , keypress: function (e) {
+ e.stopPropagation()
+ if (!this.shown) return
+
+ switch(e.keyCode) {
+ case 9: // tab
+ case 13: // enter
+ case 27: // escape
+ e.preventDefault()
+ break
+
+ case 38: // up arrow
+ e.preventDefault()
+ this.prev()
+ break
+
+ case 40: // down arrow
+ e.preventDefault()
+ this.next()
+ break
+ }
+ }
+
+ , blur: function (e) {
+ var that = this
+ e.stopPropagation()
+ e.preventDefault()
+ setTimeout(function () { that.hide() }, 150)
+ }
+
+ , click: function (e) {
+ e.stopPropagation()
+ e.preventDefault()
+ this.select()
+ }
+
+ , mouseenter: function (e) {
+ this.$menu.find('.active').removeClass('active')
+ $(e.currentTarget).addClass('active')
+ }
+
+ }
+
+
+ /* TYPEAHEAD PLUGIN DEFINITION
+ * =========================== */
+
+ $.fn.typeahead = function ( option ) {
+ return this.each(function () {
+ var $this = $(this)
+ , data = $this.data('typeahead')
+ , options = typeof option == 'object' && option
+ if (!data) $this.data('typeahead', (data = new Typeahead(this, options)))
+ if (typeof option == 'string') data[option]()
+ })
+ }
+
+ $.fn.typeahead.defaults = {
+ source: []
+ , items: 8
+ , menu: '<ul class="typeahead dropdown-menu"></ul>'
+ , item: '<li><a href="#"></a></li>'
+ }
+
+ $.fn.typeahead.Constructor = Typeahead
+
+
+ /* TYPEAHEAD DATA-API
+ * ================== */
+
+ $(function () {
+ $('body').on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
+ var $this = $(this)
+ if ($this.data('typeahead')) return
+ e.preventDefault()
+ $this.typeahead($this.data())
+ })
+ })
+
+}( window.jQuery )
diff --git a/docs/source/assets/js/bootstrap.min.js b/docs/source/assets/js/bootstrap.min.js
new file mode 100644
index 0000000..1f295a1
--- /dev/null
+++ b/docs/source/assets/js/bootstrap.min.js
@@ -0,0 +1 @@
+!function(a){a(function(){"use strict",a.support.transition=function(){var b=document.body||document.documentElement,c=b.style,d=c.transition!==undefined||c.WebkitTransition!==undefined||c.MozTransition!==undefined||c.MsTransition!==undefined||c.OTransition!==undefined;return d&&{end:function(){var b="TransitionEnd";return a.browser.webkit?b="webkitTransitionEnd":a.browser.mozilla?b="transitionend":a.browser.opera&&(b="oTransitionEnd"),b}()}}()})}(window.jQuery),!function(a){"use strict";var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype={constructor:c,close:function(b){function f(){e.remove(),e.trigger("closed")}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),e.trigger("close"),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()}},a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a(function(){a("body").on("click.alert.data-api",b,c.prototype.close)})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.button.defaults,c)};b.prototype={constructor:b,setState:function(a){var b="disabled",c=this.$element,d=c.data(),e=c.is("input")?"val":"html";a+="Text",d.resetText||c.data("resetText",c[e]()),c[e](d[a]||this.options[a]),setTimeout(function(){a=="loadingText"?c.addClass(b).attr(b,b):c.removeClass(b).removeAttr(b)},0)},toggle:function(){var a=this.$element.parent('[data-toggle="buttons-radio"]');a&&a.find(".active").removeClass("active"),this.$element.toggleClass("active")}},a.fn.button=function(c){return this.each(function(){var d=a(this),e=d.data("button"),f=typeof c=="object"&&c;e||d.data("button",e=new b(this,f)),c=="toggle"?e.toggle():c&&e.setState(c)})},a.fn.button.defaults={loadingText:"loading..."},a.fn.button.Constructor=b,a(function(){a("body").on("click.button.data-api","[data-toggle^=button]",function(b){a(b.target).button("toggle")})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.carousel.defaults,c),this.options.slide&&this.slide(this.options.slide)};b.prototype={cycle:function(){return this.interval=setInterval(a.proxy(this.next,this),this.options.interval),this},to:function(b){var c=this.$element.find(".active"),d=c.parent().children(),e=d.index(c),f=this;if(b>d.length-1||b<0)return;return this.sliding?this.$element.one("slid",function(){f.to(b)}):e==b?this.pause().cycle():this.slide(b>e?"next":"prev",a(d[b]))},pause:function(){return clearInterval(this.interval),this},next:function(){if(this.sliding)return;return this.slide("next")},prev:function(){if(this.sliding)return;return this.slide("prev")},slide:function(b,c){var d=this.$element.find(".active"),e=c||d[b](),f=this.interval,g=b=="next"?"left":"right",h=b=="next"?"first":"last",i=this;return this.sliding=!0,f&&this.pause(),e=e.length?e:this.$element.find(".item")[h](),!a.support.transition&&this.$element.hasClass("slide")?(this.$element.trigger("slide"),d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger("slid")):(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),this.$element.trigger("slide"),this.$element.one(a.support.transition.end,function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger("slid")},0)})),f&&this.cycle(),this}},a.fn.carousel=function(c){return this.each(function(){var d=a(this),e=d.data("carousel"),f=typeof c=="object"&&c;e||d.data("carousel",e=new b(this,f)),typeof c=="number"?e.to(c):typeof c=="string"||(c=f.slide)?e[c]():e.cycle()})},a.fn.carousel.defaults={interval:5e3},a.fn.carousel.Constructor=b,a(function(){a("body").on("click.carousel.data-api","[data-slide]",function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=!e.data("modal")&&a.extend({},e.data(),c.data());e.carousel(f),b.preventDefault()})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.collapse.defaults,c),this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};b.prototype={constructor:b,dimension:function(){var a=this.$element.hasClass("width");return a?"width":"height"},show:function(){var b=this.dimension(),c=a.camelCase(["scroll",b].join("-")),d=this.$parent&&this.$parent.find(".in"),e;d&&d.length&&(e=d.data("collapse"),d.collapse("hide"),e||d.data("collapse",null)),this.$element[b](0),this.transition("addClass","show","shown"),this.$element[b](this.$element[0][c])},hide:function(){var a=this.dimension();this.reset(this.$element[a]()),this.transition("removeClass","hide","hidden"),this.$element[a](0)},reset:function(a){var b=this.dimension();this.$element.removeClass("collapse")[b](a||"auto")[0].offsetWidth,this.$element.addClass("collapse")},transition:function(b,c,d){var e=this,f=function(){c=="show"&&e.reset(),e.$element.trigger(d)};this.$element.trigger(c)[b]("in"),a.support.transition&&this.$element.hasClass("collapse")?this.$element.one(a.support.transition.end,f):f()},toggle:function(){this[this.$element.hasClass("in")?"hide":"show"]()}},a.fn.collapse=function(c){return this.each(function(){var d=a(this),e=d.data("collapse"),f=typeof c=="object"&&c;e||d.data("collapse",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.collapse.defaults={toggle:!0},a.fn.collapse.Constructor=b,a(function(){a("body").on("click.collapse.data-api","[data-toggle=collapse]",function(b){var c=a(this),d,e=c.attr("data-target")||b.preventDefault()||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),f=a(e).data("collapse")?"toggle":c.data();a(e).collapse(f)})})}(window.jQuery),!function(a){function d(){a(b).parent().removeClass("open")}"use strict";var b='[data-toggle="dropdown"]',c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),e=c.attr("data-target"),f,g;return e||(e=c.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,"")),f=a(e),f.length||(f=c.parent()),g=f.hasClass("open"),d(),!g&&f.toggleClass("open"),!1}},a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a(function(){a("html").on("click.dropdown.data-api",d),a("body").on("click.dropdown.data-api",b,c.prototype.toggle)})}(window.jQuery),!function(a){function c(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),d.call(b)},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),d.call(b)})}function d(a){this.$element.hide().trigger("hidden"),e.call(this)}function e(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('<div class="modal-backdrop '+d+'" />').appendTo(document.body),this.options.backdrop!="static"&&this.$backdrop.click(a.proxy(this.hide,this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),e?this.$backdrop.one(a.support.transition.end,b):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,a.proxy(f,this)):f.call(this)):b&&b()}function f(){this.$backdrop.remove(),this.$backdrop=null}function g(){var b=this;this.isShown&&this.options.keyboard?a(document).on("keyup.dismiss.modal",function(a){a.which==27&&b.hide()}):this.isShown||a(document).off("keyup.dismiss.modal")}"use strict";var b=function(b,c){this.options=a.extend({},a.fn.modal.defaults,c),this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this))};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this;if(this.isShown)return;a("body").addClass("modal-open"),this.isShown=!0,this.$element.trigger("show"),g.call(this),e.call(this,function(){var c=a.support.transition&&b.$element.hasClass("fade");!b.$element.parent().length&&b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in"),c?b.$element.one(a.support.transition.end,function(){b.$element.trigger("shown")}):b.$element.trigger("shown")})},hide:function(b){b&&b.preventDefault();if(!this.isShown)return;var e=this;this.isShown=!1,a("body").removeClass("modal-open"),g.call(this),this.$element.trigger("hide").removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?c.call(this):d.call(this)}},a.fn.modal=function(c){return this.each(function(){var d=a(this),e=d.data("modal"),f=typeof c=="object"&&c;e||d.data("modal",e=new b(this,f)),typeof c=="string"?e[c]():e.show()})},a.fn.modal.defaults={backdrop:!0,keyboard:!0},a.fn.modal.Constructor=b,a(function(){a("body").on("click.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d,e=a(c.attr("data-target")||(d=c.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({},e.data(),c.data());b.preventDefault(),e.modal(f)})})}(window.jQuery),!function(a){"use strict";var b=function(a,b){this.init("tooltip",a,b)};b.prototype={constructor:b,init:function(b,c,d){var e,f;this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.enabled=!0,this.options.trigger!="manual"&&(e=this.options.trigger=="hover"?"mouseenter":"focus",f=this.options.trigger=="hover"?"mouseleave":"blur",this.$element.on(e,this.options.selector,a.proxy(this.enter,this)),this.$element.on(f,this.options.selector,a.proxy(this.leave,this))),this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},getOptions:function(b){return b=a.extend({},a.fn[this.type].defaults,b,this.$element.data()),b.delay&&typeof b.delay=="number"&&(b.delay={show:b.delay,hide:b.delay}),b},enter:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);!c.options.delay||!c.options.delay.show?c.show():(c.hoverState="in",setTimeout(function(){c.hoverState=="in"&&c.show()},c.options.delay.show))},leave:function(b){var c=a(b.currentTarget)[this.type](this._options).data(this.type);!c.options.delay||!c.options.delay.hide?c.hide():(c.hoverState="out",setTimeout(function(){c.hoverState=="out"&&c.hide()},c.options.delay.hide))},show:function(){var a,b,c,d,e,f,g;if(this.hasContent()&&this.enabled){a=this.tip(),this.setContent(),this.options.animation&&a.addClass("fade"),f=typeof this.options.placement=="function"?this.options.placement.call(this,a[0],this.$element[0]):this.options.placement,b=/in/.test(f),a.remove().css({top:0,left:0,display:"block"}).appendTo(b?this.$element:document.body),c=this.getPosition(b),d=a[0].offsetWidth,e=a[0].offsetHeight;switch(b?f.split(" ")[1]:f){case"bottom":g={top:c.top+c.height,left:c.left+c.width/2-d/2};break;case"top":g={top:c.top-e,left:c.left+c.width/2-d/2};break;case"left":g={top:c.top+c.height/2-e/2,left:c.left-d};break;case"right":g={top:c.top+c.height/2-e/2,left:c.left+c.width}}a.css(g).addClass(f).addClass("in")}},setContent:function(){var a=this.tip();a.find(".tooltip-inner").html(this.getTitle()),a.removeClass("fade in top bottom left right")},hide:function(){function d(){var b=setTimeout(function(){c.off(a.support.transition.end).remove()},500);c.one(a.support.transition.end,function(){clearTimeout(b),c.remove()})}var b=this,c=this.tip();c.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d():c.remove()},fixTitle:function(){var a=this.$element;(a.attr("title")||typeof a.attr("data-original-title")!="string")&&a.attr("data-original-title",a.attr("title")||"").removeAttr("title")},hasContent:function(){return this.getTitle()},getPosition:function(b){return a.extend({},b?{top:0,left:0}:this.$element.offset(),{width:this.$element[0].offsetWidth,height:this.$element[0].offsetHeight})},getTitle:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||(typeof c.title=="function"?c.title.call(b[0]):c.title),a=a.toString().replace(/(^\s*|\s*$)/,""),a},tip:function(){return this.$tip=this.$tip||a(this.options.template)},validate:function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},enable:function(){this.enabled=!0},disable:function(){this.enabled=!1},toggleEnabled:function(){this.enabled=!this.enabled},toggle:function(){this[this.tip().hasClass("in")?"hide":"show"]()}},a.fn.tooltip=function(c){return this.each(function(){var d=a(this),e=d.data("tooltip"),f=typeof c=="object"&&c;e||d.data("tooltip",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.tooltip.Constructor=b,a.fn.tooltip.defaults={animation:!0,delay:0,selector:!1,placement:"top",trigger:"hover",title:"",template:'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'}}(window.jQuery),!function(a){"use strict";var b=function(a,b){this.init("popover",a,b)};b.prototype=a.extend({},a.fn.tooltip.Constructor.prototype,{constructor:b,setContent:function(){var b=this.tip(),c=this.getTitle(),d=this.getContent();b.find(".popover-title")[a.type(c)=="object"?"append":"html"](c),b.find(".popover-content > *")[a.type(d)=="object"?"append":"html"](d),b.removeClass("fade top bottom left right in")},hasContent:function(){return this.getTitle()||this.getContent()},getContent:function(){var a,b=this.$element,c=this.options;return a=b.attr("data-content")||(typeof c.content=="function"?c.content.call(b[0]):c.content),a=a.toString().replace(/(^\s*|\s*$)/,""),a},tip:function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip}}),a.fn.popover=function(c){return this.each(function(){var d=a(this),e=d.data("popover"),f=typeof c=="object"&&c;e||d.data("popover",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.popover.Constructor=b,a.fn.popover.defaults=a.extend({},a.fn.tooltip.defaults,{placement:"right",content:"",template:'<div class="popover"><div class="arrow"></div><div class="popover-inner"><h3 class="popover-title"></h3><div class="popover-content"><p></p></div></div></div>'})}(window.jQuery),!function(a){function b(b,c){var d=a.proxy(this.process,this),e=a(b).is("body")?a(window):a(b),f;this.options=a.extend({},a.fn.scrollspy.defaults,c),this.$scrollElement=e.on("scroll.scroll.data-api",d),this.selector=(this.options.target||(f=a(b).attr("href"))&&f.replace(/.*(?=#[^\s]+$)/,"")||"")+" .nav li > a",this.$body=a("body").on("click.scroll.data-api",this.selector,d),this.refresh(),this.process()}"use strict",b.prototype={constructor:b,refresh:function(){this.targets=this.$body.find(this.selector).map(function(){var b=a(this).attr("href");return/^#\w/.test(b)&&a(b).length?b:null}),this.offsets=a.map(this.targets,function(b){return a(b).position().top})},process:function(){var a=this.$scrollElement.scrollTop()+this.options.offset,b=this.offsets,c=this.targets,d=this.activeTarget,e;for(e=b.length;e--;)d!=c[e]&&a>=b[e]&&(!b[e+1]||a<=b[e+1])&&this.activate(c[e])},activate:function(a){var b;this.activeTarget=a,this.$body.find(this.selector).parent(".active").removeClass("active"),b=this.$body.find(this.selector+'[href="'+a+'"]').parent("li").addClass("active"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active")}},a.fn.scrollspy=function(c){return this.each(function(){var d=a(this),e=d.data("scrollspy"),f=typeof c=="object"&&c;e||d.data("scrollspy",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.scrollspy.Constructor=b,a.fn.scrollspy.defaults={offset:10},a(function(){a('[data-spy="scroll"]').each(function(){var b=a(this);b.scrollspy(b.data())})})}(window.jQuery),!function(a){"use strict";var b=function(b){this.element=a(b)};b.prototype={constructor:b,show:function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.attr("data-target"),e,f;d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,""));if(b.parent("li").hasClass("active"))return;e=c.find(".active a").last()[0],b.trigger({type:"show",relatedTarget:e}),f=a(d),this.activate(b.parent("li"),c),this.activate(f,f.parent(),function(){b.trigger({type:"shown",relatedTarget:e})})},activate:function(b,c,d){function g(){e.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),f?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var e=c.find("> .active"),f=d&&a.support.transition&&e.hasClass("fade");f?e.one(a.support.transition.end,g):g(),e.removeClass("in")}},a.fn.tab=function(c){return this.each(function(){var d=a(this),e=d.data("tab");e||d.data("tab",e=new b(this)),typeof c=="string"&&e[c]()})},a.fn.tab.Constructor=b,a(function(){a("body").on("click.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(b){b.preventDefault(),a(this).tab("show")})})}(window.jQuery),!function(a){"use strict";var b=function(b,c){this.$element=a(b),this.options=a.extend({},a.fn.typeahead.defaults,c),this.matcher=this.options.matcher||this.matcher,this.sorter=this.options.sorter||this.sorter,this.highlighter=this.options.highlighter||this.highlighter,this.$menu=a(this.options.menu).appendTo("body"),this.source=this.options.source,this.shown=!1,this.listen()};b.prototype={constructor:b,select:function(){var a=this.$menu.find(".active").attr("data-value");return this.$element.val(a),this.hide()},show:function(){var b=a.extend({},this.$element.offset(),{height:this.$element[0].offsetHeight});return this.$menu.css({top:b.top+b.height,left:b.left}),this.$menu.show(),this.shown=!0,this},hide:function(){return this.$menu.hide(),this.shown=!1,this},lookup:function(b){var c=this,d,e;return this.query=this.$element.val(),this.query?(d=a.grep(this.source,function(a){if(c.matcher(a))return a}),d=this.sorter(d),d.length?this.render(d.slice(0,this.options.items)).show():this.shown?this.hide():this):this.shown?this.hide():this},matcher:function(a){return~a.toLowerCase().indexOf(this.query.toLowerCase())},sorter:function(a){var b=[],c=[],d=[],e;while(e=a.shift())e.toLowerCase().indexOf(this.query.toLowerCase())?~e.indexOf(this.query)?c.push(e):d.push(e):b.push(e);return b.concat(c,d)},highlighter:function(a){return a.replace(new RegExp("("+this.query+")","ig"),function(a,b){return"<strong>"+b+"</strong>"})},render:function(b){var c=this;return b=a(b).map(function(b,d){return b=a(c.options.item).attr("data-value",d),b.find("a").html(c.highlighter(d)),b[0]}),b.first().addClass("active"),this.$menu.html(b),this},next:function(b){var c=this.$menu.find(".active").removeClass("active"),d=c.next();d.length||(d=a(this.$menu.find("li")[0])),d.addClass("active")},prev:function(a){var b=this.$menu.find(".active").removeClass("active"),c=b.prev();c.length||(c=this.$menu.find("li").last()),c.addClass("active")},listen:function(){this.$element.on("blur",a.proxy(this.blur,this)).on("keypress",a.proxy(this.keypress,this)).on("keyup",a.proxy(this.keyup,this)),(a.browser.webkit||a.browser.msie)&&this.$element.on("keydown",a.proxy(this.keypress,this)),this.$menu.on("click",a.proxy(this.click,this)).on("mouseenter","li",a.proxy(this.mouseenter,this))},keyup:function(a){a.stopPropagation(),a.preventDefault();switch(a.keyCode){case 40:case 38:break;case 9:case 13:if(!this.shown)return;this.select();break;case 27:this.hide();break;default:this.lookup()}},keypress:function(a){a.stopPropagation();if(!this.shown)return;switch(a.keyCode){case 9:case 13:case 27:a.preventDefault();break;case 38:a.preventDefault(),this.prev();break;case 40:a.preventDefault(),this.next()}},blur:function(a){var b=this;a.stopPropagation(),a.preventDefault(),setTimeout(function(){b.hide()},150)},click:function(a){a.stopPropagation(),a.preventDefault(),this.select()},mouseenter:function(b){this.$menu.find(".active").removeClass("active"),a(b.currentTarget).addClass("active")}},a.fn.typeahead=function(c){return this.each(function(){var d=a(this),e=d.data("typeahead"),f=typeof c=="object"&&c;e||d.data("typeahead",e=new b(this,f)),typeof c=="string"&&e[c]()})},a.fn.typeahead.defaults={source:[],items:8,menu:'<ul class="typeahead dropdown-menu"></ul>',item:'<li><a href="#"></a></li>'},a.fn.typeahead.Constructor=b,a(function(){a("body").on("focus.typeahead.data-api",'[data-provide="typeahead"]',function(b){var c=a(this);if(c.data("typeahead"))return;b.preventDefault(),c.typeahead(c.data())})})}(window.jQuery);
\ No newline at end of file
diff --git a/docs/source/assets/js/jquery-1.7.1.min.js b/docs/source/assets/js/jquery-1.7.1.min.js
new file mode 100644
index 0000000..ee02337
--- /dev/null
+++ b/docs/source/assets/js/jquery-1.7.1.min.js
@@ -0,0 +1,4 @@
+/*! jQuery v1.7.1 jquery.com | jquery.org/license */
+(function(a,b){function cy(a){return f.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:!1}function cv(a){if(!ck[a]){var b=c.body,d=f("<"+a+">").appendTo(b),e=d.css("display");d.remove();if(e==="none"||e===""){cl||(cl=c.createElement("iframe"),cl.frameBorder=cl.width=cl.height=0),b.appendChild(cl);if(!cm||!cl.createElement)cm=(cl.contentWindow||cl.contentDocument).document,cm.write((c.compatMode==="CSS1Compat"?"<!doctype html>":"")+"<html><body>"),cm.close();d=cm.createElement(a),cm.body.appendChild(d),e=f.css(d,"display"),b.removeChild(cl)}ck[a]=e}return ck[a]}function cu(a,b){var c={};f.each(cq.concat.apply([],cq.slice(0,b)),function(){c[this]=a});return c}function ct(){cr=b}function cs(){setTimeout(ct,0);return cr=f.now()}function cj(){try{return new a.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}}function ci(){try{return new a.XMLHttpRequest}catch(b){}}function cc(a,c){a.dataFilter&&(c=a.dataFilter(c,a.dataType));var d=a.dataTypes,e={},g,h,i=d.length,j,k=d[0],l,m,n,o,p;for(g=1;g<i;g++){if(g===1)for(h in a.converters)typeof h=="string"&&(e[h.toLowerCase()]=a.converters[h]);l=k,k=d[g];if(k==="*")k=l;else if(l!=="*"&&l!==k){m=l+" "+k,n=e[m]||e["* "+k];if(!n){p=b;for(o in e){j=o.split(" ");if(j[0]===l||j[0]==="*"){p=e[j[1]+" "+k];if(p){o=e[o],o===!0?n=p:p===!0&&(n=o);break}}}}!n&&!p&&f.error("No conversion from "+m.replace(" "," to ")),n!==!0&&(c=n?n(c):p(o(c)))}}return c}function cb(a,c,d){var e=a.contents,f=a.dataTypes,g=a.responseFields,h,i,j,k;for(i in g)i in d&&(c[g[i]]=d[i]);while(f[0]==="*")f.shift(),h===b&&(h=a.mimeType||c.getResponseHeader("content-type"));if(h)for(i in e)if(e[i]&&e[i].test(h)){f.unshift(i);break}if(f[0]in d)j=f[0];else{for(i in d){if(!f[0]||a.converters[i+" "+f[0]]){j=i;break}k||(k=i)}j=j||k}if(j){j!==f[0]&&f.unshift(j);return d[j]}}function ca(a,b,c,d){if(f.isArray(b))f.each(b,function(b,e){c||bE.test(a)?d(a,e):ca(a+"["+(typeof e=="object"||f.isArray(e)?b:"")+"]",e,c,d)});else if(!c&&b!=null&&typeof b=="object")for(var e in b)ca(a+"["+e+"]",b[e],c,d);else d(a,b)}function b_(a,c){var d,e,g=f.ajaxSettings.flatOptions||{};for(d in c)c[d]!==b&&((g[d]?a:e||(e={}))[d]=c[d]);e&&f.extend(!0,a,e)}function b$(a,c,d,e,f,g){f=f||c.dataTypes[0],g=g||{},g[f]=!0;var h=a[f],i=0,j=h?h.length:0,k=a===bT,l;for(;i<j&&(k||!l);i++)l=h[i](c,d,e),typeof l=="string"&&(!k||g[l]?l=b:(c.dataTypes.unshift(l),l=b$(a,c,d,e,l,g)));(k||!l)&&!g["*"]&&(l=b$(a,c,d,e,"*",g));return l}function bZ(a){return function(b,c){typeof b!="string"&&(c=b,b="*");if(f.isFunction(c)){var d=b.toLowerCase().split(bP),e=0,g=d.length,h,i,j;for(;e<g;e++)h=d[e],j=/^\+/.test(h),j&&(h=h.substr(1)||"*"),i=a[h]=a[h]||[],i[j?"unshift":"push"](c)}}}function bC(a,b,c){var d=b==="width"?a.offsetWidth:a.offsetHeight,e=b==="width"?bx:by,g=0,h=e.length;if(d>0){if(c!=="border")for(;g<h;g++)c||(d-=parseFloat(f.css(a,"padding"+e[g]))||0),c==="margin"?d+=parseFloat(f.css(a,c+e[g]))||0:d-=parseFloat(f.css(a,"border"+e[g]+"Width"))||0;return d+"px"}d=bz(a,b,b);if(d<0||d==null)d=a.style[b]||0;d=parseFloat(d)||0;if(c)for(;g<h;g++)d+=parseFloat(f.css(a,"padding"+e[g]))||0,c!=="padding"&&(d+=parseFloat(f.css(a,"border"+e[g]+"Width"))||0),c==="margin"&&(d+=parseFloat(f.css(a,c+e[g]))||0);return d+"px"}function bp(a,b){b.src?f.ajax({url:b.src,async:!1,dataType:"script"}):f.globalEval((b.text||b.textContent||b.innerHTML||"").replace(bf,"/*$0*/")),b.parentNode&&b.parentNode.removeChild(b)}function bo(a){var b=c.createElement("div");bh.appendChild(b),b.innerHTML=a.outerHTML;return b.firstChild}function bn(a){var b=(a.nodeName||"").toLowerCase();b==="input"?bm(a):b!=="script"&&typeof a.getElementsByTagName!="undefined"&&f.grep(a.getElementsByTagName("input"),bm)}function bm(a){if(a.type==="checkbox"||a.type==="radio")a.defaultChecked=a.checked}function bl(a){return typeof a.getElementsByTagName!="undefined"?a.getElementsByTagName("*"):typeof a.querySelectorAll!="undefined"?a.querySelectorAll("*"):[]}function bk(a,b){var c;if(b.nodeType===1){b.clearAttributes&&b.clearAttributes(),b.mergeAttributes&&b.mergeAttributes(a),c=b.nodeName.toLowerCase();if(c==="object")b.outerHTML=a.outerHTML;else if(c!=="input"||a.type!=="checkbox"&&a.type!=="radio"){if(c==="option")b.selected=a.defaultSelected;else if(c==="input"||c==="textarea")b.defaultValue=a.defaultValue}else a.checked&&(b.defaultChecked=b.checked=a.checked),b.value!==a.value&&(b.value=a.value);b.removeAttribute(f.expando)}}function bj(a,b){if(b.nodeType===1&&!!f.hasData(a)){var c,d,e,g=f._data(a),h=f._data(b,g),i=g.events;if(i){delete h.handle,h.events={};for(c in i)for(d=0,e=i[c].length;d<e;d++)f.event.add(b,c+(i[c][d].namespace?".":"")+i[c][d].namespace,i[c][d],i[c][d].data)}h.data&&(h.data=f.extend({},h.data))}}function bi(a,b){return f.nodeName(a,"table")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function U(a){var b=V.split("|"),c=a.createDocumentFragment();if(c.createElement)while(b.length)c.createElement(b.pop());return c}function T(a,b,c){b=b||0;if(f.isFunction(b))return f.grep(a,function(a,d){var e=!!b.call(a,d,a);return e===c});if(b.nodeType)return f.grep(a,function(a,d){return a===b===c});if(typeof b=="string"){var d=f.grep(a,function(a){return a.nodeType===1});if(O.test(b))return f.filter(b,d,!c);b=f.filter(b,d)}return f.grep(a,function(a,d){return f.inArray(a,b)>=0===c})}function S(a){return!a||!a.parentNode||a.parentNode.nodeType===11}function K(){return!0}function J(){return!1}function n(a,b,c){var d=b+"defer",e=b+"queue",g=b+"mark",h=f._data(a,d);h&&(c==="queue"||!f._data(a,e))&&(c==="mark"||!f._data(a,g))&&setTimeout(function(){!f._data(a,e)&&!f._data(a,g)&&(f.removeData(a,d,!0),h.fire())},0)}function m(a){for(var b in a){if(b==="data"&&f.isEmptyObject(a[b]))continue;if(b!=="toJSON")return!1}return!0}function l(a,c,d){if(d===b&&a.nodeType===1){var e="data-"+c.replace(k,"-$1").toLowerCase();d=a.getAttribute(e);if(typeof d=="string"){try{d=d==="true"?!0:d==="false"?!1:d==="null"?null:f.isNumeric(d)?parseFloat(d):j.test(d)?f.parseJSON(d):d}catch(g){}f.data(a,c,d)}else d=b}return d}function h(a){var b=g[a]={},c,d;a=a.split(/\s+/);for(c=0,d=a.length;c<d;c++)b[a[c]]=!0;return b}var c=a.document,d=a.navigator,e=a.location,f=function(){function J(){if(!e.isReady){try{c.documentElement.doScroll("left")}catch(a){setTimeout(J,1);return}e.ready()}}var e=function(a,b){return new e.fn.init(a,b,h)},f=a.jQuery,g=a.$,h,i=/^(?:[^#<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/,j=/\S/,k=/^\s+/,l=/\s+$/,m=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,n=/^[\],:{}\s]*$/,o=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,p=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,q=/(?:^|:|,)(?:\s*\[)+/g,r=/(webkit)[ \/]([\w.]+)/,s=/(opera)(?:.*version)?[ \/]([\w.]+)/,t=/(msie) ([\w.]+)/,u=/(mozilla)(?:.*? rv:([\w.]+))?/,v=/-([a-z]|[0-9])/ig,w=/^-ms-/,x=function(a,b){return(b+"").toUpperCase()},y=d.userAgent,z,A,B,C=Object.prototype.toString,D=Object.prototype.hasOwnProperty,E=Array.prototype.push,F=Array.prototype.slice,G=String.prototype.trim,H=Array.prototype.indexOf,I={};e.fn=e.prototype={constructor:e,init:function(a,d,f){var g,h,j,k;if(!a)return this;if(a.nodeType){this.context=this[0]=a,this.length=1;return this}if(a==="body"&&!d&&c.body){this.context=c,this[0]=c.body,this.selector=a,this.length=1;return this}if(typeof a=="string"){a.charAt(0)!=="<"||a.charAt(a.length-1)!==">"||a.length<3?g=i.exec(a):g=[null,a,null];if(g&&(g[1]||!d)){if(g[1]){d=d instanceof e?d[0]:d,k=d?d.ownerDocument||d:c,j=m.exec(a),j?e.isPlainObject(d)?(a=[c.createElement(j[1])],e.fn.attr.call(a,d,!0)):a=[k.createElement(j[1])]:(j=e.buildFragment([g[1]],[k]),a=(j.cacheable?e.clone(j.fragment):j.fragment).childNodes);return e.merge(this,a)}h=c.getElementById(g[2]);if(h&&h.parentNode){if(h.id!==g[2])return f.find(a);this.length=1,this[0]=h}this.context=c,this.selector=a;return this}return!d||d.jquery?(d||f).find(a):this.constructor(d).find(a)}if(e.isFunction(a))return f.ready(a);a.selector!==b&&(this.selector=a.selector,this.context=a.context);return e.makeArray(a,this)},selector:"",jquery:"1.7.1",length:0,size:function(){return this.length},toArray:function(){return F.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this[this.length+a]:this[a]},pushStack:function(a,b,c){var d=this.constructor();e.isArray(a)?E.apply(d,a):e.merge(d,a),d.prevObject=this,d.context=this.context,b==="find"?d.selector=this.selector+(this.selector?" ":"")+c:b&&(d.selector=this.selector+"."+b+"("+c+")");return d},each:function(a,b){return e.each(this,a,b)},ready:function(a){e.bindReady(),A.add(a);return this},eq:function(a){a=+a;return a===-1?this.slice(a):this.slice(a,a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(F.apply(this,arguments),"slice",F.call(arguments).join(","))},map:function(a){return this.pushStack(e.map(this,function(b,c){return a.call(b,c,b)}))},end:function(){return this.prevObject||this.constructor(null)},push:E,sort:[].sort,splice:[].splice},e.fn.init.prototype=e.fn,e.extend=e.fn.extend=function(){var a,c,d,f,g,h,i=arguments[0]||{},j=1,k=arguments.length,l=!1;typeof i=="boolean"&&(l=i,i=arguments[1]||{},j=2),typeof i!="object"&&!e.isFunction(i)&&(i={}),k===j&&(i=this,--j);for(;j<k;j++)if((a=arguments[j])!=null)for(c in a){d=i[c],f=a[c];if(i===f)continue;l&&f&&(e.isPlainObject(f)||(g=e.isArray(f)))?(g?(g=!1,h=d&&e.isArray(d)?d:[]):h=d&&e.isPlainObject(d)?d:{},i[c]=e.extend(l,h,f)):f!==b&&(i[c]=f)}return i},e.extend({noConflict:function(b){a.$===e&&(a.$=g),b&&a.jQuery===e&&(a.jQuery=f);return e},isReady:!1,readyWait:1,holdReady:function(a){a?e.readyWait++:e.ready(!0)},ready:function(a){if(a===!0&&!--e.readyWait||a!==!0&&!e.isReady){if(!c.body)return setTimeout(e.ready,1);e.isReady=!0;if(a!==!0&&--e.readyWait>0)return;A.fireWith(c,[e]),e.fn.trigger&&e(c).trigger("ready").off("ready")}},bindReady:function(){if(!A){A=e.Callbacks("once memory");if(c.readyState==="complete")return setTimeout(e.ready,1);if(c.addEventListener)c.addEventListener("DOMContentLoaded",B,!1),a.addEventListener("load",e.ready,!1);else if(c.attachEvent){c.attachEvent("onreadystatechange",B),a.attachEvent("onload",e.ready);var b=!1;try{b=a.frameElement==null}catch(d){}c.documentElement.doScroll&&b&&J()}}},isFunction:function(a){return e.type(a)==="function"},isArray:Array.isArray||function(a){return e.type(a)==="array"},isWindow:function(a){return a&&typeof a=="object"&&"setInterval"in a},isNumeric:function(a){return!isNaN(parseFloat(a))&&isFinite(a)},type:function(a){return a==null?String(a):I[C.call(a)]||"object"},isPlainObject:function(a){if(!a||e.type(a)!=="object"||a.nodeType||e.isWindow(a))return!1;try{if(a.constructor&&!D.call(a,"constructor")&&!D.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}var d;for(d in a);return d===b||D.call(a,d)},isEmptyObject:function(a){for(var b in a)return!1;return!0},error:function(a){throw new Error(a)},parseJSON:function(b){if(typeof b!="string"||!b)return null;b=e.trim(b);if(a.JSON&&a.JSON.parse)return a.JSON.parse(b);if(n.test(b.replace(o,"@").replace(p,"]").replace(q,"")))return(new Function("return "+b))();e.error("Invalid JSON: "+b)},parseXML:function(c){var d,f;try{a.DOMParser?(f=new DOMParser,d=f.parseFromString(c,"text/xml")):(d=new ActiveXObject("Microsoft.XMLDOM"),d.async="false",d.loadXML(c))}catch(g){d=b}(!d||!d.documentElement||d.getElementsByTagName("parsererror").length)&&e.error("Invalid XML: "+c);return d},noop:function(){},globalEval:function(b){b&&j.test(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(w,"ms-").replace(v,x)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toUpperCase()===b.toUpperCase()},each:function(a,c,d){var f,g=0,h=a.length,i=h===b||e.isFunction(a);if(d){if(i){for(f in a)if(c.apply(a[f],d)===!1)break}else for(;g<h;)if(c.apply(a[g++],d)===!1)break}else if(i){for(f in a)if(c.call(a[f],f,a[f])===!1)break}else for(;g<h;)if(c.call(a[g],g,a[g++])===!1)break;return a},trim:G?function(a){return a==null?"":G.call(a)}:function(a){return a==null?"":(a+"").replace(k,"").replace(l,"")},makeArray:function(a,b){var c=b||[];if(a!=null){var d=e.type(a);a.length==null||d==="string"||d==="function"||d==="regexp"||e.isWindow(a)?E.call(c,a):e.merge(c,a)}return c},inArray:function(a,b,c){var d;if(b){if(H)return H.call(b,a,c);d=b.length,c=c?c<0?Math.max(0,d+c):c:0;for(;c<d;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,c){var d=a.length,e=0;if(typeof c.length=="number")for(var f=c.length;e<f;e++)a[d++]=c[e];else while(c[e]!==b)a[d++]=c[e++];a.length=d;return a},grep:function(a,b,c){var d=[],e;c=!!c;for(var f=0,g=a.length;f<g;f++)e=!!b(a[f],f),c!==e&&d.push(a[f]);return d},map:function(a,c,d){var f,g,h=[],i=0,j=a.length,k=a instanceof e||j!==b&&typeof j=="number"&&(j>0&&a[0]&&a[j-1]||j===0||e.isArray(a));if(k)for(;i<j;i++)f=c(a[i],i,d),f!=null&&(h[h.length]=f);else for(g in a)f=c(a[g],g,d),f!=null&&(h[h.length]=f);return h.concat.apply([],h)},guid:1,proxy:function(a,c){if(typeof c=="string"){var d=a[c];c=a,a=d}if(!e.isFunction(a))return b;var f=F.call(arguments,2),g=function(){return a.apply(c,f.concat(F.call(arguments)))};g.guid=a.guid=a.guid||g.guid||e.guid++;return g},access:function(a,c,d,f,g,h){var i=a.length;if(typeof c=="object"){for(var j in c)e.access(a,j,c[j],f,g,d);return a}if(d!==b){f=!h&&f&&e.isFunction(d);for(var k=0;k<i;k++)g(a[k],c,f?d.call(a[k],k,g(a[k],c)):d,h);return a}return i?g(a[0],c):b},now:function(){return(new Date).getTime()},uaMatch:function(a){a=a.toLowerCase();var b=r.exec(a)||s.exec(a)||t.exec(a)||a.indexOf("compatible")<0&&u.exec(a)||[];return{browser:b[1]||"",version:b[2]||"0"}},sub:function(){function a(b,c){return new a.fn.init(b,c)}e.extend(!0,a,this),a.superclass=this,a.fn=a.prototype=this(),a.fn.constructor=a,a.sub=this.sub,a.fn.init=function(d,f){f&&f instanceof e&&!(f instanceof a)&&(f=a(f));return e.fn.init.call(this,d,f,b)},a.fn.init.prototype=a.fn;var b=a(c);return a},browser:{}}),e.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(a,b){I["[object "+b+"]"]=b.toLowerCase()}),z=e.uaMatch(y),z.browser&&(e.browser[z.browser]=!0,e.browser.version=z.version),e.browser.webkit&&(e.browser.safari=!0),j.test(" ")&&(k=/^[\s\xA0]+/,l=/[\s\xA0]+$/),h=e(c),c.addEventListener?B=function(){c.removeEventListener("DOMContentLoaded",B,!1),e.ready()}:c.attachEvent&&(B=function(){c.readyState==="complete"&&(c.detachEvent("onreadystatechange",B),e.ready())});return e}(),g={};f.Callbacks=function(a){a=a?g[a]||h(a):{};var c=[],d=[],e,i,j,k,l,m=function(b){var d,e,g,h,i;for(d=0,e=b.length;d<e;d++)g=b[d],h=f.type(g),h==="array"?m(g):h==="function"&&(!a.unique||!o.has(g))&&c.push(g)},n=function(b,f){f=f||[],e=!a.memory||[b,f],i=!0,l=j||0,j=0,k=c.length;for(;c&&l<k;l++)if(c[l].apply(b,f)===!1&&a.stopOnFalse){e=!0;break}i=!1,c&&(a.once?e===!0?o.disable():c=[]:d&&d.length&&(e=d.shift(),o.fireWith(e[0],e[1])))},o={add:function(){if(c){var a=c.length;m(arguments),i?k=c.length:e&&e!==!0&&(j=a,n(e[0],e[1]))}return this},remove:function(){if(c){var b=arguments,d=0,e=b.length;for(;d<e;d++)for(var f=0;f<c.length;f++)if(b[d]===c[f]){i&&f<=k&&(k--,f<=l&&l--),c.splice(f--,1);if(a.unique)break}}return this},has:function(a){if(c){var b=0,d=c.length;for(;b<d;b++)if(a===c[b])return!0}return!1},empty:function(){c=[];return this},disable:function(){c=d=e=b;return this},disabled:function(){return!c},lock:function(){d=b,(!e||e===!0)&&o.disable();return this},locked:function(){return!d},fireWith:function(b,c){d&&(i?a.once||d.push([b,c]):(!a.once||!e)&&n(b,c));return this},fire:function(){o.fireWith(this,arguments);return this},fired:function(){return!!e}};return o};var i=[].slice;f.extend({Deferred:function(a){var b=f.Callbacks("once memory"),c=f.Callbacks("once memory"),d=f.Callbacks("memory"),e="pending",g={resolve:b,reject:c,notify:d},h={done:b.add,fail:c.add,progress:d.add,state:function(){return e},isResolved:b.fired,isRejected:c.fired,then:function(a,b,c){i.done(a).fail(b).progress(c);return this},always:function(){i.done.apply(i,arguments).fail.apply(i,arguments);return this},pipe:function(a,b,c){return f.Deferred(function(d){f.each({done:[a,"resolve"],fail:[b,"reject"],progress:[c,"notify"]},function(a,b){var c=b[0],e=b[1],g;f.isFunction(c)?i[a](function(){g=c.apply(this,arguments),g&&f.isFunction(g.promise)?g.promise().then(d.resolve,d.reject,d.notify):d[e+"With"](this===i?d:this,[g])}):i[a](d[e])})}).promise()},promise:function(a){if(a==null)a=h;else for(var b in h)a[b]=h[b];return a}},i=h.promise({}),j;for(j in g)i[j]=g[j].fire,i[j+"With"]=g[j].fireWith;i.done(function(){e="resolved"},c.disable,d.lock).fail(function(){e="rejected"},b.disable,d.lock),a&&a.call(i,i);return i},when:function(a){function m(a){return function(b){e[a]=arguments.length>1?i.call(arguments,0):b,j.notifyWith(k,e)}}function l(a){return function(c){b[a]=arguments.length>1?i.call(arguments,0):c,--g||j.resolveWith(j,b)}}var b=i.call(arguments,0),c=0,d=b.length,e=Array(d),g=d,h=d,j=d<=1&&a&&f.isFunction(a.promise)?a:f.Deferred(),k=j.promise();if(d>1){for(;c<d;c++)b[c]&&b[c].promise&&f.isFunction(b[c].promise)?b[c].promise().then(l(c),j.reject,m(c)):--g;g||j.resolveWith(j,b)}else j!==a&&j.resolveWith(j,d?[a]:[]);return k}}),f.support=function(){var b,d,e,g,h,i,j,k,l,m,n,o,p,q=c.createElement("div"),r=c.documentElement;q.setAttribute("className","t"),q.innerHTML=" <link/><table></table><a href='/a' style='top:1px;float:left;opacity:.55;'>a</a><input type='checkbox'/>",d=q.getElementsByTagName("*"),e=q.getElementsByTagName("a")[0];if(!d||!d.length||!e)return{};g=c.createElement("select"),h=g.appendChild(c.createElement("option")),i=q.getElementsByTagName("input")[0],b={leadingWhitespace:q.firstChild.nodeType===3,tbody:!q.getElementsByTagName("tbody").length,htmlSerialize:!!q.getElementsByTagName("link").length,style:/top/.test(e.getAttribute("style")),hrefNormalized:e.getAttribute("href")==="/a",opacity:/^0.55/.test(e.style.opacity),cssFloat:!!e.style.cssFloat,checkOn:i.value==="on",optSelected:h.selected,getSetAttribute:q.className!=="t",enctype:!!c.createElement("form").enctype,html5Clone:c.createElement("nav").cloneNode(!0).outerHTML!=="<:nav></:nav>",submitBubbles:!0,changeBubbles:!0,focusinBubbles:!1,deleteExpando:!0,noCloneEvent:!0,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0},i.checked=!0,b.noCloneChecked=i.cloneNode(!0).checked,g.disabled=!0,b.optDisabled=!h.disabled;try{delete q.test}catch(s){b.deleteExpando=!1}!q.addEventListener&&q.attachEvent&&q.fireEvent&&(q.attachEvent("onclick",function(){b.noCloneEvent=!1}),q.cloneNode(!0).fireEvent("onclick")),i=c.createElement("input"),i.value="t",i.setAttribute("type","radio"),b.radioValue=i.value==="t",i.setAttribute("checked","checked"),q.appendChild(i),k=c.createDocumentFragment(),k.appendChild(q.lastChild),b.checkClone=k.cloneNode(!0).cloneNode(!0).lastChild.checked,b.appendChecked=i.checked,k.removeChild(i),k.appendChild(q),q.innerHTML="",a.getComputedStyle&&(j=c.createElement("div"),j.style.width="0",j.style.marginRight="0",q.style.width="2px",q.appendChild(j),b.reliableMarginRight=(parseInt((a.getComputedStyle(j,null)||{marginRight:0}).marginRight,10)||0)===0);if(q.attachEvent)for(o in{submit:1,change:1,focusin:1})n="on"+o,p=n in q,p||(q.setAttribute(n,"return;"),p=typeof q[n]=="function"),b[o+"Bubbles"]=p;k.removeChild(q),k=g=h=j=q=i=null,f(function(){var a,d,e,g,h,i,j,k,m,n,o,r=c.getElementsByTagName("body")[0];!r||(j=1,k="position:absolute;top:0;left:0;width:1px;height:1px;margin:0;",m="visibility:hidden;border:0;",n="style='"+k+"border:5px solid #000;padding:0;'",o="<div "+n+"><div></div></div>"+"<table "+n+" cellpadding='0' cellspacing='0'>"+"<tr><td></td></tr></table>",a=c.createElement("div"),a.style.cssText=m+"width:0;height:0;position:static;top:0;margin-top:"+j+"px",r.insertBefore(a,r.firstChild),q=c.createElement("div"),a.appendChild(q),q.innerHTML="<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>",l=q.getElementsByTagName("td"),p=l[0].offsetHeight===0,l[0].style.display="",l[1].style.display="none",b.reliableHiddenOffsets=p&&l[0].offsetHeight===0,q.innerHTML="",q.style.width=q.style.paddingLeft="1px",f.boxModel=b.boxModel=q.offsetWidth===2,typeof q.style.zoom!="undefined"&&(q.style.display="inline",q.style.zoom=1,b.inlineBlockNeedsLayout=q.offsetWidth===2,q.style.display="",q.innerHTML="<div style='width:4px;'></div>",b.shrinkWrapBlocks=q.offsetWidth!==2),q.style.cssText=k+m,q.innerHTML=o,d=q.firstChild,e=d.firstChild,h=d.nextSibling.firstChild.firstChild,i={doesNotAddBorder:e.offsetTop!==5,doesAddBorderForTableAndCells:h.offsetTop===5},e.style.position="fixed",e.style.top="20px",i.fixedPosition=e.offsetTop===20||e.offsetTop===15,e.style.position=e.style.top="",d.style.overflow="hidden",d.style.position="relative",i.subtractsBorderForOverflowNotVisible=e.offsetTop===-5,i.doesNotIncludeMarginInBodyOffset=r.offsetTop!==j,r.removeChild(a),q=a=null,f.extend(b,i))});return b}();var j=/^(?:\{.*\}|\[.*\])$/,k=/([A-Z])/g;f.extend({cache:{},uuid:0,expando:"jQuery"+(f.fn.jquery+Math.random()).replace(/\D/g,""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:!0},hasData:function(a){a=a.nodeType?f.cache[a[f.expando]]:a[f.expando];return!!a&&!m(a)},data:function(a,c,d,e){if(!!f.acceptData(a)){var g,h,i,j=f.expando,k=typeof c=="string",l=a.nodeType,m=l?f.cache:a,n=l?a[j]:a[j]&&j,o=c==="events";if((!n||!m[n]||!o&&!e&&!m[n].data)&&k&&d===b)return;n||(l?a[j]=n=++f.uuid:n=j),m[n]||(m[n]={},l||(m[n].toJSON=f.noop));if(typeof c=="object"||typeof c=="function")e?m[n]=f.extend(m[n],c):m[n].data=f.extend(m[n].data,c);g=h=m[n],e||(h.data||(h.data={}),h=h.data),d!==b&&(h[f.camelCase(c)]=d);if(o&&!h[c])return g.events;k?(i=h[c],i==null&&(i=h[f.camelCase(c)])):i=h;return i}},removeData:function(a,b,c){if(!!f.acceptData(a)){var d,e,g,h=f.expando,i=a.nodeType,j=i?f.cache:a,k=i?a[h]:h;if(!j[k])return;if(b){d=c?j[k]:j[k].data;if(d){f.isArray(b)||(b in d?b=[b]:(b=f.camelCase(b),b in d?b=[b]:b=b.split(" ")));for(e=0,g=b.length;e<g;e++)delete d[b[e]];if(!(c?m:f.isEmptyObject)(d))return}}if(!c){delete j[k].data;if(!m(j[k]))return}f.support.deleteExpando||!j.setInterval?delete j[k]:j[k]=null,i&&(f.support.deleteExpando?delete a[h]:a.removeAttribute?a.removeAttribute(h):a[h]=null)}},_data:function(a,b,c){return f.data(a,b,c,!0)},acceptData:function(a){if(a.nodeName){var b=f.noData[a.nodeName.toLowerCase()];if(b)return b!==!0&&a.getAttribute("classid")===b}return!0}}),f.fn.extend({data:function(a,c){var d,e,g,h=null;if(typeof a=="undefined"){if(this.length){h=f.data(this[0]);if(this[0].nodeType===1&&!f._data(this[0],"parsedAttrs")){e=this[0].attributes;for(var i=0,j=e.length;i<j;i++)g=e[i].name,g.indexOf("data-")===0&&(g=f.camelCase(g.substring(5)),l(this[0],g,h[g]));f._data(this[0],"parsedAttrs",!0)}}return h}if(typeof a=="object")return this.each(function(){f.data(this,a)});d=a.split("."),d[1]=d[1]?"."+d[1]:"";if(c===b){h=this.triggerHandler("getData"+d[1]+"!",[d[0]]),h===b&&this.length&&(h=f.data(this[0],a),h=l(this[0],a,h));return h===b&&d[1]?this.data(d[0]):h}return this.each(function(){var b=f(this),e=[d[0],c];b.triggerHandler("setData"+d[1]+"!",e),f.data(this,a,c),b.triggerHandler("changeData"+d[1]+"!",e)})},removeData:function(a){return this.each(function(){f.removeData(this,a)})}}),f.extend({_mark:function(a,b){a&&(b=(b||"fx")+"mark",f._data(a,b,(f._data(a,b)||0)+1))},_unmark:function(a,b,c){a!==!0&&(c=b,b=a,a=!1);if(b){c=c||"fx";var d=c+"mark",e=a?0:(f._data(b,d)||1)-1;e?f._data(b,d,e):(f.removeData(b,d,!0),n(b,c,"mark"))}},queue:function(a,b,c){var d;if(a){b=(b||"fx")+"queue",d=f._data(a,b),c&&(!d||f.isArray(c)?d=f._data(a,b,f.makeArray(c)):d.push(c));return d||[]}},dequeue:function(a,b){b=b||"fx";var c=f.queue(a,b),d=c.shift(),e={};d==="inprogress"&&(d=c.shift()),d&&(b==="fx"&&c.unshift("inprogress"),f._data(a,b+".run",e),d.call(a,function(){f.dequeue(a,b)},e)),c.length||(f.removeData(a,b+"queue "+b+".run",!0),n(a,b,"queue"))}}),f.fn.extend({queue:function(a,c){typeof a!="string"&&(c=a,a="fx");if(c===b)return f.queue(this[0],a);return this.each(function(){var b=f.queue(this,a,c);a==="fx"&&b[0]!=="inprogress"&&f.dequeue(this,a)})},dequeue:function(a){return this.each(function(){f.dequeue(this,a)})},delay:function(a,b){a=f.fx?f.fx.speeds[a]||a:a,b=b||"fx";return this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,c){function m(){--h||d.resolveWith(e,[e])}typeof a!="string"&&(c=a,a=b),a=a||"fx";var d=f.Deferred(),e=this,g=e.length,h=1,i=a+"defer",j=a+"queue",k=a+"mark",l;while(g--)if(l=f.data(e[g],i,b,!0)||(f.data(e[g],j,b,!0)||f.data(e[g],k,b,!0))&&f.data(e[g],i,f.Callbacks("once memory"),!0))h++,l.add(m);m();return d.promise()}});var o=/[\n\t\r]/g,p=/\s+/,q=/\r/g,r=/^(?:button|input)$/i,s=/^(?:button|input|object|select|textarea)$/i,t=/^a(?:rea)?$/i,u=/^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,v=f.support.getSetAttribute,w,x,y;f.fn.extend({attr:function(a,b){return f.access(this,a,b,!0,f.attr)},removeAttr:function(a){return this.each(function(){f.removeAttr(this,a)})},prop:function(a,b){return f.access(this,a,b,!0,f.prop)},removeProp:function(a){a=f.propFix[a]||a;return this.each(function(){try{this[a]=b,delete this[a]}catch(c){}})},addClass:function(a){var b,c,d,e,g,h,i;if(f.isFunction(a))return this.each(function(b){f(this).addClass(a.call(this,b,this.className))});if(a&&typeof a=="string"){b=a.split(p);for(c=0,d=this.length;c<d;c++){e=this[c];if(e.nodeType===1)if(!e.className&&b.length===1)e.className=a;else{g=" "+e.className+" ";for(h=0,i=b.length;h<i;h++)~g.indexOf(" "+b[h]+" ")||(g+=b[h]+" ");e.className=f.trim(g)}}}return this},removeClass:function(a){var c,d,e,g,h,i,j;if(f.isFunction(a))return this.each(function(b){f(this).removeClass(a.call(this,b,this.className))});if(a&&typeof a=="string"||a===b){c=(a||"").split(p);for(d=0,e=this.length;d<e;d++){g=this[d];if(g.nodeType===1&&g.className)if(a){h=(" "+g.className+" ").replace(o," ");for(i=0,j=c.length;i<j;i++)h=h.replace(" "+c[i]+" "," ");g.className=f.trim(h)}else g.className=""}}return this},toggleClass:function(a,b){var c=typeof a,d=typeof b=="boolean";if(f.isFunction(a))return this.each(function(c){f(this).toggleClass(a.call(this,c,this.className,b),b)});return this.each(function(){if(c==="string"){var e,g=0,h=f(this),i=b,j=a.split(p);while(e=j[g++])i=d?i:!h.hasClass(e),h[i?"addClass":"removeClass"](e)}else if(c==="undefined"||c==="boolean")this.className&&f._data(this,"__className__",this.className),this.className=this.className||a===!1?"":f._data(this,"__className__")||""})},hasClass:function(a){var b=" "+a+" ",c=0,d=this.length;for(;c<d;c++)if(this[c].nodeType===1&&(" "+this[c].className+" ").replace(o," ").indexOf(b)>-1)return!0;return!1},val:function(a){var c,d,e,g=this[0];{if(!!arguments.length){e=f.isFunction(a);return this.each(function(d){var g=f(this),h;if(this.nodeType===1){e?h=a.call(this,d,g.val()):h=a,h==null?h="":typeof h=="number"?h+="":f.isArray(h)&&(h=f.map(h,function(a){return a==null?"":a+""})),c=f.valHooks[this.nodeName.toLowerCase()]||f.valHooks[this.type];if(!c||!("set"in c)||c.set(this,h,"value")===b)this.value=h}})}if(g){c=f.valHooks[g.nodeName.toLowerCase()]||f.valHooks[g.type];if(c&&"get"in c&&(d=c.get(g,"value"))!==b)return d;d=g.value;return typeof d=="string"?d.replace(q,""):d==null?"":d}}}}),f.extend({valHooks:{option:{get:function(a){var b=a.attributes.value;return!b||b.specified?a.value:a.text}},select:{get:function(a){var b,c,d,e,g=a.selectedIndex,h=[],i=a.options,j=a.type==="select-one";if(g<0)return null;c=j?g:0,d=j?g+1:i.length;for(;c<d;c++){e=i[c];if(e.selected&&(f.support.optDisabled?!e.disabled:e.getAttribute("disabled")===null)&&(!e.parentNode.disabled||!f.nodeName(e.parentNode,"optgroup"))){b=f(e).val();if(j)return b;h.push(b)}}if(j&&!h.length&&i.length)return f(i[g]).val();return h},set:function(a,b){var c=f.makeArray(b);f(a).find("option").each(function(){this.selected=f.inArray(f(this).val(),c)>=0}),c.length||(a.selectedIndex=-1);return c}}},attrFn:{val:!0,css:!0,html:!0,text:!0,data:!0,width:!0,height:!0,offset:!0},attr:function(a,c,d,e){var g,h,i,j=a.nodeType;if(!!a&&j!==3&&j!==8&&j!==2){if(e&&c in f.attrFn)return f(a)[c](d);if(typeof a.getAttribute=="undefined")return f.prop(a,c,d);i=j!==1||!f.isXMLDoc(a),i&&(c=c.toLowerCase(),h=f.attrHooks[c]||(u.test(c)?x:w));if(d!==b){if(d===null){f.removeAttr(a,c);return}if(h&&"set"in h&&i&&(g=h.set(a,d,c))!==b)return g;a.setAttribute(c,""+d);return d}if(h&&"get"in h&&i&&(g=h.get(a,c))!==null)return g;g=a.getAttribute(c);return g===null?b:g}},removeAttr:function(a,b){var c,d,e,g,h=0;if(b&&a.nodeType===1){d=b.toLowerCase().split(p),g=d.length;for(;h<g;h++)e=d[h],e&&(c=f.propFix[e]||e,f.attr(a,e,""),a.removeAttribute(v?e:c),u.test(e)&&c in a&&(a[c]=!1))}},attrHooks:{type:{set:function(a,b){if(r.test(a.nodeName)&&a.parentNode)f.error("type property can't be changed");else if(!f.support.radioValue&&b==="radio"&&f.nodeName(a,"input")){var c=a.value;a.setAttribute("type",b),c&&(a.value=c);return b}}},value:{get:function(a,b){if(w&&f.nodeName(a,"button"))return w.get(a,b);return b in a?a.value:null},set:function(a,b,c){if(w&&f.nodeName(a,"button"))return w.set(a,b,c);a.value=b}}},propFix:{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},prop:function(a,c,d){var e,g,h,i=a.nodeType;if(!!a&&i!==3&&i!==8&&i!==2){h=i!==1||!f.isXMLDoc(a),h&&(c=f.propFix[c]||c,g=f.propHooks[c]);return d!==b?g&&"set"in g&&(e=g.set(a,d,c))!==b?e:a[c]=d:g&&"get"in g&&(e=g.get(a,c))!==null?e:a[c]}},propHooks:{tabIndex:{get:function(a){var c=a.getAttributeNode("tabindex");return c&&c.specified?parseInt(c.value,10):s.test(a.nodeName)||t.test(a.nodeName)&&a.href?0:b}}}}),f.attrHooks.tabindex=f.propHooks.tabIndex,x={get:function(a,c){var d,e=f.prop(a,c);return e===!0||typeof e!="boolean"&&(d=a.getAttributeNode(c))&&d.nodeValue!==!1?c.toLowerCase():b},set:function(a,b,c){var d;b===!1?f.removeAttr(a,c):(d=f.propFix[c]||c,d in a&&(a[d]=!0),a.setAttribute(c,c.toLowerCase()));return c}},v||(y={name:!0,id:!0},w=f.valHooks.button={get:function(a,c){var d;d=a.getAttributeNode(c);return d&&(y[c]?d.nodeValue!=="":d.specified)?d.nodeValue:b},set:function(a,b,d){var e=a.getAttributeNode(d);e||(e=c.createAttribute(d),a.setAttributeNode(e));return e.nodeValue=b+""}},f.attrHooks.tabindex.set=w.set,f.each(["width","height"],function(a,b){f.attrHooks[b]=f.extend(f.attrHooks[b],{set:function(a,c){if(c===""){a.setAttribute(b,"auto");return c}}})}),f.attrHooks.contenteditable={get:w.get,set:function(a,b,c){b===""&&(b="false"),w.set(a,b,c)}}),f.support.hrefNormalized||f.each(["href","src","width","height"],function(a,c){f.attrHooks[c]=f.extend(f.attrHooks[c],{get:function(a){var d=a.getAttribute(c,2);return d===null?b:d}})}),f.support.style||(f.attrHooks.style={get:function(a){return a.style.cssText.toLowerCase()||b},set:function(a,b){return a.style.cssText=""+b}}),f.support.optSelected||(f.propHooks.selected=f.extend(f.propHooks.selected,{get:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex);return null}})),f.support.enctype||(f.propFix.enctype="encoding"),f.support.checkOn||f.each(["radio","checkbox"],function(){f.valHooks[this]={get:function(a){return a.getAttribute("value")===null?"on":a.value}}}),f.each(["radio","checkbox"],function(){f.valHooks[this]=f.extend(f.valHooks[this],{set:function(a,b){if(f.isArray(b))return a.checked=f.inArray(f(a).val(),b)>=0}})});var z=/^(?:textarea|input|select)$/i,A=/^([^\.]*)?(?:\.(.+))?$/,B=/\bhover(\.\S+)?\b/,C=/^key/,D=/^(?:mouse|contextmenu)|click/,E=/^(?:focusinfocus|focusoutblur)$/,F=/^(\w*)(?:#([\w\-]+))?(?:\.([\w\-]+))?$/,G=function(a){var b=F.exec(a);b&&(b[1]=(b[1]||"").toLowerCase(),b[3]=b[3]&&new RegExp("(?:^|\\s)"+b[3]+"(?:\\s|$)"));return b},H=function(a,b){var c=a.attributes||{};return(!b[1]||a.nodeName.toLowerCase()===b[1])&&(!b[2]||(c.id||{}).value===b[2])&&(!b[3]||b[3].test((c["class"]||{}).value))},I=function(a){return f.event.special.hover?a:a.replace(B,"mouseenter$1 mouseleave$1")};
+f.event={add:function(a,c,d,e,g){var h,i,j,k,l,m,n,o,p,q,r,s;if(!(a.nodeType===3||a.nodeType===8||!c||!d||!(h=f._data(a)))){d.handler&&(p=d,d=p.handler),d.guid||(d.guid=f.guid++),j=h.events,j||(h.events=j={}),i=h.handle,i||(h.handle=i=function(a){return typeof f!="undefined"&&(!a||f.event.triggered!==a.type)?f.event.dispatch.apply(i.elem,arguments):b},i.elem=a),c=f.trim(I(c)).split(" ");for(k=0;k<c.length;k++){l=A.exec(c[k])||[],m=l[1],n=(l[2]||"").split(".").sort(),s=f.event.special[m]||{},m=(g?s.delegateType:s.bindType)||m,s=f.event.special[m]||{},o=f.extend({type:m,origType:l[1],data:e,handler:d,guid:d.guid,selector:g,quick:G(g),namespace:n.join(".")},p),r=j[m];if(!r){r=j[m]=[],r.delegateCount=0;if(!s.setup||s.setup.call(a,e,n,i)===!1)a.addEventListener?a.addEventListener(m,i,!1):a.attachEvent&&a.attachEvent("on"+m,i)}s.add&&(s.add.call(a,o),o.handler.guid||(o.handler.guid=d.guid)),g?r.splice(r.delegateCount++,0,o):r.push(o),f.event.global[m]=!0}a=null}},global:{},remove:function(a,b,c,d,e){var g=f.hasData(a)&&f._data(a),h,i,j,k,l,m,n,o,p,q,r,s;if(!!g&&!!(o=g.events)){b=f.trim(I(b||"")).split(" ");for(h=0;h<b.length;h++){i=A.exec(b[h])||[],j=k=i[1],l=i[2];if(!j){for(j in o)f.event.remove(a,j+b[h],c,d,!0);continue}p=f.event.special[j]||{},j=(d?p.delegateType:p.bindType)||j,r=o[j]||[],m=r.length,l=l?new RegExp("(^|\\.)"+l.split(".").sort().join("\\.(?:.*\\.)?")+"(\\.|$)"):null;for(n=0;n<r.length;n++)s=r[n],(e||k===s.origType)&&(!c||c.guid===s.guid)&&(!l||l.test(s.namespace))&&(!d||d===s.selector||d==="**"&&s.selector)&&(r.splice(n--,1),s.selector&&r.delegateCount--,p.remove&&p.remove.call(a,s));r.length===0&&m!==r.length&&((!p.teardown||p.teardown.call(a,l)===!1)&&f.removeEvent(a,j,g.handle),delete o[j])}f.isEmptyObject(o)&&(q=g.handle,q&&(q.elem=null),f.removeData(a,["events","handle"],!0))}},customEvent:{getData:!0,setData:!0,changeData:!0},trigger:function(c,d,e,g){if(!e||e.nodeType!==3&&e.nodeType!==8){var h=c.type||c,i=[],j,k,l,m,n,o,p,q,r,s;if(E.test(h+f.event.triggered))return;h.indexOf("!")>=0&&(h=h.slice(0,-1),k=!0),h.indexOf(".")>=0&&(i=h.split("."),h=i.shift(),i.sort());if((!e||f.event.customEvent[h])&&!f.event.global[h])return;c=typeof c=="object"?c[f.expando]?c:new f.Event(h,c):new f.Event(h),c.type=h,c.isTrigger=!0,c.exclusive=k,c.namespace=i.join("."),c.namespace_re=c.namespace?new RegExp("(^|\\.)"+i.join("\\.(?:.*\\.)?")+"(\\.|$)"):null,o=h.indexOf(":")<0?"on"+h:"";if(!e){j=f.cache;for(l in j)j[l].events&&j[l].events[h]&&f.event.trigger(c,d,j[l].handle.elem,!0);return}c.result=b,c.target||(c.target=e),d=d!=null?f.makeArray(d):[],d.unshift(c),p=f.event.special[h]||{};if(p.trigger&&p.trigger.apply(e,d)===!1)return;r=[[e,p.bindType||h]];if(!g&&!p.noBubble&&!f.isWindow(e)){s=p.delegateType||h,m=E.test(s+h)?e:e.parentNode,n=null;for(;m;m=m.parentNode)r.push([m,s]),n=m;n&&n===e.ownerDocument&&r.push([n.defaultView||n.parentWindow||a,s])}for(l=0;l<r.length&&!c.isPropagationStopped();l++)m=r[l][0],c.type=r[l][1],q=(f._data(m,"events")||{})[c.type]&&f._data(m,"handle"),q&&q.apply(m,d),q=o&&m[o],q&&f.acceptData(m)&&q.apply(m,d)===!1&&c.preventDefault();c.type=h,!g&&!c.isDefaultPrevented()&&(!p._default||p._default.apply(e.ownerDocument,d)===!1)&&(h!=="click"||!f.nodeName(e,"a"))&&f.acceptData(e)&&o&&e[h]&&(h!=="focus"&&h!=="blur"||c.target.offsetWidth!==0)&&!f.isWindow(e)&&(n=e[o],n&&(e[o]=null),f.event.triggered=h,e[h](),f.event.triggered=b,n&&(e[o]=n));return c.result}},dispatch:function(c){c=f.event.fix(c||a.event);var d=(f._data(this,"events")||{})[c.type]||[],e=d.delegateCount,g=[].slice.call(arguments,0),h=!c.exclusive&&!c.namespace,i=[],j,k,l,m,n,o,p,q,r,s,t;g[0]=c,c.delegateTarget=this;if(e&&!c.target.disabled&&(!c.button||c.type!=="click")){m=f(this),m.context=this.ownerDocument||this;for(l=c.target;l!=this;l=l.parentNode||this){o={},q=[],m[0]=l;for(j=0;j<e;j++)r=d[j],s=r.selector,o[s]===b&&(o[s]=r.quick?H(l,r.quick):m.is(s)),o[s]&&q.push(r);q.length&&i.push({elem:l,matches:q})}}d.length>e&&i.push({elem:this,matches:d.slice(e)});for(j=0;j<i.length&&!c.isPropagationStopped();j++){p=i[j],c.currentTarget=p.elem;for(k=0;k<p.matches.length&&!c.isImmediatePropagationStopped();k++){r=p.matches[k];if(h||!c.namespace&&!r.namespace||c.namespace_re&&c.namespace_re.test(r.namespace))c.data=r.data,c.handleObj=r,n=((f.event.special[r.origType]||{}).handle||r.handler).apply(p.elem,g),n!==b&&(c.result=n,n===!1&&(c.preventDefault(),c.stopPropagation()))}}return c.result},props:"attrChange attrName relatedNode srcElement altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){a.which==null&&(a.which=b.charCode!=null?b.charCode:b.keyCode);return a}},mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,d){var e,f,g,h=d.button,i=d.fromElement;a.pageX==null&&d.clientX!=null&&(e=a.target.ownerDocument||c,f=e.documentElement,g=e.body,a.pageX=d.clientX+(f&&f.scrollLeft||g&&g.scrollLeft||0)-(f&&f.clientLeft||g&&g.clientLeft||0),a.pageY=d.clientY+(f&&f.scrollTop||g&&g.scrollTop||0)-(f&&f.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&i&&(a.relatedTarget=i===a.target?d.toElement:i),!a.which&&h!==b&&(a.which=h&1?1:h&2?3:h&4?2:0);return a}},fix:function(a){if(a[f.expando])return a;var d,e,g=a,h=f.event.fixHooks[a.type]||{},i=h.props?this.props.concat(h.props):this.props;a=f.Event(g);for(d=i.length;d;)e=i[--d],a[e]=g[e];a.target||(a.target=g.srcElement||c),a.target.nodeType===3&&(a.target=a.target.parentNode),a.metaKey===b&&(a.metaKey=a.ctrlKey);return h.filter?h.filter(a,g):a},special:{ready:{setup:f.bindReady},load:{noBubble:!0},focus:{delegateType:"focusin"},blur:{delegateType:"focusout"},beforeunload:{setup:function(a,b,c){f.isWindow(this)&&(this.onbeforeunload=c)},teardown:function(a,b){this.onbeforeunload===b&&(this.onbeforeunload=null)}}},simulate:function(a,b,c,d){var e=f.extend(new f.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?f.event.trigger(e,null,b):f.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},f.event.handle=f.event.dispatch,f.removeEvent=c.removeEventListener?function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)}:function(a,b,c){a.detachEvent&&a.detachEvent("on"+b,c)},f.Event=function(a,b){if(!(this instanceof f.Event))return new f.Event(a,b);a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||a.returnValue===!1||a.getPreventDefault&&a.getPreventDefault()?K:J):this.type=a,b&&f.extend(this,b),this.timeStamp=a&&a.timeStamp||f.now(),this[f.expando]=!0},f.Event.prototype={preventDefault:function(){this.isDefaultPrevented=K;var a=this.originalEvent;!a||(a.preventDefault?a.preventDefault():a.returnValue=!1)},stopPropagation:function(){this.isPropagationStopped=K;var a=this.originalEvent;!a||(a.stopPropagation&&a.stopPropagation(),a.cancelBubble=!0)},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=K,this.stopPropagation()},isDefaultPrevented:J,isPropagationStopped:J,isImmediatePropagationStopped:J},f.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){f.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c=this,d=a.relatedTarget,e=a.handleObj,g=e.selector,h;if(!d||d!==c&&!f.contains(c,d))a.type=e.origType,h=e.handler.apply(this,arguments),a.type=b;return h}}}),f.support.submitBubbles||(f.event.special.submit={setup:function(){if(f.nodeName(this,"form"))return!1;f.event.add(this,"click._submit keypress._submit",function(a){var c=a.target,d=f.nodeName(c,"input")||f.nodeName(c,"button")?c.form:b;d&&!d._submit_attached&&(f.event.add(d,"submit._submit",function(a){this.parentNode&&!a.isTrigger&&f.event.simulate("submit",this.parentNode,a,!0)}),d._submit_attached=!0)})},teardown:function(){if(f.nodeName(this,"form"))return!1;f.event.remove(this,"._submit")}}),f.support.changeBubbles||(f.event.special.change={setup:function(){if(z.test(this.nodeName)){if(this.type==="checkbox"||this.type==="radio")f.event.add(this,"propertychange._change",function(a){a.originalEvent.propertyName==="checked"&&(this._just_changed=!0)}),f.event.add(this,"click._change",function(a){this._just_changed&&!a.isTrigger&&(this._just_changed=!1,f.event.simulate("change",this,a,!0))});return!1}f.event.add(this,"beforeactivate._change",function(a){var b=a.target;z.test(b.nodeName)&&!b._change_attached&&(f.event.add(b,"change._change",function(a){this.parentNode&&!a.isSimulated&&!a.isTrigger&&f.event.simulate("change",this.parentNode,a,!0)}),b._change_attached=!0)})},handle:function(a){var b=a.target;if(this!==b||a.isSimulated||a.isTrigger||b.type!=="radio"&&b.type!=="checkbox")return a.handleObj.handler.apply(this,arguments)},teardown:function(){f.event.remove(this,"._change");return z.test(this.nodeName)}}),f.support.focusinBubbles||f.each({focus:"focusin",blur:"focusout"},function(a,b){var d=0,e=function(a){f.event.simulate(b,a.target,f.event.fix(a),!0)};f.event.special[b]={setup:function(){d++===0&&c.addEventListener(a,e,!0)},teardown:function(){--d===0&&c.removeEventListener(a,e,!0)}}}),f.fn.extend({on:function(a,c,d,e,g){var h,i;if(typeof a=="object"){typeof c!="string"&&(d=c,c=b);for(i in a)this.on(i,c,d,a[i],g);return this}d==null&&e==null?(e=c,d=c=b):e==null&&(typeof c=="string"?(e=d,d=b):(e=d,d=c,c=b));if(e===!1)e=J;else if(!e)return this;g===1&&(h=e,e=function(a){f().off(a);return h.apply(this,arguments)},e.guid=h.guid||(h.guid=f.guid++));return this.each(function(){f.event.add(this,a,e,d,c)})},one:function(a,b,c,d){return this.on.call(this,a,b,c,d,1)},off:function(a,c,d){if(a&&a.preventDefault&&a.handleObj){var e=a.handleObj;f(a.delegateTarget).off(e.namespace?e.type+"."+e.namespace:e.type,e.selector,e.handler);return this}if(typeof a=="object"){for(var g in a)this.off(g,c,a[g]);return this}if(c===!1||typeof c=="function")d=c,c=b;d===!1&&(d=J);return this.each(function(){f.event.remove(this,a,d,c)})},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},live:function(a,b,c){f(this.context).on(a,this.selector,b,c);return this},die:function(a,b){f(this.context).off(a,this.selector||"**",b);return this},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return arguments.length==1?this.off(a,"**"):this.off(b,a,c)},trigger:function(a,b){return this.each(function(){f.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0])return f.event.trigger(a,b,this[0],!0)},toggle:function(a){var b=arguments,c=a.guid||f.guid++,d=0,e=function(c){var e=(f._data(this,"lastToggle"+a.guid)||0)%d;f._data(this,"lastToggle"+a.guid,e+1),c.preventDefault();return b[e].apply(this,arguments)||!1};e.guid=c;while(d<b.length)b[d++].guid=c;return this.click(e)},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),f.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){f.fn[b]=function(a,c){c==null&&(c=a,a=null);return arguments.length>0?this.on(b,null,a,c):this.trigger(b)},f.attrFn&&(f.attrFn[b]=!0),C.test(b)&&(f.event.fixHooks[b]=f.event.keyHooks),D.test(b)&&(f.event.fixHooks[b]=f.event.mouseHooks)}),function(){function x(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}if(j.nodeType===1){g||(j[d]=c,j.sizset=h);if(typeof b!="string"){if(j===b){k=!0;break}}else if(m.filter(b,[j]).length>0){k=j;break}}j=j[a]}e[h]=k}}}function w(a,b,c,e,f,g){for(var h=0,i=e.length;h<i;h++){var j=e[h];if(j){var k=!1;j=j[a];while(j){if(j[d]===c){k=e[j.sizset];break}j.nodeType===1&&!g&&(j[d]=c,j.sizset=h);if(j.nodeName.toLowerCase()===b){k=j;break}j=j[a]}e[h]=k}}}var a=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,d="sizcache"+(Math.random()+"").replace(".",""),e=0,g=Object.prototype.toString,h=!1,i=!0,j=/\\/g,k=/\r\n/g,l=/\W/;[0,0].sort(function(){i=!1;return 0});var m=function(b,d,e,f){e=e||[],d=d||c;var h=d;if(d.nodeType!==1&&d.nodeType!==9)return[];if(!b||typeof b!="string")return e;var i,j,k,l,n,q,r,t,u=!0,v=m.isXML(d),w=[],x=b;do{a.exec(""),i=a.exec(x);if(i){x=i[3],w.push(i[1]);if(i[2]){l=i[3];break}}}while(i);if(w.length>1&&p.exec(b))if(w.length===2&&o.relative[w[0]])j=y(w[0]+w[1],d,f);else{j=o.relative[w[0]]?[d]:m(w.shift(),d);while(w.length)b=w.shift(),o.relative[b]&&(b+=w.shift()),j=y(b,j,f)}else{!f&&w.length>1&&d.nodeType===9&&!v&&o.match.ID.test(w[0])&&!o.match.ID.test(w[w.length-1])&&(n=m.find(w.shift(),d,v),d=n.expr?m.filter(n.expr,n.set)[0]:n.set[0]);if(d){n=f?{expr:w.pop(),set:s(f)}:m.find(w.pop(),w.length===1&&(w[0]==="~"||w[0]==="+")&&d.parentNode?d.parentNode:d,v),j=n.expr?m.filter(n.expr,n.set):n.set,w.length>0?k=s(j):u=!1;while(w.length)q=w.pop(),r=q,o.relative[q]?r=w.pop():q="",r==null&&(r=d),o.relative[q](k,r,v)}else k=w=[]}k||(k=j),k||m.error(q||b);if(g.call(k)==="[object Array]")if(!u)e.push.apply(e,k);else if(d&&d.nodeType===1)for(t=0;k[t]!=null;t++)k[t]&&(k[t]===!0||k[t].nodeType===1&&m.contains(d,k[t]))&&e.push(j[t]);else for(t=0;k[t]!=null;t++)k[t]&&k[t].nodeType===1&&e.push(j[t]);else s(k,e);l&&(m(l,h,e,f),m.uniqueSort(e));return e};m.uniqueSort=function(a){if(u){h=i,a.sort(u);if(h)for(var b=1;b<a.length;b++)a[b]===a[b-1]&&a.splice(b--,1)}return a},m.matches=function(a,b){return m(a,null,null,b)},m.matchesSelector=function(a,b){return m(b,null,null,[a]).length>0},m.find=function(a,b,c){var d,e,f,g,h,i;if(!a)return[];for(e=0,f=o.order.length;e<f;e++){h=o.order[e];if(g=o.leftMatch[h].exec(a)){i=g[1],g.splice(1,1);if(i.substr(i.length-1)!=="\\"){g[1]=(g[1]||"").replace(j,""),d=o.find[h](g,b,c);if(d!=null){a=a.replace(o.match[h],"");break}}}}d||(d=typeof b.getElementsByTagName!="undefined"?b.getElementsByTagName("*"):[]);return{set:d,expr:a}},m.filter=function(a,c,d,e){var f,g,h,i,j,k,l,n,p,q=a,r=[],s=c,t=c&&c[0]&&m.isXML(c[0]);while(a&&c.length){for(h in o.filter)if((f=o.leftMatch[h].exec(a))!=null&&f[2]){k=o.filter[h],l=f[1],g=!1,f.splice(1,1);if(l.substr(l.length-1)==="\\")continue;s===r&&(r=[]);if(o.preFilter[h]){f=o.preFilter[h](f,s,d,r,e,t);if(!f)g=i=!0;else if(f===!0)continue}if(f)for(n=0;(j=s[n])!=null;n++)j&&(i=k(j,f,n,s),p=e^i,d&&i!=null?p?g=!0:s[n]=!1:p&&(r.push(j),g=!0));if(i!==b){d||(s=r),a=a.replace(o.match[h],"");if(!g)return[];break}}if(a===q)if(g==null)m.error(a);else break;q=a}return s},m.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)};var n=m.getText=function(a){var b,c,d=a.nodeType,e="";if(d){if(d===1||d===9){if(typeof a.textContent=="string")return a.textContent;if(typeof a.innerText=="string")return a.innerText.replace(k,"");for(a=a.firstChild;a;a=a.nextSibling)e+=n(a)}else if(d===3||d===4)return a.nodeValue}else for(b=0;c=a[b];b++)c.nodeType!==8&&(e+=n(c));return e},o=m.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(?:(['"])(.*?)\3|(#?(?:[\w\u00c0-\uFFFF\-]|\\.)*)|)|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\(\s*(even|odd|(?:[+\-]?\d+|(?:[+\-]?\d*)?n\s*(?:[+\-]\s*\d+)?))\s*\))?/,POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(a){return a.getAttribute("href")},type:function(a){return a.getAttribute("type")}},relative:{"+":function(a,b){var c=typeof b=="string",d=c&&!l.test(b),e=c&&!d;d&&(b=b.toLowerCase());for(var f=0,g=a.length,h;f<g;f++)if(h=a[f]){while((h=h.previousSibling)&&h.nodeType!==1);a[f]=e||h&&h.nodeName.toLowerCase()===b?h||!1:h===b}e&&m.filter(b,a,!0)},">":function(a,b){var c,d=typeof b=="string",e=0,f=a.length;if(d&&!l.test(b)){b=b.toLowerCase();for(;e<f;e++){c=a[e];if(c){var g=c.parentNode;a[e]=g.nodeName.toLowerCase()===b?g:!1}}}else{for(;e<f;e++)c=a[e],c&&(a[e]=d?c.parentNode:c.parentNode===b);d&&m.filter(b,a,!0)}},"":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("parentNode",b,f,a,d,c)},"~":function(a,b,c){var d,f=e++,g=x;typeof b=="string"&&!l.test(b)&&(b=b.toLowerCase(),d=b,g=w),g("previousSibling",b,f,a,d,c)}},find:{ID:function(a,b,c){if(typeof b.getElementById!="undefined"&&!c){var d=b.getElementById(a[1]);return d&&d.parentNode?[d]:[]}},NAME:function(a,b){if(typeof b.getElementsByName!="undefined"){var c=[],d=b.getElementsByName(a[1]);for(var e=0,f=d.length;e<f;e++)d[e].getAttribute("name")===a[1]&&c.push(d[e]);return c.length===0?null:c}},TAG:function(a,b){if(typeof b.getElementsByTagName!="undefined")return b.getElementsByTagName(a[1])}},preFilter:{CLASS:function(a,b,c,d,e,f){a=" "+a[1].replace(j,"")+" ";if(f)return a;for(var g=0,h;(h=b[g])!=null;g++)h&&(e^(h.className&&(" "+h.className+" ").replace(/[\t\n\r]/g," ").indexOf(a)>=0)?c||d.push(h):c&&(b[g]=!1));return!1},ID:function(a){return a[1].replace(j,"")},TAG:function(a,b){return a[1].replace(j,"").toLowerCase()},CHILD:function(a){if(a[1]==="nth"){a[2]||m.error(a[0]),a[2]=a[2].replace(/^\+|\s*/g,"");var b=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(a[2]==="even"&&"2n"||a[2]==="odd"&&"2n+1"||!/\D/.test(a[2])&&"0n+"+a[2]||a[2]);a[2]=b[1]+(b[2]||1)-0,a[3]=b[3]-0}else a[2]&&m.error(a[0]);a[0]=e++;return a},ATTR:function(a,b,c,d,e,f){var g=a[1]=a[1].replace(j,"");!f&&o.attrMap[g]&&(a[1]=o.attrMap[g]),a[4]=(a[4]||a[5]||"").replace(j,""),a[2]==="~="&&(a[4]=" "+a[4]+" ");return a},PSEUDO:function(b,c,d,e,f){if(b[1]==="not")if((a.exec(b[3])||"").length>1||/^\w/.test(b[3]))b[3]=m(b[3],null,null,c);else{var g=m.filter(b[3],c,d,!0^f);d||e.push.apply(e,g);return!1}else if(o.match.POS.test(b[0])||o.match.CHILD.test(b[0]))return!0;return b},POS:function(a){a.unshift(!0);return a}},filters:{enabled:function(a){return a.disabled===!1&&a.type!=="hidden"},disabled:function(a){return a.disabled===!0},checked:function(a){return a.checked===!0},selected:function(a){a.parentNode&&a.parentNode.selectedIndex;return a.selected===!0},parent:function(a){return!!a.firstChild},empty:function(a){return!a.firstChild},has:function(a,b,c){return!!m(c[3],a).length},header:function(a){return/h\d/i.test(a.nodeName)},text:function(a){var b=a.getAttribute("type"),c=a.type;return a.nodeName.toLowerCase()==="input"&&"text"===c&&(b===c||b===null)},radio:function(a){return a.nodeName.toLowerCase()==="input"&&"radio"===a.type},checkbox:function(a){return a.nodeName.toLowerCase()==="input"&&"checkbox"===a.type},file:function(a){return a.nodeName.toLowerCase()==="input"&&"file"===a.type},password:function(a){return a.nodeName.toLowerCase()==="input"&&"password"===a.type},submit:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"submit"===a.type},image:function(a){return a.nodeName.toLowerCase()==="input"&&"image"===a.type},reset:function(a){var b=a.nodeName.toLowerCase();return(b==="input"||b==="button")&&"reset"===a.type},button:function(a){var b=a.nodeName.toLowerCase();return b==="input"&&"button"===a.type||b==="button"},input:function(a){return/input|select|textarea|button/i.test(a.nodeName)},focus:function(a){return a===a.ownerDocument.activeElement}},setFilters:{first:function(a,b){return b===0},last:function(a,b,c,d){return b===d.length-1},even:function(a,b){return b%2===0},odd:function(a,b){return b%2===1},lt:function(a,b,c){return b<c[3]-0},gt:function(a,b,c){return b>c[3]-0},nth:function(a,b,c){return c[3]-0===b},eq:function(a,b,c){return c[3]-0===b}},filter:{PSEUDO:function(a,b,c,d){var e=b[1],f=o.filters[e];if(f)return f(a,c,b,d);if(e==="contains")return(a.textContent||a.innerText||n([a])||"").indexOf(b[3])>=0;if(e==="not"){var g=b[3];for(var h=0,i=g.length;h<i;h++)if(g[h]===a)return!1;return!0}m.error(e)},CHILD:function(a,b){var c,e,f,g,h,i,j,k=b[1],l=a;switch(k){case"only":case"first":while(l=l.previousSibling)if(l.nodeType===1)return!1;if(k==="first")return!0;l=a;case"last":while(l=l.nextSibling)if(l.nodeType===1)return!1;return!0;case"nth":c=b[2],e=b[3];if(c===1&&e===0)return!0;f=b[0],g=a.parentNode;if(g&&(g[d]!==f||!a.nodeIndex)){i=0;for(l=g.firstChild;l;l=l.nextSibling)l.nodeType===1&&(l.nodeIndex=++i);g[d]=f}j=a.nodeIndex-e;return c===0?j===0:j%c===0&&j/c>=0}},ID:function(a,b){return a.nodeType===1&&a.getAttribute("id")===b},TAG:function(a,b){return b==="*"&&a.nodeType===1||!!a.nodeName&&a.nodeName.toLowerCase()===b},CLASS:function(a,b){return(" "+(a.className||a.getAttribute("class"))+" ").indexOf(b)>-1},ATTR:function(a,b){var c=b[1],d=m.attr?m.attr(a,c):o.attrHandle[c]?o.attrHandle[c](a):a[c]!=null?a[c]:a.getAttribute(c),e=d+"",f=b[2],g=b[4];return d==null?f==="!=":!f&&m.attr?d!=null:f==="="?e===g:f==="*="?e.indexOf(g)>=0:f==="~="?(" "+e+" ").indexOf(g)>=0:g?f==="!="?e!==g:f==="^="?e.indexOf(g)===0:f==="$="?e.substr(e.length-g.length)===g:f==="|="?e===g||e.substr(0,g.length+1)===g+"-":!1:e&&d!==!1},POS:function(a,b,c,d){var e=b[2],f=o.setFilters[e];if(f)return f(a,c,b,d)}}},p=o.match.POS,q=function(a,b){return"\\"+(b-0+1)};for(var r in o.match)o.match[r]=new RegExp(o.match[r].source+/(?![^\[]*\])(?![^\(]*\))/.source),o.leftMatch[r]=new RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[r].source.replace(/\\(\d+)/g,q));var s=function(a,b){a=Array.prototype.slice.call(a,0);if(b){b.push.apply(b,a);return b}return a};try{Array.prototype.slice.call(c.documentElement.childNodes,0)[0].nodeType}catch(t){s=function(a,b){var c=0,d=b||[];if(g.call(a)==="[object Array]")Array.prototype.push.apply(d,a);else if(typeof a.length=="number")for(var e=a.length;c<e;c++)d.push(a[c]);else for(;a[c];c++)d.push(a[c]);return d}}var u,v;c.documentElement.compareDocumentPosition?u=function(a,b){if(a===b){h=!0;return 0}if(!a.compareDocumentPosition||!b.compareDocumentPosition)return a.compareDocumentPosition?-1:1;return a.compareDocumentPosition(b)&4?-1:1}:(u=function(a,b){if(a===b){h=!0;return 0}if(a.sourceIndex&&b.sourceIndex)return a.sourceIndex-b.sourceIndex;var c,d,e=[],f=[],g=a.parentNode,i=b.parentNode,j=g;if(g===i)return v(a,b);if(!g)return-1;if(!i)return 1;while(j)e.unshift(j),j=j.parentNode;j=i;while(j)f.unshift(j),j=j.parentNode;c=e.length,d=f.length;for(var k=0;k<c&&k<d;k++)if(e[k]!==f[k])return v(e[k],f[k]);return k===c?v(a,f[k],-1):v(e[k],b,1)},v=function(a,b,c){if(a===b)return c;var d=a.nextSibling;while(d){if(d===b)return-1;d=d.nextSibling}return 1}),function(){var a=c.createElement("div"),d="script"+(new Date).getTime(),e=c.documentElement;a.innerHTML="<a name='"+d+"'/>",e.insertBefore(a,e.firstChild),c.getElementById(d)&&(o.find.ID=function(a,c,d){if(typeof c.getElementById!="undefined"&&!d){var e=c.getElementById(a[1]);return e?e.id===a[1]||typeof e.getAttributeNode!="undefined"&&e.getAttributeNode("id").nodeValue===a[1]?[e]:b:[]}},o.filter.ID=function(a,b){var c=typeof a.getAttributeNode!="undefined"&&a.getAttributeNode("id");return a.nodeType===1&&c&&c.nodeValue===b}),e.removeChild(a),e=a=null}(),function(){var a=c.createElement("div");a.appendChild(c.createComment("")),a.getElementsByTagName("*").length>0&&(o.find.TAG=function(a,b){var c=b.getElementsByTagName(a[1]);if(a[1]==="*"){var d=[];for(var e=0;c[e];e++)c[e].nodeType===1&&d.push(c[e]);c=d}return c}),a.innerHTML="<a href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!="undefined"&&a.firstChild.getAttribute("href")!=="#"&&(o.attrHandle.href=function(a){return a.getAttribute("href",2)}),a=null}(),c.querySelectorAll&&function(){var a=m,b=c.createElement("div"),d="__sizzle__";b.innerHTML="<p class='TEST'></p>";if(!b.querySelectorAll||b.querySelectorAll(".TEST").length!==0){m=function(b,e,f,g){e=e||c;if(!g&&!m.isXML(e)){var h=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(b);if(h&&(e.nodeType===1||e.nodeType===9)){if(h[1])return s(e.getElementsByTagName(b),f);if(h[2]&&o.find.CLASS&&e.getElementsByClassName)return s(e.getElementsByClassName(h[2]),f)}if(e.nodeType===9){if(b==="body"&&e.body)return s([e.body],f);if(h&&h[3]){var i=e.getElementById(h[3]);if(!i||!i.parentNode)return s([],f);if(i.id===h[3])return s([i],f)}try{return s(e.querySelectorAll(b),f)}catch(j){}}else if(e.nodeType===1&&e.nodeName.toLowerCase()!=="object"){var k=e,l=e.getAttribute("id"),n=l||d,p=e.parentNode,q=/^\s*[+~]/.test(b);l?n=n.replace(/'/g,"\\$&"):e.setAttribute("id",n),q&&p&&(e=e.parentNode);try{if(!q||p)return s(e.querySelectorAll("[id='"+n+"'] "+b),f)}catch(r){}finally{l||k.removeAttribute("id")}}}return a(b,e,f,g)};for(var e in a)m[e]=a[e];b=null}}(),function(){var a=c.documentElement,b=a.matchesSelector||a.mozMatchesSelector||a.webkitMatchesSelector||a.msMatchesSelector;if(b){var d=!b.call(c.createElement("div"),"div"),e=!1;try{b.call(c.documentElement,"[test!='']:sizzle")}catch(f){e=!0}m.matchesSelector=function(a,c){c=c.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!m.isXML(a))try{if(e||!o.match.PSEUDO.test(c)&&!/!=/.test(c)){var f=b.call(a,c);if(f||!d||a.document&&a.document.nodeType!==11)return f}}catch(g){}return m(c,null,null,[a]).length>0}}}(),function(){var a=c.createElement("div");a.innerHTML="<div class='test e'></div><div class='test'></div>";if(!!a.getElementsByClassName&&a.getElementsByClassName("e").length!==0){a.lastChild.className="e";if(a.getElementsByClassName("e").length===1)return;o.order.splice(1,0,"CLASS"),o.find.CLASS=function(a,b,c){if(typeof b.getElementsByClassName!="undefined"&&!c)return b.getElementsByClassName(a[1])},a=null}}(),c.documentElement.contains?m.contains=function(a,b){return a!==b&&(a.contains?a.contains(b):!0)}:c.documentElement.compareDocumentPosition?m.contains=function(a,b){return!!(a.compareDocumentPosition(b)&16)}:m.contains=function(){return!1},m.isXML=function(a){var b=(a?a.ownerDocument||a:0).documentElement;return b?b.nodeName!=="HTML":!1};var y=function(a,b,c){var d,e=[],f="",g=b.nodeType?[b]:b;while(d=o.match.PSEUDO.exec(a))f+=d[0],a=a.replace(o.match.PSEUDO,"");a=o.relative[a]?a+"*":a;for(var h=0,i=g.length;h<i;h++)m(a,g[h],e,c);return m.filter(f,e)};m.attr=f.attr,m.selectors.attrMap={},f.find=m,f.expr=m.selectors,f.expr[":"]=f.expr.filters,f.unique=m.uniqueSort,f.text=m.getText,f.isXMLDoc=m.isXML,f.contains=m.contains}();var L=/Until$/,M=/^(?:parents|prevUntil|prevAll)/,N=/,/,O=/^.[^:#\[\.,]*$/,P=Array.prototype.slice,Q=f.expr.match.POS,R={children:!0,contents:!0,next:!0,prev:!0};f.fn.extend({find:function(a){var b=this,c,d;if(typeof a!="string")return f(a).filter(function(){for(c=0,d=b.length;c<d;c++)if(f.contains(b[c],this))return!0});var e=this.pushStack("","find",a),g,h,i;for(c=0,d=this.length;c<d;c++){g=e.length,f.find(a,this[c],e);if(c>0)for(h=g;h<e.length;h++)for(i=0;i<g;i++)if(e[i]===e[h]){e.splice(h--,1);break}}return e},has:function(a){var b=f(a);return this.filter(function(){for(var a=0,c=b.length;a<c;a++)if(f.contains(this,b[a]))return!0})},not:function(a){return this.pushStack(T(this,a,!1),"not",a)},filter:function(a){return this.pushStack(T(this,a,!0),"filter",a)},is:function(a){return!!a&&(typeof a=="string"?Q.test(a)?f(a,this.context).index(this[0])>=0:f.filter(a,this).length>0:this.filter(a).length>0)},closest:function(a,b){var c=[],d,e,g=this[0];if(f.isArray(a)){var h=1;while(g&&g.ownerDocument&&g!==b){for(d=0;d<a.length;d++)f(g).is(a[d])&&c.push({selector:a[d],elem:g,level:h});g=g.parentNode,h++}return c}var i=Q.test(a)||typeof a!="string"?f(a,b||this.context):0;for(d=0,e=this.length;d<e;d++){g=this[d];while(g){if(i?i.index(g)>-1:f.find.matchesSelector(g,a)){c.push(g);break}g=g.parentNode;if(!g||!g.ownerDocument||g===b||g.nodeType===11)break}}c=c.length>1?f.unique(c):c;return this.pushStack(c,"closest",a)},index:function(a){if(!a)return this[0]&&this[0].parentNode?this.prevAll().length:-1;if(typeof a=="string")return f.inArray(this[0],f(a));return f.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var c=typeof a=="string"?f(a,b):f.makeArray(a&&a.nodeType?[a]:a),d=f.merge(this.get(),c);return this.pushStack(S(c[0])||S(d[0])?d:f.unique(d))},andSelf:function(){return this.add(this.prevObject)}}),f.each({parent:function(a){var b=a.parentNode;return b&&b.nodeType!==11?b:null},parents:function(a){return f.dir(a,"parentNode")},parentsUntil:function(a,b,c){return f.dir(a,"parentNode",c)},next:function(a){return f.nth(a,2,"nextSibling")},prev:function(a){return f.nth(a,2,"previousSibling")},nextAll:function(a){return f.dir(a,"nextSibling")},prevAll:function(a){return f.dir(a,"previousSibling")},nextUntil:function(a,b,c){return f.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return f.dir(a,"previousSibling",c)},siblings:function(a){return f.sibling(a.parentNode.firstChild,a)},children:function(a){return f.sibling(a.firstChild)},contents:function(a){return f.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:f.makeArray(a.childNodes)}},function(a,b){f.fn[a]=function(c,d){var e=f.map(this,b,c);L.test(a)||(d=c),d&&typeof d=="string"&&(e=f.filter(d,e)),e=this.length>1&&!R[a]?f.unique(e):e,(this.length>1||N.test(d))&&M.test(a)&&(e=e.reverse());return this.pushStack(e,a,P.call(arguments).join(","))}}),f.extend({filter:function(a,b,c){c&&(a=":not("+a+")");return b.length===1?f.find.matchesSelector(b[0],a)?[b[0]]:[]:f.find.matches(a,b)},dir:function(a,c,d){var e=[],g=a[c];while(g&&g.nodeType!==9&&(d===b||g.nodeType!==1||!f(g).is(d)))g.nodeType===1&&e.push(g),g=g[c];return e},nth:function(a,b,c,d){b=b||1;var e=0;for(;a;a=a[c])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){var c=[];for(;a;a=a.nextSibling)a.nodeType===1&&a!==b&&c.push(a);return c}});var V="abbr|article|aside|audio|canvas|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",W=/ jQuery\d+="(?:\d+|null)"/g,X=/^\s+/,Y=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Z=/<([\w:]+)/,$=/<tbody/i,_=/<|&#?\w+;/,ba=/<(?:script|style)/i,bb=/<(?:script|object|embed|option|style)/i,bc=new RegExp("<(?:"+V+")","i"),bd=/checked\s*(?:[^=]|=\s*.checked.)/i,be=/\/(java|ecma)script/i,bf=/^\s*<!(?:\[CDATA\[|\-\-)/,bg={option:[1,"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]},bh=U(c);bg.optgroup=bg.option,bg.tbody=bg.tfoot=bg.colgroup=bg.caption=bg.thead,bg.th=bg.td,f.support.htmlSerialize||(bg._default=[1,"div<div>","</div>"]),f.fn.extend({text:function(a){if(f.isFunction(a))return this.each(function(b){var c=f(this);c.text(a.call(this,b,c.text()))});if(typeof a!="object"&&a!==b)return this.empty().append((this[0]&&this[0].ownerDocument||c).createTextNode(a));return f.text(this)},wrapAll:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapAll(a.call(this,b))});if(this[0]){var b=f(a,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstChild&&a.firstChild.nodeType===1)a=a.firstChild;return a}).append(this)}return this},wrapInner:function(a){if(f.isFunction(a))return this.each(function(b){f(this).wrapInner(a.call(this,b))});return this.each(function(){var b=f(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=f.isFunction(a);return this.each(function(c){f(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){f.nodeName(this,"body")||f(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,!0,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this)});if(arguments.length){var a=f.clean(arguments);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,!1,function(a){this.parentNode.insertBefore(a,this.nextSibling)});if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,f.clean(arguments));return a}},remove:function(a,b){for(var c=0,d;(d=this[c])!=null;c++)if(!a||f.filter(a,[d]).length)!b&&d.nodeType===1&&(f.cleanData(d.getElementsByTagName("*")),f.cleanData([d])),d.parentNode&&d.parentNode.removeChild(d);return this},empty:function()
+{for(var a=0,b;(b=this[a])!=null;a++){b.nodeType===1&&f.cleanData(b.getElementsByTagName("*"));while(b.firstChild)b.removeChild(b.firstChild)}return this},clone:function(a,b){a=a==null?!1:a,b=b==null?a:b;return this.map(function(){return f.clone(this,a,b)})},html:function(a){if(a===b)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(W,""):null;if(typeof a=="string"&&!ba.test(a)&&(f.support.leadingWhitespace||!X.test(a))&&!bg[(Z.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Y,"<$1></$2>");try{for(var c=0,d=this.length;c<d;c++)this[c].nodeType===1&&(f.cleanData(this[c].getElementsByTagName("*")),this[c].innerHTML=a)}catch(e){this.empty().append(a)}}else f.isFunction(a)?this.each(function(b){var c=f(this);c.html(a.call(this,b,c.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(f.isFunction(a))return this.each(function(b){var c=f(this),d=c.html();c.replaceWith(a.call(this,b,d))});typeof a!="string"&&(a=f(a).detach());return this.each(function(){var b=this.nextSibling,c=this.parentNode;f(this).remove(),b?f(b).before(a):f(c).append(a)})}return this.length?this.pushStack(f(f.isFunction(a)?a():a),"replaceWith",a):this},detach:function(a){return this.remove(a,!0)},domManip:function(a,c,d){var e,g,h,i,j=a[0],k=[];if(!f.support.checkClone&&arguments.length===3&&typeof j=="string"&&bd.test(j))return this.each(function(){f(this).domManip(a,c,d,!0)});if(f.isFunction(j))return this.each(function(e){var g=f(this);a[0]=j.call(this,e,c?g.html():b),g.domManip(a,c,d)});if(this[0]){i=j&&j.parentNode,f.support.parentNode&&i&&i.nodeType===11&&i.childNodes.length===this.length?e={fragment:i}:e=f.buildFragment(a,this,k),h=e.fragment,h.childNodes.length===1?g=h=h.firstChild:g=h.firstChild;if(g){c=c&&f.nodeName(g,"tr");for(var l=0,m=this.length,n=m-1;l<m;l++)d.call(c?bi(this[l],g):this[l],e.cacheable||m>1&&l<n?f.clone(h,!0,!0):h)}k.length&&f.each(k,bp)}return this}}),f.buildFragment=function(a,b,d){var e,g,h,i,j=a[0];b&&b[0]&&(i=b[0].ownerDocument||b[0]),i.createDocumentFragment||(i=c),a.length===1&&typeof j=="string"&&j.length<512&&i===c&&j.charAt(0)==="<"&&!bb.test(j)&&(f.support.checkClone||!bd.test(j))&&(f.support.html5Clone||!bc.test(j))&&(g=!0,h=f.fragments[j],h&&h!==1&&(e=h)),e||(e=i.createDocumentFragment(),f.clean(a,i,e,d)),g&&(f.fragments[j]=h?e:1);return{fragment:e,cacheable:g}},f.fragments={},f.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){f.fn[a]=function(c){var d=[],e=f(c),g=this.length===1&&this[0].parentNode;if(g&&g.nodeType===11&&g.childNodes.length===1&&e.length===1){e[b](this[0]);return this}for(var h=0,i=e.length;h<i;h++){var j=(h>0?this.clone(!0):this).get();f(e[h])[b](j),d=d.concat(j)}return this.pushStack(d,a,e.selector)}}),f.extend({clone:function(a,b,c){var d,e,g,h=f.support.html5Clone||!bc.test("<"+a.nodeName)?a.cloneNode(!0):bo(a);if((!f.support.noCloneEvent||!f.support.noCloneChecked)&&(a.nodeType===1||a.nodeType===11)&&!f.isXMLDoc(a)){bk(a,h),d=bl(a),e=bl(h);for(g=0;d[g];++g)e[g]&&bk(d[g],e[g])}if(b){bj(a,h);if(c){d=bl(a),e=bl(h);for(g=0;d[g];++g)bj(d[g],e[g])}}d=e=null;return h},clean:function(a,b,d,e){var g;b=b||c,typeof b.createElement=="undefined"&&(b=b.ownerDocument||b[0]&&b[0].ownerDocument||c);var h=[],i;for(var j=0,k;(k=a[j])!=null;j++){typeof k=="number"&&(k+="");if(!k)continue;if(typeof k=="string")if(!_.test(k))k=b.createTextNode(k);else{k=k.replace(Y,"<$1></$2>");var l=(Z.exec(k)||["",""])[1].toLowerCase(),m=bg[l]||bg._default,n=m[0],o=b.createElement("div");b===c?bh.appendChild(o):U(b).appendChild(o),o.innerHTML=m[1]+k+m[2];while(n--)o=o.lastChild;if(!f.support.tbody){var p=$.test(k),q=l==="table"&&!p?o.firstChild&&o.firstChild.childNodes:m[1]==="<table>"&&!p?o.childNodes:[];for(i=q.length-1;i>=0;--i)f.nodeName(q[i],"tbody")&&!q[i].childNodes.length&&q[i].parentNode.removeChild(q[i])}!f.support.leadingWhitespace&&X.test(k)&&o.insertBefore(b.createTextNode(X.exec(k)[0]),o.firstChild),k=o.childNodes}var r;if(!f.support.appendChecked)if(k[0]&&typeof (r=k.length)=="number")for(i=0;i<r;i++)bn(k[i]);else bn(k);k.nodeType?h.push(k):h=f.merge(h,k)}if(d){g=function(a){return!a.type||be.test(a.type)};for(j=0;h[j];j++)if(e&&f.nodeName(h[j],"script")&&(!h[j].type||h[j].type.toLowerCase()==="text/javascript"))e.push(h[j].parentNode?h[j].parentNode.removeChild(h[j]):h[j]);else{if(h[j].nodeType===1){var s=f.grep(h[j].getElementsByTagName("script"),g);h.splice.apply(h,[j+1,0].concat(s))}d.appendChild(h[j])}}return h},cleanData:function(a){var b,c,d=f.cache,e=f.event.special,g=f.support.deleteExpando;for(var h=0,i;(i=a[h])!=null;h++){if(i.nodeName&&f.noData[i.nodeName.toLowerCase()])continue;c=i[f.expando];if(c){b=d[c];if(b&&b.events){for(var j in b.events)e[j]?f.event.remove(i,j):f.removeEvent(i,j,b.handle);b.handle&&(b.handle.elem=null)}g?delete i[f.expando]:i.removeAttribute&&i.removeAttribute(f.expando),delete d[c]}}}});var bq=/alpha\([^)]*\)/i,br=/opacity=([^)]*)/,bs=/([A-Z]|^ms)/g,bt=/^-?\d+(?:px)?$/i,bu=/^-?\d/,bv=/^([\-+])=([\-+.\de]+)/,bw={position:"absolute",visibility:"hidden",display:"block"},bx=["Left","Right"],by=["Top","Bottom"],bz,bA,bB;f.fn.css=function(a,c){if(arguments.length===2&&c===b)return this;return f.access(this,a,c,!0,function(a,c,d){return d!==b?f.style(a,c,d):f.css(a,c)})},f.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=bz(a,"opacity","opacity");return c===""?"1":c}return a.style.opacity}}},cssNumber:{fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":f.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,c,d,e){if(!!a&&a.nodeType!==3&&a.nodeType!==8&&!!a.style){var g,h,i=f.camelCase(c),j=a.style,k=f.cssHooks[i];c=f.cssProps[i]||i;if(d===b){if(k&&"get"in k&&(g=k.get(a,!1,e))!==b)return g;return j[c]}h=typeof d,h==="string"&&(g=bv.exec(d))&&(d=+(g[1]+1)*+g[2]+parseFloat(f.css(a,c)),h="number");if(d==null||h==="number"&&isNaN(d))return;h==="number"&&!f.cssNumber[i]&&(d+="px");if(!k||!("set"in k)||(d=k.set(a,d))!==b)try{j[c]=d}catch(l){}}},css:function(a,c,d){var e,g;c=f.camelCase(c),g=f.cssHooks[c],c=f.cssProps[c]||c,c==="cssFloat"&&(c="float");if(g&&"get"in g&&(e=g.get(a,!0,d))!==b)return e;if(bz)return bz(a,c)},swap:function(a,b,c){var d={};for(var e in b)d[e]=a.style[e],a.style[e]=b[e];c.call(a);for(e in b)a.style[e]=d[e]}}),f.curCSS=f.css,f.each(["height","width"],function(a,b){f.cssHooks[b]={get:function(a,c,d){var e;if(c){if(a.offsetWidth!==0)return bC(a,b,d);f.swap(a,bw,function(){e=bC(a,b,d)});return e}},set:function(a,b){if(!bt.test(b))return b;b=parseFloat(b);if(b>=0)return b+"px"}}}),f.support.opacity||(f.cssHooks.opacity={get:function(a,b){return br.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var c=a.style,d=a.currentStyle,e=f.isNumeric(b)?"alpha(opacity="+b*100+")":"",g=d&&d.filter||c.filter||"";c.zoom=1;if(b>=1&&f.trim(g.replace(bq,""))===""){c.removeAttribute("filter");if(d&&!d.filter)return}c.filter=bq.test(g)?g.replace(bq,e):g+" "+e}}),f(function(){f.support.reliableMarginRight||(f.cssHooks.marginRight={get:function(a,b){var c;f.swap(a,{display:"inline-block"},function(){b?c=bz(a,"margin-right","marginRight"):c=a.style.marginRight});return c}})}),c.defaultView&&c.defaultView.getComputedStyle&&(bA=function(a,b){var c,d,e;b=b.replace(bs,"-$1").toLowerCase(),(d=a.ownerDocument.defaultView)&&(e=d.getComputedStyle(a,null))&&(c=e.getPropertyValue(b),c===""&&!f.contains(a.ownerDocument.documentElement,a)&&(c=f.style(a,b)));return c}),c.documentElement.currentStyle&&(bB=function(a,b){var c,d,e,f=a.currentStyle&&a.currentStyle[b],g=a.style;f===null&&g&&(e=g[b])&&(f=e),!bt.test(f)&&bu.test(f)&&(c=g.left,d=a.runtimeStyle&&a.runtimeStyle.left,d&&(a.runtimeStyle.left=a.currentStyle.left),g.left=b==="fontSize"?"1em":f||0,f=g.pixelLeft+"px",g.left=c,d&&(a.runtimeStyle.left=d));return f===""?"auto":f}),bz=bA||bB,f.expr&&f.expr.filters&&(f.expr.filters.hidden=function(a){var b=a.offsetWidth,c=a.offsetHeight;return b===0&&c===0||!f.support.reliableHiddenOffsets&&(a.style&&a.style.display||f.css(a,"display"))==="none"},f.expr.filters.visible=function(a){return!f.expr.filters.hidden(a)});var bD=/%20/g,bE=/\[\]$/,bF=/\r?\n/g,bG=/#.*$/,bH=/^(.*?):[ \t]*([^\r\n]*)\r?$/mg,bI=/^(?:color|date|datetime|datetime-local|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,bJ=/^(?:about|app|app\-storage|.+\-extension|file|res|widget):$/,bK=/^(?:GET|HEAD)$/,bL=/^\/\//,bM=/\?/,bN=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,bO=/^(?:select|textarea)/i,bP=/\s+/,bQ=/([?&])_=[^&]*/,bR=/^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/,bS=f.fn.load,bT={},bU={},bV,bW,bX=["*/"]+["*"];try{bV=e.href}catch(bY){bV=c.createElement("a"),bV.href="",bV=bV.href}bW=bR.exec(bV.toLowerCase())||[],f.fn.extend({load:function(a,c,d){if(typeof a!="string"&&bS)return bS.apply(this,arguments);if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var g=a.slice(e,a.length);a=a.slice(0,e)}var h="GET";c&&(f.isFunction(c)?(d=c,c=b):typeof c=="object"&&(c=f.param(c,f.ajaxSettings.traditional),h="POST"));var i=this;f.ajax({url:a,type:h,dataType:"html",data:c,complete:function(a,b,c){c=a.responseText,a.isResolved()&&(a.done(function(a){c=a}),i.html(g?f("<div>").append(c.replace(bN,"")).find(g):c)),d&&i.each(d,[c,b,a])}});return this},serialize:function(){return f.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?f.makeArray(this.elements):this}).filter(function(){return this.name&&!this.disabled&&(this.checked||bO.test(this.nodeName)||bI.test(this.type))}).map(function(a,b){var c=f(this).val();return c==null?null:f.isArray(c)?f.map(c,function(a,c){return{name:b.name,value:a.replace(bF,"\r\n")}}):{name:b.name,value:c.replace(bF,"\r\n")}}).get()}}),f.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){f.fn[b]=function(a){return this.on(b,a)}}),f.each(["get","post"],function(a,c){f[c]=function(a,d,e,g){f.isFunction(d)&&(g=g||e,e=d,d=b);return f.ajax({type:c,url:a,data:d,success:e,dataType:g})}}),f.extend({getScript:function(a,c){return f.get(a,b,c,"script")},getJSON:function(a,b,c){return f.get(a,b,c,"json")},ajaxSetup:function(a,b){b?b_(a,f.ajaxSettings):(b=a,a=f.ajaxSettings),b_(a,b);return a},ajaxSettings:{url:bV,isLocal:bJ.test(bW[1]),global:!0,type:"GET",contentType:"application/x-www-form-urlencoded",processData:!0,async:!0,accepts:{xml:"application/xml, text/xml",html:"text/html",text:"text/plain",json:"application/json, text/javascript","*":bX},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText"},converters:{"* text":a.String,"text html":!0,"text json":f.parseJSON,"text xml":f.parseXML},flatOptions:{context:!0,url:!0}},ajaxPrefilter:bZ(bT),ajaxTransport:bZ(bU),ajax:function(a,c){function w(a,c,l,m){if(s!==2){s=2,q&&clearTimeout(q),p=b,n=m||"",v.readyState=a>0?4:0;var o,r,u,w=c,x=l?cb(d,v,l):b,y,z;if(a>=200&&a<300||a===304){if(d.ifModified){if(y=v.getResponseHeader("Last-Modified"))f.lastModified[k]=y;if(z=v.getResponseHeader("Etag"))f.etag[k]=z}if(a===304)w="notmodified",o=!0;else try{r=cc(d,x),w="success",o=!0}catch(A){w="parsererror",u=A}}else{u=w;if(!w||a)w="error",a<0&&(a=0)}v.status=a,v.statusText=""+(c||w),o?h.resolveWith(e,[r,w,v]):h.rejectWith(e,[v,w,u]),v.statusCode(j),j=b,t&&g.trigger("ajax"+(o?"Success":"Error"),[v,d,o?r:u]),i.fireWith(e,[v,w]),t&&(g.trigger("ajaxComplete",[v,d]),--f.active||f.event.trigger("ajaxStop"))}}typeof a=="object"&&(c=a,a=b),c=c||{};var d=f.ajaxSetup({},c),e=d.context||d,g=e!==d&&(e.nodeType||e instanceof f)?f(e):f.event,h=f.Deferred(),i=f.Callbacks("once memory"),j=d.statusCode||{},k,l={},m={},n,o,p,q,r,s=0,t,u,v={readyState:0,setRequestHeader:function(a,b){if(!s){var c=a.toLowerCase();a=m[c]=m[c]||a,l[a]=b}return this},getAllResponseHeaders:function(){return s===2?n:null},getResponseHeader:function(a){var c;if(s===2){if(!o){o={};while(c=bH.exec(n))o[c[1].toLowerCase()]=c[2]}c=o[a.toLowerCase()]}return c===b?null:c},overrideMimeType:function(a){s||(d.mimeType=a);return this},abort:function(a){a=a||"abort",p&&p.abort(a),w(0,a);return this}};h.promise(v),v.success=v.done,v.error=v.fail,v.complete=i.add,v.statusCode=function(a){if(a){var b;if(s<2)for(b in a)j[b]=[j[b],a[b]];else b=a[v.status],v.then(b,b)}return this},d.url=((a||d.url)+"").replace(bG,"").replace(bL,bW[1]+"//"),d.dataTypes=f.trim(d.dataType||"*").toLowerCase().split(bP),d.crossDomain==null&&(r=bR.exec(d.url.toLowerCase()),d.crossDomain=!(!r||r[1]==bW[1]&&r[2]==bW[2]&&(r[3]||(r[1]==="http:"?80:443))==(bW[3]||(bW[1]==="http:"?80:443)))),d.data&&d.processData&&typeof d.data!="string"&&(d.data=f.param(d.data,d.traditional)),b$(bT,d,c,v);if(s===2)return!1;t=d.global,d.type=d.type.toUpperCase(),d.hasContent=!bK.test(d.type),t&&f.active++===0&&f.event.trigger("ajaxStart");if(!d.hasContent){d.data&&(d.url+=(bM.test(d.url)?"&":"?")+d.data,delete d.data),k=d.url;if(d.cache===!1){var x=f.now(),y=d.url.replace(bQ,"$1_="+x);d.url=y+(y===d.url?(bM.test(d.url)?"&":"?")+"_="+x:"")}}(d.data&&d.hasContent&&d.contentType!==!1||c.contentType)&&v.setRequestHeader("Content-Type",d.contentType),d.ifModified&&(k=k||d.url,f.lastModified[k]&&v.setRequestHeader("If-Modified-Since",f.lastModified[k]),f.etag[k]&&v.setRequestHeader("If-None-Match",f.etag[k])),v.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+(d.dataTypes[0]!=="*"?", "+bX+"; q=0.01":""):d.accepts["*"]);for(u in d.headers)v.setRequestHeader(u,d.headers[u]);if(d.beforeSend&&(d.beforeSend.call(e,v,d)===!1||s===2)){v.abort();return!1}for(u in{success:1,error:1,complete:1})v[u](d[u]);p=b$(bU,d,c,v);if(!p)w(-1,"No Transport");else{v.readyState=1,t&&g.trigger("ajaxSend",[v,d]),d.async&&d.timeout>0&&(q=setTimeout(function(){v.abort("timeout")},d.timeout));try{s=1,p.send(l,w)}catch(z){if(s<2)w(-1,z);else throw z}}return v},param:function(a,c){var d=[],e=function(a,b){b=f.isFunction(b)?b():b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};c===b&&(c=f.ajaxSettings.traditional);if(f.isArray(a)||a.jquery&&!f.isPlainObject(a))f.each(a,function(){e(this.name,this.value)});else for(var g in a)ca(g,a[g],c,e);return d.join("&").replace(bD,"+")}}),f.extend({active:0,lastModified:{},etag:{}});var cd=f.now(),ce=/(\=)\?(&|$)|\?\?/i;f.ajaxSetup({jsonp:"callback",jsonpCallback:function(){return f.expando+"_"+cd++}}),f.ajaxPrefilter("json jsonp",function(b,c,d){var e=b.contentType==="application/x-www-form-urlencoded"&&typeof b.data=="string";if(b.dataTypes[0]==="jsonp"||b.jsonp!==!1&&(ce.test(b.url)||e&&ce.test(b.data))){var g,h=b.jsonpCallback=f.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,i=a[h],j=b.url,k=b.data,l="$1"+h+"$2";b.jsonp!==!1&&(j=j.replace(ce,l),b.url===j&&(e&&(k=k.replace(ce,l)),b.data===k&&(j+=(/\?/.test(j)?"&":"?")+b.jsonp+"="+h))),b.url=j,b.data=k,a[h]=function(a){g=[a]},d.always(function(){a[h]=i,g&&f.isFunction(i)&&a[h](g[0])}),b.converters["script json"]=function(){g||f.error(h+" was not called");return g[0]},b.dataTypes[0]="json";return"script"}}),f.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/javascript|ecmascript/},converters:{"text script":function(a){f.globalEval(a);return a}}}),f.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET",a.global=!1)}),f.ajaxTransport("script",function(a){if(a.crossDomain){var d,e=c.head||c.getElementsByTagName("head")[0]||c.documentElement;return{send:function(f,g){d=c.createElement("script"),d.async="async",a.scriptCharset&&(d.charset=a.scriptCharset),d.src=a.url,d.onload=d.onreadystatechange=function(a,c){if(c||!d.readyState||/loaded|complete/.test(d.readyState))d.onload=d.onreadystatechange=null,e&&d.parentNode&&e.removeChild(d),d=b,c||g(200,"success")},e.insertBefore(d,e.firstChild)},abort:function(){d&&d.onload(0,1)}}}});var cf=a.ActiveXObject?function(){for(var a in ch)ch[a](0,1)}:!1,cg=0,ch;f.ajaxSettings.xhr=a.ActiveXObject?function(){return!this.isLocal&&ci()||cj()}:ci,function(a){f.extend(f.support,{ajax:!!a,cors:!!a&&"withCredentials"in a})}(f.ajaxSettings.xhr()),f.support.ajax&&f.ajaxTransport(function(c){if(!c.crossDomain||f.support.cors){var d;return{send:function(e,g){var h=c.xhr(),i,j;c.username?h.open(c.type,c.url,c.async,c.username,c.password):h.open(c.type,c.url,c.async);if(c.xhrFields)for(j in c.xhrFields)h[j]=c.xhrFields[j];c.mimeType&&h.overrideMimeType&&h.overrideMimeType(c.mimeType),!c.crossDomain&&!e["X-Requested-With"]&&(e["X-Requested-With"]="XMLHttpRequest");try{for(j in e)h.setRequestHeader(j,e[j])}catch(k){}h.send(c.hasContent&&c.data||null),d=function(a,e){var j,k,l,m,n;try{if(d&&(e||h.readyState===4)){d=b,i&&(h.onreadystatechange=f.noop,cf&&delete ch[i]);if(e)h.readyState!==4&&h.abort();else{j=h.status,l=h.getAllResponseHeaders(),m={},n=h.responseXML,n&&n.documentElement&&(m.xml=n),m.text=h.responseText;try{k=h.statusText}catch(o){k=""}!j&&c.isLocal&&!c.crossDomain?j=m.text?200:404:j===1223&&(j=204)}}}catch(p){e||g(-1,p)}m&&g(j,k,m,l)},!c.async||h.readyState===4?d():(i=++cg,cf&&(ch||(ch={},f(a).unload(cf)),ch[i]=d),h.onreadystatechange=d)},abort:function(){d&&d(0,1)}}}});var ck={},cl,cm,cn=/^(?:toggle|show|hide)$/,co=/^([+\-]=)?([\d+.\-]+)([a-z%]*)$/i,cp,cq=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]],cr;f.fn.extend({show:function(a,b,c){var d,e;if(a||a===0)return this.animate(cu("show",3),a,b,c);for(var g=0,h=this.length;g<h;g++)d=this[g],d.style&&(e=d.style.display,!f._data(d,"olddisplay")&&e==="none"&&(e=d.style.display=""),e===""&&f.css(d,"display")==="none"&&f._data(d,"olddisplay",cv(d.nodeName)));for(g=0;g<h;g++){d=this[g];if(d.style){e=d.style.display;if(e===""||e==="none")d.style.display=f._data(d,"olddisplay")||""}}return this},hide:function(a,b,c){if(a||a===0)return this.animate(cu("hide",3),a,b,c);var d,e,g=0,h=this.length;for(;g<h;g++)d=this[g],d.style&&(e=f.css(d,"display"),e!=="none"&&!f._data(d,"olddisplay")&&f._data(d,"olddisplay",e));for(g=0;g<h;g++)this[g].style&&(this[g].style.display="none");return this},_toggle:f.fn.toggle,toggle:function(a,b,c){var d=typeof a=="boolean";f.isFunction(a)&&f.isFunction(b)?this._toggle.apply(this,arguments):a==null||d?this.each(function(){var b=d?a:f(this).is(":hidden");f(this)[b?"show":"hide"]()}):this.animate(cu("toggle",3),a,b,c);return this},fadeTo:function(a,b,c,d){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){function g(){e.queue===!1&&f._mark(this);var b=f.extend({},e),c=this.nodeType===1,d=c&&f(this).is(":hidden"),g,h,i,j,k,l,m,n,o;b.animatedProperties={};for(i in a){g=f.camelCase(i),i!==g&&(a[g]=a[i],delete a[i]),h=a[g],f.isArray(h)?(b.animatedProperties[g]=h[1],h=a[g]=h[0]):b.animatedProperties[g]=b.specialEasing&&b.specialEasing[g]||b.easing||"swing";if(h==="hide"&&d||h==="show"&&!d)return b.complete.call(this);c&&(g==="height"||g==="width")&&(b.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY],f.css(this,"display")==="inline"&&f.css(this,"float")==="none"&&(!f.support.inlineBlockNeedsLayout||cv(this.nodeName)==="inline"?this.style.display="inline-block":this.style.zoom=1))}b.overflow!=null&&(this.style.overflow="hidden");for(i in a)j=new f.fx(this,b,i),h=a[i],cn.test(h)?(o=f._data(this,"toggle"+i)||(h==="toggle"?d?"show":"hide":0),o?(f._data(this,"toggle"+i,o==="show"?"hide":"show"),j[o]()):j[h]()):(k=co.exec(h),l=j.cur(),k?(m=parseFloat(k[2]),n=k[3]||(f.cssNumber[i]?"":"px"),n!=="px"&&(f.style(this,i,(m||1)+n),l=(m||1)/j.cur()*l,f.style(this,i,l+n)),k[1]&&(m=(k[1]==="-="?-1:1)*m+l),j.custom(l,m,n)):j.custom(l,h,""));return!0}var e=f.speed(b,c,d);if(f.isEmptyObject(a))return this.each(e.complete,[!1]);a=f.extend({},a);return e.queue===!1?this.each(g):this.queue(e.queue,g)},stop:function(a,c,d){typeof a!="string"&&(d=c,c=a,a=b),c&&a!==!1&&this.queue(a||"fx",[]);return this.each(function(){function h(a,b,c){var e=b[c];f.removeData(a,c,!0),e.stop(d)}var b,c=!1,e=f.timers,g=f._data(this);d||f._unmark(!0,this);if(a==null)for(b in g)g[b]&&g[b].stop&&b.indexOf(".run")===b.length-4&&h(this,g,b);else g[b=a+".run"]&&g[b].stop&&h(this,g,b);for(b=e.length;b--;)e[b].elem===this&&(a==null||e[b].queue===a)&&(d?e[b](!0):e[b].saveState(),c=!0,e.splice(b,1));(!d||!c)&&f.dequeue(this,a)})}}),f.each({slideDown:cu("show",1),slideUp:cu("hide",1),slideToggle:cu("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){f.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),f.extend({speed:function(a,b,c){var d=a&&typeof a=="object"?f.extend({},a):{complete:c||!c&&b||f.isFunction(a)&&a,duration:a,easing:c&&b||b&&!f.isFunction(b)&&b};d.duration=f.fx.off?0:typeof d.duration=="number"?d.duration:d.duration in f.fx.speeds?f.fx.speeds[d.duration]:f.fx.speeds._default;if(d.queue==null||d.queue===!0)d.queue="fx";d.old=d.complete,d.complete=function(a){f.isFunction(d.old)&&d.old.call(this),d.queue?f.dequeue(this,d.queue):a!==!1&&f._unmark(this)};return d},easing:{linear:function(a,b,c,d){return c+d*a},swing:function(a,b,c,d){return(-Math.cos(a*Math.PI)/2+.5)*d+c}},timers:[],fx:function(a,b,c){this.options=b,this.elem=a,this.prop=c,b.orig=b.orig||{}}}),f.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this),(f.fx.step[this.prop]||f.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a,b=f.css(this.elem,this.prop);return isNaN(a=parseFloat(b))?!b||b==="auto"?0:b:a},custom:function(a,c,d){function h(a){return e.step(a)}var e=this,g=f.fx;this.startTime=cr||cs(),this.end=c,this.now=this.start=a,this.pos=this.state=0,this.unit=d||this.unit||(f.cssNumber[this.prop]?"":"px"),h.queue=this.options.queue,h.elem=this.elem,h.saveState=function(){e.options.hide&&f._data(e.elem,"fxshow"+e.prop)===b&&f._data(e.elem,"fxshow"+e.prop,e.start)},h()&&f.timers.push(h)&&!cp&&(cp=setInterval(g.tick,g.interval))},show:function(){var a=f._data(this.elem,"fxshow"+this.prop);this.options.orig[this.prop]=a||f.style(this.elem,this.prop),this.options.show=!0,a!==b?this.custom(this.cur(),a):this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur()),f(this.elem).show()},hide:function(){this.options.orig[this.prop]=f._data(this.elem,"fxshow"+this.prop)||f.style(this.elem,this.prop),this.options.hide=!0,this.custom(this.cur(),0)},step:function(a){var b,c,d,e=cr||cs(),g=!0,h=this.elem,i=this.options;if(a||e>=i.duration+this.startTime){this.now=this.end,this.pos=this.state=1,this.update(),i.animatedProperties[this.prop]=!0;for(b in i.animatedProperties)i.animatedProperties[b]!==!0&&(g=!1);if(g){i.overflow!=null&&!f.support.shrinkWrapBlocks&&f.each(["","X","Y"],function(a,b){h.style["overflow"+b]=i.overflow[a]}),i.hide&&f(h).hide();if(i.hide||i.show)for(b in i.animatedProperties)f.style(h,b,i.orig[b]),f.removeData(h,"fxshow"+b,!0),f.removeData(h,"toggle"+b,!0);d=i.complete,d&&(i.complete=!1,d.call(h))}return!1}i.duration==Infinity?this.now=e:(c=e-this.startTime,this.state=c/i.duration,this.pos=f.easing[i.animatedProperties[this.prop]](this.state,c,0,1,i.duration),this.now=this.start+(this.end-this.start)*this.pos),this.update();return!0}},f.extend(f.fx,{tick:function(){var a,b=f.timers,c=0;for(;c<b.length;c++)a=b[c],!a()&&b[c]===a&&b.splice(c--,1);b.length||f.fx.stop()},interval:13,stop:function(){clearInterval(cp),cp=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){f.style(a.elem,"opacity",a.now)},_default:function(a){a.elem.style&&a.elem.style[a.prop]!=null?a.elem.style[a.prop]=a.now+a.unit:a.elem[a.prop]=a.now}}}),f.each(["width","height"],function(a,b){f.fx.step[b]=function(a){f.style(a.elem,b,Math.max(0,a.now)+a.unit)}}),f.expr&&f.expr.filters&&(f.expr.filters.animated=function(a){return f.grep(f.timers,function(b){return a===b.elem}).length});var cw=/^t(?:able|d|h)$/i,cx=/^(?:body|html)$/i;"getBoundingClientRect"in c.documentElement?f.fn.offset=function(a){var b=this[0],c;if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);try{c=b.getBoundingClientRect()}catch(d){}var e=b.ownerDocument,g=e.documentElement;if(!c||!f.contains(g,b))return c?{top:c.top,left:c.left}:{top:0,left:0};var h=e.body,i=cy(e),j=g.clientTop||h.clientTop||0,k=g.clientLeft||h.clientLeft||0,l=i.pageYOffset||f.support.boxModel&&g.scrollTop||h.scrollTop,m=i.pageXOffset||f.support.boxModel&&g.scrollLeft||h.scrollLeft,n=c.top+l-j,o=c.left+m-k;return{top:n,left:o}}:f.fn.offset=function(a){var b=this[0];if(a)return this.each(function(b){f.offset.setOffset(this,a,b)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return f.offset.bodyOffset(b);var c,d=b.offsetParent,e=b,g=b.ownerDocument,h=g.documentElement,i=g.body,j=g.defaultView,k=j?j.getComputedStyle(b,null):b.currentStyle,l=b.offsetTop,m=b.offsetLeft;while((b=b.parentNode)&&b!==i&&b!==h){if(f.support.fixedPosition&&k.position==="fixed")break;c=j?j.getComputedStyle(b,null):b.currentStyle,l-=b.scrollTop,m-=b.scrollLeft,b===d&&(l+=b.offsetTop,m+=b.offsetLeft,f.support.doesNotAddBorder&&(!f.support.doesAddBorderForTableAndCells||!cw.test(b.nodeName))&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),e=d,d=b.offsetParent),f.support.subtractsBorderForOverflowNotVisible&&c.overflow!=="visible"&&(l+=parseFloat(c.borderTopWidth)||0,m+=parseFloat(c.borderLeftWidth)||0),k=c}if(k.position==="relative"||k.position==="static")l+=i.offsetTop,m+=i.offsetLeft;f.support.fixedPosition&&k.position==="fixed"&&(l+=Math.max(h.scrollTop,i.scrollTop),m+=Math.max(h.scrollLeft,i.scrollLeft));return{top:l,left:m}},f.offset={bodyOffset:function(a){var b=a.offsetTop,c=a.offsetLeft;f.support.doesNotIncludeMarginInBodyOffset&&(b+=parseFloat(f.css(a,"marginTop"))||0,c+=parseFloat(f.css(a,"marginLeft"))||0);return{top:b,left:c}},setOffset:function(a,b,c){var d=f.css(a,"position");d==="static"&&(a.style.position="relative");var e=f(a),g=e.offset(),h=f.css(a,"top"),i=f.css(a,"left"),j=(d==="absolute"||d==="fixed")&&f.inArray("auto",[h,i])>-1,k={},l={},m,n;j?(l=e.position(),m=l.top,n=l.left):(m=parseFloat(h)||0,n=parseFloat(i)||0),f.isFunction(b)&&(b=b.call(a,c,g)),b.top!=null&&(k.top=b.top-g.top+m),b.left!=null&&(k.left=b.left-g.left+n),"using"in b?b.using.call(a,k):e.css(k)}},f.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),c=this.offset(),d=cx.test(b[0].nodeName)?{top:0,left:0}:b.offset();c.top-=parseFloat(f.css(a,"marginTop"))||0,c.left-=parseFloat(f.css(a,"marginLeft"))||0,d.top+=parseFloat(f.css(b[0],"borderTopWidth"))||0,d.left+=parseFloat(f.css(b[0],"borderLeftWidth"))||0;return{top:c.top-d.top,left:c.left-d.left}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||c.body;while(a&&!cx.test(a.nodeName)&&f.css(a,"position")==="static")a=a.offsetParent;return a})}}),f.each(["Left","Top"],function(a,c){var d="scroll"+c;f.fn[d]=function(c){var e,g;if(c===b){e=this[0];if(!e)return null;g=cy(e);return g?"pageXOffset"in g?g[a?"pageYOffset":"pageXOffset"]:f.support.boxModel&&g.document.documentElement[d]||g.document.body[d]:e[d]}return this.each(function(){g=cy(this),g?g.scrollTo(a?f(g).scrollLeft():c,a?c:f(g).scrollTop()):this[d]=c})}}),f.each(["Height","Width"],function(a,c){var d=c.toLowerCase();f.fn["inner"+c]=function(){var a=this[0];return a?a.style?parseFloat(f.css(a,d,"padding")):this[d]():null},f.fn["outer"+c]=function(a){var b=this[0];return b?b.style?parseFloat(f.css(b,d,a?"margin":"border")):this[d]():null},f.fn[d]=function(a){var e=this[0];if(!e)return a==null?null:this;if(f.isFunction(a))return this.each(function(b){var c=f(this);c[d](a.call(this,b,c[d]()))});if(f.isWindow(e)){var g=e.document.documentElement["client"+c],h=e.document.body;return e.document.compatMode==="CSS1Compat"&&g||h&&h["client"+c]||g}if(e.nodeType===9)return Math.max(e.documentElement["client"+c],e.body["scroll"+c],e.documentElement["scroll"+c],e.body["offset"+c],e.documentElement["offset"+c]);if(a===b){var i=f.css(e,d),j=parseFloat(i);return f.isNumeric(j)?j:i}return this.css(d,typeof a=="string"?a:a+"px")}}),a.jQuery=a.$=f,typeof define=="function"&&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return f})})(window);
\ No newline at end of file
diff --git a/docs/source/changes.html b/docs/source/changes.html
new file mode 100644
index 0000000..966b0c9
--- /dev/null
+++ b/docs/source/changes.html
@@ -0,0 +1,70 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>DevStack - Recent Changes</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="assets/css/bootstrap.css" rel="stylesheet">
+ <link href="assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="changes.html">Changes</a></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container" id="home">
+
+ <section id="faq" class="span12">
+
+ <div class='row pull-left'>
+ <h2>Recent Changes <small>What's been happening?</small></h2>
+ <p>These are the commits to DevStack for the last six months. For the complete list see <a href="https://review.openstack.org/#/q/status:merged+project:openstack-dev/devstack,n,z">the DevStack project in Gerrit</a>.</p>
+
+ <ul class='pull-left'>
+ <!--
+ This list is generated by:
+ git log --pretty=format:' <li>%s - <em>Commit <a href="https://review.openstack.org/#q,%h,n,z">%h</a> %cd</em></li>' --date=short --since 2014-01-01 | grep -v Merge
+ -->
+ <!-- Begin git log %GIT_LOG% -->
+ <!-- End git log -->
+ </ul>
+ </div>
+
+ </section>
+
+ <footer>
+ <p>© Openstack Foundation 2011-2014 — An <a href="https://www.openstack.org/">OpenStack</a> <a href="https://wiki.openstack.org/wiki/Programs">program</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+ </body>
+</html>
diff --git a/docs/source/configuration.html b/docs/source/configuration.html
new file mode 100644
index 0000000..c26aee4
--- /dev/null
+++ b/docs/source/configuration.html
@@ -0,0 +1,243 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>DevStack - Overview</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="assets/css/bootstrap.css" rel="stylesheet">
+ <link href="assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="changes.html">Changes</a></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container" id="home">
+
+ <section id="overview" class="span12">
+
+ <div class='row pull-left'>
+ <h2>Configuration <small>Making it go my way</small></h2>
+ <p>DevStack has always tried to be mostly-functional with a minimal amount of configuration. The number of options has ballooned as projects add features, new projects added and more combinations need to be tested. Historically DevStack obtained all local configuration and customizations from a <code>localrc</code> file. The number of configuration variables that are simply passed-through to the individual project configuration files is also increasing. The old mechanism for this (<code>EXTRAS_OPTS</code> and friends) required specific code for each file and did not scale well.</p>
+ <p>In Oct 2013 a new configuration method was introduced (in <a href="https://review.openstack.org/#/c/46768/">review 46768</a>) to hopefully simplify this process and meet the following goals:</p>
+ <ul>
+ <li>contain all non-default local configuration in a single file</li>
+ <li>be backward-compatible with <code>localrc</code> to smooth the transition process</li>
+ <li>allow settings in arbitrary configuration files to be changed</li>
+ </ul>
+
+ <h3>local.conf</h3>
+ <p>The new configuration file is <code>local.conf</code> and resides in the root DevStack directory like the old <code>localrc</code> file. It is a modified INI format file that introduces a meta-section header to carry additional information regarding the configuration files to be changed.</p>
+
+ <p>The new header is similar to a normal INI section header but with two '[[ ]]' chars and two internal fields separated by a pipe ('|'):</p>
+<pre>[[ <phase> | <config-file-name> ]]
+</pre>
+
+ <p>where <code><phase></code> is one of a set of phase names defined by <code>stack.sh</code> and <code><config-file-name></code> is the configuration filename. The filename is eval'ed in the <code>stack.sh</code> context so all environment variables are available and may be used. Using the project config file variables in the header is strongly suggested (see the <code>NOVA_CONF</code> example below). If the path of the config file does not exist it is skipped.</p>
+
+ <p>The defined phases are:</p>
+ <ul>
+ <li><strong>local</strong> - extracts <code>localrc</code> from <code>local.conf</code> before <code>stackrc</code> is sourced</li>
+ <li><strong>post-config</strong> - runs after the layer 2 services are configured and before they are started</li>
+ <li><strong>extra</strong> - runs after services are started and before any files in <code>extra.d</code> are executed
+ </ul>
+
+ <p>The file is processed strictly in sequence; meta-sections may be specified more than once but if any settings are duplicated the last to appear in the file will be used.</p>
+<pre>[[post-config|$NOVA_CONF]]
+[DEFAULT]
+use_syslog = True
+
+[osapi_v3]
+enabled = False
+</pre>
+
+ <p>A specific meta-section <code>local|localrc</code> is used to
+ provide a default <code>localrc</code> file (actually
+ <code>.localrc.auto</code>). This allows all custom settings
+ for DevStack to be contained in a single file. If <code>localrc</code>
+ exists it will be used instead to preserve backward-compatibility. More
+ details on the <a href="localrc.html">contents of localrc</a> are available.</p>
+<pre>[[local|localrc]]
+FIXED_RANGE=10.254.1.0/24
+ADMIN_PASSWORD=speciale
+LOGFILE=$DEST/logs/stack.sh.log
+</pre>
+
+ <p>Note that <code>Q_PLUGIN_CONF_FILE</code> is unique in that it is assumed to <em>NOT</em> start with a <code>/</code> (slash) character. A slash will need to be added:</p>
+<pre>[[post-config|/$Q_PLUGIN_CONF_FILE]]
+</pre>
+
+ <p>The existing ``EXTRAS_OPTS`` and similar variables are now deprecated. If used a warning will be printed at the end of the <code>stack.sh</code> run.</p>
+
+ <a id="minimal"></a>
+ <h3>Minimal Configuration</h3>
+ <p>While <code>stack.sh</code> is happy to run without a <code>localrc</code> section in <code>local.conf</code>, devlife is better when there are a few minimal variables set. This is an example of a minimal configuration that touches the values that most often need to be set.</p>
+ <ul>
+ <li>no logging</li>
+ <li>pre-set the passwords to prevent interactive prompts</li>
+ <li>move network ranges away from the local network (<code>FIXED_RANGE</code> and <code>FLOATING_RANGE</code>, commented out below)</li>
+ <li>set the host IP if detection is unreliable (<code>HOST_IP</code>, commented out below)</li>
+ </ul>
+ <pre>[[local|localrc]]
+ADMIN_PASSWORD=secrete
+DATABASE_PASSWORD=$ADMIN_PASSWORD
+RABBIT_PASSWORD=$ADMIN_PASSWORD
+SERVICE_PASSWORD=$ADMIN_PASSWORD
+SERVICE_TOKEN=a682f596-76f3-11e3-b3b2-e716f9080d50
+#FIXED_RANGE=172.31.1.0/24
+#FLOATING_RANGE=192.168.20.0/25
+#HOST_IP=10.3.4.5</pre>
+ <p>If the <code>*_PASSWORD</code> variables are not set here you will be prompted to enter values for them by <code>stack.sh</code>.</p>
+ <p>The network ranges must not overlap with any networks in use on the host. Overlap is not uncommon as RFC-1918 'private' ranges are commonly used for both the local networking and Nova's fixed and floating ranges.</p>
+ <p><code>HOST_IP</code> is normally detected on the first run of <code>stack.sh</code> but often is indeterminate on later runs due to the IP being moved from an Ethernet integace to a bridge on the host. Setting it here also makes it available for <code>openrc</code> to set <code>OS_AUTH_URL</code>. <code>HOST_IP</code> is not set by default.</p>
+
+ <h3>Common Configuration Variables</h3>
+ <dl>
+ <dt>Set DevStack install directory</dt>
+ <dd><em>Default: <code>DEST=/opt/stack</code></em><br />
+ The DevStack install directory is set by the <code>DEST</code> variable. By setting it early in the <code>localrc</code> section you can reference it in later variables. It can be useful to set it even though it is not changed from the default value.
+ <pre>DEST=/opt/stack</pre></dd>
+
+ <dt>stack.sh logging</dt>
+ <dd><em>Defaults: <code>LOGFILE="" LOGDAYS=7 LOG_COLOR=True</code></em><br />
+ By default <code>stack.sh</code> output is only written to the console where is runs. It can be sent to a file in addition to the console by setting <code>LOGFILE</code> to the fully-qualified name of the destination log file. A timestamp will be appended to the given filename for each run of <code>stack.sh</code>.
+ <pre>LOGFILE=$DEST/logs/stack.sh.log</pre>
+ Old log files are cleaned automatically if <code>LOGDAYS</code> is set to the number of days of old log files to keep.
+ <pre>LOGDAYS=1</pre>
+ The some of the project logs (Nova, Cinder, etc) will be colorized by default (if <code>SYSLOG</code> is not set below); this can be turned off by setting <code>LOG_COLOR</code> False.
+ <pre>LOG_COLOR=False</pre></dd>
+
+ <dt>Screen logging</dt>
+ <dd><em>Default: <code>SCREEN_LOGDIR=""</code></em><br />
+ By default DevStack runs the OpenStack services using <code>screen</code> which is useful for watching log and debug output. However, in automated testing the interactive <code>screen</code> sessions may not be available after the fact; setting <code>SCREEN_LOGDIR</code> enables logging of the <code>screen</code> sessions in the specified diretory. There will be one file per <code>screen</code> session named for the session name and a timestamp.
+ <pre>SCREEN_LOGDIR=$DEST/logs/screen</pre>
+ <em>Note the use of <code>DEST</code> to locate the main install directory; this is why we suggest setting it in <code>local.conf</code>.</em></dd><br />
+
+ <dt>One syslog to bind them all</dt>
+ <dd><em>Default: <code>SYSLOG=False SYSLOG_HOST=$HOST_IP SYSLOG_PORT=516</code></em><br />
+ Logging all services to a single syslog can be convenient. Enable syslogging by seting <code>SYSLOG</code> to <code>True</code>. If the destination log host is not localhost <code>SYSLOG_HOST</code> and <code>SYSLOG_PORT</code> can be used to direct the message stream to the log host.
+ <pre>SYSLOG=True
+SYSLOG_HOST=$HOST_IP
+SYSLOG_PORT=516</pre></dd>
+
+ <dt>A clean install every time</dt>
+ <dd><em>Default: <code>RECLONE=""</code></em><br />
+ By default <code>stack.sh</code> only clones the project repos if they do not exist in <code>$DEST</code>. <code>stack.sh</code> will freshen each repo on each run if <code>RECLONE</code> is set to <code>yes</code>. This avoids having to manually remove repos in order to get the current branch from <code>$GIT_BASE</code>.
+ <pre>RECLONE=yes</code></dd>
+
+ <dt>Swift</dt>
+ <dd><em>Default: <code>SWIFT_HASH="" SWIFT_REPLICAS=1 SWIFT_DATA_DIR=$DEST/data/swift</code></em><br />
+ Swift is now used as the back-end for the S3-like object store. When enabled Nova's objectstore (n-obj in <code>ENABLED_SERVICES</code>) is automatically disabled. Enable Swift by adding it services to <code>ENABLED_SERVICES</code>:
+ <pre>enable_service s-proxy s-object s-container s-account</pre>
+ Setting Swift's hash value is required and you will be prompted for it if Swift is enabled so just set it to something already:
+ <pre>SWIFT_HASH=66a3d6b56c1f479c8b4e70ab5c2000f5</pre>
+ For development purposes the default number of replicas is set to <code>1</code> to reduce the overhead required. To better simulate a production deployment set this to <code>3</code> or more.
+ <pre>SWIFT_REPLICAS=3</pre>
+ The data for Swift is stored in the source tree by default
+ (in <code>$DEST/swift/data</code>) and can be moved by setting
+ <code>SWIFT_DATA_DIR</code>. The specified directory will be created if it does not exist.
+ <pre>SWIFT_DATA_DIR=$DEST/data/swift</pre>
+ <em>Note: Previously just enabling <code>swift</code> was sufficient to start the Swift services. That does not provide proper service granularity, particularly in multi-host configurations, and is considered deprecated. Some service combination tests now check for specific Swift services and the old blanket acceptance will longer work correctly.</em>
+ </dd>
+
+ <dt>Service Catalog Backend</dt>
+ <dd><em>Default: <code>KEYSTONE_CATALOG_BACKEND=sql</code></em><br />
+ DevStack uses Keystone's <code>sql</code> service catalog backend. An alternate <code>template</code> backend is also available. However, it does not support the <code>service-*</code> and <code>endpoint-*</code> commands of the <code>keystone</code> CLI. To
+ do so requires the <code>sql</code> backend be enabled:
+ <pre>KEYSTONE_CATALOG_BACKEND=template</pre>
+ DevStack's default configuration in <code>sql</code> mode is set in
+ <code>files/keystone_data.sh</code></dd>
+
+ <dt>Cinder</dt>
+ <dd><em>Default: <code>VOLUME_GROUP="stack-volumes" VOLUME_NAME_PREFIX="volume-" VOLUME_BACKING_FILE_SIZE=10250M</code></em><br />
+ The logical volume group used to hold the Cinder-managed volumes is set by <code>VOLUME_GROUP</code>, the logical volume name prefix is set with <code>VOLUME_NAME_PREFIX</code> and the size of the volume backing file is set with <code>VOLUME_BACKING_FILE_SIZE</code>.
+ <pre>VOLUME_GROUP="stack-volumes"
+VOLUME_NAME_PREFIX="volume-"
+VOLUME_BACKING_FILE_SIZE=10250M</pre></dd>
+
+ <dt>Multi-host DevStack</dt>
+ <dd><em>Default: <code>MULTI_HOST=False</code></em><br />
+ Running DevStack with multiple hosts requires a custom <code>local.conf</code> section for each host. The master is the same as a single host installation with <code>MULTI_HOST=True</code>. The slaves have fewer services enabled and a couple of host variables pointing to the master.
+ <br /><br />
+ <strong>Master</strong>
+ <pre>MULTI_HOST=True</pre>
+
+ <strong>Slave</strong>
+ <pre>MYSQL_HOST=w.x.y.z
+RABBIT_HOST=w.x.y.z
+GLANCE_HOSTPORT=w.x.y.z:9292
+ENABLED_SERVICES=n-vol,n-cpu,n-net,n-api</pre></dd>
+
+ <dt>API rate limits</dt>
+ <dd><em>Default: <code>API_RATE_LIMIT=True</code><br />
+ Integration tests such as Tempest will likely run afoul of the default rate limits configured for Nova. Turn off rate limiting during testing by setting <code>API_RATE_LIMIT=False</code>.
+ <pre>API_RATE_LIMIT=False</pre></dd>
+ </dl>
+
+ <h3>Examples</h3>
+ <ul>
+ <li>Convert EXTRA_OPTS from (<code>localrc</code>):
+<pre>EXTRA_OPTS=api_rate_limit=False
+</pre>
+ to (<code>local.conf</code>):
+<pre>[[post-config|$NOVA_CONF]]
+[DEFAULT]
+api_rate_limit = False
+</pre></li>
+ <li>Eliminate a Cinder pass-through (<code>CINDER_PERIODIC_INTERVAL</code>):
+<pre>[[post-config|$CINDER_CONF]]
+[DEFAULT]
+periodic_interval = 60
+</pre></li>
+ <li>Sample <code>local.conf</code> with screen logging enabled:
+<pre>[[local|localrc]]
+FIXED_RANGE=10.254.1.0/24
+NETWORK_GATEWAY=10.254.1.1
+LOGDAYS=1
+LOGFILE=$DEST/logs/stack.sh.log
+SCREEN_LOGDIR=$DEST/logs/screen
+ADMIN_PASSWORD=quiet
+DATABASE_PASSWORD=$ADMIN_PASSWORD
+RABBIT_PASSWORD=$ADMIN_PASSWORD
+SERVICE_PASSWORD=$ADMIN_PASSWORD
+SERVICE_TOKEN=a682f596-76f3-11e3-b3b2-e716f9080d50</pre></li>
+ </ul>
+
+ </section>
+
+ <footer>
+ <p>© Openstack Foundation 2011-2014 — An <a href="https://www.openstack.org/">OpenStack</a> <a href="https://wiki.openstack.org/wiki/Programs">program</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+ </body>
+</html>
diff --git a/docs/source/contributing.html b/docs/source/contributing.html
new file mode 100644
index 0000000..8dbd179
--- /dev/null
+++ b/docs/source/contributing.html
@@ -0,0 +1,87 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>DevStack - Overview</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="assets/css/bootstrap.css" rel="stylesheet">
+ <link href="assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="changes.html">Changes</a></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container" id="home">
+
+ <section id="overview" class="span12">
+
+ <div class='row pull-left'>
+ <h2>Contributing <small>Help us help you</small></h2>
+ <p>DevStack uses the standard OpenStack contribution process as outlined in <a href="https://wiki.openstack.org/wiki/How_To_Contribute">the OpenStack wiki 'How To Contribute'</a>. This means that you will need to meet the requirements of the Contribututors License Agreement (CLA). If you have already done that for another OpenStack project you are good to go.</p>
+
+ <h3>Things To Know</h3>
+
+ <br /><strong>Where Things Are</strong>
+ <p>The official DevStack repository is located at <code>git://github.com/openstack-dev/devstack.git</code> and <code>git://git.openstack.org/openstack-dev/devstack.git</code>, both mirrors of the official repo maintained by Gerrit.</p>
+ <p>The <a href="https://blueprints.launchpad.net/devstack">blueprint</a> and <a href="https://bugs.launchpad.net/devstack">bug trackers</a> are on Launchpad. It should be noted that DevStack generally does not use these as strongly as other projects, but we're trying to change that.</p>
+ <p>The <a href="https://review.openstack.org/#/q/project:openstack-dev/devstack,n,z">Gerrit review queue</a> is, however, used for all commits except for the text of this website. That should also change in the near future.</p>
+
+ <br /><strong>HACKING.rst</strong>
+ <p>Like most OpenStack projects, DevStack includes a <code>HACKING.rst</code> file that describes the layout, style and conventions of the project. Because <code>HACKING.rst</code> is in the main DevStack repo it is considered authoritative. Much of the content on this page is taken from there.</p>
+
+ <br /><strong>bash8 Formatting</strong>
+ <p>Around the time of the OpenStack Havana release we added a tool to do style checking in DevStack similar to what pep8/flake8 do for Python projects. It is still _very_ simplistic, focusing mostly on stray whitespace to help prevent -1 on reviews that are otherwise acceptable. Oddly enough it is called <code>bash8</code>. It will be expanded to enforce some of the documentation rules in comments that are used in formatting the script pages for devstack.org and possibly even simple code formatting. Run it on the entire project with <code>./run_tests.sh</code>.</p>
+
+ <h3>Code</h3>
+
+ <br /><strong>Repo Layout</strong>
+ <p>The DevStack repo generally keeps all of the primary scripts at the root level.</p>
+ <p><code>exercises</code> - contains the test scripts used to validate and demonstrate some OpenStack functions. These scripts know how to exit early or skip services that are not enabled.</p>
+ <p><code>extras.d</code> - contains the dispatch scripts called by the hooks in <code>stack.sh</code>, <code>unstack.sh</code> and <code>clean.sh</code>. See <a href="plugins.html">the plugins docs</a> for more information.</p>
+ <p><code>files</code> - contains a variety of otherwise lost files used in configuring and operating DevStack. This includes templates for configuration files and the system dependency information. This is also where image files are downloaded and expanded if necessary.</p>
+ <p><code>lib</code> - contains the sub-scripts specific to each project. This is where the work of managing a project's services is located. Each top-level project (Keystone, Nova, etc) has a file here. Additionally there are some for system services and project plugins.</p>
+ <p><code>samples</code> - contains a sample of the local files not included in the DevStack repo.</p>
+ <p><code>tests</code> - the DevStack test suite is rather sparse, mostly consisting of test of specific fragile functions in the <code>functions</code> file.</p>
+ <p><code>tools</code> - contains a collection of stand-alone scripts, some of which have aged a bit (does anyone still do pamdisk installs?). While these may reference the top-level DevStack configuration they can generally be run alone. There are also some sub-directories to support specific environments such as XenServer and Docker.</p>
+
+
+
+ </section>
+
+ <footer>
+ <p>© Openstack Foundation 2011-2013 — An <a href="https://wiki.openstack.org/wiki/Programs">OpenStack program</a> created by <a href="http://www.rackspace.com/cloud/private_edition/">Rackspace Cloud Builders</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+ </body>
+</html>
diff --git a/docs/source/eucarc.html b/docs/source/eucarc.html
new file mode 100644
index 0000000..df52972
--- /dev/null
+++ b/docs/source/eucarc.html
@@ -0,0 +1,94 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>DevStack - eucarc</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="assets/css/bootstrap.css" rel="stylesheet">
+ <link href="assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="../assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="../assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="changes.html">Changes</a></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+
+ <section class="span12">
+ <div class="page-header">
+ <h2>eucarc <small>EC2 settings</small></h2>
+ <p><code>eucarc</code> creates EC2 credentials for the current user as
+ defined by <code>OS_TENANT_NAME:OS_USERNAME</code>.
+ <code>eucarc</code> sources <code>openrc</code> at the beginning
+ (which in turn sources <code>stackrc</code> and <code>localrc</code>)
+ in order to set credentials to create EC2 credentials in Keystone.
+ </div>
+ <dl>
+
+ <dt>EC2_URL</dt>
+ <dd>Set the EC2 url for euca2ools. The endpoint is extracted from the
+ service catalog for <code>OS_TENANT_NAME:OS_USERNAME</code>.
+ <pre>EC2_URL=$(keystone catalog --service ec2 | awk '/ publicURL / { print $4 }')</pre></dd>
+
+ <dt>S3_URL</dt>
+ <dd>Set the S3 endpoint for euca2ools. The endpoint is extracted from the
+ service catalog for <code>OS_TENANT_NAME:OS_USERNAME</code>.
+ <pre>export S3_URL=$(keystone catalog --service s3 | awk '/ publicURL / { print $4 }')</pre></dd>
+
+ <dt>EC2_ACCESS_KEY, EC2_SECRET_KEY</dt>
+ <dd>Create EC2 credentials for the current tenant:user in Keystone.
+ <pre>CREDS=$(keystone ec2-credentials-create)
+export EC2_ACCESS_KEY=$(echo "$CREDS" | awk '/ access / { print $4 }')
+export EC2_SECRET_KEY=$(echo "$CREDS" | awk '/ secret / { print $4 }')</pre></dd>
+
+ <dt>Certificates for Bundling</dt>
+ <dd>Euca2ools requires certificate files to enable bundle uploading.
+ The exercise script <code>exercises/bundle.sh</code> demonstrated
+ retrieving certificates using the Nova CLI.
+ <pre>EC2_PRIVATE_KEY=pk.pem
+EC2_CERT=cert.pem
+NOVA_CERT=cacert.pem
+EUCALYPTUS_CERT=${NOVA_CERT}</pre></dd>
+
+ </dl>
+ </section
+
+ <footer>
+ <p>© Openstack Foundation 2011-2013 — An
+ <a href="https://wiki.openstack.org/wiki/Programs">OpenStack program</a>
+ created by <a href="http://www.rackspace.com/cloud/private_edition/">Rackspace Cloud Builders</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+
+ </body>
+</html>
diff --git a/docs/source/exerciserc.html b/docs/source/exerciserc.html
new file mode 100644
index 0000000..7e4dd54
--- /dev/null
+++ b/docs/source/exerciserc.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>DevStack - exerciserc</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="assets/css/bootstrap.css" rel="stylesheet">
+ <link href="assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="../assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="../assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="changes.html">Changes</a></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+
+ <section class="span12">
+ <div class="page-header">
+ <h2>exerciserc <small>Exercise settings</small></h2>
+ <p><code>exerciserc</code> is used to configure settings for the
+ exercise scripts. The values shown below are the default values.
+ Thse can all be overridden by setting them in the <code>localrc</code>
+ section.</p>
+ </div>
+ <dl>
+
+ <dt>ACTIVE_TIMEOUT</dt>
+ <dd>Max time to wait while vm goes from build to active state
+ <pre>ACTIVE_TIMEOUT==30</pre></dd>
+
+ <dt>ASSOCIATE_TIMEOUT</dt>
+ <dd>Max time to wait for proper IP association and dis-association.
+ <pre>ASSOCIATE_TIMEOUT=15</pre></dd>
+
+ <dt>BOOT_TIMEOUT</dt>
+ <dd>Max time till the vm is bootable
+ <pre>BOOT_TIMEOUT=30</pre></dd>
+
+ <dt>RUNNING_TIMEOUT</dt>
+ <dd>Max time from run instance command until it is running
+ <pre>RUNNING_TIMEOUT=$(($BOOT_TIMEOUT + $ACTIVE_TIMEOUT))</pre></dd>
+
+ <dt>TERMINATE_TIMEOUT</dt>
+ <dd>Max time to wait for a vm to terminate
+ <pre>TERMINATE_TIMEOUT=30</pre></dd>
+
+ </dl>
+ </section
+
+ <footer>
+ <p>© Openstack Foundation 2011-2013 — An
+ <a href="https://wiki.openstack.org/wiki/Programs">OpenStack program</a>
+ created by <a href="http://www.rackspace.com/cloud/private_edition/">Rackspace Cloud Builders</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+
+ </body>
+</html>
diff --git a/docs/source/faq.html b/docs/source/faq.html
new file mode 100644
index 0000000..bfac1dc
--- /dev/null
+++ b/docs/source/faq.html
@@ -0,0 +1,169 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>DevStack - Frequently Asked Questions</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="assets/css/bootstrap.css" rel="stylesheet">
+ <link href="assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="changes.html">Changes</a></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container" id="home">
+
+ <section id="faq" class="span12">
+
+ <div class='row pull-left'>
+ <h2>FAQ: Using DevStack <small>Making to behave</small></h2>
+
+ <ul>
+ <li><a href="#general">General Questions</a></li>
+ <li><a href="#ops_conf">Operation and Configuration</a></li>
+ <li><a href="#misc">Miscellaneous</a></li>
+ </ul>
+
+ <h3><a name="general">General Questions</a></h3>
+
+ <dl class='pull-left'>
+ <dt>Q: Can I use DevStack for production?</dt>
+ <dd>A: No. We mean it. Really. DevStack makes some implementation choices that are not appropriate for production deployments. We warned you!</dd>
+
+ <dt>Q: Then why selinux in enforcing mode?</dt>
+ <dd>A: That is the default on current Fedora and RHEL releases. DevStack has (rightly so) a bad reputation for its security practices; it has always been meant as a development tool first and system integration later. This is changing as the security issues around OpenStack's use of root (for example) have been tightened and developers need to be better equipped to work in these environments. <code>stack.sh</code>'s use of root is primarily to support the activities that would be handled by packaging in "real" deployments. To remove additional protections that will be desired/required in production would be a step backward.</dd>
+
+ <dt>Q: But selinux is disabled in RHEL 6!</dt>
+ <dd>A: Today it is, yes. That is a specific exception that certain DevStack contributors fought strongly against. The primary reason it was allowed was to support using RHEL6 as the Python 2.6 test platform and that took priority time-wise. This will not be the case with RHEL 7.</dd>
+
+ <dt>Q: Why a shell script, why not chef/puppet/...</dt>
+ <dd>A: The script is meant to be read by humans (as well as ran by computers); it is the primary documentation after all. Using a recipe system requires everyone to agree and understand chef or puppet.</dd>
+
+ <dt>Q: Why not use Crowbar?</dt>
+ <dd>A: DevStack is optimized for documentation & developers. As some of us use <a href="https://github.com/dellcloudedge/crowbar">Crowbar</a> for production deployments, we hope developers documenting how they setup systems for new features supports projects like Crowbar.</dd>
+
+ <dt>Q: I'd like to help!</dt>
+ <dd>A: That isn't a question, but please do! The source for DevStack is <a href="http://github.com/openstack-dev/devstack">github</a> and bug reports go to <a href="http://bugs.launchpad.net/devstack/">LaunchPad</a>. Contributions follow the usual process as described in the <a href="http://wiki.openstack.org/HowToContribute">OpenStack wiki</a>. DevStack is not a core project but a gating project and therefore an official OpenStack project. This site is housed in the CloudBuilder's <a href="http://github.com/cloudbuilders/devstack">github</a> in the gh-pages branch.</dd>
+
+ <dt>Q: Why not use packages?</dt>
+ <dd>A: Unlike packages, DevStack leaves your cloud ready to develop - checkouts of the code and services running in screen. However, many people are doing the hard work of packaging and recipes for production deployments. We hope this script serves as a way to communicate configuration changes between developers and packagers.</dd>
+
+ <dt>Q: Why isn't $MY_FAVORITE_DISTRO supported?</dt>
+ <dd>A: DevStack is meant for developers and those who want to see how OpenStack really works. DevStack is known to run on the distro/release combinations listed in <code>README.md</code>. DevStack is only supported on releases other than those documented in <code>README.md</code> on a best-effort basis.</dd>
+
+ <dt>Q: What about Fedora/RHEL/CentOS?</dt>
+ <dd>A: Fedora and CentOS/RHEL are supported via rpm dependency files and specific checks in <code>stack.sh</code>. Support will follow the pattern set with the Ubuntu testing, i.e. only a single release of the distro will receive regular testing, others will be handled on a best-effort basis.</dd>
+
+ <dt>Q: Are there any differences between Ubuntu and Fedora support?</dt>
+ <dd>A: LXC support is not complete on Fedora; Neutron is not fully supported prior to Fedora 18 due lack of OpenVSwitch packages.</dd>
+
+ <dt>Q: How about RHEL 6?</dt>
+ <dd>A: RHEL 6 has Python 2.6 and many old modules packaged and is a challenge to support. There are a number of specific RHEL6 work-arounds in <code>stack.sh</code> to handle this. But the testing on py26 is valuable so we do it...</dd>
+ </dl>
+
+ <h3><a name="ops_conf">Operation and Configuration</a></h3>
+
+ <dl class='pull-left'>
+ <dt>Q: Can DevStack handle a multi-node installation?</dt>
+ <dd>A: Indirectly, yes. You run DevStack on each node with the appropriate configuration in <code>local.conf</code>. The primary considerations are turning off the services not required on the secondary nodes, making sure the passwords match and setting the various API URLs to the right place.</dd>
+
+ <dt>Q: How can I document the environment that DevStack is using?</dt>
+ <dd>A: DevStack includes a script (<code>tools/info.sh</code>) that gathers the versions of the relevant installed apt packages, pip packages and git repos. This is a good way to verify what Python modules are installed.</dd>
+
+ <dt>Q: How do I turn off a service that is enabled by default?</dt>
+ <dd>A: Services can be turned off by adding <code>disable_service xxx</code> to <code>local.conf</code> (using <code>n-vol</code> in this example):
+ <pre>disable_service n-vol</pre>
+ </dd>
+
+ <dt>Q: Is enabling a service that defaults to off done with the reverse of the above?</dt>
+ <dd>A: Of course!
+ <pre>enable_service qpid</pre>
+ </dd>
+
+ <dt>Q: How do I run a specific OpenStack milestone?</dt>
+ <dd>A: OpenStack milestones have tags set in the git repo. Set the appropriate tag in the <code>*_BRANCH</code> variables in <code>local.conf</code>. Swift is on its own release schedule so pick a tag in the Swift repo that is just before the milestone release. For example:
+ <pre>[[local|localrc]]
+GLANCE_BRANCH=stable/grizzly
+HORIZON_BRANCH=stable/grizzly
+KEYSTONE_BRANCH=stable/grizzly
+NOVA_BRANCH=stable/grizzly
+GLANCE_BRANCH=stable/grizzly
+NEUTRON_BRANCH=stable/grizzly
+SWIFT_BRANCH=1.10.0</pre>
+ </dd>
+<!--- this is incomplete, remove it until populating the sql catalog is complete
+ <dt>Q: How do I use the SQL catalog backend in Keystone?</dt>
+ <dd>A: Comment out the template backend lines in the <code>[catalog]</code> section of <code>keystone/etc/keystone.conf</code> and add the SQL backend config like this:
+ <pre>[catalog]
+#driver = keystone.catalog.backends.templated.TemplatedCatalog
+#template_file = ./etc/default_catalog.templates
+driver = keystone.catalog.backends.sql.Catalog</pre>
+ </dd>
+-->
+ <dt>Q: Why not use <strike><code>tools/pip-requires</code></strike><code>requirements.txt</code> to grab project dependencies?</dt>
+ <dd><strike>The majority of deployments will use packages to install OpenStack that will have distro-based packages as dependencies. DevStack installs as many of these Python packages as possible to mimic the expected production environemnt.</strike> Certain Linux distributions have a 'lack of workaround' in their Python configurations that installs vendor packaged Python modules and pip-installed modules to the SAME DIRECTORY TREE. This is causing heartache and moving us in the direction of installing more modules from PyPI than vendor packages. However, that is only being done as necessary as the packaging needs to catch up to the development cycle anyway so this is kept to a minimum.</dd>
+
+ <dt>Q: What can I do about RabbitMQ not wanting to start on my fresh new VM?</dt>
+ <dd>A: This is often caused by <code>erlang</code> not being happy with the hostname resolving to a reachable IP address. Make sure your hostname resolves to a working IP address; setting it to 127.0.0.1 in <code>/etc/hosts</code> is often good enough for a single-node installation. And in an extreme case, use <code>clean.sh</code> to eradicate it and try again.</dd>
+
+ <dt>Q: How can I set up Heat in stand-alone configuration?</dt>
+ <dd>A: Configure <code>local.conf</code> thusly:
+ <pre>[[local|localrc]]
+HEAT_STANDALONE=True
+ENABLED_SERVICES=rabbit,mysql,heat,h-api,h-api-cfn,h-api-cw,h-eng
+KEYSTONE_SERVICE_HOST=<keystone-host>
+KEYSTONE_AUTH_HOST=<keystone-host></pre>
+ </dd>
+
+ <dt>Q: Why are my configuration changes ignored?</dt>
+ <dd>A: You may have run into the package prerequisite installation timeout. <code>tools/install_prereqs.sh</code> has a timer that skips the package installation checks if it was run within the last <code>PREREQ_RERUN_HOURS</code> hours (default is 2). To override this, set <code>FORCE_PREREQ=1</code> and the package checks will never be skipped.
+ </dd>
+ </dl>
+
+ <h3><a name="misc">Miscellaneous</a></h3>
+
+ <dl class='pull-left'>
+ <dt>Q: <code>tools/fixup_stuff.sh</code> is broken and shouldn't 'fix' just one version of packages.</dt>
+ <dd>A: [Another not-a-question] No it isn't. Stuff in there is to correct problems in an environment that need to be fixed elsewhere or may/will be fixed in a future release. In the case of <code>httplib2</code> and <code>prettytable</code> specific problems with specific versions are being worked around. If later releases have those problems than we'll add them to the script. Knowing about the broken future releases is valuable rather than polling to see if it has been fixed.</dd>
+ </dl>
+ </div>
+
+ </section>
+
+ <footer>
+ <p>© Openstack Foundation 2011-2014 — An <a href="https://www.openstack.org/">OpenStack</a> <a href="https://wiki.openstack.org/wiki/Programs">program</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+ </body>
+</html>
diff --git a/docs/source/guides/multinode-lab.html b/docs/source/guides/multinode-lab.html
new file mode 100644
index 0000000..28a6585
--- /dev/null
+++ b/docs/source/guides/multinode-lab.html
@@ -0,0 +1,330 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Multi-Node Lab Server Guide - DevStack</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="../assets/css/bootstrap.css" rel="stylesheet">
+ <link href="../assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="../assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="../assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="../overview.html">Overview</a></li>
+ <li><a href="../changes.html">Changes</a></li>
+ <li><a href="../faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+
+ <section id="overview">
+ <h1>Multi-Node Lab: Serious Stuff</h1>
+ <p>Here is OpenStack in a realistic test configuration with multiple physical servers.</p>
+ </section>
+
+ <section id="prerequisites">
+ <div class="page-header">
+ <h2>Prerequisites <small>Linux & Network</small></h2>
+ </div>
+
+ <h3>Minimal Install</h3>
+ <p>You need to have a fresh install of Linux on all of your nodes. You can download the <a href="https://help.ubuntu.com/community/Installation/MinimalCD">Minimal CD</a> for Ubuntu 12.04 (only 27MB) since DevStack will download & install all the additional dependencies. The netinstall ISO is available for <a href="http://mirrors.kernel.org/fedora/releases/20/Fedora/x86_64/iso/Fedora-20-x86_64-netinst.iso">Fedora</a> and <a href="http://mirrors.kernel.org/centos/6.5/isos/x86_64/CentOS-6.5-x86_64-netinstall.iso">CentOS/RHEL</a>.</p>
+
+ <p>Install a couple of packages to bootstrap configuration:</p>
+ <pre>apt-get install -y git sudo || yum install -y git sudo</pre>
+
+ <h3>Network Configuration</h3>
+ <p>The first iteration of the lab uses OpenStack's FlatDHCP network controller so
+ only a single network will be required. It should be on its own subnet without DHCP;
+ the host IPs and floating IP pool(s) will come out of this block. This example
+ uses the following:</p>
+ <ul>
+ <li>Gateway: 192.168.42.1</li>
+ <li>Physical nodes: 192.168.42.11-192.168.42.99</li>
+ <li>Floating IPs: 192.168.42.128-192.168.42.254</li>
+ </ul>
+ <p>Configure each node with a static IP.
+ For Ubuntu edit <code>/etc/network/interfaces</code>:</p>
+
+ <pre>auto eth0
+iface eth0 inet static
+ address 192.168.42.11
+ netmask 255.255.255.0
+ gateway 192.168.42.1
+</pre>
+ <p>For Fedora and CentOS/RHEL edit
+ <code>/etc/sysconfig/network-scripts/ifcfg-eth0</code>:</p>
+
+ <pre>BOOTPROTO=static
+IPADDR=192.168.42.11
+NETMASK=255.255.255.0
+GATEWAY=192.168.42.1
+</pre>
+
+<!-- save these for the VLAN version
+ auto eth0.926
+ iface eth0.926 inet static
+ address 10.4.144.3
+ netmask 255.255.240.0
+ #gateway 10.4.144.1
+ up ifconfig eth0.926
+
+ auto eth0.605
+ iface eth0.605 inet static
+ address 172.16.103.3
+ netmask 255.255.255.0
+ #gateway 172.16.103.1
+ up ifconfig eth0.605 up
+-->
+
+ </section>
+
+ <section id="installation">
+ <div class="page-header">
+ <h2>Installation <small>shake and bake</small></h2>
+ </div>
+
+ <h3>Add the DevStack User</h3>
+ <p>OpenStack runs as a non-root user that has sudo access to root. There is nothing special
+ about the name, we'll use <code>stack</code> here. Every node must use the same name and
+ preferably uid. If you created a user during the OS install you can use it and give it
+ sudo priviledges below. Otherwise create the stack user:</p>
+ <pre>groupadd stack
+useradd -g stack -s /bin/bash -d /opt/stack -m stack</pre>
+ <p>This user will be making many changes to your system during installation and operation
+ so it needs to have sudo priviledges to root without a password:</p>
+ <pre>echo "stack ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers</pre>
+ <p>From here on use the <code>stack</code> user. <b>Logout</b> and <b>login</b> as the
+ <code>stack</code> user.</p>
+
+ <h3>Set Up Ssh</h3>
+ <p>Set up the stack user on each node with an ssh key for access:</p>
+ <pre>mkdir ~/.ssh; chmod 700 ~/.ssh
+echo "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCyYjfgyPazTvGpd8OaAvtU2utL8W6gWC4JdRS1J95GhNNfQd657yO6s1AH5KYQWktcE6FO/xNUC2reEXSGC7ezy+sGO1kj9Limv5vrvNHvF1+wts0Cmyx61D2nQw35/Qz8BvpdJANL7VwP/cFI/p3yhvx2lsnjFE3hN8xRB2LtLUopUSVdBwACOVUmH2G+2BWMJDjVINd2DPqRIA4Zhy09KJ3O1Joabr0XpQL0yt/I9x8BVHdAx6l9U0tMg9dj5+tAjZvMAFfye3PJcYwwsfJoFxC8w/SLtqlFX7Ehw++8RtvomvuipLdmWCy+T9hIkl+gHYE4cS3OIqXH7f49jdJf jesse@spacey.local" > ~/.ssh/authorized_keys</pre>
+
+ <h3>Download DevStack</h3>
+ <p>Grab the latest version of DevStack from github:</p>
+ <pre>git clone https://github.com/openstack-dev/devstack.git
+cd devstack</pre>
+
+ <p>Up to this point all of the steps apply to each node in the cluster. From here on
+ there are some differences between the cluster controller (aka 'head node') and the
+ compute nodes.</p>
+
+ <h3>Configure Cluster Controller</h3>
+ <p>The cluster controller runs all OpenStack services. Configure the cluster controller's DevStack in <code>local.conf</code>:</p>
+ <pre>[[local|localrc]]
+HOST_IP=192.168.42.11
+FLAT_INTERFACE=eth0
+FIXED_RANGE=10.4.128.0/20
+FIXED_NETWORK_SIZE=4096
+FLOATING_RANGE=192.168.42.128/25
+MULTI_HOST=1
+LOGFILE=/opt/stack/logs/stack.sh.log
+ADMIN_PASSWORD=labstack
+MYSQL_PASSWORD=supersecret
+RABBIT_PASSWORD=supersecrete
+SERVICE_PASSWORD=supersecrete
+SERVICE_TOKEN=xyzpdqlazydog</pre>
+<!-- save for vlan
+FLAT_INTERFACE=eth0.926
+-->
+
+ <p>In the multi-node configuration the first 10 or so IPs in the private subnet are usually reserved. Add this to <code>local.sh</code> to have it run after every <code>stack.sh</code> run:</p>
+ <pre>for i in `seq 2 10`; do /opt/stack/nova/bin/nova-manage fixed reserve 10.4.128.$i; done</pre>
+
+ <p>Fire up OpenStack:</p>
+ <pre>./stack.sh</pre>
+ <p>A stream of activity ensues. When complete you will see a summary of
+ <code>stack.sh</code>'s work, including the relevant URLs, accounts and passwords to poke at your
+ shiny new OpenStack. The most recent log file is available in <code>stack.sh.log</code>.</p>
+
+ <h3>Configure Compute Nodes</h3>
+ <p>The compute nodes only run the OpenStack worker services. For additional machines, create a <code>local.conf</code> with:</p>
+ <pre>HOST_IP=192.168.42.12 # change this per compute node
+FLAT_INTERFACE=eth0
+FIXED_RANGE=10.4.128.0/20
+FIXED_NETWORK_SIZE=4096
+FLOATING_RANGE=192.168.42.128/25
+MULTI_HOST=1
+LOGFILE=/opt/stack/logs/stack.sh.log
+ADMIN_PASSWORD=labstack
+MYSQL_PASSWORD=supersecret
+RABBIT_PASSWORD=supersecrete
+SERVICE_PASSWORD=supersecrete
+SERVICE_TOKEN=xyzpdqlazydog
+DATABASE_TYPE=mysql
+SERVICE_HOST=192.168.42.11
+MYSQL_HOST=192.168.42.11
+RABBIT_HOST=192.168.42.11
+GLANCE_HOSTPORT=192.168.42.11:9292
+ENABLED_SERVICES=n-cpu,n-net,n-api,c-sch,c-api,c-vol</pre>
+<!-- save for vlan
+FLAT_INTERFACE=eth0.926
+-->
+
+ <p>Fire up OpenStack:</p>
+ <pre>./stack.sh</pre>
+ <p>A stream of activity ensues. When complete you will see a summary of
+ <code>stack.sh</code>'s work, including the relevant URLs, accounts and passwords to poke at your
+ shiny new OpenStack. The most recent log file is available in <code>stack.sh.log</code>.</p>
+
+ <h3>Cleaning Up After DevStack</h3>
+ <p>Shutting down OpenStack is now as simple as running the included <code>unstack.sh</code> script:</p>
+ <pre>./unstack.sh</pre>
+
+ <p>A more aggressive cleanup can be performed using <code>clean.sh</code>. It removes certain troublesome packages and attempts to leave the system in a state where changing the database or queue manager can be reliably performed.
+ <pre>./clean.sh</pre>
+
+ <p>Sometimes running instances are not cleaned up. DevStack attempts to do this when it
+ runs but there are times it needs to still be done by hand:</p>
+ <pre>sudo rm -rf /etc/libvirt/qemu/inst*
+sudo virsh list | grep inst | awk '{print $1}' | xargs -n1 virsh destroy</pre>
+
+ </section>
+
+ <section id="options">
+ <div class="page-header">
+ <h2>Options <small>pimp your stack</small></h2>
+ </div>
+
+ <h3>Additional Users</h3>
+ <p>DevStack creates two OpenStack users (<code>admin</code> and <code>demo</code>) and two tenants (also <code>admin</code> and <code>demo</code>). <code>admin</code> is exactly what it sounds like, a priveleged administrative account that is a member of both the <code>admin</code> and <code>demo</code> tenants. <code>demo</code> is a normal user account that is only a member of the <code>demo</code> tenant. Creating additional OpenStack users can be done through the dashboard, sometimes it is easier to do them in bulk from a script, especially since they get blown away every time
+ <code>stack.sh</code> runs. The following steps are ripe for scripting:</p>
+ <pre># Get admin creds
+. openrc admin admin
+
+# List existing tenants
+keystone tenant-list
+
+# List existing users
+keystone user-list
+
+# Add a user and tenant
+NAME=bob
+PASSWORD=BigSecrete
+TENANT=$NAME
+keystone tenant-create --name=$NAME
+keystone user-create --name=$NAME --pass=$PASSWORD
+keystone user-role-add --user-id=<bob-user-id> --tenant-id=<bob-tenant-id> --role-id=<member-role-id>
+# member-role-id comes from the existing member role created by stack.sh
+# keystone role-list</pre>
+
+ <h3>Swift</h3>
+ <p>Swift requires a significant amount of resources and is disabled by default in DevStack.
+ The support in DevStack is geared toward a minimal installation but can be used for
+ testing. To implement a true multi-node test of Swift required more than DevStack provides.
+ Enabling it is as simple as enabling the <code>swift</code> service in <code>local.conf</code>:
+ <pre>enable_service swift</pre>
+
+ <p>Swift will put its data files in <code>SWIFT_DATA_DIR</code> (default <code>/opt/stack/data/swift</code>).
+ The size of the data 'partition' created (really a loop-mounted file) is set by
+ <code>SWIFT_LOOPBACK_DISK_SIZE</code>. The Swift config files are located in
+ <code>SWIFT_CONFIG_DIR</code> (default <code>/etc/swift</code>). All of these settings can be overridden in
+ (wait for it...) <code>local.conf</code>.</p>
+
+ <h3>Volumes</h3>
+ <p>DevStack will automatically use an existing LVM volume group named <code>stack-volumes</code>
+ to store cloud-created volumes. If <code>stack-volumes</code> doesn't exist, DevStack
+ will set up a 5Gb loop-mounted file to contain it. This obviously limits the
+ number and size of volumes that can be created inside OpenStack. The size can be
+ overridden by setting <code>VOLUME_BACKING_FILE_SIZE</code> in <code>local.conf</code>.</p>
+
+ <p><code>stack-volumes</code> can be pre-created on any physical volume supported by
+ Linux's LVM. The name of the volume group can be changed by setting <code>VOLUME_GROUP</code>
+ in <code>localrc</code>. <code>stack.sh</code> deletes
+ all logical volumes in <code>VOLUME_GROUP</code> that begin with
+ <code>VOLUME_NAME_PREFIX</code> as part of cleaning up from previous runs.
+ It is recommended to not use the root volume group as <code>VOLUME_GROUP</code>.</p>
+
+ <p>The details of creating the volume group depends on the server hardware involved
+ but looks something like this:</p>
+ <pre>pvcreate /dev/sdc
+vgcreate stack-volumes /dev/sdc</pre>
+
+ <h3>Syslog</h3>
+ <p>DevStack is capable of using <code>rsyslog</code> to agregate logging across the cluster.
+ It is off by default; to turn it on set <code>SYSLOG=True</code> in <code>local.conf</code>.
+ <code>SYSLOG_HOST</code> defaults to <code>HOST_IP</code>; on the compute nodes it
+ must be set to the IP of the cluster controller to send syslog output there. In the example
+ above, add this to the compute node <code>local.conf</code>:</p>
+ <pre>SYSLOG_HOST=192.168.42.11</pre>
+
+ <h3>Using Alternate Repositories/Branches</h3>
+ <p>The git repositories for all of the OpenStack services are defined in <code>stackrc</code>.
+ Since this file is a part of the DevStack package changes to it will probably be overwritten
+ as updates are applied. Every setting in <code>stackrc</code> can be redefined in
+ <code>local.conf</code>.</p>
+
+ <p>To change the repository or branch that a particular OpenStack service is created from,
+ simply change the value of <code>*_REPO</code> or <code>*_BRANCH</code> corresponding to
+ that service.</p>
+
+ <p>After making changes to the repository or branch, if <code>RECLONE</code> is not set
+ in <code>localrc</code> it may be necessary to remove the corresponding directory from
+ <code>/opt/stack</code> to force git to re-clone the repository.</p>
+
+ <p>For example, to pull Nova from a proposed release candidate in the primary Nova
+ repository:</p>
+ <pre>NOVA_BRANCH=rc-proposed</pre>
+
+ <p>To pull Glance from an experimental fork:</p>
+ <pre>GLANCE_BRANCH=try-something-big
+GLANCE_REPO=https://github.com/mcuser/glance.git</pre>
+
+ </section>
+
+ <section id="Notes">
+ <div class="page-header">
+ <h2>Notes <small>stuff you might need to know</small></h2>
+ </div>
+
+ <h3>Reset the Bridge</h3>
+ <p>How to reset the bridge configuration:</p>
+ <pre>sudo brctl delif br100 eth0.926
+sudo ip link set dev br100 down
+sudo brctl delbr br100</pre>
+<!--
+ sudo rm /etc/libvirt/qemu/*.xml
+-->
+
+ <h3>Set MySQL Password</h3>
+ <p>If you forgot to set the root password you can do this:</p>
+ <pre>mysqladmin -u root -pnova password 'supersecret'</pre>
+
+ </section>
+
+ <footer>
+ <p>© Openstack Foundation 2011-2014 — An <a href="https://www.openstack.org/">OpenStack</a> <a href="https://wiki.openstack.org/wiki/Programs">program</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+
+ </body>
+</html>
diff --git a/docs/source/guides/pxe-boot.html b/docs/source/guides/pxe-boot.html
new file mode 100644
index 0000000..4dc61a3
--- /dev/null
+++ b/docs/source/guides/pxe-boot.html
@@ -0,0 +1,147 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>PXE Boot Server Guide - DevStack</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="../assets/css/bootstrap.css" rel="stylesheet">
+ <link href="../assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="../assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="../assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="../overview.html">Overview</a></li>
+ <li><a href="../changes.html">Changes</a></li>
+ <li><a href="../faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+ <section id="overview">
+ <h1>PXE Boot Server Guide: Magic Dust for Network Boot</h1>
+ <p>Boot DevStack from a PXE server to a RAM disk.</p>
+ </section>
+
+ <section id="requirements">
+ <div class="page-header">
+ <h2>Prerequisites <small>Hardware & OpenWRT</small></h2>
+ </div>
+
+ <h3>Hardware</h3>
+ <p>The whole point of this exercise is to have a highly portable boot server, so using a small router with a USB port is the desired platform. This guide uses a Buffalo WZR-HP-G300NH as an example, but it is easily generalized for other supported platforms. See openwrt.org for more.</p>
+
+ <h3>OpenWRT</h3>
+ <p>Any recent 'Backfire' build of OpenWRT will work for the boot server project. We build from trunk and have made the images available at <a href="http://openwrt.xr7.org/openwrt">http://openwrt.xr7.org/openwrt</a>.</p>
+ </section>
+
+ <section id="installation">
+ <div class="page-header">
+ <h2>Installation <small>bit blasting</small></h2>
+ </div>
+
+ <h3>Install the Image</h3>
+ <p>This process follows <a href="http://wiki.openwrt.org/toh/buffalo/wzr-hp-g300h">the OpenWRT doc OEM Install</a> to tftp the new image onto the router. You need a computer to set up the router, we assume it is a recent Linux or OS/X installation.</p>
+ <ul>
+ <li>Get openwrt-ar71xx-wzr-hp-g300nh-squashfs-tftp.bin
+ <pre>wget http://openwrt.xr7.org/openwrt/ar71xx/openwrt-ar71xx-wzr-hp-g300nh-squashfs-tftp.bin</pre>
+ </li>
+ <li>Connect computer to LAN port 4 (closest to WAN port)</li>
+ <li>Set computer interface to IP address in the 192.168.11.2</li>
+ <li>Add static arp entry for router
+ <pre>arp -s 192.168.11.1 <mac-address></pre>
+ </li>
+ <li>Start TFTP transfer attempt
+ <pre>tftp 192.168.11.1
+binary
+rexmt 1
+timeout 60
+put openwrt-ar71xx-wzr-hp-g300nh-squashfs-tftp.bin</pre>
+ </li>
+ <li>Power on router. Router will reboot and initialize on 192.168.1.1.</li>
+ <li>Delete static arp entry for router
+ <pre>arp -d 192.168.11.1</pre>
+ </li>
+ <li>Set computer to DHCP, connect and telnet to router and set root password.</li>
+ </ul>
+
+ <h3>Configure the Router</h3>
+ <ul>
+ <li>Update <code>/etc/opkg.conf</code> to point to our repo:
+ <pre>src/gz packages http://192.168.5.13/openwrt/build/ar71xx/packages</pre>
+ </li>
+ <li>Configure anon mounts:
+ <pre>uci delete fstab.@mount[0]
+uci commit fstab
+/etc/init.d/fstab restart</pre>
+ </li>
+ <li>Reset the DHCP address range. DevStack will claim the upper
+ /25 of the router's LAN address space for floating IPs so the
+ default DHCP address range needs to be moved:
+ <pre>uci set dhcp.lan.start=65
+uci set dhcp.lan.limit=60
+uci commit dhcp</pre>
+ </li>
+ <li>Enable TFTP:
+ <pre>uci set dhcp.@dnsmasq[0].enable_tftp=1
+uci set dhcp.@dnsmasq[0].tftp_root=/mnt/sda1/tftpboot
+uci set dhcp.@dnsmasq[0].dhcp_boot=pxelinux.0
+uci commit dhcp
+/etc/init.d/dnsmasq restart</pre>
+ </li>
+ </ul>
+
+ <h3>Set Up tftpboot</h3>
+ <ul>
+ <li>Create the <code>/tmp/tftpboot</code> structure and populate it:
+ <pre>cd ~/devstack
+tools/build_pxe_boot.sh /tmp</pre>
+ This calls <code>tools/build_ramdisk.sh</code> to create a 2GB ramdisk
+ containing a complete development Oneiric OS plus the
+ OpenStack code checkouts.
+ </li>
+ <li>Copy <code>tftpboot</code> to a USB drive:
+ <pre>mount /dev/sdb1 /mnt/tmp
+rsync -a /tmp/tftpboot/ /mnt/tmp/tftpboot/
+umount /mnt/tmp</pre>
+ </li>
+ <li>Plug USB drive into router. It will be automounted and is ready to serve content.</li>
+ </ul>
+
+ <p>Now <a href="ramdisk.html">return</a> to the RAM disk Guide to kick
+ off your DevStack experience.</p>
+
+ </section>
+
+ <footer>
+ <p>© Openstack Foundation 2011-2013 — this is not an official OpenStack project...</p>
+ </footer>
+
+ </div> <!-- /container -->
+
+ </body>
+</html>
diff --git a/docs/source/guides/ramdisk.html b/docs/source/guides/ramdisk.html
new file mode 100644
index 0000000..eaef16e
--- /dev/null
+++ b/docs/source/guides/ramdisk.html
@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>RAMdisk Boot Guide - DevStack</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="../assets/css/bootstrap.css" rel="stylesheet">
+ <link href="../assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="../assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="../assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="../overview.html">Overview</a></li>
+ <li><a href="../changes.html">Changes</a></li>
+ <li><a href="../faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+ <section id="overview">
+ <h1>Stack-in-a-Box: Try before you mkfs</h1>
+ <p>Run DevStack from a RAM disk to give it a whirl before making the
+ commitment to install it. We'll cover booting from a USB drive or
+ over the network via PXE. We'll even thow in configuring a home
+ router to handle the PXE boot. You will need a minimum of 3GB
+ for both of these configurations as the RAM disk itself is 2GB.</p>
+ </section>
+
+ <section id="requirements">
+ <div class="page-header">
+ <h2>Prerequisites <small>Hardware</small></h2>
+ </div>
+
+ <h3>USB Boot</h3>
+ <p><a href="usb-boot.html">This guide</a> covers the creation of a bootable USB drive. Your
+ computer BIOS must support booting from USB.</p>
+
+ <h3>PXE Boot</h3>
+ <p><a href="pxe-boot.html">This guide</a> covers the installation of OpenWRT on a home router
+ and configuring it as a PXE server, plus the creation of the
+ boot images and PXE support files.
+ </section>
+
+ <section id="installation">
+ <div class="page-header">
+ <h2>Installation <small>bit blasting</small></h2>
+ </div>
+
+ <h3>Install DevStack</h3>
+ <p>Grab the latest version of DevStack via https:</p>
+ <pre>sudo apt-get install git -y
+git clone https://github.com/openstack-dev/devstack.git
+cd devstack</pre>
+
+ <h3>Prepare the Boot RAMdisk</h3>
+ <p>Pick your boot method and follow the guide to prepare to build
+ the RAM disk and set up the boot process:</p>
+ <ul>
+ <li><a href="usb-boot.html">USB boot</a></li>
+ <li><a href="pxe-boot.html">PXE boot</a></li>
+ </ul>
+
+ <h3>Fire It Up</h3>
+ <ul>
+ <li>Boot the computer into the RAM disk. The details will vary from
+ machine to machine but most BIOSes have a method to select the
+ boot device, often by pressing F12 during POST.</li>
+ <li>Select 'DevStack' from the Boot Menu.</li>
+ <li>Log in with the 'stack' user and 'pass' password.</li>
+ <li>Create <code>devstack/localrc</code> if you wish to change any
+ of the configuration variables. You will probably want to at
+ least set the admin login password to something memorable rather
+ than the default 20 random characters:
+ <pre>ADMIN_PASSWORD=openstack</pre>
+ </li>
+ <li>Fire up OpenStack!
+ <pre>./run.sh</pre>
+ </li>
+ <li>See the processes running in screen:
+ <pre>screen -x</pre>
+ </li>
+ <li>Connect to the dashboard at <code>http://<ip-address>/</code></li>
+ </ul>
+
+ </section>
+
+ <footer>
+ <p>© Openstack Foundation 2011-2013 — this is not an official OpenStack project...</p>
+ </footer>
+
+ </div> <!-- /container -->
+
+ </body>
+</html>
diff --git a/docs/source/guides/single-machine.html b/docs/source/guides/single-machine.html
new file mode 100644
index 0000000..2280793
--- /dev/null
+++ b/docs/source/guides/single-machine.html
@@ -0,0 +1,131 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Single Machine Guide - DevStack</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="../assets/css/bootstrap.css" rel="stylesheet">
+ <link href="../assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="../assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="../assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="../overview.html">Overview</a></li>
+ <li><a href="../changes.html">Changes</a></li>
+ <li><a href="../faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+ <section id="overview">
+ <h1>All-In-One: Dedicated Hardware</h1>
+ <p>Things are about to get real! Using OpenStack in containers or VMs is nice for kicking the tires, but doesn't compare to the feeling you get with hardware.</p>
+ </section>
+
+ <section id="prerequisites">
+ <div class="page-header">
+ <h2>Prerequisites <small>Linux & Network</small></h2>
+ </div>
+
+ <h3>Minimal Install</h3>
+ <p>You need to have a system with a fresh install of Linux. You can download the <a href="https://help.ubuntu.com/community/Installation/MinimalCD">Minimal CD</a> for Ubuntu 12.04 (only 27MB) since DevStack will download & install all the additional dependencies. The netinstall ISO is available for <a href="http://mirrors.kernel.org/fedora/releases/18/Fedora/x86_64/iso/Fedora-18-x86_64-netinst.iso">Fedora</a> and <a href="http://mirrors.kernel.org/centos/6.4/isos/x86_64/CentOS-6.4-x86_64-netinstall.iso">CentOS/RHEL</a>. You may be tempted to use a desktop distro on a laptop, it will probably work but you may need to tell Network Manager to keep its fingers off the interface(s) that OpenStack uses for bridging.</p>
+
+ <h3>Network Configuration</h3>
+ <p>Determine the network configuration on the interface used to integrate your
+ OpenStack cloud with your existing network. For example, if the IPs given out on your network
+ by DHCP are 192.168.1.X - where X is between 100 and 200 you will be able to use IPs
+ 201-254 for <b>floating ips</b>.</p>
+ <p>To make things easier later change your host to use a static IP instead of DHCP (i.e. 192.168.1.201).</p>
+ </section>
+
+ <section id="installation">
+ <div class="page-header">
+ <h2>Installation <small>shake and bake</small></h2>
+ </div>
+
+ <h3>Add your user</h3>
+ <p>We need to add a user to install DevStack. (if you created a user during install you can skip this step and just give the user sudo priviledges below)</p>
+ <pre>adduser stack</pre>
+ <p>Since this user will be making many changes to your system, it will need to have sudo priviledges:</p>
+ <pre>apt-get install sudo -y || yum install -y sudo
+echo "stack ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers</pre>
+ <p>From here on you should use the user you created. <b>Logout</b> and <b>login</b> as that user.</p>
+
+ <h3>Download DevStack</h3>
+ <p>We'll grab the latest version of DevStack via https:</p>
+ <pre>sudo apt-get install git -y || yum install -y git
+git clone https://github.com/openstack-dev/devstack.git
+cd devstack</pre>
+
+ <h3>Run DevStack</h3>
+ <p>Now to configure <code>stack.sh</code>. DevStack includes a sample in <code>devstack/samples/local.conf</code>. Create <code>local.conf</code> as shown below to do the following:</p>
+ <ul>
+ <li>Set <code>FLOATING_RANGE</code> to a range not used on the local network, i.e. 192.168.1.224/27. This configures IP addresses ending in 225-254 to be used as floating IPs.</li>
+ <li>Set <code>FIXED_RANGE</code> and <code>FIXED_NETWORK_SIZE</code> to configure the internal address space used by the instances.</li>
+ <li>Set <code>FLAT_INTERFACE</code> to the Ethernet interface that connects the host to your local network. This is the interface that should be configured with the static IP address mentioned above.</li>
+ <li>Set the administrative password. This password is used for the <b>admin</b> and <b>demo</b> accounts set up as OpenStack users.</li>
+ <li>Set the MySQL administrative password. The default here is a random hex string which is inconvenient if you need to look at the database directly for anything.</li>
+ <li>Set the RabbitMQ password.</li>
+ <li>Set the service password. This is used by the OpenStack services (Nova, Glance, etc) to authenticate with Keystone.</li>
+ </ul>
+ <p><code>local.conf</code> should look something like this:</p>
+ <pre>[[local|localrc]]
+FLOATING_RANGE=192.168.1.224/27
+FIXED_RANGE=10.11.12.0/24
+FIXED_NETWORK_SIZE=256
+FLAT_INTERFACE=eth0
+ADMIN_PASSWORD=supersecret
+MYSQL_PASSWORD=iheartdatabases
+RABBIT_PASSWORD=flopsymopsy
+SERVICE_PASSWORD=iheartksl</pre>
+
+ <p>Run DevStack:</p>
+ <pre>./stack.sh</pre>
+ <p>A seemingly endless stream of activity ensues. When complete you will see a summary of
+ <code>stack.sh</code>'s work, including the relevant URLs, accounts and passwords to poke at your
+ shiny new OpenStack.</p>
+
+ <h3>Using OpenStack</h3>
+ <p>At this point you should be able to access the dashboard from other computers on the
+ local network. In this example that would be http://192.168.1.201/ for the dashboard (aka Horizon).
+ Launch VMs and if you give them floating IPs and security group access those VMs will be accessable from other machines on your network.</p>
+
+ <p>Some examples of using the OpenStack command-line clients <code>nova</code> and <code>glance</code>
+ are in the shakedown scripts in <code>devstack/exercises</code>. <code>exercise.sh</code>
+ will run all of those scripts and report on the results.</p>
+
+ </section>
+
+ <footer>
+ <p>© Openstack Foundation 2011-2013 — An <a href="https://wiki.openstack.org/wiki/Programs">OpenStack program</a> created by <a href="http://www.rackspace.com/cloud/private_edition/">Rackspace Cloud Builders</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+
+ </body>
+</html>
diff --git a/docs/source/guides/single-vm.html b/docs/source/guides/single-vm.html
new file mode 100644
index 0000000..2f1990a
--- /dev/null
+++ b/docs/source/guides/single-vm.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>Single Machine Guide - DevStack</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="../assets/css/bootstrap.css" rel="stylesheet">
+ <link href="../assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="../assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="../assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="../overview.html">Overview</a></li>
+ <li><a href="../changes.html">Changes</a></li>
+ <li><a href="../faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+ <section id="overview">
+ <h1>Running a Cloud in a VM</h1>
+ <p>Use the cloud to build the cloud! Use your cloud to launch new versions of OpenStack
+ in about 5 minutes. When you break it, start over! The VMs launched in the cloud will
+ be slow as they are running in QEMU (emulation), but their primary use is testing
+ OpenStack development and operation. Speed not required.</p>
+ </section>
+
+ <section id="prerequisites">
+ <div class="page-header">
+ <h2>Prerequisites <small>Cloud & Image</small></h2>
+ </div>
+
+ <h3>Virtual Machine</h3>
+ <p>DevStack should run in any virtual machine running a supported Linux release. It will perform best with 2Gb or more of RAM.</p>
+
+ <h3>OpenStack Deployment & cloud-init</h3>
+ <p>If the cloud service has an image with <code>cloud-init</code> pre-installed, use it. You can
+ get one from <a href="http://uec-images.ubuntu.com">Ubuntu's Daily Build</a>
+ site if necessary. This will enable you to launch VMs with userdata that installs
+ everything at boot time. The userdata script below will install and run
+ DevStack with a minimal configuration. The use of <code>cloud-init</code>
+ is outside the scope of this document, refer to <a href"http://cloudinit.readthedocs.org/en/latest/index.html">the
+ <code>cloud-init</code> docs</a> for more information.</p>
+
+ <p>If you are directly using a hypervisor like Xen, kvm or VirtualBox you can manually kick off
+ the script below as a non-root user in a bare-bones server installation.</p>
+ </section>
+
+ <section id="requirements">
+ <div class="page-header">
+ <h2>Installation <small>shake and bake</small></h2>
+ </div>
+
+ <h3>Launching With Cloud-Init</h3>
+ <p>This cloud config grabs the latest version of DevStack via git, creates a minimal
+ <code>local.conf</code> file and kicks off <code>stack.sh</code>. It should
+ be passed as the user-data file when booting the VM.</p>
+ <pre>#cloud-config
+
+users:
+ - default
+ - name: stack
+ lock_passwd: False
+ sudo: ["ALL=(ALL) NOPASSWD:ALL\nDefaults:stack !requiretty"]
+ shell: /bin/bash
+
+write_files:
+ - content: |
+ #!/bin/sh
+ DEBIAN_FRONTEND=noninteractive sudo apt-get -qqy update || sudo yum update -qy
+ DEBIAN_FRONTEND=noninteractive sudo apt-get install -qqy git || sudo yum install -qy git
+ sudo chown stack:stack /home/stack
+ cd /home/stack
+ git clone https://github.com/openstack-dev/devstack.git
+ cd devstack
+ echo '[[local|localrc]]' > local.conf
+ echo ADMIN_PASSWORD=password >> local.conf
+ echo MYSQL_PASSWORD=password >> local.conf
+ echo RABBIT_PASSWORD=password >> local.conf
+ echo SERVICE_PASSWORD=password >> local.conf
+ echo SERVICE_TOKEN=tokentoken >> local.conf
+ ./stack.sh
+ path: /home/stack/start.sh
+ permissions: 0755
+
+runcmd:
+ - su -l stack ./start.sh</pre>
+ <p>As DevStack will refuse to run as root, this configures <code>cloud-init</code>
+ to create a non-root user and run the <code>start.sh</code> script as that user.</p>
+
+ <h3>Launching By Hand</h3>
+ <p>Using a hypervisor directly, launch the VM and either manually perform the steps in the
+ embedded shell script above or copy it into the VM.</p>
+
+ <h3>Using OpenStack</h3>
+ <p>At this point you should be able to access the dashboard. Launch VMs and if you give them floating IPs access those VMs from other machines on your network.</p>
+
+ <p>One interesting use case is for developers working on a VM on their laptop. Once
+ <code>stack.sh</code> has completed once, all of the pre-requisite packages are installed
+ in the VM and the source trees checked out. Setting <code>OFFLINE=True</code> in
+ <code>local.conf</code> enables <code>stack.sh</code> to run multiple times without an Internet
+ connection. DevStack, making hacking at the lake possible since 2012!</p>
+ </section>
+
+ <footer>
+ <p>© Openstack Foundation 2011-2014 — An <a href="https://www.openstack.org/">OpenStack</a> <a href="https://wiki.openstack.org/wiki/Programs">program</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+
+ </body>
+</html>
diff --git a/docs/source/guides/usb-boot.html b/docs/source/guides/usb-boot.html
new file mode 100644
index 0000000..75adc6f
--- /dev/null
+++ b/docs/source/guides/usb-boot.html
@@ -0,0 +1,99 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>USB Boot Server Guide - DevStack</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="../assets/css/bootstrap.css" rel="stylesheet">
+ <link href="../assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="../assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="../assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="../overview.html">Overview</a></li>
+ <li><a href="../changes.html">Changes</a></li>
+ <li><a href="../faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+ <section id="overview">
+ <h1>USB Boot: Undoable Stack Boot</h1>
+ <p>Boot DevStack from a USB disk into a RAM disk.</p>
+ </section>
+
+ <section id="requirements">
+ <div class="page-header">
+ <h2>Prerequisites</h2>
+ </div>
+
+ <h3>Hardware</h3>
+ <p>This guide covers the creation of a bootable USB drive. Your
+ computer BIOS must support booting from USB and You will want at least 3GB of
+ RAM. You also will need a USB drive of at least 2GB.</p>
+
+ <h3>Software</h3>
+ <p>Ubuntu 11.10 (Oneiric Ocelot) is required on host to create images.</p>
+ </section>
+
+ <section id="installation">
+ <div class="page-header">
+ <h2>Installation <small>bit blasting</small></h2>
+ </div>
+
+ <h3>Set Up USB Drive</h3>
+ <ul>
+ <li>Insert the USB drive into the computer. Make a note of the device name, such as
+ <code>sdb</code>. Do not mount the device.</li>
+ <li>Install the boot system:
+ <pre>tools/build_usb_boot.sh /dev/sdb1</pre>
+ <p>This calls tools/build_ramdisk.sh to create a 2GB ramdisk
+ containing a complete development Oneiric OS plus the
+ OpenStack code checkouts. It then writes a syslinux boot sector
+ to the specified device and creates <code>/syslinux</code>.</p>
+ </li>
+ <li>If desired, you may now mount the device:
+ <pre>mount /dev/sdb1 /mnt/tmp
+# foo
+umount /mnt/tmp</pre>
+ </li>
+ </ul>
+
+ <p>Now <a href="ramdisk.html">return</a> to the RAM disk Guide to kick
+ off your DevStack experience.</p>
+
+ </section>
+
+ <footer>
+ <p>© Openstack Foundation 2011-2013 — this is not an official OpenStack project...</p>
+ </footer>
+
+ </div> <!-- /container -->
+
+ </body>
+</html>
diff --git a/docs/source/index.html b/docs/source/index.html
new file mode 100644
index 0000000..71c8c98
--- /dev/null
+++ b/docs/source/index.html
@@ -0,0 +1,529 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>DevStack - Deploying OpenStack for Developers</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="assets/css/bootstrap.css" rel="stylesheet">
+ <link href="assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="changes.html">Changes</a></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container" id="home">
+
+ <div class="hero-unit">
+ <div class="pull-left">
+ <h1 id="main_header">DevStack - an OpenStack Community Production</h1>
+ <div class="sub_header">
+ <p></p>
+ <p>A documented shell script to build complete OpenStack development environments. <br /><br />
+ An OpenStack program maintained by the developer community.</p>
+ </div>
+ </div>
+ <div class="pull-left">
+ <ol id="getting_started">
+ <li id="ubuntu">Setup a fresh supported Linux installation.</li>
+ <li id="github">
+ Clone devstack from devstack.
+ <pre>git clone https://github.com/openstack-dev/devstack.git</pre>
+ </li>
+ <li id="install">
+ Deploy your OpenStack Cloud
+ <pre>cd devstack && ./stack.sh</pre>
+ </li>
+ </ol>
+ </div>
+ <div class="clear"> </div>
+ </div>
+
+
+ <section id="quickstart" class="span12">
+ <div class="page-header">
+ <h2>Quick Start <small>This ain't your first rodeo</small></h2>
+ </div>
+ <ol>
+ <li value="0">
+ <h3>Select a Linux Distribution</h3>
+ <p>Only Ubuntu 12.04 (Precise), Fedora 20 and CentOS/RHEL 6.5 are documented here. OpenStack also runs and is packaged on other flavors of Linux such as OpenSUSE and Debian.</p>
+ </li>
+ <li>
+ <h3>Install Selected OS</h3>
+ <p>In order to correctly install all the dependencies, we assume a specific minimal version of the supported distributions to make it as easy as possible. We recommend using a minimal install of Ubuntu or Fedora server in a VM if this is your first time.</p>
+ </li>
+ <li>
+ <h3>Download DevStack</h3>
+ <pre>git clone https://github.com/openstack-dev/devstack.git</pre>
+ <p>The <code>devstack</code> repo contains a script that installs OpenStack and templates for configuration files</p>
+ </li>
+ <li>
+ <h3>Configure</h3>
+ <p>While optional, we recommend a <a href="configuration.html">minimal configuration</a> be set up as you may not want our default values for everything.</p>
+ </li>
+ <li>
+ <h3>Start the install</h3>
+ <pre>cd devstack; ./stack.sh</pre>
+ <p>It takes a few minutes, we recommend <a href="stack.sh.html">reading the script</a> while it is building.</p>
+ </li>
+ </ol>
+ </section>
+
+ <section id="guides" class='span12'>
+ <div class="page-header">
+ <h2>Guides <small>Walk through various setups used by stackers</small></h2>
+ </div>
+
+ <div class='row span8'>
+ <h2>OpenStack on VMs</h2>
+ <table class='table table-striped table-bordered'>
+ <thead>
+ <tr>
+ <th>Title</th>
+ <th>Description</th>
+ <th>Link</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>Virtual Machine</td>
+ <td>Run OpenStack in a VM. The VMs launched in your cloud will be slow as they are running in QEMU (emulation), but it is useful if you don't have spare hardware laying around.</td>
+ <td><a class="btn btn-small btn-primary table-action" href="guides/single-vm.html">Read »</a></td>
+ </tr>
+
+<!--
+ <tr>
+ <td>LXC Containers</td>
+ <td>Already running Ubuntu on your machine? Using containers lets you build even faster.</td>
+ <td>Coming soon!</td>
+ </tr>
+-->
+ </tbody>
+ <tfoot>
+ <td colspan="3">1 Guide</td>
+ </tfoot>
+ </table>
+ </div>
+ <div class="wat span3 pull-right">
+ <h4>What is this?</h4>
+ <p>These guides tell you how to virtualize your OpenStack cloud in virtual machines. This means that you can get started without having to purchase any hardware.</p>
+ </div>
+
+ <div class='row span8'>
+ <h2>OpenStack on Hardware</h2>
+ <table class='table table-striped table-bordered'>
+ <thead>
+ <tr>
+ <th>Title</th>
+ <th>Description</th>
+ <th>Link</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>All-In-One</td>
+ <td>Run OpenStack on dedicated hardware to get real performance in your VMs. This can include a server-class machine or a laptop at home.</td>
+ <td><a class="btn btn-small btn-primary table-action" href="guides/single-machine.html">Read »</a></td>
+ </tr>
+
+ <tr>
+ <td>Multi-Node + VLANs</td>
+ <td>Setup a multi-node cluster with dedicated VLANs for VMs & Management.</td>
+ <td><a class="btn btn-small btn-primary table-action" href="guides/multinode-lab.html">Read »</a></td>
+ </tr>
+
+<!--
+ <tr>
+ <td>Stack-in-a-Box</td>
+ <td>Run OpenStack from a RAM disk to give it a spin without touching your existing OS installation. Includes PXE and USB boot methods.</td>
+ <td><a class="btn btn-small btn-primary table-action" href="guides/ramdisk.html">Read »</a></td>
+ </tr>
+-->
+ </tbody>
+ <tfoot>
+ <td colspan="3">2 Guides</td>
+ </tfoot>
+ </table>
+ </div>
+ <div class="wat span3 pull-right">
+ <h4>What is this?</h4>
+ <p>These guides tell you how to deploy a development environment on real hardware. Guides range from running OpenStack on a single laptop to running a multi-node deployment on datacenter hardware.</p>
+ </div>
+
+ </section>
+
+ <section id="docs" class="span12">
+ <div class="page-header">
+ <h2>Documentation <small>Help yourself to stack</small></h2>
+ </div>
+
+ <div class='row span5 pull-left'>
+ <h2>Overview</h2>
+ <p><a href="overview.html">An overview of DevStack goals and priorities</a></p>
+ <h2>Configuration</h2>
+ <p><a href="configuration.html">Configuring and customizing the stack</a></p>
+ <h2>Plugins</h2>
+ <p><a href="plugins.html">Extending DevStack with new features</a></p>
+ </div>
+
+ <div class='span5 pull-right'>
+ <h2>Recent Changes</h2>
+ <p><a href="changes.html">An incomplete summary of recent changes</a></p>
+ <h2>FAQ</h2>
+ <p><a href="faq.html">The DevStack FAQ</a></p>
+ <h2>Contributing</h2>
+ <p><a href="contributing.html">Pitching in to make DevStack a better place</a></p>
+ </div>
+
+ </section>
+
+ <section id="docs" class="span12">
+ <div class="page-header">
+ <h2>Code <small>A look at the bits that make it all go</small></h2>
+ </div>
+
+ <div class='row span5 pull-left'>
+ <h2>Scripts <small>Generated documentation of DevStack scripts.</small></h2>
+ <table class='table table-striped table-bordered'>
+ <thead>
+ <tr>
+ <th>Filename</th>
+ <th>Link</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>stack.sh</td>
+ <td><a href="stack.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>functions</td>
+ <td><a href="functions.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/apache</td>
+ <td><a href="lib/apache.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/baremetal</td>
+ <td><a href="lib/baremetal.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/ceilometer</td>
+ <td><a href="lib/ceilometer.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/cinder</td>
+ <td><a href="lib/cinder.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/config</td>
+ <td><a href="lib/config.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/database</td>
+ <td><a href="lib/database.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/glance</td>
+ <td><a href="lib/glance.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/heat</td>
+ <td><a href="lib/heat.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/horizon</td>
+ <td><a href="lib/horizon.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/infra</td>
+ <td><a href="lib/infra.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/ironic</td>
+ <td><a href="lib/ironic.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/keystone</td>
+ <td><a href="lib/keystone.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/ldap</td>
+ <td><a href="lib/ldap.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/marconi</td>
+ <td><a href="lib/marconi.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/neutron</td>
+ <td><a href="lib/neutron.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/nova</td>
+ <td><a href="lib/nova.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/oslo</td>
+ <td><a href="lib/oslo.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/rpc_backend</td>
+ <td><a href="lib/rpc_backend.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/savanna</td>
+ <td><a href="lib/savanna.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/savanna-dashboard</td>
+ <td><a href="lib/savanna-dashboard.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/stackforge</td>
+ <td><a href="lib/stackforge.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/swift</td>
+ <td><a href="lib/swift.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/tempest</td>
+ <td><a href="lib/tempest.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/tls</td>
+ <td><a href="lib/tls.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>lib/trove</td>
+ <td><a href="lib/trove.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>unstack.sh</td>
+ <td><a href="unstack.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>clean.sh</td>
+ <td><a href="clean.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>run_tests.sh</td>
+ <td><a href="run_tests.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>extras.d/70-marconi.sh</td>
+ <td><a href="extras.d/70-marconi.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>extras.d/70-savanna.sh</td>
+ <td><a href="extras.d/70-savanna.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>extras.d/80-tempest.sh</td>
+ <td><a href="extras.d/80-tempest.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>tools/info.sh</td>
+ <td><a href="tools/info.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>tools/build_docs.sh</td>
+ <td><a href="tools/build_docs.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>tools/create_userrc.sh</td>
+ <td><a href="tools/create_userrc.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>tools/fixup_stuff.sh</td>
+ <td><a href="tools/fixup_stuff.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>tools/install_prereqs.sh</td>
+ <td><a href="tools/install_prereqs.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>tools/install_pip.sh</td>
+ <td><a href="tools/install_pip.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>tools/upload_image.sh</td>
+ <td><a href="tools/upload_image.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <td colspan="3">40 bash scripts</td>
+ </tfoot>
+ </table>
+ </div>
+
+ <div class='span5 pull-right'>
+ <h2>Configuration <small>Setting the table</small></h2>
+ <table class='table table-striped table-bordered'>
+ <thead>
+ <tr>
+ <th>Filename</th>
+ <th>Link</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>local.conf</td>
+ <td><a href="local.conf.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>stackrc</td>
+ <td><a href="stackrc.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>openrc</td>
+ <td><a href="openrc.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>exerciserc</td>
+ <td><a href="exerciserc.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>eucarc</td>
+ <td><a href="eucarc.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <td colspan="3">5 configuration files</td>
+ </tfoot>
+ </table>
+
+ <h2>Samples <small>Generated documentation of DevStack sample files.</small></h2>
+ <table class='table table-striped table-bordered'>
+ <thead>
+ <tr>
+ <th>Filename</th>
+ <th>Link</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>local.sh</td>
+ <td><a href="samples/local.sh.html" class="btn btn-small btn-success table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>localrc</td>
+ <td><a href="samples/localrc.html" class="btn btn-small btn-success table-action">Read »</a></td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <td colspan="3">2 sample files</td>
+ </tfoot>
+ </table>
+
+ <div class='row span5 pull-right'>
+ <h2>Exercises <small>Generated documentation of DevStack scripts.</small></h2>
+ <table class='table table-striped table-bordered'>
+ <thead>
+ <tr>
+ <th>Filename</th>
+ <th>Link</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>exercise.sh</td>
+ <td><a href="exercise.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>exercises/aggregates.sh</td>
+ <td><a href="exercises/aggregates.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>exercises/boot_from_volume.sh</td>
+ <td><a href="exercises/boot_from_volume.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>exercises/bundle.sh</td>
+ <td><a href="exercises/bundle.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>exercises/client-args.sh</td>
+ <td><a href="exercises/client-args.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>exercises/client-env.sh</td>
+ <td><a href="exercises/client-env.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>exercises/euca.sh</td>
+ <td><a href="exercises/euca.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>exercises/floating_ips.sh</td>
+ <td><a href="exercises/floating_ips.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>exercises/horizon.sh</td>
+ <td><a href="exercises/horizon.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>exercises/neutron-adv-test.sh</td>
+ <td><a href="exercises/neutron-adv-test.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>exercises/sec_groups.sh</td>
+ <td><a href="exercises/sec_groups.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>exercises/swift.sh</td>
+ <td><a href="exercises/swift.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ <tr>
+ <td>exercises/volumes.sh</td>
+ <td><a href="exercises/volumes.sh.html" class="btn btn-small btn-primary table-action">Read »</a></td>
+ </tr>
+ </tbody>
+ <tfoot>
+ <td colspan="3">13 exercise scripts</td>
+ </tfoot>
+ </table>
+
+ </div>
+
+ </section>
+
+ <footer>
+ <p>© Openstack Foundation 2011-2014 — An <a href="https://www.openstack.org/">OpenStack</a> <a href="https://wiki.openstack.org/wiki/Programs">program</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+ </body>
+</html>
diff --git a/docs/source/local.conf.html b/docs/source/local.conf.html
new file mode 100644
index 0000000..ed53adf
--- /dev/null
+++ b/docs/source/local.conf.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>DevStack - local.conf</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="assets/css/bootstrap.css" rel="stylesheet">
+ <link href="assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="../assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="../assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="changes.html">Changes</a></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+
+ <section class="span12">
+ <div class="page-header">
+ <h2>local.conf <small>User settings</small></h2>
+ <p><code>local.conf</code> is a user-maintained setings file that is
+ sourced in <code>stackrc</code>. It contains a section that replaces
+ the historical <code>localrc</code> file. See
+ <a href="configuration.html">the description of local.conf</a> for
+ more details about the mechanics of the file.</p>
+ </div>
+ </section
+
+ <footer>
+ <p>© Openstack Foundation 2011-2014 — An <a href="https://www.openstack.org/">OpenStack</a> <a href="https://wiki.openstack.org/wiki/Programs">program</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+
+ </body>
+</html>
diff --git a/docs/source/localrc.html b/docs/source/localrc.html
new file mode 100644
index 0000000..0f669bd
--- /dev/null
+++ b/docs/source/localrc.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>DevStack - localrc</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="assets/css/bootstrap.css" rel="stylesheet">
+ <link href="assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="../assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="../assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="changes.html">Changes</a></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+
+ <section class="span12">
+ <div class="page-header">
+ <h2>localrc <small>User settings</small></h2>
+ <p><code>localrc</code> is the old file used to configure DevStack. It is deprecated and has been replaced by <a href="local.conf.html"><code>local.conf</code></a>. DevStack will continue to use <code>localrc</code> if it is present and ignore the <code>localrc</code> section in <code>local.conf.</code>. Remove <code>localrc</code> to switch to using the new file.</p>
+ </div>
+ </section
+
+ <footer>
+ <p>© Openstack Foundation 2011-2014 — An <a href="https://www.openstack.org/">OpenStack</a> <a href="https://wiki.openstack.org/wiki/Programs">program</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+
+ </body>
+</html>
diff --git a/docs/source/openrc.html b/docs/source/openrc.html
new file mode 100644
index 0000000..b84d268
--- /dev/null
+++ b/docs/source/openrc.html
@@ -0,0 +1,115 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>DevStack - openrc</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="assets/css/bootstrap.css" rel="stylesheet">
+ <link href="assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="../assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="../assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="changes.html">Changes</a></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+
+ <section class="span12">
+ <div class="page-header">
+ <h2>openrc <small>User authentication settings</small></h2>
+ <p><code>openrc</code> configures login credentials suitable for use
+ with the OpenStack command-line tools. <code>openrc</code> sources
+ <code>stackrc</code> at the beginning (which in turn sources
+ the <code>localrc</code> setion of <code>local.conf</code>) in
+ order to pick up <code>HOST_IP</code>
+ and/or <code>SERVICE_HOST</code> to use in the endpoints.
+ The values shown below are the default values.</p>
+ </div>
+ <dl>
+
+ <dt>OS_TENANT_NAME</dt>
+ <dd>The introduction of Keystone to the OpenStack ecosystem has standardized the
+ term <em>tenant</em> as the entity that owns resources. In some places references
+ still exist to the original Nova term <em>project</em> for this use. Also,
+ <em>tenant_name</em> is prefered to <em>tenant_id</em>.
+ <pre>OS_TENANT_NAME=demo</pre></dd>
+
+ <dt>OS_USERNAME</dt>
+ <dd>In addition to the owning entity (tenant), Nova stores the entity performing
+ the action as the <em>user</em>.
+ <pre>OS_USERNAME=demo</pre></dd>
+
+ <dt>OS_PASSWORD</dt>
+ <dd>With Keystone you pass the keystone password instead of an api key.
+ Recent versions of novaclient use OS_PASSWORD instead of NOVA_API_KEYs
+ or NOVA_PASSWORD.
+ <pre>OS_PASSWORD=secrete</pre></dd>
+
+ <dt>HOST_IP, SERVICE_HOST</dt>
+ <dd>Set API endpoint host using <code>HOST_IP</code>. <code>SERVICE_HOST</code>
+ may also be used to specify the endpoint, which is convenient for
+ some <code>localrc</code> configurations. Typically, <code>HOST_IP</code>
+ is set in the <code>localrc</code> section.
+ <pre>HOST_IP=127.0.0.1
+SERVICE_HOST=$HOST_IP</pre></dd>
+
+ <dt>OS_AUTH_URL</dt>
+ <dd>Authenticating against an OpenStack cloud using Keystone returns a <em>Token</em>
+ and <em>Service Catalog</em>. The catalog contains the endpoints for all services
+ the user/tenant has access to - including Nova, Glance, Keystone and Swift.
+ <pre>OS_AUTH_URL=http://$SERVICE_HOST:5000/v2.0</pre></dd>
+
+ <dt>GLANCE_HOST</dt>
+ <dd>Some exercises call Glance directly. On a single-node installation, Glance
+ should be listening on <code>HOST_IP</code>. If its running elsewhere
+ it can be set here.
+ <pre>GLANCE_HOST=$HOST_IP</pre></dd>
+
+ <dt>KEYSTONECLIENT_DEBUG, NOVACLIENT_DEBUG</dt>
+ <dd>Set command-line client log level to <code>DEBUG</code>. These are
+ commented out by default.
+ <pre># export KEYSTONECLIENT_DEBUG=1
+# export NOVACLIENT_DEBUG=1</pre></dd>
+
+ </dl>
+ </section
+
+ <footer>
+ <p>© Openstack Foundation 2011-2013 — An
+ <a href="https://wiki.openstack.org/wiki/Programs">OpenStack program</a>
+ created by <a href="http://www.rackspace.com/cloud/private_edition/">Rackspace Cloud Builders</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+
+ </body>
+</html>
diff --git a/docs/source/overview.html b/docs/source/overview.html
new file mode 100644
index 0000000..c0b6ea2
--- /dev/null
+++ b/docs/source/overview.html
@@ -0,0 +1,118 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>DevStack - Overview</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="assets/css/bootstrap.css" rel="stylesheet">
+ <link href="assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="changes.html">Changes</a></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container" id="home">
+
+ <section id="overview" class="span12">
+
+ <div class='row pull-left'>
+ <h2>Overview <small>DevStack from a cloud-height view</small></h2>
+ <p>DevStack is not and has never been intended to be a general OpenStack installer. It has evolved to support a large number of configuration options and alternative platforms and support services. However, that evolution has grown well beyond what was originally intended and the majority of configuration combinations are rarely, if ever, tested. DevStack was never meant to be everything to everyone and can not continue in that direction.</p>
+ <p>Below is a list of what is specifically is supported (read that as "tested and assumed to work") going forward.</p>
+
+ <h2>Supported Components</h2>
+
+ <h3>Base OS</h3>
+ <p><em>The OpenStack Technical Committee (TC) has defined the current CI strategy to include the latest Ubuntu release and the latest RHEL release (for Python 2.6 testing).</em></p>
+ <ul>
+ <li>Ubuntu: current LTS release plus current development release</li>
+ <li>Fedora: current release plus previous release</li>
+ <li>RHEL: current major release</li>
+ <li>Other OS platforms may continue to be included but the maintenance of those platforms shall not be assumed simply due to their presence. Having a listed point-of-contact for each additional OS will greatly increase its chance of being well-maintained.</li>
+ <li>Patches for Ubuntu and/or Fedora will not be held up due to side-effects on other OS platforms.</li>
+ </ul>
+
+ <h3>Databases</h3>
+ <p><em>As packaged by the host OS</em></p>
+ <ul>
+ <li>MySQL</li>
+ <li>PostgreSQL</li>
+ </ul>
+
+ <h3>Queues</h3>
+ <p><em>As packaged by the host OS</em></p>
+ <ul>
+ <li>Rabbit</li>
+ <li>Qpid</li>
+<!--
+ <li>ZeroMQ</li>
+-->
+ </ul>
+
+ <h3>Web Server</h3>
+ <p><em>As packaged by the host OS</em></p>
+ <ul>
+ <li>Apache</li>
+ </ul>
+
+ <h3>OpenStack Network</h3>
+ <p><em>Default to Nova Network, optionally use Neutron</em></p>
+ <ul>
+ <li>Nova Network: FlatDHCP</li>
+ <li>Neutron: A basic configuration approximating the original FlatDHCP mode using linuxbridge or OpenVSwitch.</li>
+ </ul>
+
+ <h3>Services</h3>
+ <p>The default services configured by DevStack are Identity (Keystone), Object Storage (Swift), Image Storage (Glance), Block Storage (Cinder), Compute (Nova), Network (Nova), Dashboard (Horizon)</p>
+ <p>Additional services not included directly in DevStack can be tied in to <code>stack.sh</code> using the <a href="plugins.html">plugin mechanism</a> to call scripts that perform the configuration and startup of the service.</p>
+
+ <h3>Node Configurations</h3>
+ <ul>
+ <li>single node</li>
+ <li>multi-node is not tested regularly by the core team, and even then only minimal configurations are reviewed</li>
+ </ul>
+
+ <h3>Exercises</h3>
+ <p>The DevStack exercise scripts have been replaced as integration and gating test with Tempest. They will continue to be maintained as they are valuable as demonstrations of using OpenStack from the command line and for quick operational testing.</p>
+
+ </div>
+
+ </section>
+
+ <footer>
+ <p>© Openstack Foundation 2011-2014 — An <a href="https://www.openstack.org/">OpenStack</a> <a href="https://wiki.openstack.org/wiki/Programs">program</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+ </body>
+</html>
diff --git a/docs/source/plugins.html b/docs/source/plugins.html
new file mode 100644
index 0000000..85cf8e4
--- /dev/null
+++ b/docs/source/plugins.html
@@ -0,0 +1,136 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>DevStack - Plugins</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="assets/css/bootstrap.css" rel="stylesheet">
+ <link href="assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="changes.html">Changes</a></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container" id="home">
+
+ <section id="faq" class="span12">
+
+ <div class='row pull-left'>
+ <h2>Plugins <small>Add stuff</small></h2>
+ <p>DevStack has a couple of plugin mechanisms to allow easily adding support for additional projects and features.</p>
+
+ <h3>Extras.d Hooks</h3>
+ <p>These relatively new hooks are an extension of the existing calls from <code>stack.sh</code> at the end of its run, plus <code>unstack.sh</code> and <code>clean.sh</code>. A number of the higher-layer projects are implemented in DevStack using this mechanism.</p>
+
+ <p>The script in <code>extras.d</code> is expected to be mostly a dispatcher to functions in a <code>lib/*</code> script. The scripts are named with a zero-padded two digits sequence number prefix to control the order that the scripts are called, and with a suffix of <code>.sh</code>. DevSack reserves for itself the sequence numbers 00 through 09 and 90 through 99.</p>
+
+ <p>Below is a template that shows handlers for the possible command-line arguments:</p>
+
+<pre>
+# template.sh - DevStack extras.d dispatch script template
+
+# check for service enabled
+if is_service_enabled template; then
+
+ if [[ "$1" == "source" ]]; then
+ # Initial source of lib script
+ source $TOP_DIR/lib/template
+ fi
+
+ if [[ "$1" == "stack" && "$2" == "install" ]]; then
+ # Perform installation of service source
+ echo_summary "Installing Template"
+ install_template
+
+ elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
+ # Configure after the other layer 1 and 2 services have been configured
+ echo_summary "Configuring Template"
+ configure_template
+
+ elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
+ # Initialize and start the template service
+ echo_summary "Initializing Template"
+ ##init_template
+ fi
+
+ if [[ "$1" == "unstack" ]]; then
+ # Shut down template services
+ # no-op
+ :
+ fi
+
+ if [[ "$1" == "clean" ]]; then
+ # Remove state and transient data
+ # Remember clean.sh first calls unstack.sh
+ # no-op
+ :
+ fi
+fi
+</pre>
+
+ <p>The arguments are:
+ <ul>
+ <li><strong>source</strong> - Called by each script that utilizes <code>extras.d</code> hooks; this replaces directly sourcing the <code>lib/*</code> script.</li>
+ <li><strong>stack</strong> - Called by <code>stack.sh</code> three times for different phases of its run:
+ <ul>
+ <li><strong>install</strong> - Called after the layer 1 and 2 projects source and their dependencies have been installed.</li>
+ <li><strong>post-config</strong> - Called after the layer 1 and 2 services have been configured. All configuration files for enabled services should exist at this point.</li>
+ <li><strong>extra</strong> - Called near the end after layer 1 and 2 services have been started. This is the existing hook and has not otherwise changed.</li>
+ </ul></li>
+ <li><strong>unstack</strong> - Called by <code>unstack.sh</code> before other services are shut down.</li>
+ <li><strong>clean</strong> - Called by <code>clean.sh</code> before other services are cleaned, but after <code>unstack.sh</code> has been called.
+ </ul></p>
+
+
+ <h3>Hypervisor</h3>
+ <p>Hypervisor plugins are fairly new and condense most hypervisor configuration into one place.</p>
+
+ <p>The initial plugin implemented was for Docker support and is a useful template for the required support. Plugins are placed in <code>lib/nova_plugins</code> and named <code>hypervisor-<name></code> where <code><name></code> is the value of <code>VIRT_DRIVER</code>. Plugins must define the following functions:</p>
+ <ul>
+ <li><code>install_nova_hypervisor</code> - install any external requirements</li>
+ <li><code>configure_nova_hypervisor</code> - make configuration changes, including those to other services</li>
+ <li><code>start_nova_hypervisor</code> - start any external services</li>
+ <li><code>stop_nova_hypervisor</code> - stop any external services</li>
+ <li><code>cleanup_nova_hypervisor</code> - remove transient data and cache</li>
+ </ul>
+ </div>
+
+ </section>
+
+ <footer>
+ <p>© Openstack Foundation 2011-2013 — An <a href="https://wiki.openstack.org/wiki/Programs">OpenStack program</a> created by <a href="http://www.rackspace.com/cloud/private_edition/">Rackspace Cloud Builders</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+ </body>
+</html>
diff --git a/docs/source/stackrc.html b/docs/source/stackrc.html
new file mode 100644
index 0000000..23a48c5
--- /dev/null
+++ b/docs/source/stackrc.html
@@ -0,0 +1,101 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta charset="utf-8">
+ <title>DevStack - stackrc</title>
+ <meta name="description" content="">
+ <meta name="author" content="">
+
+ <!-- Le HTML5 shim, for IE6-8 support of HTML elements -->
+ <!--[if lt IE 9]>
+ <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
+ <![endif]-->
+
+ <!-- Le styles -->
+ <link href="assets/css/bootstrap.css" rel="stylesheet">
+ <link href="assets/css/local.css" rel="stylesheet">
+ <style type="text/css">
+ body { padding-top: 60px; }
+ dd { padding: 10px; }
+ </style>
+
+ <!-- Le javascripts -->
+ <script src="../assets/js/jquery-1.7.1.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="../assets/js/bootstrap.js" type="text/javascript" charset="utf-8"></script>
+ </head>
+
+ <body>
+
+ <div class="navbar navbar-fixed-top">
+ <div class="navbar-inner">
+ <div class="container">
+ <a class="brand" href="/">DevStack</a>
+ <ul class="nav pull-right">
+ <li><a href="overview.html">Overview</a></li>
+ <li><a href="changes.html">Changes</a></li>
+ <li><a href="faq.html">FAQ</a></li>
+ <li><a href="http://github.com/openstack-dev/devstack">GitHub</a></li>
+ <li><a href="https://review.openstack.org/#/q/status:open+project:openstack-dev/devstack,n,z">Gerrit</a></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <div class="container">
+
+ <section class="span12">
+ <div class="page-header">
+ <h2>stackrc <small>DevStack settings</small></h2>
+ <p><code>stackrc</code> is the primary configuration file for DevStack.
+ It contains all of the settings that control the services started
+ and the repositories used to download the source for those services.
+ <code>stackrc</code> sources the <code>localrc</code> section of
+ <code>local.conf</code> to perform the default overrides.</p>
+ </div>
+ <dl>
+
+ <dt>DATABASE_TYPE</dt>
+ <dd>Select the database backend to use. The default is <code>mysql</code>,
+ <code>postgresql</code> is also available.</dd>
+
+ <dt>ENABLED_SERVICES</dt>
+ <dd>Specify which services to launch. These generally correspond to
+ screen tabs.
+ The default includes: Glance (API and Registry), Keystone, Nova (API,
+ Certificate, Object Store, Compute, Network, Scheduler, VNC proxies,
+ Certificate Authentication), Cinder (Scheduler, API, Volume), Horizon, MySQL, RabbitMQ, Tempest.
+ <pre>ENABLED_SERVICES=g-api,g-reg,key,n-api,n-crt,n-obj,n-cpu,n-net,n-cond,cinder,c-sch,c-api,c-vol,n-sch,n-novnc,n-xvnc,n-cauth,horizon,rabbit,tempest,$DATABASE_TYPE</pre>
+ Other services that are not enabled by default can be enabled in
+ <code>localrc</code>. For example, to add Swift:
+ <pre>enable_service swift</pre>
+ A service can similarly be disabled:
+ <pre>disable_service horizon</pre></dd>
+
+ <dt>Service Repos</dt>
+ <dd>The Git repositories used to check out the source for each service
+ are controlled by a pair of variables set for each service.
+ <code>*_REPO</code> points to the repository and <code>*_BRANCH</code>
+ selects which branch to check out. These may be overridden in
+ <code>local.conf</code> to pull source from a different repo for testing,
+ such as a Gerrit branch proposal. <code>GIT_BASE</code> points to the primary repository server.
+ <pre>NOVA_REPO=$GIT_BASE/openstack/nova.git
+NOVA_BRANCH=master</pre>
+ To pull a branch directly from Gerrit, get the repo and branch from the
+ Gerrit review page:
+ <pre>git fetch https://review.openstack.org/p/openstack/nova refs/changes/50/5050/1 && git checkout FETCH_HEAD</pre>
+ The repo is the stanza following <code>fetch</code> and the branch
+ is the stanza following that:
+ <pre>NOVA_REPO=https://review.openstack.org/p/openstack/nova
+NOVA_BRANCH=refs/changes/50/5050/1</pre></dd>
+
+ </dl>
+ </section
+
+ <footer>
+ <p>© Openstack Foundation 2011-2014 — An <a href="https://www.openstack.org/">OpenStack</a> <a href="https://wiki.openstack.org/wiki/Programs">program</a></p>
+ </footer>
+
+ </div> <!-- /container -->
+
+ </body>
+</html>
diff --git a/exercises/trove.sh b/exercises/trove.sh
index d48d5fe..053f872 100755
--- a/exercises/trove.sh
+++ b/exercises/trove.sh
@@ -35,8 +35,12 @@
is_service_enabled trove || exit 55
-# can we get a list versions
-curl http://$SERVICE_HOST:8779/ 2>/dev/null | grep -q 'versions' || die $LINENO "Trove API not functioning!"
+# can try to get datastore id
+DSTORE_ID=$(trove datastore-list | tail -n +4 |head -3 | get_field 1)
+die_if_not_set $LINENO DSTORE_ID "Trove API not functioning!"
+
+DV_ID=$(trove datastore-version-list $DSTORE_ID | tail -n +4 | get_field 1)
+die_if_not_set $LINENO DV_ID "Trove API not functioning!"
set +o xtrace
echo "*********************************************************************"
diff --git a/extras.d/80-opendaylight.sh b/extras.d/80-opendaylight.sh
index bfbabc2..b673777 100644
--- a/extras.d/80-opendaylight.sh
+++ b/extras.d/80-opendaylight.sh
@@ -40,7 +40,9 @@
elif [[ "$1" == "stack" && "$2" == "install" ]]; then
install_opendaylight-compute
elif [[ "$1" == "stack" && "$2" == "post-config" ]]; then
- create_nova_conf_neutron
+ if is_service_enabled nova; then
+ create_nova_conf_neutron
+ fi
elif [[ "$1" == "stack" && "$2" == "extra" ]]; then
echo_summary "Initializing OpenDaylight"
ODL_LOCAL_IP=${ODL_LOCAL_IP:-$HOST_IP}
diff --git a/extras.d/README.md b/extras.d/README.md
index 1dd17da..7c2e4fe 100644
--- a/extras.d/README.md
+++ b/extras.d/README.md
@@ -22,9 +22,24 @@
stack: called by stack.sh. There are four possible values for
the second arg to distinguish the phase stack.sh is in:
- arg 2: install | post-config | extra | post-extra
+ arg 2: pre-install | install | post-config | extra
unstack: called by unstack.sh
clean: called by clean.sh. Remember, clean.sh also calls unstack.sh
so that work need not be repeated.
+
+The `stack` phase sub-phases are called from `stack.sh` in the following places:
+
+ pre-install - After all system prerequisites have been installed but before any
+ DevStack-specific services are installed (including database and rpc).
+
+ install - After all OpenStack services have been installed and configured
+ but before any OpenStack services have been started. Changes to OpenStack
+ service configurations should be done here.
+
+ post-config - After OpenStack services have been initialized but still before
+ they have been started. (This is probably mis-named, think of it as post-init.)
+
+ extra - After everything is started.
+
diff --git a/files/apache-keystone.template b/files/apache-keystone.template
index 919452a..805e7b8 100644
--- a/files/apache-keystone.template
+++ b/files/apache-keystone.template
@@ -20,3 +20,7 @@
LogLevel debug
CustomLog /var/log/%APACHE_NAME%/access.log combined
</VirtualHost>
+
+# Workaround for missing path on RHEL6, see
+# https://bugzilla.redhat.com/show_bug.cgi?id=1121019
+WSGISocketPrefix /var/run/%APACHE_NAME%
diff --git a/files/apts/general b/files/apts/general
index d81ec7a..d65cab3 100644
--- a/files/apts/general
+++ b/files/apts/general
@@ -20,5 +20,8 @@
tar
python-cmd2 # dist:precise
python-dev
+python-mock # testonly
python2.7
bc
+libyaml-dev
+libffi-dev
diff --git a/files/apts/glance b/files/apts/glance
index b5d8c77..15e09aa 100644
--- a/files/apts/glance
+++ b/files/apts/glance
@@ -1,4 +1,3 @@
-libffi-dev
libmysqlclient-dev # testonly
libpq-dev # testonly
libssl-dev # testonly
diff --git a/files/apts/ironic b/files/apts/ironic
index b77a6b1..fe9c07f 100644
--- a/files/apts/ironic
+++ b/files/apts/ironic
@@ -1,3 +1,4 @@
+ipmitool
iptables
libguestfs0
libvirt-bin
diff --git a/files/apts/keystone b/files/apts/keystone
index 57fde80..b7218b7 100644
--- a/files/apts/keystone
+++ b/files/apts/keystone
@@ -11,3 +11,4 @@
python-routes
libldap2-dev
libsasl2-dev
+libkrb5-dev
diff --git a/files/apts/nova b/files/apts/nova
index 38c99c7..e779849 100644
--- a/files/apts/nova
+++ b/files/apts/nova
@@ -1,5 +1,6 @@
dnsmasq-base
dnsmasq-utils # for dhcp_release
+conntrack
kpartx
parted
iputils-arping
diff --git a/files/apts/opendaylight b/files/apts/opendaylight
deleted file mode 100644
index ec3cc9d..0000000
--- a/files/apts/opendaylight
+++ /dev/null
@@ -1,2 +0,0 @@
-openvswitch-datapath-dkms # NOPRIME
-openvswitch-switch # NOPRIME
diff --git a/files/apts/openvswitch b/files/apts/openvswitch
new file mode 100644
index 0000000..4c0af4a
--- /dev/null
+++ b/files/apts/openvswitch
@@ -0,0 +1,3 @@
+fakeroot
+make
+openvswitch-switch
diff --git a/files/apts/swift b/files/apts/swift
index 080ecdb..fd51699 100644
--- a/files/apts/swift
+++ b/files/apts/swift
@@ -1,5 +1,4 @@
curl
-libffi-dev
memcached
python-configobj
python-coverage
diff --git a/files/apts/tls-proxy b/files/apts/tls-proxy
index 8fca42d..dce9c07 100644
--- a/files/apts/tls-proxy
+++ b/files/apts/tls-proxy
@@ -1 +1 @@
-stud # only available in dist:precise
+stud
diff --git a/files/rpms-suse/nova b/files/rpms-suse/nova
index 3e95724..7a1160e 100644
--- a/files/rpms-suse/nova
+++ b/files/rpms-suse/nova
@@ -1,6 +1,7 @@
curl
dnsmasq
dnsmasq-utils # dist:opensuse-12.3,opensuse-13.1
+conntrack-tools
ebtables
gawk
genisoimage # required for config_drive
diff --git a/files/rpms-suse/opendaylight b/files/rpms-suse/opendaylight
deleted file mode 100644
index f7fafff..0000000
--- a/files/rpms-suse/opendaylight
+++ /dev/null
@@ -1,3 +0,0 @@
-openvswitch # NOPRIME
-openvswitch-switch # NOPRIME
-
diff --git a/files/rpms-suse/openvswitch b/files/rpms-suse/openvswitch
new file mode 100644
index 0000000..edfb4d2
--- /dev/null
+++ b/files/rpms-suse/openvswitch
@@ -0,0 +1,3 @@
+openvswitch
+openvswitch-switch
+
diff --git a/files/rpms/general b/files/rpms/general
index c940de6..74997a8 100644
--- a/files/rpms/general
+++ b/files/rpms/general
@@ -7,6 +7,7 @@
openssh-server
openssl
openssl-devel # to rebuild pyOpenSSL if needed
+libffi-devel
libxml2-devel
libxslt-devel
psmisc
@@ -23,6 +24,7 @@
wget
which
bc
+libyaml-devel
# [1] : some of installed tools have unversioned dependencies on this,
# but others have versioned (<=0.7). So if a later version (0.7.1)
diff --git a/files/rpms/glance b/files/rpms/glance
index fc07fa7..5a7f073 100644
--- a/files/rpms/glance
+++ b/files/rpms/glance
@@ -1,4 +1,3 @@
-libffi-devel
libxml2-devel # testonly
libxslt-devel # testonly
mysql-devel # testonly
diff --git a/files/rpms/ironic b/files/rpms/ironic
index 6534095..0c81081 100644
--- a/files/rpms/ironic
+++ b/files/rpms/ironic
@@ -1,3 +1,4 @@
+ipmitool
iptables
libguestfs
libvirt
diff --git a/files/rpms/nova b/files/rpms/nova
index 0c828f4..6097991 100644
--- a/files/rpms/nova
+++ b/files/rpms/nova
@@ -2,6 +2,7 @@
curl
dnsmasq # for nova-network
dnsmasq-utils # for dhcp_release
+conntrack-tools
ebtables
gawk
genisoimage # required for config_drive
diff --git a/files/rpms/opendaylight b/files/rpms/opendaylight
deleted file mode 100644
index 98aaaf4..0000000
--- a/files/rpms/opendaylight
+++ /dev/null
@@ -1 +0,0 @@
-openvswitch # NOPRIME
diff --git a/files/rpms/openvswitch b/files/rpms/openvswitch
new file mode 100644
index 0000000..64796f7
--- /dev/null
+++ b/files/rpms/openvswitch
@@ -0,0 +1 @@
+openvswitch
diff --git a/files/rpms/swift b/files/rpms/swift
index 938d2c8..9ec4aab 100644
--- a/files/rpms/swift
+++ b/files/rpms/swift
@@ -1,5 +1,4 @@
curl
-libffi-devel
memcached
python-configobj
python-coverage
diff --git a/functions b/functions
index 80f98ad..ca8ef80 100644
--- a/functions
+++ b/functions
@@ -16,6 +16,10 @@
XTRACE=$(set +o | grep xtrace)
set +o xtrace
+# Check if a function already exists
+function function_exists {
+ declare -f -F $1 > /dev/null
+}
# Checks if installed Apache is <= given version
# $1 = x.y.z (version string of Apache)
@@ -246,7 +250,7 @@
xdir="$FILES/images/$IMAGE_NAME"
rm -Rf "$xdir";
mkdir "$xdir"
- tar -zxf $FILES/$IMAGE_FNAME -C "$xdir"
+ tar -zxf $IMAGE -C "$xdir"
KERNEL=$(for f in "$xdir/"*-vmlinuz* "$xdir/"aki-*/image; do
[ -f "$f" ] && echo "$f" && break; done; true)
RAMDISK=$(for f in "$xdir/"*-initrd* "$xdir/"ari-*/image; do
@@ -527,6 +531,20 @@
iniset $conf_file $conf_section logging_exception_prefix "%(color)s%(asctime)s.%(msecs)03d TRACE %(name)s [01;35m%(instance)s[00m"
}
+# These functions are provided for basic fall-back functionality for
+# projects that include parts of devstack (grenade). stack.sh will
+# override these with more specific versions for devstack (with fancy
+# spinners, etc). We never override an existing version
+if ! function_exists echo_summary; then
+ function echo_summary {
+ echo $@
+ }
+fi
+if ! function_exists echo_nolog; then
+ function echo_nolog {
+ echo $@
+ }
+fi
# Restore xtrace
$XTRACE
diff --git a/functions-common b/functions-common
index cc90c07..4c9d1da 100644
--- a/functions-common
+++ b/functions-common
@@ -435,7 +435,9 @@
else
DISTRO="sle${os_RELEASE}sp${os_UPDATE}"
fi
- elif [[ "$os_VENDOR" =~ (Red Hat) || "$os_VENDOR" =~ (CentOS) ]]; then
+ elif [[ "$os_VENDOR" =~ (Red Hat) || \
+ "$os_VENDOR" =~ (CentOS) || \
+ "$os_VENDOR" =~ (OracleServer) ]]; then
# Drop the . release as we assume it's compatible
DISTRO="rhel${os_RELEASE::1}"
elif [[ "$os_VENDOR" =~ (XenServer) ]]; then
@@ -463,7 +465,8 @@
GetOSVersion
fi
- [ "$os_VENDOR" = "Fedora" ] || [ "$os_VENDOR" = "Red Hat" ] || [ "$os_VENDOR" = "CentOS" ]
+ [ "$os_VENDOR" = "Fedora" ] || [ "$os_VENDOR" = "Red Hat" ] || \
+ [ "$os_VENDOR" = "CentOS" ] || [ "$os_VENDOR" = "OracleServer" ]
}
@@ -719,6 +722,114 @@
mv ${tmpfile} ${policy_file}
}
+# Gets or creates user
+# Usage: get_or_create_user <username> <password> <project> [<email>]
+function get_or_create_user {
+ if [[ ! -z "$4" ]]; then
+ local EMAIL="--email=$4"
+ else
+ local EMAIL=""
+ fi
+ # Gets user id
+ USER_ID=$(
+ # Gets user id
+ openstack user show $1 -f value -c id 2>/dev/null ||
+ # Creates new user
+ openstack user create \
+ $1 \
+ --password "$2" \
+ --project $3 \
+ $EMAIL \
+ -f value -c id
+ )
+ echo $USER_ID
+}
+
+# Gets or creates project
+# Usage: get_or_create_project <name>
+function get_or_create_project {
+ # Gets project id
+ PROJECT_ID=$(
+ # Gets project id
+ openstack project show $1 -f value -c id 2>/dev/null ||
+ # Creates new project if not exists
+ openstack project create $1 -f value -c id
+ )
+ echo $PROJECT_ID
+}
+
+# Gets or creates role
+# Usage: get_or_create_role <name>
+function get_or_create_role {
+ ROLE_ID=$(
+ # Gets role id
+ openstack role show $1 -f value -c id 2>/dev/null ||
+ # Creates role if not exists
+ openstack role create $1 -f value -c id
+ )
+ echo $ROLE_ID
+}
+
+# Gets or adds user role
+# Usage: get_or_add_user_role <role> <user> <project>
+function get_or_add_user_role {
+ # Gets user role id
+ USER_ROLE_ID=$(openstack user role list \
+ $2 \
+ --project $3 \
+ --column "ID" \
+ --column "Name" \
+ | grep " $1 " | get_field 1)
+ if [[ -z "$USER_ROLE_ID" ]]; then
+ # Adds role to user
+ USER_ROLE_ID=$(openstack role add \
+ $1 \
+ --user $2 \
+ --project $3 \
+ | grep " id " | get_field 2)
+ fi
+ echo $USER_ROLE_ID
+}
+
+# Gets or creates service
+# Usage: get_or_create_service <name> <type> <description>
+function get_or_create_service {
+ # Gets service id
+ SERVICE_ID=$(
+ # Gets service id
+ openstack service show $1 -f value -c id 2>/dev/null ||
+ # Creates new service if not exists
+ openstack service create \
+ $1 \
+ --type=$2 \
+ --description="$3" \
+ -f value -c id
+ )
+ echo $SERVICE_ID
+}
+
+# Gets or creates endpoint
+# Usage: get_or_create_endpoint <service> <region> <publicurl> <adminurl> <internalurl>
+function get_or_create_endpoint {
+ # Gets endpoint id
+ ENDPOINT_ID=$(openstack endpoint list \
+ --column "ID" \
+ --column "Region" \
+ --column "Service Name" \
+ | grep " $2 " \
+ | grep " $1 " | get_field 1)
+ if [[ -z "$ENDPOINT_ID" ]]; then
+ # Creates new endpoint
+ ENDPOINT_ID=$(openstack endpoint create \
+ $1 \
+ --region $2 \
+ --publicurl $3 \
+ --adminurl $4 \
+ --internalurl $5 \
+ | grep " id " | get_field 2)
+ fi
+ echo $ENDPOINT_ID
+}
# Package Functions
# =================
@@ -881,29 +992,43 @@
# Distro-agnostic package installer
# install_package package [package ...]
-function install_package {
- local xtrace=$(set +o | grep xtrace)
- set +o xtrace
- if is_ubuntu; then
- # if there are transient errors pulling the updates, that's fine. It may
- # be secondary repositories that we don't really care about.
- [[ "$NO_UPDATE_REPOS" = "True" ]] || apt_get update || /bin/true
- NO_UPDATE_REPOS=True
+function update_package_repo {
+ if [[ "$NO_UPDATE_REPOS" = "True" ]]; then
+ return 0
+ fi
+ if is_ubuntu; then
+ local xtrace=$(set +o | grep xtrace)
+ set +o xtrace
+ if [[ "$REPOS_UPDATED" != "True" || "$RETRY_UPDATE" = "True" ]]; then
+ # if there are transient errors pulling the updates, that's fine.
+ # It may be secondary repositories that we don't really care about.
+ apt_get update || /bin/true
+ REPOS_UPDATED=True
+ fi
$xtrace
+ fi
+}
+
+function real_install_package {
+ if is_ubuntu; then
apt_get install "$@"
elif is_fedora; then
- $xtrace
yum_install "$@"
elif is_suse; then
- $xtrace
zypper_install "$@"
else
- $xtrace
exit_distro_not_supported "installing packages"
fi
}
+# Distro-agnostic package installer
+# install_package package [package ...]
+function install_package {
+ update_package_repo
+ real_install_package $@ || RETRY_UPDATE=True update_package_repo && real_install_package $@
+}
+
# Distro-agnostic function to tell if a package is installed
# is_package_installed package [package ...]
function is_package_installed {
@@ -1067,7 +1192,7 @@
# sleep to allow bash to be ready to be send the command - we are
# creating a new window in screen and then sends characters, so if
# bash isn't running by the time we send the command, nothing happens
- sleep 1.5
+ sleep 3
NL=`echo -ne '\015'`
# This fun command does the following:
diff --git a/lib/apache b/lib/apache
index 55083e7..f4f82a1 100644
--- a/lib/apache
+++ b/lib/apache
@@ -8,7 +8,6 @@
#
# lib/apache exports the following functions:
#
-# - is_apache_enabled_service
# - install_apache_wsgi
# - config_apache_wsgi
# - apache_site_config_for
@@ -31,34 +30,17 @@
# Set up apache name and configuration directory
if is_ubuntu; then
APACHE_NAME=apache2
- APACHE_CONF_DIR=sites-available
+ APACHE_CONF_DIR=${APACHE_CONF_DIR:-/etc/$APACHE_NAME/sites-available}
elif is_fedora; then
APACHE_NAME=httpd
- APACHE_CONF_DIR=conf.d
+ APACHE_CONF_DIR=${APACHE_CONF_DIR:-/etc/$APACHE_NAME/conf.d}
elif is_suse; then
APACHE_NAME=apache2
- APACHE_CONF_DIR=vhosts.d
+ APACHE_CONF_DIR=${APACHE_CONF_DIR:-/etc/$APACHE_NAME/vhosts.d}
fi
# Functions
# ---------
-
-# is_apache_enabled_service() checks if the service(s) specified as arguments are
-# apache enabled by the user in ``APACHE_ENABLED_SERVICES`` as web front end.
-#
-# Multiple services specified as arguments are ``OR``'ed together; the test
-# is a short-circuit boolean, i.e it returns on the first match.
-#
-# Uses global ``APACHE_ENABLED_SERVICES``
-# APACHE_ENABLED_SERVICES service [service ...]
-function is_apache_enabled_service {
- services=$@
- for service in ${services}; do
- [[ ,${APACHE_ENABLED_SERVICES}, =~ ,${service}, ]] && return 0
- done
- return 1
-}
-
# install_apache_wsgi() - Install Apache server and wsgi module
function install_apache_wsgi {
# Apache installation, because we mark it NOPRIME
@@ -90,7 +72,7 @@
# /etc/apache2/sites-available/. a2ensite and a2dissite need the entire file name to work. The default
# sites' files are default and default-ssl.
#
-# On Fedora, any file in /etc/httpd/conf.d/ whose name ends with .conf is enabled.
+# On Fedora and openSUSE, any file in /etc/httpd/conf.d/ whose name ends with .conf is enabled.
#
# On RHEL and CentOS, things should hopefully work as in Fedora.
#
@@ -108,14 +90,14 @@
local apache_version=$(sudo /usr/sbin/apache2ctl -v | awk '/Server version/ {print $3}' | cut -f2 -d/)
if [[ "$apache_version" =~ ^2\.2\. ]]; then
# Ubuntu 12.04 - Apache 2.2
- echo /etc/$APACHE_NAME/$APACHE_CONF_DIR/${site}
+ echo $APACHE_CONF_DIR/${site}
else
# Ubuntu 14.04 - Apache 2.4
- echo /etc/$APACHE_NAME/$APACHE_CONF_DIR/${site}.conf
+ echo $APACHE_CONF_DIR/${site}.conf
fi
- elif is_fedora; then
+ elif is_fedora || is_suse; then
# fedora conf.d is only imported if it ends with .conf so this is approx the same
- local enabled_site_file="/etc/$APACHE_NAME/$APACHE_CONF_DIR/${site}.conf"
+ local enabled_site_file="$APACHE_CONF_DIR/${site}.conf"
if [ -f $enabled_site_file ]; then
echo ${enabled_site_file}
else
@@ -129,9 +111,12 @@
local site=$@
if is_ubuntu; then
sudo a2ensite ${site}
- elif is_fedora; then
- # fedora conf.d is only imported if it ends with .conf so this is approx the same
- sudo mv /etc/$APACHE_NAME/$APACHE_CONF_DIR/${site}.conf.disabled /etc/$APACHE_NAME/$APACHE_CONF_DIR/${site}.conf
+ elif is_fedora || is_suse; then
+ local enabled_site_file="$APACHE_CONF_DIR/${site}.conf"
+ # Do nothing if site already enabled or no site config exists
+ if [[ -f ${enabled_site_file}.disabled ]] && [[ ! -f ${enabled_site_file} ]]; then
+ sudo mv ${enabled_site_file}.disabled ${enabled_site_file}
+ fi
fi
}
@@ -140,8 +125,12 @@
local site=$@
if is_ubuntu; then
sudo a2dissite ${site}
- elif is_fedora; then
- sudo mv /etc/$APACHE_NAME/$APACHE_CONF_DIR/${site}.conf /etc/$APACHE_NAME/$APACHE_CONF_DIR/${site}.conf.disabled
+ elif is_fedora || is_suse; then
+ local enabled_site_file="$APACHE_CONF_DIR/${site}.conf"
+ # Do nothing if no site config exists
+ if [[ -f ${enabled_site_file} ]]; then
+ sudo mv ${enabled_site_file} ${enabled_site_file}.disabled
+ fi
fi
}
@@ -161,7 +150,12 @@
# restart_apache_server
function restart_apache_server {
- restart_service $APACHE_NAME
+ # Apache can be slow to stop, doing an explicit stop, sleep, start helps
+ # to mitigate issues where apache will claim a port it's listening on is
+ # still in use and fail to start.
+ stop_service $APACHE_NAME
+ sleep 3
+ start_service $APACHE_NAME
}
# Restore xtrace
diff --git a/lib/ceilometer b/lib/ceilometer
index a4be7af..54d95c5 100644
--- a/lib/ceilometer
+++ b/lib/ceilometer
@@ -53,6 +53,9 @@
CEILOMETER_SERVICE_HOST=$SERVICE_HOST
CEILOMETER_SERVICE_PORT=${CEILOMETER_SERVICE_PORT:-8777}
+# To enable OSprofiler change value of this variable to "notifications,profiler"
+CEILOMETER_NOTIFICATION_TOPICS=${CEILOMETER_NOTIFICATION_TOPICS:-notifications}
+
# Tell Tempest this project is present
TEMPEST_SERVICES+=,ceilometer
@@ -81,35 +84,22 @@
# Ceilometer
if [[ "$ENABLED_SERVICES" =~ "ceilometer-api" ]]; then
- CEILOMETER_USER=$(openstack user create \
- ceilometer \
- --password "$SERVICE_PASSWORD" \
- --project $SERVICE_TENANT \
- --email ceilometer@example.com \
- | grep " id " | get_field 2)
- openstack role add \
- $ADMIN_ROLE \
- --project $SERVICE_TENANT \
- --user $CEILOMETER_USER
+ CEILOMETER_USER=$(get_or_create_user "ceilometer" \
+ "$SERVICE_PASSWORD" $SERVICE_TENANT)
+ get_or_add_user_role $ADMIN_ROLE $CEILOMETER_USER $SERVICE_TENANT
+
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
- CEILOMETER_SERVICE=$(openstack service create \
- ceilometer \
- --type=metering \
- --description="OpenStack Telemetry Service" \
- | grep " id " | get_field 2)
- openstack endpoint create \
- $CEILOMETER_SERVICE \
- --region RegionOne \
- --publicurl "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/" \
- --adminurl "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/" \
- --internalurl "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/"
+ CEILOMETER_SERVICE=$(get_or_create_service "ceilometer" \
+ "metering" "OpenStack Telemetry Service")
+ get_or_create_endpoint $CEILOMETER_SERVICE \
+ "$REGION_NAME" \
+ "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/" \
+ "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/" \
+ "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/"
fi
if is_service_enabled swift; then
# Ceilometer needs ResellerAdmin role to access swift account stats.
- openstack role add \
- --project $SERVICE_TENANT_NAME \
- --user ceilometer \
- ResellerAdmin
+ get_or_add_user_role "ResellerAdmin" "ceilometer" $SERVICE_TENANT_NAME
fi
fi
}
@@ -123,16 +113,8 @@
fi
}
-# configure_ceilometerclient() - Set config files, create data dirs, etc
-function configure_ceilometerclient {
- setup_develop $CEILOMETERCLIENT_DIR
- sudo install -D -m 0644 -o $STACK_USER {$CEILOMETERCLIENT_DIR/tools/,/etc/bash_completion.d/}ceilometer.bash_completion
-}
-
# configure_ceilometer() - Set config files, create data dirs, etc
function configure_ceilometer {
- setup_develop $CEILOMETER_DIR
-
[ ! -d $CEILOMETER_CONF_DIR ] && sudo mkdir -m 755 -p $CEILOMETER_CONF_DIR
sudo chown $STACK_USER $CEILOMETER_CONF_DIR
@@ -141,7 +123,7 @@
iniset_rpc_backend ceilometer $CEILOMETER_CONF DEFAULT
- iniset $CEILOMETER_CONF DEFAULT notification_topics 'notifications'
+ iniset $CEILOMETER_CONF DEFAULT notification_topics "$CEILOMETER_NOTIFICATION_TOPICS"
iniset $CEILOMETER_CONF DEFAULT verbose True
iniset $CEILOMETER_CONF DEFAULT debug "$ENABLE_DEBUG_LOG_LEVEL"
@@ -164,9 +146,7 @@
iniset $CEILOMETER_CONF service_credentials os_password $SERVICE_PASSWORD
iniset $CEILOMETER_CONF service_credentials os_tenant_name $SERVICE_TENANT_NAME
- iniset $CEILOMETER_CONF keystone_authtoken auth_host $KEYSTONE_AUTH_HOST
- iniset $CEILOMETER_CONF keystone_authtoken auth_port $KEYSTONE_AUTH_PORT
- iniset $CEILOMETER_CONF keystone_authtoken auth_protocol $KEYSTONE_AUTH_PROTOCOL
+ iniset $CEILOMETER_CONF keystone_authtoken identity_uri $KEYSTONE_AUTH_URI
iniset $CEILOMETER_CONF keystone_authtoken admin_user ceilometer
iniset $CEILOMETER_CONF keystone_authtoken admin_password $SERVICE_PASSWORD
iniset $CEILOMETER_CONF keystone_authtoken admin_tenant_name $SERVICE_TENANT_NAME
@@ -230,11 +210,15 @@
# install_ceilometer() - Collect source and prepare
function install_ceilometer {
git_clone $CEILOMETER_REPO $CEILOMETER_DIR $CEILOMETER_BRANCH
+ setup_develop $CEILOMETER_DIR
+
}
# install_ceilometerclient() - Collect source and prepare
function install_ceilometerclient {
git_clone $CEILOMETERCLIENT_REPO $CEILOMETERCLIENT_DIR $CEILOMETERCLIENT_BRANCH
+ setup_develop $CEILOMETERCLIENT_DIR
+ sudo install -D -m 0644 -o $STACK_USER {$CEILOMETERCLIENT_DIR/tools/,/etc/bash_completion.d/}ceilometer.bash_completion
}
# start_ceilometer() - Start running processes, including screen
diff --git a/lib/cinder b/lib/cinder
index d5ee17e..a51e4a0 100644
--- a/lib/cinder
+++ b/lib/cinder
@@ -28,6 +28,7 @@
# set up default driver
CINDER_DRIVER=${CINDER_DRIVER:-default}
CINDER_PLUGINS=$TOP_DIR/lib/cinder_plugins
+CINDER_BACKENDS=$TOP_DIR/lib/cinder_backends
# grab plugin config if specified via cinder_driver
if [[ -r $CINDER_PLUGINS/$CINDER_DRIVER ]]; then
@@ -57,9 +58,24 @@
CINDER_BIN_DIR=$(get_python_exec_prefix)
fi
+
+# Maintain this here for backward-compatibility with the old configuration
+# DEPRECATED: Use CINDER_ENABLED_BACKENDS instead
# Support for multi lvm backend configuration (default is no support)
CINDER_MULTI_LVM_BACKEND=$(trueorfalse False $CINDER_MULTI_LVM_BACKEND)
+# Default backends
+# The backend format is type:name where type is one of the supported backend
+# types (lvm, nfs, etc) and name is the identifier used in the Cinder
+# configuration and for the volume type name. Multiple backends are
+# comma-separated.
+if [[ $CINDER_MULTI_LVM_BACKEND == "False" ]]; then
+ CINDER_ENABLED_BACKENDS=${CINDER_ENABLED_BACKENDS:-lvm:lvmdriver-1}
+else
+ CINDER_ENABLED_BACKENDS=${CINDER_ENABLED_BACKENDS:-lvm:lvmdriver-1,lvm:lvmdriver-2}
+fi
+
+
# Should cinder perform secure deletion of volumes?
# Defaults to true, can be set to False to avoid this bug when testing:
# https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1023755
@@ -73,22 +89,22 @@
# https://bugs.launchpad.net/cinder/+bug/1180976
CINDER_PERIODIC_INTERVAL=${CINDER_PERIODIC_INTERVAL:-60}
-# Name of the lvm volume groups to use/create for iscsi volumes
-VOLUME_GROUP=${VOLUME_GROUP:-stack-volumes}
-VOLUME_BACKING_FILE=${VOLUME_BACKING_FILE:-$DATA_DIR/${VOLUME_GROUP}-backing-file}
-VOLUME_BACKING_DEVICE=${VOLUME_BACKING_DEVICE:-}
-
-# VOLUME_GROUP2 is used only if CINDER_MULTI_LVM_BACKEND = True
-VOLUME_GROUP2=${VOLUME_GROUP2:-stack-volumes2}
-VOLUME_BACKING_FILE2=${VOLUME_BACKING_FILE2:-$DATA_DIR/${VOLUME_GROUP2}-backing-file}
-VOLUME_BACKING_DEVICE2=${VOLUME_BACKING_DEVICE2:-}
-
-VOLUME_NAME_PREFIX=${VOLUME_NAME_PREFIX:-volume-}
-
# Tell Tempest this project is present
TEMPEST_SERVICES+=,cinder
+# Source the enabled backends
+if is_service_enabled c-vol && [[ -n "$CINDER_ENABLED_BACKENDS" ]]; then
+ for be in ${CINDER_ENABLED_BACKENDS//,/ }; do
+ BE_TYPE=${be%%:*}
+ BE_NAME=${be##*:}
+ if [[ -r $CINDER_BACKENDS/${BE_TYPE} ]]; then
+ source $CINDER_BACKENDS/${BE_TYPE}
+ fi
+ done
+fi
+
+
# Functions
# ---------
@@ -99,41 +115,6 @@
return 1
}
-# _clean_lvm_lv removes all cinder LVM volumes
-#
-# Usage: _clean_lvm_lv $VOLUME_GROUP $VOLUME_NAME_PREFIX
-function _clean_lvm_lv {
- local vg=$1
- local lv_prefix=$2
-
- # Clean out existing volumes
- for lv in `sudo lvs --noheadings -o lv_name $vg`; do
- # lv_prefix prefixes the LVs we want
- if [[ "${lv#$lv_prefix}" != "$lv" ]]; then
- sudo lvremove -f $vg/$lv
- fi
- done
-}
-
-# _clean_lvm_backing_file() removes the backing file of the
-# volume group used by cinder
-#
-# Usage: _clean_lvm_backing_file() $VOLUME_GROUP
-function _clean_lvm_backing_file {
- local vg=$1
-
- # if there is no logical volume left, it's safe to attempt a cleanup
- # of the backing file
- if [ -z "`sudo lvs --noheadings -o lv_name $vg`" ]; then
- # if the backing physical device is a loop device, it was probably setup by devstack
- if [[ -n "$VG_DEV" ]] && [[ -e "$VG_DEV" ]]; then
- VG_DEV=$(sudo losetup -j $DATA_DIR/${vg}-backing-file | awk -F':' '/backing-file/ { print $1}')
- sudo losetup -d $VG_DEV
- rm -f $DATA_DIR/${vg}-backing-file
- fi
- fi
-}
-
# cleanup_cinder() - Remove residual data files, anything left over from previous
# runs that a clean run would need to clean up
function cleanup_cinder {
@@ -160,23 +141,20 @@
done
fi
- if is_service_enabled cinder; then
- sudo rm -rf $CINDER_STATE_PATH/volumes/*
- fi
-
if is_ubuntu; then
stop_service tgt
else
stop_service tgtd
fi
- # Campsite rule: leave behind a volume group at least as clean as we found it
- _clean_lvm_lv $VOLUME_GROUP $VOLUME_NAME_PREFIX
- _clean_lvm_backing_file $VOLUME_GROUP
-
- if [ "$CINDER_MULTI_LVM_BACKEND" = "True" ]; then
- _clean_lvm_lv $VOLUME_GROUP2 $VOLUME_NAME_PREFIX
- _clean_lvm_backing_file $VOLUME_GROUP2
+ if is_service_enabled c-vol && [[ -n "$CINDER_ENABLED_BACKENDS" ]]; then
+ for be in ${CINDER_ENABLED_BACKENDS//,/ }; do
+ BE_TYPE=${be%%:*}
+ BE_NAME=${be##*:}
+ if type cleanup_cinder_backend_${BE_TYPE} >/dev/null 2>&1; then
+ cleanup_cinder_backend_${BE_TYPE} ${BE_NAME}
+ fi
+ done
fi
}
@@ -233,9 +211,7 @@
inicomment $CINDER_API_PASTE_INI filter:authtoken admin_password
inicomment $CINDER_API_PASTE_INI filter:authtoken signing_dir
- iniset $CINDER_CONF keystone_authtoken auth_host $KEYSTONE_AUTH_HOST
- iniset $CINDER_CONF keystone_authtoken auth_port $KEYSTONE_AUTH_PORT
- iniset $CINDER_CONF keystone_authtoken auth_protocol $KEYSTONE_AUTH_PROTOCOL
+ iniset $CINDER_CONF keystone_authtoken identity_uri $KEYSTONE_AUTH_URI
iniset $CINDER_CONF keystone_authtoken cafile $KEYSTONE_SSL_CA
iniset $CINDER_CONF keystone_authtoken admin_tenant_name $SERVICE_TENANT_NAME
iniset $CINDER_CONF keystone_authtoken admin_user cinder
@@ -245,23 +221,7 @@
iniset $CINDER_CONF DEFAULT auth_strategy keystone
iniset $CINDER_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL
iniset $CINDER_CONF DEFAULT verbose True
- if [ "$CINDER_MULTI_LVM_BACKEND" = "True" ]; then
- iniset $CINDER_CONF DEFAULT enabled_backends lvmdriver-1,lvmdriver-2
- iniset $CINDER_CONF lvmdriver-1 volume_group $VOLUME_GROUP
- iniset $CINDER_CONF lvmdriver-1 volume_driver cinder.volume.drivers.lvm.LVMISCSIDriver
- iniset $CINDER_CONF lvmdriver-1 volume_backend_name LVM_iSCSI
- iniset $CINDER_CONF lvmdriver-2 volume_group $VOLUME_GROUP2
- iniset $CINDER_CONF lvmdriver-2 volume_driver cinder.volume.drivers.lvm.LVMISCSIDriver
- iniset $CINDER_CONF lvmdriver-2 volume_backend_name LVM_iSCSI_2
- # NOTE(mriedem): Work around Cinder "wishlist" bug 1255593
- if [[ "$CINDER_SECURE_DELETE" == "False" ]]; then
- iniset $CINDER_CONF lvmdriver-1 volume_clear none
- iniset $CINDER_CONF lvmdriver-2 volume_clear none
- fi
- else
- iniset $CINDER_CONF DEFAULT volume_group $VOLUME_GROUP
- iniset $CINDER_CONF DEFAULT volume_name_template ${VOLUME_NAME_PREFIX}%s
- fi
+
iniset $CINDER_CONF DEFAULT my_ip "$CINDER_SERVICE_HOST"
iniset $CINDER_CONF DEFAULT iscsi_helper tgtadm
iniset $CINDER_CONF DEFAULT sql_connection `database_connection_url cinder`
@@ -271,13 +231,37 @@
iniset $CINDER_CONF DEFAULT state_path $CINDER_STATE_PATH
iniset $CINDER_CONF DEFAULT lock_path $CINDER_STATE_PATH
iniset $CINDER_CONF DEFAULT periodic_interval $CINDER_PERIODIC_INTERVAL
+ # NOTE(thingee): Cinder V1 API is deprecated and defaults to off as of
+ # Juno. Keep it enabled so we can continue testing while it's still
+ # supported.
+ iniset $CINDER_CONF DEFAULT enable_v1_api true
+
+ if is_service_enabled c-vol && [[ -n "$CINDER_ENABLED_BACKENDS" ]]; then
+ enabled_backends=""
+ default_type=""
+ for be in ${CINDER_ENABLED_BACKENDS//,/ }; do
+ BE_TYPE=${be%%:*}
+ BE_NAME=${be##*:}
+ if type configure_cinder_backend_${BE_TYPE} >/dev/null 2>&1; then
+ configure_cinder_backend_${BE_TYPE} ${BE_NAME}
+ fi
+ if [[ -z "$default_type" ]]; then
+ default_type=$BE_TYPE
+ fi
+ enabled_backends+=$BE_NAME,
+ done
+ iniset $CINDER_CONF DEFAULT enabled_backends ${enabled_backends%,*}
+ if [[ -n "$default_type" ]]; then
+ iniset $CINDER_CONF DEFAULT default_volume_type ${default_type}
+ fi
+ fi
if is_service_enabled swift; then
iniset $CINDER_CONF DEFAULT backup_swift_url "http://$SERVICE_HOST:8080/v1/AUTH_"
fi
if is_service_enabled ceilometer; then
- iniset $CINDER_CONF DEFAULT notification_driver "cinder.openstack.common.notifier.rpc_notifier"
+ iniset $CINDER_CONF DEFAULT notification_driver "messaging"
fi
if is_service_enabled tls-proxy; then
@@ -337,39 +321,26 @@
# Cinder
if [[ "$ENABLED_SERVICES" =~ "c-api" ]]; then
- CINDER_USER=$(openstack user create \
- cinder \
- --password "$SERVICE_PASSWORD" \
- --project $SERVICE_TENANT \
- --email cinder@example.com \
- | grep " id " | get_field 2)
- openstack role add \
- $ADMIN_ROLE \
- --project $SERVICE_TENANT \
- --user $CINDER_USER
+
+ CINDER_USER=$(get_or_create_user "cinder" \
+ "$SERVICE_PASSWORD" $SERVICE_TENANT)
+ get_or_add_user_role $ADMIN_ROLE $CINDER_USER $SERVICE_TENANT
+
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
- CINDER_SERVICE=$(openstack service create \
- cinder \
- --type=volume \
- --description="Cinder Volume Service" \
- | grep " id " | get_field 2)
- openstack endpoint create \
- $CINDER_SERVICE \
- --region RegionOne \
- --publicurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" \
- --adminurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" \
- --internalurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s"
- CINDER_V2_SERVICE=$(openstack service create \
- cinderv2 \
- --type=volumev2 \
- --description="Cinder Volume Service V2" \
- | grep " id " | get_field 2)
- openstack endpoint create \
- $CINDER_V2_SERVICE \
- --region RegionOne \
- --publicurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s" \
- --adminurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s" \
- --internalurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s"
+
+ CINDER_SERVICE=$(get_or_create_service "cinder" \
+ "volume" "Cinder Volume Service")
+ get_or_create_endpoint $CINDER_SERVICE "$REGION_NAME" \
+ "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" \
+ "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" \
+ "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s"
+
+ CINDER_V2_SERVICE=$(get_or_create_service "cinderv2" \
+ "volumev2" "Cinder Volume Service V2")
+ get_or_create_endpoint $CINDER_V2_SERVICE "$REGION_NAME" \
+ "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s" \
+ "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s" \
+ "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s"
fi
fi
}
@@ -382,53 +353,6 @@
rm -f $CINDER_AUTH_CACHE_DIR/*
}
-function create_cinder_volume_group {
- # According to the ``CINDER_MULTI_LVM_BACKEND`` value, configure one or two default volumes
- # group called ``stack-volumes`` (and ``stack-volumes2``) for the volume
- # service if it (they) does (do) not yet exist. If you don't wish to use a
- # file backed volume group, create your own volume group called ``stack-volumes``
- # and ``stack-volumes2`` before invoking ``stack.sh``.
- #
- # The two backing files are ``VOLUME_BACKING_FILE_SIZE`` in size, and they are stored in
- # the ``DATA_DIR``.
-
- if ! sudo vgs $VOLUME_GROUP; then
- if [ -z "$VOLUME_BACKING_DEVICE" ]; then
- # Only create if the file doesn't already exists
- [[ -f $VOLUME_BACKING_FILE ]] || truncate -s $VOLUME_BACKING_FILE_SIZE $VOLUME_BACKING_FILE
- DEV=`sudo losetup -f --show $VOLUME_BACKING_FILE`
-
- # Only create if the loopback device doesn't contain $VOLUME_GROUP
- if ! sudo vgs $VOLUME_GROUP; then
- sudo vgcreate $VOLUME_GROUP $DEV
- fi
- else
- sudo vgcreate $VOLUME_GROUP $VOLUME_BACKING_DEVICE
- fi
- fi
- if [ "$CINDER_MULTI_LVM_BACKEND" = "True" ]; then
- #set up the second volume if CINDER_MULTI_LVM_BACKEND is enabled
-
- if ! sudo vgs $VOLUME_GROUP2; then
- if [ -z "$VOLUME_BACKING_DEVICE2" ]; then
- # Only create if the file doesn't already exists
- [[ -f $VOLUME_BACKING_FILE2 ]] || truncate -s $VOLUME_BACKING_FILE_SIZE $VOLUME_BACKING_FILE2
-
- DEV=`sudo losetup -f --show $VOLUME_BACKING_FILE2`
-
- # Only create if the loopback device doesn't contain $VOLUME_GROUP
- if ! sudo vgs $VOLUME_GROUP2; then
- sudo vgcreate $VOLUME_GROUP2 $DEV
- fi
- else
- sudo vgcreate $VOLUME_GROUP2 $VOLUME_BACKING_DEVICE2
- fi
- fi
- fi
-
- mkdir -p $CINDER_STATE_PATH/volumes
-}
-
# init_cinder() - Initialize database and volume group
function init_cinder {
# Force nova volumes off
@@ -442,26 +366,17 @@
$CINDER_BIN_DIR/cinder-manage db sync
fi
- if is_service_enabled c-vol; then
-
- create_cinder_volume_group
-
- if sudo vgs $VOLUME_GROUP; then
- if is_fedora || is_suse; then
- # service is not started by default
- start_service tgtd
+ if is_service_enabled c-vol && [[ -n "$CINDER_ENABLED_BACKENDS" ]]; then
+ for be in ${CINDER_ENABLED_BACKENDS//,/ }; do
+ BE_TYPE=${be%%:*}
+ BE_NAME=${be##*:}
+ if type init_cinder_backend_${BE_TYPE} >/dev/null 2>&1; then
+ init_cinder_backend_${BE_TYPE} ${BE_NAME}
fi
-
- # Remove iscsi targets
- sudo tgtadm --op show --mode target | grep $VOLUME_NAME_PREFIX | grep Target | cut -f3 -d ' ' | sudo xargs -n1 tgt-admin --delete || true
- # Start with a clean volume group
- _clean_lvm_lv $VOLUME_GROUP $VOLUME_NAME_PREFIX
- if [ "$CINDER_MULTI_LVM_BACKEND" = "True" ]; then
- _clean_lvm_lv $VOLUME_GROUP2 $VOLUME_NAME_PREFIX
- fi
- fi
+ done
fi
+ mkdir -p $CINDER_STATE_PATH/volumes
create_cinder_cache_dir
}
@@ -513,6 +428,11 @@
fi
screen_it c-api "cd $CINDER_DIR && $CINDER_BIN_DIR/cinder-api --config-file $CINDER_CONF"
+ echo "Waiting for Cinder API to start..."
+ if ! wait_for_service $SERVICE_TIMEOUT $CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT; then
+ die $LINENO "c-api did not start"
+ fi
+
screen_it c-sch "cd $CINDER_DIR && $CINDER_BIN_DIR/cinder-scheduler --config-file $CINDER_CONF"
screen_it c-bak "cd $CINDER_DIR && $CINDER_BIN_DIR/cinder-backup --config-file $CINDER_CONF"
screen_it c-vol "cd $CINDER_DIR && $CINDER_BIN_DIR/cinder-volume --config-file $CINDER_CONF"
@@ -543,6 +463,30 @@
fi
}
+# create_volume_types() - Create Cinder's configured volume types
+function create_volume_types {
+ # Create volume types
+ if is_service_enabled c-api && [[ -n "$CINDER_ENABLED_BACKENDS" ]]; then
+ for be in ${CINDER_ENABLED_BACKENDS//,/ }; do
+ BE_TYPE=${be%%:*}
+ BE_NAME=${be##*:}
+ if type configure_cinder_backend_${BE_TYPE} >/dev/null 2>&1; then
+ # openstack volume type create --property volume_backend_name="${BE_TYPE}" ${BE_NAME}
+ cinder type-create ${BE_NAME} && \
+ cinder type-key ${BE_NAME} set volume_backend_name="${BE_NAME}"
+ fi
+ done
+ fi
+}
+
+# Compatibility for Grenade
+
+function create_cinder_volume_group {
+ # During a transition period Grenade needs to have this function defined
+ # It is effectively a no-op in the Grenade 'target' use case
+ :
+}
+
# Restore xtrace
$XTRACE
diff --git a/lib/cinder_backends/lvm b/lib/cinder_backends/lvm
new file mode 100644
index 0000000..324c323
--- /dev/null
+++ b/lib/cinder_backends/lvm
@@ -0,0 +1,179 @@
+# lib/cinder_backends/lvm
+# Configure the LVM backend
+
+# Enable with:
+#
+# CINDER_ENABLED_BACKENDS+=,lvm:lvmname
+
+# Dependencies:
+#
+# - ``functions`` file
+# - ``cinder`` configurations
+
+# CINDER_CONF
+# DATA_DIR
+
+# clean_cinder_backend_lvm - called from clean_cinder()
+# configure_cinder_backend_lvm - called from configure_cinder()
+# init_cinder_backend_lvm - called from init_cinder()
+
+
+# Save trace setting
+MY_XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+
+# Defaults
+# --------
+
+# Name of the lvm volume groups to use/create for iscsi volumes
+# This monkey-motion is for compatibility with icehouse-generation Grenade
+# If ``VOLUME_GROUP`` is set, use it, otherwise we'll build a VG name based
+# on ``VOLUME_GROUP_NAME`` that includes the backend name
+# Grenade doesn't use ``VOLUME_GROUP2`` so it is left out
+VOLUME_GROUP_NAME=${VOLUME_GROUP:-${VOLUME_GROUP_NAME:-stack-volumes}}
+
+# TODO: resurrect backing device...need to know how to set values
+#VOLUME_BACKING_DEVICE=${VOLUME_BACKING_DEVICE:-}
+
+VOLUME_NAME_PREFIX=${VOLUME_NAME_PREFIX:-volume-}
+
+
+# Entry Points
+# ------------
+
+# Compatibility for getting a volume group name from either ``VOLUME_GROUP``
+# or from ``VOLUME_GROUP_NAME`` plus the backend name
+function get_volume_group_name {
+ local be_name=$1
+
+ # Again with the icehouse-generation compatibility
+ local volume_group_name=$VOLUME_GROUP_NAME
+ if [[ -z $VOLUME_GROUP ]]; then
+ volume_group_name+="-$be_name"
+ fi
+ echo $volume_group_name
+}
+
+function cleanup_cinder_backend_lvm {
+ local be_name=$1
+
+ # Again with the icehouse-generation compatibility
+ local volume_group_name=$(get_volume_group_name $be_name)
+
+ # Campsite rule: leave behind a volume group at least as clean as we found it
+ _clean_lvm_lv ${volume_group_name} $VOLUME_NAME_PREFIX
+ _clean_lvm_backing_file ${volume_group_name} $DATA_DIR/${volume_group_name}-backing-file
+}
+
+# configure_cinder_backend_lvm - Set config files, create data dirs, etc
+# configure_cinder_backend_lvm $name
+function configure_cinder_backend_lvm {
+ local be_name=$1
+
+ # Again with the icehouse-generation compatibility
+ local volume_group_name=$(get_volume_group_name $be_name)
+
+ iniset $CINDER_CONF $be_name volume_backend_name $be_name
+ iniset $CINDER_CONF $be_name volume_driver "cinder.volume.drivers.lvm.LVMISCSIDriver"
+ iniset $CINDER_CONF $be_name volume_group $volume_group_name
+
+ if [[ "$CINDER_SECURE_DELETE" == "False" ]]; then
+ iniset $CINDER_CONF $be_name volume_clear none
+ fi
+}
+
+
+function init_cinder_backend_lvm {
+ local be_name=$1
+
+ # Again with the icehouse-generation compatibility
+ local volume_group_name=$(get_volume_group_name $be_name)
+
+ # Start with a clean volume group
+ _create_cinder_volume_group ${volume_group_name} $DATA_DIR/${volume_group_name}-backing-file
+
+ if is_fedora || is_suse; then
+ # service is not started by default
+ start_service tgtd
+ fi
+
+ # Remove iscsi targets
+ sudo tgtadm --op show --mode target | grep $VOLUME_NAME_PREFIX | grep Target | cut -f3 -d ' ' | sudo xargs -n1 tgt-admin --delete || true
+ _clean_lvm_lv ${volume_group_name} $VOLUME_NAME_PREFIX
+}
+
+
+# _clean_lvm_lv removes all cinder LVM volumes
+#
+# Usage: _clean_lvm_lv volume-group-name $VOLUME_NAME_PREFIX
+function _clean_lvm_lv {
+ local vg=$1
+ local lv_prefix=$2
+
+ # Clean out existing volumes
+ for lv in $(sudo lvs --noheadings -o lv_name $vg 2>/dev/null); do
+ # lv_prefix prefixes the LVs we want
+ if [[ "${lv#$lv_prefix}" != "$lv" ]]; then
+ sudo lvremove -f $vg/$lv
+ fi
+ done
+}
+
+# _clean_lvm_backing_file() removes the backing file of the
+# volume group used by cinder
+#
+# Usage: _clean_lvm_backing_file() volume-group-name backing-file-name
+function _clean_lvm_backing_file {
+ local vg=$1
+ local backing_file=$2
+
+ # if there is no logical volume left, it's safe to attempt a cleanup
+ # of the backing file
+ if [[ -z "$(sudo lvs --noheadings -o lv_name $vg 2>/dev/null)" ]]; then
+ # if the backing physical device is a loop device, it was probably setup by devstack
+ VG_DEV=$(sudo losetup -j $backing_file | awk -F':' '/backing-file/ { print $1}')
+ if [[ -n "$VG_DEV" ]] && [[ -e "$VG_DEV" ]]; then
+ sudo losetup -d $VG_DEV
+ rm -f $backing_file
+ fi
+ fi
+}
+
+# _create_cinder_volume_group volume-group-name backing-file-name
+function _create_cinder_volume_group {
+ # According to the ``CINDER_MULTI_LVM_BACKEND`` value, configure one or two default volumes
+ # group called ``stack-volumes`` (and ``stack-volumes2``) for the volume
+ # service if it (they) does (do) not yet exist. If you don't wish to use a
+ # file backed volume group, create your own volume group called ``stack-volumes``
+ # and ``stack-volumes2`` before invoking ``stack.sh``.
+ #
+ # The two backing files are ``VOLUME_BACKING_FILE_SIZE`` in size, and they are stored in
+ # the ``DATA_DIR``.
+
+ local vg_name=$1
+ local backing_file=$2
+
+ if ! sudo vgs $vg_name; then
+ # TODO: fix device handling
+ if [ -z "$VOLUME_BACKING_DEVICE" ]; then
+ # Only create if the file doesn't already exists
+ [[ -f $backing_file ]] || truncate -s $VOLUME_BACKING_FILE_SIZE $backing_file
+ DEV=`sudo losetup -f --show $backing_file`
+
+ # Only create if the loopback device doesn't contain $VOLUME_GROUP
+ if ! sudo vgs $vg_name; then
+ sudo vgcreate $vg_name $DEV
+ fi
+ else
+ sudo vgcreate $vg_name $VOLUME_BACKING_DEVICE
+ fi
+ fi
+}
+
+
+# Restore xtrace
+$MY_XTRACE
+
+# mode: shell-script
+# End:
diff --git a/lib/cinder_backends/nfs b/lib/cinder_backends/nfs
new file mode 100644
index 0000000..7648788
--- /dev/null
+++ b/lib/cinder_backends/nfs
@@ -0,0 +1,43 @@
+# lib/cinder_backends/nfs
+# Configure the nfs backend
+
+# Enable with:
+#
+# CINDER_ENABLED_BACKENDS+=,nfs:<volume-type-name>
+
+# Dependencies:
+#
+# - ``functions`` file
+# - ``cinder`` configurations
+
+# CINDER_CONF
+# CINDER_CONF_DIR
+# CINDER_NFS_SERVERPATH - contents of nfs shares config file
+
+# configure_cinder_backend_nfs - Configure Cinder for NFS backends
+
+# Save trace setting
+NFS_XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+
+# Entry Points
+# ------------
+
+# configure_cinder_backend_nfs - Set config files, create data dirs, etc
+function configure_cinder_backend_nfs {
+ local be_name=$1
+ iniset $CINDER_CONF $be_name volume_backend_name $be_name
+ iniset $CINDER_CONF $be_name volume_driver "cinder.volume.drivers.nfs.NfsDriver"
+ iniset $CINDER_CONF $be_name nfs_shares_config "$CINDER_CONF_DIR/nfs-shares-$be_name.conf"
+
+ echo "$CINDER_NFS_SERVERPATH" | tee "$CINDER_CONF_DIR/nfs-shares-$be_name.conf"
+}
+
+
+# Restore xtrace
+$NFS_XTRACE
+
+# Local variables:
+# mode: shell-script
+# End:
diff --git a/lib/config b/lib/config
index 552aeb0..67d788c 100644
--- a/lib/config
+++ b/lib/config
@@ -82,8 +82,6 @@
local matchgroup=$2
local configfile=$3
- [[ -r $configfile ]] || touch $configfile
-
get_meta_section $file $matchgroup $configfile | \
$CONFIG_AWK_CMD -v configfile=$configfile '
BEGIN { section = "" }
@@ -114,7 +112,7 @@
for group in $matchgroups; do
for configfile in $(get_meta_section_files $localfile $group); do
- if [[ -d $(dirname $configfile) ]]; then
+ if [[ -d $(dirname $(eval "echo $configfile")) ]]; then
merge_config_file $localfile $group $configfile
fi
done
diff --git a/lib/databases/mysql b/lib/databases/mysql
index ea22d14..0ccfce5 100644
--- a/lib/databases/mysql
+++ b/lib/databases/mysql
@@ -88,6 +88,7 @@
# set default db type to InnoDB
sudo bash -c "source $TOP_DIR/functions && \
iniset $MY_CONF mysqld bind-address 0.0.0.0 && \
+ iniset $MY_CONF mysqld sql_mode STRICT_ALL_TABLES && \
iniset $MY_CONF mysqld default-storage-engine InnoDB"
diff --git a/lib/databases/postgresql b/lib/databases/postgresql
index 96a5947..6e85d6e 100644
--- a/lib/databases/postgresql
+++ b/lib/databases/postgresql
@@ -10,6 +10,9 @@
set +o xtrace
+MAX_DB_CONNECTIONS=${MAX_DB_CONNECTIONS:-200}
+
+
register_database postgresql
@@ -23,7 +26,7 @@
# Get ruthless with mysql
apt_get purge -y postgresql*
return
- elif is_fedora; then
+ elif is_fedora || is_suse; then
uninstall_package postgresql-server
else
return
@@ -64,6 +67,8 @@
fi
# Listen on all addresses
sudo sed -i "/listen_addresses/s/.*/listen_addresses = '*'/" $PG_CONF
+ # Set max_connections
+ sudo sed -i "/max_connections/s/.*/max_connections = $MAX_DB_CONNECTIONS/" $PG_CONF
# Do password auth from all IPv4 clients
sudo sed -i "/^host/s/all\s\+127.0.0.1\/32\s\+ident/$DATABASE_USER\t0.0.0.0\/0\tpassword/" $PG_HBA
# Do password auth for all IPv6 clients
diff --git a/lib/glance b/lib/glance
index 51e4399..92577d9 100644
--- a/lib/glance
+++ b/lib/glance
@@ -89,9 +89,7 @@
iniset $GLANCE_REGISTRY_CONF DEFAULT sql_connection $dburl
iniset $GLANCE_REGISTRY_CONF DEFAULT use_syslog $SYSLOG
iniset $GLANCE_REGISTRY_CONF paste_deploy flavor keystone
- iniset $GLANCE_REGISTRY_CONF keystone_authtoken auth_host $KEYSTONE_AUTH_HOST
- iniset $GLANCE_REGISTRY_CONF keystone_authtoken auth_port $KEYSTONE_AUTH_PORT
- iniset $GLANCE_REGISTRY_CONF keystone_authtoken auth_protocol $KEYSTONE_AUTH_PROTOCOL
+ iniset $GLANCE_REGISTRY_CONF keystone_authtoken identity_uri $KEYSTONE_AUTH_URI
iniset $GLANCE_REGISTRY_CONF keystone_authtoken cafile $KEYSTONE_SSL_CA
configure_API_version $GLANCE_REGISTRY_CONF $IDENTITY_API_VERSION
iniset $GLANCE_REGISTRY_CONF keystone_authtoken admin_tenant_name $SERVICE_TENANT_NAME
@@ -107,9 +105,7 @@
iniset $GLANCE_API_CONF DEFAULT filesystem_store_datadir $GLANCE_IMAGE_DIR/
iniset $GLANCE_API_CONF DEFAULT image_cache_dir $GLANCE_CACHE_DIR/
iniset $GLANCE_API_CONF paste_deploy flavor keystone+cachemanagement
- iniset $GLANCE_API_CONF keystone_authtoken auth_host $KEYSTONE_AUTH_HOST
- iniset $GLANCE_API_CONF keystone_authtoken auth_port $KEYSTONE_AUTH_PORT
- iniset $GLANCE_API_CONF keystone_authtoken auth_protocol $KEYSTONE_AUTH_PROTOCOL
+ iniset $GLANCE_API_CONF keystone_authtoken identity_uri $KEYSTONE_AUTH_URI
iniset $GLANCE_API_CONF keystone_authtoken cafile $KEYSTONE_SSL_CA
configure_API_version $GLANCE_API_CONF $IDENTITY_API_VERSION
iniset $GLANCE_API_CONF keystone_authtoken admin_tenant_name $SERVICE_TENANT_NAME
@@ -128,7 +124,7 @@
# Store the images in swift if enabled.
if is_service_enabled s-proxy; then
iniset $GLANCE_API_CONF DEFAULT default_store swift
- iniset $GLANCE_API_CONF DEFAULT swift_store_auth_address $KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v2.0/
+ iniset $GLANCE_API_CONF DEFAULT swift_store_auth_address $KEYSTONE_SERVICE_URI/v2.0/
iniset $GLANCE_API_CONF DEFAULT swift_store_user $SERVICE_TENANT_NAME:glance-swift
iniset $GLANCE_API_CONF DEFAULT swift_store_key $SERVICE_PASSWORD
iniset $GLANCE_API_CONF DEFAULT swift_store_create_container_on_put True
@@ -147,7 +143,7 @@
iniset $GLANCE_CACHE_CONF DEFAULT filesystem_store_datadir $GLANCE_IMAGE_DIR/
iniset $GLANCE_CACHE_CONF DEFAULT image_cache_dir $GLANCE_CACHE_DIR/
iniuncomment $GLANCE_CACHE_CONF DEFAULT auth_url
- iniset $GLANCE_CACHE_CONF DEFAULT auth_url $KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT/v2.0
+ iniset $GLANCE_CACHE_CONF DEFAULT auth_url $KEYSTONE_AUTH_URI/v2.0
iniuncomment $GLANCE_CACHE_CONF DEFAULT auth_tenant_name
iniset $GLANCE_CACHE_CONF DEFAULT admin_tenant_name $SERVICE_TENANT_NAME
iniuncomment $GLANCE_CACHE_CONF DEFAULT auth_user
@@ -168,36 +164,28 @@
function create_glance_accounts {
if is_service_enabled g-api; then
- openstack user create \
- --password "$SERVICE_PASSWORD" \
- --project $SERVICE_TENANT_NAME \
- glance
- openstack role add \
- --project $SERVICE_TENANT_NAME \
- --user glance \
- service
+
+ GLANCE_USER=$(get_or_create_user "glance" \
+ "$SERVICE_PASSWORD" $SERVICE_TENANT_NAME)
+ get_or_add_user_role service $GLANCE_USER $SERVICE_TENANT_NAME
+
# required for swift access
if is_service_enabled s-proxy; then
- openstack user create \
- --password "$SERVICE_PASSWORD" \
- --project $SERVICE_TENANT_NAME \
- glance-swift
- openstack role add \
- --project $SERVICE_TENANT_NAME \
- --user glance-swift \
- ResellerAdmin
+
+ GLANCE_SWIFT_USER=$(get_or_create_user "glance-swift" \
+ "$SERVICE_PASSWORD" $SERVICE_TENANT_NAME "glance-swift@example.com")
+ get_or_add_user_role "ResellerAdmin" $GLANCE_SWIFT_USER $SERVICE_TENANT_NAME
fi
+
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
- openstack service create \
- --type image \
- --description "Glance Image Service" \
- glance
- openstack endpoint create \
- --region RegionOne \
- --publicurl "http://$GLANCE_HOSTPORT" \
- --adminurl "http://$GLANCE_HOSTPORT" \
- --internalurl "http://$GLANCE_HOSTPORT" \
- glance
+
+ GLANCE_SERVICE=$(get_or_create_service "glance" \
+ "image" "Glance Image Service")
+ get_or_create_endpoint $GLANCE_SERVICE \
+ "$REGION_NAME" \
+ "http://$GLANCE_HOSTPORT" \
+ "http://$GLANCE_HOSTPORT" \
+ "http://$GLANCE_HOSTPORT"
fi
fi
}
diff --git a/lib/heat b/lib/heat
index fe75ec9..510b683 100644
--- a/lib/heat
+++ b/lib/heat
@@ -98,6 +98,8 @@
iniset $HEAT_CONF database connection `database_connection_url heat`
iniset $HEAT_CONF DEFAULT auth_encryption_key `hexdump -n 16 -v -e '/1 "%02x"' /dev/urandom`
+ iniset $HEAT_CONF DEFAULT region_name_for_services "$REGION_NAME"
+
# logging
iniset $HEAT_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL
iniset $HEAT_CONF DEFAULT use_syslog $SYSLOG
@@ -107,9 +109,7 @@
fi
# keystone authtoken
- iniset $HEAT_CONF keystone_authtoken auth_host $KEYSTONE_AUTH_HOST
- iniset $HEAT_CONF keystone_authtoken auth_port $KEYSTONE_AUTH_PORT
- iniset $HEAT_CONF keystone_authtoken auth_protocol $KEYSTONE_AUTH_PROTOCOL
+ iniset $HEAT_CONF keystone_authtoken identity_uri $KEYSTONE_AUTH_URI
configure_API_version $HEAT_CONF $IDENTITY_API_VERSION
iniset $HEAT_CONF keystone_authtoken cafile $KEYSTONE_SSL_CA
iniset $HEAT_CONF keystone_authtoken admin_tenant_name $SERVICE_TENANT_NAME
@@ -117,8 +117,12 @@
iniset $HEAT_CONF keystone_authtoken admin_password $SERVICE_PASSWORD
iniset $HEAT_CONF keystone_authtoken signing_dir $HEAT_AUTH_CACHE_DIR
+ if is_ssl_enabled_service "key"; then
+ iniset $HEAT_CONF clients_keystone ca_file $KEYSTONE_SSL_CA
+ fi
+
# ec2authtoken
- iniset $HEAT_CONF ec2authtoken auth_uri $KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v2.0
+ iniset $HEAT_CONF ec2authtoken auth_uri $KEYSTONE_SERVICE_URI/v2.0
# paste_deploy
[[ "$HEAT_STANDALONE" = "True" ]] && iniset $HEAT_CONF paste_deploy flavor standalone
@@ -212,79 +216,72 @@
SERVICE_TENANT=$(openstack project list | awk "/ $SERVICE_TENANT_NAME / { print \$2 }")
ADMIN_ROLE=$(openstack role list | awk "/ admin / { print \$2 }")
- HEAT_USER=$(openstack user create \
- heat \
- --password "$SERVICE_PASSWORD" \
- --project $SERVICE_TENANT \
- --email heat@example.com \
- | grep " id " | get_field 2)
- openstack role add \
- $ADMIN_ROLE \
- --project $SERVICE_TENANT \
- --user $HEAT_USER
+ HEAT_USER=$(get_or_create_user "heat" \
+ "$SERVICE_PASSWORD" $SERVICE_TENANT)
+ get_or_add_user_role $ADMIN_ROLE $HEAT_USER $SERVICE_TENANT
+
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
- HEAT_SERVICE=$(openstack service create \
- heat \
- --type=orchestration \
- --description="Heat Orchestration Service" \
- | grep " id " | get_field 2)
- openstack endpoint create \
- $HEAT_SERVICE \
- --region RegionOne \
- --publicurl "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s" \
- --adminurl "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s" \
- --internalurl "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s"
- HEAT_CFN_SERVICE=$(openstack service create \
- heat \
- --type=cloudformation \
- --description="Heat CloudFormation Service" \
- | grep " id " | get_field 2)
- openstack endpoint create \
- $HEAT_CFN_SERVICE \
- --region RegionOne \
- --publicurl "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1" \
- --adminurl "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1" \
- --internalurl "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1"
+
+ HEAT_SERVICE=$(get_or_create_service "heat" \
+ "orchestration" "Heat Orchestration Service")
+ get_or_create_endpoint $HEAT_SERVICE \
+ "$REGION_NAME" \
+ "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s" \
+ "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s" \
+ "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s"
+
+ HEAT_CFN_SERVICE=$(get_or_create_service "heat-cfn" \
+ "cloudformation" "Heat CloudFormation Service")
+ get_or_create_endpoint $HEAT_CFN_SERVICE \
+ "$REGION_NAME" \
+ "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1" \
+ "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1" \
+ "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1"
fi
# heat_stack_user role is for users created by Heat
- openstack role create heat_stack_user
+ get_or_create_role "heat_stack_user"
if [[ $HEAT_DEFERRED_AUTH == trusts ]]; then
+
# heat_stack_owner role is given to users who create Heat stacks,
# it's the default role used by heat to delegate to the heat service
# user (for performing deferred operations via trusts), see heat.conf
- HEAT_OWNER_ROLE=$(openstack role create \
- heat_stack_owner \
- | grep " id " | get_field 2)
+ HEAT_OWNER_ROLE=$(get_or_create_role "heat_stack_owner")
# Give the role to the demo and admin users so they can create stacks
# in either of the projects created by devstack
- openstack role add $HEAT_OWNER_ROLE --project demo --user demo
- openstack role add $HEAT_OWNER_ROLE --project demo --user admin
- openstack role add $HEAT_OWNER_ROLE --project admin --user admin
+ get_or_add_user_role $HEAT_OWNER_ROLE demo demo
+ get_or_add_user_role $HEAT_OWNER_ROLE admin demo
+ get_or_add_user_role $HEAT_OWNER_ROLE admin admin
iniset $HEAT_CONF DEFAULT deferred_auth_method trusts
fi
if [[ "$HEAT_STACK_DOMAIN" == "True" ]]; then
# Note we have to pass token/endpoint here because the current endpoint and
# version negotiation in OSC means just --os-identity-api-version=3 won't work
- KS_ENDPOINT_V3="$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v3"
- D_ID=$(openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
- --os-identity-api-version=3 domain create heat \
- --description "Owns users and projects created by heat" \
- | grep ' id ' | get_field 2)
- iniset $HEAT_CONF DEFAULT stack_user_domain ${D_ID}
+ KS_ENDPOINT_V3="$KEYSTONE_SERVICE_URI/v3"
- openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
- --os-identity-api-version=3 user create --password $SERVICE_PASSWORD \
- --domain $D_ID heat_domain_admin \
- --description "Manages users and projects created by heat"
- openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
- --os-identity-api-version=3 role add \
- --user heat_domain_admin --domain ${D_ID} admin
- iniset $HEAT_CONF DEFAULT stack_domain_admin heat_domain_admin
- iniset $HEAT_CONF DEFAULT stack_domain_admin_password $SERVICE_PASSWORD
+ D_ID=$(openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
+ --os-identity-api-version=3 domain list | grep ' heat ' | get_field 1)
+
+ if [[ -z "$D_ID" ]]; then
+ D_ID=$(openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
+ --os-identity-api-version=3 domain create heat \
+ --description "Owns users and projects created by heat" \
+ | grep ' id ' | get_field 2)
+ iniset $HEAT_CONF DEFAULT stack_user_domain ${D_ID}
+
+ openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
+ --os-identity-api-version=3 user create --password $SERVICE_PASSWORD \
+ --domain $D_ID heat_domain_admin \
+ --description "Manages users and projects created by heat"
+ openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
+ --os-identity-api-version=3 role add \
+ --user heat_domain_admin --domain ${D_ID} admin
+ iniset $HEAT_CONF DEFAULT stack_domain_admin heat_domain_admin
+ iniset $HEAT_CONF DEFAULT stack_domain_admin_password $SERVICE_PASSWORD
+ fi
fi
}
diff --git a/lib/horizon b/lib/horizon
index 9e4f2f9..a65b243 100644
--- a/lib/horizon
+++ b/lib/horizon
@@ -26,6 +26,7 @@
# Set up default directories
HORIZON_DIR=$DEST/horizon
+HORIZONAUTH_DIR=$DEST/django_openstack_auth
# local_settings.py is used to customize Dashboard settings.
# The example file in Horizon repo is used by default.
@@ -75,6 +76,9 @@
sudo rm /usr/bin/node
fi
fi
+
+ local horizon_conf=$(apache_site_config_for horizon)
+ sudo rm -f $horizon_conf
}
# configure_horizon() - Set config files, create data dirs, etc
@@ -107,7 +111,7 @@
fi
_horizon_config_set $local_settings "" OPENSTACK_HOST \"${KEYSTONE_SERVICE_HOST}\"
- _horizon_config_set $local_settings "" OPENSTACK_KEYSTONE_URL "\"${KEYSTONE_SERVICE_PROTOCOL}://%s:${KEYSTONE_SERVICE_PORT}/v2.0\" % OPENSTACK_HOST"
+ _horizon_config_set $local_settings "" OPENSTACK_KEYSTONE_URL "\"${KEYSTONE_SERVICE_PROTOCOL}://${KEYSTONE_SERVICE_HOST}:${KEYSTONE_SERVICE_PORT}/v2.0\""
if [ -f $SSL_BUNDLE_FILE ]; then
_horizon_config_set $local_settings "" OPENSTACK_SSL_CACERT \"${SSL_BUNDLE_FILE}\"
@@ -123,21 +127,6 @@
fi
local horizon_conf=$(apache_site_config_for horizon)
- if is_ubuntu; then
- disable_apache_site 000-default
- sudo touch $horizon_conf
- enable_apache_site horizon
- elif is_fedora; then
- sudo sed '/^Listen/s/^.*$/Listen 0.0.0.0:80/' -i /etc/httpd/conf/httpd.conf
- elif is_suse; then
- : # nothing to do
- else
- exit_distro_not_supported "horizon apache configuration"
- fi
-
- # Remove old log files that could mess with how devstack detects whether Horizon
- # has been successfully started (see start_horizon() and functions::screen_it())
- sudo rm -f /var/log/$APACHE_NAME/horizon_*
# Configure apache to run horizon
sudo sh -c "sed -e \"
@@ -148,6 +137,29 @@
s,%DEST%,$DEST,g;
s,%HORIZON_REQUIRE%,$HORIZON_REQUIRE,g;
\" $FILES/apache-horizon.template >$horizon_conf"
+
+ if is_ubuntu; then
+ disable_apache_site 000-default
+ sudo touch $horizon_conf
+ elif is_fedora; then
+ sudo sed '/^Listen/s/^.*$/Listen 0.0.0.0:80/' -i /etc/httpd/conf/httpd.conf
+ elif is_suse; then
+ : # nothing to do
+ else
+ exit_distro_not_supported "horizon apache configuration"
+ fi
+ enable_apache_site horizon
+
+ # Remove old log files that could mess with how devstack detects whether Horizon
+ # has been successfully started (see start_horizon() and functions::screen_it())
+ sudo rm -f /var/log/$APACHE_NAME/horizon_*
+
+}
+
+# install_django_openstack_auth() - Collect source and prepare
+function install_django_openstack_auth {
+ git_clone $HORIZONAUTH_REPO $HORIZONAUTH_DIR $HORIZONAUTH_BRANCH
+ setup_install $HORIZONAUTH_DIR
}
# install_horizon() - Collect source and prepare
diff --git a/lib/infra b/lib/infra
index e2f7dad..e18c66e 100644
--- a/lib/infra
+++ b/lib/infra
@@ -10,7 +10,6 @@
# ``stack.sh`` calls the entry points in this order:
#
-# - unfubar_setuptools
# - install_infra
# Save trace setting
@@ -26,19 +25,6 @@
# Entry Points
# ------------
-# unfubar_setuptools() - Unbreak the giant mess that is the current state of setuptools
-function unfubar_setuptools {
- # this is a giant game of who's on first, but it does consistently work
- # there is hope that upstream python packaging fixes this in the future
- echo_summary "Unbreaking setuptools"
- pip_install -U setuptools
- pip_install -U pip
- uninstall_package python-setuptools
- pip_install -U setuptools
- pip_install -U pip
-}
-
-
# install_infra() - Collect source and prepare
function install_infra {
# bring down global requirements
diff --git a/lib/ironic b/lib/ironic
index 389040c..08ac278 100644
--- a/lib/ironic
+++ b/lib/ironic
@@ -53,12 +53,7 @@
IRONIC_VM_SSH_ADDRESS=${IRONIC_VM_SSH_ADDRESS:-$HOST_IP}
IRONIC_VM_COUNT=${IRONIC_VM_COUNT:-1}
IRONIC_VM_SPECS_CPU=${IRONIC_VM_SPECS_CPU:-1}
-# NOTE(adam_g): Kernels 3.12 and newer user tmpfs by default for initramfs.
-# DIB produced ramdisks tend to be ~250MB but tmpfs will only allow
-# use of 50% of available memory before ENOSPC. Set minimum 1GB
-# for nodes to avoid (LP: #1311987) and ensure consistency across
-# older and newer kernels.
-IRONIC_VM_SPECS_RAM=${IRONIC_VM_SPECS_RAM:-1024}
+IRONIC_VM_SPECS_RAM=${IRONIC_VM_SPECS_RAM:-512}
IRONIC_VM_SPECS_DISK=${IRONIC_VM_SPECS_DISK:-10}
IRONIC_VM_EPHEMERAL_DISK=${IRONIC_VM_EPHEMERAL_DISK:-0}
IRONIC_VM_EMULATOR=${IRONIC_VM_EMULATOR:-/usr/bin/qemu-system-x86_64}
@@ -147,6 +142,11 @@
configure_ironic_api
fi
+ # Format logging
+ if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then
+ setup_colorized_logging $IRONIC_CONF_FILE DEFAULT
+ fi
+
if [[ "$IRONIC_BAREMETAL_BASIC_OPS" == "True" ]]; then
configure_ironic_auxiliary
fi
@@ -157,11 +157,9 @@
function configure_ironic_api {
iniset $IRONIC_CONF_FILE DEFAULT auth_strategy keystone
iniset $IRONIC_CONF_FILE DEFAULT policy_file $IRONIC_POLICY_JSON
- iniset $IRONIC_CONF_FILE keystone_authtoken auth_host $KEYSTONE_AUTH_HOST
- iniset $IRONIC_CONF_FILE keystone_authtoken auth_port $KEYSTONE_AUTH_PORT
- iniset $IRONIC_CONF_FILE keystone_authtoken auth_protocol $KEYSTONE_AUTH_PROTOCOL
+ iniset $IRONIC_CONF_FILE keystone_authtoken identity_uri $KEYSTONE_AUTH_URI
iniset $IRONIC_CONF_FILE keystone_authtoken cafile $KEYSTONE_SSL_CA
- iniset $IRONIC_CONF_FILE keystone_authtoken auth_uri $KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/
+ iniset $IRONIC_CONF_FILE keystone_authtoken auth_uri $KEYSTONE_SERVICE_URI
iniset $IRONIC_CONF_FILE keystone_authtoken admin_tenant_name $SERVICE_TENANT_NAME
iniset $IRONIC_CONF_FILE keystone_authtoken admin_user ironic
iniset $IRONIC_CONF_FILE keystone_authtoken admin_password $SERVICE_PASSWORD
@@ -220,28 +218,21 @@
# Ironic
if [[ "$ENABLED_SERVICES" =~ "ir-api" ]]; then
- IRONIC_USER=$(openstack user create \
- ironic \
- --password "$SERVICE_PASSWORD" \
- --project $SERVICE_TENANT \
- --email ironic@example.com \
- | grep " id " | get_field 2)
- openstack role add \
- $ADMIN_ROLE \
- --project $SERVICE_TENANT \
- --user $IRONIC_USER
+ # Get ironic user if exists
+
+ IRONIC_USER=$(get_or_create_user "ironic" \
+ "$SERVICE_PASSWORD" $SERVICE_TENANT)
+ get_or_add_user_role $ADMIN_ROLE $IRONIC_USER $SERVICE_TENANT
+
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
- IRONIC_SERVICE=$(openstack service create \
- ironic \
- --type=baremetal \
- --description="Ironic baremetal provisioning service" \
- | grep " id " | get_field 2)
- openstack endpoint create \
- $IRONIC_SERVICE \
- --region RegionOne \
- --publicurl "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT" \
- --adminurl "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT" \
- --internalurl "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT"
+
+ IRONIC_SERVICE=$(get_or_create_service "ironic" \
+ "baremetal" "Ironic baremetal provisioning service")
+ get_or_create_endpoint $IRONIC_SERVICE \
+ "$REGION_NAME" \
+ "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT" \
+ "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT" \
+ "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT"
fi
fi
}
@@ -253,7 +244,7 @@
recreate_database ironic utf8
# Migrate ironic database
- $IRONIC_BIN_DIR/ironic-dbsync
+ $IRONIC_BIN_DIR/ironic-dbsync --config-file=$IRONIC_CONF_FILE
create_ironic_cache_dir
}
@@ -352,6 +343,8 @@
while read MAC; do
NODE_ID=$(ironic node-create --chassis_uuid $CHASSIS_ID --driver pxe_ssh \
+ -i pxe_deploy_kernel=$IRONIC_DEPLOY_KERNEL_ID \
+ -i pxe_deploy_ramdisk=$IRONIC_DEPLOY_RAMDISK_ID \
-i ssh_virt_type=$IRONIC_SSH_VIRT_TYPE \
-i ssh_address=$IRONIC_VM_SSH_ADDRESS \
-i ssh_port=$IRONIC_VM_SSH_PORT \
@@ -372,6 +365,10 @@
# create the nova flavor
adjusted_disk=$(($IRONIC_VM_SPECS_DISK - $IRONIC_VM_EPHEMERAL_DISK))
nova flavor-create --ephemeral $IRONIC_VM_EPHEMERAL_DISK baremetal auto $IRONIC_VM_SPECS_RAM $adjusted_disk $IRONIC_VM_SPECS_CPU
+ # TODO(lucasagomes): Remove the 'baremetal:deploy_kernel_id'
+ # and 'baremetal:deploy_ramdisk_id' parameters
+ # from the flavor after the completion of
+ # https://blueprints.launchpad.net/ironic/+spec/add-node-instance-info
nova flavor-key baremetal set "cpu_arch"="x86_64" "baremetal:deploy_kernel_id"="$IRONIC_DEPLOY_KERNEL_ID" "baremetal:deploy_ramdisk_id"="$IRONIC_DEPLOY_RAMDISK_ID"
# intentional sleep to make sure the tag has been set to port
diff --git a/lib/keystone b/lib/keystone
index c4266b9..547646a 100644
--- a/lib/keystone
+++ b/lib/keystone
@@ -39,8 +39,16 @@
KEYSTONE_AUTH_CACHE_DIR=${KEYSTONE_AUTH_CACHE_DIR:-/var/cache/keystone}
KEYSTONE_WSGI_DIR=${KEYSTONE_WSGI_DIR:-/var/www/keystone}
+KEYSTONEMIDDLEWARE_DIR=$DEST/keystonemiddleware
KEYSTONECLIENT_DIR=$DEST/python-keystoneclient
+# Set up additional extensions, such as oauth1, federation
+# Example of KEYSTONE_EXTENSIONS=oauth1,federation
+KEYSTONE_EXTENSIONS=${KEYSTONE_EXTENSIONS:-}
+
+# Toggle for deploying Keystone under HTTPD + mod_wsgi
+KEYSTONE_USE_MOD_WSGI=${KEYSTONE_USE_MOD_WSGI:-${ENABLE_HTTPD_MOD_WSGI_SERVICES}}
+
# Select the backend for Keystone's service catalog
KEYSTONE_CATALOG_BACKEND=${KEYSTONE_CATALOG_BACKEND:-sql}
KEYSTONE_CATALOG=$KEYSTONE_CONF_DIR/default_catalog.templates
@@ -55,8 +63,8 @@
KEYSTONE_ASSIGNMENT_BACKEND=${KEYSTONE_ASSIGNMENT_BACKEND:-sql}
# Select Keystone's token format
-# Choose from 'UUID' and 'PKI'
-KEYSTONE_TOKEN_FORMAT=${KEYSTONE_TOKEN_FORMAT:-PKI}
+# Choose from 'UUID', 'PKI', or 'PKIZ'
+KEYSTONE_TOKEN_FORMAT=$(echo ${KEYSTONE_TOKEN_FORMAT} | tr '[:upper:]' '[:lower:]')
# Set Keystone interface configuration
KEYSTONE_AUTH_HOST=${KEYSTONE_AUTH_HOST:-$SERVICE_HOST}
@@ -87,9 +95,9 @@
KEYSTONE_SERVICE_PROTOCOL="https"
fi
-# Apache configuration file for keystone
-KEYSTONE_APACHE_CONF_FILE=$(apache_site_config_for keystone)
-
+# complete URIs
+KEYSTONE_AUTH_URI=${KEYSTONE_AUTH_PROTOCOL}://${KEYSTONE_AUTH_HOST}:${KEYSTONE_AUTH_PORT}
+KEYSTONE_SERVICE_URI=${KEYSTONE_SERVICE_PROTOCOL}://${KEYSTONE_SERVICE_HOST}:${KEYSTONE_SERVICE_PORT}
# Functions
# ---------
@@ -106,18 +114,21 @@
function _cleanup_keystone_apache_wsgi {
sudo rm -f $KEYSTONE_WSGI_DIR/*.wsgi
disable_apache_site keystone
- sudo rm -f $KEYSTONE_APACHE_CONF_FILE
+ sudo rm -f $(apache_site_config_for keystone)
+ restart_apache_server
}
# _config_keystone_apache_wsgi() - Set WSGI config files of Keystone
function _config_keystone_apache_wsgi {
sudo mkdir -p $KEYSTONE_WSGI_DIR
+ local keystone_apache_conf=$(apache_site_config_for keystone)
+
# copy proxy vhost and wsgi file
sudo cp $KEYSTONE_DIR/httpd/keystone.py $KEYSTONE_WSGI_DIR/main
sudo cp $KEYSTONE_DIR/httpd/keystone.py $KEYSTONE_WSGI_DIR/admin
- sudo cp $FILES/apache-keystone.template $KEYSTONE_APACHE_CONF_FILE
+ sudo cp $FILES/apache-keystone.template $keystone_apache_conf
sudo sed -e "
s|%PUBLICPORT%|$KEYSTONE_SERVICE_PORT|g;
s|%ADMINPORT%|$KEYSTONE_AUTH_PORT|g;
@@ -125,7 +136,7 @@
s|%PUBLICWSGI%|$KEYSTONE_WSGI_DIR/main|g;
s|%ADMINWSGI%|$KEYSTONE_WSGI_DIR/admin|g;
s|%USER%|$STACK_USER|g
- " -i $KEYSTONE_APACHE_CONF_FILE
+ " -i $keystone_apache_conf
enable_apache_site keystone
}
@@ -151,6 +162,8 @@
KEYSTONE_PASTE_INI="$KEYSTONE_CONF"
fi
+ configure_keystone_extensions
+
# Rewrite stock ``keystone.conf``
if is_service_enabled ldap; then
@@ -180,6 +193,12 @@
iniset $KEYSTONE_CONF assignment driver "keystone.assignment.backends.$KEYSTONE_ASSIGNMENT_BACKEND.Assignment"
fi
+ # Configure rabbitmq credentials
+ if is_service_enabled rabbit; then
+ iniset $KEYSTONE_CONF DEFAULT rabbit_password $RABBIT_PASSWORD
+ iniset $KEYSTONE_CONF DEFAULT rabbit_host $RABBIT_HOST
+ fi
+
# Set the URL advertised in the ``versions`` structure returned by the '/' route
iniset $KEYSTONE_CONF DEFAULT public_endpoint "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:%(public_port)s/"
iniset $KEYSTONE_CONF DEFAULT admin_endpoint "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:%(admin_port)s/"
@@ -202,8 +221,8 @@
iniset $KEYSTONE_CONF DEFAULT admin_token "$SERVICE_TOKEN"
- if [[ "$KEYSTONE_TOKEN_FORMAT" = "UUID" ]]; then
- iniset $KEYSTONE_CONF token provider keystone.token.providers.uuid.Provider
+ if [[ "$KEYSTONE_TOKEN_FORMAT" != "" ]]; then
+ iniset $KEYSTONE_CONF token provider keystone.token.providers.$KEYSTONE_TOKEN_FORMAT.Provider
fi
iniset $KEYSTONE_CONF database connection `database_connection_url keystone`
@@ -256,11 +275,11 @@
fi
# Format logging
- if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ] && ! is_apache_enabled_service key ; then
+ if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ] && [ "$KEYSTONE_USE_MOD_WSGI" == "False" ] ; then
setup_colorized_logging $KEYSTONE_CONF DEFAULT
fi
- if is_apache_enabled_service key; then
+ if [ "$KEYSTONE_USE_MOD_WSGI" == "True" ]; then
iniset $KEYSTONE_CONF DEFAULT debug "True"
# Eliminate the %(asctime)s.%(msecs)03d from the log format strings
iniset $KEYSTONE_CONF DEFAULT logging_context_format_string "%(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s"
@@ -269,6 +288,27 @@
iniset $KEYSTONE_CONF DEFAULT logging_exception_prefix "%(process)d TRACE %(name)s %(instance)s"
_config_keystone_apache_wsgi
fi
+
+ iniset $KEYSTONE_CONF DEFAULT max_token_size 16384
+}
+
+function configure_keystone_extensions {
+ # Add keystone extension into keystone v3 application pipeline
+ local extension_value
+ local api_v3
+ local extension
+ local api_v3_extension
+ for extension_value in ${KEYSTONE_EXTENSIONS//,/ }; do
+ if [[ -z "${extension_value}" ]]; then
+ continue
+ fi
+ api_v3=$(iniget $KEYSTONE_PASTE_INI pipeline:api_v3 pipeline)
+ extension=$(echo $api_v3 | sed -ne "/${extension_value}/ p;" )
+ if [[ -z $extension ]]; then
+ api_v3_extension=$(echo $api_v3 | sed -ne "s/service_v3/${extension_value}_extension service_v3/p;" )
+ iniset $KEYSTONE_PASTE_INI pipeline:api_v3 pipeline "$api_v3_extension"
+ fi
+ done
}
# create_keystone_accounts() - Sets up common required keystone accounts
@@ -288,79 +328,55 @@
function create_keystone_accounts {
# admin
- ADMIN_TENANT=$(openstack project create \
- admin \
- | grep " id " | get_field 2)
- ADMIN_USER=$(openstack user create \
- admin \
- --project "$ADMIN_TENANT" \
- --email admin@example.com \
- --password "$ADMIN_PASSWORD" \
- | grep " id " | get_field 2)
- ADMIN_ROLE=$(openstack role create \
- admin \
- | grep " id " | get_field 2)
- openstack role add \
- $ADMIN_ROLE \
- --project $ADMIN_TENANT \
- --user $ADMIN_USER
+ ADMIN_TENANT=$(get_or_create_project "admin")
+ ADMIN_USER=$(get_or_create_user "admin" \
+ "$ADMIN_PASSWORD" "$ADMIN_TENANT")
+ ADMIN_ROLE=$(get_or_create_role "admin")
+ get_or_add_user_role $ADMIN_ROLE $ADMIN_USER $ADMIN_TENANT
# Create service project/role
- openstack project create $SERVICE_TENANT_NAME
+ get_or_create_project "$SERVICE_TENANT_NAME"
# Service role, so service users do not have to be admins
- openstack role create service
+ get_or_create_role service
# The ResellerAdmin role is used by Nova and Ceilometer so we need to keep it.
# The admin role in swift allows a user to act as an admin for their tenant,
# but ResellerAdmin is needed for a user to act as any tenant. The name of this
# role is also configurable in swift-proxy.conf
- openstack role create ResellerAdmin
+ get_or_create_role ResellerAdmin
# The Member role is used by Horizon and Swift so we need to keep it:
- MEMBER_ROLE=$(openstack role create \
- Member \
- | grep " id " | get_field 2)
+ MEMBER_ROLE=$(get_or_create_role "Member")
+
# ANOTHER_ROLE demonstrates that an arbitrary role may be created and used
# TODO(sleepsonthefloor): show how this can be used for rbac in the future!
- ANOTHER_ROLE=$(openstack role create \
- anotherrole \
- | grep " id " | get_field 2)
+
+ ANOTHER_ROLE=$(get_or_create_role "anotherrole")
# invisible tenant - admin can't see this one
- INVIS_TENANT=$(openstack project create \
- invisible_to_admin \
- | grep " id " | get_field 2)
+ INVIS_TENANT=$(get_or_create_project "invisible_to_admin")
# demo
- DEMO_TENANT=$(openstack project create \
- demo \
- | grep " id " | get_field 2)
- DEMO_USER=$(openstack user create \
- demo \
- --project $DEMO_TENANT \
- --email demo@example.com \
- --password "$ADMIN_PASSWORD" \
- | grep " id " | get_field 2)
+ DEMO_TENANT=$(get_or_create_project "demo")
+ DEMO_USER=$(get_or_create_user "demo" \
+ "$ADMIN_PASSWORD" "$DEMO_TENANT" "demo@example.com")
- openstack role add --project $DEMO_TENANT --user $DEMO_USER $MEMBER_ROLE
- openstack role add --project $DEMO_TENANT --user $ADMIN_USER $ADMIN_ROLE
- openstack role add --project $DEMO_TENANT --user $DEMO_USER $ANOTHER_ROLE
- openstack role add --project $INVIS_TENANT --user $DEMO_USER $MEMBER_ROLE
+ get_or_add_user_role $MEMBER_ROLE $DEMO_USER $DEMO_TENANT
+ get_or_add_user_role $ADMIN_ROLE $ADMIN_USER $DEMO_TENANT
+ get_or_add_user_role $ANOTHER_ROLE $DEMO_USER $DEMO_TENANT
+ get_or_add_user_role $MEMBER_ROLE $DEMO_USER $INVIS_TENANT
# Keystone
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
- KEYSTONE_SERVICE=$(openstack service create \
- keystone \
- --type identity \
- --description "Keystone Identity Service" \
- | grep " id " | get_field 2)
- openstack endpoint create \
- $KEYSTONE_SERVICE \
- --region RegionOne \
- --publicurl "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION" \
- --adminurl "$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT/v$IDENTITY_API_VERSION" \
- --internalurl "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION"
+
+ KEYSTONE_SERVICE=$(get_or_create_service "keystone" \
+ "identity" "Keystone Identity Service")
+ get_or_create_endpoint $KEYSTONE_SERVICE \
+ "$REGION_NAME" \
+ "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION" \
+ "$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT/v$IDENTITY_API_VERSION" \
+ "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION"
fi
}
@@ -384,7 +400,15 @@
# Initialize keystone database
$KEYSTONE_DIR/bin/keystone-manage db_sync
- if [[ "$KEYSTONE_TOKEN_FORMAT" == "PKI" ]]; then
+ local extension_value
+ for extension_value in ${KEYSTONE_EXTENSIONS//,/ }; do
+ if [[ -z "${extension_value}" ]]; then
+ continue
+ fi
+ $KEYSTONE_DIR/bin/keystone-manage db_sync --extension "${extension_value}"
+ done
+
+ if [[ "$KEYSTONE_TOKEN_FORMAT" != "uuid" ]]; then
# Set up certificates
rm -rf $KEYSTONE_CONF_DIR/ssl
$KEYSTONE_DIR/bin/keystone-manage pki_setup
@@ -403,6 +427,12 @@
sudo install -D -m 0644 -o $STACK_USER {$KEYSTONECLIENT_DIR/tools/,/etc/bash_completion.d/}keystone.bash_completion
}
+# install_keystonemiddleware() - Collect source and prepare
+function install_keystonemiddleware {
+ git_clone $KEYSTONEMIDDLEWARE_REPO $KEYSTONEMIDDLEWARE_DIR $KEYSTONEMIDDLEWARE_BRANCH
+ setup_install $KEYSTONEMIDDLEWARE_DIR
+}
+
# install_keystone() - Collect source and prepare
function install_keystone {
# only install ldap if the service has been enabled
@@ -422,7 +452,7 @@
fi
git_clone $KEYSTONE_REPO $KEYSTONE_DIR $KEYSTONE_BRANCH
setup_develop $KEYSTONE_DIR
- if is_apache_enabled_service key; then
+ if [ "$KEYSTONE_USE_MOD_WSGI" == "True" ]; then
install_apache_wsgi
fi
}
@@ -435,7 +465,7 @@
service_port=$KEYSTONE_SERVICE_PORT_INT
fi
- if is_apache_enabled_service key; then
+ if [ "$KEYSTONE_USE_MOD_WSGI" == "True" ]; then
restart_apache_server
screen_it key "cd $KEYSTONE_DIR && sudo tail -f /var/log/$APACHE_NAME/keystone"
else
@@ -444,7 +474,10 @@
fi
echo "Waiting for keystone to start..."
- if ! timeout $SERVICE_TIMEOUT sh -c "while ! curl --noproxy '*' -k -s $KEYSTONE_AUTH_PROTOCOL://$SERVICE_HOST:$service_port/v$IDENTITY_API_VERSION/ >/dev/null; do sleep 1; done"; then
+ # Check that the keystone service is running. Even if the tls tunnel
+ # should be enabled, make sure the internal port is checked using
+ # unencryted traffic at this point.
+ if ! timeout $SERVICE_TIMEOUT sh -c "while ! curl --noproxy '*' -k -s http://$KEYSTONE_SERVICE_HOST:$service_port/v$IDENTITY_API_VERSION/ >/dev/null; do sleep 1; done"; then
die $LINENO "keystone did not start"
fi
@@ -463,6 +496,9 @@
_cleanup_keystone_apache_wsgi
}
+function is_keystone_enabled {
+ return is_service_enabled key
+}
# Restore xtrace
$XTRACE
diff --git a/lib/marconi b/lib/marconi
index 20bf0e1..063ed3d 100644
--- a/lib/marconi
+++ b/lib/marconi
@@ -178,29 +178,19 @@
SERVICE_TENANT=$(openstack project list | awk "/ $SERVICE_TENANT_NAME / { print \$2 }")
ADMIN_ROLE=$(openstack role list | awk "/ admin / { print \$2 }")
- MARCONI_USER=$(openstack user create \
- marconi \
- --password "$SERVICE_PASSWORD" \
- --project $SERVICE_TENANT \
- --email marconi@example.com \
- | grep " id " | get_field 2)
- openstack role add \
- $ADMIN_ROLE \
- --project $SERVICE_TENANT \
- --user $MARCONI_USER
+ MARCONI_USER=$(get_or_create_user "marconi" \
+ "$SERVICE_PASSWORD" $SERVICE_TENANT)
+ get_or_add_user_role $ADMIN_ROLE $MARCONI_USER $SERVICE_TENANT
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
- MARCONI_SERVICE=$(openstack service create \
- marconi \
- --type=queuing \
- --description="Marconi Service" \
- | grep " id " | get_field 2)
- openstack endpoint create \
- $MARCONI_SERVICE \
- --region RegionOne \
- --publicurl "$MARCONI_SERVICE_PROTOCOL://$MARCONI_SERVICE_HOST:$MARCONI_SERVICE_PORT" \
- --adminurl "$MARCONI_SERVICE_PROTOCOL://$MARCONI_SERVICE_HOST:$MARCONI_SERVICE_PORT" \
- --internalurl "$MARCONI_SERVICE_PROTOCOL://$MARCONI_SERVICE_HOST:$MARCONI_SERVICE_PORT"
+
+ MARCONI_SERVICE=$(get_or_create_service "marconi" \
+ "queuing" "Marconi Service")
+ get_or_create_endpoint $MARCONI_SERVICE \
+ "$REGION_NAME" \
+ "$MARCONI_SERVICE_PROTOCOL://$MARCONI_SERVICE_HOST:$MARCONI_SERVICE_PORT" \
+ "$MARCONI_SERVICE_PROTOCOL://$MARCONI_SERVICE_HOST:$MARCONI_SERVICE_PORT" \
+ "$MARCONI_SERVICE_PROTOCOL://$MARCONI_SERVICE_HOST:$MARCONI_SERVICE_PORT"
fi
}
diff --git a/lib/neutron b/lib/neutron
index e918286..2d8e1df 100644
--- a/lib/neutron
+++ b/lib/neutron
@@ -85,6 +85,8 @@
NEUTRON_CONF=$NEUTRON_CONF_DIR/neutron.conf
export NEUTRON_TEST_CONFIG_FILE=${NEUTRON_TEST_CONFIG_FILE:-"$NEUTRON_CONF_DIR/debug.ini"}
+# Default name for Neutron database
+Q_DB_NAME=${Q_DB_NAME:-neutron}
# Default Neutron Plugin
Q_PLUGIN=${Q_PLUGIN:-ml2}
# Default Neutron Port
@@ -143,6 +145,17 @@
Q_RR_COMMAND="sudo $NEUTRON_ROOTWRAP $Q_RR_CONF_FILE"
fi
+
+# Distributed Virtual Router (DVR) configuration
+# Can be:
+# legacy - No DVR functionality
+# dvr_snat - Controller or single node DVR
+# dvr - Compute node in multi-node DVR
+Q_DVR_MODE=${Q_DVR_MODE:-legacy}
+if [[ "$Q_DVR_MODE" != "legacy" ]]; then
+ Q_ML2_PLUGIN_MECHANISM_DRIVERS=openvswitch,linuxbridge,l2population
+fi
+
# Provider Network Configurations
# --------------------------------
@@ -161,7 +174,7 @@
# If using GRE tunnels for tenant networks, specify the range of
# tunnel IDs from which tenant networks are allocated. Can be
# overriden in ``localrc`` in necesssary.
-TENANT_TUNNEL_RANGES=${TENANT_TUNNEL_RANGE:-1:1000}
+TENANT_TUNNEL_RANGES=${TENANT_TUNNEL_RANGES:-1:1000}
# To use VLANs for tenant networks, set to True in localrc. VLANs
# are supported by the openvswitch and linuxbridge plugins, each
@@ -203,6 +216,13 @@
# Example: ``LB_PHYSICAL_INTERFACE=eth1``
LB_PHYSICAL_INTERFACE=${LB_PHYSICAL_INTERFACE:-}
+# When Neutron tunnels are enabled it is needed to specify the
+# IP address of the end point in the local server. This IP is set
+# by default to the same IP address that the HOST IP.
+# This variable can be used to specify a different end point IP address
+# Example: ``TUNNEL_ENDPOINT_IP=1.1.1.1``
+TUNNEL_ENDPOINT_IP=${TUNNEL_ENDPOINT_IP:-$HOST_IP}
+
# With the openvswitch plugin, set to True in ``localrc`` to enable
# provider GRE tunnels when ``ENABLE_TENANT_TUNNELS`` is False.
#
@@ -297,18 +317,25 @@
_configure_neutron_metadata_agent
fi
+ if [[ "$Q_DVR_MODE" != "legacy" ]]; then
+ _configure_dvr
+ fi
+ if is_service_enabled ceilometer; then
+ _configure_neutron_ceilometer_notifications
+ fi
+
_configure_neutron_debug_command
}
function create_nova_conf_neutron {
iniset $NOVA_CONF DEFAULT network_api_class "nova.network.neutronv2.api.API"
- iniset $NOVA_CONF DEFAULT neutron_admin_username "$Q_ADMIN_USERNAME"
- iniset $NOVA_CONF DEFAULT neutron_admin_password "$SERVICE_PASSWORD"
- iniset $NOVA_CONF DEFAULT neutron_admin_auth_url "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_AUTH_PORT/v2.0"
- iniset $NOVA_CONF DEFAULT neutron_auth_strategy "$Q_AUTH_STRATEGY"
- iniset $NOVA_CONF DEFAULT neutron_admin_tenant_name "$SERVICE_TENANT_NAME"
- iniset $NOVA_CONF DEFAULT neutron_region_name "RegionOne"
- iniset $NOVA_CONF DEFAULT neutron_url "http://$Q_HOST:$Q_PORT"
+ iniset $NOVA_CONF neutron admin_username "$Q_ADMIN_USERNAME"
+ iniset $NOVA_CONF neutron admin_password "$SERVICE_PASSWORD"
+ iniset $NOVA_CONF neutron admin_auth_url "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_AUTH_PORT/v2.0"
+ iniset $NOVA_CONF neutron auth_strategy "$Q_AUTH_STRATEGY"
+ iniset $NOVA_CONF neutron admin_tenant_name "$SERVICE_TENANT_NAME"
+ iniset $NOVA_CONF neutron region_name "$REGION_NAME"
+ iniset $NOVA_CONF neutron url "http://$Q_HOST:$Q_PORT"
if [[ "$Q_USE_SECGROUP" == "True" ]]; then
LIBVIRT_FIREWALL_DRIVER=nova.virt.firewall.NoopFirewallDriver
@@ -350,28 +377,20 @@
ADMIN_ROLE=$(openstack role list | awk "/ admin / { print \$2 }")
if [[ "$ENABLED_SERVICES" =~ "q-svc" ]]; then
- NEUTRON_USER=$(openstack user create \
- neutron \
- --password "$SERVICE_PASSWORD" \
- --project $SERVICE_TENANT \
- --email neutron@example.com \
- | grep " id " | get_field 2)
- openstack role add \
- $ADMIN_ROLE \
- --project $SERVICE_TENANT \
- --user $NEUTRON_USER
+
+ NEUTRON_USER=$(get_or_create_user "neutron" \
+ "$SERVICE_PASSWORD" $SERVICE_TENANT)
+ get_or_add_user_role $ADMIN_ROLE $NEUTRON_USER $SERVICE_TENANT
+
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
- NEUTRON_SERVICE=$(openstack service create \
- neutron \
- --type=network \
- --description="Neutron Service" \
- | grep " id " | get_field 2)
- openstack endpoint create \
- $NEUTRON_SERVICE \
- --region RegionOne \
- --publicurl "http://$SERVICE_HOST:9696/" \
- --adminurl "http://$SERVICE_HOST:9696/" \
- --internalurl "http://$SERVICE_HOST:9696/"
+
+ NEUTRON_SERVICE=$(get_or_create_service "neutron" \
+ "network" "Neutron Service")
+ get_or_create_endpoint $NEUTRON_SERVICE \
+ "$REGION_NAME" \
+ "http://$SERVICE_HOST:9696/" \
+ "http://$SERVICE_HOST:9696/" \
+ "http://$SERVICE_HOST:9696/"
fi
fi
}
@@ -401,7 +420,7 @@
elif is_provider_network; then
die_if_not_set $LINENO SEGMENTATION_ID "A SEGMENTATION_ID is required to use provider networking"
die_if_not_set $LINENO PROVIDER_NETWORK_TYPE "You must specifiy the PROVIDER_NETWORK_TYPE"
- NET_ID=$(neutron net-create $PHYSICAL_NETWORK --tenant_id $TENANT_ID --provider:network_type $PROVIDER_NETWORK_TYPE --provider:physical_network "$PHYSICAL_NETWORK" --provider:segmentation_id "$SEGMENTATION_ID" --router:external=true --shared | grep ' id ' | get_field 2)
+ NET_ID=$(neutron net-create $PHYSICAL_NETWORK --tenant_id $TENANT_ID --provider:network_type $PROVIDER_NETWORK_TYPE --provider:physical_network "$PHYSICAL_NETWORK" --provider:segmentation_id "$SEGMENTATION_ID" --shared | grep ' id ' | get_field 2)
SUBNET_ID=$(neutron subnet-create --tenant_id $TENANT_ID --ip_version 4 ${ALLOCATION_POOL:+--allocation-pool $ALLOCATION_POOL} --name $PROVIDER_SUBNET_NAME $NET_ID $FIXED_RANGE | grep ' id ' | get_field 2)
SUBNET_V6_ID=$(neutron subnet-create --tenant_id $TENANT_ID --ip_version 6 --ipv6-address-mode slaac --gateway $V6_NETWORK_GATEWAY --name $PROVIDER_SUBNET_NAME_V6 $NET_ID $FIXED_RANGE_V6 | grep 'id' | get_field 2)
sudo ip link set $OVS_PHYSICAL_BRIDGE up
@@ -572,7 +591,7 @@
fi
# delete all namespaces created by neutron
- for ns in $(sudo ip netns list | grep -o -E '(qdhcp|qrouter|qlbaas)-[0-9a-f-]*'); do
+ for ns in $(sudo ip netns list | grep -o -E '(qdhcp|qrouter|qlbaas|fip|snat)-[0-9a-f-]*'); do
sudo ip netns delete ${ns}
done
}
@@ -668,14 +687,6 @@
iniset $Q_DHCP_CONF_FILE DEFAULT use_namespaces $Q_USE_NAMESPACE
iniset $Q_DHCP_CONF_FILE DEFAULT root_helper "$Q_RR_COMMAND"
- # Define extra "DEFAULT" configuration options when q-dhcp is configured by
- # defining the array ``Q_DHCP_EXTRA_DEFAULT_OPTS``.
- # For Example: ``Q_DHCP_EXTRA_DEFAULT_OPTS=(foo=true bar=2)``
- for I in "${Q_DHCP_EXTRA_DEFAULT_OPTS[@]}"; do
- # Replace the first '=' with ' ' for iniset syntax
- iniset $Q_DHCP_CONF_FILE DEFAULT ${I/=/ }
- done
-
_neutron_setup_interface_driver $Q_DHCP_CONF_FILE
neutron_plugin_configure_dhcp_agent
@@ -726,10 +737,14 @@
iniset $Q_META_CONF_FILE DEFAULT nova_metadata_ip $Q_META_DATA_IP
iniset $Q_META_CONF_FILE DEFAULT root_helper "$Q_RR_COMMAND"
- _neutron_setup_keystone $Q_META_CONF_FILE DEFAULT True True True
+ _neutron_setup_keystone $Q_META_CONF_FILE DEFAULT True True
}
+function _configure_neutron_ceilometer_notifications {
+ iniset $NEUTRON_CONF DEFAULT notification_driver neutron.openstack.common.notifier.rpc_notifier
+}
+
function _configure_neutron_lbaas {
neutron_agent_lbaas_configure_common
neutron_agent_lbaas_configure_agent
@@ -750,6 +765,12 @@
neutron_vpn_configure_common
}
+function _configure_dvr {
+ iniset $NEUTRON_CONF DEFAULT router_distributed True
+ iniset $Q_L3_CONF_FILE DEFAULT agent_mode $Q_DVR_MODE
+}
+
+
# _configure_neutron_plugin_agent() - Set config files for neutron plugin agent
# It is called when q-agt is enabled.
function _configure_neutron_plugin_agent {
@@ -787,14 +808,6 @@
iniset $NEUTRON_CONF DEFAULT auth_strategy $Q_AUTH_STRATEGY
_neutron_setup_keystone $NEUTRON_CONF keystone_authtoken
- # Define extra "DEFAULT" configuration options when q-svc is configured by
- # defining the array ``Q_SRV_EXTRA_DEFAULT_OPTS``.
- # For Example: ``Q_SRV_EXTRA_DEFAULT_OPTS=(foo=true bar=2)``
- for I in "${Q_SRV_EXTRA_DEFAULT_OPTS[@]}"; do
- # Replace the first '=' with ' ' for iniset syntax
- iniset $NEUTRON_CONF DEFAULT ${I/=/ }
- done
-
# Configuration for neutron notifations to nova.
iniset $NEUTRON_CONF DEFAULT notify_nova_on_port_status_changes $Q_NOTIFY_NOVA_PORT_STATUS_CHANGES
iniset $NEUTRON_CONF DEFAULT notify_nova_on_port_data_changes $Q_NOTIFY_NOVA_PORT_DATA_CHANGES
@@ -868,18 +881,9 @@
local section=$2
local use_auth_url=$3
local skip_auth_cache=$4
- local use_service_port=$5
- local keystone_port=$KEYSTONE_AUTH_PORT
- if [[ -n $use_service_port ]]; then
- keystone_port=$KEYSTONE_SERVICE_PORT
- fi
- if [[ -n $use_auth_url ]]; then
- iniset $conf_file $section auth_url "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_AUTH_HOST:$keystone_port/v2.0"
- else
- iniset $conf_file $section auth_host $KEYSTONE_SERVICE_HOST
- iniset $conf_file $section auth_port $keystone_port
- iniset $conf_file $section auth_protocol $KEYSTONE_SERVICE_PROTOCOL
- fi
+
+ iniset $conf_file $section auth_uri $KEYSTONE_SERVICE_URI
+ iniset $conf_file $section identity_uri $KEYSTONE_AUTH_URI
iniset $conf_file $section admin_tenant_name $SERVICE_TENANT_NAME
iniset $conf_file $section admin_user $Q_ADMIN_USERNAME
iniset $conf_file $section admin_password $SERVICE_PASSWORD
diff --git a/lib/neutron_plugins/README.md b/lib/neutron_plugins/README.md
index be8fd96..7192a05 100644
--- a/lib/neutron_plugins/README.md
+++ b/lib/neutron_plugins/README.md
@@ -25,7 +25,7 @@
install_package bridge-utils
* ``neutron_plugin_configure_common`` :
set plugin-specific variables, ``Q_PLUGIN_CONF_PATH``, ``Q_PLUGIN_CONF_FILENAME``,
- ``Q_DB_NAME``, ``Q_PLUGIN_CLASS``
+ ``Q_PLUGIN_CLASS``
* ``neutron_plugin_configure_debug_command``
* ``neutron_plugin_configure_dhcp_agent``
* ``neutron_plugin_configure_l3_agent``
diff --git a/lib/neutron_plugins/bigswitch_floodlight b/lib/neutron_plugins/bigswitch_floodlight
index efdd9ef..9e84f2e 100644
--- a/lib/neutron_plugins/bigswitch_floodlight
+++ b/lib/neutron_plugins/bigswitch_floodlight
@@ -19,7 +19,6 @@
function neutron_plugin_configure_common {
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/bigswitch
Q_PLUGIN_CONF_FILENAME=restproxy.ini
- Q_DB_NAME="restproxy_neutron"
Q_PLUGIN_CLASS="neutron.plugins.bigswitch.plugin.NeutronRestProxyV2"
BS_FL_CONTROLLERS_PORT=${BS_FL_CONTROLLERS_PORT:-localhost:80}
BS_FL_CONTROLLER_TIMEOUT=${BS_FL_CONTROLLER_TIMEOUT:-10}
diff --git a/lib/neutron_plugins/brocade b/lib/neutron_plugins/brocade
index e4cc754..511fb71 100644
--- a/lib/neutron_plugins/brocade
+++ b/lib/neutron_plugins/brocade
@@ -20,7 +20,6 @@
function neutron_plugin_configure_common {
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/brocade
Q_PLUGIN_CONF_FILENAME=brocade.ini
- Q_DB_NAME="brcd_neutron"
Q_PLUGIN_CLASS="neutron.plugins.brocade.NeutronPlugin.BrocadePluginV2"
}
diff --git a/lib/neutron_plugins/cisco b/lib/neutron_plugins/cisco
index dccf400..da90ee3 100644
--- a/lib/neutron_plugins/cisco
+++ b/lib/neutron_plugins/cisco
@@ -197,7 +197,6 @@
Q_PLUGIN_CONF_FILENAME=cisco_plugins.ini
fi
Q_PLUGIN_CLASS="neutron.plugins.cisco.network_plugin.PluginV2"
- Q_DB_NAME=cisco_neutron
}
function neutron_plugin_configure_debug_command {
diff --git a/lib/neutron_plugins/embrane b/lib/neutron_plugins/embrane
index cce108a..7dafdc0 100644
--- a/lib/neutron_plugins/embrane
+++ b/lib/neutron_plugins/embrane
@@ -18,7 +18,6 @@
function neutron_plugin_configure_common {
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/embrane
Q_PLUGIN_CONF_FILENAME=heleos_conf.ini
- Q_DB_NAME="ovs_neutron"
Q_PLUGIN_CLASS="neutron.plugins.embrane.plugins.embrane_ovs_plugin.EmbraneOvsPlugin"
}
diff --git a/lib/neutron_plugins/ibm b/lib/neutron_plugins/ibm
index 3aef9d0..39b0040 100644
--- a/lib/neutron_plugins/ibm
+++ b/lib/neutron_plugins/ibm
@@ -60,7 +60,6 @@
function neutron_plugin_configure_common {
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/ibm
Q_PLUGIN_CONF_FILENAME=sdnve_neutron_plugin.ini
- Q_DB_NAME="sdnve_neutron"
Q_PLUGIN_CLASS="neutron.plugins.ibm.sdnve_neutron_plugin.SdnvePluginV2"
}
diff --git a/lib/neutron_plugins/linuxbridge b/lib/neutron_plugins/linuxbridge
index 113a7df..5f989ae 100644
--- a/lib/neutron_plugins/linuxbridge
+++ b/lib/neutron_plugins/linuxbridge
@@ -10,7 +10,6 @@
function neutron_plugin_configure_common {
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/linuxbridge
Q_PLUGIN_CONF_FILENAME=linuxbridge_conf.ini
- Q_DB_NAME="neutron_linux_bridge"
Q_PLUGIN_CLASS="neutron.plugins.linuxbridge.lb_neutron_plugin.LinuxBridgePluginV2"
}
diff --git a/lib/neutron_plugins/midonet b/lib/neutron_plugins/midonet
index c5373d6..6ccd502 100644
--- a/lib/neutron_plugins/midonet
+++ b/lib/neutron_plugins/midonet
@@ -26,7 +26,6 @@
function neutron_plugin_configure_common {
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/midonet
Q_PLUGIN_CONF_FILENAME=midonet.ini
- Q_DB_NAME="neutron_midonet"
Q_PLUGIN_CLASS="neutron.plugins.midonet.plugin.MidonetPluginV2"
}
diff --git a/lib/neutron_plugins/ml2 b/lib/neutron_plugins/ml2
index 9966373..f7f7838 100644
--- a/lib/neutron_plugins/ml2
+++ b/lib/neutron_plugins/ml2
@@ -50,7 +50,6 @@
function neutron_plugin_configure_common {
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/ml2
Q_PLUGIN_CONF_FILENAME=ml2_conf.ini
- Q_DB_NAME="neutron_ml2"
Q_PLUGIN_CLASS="neutron.plugins.ml2.plugin.Ml2Plugin"
# The ML2 plugin delegates L3 routing/NAT functionality to
# the L3 service plugin which must therefore be specified.
@@ -99,7 +98,7 @@
fi
# Since we enable the tunnel TypeDrivers, also enable a local_ip
- iniset /$Q_PLUGIN_CONF_FILE ovs local_ip $HOST_IP
+ iniset /$Q_PLUGIN_CONF_FILE ovs local_ip $TUNNEL_ENDPOINT_IP
populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2 mechanism_drivers=$Q_ML2_PLUGIN_MECHANISM_DRIVERS
@@ -112,6 +111,12 @@
populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2_type_vxlan $Q_ML2_PLUGIN_VXLAN_TYPE_OPTIONS
populate_ml2_config /$Q_PLUGIN_CONF_FILE ml2_type_vlan $Q_ML2_PLUGIN_VLAN_TYPE_OPTIONS
+
+ if [[ "$Q_DVR_MODE" != "legacy" ]]; then
+ populate_ml2_config /$Q_PLUGIN_CONF_FILE agent l2_population=True
+ populate_ml2_config /$Q_PLUGIN_CONF_FILE agent tunnel_types=vxlan
+ populate_ml2_config /$Q_PLUGIN_CONF_FILE agent enable_distributed_routing=True
+ fi
}
function has_neutron_plugin_security_group {
diff --git a/lib/neutron_plugins/nec b/lib/neutron_plugins/nec
index d76f7d4..f8d98c3 100644
--- a/lib/neutron_plugins/nec
+++ b/lib/neutron_plugins/nec
@@ -39,7 +39,6 @@
function neutron_plugin_configure_common {
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/nec
Q_PLUGIN_CONF_FILENAME=nec.ini
- Q_DB_NAME="neutron_nec"
Q_PLUGIN_CLASS="neutron.plugins.nec.nec_plugin.NECPluginV2"
}
diff --git a/lib/neutron_plugins/nuage b/lib/neutron_plugins/nuage
index 86f09d2..52d85a2 100644
--- a/lib/neutron_plugins/nuage
+++ b/lib/neutron_plugins/nuage
@@ -20,7 +20,6 @@
function neutron_plugin_configure_common {
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/nuage
Q_PLUGIN_CONF_FILENAME=nuage_plugin.ini
- Q_DB_NAME="nuage_neutron"
Q_PLUGIN_CLASS="neutron.plugins.nuage.plugin.NuagePlugin"
Q_PLUGIN_EXTENSIONS_PATH=neutron/plugins/nuage/extensions
#Nuage specific Neutron defaults. Actual value must be set and sourced
diff --git a/lib/neutron_plugins/ofagent_agent b/lib/neutron_plugins/ofagent_agent
index b8321f3..66283ad 100644
--- a/lib/neutron_plugins/ofagent_agent
+++ b/lib/neutron_plugins/ofagent_agent
@@ -54,7 +54,7 @@
die $LINENO "You are running OVS version $OVS_VERSION. OVS 1.4+ is required for tunneling between multiple hosts."
fi
iniset /$Q_PLUGIN_CONF_FILE ovs enable_tunneling True
- iniset /$Q_PLUGIN_CONF_FILE ovs local_ip $HOST_IP
+ iniset /$Q_PLUGIN_CONF_FILE ovs local_ip $TUNNEL_ENDPOINT_IP
fi
# Setup physical network bridge mappings. Override
diff --git a/lib/neutron_plugins/oneconvergence b/lib/neutron_plugins/oneconvergence
index 06f1eee..e5f0d71 100644
--- a/lib/neutron_plugins/oneconvergence
+++ b/lib/neutron_plugins/oneconvergence
@@ -19,7 +19,6 @@
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/oneconvergence
Q_PLUGIN_CONF_FILENAME=nvsdplugin.ini
Q_PLUGIN_CLASS="neutron.plugins.oneconvergence.plugin.OneConvergencePluginV2"
- Q_DB_NAME='oc_nvsd_neutron'
}
# Configure plugin specific information
diff --git a/lib/neutron_plugins/openvswitch b/lib/neutron_plugins/openvswitch
index fc81092..c468132 100644
--- a/lib/neutron_plugins/openvswitch
+++ b/lib/neutron_plugins/openvswitch
@@ -10,7 +10,6 @@
function neutron_plugin_configure_common {
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/openvswitch
Q_PLUGIN_CONF_FILENAME=ovs_neutron_plugin.ini
- Q_DB_NAME="ovs_neutron"
Q_PLUGIN_CLASS="neutron.plugins.openvswitch.ovs_neutron_plugin.OVSNeutronPluginV2"
}
diff --git a/lib/neutron_plugins/openvswitch_agent b/lib/neutron_plugins/openvswitch_agent
index fbc013f..5adb0c5 100644
--- a/lib/neutron_plugins/openvswitch_agent
+++ b/lib/neutron_plugins/openvswitch_agent
@@ -48,7 +48,7 @@
die $LINENO "You are running OVS version $OVS_VERSION. OVS 1.4+ is required for tunneling between multiple hosts."
fi
iniset /$Q_PLUGIN_CONF_FILE ovs enable_tunneling True
- iniset /$Q_PLUGIN_CONF_FILE ovs local_ip $HOST_IP
+ iniset /$Q_PLUGIN_CONF_FILE ovs local_ip $TUNNEL_ENDPOINT_IP
fi
# Setup physical network bridge mappings. Override
diff --git a/lib/neutron_plugins/ovs_base b/lib/neutron_plugins/ovs_base
index 1e293a1..26c5489 100644
--- a/lib/neutron_plugins/ovs_base
+++ b/lib/neutron_plugins/ovs_base
@@ -32,19 +32,24 @@
done
}
+function _neutron_ovs_base_install_ubuntu_dkms {
+ # install Dynamic Kernel Module Support packages if needed
+ local kernel_version=$(uname -r)
+ local kernel_major_minor=`echo $kernel_version | cut -d. -f1-2`
+ # From kernel 3.13 on, openvswitch-datapath-dkms is not needed
+ if [ `vercmp_numbers "$kernel_major_minor" "3.13"` -lt "0" ]; then
+ install_package "dkms openvswitch-datapath-dkms linux-headers-$kernel_version"
+ fi
+}
+
function _neutron_ovs_base_install_agent_packages {
- local kernel_version
# Install deps
- # FIXME add to ``files/apts/neutron``, but don't install if not needed!
+ install_package $(get_packages "openvswitch")
if is_ubuntu; then
- kernel_version=`cat /proc/version | cut -d " " -f3`
- install_package make fakeroot dkms openvswitch-switch openvswitch-datapath-dkms linux-headers-$kernel_version
+ _neutron_ovs_base_install_ubuntu_dkms
elif is_fedora; then
- install_package openvswitch
- # Ensure that the service is started
restart_service openvswitch
elif is_suse; then
- install_package openvswitch-switch
restart_service openvswitch-switch
fi
}
@@ -65,8 +70,9 @@
iniset $Q_L3_CONF_FILE DEFAULT external_network_bridge $PUBLIC_BRIDGE
neutron-ovs-cleanup
- sudo ovs-vsctl --no-wait -- --may-exist add-br $PUBLIC_BRIDGE
- sudo ovs-vsctl --no-wait br-set-external-id $PUBLIC_BRIDGE bridge-id $PUBLIC_BRIDGE
+ # --no-wait causes a race condition if $PUBLIC_BRIDGE is not up when ip addr flush is called
+ sudo ovs-vsctl -- --may-exist add-br $PUBLIC_BRIDGE
+ sudo ovs-vsctl br-set-external-id $PUBLIC_BRIDGE bridge-id $PUBLIC_BRIDGE
# ensure no IP is configured on the public bridge
sudo ip addr flush dev $PUBLIC_BRIDGE
}
diff --git a/lib/neutron_plugins/plumgrid b/lib/neutron_plugins/plumgrid
index 178bca7..37b9e4c 100644
--- a/lib/neutron_plugins/plumgrid
+++ b/lib/neutron_plugins/plumgrid
@@ -17,7 +17,6 @@
function neutron_plugin_configure_common {
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/plumgrid
Q_PLUGIN_CONF_FILENAME=plumgrid.ini
- Q_DB_NAME="plumgrid_neutron"
Q_PLUGIN_CLASS="neutron.plugins.plumgrid.plumgrid_plugin.plumgrid_plugin.NeutronPluginPLUMgridV2"
PLUMGRID_DIRECTOR_IP=${PLUMGRID_DIRECTOR_IP:-localhost}
PLUMGRID_DIRECTOR_PORT=${PLUMGRID_DIRECTOR_PORT:-7766}
diff --git a/lib/neutron_plugins/ryu b/lib/neutron_plugins/ryu
index ceb89fa..f45a797 100644
--- a/lib/neutron_plugins/ryu
+++ b/lib/neutron_plugins/ryu
@@ -25,7 +25,6 @@
function neutron_plugin_configure_common {
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/ryu
Q_PLUGIN_CONF_FILENAME=ryu.ini
- Q_DB_NAME="ovs_neutron"
Q_PLUGIN_CLASS="neutron.plugins.ryu.ryu_neutron_plugin.RyuNeutronPluginV2"
}
diff --git a/lib/neutron_plugins/vmware_nsx b/lib/neutron_plugins/vmware_nsx
index f2f8735..5802ebf 100644
--- a/lib/neutron_plugins/vmware_nsx
+++ b/lib/neutron_plugins/vmware_nsx
@@ -40,7 +40,6 @@
function neutron_plugin_configure_common {
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/vmware
Q_PLUGIN_CONF_FILENAME=nsx.ini
- Q_DB_NAME="neutron_nsx"
Q_PLUGIN_CLASS="neutron.plugins.vmware.plugin.NsxPlugin"
}
@@ -58,7 +57,7 @@
function neutron_plugin_configure_l3_agent {
# VMware NSX plugin does not run L3 agent
- die $LINENO "q-l3 should must not be executed with VMware NSX plugin!"
+ die $LINENO "q-l3 should not be executed with VMware NSX plugin!"
}
function neutron_plugin_configure_plugin_agent {
diff --git a/lib/neutron_thirdparty/ryu b/lib/neutron_thirdparty/ryu
index bbe227e..c737600 100644
--- a/lib/neutron_thirdparty/ryu
+++ b/lib/neutron_thirdparty/ryu
@@ -58,6 +58,7 @@
if [[ "$_RYU_INSTALLED" == "False" ]]; then
git_clone $RYU_REPO $RYU_DIR $RYU_BRANCH
export PYTHONPATH=$RYU_DIR:$PYTHONPATH
+ pip_install $(cat $RYU_DIR/tools/pip-requires)
_RYU_INSTALLED=True
fi
}
diff --git a/lib/nova b/lib/nova
index 722eabb..8da8b69 100644
--- a/lib/nova
+++ b/lib/nova
@@ -81,7 +81,12 @@
# the new p* interfaces, then basically picks the first
# alphabetically. It's probably wrong, however it's less wrong than
# always using 'eth0' which doesn't exist on new Linux distros at all.
-GUEST_INTERFACE_DEFAULT=$(route -n | awk '{print $8}' | grep ^[ep] | sort | head -1)
+GUEST_INTERFACE_DEFAULT=$(ip link \
+ | grep 'state UP' \
+ | awk '{print $2}' \
+ | sed 's/://' \
+ | grep ^[ep] \
+ | head -1)
# Get hypervisor configuration
# ----------------------------
@@ -241,16 +246,6 @@
# Get the sample configuration file in place
cp $NOVA_DIR/etc/nova/api-paste.ini $NOVA_CONF_DIR
-
- # Comment out the keystone configs in Nova's api-paste.ini.
- # We are using nova.conf to configure this instead.
- inicomment $NOVA_API_PASTE_INI filter:authtoken auth_host
- inicomment $NOVA_API_PASTE_INI filter:authtoken auth_protocol
- inicomment $NOVA_API_PASTE_INI filter:authtoken admin_tenant_name
- inicomment $NOVA_API_PASTE_INI filter:authtoken cafile
- inicomment $NOVA_API_PASTE_INI filter:authtoken admin_user
- inicomment $NOVA_API_PASTE_INI filter:authtoken admin_password
- inicomment $NOVA_API_PASTE_INI filter:authtoken signing_dir
fi
if is_service_enabled n-cpu; then
@@ -338,39 +333,28 @@
# Nova
if [[ "$ENABLED_SERVICES" =~ "n-api" ]]; then
- NOVA_USER=$(openstack user create \
- nova \
- --password "$SERVICE_PASSWORD" \
- --project $SERVICE_TENANT \
- --email nova@example.com \
- | grep " id " | get_field 2)
- openstack role add \
- $ADMIN_ROLE \
- --project $SERVICE_TENANT \
- --user $NOVA_USER
+
+ NOVA_USER=$(get_or_create_user "nova" \
+ "$SERVICE_PASSWORD" $SERVICE_TENANT)
+ get_or_add_user_role $ADMIN_ROLE $NOVA_USER $SERVICE_TENANT
+
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
- NOVA_SERVICE=$(openstack service create \
- nova \
- --type=compute \
- --description="Nova Compute Service" \
- | grep " id " | get_field 2)
- openstack endpoint create \
- $NOVA_SERVICE \
- --region RegionOne \
- --publicurl "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s" \
- --adminurl "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s" \
- --internalurl "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s"
- NOVA_V3_SERVICE=$(openstack service create \
- novav3 \
- --type=computev3 \
- --description="Nova Compute Service V3" \
- | grep " id " | get_field 2)
- openstack endpoint create \
- $NOVA_V3_SERVICE \
- --region RegionOne \
- --publicurl "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v3" \
- --adminurl "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v3" \
- --internalurl "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v3"
+
+ NOVA_SERVICE=$(get_or_create_service "nova" \
+ "compute" "Nova Compute Service")
+ get_or_create_endpoint $NOVA_SERVICE \
+ "$REGION_NAME" \
+ "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s" \
+ "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s" \
+ "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s"
+
+ NOVA_V3_SERVICE=$(get_or_create_service "novav3" \
+ "computev3" "Nova Compute Service V3")
+ get_or_create_endpoint $NOVA_V3_SERVICE \
+ "$REGION_NAME" \
+ "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v3" \
+ "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v3" \
+ "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v3"
fi
fi
@@ -379,40 +363,32 @@
if is_service_enabled swift; then
# Nova needs ResellerAdmin role to download images when accessing
# swift through the s3 api.
- openstack role add \
- --project $SERVICE_TENANT_NAME \
- --user nova \
- ResellerAdmin
+ get_or_add_user_role ResellerAdmin nova $SERVICE_TENANT_NAME
fi
# EC2
if [[ "$KEYSTONE_CATALOG_BACKEND" = "sql" ]]; then
- openstack service create \
- --type ec2 \
- --description "EC2 Compatibility Layer" \
- ec2
- openstack endpoint create \
- --region RegionOne \
- --publicurl "http://$SERVICE_HOST:8773/services/Cloud" \
- --adminurl "http://$SERVICE_HOST:8773/services/Admin" \
- --internalurl "http://$SERVICE_HOST:8773/services/Cloud" \
- ec2
+
+ EC2_SERVICE=$(get_or_create_service "ec2" \
+ "ec2" "EC2 Compatibility Layer")
+ get_or_create_endpoint $EC2_SERVICE \
+ "$REGION_NAME" \
+ "http://$SERVICE_HOST:8773/services/Cloud" \
+ "http://$SERVICE_HOST:8773/services/Admin" \
+ "http://$SERVICE_HOST:8773/services/Cloud"
fi
fi
# S3
if is_service_enabled n-obj swift3; then
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
- openstack service create \
- --type s3 \
- --description "S3" \
- s3
- openstack endpoint create \
- --region RegionOne \
- --publicurl "http://$SERVICE_HOST:$S3_SERVICE_PORT" \
- --adminurl "http://$SERVICE_HOST:$S3_SERVICE_PORT" \
- --internalurl "http://$SERVICE_HOST:$S3_SERVICE_PORT" \
- s3
+
+ S3_SERVICE=$(get_or_create_service "s3" "s3" "S3")
+ get_or_create_endpoint $S3_SERVICE \
+ "$REGION_NAME" \
+ "http://$SERVICE_HOST:$S3_SERVICE_PORT" \
+ "http://$SERVICE_HOST:$S3_SERVICE_PORT" \
+ "http://$SERVICE_HOST:$S3_SERVICE_PORT"
fi
fi
}
@@ -438,10 +414,6 @@
iniset $NOVA_CONF DEFAULT s3_host "$SERVICE_HOST"
iniset $NOVA_CONF DEFAULT s3_port "$S3_SERVICE_PORT"
iniset $NOVA_CONF DEFAULT my_ip "$HOST_IP"
- iniset $NOVA_CONF DEFAULT osapi_compute_workers "4"
- iniset $NOVA_CONF DEFAULT ec2_workers "4"
- iniset $NOVA_CONF DEFAULT metadata_workers "4"
- iniset $NOVA_CONF conductor workers "4"
iniset $NOVA_CONF DEFAULT sql_connection `database_connection_url nova`
iniset $NOVA_CONF DEFAULT instance_name_template "${INSTANCE_NAME_PREFIX}%08x"
iniset $NOVA_CONF osapi_v3 enabled "True"
@@ -465,9 +437,7 @@
# Add keystone authtoken configuration
- iniset $NOVA_CONF keystone_authtoken auth_host $KEYSTONE_AUTH_HOST
- iniset $NOVA_CONF keystone_authtoken auth_port $KEYSTONE_AUTH_PORT
- iniset $NOVA_CONF keystone_authtoken auth_protocol $KEYSTONE_AUTH_PROTOCOL
+ iniset $NOVA_CONF keystone_authtoken identity_uri $KEYSTONE_AUTH_URI
iniset $NOVA_CONF keystone_authtoken admin_tenant_name $SERVICE_TENANT_NAME
iniset $NOVA_CONF keystone_authtoken cafile $KEYSTONE_SSL_CA
iniset $NOVA_CONF keystone_authtoken admin_user nova
@@ -510,18 +480,6 @@
iniset $NOVA_CONF DEFAULT notification_driver "messaging"
fi
- # Provide some transition from ``EXTRA_FLAGS`` to ``EXTRA_OPTS``
- if [[ -z "$EXTRA_OPTS" && -n "$EXTRA_FLAGS" ]]; then
- EXTRA_OPTS=$EXTRA_FLAGS
- fi
-
- # Define extra nova conf flags by defining the array ``EXTRA_OPTS``.
- # For Example: ``EXTRA_OPTS=(foo=true bar=2)``
- for I in "${EXTRA_OPTS[@]}"; do
- # Replace the first '=' with ' ' for iniset syntax
- iniset $NOVA_CONF DEFAULT ${I/=/ }
- done
-
# All nova-compute workers need to know the vnc configuration options
# These settings don't hurt anything if n-xvnc and n-novnc are disabled
if is_service_enabled n-cpu; then
@@ -559,7 +517,7 @@
iniset $NOVA_CONF DEFAULT ec2_dmz_host "$EC2_DMZ_HOST"
iniset_rpc_backend nova $NOVA_CONF DEFAULT
- iniset $NOVA_CONF DEFAULT glance_api_servers "$GLANCE_HOSTPORT"
+ iniset $NOVA_CONF glance api_servers "$GLANCE_HOSTPORT"
}
function init_nova_cells {
diff --git a/lib/nova_plugins/functions-libvirt b/lib/nova_plugins/functions-libvirt
index f435456..6fb5c38 100644
--- a/lib/nova_plugins/functions-libvirt
+++ b/lib/nova_plugins/functions-libvirt
@@ -29,21 +29,16 @@
install_package python-libguestfs
fi
- # workaround for
- # https://bugzilla.redhat.com/show_bug.cgi?id=1098376; if we see
- # the empty Xen proc file then remove the xen/libxl plugin
- # shared-libraries (yum remove would uninstall libvirt due to
- # dependencies, so let's avoid that...)
- if is_fedora && [ -f /proc/xen/capabilities ] && \
- [ $(stat -c '%s' /proc/xen/capabilities) -eq 0 ]; then
- sudo rm -f /usr/lib64/libvirt/connection-driver/libvirt_driver_libxl.so
- sudo rm -f /usr/lib64/libvirt/connection-driver/libvirt_driver_xen.so
+ # Restart firewalld after install of libvirt to avoid a problem
+ # with polkit, which libvirtd brings in. See
+ # https://bugzilla.redhat.com/show_bug.cgi?id=1099031
- # another bug requires these to be restarted to avoid
- # potential hang of libvirtd
- # https://bugzilla.redhat.com/show_bug.cgi?id=1098866
- sudo service dbus restart
- sudo service firewalld restart
+ # Note there is a difference between F20 rackspace cloud images
+ # and HP images used in the gate; rackspace has firewalld but hp
+ # cloud doesn't. RHEL6 doesn't have firewalld either. So we
+ # don't care if it fails.
+ if is_fedora; then
+ sudo service firewalld restart || true
fi
}
@@ -117,7 +112,15 @@
# Enable server side traces for libvirtd
if [[ "$DEBUG_LIBVIRT" = "True" ]] ; then
- local log_filters="1:libvirt 1:qemu 1:conf 1:security 3:event 3:json 3:file 1:util"
+ if is_ubuntu; then
+ # Unexpectedly binary package builds in ubuntu get fully qualified
+ # source file paths, not relative paths. This screws with the matching
+ # of '1:libvirt' making everything turn on. So use libvirt.c for now.
+ # This will have to be re-visited when Ubuntu ships libvirt >= 1.2.3
+ local log_filters="1:libvirt.c 1:qemu 1:conf 1:security 3:object 3:event 3:json 3:file 1:util"
+ else
+ local log_filters="1:libvirt 1:qemu 1:conf 1:security 3:object 3:event 3:json 3:file 1:util"
+ fi
local log_outputs="1:file:/var/log/libvirt/libvirtd.log"
if ! grep -q "log_filters=\"$log_filters\"" /etc/libvirt/libvirtd.conf; then
echo "log_filters=\"$log_filters\"" | sudo tee -a /etc/libvirt/libvirtd.conf
diff --git a/lib/nova_plugins/hypervisor-baremetal b/lib/nova_plugins/hypervisor-baremetal
index 1d4d414..22d16a6 100644
--- a/lib/nova_plugins/hypervisor-baremetal
+++ b/lib/nova_plugins/hypervisor-baremetal
@@ -58,12 +58,6 @@
sudo cp "$FILES/dnsmasq-for-baremetal-from-nova-network.conf" "$BM_DNSMASQ_CONF"
iniset $NOVA_CONF DEFAULT dnsmasq_config_file "$BM_DNSMASQ_CONF"
fi
-
- # Define extra baremetal nova conf flags by defining the array ``EXTRA_BAREMETAL_OPTS``.
- for I in "${EXTRA_BAREMETAL_OPTS[@]}"; do
- # Attempt to convert flags to options
- iniset $NOVA_CONF baremetal ${I/=/ }
- done
}
# install_nova_hypervisor() - Install external components
diff --git a/lib/nova_plugins/hypervisor-ironic b/lib/nova_plugins/hypervisor-ironic
index e72f7c1..c068c74 100644
--- a/lib/nova_plugins/hypervisor-ironic
+++ b/lib/nova_plugins/hypervisor-ironic
@@ -48,7 +48,7 @@
# ironic section
iniset $NOVA_CONF ironic admin_username admin
iniset $NOVA_CONF ironic admin_password $ADMIN_PASSWORD
- iniset $NOVA_CONF ironic admin_url $KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT/v2.0
+ iniset $NOVA_CONF ironic admin_url $KEYSTONE_AUTH_URI/v2.0
iniset $NOVA_CONF ironic admin_tenant_name demo
iniset $NOVA_CONF ironic api_endpoint http://$SERVICE_HOST:6385/v1
iniset $NOVA_CONF ironic sql_connection `database_connection_url nova_bm`
diff --git a/lib/nova_plugins/hypervisor-xenserver b/lib/nova_plugins/hypervisor-xenserver
index c37969b..0dba471 100644
--- a/lib/nova_plugins/hypervisor-xenserver
+++ b/lib/nova_plugins/hypervisor-xenserver
@@ -49,9 +49,9 @@
fi
read_password XENAPI_PASSWORD "ENTER A PASSWORD TO USE FOR XEN."
iniset $NOVA_CONF DEFAULT compute_driver "xenapi.XenAPIDriver"
- iniset $NOVA_CONF DEFAULT xenapi_connection_url "$XENAPI_CONNECTION_URL"
- iniset $NOVA_CONF DEFAULT xenapi_connection_username "$XENAPI_USER"
- iniset $NOVA_CONF DEFAULT xenapi_connection_password "$XENAPI_PASSWORD"
+ iniset $NOVA_CONF xenserver connection_url "$XENAPI_CONNECTION_URL"
+ iniset $NOVA_CONF xenserver connection_username "$XENAPI_USER"
+ iniset $NOVA_CONF xenserver connection_password "$XENAPI_PASSWORD"
iniset $NOVA_CONF DEFAULT flat_injected "False"
# Need to avoid crash due to new firewall support
XEN_FIREWALL_DRIVER=${XEN_FIREWALL_DRIVER:-"nova.virt.firewall.IptablesFirewallDriver"}
diff --git a/lib/opendaylight b/lib/opendaylight
index 0ac7f2b..33b3f0a 100644
--- a/lib/opendaylight
+++ b/lib/opendaylight
@@ -122,22 +122,10 @@
unzip -u $ODL_PKG
}
-# install_opendaylight-compute - Make sure OVS is install
+# install_opendaylight-compute - Make sure OVS is installed
function install_opendaylight-compute {
- local kernel_version
- # Install deps
- # FIXME add to ``files/apts/neutron``, but don't install if not needed!
- if is_ubuntu; then
- kernel_version=`cat /proc/version | cut -d " " -f3`
- install_package make fakeroot dkms openvswitch-switch openvswitch-datapath-dkms linux-headers-$kernel_version
- elif is_fedora; then
- install_package openvswitch
- # Ensure that the service is started
- restart_service openvswitch
- elif is_suse; then
- install_package openvswitch-switch
- restart_service openvswitch-switch
- fi
+ # packages are the same as for Neutron OVS agent
+ _neutron_ovs_base_install_agent_packages
}
# start_opendaylight() - Start running processes, including screen
diff --git a/lib/oslo b/lib/oslo
index dc6b550..421fbce 100644
--- a/lib/oslo
+++ b/lib/oslo
@@ -23,6 +23,7 @@
CLIFF_DIR=$DEST/cliff
OSLOCFG_DIR=$DEST/oslo.config
OSLODB_DIR=$DEST/oslo.db
+OSLOI18N_DIR=$DEST/oslo.i18n
OSLOMSG_DIR=$DEST/oslo.messaging
OSLORWRAP_DIR=$DEST/oslo.rootwrap
OSLOVMWARE_DIR=$DEST/oslo.vmware
@@ -30,6 +31,9 @@
STEVEDORE_DIR=$DEST/stevedore
TASKFLOW_DIR=$DEST/taskflow
+# Support entry points installation of console scripts
+OSLO_BIN_DIR=$(get_python_exec_prefix)
+
# Entry Points
# ------------
@@ -42,6 +46,9 @@
git_clone $CLIFF_REPO $CLIFF_DIR $CLIFF_BRANCH
setup_install $CLIFF_DIR
+ git_clone $OSLOI18N_REPO $OSLOI18N_DIR $OSLOI18N_BRANCH
+ setup_install $OSLOI18N_DIR
+
git_clone $OSLOCFG_REPO $OSLOCFG_DIR $OSLOCFG_BRANCH
setup_install $OSLOCFG_DIR
@@ -51,6 +58,9 @@
git_clone $OSLORWRAP_REPO $OSLORWRAP_DIR $OSLORWRAP_BRANCH
setup_install $OSLORWRAP_DIR
+ git_clone $OSLODB_REPO $OSLODB_DIR $OSLODB_BRANCH
+ setup_install $OSLODB_DIR
+
git_clone $OSLOVMWARE_REPO $OSLOVMWARE_DIR $OSLOVMWARE_BRANCH
setup_install $OSLOVMWARE_DIR
diff --git a/lib/rpc_backend b/lib/rpc_backend
index e922daa..a62d4e7 100644
--- a/lib/rpc_backend
+++ b/lib/rpc_backend
@@ -94,11 +94,7 @@
function install_rpc_backend {
if is_service_enabled rabbit; then
# Install rabbitmq-server
- # the temp file is necessary due to LP: #878600
- tfile=$(mktemp)
- install_package rabbitmq-server > "$tfile" 2>&1
- cat "$tfile"
- rm -f "$tfile"
+ install_package rabbitmq-server
elif is_service_enabled qpid; then
if is_fedora; then
install_package qpid-cpp-server
diff --git a/lib/sahara b/lib/sahara
index d56cf1b..70feacd 100644
--- a/lib/sahara
+++ b/lib/sahara
@@ -60,29 +60,19 @@
SERVICE_TENANT=$(openstack project list | awk "/ $SERVICE_TENANT_NAME / { print \$2 }")
ADMIN_ROLE=$(openstack role list | awk "/ admin / { print \$2 }")
- SAHARA_USER=$(openstack user create \
- sahara \
- --password "$SERVICE_PASSWORD" \
- --project $SERVICE_TENANT \
- --email sahara@example.com \
- | grep " id " | get_field 2)
- openstack role add \
- $ADMIN_ROLE \
- --project $SERVICE_TENANT \
- --user $SAHARA_USER
+ SAHARA_USER=$(get_or_create_user "sahara" \
+ "$SERVICE_PASSWORD" $SERVICE_TENANT)
+ get_or_add_user_role $ADMIN_ROLE $SAHARA_USER $SERVICE_TENANT
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
- SAHARA_SERVICE=$(openstack service create \
- sahara \
- --type=data_processing \
- --description="Sahara Data Processing" \
- | grep " id " | get_field 2)
- openstack endpoint create \
- $SAHARA_SERVICE \
- --region RegionOne \
- --publicurl "$SAHARA_SERVICE_PROTOCOL://$SAHARA_SERVICE_HOST:$SAHARA_SERVICE_PORT/v1.1/\$(tenant_id)s" \
- --adminurl "$SAHARA_SERVICE_PROTOCOL://$SAHARA_SERVICE_HOST:$SAHARA_SERVICE_PORT/v1.1/\$(tenant_id)s" \
- --internalurl "$SAHARA_SERVICE_PROTOCOL://$SAHARA_SERVICE_HOST:$SAHARA_SERVICE_PORT/v1.1/\$(tenant_id)s"
+
+ SAHARA_SERVICE=$(get_or_create_service "sahara" \
+ "data_processing" "Sahara Data Processing")
+ get_or_create_endpoint $SAHARA_SERVICE \
+ "$REGION_NAME" \
+ "$SAHARA_SERVICE_PROTOCOL://$SAHARA_SERVICE_HOST:$SAHARA_SERVICE_PORT/v1.1/\$(tenant_id)s" \
+ "$SAHARA_SERVICE_PROTOCOL://$SAHARA_SERVICE_HOST:$SAHARA_SERVICE_PORT/v1.1/\$(tenant_id)s" \
+ "$SAHARA_SERVICE_PROTOCOL://$SAHARA_SERVICE_HOST:$SAHARA_SERVICE_PORT/v1.1/\$(tenant_id)s"
fi
}
@@ -110,14 +100,6 @@
sudo chown $STACK_USER $SAHARA_AUTH_CACHE_DIR
rm -rf $SAHARA_AUTH_CACHE_DIR/*
- # Set obsolete keystone auth configs for backward compatibility
- iniset $SAHARA_CONF_FILE DEFAULT os_auth_host $KEYSTONE_AUTH_HOST
- iniset $SAHARA_CONF_FILE DEFAULT os_auth_port $KEYSTONE_AUTH_PORT
- iniset $SAHARA_CONF_FILE DEFAULT os_auth_protocol $KEYSTONE_AUTH_PROTOCOL
- iniset $SAHARA_CONF_FILE DEFAULT os_admin_password $SERVICE_PASSWORD
- iniset $SAHARA_CONF_FILE DEFAULT os_admin_username sahara
- iniset $SAHARA_CONF_FILE DEFAULT os_admin_tenant_name $SERVICE_TENANT_NAME
-
# Set actual keystone auth configs
iniset $SAHARA_CONF_FILE keystone_authtoken auth_uri $KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/
iniset $SAHARA_CONF_FILE keystone_authtoken auth_host $KEYSTONE_AUTH_HOST
diff --git a/lib/swift b/lib/swift
index c47b09f..84304d3 100644
--- a/lib/swift
+++ b/lib/swift
@@ -118,6 +118,8 @@
# Tell Tempest this project is present
TEMPEST_SERVICES+=,swift
+# Toggle for deploying Keystone under HTTPD + mod_wsgi
+SWIFT_USE_MOD_WSGI=${SWIFT_USE_MOD_WSGI:-False}
# Functions
# ---------
@@ -139,7 +141,7 @@
rm ${SWIFT_DISK_IMAGE}
fi
rm -rf ${SWIFT_DATA_DIR}/run/
- if is_apache_enabled_service swift; then
+ if [ "$SWIFT_USE_MOD_WSGI" == "True" ]; then
_cleanup_swift_apache_wsgi
fi
}
@@ -337,12 +339,12 @@
iniset ${SWIFT_CONFIG_PROXY_SERVER} app:proxy-server node_timeout 120
iniset ${SWIFT_CONFIG_PROXY_SERVER} app:proxy-server conn_timeout 20
- # Skipped due to bug 1294789
- ## Configure Ceilometer
- #if is_service_enabled ceilometer; then
- # iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:ceilometer use "egg:ceilometer#swift"
- # SWIFT_EXTRAS_MIDDLEWARE_LAST="${SWIFT_EXTRAS_MIDDLEWARE_LAST} ceilometer"
- #fi
+ # Configure Ceilometer
+ if is_service_enabled ceilometer; then
+ iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:ceilometer "set log_level" "WARN"
+ iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:ceilometer use "egg:ceilometer#swift"
+ SWIFT_EXTRAS_MIDDLEWARE_LAST="${SWIFT_EXTRAS_MIDDLEWARE_LAST} ceilometer"
+ fi
# Restrict the length of auth tokens in the swift proxy-server logs.
iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:proxy-logging reveal_sensitive_prefix ${SWIFT_LOG_TOKEN_LENGTH}
@@ -354,7 +356,12 @@
if is_service_enabled swift3;then
swift_pipeline+=" swift3 s3token "
fi
- swift_pipeline+=" authtoken keystoneauth tempauth "
+
+ if is_service_enabled key;then
+ swift_pipeline+=" authtoken keystoneauth"
+ fi
+ swift_pipeline+=" tempauth "
+
sed -i "/^pipeline/ { s/tempauth/${swift_pipeline} ${SWIFT_EXTRAS_MIDDLEWARE}/ ;}" ${SWIFT_CONFIG_PROXY_SERVER}
sed -i "/^pipeline/ { s/proxy-server/${SWIFT_EXTRAS_MIDDLEWARE_LAST} proxy-server/ ; }" ${SWIFT_CONFIG_PROXY_SERVER}
@@ -465,7 +472,7 @@
sudo killall -HUP rsyslogd
fi
- if is_apache_enabled_service swift; then
+ if [ "$SWIFT_USE_MOD_WSGI" == "True" ]; then
_config_swift_apache_wsgi
fi
}
@@ -542,50 +549,40 @@
SERVICE_TENANT=$(openstack project list | awk "/ $SERVICE_TENANT_NAME / { print \$2 }")
ADMIN_ROLE=$(openstack role list | awk "/ admin / { print \$2 }")
- SWIFT_USER=$(openstack user create \
- swift \
- --password "$SERVICE_PASSWORD" \
- --project $SERVICE_TENANT \
- --email=swift@example.com \
- | grep " id " | get_field 2)
- openstack role add \
- $ADMIN_ROLE \
- --project $SERVICE_TENANT \
- --user $SWIFT_USER
+ SWIFT_USER=$(get_or_create_user "swift" \
+ "$SERVICE_PASSWORD" $SERVICE_TENANT)
+ get_or_add_user_role $ADMIN_ROLE $SWIFT_USER $SERVICE_TENANT
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
- SWIFT_SERVICE=$(openstack service create \
- swift \
- --type="object-store" \
- --description="Swift Service" \
- | grep " id " | get_field 2)
- openstack endpoint create \
- $SWIFT_SERVICE \
- --region RegionOne \
- --publicurl "http://$SERVICE_HOST:8080/v1/AUTH_\$(tenant_id)s" \
- --adminurl "http://$SERVICE_HOST:8080" \
- --internalurl "http://$SERVICE_HOST:8080/v1/AUTH_\$(tenant_id)s"
+
+ SWIFT_SERVICE=$(get_or_create_service "swift" \
+ "object-store" "Swift Service")
+ get_or_create_endpoint $SWIFT_SERVICE \
+ "$REGION_NAME" \
+ "http://$SERVICE_HOST:8080/v1/AUTH_\$(tenant_id)s" \
+ "http://$SERVICE_HOST:8080" \
+ "http://$SERVICE_HOST:8080/v1/AUTH_\$(tenant_id)s"
fi
- SWIFT_TENANT_TEST1=$(openstack project create swifttenanttest1 | grep " id " | get_field 2)
+ SWIFT_TENANT_TEST1=$(get_or_create_project swifttenanttest1)
die_if_not_set $LINENO SWIFT_TENANT_TEST1 "Failure creating SWIFT_TENANT_TEST1"
- SWIFT_USER_TEST1=$(openstack user create swiftusertest1 --password=$SWIFTUSERTEST1_PASSWORD \
- --project "$SWIFT_TENANT_TEST1" --email=test@example.com | grep " id " | get_field 2)
+ SWIFT_USER_TEST1=$(get_or_create_user swiftusertest1 $SWIFTUSERTEST1_PASSWORD \
+ "$SWIFT_TENANT_TEST1" "test@example.com")
die_if_not_set $LINENO SWIFT_USER_TEST1 "Failure creating SWIFT_USER_TEST1"
- openstack role add --user $SWIFT_USER_TEST1 --project $SWIFT_TENANT_TEST1 $ADMIN_ROLE
+ get_or_add_user_role $ADMIN_ROLE $SWIFT_USER_TEST1 $SWIFT_TENANT_TEST1
- SWIFT_USER_TEST3=$(openstack user create swiftusertest3 --password=$SWIFTUSERTEST3_PASSWORD \
- --project "$SWIFT_TENANT_TEST1" --email=test3@example.com | grep " id " | get_field 2)
+ SWIFT_USER_TEST3=$(get_or_create_user swiftusertest3 $SWIFTUSERTEST3_PASSWORD \
+ "$SWIFT_TENANT_TEST1" "test3@example.com")
die_if_not_set $LINENO SWIFT_USER_TEST3 "Failure creating SWIFT_USER_TEST3"
- openstack role add --user $SWIFT_USER_TEST3 --project $SWIFT_TENANT_TEST1 $ANOTHER_ROLE
+ get_or_add_user_role $ANOTHER_ROLE $SWIFT_USER_TEST3 $SWIFT_TENANT_TEST1
- SWIFT_TENANT_TEST2=$(openstack project create swifttenanttest2 | grep " id " | get_field 2)
+ SWIFT_TENANT_TEST2=$(get_or_create_project swifttenanttest2)
die_if_not_set $LINENO SWIFT_TENANT_TEST2 "Failure creating SWIFT_TENANT_TEST2"
- SWIFT_USER_TEST2=$(openstack user create swiftusertest2 --password=$SWIFTUSERTEST2_PASSWORD \
- --project "$SWIFT_TENANT_TEST2" --email=test2@example.com | grep " id " | get_field 2)
+ SWIFT_USER_TEST2=$(get_or_create_user swiftusertest2 $SWIFTUSERTEST2_PASSWORD \
+ "$SWIFT_TENANT_TEST2" "test2@example.com")
die_if_not_set $LINENO SWIFT_USER_TEST2 "Failure creating SWIFT_USER_TEST2"
- openstack role add --user $SWIFT_USER_TEST2 --project $SWIFT_TENANT_TEST2 $ADMIN_ROLE
+ get_or_add_user_role $ADMIN_ROLE $SWIFT_USER_TEST2 $SWIFT_TENANT_TEST2
}
# init_swift() - Initialize rings
@@ -626,7 +623,7 @@
function install_swift {
git_clone $SWIFT_REPO $SWIFT_DIR $SWIFT_BRANCH
setup_develop $SWIFT_DIR
- if is_apache_enabled_service swift; then
+ if [ "$SWIFT_USE_MOD_WSGI" == "True" ]; then
install_apache_wsgi
fi
}
@@ -650,7 +647,7 @@
start_service rsyncd
fi
- if is_apache_enabled_service swift; then
+ if [ "$SWIFT_USE_MOD_WSGI" == "True" ]; then
restart_apache_server
swift-init --run-dir=${SWIFT_DATA_DIR}/run rest start
screen_it s-proxy "cd $SWIFT_DIR && sudo tail -f /var/log/$APACHE_NAME/proxy-server"
@@ -687,7 +684,7 @@
# stop_swift() - Stop running processes (non-screen)
function stop_swift {
- if is_apache_enabled_service swift; then
+ if [ "$SWIFT_USE_MOD_WSGI" == "True" ]; then
swift-init --run-dir=${SWIFT_DATA_DIR}/run rest stop && return 0
fi
diff --git a/lib/tempest b/lib/tempest
index 79412f9..59c5bbc 100644
--- a/lib/tempest
+++ b/lib/tempest
@@ -64,6 +64,7 @@
# Neutron/Network variables
IPV6_ENABLED=$(trueorfalse True $IPV6_ENABLED)
+IPV6_SUBNET_ATTRIBUTES_ENABLED=$(trueorfalse True $IPV6_SUBNET_ATTRIBUTES_ENABLED)
# Functions
# ---------
@@ -148,6 +149,7 @@
TEMPEST_TENANT_NAME=${TEMPEST_TENANT_NAME:-demo}
ALT_USERNAME=${ALT_USERNAME:-alt_demo}
ALT_TENANT_NAME=${ALT_TENANT_NAME:-alt_demo}
+ ADMIN_TENANT_ID=$(openstack project list | awk "/ admin / { print \$2 }")
# If the ``DEFAULT_INSTANCE_TYPE`` not declared, use the new behavior
# Tempest creates instane types for himself
@@ -241,9 +243,6 @@
iniset $TEMPEST_CONFIG compute build_timeout $BUILD_TIMEOUT
iniset $TEMPEST_CONFIG volume build_timeout $BUILD_TIMEOUT
iniset $TEMPEST_CONFIG boto build_timeout $BUILD_TIMEOUT
- iniset $TEMPEST_CONFIG compute build_interval $BUILD_INTERVAL
- iniset $TEMPEST_CONFIG volume build_interval $BUILD_INTERVAL
- iniset $TEMPEST_CONFIG boto build_interval $BUILD_INTERVAL
iniset $TEMPEST_CONFIG boto http_socket_timeout 5
# Identity
@@ -258,6 +257,7 @@
iniset $TEMPEST_CONFIG identity admin_username $ADMIN_USERNAME
iniset $TEMPEST_CONFIG identity admin_password "$password"
iniset $TEMPEST_CONFIG identity admin_tenant_name $ADMIN_TENANT_NAME
+ iniset $TEMPEST_CONFIG identity admin_tenant_id $ADMIN_TENANT_ID
iniset $TEMPEST_CONFIG identity admin_domain_name $ADMIN_DOMAIN_NAME
iniset $TEMPEST_CONFIG identity auth_version ${TEMPEST_AUTH_VERSION:-v2}
@@ -283,6 +283,7 @@
iniset $TEMPEST_CONFIG compute ssh_connect_method $ssh_connect_method
# Compute Features
+ iniset $TEMPEST_CONFIG compute-feature-enabled api_v3 ${TEMPEST_NOVA_API_V3:-False}
iniset $TEMPEST_CONFIG compute-feature-enabled resize True
iniset $TEMPEST_CONFIG compute-feature-enabled live_migration ${LIVE_MIGRATION_AVAILABLE:-False}
iniset $TEMPEST_CONFIG compute-feature-enabled change_password False
@@ -318,10 +319,10 @@
if [[ ! -z "$HEAT_CFN_IMAGE_URL" ]]; then
iniset $TEMPEST_CONFIG orchestration image_ref $(basename "$HEAT_CFN_IMAGE_URL" ".qcow2")
fi
- # build a specialized heat flavor that is likely to be fast
+ # build a specialized heat flavor
available_flavors=$(nova flavor-list)
if [[ ! ( $available_flavors =~ 'm1.heat' ) ]]; then
- nova flavor-create m1.heat 451 1024 0 2
+ nova flavor-create m1.heat 451 512 0 1
fi
iniset $TEMPEST_CONFIG orchestration instance_type "m1.heat"
iniset $TEMPEST_CONFIG orchestration build_timeout 900
@@ -336,6 +337,11 @@
# Large Ops Number
iniset $TEMPEST_CONFIG scenario large_ops_number ${TEMPEST_LARGE_OPS_NUMBER:-0}
+ # Telemetry
+ # Ceilometer API optimization happened in juno that allows to run more tests in tempest.
+ # Once Tempest retires support for icehouse this flag can be removed.
+ iniset $TEMPEST_CONFIG telemetry too_slow_to_test "False"
+
# Volume
if ! is_service_enabled c-bak; then
iniset $TEMPEST_CONFIG volume-feature-enabled backup False
@@ -391,16 +397,9 @@
if is_service_enabled tempest; then
# Tempest has some tests that validate various authorization checks
# between two regular users in separate tenants
- openstack project create \
- alt_demo
- openstack user create \
- --project alt_demo \
- --password "$ADMIN_PASSWORD" \
- alt_demo
- openstack role add \
- --project alt_demo \
- --user alt_demo \
- Member
+ get_or_create_project alt_demo
+ get_or_create_user alt_demo "$ADMIN_PASSWORD" alt_demo "alt_demo@example.com"
+ get_or_add_user_role Member alt_demo alt_demo
fi
}
diff --git a/lib/tls b/lib/tls
index 88e5f60..e58e513 100644
--- a/lib/tls
+++ b/lib/tls
@@ -18,9 +18,12 @@
# - configure_proxy
# - start_tls_proxy
-# - make_root_ca
-# - make_int_ca
-# - new_cert $INT_CA_DIR int-server "abc"
+# - stop_tls_proxy
+# - cleanup_CA
+
+# - make_root_CA
+# - make_int_CA
+# - make_cert ca-dir cert-name "common-name" ["alt-name" ...]
# - start_tls_proxy HOST_IP 5000 localhost 5000
# - ensure_certificates
# - is_ssl_enabled_service
@@ -320,7 +323,8 @@
#
# Uses global ``SSL_ENABLED_SERVICES``
function is_ssl_enabled_service {
- services=$@
+ local services=$@
+ local service=""
for service in ${services}; do
[[ ,${SSL_ENABLED_SERVICES}, =~ ,${service}, ]] && return 0
done
@@ -372,6 +376,22 @@
}
+# Cleanup Functions
+# ===============
+
+
+# Stops all stud processes. This should be done only after all services
+# using tls configuration are down.
+function stop_tls_proxy {
+ killall stud
+}
+
+
+# Remove CA along with configuration, as well as the local server certificate
+function cleanup_CA {
+ rm -rf "$DATA_DIR/CA" "$DEVSTACK_CERT"
+}
+
# Tell emacs to use shell-script-mode
## Local variables:
## mode: shell-script
diff --git a/lib/trove b/lib/trove
index 82c8c96..2a54336 100644
--- a/lib/trove
+++ b/lib/trove
@@ -33,6 +33,9 @@
TROVE_CONF_DIR=/etc/trove
TROVE_LOCAL_CONF_DIR=$TROVE_DIR/etc/trove
TROVE_AUTH_CACHE_DIR=${TROVE_AUTH_CACHE_DIR:-/var/cache/trove}
+TROVE_DATASTORE_TYPE=${TROVE_DATASTORE_TYPE:-"mysql"}
+TROVE_DATASTORE_VERSION=${TROVE_DATASTORE_VERSION:-"5.5"}
+TROVE_DATASTORE_PACKAGE=${TROVE_DATASTORE_PACKAGE:-"mysql-server-5.5"}
# Support entry points installation of console scripts
if [[ -d $TROVE_DIR/bin ]]; then
@@ -78,28 +81,20 @@
SERVICE_ROLE=$(openstack role list | awk "/ admin / { print \$2 }")
if [[ "$ENABLED_SERVICES" =~ "trove" ]]; then
- TROVE_USER=$(openstack user create \
- trove \
- --password "$SERVICE_PASSWORD" \
- --project $SERVICE_TENANT \
- --email trove@example.com \
- | grep " id " | get_field 2)
- openstack role add \
- $SERVICE_ROLE \
- --project $SERVICE_TENANT \
- --user $TROVE_USER
+
+ TROVE_USER=$(get_or_create_user "trove" \
+ "$SERVICE_PASSWORD" $SERVICE_TENANT)
+ get_or_add_user_role $SERVICE_ROLE $TROVE_USER $SERVICE_TENANT
+
if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
- TROVE_SERVICE=$(openstack service create \
- trove \
- --type=database \
- --description="Trove Service" \
- | grep " id " | get_field 2)
- openstack endpoint create \
- $TROVE_SERVICE \
- --region RegionOne \
- --publicurl "http://$SERVICE_HOST:8779/v1.0/\$(tenant_id)s" \
- --adminurl "http://$SERVICE_HOST:8779/v1.0/\$(tenant_id)s" \
- --internalurl "http://$SERVICE_HOST:8779/v1.0/\$(tenant_id)s"
+
+ TROVE_SERVICE=$(get_or_create_service "trove" \
+ "database" "Trove Service")
+ get_or_create_endpoint $TROVE_SERVICE \
+ "$REGION_NAME" \
+ "http://$SERVICE_HOST:8779/v1.0/\$(tenant_id)s" \
+ "http://$SERVICE_HOST:8779/v1.0/\$(tenant_id)s" \
+ "http://$SERVICE_HOST:8779/v1.0/\$(tenant_id)s"
fi
fi
}
@@ -133,9 +128,8 @@
# Copy api-paste file over to the trove conf dir and configure it
cp $TROVE_LOCAL_CONF_DIR/api-paste.ini $TROVE_CONF_DIR/api-paste.ini
TROVE_API_PASTE_INI=$TROVE_CONF_DIR/api-paste.ini
- iniset $TROVE_API_PASTE_INI filter:authtoken auth_host $KEYSTONE_AUTH_HOST
- iniset $TROVE_API_PASTE_INI filter:authtoken auth_port $KEYSTONE_AUTH_PORT
- iniset $TROVE_API_PASTE_INI filter:authtoken auth_protocol $KEYSTONE_AUTH_PROTOCOL
+
+ iniset $TROVE_API_PASTE_INI filter:authtoken identity_uri $KEYSTONE_AUTH_URI
iniset $TROVE_API_PASTE_INI filter:authtoken cafile $KEYSTONE_SSL_CA
iniset $TROVE_API_PASTE_INI filter:authtoken admin_tenant_name $SERVICE_TENANT_NAME
iniset $TROVE_API_PASTE_INI filter:authtoken admin_user trove
@@ -149,16 +143,12 @@
iniset $TROVE_CONF_DIR/trove.conf DEFAULT rabbit_password $RABBIT_PASSWORD
iniset $TROVE_CONF_DIR/trove.conf DEFAULT sql_connection `database_connection_url trove`
-
- iniset $TROVE_LOCAL_CONF_DIR/trove-guestagent.conf.sample DEFAULT rabbit_password $RABBIT_PASSWORD
- sed -i "s/localhost/$TROVE_HOST_GATEWAY/g" $TROVE_LOCAL_CONF_DIR/trove-guestagent.conf.sample
-
+ iniset $TROVE_CONF_DIR/trove.conf DEFAULT default_datastore $TROVE_DATASTORE_TYPE
setup_trove_logging $TROVE_CONF_DIR/trove.conf
- setup_trove_logging $TROVE_LOCAL_CONF_DIR/trove-guestagent.conf.sample
# (Re)create trove taskmanager conf file if needed
if is_service_enabled tr-tmgr; then
- TROVE_AUTH_ENDPOINT=$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT//v$IDENTITY_API_VERSION
+ TROVE_AUTH_ENDPOINT=$KEYSTONE_AUTH_URI/v$IDENTITY_API_VERSION
iniset $TROVE_CONF_DIR/trove-taskmanager.conf DEFAULT rabbit_password $RABBIT_PASSWORD
iniset $TROVE_CONF_DIR/trove-taskmanager.conf DEFAULT sql_connection `database_connection_url trove`
@@ -181,6 +171,18 @@
iniset $TROVE_CONF_DIR/trove-conductor.conf DEFAULT control_exchange trove
setup_trove_logging $TROVE_CONF_DIR/trove-conductor.conf
fi
+
+ # Set up Guest Agent conf
+ iniset $TROVE_CONF_DIR/trove-guestagent.conf DEFAULT rabbit_host $TROVE_HOST_GATEWAY
+ iniset $TROVE_CONF_DIR/trove-guestagent.conf DEFAULT rabbit_password $RABBIT_PASSWORD
+ iniset $TROVE_CONF_DIR/trove-guestagent.conf DEFAULT nova_proxy_admin_user radmin
+ iniset $TROVE_CONF_DIR/trove-guestagent.conf DEFAULT nova_proxy_admin_tenant_name trove
+ iniset $TROVE_CONF_DIR/trove-guestagent.conf DEFAULT nova_proxy_admin_pass $RADMIN_USER_PASS
+ iniset $TROVE_CONF_DIR/trove-guestagent.conf DEFAULT trove_auth_url $TROVE_AUTH_ENDPOINT
+ iniset $TROVE_CONF_DIR/trove-guestagent.conf DEFAULT control_exchange trove
+ iniset $TROVE_CONF_DIR/trove-guestagent.conf DEFAULT log_dir /tmp/
+ iniset $TROVE_CONF_DIR/trove-guestagent.conf DEFAULT log_file trove-guestagent.log
+ setup_trove_logging $TROVE_CONF_DIR/trove-guestagent.conf
}
# install_troveclient() - Collect source and prepare
@@ -195,11 +197,22 @@
# init_trove() - Initializes Trove Database as a Service
function init_trove {
- #(Re)Create trove db
+ # (Re)Create trove db
recreate_database trove utf8
- #Initialize the trove database
+ # Initialize the trove database
$TROVE_BIN_DIR/trove-manage db_sync
+
+ # Upload the trove-guest image to glance
+ TROVE_GUEST_IMAGE_ID=$(upload_image $TROVE_GUEST_IMAGE_URL $TOKEN | grep ' id ' | get_field 2)
+
+ # Initialize appropriate datastores / datastore versions
+ $TROVE_BIN_DIR/trove-manage datastore_update "$TROVE_DATASTORE_TYPE" ""
+ $TROVE_BIN_DIR/trove-manage datastore_version_update "$TROVE_DATASTORE_TYPE" "$TROVE_DATASTORE_VERSION" "$TROVE_DATASTORE_TYPE" \
+ "$TROVE_GUEST_IMAGE_ID" "$TROVE_DATASTORE_PACKAGE" 1
+ $TROVE_BIN_DIR/trove-manage datastore_version_update "$TROVE_DATASTORE_TYPE" "inactive_version" "inactive_manager" "$TROVE_GUEST_IMAGE_ID" "" 0
+ $TROVE_BIN_DIR/trove-manage datastore_update "$TROVE_DATASTORE_TYPE" "$TROVE_DATASTORE_VERSION"
+ $TROVE_BIN_DIR/trove-manage datastore_update "Inactive_Datastore" ""
}
# start_trove() - Start running processes, including screen
diff --git a/openrc b/openrc
index fc066ad..aec8a2a 100644
--- a/openrc
+++ b/openrc
@@ -53,12 +53,16 @@
# easier with this off.
export OS_NO_CACHE=${OS_NO_CACHE:-1}
+# Region
+export OS_REGION_NAME=${REGION_NAME:-RegionOne}
+
# Set api HOST_IP endpoint. SERVICE_HOST may also be used to specify the endpoint,
# which is convenient for some localrc configurations.
HOST_IP=${HOST_IP:-127.0.0.1}
SERVICE_HOST=${SERVICE_HOST:-$HOST_IP}
SERVICE_PROTOCOL=${SERVICE_PROTOCOL:-http}
KEYSTONE_AUTH_PROTOCOL=${KEYSTONE_AUTH_PROTOCOL:-$SERVICE_PROTOCOL}
+KEYSTONE_AUTH_HOST=${KEYSTONE_AUTH_HOST:-$SERVICE_HOST}
# Some exercises call glance directly. On a single-node installation, Glance
# should be listening on HOST_IP. If its running elsewhere, it can be set here
@@ -72,7 +76,7 @@
# the user/tenant has access to - including nova, glance, keystone, swift, ...
# We currently recommend using the 2.0 *identity api*.
#
-export OS_AUTH_URL=$KEYSTONE_AUTH_PROTOCOL://$SERVICE_HOST:5000/v${OS_IDENTITY_API_VERSION}
+export OS_AUTH_URL=$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:5000/v${OS_IDENTITY_API_VERSION}
# Set the pointer to our CA certificate chain. Harmless if TLS is not used.
export OS_CACERT=${OS_CACERT:-$INT_CA_DIR/ca-chain.pem}
diff --git a/samples/local.conf b/samples/local.conf
index c8126c2..20c5892 100644
--- a/samples/local.conf
+++ b/samples/local.conf
@@ -24,8 +24,10 @@
# While ``stack.sh`` is happy to run without ``localrc``, devlife is better when
# there are a few minimal variables set:
-# If the ``*_PASSWORD`` variables are not set here you will be prompted to enter
-# values for them by ``stack.sh`` and they will be added to ``local.conf``.
+# If the ``SERVICE_TOKEN`` and ``*_PASSWORD`` variables are not set
+# here you will be prompted to enter values for them by ``stack.sh``
+# and they will be added to ``local.conf``.
+SERVICE_TOKEN=azertytoken
ADMIN_PASSWORD=nomoresecrete
MYSQL_PASSWORD=stackdb
RABBIT_PASSWORD=stackqueue
diff --git a/stack.sh b/stack.sh
index d2f18d4..f1cfe97 100755
--- a/stack.sh
+++ b/stack.sh
@@ -142,7 +142,7 @@
# Warn users who aren't on an explicitly supported distro, but allow them to
# override check and attempt installation with ``FORCE=yes ./stack``
-if [[ ! ${DISTRO} =~ (precise|saucy|trusty|7.0|wheezy|sid|testing|jessie|f19|f20|rhel6) ]]; then
+if [[ ! ${DISTRO} =~ (precise|saucy|trusty|7.0|wheezy|sid|testing|jessie|f19|f20|rhel6|rhel7) ]]; then
echo "WARNING: this script has not been tested on $DISTRO"
if [[ "$FORCE" != "yes" ]]; then
die $LINENO "If you wish to run this script anyway run with FORCE=yes"
@@ -152,7 +152,7 @@
# Look for obsolete stuff
if [[ ,${ENABLED_SERVICES}, =~ ,"swift", ]]; then
echo "FATAL: 'swift' is not supported as a service name"
- echo "FATAL: Use the actual swift service names to enable tham as required:"
+ echo "FATAL: Use the actual swift service names to enable them as required:"
echo "FATAL: s-proxy s-object s-container s-account"
exit 1
fi
@@ -211,18 +211,14 @@
# Additional repos
# ----------------
+# For debian/ubuntu make apt attempt to retry network ops on it's own
+if is_ubuntu; then
+ echo 'APT::Acquire::Retries "20";' | sudo tee /etc/apt/apt.conf.d/80retry
+fi
+
# Some distros need to add repos beyond the defaults provided by the vendor
# to pick up required packages.
-# The Debian Wheezy official repositories do not contain all required packages,
-# add gplhost repository.
-if [[ "$os_VENDOR" =~ (Debian) ]]; then
- echo 'deb http://archive.gplhost.com/debian grizzly main' | sudo tee /etc/apt/sources.list.d/gplhost_wheezy-backports.list
- echo 'deb http://archive.gplhost.com/debian grizzly-backports main' | sudo tee -a /etc/apt/sources.list.d/gplhost_wheezy-backports.list
- apt_get update
- apt_get install --force-yes gplhost-archive-keyring
-fi
-
if [[ is_fedora && $DISTRO =~ (rhel) ]]; then
# Installing Open vSwitch on RHEL requires enabling the RDO repo.
RHEL6_RDO_REPO_RPM=${RHEL6_RDO_REPO_RPM:-"http://rdo.fedorapeople.org/openstack-icehouse/rdo-release-icehouse.rpm"}
@@ -234,7 +230,7 @@
fi
# RHEL requires EPEL for many Open Stack dependencies
if [[ $DISTRO =~ (rhel7) ]]; then
- EPEL_RPM=${RHEL7_EPEL_RPM:-"http://dl.fedoraproject.org/pub/epel/beta/7/x86_64/epel-release-7-0.1.noarch.rpm"}
+ EPEL_RPM=${RHEL7_EPEL_RPM:-"http://dl.fedoraproject.org/pub/epel/beta/7/x86_64/epel-release-7-0.2.noarch.rpm"}
else
EPEL_RPM=${RHEL6_EPEL_RPM:-"http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm"}
fi
@@ -246,7 +242,12 @@
# ... and also optional to be enabled
is_package_installed yum-utils || install_package yum-utils
- sudo yum-config-manager --enable rhel-6-server-optional-rpms
+ if [[ $DISTRO =~ (rhel7) ]]; then
+ OPTIONAL_REPO=rhel-7-server-optional-rpms
+ else
+ OPTIONAL_REPO=rhel-6-server-optional-rpms
+ fi
+ sudo yum-config-manager --enable ${OPTIONAL_REPO}
fi
@@ -307,9 +308,6 @@
# Allow the use of an alternate hostname (such as localhost/127.0.0.1) for service endpoints.
SERVICE_HOST=${SERVICE_HOST:-$HOST_IP}
-# Allow the use of an alternate protocol (such as https) for service endpoints
-SERVICE_PROTOCOL=${SERVICE_PROTOCOL:-http}
-
# Configure services to use syslog instead of writing to individual log files
SYSLOG=`trueorfalse False $SYSLOG`
SYSLOG_HOST=${SYSLOG_HOST:-$HOST_IP}
@@ -520,6 +518,12 @@
echo $@ >&3
}
+if [[ is_fedora && $DISTRO =~ (rhel) ]]; then
+ # poor old python2.6 doesn't have argparse by default, which
+ # outfilter.py uses
+ is_package_installed python-argparse || install_package python-argparse
+fi
+
# Set up logging for ``stack.sh``
# Set ``LOGFILE`` to turn on logging
# Append '.xxxxxxxx' to the given name to maintain history
@@ -548,25 +552,14 @@
exec 3>&1
if [[ "$VERBOSE" == "True" ]]; then
# Set fd 1 and 2 to write the log file
- exec 1> >( awk -v logfile=${LOGFILE} '
- /((set \+o$)|xtrace)/ { next }
- {
- cmd ="date +\"%Y-%m-%d %H:%M:%S.%3N | \""
- cmd | getline now
- close("date +\"%Y-%m-%d %H:%M:%S.%3N | \"")
- sub(/^/, now)
- print > logfile
- fflush(logfile)
- print
- fflush("")
- }' ) 2>&1
+ exec 1> >( $TOP_DIR/tools/outfilter.py -v -o "${LOGFILE}" ) 2>&1
# Set fd 6 to summary log file
- exec 6> >( tee "${SUMFILE}" )
+ exec 6> >( $TOP_DIR/tools/outfilter.py -o "${SUMFILE}" )
else
# Set fd 1 and 2 to primary logfile
- exec 1> "${LOGFILE}" 2>&1
+ exec 1> >( $TOP_DIR/tools/outfilter.py -o "${LOGFILE}" ) 2>&1
# Set fd 6 to summary logfile and stdout
- exec 6> >( tee "${SUMFILE}" >&3 )
+ exec 6> >( $TOP_DIR/tools/outfilter.py -v -o "${SUMFILE}" >&3 )
fi
echo_summary "stack.sh log $LOGFILE"
@@ -583,7 +576,7 @@
exec 1>/dev/null 2>&1
fi
# Always send summary fd to original stdout
- exec 6>&3
+ exec 6> >( $TOP_DIR/tools/outfilter.py -v >&3 )
fi
# Set up logging of screen windows
@@ -622,6 +615,11 @@
# Kill the last spinner process
kill_spinner
+ if [[ $r -ne 0 ]]; then
+ echo "Error on exit"
+ ./tools/worlddump.py -d $LOGDIR
+ fi
+
exit $r
}
@@ -661,9 +659,21 @@
$TOP_DIR/tools/install_pip.sh
fi
-# Do the ugly hacks for borken packages and distros
+# Do the ugly hacks for broken packages and distros
$TOP_DIR/tools/fixup_stuff.sh
+
+# Extras Pre-install
+# ------------------
+
+# Phase: pre-install
+if [[ -d $TOP_DIR/extras.d ]]; then
+ for i in $TOP_DIR/extras.d/*.sh; do
+ [[ -r $i ]] && source $i stack pre-install
+ done
+fi
+
+
install_rpc_backend
if is_service_enabled $DATABASE_BACKENDS; then
@@ -718,12 +728,17 @@
install_heatclient
fi
+# Install middleware
+install_keystonemiddleware
+
git_clone $OPENSTACKCLIENT_REPO $OPENSTACKCLIENT_DIR $OPENSTACKCLIENT_BRANCH
setup_develop $OPENSTACKCLIENT_DIR
if is_service_enabled key; then
- install_keystone
- configure_keystone
+ if [ "$KEYSTONE_AUTH_HOST" == "$SERVICE_HOST" ]; then
+ install_keystone
+ configure_keystone
+ fi
fi
if is_service_enabled s-proxy; then
@@ -763,6 +778,8 @@
fi
if is_service_enabled horizon; then
+ # django openstack_auth
+ install_django_openstack_auth
# dashboard
install_horizon
configure_horizon
@@ -773,7 +790,6 @@
install_ceilometer
echo_summary "Configuring Ceilometer"
configure_ceilometer
- configure_ceilometerclient
fi
if is_service_enabled heat; then
@@ -920,11 +936,14 @@
if is_service_enabled key; then
echo_summary "Starting Keystone"
- init_keystone
- start_keystone
+
+ if [ "$KEYSTONE_AUTH_HOST" == "$SERVICE_HOST" ]; then
+ init_keystone
+ start_keystone
+ fi
# Set up a temporary admin URI for Keystone
- SERVICE_ENDPOINT=$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT/v2.0
+ SERVICE_ENDPOINT=$KEYSTONE_AUTH_URI/v2.0
if is_service_enabled tls-proxy; then
export OS_CACERT=$INT_CA_DIR/ca-chain.pem
@@ -962,6 +981,7 @@
export OS_TENANT_NAME=admin
export OS_USERNAME=admin
export OS_PASSWORD=$ADMIN_PASSWORD
+ export OS_REGION_NAME=$REGION_NAME
fi
@@ -1173,7 +1193,7 @@
if is_service_enabled zeromq; then
echo_summary "Starting zermomq receiver"
- screen_it zeromq "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-rpc-zmq-receiver"
+ screen_it zeromq "cd $NOVA_DIR && $OSLO_BIN_DIR/oslo-messaging-zmq-receiver"
fi
# Launch the nova-api and wait for it to answer before continuing
@@ -1218,6 +1238,7 @@
if is_service_enabled cinder; then
echo_summary "Starting Cinder"
start_cinder
+ create_volume_types
fi
if is_service_enabled ceilometer; then
echo_summary "Starting Ceilometer"
@@ -1357,7 +1378,7 @@
# If Keystone is present you can point ``nova`` cli to this server
if is_service_enabled key; then
- echo "Keystone is serving at $KEYSTONE_AUTH_PROTOCOL://$SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v2.0/"
+ echo "Keystone is serving at $KEYSTONE_SERVICE_URI/v2.0/"
echo "Examples on using novaclient command line is in exercise.sh"
echo "The default users are: admin and demo"
echo "The password: $ADMIN_PASSWORD"
@@ -1371,41 +1392,6 @@
echo_summary "WARNING: $DEPRECATED_TEXT"
fi
-# TODO(dtroyer): Remove EXTRA_OPTS after stable/icehouse branch is cut
-# Specific warning for deprecated configs
-if [[ -n "$EXTRA_OPTS" ]]; then
- echo ""
- echo_summary "WARNING: EXTRA_OPTS is used"
- echo "You are using EXTRA_OPTS to pass configuration into nova.conf."
- echo "Please convert that configuration in localrc to a nova.conf section in local.conf:"
- echo "EXTRA_OPTS will be removed early in the Juno development cycle"
- echo "
-[[post-config|\$NOVA_CONF]]
-[DEFAULT]
-"
- for I in "${EXTRA_OPTS[@]}"; do
- # Replace the first '=' with ' ' for iniset syntax
- echo ${I}
- done
-fi
-
-# TODO(dtroyer): Remove EXTRA_BAREMETAL_OPTS after stable/icehouse branch is cut
-if [[ -n "$EXTRA_BAREMETAL_OPTS" ]]; then
- echo ""
- echo_summary "WARNING: EXTRA_BAREMETAL_OPTS is used"
- echo "You are using EXTRA_BAREMETAL_OPTS to pass configuration into nova.conf."
- echo "Please convert that configuration in localrc to a nova.conf section in local.conf:"
- echo "EXTRA_BAREMETAL_OPTS will be removed early in the Juno development cycle"
- echo "
-[[post-config|\$NOVA_CONF]]
-[baremetal]
-"
- for I in "${EXTRA_BAREMETAL_OPTS[@]}"; do
- # Replace the first '=' with ' ' for iniset syntax
- echo ${I}
- done
-fi
-
# TODO(dtroyer): Remove Q_AGENT_EXTRA_AGENT_OPTS after stable/juno branch is cut
if [[ -n "$Q_AGENT_EXTRA_AGENT_OPTS" ]]; then
echo ""
@@ -1440,38 +1426,17 @@
done
fi
-# TODO(dtroyer): Remove Q_DHCP_EXTRA_DEFAULT_OPTS after stable/icehouse branch is cut
-if [[ -n "$Q_DHCP_EXTRA_DEFAULT_OPTS" ]]; then
+# TODO(dtroyer): Remove CINDER_MULTI_LVM_BACKEND after stable/juno branch is cut
+if [[ "$CINDER_MULTI_LVM_BACKEND" = "True" ]]; then
echo ""
- echo_summary "WARNING: Q_DHCP_EXTRA_DEFAULT_OPTS is used"
- echo "You are using Q_DHCP_EXTRA_DEFAULT_OPTS to pass configuration into $Q_DHCP_CONF_FILE."
- echo "Please convert that configuration in localrc to a $Q_DHCP_CONF_FILE section in local.conf:"
- echo "Q_DHCP_EXTRA_DEFAULT_OPTS will be removed early in the Juno development cycle"
+ echo_summary "WARNING: CINDER_MULTI_LVM_BACKEND is used"
+ echo "You are using CINDER_MULTI_LVM_BACKEND to configure Cinder's multiple LVM backends"
+ echo "Please convert that configuration in local.conf to use CINDER_ENABLED_BACKENDS."
+ echo "CINDER_ENABLED_BACKENDS will be removed early in the 'K' development cycle"
echo "
-[[post-config|/\$Q_DHCP_CONF_FILE]]
-[DEFAULT]
+[[local|localrc]]
+CINDER_ENABLED_BACKENDS=lvm:lvmdriver-1,lvm:lvmdriver-2
"
- for I in "${Q_DHCP_EXTRA_DEFAULT_OPTS[@]}"; do
- # Replace the first '=' with ' ' for iniset syntax
- echo ${I}
- done
-fi
-
-# TODO(dtroyer): Remove Q_SRV_EXTRA_DEFAULT_OPTS after stable/icehouse branch is cut
-if [[ -n "$Q_SRV_EXTRA_DEFAULT_OPTS" ]]; then
- echo ""
- echo_summary "WARNING: Q_SRV_EXTRA_DEFAULT_OPTS is used"
- echo "You are using Q_SRV_EXTRA_DEFAULT_OPTS to pass configuration into $NEUTRON_CONF."
- echo "Please convert that configuration in localrc to a $NEUTRON_CONF section in local.conf:"
- echo "Q_SRV_EXTRA_DEFAULT_OPTS will be removed early in the Juno development cycle"
- echo "
-[[post-config|\$NEUTRON_CONF]]
-[DEFAULT]
-"
- for I in "${Q_SRV_EXTRA_DEFAULT_OPTS[@]}"; do
- # Replace the first '=' with ' ' for iniset syntax
- echo ${I}
- done
fi
# Indicate how long this took to run (bash maintained variable ``SECONDS``)
diff --git a/stackrc b/stackrc
index 01d0e0f..9701d2d 100644
--- a/stackrc
+++ b/stackrc
@@ -19,6 +19,9 @@
STACK_USER=$(whoami)
fi
+# Specify region name Region
+REGION_NAME=${REGION_NAME:-RegionOne}
+
# Specify which services to launch. These generally correspond to
# screen tabs. To change the default list, use the ``enable_service`` and
# ``disable_service`` functions in ``local.conf``.
@@ -35,17 +38,25 @@
# # Optional, to enable tempest configuration as part of devstack
# enable_service tempest
-# core compute (glance / keystone / nova (+ nova-network))
-ENABLED_SERVICES=g-api,g-reg,key,n-api,n-crt,n-obj,n-cpu,n-net,n-cond,n-sch,n-novnc,n-xvnc,n-cauth
-# cinder
-ENABLED_SERVICES+=,c-sch,c-api,c-vol
-# heat
-ENABLED_SERVICES+=,h-eng,h-api,h-api-cfn,h-api-cw
-# dashboard
-ENABLED_SERVICES+=,horizon
-# additional services
-ENABLED_SERVICES+=,rabbit,tempest,mysql
+# this allows us to pass ENABLED_SERVICES
+if [[ -z "$ENABLED_SERVICES" ]]; then
+ # core compute (glance / keystone / nova (+ nova-network))
+ ENABLED_SERVICES=g-api,g-reg,key,n-api,n-crt,n-obj,n-cpu,n-net,n-cond,n-sch,n-novnc,n-xvnc,n-cauth
+ # cinder
+ ENABLED_SERVICES+=,c-sch,c-api,c-vol
+ # heat
+ ENABLED_SERVICES+=,h-eng,h-api,h-api-cfn,h-api-cw
+ # dashboard
+ ENABLED_SERVICES+=,horizon
+ # additional services
+ ENABLED_SERVICES+=,rabbit,tempest,mysql
+fi
+# Global toggle for enabling services under mod_wsgi. If this is set to
+# ``True`` all services that use HTTPD + mod_wsgi as the preferred method of
+# deployment, will be deployed under Apache. If this is set to ``False`` all
+# services will rely on the local toggle variable (e.g. ``KEYSTONE_USE_MOD_WSGI``)
+ENABLE_HTTPD_MOD_WSGI_SERVICES=True
# Tell Tempest which services are available. The default is set here as
# Tempest falls late in the configuration sequence. This differs from
@@ -133,6 +144,10 @@
HORIZON_REPO=${HORIZON_REPO:-${GIT_BASE}/openstack/horizon.git}
HORIZON_BRANCH=${HORIZON_BRANCH:-master}
+# django openstack_auth library
+HORIZONAUTH_REPO=${HORIZONAUTH_REPO:-${GIT_BASE}/openstack/django_openstack_auth.git}
+HORIZONAUTH_BRANCH=${HORIZONAUTH_BRANCH:-master}
+
# baremetal provisionint service
IRONIC_REPO=${IRONIC_REPO:-${GIT_BASE}/openstack/ironic.git}
IRONIC_BRANCH=${IRONIC_BRANCH:-master}
@@ -149,6 +164,10 @@
KEYSTONECLIENT_REPO=${KEYSTONECLIENT_REPO:-${GIT_BASE}/openstack/python-keystoneclient.git}
KEYSTONECLIENT_BRANCH=${KEYSTONECLIENT_BRANCH:-master}
+# keystone middleware
+KEYSTONEMIDDLEWARE_REPO=${KEYSTONEMIDDLEWARE_REPO:-${GIT_BASE}/openstack/keystonemiddleware.git}
+KEYSTONEMIDDLEWARE_BRANCH=${KEYSTONEMIDDLEWARE_BRANCH:-master}
+
# compute service
NOVA_REPO=${NOVA_REPO:-${GIT_BASE}/openstack/nova.git}
NOVA_BRANCH=${NOVA_BRANCH:-master}
@@ -173,6 +192,10 @@
OSLODB_REPO=${OSLODB_REPO:-${GIT_BASE}/openstack/oslo.db.git}
OSLODB_BRANCH=${OSLODB_BRANCH:-master}
+# oslo.i18n
+OSLOI18N_REPO=${OSLOI18N_REPO:-${GIT_BASE}/openstack/oslo.i18n.git}
+OSLOI18N_BRANCH=${OSLOI18N_BRANCH:-master}
+
# oslo.messaging
OSLOMSG_REPO=${OSLOMSG_REPO:-${GIT_BASE}/openstack/oslo.messaging.git}
OSLOMSG_BRANCH=${OSLOMSG_BRANCH:-master}
@@ -340,7 +363,8 @@
IMAGE_URLS=${IMAGE_URLS:-"http://partnerweb.vmware.com/programs/vmdkimage/cirros-0.3.2-i386-disk.vmdk"};;
xenserver)
DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-0.3.0-x86_64-disk}
- IMAGE_URLS=${IMAGE_URLS:-"https://github.com/downloads/citrix-openstack/warehouse/cirros-0.3.0-x86_64-disk.vhd.tgz"};;
+ IMAGE_URLS=${IMAGE_URLS:-"https://github.com/downloads/citrix-openstack/warehouse/cirros-0.3.0-x86_64-disk.vhd.tgz"}
+ IMAGE_URLS+=",http://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-x86_64-uec.tar.gz";;
*) # Default to Cirros with kernel, ramdisk and disk image
DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-${CIRROS_VERSION}-x86_64-uec}
IMAGE_URLS=${IMAGE_URLS:-"http://download.cirros-cloud.net/${CIRROS_VERSION}/cirros-${CIRROS_VERSION}-x86_64-uec.tar.gz"};;
@@ -350,26 +374,41 @@
if [[ "$ENABLED_SERVICES" =~ 'h-api' ]]; then
case "$VIRT_DRIVER" in
libvirt|baremetal|ironic)
- HEAT_CFN_IMAGE_URL=${HEAT_CFN_IMAGE_URL:-"https://dl.fedoraproject.org/pub/fedora/linux/releases/20/Images/x86_64/Fedora-x86_64-20-20131211.1-sda.qcow2"}
+ HEAT_CFN_IMAGE_URL=${HEAT_CFN_IMAGE_URL:-"http://dl.fedoraproject.org/pub/alt/openstack/20/x86_64/Fedora-x86_64-20-20140618-sda.qcow2"}
IMAGE_URLS+=",$HEAT_CFN_IMAGE_URL"
;;
*)
;;
esac
fi
+
+# Trove needs a custom image for it's work
+if [[ "$ENABLED_SERVICES" =~ 'tr-api' ]]; then
+ case "$VIRT_DRIVER" in
+ libvirt|baremetal|ironic)
+ TROVE_GUEST_IMAGE_URL=${TROVE_GUEST_IMAGE_URL:-"http://tarballs.openstack.org/trove/images/ubuntu_mysql.qcow2/ubuntu_mysql.qcow2"}
+ IMAGE_URLS+=",${TROVE_GUEST_IMAGE_URL}"
+ ;;
+ *)
+ ;;
+ esac
+fi
+
# Staging Area for New Images, have them here for at least 24hrs for nodepool
# to cache them otherwise the failure rates in the gate are too high
PRECACHE_IMAGES=$(trueorfalse False $PRECACHE_IMAGES)
if [[ "$PRECACHE_IMAGES" == "True" ]]; then
# staging in update for nodepool
- IMAGE_URLS+=",https://dl.fedoraproject.org/pub/fedora/linux/updates/20/Images/x86_64/Fedora-x86_64-20-20140407-sda.qcow2"
+ IMAGE_URL="http://dl.fedoraproject.org/pub/alt/openstack/20/x86_64/Fedora-x86_64-20-20140618-sda.qcow2"
+ if ! [[ "$IMAGE_URLS" =~ "$IMAGE_URL" ]]; then
+ IMAGE_URLS+=",$IMAGE_URL"
+ fi
fi
# 10Gb default volume backing file size
VOLUME_BACKING_FILE_SIZE=${VOLUME_BACKING_FILE_SIZE:-10250M}
-# Name of the LVM volume group to use/create for iscsi volumes
-VOLUME_GROUP=${VOLUME_GROUP:-stack-volumes}
+# Prefixes for volume and instance names
VOLUME_NAME_PREFIX=${VOLUME_NAME_PREFIX:-volume-}
INSTANCE_NAME_PREFIX=${INSTANCE_NAME_PREFIX:-instance-}
@@ -392,6 +431,9 @@
# Undo requirements changes by global requirements
UNDO_REQUIREMENTS=${UNDO_REQUIREMENTS:-True}
+# Allow the use of an alternate protocol (such as https) for service endpoints
+SERVICE_PROTOCOL=${SERVICE_PROTOCOL:-http}
+
# Local variables:
# mode: shell-script
# End:
diff --git a/tests/test_config.sh b/tests/test_config.sh
index 5700f8d..2634ce0 100755
--- a/tests/test_config.sh
+++ b/tests/test_config.sh
@@ -42,6 +42,17 @@
EOF
}
+function setup_test4 {
+ mkdir -p test-etc
+ cat >test-etc/test4.conf <<EOF
+[fff]
+# original comment
+type=original
+EOF
+ TEST4_DIR="test-etc"
+ TEST4_FILE="test4.conf"
+}
+
cat >test.conf <<EOF
[[test1|test1a.conf]]
[default]
@@ -76,8 +87,11 @@
attribute=value
# the above line has a single space
-EOF
+[[test4|\$TEST4_DIR/\$TEST4_FILE]]
+[fff]
+type=new
+EOF
echo -n "get_meta_section_files: test0 doesn't exist: "
VAL=$(get_meta_section_files test.conf test0)
@@ -192,4 +206,24 @@
attribute = value"
check_result "$VAL" "$EXPECT_VAL"
+echo -n "merge_config_group test4 variable filename: "
+setup_test4
+merge_config_group test.conf test4
+VAL=$(cat test-etc/test4.conf)
+EXPECT_VAL="[fff]
+# original comment
+type=new"
+check_result "$VAL" "$EXPECT_VAL"
+
+echo -n "merge_config_group test4 variable filename (not exist): "
+setup_test4
+rm test-etc/test4.conf
+merge_config_group test.conf test4
+VAL=$(cat test-etc/test4.conf)
+EXPECT_VAL="
+[fff]
+type = new"
+check_result "$VAL" "$EXPECT_VAL"
+
rm -f test.conf test1c.conf test2a.conf test-space.conf
+rm -rf test-etc
diff --git a/tools/build_docs.sh b/tools/build_docs.sh
index 384b1fa..e999eff 100755
--- a/tools/build_docs.sh
+++ b/tools/build_docs.sh
@@ -2,21 +2,22 @@
# **build_docs.sh** - Build the gh-pages docs for DevStack
#
-# - Install shocco if not found on PATH
+# - Install shocco if not found on PATH and INSTALL_SHOCCO is set
# - Clone MASTER_REPO branch MASTER_BRANCH
-# - Re-creates ``docs`` directory from existing repo + new generated script docs
+# - Re-creates ``docs/html`` directory from existing repo + new generated script docs
# Usage:
-## build_docs.sh [[-b branch] [-p] repo] | .
-## -b branch The DevStack branch to check out (default is master; ignored if
-## repo is not specified)
-## -p Push the resulting docs tree to the source repo; fatal error if
-## repo is not specified
-## repo The DevStack repository to clone (default is DevStack github repo)
+## build_docs.sh [-o <out-dir>] [-g] [master|<repo> [<branch>]]
+## <repo> The DevStack repository to clone (default is DevStack github repo)
## If a repo is not supplied use the current directory
## (assumed to be a DevStack checkout) as the source.
+## <branch> The DevStack branch to check out (default is master; ignored if
+## repo is not specified)
## . Use the current repo and branch (do not use with -p to
## prevent stray files in the workspace being added tot he docs)
+## -o <out-dir> Write the static HTML output to <out-dir>
+## (Note that <out-dir> will be deleted and re-created to ensure it is clean)
+## -g Update the old gh-pages repo (set PUSH=1 to actualy push up to RCB)
# Defaults
# --------
@@ -28,6 +29,9 @@
# http://devstack.org is a GitHub gh-pages site in the https://github.com/cloudbuilders/devtack.git repo
GH_PAGES_REPO=git@github.com:cloudbuilders/devstack.git
+DOCS_SOURCE=docs/source
+HTML_BUILD=docs/html
+
# Keep track of the devstack directory
TOP_DIR=$(cd $(dirname "$0")/.. && pwd)
@@ -49,97 +53,119 @@
git clone -b rst_support https://github.com/dtroyer/shocco shocco
cd shocco
./configure
- make
+ make || exit
cd ..
fi
SHOCCO=$TOP_DIR/shocco/shocco
fi
# Process command-line args
-while getopts b:p c; do
+while getopts go: c; do
case $c in
- b) MASTER_BRANCH=$OPTARG
+ g) GH_UPDATE=1
;;
- p) PUSH_REPO=1
+ o) HTML_BUILD=$OPTARG
;;
esac
done
shift `expr $OPTIND - 1`
-# Sanity check the args
-if [[ "$1" == "." ]]; then
- REPO=""
- if [[ -n $PUSH_REPO ]]; then
- echo "Push not allowed from an active workspace"
- unset PUSH_REPO
- fi
-else
- if [[ -z "$1" ]]; then
+
+if [[ -n "$1" ]]; then
+ master="master"
+ if [[ "${master/#$1}" != "master" ]]; then
+ # Partial match on "master"
REPO=$MASTER_REPO
else
REPO=$1
fi
+ REPO_BRANCH=${2:-$MASTER_BRANCH}
fi
# Check out a specific DevStack branch
if [[ -n $REPO ]]; then
# Make a workspace
- TMP_ROOT=$(mktemp -d devstack-docs-XXXX)
+ TMP_ROOT=$(mktemp -d work-docs-XXXX)
echo "Building docs in $TMP_ROOT"
cd $TMP_ROOT
# Get the master branch
git clone $REPO devstack
cd devstack
- git checkout $MASTER_BRANCH
+ if [[ -n "$REPO_BRANCH" ]]; then
+ git checkout $REPO_BRANCH
+ fi
fi
+# Assumption is we are now in the DevStack workspace to be processed
+
# Processing
# ----------
-# Assumption is we are now in the DevStack repo workspace to be processed
+# Clean up build dir
+rm -rf $HTML_BUILD
+mkdir -p $HTML_BUILD
-# Pull the latest docs branch from devstack.org repo
-if ! [ -d docs ]; then
- git clone -b gh-pages $GH_PAGES_REPO docs
-fi
+# Get fully qualified dirs
+FQ_DOCS_SOURCE=$(cd $DOCS_SOURCE && pwd)
+FQ_HTML_BUILD=$(cd $HTML_BUILD && pwd)
+
+# Get repo static
+cp -pr $FQ_DOCS_SOURCE/* $FQ_HTML_BUILD
+
+# Insert automated bits
+GLOG=$(mktemp gitlogXXXX)
+git log \
+ --pretty=format:' <li>%s - <em>Commit <a href="https://review.openstack.org/#q,%h,n,z">%h</a> %cd</em></li>' \
+ --date=short \
+ --since '6 months ago' | grep -v Merge >$GLOG
+sed -e $"/%GIT_LOG%/r $GLOG" $FQ_DOCS_SOURCE/changes.html >$FQ_HTML_BUILD/changes.html
+rm -f $GLOG
# Build list of scripts to process
FILES=""
for f in $(find . -name .git -prune -o \( -type f -name \*.sh -not -path \*shocco/\* -print \)); do
echo $f
FILES+="$f "
- mkdir -p docs/`dirname $f`;
- $SHOCCO $f > docs/$f.html
+ mkdir -p $FQ_HTML_BUILD/`dirname $f`;
+ $SHOCCO $f > $FQ_HTML_BUILD/$f.html
done
-for f in $(find functions lib samples -type f -name \*); do
+for f in $(find functions functions-common lib samples -type f -name \*); do
echo $f
FILES+="$f "
- mkdir -p docs/`dirname $f`;
- $SHOCCO $f > docs/$f.html
+ mkdir -p $FQ_HTML_BUILD/`dirname $f`;
+ $SHOCCO $f > $FQ_HTML_BUILD/$f.html
done
-echo "$FILES" >docs-files
+echo "$FILES" >docs/files
-# Switch to the gh_pages repo
-cd docs
+if [[ -n $GH_UPDATE ]]; then
+ GH_ROOT=$(mktemp -d work-gh-XXXX)
+ cd $GH_ROOT
-# Collect the new generated pages
-find . -name \*.html -print0 | xargs -0 git add
+ # Pull the latest docs branch from devstack.org repo
+ git clone -b gh-pages $GH_PAGES_REPO gh-docs
-# Push our changes back up to the docs branch
-if ! git diff-index HEAD --quiet; then
- git commit -a -m "Update script docs"
- if [[ -n $PUSH ]]; then
- git push
+ # Get the generated files
+ cp -pr $FQ_HTML_BUILD/* gh-docs
+
+ # Collect the new generated pages
+ (cd gh-docs; find . -name \*.html -print0 | xargs -0 git add)
+
+ # Push our changes back up to the docs branch
+ if ! git diff-index HEAD --quiet; then
+ git commit -a -m "Update script docs"
+ if [[ -n $PUSH ]]; then
+ git push
+ fi
fi
fi
# Clean up or report the temp workspace
if [[ -n REPO && -n $PUSH_REPO ]]; then
- rm -rf $TMP_ROOT
+ echo rm -rf $TMP_ROOT
else
if [[ -z "$TMP_ROOT" ]]; then
TMP_ROOT="$(pwd)"
fi
- echo "Built docs in $TMP_ROOT"
+ echo "Built docs in $HTML_BUILD"
fi
diff --git a/tools/create_userrc.sh b/tools/create_userrc.sh
index a34ad28..5b1111a 100755
--- a/tools/create_userrc.sh
+++ b/tools/create_userrc.sh
@@ -126,12 +126,12 @@
export -n SERVICE_TOKEN SERVICE_ENDPOINT OS_SERVICE_TOKEN OS_SERVICE_ENDPOINT
-EC2_URL=$(openstack endpoint show -f value -c publicurl ec2)
+EC2_URL=$(openstack endpoint show -f value -c publicurl ec2 || true)
if [[ -z $EC2_URL ]]; then
EC2_URL=http://localhost:8773/services/Cloud
fi
-S3_URL=$(openstack endpoint show -f value -c publicurl s3)
+S3_URL=$(openstack endpoint show -f value -c publicurl s3 || true)
if [[ -z $S3_URL ]]; then
S3_URL=http://localhost:3333
fi
diff --git a/tools/fixup_stuff.sh b/tools/fixup_stuff.sh
index e6a6a79..f1dc76a 100755
--- a/tools/fixup_stuff.sh
+++ b/tools/fixup_stuff.sh
@@ -35,6 +35,30 @@
FILES=$TOP_DIR/files
+# Keystone Port Reservation
+# -------------------------
+# Reserve and prevent $KEYSTONE_AUTH_PORT and $KEYSTONE_AUTH_PORT_INT from
+# being used as ephemeral ports by the system. The default(s) are 35357 and
+# 35358 which are in the Linux defined ephemeral port range (in disagreement
+# with the IANA ephemeral port range). This is a workaround for bug #1253482
+# where Keystone will try and bind to the port and the port will already be
+# in use as an ephemeral port by another process. This places an explicit
+# exception into the Kernel for the Keystone AUTH ports.
+keystone_ports=${KEYSTONE_AUTH_PORT:-35357},${KEYSTONE_AUTH_PORT_INT:-35358}
+
+# Get any currently reserved ports, strip off leading whitespace
+reserved_ports=$(sysctl net.ipv4.ip_local_reserved_ports | awk -F'=' '{print $2;}' | sed 's/^ //')
+
+if [[ -z "${reserved_ports}" ]]; then
+ # If there are no currently reserved ports, reserve the keystone ports
+ sudo sysctl -w net.ipv4.ip_local_reserved_ports=${keystone_ports}
+else
+ # If there are currently reserved ports, keep those and also reserve the
+ # keystone specific ports. Duplicate reservations are merged into a single
+ # reservation (or range) automatically by the kernel.
+ sudo sysctl -w net.ipv4.ip_local_reserved_ports=${keystone_ports},${reserved_ports}
+fi
+
# Python Packages
# ---------------
@@ -87,16 +111,18 @@
fi
-# RHEL6
-# -----
-
-if [[ $DISTRO =~ (rhel6) ]]; then
-
+if is_fedora; then
# Disable selinux to avoid configuring to allow Apache access
# to Horizon files (LP#1175444)
if selinuxenabled; then
sudo setenforce 0
fi
+fi
+
+# RHEL6
+# -----
+
+if [[ $DISTRO =~ (rhel6) ]]; then
# If the ``dbus`` package was installed by DevStack dependencies the
# uuid may not be generated because the service was never started (PR#598200),
diff --git a/tools/image_list.sh b/tools/image_list.sh
index f9a4e2f..0bb49ab 100755
--- a/tools/image_list.sh
+++ b/tools/image_list.sh
@@ -10,7 +10,7 @@
DRIVERS="openvz ironic libvirt vsphere xenserver dummy"
# Extra variables to trigger getting additional images.
-ENABLED_SERVICES=h-api
+export ENABLED_SERVICES="h-api,tr-api"
HEAT_FETCHED_TEST_IMAGE="Fedora-i386-20-20131211.1-sda"
PRECACHE_IMAGES=True
diff --git a/tools/install_pip.sh b/tools/install_pip.sh
index 1eb9e7a..150faaa 100755
--- a/tools/install_pip.sh
+++ b/tools/install_pip.sh
@@ -24,28 +24,8 @@
FILES=$TOP_DIR/files
-# Handle arguments
-
-USE_GET_PIP=${USE_GET_PIP:-0}
-INSTALL_PIP_VERSION=${INSTALL_PIP_VERSION:-"1.4.1"}
-while [[ -n "$1" ]]; do
- case $1 in
- --force)
- FORCE=1
- ;;
- --pip-version)
- INSTALL_PIP_VERSION="$2"
- shift
- ;;
- --use-get-pip)
- USE_GET_PIP=1;
- ;;
- esac
- shift
-done
-
-PIP_GET_PIP_URL=https://raw.github.com/pypa/pip/master/contrib/get-pip.py
-PIP_TAR_URL=https://pypi.python.org/packages/source/p/pip/pip-$INSTALL_PIP_VERSION.tar.gz
+PIP_GET_PIP_URL=https://bootstrap.pypa.io/get-pip.py
+LOCAL_PIP="$FILES/$(basename $PIP_GET_PIP_URL)"
GetDistro
echo "Distro: $DISTRO"
@@ -62,23 +42,13 @@
function install_get_pip {
- if [[ ! -r $FILES/get-pip.py ]]; then
- (cd $FILES; \
- curl -O $PIP_GET_PIP_URL; \
- )
+ if [[ ! -r $LOCAL_PIP ]]; then
+ curl -o $LOCAL_PIP $PIP_GET_PIP_URL || \
+ die $LINENO "Download of get-pip.py failed"
fi
- sudo -E python $FILES/get-pip.py
+ sudo -E python $LOCAL_PIP
}
-function install_pip_tarball {
- if [[ ! -r $FILES/pip-$INSTALL_PIP_VERSION.tar.gz ]]; then
- (cd $FILES; \
- curl -O $PIP_TAR_URL; \
- tar xvfz pip-$INSTALL_PIP_VERSION.tar.gz 1>/dev/null)
- fi
- (cd $FILES/pip-$INSTALL_PIP_VERSION; \
- sudo -E python setup.py install 1>/dev/null)
-}
# Show starting versions
get_versions
@@ -88,10 +58,8 @@
# Eradicate any and all system packages
uninstall_package python-pip
-if [[ "$USE_GET_PIP" == "1" ]]; then
- install_get_pip
-else
- install_pip_tarball
-fi
+install_get_pip
+
+pip_install -U setuptools
get_versions
diff --git a/tools/outfilter.py b/tools/outfilter.py
new file mode 100755
index 0000000..9686a38
--- /dev/null
+++ b/tools/outfilter.py
@@ -0,0 +1,87 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
+#
+# 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.
+
+# This is an output filter to filter and timestamp the logs from grenade and
+# devstack. Largely our awk filters got beyond the complexity level which were
+# sustainable, so this provides us much more control in a single place.
+#
+# The overhead of running python should be less than execing `date` a million
+# times during a run.
+
+import argparse
+import datetime
+import re
+import sys
+
+IGNORE_LINES = re.compile('(set \+o|xtrace)')
+HAS_DATE = re.compile('^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}.\d{3} \|')
+
+
+def get_options():
+ parser = argparse.ArgumentParser(
+ description='Filter output by devstack and friends')
+ parser.add_argument('-o', '--outfile',
+ help='Output file for content',
+ default=None)
+ parser.add_argument('-v', '--verbose', action='store_true',
+ default=False)
+ return parser.parse_args()
+
+
+def skip_line(line):
+ """Should we skip this line."""
+ return IGNORE_LINES.search(line) is not None
+
+
+def main():
+ opts = get_options()
+ outfile = None
+ if opts.outfile:
+ outfile = open(opts.outfile, 'a', 0)
+
+ # otherwise fileinput reprocess args as files
+ sys.argv = []
+ while True:
+ line = sys.stdin.readline()
+ if not line:
+ return 0
+
+ # put skip lines here
+ if skip_line(line):
+ continue
+
+ # this prevents us from nesting date lines, because
+ # we'd like to pull this in directly in grenade and not double
+ # up on devstack lines
+ if HAS_DATE.search(line) is None:
+ now = datetime.datetime.utcnow()
+ line = ("%s | %s" % (
+ now.strftime("%Y-%m-%d %H:%M:%S.%f")[:-3],
+ line))
+
+ if opts.verbose:
+ sys.stdout.write(line)
+ sys.stdout.flush()
+ if outfile:
+ outfile.write(line)
+ outfile.flush()
+
+
+if __name__ == '__main__':
+ try:
+ sys.exit(main())
+ except KeyboardInterrupt:
+ sys.exit(1)
diff --git a/tools/worlddump.py b/tools/worlddump.py
new file mode 100755
index 0000000..9a62c0d
--- /dev/null
+++ b/tools/worlddump.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
+#
+# 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.
+
+"""Dump the state of the world for post mortem."""
+
+import argparse
+import datetime
+import os
+import os.path
+import sys
+
+
+def get_options():
+ parser = argparse.ArgumentParser(
+ description='Dump world state for debugging')
+ parser.add_argument('-d', '--dir',
+ default='.',
+ help='Output directory for worlddump')
+ return parser.parse_args()
+
+
+def filename(dirname):
+ now = datetime.datetime.utcnow()
+ return os.path.join(dirname, now.strftime("worlddump-%Y-%m-%d-%H%M%S.txt"))
+
+
+def warn(msg):
+ print "WARN: %s" % msg
+
+
+def disk_space():
+ # the df output
+ print """
+File System Summary
+===================
+"""
+ dfraw = os.popen("df -Ph").read()
+ df = [s.split() for s in dfraw.splitlines()]
+ for fs in df:
+ try:
+ if int(fs[4][:-1]) > 95:
+ warn("Device %s (%s) is %s full, might be an issue" % (
+ fs[0], fs[5], fs[4]))
+ except ValueError:
+ # if it doesn't look like an int, that's fine
+ pass
+
+ print dfraw
+
+
+def process_list():
+ print """
+Process Listing
+===============
+"""
+ psraw = os.popen("ps auxw").read()
+ print psraw
+
+
+def main():
+ opts = get_options()
+ fname = filename(opts.dir)
+ print "World dumping... see %s for details" % fname
+ sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0)
+ with open(fname, 'w') as f:
+ os.dup2(f.fileno(), sys.stdout.fileno())
+ disk_space()
+ process_list()
+
+
+if __name__ == '__main__':
+ try:
+ sys.exit(main())
+ except KeyboardInterrupt:
+ sys.exit(1)
diff --git a/tools/xen/install_os_domU.sh b/tools/xen/install_os_domU.sh
index a4b3e06..12e861e 100755
--- a/tools/xen/install_os_domU.sh
+++ b/tools/xen/install_os_domU.sh
@@ -207,6 +207,8 @@
-e "s,\(d-i mirror/http/hostname string\).*,\1 $UBUNTU_INST_HTTP_HOSTNAME,g" \
-e "s,\(d-i mirror/http/directory string\).*,\1 $UBUNTU_INST_HTTP_DIRECTORY,g" \
-e "s,\(d-i mirror/http/proxy string\).*,\1 $UBUNTU_INST_HTTP_PROXY,g" \
+ -e "s,\(d-i passwd/root-password password\).*,\1 $GUEST_PASSWORD,g" \
+ -e "s,\(d-i passwd/root-password-again password\).*,\1 $GUEST_PASSWORD,g" \
-i "${HTTP_SERVER_LOCATION}/devstackubuntupreseed.cfg"
fi
@@ -382,14 +384,19 @@
while ! ssh_no_check -q stack@$OS_VM_MANAGEMENT_ADDRESS "service devstack status | grep -q running"; do
sleep 10
done
- echo -n "devstack is running"
- while ssh_no_check -q stack@$OS_VM_MANAGEMENT_ADDRESS "service devstack status | grep -q running"; do
+ echo -n "devstack service is running, waiting for stack.sh to start logging..."
+
+ while ! ssh_no_check -q stack@$OS_VM_MANAGEMENT_ADDRESS "test -e /tmp/devstack/log/stack.log"; do
sleep 10
- echo -n "."
done
- echo "done!"
set -x
+ # Watch devstack's output (which doesn't start until stack.sh is running,
+ # but wait for run.sh (which starts stack.sh) to exit as that is what
+ # hopefully writes the succeded cookie.
+ pid=`ssh_no_check -q stack@$OS_VM_MANAGEMENT_ADDRESS pgrep run.sh`
+ ssh_no_check -q stack@$OS_VM_MANAGEMENT_ADDRESS "tail --pid $pid -n +1 -f /tmp/devstack/log/stack.log"
+
# Fail if devstack did not succeed
ssh_no_check -q stack@$OS_VM_MANAGEMENT_ADDRESS 'test -e /var/run/devstack.succeeded'
diff --git a/tools/xen/prepare_guest_template.sh b/tools/xen/prepare_guest_template.sh
index eaab2fe..e6a7e02 100755
--- a/tools/xen/prepare_guest_template.sh
+++ b/tools/xen/prepare_guest_template.sh
@@ -70,7 +70,7 @@
else
echo "WARNING: no XenServer tools found, falling back to 5.6 tools"
TOOLS_URL="https://github.com/downloads/citrix-openstack/warehouse/xe-guest-utilities_5.6.100-651_amd64.deb"
- wget $TOOLS_URL -O $XS_TOOLS_FILE_NAME
+ curl --no-sessionid -L -o "$XS_TOOLS_FILE_NAME" $TOOLS_URL
cp $XS_TOOLS_FILE_NAME "${STAGING_DIR}${XS_TOOLS_PATH}"
rm -rf $XS_TOOLS_FILE_NAME
fi
diff --git a/unstack.sh b/unstack.sh
index a5e7b87..fe5fc77 100755
--- a/unstack.sh
+++ b/unstack.sh
@@ -122,9 +122,10 @@
stop_horizon
fi
-# Kill TLS proxies
+# Kill TLS proxies and cleanup certificates
if is_service_enabled tls-proxy; then
- killall stud
+ stop_tls_proxy
+ cleanup_CA
fi
SCSI_PERSIST_DIR=$CINDER_STATE_PATH/volumes/*