Merge "Fixes bug 960864- Testcases for the action list Volumes and list Volumes with Detail"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index b63b077..be05015 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -1,36 +1,93 @@
 [identity]
-use_ssl=False
-host=127.0.0.1
-port=5000
-api_version=v2.0
-path=tokens
-nonadmin_user1=user1
-nonadmin_user1_password=password
-nonadmin_user1_tenant_name=user1-project
-nonadmin_user2=user2
-nonadmin_user2_password=password
-nonadmin_user2_tenant_name=user2-project
-strategy=keystone
+# This section contains configuration options that a variety of Tempest
+# test clients use when authenticating with different user/tenant
+# combinations
+
+# Set to True if your test environment's Keystone authentication service should
+# be accessed over HTTPS
+use_ssl = False
+# This is the main host address of the authentication service API
+host = 127.0.0.1
+# Port that the authentication service API is running on
+port = 5000
+# Version of the authentication service API (a string)
+api_version = v2.0
+# Path to the authentication service tokens resource (do not modify unless you
+# have a custom authentication API and are not using Keystone)
+path = tokens
+# Should typically be left as keystone unless you have a non-Keystone
+# authentication API service
+strategy = keystone
 
 [compute]
+# This section contains configuration options used when executing tests
+# against the OpenStack Compute API.
+
+# This should be the username of a user WITHOUT administrative privileges
+username = {$USERNAME}
+# The above non-administrative user's password
+password = {$PASSWORD}
+# The above non-administrative user's tenant name
+tenant_name = {$TENANT_NAME}
+
+# This should be the username of an alternate user WITHOUT
+# administrative privileges
+alt_username = {$ALT_USERNAME}
+# The above non-administrative user's password
+alt_password = {$ALT_PASSWORD}
+# The above non-administrative user's tenant name
+alt_tenant_name = {$ALT_TENANT_NAME}
+
 # Reference data for tests. The ref and ref_alt should be
 # distinct images/flavors.
-image_ref=e7ddc02e-92fa-4f82-b36f-59b39bf66a67
-image_ref_alt=346f4039-a81e-44e0-9223-4a3d13c92a07
-flavor_ref=1
-flavor_ref_alt=2
-ssh_timeout=300
-build_interval=10
-build_timeout=600
-catalog_type=compute
-create_image_enabled=true
+image_ref = {$IMAGE_ID}
+image_ref_alt = {$IMAGE_ID_ALT}
+flavor_ref = 1
+flavor_ref_alt = 2
+
+# Number of seconds to wait while looping to check the status of an
+# instance or volume that is building.
+build_interval = 10
+
+# Number of seconds to time out on waiting for an instance or volume
+# to build or reach an expected status
+build_timeout = 600
+
+# The type of endpoint for a Compute API service. Unless you have a
+# custom Keystone service catalog implementation, you probably want to leave
+# this value as "compute"
+catalog_type = compute
+
+# Does the Compute API support creation of images?
+create_image_enabled = true
+
 # For resize to work with libvirt/kvm, one of the following must be true:
 # Single node: allow_resize_to_same_host=True must be set in nova.conf
 # Cluster: the 'nova' user must have scp access between cluster nodes
-resize_available=true
+resize_available = true
+
+# Level to log Compute API request/response details.
+log_level = ERROR
 
 [image]
-username=admin
-password=********
-tenant=admin
-auth_url=http://localhost:5000/v2.0
+# This section contains configuration options used when executing tests
+# against the OpenStack Images API
+
+# This should be the username of a user WITHOUT administrative privileges
+username = {$USERNAME}
+# The above non-administrative user's password
+password = {$PASSWORD}
+# The above non-administrative user's tenant name
+tenant_name = {$TENANT_NAME}
+
+[compute-admin]
+# This section contains configuration options for an administrative
+# user of the Compute API. These options are used in tests that stress
+# the admin-only parts of the Compute API
+
+# This should be the username of a user WITH administrative privileges
+username = {$ADMIN_USERNAME}
+# The above administrative user's password
+password = {$ADMIN_PASSWORD}
+# The above administrative user's tenant name
+tenant_name = {$ADMIN_TENANT_NAME}
diff --git a/stress/README.rst b/stress/README.rst
index bf44f13..1667e31 100644
--- a/stress/README.rst
+++ b/stress/README.rst
@@ -32,6 +32,7 @@
   host_admin_user=<name of user for ssh command>

   nova_logdir=<value of --logdir in nova.conf>

   controller=<hostname for calling nova-manage>

+  max_instances=<limit on instances that will be created>

 

 The stress test needs the top-level tempest directory to be on PYTHONPATH

 if you are not using nosetests to run.

diff --git a/stress/config.py b/stress/config.py
index 0dce816..16972d8 100755
--- a/stress/config.py
+++ b/stress/config.py
@@ -46,3 +46,8 @@
     def controller(self):

         """Controller host"""

         return self.get("controller", None)

+

+    @property

+    def max_instances(self):

+        """Maximum number of instances to create during test"""

+        return self.get("max_instances", 16)

diff --git a/stress/driver.py b/stress/driver.py
index b68825e..e8c8f12 100644
--- a/stress/driver.py
+++ b/stress/driver.py
@@ -114,14 +114,14 @@
                                    (default: 32)

                     `seed`       = random seed (default: None)

     """

+    stress_config = StressConfig(manager.config._conf)

     # get keyword arguments

     duration = kwargs.get('duration', datetime.timedelta(seconds=10))

     seed = kwargs.get('seed', None)

     sleep_time = float(kwargs.get('sleep_time', 3000)) / 1000

-    max_vms = int(kwargs.get('max_vms', 32))

+    max_vms = int(kwargs.get('max_vms', stress_config.max_instances))

     test_name = kwargs.get('test_name', 'unamed test')

 

-    stress_config = StressConfig(manager.config._conf)

     keypath = stress_config.host_private_key_path

     user = stress_config.host_admin_user

     logdir = stress_config.nova_logdir

@@ -194,7 +194,8 @@
                 break

             i += 1

             if i > 60:

-                raise

+                _error_in_logs(keypath, logdir, user, computes)

+                raise Exception("Cleanup timed out")

             time.sleep(1)

         logging.info('killed %s' % kill_id)

         state.delete_instance_state(kill_id)

diff --git a/stress/test_server_actions.py b/stress/test_server_actions.py
index 3cf3698..7080630 100644
--- a/stress/test_server_actions.py
+++ b/stress/test_server_actions.py
@@ -25,7 +25,7 @@
 # local imports
 import test_case
 import pending_action
-from tempest.exceptions import TimeoutException
+from tempest.exceptions import TimeoutException, Duplicate
 from utils.util import *
 
 
@@ -52,51 +52,35 @@
             self._logger.info('no ACTIVE instances to reboot')
             return
 
-        _reboot_type = kwargs.get('type', 'SOFT')
+        _reboot_arg = kwargs.get('type', 'SOFT')
 
         # select active vm to reboot and then send request to nova controller
         target = random.choice(active_vms)
         reboot_target = target[0]
+        # It seems that doing a reboot when in reboot is an error.
+        try:
+            response, body = manager.servers_client.reboot(
+                                                           reboot_target['id'],
+                                                           _reboot_arg)
+        except Duplicate:
+            return
 
-        response, body = manager.servers_client.reboot(
-                                                          reboot_target['id'],
-                                                          _reboot_type)
         if (response.status != 202):
             self._logger.error("response: %s" % response)
             raise Exception
 
-        if _reboot_type == 'SOFT':
-            state_name = 'REBOOT'
+        if _reboot_arg == 'SOFT':
+            reboot_state = 'REBOOT'
         else:
-            state_name = 'REBOOT'  # this is a bug, should be HARD_REBOOT
+            reboot_state = 'HARD_REBOOT'
 
         self._logger.info('waiting for machine %s to change to %s' %
-                          (reboot_target['id'], state_name))
-
-        # check for state transition
-        _resp, body = manager.servers_client.get_server(reboot_target['id'])
-        if body['status'] == state_name:
-            state_string = state_name
-        else:
-            # grab the actual state as we think it is
-            temp_obj = state.get_instances()[self._target['id']]
-            self._logger.debug(
-                "machine %s in state %s" %
-                (reboot_target['id'], temp_obj[1])
-                )
-            state_string = temp_obj[1]
-
-        if state_string == state_name:
-            self._logger.info('machine %s ACTIVE -> %s' %
-                              (reboot_target['id'], state_name))
-            state.set_instance_state(reboot_target['id'],
-                                    (reboot_target, state_name))
+                          (reboot_target['id'], reboot_state))
 
         return VerifyRebootVM(manager,
                               state,
                               reboot_target,
-                              reboot_type=_reboot_type,
-                              state_name=state_string)
+                              reboot_state=reboot_state)
 
 
 class VerifyRebootVM(pending_action.PendingAction):
@@ -104,22 +88,13 @@
     States = enum('REBOOT_CHECK', 'ACTIVE_CHECK')
 
     def __init__(self, manager, state, target_server,
-                 reboot_type=None,
-                 state_name=None,
+                 reboot_state=None,
                  ip_addr=None):
         super(VerifyRebootVM, self).__init__(manager,
                                              state,
                                              target_server)
-        # FIX ME: this is a nova bug
-        if reboot_type == 'SOFT':
-            self._reboot_state = 'REBOOT'
-        else:
-            self._reboot_state = 'REBOOT'  # should be HARD REBOOT
-
-        if state_name == 'ACTIVE':  # was still active, check to see if REBOOT
-            self._retry_state = self.States.REBOOT_CHECK
-        else:  # was REBOOT, so now check for ACTIVE
-            self._retry_state = self.States.ACTIVE_CHECK
+        self._reboot_state = reboot_state
+        self._retry_state = self.States.REBOOT_CHECK
 
     def retry(self):
         """
@@ -155,8 +130,9 @@
             if not self._check_for_status('ACTIVE'):
                 return False
         target = self._target
-        self._logger.info('machine %s REBOOT -> ACTIVE [%.1f secs elapsed]' %
-                              (target['id'], time.time() - self._start_time))
+        self._logger.info('machine %s %s -> ACTIVE [%.1f secs elapsed]' %
+                              (target['id'], reboot_state,
+                                time.time() - self._start_time))
         self._state.set_instance_state(target['id'],
                                       (target, 'ACTIVE'))
 
diff --git a/stress/test_servers.py b/stress/test_servers.py
index 47d30b5..a71bea2 100644
--- a/stress/test_servers.py
+++ b/stress/test_servers.py
@@ -214,7 +214,7 @@
             target = self._target
             self._logger.info('machine %s: DELETED [%.1f secs elapsed]' %
                               (target['id'], time.time() - self._start_time))
-            self._state.delete_machine_state(target['id'])
+            self._state.delete_instance_state(target['id'])
             return True
 
         return False
diff --git a/stress/tests/create_kill.py b/stress/tests/create_kill.py
index 752f72d..8169fc4 100644
--- a/stress/tests/create_kill.py
+++ b/stress/tests/create_kill.py
@@ -32,4 +32,4 @@
                sleep_time=100,  # in milliseconds

                seed=int(time.time()),

                test_name="create and delete",

-               max_vms=32)

+               )

diff --git a/stress/tests/hard_reboots.py b/stress/tests/hard_reboots.py
index f38ef6f..1b5928e 100644
--- a/stress/tests/hard_reboots.py
+++ b/stress/tests/hard_reboots.py
@@ -34,4 +34,4 @@
                sleep_time=500,  # in milliseconds

                seed=int(time.time()),

                test_name="hard reboots",

-               max_vms=32)

+               )

diff --git a/stress/tests/user_script_sample.py b/stress/tests/user_script_sample.py
index e4f53c4..3a6972c 100644
--- a/stress/tests/user_script_sample.py
+++ b/stress/tests/user_script_sample.py
@@ -35,4 +35,4 @@
                sleep_time=1000,  # in milliseconds

                seed=None,

                test_name="simple create and delete",

-               max_vms=10)

+               max_vms=4)

diff --git a/stress/tools/nova_destroy_all.py b/stress/tools/nova_destroy_all.py
index 1fa0487..3816557 100755
--- a/stress/tools/nova_destroy_all.py
+++ b/stress/tools/nova_destroy_all.py
@@ -21,9 +21,10 @@
 

 # get the environment variables for credentials

 identity = tempest.config.TempestConfig().identity

+compute = tempest.config.TempestConfig().compute

 

-nt = client.Client(identity.username, identity.password,

-                   identity.tenant_name, identity.auth_url)

+nt = client.Client(compute.username, compute.password,

+                   compute.tenant_name, identity.auth_url)

 

 flavor_list = nt.flavors.list()

 server_list = nt.servers.list()

diff --git a/stress/tools/nova_status.py b/stress/tools/nova_status.py
index 65dfc82..c0b7893 100755
--- a/stress/tools/nova_status.py
+++ b/stress/tools/nova_status.py
@@ -21,11 +21,12 @@
 

 # get the environment variables for credentials

 identity = tempest.config.TempestConfig().identity

-print identity.username, identity.password,\

-    identity.tenant_name, identity.auth_url

+compute = tempest.config.TempestConfig().compute

+print compute.username, compute.password,\

+    compute.tenant_name, identity.auth_url

 

-nt = client.Client(identity.username, identity.password,

-                   identity.tenant_name, identity.auth_url)

+nt = client.Client(compute.username, compute.password,

+                   compute.tenant_name, identity.auth_url)

 

 flavor_list = nt.flavors.list()

 server_list = nt.servers.list()

diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index ff27384..c8af2ca 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -1,8 +1,26 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack, LLC
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
 import json
 import httplib2
 import logging
 import sys
 import time
+
 from tempest import exceptions
 
 
@@ -15,7 +33,7 @@
     def __init__(self, config, user, password, auth_url, service,
                  tenant_name=None):
         self.log = logging.getLogger(__name__)
-        self.log.setLevel(logging.ERROR)
+        self.log.setLevel(getattr(logging, config.compute.log_level))
         self.config = config
         if self.config.identity.strategy == 'keystone':
             self.token, self.base_url = self.keystone_auth(user,
diff --git a/tempest/config.py b/tempest/config.py
index f805d93..2a64869 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -1,24 +1,49 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack, LLC
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
 import ConfigParser
 import logging
 import os
+
 from tempest.common.utils import data_utils
 
 LOG = logging.getLogger(__name__)
 
 
-class IdentityConfig(object):
-    """Provides configuration information for authenticating with Keystone."""
+class BaseConfig(object):
+
+    SECTION_NAME = None
 
     def __init__(self, conf):
-        """Initialize an Identity-specific configuration object"""
         self.conf = conf
 
     def get(self, item_name, default_value=None):
         try:
-            return self.conf.get("identity", item_name)
+            return self.conf.get(self.SECTION_NAME, item_name)
         except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
             return default_value
 
+
+class IdentityConfig(BaseConfig):
+
+    """Provides configuration information for authenticating with Keystone."""
+
+    SECTION_NAME = "identity"
+
     @property
     def host(self):
         """Host IP for making Identity API requests."""
@@ -55,61 +80,54 @@
         return self.get("use_ssl", 'false').lower() != 'false'
 
     @property
-    def nonadmin_user1(self):
-        """Username to use for Nova API requests."""
-        return self.get("nonadmin_user1")
-
-    @property
-    def nonadmin_user1_tenant_name(self):
-        """Tenant name to use for Nova API requests."""
-        return self.get("nonadmin_user1_tenant_name")
-
-    @property
-    def nonadmin_user1_password(self):
-        """API key to use when authenticating."""
-        return self.get("nonadmin_user1_password")
-
-    @property
-    def nonadmin_user2(self):
-        """Alternate username to use for Nova API requests."""
-        return self.get("nonadmin_user2")
-
-    @property
-    def nonadmin_user2_tenant_name(self):
-        """Alternate tenant name for Nova API requests."""
-        return self.get("nonadmin_user2_tenant_name")
-
-    @property
-    def nonadmin_user2_password(self):
-        """Alternate API key to use when authenticating."""
-        return self.get("nonadmin_user2_password")
-
-    @property
     def strategy(self):
         """Which auth method does the environment use? (basic|keystone)"""
         return self.get("strategy", 'keystone')
 
 
-class ComputeConfig(object):
-    def __init__(self, conf):
-        """Initialize a Compute-specific configuration object."""
-        self.conf = conf
+class ComputeConfig(BaseConfig):
 
-    def get(self, item_name, default_value):
-        try:
-            return self.conf.get("compute", item_name)
-        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
-            return default_value
+    SECTION_NAME = "compute"
+
+    @property
+    def username(self):
+        """Username to use for Nova API requests."""
+        return self.get("username", "demo")
+
+    @property
+    def tenant_name(self):
+        """Tenant name to use for Nova API requests."""
+        return self.get("tenant_name", "demo")
+
+    @property
+    def password(self):
+        """API key to use when authenticating."""
+        return self.get("password", "pass")
+
+    @property
+    def alt_username(self):
+        """Username of alternate user to use for Nova API requests."""
+        return self.get("alt_username")
+
+    @property
+    def alt_tenant_name(self):
+        """Alternate user's Tenant name to use for Nova API requests."""
+        return self.get("alt_tenant_name")
+
+    @property
+    def alt_password(self):
+        """API key to use when authenticating as alternate user."""
+        return self.get("alt_password")
 
     @property
     def image_ref(self):
         """Valid primary image to use in tests."""
-        return self.get("image_ref", 'e7ddc02e-92fa-4f82-b36f-59b39bf66a67')
+        return self.get("image_ref", "{$IMAGE_ID}")
 
     @property
     def image_ref_alt(self):
         """Valid secondary image reference to be used in tests."""
-        return self.get("image_ref_alt", '346f4039-a81e-44e0-9223-4a3d13c907')
+        return self.get("image_ref_alt", "{$IMAGE_ID_ALT}")
 
     @property
     def flavor_ref(self):
@@ -132,21 +150,11 @@
         return self.get("create_image_enabled", 'false').lower() != 'false'
 
     @property
-    def release_name(self):
-        """Which release is this?"""
-        return self.get("release_name", 'essex')
-
-    @property
     def build_interval(self):
         """Time in seconds between build status checks."""
         return float(self.get("build_interval", 10))
 
     @property
-    def ssh_timeout(self):
-        """Timeout in seconds to use when connecting via ssh."""
-        return float(self.get("ssh_timeout", 300))
-
-    @property
     def build_timeout(self):
         """Timeout in seconds to wait for an entity to build."""
         return float(self.get("build_timeout", 300))
@@ -156,21 +164,20 @@
         """Catalog type of the Compute service."""
         return self.get("catalog_type", 'compute')
 
+    @property
+    def log_level(self):
+        """Level for logging compute API calls."""
+        return self.get("log_level", 'ERROR')
 
-class ImagesConfig(object):
+
+class ImagesConfig(BaseConfig):
+
     """
     Provides configuration information for connecting to an
     OpenStack Images service.
     """
 
-    def __init__(self, conf):
-        self.conf = conf
-
-    def get(self, item_name, default_value=None):
-        try:
-            return self.conf.get("image", item_name)
-        except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
-            return default_value
+    SECTION_NAME = "image"
 
     @property
     def host(self):
@@ -189,31 +196,34 @@
 
     @property
     def username(self):
-        """Username to use for Images API requests. Defaults to 'admin'."""
-        return self.get("user", "admin")
+        """Username to use for Images API requests. Defaults to 'demo'."""
+        return self.get("user", "demo")
 
     @property
     def password(self):
         """Password for user"""
-        return self.get("password", "")
+        return self.get("password", "pass")
 
     @property
-    def tenant(self):
-        """Tenant to use for Images API requests. Defaults to 'admin'."""
-        return self.get("tenant", "admin")
-
-    @property
-    def service_token(self):
-        """Token to use in querying the API. Default: None"""
-        return self.get("service_token")
-
-    @property
-    def auth_url(self):
-        """Optional URL to auth service. Will be discovered if None"""
-        return self.get("auth_url")
+    def tenant_name(self):
+        """Tenant to use for Images API requests. Defaults to 'demo'."""
+        return self.get("tenant_name", "demo")
 
 
-class TempestConfig(object):
+# TODO(jaypipes): Move this to a common utils (not data_utils...)
+def singleton(cls):
+    """Simple wrapper for classes that should only have a single instance"""
+    instances = {}
+
+    def getinstance():
+        if cls not in instances:
+            instances[cls] = cls()
+        return instances[cls]
+    return getinstance
+
+
+@singleton
+class TempestConfig:
     """Provides OpenStack configuration information."""
 
     DEFAULT_CONFIG_DIR = os.path.join(
@@ -235,6 +245,8 @@
 
         path = os.path.join(conf_dir, conf_file)
 
+        LOG.info("Using tempest config file %s" % path)
+
         if not os.path.exists(path):
             msg = "Config file %(path)s not found" % locals()
             raise RuntimeError(msg)
diff --git a/tempest/openstack.py b/tempest/openstack.py
index d52647b..ffe59c4 100644
--- a/tempest/openstack.py
+++ b/tempest/openstack.py
@@ -1,3 +1,22 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2012 OpenStack, LLC
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import logging
+
 import tempest.config
 from tempest import exceptions
 from tempest.services.image import service as image_service
@@ -12,25 +31,28 @@
 from tempest.services.nova.json.keypairs_client import KeyPairsClient
 from tempest.services.nova.json.volumes_client import VolumesClient
 
+LOG = logging.getLogger(__name__)
+
 
 class Manager(object):
 
-    def __init__(self, username=None, password=None, tenant_name=None):
-        """
-        Top level manager for all Openstack APIs
-        """
+    """
+    Top level manager for OpenStack Compute clients
+    """
+
+    def __init__(self):
         self.config = tempest.config.TempestConfig()
 
-        if None in [username, password, tenant_name]:
-            # Pull from the default, the first non-admin user
-            username = self.config.identity.nonadmin_user1
-            password = self.config.identity.nonadmin_user1_password
-            tenant_name = self.config.identity.nonadmin_user1_tenant_name
+        username = self.config.compute.username
+        password = self.config.compute.password
+        tenant_name = self.config.compute.tenant_name
 
-        if None in [username, password, tenant_name]:
-            # We can't find any usable credentials, fail early
-            raise exceptions.InvalidConfiguration(message="Missing complete \
-                                                  user credentials.")
+        if None in (username, password, tenant_name):
+            msg = ("Missing required credentials. "
+                   "username: %(username)s, password: %(password)s, "
+                   "tenant_name: %(tenant_name)s") % locals()
+            raise exceptions.InvalidConfiguration(msg)
+
         auth_url = self.config.identity.auth_url
 
         if self.config.identity.strategy == 'keystone':
diff --git a/tempest/services/image/service.py b/tempest/services/image/service.py
index 2cf053f..901e497 100644
--- a/tempest/services/image/service.py
+++ b/tempest/services/image/service.py
@@ -42,14 +42,14 @@
             creds = {
                 'username': config.images.username,
                 'password': config.images.password,
-                'tenant': config.images.tenant,
-                'auth_url': config.images.auth_url,
-                'strategy': 'keystone'
+                'tenant': config.images.tenant_name,
+                # rstrip() is necessary here because Glance client
+                # automatically adds the tokens/ part...
+                'auth_url': config.identity.auth_url.rstrip('/tokens'),
+                'strategy': config.identity.strategy
             }
-            service_token = config.images.service_token
             self._client = client.Client(config.images.host,
                                          config.images.port,
-                                         auth_tok=service_token,
                                          creds=creds)
         else:
             raise NotImplementedError
diff --git a/tempest/tests/image/test_images.py b/tempest/tests/image/test_images.py
index 8f75f08..0e515dc 100644
--- a/tempest/tests/image/test_images.py
+++ b/tempest/tests/image/test_images.py
@@ -109,7 +109,6 @@
         self.assertEqual(1024, results['size'])
 
     @attr(type='image')
-    @unittest.skip('Skipping until Glance Bug 912897 is fixed')
     def test_register_remote_image(self):
         """Register a new remote image"""
         meta = {
@@ -141,7 +140,6 @@
     def setUpClass(cls):
         if not GLANCE_INSTALLED:
             raise SkipTest('Glance not installed')
-        raise SkipTest('Skipping until Glance Bug 912897 is fixed')
         cls.os = openstack.ServiceManager()
         cls.client = cls.os.images.get_client()
         cls.created_images = []
@@ -149,7 +147,7 @@
 
         # We add a few images here to test the listing functionality of
         # the images API
-        for x in xrange(1, 10):
+        for x in xrange(0, 10):
             # We make even images remote and odd images standard
             if x % 2 == 0:
                 cls.created_images.append(cls._create_remote_image(x))
diff --git a/tempest/tests/test_authorization.py b/tempest/tests/test_authorization.py
index f71073d..ae7fd3f 100644
--- a/tempest/tests/test_authorization.py
+++ b/tempest/tests/test_authorization.py
@@ -4,6 +4,8 @@
 from nose.tools import raises
 
 from tempest import openstack
+from tempest.services.nova.json.images_client import ImagesClient
+from tempest.services.nova.json.servers_client import ServersClient
 from tempest.common.utils.data_utils import rand_name
 from tempest.exceptions import NotFound, ComputeFault, BadRequest, Unauthorized
 from tempest.tests import utils
@@ -23,10 +25,10 @@
         cls.flavor_ref_alt = cls.config.compute.flavor_ref_alt
 
         # Verify the second user is not the same as the first and is configured
-        cls.user1 = cls.config.identity.nonadmin_user1
-        cls.user2 = cls.config.identity.nonadmin_user2
-        cls.user2_password = cls.config.identity.nonadmin_user2_password
-        cls.user2_tenant_name = cls.config.identity.nonadmin_user2_tenant_name
+        cls.user1 = cls.config.compute.username
+        cls.user2 = cls.config.compute.alt_username
+        cls.user2_password = cls.config.compute.alt_password
+        cls.user2_tenant_name = cls.config.compute.alt_tenant_name
         cls.multi_user = False
 
         if  (cls.user2 != None and cls.user1 != cls.user2
@@ -35,10 +37,18 @@
 
             # Setup a client instance for the second user
             cls.multi_user = True
-            cls.os_other = openstack.Manager(cls.user2, cls.user2_password,
-                                             cls.user2_tenant_name)
-            cls.other_client = cls.os_other.servers_client
-            cls.other_images_client = cls.os_other.images_client
+
+            auth_url = cls.config.identity.auth_url
+
+            if cls.config.identity.strategy == 'keystone':
+                client_args = (cls.config, cls.user2, cls.user2_password,
+                               auth_url, cls.user2_tenant_name)
+            else:
+                client_args = (cls.config, cls.user2, cls.user2_password,
+                               auth_url)
+
+            cls.other_client = ServersClient(*client_args)
+            cls.other_images_client = ImagesClient(*client_args)
 
             name = rand_name('server')
             resp, server = cls.client.create_server(name, cls.image_ref,
diff --git a/tempest/tests/test_flavors.py b/tempest/tests/test_flavors.py
index ac58dba..7d8a94b 100644
--- a/tempest/tests/test_flavors.py
+++ b/tempest/tests/test_flavors.py
@@ -7,8 +7,6 @@
 
 class FlavorsTest(unittest.TestCase):
 
-    release = tempest.config.TempestConfig().compute.release_name
-
     @classmethod
     def setUpClass(cls):
         cls.os = openstack.Manager()
@@ -44,7 +42,6 @@
         self.assertRaises(exceptions.NotFound, self.client.get_flavor_details,
                           999)
 
-    @unittest.skipIf(release == 'diablo', 'bug in diablo')
     @attr(type='positive', bug='lp912922')
     def test_list_flavors_limit_results(self):
         """Only the expected number of flavors should be returned"""
@@ -52,7 +49,6 @@
         resp, flavors = self.client.list_flavors(params)
         self.assertEqual(1, len(flavors))
 
-    @unittest.skipIf(release == 'diablo', 'bug in diablo')
     @attr(type='positive', bug='lp912922')
     def test_list_flavors_detailed_limit_results(self):
         """Only the expected number of flavors (detailed) should be returned"""
@@ -84,7 +80,6 @@
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]),
                         'The list of flavors did not start after the marker.')
 
-    @unittest.skipIf(release == 'diablo', 'bug in diablo')
     @attr(type='positive')
     def test_list_flavors_detailed_filter_by_min_disk(self):
         """The detailed list of flavors should be filtered by disk space"""
@@ -96,7 +91,6 @@
         resp, flavors = self.client.list_flavors_with_detail(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
-    @unittest.skipIf(release == 'diablo', 'bug in diablo')
     @attr(type='positive')
     def test_list_flavors_detailed_filter_by_min_ram(self):
         """The detailed list of flavors should be filtered by RAM"""
@@ -108,7 +102,6 @@
         resp, flavors = self.client.list_flavors_with_detail(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
-    @unittest.skipIf(release == 'diablo', 'bug in diablo')
     @attr(type='positive')
     def test_list_flavors_filter_by_min_disk(self):
         """The list of flavors should be filtered by disk space"""
@@ -120,7 +113,6 @@
         resp, flavors = self.client.list_flavors(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
-    @unittest.skipIf(release == 'diablo', 'bug in diablo')
     @attr(type='positive')
     def test_list_flavors_filter_by_min_ram(self):
         """The list of flavors should be filtered by RAM"""
diff --git a/tempest/tests/test_keypairs.py b/tempest/tests/test_keypairs.py
index 9f17922..baedbb6 100644
--- a/tempest/tests/test_keypairs.py
+++ b/tempest/tests/test_keypairs.py
@@ -8,8 +8,6 @@
 
 class KeyPairsTest(unittest.TestCase):
 
-    release = tempest.config.TempestConfig().compute.release_name
-
     @classmethod
     def setUpClass(cls):
         cls.os = openstack.Manager()
@@ -138,7 +136,6 @@
         else:
             self.fail('empty string')
 
-    @unittest.skipIf(release == 'diablo', 'bug in diablo')
     @attr(type='negative')
     def test_create_keypair_with_long_keynames(self):
         """Keypairs with name longer than 255 chars should not be created"""
diff --git a/tempest/tests/test_servers_negative.py b/tempest/tests/test_servers_negative.py
index f8de727..6c738ea 100644
--- a/tempest/tests/test_servers_negative.py
+++ b/tempest/tests/test_servers_negative.py
@@ -6,8 +6,6 @@
 
 
 class ServersNegativeTest(unittest.TestCase):
-    release = tempest.config.TempestConfig().\
-            compute.release_name
 
     @classmethod
     def setUpClass(cls):
@@ -16,7 +14,6 @@
         cls.config = cls.os.config
         cls.image_ref = cls.config.compute.image_ref
         cls.flavor_ref = cls.config.compute.flavor_ref
-        cls.ssh_timeout = cls.config.compute.ssh_timeout
 
     def test_server_name_blank(self):
         """Create a server with name parameter empty"""
@@ -63,7 +60,6 @@
         else:
             self.fail('Cannot create a server with an invalid flavor')
 
-    @unittest.skipIf(release == 'diablo', 'Bug in Diablo, lp#891264')
     def test_invalid_access_ip_v4_address(self):
         """An access IPv4 address must match a valid address pattern"""
         accessIPv4 = '1.1.1.1.1.1'
@@ -78,7 +74,6 @@
         else:
             self.fail('Access IPv4 address must match the correct format')
 
-    @unittest.skipIf(release == 'diablo', 'Bug in Diablo, lp#891264')
     def test_invalid_ip_v6_address(self):
         """An access IPv6 address must match a valid address pattern"""
         accessIPv6 = 'notvalid'