Merge "Generate recent changes list from git log"
diff --git a/README.md b/README.md
index f0406c6..7185e9d 100644
--- a/README.md
+++ b/README.md
@@ -133,11 +133,23 @@
 
 # Apache Frontend
 
-Apache web server is enabled for wsgi services by setting
-`APACHE_ENABLED_SERVICES` in your ``localrc`` section.  Remember to
-enable these services at first as above.
+Apache web server can be enabled for wsgi services that support being deployed
+under HTTPD + mod_wsgi. By default, services that recommend running under
+HTTPD + mod_wsgi are deployed under Apache. To use an alternative deployment
+strategy (e.g. eventlet) for services that support an alternative to HTTPD +
+mod_wsgi set ``ENABLE_HTTPD_MOD_WSGI_SERVICES`` to ``False`` in your
+``local.conf``.
 
-    APACHE_ENABLED_SERVICES+=key,swift
+Each service that can be run under HTTPD + mod_wsgi also has an override
+toggle available that can be set in your ``local.conf``.
+
+Example (Keystone):
+
+    KEYSTONE_USE_MOD_WSGI="True"
+
+Example (Swift):
+
+    SWIFT_USE_MOD_WSGI="True"
 
 # Swift
 
@@ -330,6 +342,25 @@
     Q_HOST=$SERVICE_HOST
     MATCHMAKER_REDIS_HOST=$SERVICE_HOST
 
+# Multi-Region Setup
+
+We want to setup two devstack (RegionOne and RegionTwo) with shared keystone
+(same users and services) and horizon.
+Keystone and Horizon will be located in RegionOne.
+Full spec is available at:
+https://wiki.openstack.org/wiki/Heat/Blueprints/Multi_Region_Support_for_Heat.
+
+In RegionOne:
+
+    REGION_NAME=RegionOne
+
+In RegionTwo:
+
+    disable_service horizon
+    KEYSTONE_SERVICE_HOST=<KEYSTONE_IP_ADDRESS_FROM_REGION_ONE>
+    KEYSTONE_AUTH_HOST=<KEYSTONE_IP_ADDRESS_FROM_REGION_ONE>
+    REGION_NAME=RegionTwo
+
 # Cells
 
 Cells is a new scaling option with a full spec at:
diff --git a/files/apts/general b/files/apts/general
index d81ec7a..90529e5 100644
--- a/files/apts/general
+++ b/files/apts/general
@@ -22,3 +22,4 @@
 python-dev
 python2.7
 bc
+libyaml-dev
diff --git a/files/rpms/general b/files/rpms/general
index c940de6..a0074dd 100644
--- a/files/rpms/general
+++ b/files/rpms/general
@@ -23,6 +23,7 @@
 wget
 which
 bc
+libyaml-devel
 
 # [1] : some of installed tools have unversioned dependencies on this,
 # but others have versioned (<=0.7).  So if a later version (0.7.1)
diff --git a/functions-common b/functions-common
index 613a86c..44225ab 100644
--- a/functions-common
+++ b/functions-common
@@ -719,6 +719,109 @@
     mv ${tmpfile} ${policy_file}
 }
 
+# Gets or creates user
+# Usage: get_or_create_user <username> <password> <project> <email>
+function get_or_create_user {
+    # Gets user id
+    USER_ID=$(
+        # Gets user id
+        openstack user show $1 -f value -c id 2>/dev/null ||
+        # Creates new user
+        openstack user create \
+            $1 \
+            --password "$2" \
+            --project $3 \
+            --email $4 \
+            -f value -c id
+    )
+    echo $USER_ID
+}
+
+# Gets or creates project
+# Usage: get_or_create_project <name>
+function get_or_create_project {
+    # Gets project id
+    PROJECT_ID=$(
+        # Gets project id
+        openstack project show $1 -f value -c id 2>/dev/null ||
+        # Creates new project if not exists
+        openstack project create $1 -f value -c id
+    )
+    echo $PROJECT_ID
+}
+
+# Gets or creates role
+# Usage: get_or_create_role <name>
+function get_or_create_role {
+    ROLE_ID=$(
+        # Gets role id
+        openstack role show $1 -f value -c id 2>/dev/null ||
+        # Creates role if not exists
+        openstack role create $1 -f value -c id
+    )
+    echo $ROLE_ID
+}
+
+# Gets or adds user role
+# Usage: get_or_add_user_role <role> <user> <project>
+function get_or_add_user_role {
+    # Gets user role id
+    USER_ROLE_ID=$(openstack user role list \
+        $2 \
+        --project $3 \
+        --column "ID" \
+        --column "Name" \
+        | grep " $1 " | get_field 1)
+    if [[ -z "$USER_ROLE_ID" ]]; then
+        # Adds role to user
+        USER_ROLE_ID=$(openstack role add \
+            $1 \
+            --user $2 \
+            --project $3 \
+            | grep " id " | get_field 2)
+    fi
+    echo $USER_ROLE_ID
+}
+
+# Gets or creates service
+# Usage: get_or_create_service <name> <type> <description>
+function get_or_create_service {
+    # Gets service id
+    SERVICE_ID=$(
+        # Gets service id
+        openstack service show $1 -f value -c id 2>/dev/null ||
+        # Creates new service if not exists
+        openstack service create \
+            $1 \
+            --type=$2 \
+            --description="$3" \
+            -f value -c id
+    )
+    echo $SERVICE_ID
+}
+
+# Gets or creates endpoint
+# Usage: get_or_create_endpoint <service> <region> <publicurl> <adminurl> <internalurl>
+function get_or_create_endpoint {
+    # Gets endpoint id
+    ENDPOINT_ID=$(openstack endpoint list \
+        --column "ID" \
+        --column "Region" \
+        --column "Service Name" \
+        | grep " $2 " \
+        | grep " $1 " | get_field 1)
+    if [[ -z "$ENDPOINT_ID" ]]; then
+        # Creates new endpoint
+        ENDPOINT_ID=$(openstack endpoint create \
+            $1 \
+            --region $2 \
+            --publicurl $3 \
+            --adminurl $4 \
+            --internalurl $5 \
+            | grep " id " | get_field 2)
+    fi
+    echo $ENDPOINT_ID
+}
 
 # Package Functions
 # =================
diff --git a/lib/apache b/lib/apache
index f7255be..c0d32df 100644
--- a/lib/apache
+++ b/lib/apache
@@ -8,7 +8,6 @@
 #
 # lib/apache exports the following functions:
 #
-# - is_apache_enabled_service
 # - install_apache_wsgi
 # - config_apache_wsgi
 # - apache_site_config_for
@@ -42,23 +41,6 @@
 
 # Functions
 # ---------
-
-# is_apache_enabled_service() checks if the service(s) specified as arguments are
-# apache enabled by the user in ``APACHE_ENABLED_SERVICES`` as web front end.
-#
-# Multiple services specified as arguments are ``OR``'ed together; the test
-# is a short-circuit boolean, i.e it returns on the first match.
-#
-# Uses global ``APACHE_ENABLED_SERVICES``
-# APACHE_ENABLED_SERVICES service [service ...]
-function is_apache_enabled_service {
-    services=$@
-    for service in ${services}; do
-        [[ ,${APACHE_ENABLED_SERVICES}, =~ ,${service}, ]] && return 0
-    done
-    return 1
-}
-
 # install_apache_wsgi() - Install Apache server and wsgi module
 function install_apache_wsgi {
     # Apache installation, because we mark it NOPRIME
diff --git a/lib/ceilometer b/lib/ceilometer
index eef6740..1540e3e 100644
--- a/lib/ceilometer
+++ b/lib/ceilometer
@@ -53,6 +53,9 @@
 CEILOMETER_SERVICE_HOST=$SERVICE_HOST
 CEILOMETER_SERVICE_PORT=${CEILOMETER_SERVICE_PORT:-8777}
 
+# To enable OSprofiler change value of this variable to "notifications,profiler"
+CEILOMETER_NOTIFICATION_TOPICS=${CEILOMETER_NOTIFICATION_TOPICS:-notifications}
+
 # Tell Tempest this project is present
 TEMPEST_SERVICES+=,ceilometer
 
@@ -81,35 +84,22 @@
 
     # Ceilometer
     if [[ "$ENABLED_SERVICES" =~ "ceilometer-api" ]]; then
-        CEILOMETER_USER=$(openstack user create \
-            ceilometer \
-            --password "$SERVICE_PASSWORD" \
-            --project $SERVICE_TENANT \
-            --email ceilometer@example.com \
-            | grep " id " | get_field 2)
-        openstack role add \
-            $ADMIN_ROLE \
-            --project $SERVICE_TENANT \
-            --user $CEILOMETER_USER
+        CEILOMETER_USER=$(get_or_create_user "ceilometer" \
+            "$SERVICE_PASSWORD" $SERVICE_TENANT "ceilometer@example.com")
+        get_or_add_user_role $ADMIN_ROLE $CEILOMETER_USER $SERVICE_TENANT
+
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-            CEILOMETER_SERVICE=$(openstack service create \
-                ceilometer \
-                --type=metering \
-                --description="OpenStack Telemetry Service" \
-                | grep " id " | get_field 2)
-            openstack endpoint create \
-                $CEILOMETER_SERVICE \
-                --region RegionOne \
-                --publicurl "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/" \
-                --adminurl "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/" \
-                --internalurl "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/"
+            CEILOMETER_SERVICE=$(get_or_create_service "ceilometer" \
+                "metering" "OpenStack Telemetry Service")
+            get_or_create_endpoint $CEILOMETER_SERVICE \
+                "$REGION_NAME" \
+                "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/" \
+                "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/" \
+                "$CEILOMETER_SERVICE_PROTOCOL://$CEILOMETER_SERVICE_HOST:$CEILOMETER_SERVICE_PORT/"
         fi
         if is_service_enabled swift; then
             # Ceilometer needs ResellerAdmin role to access swift account stats.
-            openstack role add \
-                --project $SERVICE_TENANT_NAME \
-                --user ceilometer \
-                ResellerAdmin
+            get_or_add_user_role "ResellerAdmin" "ceilometer" $SERVICE_TENANT_NAME
         fi
     fi
 }
@@ -141,7 +131,7 @@
 
     iniset_rpc_backend ceilometer $CEILOMETER_CONF DEFAULT
 
-    iniset $CEILOMETER_CONF DEFAULT notification_topics 'notifications'
+    iniset $CEILOMETER_CONF DEFAULT notification_topics "$CEILOMETER_NOTIFICATION_TOPICS"
     iniset $CEILOMETER_CONF DEFAULT verbose True
     iniset $CEILOMETER_CONF DEFAULT debug "$ENABLE_DEBUG_LOG_LEVEL"
 
@@ -163,7 +153,6 @@
     iniset $CEILOMETER_CONF service_credentials os_username ceilometer
     iniset $CEILOMETER_CONF service_credentials os_password $SERVICE_PASSWORD
     iniset $CEILOMETER_CONF service_credentials os_tenant_name $SERVICE_TENANT_NAME
-    iniset $CEILOMETER_CONF service_credentials os_auth_url $OS_AUTH_URL
 
     iniset $CEILOMETER_CONF keystone_authtoken identity_uri $KEYSTONE_AUTH_URI
     iniset $CEILOMETER_CONF keystone_authtoken admin_user ceilometer
diff --git a/lib/cinder b/lib/cinder
index 6f2d7c6..03d2f54 100644
--- a/lib/cinder
+++ b/lib/cinder
@@ -339,39 +339,26 @@
 
     # Cinder
     if [[ "$ENABLED_SERVICES" =~ "c-api" ]]; then
-        CINDER_USER=$(openstack user create \
-            cinder \
-            --password "$SERVICE_PASSWORD" \
-            --project $SERVICE_TENANT \
-            --email cinder@example.com \
-            | grep " id " | get_field 2)
-        openstack role add \
-            $ADMIN_ROLE \
-            --project $SERVICE_TENANT \
-            --user $CINDER_USER
+
+        CINDER_USER=$(get_or_create_user "cinder" \
+            "$SERVICE_PASSWORD" $SERVICE_TENANT "cinder@example.com")
+        get_or_add_user_role $ADMIN_ROLE $CINDER_USER $SERVICE_TENANT
+
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-            CINDER_SERVICE=$(openstack service create \
-                cinder \
-                --type=volume \
-                --description="Cinder Volume Service" \
-                | grep " id " | get_field 2)
-            openstack endpoint create \
-                $CINDER_SERVICE \
-                --region RegionOne \
-                --publicurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" \
-                --adminurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" \
-                --internalurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s"
-            CINDER_V2_SERVICE=$(openstack service create \
-                cinderv2 \
-                --type=volumev2 \
-                --description="Cinder Volume Service V2" \
-                | grep " id " | get_field 2)
-            openstack endpoint create \
-                $CINDER_V2_SERVICE \
-                --region RegionOne \
-                --publicurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s" \
-                --adminurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s" \
-                --internalurl "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s"
+
+            CINDER_SERVICE=$(get_or_create_service "cinder" \
+                "volume" "Cinder Volume Service")
+            get_or_create_endpoint $CINDER_SERVICE "$REGION_NAME" \
+                "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" \
+                "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s" \
+                "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v1/\$(tenant_id)s"
+
+            CINDER_V2_SERVICE=$(get_or_create_service "cinderv2" \
+                "volumev2" "Cinder Volume Service V2")
+            get_or_create_endpoint $CINDER_V2_SERVICE "$REGION_NAME" \
+                "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s" \
+                "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s" \
+                "$CINDER_SERVICE_PROTOCOL://$CINDER_SERVICE_HOST:$CINDER_SERVICE_PORT/v2/\$(tenant_id)s"
         fi
     fi
 }
diff --git a/lib/glance b/lib/glance
index 4eb0ada..475bb48 100644
--- a/lib/glance
+++ b/lib/glance
@@ -164,36 +164,28 @@
 
 function create_glance_accounts {
     if is_service_enabled g-api; then
-        openstack user create \
-            --password "$SERVICE_PASSWORD" \
-            --project $SERVICE_TENANT_NAME \
-            glance
-        openstack role add \
-            --project $SERVICE_TENANT_NAME \
-            --user glance \
-            service
+
+        GLANCE_USER=$(get_or_create_user "glance" \
+            "$SERVICE_PASSWORD" $SERVICE_TENANT_NAME "glance@example.com")
+        get_or_add_user_role service $GLANCE_USER $SERVICE_TENANT_NAME
+
         # required for swift access
         if is_service_enabled s-proxy; then
-            openstack user create \
-                --password "$SERVICE_PASSWORD" \
-                --project $SERVICE_TENANT_NAME \
-                glance-swift
-            openstack role add \
-                --project $SERVICE_TENANT_NAME \
-                --user glance-swift \
-                ResellerAdmin
+
+            GLANCE_SWIFT_USER=$(get_or_create_user "glance-swift" \
+                "$SERVICE_PASSWORD" $SERVICE_TENANT_NAME "glance-swift@example.com")
+            get_or_add_user_role "ResellerAdmin" $GLANCE_SWIFT_USER $SERVICE_TENANT_NAME
         fi
+
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-            openstack service create \
-                --type image \
-                --description "Glance Image Service" \
-                glance
-            openstack endpoint create \
-                --region RegionOne \
-                --publicurl "http://$GLANCE_HOSTPORT" \
-                --adminurl "http://$GLANCE_HOSTPORT" \
-                --internalurl "http://$GLANCE_HOSTPORT" \
-                glance
+
+            GLANCE_SERVICE=$(get_or_create_service "glance" \
+                "image" "Glance Image Service")
+            get_or_create_endpoint $GLANCE_SERVICE \
+                "$REGION_NAME" \
+                "http://$GLANCE_HOSTPORT" \
+                "http://$GLANCE_HOSTPORT" \
+                "http://$GLANCE_HOSTPORT"
         fi
     fi
 }
diff --git a/lib/heat b/lib/heat
index b8c0359..afed52b 100644
--- a/lib/heat
+++ b/lib/heat
@@ -98,6 +98,8 @@
     iniset $HEAT_CONF database connection `database_connection_url heat`
     iniset $HEAT_CONF DEFAULT auth_encryption_key `hexdump -n 16 -v -e '/1 "%02x"' /dev/urandom`
 
+    iniset $HEAT_CONF DEFAULT region_name_for_services "$REGION_NAME"
+
     # logging
     iniset $HEAT_CONF DEFAULT debug $ENABLE_DEBUG_LOG_LEVEL
     iniset $HEAT_CONF DEFAULT use_syslog $SYSLOG
@@ -214,57 +216,44 @@
     SERVICE_TENANT=$(openstack project list | awk "/ $SERVICE_TENANT_NAME / { print \$2 }")
     ADMIN_ROLE=$(openstack role list | awk "/ admin / { print \$2 }")
 
-    HEAT_USER=$(openstack user create \
-        heat \
-        --password "$SERVICE_PASSWORD" \
-        --project $SERVICE_TENANT \
-        --email heat@example.com \
-        | grep " id " | get_field 2)
-    openstack role add \
-        $ADMIN_ROLE \
-        --project $SERVICE_TENANT \
-        --user $HEAT_USER
+    HEAT_USER=$(get_or_create_user "heat" \
+        "$SERVICE_PASSWORD" $SERVICE_TENANT "heat@example.com")
+    get_or_add_user_role $ADMIN_ROLE $HEAT_USER $SERVICE_TENANT
+
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-        HEAT_SERVICE=$(openstack service create \
-            heat \
-            --type=orchestration \
-            --description="Heat Orchestration Service" \
-            | grep " id " | get_field 2)
-        openstack endpoint create \
-                $HEAT_SERVICE \
-                --region RegionOne \
-                --publicurl "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s" \
-                --adminurl "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s" \
-                --internalurl "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s"
-        HEAT_CFN_SERVICE=$(openstack service create \
-            heat \
-            --type=cloudformation \
-            --description="Heat CloudFormation Service" \
-            | grep " id " | get_field 2)
-        openstack endpoint create \
-                $HEAT_CFN_SERVICE \
-                --region RegionOne \
-                --publicurl "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1" \
-                --adminurl "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1" \
-                --internalurl "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1"
+
+        HEAT_SERVICE=$(get_or_create_service "heat" \
+                "orchestration" "Heat Orchestration Service")
+        get_or_create_endpoint $HEAT_SERVICE \
+            "$REGION_NAME" \
+            "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s" \
+            "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s" \
+            "$SERVICE_PROTOCOL://$HEAT_API_HOST:$HEAT_API_PORT/v1/\$(tenant_id)s"
+
+        HEAT_CFN_SERVICE=$(get_or_create_service "heat-cfn" \
+                "cloudformation" "Heat CloudFormation Service")
+        get_or_create_endpoint $HEAT_CFN_SERVICE \
+            "$REGION_NAME" \
+            "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1" \
+            "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1" \
+            "$SERVICE_PROTOCOL://$HEAT_API_CFN_HOST:$HEAT_API_CFN_PORT/v1"
     fi
 
     # heat_stack_user role is for users created by Heat
-    openstack role create heat_stack_user
+    get_or_create_role "heat_stack_user"
 
     if [[ $HEAT_DEFERRED_AUTH == trusts ]]; then
+
         # heat_stack_owner role is given to users who create Heat stacks,
         # it's the default role used by heat to delegate to the heat service
         # user (for performing deferred operations via trusts), see heat.conf
-        HEAT_OWNER_ROLE=$(openstack role create \
-            heat_stack_owner \
-            | grep " id " | get_field 2)
+        HEAT_OWNER_ROLE=$(get_or_create_role "heat_stack_owner")
 
         # Give the role to the demo and admin users so they can create stacks
         # in either of the projects created by devstack
-        openstack role add $HEAT_OWNER_ROLE --project demo --user demo
-        openstack role add $HEAT_OWNER_ROLE --project demo --user admin
-        openstack role add $HEAT_OWNER_ROLE --project admin --user admin
+        get_or_add_user_role $HEAT_OWNER_ROLE demo demo
+        get_or_add_user_role $HEAT_OWNER_ROLE admin demo
+        get_or_add_user_role $HEAT_OWNER_ROLE admin admin
         iniset $HEAT_CONF DEFAULT deferred_auth_method trusts
     fi
 
@@ -272,21 +261,27 @@
         # Note we have to pass token/endpoint here because the current endpoint and
         # version negotiation in OSC means just --os-identity-api-version=3 won't work
         KS_ENDPOINT_V3="$KEYSTONE_SERVICE_URI/v3"
-        D_ID=$(openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
-            --os-identity-api-version=3 domain create heat \
-            --description "Owns users and projects created by heat" \
-            | grep ' id ' | get_field 2)
-        iniset $HEAT_CONF DEFAULT stack_user_domain ${D_ID}
 
-        openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
-            --os-identity-api-version=3 user create --password $SERVICE_PASSWORD \
-            --domain $D_ID heat_domain_admin \
-            --description "Manages users and projects created by heat"
-        openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
-            --os-identity-api-version=3 role add \
-            --user heat_domain_admin --domain ${D_ID} admin
-        iniset $HEAT_CONF DEFAULT stack_domain_admin heat_domain_admin
-        iniset $HEAT_CONF DEFAULT stack_domain_admin_password $SERVICE_PASSWORD
+        D_ID=$(openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
+            --os-identity-api-version=3 domain list | grep ' heat ' | get_field 1)
+
+        if [[ -z "$D_ID" ]]; then
+            D_ID=$(openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
+                --os-identity-api-version=3 domain create heat \
+                --description "Owns users and projects created by heat" \
+                | grep ' id ' | get_field 2)
+            iniset $HEAT_CONF DEFAULT stack_user_domain ${D_ID}
+
+            openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
+                --os-identity-api-version=3 user create --password $SERVICE_PASSWORD \
+                --domain $D_ID heat_domain_admin \
+                --description "Manages users and projects created by heat"
+            openstack --os-token $OS_TOKEN --os-url=$KS_ENDPOINT_V3 \
+                --os-identity-api-version=3 role add \
+                --user heat_domain_admin --domain ${D_ID} admin
+            iniset $HEAT_CONF DEFAULT stack_domain_admin heat_domain_admin
+            iniset $HEAT_CONF DEFAULT stack_domain_admin_password $SERVICE_PASSWORD
+        fi
     fi
 }
 
diff --git a/lib/ironic b/lib/ironic
index dbeb3d3..c24780f 100644
--- a/lib/ironic
+++ b/lib/ironic
@@ -223,28 +223,21 @@
 
     # Ironic
     if [[ "$ENABLED_SERVICES" =~ "ir-api" ]]; then
-        IRONIC_USER=$(openstack user create \
-            ironic \
-            --password "$SERVICE_PASSWORD" \
-            --project $SERVICE_TENANT \
-            --email ironic@example.com \
-            | grep " id " | get_field 2)
-        openstack role add \
-            $ADMIN_ROLE \
-            --project $SERVICE_TENANT \
-            --user $IRONIC_USER
+        # Get ironic user if exists
+
+        IRONIC_USER=$(get_or_create_user "ironic" \
+            "$SERVICE_PASSWORD" $SERVICE_TENANT "ironic@example.com")
+        get_or_add_user_role $ADMIN_ROLE $IRONIC_USER $SERVICE_TENANT
+
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-            IRONIC_SERVICE=$(openstack service create \
-                ironic \
-                --type=baremetal \
-                --description="Ironic baremetal provisioning service" \
-                | grep " id " | get_field 2)
-            openstack endpoint create \
-                $IRONIC_SERVICE \
-                --region RegionOne \
-                --publicurl "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT" \
-                --adminurl "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT" \
-                --internalurl "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT"
+
+            IRONIC_SERVICE=$(get_or_create_service "ironic" \
+                "baremetal" "Ironic baremetal provisioning service")
+            get_or_create_endpoint $IRONIC_SERVICE \
+                "$REGION_NAME" \
+                "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT" \
+                "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT" \
+                "$IRONIC_SERVICE_PROTOCOL://$IRONIC_HOSTPORT"
         fi
     fi
 }
diff --git a/lib/keystone b/lib/keystone
index 8a4683f..ec124cb 100644
--- a/lib/keystone
+++ b/lib/keystone
@@ -46,6 +46,9 @@
 # Example of KEYSTONE_EXTENSIONS=oauth1,federation
 KEYSTONE_EXTENSIONS=${KEYSTONE_EXTENSIONS:-}
 
+# Toggle for deploying Keystone under HTTPD + mod_wsgi
+KEYSTONE_USE_MOD_WSGI=${KEYSTONE_USE_MOD_WSGI:-False}
+
 # Select the backend for Keystone's service catalog
 KEYSTONE_CATALOG_BACKEND=${KEYSTONE_CATALOG_BACKEND:-sql}
 KEYSTONE_CATALOG=$KEYSTONE_CONF_DIR/default_catalog.templates
@@ -112,6 +115,7 @@
     sudo rm -f $KEYSTONE_WSGI_DIR/*.wsgi
     disable_apache_site keystone
     sudo rm -f $(apache_site_config_for keystone)
+    restart_apache_server
 }
 
 # _config_keystone_apache_wsgi() - Set WSGI config files of Keystone
@@ -265,11 +269,11 @@
     fi
 
     # Format logging
-    if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ] &&  ! is_apache_enabled_service key ; then
+    if [ "$LOG_COLOR" == "True" ] && [ "$SYSLOG" == "False" ] && [ "$KEYSTONE_USE_MOD_WSGI" == "False" ]  ; then
         setup_colorized_logging $KEYSTONE_CONF DEFAULT
     fi
 
-    if is_apache_enabled_service key; then
+    if [ "$KEYSTONE_USE_MOD_WSGI" == "True" ]; then
         iniset $KEYSTONE_CONF DEFAULT debug "True"
         # Eliminate the %(asctime)s.%(msecs)03d from the log format strings
         iniset $KEYSTONE_CONF DEFAULT logging_context_format_string "%(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s"
@@ -278,6 +282,8 @@
         iniset $KEYSTONE_CONF DEFAULT logging_exception_prefix "%(process)d TRACE %(name)s %(instance)s"
         _config_keystone_apache_wsgi
     fi
+
+    iniset $KEYSTONE_CONF DEFAULT max_token_size 16384
 }
 
 function configure_keystone_extensions {
@@ -316,79 +322,55 @@
 function create_keystone_accounts {
 
     # admin
-    ADMIN_TENANT=$(openstack project create \
-        admin \
-        | grep " id " | get_field 2)
-    ADMIN_USER=$(openstack user create \
-        admin \
-        --project "$ADMIN_TENANT" \
-        --email admin@example.com \
-        --password "$ADMIN_PASSWORD" \
-        | grep " id " | get_field 2)
-    ADMIN_ROLE=$(openstack role create \
-        admin \
-        | grep " id " | get_field 2)
-    openstack role add \
-        $ADMIN_ROLE \
-        --project $ADMIN_TENANT \
-        --user $ADMIN_USER
+    ADMIN_TENANT=$(get_or_create_project "admin")
+    ADMIN_USER=$(get_or_create_user "admin" \
+        "$ADMIN_PASSWORD" "$ADMIN_TENANT" "admin@example.com")
+    ADMIN_ROLE=$(get_or_create_role "admin")
+    get_or_add_user_role $ADMIN_ROLE $ADMIN_USER $ADMIN_TENANT
 
     # Create service project/role
-    openstack project create $SERVICE_TENANT_NAME
+    get_or_create_project "$SERVICE_TENANT_NAME"
 
     # Service role, so service users do not have to be admins
-    openstack role create service
+    get_or_create_role service
 
     # The ResellerAdmin role is used by Nova and Ceilometer so we need to keep it.
     # The admin role in swift allows a user to act as an admin for their tenant,
     # but ResellerAdmin is needed for a user to act as any tenant. The name of this
     # role is also configurable in swift-proxy.conf
-    openstack role create ResellerAdmin
+    get_or_create_role ResellerAdmin
 
     # The Member role is used by Horizon and Swift so we need to keep it:
-    MEMBER_ROLE=$(openstack role create \
-        Member \
-        | grep " id " | get_field 2)
+    MEMBER_ROLE=$(get_or_create_role "Member")
+
     # ANOTHER_ROLE demonstrates that an arbitrary role may be created and used
     # TODO(sleepsonthefloor): show how this can be used for rbac in the future!
-    ANOTHER_ROLE=$(openstack role create \
-        anotherrole \
-        | grep " id " | get_field 2)
+
+    ANOTHER_ROLE=$(get_or_create_role "anotherrole")
 
     # invisible tenant - admin can't see this one
-    INVIS_TENANT=$(openstack project create \
-        invisible_to_admin \
-        | grep " id " | get_field 2)
+    INVIS_TENANT=$(get_or_create_project "invisible_to_admin")
 
     # demo
-    DEMO_TENANT=$(openstack project create \
-        demo \
-        | grep " id " | get_field 2)
-    DEMO_USER=$(openstack user create \
-        demo \
-        --project $DEMO_TENANT \
-        --email demo@example.com \
-        --password "$ADMIN_PASSWORD" \
-        | grep " id " | get_field 2)
+    DEMO_TENANT=$(get_or_create_project "demo")
+    DEMO_USER=$(get_or_create_user "demo" \
+        "$ADMIN_PASSWORD" "$DEMO_TENANT" "demo@example.com")
 
-    openstack role add --project $DEMO_TENANT --user $DEMO_USER $MEMBER_ROLE
-    openstack role add --project $DEMO_TENANT --user $ADMIN_USER $ADMIN_ROLE
-    openstack role add --project $DEMO_TENANT --user $DEMO_USER $ANOTHER_ROLE
-    openstack role add --project $INVIS_TENANT --user $DEMO_USER $MEMBER_ROLE
+    get_or_add_user_role $MEMBER_ROLE $DEMO_USER $DEMO_TENANT
+    get_or_add_user_role $ADMIN_ROLE $ADMIN_USER $DEMO_TENANT
+    get_or_add_user_role $ANOTHER_ROLE $DEMO_USER $DEMO_TENANT
+    get_or_add_user_role $MEMBER_ROLE $DEMO_USER $INVIS_TENANT
 
     # Keystone
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-        KEYSTONE_SERVICE=$(openstack service create \
-            keystone \
-            --type identity \
-            --description "Keystone Identity Service" \
-            | grep " id " | get_field 2)
-        openstack endpoint create \
-            $KEYSTONE_SERVICE \
-            --region RegionOne \
-            --publicurl "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION" \
-            --adminurl "$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT/v$IDENTITY_API_VERSION" \
-            --internalurl "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION"
+
+        KEYSTONE_SERVICE=$(get_or_create_service "keystone" \
+            "identity" "Keystone Identity Service")
+        get_or_create_endpoint $KEYSTONE_SERVICE \
+            "$REGION_NAME" \
+            "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION" \
+            "$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT/v$IDENTITY_API_VERSION" \
+            "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v$IDENTITY_API_VERSION"
     fi
 }
 
@@ -464,7 +446,7 @@
     fi
     git_clone $KEYSTONE_REPO $KEYSTONE_DIR $KEYSTONE_BRANCH
     setup_develop $KEYSTONE_DIR
-    if is_apache_enabled_service key; then
+    if [ "$KEYSTONE_USE_MOD_WSGI" == "True" ]; then
         install_apache_wsgi
     fi
 }
@@ -477,7 +459,7 @@
         service_port=$KEYSTONE_SERVICE_PORT_INT
     fi
 
-    if is_apache_enabled_service key; then
+    if [ "$KEYSTONE_USE_MOD_WSGI" == "True" ]; then
         restart_apache_server
         screen_it key "cd $KEYSTONE_DIR && sudo tail -f /var/log/$APACHE_NAME/keystone"
     else
diff --git a/lib/marconi b/lib/marconi
index 20bf0e1..d7822c9 100644
--- a/lib/marconi
+++ b/lib/marconi
@@ -178,29 +178,19 @@
     SERVICE_TENANT=$(openstack project list | awk "/ $SERVICE_TENANT_NAME / { print \$2 }")
     ADMIN_ROLE=$(openstack role list | awk "/ admin / { print \$2 }")
 
-    MARCONI_USER=$(openstack user create \
-        marconi \
-        --password "$SERVICE_PASSWORD" \
-        --project $SERVICE_TENANT \
-        --email marconi@example.com \
-        | grep " id " | get_field 2)
-    openstack role add \
-        $ADMIN_ROLE \
-        --project $SERVICE_TENANT \
-        --user $MARCONI_USER
+    MARCONI_USER=$(get_or_create_user "marconi" \
+        "$SERVICE_PASSWORD" $SERVICE_TENANT "marconi@example.com")
+    get_or_add_user_role $ADMIN_ROLE $MARCONI_USER $SERVICE_TENANT
 
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-        MARCONI_SERVICE=$(openstack service create \
-            marconi \
-            --type=queuing \
-            --description="Marconi Service" \
-            | grep " id " | get_field 2)
-        openstack endpoint create \
-            $MARCONI_SERVICE \
-            --region RegionOne \
-            --publicurl "$MARCONI_SERVICE_PROTOCOL://$MARCONI_SERVICE_HOST:$MARCONI_SERVICE_PORT" \
-            --adminurl "$MARCONI_SERVICE_PROTOCOL://$MARCONI_SERVICE_HOST:$MARCONI_SERVICE_PORT" \
-            --internalurl "$MARCONI_SERVICE_PROTOCOL://$MARCONI_SERVICE_HOST:$MARCONI_SERVICE_PORT"
+
+        MARCONI_SERVICE=$(get_or_create_service "marconi" \
+            "queuing" "Marconi Service")
+        get_or_create_endpoint $MARCONI_SERVICE \
+            "$REGION_NAME" \
+            "$MARCONI_SERVICE_PROTOCOL://$MARCONI_SERVICE_HOST:$MARCONI_SERVICE_PORT" \
+            "$MARCONI_SERVICE_PROTOCOL://$MARCONI_SERVICE_HOST:$MARCONI_SERVICE_PORT" \
+            "$MARCONI_SERVICE_PROTOCOL://$MARCONI_SERVICE_HOST:$MARCONI_SERVICE_PORT"
     fi
 
 }
diff --git a/lib/neutron b/lib/neutron
index 2c6f53b..6039872 100644
--- a/lib/neutron
+++ b/lib/neutron
@@ -161,7 +161,7 @@
 # If using GRE tunnels for tenant networks, specify the range of
 # tunnel IDs from which tenant networks are allocated. Can be
 # overriden in ``localrc`` in necesssary.
-TENANT_TUNNEL_RANGES=${TENANT_TUNNEL_RANGE:-1:1000}
+TENANT_TUNNEL_RANGES=${TENANT_TUNNEL_RANGES:-1:1000}
 
 # To use VLANs for tenant networks, set to True in localrc. VLANs
 # are supported by the openvswitch and linuxbridge plugins, each
@@ -307,7 +307,7 @@
     iniset $NOVA_CONF neutron admin_auth_url "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:$KEYSTONE_AUTH_PORT/v2.0"
     iniset $NOVA_CONF neutron auth_strategy "$Q_AUTH_STRATEGY"
     iniset $NOVA_CONF neutron admin_tenant_name "$SERVICE_TENANT_NAME"
-    iniset $NOVA_CONF neutron region_name "RegionOne"
+    iniset $NOVA_CONF neutron region_name "$REGION_NAME"
     iniset $NOVA_CONF neutron url "http://$Q_HOST:$Q_PORT"
 
     if [[ "$Q_USE_SECGROUP" == "True" ]]; then
@@ -350,28 +350,20 @@
     ADMIN_ROLE=$(openstack role list | awk "/ admin / { print \$2 }")
 
     if [[ "$ENABLED_SERVICES" =~ "q-svc" ]]; then
-        NEUTRON_USER=$(openstack user create \
-            neutron \
-            --password "$SERVICE_PASSWORD" \
-            --project $SERVICE_TENANT \
-            --email neutron@example.com \
-            | grep " id " | get_field 2)
-        openstack role add \
-            $ADMIN_ROLE \
-            --project $SERVICE_TENANT \
-            --user $NEUTRON_USER
+
+        NEUTRON_USER=$(get_or_create_user "neutron" \
+            "$SERVICE_PASSWORD" $SERVICE_TENANT "neutron@example.com")
+        get_or_add_user_role $ADMIN_ROLE $NEUTRON_USER $SERVICE_TENANT
+
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-            NEUTRON_SERVICE=$(openstack service create \
-                neutron \
-                --type=network \
-                --description="Neutron Service" \
-                | grep " id " | get_field 2)
-            openstack endpoint create \
-                $NEUTRON_SERVICE \
-                --region RegionOne \
-                --publicurl "http://$SERVICE_HOST:9696/" \
-                --adminurl "http://$SERVICE_HOST:9696/" \
-                --internalurl "http://$SERVICE_HOST:9696/"
+
+            NEUTRON_SERVICE=$(get_or_create_service "neutron" \
+                "network" "Neutron Service")
+            get_or_create_endpoint $NEUTRON_SERVICE \
+                "$REGION_NAME" \
+                "http://$SERVICE_HOST:9696/" \
+                "http://$SERVICE_HOST:9696/" \
+                "http://$SERVICE_HOST:9696/"
         fi
     fi
 }
diff --git a/lib/nova b/lib/nova
index 3d31d68..ebdb6b4 100644
--- a/lib/nova
+++ b/lib/nova
@@ -333,39 +333,28 @@
 
     # Nova
     if [[ "$ENABLED_SERVICES" =~ "n-api" ]]; then
-        NOVA_USER=$(openstack user create \
-            nova \
-            --password "$SERVICE_PASSWORD" \
-            --project $SERVICE_TENANT \
-            --email nova@example.com \
-            | grep " id " | get_field 2)
-        openstack role add \
-            $ADMIN_ROLE \
-            --project $SERVICE_TENANT \
-            --user $NOVA_USER
+
+        NOVA_USER=$(get_or_create_user "nova" \
+            "$SERVICE_PASSWORD" $SERVICE_TENANT "nova@example.com")
+        get_or_add_user_role $ADMIN_ROLE $NOVA_USER $SERVICE_TENANT
+
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-            NOVA_SERVICE=$(openstack service create \
-                nova \
-                --type=compute \
-                --description="Nova Compute Service" \
-                | grep " id " | get_field 2)
-            openstack endpoint create \
-                $NOVA_SERVICE \
-                --region RegionOne \
-                --publicurl "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s" \
-                --adminurl "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s" \
-                --internalurl "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s"
-            NOVA_V3_SERVICE=$(openstack service create \
-                novav3 \
-                --type=computev3 \
-                --description="Nova Compute Service V3" \
-                | grep " id " | get_field 2)
-            openstack endpoint create \
-                $NOVA_V3_SERVICE \
-                --region RegionOne \
-                --publicurl "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v3" \
-                --adminurl "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v3" \
-                --internalurl "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v3"
+
+            NOVA_SERVICE=$(get_or_create_service "nova" \
+                "compute" "Nova Compute Service")
+            get_or_create_endpoint $NOVA_SERVICE \
+                "$REGION_NAME" \
+                "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s" \
+                "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s" \
+                "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v2/\$(tenant_id)s"
+
+            NOVA_V3_SERVICE=$(get_or_create_service "novav3" \
+                "computev3" "Nova Compute Service V3")
+            get_or_create_endpoint $NOVA_V3_SERVICE \
+                "$REGION_NAME" \
+                "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v3" \
+                "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v3" \
+                "$NOVA_SERVICE_PROTOCOL://$NOVA_SERVICE_HOST:$NOVA_SERVICE_PORT/v3"
         fi
     fi
 
@@ -374,40 +363,32 @@
         if is_service_enabled swift; then
             # Nova needs ResellerAdmin role to download images when accessing
             # swift through the s3 api.
-            openstack role add \
-                --project $SERVICE_TENANT_NAME \
-                --user nova \
-                ResellerAdmin
+            get_or_add_user_role ResellerAdmin nova $SERVICE_TENANT_NAME
         fi
 
         # EC2
         if [[ "$KEYSTONE_CATALOG_BACKEND" = "sql" ]]; then
-            openstack service create \
-                --type ec2 \
-                --description "EC2 Compatibility Layer" \
-                ec2
-            openstack endpoint create \
-                --region RegionOne \
-                --publicurl "http://$SERVICE_HOST:8773/services/Cloud" \
-                --adminurl "http://$SERVICE_HOST:8773/services/Admin" \
-                --internalurl "http://$SERVICE_HOST:8773/services/Cloud" \
-                ec2
+
+            EC2_SERVICE=$(get_or_create_service "ec2" \
+                "ec2" "EC2 Compatibility Layer")
+            get_or_create_endpoint $EC2_SERVICE \
+                "$REGION_NAME" \
+                "http://$SERVICE_HOST:8773/services/Cloud" \
+                "http://$SERVICE_HOST:8773/services/Admin" \
+                "http://$SERVICE_HOST:8773/services/Cloud"
         fi
     fi
 
     # S3
     if is_service_enabled n-obj swift3; then
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-            openstack service create \
-                --type s3 \
-                --description "S3" \
-                s3
-            openstack endpoint create \
-                --region RegionOne \
-                --publicurl "http://$SERVICE_HOST:$S3_SERVICE_PORT" \
-                --adminurl "http://$SERVICE_HOST:$S3_SERVICE_PORT" \
-                --internalurl "http://$SERVICE_HOST:$S3_SERVICE_PORT" \
-                s3
+
+            S3_SERVICE=$(get_or_create_service "s3" "s3" "S3")
+            get_or_create_endpoint $S3_SERVICE \
+                "$REGION_NAME" \
+                "http://$SERVICE_HOST:$S3_SERVICE_PORT" \
+                "http://$SERVICE_HOST:$S3_SERVICE_PORT" \
+                "http://$SERVICE_HOST:$S3_SERVICE_PORT"
         fi
     fi
 }
diff --git a/lib/nova_plugins/functions-libvirt b/lib/nova_plugins/functions-libvirt
index 18bdf89..6fb5c38 100644
--- a/lib/nova_plugins/functions-libvirt
+++ b/lib/nova_plugins/functions-libvirt
@@ -112,7 +112,15 @@
 
     # Enable server side traces for libvirtd
     if [[ "$DEBUG_LIBVIRT" = "True" ]] ; then
-        local log_filters="1:libvirt 1:qemu 1:conf 1:security 3:event 3:json 3:file 1:util"
+        if is_ubuntu; then
+            # Unexpectedly binary package builds in ubuntu get fully qualified
+            # source file paths, not relative paths. This screws with the matching
+            # of '1:libvirt' making everything turn on. So use libvirt.c for now.
+            # This will have to be re-visited when Ubuntu ships libvirt >= 1.2.3
+            local log_filters="1:libvirt.c 1:qemu 1:conf 1:security 3:object 3:event 3:json 3:file 1:util"
+        else
+            local log_filters="1:libvirt 1:qemu 1:conf 1:security 3:object 3:event 3:json 3:file 1:util"
+        fi
         local log_outputs="1:file:/var/log/libvirt/libvirtd.log"
         if ! grep -q "log_filters=\"$log_filters\"" /etc/libvirt/libvirtd.conf; then
             echo "log_filters=\"$log_filters\"" | sudo tee -a /etc/libvirt/libvirtd.conf
diff --git a/lib/oslo b/lib/oslo
index a0a1f8f..421fbce 100644
--- a/lib/oslo
+++ b/lib/oslo
@@ -23,6 +23,7 @@
 CLIFF_DIR=$DEST/cliff
 OSLOCFG_DIR=$DEST/oslo.config
 OSLODB_DIR=$DEST/oslo.db
+OSLOI18N_DIR=$DEST/oslo.i18n
 OSLOMSG_DIR=$DEST/oslo.messaging
 OSLORWRAP_DIR=$DEST/oslo.rootwrap
 OSLOVMWARE_DIR=$DEST/oslo.vmware
@@ -45,6 +46,9 @@
     git_clone $CLIFF_REPO $CLIFF_DIR $CLIFF_BRANCH
     setup_install $CLIFF_DIR
 
+    git_clone $OSLOI18N_REPO $OSLOI18N_DIR $OSLOI18N_BRANCH
+    setup_install $OSLOI18N_DIR
+
     git_clone $OSLOCFG_REPO $OSLOCFG_DIR $OSLOCFG_BRANCH
     setup_install $OSLOCFG_DIR
 
diff --git a/lib/sahara b/lib/sahara
index 934989b..0cc2fe9 100644
--- a/lib/sahara
+++ b/lib/sahara
@@ -60,29 +60,19 @@
     SERVICE_TENANT=$(openstack project list | awk "/ $SERVICE_TENANT_NAME / { print \$2 }")
     ADMIN_ROLE=$(openstack role list | awk "/ admin / { print \$2 }")
 
-    SAHARA_USER=$(openstack user create \
-        sahara \
-        --password "$SERVICE_PASSWORD" \
-        --project $SERVICE_TENANT \
-        --email sahara@example.com \
-        | grep " id " | get_field 2)
-    openstack role add \
-        $ADMIN_ROLE \
-        --project $SERVICE_TENANT \
-        --user $SAHARA_USER
+    SAHARA_USER=$(get_or_create_user "sahara" \
+        "$SERVICE_PASSWORD" $SERVICE_TENANT "sahara@example.com")
+    get_or_add_user_role $ADMIN_ROLE $SAHARA_USER $SERVICE_TENANT
 
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-        SAHARA_SERVICE=$(openstack service create \
-            sahara \
-            --type=data_processing \
-            --description="Sahara Data Processing" \
-            | grep " id " | get_field 2)
-        openstack endpoint create \
-            $SAHARA_SERVICE \
-            --region RegionOne \
-            --publicurl "$SAHARA_SERVICE_PROTOCOL://$SAHARA_SERVICE_HOST:$SAHARA_SERVICE_PORT/v1.1/\$(tenant_id)s" \
-            --adminurl "$SAHARA_SERVICE_PROTOCOL://$SAHARA_SERVICE_HOST:$SAHARA_SERVICE_PORT/v1.1/\$(tenant_id)s" \
-            --internalurl "$SAHARA_SERVICE_PROTOCOL://$SAHARA_SERVICE_HOST:$SAHARA_SERVICE_PORT/v1.1/\$(tenant_id)s"
+
+        SAHARA_SERVICE=$(get_or_create_service "sahara" \
+            "data_processing" "Sahara Data Processing")
+        get_or_create_endpoint $SAHARA_SERVICE \
+            "$REGION_NAME" \
+            "$SAHARA_SERVICE_PROTOCOL://$SAHARA_SERVICE_HOST:$SAHARA_SERVICE_PORT/v1.1/\$(tenant_id)s" \
+            "$SAHARA_SERVICE_PROTOCOL://$SAHARA_SERVICE_HOST:$SAHARA_SERVICE_PORT/v1.1/\$(tenant_id)s" \
+            "$SAHARA_SERVICE_PROTOCOL://$SAHARA_SERVICE_HOST:$SAHARA_SERVICE_PORT/v1.1/\$(tenant_id)s"
     fi
 }
 
diff --git a/lib/swift b/lib/swift
index c47b09f..b01dd95 100644
--- a/lib/swift
+++ b/lib/swift
@@ -118,6 +118,8 @@
 # Tell Tempest this project is present
 TEMPEST_SERVICES+=,swift
 
+# Toggle for deploying Keystone under HTTPD + mod_wsgi
+SWIFT_USE_MOD_WSGI=${SWIFT_USE_MOD_WSGI:-False}
 
 # Functions
 # ---------
@@ -139,7 +141,7 @@
         rm ${SWIFT_DISK_IMAGE}
     fi
     rm -rf ${SWIFT_DATA_DIR}/run/
-    if is_apache_enabled_service swift; then
+    if [ "$SWIFT_USE_MOD_WSGI" == "True" ]; then
         _cleanup_swift_apache_wsgi
     fi
 }
@@ -354,7 +356,12 @@
     if is_service_enabled swift3;then
         swift_pipeline+=" swift3 s3token "
     fi
-    swift_pipeline+=" authtoken keystoneauth tempauth "
+
+    if is_service_enabled key;then
+        swift_pipeline+=" authtoken keystoneauth"
+    fi
+    swift_pipeline+=" tempauth "
+
     sed -i "/^pipeline/ { s/tempauth/${swift_pipeline} ${SWIFT_EXTRAS_MIDDLEWARE}/ ;}" ${SWIFT_CONFIG_PROXY_SERVER}
     sed -i "/^pipeline/ { s/proxy-server/${SWIFT_EXTRAS_MIDDLEWARE_LAST} proxy-server/ ; }" ${SWIFT_CONFIG_PROXY_SERVER}
 
@@ -465,7 +472,7 @@
         sudo killall -HUP rsyslogd
     fi
 
-    if is_apache_enabled_service swift; then
+    if [ "$SWIFT_USE_MOD_WSGI" == "True" ]; then
         _config_swift_apache_wsgi
     fi
 }
@@ -542,50 +549,40 @@
     SERVICE_TENANT=$(openstack project list | awk "/ $SERVICE_TENANT_NAME / { print \$2 }")
     ADMIN_ROLE=$(openstack role list | awk "/ admin / { print \$2 }")
 
-    SWIFT_USER=$(openstack user create \
-        swift \
-        --password "$SERVICE_PASSWORD" \
-        --project $SERVICE_TENANT \
-        --email=swift@example.com \
-        | grep " id " | get_field 2)
-    openstack role add \
-        $ADMIN_ROLE \
-        --project $SERVICE_TENANT \
-        --user $SWIFT_USER
+    SWIFT_USER=$(get_or_create_user "swift" \
+        "$SERVICE_PASSWORD" $SERVICE_TENANT "swift@example.com")
+    get_or_add_user_role $ADMIN_ROLE $SWIFT_USER $SERVICE_TENANT
 
     if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-        SWIFT_SERVICE=$(openstack service create \
-            swift \
-            --type="object-store" \
-            --description="Swift Service" \
-            | grep " id " | get_field 2)
-        openstack endpoint create \
-            $SWIFT_SERVICE \
-            --region RegionOne \
-            --publicurl "http://$SERVICE_HOST:8080/v1/AUTH_\$(tenant_id)s" \
-            --adminurl "http://$SERVICE_HOST:8080" \
-            --internalurl "http://$SERVICE_HOST:8080/v1/AUTH_\$(tenant_id)s"
+
+        SWIFT_SERVICE=$(get_or_create_service "swift" \
+            "object-store" "Swift Service")
+        get_or_create_endpoint $SWIFT_SERVICE \
+            "$REGION_NAME" \
+            "http://$SERVICE_HOST:8080/v1/AUTH_\$(tenant_id)s" \
+            "http://$SERVICE_HOST:8080" \
+            "http://$SERVICE_HOST:8080/v1/AUTH_\$(tenant_id)s"
     fi
 
-    SWIFT_TENANT_TEST1=$(openstack project create swifttenanttest1 | grep " id " | get_field 2)
+    SWIFT_TENANT_TEST1=$(get_or_create_project swifttenanttest1)
     die_if_not_set $LINENO SWIFT_TENANT_TEST1 "Failure creating SWIFT_TENANT_TEST1"
-    SWIFT_USER_TEST1=$(openstack user create swiftusertest1 --password=$SWIFTUSERTEST1_PASSWORD \
-        --project "$SWIFT_TENANT_TEST1" --email=test@example.com | grep " id " | get_field 2)
+    SWIFT_USER_TEST1=$(get_or_create_user swiftusertest1 $SWIFTUSERTEST1_PASSWORD \
+        "$SWIFT_TENANT_TEST1" "test@example.com")
     die_if_not_set $LINENO SWIFT_USER_TEST1 "Failure creating SWIFT_USER_TEST1"
-    openstack role add --user $SWIFT_USER_TEST1 --project $SWIFT_TENANT_TEST1 $ADMIN_ROLE
+    get_or_add_user_role $ADMIN_ROLE $SWIFT_USER_TEST1 $SWIFT_TENANT_TEST1
 
-    SWIFT_USER_TEST3=$(openstack user create swiftusertest3 --password=$SWIFTUSERTEST3_PASSWORD \
-        --project "$SWIFT_TENANT_TEST1" --email=test3@example.com | grep " id " | get_field 2)
+    SWIFT_USER_TEST3=$(get_or_create_user swiftusertest3 $SWIFTUSERTEST3_PASSWORD \
+        "$SWIFT_TENANT_TEST1" "test3@example.com")
     die_if_not_set $LINENO SWIFT_USER_TEST3 "Failure creating SWIFT_USER_TEST3"
-    openstack role add --user $SWIFT_USER_TEST3 --project $SWIFT_TENANT_TEST1 $ANOTHER_ROLE
+    get_or_add_user_role $ANOTHER_ROLE $SWIFT_USER_TEST3 $SWIFT_TENANT_TEST1
 
-    SWIFT_TENANT_TEST2=$(openstack project create swifttenanttest2 | grep " id " | get_field 2)
+    SWIFT_TENANT_TEST2=$(get_or_create_project swifttenanttest2)
     die_if_not_set $LINENO SWIFT_TENANT_TEST2 "Failure creating SWIFT_TENANT_TEST2"
 
-    SWIFT_USER_TEST2=$(openstack user create swiftusertest2 --password=$SWIFTUSERTEST2_PASSWORD \
-        --project "$SWIFT_TENANT_TEST2" --email=test2@example.com | grep " id " | get_field 2)
+    SWIFT_USER_TEST2=$(get_or_create_user swiftusertest2 $SWIFTUSERTEST2_PASSWORD \
+        "$SWIFT_TENANT_TEST2" "test2@example.com")
     die_if_not_set $LINENO SWIFT_USER_TEST2 "Failure creating SWIFT_USER_TEST2"
-    openstack role add --user $SWIFT_USER_TEST2 --project $SWIFT_TENANT_TEST2 $ADMIN_ROLE
+    get_or_add_user_role $ADMIN_ROLE $SWIFT_USER_TEST2 $SWIFT_TENANT_TEST2
 }
 
 # init_swift() - Initialize rings
@@ -626,7 +623,7 @@
 function install_swift {
     git_clone $SWIFT_REPO $SWIFT_DIR $SWIFT_BRANCH
     setup_develop $SWIFT_DIR
-    if is_apache_enabled_service swift; then
+    if [ "$SWIFT_USE_MOD_WSGI" == "True" ]; then
         install_apache_wsgi
     fi
 }
@@ -650,7 +647,7 @@
         start_service rsyncd
     fi
 
-    if is_apache_enabled_service swift; then
+    if [ "$SWIFT_USE_MOD_WSGI" == "True" ]; then
         restart_apache_server
         swift-init --run-dir=${SWIFT_DATA_DIR}/run rest start
         screen_it s-proxy "cd $SWIFT_DIR && sudo tail -f /var/log/$APACHE_NAME/proxy-server"
@@ -687,7 +684,7 @@
 # stop_swift() - Stop running processes (non-screen)
 function stop_swift {
 
-    if is_apache_enabled_service swift; then
+    if [ "$SWIFT_USE_MOD_WSGI" == "True" ]; then
         swift-init --run-dir=${SWIFT_DATA_DIR}/run rest stop && return 0
     fi
 
diff --git a/lib/tempest b/lib/tempest
index 1e98bec..59c5bbc 100644
--- a/lib/tempest
+++ b/lib/tempest
@@ -397,16 +397,9 @@
     if is_service_enabled tempest; then
         # Tempest has some tests that validate various authorization checks
         # between two regular users in separate tenants
-        openstack project create \
-            alt_demo
-        openstack user create \
-            --project alt_demo \
-            --password "$ADMIN_PASSWORD" \
-            alt_demo
-        openstack role add \
-            --project alt_demo \
-            --user alt_demo \
-            Member
+        get_or_create_project alt_demo
+        get_or_create_user alt_demo "$ADMIN_PASSWORD" alt_demo "alt_demo@example.com"
+        get_or_add_user_role Member alt_demo alt_demo
     fi
 }
 
diff --git a/lib/trove b/lib/trove
index 98ab56d..2552745 100644
--- a/lib/trove
+++ b/lib/trove
@@ -81,28 +81,20 @@
     SERVICE_ROLE=$(openstack role list | awk "/ admin / { print \$2 }")
 
     if [[ "$ENABLED_SERVICES" =~ "trove" ]]; then
-        TROVE_USER=$(openstack user create \
-            trove \
-            --password "$SERVICE_PASSWORD" \
-            --project $SERVICE_TENANT \
-            --email trove@example.com \
-            | grep " id " | get_field 2)
-        openstack role add \
-            $SERVICE_ROLE \
-            --project $SERVICE_TENANT \
-            --user $TROVE_USER
+
+        TROVE_USER=$(get_or_create_user "trove" \
+            "$SERVICE_PASSWORD" $SERVICE_TENANT "trove@example.com")
+        get_or_add_user_role $SERVICE_ROLE $TROVE_USER $SERVICE_TENANT
+
         if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-            TROVE_SERVICE=$(openstack service create \
-                trove \
-                --type=database \
-                --description="Trove Service" \
-                | grep " id " | get_field 2)
-            openstack endpoint create \
-                $TROVE_SERVICE \
-                --region RegionOne \
-                --publicurl "http://$SERVICE_HOST:8779/v1.0/\$(tenant_id)s" \
-                --adminurl "http://$SERVICE_HOST:8779/v1.0/\$(tenant_id)s" \
-                --internalurl "http://$SERVICE_HOST:8779/v1.0/\$(tenant_id)s"
+
+            TROVE_SERVICE=$(get_or_create_service "trove" \
+                "database" "Trove Service")
+            get_or_create_endpoint $TROVE_SERVICE \
+                "$REGION_NAME" \
+                "http://$SERVICE_HOST:8779/v1.0/\$(tenant_id)s" \
+                "http://$SERVICE_HOST:8779/v1.0/\$(tenant_id)s" \
+                "http://$SERVICE_HOST:8779/v1.0/\$(tenant_id)s"
         fi
     fi
 }
diff --git a/openrc b/openrc
index fc066ad..aec8a2a 100644
--- a/openrc
+++ b/openrc
@@ -53,12 +53,16 @@
 # easier with this off.
 export OS_NO_CACHE=${OS_NO_CACHE:-1}
 
+# Region
+export OS_REGION_NAME=${REGION_NAME:-RegionOne}
+
 # Set api HOST_IP endpoint.  SERVICE_HOST may also be used to specify the endpoint,
 # which is convenient for some localrc configurations.
 HOST_IP=${HOST_IP:-127.0.0.1}
 SERVICE_HOST=${SERVICE_HOST:-$HOST_IP}
 SERVICE_PROTOCOL=${SERVICE_PROTOCOL:-http}
 KEYSTONE_AUTH_PROTOCOL=${KEYSTONE_AUTH_PROTOCOL:-$SERVICE_PROTOCOL}
+KEYSTONE_AUTH_HOST=${KEYSTONE_AUTH_HOST:-$SERVICE_HOST}
 
 # Some exercises call glance directly.  On a single-node installation, Glance
 # should be listening on HOST_IP.  If its running elsewhere, it can be set here
@@ -72,7 +76,7 @@
 # the user/tenant has access to - including nova, glance, keystone, swift, ...
 # We currently recommend using the 2.0 *identity api*.
 #
-export OS_AUTH_URL=$KEYSTONE_AUTH_PROTOCOL://$SERVICE_HOST:5000/v${OS_IDENTITY_API_VERSION}
+export OS_AUTH_URL=$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:5000/v${OS_IDENTITY_API_VERSION}
 
 # Set the pointer to our CA certificate chain.  Harmless if TLS is not used.
 export OS_CACERT=${OS_CACERT:-$INT_CA_DIR/ca-chain.pem}
diff --git a/stack.sh b/stack.sh
index e58436d..f3d8d44 100755
--- a/stack.sh
+++ b/stack.sh
@@ -729,8 +729,10 @@
 setup_develop $OPENSTACKCLIENT_DIR
 
 if is_service_enabled key; then
-    install_keystone
-    configure_keystone
+    if [ "$KEYSTONE_AUTH_HOST" == "$SERVICE_HOST" ]; then
+        install_keystone
+        configure_keystone
+    fi
 fi
 
 if is_service_enabled s-proxy; then
@@ -929,8 +931,11 @@
 
 if is_service_enabled key; then
     echo_summary "Starting Keystone"
-    init_keystone
-    start_keystone
+
+    if [ "$KEYSTONE_AUTH_HOST" == "$SERVICE_HOST" ]; then
+        init_keystone
+        start_keystone
+    fi
 
     # Set up a temporary admin URI for Keystone
     SERVICE_ENDPOINT=$KEYSTONE_AUTH_URI/v2.0
@@ -971,6 +976,7 @@
     export OS_TENANT_NAME=admin
     export OS_USERNAME=admin
     export OS_PASSWORD=$ADMIN_PASSWORD
+    export OS_REGION_NAME=$REGION_NAME
 fi
 
 
diff --git a/stackrc b/stackrc
index 313fdd2..6af3db7 100644
--- a/stackrc
+++ b/stackrc
@@ -19,6 +19,9 @@
     STACK_USER=$(whoami)
 fi
 
+# Specify region name Region
+REGION_NAME=${REGION_NAME:-RegionOne}
+
 # Specify which services to launch.  These generally correspond to
 # screen tabs. To change the default list, use the ``enable_service`` and
 # ``disable_service`` functions in ``local.conf``.
@@ -49,6 +52,12 @@
     ENABLED_SERVICES+=,rabbit,tempest,mysql
 fi
 
+# Global toggle for enabling services under mod_wsgi. If this is set to
+# ``True`` all services that use HTTPD + mod_wsgi as the preferred method of
+# deployment, will be deployed under Apache. If this is set to ``False`` all
+# services will rely on the local toggle variable (e.g. ``KEYSTONE_USE_MOD_WSGI``)
+ENABLE_HTTPD_MOD_WSGI_SERVICES=True
+
 # Tell Tempest which services are available.  The default is set here as
 # Tempest falls late in the configuration sequence.  This differs from
 # ``ENABLED_SERVICES`` in that the project names are used here rather than
@@ -183,6 +192,10 @@
 OSLODB_REPO=${OSLODB_REPO:-${GIT_BASE}/openstack/oslo.db.git}
 OSLODB_BRANCH=${OSLODB_BRANCH:-master}
 
+# oslo.i18n
+OSLOI18N_REPO=${OSLOI18N_REPO:-${GIT_BASE}/openstack/oslo.i18n.git}
+OSLOI18N_BRANCH=${OSLOI18N_BRANCH:-master}
+
 # oslo.messaging
 OSLOMSG_REPO=${OSLOMSG_REPO:-${GIT_BASE}/openstack/oslo.messaging.git}
 OSLOMSG_BRANCH=${OSLOMSG_BRANCH:-master}
@@ -360,7 +373,7 @@
 if [[ "$ENABLED_SERVICES" =~ 'h-api' ]]; then
     case "$VIRT_DRIVER" in
         libvirt|baremetal|ironic)
-            HEAT_CFN_IMAGE_URL=${HEAT_CFN_IMAGE_URL:-"https://dl.fedoraproject.org/pub/fedora/linux/releases/20/Images/x86_64/Fedora-x86_64-20-20131211.1-sda.qcow2"}
+            HEAT_CFN_IMAGE_URL=${HEAT_CFN_IMAGE_URL:-"http://dl.fedoraproject.org/pub/alt/openstack/20/x86_64/Fedora-x86_64-20-20140618-sda.qcow2"}
             IMAGE_URLS+=",$HEAT_CFN_IMAGE_URL"
             ;;
         *)
@@ -385,7 +398,10 @@
 PRECACHE_IMAGES=$(trueorfalse False $PRECACHE_IMAGES)
 if [[ "$PRECACHE_IMAGES" == "True" ]]; then
     # staging in update for nodepool
-    IMAGE_URLS+=",http://dl.fedoraproject.org/pub/alt/openstack/20/x86_64/Fedora-x86_64-20-20140618-sda.qcow2"
+    IMAGE_URL="http://dl.fedoraproject.org/pub/alt/openstack/20/x86_64/Fedora-x86_64-20-20140618-sda.qcow2"
+    if ! [[ "$IMAGE_URLS"  =~ "$IMAGE_URL" ]]; then
+        IMAGE_URLS+=",$IMAGE_URL"
+    fi
 fi
 
 # 10Gb default volume backing file size