Merge "use pip_install to install packages for tempest"
diff --git a/files/keystone_data.sh b/files/keystone_data.sh
index 20749bc..c8e68dd 100755
--- a/files/keystone_data.sh
+++ b/files/keystone_data.sh
@@ -4,7 +4,6 @@
 #
 # Tenant               User       Roles
 # ------------------------------------------------------------------
-# admin                admin      admin
 # service              glance     admin
 # service              nova       admin, [ResellerAdmin (swift only)]
 # service              quantum    admin        # if enabled
@@ -12,9 +11,6 @@
 # service              cinder     admin        # if enabled
 # service              heat       admin        # if enabled
 # service              ceilometer admin        # if enabled
-# demo                 admin      admin
-# demo                 demo       Member, anotherrole
-# invisible_to_admin   demo       Member
 # Tempest Only:
 # alt_demo             alt_demo  Member
 #
@@ -40,53 +36,14 @@
     echo `"$@" | awk '/ id / { print $4 }'`
 }
 
-
-# Tenants
-# -------
-
-ADMIN_TENANT=$(get_id keystone tenant-create --name=admin)
-SERVICE_TENANT=$(get_id keystone tenant-create --name=$SERVICE_TENANT_NAME)
-DEMO_TENANT=$(get_id keystone tenant-create --name=demo)
-INVIS_TENANT=$(get_id keystone tenant-create --name=invisible_to_admin)
-
-
-# Users
-# -----
-
-ADMIN_USER=$(get_id keystone user-create --name=admin \
-                                         --pass="$ADMIN_PASSWORD" \
-                                         --email=admin@example.com)
-DEMO_USER=$(get_id keystone user-create --name=demo \
-                                        --pass="$ADMIN_PASSWORD" \
-                                        --email=demo@example.com)
+# Lookups
+SERVICE_TENANT=$(keystone tenant-list | awk "/ $SERVICE_TENANT_NAME / { print \$2 }")
+ADMIN_ROLE=$(keystone role-list | awk "/ admin / { print \$2 }")
 
 
 # Roles
 # -----
 
-ADMIN_ROLE=$(get_id keystone role-create --name=admin)
-KEYSTONEADMIN_ROLE=$(get_id keystone role-create --name=KeystoneAdmin)
-KEYSTONESERVICE_ROLE=$(get_id keystone role-create --name=KeystoneServiceAdmin)
-# 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=$(get_id keystone role-create --name=anotherrole)
-
-
-# Add Roles to Users in Tenants
-keystone user-role-add --user_id $ADMIN_USER --role_id $ADMIN_ROLE --tenant_id $ADMIN_TENANT
-keystone user-role-add --user_id $ADMIN_USER --role_id $ADMIN_ROLE --tenant_id $DEMO_TENANT
-keystone user-role-add --user_id $DEMO_USER --role_id $ANOTHER_ROLE --tenant_id $DEMO_TENANT
-
-# TODO(termie): these two might be dubious
-keystone user-role-add --user_id $ADMIN_USER --role_id $KEYSTONEADMIN_ROLE --tenant_id $ADMIN_TENANT
-keystone user-role-add --user_id $ADMIN_USER --role_id $KEYSTONESERVICE_ROLE --tenant_id $ADMIN_TENANT
-
-
-# The Member role is used by Horizon and Swift so we need to keep it:
-MEMBER_ROLE=$(get_id keystone role-create --name=Member)
-keystone user-role-add --user_id $DEMO_USER --role_id $MEMBER_ROLE --tenant_id $DEMO_TENANT
-keystone user-role-add --user_id $DEMO_USER --role_id $MEMBER_ROLE --tenant_id $INVIS_TENANT
-
 # 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
@@ -96,20 +53,6 @@
 # Services
 # --------
 
-# Keystone
-if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
-    KEYSTONE_SERVICE=$(get_id keystone service-create \
-        --name=keystone \
-        --type=identity \
-        --description="Keystone Identity Service")
-    keystone endpoint-create \
-        --region RegionOne \
-        --service_id $KEYSTONE_SERVICE \
-        --publicurl "http://$SERVICE_HOST:\$(public_port)s/v2.0" \
-        --adminurl "http://$SERVICE_HOST:\$(admin_port)s/v2.0" \
-        --internalurl "http://$SERVICE_HOST:\$(public_port)s/v2.0"
-fi
-
 # Nova
 if [[ "$ENABLED_SERVICES" =~ "n-api" ]]; then
     NOVA_USER=$(get_id keystone user-create \
diff --git a/files/rpms-suse/ceilometer-collector b/files/rpms-suse/ceilometer-collector
new file mode 100644
index 0000000..c76454f
--- /dev/null
+++ b/files/rpms-suse/ceilometer-collector
@@ -0,0 +1,4 @@
+# Not available in openSUSE main repositories, but can be fetched from OBS
+# (devel:languages:python and server:database projects)
+mongodb
+python-pymongo
diff --git a/files/rpms-suse/cinder b/files/rpms-suse/cinder
new file mode 100644
index 0000000..e5b4727
--- /dev/null
+++ b/files/rpms-suse/cinder
@@ -0,0 +1,2 @@
+lvm2
+tgt
diff --git a/files/rpms-suse/general b/files/rpms-suse/general
new file mode 100644
index 0000000..8ed74ec
--- /dev/null
+++ b/files/rpms-suse/general
@@ -0,0 +1,23 @@
+bridge-utils
+curl
+euca2ools
+git-core
+iputils
+openssh
+psmisc
+python-cmd2 # dist:opensuse-12.3
+python-netaddr
+python-pep8
+python-pip
+python-pylint
+python-unittest2
+python-virtualenv
+screen
+tar
+tcpdump
+unzip
+vim-enhanced
+wget
+
+findutils-locate # useful when debugging
+lsof # useful when debugging
diff --git a/files/rpms-suse/glance b/files/rpms-suse/glance
new file mode 100644
index 0000000..dd68ac0
--- /dev/null
+++ b/files/rpms-suse/glance
@@ -0,0 +1,12 @@
+gcc
+libxml2-devel
+python-PasteDeploy
+python-Routes
+python-SQLAlchemy
+python-argparse
+python-devel
+python-eventlet
+python-greenlet
+python-iso8601
+python-wsgiref
+python-xattr
diff --git a/files/rpms-suse/horizon b/files/rpms-suse/horizon
new file mode 100644
index 0000000..7e46ffe
--- /dev/null
+++ b/files/rpms-suse/horizon
@@ -0,0 +1,23 @@
+apache2  # NOPRIME
+apache2-mod_wsgi  # NOPRIME
+nodejs
+python-CherryPy # why? (coming from apts)
+python-Paste
+python-PasteDeploy
+python-Routes
+python-Sphinx
+python-SQLAlchemy
+python-WebOb
+python-anyjson
+python-beautifulsoup
+python-coverage
+python-dateutil
+python-eventlet
+python-kombu
+python-mox
+python-netaddr
+python-nose
+python-pep8
+python-pylint
+python-sqlalchemy-migrate
+python-xattr
diff --git a/files/rpms-suse/keystone b/files/rpms-suse/keystone
new file mode 100644
index 0000000..b3c876a
--- /dev/null
+++ b/files/rpms-suse/keystone
@@ -0,0 +1,17 @@
+cyrus-sasl-devel
+openldap2-devel
+python-Paste
+python-PasteDeploy
+python-PasteScript
+python-Routes
+python-SQLAlchemy
+python-WebOb
+python-devel
+python-distribute
+python-setuptools # instead of python-distribute; dist:sle11sp2
+python-greenlet
+python-lxml
+python-mysql
+python-py-bcrypt
+python-pysqlite
+sqlite3
diff --git a/files/rpms-suse/n-api b/files/rpms-suse/n-api
new file mode 100644
index 0000000..ad943ff
--- /dev/null
+++ b/files/rpms-suse/n-api
@@ -0,0 +1,2 @@
+gcc  # temporary because this pulls in glance to get the client without running the glance prereqs
+python-dateutil
diff --git a/files/rpms-suse/n-cpu b/files/rpms-suse/n-cpu
new file mode 100644
index 0000000..27d3254
--- /dev/null
+++ b/files/rpms-suse/n-cpu
@@ -0,0 +1,4 @@
+# Stuff for diablo volumes
+genisoimage
+lvm2
+open-iscsi
diff --git a/files/rpms-suse/n-novnc b/files/rpms-suse/n-novnc
new file mode 100644
index 0000000..c8722b9
--- /dev/null
+++ b/files/rpms-suse/n-novnc
@@ -0,0 +1 @@
+python-numpy
diff --git a/files/rpms-suse/n-vol b/files/rpms-suse/n-vol
new file mode 100644
index 0000000..e5b4727
--- /dev/null
+++ b/files/rpms-suse/n-vol
@@ -0,0 +1,2 @@
+lvm2
+tgt
diff --git a/files/rpms-suse/nova b/files/rpms-suse/nova
new file mode 100644
index 0000000..0c03678
--- /dev/null
+++ b/files/rpms-suse/nova
@@ -0,0 +1,48 @@
+curl
+# Note: we need to package dhcp_release in dnsmasq!
+dnsmasq
+ebtables
+gawk
+iptables
+iputils
+kpartx
+kvm
+libvirt # NOPRIME
+libvirt-python
+libxml2-python
+mysql-community-server # NOPRIME
+parted
+python-M2Crypto
+python-m2crypto # dist:sle11sp2
+python-Paste
+python-PasteDeploy
+python-Routes
+python-SQLAlchemy
+python-Tempita
+python-boto
+python-carrot
+python-cheetah
+python-eventlet
+python-feedparser
+python-greenlet
+python-iso8601
+python-kombu
+python-lockfile
+python-lxml # needed for glance which is needed for nova --- this shouldn't be here
+python-mox
+python-mysql
+python-netaddr
+python-paramiko
+python-python-gflags
+python-sqlalchemy-migrate
+python-suds
+python-xattr # needed for glance which is needed for nova --- this shouldn't be here
+rabbitmq-server # NOPRIME
+socat
+sqlite3
+sudo
+vlan
+
+# FIXME: qpid is not part of openSUSE, those names are tentative
+python-qpid # NOPRIME
+qpidd # NOPRIME
diff --git a/files/rpms-suse/postgresql b/files/rpms-suse/postgresql
new file mode 100644
index 0000000..bf19d39
--- /dev/null
+++ b/files/rpms-suse/postgresql
@@ -0,0 +1 @@
+python-psycopg2
diff --git a/files/rpms-suse/quantum b/files/rpms-suse/quantum
new file mode 100644
index 0000000..068c15c
--- /dev/null
+++ b/files/rpms-suse/quantum
@@ -0,0 +1,27 @@
+# Note: we need to package dhcp_release in dnsmasq!
+dnsmasq
+ebtables
+iptables
+iputils
+mysql-community-server # NOPRIME
+python-boto
+python-eventlet
+python-greenlet
+python-iso8601
+python-kombu
+python-mysql
+python-netaddr
+python-Paste
+python-PasteDeploy
+python-pyudev
+python-Routes
+python-SQLAlchemy
+python-suds
+rabbitmq-server # NOPRIME
+sqlite3
+sudo
+vlan
+
+# FIXME: qpid is not part of openSUSE, those names are tentative
+python-qpid # NOPRIME
+qpidd # NOPRIME
diff --git a/files/rpms-suse/ryu b/files/rpms-suse/ryu
new file mode 100644
index 0000000..763fd24
--- /dev/null
+++ b/files/rpms-suse/ryu
@@ -0,0 +1,5 @@
+python-distribute
+python-setuptools # instead of python-distribute; dist:sle11sp2
+python-Sphinx
+python-gevent
+python-python-gflags
diff --git a/files/rpms-suse/swift b/files/rpms-suse/swift
new file mode 100644
index 0000000..db379bb
--- /dev/null
+++ b/files/rpms-suse/swift
@@ -0,0 +1,19 @@
+curl
+gcc
+memcached
+python-PasteDeploy
+python-WebOb
+python-configobj
+python-coverage
+python-devel
+python-distribute
+python-setuptools # instead of python-distribute; dist:sle11sp2
+python-eventlet
+python-greenlet
+python-netifaces
+python-nose
+python-simplejson
+python-xattr
+sqlite3
+xfsprogs
+xinetd
diff --git a/functions b/functions
index 794e474..0911557 100644
--- a/functions
+++ b/functions
@@ -341,6 +341,19 @@
 }
 
 
+# Determine if current distribution is an Ubuntu-based distribution.
+# It will also detect non-Ubuntu but Debian-based distros; this is not an issue
+# since Debian and Ubuntu should be compatible.
+# is_ubuntu
+function is_ubuntu {
+    if [[ -z "$os_PACKAGE" ]]; then
+        GetOSVersion
+    fi
+
+    [ "$os_PACKAGE" = "deb" ]
+}
+
+
 # Determine if current distribution is a SUSE-based distribution
 # (openSUSE, SLE).
 # is_suse
@@ -580,11 +593,7 @@
 # Distro-agnostic package installer
 # install_package package [package ...]
 function install_package() {
-    if [[ -z "$os_PACKAGE" ]]; then
-        GetOSVersion
-    fi
-
-    if [[ "$os_PACKAGE" = "deb" ]]; then
+    if is_ubuntu; then
         [[ "$NO_UPDATE_REPOS" = "True" ]] || apt_get update
         NO_UPDATE_REPOS=True
 
@@ -609,6 +618,7 @@
     if [[ -z "$os_PACKAGE" ]]; then
         GetOSVersion
     fi
+
     if [[ "$os_PACKAGE" = "deb" ]]; then
         dpkg -l "$@" > /dev/null
         return $?
@@ -661,10 +671,7 @@
 # Service wrapper to restart services
 # restart_service service-name
 function restart_service() {
-    if [[ -z "$os_PACKAGE" ]]; then
-        GetOSVersion
-    fi
-    if [[ "$os_PACKAGE" = "deb" ]]; then
+    if is_ubuntu; then
         sudo /usr/sbin/service $1 restart
     else
         sudo /sbin/service $1 restart
@@ -746,10 +753,7 @@
 # Service wrapper to start services
 # start_service service-name
 function start_service() {
-    if [[ -z "$os_PACKAGE" ]]; then
-        GetOSVersion
-    fi
-    if [[ "$os_PACKAGE" = "deb" ]]; then
+    if is_ubuntu; then
         sudo /usr/sbin/service $1 start
     else
         sudo /sbin/service $1 start
@@ -760,10 +764,7 @@
 # Service wrapper to stop services
 # stop_service service-name
 function stop_service() {
-    if [[ -z "$os_PACKAGE" ]]; then
-        GetOSVersion
-    fi
-    if [[ "$os_PACKAGE" = "deb" ]]; then
+    if is_ubuntu; then
         sudo /usr/sbin/service $1 stop
     else
         sudo /sbin/service $1 stop
@@ -1031,11 +1032,7 @@
 function get_rootwrap_location() {
     local module=$1
 
-    if [[ -z "$os_PACKAGE" ]]; then
-        GetOSVersion
-    fi
-
-    if [[ "$os_PACKAGE" = "deb" ]] || is_suse; then
+    if is_ubuntu || is_suse; then
         echo "/usr/local/bin/$module-rootwrap"
     else
         echo "/usr/bin/$module-rootwrap"
@@ -1045,11 +1042,7 @@
 # Get the path to the pip command.
 # get_pip_command
 function get_pip_command() {
-    if [[ -z "$os_PACKAGE" ]]; then
-        GetOSVersion
-    fi
-
-    if [[ "$os_PACKAGE" = "deb" ]] || is_suse; then
+    if is_ubuntu || is_suse; then
         echo "/usr/bin/pip"
     else
         echo "/usr/bin/pip-python"
diff --git a/lib/cinder b/lib/cinder
index 1aa34cd..ce160bf 100644
--- a/lib/cinder
+++ b/lib/cinder
@@ -237,7 +237,7 @@
 # start_cinder() - Start running processes, including screen
 function start_cinder() {
     if is_service_enabled c-vol; then
-        if [[ "$os_PACKAGE" = "deb" ]]; then
+        if is_ubuntu; then
             _configure_tgt_for_config_d
             if [[ ! -f /etc/tgt/conf.d/cinder.conf ]]; then
                echo "include $CINDER_STATE_PATH/volumes/*" | sudo tee /etc/tgt/conf.d/cinder.conf
diff --git a/lib/databases/mysql b/lib/databases/mysql
index fc6a3b7..60ea143 100644
--- a/lib/databases/mysql
+++ b/lib/databases/mysql
@@ -20,7 +20,7 @@
 function configure_database_mysql {
     echo_summary "Configuring and starting MySQL"
 
-    if [[ "$os_PACKAGE" = "deb" ]]; then
+    if is_ubuntu; then
         MY_CONF=/etc/mysql/my.cnf
         MYSQL=mysql
     else
@@ -61,7 +61,7 @@
 }
 
 function install_database_mysql {
-    if [[ "$os_PACKAGE" = "deb" ]]; then
+    if is_ubuntu; then
         # Seed configuration with mysql password so that apt-get install doesn't
         # prompt us for a password upon install.
         cat <<MYSQL_PRESEED | sudo debconf-set-selections
@@ -84,7 +84,11 @@
         chmod 0600 $HOME/.my.cnf
     fi
     # Install mysql-server
-    install_package mysql-server
+    if is_suse; then
+        install_package mysql-community-server
+    else
+        install_package mysql-server
+    fi
 }
 
 function database_connection_url_mysql {
diff --git a/lib/glance b/lib/glance
index 60026d5..b02a4b6 100644
--- a/lib/glance
+++ b/lib/glance
@@ -70,13 +70,6 @@
     setup_develop $GLANCECLIENT_DIR
 }
 
-# durable_glance_queues() - Determine if RabbitMQ queues are durable or not
-function durable_glance_queues() {
-    test `rabbitmqctl list_queues name durable | grep true | wc -l` -gt 0 && return 0
-    test `rabbitmqctl list_exchanges name durable | grep true | wc -l` -gt 0 && return 0
-    return 1
-}
-
 # configure_glance() - Set config files, create data dirs, etc
 function configure_glance() {
     setup_develop $GLANCE_DIR
@@ -127,12 +120,6 @@
         iniset $GLANCE_API_CONF DEFAULT notifier_strategy rabbit
         iniset $GLANCE_API_CONF DEFAULT rabbit_host $RABBIT_HOST
         iniset $GLANCE_API_CONF DEFAULT rabbit_password $RABBIT_PASSWORD
-        if [[ durable_glance_queues -eq 0 ]]; then
-            # This gets around https://bugs.launchpad.net/glance/+bug/1074132
-            # that results in a g-api server becoming unresponsive during
-            # startup...
-            iniset $GLANCE_API_CONF DEFAULT rabbit_durable_queues True
-        fi
     fi
     if [[ "$KEYSTONE_TOKEN_FORMAT" == "PKI" ]]; then
         iniset $GLANCE_API_CONF keystone_authtoken signing_dir $GLANCE_AUTH_CACHE_DIR/api
diff --git a/lib/horizon b/lib/horizon
index 6173042..7321cbc 100644
--- a/lib/horizon
+++ b/lib/horizon
@@ -29,10 +29,10 @@
 # Set up default directories
 HORIZON_DIR=$DEST/horizon
 
-# Allow overriding the default Apache user and group, default both to
-# current user.
+# Allow overriding the default Apache user and group, default to
+# current user and his default group.
 APACHE_USER=${APACHE_USER:-$USER}
-APACHE_GROUP=${APACHE_GROUP:-$APACHE_USER}
+APACHE_GROUP=${APACHE_GROUP:-$(id -gn $APACHE_USER)}
 
 
 # Entry Points
@@ -71,7 +71,7 @@
     sudo mkdir -p $HORIZON_DIR/.blackhole
 
 
-    if [[ "$os_PACKAGE" = "deb" ]]; then
+    if is_ubuntu; then
         APACHE_NAME=apache2
         APACHE_CONF=sites-available/horizon
         # Clean up the old config name
@@ -110,16 +110,18 @@
 # install_horizon() - Collect source and prepare
 function install_horizon() {
     # Apache installation, because we mark it NOPRIME
-    if [[ "$os_PACKAGE" = "deb" ]]; then
+    if is_ubuntu; then
         # Install apache2, which is NOPRIME'd
         install_package apache2 libapache2-mod-wsgi
+    elif is_suse; then
+        install_package apache2 apache2-mod_wsgi
     else
         sudo rm -f /etc/httpd/conf.d/000-*
         install_package httpd mod_wsgi
     fi
 
     # NOTE(sdague) quantal changed the name of the node binary
-    if [[ "$os_PACKAGE" = "deb" ]]; then
+    if is_ubuntu; then
         if [[ ! -e "/usr/bin/node" ]]; then
             install_package nodejs-legacy
         fi
diff --git a/lib/keystone b/lib/keystone
index ae89056..f6a6d66 100644
--- a/lib/keystone
+++ b/lib/keystone
@@ -15,6 +15,7 @@
 # configure_keystone
 # init_keystone
 # start_keystone
+# create_keystone_accounts
 # stop_keystone
 # cleanup_keystone
 
@@ -45,7 +46,6 @@
 KEYSTONE_TOKEN_FORMAT=${KEYSTONE_TOKEN_FORMAT:-PKI}
 
 # Set Keystone interface configuration
-KEYSTONE_API_PORT=${KEYSTONE_API_PORT:-5000}
 KEYSTONE_AUTH_HOST=${KEYSTONE_AUTH_HOST:-$SERVICE_HOST}
 KEYSTONE_AUTH_PORT=${KEYSTONE_AUTH_PORT:-35357}
 KEYSTONE_AUTH_PROTOCOL=${KEYSTONE_AUTH_PROTOCOL:-http}
@@ -144,6 +144,100 @@
 
 }
 
+# create_keystone_accounts() - Sets up common required keystone accounts
+
+# Tenant               User       Roles
+# ------------------------------------------------------------------
+# service              --         --
+# --                   --         Member
+# admin                admin      admin
+# demo                 admin      admin
+# demo                 demo       Member, anotherrole
+# invisible_to_admin   demo       Member
+
+# Migrated from keystone_data.sh
+create_keystone_accounts() {
+
+    # admin
+    ADMIN_TENANT=$(keystone tenant-create \
+        --name admin \
+        | grep " id " | get_field 2)
+    ADMIN_USER=$(keystone user-create \
+        --name admin \
+        --pass "$ADMIN_PASSWORD" \
+        --email admin@example.com \
+        | grep " id " | get_field 2)
+    ADMIN_ROLE=$(keystone role-create \
+        --name admin \
+        | grep " id " | get_field 2)
+    keystone user-role-add \
+        --user_id $ADMIN_USER \
+        --role_id $ADMIN_ROLE \
+        --tenant_id $ADMIN_TENANT
+
+    # service
+    SERVICE_TENANT=$(keystone tenant-create \
+        --name $SERVICE_TENANT_NAME \
+        | grep " id " | get_field 2)
+
+    # The Member role is used by Horizon and Swift so we need to keep it:
+    MEMBER_ROLE=$(keystone role-create --name=Member | grep " id " | get_field 2)
+    # 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=$(keystone role-create --name=anotherrole | grep " id " | get_field 2)
+
+    # invisible tenant - admin can't see this one
+    INVIS_TENANT=$(keystone tenant-create --name=invisible_to_admin | grep " id " | get_field 2)
+
+    # demo
+    DEMO_TENANT=$(keystone tenant-create \
+        --name=demo \
+        | grep " id " | get_field 2)
+    DEMO_USER=$(keystone user-create \
+        --name demo \
+        --pass "$ADMIN_PASSWORD" \
+        --email demo@example.com \
+        | grep " id " | get_field 2)
+    keystone user-role-add --user_id $DEMO_USER --role_id $MEMBER_ROLE --tenant_id $DEMO_TENANT
+    keystone user-role-add --user_id $ADMIN_USER --role_id $ADMIN_ROLE --tenant_id $DEMO_TENANT
+    keystone user-role-add --user_id $DEMO_USER --role_id $ANOTHER_ROLE --tenant_id $DEMO_TENANT
+    keystone user-role-add --user_id $DEMO_USER --role_id $MEMBER_ROLE --tenant_id $INVIS_TENANT
+
+    # Keystone
+    if [[ "$KEYSTONE_CATALOG_BACKEND" = 'sql' ]]; then
+        KEYSTONE_SERVICE=$(keystone service-create \
+            --name keystone \
+            --type identity \
+            --description "Keystone Identity Service" \
+            | grep " id " | get_field 2)
+        keystone endpoint-create \
+            --region RegionOne \
+            --service_id $KEYSTONE_SERVICE \
+            --publicurl "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:\$(public_port)s/v2.0" \
+            --adminurl "$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:\$(admin_port)s/v2.0" \
+            --internalurl "$KEYSTONE_SERVICE_PROTOCOL://$KEYSTONE_SERVICE_HOST:\$(public_port)s/v2.0"
+    fi
+
+    # TODO(dtroyer): This is part of a series of changes...remove these when
+    #                complete if they are really unused
+#    KEYSTONEADMIN_ROLE=$(keystone role-create \
+#        --name KeystoneAdmin \
+#        | grep " id " | get_field 2)
+#    KEYSTONESERVICE_ROLE=$(keystone role-create \
+#        --name KeystoneServiceAdmin \
+#        | grep " id " | get_field 2)
+
+    # TODO(termie): these two might be dubious
+#    keystone user-role-add \
+#        --user_id $ADMIN_USER \
+#        --role_id $KEYSTONEADMIN_ROLE \
+#        --tenant_id $ADMIN_TENANT
+#    keystone user-role-add \
+#        --user_id $ADMIN_USER \
+#        --role_id $KEYSTONESERVICE_ROLE \
+#        --tenant_id $ADMIN_TENANT
+}
+
 # init_keystone() - Initialize databases, etc.
 function init_keystone() {
     # (Re)create keystone database
@@ -176,6 +270,11 @@
 function start_keystone() {
     # Start Keystone in a screen window
     screen_it key "cd $KEYSTONE_DIR && $KEYSTONE_DIR/bin/keystone-all --config-file $KEYSTONE_CONF $KEYSTONE_LOG_CONFIG -d --debug"
+    echo "Waiting for keystone to start..."
+    if ! timeout $SERVICE_TIMEOUT sh -c "while ! http_proxy= curl -s $KEYSTONE_AUTH_PROTOCOL://$SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v2.0/ >/dev/null; do sleep 1; done"; then
+      echo "keystone did not start"
+      exit 1
+    fi
 }
 
 # stop_keystone() - Stop running processes
diff --git a/lib/nova b/lib/nova
index 6445a07..970806d 100644
--- a/lib/nova
+++ b/lib/nova
@@ -202,7 +202,7 @@
         # splitting a system into many smaller parts.  LXC uses cgroups and chroot
         # to simulate multiple systems.
         if [[ "$LIBVIRT_TYPE" == "lxc" ]]; then
-            if [[ "$os_PACKAGE" = "deb" ]]; then
+            if is_ubuntu; then
                 if [[ ! "$DISTRO" > natty ]]; then
                     cgline="none /cgroup cgroup cpuacct,memory,devices,cpu,freezer,blkio 0 0"
                     sudo mkdir -p /cgroup
@@ -228,7 +228,7 @@
 EOF
         fi
 
-        if [[ "$os_PACKAGE" = "deb" ]]; then
+        if is_ubuntu; then
             LIBVIRT_DAEMON=libvirt-bin
         else
             # http://wiki.libvirt.org/page/SSHPolicyKitSetup
@@ -393,7 +393,7 @@
 # install_nova() - Collect source and prepare
 function install_nova() {
     if is_service_enabled n-cpu; then
-        if [[ "$os_PACKAGE" = "deb" ]]; then
+        if is_ubuntu; then
             LIBVIRT_PKG_NAME=libvirt-bin
         else
             LIBVIRT_PKG_NAME=libvirt
@@ -403,7 +403,7 @@
         # splitting a system into many smaller parts.  LXC uses cgroups and chroot
         # to simulate multiple systems.
         if [[ "$LIBVIRT_TYPE" == "lxc" ]]; then
-            if [[ "$os_PACKAGE" = "deb" ]]; then
+            if is_ubuntu; then
                 if [[ "$DISTRO" > natty ]]; then
                     install_package cgroup-lite
                 fi
diff --git a/lib/swift b/lib/swift
index 366c467..140e5e9 100644
--- a/lib/swift
+++ b/lib/swift
@@ -159,7 +159,7 @@
         s,%SWIFT_DATA_DIR%,$SWIFT_DATA_DIR,;
     " $FILES/swift/rsyncd.conf | sudo tee /etc/rsyncd.conf
     # rsyncd.conf just prepared for 4 nodes
-    if [[ "$os_PACKAGE" = "deb" ]]; then
+    if is_ubuntu; then
         sudo sed -i '/^RSYNC_ENABLE=false/ { s/false/true/ }' /etc/default/rsync
     else
         sudo sed -i '/disable *= *yes/ { s/yes/no/ }' /etc/xinetd.d/rsync
@@ -341,7 +341,7 @@
     # (re)start rsyslog
     restart_service rsyslog
     # Start rsync
-    if [[ "$os_PACKAGE" = "deb" ]]; then
+    if is_ubuntu; then
         sudo /etc/init.d/rsync restart || :
     else
         sudo systemctl start xinetd.service
diff --git a/stack.sh b/stack.sh
index 8e8c519..9428356 100755
--- a/stack.sh
+++ b/stack.sh
@@ -677,14 +677,20 @@
 
 # Install package requirements
 echo_summary "Installing package prerequisites"
-if [[ "$os_PACKAGE" = "deb" ]]; then
+if is_ubuntu; then
     install_package $(get_packages $FILES/apts)
+elif is_suse; then
+    install_package $(get_packages $FILES/rpms-suse)
 else
     install_package $(get_packages $FILES/rpms)
 fi
 
 if [[ $SYSLOG != "False" ]]; then
-    install_package rsyslog-relp
+    if is_suse; then
+        install_package rsyslog-module-relp
+    else
+        install_package rsyslog-relp
+    fi
 fi
 
 if is_service_enabled rabbit; then
@@ -702,7 +708,11 @@
     fi
 elif is_service_enabled zeromq; then
     if [[ "$os_PACKAGE" = "rpm" ]]; then
-        install_package zeromq python-zmq
+        if is_suse; then
+            install_package libzmq1 python-pyzmq
+        else
+            install_package zeromq python-zmq
+        fi
     else
         install_package libzmq1 python-zmq
     fi
@@ -716,7 +726,7 @@
     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 [[ "$os_PACKAGE" = "deb" ]]; then
+        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
@@ -953,15 +963,16 @@
     configure_keystone
     init_keystone
     start_keystone
-    echo "Waiting for keystone to start..."
-    if ! timeout $SERVICE_TIMEOUT sh -c "while ! http_proxy= curl -s $KEYSTONE_AUTH_PROTOCOL://$SERVICE_HOST:$KEYSTONE_API_PORT/v2.0/ >/dev/null; do sleep 1; done"; then
-      echo "keystone did not start"
-      exit 1
-    fi
 
-    # ``keystone_data.sh`` creates services, admin and demo users, and roles.
+    # Set up a temporary admin URI for Keystone
     SERVICE_ENDPOINT=$KEYSTONE_AUTH_PROTOCOL://$KEYSTONE_AUTH_HOST:$KEYSTONE_AUTH_PORT/v2.0
 
+    # Do the keystone-specific bits from keystone_data.sh
+    export OS_SERVICE_TOKEN=$SERVICE_TOKEN
+    export OS_SERVICE_ENDPOINT=$SERVICE_ENDPOINT
+    create_keystone_accounts
+
+    # ``keystone_data.sh`` creates services, admin and demo users, and roles.
     ADMIN_PASSWORD=$ADMIN_PASSWORD SERVICE_TENANT_NAME=$SERVICE_TENANT_NAME SERVICE_PASSWORD=$SERVICE_PASSWORD \
     SERVICE_TOKEN=$SERVICE_TOKEN SERVICE_ENDPOINT=$SERVICE_ENDPOINT SERVICE_HOST=$SERVICE_HOST \
     S3_SERVICE_PORT=$S3_SERVICE_PORT KEYSTONE_CATALOG_BACKEND=$KEYSTONE_CATALOG_BACKEND \
@@ -974,6 +985,7 @@
     export OS_TENANT_NAME=admin
     export OS_USERNAME=admin
     export OS_PASSWORD=$ADMIN_PASSWORD
+    unset OS_SERVICE_TOKEN OS_SERVICE_ENDPOINT
 fi
 
 
@@ -1750,7 +1762,7 @@
 
 # If Keystone is present you can point ``nova`` cli to this server
 if is_service_enabled key; then
-    echo "Keystone is serving at $KEYSTONE_AUTH_PROTOCOL://$SERVICE_HOST:$KEYSTONE_API_PORT/v2.0/"
+    echo "Keystone is serving at $KEYSTONE_AUTH_PROTOCOL://$SERVICE_HOST:$KEYSTONE_SERVICE_PORT/v2.0/"
     echo "Examples on using novaclient command line is in exercise.sh"
     echo "The default users are: admin and demo"
     echo "The password: $ADMIN_PASSWORD"
diff --git a/tools/info.sh b/tools/info.sh
index a872d59..583a994 100755
--- a/tools/info.sh
+++ b/tools/info.sh
@@ -88,7 +88,7 @@
 # - We are going to check packages only for the services needed.
 # - We are parsing the packages files and detecting metadatas.
 
-if [[ "$os_PACKAGE" = "deb" ]]; then
+if is_ubuntu; then
     PKG_DIR=$FILES/apts
 else
     PKG_DIR=$FILES/rpms
diff --git a/unstack.sh b/unstack.sh
index 20ba17b..81ce088 100755
--- a/unstack.sh
+++ b/unstack.sh
@@ -65,7 +65,7 @@
         # If tgt driver isn't running this won't work obviously
         # So check the response and restart if need be
         echo "tgtd seems to be in a bad state, restarting..."
-        if [[ "$os_PACKAGE" = "deb" ]]; then
+        if is_ubuntu; then
             restart_service tgt
         else
             restart_service tgtd
@@ -85,7 +85,7 @@
         sudo rm -rf $CINDER_STATE_PATH/volumes/*
     fi
 
-    if [[ "$os_PACKAGE" = "deb" ]]; then
+    if is_ubuntu; then
         stop_service tgt
     else
         stop_service tgtd