Merge "Add Nova fibre channel support required packages"
diff --git a/AUTHORS b/AUTHORS
index 7ec1f66..35c0a52 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -19,6 +19,7 @@
 Gary Kotton <gkotton@redhat.com>
 Hengqing Hu <hudayou@hotmail.com>
 Hua ZHANG <zhuadl@cn.ibm.com>
+Isaku Yamahata <yamahata@private.email.ne.jp>
 Jake Dahn <admin@jakedahn.com>
 James E. Blair <james.blair@rackspace.com>
 Jason Cannavale <jason.cannavale@rackspace.com>
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/nova b/files/apts/nova
index b7d1e92..39b4060 100644
--- a/files/apts/nova
+++ b/files/apts/nova
@@ -31,6 +31,7 @@
 python-libxml2
 python-routes
 python-netaddr
+python-numpy # used by websockify for spice console
 python-pastedeploy
 python-eventlet
 python-cheetah
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/n-spice b/files/rpms/n-spice
new file mode 100644
index 0000000..24ce15a
--- /dev/null
+++ b/files/rpms/n-spice
@@ -0,0 +1 @@
+numpy
diff --git a/files/rpms/nova b/files/rpms/nova
index 88ad8c3..568ee7f 100644
--- a/files/rpms/nova
+++ b/files/rpms/nova
@@ -10,6 +10,7 @@
 libvirt-bin # NOPRIME
 libvirt-python
 libxml2-python
+numpy # needed by websockify for spice console
 m2crypto
 mysql-server # NOPRIME
 parted
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/files/swift/rsyncd.conf b/files/swift/rsyncd.conf
index 4e0dcbf..c670531 100644
--- a/files/swift/rsyncd.conf
+++ b/files/swift/rsyncd.conf
@@ -1,79 +1,79 @@
 uid = %USER%
 gid = %GROUP%
-log file = /var/log/rsyncd.log
-pid file = /var/run/rsyncd.pid
+log file = %SWIFT_DATA_DIR%/logs/rsyncd.log
+pid file = %SWIFT_DATA_DIR%/run/rsyncd.pid
 address = 127.0.0.1
 
 [account6012]
 max connections = 25
 path = %SWIFT_DATA_DIR%/1/node/
 read only = false
-lock file = /var/lock/account6012.lock
+lock file = %SWIFT_DATA_DIR%/run/account6012.lock
 
 [account6022]
 max connections = 25
 path = %SWIFT_DATA_DIR%/2/node/
 read only = false
-lock file = /var/lock/account6022.lock
+lock file = %SWIFT_DATA_DIR%/run/account6022.lock
 
 [account6032]
 max connections = 25
 path = %SWIFT_DATA_DIR%/3/node/
 read only = false
-lock file = /var/lock/account6032.lock
+lock file = %SWIFT_DATA_DIR%/run/account6032.lock
 
 [account6042]
 max connections = 25
 path = %SWIFT_DATA_DIR%/4/node/
 read only = false
-lock file = /var/lock/account6042.lock
+lock file = %SWIFT_DATA_DIR%/run/account6042.lock
 
 
 [container6011]
 max connections = 25
 path = %SWIFT_DATA_DIR%/1/node/
 read only = false
-lock file = /var/lock/container6011.lock
+lock file = %SWIFT_DATA_DIR%/run/container6011.lock
 
 [container6021]
 max connections = 25
 path = %SWIFT_DATA_DIR%/2/node/
 read only = false
-lock file = /var/lock/container6021.lock
+lock file = %SWIFT_DATA_DIR%/run/container6021.lock
 
 [container6031]
 max connections = 25
 path = %SWIFT_DATA_DIR%/3/node/
 read only = false
-lock file = /var/lock/container6031.lock
+lock file = %SWIFT_DATA_DIR%/run/container6031.lock
 
 [container6041]
 max connections = 25
 path = %SWIFT_DATA_DIR%/4/node/
 read only = false
-lock file = /var/lock/container6041.lock
+lock file = %SWIFT_DATA_DIR%/run/container6041.lock
 
 
 [object6010]
 max connections = 25
 path = %SWIFT_DATA_DIR%/1/node/
 read only = false
-lock file = /var/lock/object6010.lock
+lock file = %SWIFT_DATA_DIR%/run/object6010.lock
 
 [object6020]
 max connections = 25
 path = %SWIFT_DATA_DIR%/2/node/
 read only = false
-lock file = /var/lock/object6020.lock
+lock file = %SWIFT_DATA_DIR%/run/object6020.lock
 
 [object6030]
 max connections = 25
 path = %SWIFT_DATA_DIR%/3/node/
 read only = false
-lock file = /var/lock/object6030.lock
+lock file = %SWIFT_DATA_DIR%/run/object6030.lock
 
 [object6040]
 max connections = 25
 path = %SWIFT_DATA_DIR%/4/node/
 read only = false
-lock file = /var/lock/object6040.lock
+lock file = %SWIFT_DATA_DIR%/run/object6040.lock
diff --git a/functions b/functions
index 7948378..ae63436 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,33 @@
 # 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 [[ -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
-        screen -S $SCREEN_NAME -p $1 -X stuff "$2 || touch \"$SERVICE_DIR/$SCREEN_NAME/$1.failure\"$NL"
+
+        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
+
+            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
     fi
 }
 
@@ -1110,17 +1138,23 @@
 }
 
 
+# Get the path to the direcotry where python executables are installed.
+# get_python_exec_prefix
+function get_python_exec_prefix() {
+    if is_fedora; then
+        echo "/usr/bin"
+    else
+        echo "/usr/local/bin"
+    fi
+}
+
 # Get the location of the $module-rootwrap executables, where module is cinder
 # or nova.
 # get_rootwrap_location module
 function get_rootwrap_location() {
     local module=$1
 
-    if is_fedora; then
-        echo "/usr/bin/$module-rootwrap"
-    else
-        echo "/usr/local/bin/$module-rootwrap"
-    fi
+    echo "$(get_python_exec_prefix)/$module-rootwrap"
 }
 
 # Get the path to the pip command.
diff --git a/lib/baremetal b/lib/baremetal
index 3cc2429..2659386 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.
@@ -397,15 +400,10 @@
 }
 
 function clear_baremetal_of_all_nodes() {
-    list=$(nova-baremetal-manage node list | tail -n +2 | awk '{print $1}' )
+    list=$(nova baremetal-node-list | awk -F '| ' 'NR>3 {print $2}' )
     for node in $list
     do
-        nova-baremetal-manage node delete $node
-    done
-    list=$(nova-baremetal-manage interface list | tail -n +2 | awk '{print $1}' )
-    for iface in $list
-    do
-        nova-baremetal-manage interface delete $iface
+        nova baremetal-node-delete $node
     done
 }
 
@@ -417,16 +415,18 @@
     mac_1=${1:-$BM_FIRST_MAC}
     mac_2=${2:-$BM_SECOND_MAC}
 
-    id=$(nova-baremetal-manage node create \
-       --host=$BM_HOSTNAME --prov_mac=$mac_1 \
-       --cpus=$BM_FLAVOR_CPU --memory_mb=$BM_FLAVOR_RAM \
-       --local_gb=$BM_FLAVOR_ROOT_DISK --terminal_port=0 \
-       --pm_address=$BM_PM_ADDR --pm_user=$BM_PM_USER --pm_password=$BM_PM_PASS \
-       )
+    id=$(nova baremetal-node-create \
+       --pm_address="$BM_PM_ADDR" \
+       --pm_user="$BM_PM_USER" \
+       --pm_password="$BM_PM_PASS" \
+       "$BM_HOSTNAME" \
+       "$BM_FLAVOR_CPU" \
+       "$BM_FLAVOR_RAM" \
+       "$BM_FLAVOR_ROOT_DISK" \
+       "$mac_1" \
+       | grep ' id ' | get_field 2 )
     [ $? -eq 0 ] || [ "$id" ] || die "Error adding baremetal node"
-    id2=$(nova-baremetal-manage interface create \
-       --node_id=$id --mac_address=$mac_2 --datapath_id=0 --port_no=0 \
-       )
+    id2=$(nova baremetal-add-interface "$id" "$mac_2" )
     [ $? -eq 0 ] || [ "$id2" ] || die "Error adding interface to barmetal node $id"
 }
 
diff --git a/lib/ceilometer b/lib/ceilometer
index 0fae397..bc37d92 100644
--- a/lib/ceilometer
+++ b/lib/ceilometer
@@ -40,7 +40,7 @@
 if [ -d $CEILOMETER_DIR/bin ] ; then
     CEILOMETER_BIN_DIR=$CEILOMETER_DIR/bin
 else
-    CEILOMETER_BIN_DIR=/usr/local/bin
+    CEILOMETER_BIN_DIR=$(get_python_exec_prefix)
 fi
 
 # cleanup_ceilometer() - Remove residual data files, anything left over from previous
@@ -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/cinder b/lib/cinder
index 8b1ccd7..4d1ab42 100644
--- a/lib/cinder
+++ b/lib/cinder
@@ -47,7 +47,7 @@
 if [[ -d $CINDER_DIR/bin ]]; then
     CINDER_BIN_DIR=$CINDER_DIR/bin
 else
-    CINDER_BIN_DIR=/usr/local/bin
+    CINDER_BIN_DIR=$(get_python_exec_prefix)
 fi
 
 # Name of the lvm volume group to use/create for iscsi volumes
@@ -172,7 +172,7 @@
     iniset $CINDER_CONF DEFAULT sql_connection $dburl
     iniset $CINDER_CONF DEFAULT api_paste_config $CINDER_API_PASTE_INI
     iniset $CINDER_CONF DEFAULT root_helper "sudo ${CINDER_ROOTWRAP}"
-    iniset $CINDER_CONF DEFAULT osapi_volume_extension cinder.api.openstack.volume.contrib.standard_extensions
+    iniset $CINDER_CONF DEFAULT osapi_volume_extension cinder.api.contrib.standard_extensions
     iniset $CINDER_CONF DEFAULT state_path $CINDER_STATE_PATH
 
     if is_service_enabled tls-proxy; then
@@ -193,10 +193,10 @@
 
     if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then
         # Add color to logging output
-        iniset $CINDER_CONF DEFAULT logging_context_format_string "%(asctime)s.%(msecs)d %(color)s%(levelname)s %(name)s [%(request_id)s %(user_id)s %(project_id)s%(color)s] %(instance)s%(color)s%(message)s"
-        iniset $CINDER_CONF DEFAULT logging_default_format_string "%(asctime)s.%(msecs)d %(color)s%(levelname)s %(name)s [-%(color)s] %(instance)s%(color)s%(message)s"
+        iniset $CINDER_CONF DEFAULT logging_context_format_string "%(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [%(request_id)s %(user_id)s %(project_id)s%(color)s] %(instance)s%(color)s%(message)s"
+        iniset $CINDER_CONF DEFAULT logging_default_format_string "%(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [-%(color)s] %(instance)s%(color)s%(message)s"
         iniset $CINDER_CONF DEFAULT logging_debug_format_suffix "from (pid=%(process)d) %(funcName)s %(pathname)s:%(lineno)d"
-        iniset $CINDER_CONF DEFAULT logging_exception_prefix "%(color)s%(asctime)s.%(msecs)d TRACE %(name)s %(instance)s"
+        iniset $CINDER_CONF DEFAULT logging_exception_prefix "%(color)s%(asctime)s.%(msecs)03d TRACE %(name)s %(instance)s"
     fi
 
     if [ "$CINDER_DRIVER" == "XenAPINFS" ]; then
@@ -209,6 +209,8 @@
             iniset $CINDER_CONF DEFAULT xenapi_nfs_server "$CINDER_XENAPI_NFS_SERVER"
             iniset $CINDER_CONF DEFAULT xenapi_nfs_serverpath "$CINDER_XENAPI_NFS_SERVERPATH"
         )
+    elif [ "$CINDER_DRIVER" == "sheepdog" ]; then
+        iniset $CINDER_CONF DEFAULT volume_driver "cinder.volume.drivers.sheepdog.SheepdogDriver"
     fi
 }
 
@@ -252,37 +254,55 @@
     fi
 }
 
+# create_cinder_cache_dir() - Part of the init_cinder() process
+function create_cinder_cache_dir() {
+    # Create cache dir
+    sudo mkdir -p $CINDER_AUTH_CACHE_DIR
+    sudo chown $STACK_USER $CINDER_AUTH_CACHE_DIR
+    rm -f $CINDER_AUTH_CACHE_DIR/*
+}
+
+create_cinder_volume_group() {
+    # Configure a default volume group called '`stack-volumes`' for the volume
+    # service if it does not yet exist.  If you don't wish to use a file backed
+    # volume group, create your own volume group called ``stack-volumes`` before
+    # invoking ``stack.sh``.
+    #
+    # By default, the backing file is 5G in size, and is stored in ``/opt/stack/data``.
+
+    if ! sudo vgs $VOLUME_GROUP; then
+        VOLUME_BACKING_FILE=${VOLUME_BACKING_FILE:-$DATA_DIR/${VOLUME_GROUP}-backing-file}
+
+        # Only create if the file doesn't already exists
+        [[ -f $VOLUME_BACKING_FILE ]] || truncate -s $VOLUME_BACKING_FILE_SIZE $VOLUME_BACKING_FILE
+
+        DEV=`sudo losetup -f --show $VOLUME_BACKING_FILE`
+
+        # Only create if the loopback device doesn't contain $VOLUME_GROUP
+        if ! sudo vgs $VOLUME_GROUP; then
+            sudo vgcreate $VOLUME_GROUP $DEV
+        fi
+    fi
+
+    mkdir -p $CINDER_STATE_PATH/volumes
+}
+
 # init_cinder() - Initialize database and volume group
 function init_cinder() {
     # Force nova volumes off
     NOVA_ENABLED_APIS=$(echo $NOVA_ENABLED_APIS | sed "s/osapi_volume,//")
 
     if is_service_enabled $DATABASE_BACKENDS; then
-        # (re)create cinder database
+        # (Re)create cinder database
         recreate_database cinder utf8
 
-        # (re)create cinder database
+        # Migrate cinder database
         $CINDER_BIN_DIR/cinder-manage db sync
     fi
 
     if is_service_enabled c-vol; then
-        # Configure a default volume group called '`stack-volumes`' for the volume
-        # service if it does not yet exist.  If you don't wish to use a file backed
-        # volume group, create your own volume group called ``stack-volumes`` before
-        # invoking ``stack.sh``.
-        #
-        # By default, the backing file is 5G in size, and is stored in ``/opt/stack/data``.
 
-        if ! sudo vgs $VOLUME_GROUP; then
-            VOLUME_BACKING_FILE=${VOLUME_BACKING_FILE:-$DATA_DIR/${VOLUME_GROUP}-backing-file}
-            # Only create if the file doesn't already exists
-            [[ -f $VOLUME_BACKING_FILE ]] || truncate -s $VOLUME_BACKING_FILE_SIZE $VOLUME_BACKING_FILE
-            DEV=`sudo losetup -f --show $VOLUME_BACKING_FILE`
-            # Only create if the loopback device doesn't contain $VOLUME_GROUP
-            if ! sudo vgs $VOLUME_GROUP; then sudo vgcreate $VOLUME_GROUP $DEV; fi
-        fi
-
-        mkdir -p $CINDER_STATE_PATH/volumes
+        create_cinder_volume_group
 
         if sudo vgs $VOLUME_GROUP; then
             if is_fedora || is_suse; then
@@ -297,10 +317,7 @@
         fi
     fi
 
-    # Create cache dir
-    sudo mkdir -p $CINDER_AUTH_CACHE_DIR
-    sudo chown $STACK_USER $CINDER_AUTH_CACHE_DIR
-    rm -f $CINDER_AUTH_CACHE_DIR/*
+    create_cinder_cache_dir
 }
 
 # install_cinder() - Collect source and prepare
diff --git a/lib/databases/mysql b/lib/databases/mysql
index 965df6e..94aedc6 100644
--- a/lib/databases/mysql
+++ b/lib/databases/mysql
@@ -5,7 +5,7 @@
 # DATABASE_{HOST,USER,PASSWORD} must be defined
 
 # Save trace setting
-XTRACE=$(set +o | grep xtrace)
+MY_XTRACE=$(set +o | grep xtrace)
 set +o xtrace
 
 register_database mysql
@@ -68,10 +68,10 @@
     sudo sed -i -e "/^\[mysqld\]/ a \
 log-slow-queries = /var/log/mysql/mysql-slow.log" $MY_CONF
 
-    # Log any query taking longer than a second
+    # Log all queries (any query taking longer than 0 seconds)
     sudo sed -i '/long.query.time/d' $MY_CONF
     sudo sed -i -e "/^\[mysqld\]/ a \
-long-query-time = 1" $MY_CONF
+long-query-time = 0" $MY_CONF
 
     # Log all non-indexed queries
     sudo sed -i '/log.queries.not.using.indexes/d' $MY_CONF
@@ -121,4 +121,4 @@
 }
 
 # Restore xtrace
-$XTRACE
+$MY_XTRACE
diff --git a/lib/databases/postgresql b/lib/databases/postgresql
index 04db714..2c37f49 100644
--- a/lib/databases/postgresql
+++ b/lib/databases/postgresql
@@ -5,7 +5,7 @@
 # DATABASE_{HOST,USER,PASSWORD} must be defined
 
 # Save trace setting
-XTRACE=$(set +o | grep xtrace)
+PG_XTRACE=$(set +o | grep xtrace)
 set +o xtrace
 
 register_database postgresql
@@ -76,4 +76,4 @@
 }
 
 # Restore xtrace
-$XTRACE
+$PG_XTRACE
diff --git a/lib/glance b/lib/glance
index 1c56a67..80d3902 100644
--- a/lib/glance
+++ b/lib/glance
@@ -44,7 +44,7 @@
 if [[ -d $GLANCE_DIR/bin ]]; then
     GLANCE_BIN_DIR=$GLANCE_DIR/bin
 else
-    GLANCE_BIN_DIR=/usr/local/bin
+    GLANCE_BIN_DIR=$(get_python_exec_prefix)
 fi
 
 # Glance connection info.  Note the port must be specified.
@@ -141,6 +141,17 @@
     cp -p $GLANCE_DIR/etc/policy.json $GLANCE_POLICY_JSON
 }
 
+# create_glance_cache_dir() - Part of the init_glance() process
+function create_glance_cache_dir() {
+    # Create cache dir
+    sudo mkdir -p $GLANCE_AUTH_CACHE_DIR/api
+    sudo chown $STACK_USER $GLANCE_AUTH_CACHE_DIR/api
+    rm -f $GLANCE_AUTH_CACHE_DIR/api/*
+    sudo mkdir -p $GLANCE_AUTH_CACHE_DIR/registry
+    sudo chown $STACK_USER $GLANCE_AUTH_CACHE_DIR/registry
+    rm -f $GLANCE_AUTH_CACHE_DIR/registry/*
+}
+
 # init_glance() - Initialize databases, etc.
 function init_glance() {
     # Delete existing images
@@ -151,18 +162,13 @@
     rm -rf $GLANCE_CACHE_DIR
     mkdir -p $GLANCE_CACHE_DIR
 
-    # (re)create glance database
+    # (Re)create glance database
     recreate_database glance utf8
 
+    # Migrate glance database
     $GLANCE_BIN_DIR/glance-manage db_sync
 
-    # Create cache dir
-    sudo mkdir -p $GLANCE_AUTH_CACHE_DIR/api
-    sudo chown $STACK_USER $GLANCE_AUTH_CACHE_DIR/api
-    rm -f $GLANCE_AUTH_CACHE_DIR/api/*
-    sudo mkdir -p $GLANCE_AUTH_CACHE_DIR/registry
-    sudo chown $STACK_USER $GLANCE_AUTH_CACHE_DIR/registry
-    rm -f $GLANCE_AUTH_CACHE_DIR/registry/*
+    create_glance_cache_dir
 }
 
 # install_glanceclient() - Collect source and prepare
diff --git a/lib/keystone b/lib/keystone
index 7a70cc4..866c62e 100644
--- a/lib/keystone
+++ b/lib/keystone
@@ -39,6 +39,9 @@
 KEYSTONE_CATALOG_BACKEND=${KEYSTONE_CATALOG_BACKEND:-sql}
 KEYSTONE_CATALOG=$KEYSTONE_CONF_DIR/default_catalog.templates
 
+# Select the backend for Tokens
+KEYSTONE_TOKEN_BACKEND=${KEYSTONE_TOKEN_BACKEND:-sql}
+
 # Select Keystone's token format
 # Choose from 'UUID' and 'PKI'
 KEYSTONE_TOKEN_FORMAT=${KEYSTONE_TOKEN_FORMAT:-PKI}
@@ -91,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
@@ -108,6 +122,12 @@
     # Append the S3 bits
     iniset $KEYSTONE_CONF filter:s3_extension paste.filter_factory "keystone.contrib.s3:S3Extension.factory"
 
+    if [[ "$KEYSTONE_TOKEN_BACKEND" = "sql" ]]; then
+        iniset $KEYSTONE_CONF token driver keystone.token.backends.sql.Token
+    else
+        iniset $KEYSTONE_CONF token driver keystone.token.backends.kvs.Token
+    fi
+
     if [[ "$KEYSTONE_CATALOG_BACKEND" = "sql" ]]; then
         # Configure ``keystone.conf`` to use sql
         iniset $KEYSTONE_CONF catalog driver keystone.catalog.backends.sql.Catalog
@@ -274,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/nova b/lib/nova
index 8135bf1..849ec57 100644
--- a/lib/nova
+++ b/lib/nova
@@ -49,7 +49,7 @@
 if [[ -d $NOVA_DIR/bin ]]; then
     NOVA_BIN_DIR=$NOVA_DIR/bin
 else
-    NOVA_BIN_DIR=/usr/local/bin
+    NOVA_BIN_DIR=$(get_python_exec_prefix)
 fi
 
 # Set the paths of certain binaries
@@ -166,20 +166,13 @@
         # Get the sample configuration file in place
         cp $NOVA_DIR/etc/nova/api-paste.ini $NOVA_CONF_DIR
 
-        # Rewrite the authtoken configuration for our Keystone service.
-        # This is a bit defensive to allow the sample file some variance.
-        sed -e "
-            /^admin_token/i admin_tenant_name = $SERVICE_TENANT_NAME
-            /admin_tenant_name/s/^.*$/admin_tenant_name = $SERVICE_TENANT_NAME/;
-            /admin_user/s/^.*$/admin_user = nova/;
-            /admin_password/s/^.*$/admin_password = $SERVICE_PASSWORD/;
-            s,%SERVICE_TENANT_NAME%,$SERVICE_TENANT_NAME,g;
-            s,%SERVICE_TOKEN%,$SERVICE_TOKEN,g;
-        " -i $NOVA_API_PASTE_INI
         iniset $NOVA_API_PASTE_INI filter:authtoken auth_host $SERVICE_HOST
         if is_service_enabled tls-proxy; then
             iniset $NOVA_API_PASTE_INI filter:authtoken auth_protocol $SERVICE_PROTOCOL
         fi
+        iniset $NOVA_API_PASTE_INI filter:authtoken admin_tenant_name $SERVICE_TENANT_NAME
+        iniset $NOVA_API_PASTE_INI filter:authtoken admin_user nova
+        iniset $NOVA_API_PASTE_INI filter:authtoken admin_password $SERVICE_PASSWORD
     fi
 
     iniset $NOVA_API_PASTE_INI filter:authtoken signing_dir $NOVA_AUTH_CACHE_DIR
@@ -229,7 +222,7 @@
             configure_baremetal_nova_dirs
         fi
 
-        if is_service_enabled quantum && is_quantum_ovs_base_plugin "$Q_PLUGIN" && ! sudo grep -q '^cgroup_device_acl' $QEMU_CONF ; then
+        if is_service_enabled quantum && is_quantum_ovs_base_plugin && ! sudo grep -q '^cgroup_device_acl' $QEMU_CONF ; then
             # Add /dev/net/tun to cgroup_device_acls, needed for type=ethernet interfaces
             cat <<EOF | sudo tee -a $QEMU_CONF
 cgroup_device_acl = [
@@ -247,11 +240,25 @@
             LIBVIRT_DAEMON=libvirtd
         fi
 
-        # For distributions using polkit to authorize access to libvirt,
-        # configure polkit accordingly.
-        # Based on http://wiki.libvirt.org/page/SSHPolicyKitSetup
+
+
         if is_fedora; then
-            sudo bash -c 'cat <<EOF >/etc/polkit-1/localauthority/50-local.d/50-libvirt-remote-access.pkla
+            # Starting with fedora 18 enable stack-user to virsh -c qemu:///system
+            # by creating a policy-kit rule for stack-user
+            if [[ "$os_RELEASE" -ge "18" ]]; then
+                rules_dir=/etc/polkit-1/rules.d
+                sudo mkdir -p $rules_dir
+                sudo bash -c "cat <<EOF > $rules_dir/50-libvirt-$STACK_USER.rules
+polkit.addRule(function(action, subject) {
+     if (action.id == 'org.libvirt.unix.manage' &&
+         subject.user == '"$STACK_USER"') {
+         return polkit.Result.YES;
+     }
+});
+EOF"
+                unset rules_dir
+            else
+                sudo bash -c 'cat <<EOF >/etc/polkit-1/localauthority/50-local.d/50-libvirt-remote-access.pkla
 [libvirt Management Access]
 Identity=unix-group:libvirtd
 Action=org.libvirt.unix.manage
@@ -259,6 +266,7 @@
 ResultInactive=yes
 ResultActive=yes
 EOF'
+            fi
         elif is_suse; then
             # Work around the fact that polkit-default-privs overrules pklas
             # with 'unix-group:$group'.
@@ -355,6 +363,7 @@
     rm -f $NOVA_CONF
     add_nova_opt "[DEFAULT]"
     iniset $NOVA_CONF DEFAULT verbose "True"
+    iniset $NOVA_CONF DEFAULT debug "True"
     iniset $NOVA_CONF DEFAULT auth_strategy "keystone"
     iniset $NOVA_CONF DEFAULT allow_resize_to_same_host "True"
     iniset $NOVA_CONF DEFAULT api_paste_config "$NOVA_API_PASTE_INI"
@@ -408,13 +417,13 @@
     fi
     if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ]; then
         # Add color to logging output
-        iniset $NOVA_CONF DEFAULT logging_context_format_string "%(asctime)s.%(msecs)d %(color)s%(levelname)s %(name)s [%(request_id)s %(user_name)s %(project_name)s%(color)s] %(instance)s%(color)s%(message)s"
-        iniset $NOVA_CONF DEFAULT logging_default_format_string "%(asctime)s.%(msecs)d %(color)s%(levelname)s %(name)s [-%(color)s] %(instance)s%(color)s%(message)s"
+        iniset $NOVA_CONF DEFAULT logging_context_format_string "%(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [%(request_id)s %(user_name)s %(project_name)s%(color)s] %(instance)s%(color)s%(message)s"
+        iniset $NOVA_CONF DEFAULT logging_default_format_string "%(asctime)s.%(msecs)03d %(color)s%(levelname)s %(name)s [-%(color)s] %(instance)s%(color)s%(message)s"
         iniset $NOVA_CONF DEFAULT logging_debug_format_suffix "from (pid=%(process)d) %(funcName)s %(pathname)s:%(lineno)d"
-        iniset $NOVA_CONF DEFAULT logging_exception_prefix "%(color)s%(asctime)s.%(msecs)d TRACE %(name)s %(instance)s"
+        iniset $NOVA_CONF DEFAULT logging_exception_prefix "%(color)s%(asctime)s.%(msecs)03d TRACE %(name)s %(instance)s"
     else
         # Show user_name and project_name instead of user_id and project_id
-        iniset $NOVA_CONF DEFAULT logging_context_format_string "%(asctime)s.%(msecs)d %(levelname)s %(name)s [%(request_id)s %(user_name)s %(project_name)s] %(instance)s%(message)s"
+        iniset $NOVA_CONF DEFAULT logging_context_format_string "%(asctime)s.%(msecs)03d %(levelname)s %(name)s [%(request_id)s %(user_name)s %(project_name)s] %(instance)s%(message)s"
     fi
     if is_service_enabled ceilometer; then
         iniset $NOVA_CONF DEFAULT instance_usage_audit "True"
@@ -437,6 +446,14 @@
     done
 }
 
+# create_nova_cache_dir() - Part of the init_nova() process
+function create_nova_cache_dir() {
+    # Create cache dir
+    sudo mkdir -p $NOVA_AUTH_CACHE_DIR
+    sudo chown $STACK_USER $NOVA_AUTH_CACHE_DIR
+    rm -f $NOVA_AUTH_CACHE_DIR/*
+}
+
 function create_nova_conf_nova_network() {
     iniset $NOVA_CONF DEFAULT network_manager "nova.network.manager.$NET_MAN"
     iniset $NOVA_CONF DEFAULT public_interface "$PUBLIC_INTERFACE"
@@ -447,14 +464,17 @@
     fi
 }
 
+# create_nova_keys_dir() - Part of the init_nova() process
+function create_nova_keys_dir() {
+    # Create keys dir
+    sudo mkdir -p ${NOVA_STATE_PATH}/keys
+    sudo chown -R $STACK_USER ${NOVA_STATE_PATH}
+}
+
 # init_nova() - Initialize databases, etc.
 function init_nova() {
-    # Nova Database
-    # -------------
-
-    # All nova components talk to a central database.  We will need to do this step
-    # only once for an entire cluster.
-
+    # All nova components talk to a central database.
+    # Only do this step once on the API node for an entire cluster.
     if is_service_enabled $DATABASE_BACKENDS && is_service_enabled n-api; then
         # (Re)create nova database
         # Explicitly use latin1: to avoid lp#829209, nova expects the database to
@@ -462,7 +482,7 @@
         # 082_essex.py in nova)
         recreate_database nova latin1
 
-        # (Re)create nova database
+        # Migrate nova database
         $NOVA_BIN_DIR/nova-manage db sync
 
         # (Re)create nova baremetal database
@@ -472,15 +492,8 @@
         fi
     fi
 
-    # Create cache dir
-    sudo mkdir -p $NOVA_AUTH_CACHE_DIR
-    sudo chown $STACK_USER $NOVA_AUTH_CACHE_DIR
-    rm -f $NOVA_AUTH_CACHE_DIR/*
-
-    # Create the keys folder
-    sudo mkdir -p ${NOVA_STATE_PATH}/keys
-    # make sure we own NOVA_STATE_PATH and all subdirs
-    sudo chown -R $STACK_USER ${NOVA_STATE_PATH}
+    create_nova_cache_dir
+    create_nova_keys_dir
 }
 
 # install_novaclient() - Collect source and prepare
@@ -549,15 +562,16 @@
     screen_it n-crt "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-cert"
     screen_it n-net "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-network"
     screen_it n-sch "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-scheduler"
-    screen_it n-novnc "cd $NOVNC_DIR && ./utils/nova-novncproxy --config-file $NOVA_CONF --web ."
+    screen_it n-novnc "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-novncproxy --config-file $NOVA_CONF --web $NOVNC_DIR"
     screen_it n-xvnc "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-xvpvncproxy --config-file $NOVA_CONF"
+    screen_it n-spice "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-spicehtml5proxy --config-file $NOVA_CONF --web $SPICE_DIR"
     screen_it n-cauth "cd $NOVA_DIR && $NOVA_BIN_DIR/nova-consoleauth"
 }
 
 # stop_nova() - Stop running processes (non-screen)
 function stop_nova() {
     # Kill the nova screen windows
-    for serv in n-api n-cpu n-crt n-net n-sch n-novnc n-xvnc n-cauth n-cond; do
+    for serv in n-api n-cpu n-crt n-net n-sch n-novnc n-xvnc n-cauth n-cond n-spice; do
         screen -S $SCREEN_NAME -p $serv -X kill
     done
 }
diff --git a/lib/quantum b/lib/quantum
index 788db53..f3a3ec4 100644
--- a/lib/quantum
+++ b/lib/quantum
@@ -171,6 +171,11 @@
     OVS_ENABLE_TUNNELING=${OVS_ENABLE_TUNNELING:-$ENABLE_TENANT_TUNNELS}
 fi
 
+# Quantum plugin specific functions
+# ---------------------------------
+# Please refer to lib/quantum_plugins/README.md for details.
+source $TOP_DIR/lib/quantum_plugins/$Q_PLUGIN
+
 # Entry Points
 # ------------
 
@@ -210,22 +215,9 @@
     iniset $NOVA_CONF DEFAULT quantum_admin_tenant_name "$SERVICE_TENANT_NAME"
     iniset $NOVA_CONF DEFAULT quantum_url "http://$Q_HOST:$Q_PORT"
 
-    if [[ "$Q_PLUGIN" = "openvswitch" ]]; then
-        NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.LibvirtHybridOVSBridgeDriver"}
-        if [ "$VIRT_DRIVER" = 'xenserver' ]; then
-            add_nova_opt "xenapi_vif_driver=nova.virt.xenapi.vif.XenAPIOpenVswitchDriver"
-            add_nova_opt "xenapi_ovs_integration_bridge=$FLAT_NETWORK_BRIDGE"
-        fi
-    elif [[ "$Q_PLUGIN" = "linuxbridge" ]]; then
-        NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.QuantumLinuxBridgeVIFDriver"}
-    elif [[ "$Q_PLUGIN" = "ryu" ]]; then
-        NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"quantum.plugins.ryu.nova.vif.LibvirtOpenVswitchOFPRyuDriver"}
-        iniset $NOVA_CONF DEFAULT libvirt_ovs_integration_bridge "$OVS_BRIDGE"
-        iniset $NOVA_CONF DEFAULT linuxnet_ovs_ryu_api_host "$RYU_API_HOST:$RYU_API_PORT"
-        iniset $NOVA_CONF DEFAULT libvirt_ovs_ryu_api_host "$RYU_API_HOST:$RYU_API_PORT"
-    elif [[ "$Q_PLUGIN" = "bigswitch_floodlight" ]]; then
-        NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.LibvirtHybridOVSBridgeDriver"}
-    fi
+    # set NOVA_VIF_DRIVER and optionally set options in nova_conf
+    quantum_plugin_create_nova_conf
+
     iniset $NOVA_CONF DEFAULT libvirt_vif_driver "$NOVA_VIF_DRIVER"
     iniset $NOVA_CONF DEFAULT linuxnet_interface_driver "$LINUXNET_VIF_DRIVER"
     if is_service_enabled q-meta; then
@@ -278,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
@@ -297,7 +300,7 @@
         EXT_GW_IP=$(quantum subnet-create --ip_version 4 $EXT_NET_ID $FLOATING_RANGE -- --enable_dhcp=False | grep 'gateway_ip' | get_field 2)
         quantum router-gateway-set $ROUTER_ID $EXT_NET_ID
 
-        if is_quantum_ovs_base_plugin "$Q_PLUGIN" && [[ "$Q_USE_NAMESPACE" = "True" ]]; then
+        if is_quantum_ovs_base_plugin && [[ "$Q_USE_NAMESPACE" = "True" ]]; then
             CIDR_LEN=${FLOATING_RANGE#*/}
             sudo ip addr add $EXT_GW_IP/$CIDR_LEN dev $PUBLIC_BRIDGE
             sudo ip link set $PUBLIC_BRIDGE up
@@ -328,29 +331,8 @@
 
 # install_quantum_agent_packages() - Collect source and prepare
 function install_quantum_agent_packages() {
-    if is_quantum_ovs_base_plugin "$Q_PLUGIN"; then
-        # Install deps
-        # FIXME add to ``files/apts/quantum``, but don't install if not needed!
-        if is_ubuntu; then
-            kernel_version=`cat /proc/version | cut -d " " -f3`
-            install_package make fakeroot dkms openvswitch-switch openvswitch-datapath-dkms linux-headers-$kernel_version
-        else
-            ### FIXME(dtroyer): Find RPMs for OpenVSwitch
-            echo "OpenVSwitch packages need to be located"
-            # Fedora does not started OVS by default
-            restart_service openvswitch
-        fi
-    elif [[ "$Q_PLUGIN" = "linuxbridge" ]]; then
-       install_package bridge-utils
-    fi
-}
-
-function is_quantum_ovs_base_plugin() {
-    local plugin=$1
-    if [[ ",openvswitch,ryu,bigswitch_floodlight," =~ ,${plugin}, ]]; then
-        return 0
-    fi
-    return 1
+    # install packages that is specific to plugin agent
+    quantum_plugin_install_agent_packages
 }
 
 function setup_quantum() {
@@ -407,29 +389,9 @@
 
     cp $QUANTUM_DIR/etc/quantum.conf $QUANTUM_CONF
 
-    if [[ "$Q_PLUGIN" = "openvswitch" ]]; then
-        Q_PLUGIN_CONF_PATH=etc/quantum/plugins/openvswitch
-        Q_PLUGIN_CONF_FILENAME=ovs_quantum_plugin.ini
-        Q_DB_NAME="ovs_quantum"
-        Q_PLUGIN_CLASS="quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2"
-    elif [[ "$Q_PLUGIN" = "linuxbridge" ]]; then
-        Q_PLUGIN_CONF_PATH=etc/quantum/plugins/linuxbridge
-        Q_PLUGIN_CONF_FILENAME=linuxbridge_conf.ini
-        Q_DB_NAME="quantum_linux_bridge"
-        Q_PLUGIN_CLASS="quantum.plugins.linuxbridge.lb_quantum_plugin.LinuxBridgePluginV2"
-    elif [[ "$Q_PLUGIN" = "ryu" ]]; then
-        Q_PLUGIN_CONF_PATH=etc/quantum/plugins/ryu
-        Q_PLUGIN_CONF_FILENAME=ryu.ini
-        Q_DB_NAME="ovs_quantum"
-        Q_PLUGIN_CLASS="quantum.plugins.ryu.ryu_quantum_plugin.RyuQuantumPluginV2"
-    elif [[ "$Q_PLUGIN" = "bigswitch_floodlight" ]]; then
-        Q_PLUGIN_CONF_PATH=etc/quantum/plugins/bigswitch
-        Q_PLUGIN_CONF_FILENAME=restproxy.ini
-        Q_DB_NAME="restproxy_quantum"
-        Q_PLUGIN_CLASS="quantum.plugins.bigswitch.plugin.QuantumRestProxyV2"
-        BS_FL_CONTROLLERS_PORT=${BS_FL_CONTROLLERS_PORT:-localhost:80}
-        BS_FL_CONTROLLER_TIMEOUT=${BS_FL_CONTROLLER_TIMEOUT:-10}
-    fi
+    # set plugin-specific variables
+    # Q_PLUGIN_CONF_PATH, Q_PLUGIN_CONF_FILENAME, Q_DB_NAME, Q_PLUGIN_CLASS
+    quantum_plugin_configure_common
 
     if [[ $Q_PLUGIN_CONF_PATH == '' || $Q_PLUGIN_CONF_FILENAME == '' || $Q_PLUGIN_CLASS == '' ]]; then
         echo "Quantum plugin not set.. exiting"
@@ -459,19 +421,14 @@
     iniset $QUANTUM_TEST_CONFIG_FILE DEFAULT debug False
     iniset $QUANTUM_TEST_CONFIG_FILE DEFAULT use_namespaces $Q_USE_NAMESPACE
     iniset $QUANTUM_TEST_CONFIG_FILE DEFAULT root_helper "$Q_RR_COMMAND"
+    # Intermediate fix until Quantum patch lands and then line above will
+    # be cleaned.
+    iniset $QUANTUM_TEST_CONFIG_FILE AGENT root_helper "$Q_RR_COMMAND"
 
     _quantum_setup_keystone $QUANTUM_TEST_CONFIG_FILE DEFAULT set_auth_url
     _quantum_setup_interface_driver $QUANTUM_TEST_CONFIG_FILE
 
-    if is_quantum_ovs_base_plugin "$Q_PLUGIN"; then
-        iniset $QUANTUM_TEST_CONFIG_FILE DEFAULT external_network_bridge $PUBLIC_BRIDGE
-    elif [[ "$Q_PLUGIN" = "linuxbridge" ]]; then
-        iniset $QUANTUM_TEST_CONFIG_FILE DEFAULT external_network_bridge ''
-    fi
-
-    if [[ "$Q_PLUGIN" = "ryu" ]]; then
-        iniset $QUANTUM_TEST_CONFIG_FILE DEFAULT ryu_api_host $RYU_API_HOST:$RYU_API_PORT
-    fi
+    quantum_plugin_configure_debug_command
 }
 
 function _configure_quantum_dhcp_agent() {
@@ -489,9 +446,7 @@
     _quantum_setup_keystone $Q_DHCP_CONF_FILE DEFAULT set_auth_url
     _quantum_setup_interface_driver $Q_DHCP_CONF_FILE
 
-    if [[ "$Q_PLUGIN" = "ryu" ]]; then
-        iniset $Q_DHCP_CONF_FILE DEFAULT ryu_api_host $RYU_API_HOST:$RYU_API_PORT
-    fi
+    quantum_plugin_configure_dhcp_agent
 }
 
 function _configure_quantum_l3_agent() {
@@ -510,16 +465,7 @@
     _quantum_setup_keystone $Q_L3_CONF_FILE DEFAULT set_auth_url
     _quantum_setup_interface_driver $Q_L3_CONF_FILE
 
-    if is_quantum_ovs_base_plugin "$Q_PLUGIN"; then
-        iniset $Q_L3_CONF_FILE DEFAULT external_network_bridge $PUBLIC_BRIDGE
-        _quantum_setup_external_bridge $PUBLIC_BRIDGE
-    elif [[ "$Q_PLUGIN" = "linuxbridge" ]]; then
-        iniset $Q_L3_CONF_FILE DEFAULT external_network_bridge ''
-    fi
-
-    if [[ "$Q_PLUGIN" = "ryu" ]]; then
-        iniset $Q_L3_CONF_FILE DEFAULT ryu_api_host $RYU_API_HOST:$RYU_API_PORT
-    fi
+    quantum_plugin_configure_l3_agent
 }
 
 function _configure_quantum_metadata_agent() {
@@ -540,111 +486,12 @@
 # _configure_quantum_plugin_agent() - Set config files for quantum plugin agent
 # It is called when q-agt is enabled.
 function _configure_quantum_plugin_agent() {
-
     # Specify the default root helper prior to agent configuration to
-    # ensure that an agent's configuration can override the default.
+    # ensure that an agent's configuration can override the default
     iniset /$Q_PLUGIN_CONF_FILE AGENT root_helper "$Q_RR_COMMAND"
 
     # Configure agent for plugin
-    if [[ "$Q_PLUGIN" = "openvswitch" ]]; then
-        _configure_quantum_plugin_agent_openvswitch
-    elif [[ "$Q_PLUGIN" = "linuxbridge" ]]; then
-        _configure_quantum_plugin_agent_linuxbridge
-    elif [[ "$Q_PLUGIN" = "ryu" ]]; then
-        _configure_quantum_plugin_agent_ryu
-    fi
-}
-
-function _configure_quantum_plugin_agent_linuxbridge() {
-    # Setup physical network interface mappings.  Override
-    # ``LB_VLAN_RANGES`` and ``LB_INTERFACE_MAPPINGS`` in ``localrc`` for more
-    # complex physical network configurations.
-    if [[ "$LB_INTERFACE_MAPPINGS" = "" ]] && [[ "$PHYSICAL_NETWORK" != "" ]] && [[ "$LB_PHYSICAL_INTERFACE" != "" ]]; then
-        LB_INTERFACE_MAPPINGS=$PHYSICAL_NETWORK:$LB_PHYSICAL_INTERFACE
-    fi
-    if [[ "$LB_INTERFACE_MAPPINGS" != "" ]]; then
-        iniset /$Q_PLUGIN_CONF_FILE LINUX_BRIDGE physical_interface_mappings $LB_INTERFACE_MAPPINGS
-    fi
-    AGENT_BINARY="$QUANTUM_DIR/bin/quantum-linuxbridge-agent"
-}
-
-function _configure_quantum_plugin_agent_openvswitch() {
-    # Setup integration bridge
-    OVS_BRIDGE=${OVS_BRIDGE:-br-int}
-    _quantum_setup_ovs_bridge $OVS_BRIDGE
-
-    # Setup agent for tunneling
-    if [[ "$OVS_ENABLE_TUNNELING" = "True" ]]; then
-        # Verify tunnels are supported
-        # REVISIT - also check kernel module support for GRE and patch ports
-        OVS_VERSION=`ovs-vsctl --version | head -n 1 | awk '{print $4;}'`
-        if [ $OVS_VERSION \< "1.4" ] && ! is_service_enabled q-svc ; then
-            echo "You are running OVS version $OVS_VERSION."
-            echo "OVS 1.4+ is required for tunneling between multiple hosts."
-            exit 1
-        fi
-        iniset /$Q_PLUGIN_CONF_FILE OVS enable_tunneling True
-        iniset /$Q_PLUGIN_CONF_FILE OVS local_ip $HOST_IP
-    fi
-
-    # Setup physical network bridge mappings.  Override
-    # ``OVS_VLAN_RANGES`` and ``OVS_BRIDGE_MAPPINGS`` in ``localrc`` for more
-    # complex physical network configurations.
-    if [[ "$OVS_BRIDGE_MAPPINGS" = "" ]] && [[ "$PHYSICAL_NETWORK" != "" ]] && [[ "$OVS_PHYSICAL_BRIDGE" != "" ]]; then
-        OVS_BRIDGE_MAPPINGS=$PHYSICAL_NETWORK:$OVS_PHYSICAL_BRIDGE
-
-        # Configure bridge manually with physical interface as port for multi-node
-        sudo ovs-vsctl --no-wait -- --may-exist add-br $OVS_PHYSICAL_BRIDGE
-    fi
-    if [[ "$OVS_BRIDGE_MAPPINGS" != "" ]]; then
-        iniset /$Q_PLUGIN_CONF_FILE OVS bridge_mappings $OVS_BRIDGE_MAPPINGS
-    fi
-    AGENT_BINARY="$QUANTUM_DIR/bin/quantum-openvswitch-agent"
-
-    if [ "$VIRT_DRIVER" = 'xenserver' ]; then
-        # Nova will always be installed along with quantum for a domU
-        # devstack install, so it should be safe to rely on nova.conf
-        # for xenapi configuration.
-        Q_RR_DOM0_COMMAND="$QUANTUM_DIR/bin/quantum-rootwrap-dom0 $NOVA_CONF"
-        # Under XS/XCP, the ovs agent needs to target the dom0
-        # integration bridge.  This is enabled by using a root wrapper
-        # that executes commands on dom0 via a XenAPI plugin.
-        iniset /$Q_PLUGIN_CONF_FILE AGENT root_helper "$Q_RR_DOM0_COMMAND"
-
-        # FLAT_NETWORK_BRIDGE is the dom0 integration bridge.  To
-        # ensure the bridge lacks direct connectivity, set
-        # VM_VLAN=-1;VM_DEV=invalid in localrc
-        iniset /$Q_PLUGIN_CONF_FILE OVS integration_bridge $FLAT_NETWORK_BRIDGE
-
-        # The ovs agent needs to ensure that the ports associated with
-        # a given network share the same local vlan tag.  On
-        # single-node XS/XCP, this requires monitoring both the dom0
-        # bridge, where VM's are attached, and the domU bridge, where
-        # dhcp servers are attached.
-        if is_service_enabled q-dhcp; then
-            iniset /$Q_PLUGIN_CONF_FILE OVS domu_integration_bridge $OVS_BRIDGE
-            # DomU will use the regular rootwrap
-            iniset /$Q_PLUGIN_CONF_FILE AGENT domu_root_helper "$Q_RR_COMMAND"
-            # Plug the vm interface into the domU integration bridge.
-            sudo ip addr flush dev $GUEST_INTERFACE_DEFAULT
-            sudo ip link set $OVS_BRIDGE up
-            # Assign the VM IP only if it has been set explicitly
-            if [[ "$VM_IP" != "" ]]; then
-                sudo ip addr add $VM_IP dev $OVS_BRIDGE
-            fi
-            sudo ovs-vsctl add-port $OVS_BRIDGE $GUEST_INTERFACE_DEFAULT
-        fi
-    fi
-}
-
-function _configure_quantum_plugin_agent_ryu() {
-    # Set up integration bridge
-    OVS_BRIDGE=${OVS_BRIDGE:-br-int}
-    _quantum_setup_ovs_bridge $OVS_BRIDGE
-    if [ -n "$RYU_INTERNAL_INTERFACE" ]; then
-        sudo ovs-vsctl --no-wait -- --may-exist add-port $OVS_BRIDGE $RYU_INTERNAL_INTERFACE
-    fi
-    AGENT_BINARY="$QUANTUM_DIR/quantum/plugins/ryu/agent/ryu_quantum_agent.py"
+    quantum_plugin_configure_plugin_agent
 }
 
 # _configure_quantum_service() - Set config files for quantum service
@@ -671,60 +518,14 @@
     iniset $QUANTUM_CONF DEFAULT allow_overlapping_ips $Q_ALLOW_OVERLAPPING_IP
 
     iniset $QUANTUM_CONF DEFAULT auth_strategy $Q_AUTH_STRATEGY
-    _quantum_setup_keystone $Q_API_PASTE_FILE filter:authtoken
+    _quantum_setup_keystone $QUANTUM_CONF keystone_authtoken
+    # Comment out keystone authtoken configuration in api-paste.ini
+    # It is required to avoid any breakage in Quantum where the sample
+    # api-paste.ini has authtoken configurations.
+    _quantum_commentout_keystone_authtoken $Q_API_PASTE_FILE filter:authtoken
 
     # Configure plugin
-    if [[ "$Q_PLUGIN" = "openvswitch" ]]; then
-        if [[ "$ENABLE_TENANT_TUNNELS" = "True" ]]; then
-            iniset /$Q_PLUGIN_CONF_FILE OVS tenant_network_type gre
-            iniset /$Q_PLUGIN_CONF_FILE OVS tunnel_id_ranges $TENANT_TUNNEL_RANGES
-        elif [[ "$ENABLE_TENANT_VLANS" = "True" ]]; then
-            iniset /$Q_PLUGIN_CONF_FILE OVS tenant_network_type vlan
-        else
-            echo "WARNING - The openvswitch plugin is using local tenant networks, with no connectivity between hosts."
-        fi
-
-        # Override ``OVS_VLAN_RANGES`` and ``OVS_BRIDGE_MAPPINGS`` in ``localrc``
-        # for more complex physical network configurations.
-        if [[ "$OVS_VLAN_RANGES" = "" ]] && [[ "$PHYSICAL_NETWORK" != "" ]]; then
-            OVS_VLAN_RANGES=$PHYSICAL_NETWORK
-            if [[ "$TENANT_VLAN_RANGE" != "" ]]; then
-                OVS_VLAN_RANGES=$OVS_VLAN_RANGES:$TENANT_VLAN_RANGE
-            fi
-        fi
-        if [[ "$OVS_VLAN_RANGES" != "" ]]; then
-            iniset /$Q_PLUGIN_CONF_FILE OVS network_vlan_ranges $OVS_VLAN_RANGES
-        fi
-
-        # Enable tunnel networks if selected
-        if [[ $OVS_ENABLE_TUNNELING = "True" ]]; then
-            iniset /$Q_PLUGIN_CONF_FILE OVS enable_tunneling True
-        fi
-    elif [[ "$Q_PLUGIN" = "linuxbridge" ]]; then
-        if [[ "$ENABLE_TENANT_VLANS" = "True" ]]; then
-            iniset /$Q_PLUGIN_CONF_FILE VLANS tenant_network_type vlan
-        else
-            echo "WARNING - The linuxbridge plugin is using local tenant networks, with no connectivity between hosts."
-        fi
-
-        # Override ``LB_VLAN_RANGES`` and ``LB_INTERFACE_MAPPINGS`` in ``localrc``
-        # for more complex physical network configurations.
-        if [[ "$LB_VLAN_RANGES" = "" ]] && [[ "$PHYSICAL_NETWORK" != "" ]]; then
-            LB_VLAN_RANGES=$PHYSICAL_NETWORK
-            if [[ "$TENANT_VLAN_RANGE" != "" ]]; then
-                LB_VLAN_RANGES=$LB_VLAN_RANGES:$TENANT_VLAN_RANGE
-            fi
-        fi
-        if [[ "$LB_VLAN_RANGES" != "" ]]; then
-            iniset /$Q_PLUGIN_CONF_FILE VLANS network_vlan_ranges $LB_VLAN_RANGES
-        fi
-    elif [[ "$Q_PLUGIN" = "ryu" ]]; then
-        iniset /$Q_PLUGIN_CONF_FILE OVS openflow_controller $RYU_OFP_HOST:$RYU_OFP_PORT
-        iniset /$Q_PLUGIN_CONF_FILE OVS openflow_rest_api $RYU_API_HOST:$RYU_API_PORT
-    elif [[ "$Q_PLUGIN" = "bigswitch_floodlight" ]]; then
-        iniset /$Q_PLUGIN_CONF_FILE RESTPROXY servers $BS_FL_CONTROLLERS_PORT
-        iniset /$Q_PLUGIN_CONF_FILE RESTPROXY servertimeout $BS_FL_CONTROLLER_TIMEOUT
-    fi
+    quantum_plugin_configure_service
 }
 
 # Utility Functions
@@ -760,6 +561,9 @@
     chmod 0440 $TEMPFILE
     sudo chown root:root $TEMPFILE
     sudo mv $TEMPFILE /etc/sudoers.d/quantum-rootwrap
+
+    # Update the root_helper
+    iniset $QUANTUM_CONF AGENT root_helper "$Q_RR_COMMAND"
 }
 
 # Configures keystone integration for quantum service and agents
@@ -784,32 +588,23 @@
     rm -f $QUANTUM_AUTH_CACHE_DIR/*
 }
 
-function _quantum_setup_ovs_bridge() {
-    local bridge=$1
-    quantum-ovs-cleanup --ovs_integration_bridge $bridge
-    sudo ovs-vsctl --no-wait -- --may-exist add-br $bridge
-    sudo ovs-vsctl --no-wait br-set-external-id $bridge bridge-id $bridge
+function _quantum_commentout_keystone_authtoken() {
+    local conf_file=$1
+    local section=$2
+
+    inicomment $conf_file $section auth_host
+    inicomment $conf_file $section auth_port
+    inicomment $conf_file $section auth_protocol
+    inicomment $conf_file $section auth_url
+
+    inicomment $conf_file $section admin_tenant_name
+    inicomment $conf_file $section admin_user
+    inicomment $conf_file $section admin_password
+    inicomment $conf_file $section signing_dir
 }
 
 function _quantum_setup_interface_driver() {
-    local conf_file=$1
-    if [[ "$Q_PLUGIN" == "openvswitch" ]]; then
-        iniset $conf_file DEFAULT interface_driver quantum.agent.linux.interface.OVSInterfaceDriver
-    elif [[ "$Q_PLUGIN" = "linuxbridge" ]]; then
-        iniset $conf_file DEFAULT interface_driver quantum.agent.linux.interface.BridgeInterfaceDriver
-    elif [[ "$Q_PLUGIN" = "ryu" ]]; then
-        iniset $conf_file DEFAULT interface_driver quantum.agent.linux.interface.RyuInterfaceDriver
-    elif [[ "$Q_PLUGIN" = "bigswitch_floodlight" ]]; then
-        iniset $conf_file DEFAULT interface_driver quantum.agent.linux.interface.OVSInterfaceDriver
-    fi
-}
-
-function _quantum_setup_external_bridge() {
-    local bridge=$1
-    quantum-ovs-cleanup --external_network_bridge $bridge
-    sudo ovs-vsctl --no-wait -- --may-exist add-br $bridge
-    # ensure no IP is configured on the public bridge
-    sudo ip addr flush dev $bridge
+    quantum_plugin_setup_interface_driver $1
 }
 
 # Functions for Quantum Exercises
@@ -886,55 +681,45 @@
 
 # Quantum 3rd party programs
 #---------------------------
-# A comma-separated list of 3rd party programs
-QUANTUM_THIRD_PARTIES="ryu,bigswitch_floodlight"
-for third_party in ${QUANTUM_THIRD_PARTIES//,/ }; do
-    source lib/$third_party
+# please refer to lib/quantum_thirdparty/README.md for details
+QUANTUM_THIRD_PARTIES=""
+for f in $TOP_DIR/lib/quantum_thirdparty/*; do
+     third_party=$(basename $f)
+     if is_service_enabled $third_party; then
+         source $TOP_DIR/lib/quantum_thirdparty/$third_party
+         QUANTUM_THIRD_PARTIES="$QUANTUM_THIRD_PARTIES,$third_party"
+     fi
 done
 
+function _quantum_third_party_do() {
+    for third_party in ${QUANTUM_THIRD_PARTIES//,/ }; do
+        ${1}_${third_party}
+    done
+}
+
 # configure_quantum_third_party() - Set config files, create data dirs, etc
 function configure_quantum_third_party() {
-    for third_party in ${QUANTUM_THIRD_PARTIES//,/ }; do
-        if is_service_enabled $third_party; then
-            configure_${third_party}
-        fi
-    done
+    _quantum_third_party_do configure
 }
 
 # init_quantum_third_party() - Initialize databases, etc.
 function init_quantum_third_party() {
-    for third_party in ${QUANTUM_THIRD_PARTIES//,/ }; do
-        if is_service_enabled $third_party; then
-            init_${third_party}
-        fi
-    done
+    _quantum_third_party_do init
 }
 
 # install_quantum_third_party() - Collect source and prepare
 function install_quantum_third_party() {
-    for third_party in ${QUANTUM_THIRD_PARTIES//,/ }; do
-        if is_service_enabled $third_party; then
-            install_${third_party}
-        fi
-    done
+    _quantum_third_party_do install
 }
 
 # start_quantum_third_party() - Start running processes, including screen
 function start_quantum_third_party() {
-    for third_party in ${QUANTUM_THIRD_PARTIES//,/ }; do
-        if is_service_enabled $third_party; then
-            start_${third_party}
-        fi
-    done
+    _quantum_third_party_do start
 }
 
 # stop_quantum_third_party - Stop running processes (non-screen)
 function stop_quantum_third_party() {
-    for third_party in ${QUANTUM_THIRD_PARTIES//,/ }; do
-        if is_service_enabled $third_party; then
-            stop_${third_party}
-        fi
-    done
+    _quantum_third_party_do stop
 }
 
 
diff --git a/lib/quantum_plugins/README.md b/lib/quantum_plugins/README.md
new file mode 100644
index 0000000..a66d35a
--- /dev/null
+++ b/lib/quantum_plugins/README.md
@@ -0,0 +1,34 @@
+Quantum plugin specific files
+=============================
+Quantum plugins require plugin specific behavior.
+The files under the directory, ``lib/quantum_plugins/``, will be used
+when their service is enabled.
+Each plugin has ``lib/quantum_plugins/$Q_PLUGIN`` and define the following
+functions.
+Plugin specific configuration variables should be in this file.
+
+* filename: ``$Q_PLUGIN``
+  * The corresponding file name MUST be the same to plugin name ``$Q_PLUGIN``.
+    Plugin specific configuration variables should be in this file.
+
+functions
+---------
+``lib/quantum`` calls the following functions when the ``$Q_PLUGIN`` is enabled
+
+* ``quantum_plugin_create_nova_conf`` :
+  set ``NOVA_VIF_DRIVER`` and optionally set options in nova_conf
+  e.g.
+  NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.LibvirtHybridOVSBridgeDriver"}
+* ``quantum_plugin_install_agent_packages`` :
+  install packages that is specific to plugin agent
+  e.g.
+  install_package bridge-utils
+* ``quantum_plugin_configure_common`` :
+  set plugin-specific variables, ``Q_PLUGIN_CONF_PATH``, ``Q_PLUGIN_CONF_FILENAME``,
+  ``Q_DB_NAME``, ``Q_PLUGIN_CLASS``
+* ``quantum_plugin_configure_debug_command``
+* ``quantum_plugin_configure_dhcp_agent``
+* ``quantum_plugin_configure_l3_agent``
+* ``quantum_plugin_configure_plugin_agent``
+* ``quantum_plugin_configure_service``
+* ``quantum_plugin_setup_interface_driver``
diff --git a/lib/quantum_plugins/bigswitch_floodlight b/lib/quantum_plugins/bigswitch_floodlight
new file mode 100644
index 0000000..2c928be
--- /dev/null
+++ b/lib/quantum_plugins/bigswitch_floodlight
@@ -0,0 +1,55 @@
+# Quantum Big Switch/FloodLight plugin
+# ------------------------------------
+
+# Save trace setting
+MY_XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+source $TOP_DIR/lib/quantum_plugins/ovs_base
+source $TOP_DIR/lib/quantum_thirdparty/bigswitch_floodlight     # for third party service specific configuration values
+
+function quantum_plugin_create_nova_conf() {
+    NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.LibvirtHybridOVSBridgeDriver"}
+}
+
+function quantum_plugin_install_agent_packages() {
+    _quantum_ovs_base_install_agent_packages
+}
+
+function quantum_plugin_configure_common() {
+    Q_PLUGIN_CONF_PATH=etc/quantum/plugins/bigswitch
+    Q_PLUGIN_CONF_FILENAME=restproxy.ini
+    Q_DB_NAME="restproxy_quantum"
+    Q_PLUGIN_CLASS="quantum.plugins.bigswitch.plugin.QuantumRestProxyV2"
+    BS_FL_CONTROLLERS_PORT=${BS_FL_CONTROLLERS_PORT:-localhost:80}
+    BS_FL_CONTROLLER_TIMEOUT=${BS_FL_CONTROLLER_TIMEOUT:-10}
+}
+
+function quantum_plugin_configure_debug_command() {
+    _quantum_ovs_base_configure_debug_command
+}
+
+function quantum_plugin_configure_dhcp_agent() {
+    :
+}
+
+function quantum_plugin_configure_l3_agent() {
+    _quantum_ovs_base_configure_l3_agent
+}
+
+function quantum_plugin_configure_plugin_agent() {
+    :
+}
+
+function quantum_plugin_configure_service() {
+    iniset /$Q_PLUGIN_CONF_FILE RESTPROXY servers $BS_FL_CONTROLLERS_PORT
+    iniset /$Q_PLUGIN_CONF_FILE RESTPROXY servertimeout $BS_FL_CONTROLLER_TIMEOUT
+}
+
+function quantum_plugin_setup_interface_driver() {
+    local conf_file=$1
+    iniset $conf_file DEFAULT interface_driver quantum.agent.linux.interface.OVSInterfaceDriver
+}
+
+# Restore xtrace
+$MY_XTRACE
diff --git a/lib/quantum_plugins/brocade b/lib/quantum_plugins/brocade
new file mode 100644
index 0000000..c372c19
--- /dev/null
+++ b/lib/quantum_plugins/brocade
@@ -0,0 +1,49 @@
+# Brocade Quantum Plugin
+# ----------------------
+
+# Save trace setting
+BRCD_XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+function is_quantum_ovs_base_plugin() {
+    return 1
+}
+
+function quantum_plugin_create_nova_conf() {
+    NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.QuantumLinuxBridgeVIFDriver"}
+}
+
+function quantum_plugin_install_agent_packages() {
+    install_package bridge-utils
+}
+
+function quantum_plugin_configure_common() {
+    Q_PLUGIN_CONF_PATH=etc/quantum/plugins/brocade
+    Q_PLUGIN_CONF_FILENAME=brocade.ini
+    Q_DB_NAME="brcd_quantum"
+    Q_PLUGIN_CLASS="quantum.plugins.brocade.QuantumPlugin.BrocadePluginV2"
+}
+
+function quantum_plugin_configure_debug_command() {
+    :
+}
+
+function quantum_plugin_configure_dhcp_agent() {
+    :
+}
+
+function quantum_plugin_configure_l3_agent() {
+    :
+}
+
+function quantum_plugin_configure_plugin_agent() {
+    AGENT_BINARY="$QUANTUM_DIR/bin/quantum-linuxbridge-agent"
+}
+
+function quantum_plugin_setup_interface_driver() {
+    local conf_file=$1
+    iniset $conf_file DEFAULT interface_driver quantum.agent.linux.interface.BridgeInterfaceDriver
+}
+
+# Restore xtrace
+$BRCD_XTRACE
diff --git a/lib/quantum_plugins/linuxbridge b/lib/quantum_plugins/linuxbridge
new file mode 100644
index 0000000..6d5d4e0
--- /dev/null
+++ b/lib/quantum_plugins/linuxbridge
@@ -0,0 +1,79 @@
+# Quantum Linux Bridge plugin
+# ---------------------------
+
+# Save trace setting
+MY_XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+function is_quantum_ovs_base_plugin() {
+    # linuxbridge doesn't use OVS
+    return 1
+}
+
+function quantum_plugin_create_nova_conf() {
+    NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.QuantumLinuxBridgeVIFDriver"}
+}
+
+function quantum_plugin_install_agent_packages() {
+    install_package bridge-utils
+}
+
+function quantum_plugin_configure_common() {
+    Q_PLUGIN_CONF_PATH=etc/quantum/plugins/linuxbridge
+    Q_PLUGIN_CONF_FILENAME=linuxbridge_conf.ini
+    Q_DB_NAME="quantum_linux_bridge"
+    Q_PLUGIN_CLASS="quantum.plugins.linuxbridge.lb_quantum_plugin.LinuxBridgePluginV2"
+}
+
+function quantum_plugin_configure_debug_command() {
+    iniset $QUANTUM_TEST_CONFIG_FILE DEFAULT external_network_bridge
+}
+
+function quantum_plugin_configure_dhcp_agent() {
+    :
+}
+
+function quantum_plugin_configure_l3_agent() {
+    iniset $Q_L3_CONF_FILE DEFAULT external_network_bridge
+}
+
+function quantum_plugin_configure_plugin_agent() {
+    # Setup physical network interface mappings.  Override
+    # ``LB_VLAN_RANGES`` and ``LB_INTERFACE_MAPPINGS`` in ``localrc`` for more
+    # complex physical network configurations.
+    if [[ "$LB_INTERFACE_MAPPINGS" = "" ]] && [[ "$PHYSICAL_NETWORK" != "" ]] && [[ "$LB_PHYSICAL_INTERFACE" != "" ]]; then
+        LB_INTERFACE_MAPPINGS=$PHYSICAL_NETWORK:$LB_PHYSICAL_INTERFACE
+    fi
+    if [[ "$LB_INTERFACE_MAPPINGS" != "" ]]; then
+        iniset /$Q_PLUGIN_CONF_FILE LINUX_BRIDGE physical_interface_mappings $LB_INTERFACE_MAPPINGS
+    fi
+    AGENT_BINARY="$QUANTUM_DIR/bin/quantum-linuxbridge-agent"
+}
+
+function quantum_plugin_configure_service() {
+    if [[ "$ENABLE_TENANT_VLANS" = "True" ]]; then
+        iniset /$Q_PLUGIN_CONF_FILE VLANS tenant_network_type vlan
+    else
+        echo "WARNING - The linuxbridge plugin is using local tenant networks, with no connectivity between hosts."
+    fi
+
+    # Override ``LB_VLAN_RANGES`` and ``LB_INTERFACE_MAPPINGS`` in ``localrc``
+    # for more complex physical network configurations.
+    if [[ "$LB_VLAN_RANGES" = "" ]] && [[ "$PHYSICAL_NETWORK" != "" ]]; then
+        LB_VLAN_RANGES=$PHYSICAL_NETWORK
+        if [[ "$TENANT_VLAN_RANGE" != "" ]]; then
+            LB_VLAN_RANGES=$LB_VLAN_RANGES:$TENANT_VLAN_RANGE
+        fi
+    fi
+    if [[ "$LB_VLAN_RANGES" != "" ]]; then
+        iniset /$Q_PLUGIN_CONF_FILE VLANS network_vlan_ranges $LB_VLAN_RANGES
+    fi
+}
+
+function quantum_plugin_setup_interface_driver() {
+    local conf_file=$1
+    iniset $conf_file DEFAULT interface_driver quantum.agent.linux.interface.BridgeInterfaceDriver
+}
+
+# Restore xtrace
+$MY_XTRACE
diff --git a/lib/quantum_plugins/openvswitch b/lib/quantum_plugins/openvswitch
new file mode 100644
index 0000000..181e7e7
--- /dev/null
+++ b/lib/quantum_plugins/openvswitch
@@ -0,0 +1,144 @@
+# Quantum Open vSwtich plugin
+# ---------------------------
+
+# Save trace setting
+MY_XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+source $TOP_DIR/lib/quantum_plugins/ovs_base
+
+function quantum_plugin_create_nova_conf() {
+    NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.LibvirtHybridOVSBridgeDriver"}
+    if [ "$VIRT_DRIVER" = 'xenserver' ]; then
+        iniset $NOVA_CONF DEFAULT xenapi_vif_driver nova.virt.xenapi.vif.XenAPIOpenVswitchDriver
+        iniset $NOVA_CONF DEFAULT xenapi_ovs_integration_bridge $FLAT_NETWORK_BRIDGE
+    fi
+}
+
+function quantum_plugin_install_agent_packages() {
+    _quantum_ovs_base_install_agent_packages
+}
+
+function quantum_plugin_configure_common() {
+    Q_PLUGIN_CONF_PATH=etc/quantum/plugins/openvswitch
+    Q_PLUGIN_CONF_FILENAME=ovs_quantum_plugin.ini
+    Q_DB_NAME="ovs_quantum"
+    Q_PLUGIN_CLASS="quantum.plugins.openvswitch.ovs_quantum_plugin.OVSQuantumPluginV2"
+}
+
+function quantum_plugin_configure_debug_command() {
+    _quantum_ovs_base_configure_debug_command
+}
+
+function quantum_plugin_configure_dhcp_agent() {
+    :
+}
+
+function quantum_plugin_configure_l3_agent() {
+    _quantum_ovs_base_configure_l3_agent
+}
+
+function quantum_plugin_configure_plugin_agent() {
+    # Setup integration bridge
+    OVS_BRIDGE=${OVS_BRIDGE:-br-int}
+    _quantum_ovs_base_setup_bridge $OVS_BRIDGE
+
+    # Setup agent for tunneling
+    if [[ "$OVS_ENABLE_TUNNELING" = "True" ]]; then
+        # Verify tunnels are supported
+        # REVISIT - also check kernel module support for GRE and patch ports
+        OVS_VERSION=`ovs-vsctl --version | head -n 1 | awk '{print $4;}'`
+        if [ $OVS_VERSION \< "1.4" ] && ! is_service_enabled q-svc ; then
+            echo "You are running OVS version $OVS_VERSION."
+            echo "OVS 1.4+ is required for tunneling between multiple hosts."
+            exit 1
+        fi
+        iniset /$Q_PLUGIN_CONF_FILE OVS enable_tunneling True
+        iniset /$Q_PLUGIN_CONF_FILE OVS local_ip $HOST_IP
+    fi
+
+    # Setup physical network bridge mappings.  Override
+    # ``OVS_VLAN_RANGES`` and ``OVS_BRIDGE_MAPPINGS`` in ``localrc`` for more
+    # complex physical network configurations.
+    if [[ "$OVS_BRIDGE_MAPPINGS" = "" ]] && [[ "$PHYSICAL_NETWORK" != "" ]] && [[ "$OVS_PHYSICAL_BRIDGE" != "" ]]; then
+        OVS_BRIDGE_MAPPINGS=$PHYSICAL_NETWORK:$OVS_PHYSICAL_BRIDGE
+
+        # Configure bridge manually with physical interface as port for multi-node
+        sudo ovs-vsctl --no-wait -- --may-exist add-br $OVS_PHYSICAL_BRIDGE
+    fi
+    if [[ "$OVS_BRIDGE_MAPPINGS" != "" ]]; then
+        iniset /$Q_PLUGIN_CONF_FILE OVS bridge_mappings $OVS_BRIDGE_MAPPINGS
+    fi
+    AGENT_BINARY="$QUANTUM_DIR/bin/quantum-openvswitch-agent"
+
+    if [ "$VIRT_DRIVER" = 'xenserver' ]; then
+        # Nova will always be installed along with quantum for a domU
+        # devstack install, so it should be safe to rely on nova.conf
+        # for xenapi configuration.
+        Q_RR_DOM0_COMMAND="$QUANTUM_DIR/bin/quantum-rootwrap-xen-dom0 $NOVA_CONF"
+        # Under XS/XCP, the ovs agent needs to target the dom0
+        # integration bridge.  This is enabled by using a root wrapper
+        # that executes commands on dom0 via a XenAPI plugin.
+        iniset /$Q_PLUGIN_CONF_FILE AGENT root_helper "$Q_RR_DOM0_COMMAND"
+
+        # FLAT_NETWORK_BRIDGE is the dom0 integration bridge.  To
+        # ensure the bridge lacks direct connectivity, set
+        # VM_VLAN=-1;VM_DEV=invalid in localrc
+        iniset /$Q_PLUGIN_CONF_FILE OVS integration_bridge $FLAT_NETWORK_BRIDGE
+
+        # The ovs agent needs to ensure that the ports associated with
+        # a given network share the same local vlan tag.  On
+        # single-node XS/XCP, this requires monitoring both the dom0
+        # bridge, where VM's are attached, and the domU bridge, where
+        # dhcp servers are attached.
+        if is_service_enabled q-dhcp; then
+            iniset /$Q_PLUGIN_CONF_FILE OVS domu_integration_bridge $OVS_BRIDGE
+            # DomU will use the regular rootwrap
+            iniset /$Q_PLUGIN_CONF_FILE AGENT domu_root_helper "$Q_RR_COMMAND"
+            # Plug the vm interface into the domU integration bridge.
+            sudo ip addr flush dev $GUEST_INTERFACE_DEFAULT
+            sudo ip link set $OVS_BRIDGE up
+            # Assign the VM IP only if it has been set explicitly
+            if [[ "$VM_IP" != "" ]]; then
+                sudo ip addr add $VM_IP dev $OVS_BRIDGE
+            fi
+            sudo ovs-vsctl add-port $OVS_BRIDGE $GUEST_INTERFACE_DEFAULT
+        fi
+    fi
+}
+
+function quantum_plugin_configure_service() {
+    if [[ "$ENABLE_TENANT_TUNNELS" = "True" ]]; then
+        iniset /$Q_PLUGIN_CONF_FILE OVS tenant_network_type gre
+        iniset /$Q_PLUGIN_CONF_FILE OVS tunnel_id_ranges $TENANT_TUNNEL_RANGES
+    elif [[ "$ENABLE_TENANT_VLANS" = "True" ]]; then
+        iniset /$Q_PLUGIN_CONF_FILE OVS tenant_network_type vlan
+    else
+        echo "WARNING - The openvswitch plugin is using local tenant networks, with no connectivity between hosts."
+    fi
+
+    # Override ``OVS_VLAN_RANGES`` and ``OVS_BRIDGE_MAPPINGS`` in ``localrc``
+    # for more complex physical network configurations.
+    if [[ "$OVS_VLAN_RANGES" = "" ]] && [[ "$PHYSICAL_NETWORK" != "" ]]; then
+        OVS_VLAN_RANGES=$PHYSICAL_NETWORK
+        if [[ "$TENANT_VLAN_RANGE" != "" ]]; then
+            OVS_VLAN_RANGES=$OVS_VLAN_RANGES:$TENANT_VLAN_RANGE
+        fi
+    fi
+    if [[ "$OVS_VLAN_RANGES" != "" ]]; then
+        iniset /$Q_PLUGIN_CONF_FILE OVS network_vlan_ranges $OVS_VLAN_RANGES
+    fi
+
+    # Enable tunnel networks if selected
+    if [[ $OVS_ENABLE_TUNNELING = "True" ]]; then
+        iniset /$Q_PLUGIN_CONF_FILE OVS enable_tunneling True
+    fi
+}
+
+function quantum_plugin_setup_interface_driver() {
+    local conf_file=$1
+    iniset $conf_file DEFAULT interface_driver quantum.agent.linux.interface.OVSInterfaceDriver
+}
+
+# Restore xtrace
+$MY_XTRACE
diff --git a/lib/quantum_plugins/ovs_base b/lib/quantum_plugins/ovs_base
new file mode 100644
index 0000000..8563674
--- /dev/null
+++ b/lib/quantum_plugins/ovs_base
@@ -0,0 +1,49 @@
+# common functions for ovs based plugin
+# -------------------------------------
+
+# Save trace setting
+MY_XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+function is_quantum_ovs_base_plugin() {
+    # Yes, we use OVS.
+    return 0
+}
+
+function _quantum_ovs_base_setup_bridge() {
+    local bridge=$1
+    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
+}
+
+function _quantum_ovs_base_install_agent_packages() {
+    local kernel_version
+    # Install deps
+    # FIXME add to ``files/apts/quantum``, but don't install if not needed!
+    if is_ubuntu; then
+        kernel_version=`cat /proc/version | cut -d " " -f3`
+        install_package make fakeroot dkms openvswitch-switch openvswitch-datapath-dkms linux-headers-$kernel_version
+    else
+        ### FIXME(dtroyer): Find RPMs for OpenVSwitch
+        echo "OpenVSwitch packages need to be located"
+        # Fedora does not started OVS by default
+        restart_service openvswitch
+    fi
+}
+
+function _quantum_ovs_base_configure_debug_command() {
+    iniset $QUANTUM_TEST_CONFIG_FILE DEFAULT external_network_bridge $PUBLIC_BRIDGE
+}
+
+function _quantum_ovs_base_configure_l3_agent() {
+    iniset $Q_L3_CONF_FILE DEFAULT 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
+$MY_XTRACE
diff --git a/lib/quantum_plugins/ryu b/lib/quantum_plugins/ryu
new file mode 100644
index 0000000..2dfd4f7
--- /dev/null
+++ b/lib/quantum_plugins/ryu
@@ -0,0 +1,66 @@
+# Quantum Ryu plugin
+# ------------------
+
+# Save trace setting
+MY_XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+source $TOP_DIR/lib/quantum_plugins/ovs_base
+source $TOP_DIR/lib/quantum_thirdparty/ryu      # for configuration value
+
+function quantum_plugin_create_nova_conf() {
+    NOVA_VIF_DRIVER=${NOVA_VIF_DRIVER:-"nova.virt.libvirt.vif.LibvirtHybridOVSBridgeDriver"}
+    iniset $NOVA_CONF DEFAULT libvirt_ovs_integration_bridge "$OVS_BRIDGE"
+}
+
+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() {
+    Q_PLUGIN_CONF_PATH=etc/quantum/plugins/ryu
+    Q_PLUGIN_CONF_FILENAME=ryu.ini
+    Q_DB_NAME="ovs_quantum"
+    Q_PLUGIN_CLASS="quantum.plugins.ryu.ryu_quantum_plugin.RyuQuantumPluginV2"
+}
+
+function quantum_plugin_configure_debug_command() {
+    _quantum_ovs_base_configure_debug_command
+    iniset $QUANTUM_TEST_CONFIG_FILE DEFAULT ryu_api_host $RYU_API_HOST:$RYU_API_PORT
+}
+
+function quantum_plugin_configure_dhcp_agent() {
+    iniset $Q_DHCP_CONF_FILE DEFAULT ryu_api_host $RYU_API_HOST:$RYU_API_PORT
+}
+
+function quantum_plugin_configure_l3_agent() {
+    iniset $Q_L3_CONF_FILE DEFAULT ryu_api_host $RYU_API_HOST:$RYU_API_PORT
+    _quantum_ovs_base_configure_l3_agent
+}
+
+function quantum_plugin_configure_plugin_agent() {
+    # Set up integration bridge
+    OVS_BRIDGE=${OVS_BRIDGE:-br-int}
+    _quantum_ovs_base_setup_bridge $OVS_BRIDGE
+    if [ -n "$RYU_INTERNAL_INTERFACE" ]; then
+        sudo ovs-vsctl --no-wait -- --may-exist add-port $OVS_BRIDGE $RYU_INTERNAL_INTERFACE
+    fi
+    iniset /$Q_PLUGIN_CONF_FILE OVS integration_bridge $OVS_BRIDGE
+    AGENT_BINARY="$QUANTUM_DIR/quantum/plugins/ryu/agent/ryu_quantum_agent.py"
+}
+
+function quantum_plugin_configure_service() {
+    iniset /$Q_PLUGIN_CONF_FILE OVS openflow_rest_api $RYU_API_HOST:$RYU_API_PORT
+}
+
+function quantum_plugin_setup_interface_driver() {
+    local conf_file=$1
+    iniset $conf_file DEFAULT interface_driver quantum.agent.linux.interface.OVSInterfaceDriver
+    iniset $conf_file DEFAULT ovs_use_veth True
+}
+
+# Restore xtrace
+$MY_XTRACE
diff --git a/lib/quantum_thirdparty/README.md b/lib/quantum_thirdparty/README.md
new file mode 100644
index 0000000..3b5837d
--- /dev/null
+++ b/lib/quantum_thirdparty/README.md
@@ -0,0 +1,36 @@
+Quantum third party specific files
+==================================
+Some Quantum plugins require third party programs to function.
+The files under the directory, ``lib/quantum_thirdparty/``, will be used
+when their service are enabled.
+Third party program specific configuration variables should be in this file.
+
+* filename: ``<third_party>``
+  * The corresponding file name should be same to service name, ``<third_party>``.
+
+functions
+---------
+``lib/quantum`` calls the following functions when the ``<third_party>`` is enabled
+
+functions to be implemented
+* ``configure_<third_party>``:
+  set config files, create data dirs, etc
+  e.g.
+  sudo python setup.py deploy
+  iniset $XXXX_CONF...
+
+* ``init_<third_party>``:
+  initialize databases, etc
+
+* ``install_<third_party>``:
+  collect source and prepare
+  e.g.
+  git clone xxx
+
+* ``start_<third_party>``:
+  start running processes, including screen
+  e.g.
+  screen_it XXXX "cd $XXXXY_DIR && $XXXX_DIR/bin/XXXX-bin"
+
+* ``stop_<third_party>``:
+  stop running processes (non-screen)
diff --git a/lib/bigswitch_floodlight b/lib/quantum_thirdparty/bigswitch_floodlight
similarity index 95%
rename from lib/bigswitch_floodlight
rename to lib/quantum_thirdparty/bigswitch_floodlight
index 77aeb61..60e3924 100644
--- a/lib/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
new file mode 100644
index 0000000..7a01923
--- /dev/null
+++ b/lib/quantum_thirdparty/ryu
@@ -0,0 +1,73 @@
+# Ryu OpenFlow Controller
+# -----------------------
+
+# Save trace setting
+MY_XTRACE=$(set +o | grep xtrace)
+set +o xtrace
+
+
+RYU_DIR=$DEST/ryu
+# Ryu API Host
+RYU_API_HOST=${RYU_API_HOST:-127.0.0.1}
+# Ryu API Port
+RYU_API_PORT=${RYU_API_PORT:-8080}
+# Ryu OFP Host
+RYU_OFP_HOST=${RYU_OFP_HOST:-127.0.0.1}
+# Ryu OFP Port
+RYU_OFP_PORT=${RYU_OFP_PORT:-6633}
+# Ryu Applications
+RYU_APPS=${RYU_APPS:-ryu.app.simple_isolation,ryu.app.rest}
+# Ryu configuration
+RYU_CONF_CONTENTS=${RYU_CONF_CONTENTS:-"
+--app_lists=$RYU_APPS
+--wsapi_host=$RYU_API_HOST
+--wsapi_port=$RYU_API_PORT
+--ofp_listen_host=$RYU_OFP_HOST
+--ofp_tcp_listen_port=$RYU_OFP_PORT
+--quantum_url=http://$Q_HOST:$Q_PORT
+--quantum_admin_username=$Q_ADMIN_USERNAME
+--quantum_admin_password=$SERVICE_PASSWORD
+--quantum_admin_tenant_name=$SERVICE_TENANT_NAME
+--quantum_admin_auth_url=$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_AUTH_PORT/v2.0
+--quantum_auth_strategy=$Q_AUTH_STRATEGY
+--quantum_controller_addr=tcp:$RYU_OFP_HOST:$RYU_OFP_PORT
+"}
+
+function configure_ryu() {
+    setup_develop $RYU_DIR
+}
+
+function init_ryu() {
+    RYU_CONF_DIR=/etc/ryu
+    if [[ ! -d $RYU_CONF_DIR ]]; then
+        sudo mkdir -p $RYU_CONF_DIR
+    fi
+    sudo chown $STACK_USER $RYU_CONF_DIR
+    RYU_CONF=$RYU_CONF_DIR/ryu.conf
+    sudo rm -rf $RYU_CONF
+
+    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() {
+    if [[ "$_RYU_INSTALLED" == "False" ]]; then
+        git_clone $RYU_REPO $RYU_DIR $RYU_BRANCH
+        _RYU_INSTALLED=True
+    fi
+}
+
+function start_ryu() {
+    screen_it ryu "cd $RYU_DIR && $RYU_DIR/bin/ryu-manager --flagfile $RYU_CONF"
+}
+
+function stop_ryu() {
+    :
+}
+
+# Restore xtrace
+$MY_XTRACE
diff --git a/lib/rpc_backend b/lib/rpc_backend
index 4d7f8d2..f35f9db 100644
--- a/lib/rpc_backend
+++ b/lib/rpc_backend
@@ -100,7 +100,7 @@
         iniset $file $section rpc_backend ${package}.openstack.common.rpc.impl_zmq
     elif is_service_enabled qpid; then
         iniset $file $section rpc_backend ${package}.openstack.common.rpc.impl_qpid
-    elif is_service_enabled rabbit; then
+    elif is_service_enabled rabbit || { [ -n "$RABBIT_HOST" ] && [ -n "$RABBIT_PASSWORD" ]; }; then
         iniset $file $section rpc_backend ${package}.openstack.common.rpc.impl_kombu
         iniset $file $section rabbit_host $RABBIT_HOST
         iniset $file $section rabbit_password $RABBIT_PASSWORD
diff --git a/lib/ryu b/lib/ryu
deleted file mode 100644
index 1292313..0000000
--- a/lib/ryu
+++ /dev/null
@@ -1,63 +0,0 @@
-# Ryu OpenFlow Controller
-# -----------------------
-
-# Save trace setting
-XTRACE=$(set +o | grep xtrace)
-set +o xtrace
-
-
-RYU_DIR=$DEST/ryu
-# Ryu API Host
-RYU_API_HOST=${RYU_API_HOST:-127.0.0.1}
-# Ryu API Port
-RYU_API_PORT=${RYU_API_PORT:-8080}
-# Ryu OFP Host
-RYU_OFP_HOST=${RYU_OFP_HOST:-127.0.0.1}
-# Ryu OFP Port
-RYU_OFP_PORT=${RYU_OFP_PORT:-6633}
-# Ryu Applications
-RYU_APPS=${RYU_APPS:-ryu.app.simple_isolation,ryu.app.rest}
-
-function configure_ryu() {
-    setup_develop $RYU_DIR
-}
-
-function init_ryu() {
-    RYU_CONF_DIR=/etc/ryu
-    if [[ ! -d $RYU_CONF_DIR ]]; then
-        sudo mkdir -p $RYU_CONF_DIR
-    fi
-    sudo chown $STACK_USER $RYU_CONF_DIR
-    RYU_CONF=$RYU_CONF_DIR/ryu.conf
-    sudo rm -rf $RYU_CONF
-
-    cat <<EOF > $RYU_CONF
---app_lists=$RYU_APPS
---wsapi_host=$RYU_API_HOST
---wsapi_port=$RYU_API_PORT
---ofp_listen_host=$RYU_OFP_HOST
---ofp_tcp_listen_port=$RYU_OFP_PORT
-EOF
-}
-
-function install_ryu() {
-    git_clone $RYU_REPO $RYU_DIR $RYU_BRANCH
-}
-
-function is_ryu_required() {
-    if is_service_enabled ryu || (is_service_enabled quantum && [[ "$Q_PLUGIN" = "ryu" ]]); then
-        return 0
-    fi
-    return 1
-}
-
-function start_ryu() {
-    screen_it ryu "cd $RYU_DIR && $RYU_DIR/bin/ryu-manager --flagfile $RYU_CONF"
-}
-
-function stop_ryu() {
-    :
-}
-
-# Restore xtrace
-$XTRACE
diff --git a/lib/swift b/lib/swift
index a4faf03..5ba7e56 100644
--- a/lib/swift
+++ b/lib/swift
@@ -95,13 +95,13 @@
     setup_develop $SWIFT_DIR
 
     # Make sure to kill all swift processes first
-    swift-init all stop || true
+    swift-init --run-dir=${SWIFT_DATA_DIR}/run all stop || true
 
     # 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)
-    sudo mkdir -p ${SWIFT_DATA_DIR}/{drives,cache}
+    sudo mkdir -p ${SWIFT_DATA_DIR}/{drives,cache,run,logs}
     sudo chown -R $USER:${USER_GROUP} ${SWIFT_DATA_DIR}
 
     # Create a loopback disk and format it to XFS.
@@ -143,8 +143,8 @@
         sudo chown -R $USER: ${node}
     done
 
-   sudo mkdir -p ${SWIFT_CONFIG_DIR}/{object,container,account}-server /var/run/swift
-   sudo chown -R $USER: ${SWIFT_CONFIG_DIR} /var/run/swift
+   sudo mkdir -p ${SWIFT_CONFIG_DIR}/{object,container,account}-server
+   sudo chown -R $USER: ${SWIFT_CONFIG_DIR}
 
     if [[ "$SWIFT_CONFIG_DIR" != "/etc/swift" ]]; then
         # Some swift tools are hard-coded to use ``/etc/swift`` and are apparently not going to be fixed.
@@ -311,7 +311,7 @@
 function init_swift() {
     local node_number
     # Make sure to kill all swift processes first
-    swift-init all stop || true
+    swift-init --run-dir=${SWIFT_DATA_DIR}/run all stop || true
 
     # This is where we create three different rings for swift with
     # different object servers binding on different ports.
@@ -363,15 +363,15 @@
    # proxy service so we can run it in foreground in screen.
    # ``swift-init ... {stop|restart}`` exits with '1' if no servers are running,
    # ignore it just in case
-   swift-init all restart || true
-   swift-init proxy stop || true
+   swift-init --run-dir=${SWIFT_DATA_DIR}/run all restart || true
+   swift-init --run-dir=${SWIFT_DATA_DIR}/run proxy stop || true
    screen_it swift "cd $SWIFT_DIR && $SWIFT_DIR/bin/swift-proxy-server ${SWIFT_CONFIG_DIR}/proxy-server.conf -v"
 }
 
 # stop_swift() - Stop running processes (non-screen)
 function stop_swift() {
     # screen normally killed by unstack.sh
-    swift-init all stop || true
+    swift-init --run-dir=${SWIFT_DATA_DIR}/run all stop || true
 }
 
 # Restore xtrace
diff --git a/lib/tempest b/lib/tempest
index c08a430..e43f6d7 100644
--- a/lib/tempest
+++ b/lib/tempest
@@ -5,7 +5,7 @@
 # ``functions`` file
 # ``lib/nova`` service is runing
 # <list other global vars that are assumed to be defined>
-# - ``DEST``
+# - ``DEST``, ``FILES``
 # - ``ADMIN_PASSWORD``
 # - ``DEFAULT_IMAGE_NAME``
 # - ``S3_SERVICE_PORT``
@@ -16,10 +16,9 @@
 # - ``Q_ROUTER_NAME``
 # - ``VIRT_DRIVER``
 # - ``LIBVIRT_TYPE``
+# - ``KEYSTONE_SERVICE_PROTOCOL``, ``KEYSTONE_SERVICE_HOST`` from lib/keystone
 # Optional Dependencies:
-# IDENTITY_USE_SSL, IDENTITY_HOST, IDENTITY_PORT, IDENTITY_PATH
 # ALT_* (similar vars exists in keystone_data.sh)
-# ``IMAGE_PORT``, ``IMAGE_HOST``
 # ``LIVE_MIGRATION_AVAILABLE``
 # ``USE_BLOCK_MIGRATION_FOR_LIVE_MIGRATION``
 # ``DEFAULT_INSTANCE_TYPE``
@@ -49,13 +48,14 @@
 BUILD_TIMEOUT=400
 
 
-BOTO_MATERIALS_PATH="$DEST/devstack/files/images/s3-materials/cirros-0.3.0"
+BOTO_MATERIALS_PATH="$FILES/images/s3-materials/cirros-0.3.0"
 
 # Entry Points
 # ------------
 
 # configure_tempest() - Set config files, create data dirs, etc
 function configure_tempest() {
+    setup_develop $TEMPEST_DIR
     local image_lines
     local images
     local num_images
@@ -124,13 +124,6 @@
     # copy every time, because the image UUIDS are going to change
     cp $TEMPEST_CONF.sample $TEMPEST_CONF
 
-    IDENTITY_USE_SSL=${IDENTITY_USE_SSL:-False}
-    IDENTITY_HOST=${IDENTITY_HOST:-127.0.0.1}
-    IDENTITY_PORT=${IDENTITY_PORT:-5000}
-    # TODO(jaypipes): This is dumb and needs to be removed
-    # from the Tempest configuration file entirely...
-    IDENTITY_PATH=${IDENTITY_PATH:-tokens}
-
     password=${ADMIN_PASSWORD:-secrete}
 
     # See files/keystone_data.sh where alt_demo user
@@ -203,18 +196,16 @@
     iniset $TEMPEST_CONF boto build_interval $BUILD_INTERVAL
     iniset $TEMPEST_CONF boto http_socket_timeout 5
 
-    iniset $TEMPEST_CONF identity use_ssl $IDENTITY_USE_SSL
-    iniset $TEMPEST_CONF identity host $IDENTITY_HOST
-    iniset $TEMPEST_CONF identity port $IDENTITY_PORT
-    iniset $TEMPEST_CONF identity path $IDENTITY_PATH
+    # Identity
+    iniset $TEMPEST_CONF identity uri "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:5000/v2.0/"
+    iniset $TEMPEST_CONF identity password "$password"
+    iniset $TEMPEST_CONF identity alt_username $ALT_USERNAME
+    iniset $TEMPEST_CONF identity alt_password "$password"
+    iniset $TEMPEST_CONF identity alt_tenant_name $ALT_TENANT_NAME
+    iniset $TEMPEST_CONF identity admin_password "$password"
 
-    iniset $TEMPEST_CONF compute password "$password"
-    iniset $TEMPEST_CONF compute alt_username $ALT_USERNAME
-    iniset $TEMPEST_CONF compute alt_password "$password"
-    iniset $TEMPEST_CONF compute alt_tenant_name $ALT_TENANT_NAME
-    iniset $TEMPEST_CONF compute resize_available False
+    # Compute
     iniset $TEMPEST_CONF compute change_password_available False
-    iniset $TEMPEST_CONF compute compute_log_level ERROR
     # Note(nati) current tempest don't create network for each tenant
     # so reuse same tenant for now
     if is_service_enabled quantum; then
@@ -223,41 +214,33 @@
     iniset $TEMPEST_CONF compute allow_tenant_isolation ${TEMPEST_ALLOW_TENANT_ISOLATION:-True}
     #Skip until #1074039 is fixed
     iniset $TEMPEST_CONF compute run_ssh False
-    iniset $TEMPEST_CONF compute ssh_user ${DEFAULT_INSTANCE_USER:-cirros}
+    iniset $TEMPEST_CONF compute ssh_user ${DEFAULT_INSTANCE_USER:-cirros} # DEPRECATED
     iniset $TEMPEST_CONF compute network_for_ssh $PRIVATE_NETWORK_NAME
     iniset $TEMPEST_CONF compute ip_version_for_ssh 4
     iniset $TEMPEST_CONF compute ssh_timeout $BUILD_TIMEOUT
     iniset $TEMPEST_CONF compute image_ref $image_uuid
+    iniset $TEMPEST_CONF compute image_ssh_user ${DEFAULT_INSTANCE_USER:-cirros}
     iniset $TEMPEST_CONF compute image_ref_alt $image_uuid_alt
+    iniset $TEMPEST_CONF compute image_alt_ssh_user ${DEFAULT_INSTANCE_USER:-cirros}
     iniset $TEMPEST_CONF compute flavor_ref $flavor_ref
     iniset $TEMPEST_CONF compute flavor_ref_alt $flavor_ref_alt
-    iniset $TEMPEST_CONF compute source_dir $NOVA_SOURCE_DIR
     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}
-    # Inherited behavior, might be wrong
-    iniset $TEMPEST_CONF compute bin_dir $NOVA_BIN_DIR
+
+    # Whitebox
+    iniset $TEMPEST_CONF whitebox source_dir $NOVA_SOURCE_DIR
+    iniset $TEMPEST_CONF whitebox bin_dir $NOVA_BIN_DIR
     # TODO(jaypipes): Create the key file here... right now, no whitebox
     # tests actually use a key.
-    iniset $TEMPEST_CONF compute path_to_private_key $TEMPEST_DIR/id_rsa
-    iniset $TEMPEST_CONF compute db_uri $BASE_SQL_CONN/nova
+    iniset $TEMPEST_CONF whitebox path_to_private_key $TEMPEST_DIR/id_rsa
+    iniset $TEMPEST_CONF whitebox db_uri $BASE_SQL_CONN/nova
 
-    # image
-    iniset $TEMPEST_CONF image host ${IMAGE_HOST:-127.0.0.1}
-    iniset $TEMPEST_CONF image port ${IMAGE_PORT:-9292}
-    iniset $TEMPEST_CONF image password "$password"
-
-    # identity-admin
-    iniset $TEMPEST_CONF "identity-admin" password "$password"
 
     # compute admin
-    iniset $TEMPEST_CONF "compute-admin" password "$password"
-
-    # network admin
-    iniset $TEMPEST_CONF "network-admin" password "$password"
+    iniset $TEMPEST_CONF "compute-admin" password "$password" # DEPRECATED
 
     # network
     iniset $TEMPEST_CONF network api_version 2.0
-    iniset $TEMPEST_CONF network password "$password"
     iniset $TEMPEST_CONF network tenant_networks_reachable "$tenant_networks_reachable"
     iniset $TEMPEST_CONF network public_network_id "$public_network_id"
     iniset $TEMPEST_CONF network public_router_id "$public_router_id"
@@ -268,6 +251,7 @@
     iniset $TEMPEST_CONF boto s3_materials_path "$BOTO_MATERIALS_PATH"
     iniset $TEMPEST_CONF boto instance_type "$boto_instance_type"
     iniset $TEMPEST_CONF boto http_socket_timeout 30
+    iniset $TEMPEST_CONF boto ssh_user ${DEFAULT_INSTANCE_USER:-cirros}
 
     echo "Created tempest configuration file:"
     cat $TEMPEST_CONF
@@ -291,8 +275,7 @@
 function init_tempest() {
     local base_image_name=cirros-0.3.0-x86_64
     # /opt/stack/devstack/files/images/cirros-0.3.0-x86_64-uec
-    local devstack_dir="$DEST/devstack"
-    local image_dir="$devstack_dir/files/images/${base_image_name}-uec"
+    local image_dir="$FILES/images/${base_image_name}-uec"
     local kernel="$image_dir/${base_image_name}-vmlinuz"
     local ramdisk="$image_dir/${base_image_name}-initrd"
     local disk_image="$image_dir/${base_image_name}-blank.img"
@@ -302,7 +285,7 @@
        echo "Prepare aki/ari/ami Images"
        ( #new namespace
            # tenant:demo ; user: demo
-           source $devstack_dir/accrc/demo/demo
+           source $TOP_DIR/accrc/demo/demo
            euca-bundle-image -i "$kernel" --kernel true -d "$BOTO_MATERIALS_PATH"
            euca-bundle-image -i "$ramdisk" --ramdisk true -d "$BOTO_MATERIALS_PATH"
            euca-bundle-image -i "$disk_image" -d "$BOTO_MATERIALS_PATH"
diff --git a/stack.sh b/stack.sh
index bf473ca..0f009fc 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
@@ -160,7 +144,6 @@
 # sudo privileges and runs as that user.
 
 if [[ $EUID -eq 0 ]]; then
-    STACK_USER=$DEFAULT_STACK_USER
     ROOTSLEEP=${ROOTSLEEP:-10}
     echo "You are running this script as root."
     echo "In $ROOTSLEEP seconds, we will create a user '$STACK_USER' and run as that user"
@@ -196,7 +179,6 @@
     fi
     exit 1
 else
-    STACK_USER=`whoami`
     # We're not **root**, make sure ``sudo`` is available
     is_package_installed sudo || die "Sudo is required.  Re-run stack.sh as root ONE TIME ONLY to set up sudo."
 
@@ -253,7 +235,7 @@
 NETWORK_GATEWAY=${NETWORK_GATEWAY:-10.0.0.1}
 
 # Find the interface used for the default route
-HOST_IP_IFACE=${HOST_IP_IFACE:-$(ip route | sed -n '/^default/{ s/.*dev \(\w\+\)\s\+.*/\1/; p; }')}
+HOST_IP_IFACE=${HOST_IP_IFACE:-$(ip route | sed -n '/^default/{ s/.*dev \(\w\+\)\s\+.*/\1/; p; }' | head -1)}
 # Search for an IP unless an explicit is set by ``HOST_IP`` environment variable
 if [ -z "$HOST_IP" -o "$HOST_IP" == "dhcp" ]; then
     HOST_IP=""
@@ -308,11 +290,13 @@
 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
 OPENSTACKCLIENT_DIR=$DEST/python-openstackclient
 NOVNC_DIR=$DEST/noVNC
+SPICE_DIR=$DEST/spice-html5
 SWIFT3_DIR=$DEST/swift3
 
 # Should cinder perform secure deletion of volumes?
@@ -476,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}
@@ -632,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
 
@@ -716,6 +697,10 @@
     # 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
@@ -962,7 +947,14 @@
 
 if is_service_enabled n-net q-dhcp; then
     # Delete traces of nova networks from prior runs
-    sudo killall dnsmasq || true
+    # Do not kill any dnsmasq instance spawned by NetworkManager
+    netman_pid=$(pidof NetworkManager || true)
+    if [ -z "$netman_pid" ]; then
+        sudo killall dnsmasq || true
+    else
+        sudo ps h -o pid,ppid -C dnsmasq | grep -v $netman_pid | awk '{print $1}' | sudo xargs kill || true
+    fi
+
     clean_iptables
     rm -rf ${NOVA_STATE_PATH}/networks
     sudo mkdir -p ${NOVA_STATE_PATH}/networks
@@ -1008,17 +1000,38 @@
         iniset $NOVA_CONF DEFAULT novncproxy_base_url "$NOVNCPROXY_URL"
         XVPVNCPROXY_URL=${XVPVNCPROXY_URL:-"http://$SERVICE_HOST:6081/console"}
         iniset $NOVA_CONF DEFAULT xvpvncproxy_base_url "$XVPVNCPROXY_URL"
+        SPICEHTML5PROXY_URL=${SPICEHTML5PROXY_URL:-"http://$SERVICE_HOST:6082/spice_auto.html"}
+        iniset $NOVA_CONF spice html5proxy_base_url "$SPICEHTML5PROXY_URL"
     fi
     if [ "$VIRT_DRIVER" = 'xenserver' ]; then
         VNCSERVER_PROXYCLIENT_ADDRESS=${VNCSERVER_PROXYCLIENT_ADDRESS=169.254.0.1}
     else
         VNCSERVER_PROXYCLIENT_ADDRESS=${VNCSERVER_PROXYCLIENT_ADDRESS=127.0.0.1}
     fi
-    # Address on which instance vncservers will listen on compute hosts.
-    # For multi-host, this should be the management ip of the compute host.
-    VNCSERVER_LISTEN=${VNCSERVER_LISTEN=127.0.0.1}
-    iniset $NOVA_CONF DEFAULT vncserver_listen "$VNCSERVER_LISTEN"
-    iniset $NOVA_CONF DEFAULT vncserver_proxyclient_address "$VNCSERVER_PROXYCLIENT_ADDRESS"
+
+    if is_service_enabled n-novnc || is_service_enabled n-xvnc ; then
+      # Address on which instance vncservers will listen on compute hosts.
+      # For multi-host, this should be the management ip of the compute host.
+      VNCSERVER_LISTEN=${VNCSERVER_LISTEN=127.0.0.1}
+      iniset $NOVA_CONF DEFAULT vnc_enabled true
+      iniset $NOVA_CONF DEFAULT vncserver_listen "$VNCSERVER_LISTEN"
+      iniset $NOVA_CONF DEFAULT vncserver_proxyclient_address "$VNCSERVER_PROXYCLIENT_ADDRESS"
+    else
+      iniset $NOVA_CONF DEFAULT vnc_enabled false
+    fi
+
+    if is_service_enabled n-spice; then
+      # Address on which instance spiceservers will listen on compute hosts.
+      # For multi-host, this should be the management ip of the compute host.
+      SPICESERVER_PROXYCLIENT_ADDRESS=${SPICESERVER_PROXYCLIENT_ADDRESS=127.0.0.1}
+      SPICESERVER_LISTEN=${SPICESERVER_LISTEN=127.0.0.1}
+      iniset $NOVA_CONF spice enabled true
+      iniset $NOVA_CONF spice server_listen "$SPICESERVER_LISTEN"
+      iniset $NOVA_CONF spice server_proxyclient_address "$SPICESERVER_PROXYCLIENT_ADDRESS"
+    else
+      iniset $NOVA_CONF spice enabled false
+    fi
+
     iniset $NOVA_CONF DEFAULT ec2_dmz_host "$EC2_DMZ_HOST"
     iniset_rpc_backend nova $NOVA_CONF DEFAULT
     iniset $NOVA_CONF DEFAULT glance_api_servers "$GLANCE_HOSTPORT"
@@ -1046,9 +1059,7 @@
 
     elif [ "$VIRT_DRIVER" = 'openvz' ]; then
         echo_summary "Using OpenVZ virtualization driver"
-        # TODO(deva): OpenVZ driver does not yet work if compute_driver is set here.
-        #             Replace connection_type when this is fixed.
-        #             iniset $NOVA_CONF DEFAULT compute_driver "openvz.connection.OpenVzConnection"
+        iniset $NOVA_CONF DEFAULT compute_driver "openvz.driver.OpenVzDriver"
         iniset $NOVA_CONF DEFAULT connection_type "openvz"
         LIBVIRT_FIREWALL_DRIVER=${LIBVIRT_FIREWALL_DRIVER:-"nova.virt.libvirt.firewall.IptablesFirewallDriver"}
         iniset $NOVA_CONF DEFAULT firewall_driver "$LIBVIRT_FIREWALL_DRIVER"
@@ -1254,8 +1265,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"
@@ -1265,7 +1276,7 @@
 CURRENT_RUN_TIME=$(date "+$TIMESTAMP_FORMAT")
 echo "# $CURRENT_RUN_TIME" >$TOP_DIR/.stackenv
 for i in BASE_SQL_CONN ENABLED_SERVICES HOST_IP LOGFILE \
-  SERVICE_HOST SERVICE_PROTOCOL TLS_IP; do
+  SERVICE_HOST SERVICE_PROTOCOL STACK_USER TLS_IP; do
     echo $i=${!i} >>$TOP_DIR/.stackenv
 done
 
diff --git a/stackrc b/stackrc
index 8d19440..91f4e2b 100644
--- a/stackrc
+++ b/stackrc
@@ -12,8 +12,12 @@
 # Select the default database
 DATABASE_TYPE=mysql
 
-# Default stack user
-DEFAULT_STACK_USER=stack
+# Determine stack user
+if [[ $EUID -eq 0 ]]; then
+    STACK_USER=stack
+else
+    STACK_USER=$(whoami)
+fi
 
 # Specify which services to launch.  These generally correspond to
 # screen tabs. To change the default list, use the ``enable_service`` and
@@ -25,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
 # ------------
 
@@ -78,6 +89,10 @@
 NOVNC_REPO=https://github.com/kanaka/noVNC.git
 NOVNC_BRANCH=master
 
+# a websockets/html5 or flash powered SPICE console for vm instances
+SPICE_REPO=http://anongit.freedesktop.org/git/spice/spice-html5.git
+SPICE_BRANCH=master
+
 # django powered web control panel for openstack
 HORIZON_REPO=${GIT_BASE}/openstack/horizon.git
 HORIZON_BRANCH=master
diff --git a/tools/build_ramdisk.sh b/tools/build_ramdisk.sh
index cfcca51..2c45568 100755
--- a/tools/build_ramdisk.sh
+++ b/tools/build_ramdisk.sh
@@ -125,17 +125,17 @@
     # Create a stack user that is a member of the libvirtd group so that stack
     # is able to interact with libvirt.
     chroot $MNTDIR groupadd libvirtd
-    chroot $MNTDIR useradd $DEFAULT_STACK_USER -s /bin/bash -d $DEST -G libvirtd
+    chroot $MNTDIR useradd $STACK_USER -s /bin/bash -d $DEST -G libvirtd
     mkdir -p $MNTDIR/$DEST
-    chroot $MNTDIR chown $DEFAULT_STACK_USER $DEST
+    chroot $MNTDIR chown $STACK_USER $DEST
 
     # A simple password - pass
-    echo $DEFAULT_STACK_USER:pass | chroot $MNTDIR chpasswd
+    echo $STACK_USER:pass | chroot $MNTDIR chpasswd
     echo root:$ROOT_PASSWORD | chroot $MNTDIR chpasswd
 
     # And has sudo ability (in the future this should be limited to only what
     # stack requires)
-    echo "$DEFAULT_STACK_USER ALL=(ALL) NOPASSWD: ALL" >> $MNTDIR/etc/sudoers
+    echo "$STACK_USER ALL=(ALL) NOPASSWD: ALL" >> $MNTDIR/etc/sudoers
 
     umount $MNTDIR
     rmdir $MNTDIR
@@ -187,7 +187,7 @@
 # Use this version of devstack
 rm -rf $MNTDIR/$DEST/devstack
 cp -pr $CWD $MNTDIR/$DEST/devstack
-chroot $MNTDIR chown -R $DEFAULT_STACK_USER $DEST/devstack
+chroot $MNTDIR chown -R $STACK_USER $DEST/devstack
 
 # Configure host network for DHCP
 mkdir -p $MNTDIR/etc/network
@@ -225,7 +225,7 @@
 
 # Make the run.sh executable
 chmod 755 $RUN_SH
-chroot $MNTDIR chown $DEFAULT_STACK_USER $DEST/run.sh
+chroot $MNTDIR chown $STACK_USER $DEST/run.sh
 
 umount $MNTDIR
 rmdir $MNTDIR
diff --git a/tools/build_uec.sh b/tools/build_uec.sh
index 5748b39..6c4a26c 100755
--- a/tools/build_uec.sh
+++ b/tools/build_uec.sh
@@ -207,11 +207,11 @@
 `cat $TOP_DIR/localrc`
 LOCAL_EOF
 fi
-useradd -U -G sudo -s /bin/bash -d /opt/stack -m $DEFAULT_STACK_USER
-echo $DEFAULT_STACK_USER:pass | chpasswd
+useradd -U -G sudo -s /bin/bash -d /opt/stack -m $STACK_USER
+echo $STACK_USER:pass | chpasswd
 mkdir -p /opt/stack/.ssh
 echo "$PUB_KEY" > /opt/stack/.ssh/authorized_keys
-chown -R $DEFAULT_STACK_USER /opt/stack
+chown -R $STACK_USER /opt/stack
 chmod 700 /opt/stack/.ssh
 chmod 600 /opt/stack/.ssh/authorized_keys
 
@@ -224,7 +224,7 @@
 
 # Run stack.sh
 cat >> $vm_dir/uec/user-data<<EOF
-sudo -u $DEFAULT_STACK_USER bash -l -c "cd /opt/stack/devstack && ./stack.sh"
+sudo -u $STACK_USER bash -l -c "cd /opt/stack/devstack && ./stack.sh"
 EOF
 
 # (re)start a metadata service
diff --git a/tools/copy_dev_environment_to_uec.sh b/tools/copy_dev_environment_to_uec.sh
index add4ff6..3fd4423 100755
--- a/tools/copy_dev_environment_to_uec.sh
+++ b/tools/copy_dev_environment_to_uec.sh
@@ -46,13 +46,13 @@
 # Create a stack user that is a member of the libvirtd group so that stack
 # is able to interact with libvirt.
 chroot $STAGING_DIR groupadd libvirtd || true
-chroot $STAGING_DIR useradd $DEFAULT_STACK_USER -s /bin/bash -d $DEST -G libvirtd || true
+chroot $STAGING_DIR useradd $STACK_USER -s /bin/bash -d $DEST -G libvirtd || true
 
 # Add a simple password - pass
-echo $DEFAULT_STACK_USER:pass | chroot $STAGING_DIR chpasswd
+echo $STACK_USER:pass | chroot $STAGING_DIR chpasswd
 
 # Configure sudo
-( umask 226 && echo "$DEFAULT_STACK_USER ALL=(ALL) NOPASSWD:ALL" \
+( umask 226 && echo "$STACK_USER ALL=(ALL) NOPASSWD:ALL" \
     > $STAGING_DIR/etc/sudoers.d/50_stack_sh )
 
 # Copy over your ssh keys and env if desired
@@ -67,7 +67,7 @@
 cp_it . $STAGING_DIR/$DEST/devstack
 
 # Give stack ownership over $DEST so it may do the work needed
-chroot $STAGING_DIR chown -R $DEFAULT_STACK_USER $DEST
+chroot $STAGING_DIR chown -R $STACK_USER $DEST
 
 # Unmount
 umount $STAGING_DIR
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/README.md b/tools/xen/README.md
index f20ad04..1cd45cf 100644
--- a/tools/xen/README.md
+++ b/tools/xen/README.md
@@ -18,7 +18,7 @@
 For details on installation, see: http://wiki.openstack.org/XenServer/Install
 
 Here are some sample Xenserver network settings for when you are just
-getting started (I use settings like this with a lappy + cheap wifi router):
+getting started (Settings like this have been used with a laptop + cheap wifi router):
 
 * XenServer Host IP: 192.168.1.10
 * XenServer Netmask: 255.255.255.0
@@ -29,9 +29,9 @@
 --------------------------
 On your XenServer host, run the following commands as root:
 
-wget --no-check-certificate https://github.com/openstack-dev/devstack/zipball/master
-unzip -o master -d ./devstack
-cd devstack/*/
+    wget --no-check-certificate https://github.com/openstack-dev/devstack/zipball/master
+    unzip -o master -d ./devstack
+    cd devstack/*/
 
 Step 3: Configure your localrc inside the devstack directory
 ------------------------------------------------------------
diff --git a/tools/xen/build_xva.sh b/tools/xen/build_xva.sh
index f3f166f..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
 
@@ -65,8 +62,8 @@
 cat <<EOF >$STAGING_DIR/etc/rc.local
 # network restart required for getting the right gateway
 /etc/init.d/networking restart
-chown -R $DEFAULT_STACK_USER /opt/stack
-su -c "/opt/stack/run.sh > /opt/stack/run.sh.log" $DEFAULT_STACK_USER
+chown -R $STACK_USER /opt/stack
+su -c "/opt/stack/run.sh > /opt/stack/run.sh.log" $STACK_USER
 exit 0
 EOF
 
diff --git a/tools/xen/install_os_domU.sh b/tools/xen/install_os_domU.sh
index b4fbb69..0e27570 100755
--- a/tools/xen/install_os_domU.sh
+++ b/tools/xen/install_os_domU.sh
@@ -236,6 +236,12 @@
 SNAME_FIRST_BOOT="before_first_boot"
 
 function wait_for_VM_to_halt() {
+    set +x
+    echo "Waiting for the VM to halt.  Progress in-VM can be checked with vncviewer:"
+    mgmt_ip=$(echo $XENAPI_CONNECTION_URL | tr -d -c '1234567890.')
+    domid=$(xe vm-list name-label="$GUEST_NAME" params=dom-id minimal=true)
+    port=$(xenstore-read /local/domain/$domid/console/vnc-port)
+    echo "vncviewer -via $mgmt_ip localhost:${port:2}"
     while true
     do
         state=$(xe_min vm-list name-label="$GUEST_NAME" power-state=halted)
@@ -243,10 +249,11 @@
         then
             break
         else
-            echo "Waiting for "$GUEST_NAME" to finish installation..."
+            echo -n "."
             sleep 20
         fi
     done
+    set -x
 }
 
 templateuuid=$(xe template-list name-label="$TNAME")
@@ -405,12 +412,14 @@
     # Fail if the expected text is not found
     ssh_no_check -q stack@$DOMU_IP 'cat run.sh.log' | grep -q 'stack.sh completed in'
 
+    set +x
     echo "################################################################################"
     echo ""
     echo "All Finished!"
     echo "You can visit the OpenStack Dashboard"
     echo "at http://$DOMU_IP, and contact other services at the usual ports."
 else
+    set +x
     echo "################################################################################"
     echo ""
     echo "All Finished!"