Merge "add support in devstack to run it with cisco plugin"
diff --git a/README.md b/README.md
index 8573638..905a54d 100644
--- a/README.md
+++ b/README.md
@@ -122,6 +122,19 @@
 
 Then run `stack.sh` as normal.
 
+devstack supports adding specific Quantum configuration flags to both the Open vSwitch and LinuxBridge plugin configuration files. To make use of this feature, the following variables are defined and can be configured in your `localrc` file:
+
+    Variable Name             Plugin Config File Section Modified
+    -------------------------------------------------------------------------------------
+    Q_SRV_EXTRA_OPTS          `OVS` (for Open Vswitch) or `LINUX_BRIDGE` (for LinuxBridge)
+    Q_AGENT_EXTRA_AGENT_OPTS  AGENT
+    Q_AGENT_EXTRA_SRV_OPTS    `OVS` (for Open Vswitch) or `LINUX_BRIDGE` (for LinuxBridge)
+
+An example of using the variables in your `localrc` is below:
+
+    Q_AGENT_EXTRA_AGENT_OPTS=(tunnel_type=vxlan vxlan_udp_port=8472)
+    Q_SRV_EXTRA_OPTS=(tenant_network_type=vxlan)
+
 # Tempest
 
 If tempest has been successfully configured, a basic set of smoke tests can be run as follows:
diff --git a/clean.sh b/clean.sh
index ffc462c..758947a 100755
--- a/clean.sh
+++ b/clean.sh
@@ -63,7 +63,7 @@
 cleanup_quantum
 cleanup_swift
 
-# cinder doesn't clean up the volume group as it might be used elsewhere...
+# cinder doesn't always clean up the volume group as it might be used elsewhere...
 # clean it up if it is a loop device
 VG_DEV=$(sudo losetup -j $DATA_DIR/${VOLUME_GROUP}-backing-file | awk -F':' '/backing-file/ { print $1}')
 if [[ -n "$VG_DEV" ]]; then
diff --git a/exercises/euca.sh b/exercises/euca.sh
index d704279..7c590d0 100755
--- a/exercises/euca.sh
+++ b/exercises/euca.sh
@@ -85,7 +85,7 @@
    die_if_not_set $LINENO VOLUME "Failure to create volume"
 
    # Test that volume has been created
-   VOLUME=`euca-describe-volumes | cut -f2`
+   VOLUME=`euca-describe-volumes $VOLUME | cut -f2`
    die_if_not_set $LINENO VOLUME "Failure to get volume"
 
    # Test volume has become available
@@ -162,7 +162,7 @@
 # case changed with bug/836978. Requesting the status of an invalid instance
 # will now return an error message including the instance id, so we need to
 # filter that out.
-if ! timeout $TERMINATE_TIMEOUT sh -c "while euca-describe-instances $INSTANCE | grep -ve \"\\\(InstanceNotFound\\\|InvalidInstanceID\[.\]NotFound\\\)\" | grep -q $INSTANCE; do sleep 1; done"; then
+if ! timeout $TERMINATE_TIMEOUT sh -c "while euca-describe-instances $INSTANCE | grep -ve '\(InstanceNotFound\|InvalidInstanceID\.NotFound\)' | grep -q $INSTANCE; do sleep 1; done"; then
     die $LINENO "server didn't terminate within $TERMINATE_TIMEOUT seconds"
 fi
 
diff --git a/files/apts/general b/files/apts/general
index a1fcf3c..ec6dd0d 100644
--- a/files/apts/general
+++ b/files/apts/general
@@ -1,5 +1,4 @@
 bridge-utils
-pep8
 pylint
 python-pip
 screen
diff --git a/files/apts/horizon b/files/apts/horizon
index 2c2faf1..e1ce85f 100644
--- a/files/apts/horizon
+++ b/files/apts/horizon
@@ -11,7 +11,6 @@
 python-webob
 python-kombu
 pylint
-pep8
 python-eventlet
 python-nose
 python-sphinx
diff --git a/files/apts/n-api b/files/apts/n-api
index 0f08daa..e0e5e7f 100644
--- a/files/apts/n-api
+++ b/files/apts/n-api
@@ -1 +1,2 @@
 python-dateutil
+msgpack-python
diff --git a/files/apts/nova b/files/apts/nova
index c24333c..6a7ef74 100644
--- a/files/apts/nova
+++ b/files/apts/nova
@@ -12,8 +12,8 @@
 ebtables
 sqlite3
 sudo
-kvm
-qemu # dist:wheezy,jessie
+kvm # NOPRIME
+qemu # dist:wheezy,jessie NOPRIME
 libvirt-bin # NOPRIME
 libjs-jquery-tablesorter # Needed for coverage html reports
 vlan
@@ -27,7 +27,7 @@
 python-migrate
 python-gflags
 python-greenlet
-python-libvirt
+python-libvirt # NOPRIME
 python-libxml2
 python-routes
 python-netaddr
diff --git a/files/keystone_data.sh b/files/keystone_data.sh
index 72b5b1e..a1875e1 100755
--- a/files/keystone_data.sh
+++ b/files/keystone_data.sh
@@ -5,9 +5,9 @@
 # Tenant               User       Roles
 # ------------------------------------------------------------------
 # service              glance     admin
-# service              swift      admin        # if enabled
-# service              heat       admin        # if enabled
-# service              ceilometer admin        # if enabled
+# service              swift      service        # if enabled
+# service              heat       service        # if enabled
+# service              ceilometer service        # if enabled
 # Tempest Only:
 # alt_demo             alt_demo  Member
 #
@@ -47,6 +47,8 @@
 # but ResellerAdmin is needed for a user to act as any tenant. The name of this
 # role is also configurable in swift-proxy.conf
 RESELLER_ROLE=$(get_id keystone role-create --name=ResellerAdmin)
+# Service role, so service users do not have to be admins
+SERVICE_ROLE=$(get_id keystone role-create --name=service)
 
 
 # Services
@@ -70,7 +72,7 @@
                                               --email=heat@example.com)
     keystone user-role-add --tenant_id $SERVICE_TENANT \
                            --user_id $HEAT_USER \
-                           --role_id $ADMIN_ROLE
+                           --role_id $SERVICE_ROLE
     # heat_stack_user role is for users created by Heat
     keystone role-create --name heat_stack_user
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
@@ -133,7 +135,7 @@
     keystone user-role-add \
         --tenant_id $SERVICE_TENANT \
         --user_id $SWIFT_USER \
-        --role_id $ADMIN_ROLE
+        --role_id $SERVICE_ROLE
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
         SWIFT_SERVICE=$(get_id keystone service-create \
             --name=swift \
@@ -155,7 +157,7 @@
                                               --email=ceilometer@example.com)
     keystone user-role-add --tenant_id $SERVICE_TENANT \
                            --user_id $CEILOMETER_USER \
-                           --role_id $ADMIN_ROLE
+                           --role_id $SERVICE_ROLE
     # Ceilometer needs ResellerAdmin role to access swift account stats.
     keystone user-role-add --tenant_id $SERVICE_TENANT \
                            --user_id $CEILOMETER_USER \
diff --git a/files/ldap/openstack.ldif b/files/ldap/openstack.ldif
index 2b76372..f810fe8 100644
--- a/files/ldap/openstack.ldif
+++ b/files/ldap/openstack.ldif
@@ -4,9 +4,9 @@
 objectClass: organizationalUnit
 ou: openstack
 
-dn: ou=Groups,dc=openstack,dc=org
+dn: ou=UserGroups,dc=openstack,dc=org
 objectClass: organizationalUnit
-ou: Groups
+ou: UserGroups
 
 dn: ou=Users,dc=openstack,dc=org
 objectClass: organizationalUnit
diff --git a/files/rpms-suse/general b/files/rpms-suse/general
index b8ceeb7..93711ff 100644
--- a/files/rpms-suse/general
+++ b/files/rpms-suse/general
@@ -8,7 +8,6 @@
 psmisc
 python-cmd2 # dist:opensuse-12.3
 python-netaddr
-python-pep8
 python-pip
 python-pylint
 python-unittest2
diff --git a/files/rpms-suse/horizon b/files/rpms-suse/horizon
index 7e46ffe..405fb7a 100644
--- a/files/rpms-suse/horizon
+++ b/files/rpms-suse/horizon
@@ -17,7 +17,6 @@
 python-mox
 python-netaddr
 python-nose
-python-pep8
 python-pylint
 python-sqlalchemy-migrate
 python-xattr
diff --git a/files/rpms-suse/nova b/files/rpms-suse/nova
index a3fd479..1be24a8 100644
--- a/files/rpms-suse/nova
+++ b/files/rpms-suse/nova
@@ -7,11 +7,11 @@
 iptables
 iputils
 kpartx
-kvm
+kvm # NOPRIME
 # qemu as fallback if kvm cannot be used
-qemu
+qemu # NOPRIME
 libvirt # NOPRIME
-libvirt-python
+libvirt-python # NOPRIME
 libxml2-python
 mysql-community-server # NOPRIME
 parted
diff --git a/files/rpms/general b/files/rpms/general
index 764b602..5cb3e28 100644
--- a/files/rpms/general
+++ b/files/rpms/general
@@ -6,12 +6,12 @@
 git-core
 openssh-server
 openssl
+openssl-devel # to rebuild pyOpenSSL if needed
 libxml2-devel # dist:rhel6 [2]
 libxslt-devel # dist:rhel6 [2]
 psmisc
 pylint
 python-netaddr
-python-pep8
 python-pip
 python-prettytable # dist:rhel6 [1]
 python-unittest2
@@ -29,4 +29,4 @@
 
 # [2] : RHEL6 rpm versions of python-lxml is old, and has to be
 # removed.  Several tools rely on it, so we install the dependencies
-# pip needs to build it here (see tools/install_prereqs.sh)
\ No newline at end of file
+# pip needs to build it here (see tools/install_prereqs.sh)
diff --git a/files/rpms/glance b/files/rpms/glance
index 097cf3f..0f113ea 100644
--- a/files/rpms/glance
+++ b/files/rpms/glance
@@ -4,7 +4,7 @@
 python-devel
 python-eventlet
 python-greenlet
-python-paste-deploy #dist:f16,f17,f18
+python-paste-deploy #dist:f16,f17,f18,f19
 python-routes
 python-sqlalchemy
 python-wsgiref
diff --git a/files/rpms/horizon b/files/rpms/horizon
index cf16cdb..b844d98 100644
--- a/files/rpms/horizon
+++ b/files/rpms/horizon
@@ -18,9 +18,8 @@
 python-mox
 python-netaddr
 python-nose
-python-paste        #dist:f16,f17,f18
-python-paste-deploy #dist:f16,f17,f18
-python-pep8
+python-paste        #dist:f16,f17,f18,f19
+python-paste-deploy #dist:f16,f17,f18,f19
 python-routes
 python-sphinx
 python-sqlalchemy
diff --git a/files/rpms/keystone b/files/rpms/keystone
index 078adf7..33a4f47 100644
--- a/files/rpms/keystone
+++ b/files/rpms/keystone
@@ -1,10 +1,10 @@
 python-greenlet
-python-lxml         #dist:f16,f17,f18
-python-paste        #dist:f16,f17,f18
-python-paste-deploy #dist:f16,f17,f18
-python-paste-script #dist:f16,f17,f18
+python-lxml         #dist:f16,f17,f18,f19
+python-paste        #dist:f16,f17,f18,f19
+python-paste-deploy #dist:f16,f17,f18,f19
+python-paste-script #dist:f16,f17,f18,f19
 python-routes
-python-setuptools   #dist:f16,f17,f18
+python-setuptools   #dist:f16,f17,f18,f19
 python-sqlalchemy
 python-sqlite2
 python-webob
diff --git a/files/rpms/nova b/files/rpms/nova
index c74f396..8d8a0b8 100644
--- a/files/rpms/nova
+++ b/files/rpms/nova
@@ -7,9 +7,9 @@
 iptables
 iputils
 kpartx
-kvm
+kvm # NOPRIME
 libvirt-bin # NOPRIME
-libvirt-python
+libvirt-python # NOPRIME
 libxml2-python
 numpy # needed by websockify for spice console
 m2crypto
@@ -29,11 +29,11 @@
 python-migrate
 python-mox
 python-netaddr
-python-paramiko # dist:f16,f17,f18
+python-paramiko # dist:f16,f17,f18,f19
 # ^ on RHEL, brings in python-crypto which conflicts with version from
 # pip we need
-python-paste        # dist:f16,f17,f18
-python-paste-deploy # dist:f16,f17,f18
+python-paste        # dist:f16,f17,f18,f19
+python-paste-deploy # dist:f16,f17,f18,f19
 python-qpid
 python-routes
 python-sqlalchemy
diff --git a/files/rpms/quantum b/files/rpms/quantum
index 8827d5a..6a8fd36 100644
--- a/files/rpms/quantum
+++ b/files/rpms/quantum
@@ -12,8 +12,8 @@
 python-kombu
 python-netaddr
 #rhel6 gets via pip
-python-paste        # dist:f16,f17,f18
-python-paste-deploy # dist:f16,f17,f18
+python-paste        # dist:f16,f17,f18,f19
+python-paste-deploy # dist:f16,f17,f18,f19
 python-qpid
 python-routes
 python-sqlalchemy
diff --git a/files/rpms/ryu b/files/rpms/ryu
index 7cf3bd7..0f62f9f 100644
--- a/files/rpms/ryu
+++ b/files/rpms/ryu
@@ -1,5 +1,5 @@
 python-gevent
 python-gflags
 python-netifaces
-python-setuptools #dist:f16,f17,f18
+python-setuptools #dist:f16,f17,f18,f19
 python-sphinx
diff --git a/files/rpms/swift b/files/rpms/swift
index 1b36e34..ee1fad8 100644
--- a/files/rpms/swift
+++ b/files/rpms/swift
@@ -8,8 +8,8 @@
 python-greenlet
 python-netifaces
 python-nose
-python-paste-deploy # dist:f16,f17,f18
-python-setuptools   # dist:f16,f17,f18
+python-paste-deploy # dist:f16,f17,f18,f19
+python-setuptools   # dist:f16,f17,f18,f19
 python-simplejson
 python-webob
 pyxattr
diff --git a/functions b/functions
index dfde7dc..8aba10d 100644
--- a/functions
+++ b/functions
@@ -200,6 +200,7 @@
     echo "$pkg_dir"
 }
 
+
 # get_packages() collects a list of package names of any type from the
 # prerequisite files in ``files/{apts|rpms}``.  The list is intended
 # to be passed to a package installer such as apt or yum.
@@ -390,42 +391,6 @@
     export os_VENDOR os_RELEASE os_UPDATE os_PACKAGE os_CODENAME
 }
 
-# git update using reference as a branch.
-# git_update_branch ref
-function git_update_branch() {
-
-    GIT_BRANCH=$1
-
-    git checkout -f origin/$GIT_BRANCH
-    # a local branch might not exist
-    git branch -D $GIT_BRANCH || true
-    git checkout -b $GIT_BRANCH
-}
-
-
-# git update using reference as a tag. Be careful editing source at that repo
-# as working copy will be in a detached mode
-# git_update_tag ref
-function git_update_tag() {
-
-    GIT_TAG=$1
-
-    git tag -d $GIT_TAG
-    # fetching given tag only
-    git fetch origin tag $GIT_TAG
-    git checkout -f $GIT_TAG
-}
-
-
-# git update using reference as a branch.
-# git_update_remote_branch ref
-function git_update_remote_branch() {
-
-    GIT_BRANCH=$1
-
-    git checkout -b $GIT_BRANCH -t origin/$GIT_BRANCH
-}
-
 
 # Translate the OS version values into common nomenclature
 # Sets ``DISTRO`` from the ``os_*`` values
@@ -457,19 +422,8 @@
 }
 
 
-# Determine if current distribution is an Ubuntu-based distribution.
-# It will also detect non-Ubuntu but Debian-based distros; this is not an issue
-# since Debian and Ubuntu should be compatible.
-# is_ubuntu
-function is_ubuntu {
-    if [[ -z "$os_PACKAGE" ]]; then
-        GetOSVersion
-    fi
-    [ "$os_PACKAGE" = "deb" ]
-}
-
 # Determine if current distribution is a Fedora-based distribution
-# (Fedora, RHEL, CentOS).
+# (Fedora, RHEL, CentOS, etc).
 # is_fedora
 function is_fedora {
     if [[ -z "$os_VENDOR" ]]; then
@@ -479,6 +433,7 @@
     [ "$os_VENDOR" = "Fedora" ] || [ "$os_VENDOR" = "Red Hat" ] || [ "$os_VENDOR" = "CentOS" ]
 }
 
+
 # Determine if current distribution is a SUSE-based distribution
 # (openSUSE, SLE).
 # is_suse
@@ -491,6 +446,17 @@
 }
 
 
+# Determine if current distribution is an Ubuntu-based distribution
+# It will also detect non-Ubuntu but Debian-based distros
+# is_ubuntu
+function is_ubuntu {
+    if [[ -z "$os_PACKAGE" ]]; then
+        GetOSVersion
+    fi
+    [ "$os_PACKAGE" = "deb" ]
+}
+
+
 # Exit after outputting a message about the distribution not being supported.
 # exit_distro_not_supported [optional-string-telling-what-is-missing]
 function exit_distro_not_supported {
@@ -565,6 +531,43 @@
 }
 
 
+# git update using reference as a branch.
+# git_update_branch ref
+function git_update_branch() {
+
+    GIT_BRANCH=$1
+
+    git checkout -f origin/$GIT_BRANCH
+    # a local branch might not exist
+    git branch -D $GIT_BRANCH || true
+    git checkout -b $GIT_BRANCH
+}
+
+
+# git update using reference as a branch.
+# git_update_remote_branch ref
+function git_update_remote_branch() {
+
+    GIT_BRANCH=$1
+
+    git checkout -b $GIT_BRANCH -t origin/$GIT_BRANCH
+}
+
+
+# git update using reference as a tag. Be careful editing source at that repo
+# as working copy will be in a detached mode
+# git_update_tag ref
+function git_update_tag() {
+
+    GIT_TAG=$1
+
+    git tag -d $GIT_TAG
+    # fetching given tag only
+    git fetch origin tag $GIT_TAG
+    git checkout -f $GIT_TAG
+}
+
+
 # Comment an option in an INI file
 # inicomment config-file section option
 function inicomment() {
@@ -1020,6 +1023,7 @@
     fi
 }
 
+
 # Helper to remove the *.failure files under $SERVICE_DIR/$SCREEN_NAME
 # This is used for service_check when all the screen_it are called finished
 # init_service_check
@@ -1034,6 +1038,7 @@
     rm -f "$SERVICE_DIR/$SCREEN_NAME"/*.failure
 }
 
+
 # Helper to get the status of each running service
 # service_check
 function service_check() {
@@ -1062,6 +1067,7 @@
     fi
 }
 
+
 # ``pip install`` the dependencies of the package before ``setup.py develop``
 # so pip and not distutils processes the dependency chain
 # Uses globals ``TRACK_DEPENDES``, ``*_proxy`
@@ -1242,6 +1248,7 @@
     fi
 }
 
+
 # Set the database backend to use
 # When called from stackrc/localrc DATABASE_BACKENDS has not been
 # initialized yet, just save the configuration selection and call back later
@@ -1259,6 +1266,7 @@
     fi
 }
 
+
 # Toggle enable/disable_service for services that must run exclusive of each other
 #  $1 The name of a variable containing a space-separated list of services
 #  $2 The name of a variable in which to store the enabled service's name
@@ -1275,6 +1283,7 @@
     return 0
 }
 
+
 # Wait for an HTTP server to start answering requests
 # wait_for_service timeout url
 function wait_for_service() {
@@ -1283,6 +1292,7 @@
     timeout $timeout sh -c "while ! http_proxy= https_proxy= curl -s $url >/dev/null; do sleep 1; done"
 }
 
+
 # Wrapper for ``yum`` to set proxy environment variables
 # Uses globals ``OFFLINE``, ``*_proxy`
 # yum_install package [package ...]
@@ -1295,8 +1305,21 @@
         yum install -y "$@"
 }
 
+
+# zypper wrapper to set arguments correctly
+# zypper_install package [package ...]
+function zypper_install() {
+    [[ "$OFFLINE" = "True" ]] && return
+    local sudo="sudo"
+    [[ "$(id -u)" = "0" ]] && sudo="env"
+    $sudo http_proxy=$http_proxy https_proxy=$https_proxy \
+        zypper --non-interactive install --auto-agree-with-licenses "$@"
+}
+
+
 # ping check
 # Uses globals ``ENABLED_SERVICES``
+# ping_check from-net ip boot-timeout expected
 function ping_check() {
     if is_service_enabled quantum; then
         _ping_check_quantum  "$1" $2 $3 $4
@@ -1333,8 +1356,10 @@
     fi
 }
 
+
 # ssh check
 
+# ssh_check net-name key-file floating-ip default-user active-timeout
 function ssh_check() {
     if is_service_enabled quantum; then
         _ssh_check_quantum  "$1" $2 $3 $4 $5
@@ -1356,17 +1381,6 @@
 }
 
 
-# zypper wrapper to set arguments correctly
-# zypper_install package [package ...]
-function zypper_install() {
-    [[ "$OFFLINE" = "True" ]] && return
-    local sudo="sudo"
-    [[ "$(id -u)" = "0" ]] && sudo="env"
-    $sudo http_proxy=$http_proxy https_proxy=$https_proxy \
-        zypper --non-interactive install --auto-agree-with-licenses "$@"
-}
-
-
 # Add a user to a group.
 # add_user_to_group user group
 function add_user_to_group() {
@@ -1396,6 +1410,7 @@
     fi
 }
 
+
 # Get the location of the $module-rootwrap executables, where module is cinder
 # or nova.
 # get_rootwrap_location module
@@ -1405,6 +1420,7 @@
     echo "$(get_python_exec_prefix)/$module-rootwrap"
 }
 
+
 # Get the path to the pip command.
 # get_pip_command
 function get_pip_command() {
@@ -1419,6 +1435,7 @@
     fi
 }
 
+
 # Path permissions sanity check
 # check_path_perm_sanity path
 function check_path_perm_sanity() {
@@ -1448,6 +1465,61 @@
     done
 }
 
+
+# This function recursively compares versions, and is not meant to be
+# called by anything other than vercmp_numbers below. This function does
+# not work with alphabetic versions.
+#
+# _vercmp_r sep ver1 ver2
+function _vercmp_r {
+  typeset sep
+  typeset -a ver1=() ver2=()
+  sep=$1; shift
+  ver1=("${@:1:sep}")
+  ver2=("${@:sep+1}")
+
+  if ((ver1 > ver2)); then
+    echo 1; return 0
+  elif ((ver2 > ver1)); then
+    echo -1; return 0
+  fi
+
+  if ((sep <= 1)); then
+    echo 0; return 0
+  fi
+
+  _vercmp_r $((sep-1)) "${ver1[@]:1}" "${ver2[@]:1}"
+}
+
+
+# This function compares two versions and is meant to be called by
+# external callers. Please note the function assumes non-alphabetic
+# versions. For example, this will work:
+#
+#   vercmp_numbers 1.10 1.4
+#
+# The above will return "1", as 1.10 is greater than 1.4.
+#
+#   vercmp_numbers 5.2 6.4
+#
+# The above will return "-1", as 5.2 is less than 6.4.
+#
+#   vercmp_numbers 4.0 4.0
+#
+# The above will return "0", as the versions are equal.
+#
+# vercmp_numbers ver1 ver2
+vercmp_numbers() {
+  typeset v1=$1 v2=$2 sep
+  typeset -a ver1 ver2
+
+  IFS=. read -ra ver1 <<< "$v1"
+  IFS=. read -ra ver2 <<< "$v2"
+
+  _vercmp_r "${#ver1[@]}" "${ver1[@]}" "${ver2[@]}"
+}
+
+
 # Restore xtrace
 $XTRACE
 
diff --git a/lib/cinder b/lib/cinder
index 7e9c2ba..0eabf40 100644
--- a/lib/cinder
+++ b/lib/cinder
@@ -67,27 +67,43 @@
 CINDER_PERIODIC_INTERVAL=${CINDER_PERIODIC_INTERVAL:-60}
 
 # Name of the lvm volume groups to use/create for iscsi volumes
-# VOLUME_GROUP2 is used only if CINDER_MULTI_LVM_BACKEND = True
 VOLUME_GROUP=${VOLUME_GROUP:-stack-volumes}
+VOLUME_BACKING_FILE=${VOLUME_BACKING_FILE:-$DATA_DIR/${VOLUME_GROUP}-backing-file}
+
+# 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_NAME_PREFIX=${VOLUME_NAME_PREFIX:-volume-}
 
 
 # Functions
 # ---------
-
-# _clean_volume_group removes all cinder volumes from the specified volume group
-# _clean_volume_group $VOLUME_GROUP $VOLUME_NAME_PREFIX
-function _clean_volume_group() {
+# _cleanup_lvm removes all cinder volumes and the backing file of the
+# volume group used by cinder
+# _cleanup_lvm $VOLUME_GROUP $VOLUME_NAME_PREFIX
+function _cleanup_lvm() {
     local vg=$1
-    local vg_prefix=$2
+    local lv_prefix=$2
+
     # Clean out existing volumes
     for lv in `sudo lvs --noheadings -o lv_name $vg`; do
-        # vg_prefix prefixes the LVs we want
-        if [[ "${lv#$vg_prefix}" != "$lv" ]]; then
+        # lv_prefix prefixes the LVs we want
+        if [[ "${lv#$lv_prefix}" != "$lv" ]]; then
             sudo lvremove -f $vg/$lv
         fi
     done
+
+    # 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
+        VG_DEV=$(sudo losetup -j $DATA_DIR/${vg}-backing-file | awk -F':' '/backing-file/ { print $1}')
+        if [[ -n "$VG_DEV" ]]; then
+            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
@@ -127,9 +143,10 @@
     fi
 
     # Campsite rule: leave behind a volume group at least as clean as we found it
-    _clean_volume_group $VOLUME_GROUP $VOLUME_NAME_PREFIX
+    _cleanup_lvm $VOLUME_GROUP $VOLUME_NAME_PREFIX
+
     if [ "$CINDER_MULTI_LVM_BACKEND" = "True" ]; then
-        _clean_volume_group $VOLUME_GROUP2 $VOLUME_NAME_PREFIX
+        _cleanup_lvm $VOLUME_GROUP2 $VOLUME_NAME_PREFIX
     fi
 }
 
@@ -194,7 +211,7 @@
         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
+        iniset $CINDER_CONF lvmdriver-2 volume_backend_name LVM_iSCSI_2
     else
         iniset $CINDER_CONF DEFAULT volume_group $VOLUME_GROUP
         iniset $CINDER_CONF DEFAULT volume_name_template ${VOLUME_NAME_PREFIX}%s
@@ -318,8 +335,6 @@
     # ``/opt/stack/data``.
 
     if ! sudo vgs $VOLUME_GROUP; then
-        VOLUME_BACKING_FILE=${VOLUME_BACKING_FILE:-$DATA_DIR/${VOLUME_GROUP}-backing-file}
-
         # Only create if the file doesn't already exists
         [[ -f $VOLUME_BACKING_FILE ]] || truncate -s $VOLUME_BACKING_FILE_SIZE $VOLUME_BACKING_FILE
 
@@ -334,8 +349,6 @@
         #set up the second volume if CINDER_MULTI_LVM_BACKEND is enabled
 
         if ! sudo vgs $VOLUME_GROUP2; then
-            VOLUME_BACKING_FILE2=${VOLUME_BACKING_FILE2:-$DATA_DIR/${VOLUME_GROUP2}-backing-file}
-
             # Only create if the file doesn't already exists
             [[ -f $VOLUME_BACKING_FILE2 ]] || truncate -s $VOLUME_BACKING_FILE_SIZE $VOLUME_BACKING_FILE2
 
diff --git a/lib/horizon b/lib/horizon
index ab11399..0cc250e 100644
--- a/lib/horizon
+++ b/lib/horizon
@@ -74,13 +74,20 @@
 }
 
 
+
 # Entry Points
 # ------------
 
 # cleanup_horizon() - Remove residual data files, anything left over from previous
 # runs that a clean run would need to clean up
 function cleanup_horizon() {
-    :
+    if [[ is_fedora && $DISTRO =~ (rhel6) ]]; then
+        # If ``/usr/bin/node`` points into ``$DEST``
+        # we installed it via ``install_nodejs``
+        if [[ $(readlink -f /usr/bin/node) =~ ($DEST) ]]; then
+            sudo rm /usr/bin/node
+        fi
+    fi
 }
 
 # configure_horizon() - Set config files, create data dirs, etc
@@ -111,7 +118,6 @@
     # Create an empty directory that apache uses as docroot
     sudo mkdir -p $HORIZON_DIR/.blackhole
 
-
     HORIZON_REQUIRE=''
     if is_ubuntu; then
         # Clean up the old config name
@@ -148,7 +154,6 @@
         s,%DEST%,$DEST,g;
         s,%HORIZON_REQUIRE%,$HORIZON_REQUIRE,g;
     \" $FILES/apache-horizon.template >/etc/$APACHE_NAME/$APACHE_CONF"
-
 }
 
 # install_horizon() - Collect source and prepare
@@ -193,6 +198,7 @@
     fi
 }
 
+
 # Restore xtrace
 $XTRACE
 
diff --git a/lib/keystone b/lib/keystone
index 6bf4d9f..2edd137 100644
--- a/lib/keystone
+++ b/lib/keystone
@@ -178,7 +178,6 @@
     cp $KEYSTONE_DIR/etc/logging.conf.sample $KEYSTONE_CONF_DIR/logging.conf
     iniset $KEYSTONE_CONF_DIR/logging.conf logger_root level "DEBUG"
     iniset $KEYSTONE_CONF_DIR/logging.conf logger_root handlers "devel,production"
-
 }
 
 # create_keystone_accounts() - Sets up common required keystone accounts
@@ -254,25 +253,6 @@
             --adminurl "$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT/v2.0" \
             --internalurl "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v2.0"
     fi
-
-    # TODO(dtroyer): This is part of a series of changes...remove these when
-    #                complete if they are really unused
-#    KEYSTONEADMIN_ROLE=$(keystone role-create \
-#        --name KeystoneAdmin \
-#        | grep " id " | get_field 2)
-#    KEYSTONESERVICE_ROLE=$(keystone role-create \
-#        --name KeystoneServiceAdmin \
-#        | grep " id " | get_field 2)
-
-    # TODO(termie): these two might be dubious
-#    keystone user-role-add \
-#        --user_id $ADMIN_USER \
-#        --role_id $KEYSTONEADMIN_ROLE \
-#        --tenant_id $ADMIN_TENANT
-#    keystone user-role-add \
-#        --user_id $ADMIN_USER \
-#        --role_id $KEYSTONESERVICE_ROLE \
-#        --tenant_id $ADMIN_TENANT
 }
 
 # init_keystone() - Initialize databases, etc.
@@ -339,6 +319,7 @@
     screen -S $SCREEN_NAME -p key -X kill
 }
 
+
 # Restore xtrace
 $XTRACE
 
diff --git a/lib/nova b/lib/nova
index 2740e61..cac6330 100644
--- a/lib/nova
+++ b/lib/nova
@@ -237,37 +237,39 @@
         # Force IP forwarding on, just on case
         sudo sysctl -w net.ipv4.ip_forward=1
 
-        # Attempt to load modules: network block device - used to manage qcow images
-        sudo modprobe nbd || true
+        if [[ "$VIRT_DRIVER" = 'libvirt' ]]; then
+            # Attempt to load modules: network block device - used to manage qcow images
+            sudo modprobe nbd || true
 
-        # Check for kvm (hardware based virtualization).  If unable to initialize
-        # kvm, we drop back to the slower emulation mode (qemu).  Note: many systems
-        # come with hardware virtualization disabled in BIOS.
-        if [[ "$LIBVIRT_TYPE" == "kvm" ]]; then
-            sudo modprobe kvm || true
-            if [ ! -e /dev/kvm ]; then
-                echo "WARNING: Switching to QEMU"
-                LIBVIRT_TYPE=qemu
-                if which selinuxenabled 2>&1 > /dev/null && selinuxenabled; then
-                    # https://bugzilla.redhat.com/show_bug.cgi?id=753589
-                    sudo setsebool virt_use_execmem on
+            # Check for kvm (hardware based virtualization).  If unable to initialize
+            # kvm, we drop back to the slower emulation mode (qemu).  Note: many systems
+            # come with hardware virtualization disabled in BIOS.
+            if [[ "$LIBVIRT_TYPE" == "kvm" ]]; then
+                sudo modprobe kvm || true
+                if [ ! -e /dev/kvm ]; then
+                    echo "WARNING: Switching to QEMU"
+                    LIBVIRT_TYPE=qemu
+                    if which selinuxenabled 2>&1 > /dev/null && selinuxenabled; then
+                        # https://bugzilla.redhat.com/show_bug.cgi?id=753589
+                        sudo setsebool virt_use_execmem on
+                    fi
                 fi
             fi
-        fi
 
-        # Install and configure **LXC** if specified.  LXC is another approach to
-        # splitting a system into many smaller parts.  LXC uses cgroups and chroot
-        # to simulate multiple systems.
-        if [[ "$LIBVIRT_TYPE" == "lxc" ]]; then
-            if is_ubuntu; then
-                if [[ ! "$DISTRO" > natty ]]; then
-                    cgline="none /cgroup cgroup cpuacct,memory,devices,cpu,freezer,blkio 0 0"
-                    sudo mkdir -p /cgroup
-                    if ! grep -q cgroup /etc/fstab; then
-                        echo "$cgline" | sudo tee -a /etc/fstab
-                    fi
-                    if ! mount -n | grep -q cgroup; then
-                        sudo mount /cgroup
+            # Install and configure **LXC** if specified.  LXC is another approach to
+            # splitting a system into many smaller parts.  LXC uses cgroups and chroot
+            # to simulate multiple systems.
+            if [[ "$LIBVIRT_TYPE" == "lxc" ]]; then
+                if is_ubuntu; then
+                    if [[ ! "$DISTRO" > natty ]]; then
+                        cgline="none /cgroup cgroup cpuacct,memory,devices,cpu,freezer,blkio 0 0"
+                        sudo mkdir -p /cgroup
+                        if ! grep -q cgroup /etc/fstab; then
+                            echo "$cgline" | sudo tee -a /etc/fstab
+                        fi
+                        if ! mount -n | grep -q cgroup; then
+                            sudo mount /cgroup
+                        fi
                     fi
                 fi
             fi
@@ -278,9 +280,10 @@
             configure_baremetal_nova_dirs
         fi
 
-        if is_service_enabled quantum && is_quantum_ovs_base_plugin && ! sudo grep -q '^cgroup_device_acl' $QEMU_CONF; then
-            # Add /dev/net/tun to cgroup_device_acls, needed for type=ethernet interfaces
-            cat <<EOF | sudo tee -a $QEMU_CONF
+        if [[ "$VIRT_DRIVER" = 'libvirt' ]]; then
+            if is_service_enabled quantum && is_quantum_ovs_base_plugin && ! sudo grep -q '^cgroup_device_acl' $QEMU_CONF; then
+                # Add /dev/net/tun to cgroup_device_acls, needed for type=ethernet interfaces
+                cat <<EOF | sudo tee -a $QEMU_CONF
 cgroup_device_acl = [
     "/dev/null", "/dev/full", "/dev/zero",
     "/dev/random", "/dev/urandom",
@@ -288,19 +291,17 @@
     "/dev/rtc", "/dev/hpet","/dev/net/tun",
 ]
 EOF
-        fi
+            fi
 
-        if is_ubuntu; then
-            LIBVIRT_DAEMON=libvirt-bin
-        else
-            LIBVIRT_DAEMON=libvirtd
-        fi
+            if is_ubuntu; then
+                LIBVIRT_DAEMON=libvirt-bin
+            else
+                LIBVIRT_DAEMON=libvirtd
+            fi
 
-
-
-        if is_fedora || is_suse; then
-            if is_fedora && [[  $DISTRO =~ (rhel6) || "$os_RELEASE" -le "17" ]]; then
-                sudo bash -c "cat <<EOF >/etc/polkit-1/localauthority/50-local.d/50-libvirt-remote-access.pkla
+            if is_fedora || is_suse; then
+                if is_fedora && [[ $DISTRO =~ (rhel6) || "$os_RELEASE" -le "17" ]]; then
+                    sudo bash -c "cat <<EOF >/etc/polkit-1/localauthority/50-local.d/50-libvirt-remote-access.pkla
 [libvirt Management Access]
 Identity=unix-group:$LIBVIRT_GROUP
 Action=org.libvirt.unix.manage
@@ -308,11 +309,11 @@
 ResultInactive=yes
 ResultActive=yes
 EOF"
-            elif is_suse && [[ $os_RELEASE = 12.2 || "$os_VENDOR" = "SUSE LINUX" ]]; then
-                # openSUSE < 12.3 or SLE
-                # Work around the fact that polkit-default-privs overrules pklas
-                # with 'unix-group:$group'.
-                sudo bash -c "cat <<EOF >/etc/polkit-1/localauthority/50-local.d/50-libvirt-remote-access.pkla
+                elif is_suse && [[ $os_RELEASE = 12.2 || "$os_VENDOR" = "SUSE LINUX" ]]; then
+                    # openSUSE < 12.3 or SLE
+                    # Work around the fact that polkit-default-privs overrules pklas
+                    # with 'unix-group:$group'.
+                    sudo bash -c "cat <<EOF >/etc/polkit-1/localauthority/50-local.d/50-libvirt-remote-access.pkla
 [libvirt Management Access]
 Identity=unix-user:$USER
 Action=org.libvirt.unix.manage
@@ -320,13 +321,13 @@
 ResultInactive=yes
 ResultActive=yes
 EOF"
-            else
-                # Starting with fedora 18 and opensuse-12.3 enable stack-user to
-                # virsh -c qemu:///system by creating a policy-kit rule for
-                # stack-user using the new Javascript syntax
-                rules_dir=/etc/polkit-1/rules.d
-                sudo mkdir -p $rules_dir
-                sudo bash -c "cat <<EOF > $rules_dir/50-libvirt-$STACK_USER.rules
+                else
+                    # Starting with fedora 18 and opensuse-12.3 enable stack-user to
+                    # virsh -c qemu:///system by creating a policy-kit rule for
+                    # stack-user using the new Javascript syntax
+                    rules_dir=/etc/polkit-1/rules.d
+                    sudo mkdir -p $rules_dir
+                    sudo bash -c "cat <<EOF > $rules_dir/50-libvirt-$STACK_USER.rules
 polkit.addRule(function(action, subject) {
      if (action.id == 'org.libvirt.unix.manage' &&
          subject.user == '"$STACK_USER"') {
@@ -334,23 +335,23 @@
      }
 });
 EOF"
-                unset rules_dir
+                    unset rules_dir
+                fi
             fi
+
+            # The user that nova runs as needs to be member of **libvirtd** group otherwise
+            # nova-compute will be unable to use libvirt.
+            if ! getent group $LIBVIRT_GROUP >/dev/null; then
+                sudo groupadd $LIBVIRT_GROUP
+            fi
+            add_user_to_group $STACK_USER $LIBVIRT_GROUP
+
+            # libvirt detects various settings on startup, as we potentially changed
+            # the system configuration (modules, filesystems), we need to restart
+            # libvirt to detect those changes.
+            restart_service $LIBVIRT_DAEMON
         fi
 
-        # The user that nova runs as needs to be member of **libvirtd** group otherwise
-        # nova-compute will be unable to use libvirt.
-        if ! getent group $LIBVIRT_GROUP >/dev/null; then
-            sudo groupadd $LIBVIRT_GROUP
-        fi
-        add_user_to_group $STACK_USER $LIBVIRT_GROUP
-
-        # libvirt detects various settings on startup, as we potentially changed
-        # the system configuration (modules, filesystems), we need to restart
-        # libvirt to detect those changes.
-        restart_service $LIBVIRT_DAEMON
-
-
         # Instance Storage
         # ----------------
 
@@ -436,8 +437,10 @@
     if is_baremetal; then
         iniset $NOVA_CONF baremetal sql_connection `database_connection_url nova_bm`
     fi
-    iniset $NOVA_CONF DEFAULT libvirt_type "$LIBVIRT_TYPE"
-    iniset $NOVA_CONF DEFAULT libvirt_cpu_mode "none"
+    if [[ "$VIRT_DRIVER" = 'libvirt' ]]; then
+        iniset $NOVA_CONF DEFAULT libvirt_type "$LIBVIRT_TYPE"
+        iniset $NOVA_CONF DEFAULT libvirt_cpu_mode "none"
+    fi
     iniset $NOVA_CONF DEFAULT instance_name_template "${INSTANCE_NAME_PREFIX}%08x"
     iniset $NOVA_CONF osapi_v3 enabled "True"
 
@@ -490,7 +493,6 @@
         iniset_multiline $NOVA_CONF DEFAULT notification_driver "nova.openstack.common.notifier.rpc_notifier" "ceilometer.compute.nova_notifier"
     fi
 
-
     # Provide some transition from ``EXTRA_FLAGS`` to ``EXTRA_OPTS``
     if [[ -z "$EXTRA_OPTS" && -n "$EXTRA_FLAGS" ]]; then
         EXTRA_OPTS=$EXTRA_FLAGS
@@ -636,26 +638,32 @@
 # install_nova() - Collect source and prepare
 function install_nova() {
     if is_service_enabled n-cpu; then
-        if is_ubuntu; then
-            install_package libvirt-bin
-        elif is_fedora || is_suse; then
-            install_package libvirt
-        else
-            exit_distro_not_supported "libvirt installation"
-        fi
-
-        # Install and configure **LXC** if specified.  LXC is another approach to
-        # splitting a system into many smaller parts.  LXC uses cgroups and chroot
-        # to simulate multiple systems.
-        if [[ "$LIBVIRT_TYPE" == "lxc" ]]; then
+        if [[ "$VIRT_DRIVER" = 'libvirt' ]]; then
             if is_ubuntu; then
-                if [[ "$DISTRO" > natty ]]; then
-                    install_package cgroup-lite
-                fi
+                install_package kvm
+                install_package libvirt-bin
+                install_package python-libvirt
+            elif is_fedora || is_suse; then
+                install_package kvm
+                install_package libvirt
+                install_package libvirt-python
             else
-                ### FIXME(dtroyer): figure this out
-                echo "RPM-based cgroup not implemented yet"
-                yum_install libcgroup-tools
+                exit_distro_not_supported "libvirt installation"
+            fi
+
+            # Install and configure **LXC** if specified.  LXC is another approach to
+            # splitting a system into many smaller parts.  LXC uses cgroups and chroot
+            # to simulate multiple systems.
+            if [[ "$LIBVIRT_TYPE" == "lxc" ]]; then
+                if is_ubuntu; then
+                    if [[ "$DISTRO" > natty ]]; then
+                        install_package cgroup-lite
+                    fi
+                else
+                    ### FIXME(dtroyer): figure this out
+                    echo "RPM-based cgroup not implemented yet"
+                    yum_install libcgroup-tools
+                fi
             fi
         fi
     fi
@@ -698,9 +706,13 @@
         screen_it n-cell "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-cells --config-file $NOVA_CELLS_CONF"
     fi
 
-    # The group **$LIBVIRT_GROUP** is added to the current user in this script.
-    # Use 'sg' to execute nova-compute as a member of the **$LIBVIRT_GROUP** group.
-    screen_it n-cpu "cd $NOVA_DIR && sg $LIBVIRT_GROUP '$NOVA_BIN_DIR/nova-compute --config-file $NOVA_CONF_BOTTOM'"
+    if [[ "$VIRT_DRIVER" = 'libvirt' ]]; then
+        # The group **$LIBVIRT_GROUP** is added to the current user in this script.
+        # Use 'sg' to execute nova-compute as a member of the **$LIBVIRT_GROUP** group.
+        screen_it n-cpu "cd $NOVA_DIR && sg $LIBVIRT_GROUP '$NOVA_BIN_DIR/nova-compute --config-file $NOVA_CONF_BOTTOM'"
+    else
+        screen_it n-cpu "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-compute --config-file $NOVA_CONF_BOTTOM"
+    fi
     screen_it n-crt "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-cert"
     screen_it n-net "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-network --config-file $NOVA_CONF_BOTTOM"
     screen_it n-sch "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-scheduler --config-file $NOVA_CONF_BOTTOM"
diff --git a/lib/quantum b/lib/quantum
index d85c648..51dd761 100644
--- a/lib/quantum
+++ b/lib/quantum
@@ -52,6 +52,10 @@
 # Quantum.
 #
 # With Quantum networking the NETWORK_MANAGER variable is ignored.
+#
+# To enable specific configuration options for either the Open vSwitch or
+# LinuxBridge plugin, please see the top level README file under the
+# Quantum section.
 
 # Save trace setting
 XTRACE=$(set +o | grep xtrace)
@@ -112,18 +116,18 @@
     # The following variables control the Quantum openvswitch and
     # linuxbridge plugins' allocation of tenant networks and
     # availability of provider networks. If these are not configured
-    # in localrc, tenant networks will be local to the host (with no
+    # in ``localrc``, tenant networks will be local to the host (with no
     # remote connectivity), and no physical resources will be
     # available for the allocation of provider networks.
 
     # To use GRE tunnels for tenant networks, set to True in
-    # localrc. GRE tunnels are only supported by the openvswitch
+    # ``localrc``. GRE tunnels are only supported by the openvswitch
     # plugin, and currently only on Ubuntu.
     ENABLE_TENANT_TUNNELS=${ENABLE_TENANT_TUNNELS:-False}
 
     # 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.
+    # overriden in ``localrc`` in necesssary.
     TENANT_TUNNEL_RANGES=${TENANT_TUNNEL_RANGE:-1:1000}
 
     # To use VLANs for tenant networks, set to True in localrc. VLANs
@@ -131,7 +135,7 @@
     # requiring additional configuration described below.
     ENABLE_TENANT_VLANS=${ENABLE_TENANT_VLANS:-False}
 
-    # If using VLANs for tenant networks, set in localrc to specify
+    # If using VLANs for tenant networks, set in ``localrc`` to specify
     # the range of VLAN VIDs from which tenant networks are
     # allocated. An external network switch must be configured to
     # trunk these VLANs between hosts for multi-host connectivity.
@@ -140,16 +144,16 @@
     TENANT_VLAN_RANGE=${TENANT_VLAN_RANGE:-}
 
     # If using VLANs for tenant networks, or if using flat or VLAN
-    # provider networks, set in localrc to the name of the physical
-    # network, and also configure OVS_PHYSICAL_BRIDGE for the
-    # openvswitch agent or LB_PHYSICAL_INTERFACE for the linuxbridge
+    # provider networks, set in ``localrc`` to the name of the physical
+    # network, and also configure ``OVS_PHYSICAL_BRIDGE`` for the
+    # openvswitch agent or ``LB_PHYSICAL_INTERFACE`` for the linuxbridge
     # agent, as described below.
     #
     # Example: ``PHYSICAL_NETWORK=default``
     PHYSICAL_NETWORK=${PHYSICAL_NETWORK:-}
 
     # With the openvswitch plugin, if using VLANs for tenant networks,
-    # or if using flat or VLAN provider networks, set in localrc to
+    # or if using flat or VLAN provider networks, set in ``localrc`` to
     # the name of the OVS bridge to use for the physical network. The
     # bridge will be created if it does not already exist, but a
     # physical interface must be manually added to the bridge as a
@@ -159,30 +163,31 @@
     OVS_PHYSICAL_BRIDGE=${OVS_PHYSICAL_BRIDGE:-}
 
     # With the linuxbridge plugin, if using VLANs for tenant networks,
-    # or if using flat or VLAN provider networks, set in localrc to
+    # or if using flat or VLAN provider networks, set in ``localrc`` to
     # the name of the network interface to use for the physical
     # network.
     #
     # Example: ``LB_PHYSICAL_INTERFACE=eth1``
     LB_PHYSICAL_INTERFACE=${LB_PHYSICAL_INTERFACE:-}
 
-    # With the openvswitch plugin, set to True in localrc to enable
+    # With the openvswitch plugin, set to True in ``localrc`` to enable
     # provider GRE tunnels when ``ENABLE_TENANT_TUNNELS`` is False.
     #
     # Example: ``OVS_ENABLE_TUNNELING=True``
     OVS_ENABLE_TUNNELING=${OVS_ENABLE_TUNNELING:-$ENABLE_TENANT_TUNNELS}
 fi
 
-
 # Quantum plugin specific functions
 # ---------------------------------
-# Please refer to lib/quantum_plugins/README.md for details.
+
+# Please refer to ``lib/quantum_plugins/README.md`` for details.
 source $TOP_DIR/lib/quantum_plugins/$Q_PLUGIN
 
 # Agent loadbalancer service plugin functions
 # -------------------------------------------
+
 # Hardcoding for 1 service plugin for now
-source $TOP_DIR/lib/quantum_plugins/services/agent_loadbalancer
+source $TOP_DIR/lib/quantum_plugins/services/loadbalancer
 
 # Use security group or not
 if has_quantum_plugin_security_group; then
@@ -191,7 +196,6 @@
     Q_USE_SECGROUP=False
 fi
 
-
 # Functions
 # ---------
 
@@ -358,8 +362,14 @@
 
 # install_quantum_agent_packages() - Collect source and prepare
 function install_quantum_agent_packages() {
-    # install packages that is specific to plugin agent
-    quantum_plugin_install_agent_packages
+    # install packages that are specific to plugin agent(s)
+    if is_service_enabled q-agt q-dhcp q-l3; then
+        quantum_plugin_install_agent_packages
+    fi
+
+    if is_service_enabled q-lbaas; then
+       quantum_agent_lbaas_install_agent_packages
+    fi
 }
 
 # Start running processes, including screen
@@ -423,7 +433,7 @@
 
 # _configure_quantum_common()
 # Set common config for all quantum server and agents.
-# This MUST be called before other _configure_quantum_* functions.
+# This MUST be called before other ``_configure_quantum_*`` functions.
 function _configure_quantum_common() {
     # Put config files in ``QUANTUM_CONF_DIR`` for everyone to find
     if [[ ! -d $QUANTUM_CONF_DIR ]]; then
@@ -433,11 +443,11 @@
 
     cp $QUANTUM_DIR/etc/quantum.conf $QUANTUM_CONF
 
-    # Set plugin-specific variables Q_DB_NAME, Q_PLUGIN_CLASS.
-    # For main plugin config file, set Q_PLUGIN_CONF_PATH, Q_PLUGIN_CONF_FILENAME.
-    # For addition plugin config files, set Q_PLUGIN_EXTRA_CONF_PATH,
-    # Q_PLUGIN_EXTRA_CONF_FILES.  For example:
-    #    Q_PLUGIN_EXTRA_CONF_FILES=(file1, file2)
+    # Set plugin-specific variables ``Q_DB_NAME``, ``Q_PLUGIN_CLASS``.
+    # For main plugin config file, set ``Q_PLUGIN_CONF_PATH``, ``Q_PLUGIN_CONF_FILENAME``.
+    # For addition plugin config files, set ``Q_PLUGIN_EXTRA_CONF_PATH``,
+    # ``Q_PLUGIN_EXTRA_CONF_FILES``.  For example:
+    #    ``Q_PLUGIN_EXTRA_CONF_FILES=(file1, file2)``
     quantum_plugin_configure_common
 
     if [[ $Q_PLUGIN_CONF_PATH == '' || $Q_PLUGIN_CONF_FILENAME == '' || $Q_PLUGIN_CLASS == '' ]]; then
@@ -543,9 +553,7 @@
     _quantum_setup_keystone $Q_META_CONF_FILE DEFAULT set_auth_url
 }
 
-function _configure_quantum_lbaas()
-{
-    quantum_agent_lbaas_install_agent_packages
+function _configure_quantum_lbaas() {
     quantum_agent_lbaas_configure_common
     quantum_agent_lbaas_configure_agent
 }
@@ -606,17 +614,17 @@
         return
     fi
     # Deploy new rootwrap filters files (owned by root).
-    # Wipe any existing rootwrap.d files first
+    # Wipe any existing ``rootwrap.d`` files first
     Q_CONF_ROOTWRAP_D=$QUANTUM_CONF_DIR/rootwrap.d
     if [[ -d $Q_CONF_ROOTWRAP_D ]]; then
         sudo rm -rf $Q_CONF_ROOTWRAP_D
     fi
-    # Deploy filters to $QUANTUM_CONF_DIR/rootwrap.d
+    # Deploy filters to ``$QUANTUM_CONF_DIR/rootwrap.d``
     mkdir -p -m 755 $Q_CONF_ROOTWRAP_D
     cp -pr $QUANTUM_DIR/etc/quantum/rootwrap.d/* $Q_CONF_ROOTWRAP_D/
     sudo chown -R root:root $Q_CONF_ROOTWRAP_D
     sudo chmod 644 $Q_CONF_ROOTWRAP_D/*
-    # Set up rootwrap.conf, pointing to $QUANTUM_CONF_DIR/rootwrap.d
+    # Set up ``rootwrap.conf``, pointing to ``$QUANTUM_CONF_DIR/rootwrap.d``
     # location moved in newer versions, prefer new location
     if test -r $QUANTUM_DIR/etc/quantum/rootwrap.conf; then
       sudo cp -p $QUANTUM_DIR/etc/quantum/rootwrap.conf $Q_RR_CONF_FILE
@@ -626,7 +634,7 @@
     sudo sed -e "s:^filters_path=.*$:filters_path=$Q_CONF_ROOTWRAP_D:" -i $Q_RR_CONF_FILE
     sudo chown root:root $Q_RR_CONF_FILE
     sudo chmod 0644 $Q_RR_CONF_FILE
-    # Specify rootwrap.conf as first parameter to quantum-rootwrap
+    # Specify ``rootwrap.conf`` as first parameter to quantum-rootwrap
     ROOTWRAP_SUDOER_CMD="$QUANTUM_ROOTWRAP $Q_RR_CONF_FILE *"
 
     # Set up the rootwrap sudoers for quantum
@@ -743,7 +751,8 @@
 
 # Quantum 3rd party programs
 #---------------------------
-# please refer to lib/quantum_thirdparty/README.md for details
+
+# please refer to ``lib/quantum_thirdparty/README.md`` for details
 QUANTUM_THIRD_PARTIES=""
 for f in $TOP_DIR/lib/quantum_thirdparty/*; do
      third_party=$(basename $f)
diff --git a/lib/quantum_plugins/brocade b/lib/quantum_plugins/brocade
index fc86deb..52ce3db 100644
--- a/lib/quantum_plugins/brocade
+++ b/lib/quantum_plugins/brocade
@@ -25,15 +25,16 @@
 }
 
 function quantum_plugin_configure_debug_command() {
-    :
+    iniset $QUANTUM_TEST_CONFIG_FILE DEFAULT external_network_bridge
 }
 
 function quantum_plugin_configure_dhcp_agent() {
-    :
+    iniset $Q_DHCP_CONF_FILE DEFAULT dhcp_agent_manager quantum.agent.dhcp_agent.DhcpAgentWithStateReport
 }
 
 function quantum_plugin_configure_l3_agent() {
-    :
+    iniset $Q_L3_CONF_FILE DEFAULT external_network_bridge
+    iniset $Q_L3_CONF_FILE DEFAULT l3_agent_manager quantum.agent.l3_agent.L3NATAgentWithStateReport
 }
 
 function quantum_plugin_configure_plugin_agent() {
diff --git a/lib/quantum_plugins/linuxbridge b/lib/quantum_plugins/linuxbridge
index 71832f1..dffa32b 100644
--- a/lib/quantum_plugins/linuxbridge
+++ b/lib/quantum_plugins/linuxbridge
@@ -35,6 +35,14 @@
     else
         iniset /$Q_PLUGIN_CONF_FILE SECURITYGROUP firewall_driver quantum.agent.firewall.NoopFirewallDriver
     fi
+
+    # Define extra "LINUX_BRIDGE" configuration options when q-svc is configured by defining
+    # the array ``Q_SRV_EXTRA_OPTS``.
+    # For Example: ``Q_SRV_EXTRA_OPTS=(foo=true bar=2)``
+    for I in "${Q_SRV_EXTRA_OPTS[@]}"; do
+        # Replace the first '=' with ' ' for iniset syntax
+        iniset /$Q_PLUGIN_CONF_FILE LINUX_BRIDGE ${I/=/ }
+    done
 }
 
 function has_quantum_plugin_security_group() {
diff --git a/lib/quantum_plugins/linuxbridge_agent b/lib/quantum_plugins/linuxbridge_agent
index 1e83275..7855cd0 100644
--- a/lib/quantum_plugins/linuxbridge_agent
+++ b/lib/quantum_plugins/linuxbridge_agent
@@ -47,6 +47,20 @@
         iniset /$Q_PLUGIN_CONF_FILE SECURITYGROUP firewall_driver quantum.agent.firewall.NoopFirewallDriver
     fi
     AGENT_BINARY="$QUANTUM_DIR/bin/quantum-linuxbridge-agent"
+    # Define extra "AGENT" configuration options when q-agt is configured by defining
+    # the array ``Q_AGENT_EXTRA_AGENT_OPTS``.
+    # For Example: ``Q_AGENT_EXTRA_AGENT_OPTS=(foo=true bar=2)``
+    for I in "${Q_AGENT_EXTRA_AGENT_OPTS[@]}"; do
+        # Replace the first '=' with ' ' for iniset syntax
+        iniset /$Q_PLUGIN_CONF_FILE AGENT ${I/=/ }
+    done
+    # Define extra "LINUX_BRIDGE" configuration options when q-agt is configured by defining
+    # the array ``Q_AGENT_EXTRA_SRV_OPTS``.
+    # For Example: ``Q_AGENT_EXTRA_SRV_OPTS=(foo=true bar=2)``
+    for I in "${Q_AGENT_EXTRA_SRV_OPTS[@]}"; do
+        # Replace the first '=' with ' ' for iniset syntax
+        iniset /$Q_PLUGIN_CONF_FILE LINUX_BRIDGE ${I/=/ }
+    done
 }
 
 function quantum_plugin_setup_interface_driver() {
diff --git a/lib/quantum_plugins/nicira b/lib/quantum_plugins/nicira
index 7795eed..c9c6d0e 100644
--- a/lib/quantum_plugins/nicira
+++ b/lib/quantum_plugins/nicira
@@ -34,8 +34,8 @@
 }
 
 function quantum_plugin_install_agent_packages() {
-    # Nicira Plugin does not run q-agt
-    :
+    # Nicira Plugin does not run q-agt, but it currently needs dhcp and metadata agents
+    _quantum_ovs_base_install_agent_packages
 }
 
 function quantum_plugin_configure_common() {
@@ -46,7 +46,7 @@
 }
 
 function quantum_plugin_configure_debug_command() {
-    :
+    sudo ovs-vsctl --no-wait -- --may-exist add-br $PUBLIC_BRIDGE
 }
 
 function quantum_plugin_configure_dhcp_agent() {
diff --git a/lib/quantum_plugins/openvswitch b/lib/quantum_plugins/openvswitch
index cd29c19..e53db8a 100644
--- a/lib/quantum_plugins/openvswitch
+++ b/lib/quantum_plugins/openvswitch
@@ -42,6 +42,14 @@
     fi
 
     _quantum_ovs_base_configure_firewall_driver
+
+    # Define extra "OVS" configuration options when q-svc is configured by defining
+    # the array ``Q_SRV_EXTRA_OPTS``.
+    # For Example: ``Q_SRV_EXTRA_OPTS=(foo=true bar=2)``
+    for I in "${Q_SRV_EXTRA_OPTS[@]}"; do
+        # Replace the first '=' with ' ' for iniset syntax
+        iniset /$Q_PLUGIN_CONF_FILE OVS ${I/=/ }
+    done
 }
 
 function has_quantum_plugin_security_group() {
diff --git a/lib/quantum_plugins/openvswitch_agent b/lib/quantum_plugins/openvswitch_agent
index 87f5e97..7e83428 100644
--- a/lib/quantum_plugins/openvswitch_agent
+++ b/lib/quantum_plugins/openvswitch_agent
@@ -43,8 +43,8 @@
     if [[ "$OVS_ENABLE_TUNNELING" = "True" ]]; then
         # Verify tunnels are supported
         # REVISIT - also check kernel module support for GRE and patch ports
-        OVS_VERSION=`ovs-vsctl --version | head -n 1 | awk '{print $4;}'`
-        if [ $OVS_VERSION \< "1.4" ] && ! is_service_enabled q-svc ; then
+        OVS_VERSION=`ovs-vsctl --version | head -n 1 | grep -E -o "[0-9]+\.[0-9]+"`
+        if [ `vercmp_numbers "$OVS_VERSION" "1.4"` -lt "0" ] && ! is_service_enabled q-svc ; then
             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
@@ -102,6 +102,20 @@
         # Set root wrap
         iniset "/$Q_PLUGIN_CONF_FILE.domU" AGENT root_helper "$Q_RR_COMMAND"
     fi
+    # Define extra "AGENT" configuration options when q-agt is configured by defining
+    # defining the array ``Q_AGENT_EXTRA_AGENT_OPTS``.
+    # For Example: ``Q_AGENT_EXTRA_AGENT_OPTS=(foo=true bar=2)``
+    for I in "${Q_AGENT_EXTRA_AGENT_OPTS[@]}"; do
+        # Replace the first '=' with ' ' for iniset syntax
+        iniset /$Q_PLUGIN_CONF_FILE AGENT ${I/=/ }
+    done
+    # Define extra "OVS" configuration options when q-agt is configured by defining
+    # defining the array ``Q_AGENT_EXTRA_SRV_OPTS``.
+    # For Example: ``Q_AGENT_EXTRA_SRV_OPTS=(foo=true bar=2)``
+    for I in "${Q_AGENT_EXTRA_SRV_OPTS[@]}"; do
+        # Replace the first '=' with ' ' for iniset syntax
+        iniset /$Q_PLUGIN_CONF_FILE OVS ${I/=/ }
+    done
 }
 
 function quantum_plugin_setup_interface_driver() {
diff --git a/lib/quantum_plugins/services/agent_loadbalancer b/lib/quantum_plugins/services/loadbalancer
similarity index 81%
rename from lib/quantum_plugins/services/agent_loadbalancer
rename to lib/quantum_plugins/services/loadbalancer
index ee3faa5..ac8501f 100644
--- a/lib/quantum_plugins/services/agent_loadbalancer
+++ b/lib/quantum_plugins/services/loadbalancer
@@ -7,7 +7,7 @@
 
 
 AGENT_LBAAS_BINARY="$QUANTUM_DIR/bin/quantum-lbaas-agent"
-AGENT_LBAAS_PLUGIN=quantum.plugins.services.agent_loadbalancer.plugin.LoadBalancerPlugin
+LBAAS_PLUGIN=quantum.services.loadbalancer.plugin.LoadBalancerPlugin
 
 function quantum_agent_lbaas_install_agent_packages() {
     if is_ubuntu || is_fedora; then
@@ -20,14 +20,14 @@
 
 function quantum_agent_lbaas_configure_common() {
     if [[ $Q_SERVICE_PLUGIN_CLASSES == '' ]]; then
-        Q_SERVICE_PLUGIN_CLASSES=$AGENT_LBAAS_PLUGIN
+        Q_SERVICE_PLUGIN_CLASSES=$LBAAS_PLUGIN
     else
-        Q_SERVICE_PLUGIN_CLASSES="$Q_SERVICE_PLUGIN_CLASSES,$AGENT_LBAAS_PLUGIN"
+        Q_SERVICE_PLUGIN_CLASSES="$Q_SERVICE_PLUGIN_CLASSES,$LBAAS_PLUGIN"
     fi
 }
 
 function quantum_agent_lbaas_configure_agent() {
-    LBAAS_AGENT_CONF_PATH=/etc/quantum/plugins/services/agent_loadbalancer
+    LBAAS_AGENT_CONF_PATH=/etc/quantum/services/loadbalancer/haproxy
     mkdir -p $LBAAS_AGENT_CONF_PATH
 
     LBAAS_AGENT_CONF_FILENAME="$LBAAS_AGENT_CONF_PATH/lbaas_agent.ini"
diff --git a/lib/tempest b/lib/tempest
index a259ee9..277c68a 100644
--- a/lib/tempest
+++ b/lib/tempest
@@ -23,6 +23,7 @@
 # ``USE_BLOCK_MIGRATION_FOR_LIVE_MIGRATION``
 # ``DEFAULT_INSTANCE_TYPE``
 # ``DEFAULT_INSTANCE_USER``
+# ``CINDER_MULTI_LVM_BACKEND``
 # ``stack.sh`` calls the entry points in this order:
 #
 # install_tempest
@@ -44,7 +45,7 @@
 
 NOVA_SOURCE_DIR=$DEST/nova
 
-BUILD_INTERVAL=3
+BUILD_INTERVAL=1
 BUILD_TIMEOUT=400
 
 
@@ -166,9 +167,15 @@
         fi
         flavor_ref=${flavors[0]}
         flavor_ref_alt=$flavor_ref
-        if [[ $num_flavors -gt 1 ]]; then
-            flavor_ref_alt=${flavors[1]}
-        fi
+
+        # ensure flavor_ref and flavor_ref_alt have different values
+        # some resize instance in tempest tests depends on this.
+        for f in ${flavors[@]:1}; do
+            if [[ $f -ne $flavor_ref ]]; then
+                flavor_ref_alt=$f
+                break
+            fi
+        done
     fi
 
     if [ "$Q_USE_NAMESPACE" != "False" ]; then
@@ -205,6 +212,13 @@
     iniset $TEMPEST_CONF identity alt_tenant_name $ALT_TENANT_NAME
     iniset $TEMPEST_CONF identity admin_password "$password"
 
+    # Image
+    # for the gate we want to be able to override this variable so we aren't
+    # doing an HTTP fetch over the wide internet for this test
+    if [[ ! -z "$TEMPEST_HTTP_IMAGE" ]]; then
+        iniset $TEMPEST_CONF image http_image $TEMPEST_HTTP_IMAGE
+    fi
+
     # Compute
     iniset $TEMPEST_CONF compute change_password_available False
     # Note(nati) current tempest don't create network for each tenant
@@ -234,11 +248,10 @@
     iniset $TEMPEST_CONF whitebox path_to_private_key $TEMPEST_DIR/id_rsa
     iniset $TEMPEST_CONF whitebox db_uri $BASE_SQL_CONN/nova
 
-
-    # compute admin
+    # Compute admin
     iniset $TEMPEST_CONF "compute-admin" password "$password" # DEPRECATED
 
-    # network
+    # Network
     if is_service_enabled quantum; then
         iniset $TEMPEST_CONF network quantum_available "True"
     fi
@@ -247,7 +260,7 @@
     iniset $TEMPEST_CONF network public_network_id "$public_network_id"
     iniset $TEMPEST_CONF network public_router_id "$public_router_id"
 
-    #boto
+    # boto
     iniset $TEMPEST_CONF boto ec2_url "http://$SERVICE_HOST:8773/services/Cloud"
     iniset $TEMPEST_CONF boto s3_url "http://$SERVICE_HOST:${S3_SERVICE_PORT:-3333}"
     iniset $TEMPEST_CONF boto s3_materials_path "$BOTO_MATERIALS_PATH"
@@ -255,11 +268,19 @@
     iniset $TEMPEST_CONF boto http_socket_timeout 30
     iniset $TEMPEST_CONF boto ssh_user ${DEFAULT_INSTANCE_USER:-cirros}
 
-    # orchestration
+    # Orchestration
     if is_service_enabled heat; then
         iniset $TEMPEST_CONF orchestration heat_available "True"
     fi
 
+    # Volume
+    CINDER_MULTI_LVM_BACKEND=$(trueorfalse False $CINDER_MULTI_LVM_BACKEND)
+    if [ $CINDER_MULTI_LVM_BACKEND == "True" ]; then
+        iniset $TEMPEST_CONF volume multi_backend_enabled "True"
+        iniset $TEMPEST_CONF volume backend1_name "LVM_iSCSI"
+        iniset $TEMPEST_CONF volume backend2_name "LVM_iSCSI_2"
+    fi
+
     echo "Created tempest configuration file:"
     cat $TEMPEST_CONF
 
diff --git a/stack.sh b/stack.sh
index 1e61a3f..4089531 100755
--- a/stack.sh
+++ b/stack.sh
@@ -3,7 +3,7 @@
 # ``stack.sh`` is an opinionated OpenStack developer installation.  It
 # installs and configures various combinations of **Ceilometer**, **Cinder**,
 # **Glance**, **Heat**, **Horizon**, **Keystone**, **Nova**, **Quantum**
-# and **Swift**
+# and **Swift**.
 
 # This script allows you to specify configuration options of what git
 # repositories to use, enabled services, network configuration and various
@@ -12,9 +12,11 @@
 # developer install.
 
 # To keep this script simple we assume you are running on a recent **Ubuntu**
-# (12.04 Precise or newer) or **Fedora** (F16 or newer) machine.  It
-# should work in a VM or physical server.  Additionally we put the list of
-# ``apt`` and ``rpm`` dependencies and other configuration files in this repo.
+# (12.04 Precise or newer) or **Fedora** (F16 or newer) machine.  (It may work
+# on other platforms but support for those platforms is left to those who added
+# them to DevStack.)  It should work in a VM or physical server.  Additionally
+# we maintain a list of ``apt`` and ``rpm`` dependencies and other configuration
+# files in this repo.
 
 # Learn more and get the most recent version at http://devstack.org
 
@@ -33,55 +35,20 @@
 GetDistro
 
 
-# Configure non-default repos
-# ===========================
-
-# Repo configuration needs to occur before package installation.
-
-# Some dependencies are not available in Debian Wheezy official
-# repositories. However, it's possible to run OpenStack from 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
-
-# Installing Open vSwitch on RHEL6 requires enabling the RDO repo.
-RHEL6_RDO_REPO_RPM=${RHEL6_RDO_REPO_RPM:-"http://rdo.fedorapeople.org/openstack/openstack-grizzly/rdo-release-grizzly-3.noarch.rpm"}
-RHEL6_RDO_REPO_ID=${RHEL6_RDO_REPO_ID:-"openstack-grizzly"}
-# RHEL6 requires EPEL for many Open Stack dependencies
-RHEL6_EPEL_RPM=${RHEL6_EPEL_RPM:-"http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm"}
-
-if [[ is_fedora && $DISTRO =~ (rhel6) ]]; then
-
-    if ! yum repolist enabled $RHEL6_RDO_REPO_ID | grep -q $RHEL6_RDO_REPO_ID; then
-        echo "RDO repo not detected; installing"
-        yum_install $RHEL6_RDO_REPO_RPM || \
-            die $LINENO "Error installing RDO repo, cannot continue"
-    fi
-
-    if ! yum repolist enabled epel | grep -q 'epel'; then
-        echo "EPEL not detected; installing"
-        yum_install ${RHEL6_EPEL_RPM} || \
-            die $LINENO "Error installing EPEL repo, cannot continue"
-    fi
-
-fi
-
 # Global Settings
 # ===============
 
-# ``stack.sh`` is customizable through setting environment variables.  If you
-# want to override a setting you can set and export it::
+# ``stack.sh`` is customizable by setting environment variables.  Override a
+# default setting via export::
 #
 #     export DATABASE_PASSWORD=anothersecret
 #     ./stack.sh
 #
-# You can also pass options on a single line ``DATABASE_PASSWORD=simple ./stack.sh``
+# or by setting the variable on the command line::
 #
-# Additionally, you can put any local variables into a ``localrc`` file::
+#     DATABASE_PASSWORD=simple ./stack.sh
+#
+# Persistent variables can be placed in a ``localrc`` file::
 #
 #     DATABASE_PASSWORD=anothersecret
 #     DATABASE_USER=hellaroot
@@ -166,6 +133,41 @@
 VERBOSE=$(trueorfalse True $VERBOSE)
 
 
+# Additional repos
+# ================
+
+# 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 =~ (rhel6) ]]; then
+    # Installing Open vSwitch on RHEL6 requires enabling the RDO repo.
+    RHEL6_RDO_REPO_RPM=${RHEL6_RDO_REPO_RPM:-"http://rdo.fedorapeople.org/openstack/openstack-grizzly/rdo-release-grizzly-3.noarch.rpm"}
+    RHEL6_RDO_REPO_ID=${RHEL6_RDO_REPO_ID:-"openstack-grizzly"}
+    if ! yum repolist enabled $RHEL6_RDO_REPO_ID | grep -q $RHEL6_RDO_REPO_ID; then
+        echo "RDO repo not detected; installing"
+        yum_install $RHEL6_RDO_REPO_RPM || \
+            die $LINENO "Error installing RDO repo, cannot continue"
+    fi
+
+    # RHEL6 requires EPEL for many Open Stack dependencies
+    RHEL6_EPEL_RPM=${RHEL6_EPEL_RPM:-"http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm"}
+    if ! yum repolist enabled epel | grep -q 'epel'; then
+        echo "EPEL not detected; installing"
+        yum_install ${RHEL6_EPEL_RPM} || \
+            die $LINENO "Error installing EPEL repo, cannot continue"
+    fi
+fi
+
+
 # root Access
 # -----------
 
@@ -296,7 +298,7 @@
 # Configure Projects
 # ==================
 
-# Get project function libraries
+# Source project function libraries
 source $TOP_DIR/lib/tls
 source $TOP_DIR/lib/horizon
 source $TOP_DIR/lib/keystone
@@ -310,7 +312,7 @@
 source $TOP_DIR/lib/baremetal
 source $TOP_DIR/lib/ldap
 
-# Set the destination directories for OpenStack projects
+# Set the destination directories for other OpenStack projects
 OPENSTACKCLIENT_DIR=$DEST/python-openstackclient
 PBR_DIR=$DEST/pbr
 
@@ -565,6 +567,7 @@
 # an error.  It is also useful for following along as the install occurs.
 set -o xtrace
 
+
 # Install Packages
 # ================
 
@@ -581,65 +584,55 @@
     install_database
 fi
 
-if is_service_enabled q-agt; then
+if is_service_enabled quantum; then
     install_quantum_agent_packages
 fi
 
-#
+
 # System-specific preconfigure
 # ============================
 
 if [[ is_fedora && $DISTRO =~ (rhel6) ]]; then
-    # Avoid having to configure selinux to allow things like httpd to
-    # access horizion files or run binaries like nodejs (LP#1175444)
+    # Disable selinux to avoid configuring to allow Apache access
+    # to Horizon files or run nodejs (LP#1175444)
     if selinuxenabled; then
         sudo setenforce 0
     fi
 
-    # An old version (2.0.1) of python-crypto is probably installed on
-    # a fresh system, via the dependency chain
-    # cas->python-paramiko->python-crypto (related to anaconda).
-    # Unfortunately, "pip uninstall pycrypto" will remove the
-    # .egg-info file for this rpm-installed version, but leave most of
-    # the actual library files behind in /usr/lib64/python2.6/Crypto.
-    # When later "pip install pycrypto" happens, the built library
-    # will be installed over these existing files; the result is a
-    # useless mess of old, rpm-packaged files and pip-installed files.
-    # Unsurprisingly, the end result is it doesn't work.  Thus we have
-    # to get rid of it now so that any packages that pip-install
-    # pycrypto get a "clean slate".
-    # (note, we have to be careful about other RPM packages specified
-    # pulling in python-crypto as well.  That's why RHEL6 doesn't
-    # install python-paramiko packages for example...)
+    # An old version of ``python-crypto`` (2.0.1) may be installed on a
+    # fresh system via Anaconda and the dependency chain
+    # ``cas`` -> ``python-paramiko`` -> ``python-crypto``.
+    # ``pip uninstall pycrypto`` will remove the packaged ``.egg-info`` file
+    # but leave most of the actual library files behind in ``/usr/lib64/python2.6/Crypto``.
+    # Later ``pip install pycrypto`` will install over the packaged files resulting
+    # in a useless mess of old, rpm-packaged files and pip-installed files.
+    # Remove the package so that ``pip install python-crypto`` installs cleanly.
+    # Note: other RPM packages may require ``python-crypto`` as well.  For example,
+    # RHEL6 does not install ``python-paramiko packages``.
     uninstall_package python-crypto
 
-    # A similar thing happens for python-lxml (a dependency of
-    # ipa-client, an auditing thing we don't care about).  We have the
-    # build-dependencies the lxml pip-install will need (gcc,
-    # libxml2-dev & libxslt-dev) in the "general" rpm lists
+    # A similar situation occurs with ``python-lxml``, which is required by
+    # ``ipa-client``, an auditing package we don't care about.  The
+    # build-dependencies needed for ``pip install lxml`` (``gcc``,
+    # ``libxml2-dev`` and ``libxslt-dev``) are present in ``files/rpms/general``.
     uninstall_package python-lxml
 
-    # If the dbus rpm was installed by the devstack rpm dependencies
-    # then you may hit a bug where the uuid isn't generated because
-    # the service was never started (PR#598200), causing issues for
-    # Nova stopping later on complaining that
-    # '/var/lib/dbus/machine-id' doesn't exist.
+    # If the ``dbus`` package was installed by DevStack dependencies the
+    # uuid may not be generated because the service was never started (PR#598200),
+    # causing Nova to stop later on complaining that ``/var/lib/dbus/machine-id``
+    # does not exist.
     sudo service messagebus restart
 
-    # In setup.py, a "setup_requires" package is supposed to
-    # transient.  However there is a bug with rhel6 distribute where
-    # setup_requires packages can register entry points that aren't
-    # cleared out properly after the setup-phase; the end result is
-    # installation failures (bz#924038).  Thus we pre-install the
-    # problem package here; this way the setup_requires dependency is
-    # already satisfied and it will not need to be installed
-    # transiently, meaning we avoid the issue of it not being cleaned
-    # out properly.  Note we do this before the track-depends below.
+    # ``setup.py`` contains a ``setup_requires`` package that is supposed
+    # to be transient.  However, RHEL6 distribute has a bug where
+    # ``setup_requires`` registers entry points that are not cleaned
+    # out properly after the setup-phase resulting in installation failures
+    # (bz#924038).  Pre-install the problem package so the ``setup_requires``
+    # dependency is satisfied and it will not be installed transiently.
+    # Note we do this before the track-depends below.
     pip_install hgtools
 
-    # The version of python-nose in the RHEL6 repo is incompatible
-    # with Tempest.  As a workaround:
-
+    # RHEL6's version of ``python-nose`` is incompatible with Tempest.
     # Install nose 1.1 (Tempest-compatible) from EPEL
     install_package python-nose1.1
     # Add a symlink for the new nosetests to allow tox for Tempest to
@@ -850,10 +843,10 @@
 init_service_check
 
 
-# Kick off Sysstat
-# ------------------------
-# run sysstat if it is enabled, this has to be early as daemon
-# startup is one of the things to track.
+# Sysstat
+# -------
+
+# If enabled, systat has to start early to track OpenStack service startup.
 if is_service_enabled sysstat;then
     if [[ -n ${SCREEN_LOGDIR} ]]; then
         screen_it sysstat "sar -o $SCREEN_LOGDIR/$SYSSTAT_FILE $SYSSTAT_INTERVAL"
@@ -967,7 +960,7 @@
     rm -rf ${NOVA_STATE_PATH}/networks
     sudo mkdir -p ${NOVA_STATE_PATH}/networks
     sudo chown -R ${USER} ${NOVA_STATE_PATH}/networks
-    # Force IP forwarding on, just on case
+    # Force IP forwarding on, just in case
     sudo sysctl -w net.ipv4.ip_forward=1
 fi
 
@@ -1018,6 +1011,7 @@
         XEN_FIREWALL_DRIVER=${XEN_FIREWALL_DRIVER:-"nova.virt.firewall.IptablesFirewallDriver"}
         iniset $NOVA_CONF DEFAULT firewall_driver "$XEN_FIREWALL_DRIVER"
 
+
     # OpenVZ
     # ------
 
@@ -1028,6 +1022,7 @@
         LIBVIRT_FIREWALL_DRIVER=${LIBVIRT_FIREWALL_DRIVER:-"nova.virt.libvirt.firewall.IptablesFirewallDriver"}
         iniset $NOVA_CONF DEFAULT firewall_driver "$LIBVIRT_FIREWALL_DRIVER"
 
+
     # Bare Metal
     # ----------
 
@@ -1050,6 +1045,7 @@
            iniset $NOVA_CONF baremetal ${I/=/ }
         done
 
+
    # PowerVM
    # -------
 
@@ -1069,8 +1065,9 @@
         iniset $NOVA_CONF DEFAULT powervm_img_remote_path $POWERVM_IMG_REMOTE_PATH
         iniset $NOVA_CONF DEFAULT powervm_img_local_path $POWERVM_IMG_LOCAL_PATH
 
+
     # vSphere API
-    # -------
+    # -----------
 
     elif [ "$VIRT_DRIVER" = 'vsphere' ]; then
         echo_summary "Using VMware vCenter driver"
@@ -1081,8 +1078,9 @@
         iniset $NOVA_CONF DEFAULT vmwareapi_host_password "$VMWAREAPI_PASSWORD"
         iniset $NOVA_CONF DEFAULT vmwareapi_cluster_name "$VMWAREAPI_CLUSTER"
 
+
     # fake
-    # -----
+    # ----
 
     elif [ "$VIRT_DRIVER" = 'fake' ]; then
         echo_summary "Using fake Virt driver"
@@ -1102,8 +1100,8 @@
         iniset $NOVA_CONF DEFAULT scheduler_default_filters "RetryFilter,AvailabilityZoneFilter,ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter"
 
 
-    # Default
-    # -------
+    # Default libvirt
+    # ---------------
 
     else
         echo_summary "Using libvirt virtualization driver"
@@ -1296,7 +1294,6 @@
     screen_it baremetal "nova-baremetal-deploy-helper"
 fi
 
-
 # Save some values we generated for later use
 CURRENT_RUN_TIME=$(date "+$TIMESTAMP_FORMAT")
 echo "# $CURRENT_RUN_TIME" >$TOP_DIR/.stackenv
diff --git a/stackrc b/stackrc
index 2ac564c..ef39710 100644
--- a/stackrc
+++ b/stackrc
@@ -73,10 +73,58 @@
 CINDERCLIENT_REPO=${CINDERCLIENT_REPO:-${GIT_BASE}/openstack/python-cinderclient.git}
 CINDERCLIENT_BRANCH=${CINDERCLIENT_BRANCH:-master}
 
+# image catalog service
+GLANCE_REPO=${GLANCE_REPO:-${GIT_BASE}/openstack/glance.git}
+GLANCE_BRANCH=${GLANCE_BRANCH:-master}
+
+# python glance client library
+GLANCECLIENT_REPO=${GLANCECLIENT_REPO:-${GIT_BASE}/openstack/python-glanceclient.git}
+GLANCECLIENT_BRANCH=${GLANCECLIENT_BRANCH:-master}
+
+# heat service
+HEAT_REPO=${HEAT_REPO:-${GIT_BASE}/openstack/heat.git}
+HEAT_BRANCH=${HEAT_BRANCH:-master}
+
+# python heat client library
+HEATCLIENT_REPO=${HEATCLIENT_REPO:-${GIT_BASE}/openstack/python-heatclient.git}
+HEATCLIENT_BRANCH=${HEATCLIENT_BRANCH:-master}
+
+# django powered web control panel for openstack
+HORIZON_REPO=${HORIZON_REPO:-${GIT_BASE}/openstack/horizon.git}
+HORIZON_BRANCH=${HORIZON_BRANCH:-master}
+
+# unified auth system (manages accounts/tokens)
+KEYSTONE_REPO=${KEYSTONE_REPO:-${GIT_BASE}/openstack/keystone.git}
+KEYSTONE_BRANCH=${KEYSTONE_BRANCH:-master}
+
+# python keystone client library to nova that horizon uses
+KEYSTONECLIENT_REPO=${KEYSTONECLIENT_REPO:-${GIT_BASE}/openstack/python-keystoneclient.git}
+KEYSTONECLIENT_BRANCH=${KEYSTONECLIENT_BRANCH:-master}
+
 # compute service
 NOVA_REPO=${NOVA_REPO:-${GIT_BASE}/openstack/nova.git}
 NOVA_BRANCH=${NOVA_BRANCH:-master}
 
+# python client library to nova that horizon (and others) use
+NOVACLIENT_REPO=${NOVACLIENT_REPO:-${GIT_BASE}/openstack/python-novaclient.git}
+NOVACLIENT_BRANCH=${NOVACLIENT_BRANCH:-master}
+
+# consolidated openstack python client
+OPENSTACKCLIENT_REPO=${OPENSTACKCLIENT_REPO:-${GIT_BASE}/openstack/python-openstackclient.git}
+OPENSTACKCLIENT_BRANCH=${OPENSTACKCLIENT_BRANCH:-master}
+
+# pbr drives the setuptools configs
+PBR_REPO=${PBR_REPO:-${GIT_BASE}/openstack-dev/pbr.git}
+PBR_BRANCH=${PBR_BRANCH:-master}
+
+# quantum service
+QUANTUM_REPO=${QUANTUM_REPO:-${GIT_BASE}/openstack/quantum.git}
+QUANTUM_BRANCH=${QUANTUM_BRANCH:-master}
+
+# quantum client
+QUANTUMCLIENT_REPO=${QUANTUMCLIENT_REPO:-${GIT_BASE}/openstack/python-quantumclient.git}
+QUANTUMCLIENT_BRANCH=${QUANTUMCLIENT_BRANCH:-master}
+
 # storage service
 SWIFT_REPO=${SWIFT_REPO:-${GIT_BASE}/openstack/swift.git}
 SWIFT_BRANCH=${SWIFT_BRANCH:-master}
@@ -87,65 +135,10 @@
 SWIFTCLIENT_REPO=${SWIFTCLIENT_REPO:-${GIT_BASE}/openstack/python-swiftclient.git}
 SWIFTCLIENT_BRANCH=${SWIFTCLIENT_BRANCH:-master}
 
-# image catalog service
-GLANCE_REPO=${GLANCE_REPO:-${GIT_BASE}/openstack/glance.git}
-GLANCE_BRANCH=${GLANCE_BRANCH:-master}
-
-# python glance client library
-GLANCECLIENT_REPO=${GLANCECLIENT_REPO:-${GIT_BASE}/openstack/python-glanceclient.git}
-GLANCECLIENT_BRANCH=${GLANCECLIENT_BRANCH:-master}
-
-# unified auth system (manages accounts/tokens)
-KEYSTONE_REPO=${KEYSTONE_REPO:-${GIT_BASE}/openstack/keystone.git}
-KEYSTONE_BRANCH=${KEYSTONE_BRANCH:-master}
-
-# a websockets/html5 or flash powered VNC console for vm instances
-NOVNC_REPO=${NOVNC_REPO:-${GIT_BASE}/kanaka/noVNC.git}
-NOVNC_BRANCH=${NOVNC_BRANCH:-master}
-
-# a websockets/html5 or flash powered SPICE console for vm instances
-SPICE_REPO=${SPICE_REPO:-http://anongit.freedesktop.org/git/spice/spice-html5.git}
-SPICE_BRANCH=${SPICE_BRANCH:-master}
-
-# django powered web control panel for openstack
-HORIZON_REPO=${HORIZON_REPO:-${GIT_BASE}/openstack/horizon.git}
-HORIZON_BRANCH=${HORIZON_BRANCH:-master}
-
-# python client library to nova that horizon (and others) use
-NOVACLIENT_REPO=${NOVACLIENT_REPO:-${GIT_BASE}/openstack/python-novaclient.git}
-NOVACLIENT_BRANCH=${NOVACLIENT_BRANCH:-master}
-
-# consolidated openstack python client
-OPENSTACKCLIENT_REPO=${OPENSTACKCLIENT_REPO:-${GIT_BASE}/openstack/python-openstackclient.git}
-OPENSTACKCLIENT_BRANCH=${OPENSTACKCLIENT_BRANCH:-master}
-
-# python keystone client library to nova that horizon uses
-KEYSTONECLIENT_REPO=${KEYSTONECLIENT_REPO:-${GIT_BASE}/openstack/python-keystoneclient.git}
-KEYSTONECLIENT_BRANCH=${KEYSTONECLIENT_BRANCH:-master}
-
-# quantum service
-QUANTUM_REPO=${QUANTUM_REPO:-${GIT_BASE}/openstack/quantum.git}
-QUANTUM_BRANCH=${QUANTUM_BRANCH:-master}
-
-# quantum client
-QUANTUMCLIENT_REPO=${QUANTUMCLIENT_REPO:-${GIT_BASE}/openstack/python-quantumclient.git}
-QUANTUMCLIENT_BRANCH=${QUANTUMCLIENT_BRANCH:-master}
-
 # Tempest test suite
 TEMPEST_REPO=${TEMPEST_REPO:-${GIT_BASE}/openstack/tempest.git}
 TEMPEST_BRANCH=${TEMPEST_BRANCH:-master}
 
-# heat service
-HEAT_REPO=${HEAT_REPO:-${GIT_BASE}/openstack/heat.git}
-HEAT_BRANCH=${HEAT_BRANCH:-master}
-
-# python heat client library
-HEATCLIENT_REPO=${HEATCLIENT_REPO:-${GIT_BASE}/openstack/python-heatclient.git}
-HEATCLIENT_BRANCH=${HEATCLIENT_BRANCH:-master}
-
-# ryu service
-RYU_REPO=${RYU_REPO:-${GIT_BASE}/osrg/ryu.git}
-RYU_BRANCH=${RYU_BRANCH:-master}
 
 # diskimage-builder
 BM_IMAGE_BUILD_REPO=${BM_IMAGE_BUILD_REPO:-${GIT_BASE}/stackforge/diskimage-builder.git}
@@ -157,10 +150,18 @@
 BM_POSEUR_REPO=${BM_POSEUR_REPO:-${GIT_BASE}/tripleo/bm_poseur.git}
 BM_POSEUR_BRANCH=${BM_POSEUR_BRANCH:-master}
 
-# pbr
-# Used to drive the setuptools configs
-PBR_REPO=${PBR_REPO:-${GIT_BASE}/openstack-dev/pbr.git}
-PBR_BRANCH=${PBR_BRANCH:-master}
+# a websockets/html5 or flash powered VNC console for vm instances
+NOVNC_REPO=${NOVNC_REPO:-${GIT_BASE}/kanaka/noVNC.git}
+NOVNC_BRANCH=${NOVNC_BRANCH:-master}
+
+# ryu service
+RYU_REPO=${RYU_REPO:-${GIT_BASE}/osrg/ryu.git}
+RYU_BRANCH=${RYU_BRANCH:-master}
+
+# a websockets/html5 or flash powered SPICE console for vm instances
+SPICE_REPO=${SPICE_REPO:-http://anongit.freedesktop.org/git/spice/spice-html5.git}
+SPICE_BRANCH=${SPICE_BRANCH:-master}
+
 
 # Nova hypervisor configuration.  We default to libvirt with **kvm** but will
 # drop back to **qemu** if we are unable to load the kvm module.  ``stack.sh`` can
@@ -184,18 +185,22 @@
         ;;
 esac
 
-# Specify a comma-separated list of UEC images to download and install into glance.
-# supported urls here are:
+
+# Images
+# ------
+
+# Specify a comma-separated list of images to download and install into glance.
+# Supported urls here are:
 #  * "uec-style" images:
 #     If the file ends in .tar.gz, uncompress the tarball and and select the first
 #     .img file inside it as the image.  If present, use "*-vmlinuz*" as the kernel
 #     and "*-initrd*" as the ramdisk
-#     example: http://cloud-images.ubuntu.com/releases/oneiric/release/ubuntu-11.10-server-cloudimg-amd64.tar.gz
+#     example: http://cloud-images.ubuntu.com/releases/precise/release/ubuntu-12.04-server-cloudimg-amd64.tar.gz
 #  * disk image (*.img,*.img.gz)
 #    if file ends in .img, then it will be uploaded and registered as a to
 #    glance as a disk image.  If it ends in .gz, it is uncompressed first.
 #    example:
-#      http://cloud-images.ubuntu.com/releases/oneiric/release/ubuntu-11.10-server-cloudimg-armel-disk1.img
+#      http://cloud-images.ubuntu.com/releases/precise/release/ubuntu-12.04-server-cloudimg-armel-disk1.img
 #      http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-rootfs.img.gz
 #  * OpenVZ image:
 #    OpenVZ uses its own format of image, and does not support UEC style images
@@ -222,11 +227,12 @@
         ;;
     vsphere)
         IMAGE_URLS="";;
-    *) # otherwise, use the uec style image (with kernel, ramdisk, disk)
+    *) # Default to Cirros with kernel, ramdisk and disk image
         DEFAULT_IMAGE_NAME=${DEFAULT_IMAGE_NAME:-cirros-0.3.1-x86_64-uec}
         IMAGE_URLS=${IMAGE_URLS:-"http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-uec.tar.gz"};;
 esac
 
+
 # 5Gb default volume backing file size
 VOLUME_BACKING_FILE_SIZE=${VOLUME_BACKING_FILE_SIZE:-5130M}