Merge "Enable devstack for Ubuntu 15.10 Wily"
diff --git a/Makefile b/Makefile
index a6bb230..a94d60a 100644
--- a/Makefile
+++ b/Makefile
@@ -13,7 +13,6 @@
 
 # Duplicated from stackrc for now
 DEST=/opt/stack
-WHEELHOUSE=$(DEST)/.wheelhouse
 
 all:
 	echo "This just saved you from a terrible mistake!"
@@ -25,9 +24,6 @@
 unstack:
 	./unstack.sh
 
-wheels:
-	WHEELHOUSE=$(WHEELHOUSE) tools/build_wheels.sh
-
 docs:
 	tox -edocs
 
@@ -57,7 +53,7 @@
 
 # Clean out the cache too
 realclean: clean
-	rm -rf files/cirros*.tar.gz files/Fedora*.qcow2 $(WHEELHOUSE)
+	rm -rf files/cirros*.tar.gz files/Fedora*.qcow2
 
 # Repo stuffs
 
diff --git a/doc/source/faq.rst b/doc/source/faq.rst
index 3562bfa..7aca8d0 100644
--- a/doc/source/faq.rst
+++ b/doc/source/faq.rst
@@ -54,7 +54,7 @@
 releases other than those documented in ``README.md`` on a best-effort
 basis.
 
-Are there any differences between Ubuntu and Centos/Fedora support?
+Are there any differences between Ubuntu and CentOS/Fedora support?
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
 Both should work well and are tested by DevStack CI.
@@ -146,7 +146,7 @@
 
 
 Upstream DevStack is only tested with master and stable
-branches. Setting custom BRANCH definitions is not guarunteed to
+branches. Setting custom BRANCH definitions is not guaranteed to
 produce working results.
 
 What can I do about RabbitMQ not wanting to start on my fresh new VM?
diff --git a/doc/source/index.rst b/doc/source/index.rst
index 99e96b1..b65730f 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -206,7 +206,6 @@
 
 * `tools/build\_docs.sh <tools/build_docs.sh.html>`__
 * `tools/build\_venv.sh <tools/build_venv.sh.html>`__
-* `tools/build\_wheels.sh <tools/build_wheels.sh.html>`__
 * `tools/create-stack-user.sh <tools/create-stack-user.sh.html>`__
 * `tools/create\_userrc.sh <tools/create_userrc.sh.html>`__
 * `tools/fixup\_stuff.sh <tools/fixup_stuff.sh.html>`__
diff --git a/exercises/client-args.sh b/exercises/client-args.sh
index c33ef44..7cfef1c 100755
--- a/exercises/client-args.sh
+++ b/exercises/client-args.sh
@@ -41,7 +41,6 @@
 unset NOVA_REGION_NAME
 unset NOVA_URL
 unset NOVA_USERNAME
-unset NOVA_VERSION
 
 # Save the known variables for later
 export x_TENANT_NAME=$OS_TENANT_NAME
diff --git a/exercises/client-env.sh b/exercises/client-env.sh
index 4a0609a..1d2f4f5 100755
--- a/exercises/client-env.sh
+++ b/exercises/client-env.sh
@@ -41,7 +41,6 @@
 unset NOVA_REGION_NAME
 unset NOVA_URL
 unset NOVA_USERNAME
-unset NOVA_VERSION
 
 for i in OS_TENANT_NAME OS_USERNAME OS_PASSWORD OS_AUTH_URL; do
     is_set $i
@@ -101,9 +100,6 @@
             STATUS_EC2="Failed"
             RETURN=1
         fi
-
-        # Clean up side effects
-        unset NOVA_VERSION
     fi
 fi
 
diff --git a/files/apache-keystone.template b/files/apache-keystone.template
index 4d3d2d6..f9fa265 100644
--- a/files/apache-keystone.template
+++ b/files/apache-keystone.template
@@ -2,6 +2,16 @@
 Listen %ADMINPORT%
 LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\" %D(us)" keystone_combined
 
+<Directory %KEYSTONE_BIN%>
+    <IfVersion >= 2.4>
+        Require all granted
+    </IfVersion>
+    <IfVersion < 2.4>
+        Order allow,deny
+        Allow from all
+    </IfVersion>
+</Directory>
+
 <VirtualHost *:%PUBLICPORT%>
     WSGIDaemonProcess keystone-public processes=5 threads=1 user=%USER% display-name=%{GROUP} %VIRTUALENV%
     WSGIProcessGroup keystone-public
@@ -16,16 +26,6 @@
     %SSLENGINE%
     %SSLCERTFILE%
     %SSLKEYFILE%
-
-    <Directory %KEYSTONE_BIN%>
-        <IfVersion >= 2.4>
-            Require all granted
-        </IfVersion>
-        <IfVersion < 2.4>
-            Order allow,deny
-            Allow from all
-        </IfVersion>
-    </Directory>
 </VirtualHost>
 
 <VirtualHost *:%ADMINPORT%>
@@ -42,19 +42,9 @@
     %SSLENGINE%
     %SSLCERTFILE%
     %SSLKEYFILE%
-
-    <Directory %KEYSTONE_BIN%>
-        <IfVersion >= 2.4>
-            Require all granted
-        </IfVersion>
-        <IfVersion < 2.4>
-            Order allow,deny
-            Allow from all
-        </IfVersion>
-    </Directory>
 </VirtualHost>
 
-Alias /identity %PUBLICWSGI%
+Alias /identity %KEYSTONE_BIN%/keystone-wsgi-public
 <Location /identity>
     SetHandler wsgi-script
     Options +ExecCGI
@@ -64,7 +54,7 @@
     WSGIPassAuthorization On
 </Location>
 
-Alias /identity_admin %ADMINWSGI%
+Alias /identity_admin %KEYSTONE_BIN%/keystone-wsgi-admin
 <Location /identity_admin>
     SetHandler wsgi-script
     Options +ExecCGI
diff --git a/files/debs/general b/files/debs/general
index 1460526..80e81f5 100644
--- a/files/debs/general
+++ b/files/debs/general
@@ -20,8 +20,10 @@
 python-gdbm # needed for testr
 bc
 libyaml-dev
-libffi-dev
+libffi-dev # for pyOpenSSL
 libssl-dev # for pyOpenSSL
+libxml2-dev  # lxml
+libxslt1-dev  # lxml
 gettext  # used for compiling message catalogs
 openjdk-7-jre-headless  # NOPRIME
 pkg-config
diff --git a/files/debs/keystone b/files/debs/keystone
index 70a5649..f5816b5 100644
--- a/files/debs/keystone
+++ b/files/debs/keystone
@@ -1,4 +1,3 @@
-python-lxml
 sqlite3
 python-mysqldb
 python-mysql.connector
diff --git a/files/debs/n-novnc b/files/debs/n-novnc
deleted file mode 100644
index c8722b9..0000000
--- a/files/debs/n-novnc
+++ /dev/null
@@ -1 +0,0 @@
-python-numpy
diff --git a/files/debs/nova b/files/debs/nova
index 346b8b3..d1678a7 100644
--- a/files/debs/nova
+++ b/files/debs/nova
@@ -8,7 +8,8 @@
 mysql-server # NOPRIME
 python-mysqldb
 python-mysql.connector
-python-lxml # needed for glance which is needed for nova --- this shouldn't be here
+libxml2-dev # needed for building lxml
+libxslt1-dev
 gawk
 iptables
 ebtables
@@ -25,7 +26,3 @@
 genisoimage # required for config_drive
 rabbitmq-server # NOPRIME
 socat # used by ajaxterm
-python-libvirt # NOPRIME
-python-libxml2
-python-numpy # used by websockify for spice console
-python-m2crypto
diff --git a/files/debs/zookeeper b/files/debs/zookeeper
new file mode 100644
index 0000000..66227f7
--- /dev/null
+++ b/files/debs/zookeeper
@@ -0,0 +1 @@
+zookeeperd
\ No newline at end of file
diff --git a/files/rpms/zookeeper b/files/rpms/zookeeper
new file mode 100644
index 0000000..c0d1c30
--- /dev/null
+++ b/files/rpms/zookeeper
@@ -0,0 +1 @@
+zookeeper
\ No newline at end of file
diff --git a/files/venv-requirements.txt b/files/venv-requirements.txt
deleted file mode 100644
index b9a55b4..0000000
--- a/files/venv-requirements.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-# Once we can prebuild wheels before a devstack run, uncomment the skipped libraries
-cryptography
-# lxml # still install from from packages
-# netifaces # still install from packages
-#numpy    # slowest wheel by far, stop building until we are actually using the output
-posix-ipc
-# psycopg # still install from packages
-pycrypto
-pyOpenSSL
-PyYAML
-xattr
diff --git a/files/zookeeper/environment b/files/zookeeper/environment
new file mode 100644
index 0000000..afa2d2f
--- /dev/null
+++ b/files/zookeeper/environment
@@ -0,0 +1,36 @@
+#
+# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# Modified from http://packages.ubuntu.com/saucy/zookeeperd
+NAME=zookeeper
+ZOOCFGDIR=/etc/zookeeper/conf
+
+# seems, that log4j requires the log4j.properties file to be in the classpath
+CLASSPATH="$ZOOCFGDIR:/usr/share/java/jline.jar:/usr/share/java/log4j-1.2.jar:/usr/share/java/xercesImpl.jar:/usr/share/java/xmlParserAPIs.jar:/usr/share/java/netty.jar:/usr/share/java/slf4j-api.jar:/usr/share/java/slf4j-log4j12.jar:/usr/share/java/zookeeper.jar"
+
+ZOOCFG="$ZOOCFGDIR/zoo.cfg"
+ZOO_LOG_DIR=/var/log/zookeeper
+USER=$NAME
+GROUP=$NAME
+PIDDIR=/var/run/$NAME
+PIDFILE=$PIDDIR/$NAME.pid
+SCRIPTNAME=/etc/init.d/$NAME
+JAVA=/usr/bin/java
+ZOOMAIN="org.apache.zookeeper.server.quorum.QuorumPeerMain"
+ZOO_LOG4J_PROP="INFO,ROLLINGFILE"
+JMXLOCALONLY=false
+JAVA_OPTS=""
diff --git a/files/zookeeper/log4j.properties b/files/zookeeper/log4j.properties
new file mode 100644
index 0000000..6c45a4a
--- /dev/null
+++ b/files/zookeeper/log4j.properties
@@ -0,0 +1,69 @@
+#
+# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# From http://packages.ubuntu.com/saucy/zookeeperd
+
+# ZooKeeper Logging Configuration
+#
+
+# Format is "<default threshold> (, <appender>)+
+
+log4j.rootLogger=${zookeeper.root.logger}
+
+# Example: console appender only
+# log4j.rootLogger=INFO, CONSOLE
+
+# Example with rolling log file
+#log4j.rootLogger=DEBUG, CONSOLE, ROLLINGFILE
+
+# Example with rolling log file and tracing
+#log4j.rootLogger=TRACE, CONSOLE, ROLLINGFILE, TRACEFILE
+
+#
+# Log INFO level and above messages to the console
+#
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.Threshold=INFO
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} - %-5p [%t:%C{1}@%L] - %m%n
+
+#
+# Add ROLLINGFILE to rootLogger to get log file output
+#    Log DEBUG level and above messages to a log file
+log4j.appender.ROLLINGFILE=org.apache.log4j.RollingFileAppender
+log4j.appender.ROLLINGFILE.Threshold=WARN
+log4j.appender.ROLLINGFILE.File=${zookeeper.log.dir}/zookeeper.log
+
+# Max log file size of 10MB
+log4j.appender.ROLLINGFILE.MaxFileSize=10MB
+# uncomment the next line to limit number of backup files
+#log4j.appender.ROLLINGFILE.MaxBackupIndex=10
+
+log4j.appender.ROLLINGFILE.layout=org.apache.log4j.PatternLayout
+log4j.appender.ROLLINGFILE.layout.ConversionPattern=%d{ISO8601} - %-5p [%t:%C{1}@%L] - %m%n
+
+
+#
+# Add TRACEFILE to rootLogger to get log file output
+#    Log DEBUG level and above messages to a log file
+log4j.appender.TRACEFILE=org.apache.log4j.FileAppender
+log4j.appender.TRACEFILE.Threshold=TRACE
+log4j.appender.TRACEFILE.File=${zookeeper.log.dir}/zookeeper_trace.log
+
+log4j.appender.TRACEFILE.layout=org.apache.log4j.PatternLayout
+### Notice we are including log4j's NDC here (%x)
+log4j.appender.TRACEFILE.layout.ConversionPattern=%d{ISO8601} - %-5p [%t:%C{1}@%L][%x] - %m%n
diff --git a/files/zookeeper/myid b/files/zookeeper/myid
new file mode 100644
index 0000000..c227083
--- /dev/null
+++ b/files/zookeeper/myid
@@ -0,0 +1 @@
+0
\ No newline at end of file
diff --git a/files/zookeeper/zoo.cfg b/files/zookeeper/zoo.cfg
new file mode 100644
index 0000000..b8f5582
--- /dev/null
+++ b/files/zookeeper/zoo.cfg
@@ -0,0 +1,74 @@
+#
+# (C) Copyright 2015 Hewlett Packard Enterprise Development Company LP
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# http://hadoop.apache.org/zookeeper/docs/current/zookeeperAdmin.html
+
+# The number of milliseconds of each tick
+tickTime=2000
+# The number of ticks that the initial
+# synchronization phase can take
+initLimit=10
+# The number of ticks that can pass between
+# sending a request and getting an acknowledgement
+syncLimit=5
+# the directory where the snapshot is stored.
+dataDir=/var/lib/zookeeper
+# Place the dataLogDir to a separate physical disc for better performance
+# dataLogDir=/disk2/zookeeper
+
+# the port at which the clients will connect
+clientPort=2181
+
+# Maximum number of clients that can connect from one client
+maxClientCnxns=60
+
+# specify all zookeeper servers
+# The fist port is used by followers to connect to the leader
+# The second one is used for leader election
+
+server.0=127.0.0.1:2888:3888
+
+# To avoid seeks ZooKeeper allocates space in the transaction log file in
+# blocks of preAllocSize kilobytes. The default block size is 64M. One reason
+# for changing the size of the blocks is to reduce the block size if snapshots
+# are taken more often. (Also, see snapCount).
+#preAllocSize=65536
+
+# Clients can submit requests faster than ZooKeeper can process them,
+# especially if there are a lot of clients. To prevent ZooKeeper from running
+# out of memory due to queued requests, ZooKeeper will throttle clients so that
+# there is no more than globalOutstandingLimit outstanding requests in the
+# system. The default limit is 1,000.ZooKeeper logs transactions to a
+# transaction log. After snapCount transactions are written to a log file a
+# snapshot is started and a new transaction log file is started. The default
+# snapCount is 10,000.
+#snapCount=1000
+
+# If this option is defined, requests will be will logged to a trace file named
+# traceFile.year.month.day.
+#traceFile=
+
+# Leader accepts client connections. Default value is "yes". The leader machine
+# coordinates updates. For higher update throughput at thes slight expense of
+# read throughput the leader can be configured to not accept clients and focus
+# on coordination.
+#leaderServes=yes
+
+# Autopurge every hour to avoid using lots of disk in bursts
+# Order of the next 2 properties matters.
+# autopurge.snapRetainCount must be before autopurge.purgeInterval.
+autopurge.snapRetainCount=3
+autopurge.purgeInterval=1
\ No newline at end of file
diff --git a/functions-common b/functions-common
index d36d323..497bed2 100644
--- a/functions-common
+++ b/functions-common
@@ -1163,7 +1163,7 @@
 
     if is_ubuntu; then
         local xtrace
-    xtrace=$(set +o | grep xtrace)
+        xtrace=$(set +o | grep xtrace)
         set +o xtrace
         if [[ "$REPOS_UPDATED" != "True" || "$RETRY_UPDATE" = "True" ]]; then
             # if there are transient errors pulling the updates, that's fine.
@@ -1775,11 +1775,17 @@
 # remove extra commas from the input string (i.e. ``ENABLED_SERVICES``)
 # _cleanup_service_list service-list
 function _cleanup_service_list {
+    local xtrace
+    xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+
     echo "$1" | sed -e '
         s/,,/,/g;
         s/^,//;
         s/,$//
     '
+
+    $xtrace
 }
 
 # disable_all_services() removes all current services
@@ -1797,6 +1803,10 @@
 # Uses global ``ENABLED_SERVICES``
 # disable_negated_services
 function disable_negated_services {
+    local xtrace
+    xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+
     local to_remove=""
     local remaining=""
     local service
@@ -1814,6 +1824,8 @@
     # go through the service list.  if this service appears in the "to
     # be removed" list, drop it
     ENABLED_SERVICES=$(remove_disabled_services "$remaining" "$to_remove")
+
+    $xtrace
 }
 
 # disable_service() prepares the services passed as argument to be
@@ -1825,6 +1837,10 @@
 # Uses global ``DISABLED_SERVICES``
 # disable_service service [service ...]
 function disable_service {
+    local xtrace
+    xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+
     local disabled_svcs="${DISABLED_SERVICES}"
     local enabled_svcs=",${ENABLED_SERVICES},"
     local service
@@ -1836,6 +1852,8 @@
     done
     DISABLED_SERVICES=$(_cleanup_service_list "$disabled_svcs")
     ENABLED_SERVICES=$(_cleanup_service_list "$enabled_svcs")
+
+    $xtrace
 }
 
 # enable_service() adds the services passed as argument to the
@@ -1849,6 +1867,10 @@
 # Uses global ``ENABLED_SERVICES``
 # enable_service service [service ...]
 function enable_service {
+    local xtrace
+    xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+
     local tmpsvcs="${ENABLED_SERVICES}"
     local service
     for service in $@; do
@@ -1862,6 +1884,8 @@
     done
     ENABLED_SERVICES=$(_cleanup_service_list "$tmpsvcs")
     disable_negated_services
+
+    $xtrace
 }
 
 # is_service_enabled() checks if the service(s) specified as arguments are
@@ -1890,6 +1914,7 @@
     local xtrace
     xtrace=$(set +o | grep xtrace)
     set +o xtrace
+
     local enabled=1
     local services=$@
     local service
@@ -1915,6 +1940,7 @@
         [[ ${service} == "swift" && ${ENABLED_SERVICES} =~ "s-" ]] && enabled=0
         [[ ${service} == s-* && ${ENABLED_SERVICES} =~ "swift" ]] && enabled=0
     done
+
     $xtrace
     return $enabled
 }
@@ -1922,6 +1948,10 @@
 # remove specified list from the input string
 # remove_disabled_services service-list remove-list
 function remove_disabled_services {
+    local xtrace
+    xtrace=$(set +o | grep xtrace)
+    set +o xtrace
+
     local service_list=$1
     local remove_list=$2
     local service
@@ -1940,6 +1970,9 @@
             enabled="${enabled},$service"
         fi
     done
+
+    $xtrace
+
     _cleanup_service_list "$enabled"
 }
 
diff --git a/inc/meta-config b/inc/meta-config
index d74db59..b9ab6b2 100644
--- a/inc/meta-config
+++ b/inc/meta-config
@@ -92,7 +92,7 @@
     local real_configfile
     real_configfile=$(eval echo $configfile)
     if [ ! -f $real_configfile ]; then
-        touch $real_configfile
+        touch $real_configfile || die $LINENO "could not create config file $real_configfile ($configfile)"
     fi
 
     get_meta_section $file $matchgroup $configfile | \
@@ -178,8 +178,18 @@
     local configfile group
     for group in $matchgroups; do
         for configfile in $(get_meta_section_files $localfile $group); do
-            if [[ -d $(dirname $(eval "echo $configfile")) ]]; then
+            local realconfigfile
+            local dir
+
+            realconfigfile=$(eval "echo $configfile")
+            if [[ -z $realconfigfile ]]; then
+                die $LINENO "bogus config file specification: $configfile is undefined"
+            fi
+            dir=$(dirname $realconfigfile)
+            if [[ -d $dir ]]; then
                 merge_config_file $localfile $group $configfile
+            else
+                die $LINENO "bogus config file specification $configfile ($configfile=$realconfigfile, $dir is not a directory)"
             fi
         done
     done
diff --git a/lib/ironic b/lib/ironic
index de07b49..d786870 100644
--- a/lib/ironic
+++ b/lib/ironic
@@ -795,7 +795,7 @@
     # load them into glance
     IRONIC_DEPLOY_KERNEL_ID=$(openstack \
         --os-token $token \
-        --os-url http://$GLANCE_HOSTPORT \
+        --os-url $GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT \
         image create \
         $(basename $IRONIC_DEPLOY_KERNEL_PATH) \
         --public --disk-format=aki \
@@ -803,7 +803,7 @@
         < $IRONIC_DEPLOY_KERNEL_PATH  | grep ' id ' | get_field 2)
     IRONIC_DEPLOY_RAMDISK_ID=$(openstack \
         --os-token $token \
-        --os-url http://$GLANCE_HOSTPORT \
+        --os-url $GLANCE_SERVICE_PROTOCOL://$GLANCE_HOSTPORT \
         image create \
         $(basename $IRONIC_DEPLOY_RAMDISK_PATH) \
         --public --disk-format=ari \
diff --git a/lib/zookeeper b/lib/zookeeper
new file mode 100644
index 0000000..e62ba8a
--- /dev/null
+++ b/lib/zookeeper
@@ -0,0 +1,86 @@
+#!/bin/bash
+#
+# lib/zookeeper
+# Functions to control the installation and configuration of **zookeeper**
+
+# Dependencies:
+#
+# - ``functions`` file
+
+# ``stack.sh`` calls the entry points in this order:
+#
+# - is_zookeeper_enabled
+# - install_zookeeper
+# - configure_zookeeper
+# - init_zookeeper
+# - start_zookeeper
+# - stop_zookeeper
+# - cleanup_zookeeper
+
+# Save trace setting
+XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+
+# Defaults
+# --------
+
+# <define global variables here that belong to this project>
+
+# Set up default directories
+ZOOKEEPER_DATA_DIR=$DEST/data/zookeeper
+ZOOKEEPER_CONF_DIR=/etc/zookeeper
+
+
+# Entry Points
+# ------------
+
+# Test if any zookeeper service us enabled
+# is_zookeeper_enabled
+function is_zookeeper_enabled {
+    [[ ,${ENABLED_SERVICES}, =~ ,"zookeeper", ]] && return 0
+    return 1
+}
+
+# cleanup_zookeeper() - Remove residual data files, anything left over from previous
+# runs that a clean run would need to clean up
+function cleanup_zookeeper {
+    sudo rm -rf $ZOOKEEPER_DATA_DIR
+}
+
+# configure_zookeeper() - Set config files, create data dirs, etc
+function configure_zookeeper {
+    sudo cp $FILES/zookeeper/* $ZOOKEEPER_CONF_DIR
+    sudo sed -i -e 's|.*dataDir.*|dataDir='$ZOOKEEPER_DATA_DIR'|' $ZOOKEEPER_CONF_DIR/zoo.cfg
+}
+
+# init_zookeeper() - Initialize databases, etc.
+function init_zookeeper {
+    # clean up from previous (possibly aborted) runs
+    # create required data files
+    sudo rm -rf $ZOOKEEPER_DATA_DIR
+    sudo mkdir -p $ZOOKEEPER_DATA_DIR
+}
+
+# install_zookeeper() - Collect source and prepare
+function install_zookeeper {
+    install_package zookeeperd
+}
+
+# start_zookeeper() - Start running processes, including screen
+function start_zookeeper {
+    start_service zookeeper
+}
+
+# stop_zookeeper() - Stop running processes (non-screen)
+function stop_zookeeper {
+    stop_service zookeeper
+}
+
+# Restore xtrace
+$XTRACE
+
+# Tell emacs to use shell-script-mode
+## Local variables:
+## mode: shell-script
+## End:
diff --git a/openrc b/openrc
index 71ba5a6..9bc0fd7 100644
--- a/openrc
+++ b/openrc
@@ -95,12 +95,6 @@
     fi
 fi
 
-# Currently novaclient needs you to specify the *compute api* version.  This
-# needs to match the config of your catalog returned by Keystone.
-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}
diff --git a/stack.sh b/stack.sh
index 72253f8..68b932e 100755
--- a/stack.sh
+++ b/stack.sh
@@ -539,6 +539,7 @@
 source $TOP_DIR/lib/neutron-legacy
 source $TOP_DIR/lib/ldap
 source $TOP_DIR/lib/dstat
+source $TOP_DIR/lib/zookeeper
 
 # Extras Source
 # --------------
@@ -716,12 +717,6 @@
 # Install required infra support libraries
 install_infra
 
-# Pre-build some problematic wheels
-if [[ -n ${WHEELHOUSE:-} && ! -d ${WHEELHOUSE:-} ]]; then
-    source $TOP_DIR/tools/build_wheels.sh
-fi
-
-
 # Extras Pre-install
 # ------------------
 # Phase: pre-install
@@ -729,6 +724,11 @@
 
 install_rpc_backend
 
+if is_service_enabled zookeeper; then
+    cleanup_zookeeper
+    configure_zookeeper
+    init_zookeeper
+fi
 if is_service_enabled $DATABASE_BACKENDS; then
     install_database
 fi
@@ -968,6 +968,15 @@
 start_dstat
 
 
+# Zookeeper
+# -----
+
+# zookeeper for use with tooz for Distributed Lock Management capabilities etc.,
+if is_service_enabled zookeeper; then
+    start_zookeeper
+fi
+
+
 # Keystone
 # --------
 
diff --git a/stackrc b/stackrc
index 819aa01..3033b27 100644
--- a/stackrc
+++ b/stackrc
@@ -69,7 +69,7 @@
     # Dashboard
     ENABLED_SERVICES+=,horizon
     # Additional services
-    ENABLED_SERVICES+=,rabbit,tempest,mysql,dstat
+    ENABLED_SERVICES+=,rabbit,tempest,mysql,dstat,zookeeper
 fi
 
 # SQLAlchemy supports multiple database drivers for each database server
@@ -143,11 +143,6 @@
 # requirmenets files here, in a comma-separated list
 ADDITIONAL_VENV_PACKAGES=${ADITIONAL_VENV_PACKAGES:-""}
 
-# Configure wheel cache location
-export WHEELHOUSE=${WHEELHOUSE:-$DEST/.wheelhouse}
-export PIP_WHEEL_DIR=${PIP_WHEEL_DIR:-$WHEELHOUSE}
-export PIP_FIND_LINKS=${PIP_FIND_LINKS:-file://$WHEELHOUSE}
-
 # This can be used to turn database query logging on and off
 # (currently only implemented for MySQL backend)
 DATABASE_QUERY_LOGGING=$(trueorfalse False DATABASE_QUERY_LOGGING)
diff --git a/tests/test_meta_config.sh b/tests/test_meta_config.sh
index a04c081..f3e94af 100755
--- a/tests/test_meta_config.sh
+++ b/tests/test_meta_config.sh
@@ -23,6 +23,12 @@
     fi
 }
 
+# mock function-common:die so that it does not
+# interupt our test script
+function die {
+    exit -1
+}
+
 TEST_1C_ADD="[eee]
 type=new
 multi = foo2"
@@ -110,6 +116,15 @@
 [DEFAULT]
 servers=10.11.12.13:80
 
+[[test8|/permission-denied.conf]]
+foo=bar
+
+[[test9|\$UNDEF]]
+foo=bar
+
+[[test10|does-not-exist-dir/test.conf]]
+foo=bar
+
 [[test-multi-sections|test-multi-sections.conf]]
 [sec-1]
 cfg_item1 = abcd
@@ -340,6 +355,36 @@
 servers = 10.11.12.13:80"
 check_result "$VAL" "$EXPECT_VAL"
 
+echo "merge_config_file test8 non-touchable conf file: "
+set +e
+# function is expected to fail and exit, running it
+# in a subprocess to let this script proceed
+(merge_config_file test.conf test8 /permission-denied.conf)
+VAL=$?
+EXPECT_VAL=255
+check_result "$VAL" "$EXPECT_VAL"
+set -e
+
+echo -n "merge_config_group test9 undefined conf file: "
+set +e
+# function is expected to fail and exit, running it
+# in a subprocess to let this script proceed
+(merge_config_group test.conf test9)
+VAL=$?
+EXPECT_VAL=255
+check_result "$VAL" "$EXPECT_VAL"
+set -e
+
+echo -n "merge_config_group test10 not directory: "
+set +e
+# function is expected to fail and exit, running it
+# in a subprocess to let this script proceed
+(merge_config_group test.conf test10)
+VAL=$?
+EXPECT_VAL=255
+check_result "$VAL" "$EXPECT_VAL"
+set -e
+
 rm -f test.conf test1c.conf test2a.conf \
     test-space.conf test-equals.conf test-strip.conf \
     test-colon.conf test-env.conf test-multiline.conf \
diff --git a/tools/build_wheels.sh b/tools/build_wheels.sh
deleted file mode 100755
index 14c2999..0000000
--- a/tools/build_wheels.sh
+++ /dev/null
@@ -1,86 +0,0 @@
-#!/usr/bin/env bash
-#
-# **tools/build_wheels.sh** - Build a cache of Python wheels
-#
-# build_wheels.sh [package [...]]
-#
-# System package prerequisites listed in ``files/*/devlibs`` will be installed
-#
-# Builds wheels for all virtual env requirements listed in
-# ``venv-requirements.txt`` plus any supplied on the command line.
-#
-# Assumes:
-# - ``tools/install_pip.sh`` has been run and a suitable ``pip/setuptools`` is available.
-
-# If ``TOP_DIR`` is set we're being sourced rather than running stand-alone
-# or in a sub-shell
-if [[ -z "$TOP_DIR" ]]; then
-
-    set -o errexit
-    set -o nounset
-
-    # Keep track of the DevStack directory
-    TOP_DIR=$(cd $(dirname "$0")/.. && pwd)
-    FILES=$TOP_DIR/files
-
-    # Import common functions
-    source $TOP_DIR/functions
-
-    GetDistro
-
-    source $TOP_DIR/stackrc
-
-    trap err_trap ERR
-
-fi
-
-# Get additional packages to build
-MORE_PACKAGES="$@"
-
-# Exit on any errors so that errors don't compound
-function err_trap {
-    local r=$?
-    set +o xtrace
-
-    rm -rf $TMP_VENV_PATH
-
-    exit $r
-}
-
-# Get system prereqs
-install_package $(get_packages devlibs)
-
-# Get a modern ``virtualenv``
-pip_install virtualenv
-
-# Prepare the workspace
-TMP_VENV_PATH=$(mktemp -d tmp-venv-XXXX)
-virtualenv $TMP_VENV_PATH
-
-# Install modern pip and wheel
-PIP_VIRTUAL_ENV=$TMP_VENV_PATH pip_install -U pip wheel
-
-# BUG: cffi has a lot of issues. It has no stable ABI, if installed
-# code is built with a different ABI than the one that's detected at
-# load time, it tries to compile on the fly for the new ABI in the
-# install location (which will probably be /usr and not
-# writable). Also cffi is often included via setup_requires by
-# packages, which have different install rules (allowing betas) than
-# pip has.
-#
-# Because of this we must pip install cffi into the venv to build
-# wheels.
-PIP_VIRTUAL_ENV=$TMP_VENV_PATH pip_install_gr cffi
-
-# ``VENV_PACKAGES`` is a list of packages we want to pre-install
-VENV_PACKAGE_FILE=$FILES/venv-requirements.txt
-if [[ -r $VENV_PACKAGE_FILE ]]; then
-    VENV_PACKAGES=$(grep -v '^#' $VENV_PACKAGE_FILE)
-fi
-
-for pkg in ${VENV_PACKAGES,/ } ${MORE_PACKAGES}; do
-    $TMP_VENV_PATH/bin/pip wheel $pkg
-done
-
-# Clean up wheel workspace
-rm -rf $TMP_VENV_PATH
diff --git a/unstack.sh b/unstack.sh
index 30447a7..0cace32 100755
--- a/unstack.sh
+++ b/unstack.sh
@@ -69,6 +69,7 @@
 source $TOP_DIR/lib/neutron-legacy
 source $TOP_DIR/lib/ldap
 source $TOP_DIR/lib/dstat
+source $TOP_DIR/lib/zookeeper
 
 # Extras Source
 # --------------
@@ -172,6 +173,10 @@
     stop_dstat
 fi
 
+if is_service_enabled zookeeper; then
+    stop_zookeeper
+fi
+
 # Clean up the remainder of the screen processes
 SCREEN=$(which screen)
 if [[ -n "$SCREEN" ]]; then