Merge "Robustify shocco install and config"
diff --git a/HACKING.rst b/HACKING.rst
index 3c08e67..103b579 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -227,3 +227,51 @@
   or graciously handle possible artifacts left over from previous runs if executed
   again.  It is acceptable to require a reboot or even a re-install of DevStack
   to restore a clean test environment.
+
+
+Bash Style Guidelines
+~~~~~~~~~~~~~~~~~~~~~
+Devstack defines a bash set of best practices for maintaining large
+collections of bash scripts. These should be considered as part of the
+review process.
+
+We have a preliminary enforcing script for this called bash8 (only a
+small number of these rules are enforced).
+
+Whitespace Rules
+----------------
+
+- lines should not include trailing whitespace
+- there should be no hard tabs in the file
+- indents are 4 spaces, and all indentation should be some multiple of
+  them
+
+Control Structure Rules
+-----------------------
+- then should be on the same line as the if
+- do should be on the same line as the for
+
+Example::
+
+  if [[ -r $TOP_DIR/local.conf ]]; then
+      LRC=$(get_meta_section_files $TOP_DIR/local.conf local)
+      for lfile in $LRC; do
+          if [[ "$lfile" == "localrc" ]]; then
+              if [[ -r $TOP_DIR/localrc ]]; then
+                  warn $LINENO "localrc and local.conf:[[local]] both exist, using localrc"
+              else
+                  echo "# Generated file, do not edit" >$TOP_DIR/.localrc.auto
+                  get_meta_section $TOP_DIR/local.conf local $lfile >>$TOP_DIR/.localrc.auto
+              fi
+          fi
+      done
+  fi
+
+Variables and Functions
+-----------------------
+- functions should be used whenever possible for clarity
+- functions should use ``local`` variables as much as possible to
+  ensure they are isolated from the rest of the environment
+- local variables should be lower case, global variables should be
+  upper case
+- function names should_have_underscores, NotCamelCase.
diff --git a/README.md b/README.md
index 640fab6..cb7752d 100644
--- a/README.md
+++ b/README.md
@@ -82,7 +82,7 @@
 # Customizing
 
 You can override environment variables used in `stack.sh` by creating file
-name `local.conf` with a ``locarc`` section as shown below.  It is likely
+name `local.conf` with a ``localrc`` section as shown below.  It is likely
 that you will need to do this to tweak your networking configuration should
 you need to access your cloud from a different host.
 
@@ -171,6 +171,7 @@
     enable_service q-dhcp
     enable_service q-l3
     enable_service q-meta
+    enable_service q-metering
     enable_service neutron
     # Optional, to enable tempest configuration as part of DevStack
     enable_service tempest
diff --git a/driver_certs/cinder_driver_cert.sh b/driver_certs/cinder_driver_cert.sh
new file mode 100755
index 0000000..18bef8b
--- /dev/null
+++ b/driver_certs/cinder_driver_cert.sh
@@ -0,0 +1,87 @@
+#!/usr/bin/env bash
+
+# **cinder_cert.sh**
+
+CERT_DIR=$(cd $(dirname "$0") && pwd)
+TOP_DIR=$(cd $CERT_DIR/..; pwd)
+
+source $TOP_DIR/functions
+source $TOP_DIR/stackrc
+source $TOP_DIR/openrc
+source $TOP_DIR/lib/tempest
+source $TOP_DIR/lib/cinder
+
+TEMPFILE=`mktemp`
+RECLONE=True
+
+function log_message() {
+    MESSAGE=$1
+    STEP_HEADER=$2
+    if [[ "$STEP_HEADER" = "True" ]]; then
+        echo -e "\n========================================================" | tee -a $TEMPFILE
+    fi
+    echo -e `date +%m/%d/%y/%T:`"${MESSAGE}" | tee -a $TEMPFILE
+    if [[ "$STEP_HEADER" = "True" ]]; then
+        echo -e "========================================================" | tee -a $TEMPFILE
+    fi
+}
+
+if [[ "$OFFLINE" = "True" ]]; then
+    echo "ERROR: Driver cert requires fresh clone/pull from ${CINDER_BRANCH}"
+    echo "       Please set OFFLINE=False and retry."
+    exit 1
+fi
+
+log_message "RUNNING CINDER DRIVER CERTIFICATION CHECK", True
+log_message "Output is being logged to: $TEMPFILE"
+
+cd $CINDER_DIR
+log_message "Cloning to ${CINDER_REPO}...", True
+install_cinder
+
+log_message "Pull a fresh Clone of cinder repo...", True
+git status | tee -a $TEMPFILE
+git log --pretty=oneline -n 1 | tee -a $TEMPFILE
+
+log_message "Gathering copy of cinder.conf file (passwords will be scrubbed)...", True
+cat /etc/cinder/cinder.conf | egrep -v "(^#.*|^$)" | tee -a $TEMPFILE
+sed -i "s/\(.*password.*=\).*$/\1 xxx/i" $TEMPFILE
+log_message "End of cinder.conf.", True
+
+cd $TOP_DIR
+# Verify tempest is installed/enabled
+if ! is_service_enabled tempest; then
+    log_message "ERROR!!! Cert requires tempest in enabled_services!", True
+    log_message"       Please add tempest to enabled_services and retry."
+    exit 1
+fi
+
+cd $TEMPEST_DIR
+install_tempest
+
+log_message "Verify tempest is current....", True
+git status | tee -a $TEMPFILE
+log_message "Check status and get latest commit..."
+git log --pretty=oneline -n 1 | tee -a $TEMPFILE
+
+
+#stop and restart cinder services
+log_message "Restart Cinder services...", True
+stop_cinder
+sleep 1
+start_cinder
+sleep 5
+
+# run tempest api/volume/test_*
+log_message "Run the actual tempest volume tests (run_tests.sh -N tempest.api.volume.test_*)...", True
+exec 2> >(tee -a $TEMPFILE)
+`./run_tests.sh -N tempest.api.volume.test_*`
+if [[ $? = 0 ]]; then
+    log_message "CONGRATULATIONS!!!  Device driver PASSED!", True
+    log_message "Submit output: ($TEMPFILE)"
+    exit 0
+else
+    log_message "SORRY!!!  Device driver FAILED!", True
+    log_message "Check output in $TEMPFILE"
+    exit 1
+fi
diff --git a/files/apts/horizon b/files/apts/horizon
index 0865931..8969046 100644
--- a/files/apts/horizon
+++ b/files/apts/horizon
@@ -19,5 +19,3 @@
 python-coverage
 python-cherrypy3 # why?
 python-migrate
-nodejs
-nodejs-legacy # dist:quantal
diff --git a/files/apts/trema b/files/apts/trema
index e33ccd3..09cb7c6 100644
--- a/files/apts/trema
+++ b/files/apts/trema
@@ -6,6 +6,7 @@
 ruby1.8-dev
 libpcap-dev
 libsqlite3-dev
+libglib2.0-dev
 
 # Sliceable Switch
 sqlite3
diff --git a/files/rpms-suse/horizon b/files/rpms-suse/horizon
index 73932ac..d3bde26 100644
--- a/files/rpms-suse/horizon
+++ b/files/rpms-suse/horizon
@@ -1,6 +1,5 @@
 apache2  # NOPRIME
 apache2-mod_wsgi  # NOPRIME
-nodejs
 python-CherryPy # why? (coming from apts)
 python-Paste
 python-PasteDeploy
diff --git a/files/rpms/horizon b/files/rpms/horizon
index 0ca18ca..aa27ab4 100644
--- a/files/rpms/horizon
+++ b/files/rpms/horizon
@@ -3,7 +3,6 @@
 gcc
 httpd # NOPRIME
 mod_wsgi  # NOPRIME
-nodejs # NOPRIME
 pylint
 python-anyjson
 python-BeautifulSoup
diff --git a/functions b/functions
index 0a73b9f..6137aaf 100644
--- a/functions
+++ b/functions
@@ -557,6 +557,18 @@
     [ "($uname -m)" = "$ARCH_TYPE" ]
 }
 
+# Checks if installed Apache is <= given version
+# $1 = x.y.z (version string of Apache)
+function check_apache_version {
+    local cmd="apachectl"
+    if ! [[ -x $(which apachectl 2>/dev/null) ]]; then
+        cmd="/usr/sbin/apachectl"
+    fi
+
+    local version=$($cmd -v | grep version | grep -Po 'Apache/\K[^ ]*')
+    expr "$version" '>=' $1 > /dev/null
+}
+
 # git clone only if directory doesn't exist already.  Since ``DEST`` might not
 # be owned by the installation user, we create the directory and change the
 # ownership to the proper user.
@@ -829,6 +841,7 @@
         [[ ${service} == "cinder" && ${ENABLED_SERVICES} =~ "c-" ]] && return 0
         [[ ${service} == "ceilometer" && ${ENABLED_SERVICES} =~ "ceilometer-" ]] && return 0
         [[ ${service} == "glance" && ${ENABLED_SERVICES} =~ "g-" ]] && return 0
+        [[ ${service} == "ironic" && ${ENABLED_SERVICES} =~ "ir-" ]] && return 0
         [[ ${service} == "neutron" && ${ENABLED_SERVICES} =~ "q-" ]] && return 0
         [[ ${service} == "trove" && ${ENABLED_SERVICES} =~ "tr-" ]] && return 0
         [[ ${service} == "swift" && ${ENABLED_SERVICES} =~ "s-" ]] && return 0
@@ -1238,7 +1251,11 @@
 
 # ``pip install -e`` the package, which processes the dependencies
 # using pip before running `setup.py develop`
-# Uses globals ``STACK_USER``, ``TRACK_DEPENDS``, ``REQUIREMENTS_DIR``
+#
+# Updates the dependencies in project_dir from the
+# openstack/requirements global list before installing anything.
+#
+# Uses globals ``TRACK_DEPENDS``, ``REQUIREMENTS_DIR``
 # setup_develop directory
 function setup_develop() {
     local project_dir=$1
@@ -1254,9 +1271,7 @@
             $SUDO_CMD python update.py $project_dir)
     fi
 
-    pip_install -e $project_dir
-    # ensure that further actions can do things like setup.py sdist
-    safe_chown -R $STACK_USER $1/*.egg-info
+    setup_develop_no_requirements_update $project_dir
 
     # We've just gone and possibly modified the user's source tree in an
     # automated way, which is considered bad form if it's a development
@@ -1266,13 +1281,25 @@
     # where we really really want the overridden version to stick. So provide
     # a variable that tells us whether or not we should UNDO the requirements
     # changes (this will be set to False in the OpenStack ci gate)
-    if [ $UNDO_REQUIREMENTS = "True"]; then
+    if [ $UNDO_REQUIREMENTS = "True" ]; then
         if [ $update_requirements -eq 0 ]; then
             (cd $project_dir && git reset --hard)
         fi
     fi
 }
 
+# ``pip install -e`` the package, which processes the dependencies
+# using pip before running `setup.py develop`
+# Uses globals ``STACK_USER``
+# setup_develop_no_requirements_update directory
+function setup_develop_no_requirements_update() {
+    local project_dir=$1
+
+    pip_install -e $project_dir
+    # ensure that further actions can do things like setup.py sdist
+    safe_chown -R $STACK_USER $1/*.egg-info
+}
+
 
 # Service wrapper to start services
 # start_service service-name
@@ -1325,11 +1352,24 @@
     # Create a directory for the downloaded image tarballs.
     mkdir -p $FILES/images
 
-    # Downloads the image (uec ami+aki style), then extracts it.
-    IMAGE_FNAME=`basename "$image_url"`
-    if [[ ! -f $FILES/$IMAGE_FNAME || "$(stat -c "%s" $FILES/$IMAGE_FNAME)" = "0" ]]; then
-        wget -c $image_url -O $FILES/$IMAGE_FNAME
-        if [[ $? -ne 0 ]]; then
+    if [[ $image_url != file* ]]; then
+        # Downloads the image (uec ami+aki style), then extracts it.
+        IMAGE_FNAME=`basename "$image_url"`
+        if [[ ! -f $FILES/$IMAGE_FNAME || "$(stat -c "%s" $FILES/$IMAGE_FNAME)" = "0" ]]; then
+             wget -c $image_url -O $FILES/$IMAGE_FNAME
+             if [[ $? -ne 0 ]]; then
+                 echo "Not found: $image_url"
+                 return
+             fi
+        fi
+        IMAGE="$FILES/${IMAGE_FNAME}"
+    else
+        # File based URL (RFC 1738): file://host/path
+        # Remote files are not considered here.
+        # *nix: file:///home/user/path/file
+        # windows: file:///C:/Documents%20and%20Settings/user/path/file
+        IMAGE=$(echo $image_url | sed "s/^file:\/\///g")
+        if [[ ! -f $IMAGE || "$(stat -c "%s" $IMAGE)" == "0" ]]; then
             echo "Not found: $image_url"
             return
         fi
@@ -1337,7 +1377,6 @@
 
     # OpenVZ-format images are provided as .tar.gz, but not decompressed prior to loading
     if [[ "$image_url" =~ 'openvz' ]]; then
-        IMAGE="$FILES/${IMAGE_FNAME}"
         IMAGE_NAME="${IMAGE_FNAME%.tar.gz}"
         glance --os-auth-token $token --os-image-url http://$GLANCE_HOSTPORT image-create --name "$IMAGE_NAME" --is-public=True --container-format ami --disk-format ami < "${IMAGE}"
         return
@@ -1345,26 +1384,51 @@
 
     # vmdk format images
     if [[ "$image_url" =~ '.vmdk' ]]; then
-        IMAGE="$FILES/${IMAGE_FNAME}"
         IMAGE_NAME="${IMAGE_FNAME%.vmdk}"
 
         # Before we can upload vmdk type images to glance, we need to know it's
         # disk type, storage adapter, and networking adapter. These values are
-        # passed to glance as custom properties. We take these values from the
+        # passed to glance as custom properties.
+        # We take these values from the vmdk file if populated. Otherwise, we use
         # vmdk filename, which is expected in the following format:
         #
-        #     <name>-<disk type>:<storage adapter>:<network adapter>
+        #     <name>-<disk type>;<storage adapter>;<network adapter>
         #
         # If the filename does not follow the above format then the vsphere
         # driver will supply default values.
-        property_string=`echo "$IMAGE_NAME" | grep -oP '(?<=-)(?!.*-).+:.+:.+$'`
-        if [[ ! -z "$property_string" ]]; then
-            IFS=':' read -a props <<< "$property_string"
-            vmdk_disktype="${props[0]}"
-            vmdk_adapter_type="${props[1]}"
-            vmdk_net_adapter="${props[2]}"
+
+        vmdk_adapter_type=""
+        vmdk_disktype=""
+        vmdk_net_adapter=""
+
+        # vmdk adapter type
+        vmdk_adapter_type="$(head -25 $IMAGE | grep -a -F -m 1 'ddb.adapterType =' $IMAGE)"
+        vmdk_adapter_type="${vmdk_adapter_type#*\"}"
+        vmdk_adapter_type="${vmdk_adapter_type%?}"
+
+        # vmdk disk type
+        vmdk_create_type="$(head -25 $IMAGE | grep -a -F -m 1 'createType=' $IMAGE)"
+        vmdk_create_type="${vmdk_create_type#*\"}"
+        vmdk_create_type="${vmdk_create_type%?}"
+        if [[ "$vmdk_create_type" = "monolithicSparse" ]]; then
+            vmdk_disktype="sparse"
+        elif [[ "$vmdk_create_type" = "monolithicFlat" ]]; then
+            die $LINENO "Monolithic flat disks should use a descriptor-data pair." \
+            "Please provide the disk and not the descriptor."
+        else
+            #TODO(alegendre): handle streamOptimized once supported by VMware driver.
+            vmdk_disktype="preallocated"
         fi
 
+        # NOTE: For backwards compatibility reasons, colons may be used in place
+        # of semi-colons for property delimiters but they are not permitted
+        # characters in NTFS filesystems.
+        property_string=`echo "$IMAGE_NAME" | grep -oP '(?<=-)(?!.*-).+[:;].+[:;].+$'`
+        IFS=':;' read -a props <<< "$property_string"
+        vmdk_disktype="${props[0]:-$vmdk_disktype}"
+        vmdk_adapter_type="${props[1]:-$vmdk_adapter_type}"
+        vmdk_net_adapter="${props[2]:-$vmdk_net_adapter}"
+
         glance --os-auth-token $token --os-image-url http://$GLANCE_HOSTPORT image-create --name "$IMAGE_NAME" --is-public=True --container-format bare --disk-format vmdk --property vmware_disktype="$vmdk_disktype" --property vmware_adaptertype="$vmdk_adapter_type" --property hw_vif_model="$vmdk_net_adapter" < "${IMAGE}"
         return
     fi
@@ -1372,7 +1436,6 @@
     # XenServer-vhd-ovf-format images are provided as .vhd.tgz
     # and should not be decompressed prior to loading
     if [[ "$image_url" =~ '.vhd.tgz' ]]; then
-        IMAGE="$FILES/${IMAGE_FNAME}"
         IMAGE_NAME="${IMAGE_FNAME%.vhd.tgz}"
         glance --os-auth-token $token --os-image-url http://$GLANCE_HOSTPORT image-create --name "$IMAGE_NAME" --is-public=True --container-format=ovf --disk-format=vhd < "${IMAGE}"
         return
@@ -1382,7 +1445,6 @@
     # and should not be decompressed prior to loading.
     # Setting metadata, so PV mode is used.
     if [[ "$image_url" =~ '.xen-raw.tgz' ]]; then
-        IMAGE="$FILES/${IMAGE_FNAME}"
         IMAGE_NAME="${IMAGE_FNAME%.xen-raw.tgz}"
         glance \
             --os-auth-token $token \
@@ -1420,7 +1482,6 @@
             fi
             ;;
         *.img)
-            IMAGE="$FILES/$IMAGE_FNAME";
             IMAGE_NAME=$(basename "$IMAGE" ".img")
             format=$(qemu-img info ${IMAGE} | awk '/^file format/ { print $3; exit }')
             if [[ ",qcow2,raw,vdi,vmdk,vpc," =~ ",$format," ]]; then
@@ -1431,20 +1492,17 @@
             CONTAINER_FORMAT=bare
             ;;
         *.img.gz)
-            IMAGE="$FILES/${IMAGE_FNAME}"
             IMAGE_NAME=$(basename "$IMAGE" ".img.gz")
             DISK_FORMAT=raw
             CONTAINER_FORMAT=bare
             UNPACK=zcat
             ;;
         *.qcow2)
-            IMAGE="$FILES/${IMAGE_FNAME}"
             IMAGE_NAME=$(basename "$IMAGE" ".qcow2")
             DISK_FORMAT=qcow2
             CONTAINER_FORMAT=bare
             ;;
         *.iso)
-            IMAGE="$FILES/${IMAGE_FNAME}"
             IMAGE_NAME=$(basename "$IMAGE" ".iso")
             DISK_FORMAT=iso
             CONTAINER_FORMAT=bare
diff --git a/lib/apache b/lib/apache
index 41d6fcc..8ae78b2 100644
--- a/lib/apache
+++ b/lib/apache
@@ -4,6 +4,10 @@
 # Dependencies:
 #
 # - ``functions`` file
+# -``STACK_USER`` must be defined
+
+# lib/apache exports the following functions:
+#
 # - is_apache_enabled_service
 # - install_apache_wsgi
 # - config_apache_wsgi
@@ -19,7 +23,7 @@
 
 # Allow overriding the default Apache user and group, default to
 # current user and his default group.
-APACHE_USER=${APACHE_USER:-$USER}
+APACHE_USER=${APACHE_USER:-$STACK_USER}
 APACHE_GROUP=${APACHE_GROUP:-$(id -gn $APACHE_USER)}
 
 
diff --git a/lib/ceilometer b/lib/ceilometer
index f95ed30..8e2970c 100644
--- a/lib/ceilometer
+++ b/lib/ceilometer
@@ -67,10 +67,10 @@
     setup_develop $CEILOMETER_DIR
 
     [ ! -d $CEILOMETER_CONF_DIR ] && sudo mkdir -m 755 -p $CEILOMETER_CONF_DIR
-    sudo chown $USER $CEILOMETER_CONF_DIR
+    sudo chown $STACK_USER $CEILOMETER_CONF_DIR
 
     [ ! -d $CEILOMETER_API_LOG_DIR ] &&  sudo mkdir -m 755 -p $CEILOMETER_API_LOG_DIR
-    sudo chown $USER $CEILOMETER_API_LOG_DIR
+    sudo chown $STACK_USER $CEILOMETER_API_LOG_DIR
 
     iniset_rpc_backend ceilometer $CEILOMETER_CONF DEFAULT
 
@@ -82,6 +82,10 @@
     cp $CEILOMETER_DIR/etc/ceilometer/pipeline.yaml $CEILOMETER_CONF_DIR
     iniset $CEILOMETER_CONF DEFAULT policy_file $CEILOMETER_CONF_DIR/policy.json
 
+    if [ "$CEILOMETER_PIPELINE_INTERVAL" ]; then
+        sed -i "s/interval:.*/interval: ${CEILOMETER_PIPELINE_INTERVAL}/" $CEILOMETER_CONF_DIR/pipeline.yaml
+    fi
+
     # the compute and central agents need these credentials in order to
     # call out to the public nova and glance APIs
     iniset $CEILOMETER_CONF DEFAULT os_username ceilometer
@@ -137,7 +141,9 @@
 
 # start_ceilometer() - Start running processes, including screen
 function start_ceilometer() {
-    screen_it ceilometer-acompute "cd ; sg $LIBVIRT_GROUP \"ceilometer-agent-compute --config-file $CEILOMETER_CONF\""
+    if [[ "$VIRT_DRIVER" = 'libvirt' ]]; then
+        screen_it ceilometer-acompute "cd ; sg $LIBVIRT_GROUP \"ceilometer-agent-compute --config-file $CEILOMETER_CONF\""
+    fi
     screen_it ceilometer-acentral "cd ; ceilometer-agent-central --config-file $CEILOMETER_CONF"
     screen_it ceilometer-collector "cd ; ceilometer-collector --config-file $CEILOMETER_CONF"
     screen_it ceilometer-api "cd ; ceilometer-api -d -v --log-dir=$CEILOMETER_API_LOG_DIR --config-file $CEILOMETER_CONF"
diff --git a/lib/cinder b/lib/cinder
index 20d6e61..96d2505 100644
--- a/lib/cinder
+++ b/lib/cinder
@@ -199,7 +199,7 @@
     fi
 
     TEMPFILE=`mktemp`
-    echo "$USER ALL=(root) NOPASSWD: $ROOTWRAP_CINDER_SUDOER_CMD" >$TEMPFILE
+    echo "$STACK_USER ALL=(root) NOPASSWD: $ROOTWRAP_CINDER_SUDOER_CMD" >$TEMPFILE
     chmod 0440 $TEMPFILE
     sudo chown root:root $TEMPFILE
     sudo mv $TEMPFILE /etc/sudoers.d/cinder-rootwrap
diff --git a/lib/heat b/lib/heat
index bf4d4bc..7a9ef0d 100644
--- a/lib/heat
+++ b/lib/heat
@@ -80,7 +80,7 @@
     iniset $HEAT_CONF DEFAULT heat_metadata_server_url http://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT
     iniset $HEAT_CONF DEFAULT heat_waitcondition_server_url http://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1/waitcondition
     iniset $HEAT_CONF DEFAULT heat_watch_server_url http://$HEAT_API_CW_HOST:$HEAT_API_CW_PORT
-    iniset $HEAT_CONF DEFAULT sql_connection `database_connection_url heat`
+    iniset $HEAT_CONF database connection `database_connection_url heat`
     iniset $HEAT_CONF DEFAULT auth_encryption_key `hexdump -n 16 -v -e '/1 "%02x"' /dev/random`
 
     # logging
@@ -120,9 +120,6 @@
     iniset $HEAT_CONF heat_api_cloudwatch bind_host $HEAT_API_CW_HOST
     iniset $HEAT_CONF heat_api_cloudwatch bind_port $HEAT_API_CW_PORT
 
-    # Set limits to match tempest defaults
-    iniset $HEAT_CONF DEFAULT max_template_size 10240
-
     # heat environment
     sudo mkdir -p $HEAT_ENV_DIR
     sudo chown $STACK_USER $HEAT_ENV_DIR
diff --git a/lib/horizon b/lib/horizon
index c116ec2..5bff712 100644
--- a/lib/horizon
+++ b/lib/horizon
@@ -112,7 +112,12 @@
     # Create an empty directory that apache uses as docroot
     sudo mkdir -p $HORIZON_DIR/.blackhole
 
+    # Apache 2.4 uses mod_authz_host for access control now (instead of "Allow")
     HORIZON_REQUIRE=''
+    if check_apache_version "2.4" ; then
+        HORIZON_REQUIRE='Require all granted'
+    fi
+
     local horizon_conf=/etc/$APACHE_NAME/$APACHE_CONF_DIR/horizon.conf
     if is_ubuntu; then
         # Clean up the old config name
@@ -120,17 +125,7 @@
         # Be a good citizen and use the distro tools here
         sudo touch $horizon_conf
         sudo a2ensite horizon.conf
-        if [[ "$DISTRO" == "saucy" ]]; then
-            # Ubuntu 13.10 has Require all denied in apache2.conf
-            # and requires explicit Require all granted
-            HORIZON_REQUIRE='Require all granted'
-        fi
     elif is_fedora; then
-        if [[ "$os_RELEASE" -ge "18" ]]; then
-            # fedora 18 has Require all denied  in its httpd.conf
-            # and requires explicit Require all granted
-            HORIZON_REQUIRE='Require all granted'
-        fi
         sudo sed '/^Listen/s/^.*$/Listen 0.0.0.0:80/' -i /etc/httpd/conf/httpd.conf
     elif is_suse; then
         : # nothing to do
@@ -158,15 +153,6 @@
     # Apache installation, because we mark it NOPRIME
     install_apache_wsgi
 
-    # NOTE(sdague) quantal changed the name of the node binary
-    if is_ubuntu; then
-        if [[ ! -e "/usr/bin/node" ]]; then
-            install_package nodejs-legacy
-        fi
-    elif is_fedora && [[ $DISTRO =~ (rhel6) || "$os_RELEASE" -ge "18" ]]; then
-        install_package nodejs
-    fi
-
     git_clone $HORIZON_REPO $HORIZON_DIR $HORIZON_BRANCH $HORIZON_TAG
 }
 
diff --git a/lib/keystone b/lib/keystone
index 4353eba..978577f 100644
--- a/lib/keystone
+++ b/lib/keystone
@@ -179,7 +179,6 @@
     fi
 
     iniset $KEYSTONE_CONF DEFAULT admin_token "$SERVICE_TOKEN"
-    iniset $KEYSTONE_CONF signing token_format "$KEYSTONE_TOKEN_FORMAT"
 
     if [[ "$KEYSTONE_TOKEN_FORMAT" = "UUID" ]]; then
         iniset $KEYSTONE_CONF token provider keystone.token.providers.uuid.Provider
diff --git a/lib/neutron b/lib/neutron
index 098a589..70417be 100644
--- a/lib/neutron
+++ b/lib/neutron
@@ -4,6 +4,7 @@
 # Dependencies:
 # ``functions`` file
 # ``DEST`` must be defined
+# ``STACK_USER`` must be defined
 
 # ``stack.sh`` calls the entry points in this order:
 #
@@ -206,6 +207,12 @@
 # Hardcoding for 1 service plugin for now
 source $TOP_DIR/lib/neutron_plugins/services/loadbalancer
 
+# Agent metering service plugin functions
+# -------------------------------------------
+
+# Hardcoding for 1 service plugin for now
+source $TOP_DIR/lib/neutron_plugins/services/metering
+
 # VPN service plugin functions
 # -------------------------------------------
 # Hardcoding for 1 service plugin for now
@@ -235,6 +242,9 @@
     if is_service_enabled q-lbaas; then
         _configure_neutron_lbaas
     fi
+    if is_service_enabled q-metering; then
+        _configure_neutron_metering
+    fi
     if is_service_enabled q-vpn; then
         _configure_neutron_vpn
     fi
@@ -456,6 +466,10 @@
     if is_service_enabled q-lbaas; then
         screen_it q-lbaas "cd $NEUTRON_DIR && python $AGENT_LBAAS_BINARY --config-file $NEUTRON_CONF --config-file=$LBAAS_AGENT_CONF_FILENAME"
     fi
+
+    if is_service_enabled q-metering; then
+        screen_it q-metering "cd $NEUTRON_DIR && python $AGENT_METERING_BINARY --config-file $NEUTRON_CONF --config-file $METERING_AGENT_CONF_FILENAME"
+    fi
 }
 
 # stop_neutron() - Stop running processes (non-screen)
@@ -636,6 +650,11 @@
     neutron_agent_lbaas_configure_agent
 }
 
+function _configure_neutron_metering() {
+    neutron_agent_metering_configure_common
+    neutron_agent_metering_configure_agent
+}
+
 function _configure_neutron_fwaas() {
     neutron_fwaas_configure_common
     neutron_fwaas_configure_driver
@@ -730,7 +749,7 @@
 
     # Set up the rootwrap sudoers for neutron
     TEMPFILE=`mktemp`
-    echo "$USER ALL=(root) NOPASSWD: $ROOTWRAP_SUDOER_CMD" >$TEMPFILE
+    echo "$STACK_USER ALL=(root) NOPASSWD: $ROOTWRAP_SUDOER_CMD" >$TEMPFILE
     chmod 0440 $TEMPFILE
     sudo chown root:root $TEMPFILE
     sudo mv $TEMPFILE /etc/sudoers.d/neutron-rootwrap
diff --git a/lib/neutron_plugins/midonet b/lib/neutron_plugins/midonet
index cf45a9d..e406146 100644
--- a/lib/neutron_plugins/midonet
+++ b/lib/neutron_plugins/midonet
@@ -32,23 +32,10 @@
 
 function neutron_plugin_configure_dhcp_agent() {
     DHCP_DRIVER=${DHCP_DRIVER:-"neutron.plugins.midonet.agent.midonet_driver.DhcpNoOpDriver"}
-    DHCP_INTERFACE_DRIVER=${DHCP_INTEFACE_DRIVER:-"neutron.plugins.midonet.agent.midonet_driver.MidonetInterfaceDriver"}
+    neutron_plugin_setup_interface_driver $Q_DHCP_CONF_FILE
     iniset $Q_DHCP_CONF_FILE DEFAULT dhcp_driver $DHCP_DRIVER
-    iniset $Q_DHCP_CONF_FILE DEFAULT interface_driver $DHCP_INTERFACE_DRIVER
     iniset $Q_DHCP_CONF_FILE DEFAULT use_namespaces True
     iniset $Q_DHCP_CONF_FILE DEFAULT enable_isolated_metadata True
-    if [[ "$MIDONET_API_URI" != "" ]]; then
-        iniset $Q_DHCP_CONF_FILE MIDONET midonet_uri "$MIDONET_API_URI"
-    fi
-    if [[ "$MIDONET_USERNAME" != "" ]]; then
-        iniset $Q_DHCP_CONF_FILE MIDONET username "$MIDONET_USERNAME"
-    fi
-    if [[ "$MIDONET_PASSWORD" != "" ]]; then
-        iniset $Q_DHCP_CONF_FILE MIDONET password "$MIDONET_PASSWORD"
-    fi
-    if [[ "$MIDONET_PROJECT_ID" != "" ]]; then
-        iniset $Q_DHCP_CONF_FILE MIDONET project_id "$MIDONET_PROJECT_ID"
-    fi
 }
 
 function neutron_plugin_configure_l3_agent() {
@@ -78,8 +65,8 @@
 }
 
 function neutron_plugin_setup_interface_driver() {
-    # May change in the future
-    :
+    local conf_file=$1
+    iniset $conf_file DEFAULT interface_driver neutron.agent.linux.interface.MidonetInterfaceDriver
 }
 
 function has_neutron_plugin_security_group() {
diff --git a/lib/neutron_plugins/nec b/lib/neutron_plugins/nec
index 3806c32..d8d8b7c 100644
--- a/lib/neutron_plugins/nec
+++ b/lib/neutron_plugins/nec
@@ -55,21 +55,26 @@
     _neutron_ovs_base_configure_l3_agent
 }
 
-function neutron_plugin_configure_plugin_agent() {
+function _quantum_plugin_setup_bridge() {
     if [[ "$SKIP_OVS_BRIDGE_SETUP" = "True" ]]; then
         return
     fi
     # Set up integration bridge
     _neutron_ovs_base_setup_bridge $OVS_BRIDGE
-    sudo ovs-vsctl --no-wait set-controller $OVS_BRIDGE tcp:$OFC_OFP_HOST:$OFC_OFP_PORT
     # Generate datapath ID from HOST_IP
-    local dpid=$(printf "0x%07d%03d%03d%03d\n" ${HOST_IP//./ })
+    local dpid=$(printf "%07d%03d%03d%03d\n" ${HOST_IP//./ })
     sudo ovs-vsctl --no-wait set Bridge $OVS_BRIDGE other-config:datapath-id=$dpid
     sudo ovs-vsctl --no-wait set-fail-mode $OVS_BRIDGE secure
+    sudo ovs-vsctl --no-wait set-controller $OVS_BRIDGE tcp:$OFC_OFP_HOST:$OFC_OFP_PORT
     if [ -n "$OVS_INTERFACE" ]; then
         sudo ovs-vsctl --no-wait -- --may-exist add-port $OVS_BRIDGE $OVS_INTERFACE
     fi
     _neutron_setup_ovs_tunnels $OVS_BRIDGE
+}
+
+function neutron_plugin_configure_plugin_agent() {
+    _quantum_plugin_setup_bridge
+
     AGENT_BINARY="$NEUTRON_BIN_DIR/neutron-nec-agent"
 
     _neutron_ovs_base_configure_firewall_driver
diff --git a/lib/neutron_plugins/services/metering b/lib/neutron_plugins/services/metering
new file mode 100644
index 0000000..629f3b7
--- /dev/null
+++ b/lib/neutron_plugins/services/metering
@@ -0,0 +1,30 @@
+# Neutron metering plugin
+# ---------------------------
+
+# Save trace setting
+MY_XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+
+AGENT_METERING_BINARY="$NEUTRON_BIN_DIR/neutron-metering-agent"
+METERING_PLUGIN="neutron.services.metering.metering_plugin.MeteringPlugin"
+
+function neutron_agent_metering_configure_common() {
+    if [[ $Q_SERVICE_PLUGIN_CLASSES == '' ]]; then
+        Q_SERVICE_PLUGIN_CLASSES=$METERING_PLUGIN
+    else
+        Q_SERVICE_PLUGIN_CLASSES="$Q_SERVICE_PLUGIN_CLASSES,$METERING_PLUGIN"
+    fi
+}
+
+function neutron_agent_metering_configure_agent() {
+    METERING_AGENT_CONF_PATH=/etc/neutron/services/metering
+    mkdir -p $METERING_AGENT_CONF_PATH
+
+    METERING_AGENT_CONF_FILENAME="$METERING_AGENT_CONF_PATH/metering_agent.ini"
+
+    cp $NEUTRON_DIR/etc/metering_agent.ini $METERING_AGENT_CONF_FILENAME
+}
+
+# Restore xtrace
+$MY_XTRACE
diff --git a/lib/neutron_thirdparty/trema b/lib/neutron_thirdparty/trema
index 5b5c459..9efd3f6 100644
--- a/lib/neutron_thirdparty/trema
+++ b/lib/neutron_thirdparty/trema
@@ -28,7 +28,7 @@
 TREMA_LOG_LEVEL=${TREMA_LOG_LEVEL:-info}
 
 TREMA_SS_CONFIG=$TREMA_SS_ETC_DIR/sliceable.conf
-TREMA_SS_APACHE_CONFIG=/etc/apache2/sites-available/sliceable_switch
+TREMA_SS_APACHE_CONFIG=/etc/apache2/sites-available/sliceable_switch.conf
 
 # configure_trema - Set config files, create data dirs, etc
 function configure_trema() {
diff --git a/lib/nova b/lib/nova
index 00f977d..6ab2000 100644
--- a/lib/nova
+++ b/lib/nova
@@ -73,9 +73,6 @@
 
 QEMU_CONF=/etc/libvirt/qemu.conf
 
-NOVNC_DIR=$DEST/noVNC
-SPICE_DIR=$DEST/spice-html5
-
 # Set default defaults here as some hypervisor drivers override these
 PUBLIC_INTERFACE_DEFAULT=br100
 GUEST_INTERFACE_DEFAULT=eth0
@@ -198,7 +195,7 @@
 
     # Set up the rootwrap sudoers for nova
     TEMPFILE=`mktemp`
-    echo "$USER ALL=(root) NOPASSWD: $ROOTWRAP_SUDOER_CMD" >$TEMPFILE
+    echo "$STACK_USER ALL=(root) NOPASSWD: $ROOTWRAP_SUDOER_CMD" >$TEMPFILE
     chmod 0440 $TEMPFILE
     sudo chown root:root $TEMPFILE
     sudo mv $TEMPFILE /etc/sudoers.d/nova-rootwrap
@@ -590,6 +587,30 @@
         install_nova_hypervisor
     fi
 
+    if is_service_enabled n-novnc; then
+        # a websockets/html5 or flash powered VNC console for vm instances
+        NOVNC_FROM_PACKAGE=`trueorfalse False $NOVNC_FROM_PACKAGE`
+        if [ "$NOVNC_FROM_PACKAGE" = "True" ]; then
+            NOVNC_WEB_DIR=/usr/share/novnc
+            install_package novnc
+        else
+            NOVNC_WEB_DIR=$DEST/noVNC
+            git_clone $NOVNC_REPO $NOVNC_WEB_DIR $NOVNC_BRANCH
+        fi
+    fi
+
+    if is_service_enabled n-spice; then
+        # a websockets/html5 or flash powered SPICE console for vm instances
+        SPICE_FROM_PACKAGE=`trueorfalse True $SPICE_FROM_PACKAGE`
+        if [ "$SPICE_FROM_PACKAGE" = "True" ]; then
+            SPICE_WEB_DIR=/usr/share/spice-html5
+            install_package spice-html5
+        else
+            SPICE_WEB_DIR=$DEST/spice-html5
+            git_clone $SPICE_REPO $SPICE_WEB_DIR $SPICE_BRANCH
+        fi
+    fi
+
     git_clone $NOVA_REPO $NOVA_DIR $NOVA_BRANCH
     setup_develop $NOVA_DIR
     sudo install -D -m 0644 -o $STACK_USER {$NOVA_DIR/tools/,/etc/bash_completion.d/}nova-manage.bash_completion
@@ -658,9 +679,9 @@
     screen_it n-sch "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-scheduler --config-file $compute_cell_conf"
     screen_it n-api-meta "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-api-metadata --config-file $compute_cell_conf"
 
-    screen_it n-novnc "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-novncproxy --config-file $api_cell_conf --web $NOVNC_DIR"
+    screen_it n-novnc "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-novncproxy --config-file $api_cell_conf --web $NOVNC_WEB_DIR"
     screen_it n-xvnc "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-xvpvncproxy --config-file $api_cell_conf"
-    screen_it n-spice "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-spicehtml5proxy --config-file $api_cell_conf --web $SPICE_DIR"
+    screen_it n-spice "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-spicehtml5proxy --config-file $api_cell_conf --web $SPICE_WEB_DIR"
     screen_it n-cauth "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-consoleauth --config-file $api_cell_conf"
 
     # Starting the nova-objectstore only if swift3 service is not enabled.
diff --git a/lib/nova_plugins/hypervisor-docker b/lib/nova_plugins/hypervisor-docker
index d7d453b..0153953 100644
--- a/lib/nova_plugins/hypervisor-docker
+++ b/lib/nova_plugins/hypervisor-docker
@@ -26,7 +26,6 @@
 
 # Set up default directories
 DOCKER_DIR=$DEST/docker
-DOCKER_BRANCH=${DOCKER_BRANCH:-master}
 
 DOCKER_UNIX_SOCKET=/var/run/docker.sock
 DOCKER_PID_FILE=/var/run/docker.pid
@@ -56,8 +55,6 @@
 function configure_nova_hypervisor() {
     iniset $NOVA_CONF DEFAULT compute_driver docker.DockerDriver
     iniset $GLANCE_API_CONF DEFAULT container_formats ami,ari,aki,bare,ovf,docker
-
-    sudo cp -p ${DOCKER_DIR}/nova-driver/docker.filters $NOVA_CONF_DIR/rootwrap.d
 }
 
 # install_nova_hypervisor() - Install external components
diff --git a/lib/nova_plugins/hypervisor-libvirt b/lib/nova_plugins/hypervisor-libvirt
index 6fae0b1..6f90f4a 100644
--- a/lib/nova_plugins/hypervisor-libvirt
+++ b/lib/nova_plugins/hypervisor-libvirt
@@ -7,6 +7,7 @@
 # Dependencies:
 # ``functions`` file
 # ``nova`` configuration
+# ``STACK_USER`` has to be defined
 
 # install_nova_hypervisor - install any external requirements
 # configure_nova_hypervisor - make configuration changes, including those to other services
@@ -68,7 +69,7 @@
             # 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
+Identity=unix-user:$STACK_USER
 Action=org.libvirt.unix.manage
 ResultAny=yes
 ResultInactive=yes
diff --git a/lib/nova_plugins/hypervisor-powervm b/lib/nova_plugins/hypervisor-powervm
deleted file mode 100644
index 561dd9f..0000000
--- a/lib/nova_plugins/hypervisor-powervm
+++ /dev/null
@@ -1,76 +0,0 @@
-# lib/nova_plugins/hypervisor-powervm
-# Configure the PowerVM hypervisor
-
-# Enable with:
-# VIRT_DRIVER=powervm
-
-# Dependencies:
-# ``functions`` file
-# ``nova`` configuration
-
-# install_nova_hypervisor - install any external requirements
-# configure_nova_hypervisor - make configuration changes, including those to other services
-# start_nova_hypervisor - start any external services
-# stop_nova_hypervisor - stop any external services
-# cleanup_nova_hypervisor - remove transient data and cache
-
-# Save trace setting
-MY_XTRACE=$(set +o | grep xtrace)
-set +o xtrace
-
-
-# Defaults
-# --------
-
-
-# Entry Points
-# ------------
-
-# clean_nova_hypervisor - Clean up an installation
-function cleanup_nova_hypervisor() {
-    # This function intentionally left blank
-    :
-}
-
-# configure_nova_hypervisor - Set config files, create data dirs, etc
-function configure_nova_hypervisor() {
-    POWERVM_MGR_TYPE=${POWERVM_MGR_TYPE:-"ivm"}
-    POWERVM_MGR_HOST=${POWERVM_MGR_HOST:-"powervm.host"}
-    POWERVM_MGR_USER=${POWERVM_MGR_USER:-"padmin"}
-    POWERVM_MGR_PASSWD=${POWERVM_MGR_PASSWD:-"password"}
-    POWERVM_IMG_REMOTE_PATH=${POWERVM_IMG_REMOTE_PATH:-"/tmp"}
-    POWERVM_IMG_LOCAL_PATH=${POWERVM_IMG_LOCAL_PATH:-"/tmp"}
-    iniset $NOVA_CONF DEFAULT compute_driver nova.virt.powervm.PowerVMDriver
-    iniset $NOVA_CONF DEFAULT powervm_mgr_type $POWERVM_MGR_TYPE
-    iniset $NOVA_CONF DEFAULT powervm_mgr $POWERVM_MGR_HOST
-    iniset $NOVA_CONF DEFAULT powervm_mgr_user $POWERVM_MGR_USER
-    iniset $NOVA_CONF DEFAULT powervm_mgr_passwd $POWERVM_MGR_PASSWD
-    iniset $NOVA_CONF DEFAULT powervm_img_remote_path $POWERVM_IMG_REMOTE_PATH
-    iniset $NOVA_CONF DEFAULT powervm_img_local_path $POWERVM_IMG_LOCAL_PATH
-}
-
-# install_nova_hypervisor() - Install external components
-function install_nova_hypervisor() {
-    # This function intentionally left blank
-    :
-}
-
-# start_nova_hypervisor - Start any required external services
-function start_nova_hypervisor() {
-    # This function intentionally left blank
-    :
-}
-
-# stop_nova_hypervisor - Stop any external services
-function stop_nova_hypervisor() {
-    # This function intentionally left blank
-    :
-}
-
-
-# Restore xtrace
-$MY_XTRACE
-
-# Local variables:
-# mode: shell-script
-# End:
diff --git a/lib/stackforge b/lib/stackforge
index 4b79de0..718b818 100644
--- a/lib/stackforge
+++ b/lib/stackforge
@@ -39,10 +39,10 @@
     cleanup_stackforge
 
     git_clone $WSME_REPO $WSME_DIR $WSME_BRANCH
-    setup_develop $WSME_DIR
+    setup_develop_no_requirements_update $WSME_DIR
 
     git_clone $PECAN_REPO $PECAN_DIR $PECAN_BRANCH
-    setup_develop $PECAN_DIR
+    setup_develop_no_requirements_update $PECAN_DIR
 }
 
 # cleanup_stackforge() - purge possibly old versions of stackforge libraries
diff --git a/lib/swift b/lib/swift
index b46537f..c103b5b 100644
--- a/lib/swift
+++ b/lib/swift
@@ -59,9 +59,9 @@
 # kilobytes.
 # Default is 1 gigabyte.
 SWIFT_LOOPBACK_DISK_SIZE_DEFAULT=1G
-# if tempest enabled the default size is 4 Gigabyte.
+# if tempest enabled the default size is 6 Gigabyte.
 if is_service_enabled tempest; then
-    SWIFT_LOOPBACK_DISK_SIZE_DEFAULT=${SWIFT_LOOPBACK_DISK_SIZE:-4G}
+    SWIFT_LOOPBACK_DISK_SIZE_DEFAULT=${SWIFT_LOOPBACK_DISK_SIZE:-6G}
 fi
 
 SWIFT_LOOPBACK_DISK_SIZE=${SWIFT_LOOPBACK_DISK_SIZE:-$SWIFT_LOOPBACK_DISK_SIZE_DEFAULT}
@@ -225,7 +225,7 @@
     swift-init --run-dir=${SWIFT_DATA_DIR}/run all stop || true
 
     sudo mkdir -p ${SWIFT_CONF_DIR}/{object,container,account}-server
-    sudo chown -R $USER: ${SWIFT_CONF_DIR}
+    sudo chown -R ${STACK_USER}: ${SWIFT_CONF_DIR}
 
     if [[ "$SWIFT_CONF_DIR" != "/etc/swift" ]]; then
         # Some swift tools are hard-coded to use ``/etc/swift`` and are apparently not going to be fixed.
@@ -238,7 +238,7 @@
     # setup) we configure it with our version of rsync.
     sed -e "
         s/%GROUP%/${USER_GROUP}/;
-        s/%USER%/$USER/;
+        s/%USER%/${STACK_USER}/;
         s,%SWIFT_DATA_DIR%,$SWIFT_DATA_DIR,;
     " $FILES/swift/rsyncd.conf | sudo tee /etc/rsyncd.conf
     # rsyncd.conf just prepared for 4 nodes
@@ -252,7 +252,7 @@
     cp ${SWIFT_DIR}/etc/proxy-server.conf-sample ${SWIFT_CONFIG_PROXY_SERVER}
 
     iniuncomment ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT user
-    iniset ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT user ${USER}
+    iniset ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT user ${STACK_USER}
 
     iniuncomment ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT swift_dir
     iniset ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT swift_dir ${SWIFT_CONF_DIR}
@@ -266,6 +266,15 @@
     iniuncomment ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT bind_port
     iniset ${SWIFT_CONFIG_PROXY_SERVER} DEFAULT bind_port ${SWIFT_DEFAULT_BIND_PORT:-8080}
 
+    # Devstack is commonly run in a small slow environment, so bump the
+    # timeouts up.
+    # node_timeout is how long between read operations a node takes to
+    # respond to the proxy server
+    # conn_timeout is all about how long it takes a connect() system call to
+    # return
+    iniset ${SWIFT_CONFIG_PROXY_SERVER} app:proxy-server node_timeout 120
+    iniset ${SWIFT_CONFIG_PROXY_SERVER} app:proxy-server conn_timeout 20
+
     # Configure Ceilometer
     if is_service_enabled ceilometer; then
         iniset ${SWIFT_CONFIG_PROXY_SERVER} filter:ceilometer use "egg:ceilometer#swift"
@@ -339,7 +348,7 @@
         node_path=${SWIFT_DATA_DIR}/${node_number}
 
         iniuncomment ${swift_node_config} DEFAULT user
-        iniset ${swift_node_config} DEFAULT user ${USER}
+        iniset ${swift_node_config} DEFAULT user ${STACK_USER}
 
         iniuncomment ${swift_node_config} DEFAULT bind_port
         iniset ${swift_node_config} DEFAULT bind_port ${bind_port}
@@ -410,7 +419,7 @@
     swift_log_dir=${SWIFT_DATA_DIR}/logs
     rm -rf ${swift_log_dir}
     mkdir -p ${swift_log_dir}/hourly
-    sudo chown -R $USER:adm ${swift_log_dir}
+    sudo chown -R ${STACK_USER}:adm ${swift_log_dir}
     sed "s,%SWIFT_LOGDIR%,${swift_log_dir}," $FILES/swift/rsyslog.conf | sudo \
         tee /etc/rsyslog.d/10-swift.conf
     if is_apache_enabled_service swift; then
@@ -425,9 +434,9 @@
     # First do a bit of setup by creating the directories and
     # changing the permissions so we can run it as our user.
 
-    USER_GROUP=$(id -g)
+    USER_GROUP=$(id -g ${STACK_USER})
     sudo mkdir -p ${SWIFT_DATA_DIR}/{drives,cache,run,logs}
-    sudo chown -R $USER:${USER_GROUP} ${SWIFT_DATA_DIR}
+    sudo chown -R ${STACK_USER}:${USER_GROUP} ${SWIFT_DATA_DIR}
 
     # Create a loopback disk and format it to XFS.
     if [[ -e ${SWIFT_DISK_IMAGE} ]]; then
@@ -439,7 +448,7 @@
 
     mkdir -p ${SWIFT_DATA_DIR}/drives/images
     sudo touch ${SWIFT_DISK_IMAGE}
-    sudo chown $USER: ${SWIFT_DISK_IMAGE}
+    sudo chown ${STACK_USER}: ${SWIFT_DISK_IMAGE}
 
     truncate -s ${SWIFT_LOOPBACK_DISK_SIZE} ${SWIFT_DISK_IMAGE}
 
@@ -462,9 +471,9 @@
         node_device=${node}/sdb1
         [[ -d $node ]] && continue
         [[ -d $drive ]] && continue
-        sudo install -o ${USER} -g $USER_GROUP -d $drive
-        sudo install -o ${USER} -g $USER_GROUP -d $node_device
-        sudo chown -R $USER: ${node}
+        sudo install -o ${STACK_USER} -g $USER_GROUP -d $drive
+        sudo install -o ${STACK_USER} -g $USER_GROUP -d $node_device
+        sudo chown -R ${STACK_USER}: ${node}
     done
 }
 # create_swift_accounts() - Set up standard swift accounts and extra
diff --git a/lib/tempest b/lib/tempest
index ec1fc90..803b740 100644
--- a/lib/tempest
+++ b/lib/tempest
@@ -73,12 +73,14 @@
     local password
     local line
     local flavors
+    local available_flavors
     local flavors_ref
     local flavor_lines
     local public_network_id
     local public_router_id
     local tenant_networks_reachable
     local boto_instance_type="m1.tiny"
+    local ssh_connect_method="fixed"
 
     # TODO(afazekas):
     # sudo python setup.py deploy
@@ -142,10 +144,15 @@
     # If the ``DEFAULT_INSTANCE_TYPE`` not declared, use the new behavior
     # Tempest creates instane types for himself
     if  [[ -z "$DEFAULT_INSTANCE_TYPE" ]]; then
-        nova flavor-create m1.nano 42 64 0 1
+        available_flavors=$(nova flavor-list)
+        if [[ ! ( $available_flavors =~ 'm1.nano' ) ]]; then
+            nova flavor-create m1.nano 42 64 0 1
+        fi
         flavor_ref=42
         boto_instance_type=m1.nano
-        nova flavor-create m1.micro 84 128 0 1
+        if [[ ! ( $available_flavors =~ 'm1.micro' ) ]]; then
+            nova flavor-create m1.micro 84 128 0 1
+        fi
         flavor_ref_alt=84
     else
         # Check Nova for existing flavors and, if set, look for the
@@ -186,10 +193,13 @@
 
     if [ "$Q_USE_NAMESPACE" != "False" ]; then
         tenant_networks_reachable=false
+        ssh_connect_method="floating"
     else
         tenant_networks_reachable=true
     fi
 
+    ssh_connect_method=${TEMPEST_SSH_CONNECT_METHOD:-$ssh_connect_method}
+
     if is_service_enabled q-l3; then
         public_network_id=$(neutron net-list | grep $PUBLIC_NETWORK_NAME | \
             awk '{print $2}')
@@ -252,6 +262,7 @@
     iniset $TEMPEST_CONF compute flavor_ref_alt $flavor_ref_alt
     iniset $TEMPEST_CONF compute live_migration_available ${LIVE_MIGRATION_AVAILABLE:-False}
     iniset $TEMPEST_CONF compute use_block_migration_for_live_migration ${USE_BLOCK_MIGRATION_FOR_LIVE_MIGRATION:-False}
+    iniset $TEMPEST_CONF compute ssh_connect_method $ssh_connect_method
 
     # Compute admin
     iniset $TEMPEST_CONF "compute-admin" password "$password" # DEPRECATED
@@ -300,7 +311,7 @@
     iniset $TEMPEST_CONF cli cli_dir $NOVA_BIN_DIR
 
     # service_available
-    for service in nova cinder glance neutron swift heat horizon ceilometer; do
+    for service in nova cinder glance neutron swift heat horizon ceilometer ironic savanna; do
         if is_service_enabled $service ; then
             iniset $TEMPEST_CONF service_available $service "True"
         else
diff --git a/openrc b/openrc
index 5344d24..804bb3f 100644
--- a/openrc
+++ b/openrc
@@ -81,3 +81,8 @@
 export NOVA_VERSION=${NOVA_VERSION:-1.1}
 # In the future this will change names:
 export COMPUTE_API_VERSION=${COMPUTE_API_VERSION:-$NOVA_VERSION}
+
+# Currently cinderclient needs you to specify the *volume api* version. This
+# needs to match the config of your catalog returned by Keystone.
+export CINDER_VERSION=${CINDER_VERSION:-2}
+export OS_VOLUME_API_VERSION=${OS_VOLUME_API_VERSION:-$CINDER_VERSION}
diff --git a/stack.sh b/stack.sh
index 36312ea..47d93bd 100755
--- a/stack.sh
+++ b/stack.sh
@@ -694,16 +694,6 @@
     configure_nova
 fi
 
-if is_service_enabled n-novnc; then
-    # a websockets/html5 or flash powered VNC console for vm instances
-    git_clone $NOVNC_REPO $NOVNC_DIR $NOVNC_BRANCH
-fi
-
-if is_service_enabled n-spice; then
-    # a websockets/html5 or flash powered SPICE console for vm instances
-    git_clone $SPICE_REPO $SPICE_DIR $SPICE_BRANCH
-fi
-
 if is_service_enabled horizon; then
     # dashboard
     install_horizon
diff --git a/tools/build_docs.sh b/tools/build_docs.sh
index 8dca524..c566e63 100755
--- a/tools/build_docs.sh
+++ b/tools/build_docs.sh
@@ -100,8 +100,9 @@
 # Assumption is we are now in the DevStack repo workspace to be processed
 
 # Pull the latest docs branch from devstack.org repo
-rm -rf docs || true
-git clone -b gh-pages $GH_PAGES_REPO docs
+if ! [ -d docs ]; then
+    git clone -b gh-pages $GH_PAGES_REPO docs
+fi
 
 # Build list of scripts to process
 FILES=""
diff --git a/tools/build_ramdisk.sh b/tools/build_ramdisk.sh
index 3d9f76f..7372555 100755
--- a/tools/build_ramdisk.sh
+++ b/tools/build_ramdisk.sh
@@ -22,7 +22,7 @@
         umount $MNTDIR
         rmdir $MNTDIR
     fi
-    if [ -n "$DEV_FILE_TMP" -a -e "$DEV_FILE_TMP "]; then
+    if [ -n "$DEV_FILE_TMP" -a -e "$DEV_FILE_TMP" ]; then
         rm -f $DEV_FILE_TMP
     fi
     if [ -n "$IMG_FILE_TMP" -a -e "$IMG_FILE_TMP" ]; then
diff --git a/tools/fixup_stuff.sh b/tools/fixup_stuff.sh
index 325a6d6..5fb47dc 100755
--- a/tools/fixup_stuff.sh
+++ b/tools/fixup_stuff.sh
@@ -51,7 +51,7 @@
 
 # Fix prettytable 0.7.2 permissions
 # Don't specify --upgrade so we use the existing package if present
-pip_install prettytable
+pip_install 'prettytable>0.7'
 PACKAGE_DIR=$(get_package_path prettytable)
 # Only fix version 0.7.2
 dir=$(echo $PACKAGE_DIR/prettytable-0.7.2*)
@@ -76,8 +76,7 @@
 if [[ $DISTRO =~ (rhel6) ]]; then
 
     # Disable selinux to avoid configuring to allow Apache access
-    # to Horizon files or run nodejs (LP#1175444)
-    # FIXME(dtroyer): see if this can be skipped without node or if Horizon is not enabled
+    # to Horizon files (LP#1175444)
     if selinuxenabled; then
         sudo setenforce 0
     fi
diff --git a/tools/xen/functions b/tools/xen/functions
index b0b077d..563303d 100644
--- a/tools/xen/functions
+++ b/tools/xen/functions
@@ -137,14 +137,14 @@
     local name_label
     name_label=$1
 
-    ! [ -z $(xe network-list name-label="$name_label" --minimal) ]
+    ! [ -z "$(xe network-list name-label="$name_label" --minimal)" ]
 }
 
 function _bridge_exists() {
     local bridge
     bridge=$1
 
-    ! [ -z $(xe network-list bridge="$bridge" --minimal) ]
+    ! [ -z "$(xe network-list bridge="$bridge" --minimal)" ]
 }
 
 function _network_uuid() {
diff --git a/tools/xen/install_os_domU.sh b/tools/xen/install_os_domU.sh
index 33dc26f..6ce334b 100755
--- a/tools/xen/install_os_domU.sh
+++ b/tools/xen/install_os_domU.sh
@@ -111,12 +111,15 @@
 fi
 
 if parameter_is_specified "FLAT_NETWORK_BRIDGE"; then
-    cat >&2 << EOF
-ERROR: FLAT_NETWORK_BRIDGE is specified in localrc file
-This is considered as an error, as its value will be derived from the
-VM_BRIDGE_OR_NET_NAME variable's value.
+    if [ "$(bridge_for "$VM_BRIDGE_OR_NET_NAME")" != "$(bridge_for "$FLAT_NETWORK_BRIDGE")" ]; then
+        cat >&2 << EOF
+ERROR: FLAT_NETWORK_BRIDGE is specified in localrc file, and either no network
+found on XenServer by searching for networks by that value as name-label or
+bridge name or the network found does not match the network specified by
+VM_BRIDGE_OR_NET_NAME. Please check your localrc file.
 EOF
-    exit 1
+        exit 1
+    fi
 fi
 
 if ! xenapi_is_listening_on "$MGT_BRIDGE_OR_NET_NAME"; then
@@ -310,7 +313,7 @@
         "xen_integration_bridge=${XEN_INTEGRATION_BRIDGE}"
 fi
 
-FLAT_NETWORK_BRIDGE=$(bridge_for "$VM_BRIDGE_OR_NET_NAME")
+FLAT_NETWORK_BRIDGE="${FLAT_NETWORK_BRIDGE:-$(bridge_for "$VM_BRIDGE_OR_NET_NAME")}"
 append_kernel_cmdline "$GUEST_NAME" "flat_network_bridge=${FLAT_NETWORK_BRIDGE}"
 
 # Add a separate xvdb, if it was requested