Merge "Use heat-manage to sync heat db."
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/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/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/general b/files/rpms/general
index d6abae9..5cb3e28 100644
--- a/files/rpms/general
+++ b/files/rpms/general
@@ -6,6 +6,7 @@
 git-core
 openssh-server
 openssl
+openssl-devel # to rebuild pyOpenSSL if needed
 libxml2-devel # dist:rhel6 [2]
 libxslt-devel # dist:rhel6 [2]
 psmisc
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 e27888a..b844d98 100644
--- a/files/rpms/horizon
+++ b/files/rpms/horizon
@@ -18,8 +18,8 @@
 python-mox
 python-netaddr
 python-nose
-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-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 f50d93f..8d8a0b8 100644
--- a/files/rpms/nova
+++ b/files/rpms/nova
@@ -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 508ed78..cac6330 100644
--- a/lib/nova
+++ b/lib/nova
@@ -300,7 +300,7 @@
             fi
 
             if is_fedora || is_suse; then
-                if is_fedora && [[  $DISTRO =~ (rhel6) || "$os_RELEASE" -le "17" ]]; 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
@@ -352,7 +352,6 @@
             restart_service $LIBVIRT_DAEMON
         fi
 
-
         # Instance Storage
         # ----------------
 
@@ -494,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
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/cisco b/lib/quantum_plugins/cisco
new file mode 100644
index 0000000..92b91e4
--- /dev/null
+++ b/lib/quantum_plugins/cisco
@@ -0,0 +1,327 @@
+# Quantum Cisco plugin
+# ---------------------------
+
+# Save trace setting
+MY_XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+# Scecify the VSM parameters
+Q_CISCO_PLUGIN_VSM_IP=${Q_CISCO_PLUGIN_VSM_IP:-}
+# Specify the VSM username
+Q_CISCO_PLUGIN_VSM_USERNAME=${Q_CISCO_PLUGIN_VSM_USERNAME:-admin}
+# Specify the VSM passward for above username
+Q_CISCO_PLUGIN_VSM_PASSWORD=${Q_CISCO_PLUGIN_VSM_PASSWORD:-}
+# Specify the uVEM integration bridge name
+Q_CISCO_PLUGIN_INTEGRATION_BRIDGE=${Q_CISCO_PLUGIN_INTEGRATION_BRIDGE:-br-int}
+# Specify if tunneling is enabled
+Q_CISCO_PLUGIN_ENABLE_TUNNELING=${Q_CISCO_PLUGIN_ENABLE_TUNNELING:-True}
+# Specify the VXLAN range
+Q_CISCO_PLUGIN_VXLAN_ID_RANGES=${Q_CISCO_PLUGIN_VXLAN_ID_RANGES:-5000:10000}
+# Specify the VLAN range
+Q_CISCO_PLUGIN_VLAN_RANGES=${Q_CISCO_PLUGIN_VLAN_RANGES:-vlan:1:4094}
+
+# Specify ncclient package information
+NCCLIENT_DIR=$DEST/ncclient
+NCCLIENT_VERSION=${NCCLIENT_VERSION:-0.3.1}
+NCCLIENT_REPO=${NCCLIENT_REPO:-${GIT_BASE}/CiscoSystems/ncclient.git}
+NCCLIENT_BRANCH=${NCCLIENT_BRANCH:-master}
+
+# This routine put a prefix on an existing function name
+function _prefix_function() {
+    declare -F $1 > /dev/null || die "$1 doesn't exist"
+    eval "$(echo "${2}_${1}()"; declare -f ${1} | tail -n +2)"
+}
+
+function _has_ovs_subplugin() {
+    local subplugin
+    for subplugin in ${Q_CISCO_PLUGIN_SUBPLUGINS[@]}; do
+        if [[ "$subplugin" == "openvswitch" ]]; then
+            return 0
+        fi
+    done
+    return 1
+}
+
+function _has_nexus_subplugin() {
+    local subplugin
+    for subplugin in ${Q_CISCO_PLUGIN_SUBPLUGINS[@]}; do
+        if [[ "$subplugin" == "nexus" ]]; then
+            return 0
+        fi
+    done
+    return 1
+}
+
+function _has_n1kv_subplugin() {
+    local subplugin
+    for subplugin in ${Q_CISCO_PLUGIN_SUBPLUGINS[@]}; do
+        if [[ "$subplugin" == "n1kv" ]]; then
+            return 0
+        fi
+    done
+    return 1
+}
+
+# This routine populates the cisco config file with the information for
+# a particular nexus switch
+function _config_switch() {
+    local cisco_cfg_file=$1
+    local switch_ip=$2
+    local username=$3
+    local password=$4
+    local ssh_port=$5
+    shift 5
+
+    local section="NEXUS_SWITCH:$switch_ip"
+    iniset $cisco_cfg_file $section username $username
+    iniset $cisco_cfg_file $section password $password
+    iniset $cisco_cfg_file $section ssh_port $ssh_port
+
+    while [[ ${#@} != 0 ]]; do
+        iniset  $cisco_cfg_file $section $1 $2
+        shift 2
+    done
+}
+
+# Prefix openvswitch plugin routines with "ovs" in order to differentiate from
+# cisco plugin routines. This means, ovs plugin routines will coexist with cisco
+# plugin routines in this script.
+source $TOP_DIR/lib/quantum_plugins/openvswitch
+_prefix_function quantum_plugin_create_nova_conf ovs
+_prefix_function quantum_plugin_install_agent_packages ovs
+_prefix_function quantum_plugin_configure_common ovs
+_prefix_function quantum_plugin_configure_debug_command ovs
+_prefix_function quantum_plugin_configure_dhcp_agent ovs
+_prefix_function quantum_plugin_configure_l3_agent ovs
+_prefix_function quantum_plugin_configure_plugin_agent ovs
+_prefix_function quantum_plugin_configure_service ovs
+_prefix_function quantum_plugin_setup_interface_driver ovs
+_prefix_function has_quantum_plugin_security_group ovs
+
+# Check the version of the installed ncclient package
+function check_ncclient_version() {
+python << EOF
+version = '$NCCLIENT_VERSION'
+import sys
+try:
+    import pkg_resources
+    import ncclient
+    module_version = pkg_resources.get_distribution('ncclient').version
+    if version != module_version:
+        sys.exit(1)
+except:
+    sys.exit(1)
+EOF
+}
+
+# Install the ncclient package
+function install_ncclient() {
+    git_clone $NCCLIENT_REPO $NCCLIENT_DIR $NCCLIENT_BRANCH
+    (cd $NCCLIENT_DIR; sudo python setup.py install)
+}
+
+# Check if the required version of ncclient has been installed
+function is_ncclient_installed() {
+    # Check if the Cisco ncclient repository exists
+    if [[ -d $NCCLIENT_DIR ]]; then
+        remotes=$(cd $NCCLIENT_DIR; git remote -v | grep fetch | awk '{ print $2}')
+        for remote in $remotes; do
+            if [[ $remote == $NCCLIENT_REPO ]]; then
+                break;
+            fi
+        done
+        if [[ $remote != $NCCLIENT_REPO ]]; then
+            return 1
+        fi
+    else
+        return 1
+    fi
+
+    # Check if the ncclient is installed with the right version
+    if ! check_ncclient_version; then
+        return 1
+    fi
+    return 0
+}
+
+function has_quantum_plugin_security_group() {
+    if _has_ovs_subplugin; then
+        ovs_has_quantum_plugin_security_group
+    else
+        return 1
+    fi
+}
+
+function is_quantum_ovs_base_plugin() {
+    # Cisco uses OVS if openvswitch subplugin is deployed
+    _has_ovs_subplugin
+    return
+}
+
+# populate required nova configuration parameters
+function quantum_plugin_create_nova_conf() {
+    if _has_ovs_subplugin; then
+        ovs_quantum_plugin_create_nova_conf
+    else
+        _quantum_ovs_base_configure_nova_vif_driver
+    fi
+}
+
+function quantum_plugin_install_agent_packages() {
+    # Cisco plugin uses openvswitch to operate in one of its configurations
+    ovs_quantum_plugin_install_agent_packages
+}
+
+# Configure common parameters
+function quantum_plugin_configure_common() {
+    # setup default subplugins
+    if [ ! -v Q_CISCO_PLUGIN_SUBPLUGINS ]; then
+        declare -ga Q_CISCO_PLUGIN_SUBPLUGINS
+        Q_CISCO_PLUGIN_SUBPLUGINS=(openvswitch nexus)
+    fi
+    if _has_ovs_subplugin; then
+        ovs_quantum_plugin_configure_common
+        Q_PLUGIN_EXTRA_CONF_PATH=etc/quantum/plugins/cisco
+        Q_PLUGIN_EXTRA_CONF_FILES=(cisco_plugins.ini)
+    else
+        Q_PLUGIN_CONF_PATH=etc/quantum/plugins/cisco
+        Q_PLUGIN_CONF_FILENAME=cisco_plugins.ini
+    fi
+    Q_PLUGIN_CLASS="quantum.plugins.cisco.network_plugin.PluginV2"
+    Q_DB_NAME=cisco_quantum
+}
+
+function quantum_plugin_configure_debug_command() {
+    if _has_ovs_subplugin; then
+        ovs_quantum_plugin_configure_debug_command
+    fi
+}
+
+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() {
+    if _has_ovs_subplugin; then
+        ovs_quantum_plugin_configure_l3_agent
+    fi
+}
+
+function _configure_nexus_subplugin() {
+    local cisco_cfg_file=$1
+
+    # Install a known compatible ncclient from the Cisco repository if necessary
+    if ! is_ncclient_installed; then
+        # Preserve the two global variables
+        local offline=$OFFLINE
+        local reclone=$RECLONE
+        # Change their values to allow installation
+        OFFLINE=False
+        RECLONE=yes
+        install_ncclient
+        # Restore their values
+        OFFLINE=$offline
+        RECLONE=$reclone
+    fi
+
+    # Setup default nexus switch information
+    if [ ! -v Q_CISCO_PLUGIN_SWITCH_INFO ]; then
+        declare -A Q_CISCO_PLUGIN_SWITCH_INFO
+        HOST_NAME=$(hostname)
+        Q_CISCO_PLUGIN_SWITCH_INFO=([1.1.1.1]=stack:stack:22:${HOST_NAME}:1/10)
+    else
+        iniset $cisco_cfg_file CISCO nexus_driver quantum.plugins.cisco.nexus.cisco_nexus_network_driver_v2.CiscoNEXUSDriver
+    fi
+
+    # Setup the switch configurations
+    local nswitch
+    local sw_info
+    local segment
+    local sw_info_array
+    declare -i count=0
+    for nswitch in ${!Q_CISCO_PLUGIN_SWITCH_INFO[@]}; do
+        sw_info=${Q_CISCO_PLUGIN_SWITCH_INFO[$nswitch]}
+        sw_info_array=${sw_info//:/ }
+        sw_info_array=( $sw_info_array )
+        count=${#sw_info_array[@]}
+        if [[ $count < 5 || $(( ($count-3) % 2 )) != 0 ]]; then
+            die $LINENO "Incorrect switch configuration: ${Q_CISCO_PLUGIN_SWITCH_INFO[$nswitch]}"
+        fi
+        _config_switch $cisco_cfg_file $nswitch ${sw_info_array[@]}
+    done
+}
+
+# Configure n1kv plugin
+function _configure_n1kv_subplugin() {
+    local cisco_cfg_file=$1
+
+    # populate the cisco plugin cfg file with the VSM information
+    echo "Configuring n1kv in $cisco_cfg_file-- $Q_CISCO_PLUGIN_VSM_IP $Q_CISCO_PLUGIN_VSM_USERNAME $Q_CISCO_PLUGIN_VSM_PASSWORD"
+    iniset $cisco_cfg_file N1KV:$Q_CISCO_PLUGIN_VSM_IP username $Q_CISCO_PLUGIN_VSM_USERNAME
+    iniset $cisco_cfg_file N1KV:$Q_CISCO_PLUGIN_VSM_IP password $Q_CISCO_PLUGIN_VSM_PASSWORD
+
+    iniset $cisco_cfg_file CISCO_N1K integration_bridge $Q_CISCO_PLUGIN_INTEGRATION_BRIDGE
+    iniset $cisco_cfg_file CISCO_N1K enable_tunneling $Q_CISCO_PLUGIN_ENABLE_TUNNELING
+    iniset $cisco_cfg_file CISCO_N1K vxlan_id_ranges $Q_CISCO_PLUGIN_VXLAN_ID_RANGES
+    iniset $cisco_cfg_file CISCO_N1K network_vlan_ranges $Q_CISCO_PLUGIN_VLAN_RANGES
+
+    # Setup the integration bridge by calling the ovs_base
+    OVS_BRIDGE=$Q_CISCO_PLUGIN_INTEGRATION_BRIDGE
+    _quantum_ovs_base_setup_bridge $OVS_BRIDGE
+}
+
+function quantum_plugin_configure_plugin_agent() {
+    if _has_ovs_subplugin; then
+        ovs_quantum_plugin_configure_plugin_agent
+    fi
+}
+
+function quantum_plugin_configure_service() {
+    local subplugin
+    local cisco_cfg_file
+
+    if _has_ovs_subplugin; then
+        ovs_quantum_plugin_configure_service
+        cisco_cfg_file=/${Q_PLUGIN_EXTRA_CONF_FILES[0]}
+    else
+        cisco_cfg_file=/$Q_PLUGIN_CONF_FILE
+    fi
+
+    # Setup the [CISCO_PLUGINS] section
+    if [[ ${#Q_CISCO_PLUGIN_SUBPLUGINS[@]} > 2 ]]; then
+        die $LINENO "At most two subplugins are supported."
+    fi
+
+    if _has_ovs_subplugin && _has_n1kv_subplugin; then
+        die $LINENO "OVS subplugin and n1kv subplugin cannot coexist"
+    fi
+
+    # Setup the subplugins
+    inicomment $cisco_cfg_file CISCO_PLUGINS nexus_plugin
+    inicomment $cisco_cfg_file CISCO_PLUGINS vswitch_plugin
+    inicomment $cisco_cfg_file CISCO_TEST host
+    for subplugin in ${Q_CISCO_PLUGIN_SUBPLUGINS[@]}; do
+        case $subplugin in
+            nexus) iniset $cisco_cfg_file CISCO_PLUGINS nexus_plugin quantum.plugins.cisco.nexus.cisco_nexus_plugin_v2.NexusPlugin;;
+            openvswitch) iniset $cisco_cfg_file CISCO_PLUGINS vswitch_plugin quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2;;
+            n1kv) iniset $cisco_cfg_file CISCO_PLUGINS vswitch_plugin quantum.plugins.cisco.n1kv.n1kv_quantum_plugin.N1kvQuantumPluginV2;;
+            *) die $LINENO "Unsupported cisco subplugin: $subplugin";;
+        esac
+    done
+
+    if _has_nexus_subplugin; then
+        _configure_nexus_subplugin $cisco_cfg_file
+    fi
+
+    if _has_n1kv_subplugin; then
+        _configure_n1kv_subplugin $cisco_cfg_file
+    fi
+}
+
+function quantum_plugin_setup_interface_driver() {
+    local conf_file=$1
+    iniset $conf_file DEFAULT interface_driver quantum.agent.linux.interface.OVSInterfaceDriver
+}
+
+# Restore xtrace
+$MY_XTRACE
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}