Merge "Fixing python-heatclient's git repo path."
diff --git a/.gitignore b/.gitignore
index 5e770c8..f9e2644 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,4 @@
 stack-screenrc
 *.pem
 accrc
+.stackenv
diff --git a/HACKING.rst b/HACKING.rst
index c4641fa..6ad8c7e 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -88,6 +88,30 @@
 ``configure_swift()``.
 
 
+stackrc
+-------
+
+``stackrc`` is the global configuration file for DevStack.  It is responsible for
+calling ``localrc`` if it exists so configuration can be overridden by the user.
+
+The criteria for what belongs in ``stackrc`` can be vaguely summarized as
+follows:
+
+* All project respositories and branches (for historical reasons)
+* Global configuration that may be referenced in ``localrc``, i.e. ``DEST``, ``DATA_DIR``
+* Global service configuration like ``ENABLED_SERVICES``
+* Variables used by multiple services that do not have a clear owner, i.e.
+  ``VOLUME_BACKING_FILE_SIZE`` (nova-volumes and cinder) or ``PUBLIC_NETWORK_NAME``
+  (nova-network and quantum)
+* Variables that can not be cleanly declared in a project file due to
+  dependency ordering, i.e. the order of sourcing the project files can
+  not be changed for other reasons but the earlier file needs to dereference a
+  variable set in the later file.  This should be rare.
+
+Also, variable declarations in ``stackrc`` do NOT allow overriding (the form
+``FOO=${FOO:-baz}``); if they did then they can already be changed in ``localrc``
+and can stay in the project file.
+
 Documentation
 -------------
 
diff --git a/extras.d/80-tempest.sh b/extras.d/80-tempest.sh
new file mode 100644
index 0000000..506ccef
--- /dev/null
+++ b/extras.d/80-tempest.sh
@@ -0,0 +1,20 @@
+# tempest.sh - DevStack extras script
+
+source $TOP_DIR/lib/tempest
+
+if [[ "$1" == "stack" ]]; then
+    # Configure Tempest last to ensure that the runtime configuration of
+    # the various OpenStack services can be queried.
+    if is_service_enabled tempest; then
+        echo_summary "Configuring Tempest"
+        install_tempest
+        configure_tempest
+    fi
+fi
+
+if [[ "$1" == "unstack" ]]; then
+    # no-op
+    :
+fi
+
+
diff --git a/extras.d/README b/extras.d/README
new file mode 100644
index 0000000..ffc6793
--- /dev/null
+++ b/extras.d/README
@@ -0,0 +1,14 @@
+The extras.d directory contains project initialization scripts to be
+sourced by stack.sh at the end of its run.  This is expected to be
+used by external projects that want to be configured, started and
+stopped with DevStack.
+
+Order is controlled by prefixing the script names with the a two digit
+sequence number.  Script names must end with '.sh'.  This provides a
+convenient way to disable scripts by simoy renaming them.
+
+DevStack reserves the sequence numbers 00 through 09 and 90 through 99
+for its own use.
+
+The scripts are called with an argument of 'stack' by stack.sh and
+with an argument of 'unstack' by unstack.sh.
diff --git a/functions b/functions
index e1795ae..80e1796 100644
--- a/functions
+++ b/functions
@@ -459,7 +459,7 @@
     local file=$1
     local section=$2
     local option=$3
-    sed -i -e "/^\[ *$section *\]/,/^\[.*\]/ s|^\($option[ \t]*=.*$\)|#\1|" $file
+    sed -i -e "/^\[$section\]/,/^\[.*\]/ s|^\($option[ \t]*=.*$\)|#\1|" "$file"
 }
 
 # Uncomment an option in an INI file
@@ -468,7 +468,7 @@
     local file=$1
     local section=$2
     local option=$3
-    sed -i -e "/^\[ *$section *\]/,/^\[.*\]/ s|[^ \t]*#[ \t]*\($option[ \t]*=.*$\)|\1|" $file
+    sed -i -e "/^\[$section\]/,/^\[.*\]/ s|[^ \t]*#[ \t]*\($option[ \t]*=.*$\)|\1|" "$file"
 }
 
 
@@ -479,10 +479,20 @@
     local section=$2
     local option=$3
     local line
-    line=$(sed -ne "/^\[ *$section *\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" $file)
+    line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file")
     echo ${line#*=}
 }
 
+# Determinate is the given option present in the INI file
+# ini_has_option config-file section option
+function ini_has_option() {
+    local file=$1
+    local section=$2
+    local option=$3
+    local line
+    line=$(sed -ne "/^\[$section\]/,/^\[.*\]/ { /^$option[ \t]*=/ p; }" "$file")
+    [ -n "$line" ]
+}
 
 # Set an option in an INI file
 # iniset config-file section option value
@@ -491,18 +501,18 @@
     local section=$2
     local option=$3
     local value=$4
-    if ! grep -q "^\[ *$section *\]" $file; then
+    if ! grep -q "^\[$section\]" "$file"; then
         # Add section at the end
-        echo -e "\n[$section]" >>$file
+        echo -e "\n[$section]" >>"$file"
     fi
-    if [[ -z "$(iniget $file $section $option)" ]]; then
+    if ! ini_has_option "$file" "$section" "$option"; then
         # Add it
-        sed -i -e "/^\[ *$section *\]/ a\\
+        sed -i -e "/^\[$section\]/ a\\
 $option = $value
-" $file
+" "$file"
     else
         # Replace it
-        sed -i -e "/^\[ *$section *\]/,/^\[.*\]/ s|^\($option[ \t]*=[ \t]*\).*$|\1$value|" $file
+        sed -i -e "/^\[$section\]/,/^\[.*\]/ s|^\($option[ \t]*=[ \t]*\).*$|\1$value|" "$file"
     fi
 }
 
diff --git a/lib/cinder b/lib/cinder
index 4aaea5d..1f40984 100644
--- a/lib/cinder
+++ b/lib/cinder
@@ -37,6 +37,12 @@
 CINDER_CONF=$CINDER_CONF_DIR/cinder.conf
 CINDER_API_PASTE_INI=$CINDER_CONF_DIR/api-paste.ini
 
+# Public facing bits
+CINDER_SERVICE_HOST=${CINDER_SERVICE_HOST:-$SERVICE_HOST}
+CINDER_SERVICE_PORT=${CINDER_SERVICE_PORT:-8776}
+CINDER_SERVICE_PORT_INT=${CINDER_SERVICE_PORT_INT:-18776}
+CINDER_SERVICE_PROTOCOL=${CINDER_SERVICE_PROTOCOL:-$SERVICE_PROTOCOL}
+
 # Support entry points installation of console scripts
 if [[ -d $CINDER_DIR/bin ]]; then
     CINDER_BIN_DIR=$CINDER_DIR/bin
@@ -169,6 +175,11 @@
     iniset $CINDER_CONF DEFAULT osapi_volume_extension cinder.api.openstack.volume.contrib.standard_extensions
     iniset $CINDER_CONF DEFAULT state_path $CINDER_STATE_PATH
 
+    if is_service_enabled tls-proxy; then
+        # Set the service port for a proxy to take the original
+        iniset $CINDER_CONF DEFAULT osapi_volume_listen_port $CINDER_SERVICE_PORT_INT
+    fi
+
     if [ "$SYSLOG" != "False" ]; then
         iniset $CINDER_CONF DEFAULT use_syslog True
     fi
@@ -241,9 +252,9 @@
             keystone endpoint-create \
                 --region RegionOne \
                 --service_id $CINDER_SERVICE \
-                --publicurl "http://$SERVICE_HOST:8776/v1/\$(tenant_id)s" \
-                --adminurl "http://$SERVICE_HOST:8776/v1/\$(tenant_id)s" \
-                --internalurl "http://$SERVICE_HOST:8776/v1/\$(tenant_id)s"
+                --publicurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" \
+                --adminurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" \
+                --internalurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s"
         fi
     fi
 }
@@ -340,6 +351,11 @@
     screen_it c-api "cd $CINDER_DIR && $CINDER_BIN_DIR/cinder-api --config-file $CINDER_CONF"
     screen_it c-vol "cd $CINDER_DIR && $CINDER_BIN_DIR/cinder-volume --config-file $CINDER_CONF"
     screen_it c-sch "cd $CINDER_DIR && $CINDER_BIN_DIR/cinder-scheduler --config-file $CINDER_CONF"
+
+    # Start proxies if enabled
+    if is_service_enabled c-api && is_service_enabled tls-proxy; then
+        start_tls_proxy '*' $CINDER_SERVICE_PORT $CINDER_SERVICE_HOST $CINDER_SERVICE_PORT_INT &
+    fi
 }
 
 # stop_cinder() - Stop running processes
diff --git a/lib/swift b/lib/swift
index c433387..b418eda 100644
--- a/lib/swift
+++ b/lib/swift
@@ -39,7 +39,8 @@
 SWIFT_CONFIG_DIR=${SWIFT_CONFIG_DIR:-/etc/swift}
 
 # DevStack will create a loop-back disk formatted as XFS to store the
-# swift data. Set ``SWIFT_LOOPBACK_DISK_SIZE`` to the disk size in bytes.
+# swift data. Set ``SWIFT_LOOPBACK_DISK_SIZE`` to the disk size in
+# kilobytes.
 # Default is 1 gigabyte.
 SWIFT_LOOPBACK_DISK_SIZE=${SWIFT_LOOPBACK_DISK_SIZE:-1000000}
 
diff --git a/lib/tempest b/lib/tempest
index b408b11..fa637c1 100644
--- a/lib/tempest
+++ b/lib/tempest
@@ -134,12 +134,14 @@
     flavor_lines=`nova flavor-list`
     IFS=$'\r\n'
     flavors=""
-    for line in $flavor_lines; do
-        if [ -z $DEFAULT_INSTANCE_TYPE ]; then
-            flavors="$flavors `echo $line | grep -v "^\(|\s*ID\|+--\)" | cut -d' ' -f2`"
-        else
-            flavors="$flavors `echo $line | grep -v "^\(|\s*ID\|+--\)" | grep "$DEFAULT_INSTANCE_TYPE" | cut -d' ' -f2`"
+    if [[ -n "$DEFAULT_INSTANCE_TYPE" ]]; then
+        for line in $flavor_lines; do
+            f=$(echo $line | awk "/ $DEFAULT_INSTANCE_TYPE / { print \$2 }")
+            flavors="$flavors $f"
+        done
     fi
+    for line in $flavor_lines; do
+        flavors="$flavors `echo $line | grep -v "^\(|\s*ID\|+--\)" | cut -d' ' -f2`"
     done
 
     IFS=" "
diff --git a/lib/tls b/lib/tls
index 1e2a899..202edef 100644
--- a/lib/tls
+++ b/lib/tls
@@ -189,7 +189,7 @@
 " >$ca_dir/signing.conf
 }
 
-# Create root and intermediate CAs and an initial server cert
+# Create root and intermediate CAs
 # init_CA
 function init_CA {
     # Ensure CAs are built
@@ -198,7 +198,11 @@
 
     # Create the CA bundle
     cat $ROOT_CA_DIR/cacert.pem $INT_CA_DIR/cacert.pem >>$INT_CA_DIR/ca-chain.pem
+}
 
+# Create an initial server cert
+# init_cert
+function init_cert {
     if [[ ! -r $DEVSTACK_CERT ]]; then
         if [[ -n "$TLS_IP" ]]; then
             # Lie to let incomplete match routines work
diff --git a/stack.sh b/stack.sh
index 4122103..c564137 100755
--- a/stack.sh
+++ b/stack.sh
@@ -321,7 +321,6 @@
 source $TOP_DIR/lib/ceilometer
 source $TOP_DIR/lib/heat
 source $TOP_DIR/lib/quantum
-source $TOP_DIR/lib/tempest
 source $TOP_DIR/lib/baremetal
 
 # Set the destination directories for OpenStack projects
@@ -776,9 +775,6 @@
     install_ceilometerclient
     install_ceilometer
 fi
-if is_service_enabled tempest; then
-    install_tempest
-fi
 
 
 # Initialization
@@ -839,6 +835,7 @@
 if is_service_enabled tls-proxy; then
     configure_CA
     init_CA
+    init_cert
     # Add name to /etc/hosts
     # don't be naive and add to existing line!
 fi
@@ -1130,6 +1127,12 @@
         iniset $NOVA_CONF baremetal power_manager $BM_POWER_MANAGER
         iniset $NOVA_CONF baremetal tftp_root /tftpboot
 
+        # Define extra baremetal nova conf flags by defining the array ``EXTRA_BAREMETAL_OPTS``.
+        for I in "${EXTRA_BAREMETAL_OPTS[@]}"; do
+           # Attempt to convert flags to options
+           iniset $NOVA_CONF baremetal ${I//=/ }
+        done
+
     # Default
     # -------
 
@@ -1317,16 +1320,6 @@
     screen_it baremetal "nova-baremetal-deploy-helper"
 fi
 
-# Configure Tempest last to ensure that the runtime configuration of
-# the various OpenStack services can be queried.
-if is_service_enabled tempest; then
-    echo_summary "Configuring Tempest"
-    configure_tempest
-    echo '**************************************************'
-    echo_summary "Finished Configuring Tempest"
-    echo '**************************************************'
-fi
-
 # Save some values we generated for later use
 CURRENT_RUN_TIME=$(date "+$TIMESTAMP_FORMAT")
 echo "# $CURRENT_RUN_TIME" >$TOP_DIR/.stackenv
@@ -1336,6 +1329,16 @@
 done
 
 
+# Run extras
+# ==========
+
+if [[ -d $TOP_DIR/extras.d ]]; then
+    for i in $TOP_DIR/extras.d/*.sh; do
+        [[ -r $i ]] && source $i stack
+    done
+fi
+
+
 # Run local script
 # ================
 
diff --git a/tests/functions.sh b/tests/functions.sh
index be48729..4fe6443 100755
--- a/tests/functions.sh
+++ b/tests/functions.sh
@@ -57,6 +57,9 @@
 
 [ ccc ]
 spaces  =  yes
+
+[ddd]
+empty =
 EOF
 
 # Test with spaces
@@ -79,13 +82,22 @@
 
 # Test with spaces in section header
 
-VAL=$(iniget test.ini ccc spaces)
+VAL=$(iniget test.ini " ccc " spaces)
 if [[ "$VAL" == "yes" ]]; then
     echo "OK: $VAL"
 else
     echo "iniget failed: $VAL"
 fi
 
+iniset test.ini "b b" opt_ion 42
+
+VAL=$(iniget test.ini "b b" opt_ion)
+if [[ "$VAL" == "42" ]]; then
+    echo "OK: $VAL"
+else
+    echo "iniget failed: $VAL"
+fi
+
 # Test without spaces, end of file
 
 VAL=$(iniget test.ini bbb handlers)
@@ -104,6 +116,29 @@
     echo "iniget failed: $VAL"
 fi
 
+# test empty option
+if ini_has_option test.ini ddd empty; then
+   echo "OK: ddd.empty present"
+else
+   echo "ini_has_option failed: ddd.empty not found"
+fi
+
+# test non-empty option
+if ini_has_option test.ini bbb handlers; then
+   echo "OK: bbb.handlers present"
+else
+   echo "ini_has_option failed: bbb.handlers not found"
+fi
+
+# test changing empty option
+iniset test.ini ddd empty "42"
+
+VAL=$(iniget test.ini ddd empty)
+if [[ "$VAL" == "42" ]]; then
+    echo "OK: $VAL"
+else
+    echo "iniget failed: $VAL"
+fi
 
 # Test section not exist
 
@@ -132,6 +167,12 @@
     echo "iniget failed: $VAL"
 fi
 
+if ! ini_has_option test.ini aaa debug; then
+    echo "OK aaa.debug not present"
+else
+    echo "ini_has_option failed: aaa.debug"
+fi
+
 iniset test.ini aaa debug "999"
 
 VAL=$(iniget test.ini aaa debug)
diff --git a/tools/make_cert.sh b/tools/make_cert.sh
new file mode 100755
index 0000000..cb93e57
--- /dev/null
+++ b/tools/make_cert.sh
@@ -0,0 +1,55 @@
+#!/bin/bash
+
+# **make_cert.sh**
+
+# Create a CA hierarchy (if necessary) and server certificate
+#
+# This mimics the CA structure that DevStack sets up when ``tls_proxy`` is enabled
+# but in the curent directory unless ``DATA_DIR`` is set
+
+ENABLE_TLS=True
+DATA_DIR=${DATA_DIR:-`pwd`/ca-data}
+
+ROOT_CA_DIR=$DATA_DIR/root
+INT_CA_DIR=$DATA_DIR/int
+
+# Import common functions
+source $TOP_DIR/functions
+
+# Import TLS functions
+source lib/tls
+
+function usage {
+    echo "$0 - Create CA and/or certs"
+    echo ""
+    echo "Usage: $0 commonName [orgUnit]"
+    exit 1
+}
+
+CN=$1
+if [ -z "$CN" ]]; then
+    usage
+fi
+ORG_UNIT_NAME=${2:-$ORG_UNIT_NAME}
+
+# Useful on OS/X
+if [[ `uname -s` == 'Darwin' && -d /usr/local/Cellar/openssl ]]; then
+    # set up for brew-installed modern OpenSSL
+    OPENSSL_CONF=/usr/local/etc/openssl/openssl.cnf
+    OPENSSL=/usr/local/Cellar/openssl/*/bin/openssl
+fi
+
+DEVSTACK_CERT_NAME=$CN
+DEVSTACK_HOSTNAME=$CN
+DEVSTACK_CERT=$DATA_DIR/$DEVSTACK_CERT_NAME.pem
+
+# Make sure the CA is set up
+configure_CA
+init_CA
+
+# Create the server cert
+make_cert $INT_CA_DIR $DEVSTACK_CERT_NAME $DEVSTACK_HOSTNAME
+
+# Create a cert bundle
+cat $INT_CA_DIR/private/$DEVSTACK_CERT_NAME.key $INT_CA_DIR/$DEVSTACK_CERT_NAME.crt $INT_CA_DIR/cacert.pem >$DEVSTACK_CERT
+
diff --git a/unstack.sh b/unstack.sh
index fd70916..1d4bfd5 100755
--- a/unstack.sh
+++ b/unstack.sh
@@ -39,6 +39,15 @@
     UNSTACK_ALL=${UNSTACK_ALL:-1}
 fi
 
+# Run extras
+# ==========
+
+if [[ -d $TOP_DIR/extras.d ]]; then
+    for i in $TOP_DIR/extras.d/*.sh; do
+        [[ -r $i ]] && source $i unstack
+    done
+fi
+
 if [[ "$Q_USE_DEBUG_COMMAND" == "True" ]]; then
     source $TOP_DIR/openrc
     teardown_quantum_debug