Merge "allow resize tests to run"
diff --git a/files/apts/ldap b/files/apts/ldap
new file mode 100644
index 0000000..81a00f2
--- /dev/null
+++ b/files/apts/ldap
@@ -0,0 +1,3 @@
+ldap-utils
+slapd # NOPRIME
+python-ldap
diff --git a/files/apts/ryu b/files/apts/ryu
index 1e8f2d2..4a4fc52 100644
--- a/files/apts/ryu
+++ b/files/apts/ryu
@@ -1,4 +1,5 @@
 python-setuptools
 python-gevent
 python-gflags
+python-netifaces
 python-sphinx
diff --git a/files/ldap/manager.ldif.in b/files/ldap/manager.ldif.in
new file mode 100644
index 0000000..e522150
--- /dev/null
+++ b/files/ldap/manager.ldif.in
@@ -0,0 +1,10 @@
+dn: olcDatabase={${LDAP_OLCDB_NUMBER}}hdb,cn=config
+changetype: modify
+replace: olcSuffix
+olcSuffix: dc=openstack,dc=org
+-
+replace: olcRootDN
+olcRootDN: dc=Manager,dc=openstack,dc=org
+-
+${LDAP_ROOTPW_COMMAND}: olcRootPW
+olcRootPW: ${SLAPPASS}
diff --git a/files/ldap/openstack.ldif b/files/ldap/openstack.ldif
new file mode 100644
index 0000000..287fda4
--- /dev/null
+++ b/files/ldap/openstack.ldif
@@ -0,0 +1,21 @@
+dn: dc=openstack,dc=org
+dc: openstack
+objectClass: dcObject
+objectClass: organizationalUnit
+ou: openstack
+
+dn: ou=Groups,dc=openstack,dc=org
+objectClass: organizationalUnit
+ou: Groups
+
+dn: ou=Users,dc=openstack,dc=org
+objectClass: organizationalUnit
+ou: Users
+
+dn: ou=Roles,dc=openstack,dc=org
+objectClass: organizationalUnit
+ou: Roles
+
+dn: ou=Projects,dc=openstack,dc=org
+objectClass: organizationalUnit
+ou: Projects
diff --git a/files/rpms/ldap b/files/rpms/ldap
new file mode 100644
index 0000000..2f7ab5d
--- /dev/null
+++ b/files/rpms/ldap
@@ -0,0 +1,3 @@
+openldap-servers
+openldap-clients
+python-ldap
diff --git a/files/rpms/ryu b/files/rpms/ryu
index 1e8f2d2..4a4fc52 100644
--- a/files/rpms/ryu
+++ b/files/rpms/ryu
@@ -1,4 +1,5 @@
 python-setuptools
 python-gevent
 python-gflags
+python-netifaces
 python-sphinx
diff --git a/functions b/functions
index 68aec5d..79c82a4 100644
--- a/functions
+++ b/functions
@@ -80,6 +80,27 @@
 }
 
 
+# HTTP and HTTPS proxy servers are supported via the usual environment variables [1]
+# ``http_proxy``, ``https_proxy`` and ``no_proxy``. They can be set in
+# ``localrc`` or on the command line if necessary::
+#
+# [1] http://www.w3.org/Daemon/User/Proxies/ProxyClients.html
+#
+#     http_proxy=http://proxy.example.com:3128/ no_proxy=repo.example.net ./stack.sh
+
+function export_proxy_variables() {
+    if [[ -n "$http_proxy" ]]; then
+        export http_proxy=$http_proxy
+    fi
+    if [[ -n "$https_proxy" ]]; then
+        export https_proxy=$https_proxy
+    fi
+    if [[ -n "$no_proxy" ]]; then
+        export no_proxy=$no_proxy
+    fi
+}
+
+
 # Grab a numbered field from python prettytable output
 # Fields are numbered starting with 1
 # Reverse syntax is supported: -1 is the last field, -2 is second to last, etc.
@@ -717,26 +738,31 @@
 # Helper to launch a service in a named screen
 # screen_it service "command-line"
 function screen_it {
-    NL=`echo -ne '\015'`
     SCREEN_NAME=${SCREEN_NAME:-stack}
     SERVICE_DIR=${SERVICE_DIR:-${DEST}/status}
+    SCREEN_DEV=`trueorfalse True $SCREEN_DEV`
 
     if is_service_enabled $1; then
         # Append the service to the screen rc file
         screen_rc "$1" "$2"
 
         screen -S $SCREEN_NAME -X screen -t $1
-        # sleep to allow bash to be ready to be send the command - we are
-        # creating a new window in screen and then sends characters, so if
-        # bash isn't running by the time we send the command, nothing happens
-        sleep 1.5
+        if [[ "$SCREEN_DEV" = "True" ]]; then
+            # sleep to allow bash to be ready to be send the command - we are
+            # creating a new window in screen and then sends characters, so if
+            # bash isn't running by the time we send the command, nothing happens
+            sleep 1.5
 
-        if [[ -n ${SCREEN_LOGDIR} ]]; then
-            screen -S $SCREEN_NAME -p $1 -X logfile ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log
-            screen -S $SCREEN_NAME -p $1 -X log on
-            ln -sf ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log ${SCREEN_LOGDIR}/screen-${1}.log
+            if [[ -n ${SCREEN_LOGDIR} ]]; then
+                screen -S $SCREEN_NAME -p $1 -X logfile ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log
+                screen -S $SCREEN_NAME -p $1 -X log on
+                ln -sf ${SCREEN_LOGDIR}/screen-${1}.${CURRENT_LOG_TIME}.log ${SCREEN_LOGDIR}/screen-${1}.log
+            fi
+            NL=`echo -ne '\015'`
+            screen -S $SCREEN_NAME -p $1 -X stuff "$2 || touch \"$SERVICE_DIR/$SCREEN_NAME/$1.failure\"$NL"
+        else
+            screen -S $SCREEN_NAME -p $1 -X exec /bin/bash -c "$2 || touch \"$SERVICE_DIR/$SCREEN_NAME/$1.failure\""
         fi
-        screen -S $SCREEN_NAME -p $1 -X stuff "$2 || touch \"$SERVICE_DIR/$SCREEN_NAME/$1.failure\"$NL"
     fi
 }
 
diff --git a/lib/baremetal b/lib/baremetal
index 3cc2429..7c31d1f 100644
--- a/lib/baremetal
+++ b/lib/baremetal
@@ -90,6 +90,9 @@
     BM_DNSMASQ_RANGE=${BM_DNSMASQ_RANGE:-}
 fi
 
+# BM_DNSMASQ_DNS provide dns server to bootstrap clients
+BM_DNSMASQ_DNS=${BM_DNSMASQ_DNS:-}
+
 # BM_FIRST_MAC *must* be set to the MAC address of the node you will boot.
 #              This is passed to dnsmasq along with the kernel/ramdisk to
 #              deploy via PXE.
diff --git a/lib/ceilometer b/lib/ceilometer
index 41a5f53..bc37d92 100644
--- a/lib/ceilometer
+++ b/lib/ceilometer
@@ -73,6 +73,7 @@
 
     # Install the policy file for the API server
     cp $CEILOMETER_DIR/etc/ceilometer/policy.json $CEILOMETER_CONF_DIR
+    cp $CEILOMETER_DIR/etc/ceilometer/pipeline.yaml $CEILOMETER_CONF_DIR
     iniset $CEILOMETER_CONF DEFAULT policy_file $CEILOMETER_CONF_DIR/policy.json
 
     # the compute and central agents need these credentials in order to
diff --git a/lib/keystone b/lib/keystone
index 5714670..866c62e 100644
--- a/lib/keystone
+++ b/lib/keystone
@@ -94,6 +94,17 @@
     local dburl
     database_connection_url dburl keystone
 
+    if is_service_enabled ldap; then
+        #Set all needed ldap values
+        iniset $KEYSTONE_CONF ldap password  $LDAP_PASSWORD
+        iniset $KEYSTONE_CONF ldap user "dc=Manager,dc=openstack,dc=org"
+        iniset $KEYSTONE_CONF ldap suffix "dc=openstack,dc=org"
+    fi
+
+    if [[  "$KEYSTONE_IDENTITY_BACKEND" == "ldap"  ]]; then
+        iniset $KEYSTONE_CONF identity driver "keystone.identity.backends.ldap.Identity"
+    fi
+
     if is_service_enabled tls-proxy; then
         # Set the service ports for a proxy to take the originals
         iniset $KEYSTONE_CONF DEFAULT public_port $KEYSTONE_SERVICE_PORT_INT
@@ -283,6 +294,10 @@
 
 # install_keystone() - Collect source and prepare
 function install_keystone() {
+    # only install ldap if the service has been enabled
+    if is_service_enabled ldap; then
+        install_ldap
+    fi
     git_clone $KEYSTONE_REPO $KEYSTONE_DIR $KEYSTONE_BRANCH
 }
 
diff --git a/lib/ldap b/lib/ldap
new file mode 100644
index 0000000..5cb4534
--- /dev/null
+++ b/lib/ldap
@@ -0,0 +1,74 @@
+# lib/ldap
+# Functions to control the installation and configuration of **ldap**
+
+# ``stack.sh`` calls the entry points in this order:
+#
+
+# Save trace setting
+XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+# install_ldap
+# install_ldap() - Collect source and prepare
+function install_ldap() {
+    echo "Installing LDAP inside function"
+    echo "LDAP_PASSWORD is $LDAP_PASSWORD"
+    echo "os_VENDOR is $os_VENDOR"
+    printf "installing"
+    if is_ubuntu; then
+        echo "os vendor is Ubuntu"
+        LDAP_OLCDB_NUMBER=1
+        LDAP_ROOTPW_COMMAND=replace
+        sudo DEBIAN_FRONTEND=noninteractive apt-get install slapd ldap-utils
+        #automatically starts LDAP on ubuntu so no need to call start_ldap
+    elif is_fedora; then
+        echo "os vendor is Fedora"
+        LDAP_OLCDB_NUMBER=2
+        LDAP_ROOTPW_COMMAND=add
+        start_ldap
+    fi
+
+    printf "generate password file"
+    SLAPPASS=`slappasswd -s $LDAP_PASSWORD`
+
+    printf "secret is $SLAPPASS\n"
+    #create manager.ldif
+    TMP_MGR_DIFF_FILE=`mktemp -t manager_ldiff.$$.XXXXXXXXXX.ldif`
+    sed -e "s|\${LDAP_OLCDB_NUMBER}|$LDAP_OLCDB_NUMBER|" -e "s|\${SLAPPASS}|$SLAPPASS|" -e "s|\${LDAP_ROOTPW_COMMAND}|$LDAP_ROOTPW_COMMAND|" $FILES/ldap/manager.ldif.in >> $TMP_MGR_DIFF_FILE
+
+    #update ldap olcdb
+    sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f $TMP_MGR_DIFF_FILE
+
+    # add our top level ldap nodes
+    if ldapsearch -x -w $LDAP_PASSWORD -H ldap://localhost -D dc=Manager,dc=openstack,dc=org -x -b dc=openstack,dc=org | grep -q "Success" ; then
+        printf "LDAP already configured for OpenStack\n"
+        if [[ "$KEYSTONE_CLEAR_LDAP" == "yes" ]]; then
+            # clear LDAP state
+            clear_ldap_state
+            # reconfigure LDAP for OpenStack
+            ldapadd -c -x -H ldap://localhost -D dc=Manager,dc=openstack,dc=org -w $LDAP_PASSWORD -f  $FILES/ldap/openstack.ldif
+        fi
+    else
+        printf "Configuring LDAP for OpenStack\n"
+        ldapadd -c -x -H ldap://localhost -D dc=Manager,dc=openstack,dc=org -w $LDAP_PASSWORD -f  $FILES/ldap/openstack.ldif
+    fi
+}
+
+# start_ldap() - Start LDAP
+function start_ldap() {
+    sudo service slapd restart
+}
+
+
+# stop_ldap() - Stop LDAP
+function stop_ldap() {
+    sudo service slapd stop
+}
+
+# clear_ldap_state() - Clear LDAP State
+function clear_ldap_state() {
+    ldapdelete -x -w $LDAP_PASSWORD -H ldap://localhost -D dc=Manager,dc=openstack,dc=org -x -r "dc=openstack,dc=org"
+}
+
+# Restore xtrace
+$XTRACE
diff --git a/lib/quantum b/lib/quantum
index d5733b3..5b04558 100644
--- a/lib/quantum
+++ b/lib/quantum
@@ -270,8 +270,19 @@
     # Create a small network
     # Since quantum command is executed in admin context at this point,
     # ``--tenant_id`` needs to be specified.
-    NET_ID=$(quantum net-create --tenant_id $TENANT_ID "$PRIVATE_NETWORK_NAME" | grep ' id ' | get_field 2)
-    SUBNET_ID=$(quantum subnet-create --tenant_id $TENANT_ID --ip_version 4 --gateway $NETWORK_GATEWAY $NET_ID $FIXED_RANGE | grep ' id ' | get_field 2)
+    if is_baremetal; then
+        sudo ovs-vsctl add-port $OVS_PHYSICAL_BRIDGE $PUBLIC_INTERFACE
+        for IP in $(ip addr show dev $PUBLIC_INTERFACE | grep ' inet ' | awk '{print $2}'); do
+            sudo ip addr del $IP dev $PUBLIC_INTERFACE
+            sudo ip addr add $IP dev $OVS_PHYSICAL_BRIDGE
+        done
+        NET_ID=$(quantum net-create $PHYSICAL_NETWORK --tenant_id $TENANT_ID --provider:network_type flat --provider:physical_network "$PHYSICAL_NETWORK" | grep ' id ' | get_field 2)
+        SUBNET_ID=$(quantum subnet-create --tenant_id $TENANT_ID --ip_version 4 ${ALLOCATION_POOL:+--allocation-pool $ALLOCATION_POOL} --gateway $NETWORK_GATEWAY $NET_ID $FIXED_RANGE | grep ' id ' | get_field 2)
+        sudo ifconfig $OVS_PHYSICAL_BRIDGE up
+    else
+        NET_ID=$(quantum net-create --tenant_id $TENANT_ID "$PRIVATE_NETWORK_NAME" | grep ' id ' | get_field 2)
+        SUBNET_ID=$(quantum subnet-create --tenant_id $TENANT_ID --ip_version 4 --gateway $NETWORK_GATEWAY $NET_ID $FIXED_RANGE | grep ' id ' | get_field 2)
+    fi
 
     if is_service_enabled q-l3; then
         # Create a router, and add the private subnet as one of its interfaces
diff --git a/lib/quantum_plugins/bigswitch_floodlight b/lib/quantum_plugins/bigswitch_floodlight
index 35276a5..2c928be 100644
--- a/lib/quantum_plugins/bigswitch_floodlight
+++ b/lib/quantum_plugins/bigswitch_floodlight
@@ -2,7 +2,7 @@
 # ------------------------------------
 
 # Save trace setting
-XTRACE=$(set +o | grep xtrace)
+MY_XTRACE=$(set +o | grep xtrace)
 set +o xtrace
 
 source $TOP_DIR/lib/quantum_plugins/ovs_base
@@ -52,4 +52,4 @@
 }
 
 # Restore xtrace
-$XTRACE
+$MY_XTRACE
diff --git a/lib/quantum_plugins/linuxbridge b/lib/quantum_plugins/linuxbridge
index e8ba68c..6d5d4e0 100644
--- a/lib/quantum_plugins/linuxbridge
+++ b/lib/quantum_plugins/linuxbridge
@@ -2,7 +2,7 @@
 # ---------------------------
 
 # Save trace setting
-XTRACE=$(set +o | grep xtrace)
+MY_XTRACE=$(set +o | grep xtrace)
 set +o xtrace
 
 function is_quantum_ovs_base_plugin() {
@@ -76,4 +76,4 @@
 }
 
 # Restore xtrace
-$XTRACE
+$MY_XTRACE
diff --git a/lib/quantum_plugins/openvswitch b/lib/quantum_plugins/openvswitch
index 5415e86..12bc244 100644
--- a/lib/quantum_plugins/openvswitch
+++ b/lib/quantum_plugins/openvswitch
@@ -2,7 +2,7 @@
 # ---------------------------
 
 # Save trace setting
-XTRACE=$(set +o | grep xtrace)
+MY_XTRACE=$(set +o | grep xtrace)
 set +o xtrace
 
 source $TOP_DIR/lib/quantum_plugins/ovs_base
@@ -141,4 +141,4 @@
 }
 
 # Restore xtrace
-$XTRACE
+$MY_XTRACE
diff --git a/lib/quantum_plugins/ovs_base b/lib/quantum_plugins/ovs_base
index d9f6fd0..8563674 100644
--- a/lib/quantum_plugins/ovs_base
+++ b/lib/quantum_plugins/ovs_base
@@ -2,7 +2,7 @@
 # -------------------------------------
 
 # Save trace setting
-XTRACE=$(set +o | grep xtrace)
+MY_XTRACE=$(set +o | grep xtrace)
 set +o xtrace
 
 function is_quantum_ovs_base_plugin() {
@@ -12,7 +12,7 @@
 
 function _quantum_ovs_base_setup_bridge() {
     local bridge=$1
-    quantum-ovs-cleanup --ovs_integration_bridge $bridge
+    quantum-ovs-cleanup
     sudo ovs-vsctl --no-wait -- --may-exist add-br $bridge
     sudo ovs-vsctl --no-wait br-set-external-id $bridge bridge-id $bridge
 }
@@ -39,11 +39,11 @@
 function _quantum_ovs_base_configure_l3_agent() {
     iniset $Q_L3_CONF_FILE DEFAULT external_network_bridge $PUBLIC_BRIDGE
 
-    quantum-ovs-cleanup --external_network_bridge $PUBLIC_BRIDGE
+    quantum-ovs-cleanup
     sudo ovs-vsctl --no-wait -- --may-exist add-br $PUBLIC_BRIDGE
     # ensure no IP is configured on the public bridge
     sudo ip addr flush dev $PUBLIC_BRIDGE
 }
 
 # Restore xtrace
-$XTRACE
+$MY_XTRACE
diff --git a/lib/quantum_plugins/ryu b/lib/quantum_plugins/ryu
index 86105bc..2dfd4f7 100644
--- a/lib/quantum_plugins/ryu
+++ b/lib/quantum_plugins/ryu
@@ -2,7 +2,7 @@
 # ------------------
 
 # Save trace setting
-XTRACE=$(set +o | grep xtrace)
+MY_XTRACE=$(set +o | grep xtrace)
 set +o xtrace
 
 source $TOP_DIR/lib/quantum_plugins/ovs_base
@@ -15,6 +15,9 @@
 
 function quantum_plugin_install_agent_packages() {
     _quantum_ovs_base_install_agent_packages
+
+    # quantum_ryu_agent requires ryu module
+    install_ryu
 }
 
 function quantum_plugin_configure_common() {
@@ -60,4 +63,4 @@
 }
 
 # Restore xtrace
-$XTRACE
+$MY_XTRACE
diff --git a/lib/quantum_thirdparty/bigswitch_floodlight b/lib/quantum_thirdparty/bigswitch_floodlight
index 77aeb61..60e3924 100644
--- a/lib/quantum_thirdparty/bigswitch_floodlight
+++ b/lib/quantum_thirdparty/bigswitch_floodlight
@@ -2,7 +2,7 @@
 # ------------------------------------------
 
 # Save trace setting
-XTRACE=$(set +o | grep xtrace)
+MY_XTRACE=$(set +o | grep xtrace)
 set +o xtrace
 
 BS_FL_CONTROLLERS_PORT=${BS_FL_CONTROLLERS_PORT:-localhost:80}
@@ -47,4 +47,4 @@
 }
 
 # Restore xtrace
-$XTRACE
+$MY_XTRACE
diff --git a/lib/quantum_thirdparty/ryu b/lib/quantum_thirdparty/ryu
index f11951a..7a01923 100644
--- a/lib/quantum_thirdparty/ryu
+++ b/lib/quantum_thirdparty/ryu
@@ -2,7 +2,7 @@
 # -----------------------
 
 # Save trace setting
-XTRACE=$(set +o | grep xtrace)
+MY_XTRACE=$(set +o | grep xtrace)
 set +o xtrace
 
 
@@ -49,8 +49,16 @@
     echo "${RYU_CONF_CONTENTS}" > $RYU_CONF
 }
 
+# install_ryu can be called multiple times as quantum_pluing/ryu may call
+# this function for quantum-ryu-agent
+# Make this function idempotent and avoid cloning same repo many times
+# with RECLONE=yes
+_RYU_INSTALLED=${_RYU_INSTALLED:-False}
 function install_ryu() {
-    git_clone $RYU_REPO $RYU_DIR $RYU_BRANCH
+    if [[ "$_RYU_INSTALLED" == "False" ]]; then
+        git_clone $RYU_REPO $RYU_DIR $RYU_BRANCH
+        _RYU_INSTALLED=True
+    fi
 }
 
 function start_ryu() {
@@ -62,4 +70,4 @@
 }
 
 # Restore xtrace
-$XTRACE
+$MY_XTRACE
diff --git a/stack.sh b/stack.sh
index 4608648..c1525bd 100755
--- a/stack.sh
+++ b/stack.sh
@@ -30,9 +30,8 @@
 GetDistro
 
 
-
-# Settings
-# ========
+# Global Settings
+# ===============
 
 # ``stack.sh`` is customizable through setting environment variables.  If you
 # want to override a setting you can set and export it::
@@ -62,33 +61,18 @@
 source $TOP_DIR/stackrc
 
 
-# Proxy Settings
+# Local Settings
 # --------------
 
-# HTTP and HTTPS proxy servers are supported via the usual environment variables [1]
-# ``http_proxy``, ``https_proxy`` and ``no_proxy``. They can be set in
-# ``localrc`` if necessary or on the command line::
-#
-# [1] http://www.w3.org/Daemon/User/Proxies/ProxyClients.html
-#
-#     http_proxy=http://proxy.example.com:3128/ no_proxy=repo.example.net ./stack.sh
-
-if [[ -n "$http_proxy" ]]; then
-    export http_proxy=$http_proxy
-fi
-if [[ -n "$https_proxy" ]]; then
-    export https_proxy=$https_proxy
-fi
-if [[ -n "$no_proxy" ]]; then
-    export no_proxy=$no_proxy
-fi
+# Make sure the proxy config is visible to sub-processes
+export_proxy_variables
 
 # Destination path for installation ``DEST``
 DEST=${DEST:-/opt/stack}
 
 
 # Sanity Check
-# ============
+# ------------
 
 # Clean up last environment var cache
 if [[ -r $TOP_DIR/.stackenv ]]; then
@@ -306,6 +290,7 @@
 source $TOP_DIR/lib/heat
 source $TOP_DIR/lib/quantum
 source $TOP_DIR/lib/baremetal
+source $TOP_DIR/lib/ldap
 
 # Set the destination directories for OpenStack projects
 HORIZON_DIR=$DEST/horizon
@@ -475,6 +460,20 @@
 read_password SERVICE_PASSWORD "ENTER A SERVICE_PASSWORD TO USE FOR THE SERVICE AUTHENTICATION."
 # Horizon currently truncates usernames and passwords at 20 characters
 read_password ADMIN_PASSWORD "ENTER A PASSWORD TO USE FOR HORIZON AND KEYSTONE (20 CHARS OR LESS)."
+# Keystone can now optionally install OpenLDAP by adding ldap to the list
+# of enabled services in the localrc file (e.g. ENABLED_SERVICES=key,ldap).
+# If OpenLDAP has already been installed but you need to clear out
+# the Keystone contents of LDAP set KEYSTONE_CLEAR_LDAP to yes
+# (e.g. KEYSTONE_CLEAR_LDAP=yes ) in the localrc file.  To enable the
+# Keystone Identity Driver (keystone.identity.backends.ldap.Identity)
+# set KEYSTONE_IDENTITY_BACKEND to ldap (e.g. KEYSTONE_IDENTITY_BACKEND=ldap)
+# in the localrc file.
+
+
+# only request ldap password if the service is enabled
+if is_service_enabled ldap; then
+    read_password LDAP_PASSWORD "ENTER A PASSWORD TO USE FOR LDAP"
+fi
 
 # Set the tenant for service accounts in Keystone
 SERVICE_TENANT_NAME=${SERVICE_TENANT_NAME:-service}
@@ -631,26 +630,9 @@
 # OpenStack uses a fair number of other projects.
 
 # Install package requirements
+# Source it so the entire environment is available
 echo_summary "Installing package prerequisites"
-if is_ubuntu; then
-    install_package $(get_packages $FILES/apts)
-elif is_fedora; then
-    install_package $(get_packages $FILES/rpms)
-elif is_suse; then
-    install_package $(get_packages $FILES/rpms-suse)
-else
-    exit_distro_not_supported "list of packages"
-fi
-
-if [[ $SYSLOG != "False" ]]; then
-    if is_ubuntu || is_fedora; then
-        install_package rsyslog-relp
-    elif is_suse; then
-        install_package rsyslog-module-relp
-    else
-        exit_distro_not_supported "rsyslog-relp installation"
-    fi
-fi
+source $TOP_DIR/tools/install_prereqs.sh
 
 install_rpc_backend
 
@@ -1285,8 +1267,8 @@
     sudo pkill dnsmasq || true
     sudo dnsmasq --conf-file= --port=0 --enable-tftp --tftp-root=/tftpboot \
         --dhcp-boot=pxelinux.0 --bind-interfaces --pid-file=/var/run/dnsmasq.pid \
-        --interface=$BM_DNSMASQ_IFACE --dhcp-range=$BM_DNSMASQ_RANGE
-
+        --interface=$BM_DNSMASQ_IFACE --dhcp-range=$BM_DNSMASQ_RANGE \
+        ${$BM_DNSMASQ_DNS:+--dhcp-option=option:dns-server,$BM_DNSMASQ_DNS}
     # ensure callback daemon is running
     sudo pkill nova-baremetal-deploy-helper || true
     screen_it baremetal "nova-baremetal-deploy-helper"
diff --git a/stackrc b/stackrc
index 789fc82..91f4e2b 100644
--- a/stackrc
+++ b/stackrc
@@ -29,6 +29,13 @@
 # Set the default Nova APIs to enable
 NOVA_ENABLED_APIS=ec2,osapi_compute,metadata
 
+# Whether to use 'dev mode' for screen windows. Dev mode works by
+# stuffing text into the screen windows so that a developer can use
+# ctrl-c, up-arrow, enter to restart the service. Starting services
+# this way is slightly unreliable, and a bit slower, so this can
+# be disabled for automated testing by setting this value to false.
+SCREEN_DEV=True
+
 # Repositories
 # ------------
 
diff --git a/tools/install_prereqs.sh b/tools/install_prereqs.sh
new file mode 100755
index 0000000..4d151db
--- /dev/null
+++ b/tools/install_prereqs.sh
@@ -0,0 +1,82 @@
+#!/usr/bin/env bash
+
+# **install_prereqs.sh**
+
+# Install system package prerequisites
+#
+# install_prereqs.sh [-f]
+#
+# -f        Force an install run now
+
+if [[ -n "$1" &&  "$1" = "-f" ]]; then
+    FORCE_PREREQ=1
+fi
+
+# If TOP_DIR is set we're being sourced rather than running stand-alone
+# or in a sub-shell
+if [[ -z "$TOP_DIR" ]]; then
+    # Keep track of the devstack directory
+    TOP_DIR=$(cd $(dirname "$0")/.. && pwd)
+
+    # Import common functions
+    source $TOP_DIR/functions
+
+    # Determine what system we are running on.  This provides ``os_VENDOR``,
+    # ``os_RELEASE``, ``os_UPDATE``, ``os_PACKAGE``, ``os_CODENAME``
+    # and ``DISTRO``
+    GetDistro
+
+    # Needed to get ``ENABLED_SERVICES``
+    source $TOP_DIR/stackrc
+
+    # Prereq dirs are here
+    FILES=$TOP_DIR/files
+fi
+
+# Minimum wait time
+PREREQ_RERUN_MARKER=${PREREQ_RERUN_MARKER:-$TOP_DIR/.prereqs}
+PREREQ_RERUN_HOURS=${PREREQ_RERUN_HOURS:-2}
+PREREQ_RERUN_SECONDS=$((60*60*$PREREQ_RERUN_HOURS))
+
+NOW=$(date "+%s")
+LAST_RUN=$(head -1 $PREREQ_RERUN_MARKER 2>/dev/null || echo "0")
+DELTA=$(($NOW - $LAST_RUN))
+if [[ $DELTA -lt $PREREQ_RERUN_SECONDS && -z "$FORCE_PREREQ" ]]; then
+    echo "Re-run time has not expired ($(($PREREQ_RERUN_SECONDS - $DELTA)) seconds remaining); exiting..."
+    return 0
+fi
+
+# Make sure the proxy config is visible to sub-processes
+export_proxy_variables
+
+
+# Install Packages
+# ================
+
+# Install package requirements
+if is_ubuntu; then
+    install_package $(get_packages $FILES/apts)
+elif is_fedora; then
+    install_package $(get_packages $FILES/rpms)
+elif is_suse; then
+    install_package $(get_packages $FILES/rpms-suse)
+else
+    exit_distro_not_supported "list of packages"
+fi
+
+if [[ -n "$SYSLOG" && "$SYSLOG" != "False" ]]; then
+    if is_ubuntu || is_fedora; then
+        install_package rsyslog-relp
+    elif is_suse; then
+        install_package rsyslog-module-relp
+    else
+        exit_distro_not_supported "rsyslog-relp installation"
+    fi
+fi
+
+
+# Mark end of run
+# ---------------
+
+date "+%s" >$PREREQ_RERUN_MARKER
+date >>$PREREQ_RERUN_MARKER
diff --git a/tools/xen/build_xva.sh b/tools/xen/build_xva.sh
index 0e874cf..b0fd003 100755
--- a/tools/xen/build_xva.sh
+++ b/tools/xen/build_xva.sh
@@ -44,12 +44,9 @@
     exit 1
 fi
 
-# Configure dns (use same dns as dom0)
-# but only when not precise
-if [ "$UBUNTU_INST_RELEASE" != "precise" ]; then
-    cp /etc/resolv.conf $STAGING_DIR/etc/resolv.conf
-elif [ "$MGT_IP" != "dhcp" ] && [ "$PUB_IP" != "dhcp" ]; then
-    echo "Configuration without DHCP not supported on Precise"
+# Only support DHCP for now - don't support how different versions of Ubuntu handle resolv.conf
+if [ "$MGT_IP" != "dhcp" ] && [ "$PUB_IP" != "dhcp" ]; then
+    echo "Configuration without DHCP not supported"
     exit 1
 fi