Merge "Fix init of test_volume_type_extra_specs_list"
diff --git a/HACKING.rst b/HACKING.rst
index fed4130..a546f8c 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -153,10 +153,25 @@
                              kwarg2=dict_of_numbers)
 
 
+openstack-common
+----------------
+
+A number of modules from openstack-common are imported into the project.
+
+These modules are "incubating" in openstack-common and are kept in sync
+with the help of openstack-common's update.py script. See:
+
+  http://wiki.openstack.org/CommonLibrary#Incubation
+
+The copy of the code should never be directly modified here. Please
+always update openstack-common first and then run the script to copy
+the changes across.
+
+
 OpenStack Trademark
 -------------------
 
-OpenStack is a registered trademark of OpenStack, LLC, and uses the
+OpenStack is a registered trademark of the OpenStack Foundation, and uses the
 following capitalization:
 
    OpenStack
diff --git a/tempest/clients.py b/tempest/clients.py
index 28abb79..aa9b558 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -19,8 +19,7 @@
 
 from tempest import config
 from tempest import exceptions
-from tempest.services.boto.clients import APIClientEC2
-from tempest.services.boto.clients import ObjectClientS3
+from tempest.services import botoclients
 from tempest.services.compute.json.extensions_client import \
     ExtensionsClientJSON
 from tempest.services.compute.json.flavors_client import FlavorsClientJSON
@@ -52,7 +51,7 @@
 from tempest.services.identity.json.identity_client import TokenClientJSON
 from tempest.services.identity.xml.identity_client import IdentityClientXML
 from tempest.services.identity.xml.identity_client import TokenClientXML
-from tempest.services.image import service as image_service
+from tempest.services.image.json.image_client import ImageClientJSON
 from tempest.services.network.json.network_client import NetworkClient
 from tempest.services.object_storage.account_client import AccountClient
 from tempest.services.object_storage.container_client import ContainerClient
@@ -202,10 +201,11 @@
             raise exceptions.InvalidConfiguration(msg)
         self.network_client = NetworkClient(*client_args)
         self.account_client = AccountClient(*client_args)
+        self.image_client = ImageClientJSON(*client_args)
         self.container_client = ContainerClient(*client_args)
         self.object_client = ObjectClient(*client_args)
-        self.ec2api_client = APIClientEC2(*client_args)
-        self.s3_client = ObjectClientS3(*client_args)
+        self.ec2api_client = botoclients.APIClientEC2(*client_args)
+        self.s3_client = botoclients.ObjectClientS3(*client_args)
         self.custom_object_client = ObjectClientCustomizedHeader(*client_args)
         self.custom_account_client = \
             AccountClientCustomizedHeader(*client_args)
@@ -254,16 +254,3 @@
                       conf.compute_admin.password,
                       conf.compute_admin.tenant_name,
                       interface=interface)
-
-
-class ServiceManager(object):
-
-    """
-    Top-level object housing clients for OpenStack APIs
-    """
-
-    def __init__(self):
-        self.config = config.TempestConfig()
-        self.services = {}
-        self.services['image'] = image_service.Service(self.config)
-        self.images = self.services['image']
diff --git a/tempest/common/glance_http.py b/tempest/common/glance_http.py
new file mode 100644
index 0000000..faac1a0
--- /dev/null
+++ b/tempest/common/glance_http.py
@@ -0,0 +1,375 @@
+# 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.
+
+# Originally copied from python-glanceclient
+
+import copy
+import httplib
+import logging
+import posixpath
+import socket
+import StringIO
+import struct
+import urlparse
+
+try:
+    import json
+except ImportError:
+    import simplejson as json
+
+# Python 2.5 compat fix
+if not hasattr(urlparse, 'parse_qsl'):
+    import cgi
+    urlparse.parse_qsl = cgi.parse_qsl
+
+import OpenSSL
+
+from tempest import exceptions as exc
+
+
+LOG = logging.getLogger(__name__)
+USER_AGENT = 'tempest'
+CHUNKSIZE = 1024 * 64  # 64kB
+
+
+class HTTPClient(object):
+
+    def __init__(self, endpoint, **kwargs):
+        self.endpoint = endpoint
+        endpoint_parts = self.parse_endpoint(self.endpoint)
+        self.endpoint_scheme = endpoint_parts.scheme
+        self.endpoint_hostname = endpoint_parts.hostname
+        self.endpoint_port = endpoint_parts.port
+        self.endpoint_path = endpoint_parts.path
+
+        self.connection_class = self.get_connection_class(self.endpoint_scheme)
+        self.connection_kwargs = self.get_connection_kwargs(
+            self.endpoint_scheme, **kwargs)
+
+        self.auth_token = kwargs.get('token')
+
+    @staticmethod
+    def parse_endpoint(endpoint):
+        return urlparse.urlparse(endpoint)
+
+    @staticmethod
+    def get_connection_class(scheme):
+        if scheme == 'https':
+            return VerifiedHTTPSConnection
+        else:
+            return httplib.HTTPConnection
+
+    @staticmethod
+    def get_connection_kwargs(scheme, **kwargs):
+        _kwargs = {'timeout': float(kwargs.get('timeout', 600))}
+
+        if scheme == 'https':
+            _kwargs['cacert'] = kwargs.get('cacert', None)
+            _kwargs['cert_file'] = kwargs.get('cert_file', None)
+            _kwargs['key_file'] = kwargs.get('key_file', None)
+            _kwargs['insecure'] = kwargs.get('insecure', False)
+            _kwargs['ssl_compression'] = kwargs.get('ssl_compression', True)
+
+        return _kwargs
+
+    def get_connection(self):
+        _class = self.connection_class
+        try:
+            return _class(self.endpoint_hostname, self.endpoint_port,
+                          **self.connection_kwargs)
+        except httplib.InvalidURL:
+            raise exc.EndpointNotFound
+
+    def log_curl_request(self, method, url, kwargs):
+        curl = ['curl -i -X %s' % method]
+
+        for (key, value) in kwargs['headers'].items():
+            header = '-H \'%s: %s\'' % (key, value)
+            curl.append(header)
+
+        conn_params_fmt = [
+            ('key_file', '--key %s'),
+            ('cert_file', '--cert %s'),
+            ('cacert', '--cacert %s'),
+        ]
+        for (key, fmt) in conn_params_fmt:
+            value = self.connection_kwargs.get(key)
+            if value:
+                curl.append(fmt % value)
+
+        if self.connection_kwargs.get('insecure'):
+            curl.append('-k')
+
+        if 'body' in kwargs:
+            curl.append('-d \'%s\'' % kwargs['body'])
+
+        curl.append('%s%s' % (self.endpoint, url))
+        LOG.debug(' '.join(curl))
+
+    @staticmethod
+    def log_http_response(resp, body=None):
+        status = (resp.version / 10.0, resp.status, resp.reason)
+        dump = ['\nHTTP/%.1f %s %s' % status]
+        dump.extend(['%s: %s' % (k, v) for k, v in resp.getheaders()])
+        dump.append('')
+        if body:
+            dump.extend([body, ''])
+        LOG.debug('\n'.join(dump))
+
+    def _http_request(self, url, method, **kwargs):
+        """ Send an http request with the specified characteristics.
+
+        Wrapper around httplib.HTTP(S)Connection.request to handle tasks such
+        as setting headers and error handling.
+        """
+        # Copy the kwargs so we can reuse the original in case of redirects
+        kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {}))
+        kwargs['headers'].setdefault('User-Agent', USER_AGENT)
+        if self.auth_token:
+            kwargs['headers'].setdefault('X-Auth-Token', self.auth_token)
+
+        self.log_curl_request(method, url, kwargs)
+        conn = self.get_connection()
+
+        try:
+            conn_url = posixpath.normpath('%s/%s' % (self.endpoint_path, url))
+            if kwargs['headers'].get('Transfer-Encoding') == 'chunked':
+                conn.putrequest(method, conn_url)
+                for header, value in kwargs['headers'].items():
+                    conn.putheader(header, value)
+                conn.endheaders()
+                chunk = kwargs['body'].read(CHUNKSIZE)
+                # Chunk it, baby...
+                while chunk:
+                    conn.send('%x\r\n%s\r\n' % (len(chunk), chunk))
+                    chunk = kwargs['body'].read(CHUNKSIZE)
+                conn.send('0\r\n\r\n')
+            else:
+                conn.request(method, conn_url, **kwargs)
+            resp = conn.getresponse()
+        except socket.gaierror as e:
+            message = "Error finding address for %(url)s: %(e)s" % locals()
+            raise exc.EndpointNotFound
+        except (socket.error, socket.timeout) as e:
+            endpoint = self.endpoint
+            message = "Error communicating with %(endpoint)s %(e)s" % locals()
+            raise exc.TimeoutException
+
+        body_iter = ResponseBodyIterator(resp)
+
+        # Read body into string if it isn't obviously image data
+        if resp.getheader('content-type', None) != 'application/octet-stream':
+            body_str = ''.join([chunk for chunk in body_iter])
+            self.log_http_response(resp, body_str)
+            body_iter = StringIO.StringIO(body_str)
+        else:
+            self.log_http_response(resp)
+
+        return resp, body_iter
+
+    def json_request(self, method, url, **kwargs):
+        kwargs.setdefault('headers', {})
+        kwargs['headers'].setdefault('Content-Type', 'application/json')
+
+        if 'body' in kwargs:
+            kwargs['body'] = json.dumps(kwargs['body'])
+
+        resp, body_iter = self._http_request(url, method, **kwargs)
+
+        if 'application/json' in resp.getheader('content-type', None):
+            body = ''.join([chunk for chunk in body_iter])
+            try:
+                body = json.loads(body)
+            except ValueError:
+                LOG.error('Could not decode response body as JSON')
+        else:
+            body = None
+
+        return resp, body
+
+    def raw_request(self, method, url, **kwargs):
+        kwargs.setdefault('headers', {})
+        kwargs['headers'].setdefault('Content-Type',
+                                     'application/octet-stream')
+        if 'body' in kwargs:
+            if (hasattr(kwargs['body'], 'read')
+                    and method.lower() in ('post', 'put')):
+                # We use 'Transfer-Encoding: chunked' because
+                # body size may not always be known in advance.
+                kwargs['headers']['Transfer-Encoding'] = 'chunked'
+        return self._http_request(url, method, **kwargs)
+
+
+class OpenSSLConnectionDelegator(object):
+    """
+    An OpenSSL.SSL.Connection delegator.
+
+    Supplies an additional 'makefile' method which httplib requires
+    and is not present in OpenSSL.SSL.Connection.
+
+    Note: Since it is not possible to inherit from OpenSSL.SSL.Connection
+    a delegator must be used.
+    """
+    def __init__(self, *args, **kwargs):
+        self.connection = OpenSSL.SSL.Connection(*args, **kwargs)
+
+    def __getattr__(self, name):
+        return getattr(self.connection, name)
+
+    def makefile(self, *args, **kwargs):
+        return socket._fileobject(self.connection, *args, **kwargs)
+
+
+class VerifiedHTTPSConnection(httplib.HTTPSConnection):
+    """
+    Extended HTTPSConnection which uses the OpenSSL library
+    for enhanced SSL support.
+    Note: Much of this functionality can eventually be replaced
+          with native Python 3.3 code.
+    """
+    def __init__(self, host, port=None, key_file=None, cert_file=None,
+                 cacert=None, timeout=None, insecure=False,
+                 ssl_compression=True):
+        httplib.HTTPSConnection.__init__(self, host, port,
+                                         key_file=key_file,
+                                         cert_file=cert_file)
+        self.key_file = key_file
+        self.cert_file = cert_file
+        self.timeout = timeout
+        self.insecure = insecure
+        self.ssl_compression = ssl_compression
+        self.cacert = cacert
+        self.setcontext()
+
+    @staticmethod
+    def host_matches_cert(host, x509):
+        """
+        Verify that the the x509 certificate we have received
+        from 'host' correctly identifies the server we are
+        connecting to, ie that the certificate's Common Name
+        or a Subject Alternative Name matches 'host'.
+        """
+        # First see if we can match the CN
+        if x509.get_subject().commonName == host:
+            return True
+
+        # Also try Subject Alternative Names for a match
+        san_list = None
+        for i in xrange(x509.get_extension_count()):
+            ext = x509.get_extension(i)
+            if ext.get_short_name() == 'subjectAltName':
+                san_list = str(ext)
+                for san in ''.join(san_list.split()).split(','):
+                    if san == "DNS:%s" % host:
+                        return True
+
+        # Server certificate does not match host
+        msg = ('Host "%s" does not match x509 certificate contents: '
+               'CommonName "%s"' % (host, x509.get_subject().commonName))
+        if san_list is not None:
+            msg = msg + ', subjectAltName "%s"' % san_list
+        raise exc.SSLCertificateError(msg)
+
+    def verify_callback(self, connection, x509, errnum,
+                        depth, preverify_ok):
+        if x509.has_expired():
+            msg = "SSL Certificate expired on '%s'" % x509.get_notAfter()
+            raise exc.SSLCertificateError(msg)
+
+        if depth == 0 and preverify_ok is True:
+            # We verify that the host matches against the last
+            # certificate in the chain
+            return self.host_matches_cert(self.host, x509)
+        else:
+            # Pass through OpenSSL's default result
+            return preverify_ok
+
+    def setcontext(self):
+        """
+        Set up the OpenSSL context.
+        """
+        self.context = OpenSSL.SSL.Context(OpenSSL.SSL.SSLv23_METHOD)
+
+        if self.ssl_compression is False:
+            self.context.set_options(0x20000)  # SSL_OP_NO_COMPRESSION
+
+        if self.insecure is not True:
+            self.context.set_verify(OpenSSL.SSL.VERIFY_PEER,
+                                    self.verify_callback)
+        else:
+            self.context.set_verify(OpenSSL.SSL.VERIFY_NONE,
+                                    self.verify_callback)
+
+        if self.cert_file:
+            try:
+                self.context.use_certificate_file(self.cert_file)
+            except Exception, e:
+                msg = 'Unable to load cert from "%s" %s' % (self.cert_file, e)
+                raise exc.SSLConfigurationError(msg)
+            if self.key_file is None:
+                # We support having key and cert in same file
+                try:
+                    self.context.use_privatekey_file(self.cert_file)
+                except Exception, e:
+                    msg = ('No key file specified and unable to load key '
+                           'from "%s" %s' % (self.cert_file, e))
+                    raise exc.SSLConfigurationError(msg)
+
+        if self.key_file:
+            try:
+                self.context.use_privatekey_file(self.key_file)
+            except Exception, e:
+                msg = 'Unable to load key from "%s" %s' % (self.key_file, e)
+                raise exc.SSLConfigurationError(msg)
+
+        if self.cacert:
+            try:
+                self.context.load_verify_locations(self.cacert)
+            except Exception, e:
+                msg = 'Unable to load CA from "%s"' % (self.cacert, e)
+                raise exc.SSLConfigurationError(msg)
+        else:
+            self.context.set_default_verify_paths()
+
+    def connect(self):
+        """
+        Connect to an SSL port using the OpenSSL library and apply
+        per-connection parameters.
+        """
+        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        if self.timeout is not None:
+            # '0' microseconds
+            sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO,
+                            struct.pack('LL', self.timeout, 0))
+        self.sock = OpenSSLConnectionDelegator(self.context, sock)
+        self.sock.connect((self.host, self.port))
+
+
+class ResponseBodyIterator(object):
+    """A class that acts as an iterator over an HTTP response."""
+
+    def __init__(self, resp):
+        self.resp = resp
+
+    def __iter__(self):
+        while True:
+            yield self.next()
+
+    def next(self):
+        chunk = self.resp.read(CHUNKSIZE)
+        if chunk:
+            return chunk
+        else:
+            raise StopIteration()
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 5af4a40..e163126 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -275,6 +275,45 @@
         self._log_response(resp, resp_body)
         self.response_checker(method, url, headers, body, resp, resp_body)
 
+        self._error_checker(method, url, headers, body, resp, resp_body, depth,
+                            wait)
+
+        return resp, resp_body
+
+    def _error_checker(self, method, url,
+                       headers, body, resp, resp_body, depth=0, wait=None):
+
+        # NOTE(mtreinish): Check for httplib response from glance_http. The
+        # object can't be used here because importing httplib breaks httplib2.
+        # If another object from a class not imported were passed here as
+        # resp this could possibly fail
+        if str(type(resp)) == "<type 'instance'>":
+            ctype = resp.getheader('content-type')
+        else:
+            try:
+                ctype = resp['content-type']
+            # NOTE(mtreinish): Keystone delete user responses doesn't have a
+            # content-type header. (They don't have a body) So just pretend it
+            # is set.
+            except KeyError:
+                ctype = 'application/json'
+
+        JSON_ENC = ['application/json; charset=UTF-8', 'application/json',
+                    'application/json; charset=utf-8']
+        # NOTE(mtreinish): This is for compatibility with Glance and swift
+        # APIs. These are the return content types that Glance api v1
+        # (and occasionally swift) are using.
+        TXT_ENC = ['text/plain; charset=UTF-8', 'text/html; charset=UTF-8',
+                   'text/plain; charset=utf-8']
+        XML_ENC = ['application/xml', 'application/xml; charset=UTF-8']
+
+        if ctype in JSON_ENC or ctype in XML_ENC:
+            parse_resp = True
+        elif ctype in TXT_ENC:
+            parse_resp = False
+        else:
+            raise exceptions.RestClientException(str(resp.status))
+
         if resp.status == 401 or resp.status == 403:
             raise exceptions.Unauthorized()
 
@@ -282,44 +321,45 @@
             raise exceptions.NotFound(resp_body)
 
         if resp.status == 400:
-            resp_body = self._parse_resp(resp_body)
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
             raise exceptions.BadRequest(resp_body)
 
         if resp.status == 409:
-            resp_body = self._parse_resp(resp_body)
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
             raise exceptions.Duplicate(resp_body)
 
         if resp.status == 413:
-            resp_body = self._parse_resp(resp_body)
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
             #Checking whether Absolute/Rate limit
             return self.check_over_limit(resp_body, method, url, headers, body,
                                          depth, wait)
 
         if resp.status in (500, 501):
-            resp_body = self._parse_resp(resp_body)
-            #I'm seeing both computeFault and cloudServersFault come back.
-            #Will file a bug to fix, but leave as is for now.
-
-            if 'cloudServersFault' in resp_body:
-                message = resp_body['cloudServersFault']['message']
-            elif 'computeFault' in resp_body:
-                message = resp_body['computeFault']['message']
-            elif 'error' in resp_body:  # Keystone errors
-                message = resp_body['error']['message']
-                raise exceptions.IdentityError(message)
-            elif 'message' in resp_body:
-                message = resp_body['message']
-            else:
-                message = resp_body
+            message = resp_body
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
+                #I'm seeing both computeFault and cloudServersFault come back.
+                #Will file a bug to fix, but leave as is for now.
+                if 'cloudServersFault' in resp_body:
+                    message = resp_body['cloudServersFault']['message']
+                elif 'computeFault' in resp_body:
+                    message = resp_body['computeFault']['message']
+                elif 'error' in resp_body:  # Keystone errors
+                    message = resp_body['error']['message']
+                    raise exceptions.IdentityError(message)
+                elif 'message' in resp_body:
+                    message = resp_body['message']
 
             raise exceptions.ComputeFault(message)
 
         if resp.status >= 400:
-            resp_body = self._parse_resp(resp_body)
+            if parse_resp:
+                resp_body = self._parse_resp(resp_body)
             raise exceptions.RestClientException(str(resp.status))
 
-        return resp, resp_body
-
     def check_over_limit(self, resp_body, method, url,
                          headers, body, depth, wait):
         self.is_absolute_limit(resp_body['overLimit'])
diff --git a/tempest/config.py b/tempest/config.py
index ec48f67..c982dee 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -19,7 +19,6 @@
 import os
 import sys
 
-from tempest.common.utils import data_utils
 from tempest.common.utils.misc import singleton
 from tempest.openstack.common import cfg
 
@@ -237,6 +236,9 @@
     cfg.StrOpt('api_version',
                default='1',
                help="Version of the API"),
+    cfg.StrOpt('catalog_type',
+               default='image',
+               help='Catalog type of the Image service.')
 ]
 
 
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
index fca2d2d..577aa13 100644
--- a/tempest/exceptions.py
+++ b/tempest/exceptions.py
@@ -116,6 +116,10 @@
     message = "Got compute fault"
 
 
+class ImageFault(TempestException):
+    message = "Got image fault"
+
+
 class IdentityError(TempestException):
     message = "Got identity error"
 
diff --git a/tempest/services/boto/__init__.py b/tempest/services/boto/__init__.py
deleted file mode 100644
index f744d9d..0000000
--- a/tempest/services/boto/__init__.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# 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.
-
-from ConfigParser import DuplicateSectionError
-from contextlib import closing
-import re
-from types import MethodType
-
-import boto
-
-from tempest.exceptions import InvalidConfiguration
-from tempest.exceptions import NotFound
-
-
-class BotoClientBase(object):
-
-    ALLOWED_METHODS = set()
-
-    def __init__(self, config,
-                 username=None, password=None,
-                 auth_url=None, tenant_name=None,
-                 *args, **kwargs):
-
-        self.connection_timeout = str(config.boto.http_socket_timeout)
-        self.num_retries = str(config.boto.num_retries)
-        self.build_timeout = config.boto.build_timeout
-        self.ks_cred = {"username": username,
-                        "password": password,
-                        "auth_url": auth_url,
-                        "tenant_name": tenant_name}
-
-    def _keystone_aws_get(self):
-        import keystoneclient.v2_0.client
-
-        keystone = keystoneclient.v2_0.client.Client(**self.ks_cred)
-        ec2_cred_list = keystone.ec2.list(keystone.auth_user_id)
-        ec2_cred = None
-        for cred in ec2_cred_list:
-            if cred.tenant_id == keystone.auth_tenant_id:
-                ec2_cred = cred
-                break
-        else:
-            ec2_cred = keystone.ec2.create(keystone.auth_user_id,
-                                           keystone.auth_tenant_id)
-        if not all((ec2_cred, ec2_cred.access, ec2_cred.secret)):
-            raise NotFound("Unable to get access and secret keys")
-        return ec2_cred
-
-    def _config_boto_timeout(self, timeout, retries):
-        try:
-            boto.config.add_section("Boto")
-        except DuplicateSectionError:
-            pass
-        boto.config.set("Boto", "http_socket_timeout", timeout)
-        boto.config.set("Boto", "num_retries", retries)
-
-    def __getattr__(self, name):
-        """Automatically creates methods for the allowed methods set."""
-        if name in self.ALLOWED_METHODS:
-            def func(self, *args, **kwargs):
-                with closing(self.get_connection()) as conn:
-                    return getattr(conn, name)(*args, **kwargs)
-
-            func.__name__ = name
-            setattr(self, name, MethodType(func, self, self.__class__))
-            setattr(self.__class__, name,
-                    MethodType(func, None, self.__class__))
-            return getattr(self, name)
-        else:
-            raise AttributeError(name)
-
-    def get_connection(self):
-        self._config_boto_timeout(self.connection_timeout, self.num_retries)
-        if not all((self.connection_data["aws_access_key_id"],
-                   self.connection_data["aws_secret_access_key"])):
-            if all(self.ks_cred.itervalues()):
-                ec2_cred = self._keystone_aws_get()
-                self.connection_data["aws_access_key_id"] = \
-                    ec2_cred.access
-                self.connection_data["aws_secret_access_key"] = \
-                    ec2_cred.secret
-            else:
-                raise InvalidConfiguration(
-                                    "Unable to get access and secret keys")
-        return self.connect_method(**self.connection_data)
diff --git a/tempest/services/boto/clients.py b/tempest/services/botoclients.py
similarity index 63%
rename from tempest/services/boto/clients.py
rename to tempest/services/botoclients.py
index 228e826..143257a 100644
--- a/tempest/services/boto/clients.py
+++ b/tempest/services/botoclients.py
@@ -15,13 +15,90 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import ConfigParser
+import contextlib
+import re
+import types
 import urlparse
 
-import boto
-from boto.ec2.regioninfo import RegionInfo
-from boto.s3.connection import OrdinaryCallingFormat
+from tempest import exceptions
 
-from tempest.services.boto import BotoClientBase
+import boto
+import boto.ec2
+import boto.s3.connection
+
+
+class BotoClientBase(object):
+
+    ALLOWED_METHODS = set()
+
+    def __init__(self, config,
+                 username=None, password=None,
+                 auth_url=None, tenant_name=None,
+                 *args, **kwargs):
+
+        self.connection_timeout = str(config.boto.http_socket_timeout)
+        self.num_retries = str(config.boto.num_retries)
+        self.build_timeout = config.boto.build_timeout
+        self.ks_cred = {"username": username,
+                        "password": password,
+                        "auth_url": auth_url,
+                        "tenant_name": tenant_name}
+
+    def _keystone_aws_get(self):
+        import keystoneclient.v2_0.client
+
+        keystone = keystoneclient.v2_0.client.Client(**self.ks_cred)
+        ec2_cred_list = keystone.ec2.list(keystone.auth_user_id)
+        ec2_cred = None
+        for cred in ec2_cred_list:
+            if cred.tenant_id == keystone.auth_tenant_id:
+                ec2_cred = cred
+                break
+        else:
+            ec2_cred = keystone.ec2.create(keystone.auth_user_id,
+                                           keystone.auth_tenant_id)
+        if not all((ec2_cred, ec2_cred.access, ec2_cred.secret)):
+            raise exceptions.NotFound("Unable to get access and secret keys")
+        return ec2_cred
+
+    def _config_boto_timeout(self, timeout, retries):
+        try:
+            boto.config.add_section("Boto")
+        except ConfigParser.DuplicateSectionError:
+            pass
+        boto.config.set("Boto", "http_socket_timeout", timeout)
+        boto.config.set("Boto", "num_retries", retries)
+
+    def __getattr__(self, name):
+        """Automatically creates methods for the allowed methods set."""
+        if name in self.ALLOWED_METHODS:
+            def func(self, *args, **kwargs):
+                with contextlib.closing(self.get_connection()) as conn:
+                    return getattr(conn, name)(*args, **kwargs)
+
+            func.__name__ = name
+            setattr(self, name, types.MethodType(func, self, self.__class__))
+            setattr(self.__class__, name,
+                    types.MethodType(func, None, self.__class__))
+            return getattr(self, name)
+        else:
+            raise AttributeError(name)
+
+    def get_connection(self):
+        self._config_boto_timeout(self.connection_timeout, self.num_retries)
+        if not all((self.connection_data["aws_access_key_id"],
+                   self.connection_data["aws_secret_access_key"])):
+            if all(self.ks_cred.itervalues()):
+                ec2_cred = self._keystone_aws_get()
+                self.connection_data["aws_access_key_id"] = \
+                    ec2_cred.access
+                self.connection_data["aws_secret_access_key"] = \
+                    ec2_cred.secret
+            else:
+                raise exceptions.InvalidConfiguration(
+                                    "Unable to get access and secret keys")
+        return self.connect_method(**self.connection_data)
 
 
 class APIClientEC2(BotoClientBase):
@@ -35,8 +112,8 @@
         aws_secret = config.boto.aws_secret
         purl = urlparse.urlparse(config.boto.ec2_url)
 
-        region = RegionInfo(name=config.identity.region,
-                            endpoint=purl.hostname)
+        region = boto.ec2.regioninfo.RegionInfo(name=config.identity.region,
+                                                endpoint=purl.hostname)
         port = purl.port
         if port is None:
             if purl.scheme is not "https":
@@ -134,7 +211,8 @@
                                 "is_secure": purl.scheme == "https",
                                 "host": purl.hostname,
                                 "port": port,
-                                "calling_format": OrdinaryCallingFormat()}
+                                "calling_format": boto.s3.connection.
+                                OrdinaryCallingFormat()}
 
     ALLOWED_METHODS = set(('create_bucket', 'delete_bucket', 'generate_url',
                            'get_all_buckets', 'get_bucket', 'delete_key',
diff --git a/tempest/services/compute/admin/json/quotas_client.py b/tempest/services/compute/admin/json/quotas_client.py
index 0a4bd72..b886834 100644
--- a/tempest/services/compute/admin/json/quotas_client.py
+++ b/tempest/services/compute/admin/json/quotas_client.py
@@ -37,38 +37,38 @@
         """
         post_body = {}
 
-        if injected_file_content_bytes >= 0:
+        if injected_file_content_bytes is not None:
             post_body['injected_file_content_bytes'] = \
                 injected_file_content_bytes
 
-        if metadata_items >= 0:
+        if metadata_items is not None:
             post_body['metadata_items'] = metadata_items
 
-        if ram >= 0:
+        if ram is not None:
             post_body['ram'] = ram
 
-        if floating_ips >= 0:
+        if floating_ips is not None:
             post_body['floating_ips'] = floating_ips
 
-        if key_pairs >= 0:
+        if key_pairs is not None:
             post_body['key_pairs'] = key_pairs
 
-        if instances >= 0:
+        if instances is not None:
             post_body['instances'] = instances
 
-        if security_group_rules >= 0:
+        if security_group_rules is not None:
             post_body['security_group_rules'] = security_group_rules
 
-        if injected_files >= 0:
+        if injected_files is not None:
             post_body['injected_files'] = injected_files
 
-        if cores >= 0:
+        if cores is not None:
             post_body['cores'] = cores
 
-        if injected_file_path_bytes >= 0:
+        if injected_file_path_bytes is not None:
             post_body['injected_file_path_bytes'] = injected_file_path_bytes
 
-        if security_groups >= 0:
+        if security_groups is not None:
             post_body['security_groups'] = security_groups
 
         post_body = json.dumps({'quota_set': post_body})
diff --git a/tempest/services/compute/admin/xml/quotas_client.py b/tempest/services/compute/admin/xml/quotas_client.py
index d567a9c..f416334 100644
--- a/tempest/services/compute/admin/xml/quotas_client.py
+++ b/tempest/services/compute/admin/xml/quotas_client.py
@@ -15,11 +15,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import urllib
-
 from lxml import etree
 
-from tempest.common.rest_client import RestClientXML
 from tempest.services.compute.xml.common import Document
 from tempest.services.compute.xml.common import Element
 from tempest.services.compute.xml.common import xml_to_json
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 2116e1e..02cf970 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -403,7 +403,7 @@
 
         url = self.base_url + '/servers?all_tenants=1'
         resp = self.requests.get(url)
-        resp, body = self.post('servers', post_body, self.headers)
+        resp, body = self.get('servers', self.headers)
 
         body = json.loads(body)
         return resp, body['servers']
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index a5f6ec3..e4271d9 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -105,7 +105,7 @@
 
     def is_resource_deleted(self, id):
         try:
-            self.get_volume(id, wait=True)
+            self.get_volume(id)
         except exceptions.NotFound:
             return True
         return False
diff --git a/tempest/services/compute/xml/common.py b/tempest/services/compute/xml/common.py
index 9bb1d11..6469761 100644
--- a/tempest/services/compute/xml/common.py
+++ b/tempest/services/compute/xml/common.py
@@ -15,8 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from lxml import etree
-
 XMLNS_11 = "http://docs.openstack.org/compute/api/v1.1"
 
 
diff --git a/tempest/services/compute/xml/images_client.py b/tempest/services/compute/xml/images_client.py
index bde9e16..3b01efb 100644
--- a/tempest/services/compute/xml/images_client.py
+++ b/tempest/services/compute/xml/images_client.py
@@ -39,43 +39,43 @@
         self.build_timeout = self.config.compute.build_timeout
 
     def _parse_server(self, node):
-        json = xml_to_json(node)
-        return self._parse_links(node, json)
+        data = xml_to_json(node)
+        return self._parse_links(node, data)
 
     def _parse_image(self, node):
         """Parses detailed XML image information into dictionary."""
-        json = xml_to_json(node)
+        data = xml_to_json(node)
 
-        self._parse_links(node, json)
+        self._parse_links(node, data)
 
         # parse all metadata
-        if 'metadata' in json:
+        if 'metadata' in data:
             tag = node.find('{%s}metadata' % XMLNS_11)
-            json['metadata'] = dict((x.get('key'), x.text)
+            data['metadata'] = dict((x.get('key'), x.text)
                                     for x in tag.getchildren())
 
         # parse server information
-        if 'server' in json:
+        if 'server' in data:
             tag = node.find('{%s}server' % XMLNS_11)
-            json['server'] = self._parse_server(tag)
-        return json
+            data['server'] = self._parse_server(tag)
+        return data
 
-    def _parse_links(self, node, json):
+    def _parse_links(self, node, data):
         """Append multiple links under a list."""
         # look for links
-        if 'link' in json:
+        if 'link' in data:
             # remove single link element
-            del json['link']
-            json['links'] = [xml_to_json(x) for x in
+            del data['link']
+            data['links'] = [xml_to_json(x) for x in
                              node.findall('{http://www.w3.org/2005/Atom}link')]
-        return json
+        return data
 
     def _parse_images(self, xml):
-        json = {'images': []}
+        data = {'images': []}
         images = xml.getchildren()
         for image in images:
-            json['images'].append(self._parse_image(image))
-        return json
+            data['images'].append(self._parse_image(image))
+        return data
 
     def create_image(self, server_id, name, meta=None):
         """Creates an image of the original server."""
@@ -160,9 +160,17 @@
         body = xml_to_json(etree.fromstring(body))
         return resp, body['metadata']
 
+    def _metadata_body(image_id, meta):
+        post_body = Document('metadata')
+        for k, v in meta:
+            text = Text(v)
+            metadata = Element('meta', text, key=k)
+            post_body.append(metadata)
+        return post_body
+
     def set_image_metadata(self, image_id, meta):
         """Sets the metadata for an image."""
-        post_body = json.dumps({'metadata': meta})
+        post_body = self._metadata_body(image_id, meta)
         resp, body = self.put('images/%s/metadata' % str(image_id),
                               post_body, self.headers)
         body = xml_to_json(etree.fromstring(body))
@@ -170,13 +178,7 @@
 
     def update_image_metadata(self, image_id, meta):
         """Updates the metadata for an image."""
-        post_body = Element('metadata', meta)
-        for k, v in meta:
-            metadata = Element('meta', key=k)
-            text = Text(v)
-            metadata.append(text)
-            post_body.append(metadata)
-
+        post_body = self._metadata_body(image_id, meta)
         resp, body = self.post('images/%s/metadata' % str(image_id),
                                post_body, self.headers)
         body = xml_to_json(etree.fromstring(body))
@@ -191,7 +193,15 @@
 
     def set_image_metadata_item(self, image_id, key, meta):
         """Sets the value for a specific image metadata key."""
-        post_body = json.dumps({'meta': meta})
+        post_body = Document('meta', Text(meta), key=key)
+        resp, body = self.post('images/%s/metadata/%s' % (str(image_id), key),
+                               post_body, self.headers)
+        body = xml_to_json(etree.fromstring(body))
+        return resp, body['meta']
+
+    def update_image_metadata_item(self, image_id, key, meta):
+        """Sets the value for a specific image metadata key."""
+        post_body = Document('meta', Text(meta), key=key)
         resp, body = self.put('images/%s/metadata/%s' % (str(image_id), key),
                               post_body, self.headers)
         body = xml_to_json(etree.fromstring(body))
diff --git a/tempest/services/compute/xml/limits_client.py b/tempest/services/compute/xml/limits_client.py
index 473952b..d233bba 100644
--- a/tempest/services/compute/xml/limits_client.py
+++ b/tempest/services/compute/xml/limits_client.py
@@ -15,7 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from lxml import etree
 from lxml import objectify
 
 from tempest.common.rest_client import RestClientXML
diff --git a/tempest/services/compute/xml/quotas_client.py b/tempest/services/compute/xml/quotas_client.py
index 8978214..faa0aab 100644
--- a/tempest/services/compute/xml/quotas_client.py
+++ b/tempest/services/compute/xml/quotas_client.py
@@ -15,15 +15,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import urllib
-
 from lxml import etree
 
 from tempest.common.rest_client import RestClientXML
-from tempest.services.compute.xml.common import Document
-from tempest.services.compute.xml.common import Element
 from tempest.services.compute.xml.common import xml_to_json
-from tempest.services.compute.xml.common import XMLNS_11
 
 
 class QuotasClientXML(RestClientXML):
diff --git a/tempest/services/compute/xml/volumes_extensions_client.py b/tempest/services/compute/xml/volumes_extensions_client.py
index 60ef398..69b9bac 100644
--- a/tempest/services/compute/xml/volumes_extensions_client.py
+++ b/tempest/services/compute/xml/volumes_extensions_client.py
@@ -141,7 +141,7 @@
 
     def is_resource_deleted(self, id):
         try:
-            self.get_volume(id, wait=True)
+            self.get_volume(id)
         except exceptions.NotFound:
             return True
         return False
diff --git a/tempest/services/identity/json/identity_client.py b/tempest/services/identity/json/identity_client.py
index 403a3ac..68e7d4b 100644
--- a/tempest/services/identity/json/identity_client.py
+++ b/tempest/services/identity/json/identity_client.py
@@ -244,8 +244,10 @@
         if headers is None:
             headers = {}
 
+        self._log_request(method, url, headers, body)
         resp, resp_body = self.http_obj.request(url, method,
                                                 headers=headers, body=body)
+        self._log_response(resp, resp_body)
 
         if resp.status in (401, 403):
             resp_body = json.loads(resp_body)
diff --git a/tempest/services/identity/xml/identity_client.py b/tempest/services/identity/xml/identity_client.py
index f79c3d5..2431282 100644
--- a/tempest/services/identity/xml/identity_client.py
+++ b/tempest/services/identity/xml/identity_client.py
@@ -17,16 +17,13 @@
 
 import httplib2
 import json
-import logging
 
 from lxml import etree
 
-from tempest.common.rest_client import RestClient
 from tempest.common.rest_client import RestClientXML
 from tempest import exceptions
 from tempest.services.compute.xml.common import Document
 from tempest.services.compute.xml.common import Element
-from tempest.services.compute.xml.common import Text
 from tempest.services.compute.xml.common import xml_to_json
 
 
@@ -48,8 +45,8 @@
         return array
 
     def _parse_body(self, body):
-        json = xml_to_json(body)
-        return json
+        data = xml_to_json(body)
+        return data
 
     def has_admin_extensions(self):
         """
@@ -275,9 +272,10 @@
         self.http_obj = httplib2.Http(disable_ssl_certificate_validation=dscv)
         if headers is None:
             headers = {}
-
+        self._log_request(method, url, headers, body)
         resp, resp_body = self.http_obj.request(url, method,
                                                 headers=headers, body=body)
+        self._log_response(resp, resp_body)
 
         if resp.status in (401, 403):
             resp_body = json.loads(resp_body)
diff --git a/tempest/services/image/json/__init__.py b/tempest/services/image/json/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/services/image/json/__init__.py
diff --git a/tempest/services/image/json/image_client.py b/tempest/services/image/json/image_client.py
new file mode 100644
index 0000000..e9276aa
--- /dev/null
+++ b/tempest/services/image/json/image_client.py
@@ -0,0 +1,200 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+#
+# Copyright 2013 IBM
+# 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 copy
+import errno
+import json
+import os
+import time
+import urllib
+
+from tempest.common import glance_http
+from tempest.common.rest_client import RestClient
+from tempest import exceptions
+from tempest import manager
+
+
+class ImageClientJSON(RestClient):
+
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(ImageClientJSON, self).__init__(config, username, password,
+                                              auth_url, tenant_name)
+        self.service = self.config.images.catalog_type
+        self.http = self._get_http()
+
+    def _image_meta_from_headers(self, headers):
+        meta = {'properties': {}}
+        for key, value in headers.iteritems():
+            if key.startswith('x-image-meta-property-'):
+                _key = key[22:]
+                meta['properties'][_key] = value
+            elif key.startswith('x-image-meta-'):
+                _key = key[13:]
+                meta[_key] = value
+
+        for key in ['is_public', 'protected', 'deleted']:
+            if key in meta:
+                meta[key] = meta[key].strip().lower() in ('t', 'true', 'yes',
+                                                          '1')
+        for key in ['size', 'min_ram', 'min_disk']:
+            if key in meta:
+                try:
+                    meta[key] = int(meta[key])
+                except ValueError:
+                    pass
+        return meta
+
+    def _image_meta_to_headers(self, fields):
+        headers = {}
+        fields_copy = copy.deepcopy(fields)
+        for key, value in fields_copy.pop('properties', {}).iteritems():
+            headers['x-image-meta-property-%s' % key] = str(value)
+        for key, value in fields_copy.iteritems():
+            headers['x-image-meta-%s' % key] = str(value)
+        return headers
+
+    def _get_file_size(self, obj):
+        """Analyze file-like object and attempt to determine its size.
+
+        :param obj: file-like object, typically redirected from stdin.
+        :retval The file's size or None if it cannot be determined.
+        """
+        # For large images, we need to supply the size of the
+        # image file. See LP Bugs #827660 and #845788.
+        if hasattr(obj, 'seek') and hasattr(obj, 'tell'):
+            try:
+                obj.seek(0, os.SEEK_END)
+                obj_size = obj.tell()
+                obj.seek(0)
+                return obj_size
+            except IOError, e:
+                if e.errno == errno.ESPIPE:
+                    # Illegal seek. This means the user is trying
+                    # to pipe image data to the client, e.g.
+                    # echo testdata | bin/glance add blah..., or
+                    # that stdin is empty, or that a file-like
+                    # object which doesn't support 'seek/tell' has
+                    # been supplied.
+                    return None
+                else:
+                    raise
+        else:
+            # Cannot determine size of input image
+            return None
+
+    def _get_http(self):
+        temp_manager = manager.DefaultClientManager()
+        keystone = temp_manager._get_identity_client()
+        token = keystone.auth_token
+        endpoint = keystone.service_catalog.url_for(service_type='image',
+                                                    endpoint_type='publicURL')
+        dscv = self.config.identity.disable_ssl_certificate_validation
+        return glance_http.HTTPClient(endpoint=endpoint, token=token,
+                                      insecure=dscv)
+
+    def _create_with_data(self, headers, data):
+        resp, body_iter = self.http.raw_request('POST', '/v1/images',
+                                                headers=headers, body=data)
+        self._error_checker('POST', '/v1/images', headers, data, resp,
+                            body_iter)
+        body = json.loads(''.join([c for c in body_iter]))
+        return resp, body['image']
+
+    def _update_with_data(self, image_id, headers, data):
+        url = '/v1/images/%s' % image_id
+        resp, body_iter = self.http.raw_request('PUT', url, headers=headers,
+                                                body=data)
+        self._error_checker('PUT', url, headers, data,
+                            resp, body_iter)
+        body = json.loads(''.join([c for c in body_iter]))
+        return resp, body['image']
+
+    def create_image(self, name, container_format, disk_format, is_public=True,
+                     location=None, properties=None, data=None):
+        params = {
+            "name": name,
+            "container_format": container_format,
+            "disk_format": disk_format,
+            "is_public": is_public,
+        }
+        headers = {}
+
+        if location is not None:
+            params['location'] = location
+
+        if properties is not None:
+            params['properties'] = properties
+
+        headers.update(self._image_meta_to_headers(params))
+
+        if data is not None:
+            return self._create_with_data(headers, data)
+
+        resp, body = self.post('v1/images', data, headers)
+        body = json.loads(body)
+        return resp, body['image']
+
+    def update_image(self, image_id, name=None, container_format=None,
+                     data=None):
+        params = {}
+        headers = {}
+        if name is not None:
+            params['name'] = name
+
+        if container_format is not None:
+            params['container_format'] = container_format
+
+        headers.update(self._image_meta_to_headers(params))
+
+        if data is not None:
+            return self._update_with_data(image_id, headers, data)
+
+        url = 'v1/images/%s' % image_id
+        resp, body = self.put(url, data, headers)
+        body = json.loads(body)
+        return resp, body['image']
+
+    def delete_image(self, image_id):
+        url = 'v1/images/%s' % image_id
+        try:
+            self.delete(url)
+        except exceptions.Unauthorized:
+            url = '/' + url
+            self.http.raw_request('DELETE', url)
+
+    def image_list(self, params=None):
+        url = 'v1/images'
+
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+
+        resp, body = self.get(url)
+        body = json.loads(body)
+        return resp, body['images']
+
+    def get_image(self, image_id, wait=None):
+        url = 'v1/images/%s' % image_id
+        resp, __ = self.get(url, wait=wait)
+        body = self._image_meta_from_headers(resp)
+        return resp, body
+
+    def is_resource_deleted(self, id):
+        try:
+            self.get_image(id, wait=True)
+        except exceptions.NotFound:
+            return True
+        return False
diff --git a/tempest/services/image/service.py b/tempest/services/image/service.py
deleted file mode 100644
index 66ba219..0000000
--- a/tempest/services/image/service.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# 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.
-
-"""
-Image Service class, which acts as a descriptor for the OpenStack Images
-service running in the test environment.
-"""
-
-from tempest.services import Service as BaseService
-
-
-class Service(BaseService):
-
-    def __init__(self, config):
-        """
-        Initializes the service.
-
-        :param config: `tempest.config.Config` object
-        """
-        self.config = config
-
-        # Determine the Images API version
-        self.api_version = int(config.images.api_version)
-
-        # We load the client class specific to the API version...
-        if self.api_version == 1:
-            import glanceclient
-            import keystoneclient.v2_0.client
-
-            dscv = self.config.identity.disable_ssl_certificate_validation
-            auth_url = self.config.identity.uri
-            keystone = keystoneclient.v2_0.client.Client(
-                    username=config.identity.username,
-                    password=config.identity.password,
-                    tenant_name=config.identity.tenant_name,
-                    auth_url=auth_url,
-                    insecure=dscv)
-            token = keystone.auth_token
-            endpoint = keystone.service_catalog.url_for(
-                    service_type='image',
-                    endpoint_type='publicURL')
-
-            self._client = glanceclient.Client('1',
-                                               endpoint=endpoint,
-                                               token=token,
-                                               insecure=dscv)
-        else:
-            raise NotImplementedError
-
-    def get_client(self):
-        """
-        Returns a client object that may be used to query
-        the service API.
-        """
-        assert self._client
-        return self._client
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 187e80d..ac1859a 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -18,11 +18,10 @@
 from hashlib import sha1
 import hmac
 import httplib2
-import json
-import re
+from urlparse import urlparse
+
 from tempest.common.rest_client import RestClient
 from tempest import exceptions
-from urlparse import urlparse
 
 
 class ObjectClient(RestClient):
@@ -41,7 +40,7 @@
 
     def update_object(self, container, object_name, data):
         """Upload data to replace current storage object."""
-        return create_object(container, object_name, data)
+        return self.create_object(container, object_name, data)
 
     def delete_object(self, container, object_name):
         """Delete storage object."""
diff --git a/tempest/services/volume/json/volumes_client.py b/tempest/services/volume/json/volumes_client.py
index 75e1a8b..ff1556f 100644
--- a/tempest/services/volume/json/volumes_client.py
+++ b/tempest/services/volume/json/volumes_client.py
@@ -125,7 +125,7 @@
 
     def is_resource_deleted(self, id):
         try:
-            self.get_volume(id, wait=True)
+            self.get_volume(id)
         except exceptions.NotFound:
             return True
         return False
diff --git a/tempest/services/volume/xml/snapshots_client.py b/tempest/services/volume/xml/snapshots_client.py
index c89f66e..dc70cb7 100644
--- a/tempest/services/volume/xml/snapshots_client.py
+++ b/tempest/services/volume/xml/snapshots_client.py
@@ -85,10 +85,6 @@
         body = xml_to_json(etree.fromstring(body))
         return resp, body
 
-    def _get_snapshot_status(self, snapshot_id):
-        resp, body = self.get_snapshot(snapshot_id)
-        return body['status']
-
     #NOTE(afazekas): just for the wait function
     def _get_snapshot_status(self, snapshot_id):
         resp, body = self.get_snapshot(snapshot_id)
diff --git a/tempest/services/volume/xml/volumes_client.py b/tempest/services/volume/xml/volumes_client.py
index 862ffae..5041869 100644
--- a/tempest/services/volume/xml/volumes_client.py
+++ b/tempest/services/volume/xml/volumes_client.py
@@ -151,7 +151,7 @@
 
     def is_resource_deleted(self, id):
         try:
-            self.get_volume(id, wait=True)
+            self.get_volume(id)
         except exceptions.NotFound:
             return True
         return False
diff --git a/tempest/testboto.py b/tempest/testboto.py
index 1b768ef..14844b3 100644
--- a/tempest/testboto.py
+++ b/tempest/testboto.py
@@ -18,13 +18,11 @@
 from contextlib import closing
 import logging
 import re
-import time
 
 import boto
 from boto.exception import BotoServerError
 from boto.exception import EC2ResponseError
 from boto.s3.bucket import Bucket
-from boto.s3.key import Key
 import testresources
 import testtools
 
@@ -33,7 +31,6 @@
 from tempest.tests.boto.utils.wait import re_search_wait
 from tempest.tests.boto.utils.wait import state_wait
 from tempest.tests.boto.utils.wait import wait_exception
-from tempest.tests.boto.utils.wait import wait_no_exception
 
 LOG = logging.getLogger(__name__)
 
@@ -379,7 +376,7 @@
         snaps = volume.snapshots()
         if len(snaps):
             LOG.critical("%s Volume has %s snapshot(s)", volume.id,
-                         map(snps.id, snaps))
+                         map(snaps.id, snaps))
 
         #Note(afazekas): detaching/attching not valid EC2 status
         def _volume_state():
diff --git a/tempest/tests/boto/test_ec2_instance_run.py b/tempest/tests/boto/test_ec2_instance_run.py
index 8358ef9..403ec4c 100644
--- a/tempest/tests/boto/test_ec2_instance_run.py
+++ b/tempest/tests/boto/test_ec2_instance_run.py
@@ -15,17 +15,14 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from contextlib import closing
 import logging
 
 from boto.exception import EC2ResponseError
-from boto.s3.key import Key
 import testtools
 
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 from tempest.common.utils.linux.remote_client import RemoteClient
-from tempest.exceptions import EC2RegisterImageException
 from tempest.test import attr
 from tempest.testboto import BotoTestCase
 import tempest.tests.boto
@@ -88,8 +85,8 @@
             state = state_wait(_state, "available")
             if state != "available":
                 for _image in cls.images.itervalues():
-                    ec2_client.deregister_image(_image["image_id"])
-                raise RegisterImageException(image_id=image["image_id"])
+                    cls.ec2_client.deregister_image(_image["image_id"])
+                raise EC2RegisterImageException(image_id=image["image_id"])
 
     @attr(type='smoke')
     def test_run_stop_terminate_instance(self):
diff --git a/tempest/tests/boto/test_ec2_network.py b/tempest/tests/boto/test_ec2_network.py
index ef476a2..ef307a1 100644
--- a/tempest/tests/boto/test_ec2_network.py
+++ b/tempest/tests/boto/test_ec2_network.py
@@ -47,4 +47,4 @@
                              address.disassociate)
         self.client.release_address(public_ip)
         self.cancelResourceCleanUp(rcuk)
-        assertAddressReleasedWait(address)
+        self.assertAddressReleasedWait(address)
diff --git a/tempest/tests/boto/test_ec2_security_groups.py b/tempest/tests/boto/test_ec2_security_groups.py
index 5981408..dd46a91 100644
--- a/tempest/tests/boto/test_ec2_security_groups.py
+++ b/tempest/tests/boto/test_ec2_security_groups.py
@@ -15,8 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 from tempest.test import attr
diff --git a/tempest/tests/boto/test_ec2_volumes.py b/tempest/tests/boto/test_ec2_volumes.py
index 7d3c5ab..aa2325f 100644
--- a/tempest/tests/boto/test_ec2_volumes.py
+++ b/tempest/tests/boto/test_ec2_volumes.py
@@ -16,9 +16,6 @@
 #    under the License.
 
 import logging
-import time
-
-import testtools
 
 from tempest import clients
 from tempest.test import attr
diff --git a/tempest/tests/boto/test_s3_ec2_images.py b/tempest/tests/boto/test_s3_ec2_images.py
index da248e1..8913395 100644
--- a/tempest/tests/boto/test_s3_ec2_images.py
+++ b/tempest/tests/boto/test_s3_ec2_images.py
@@ -15,10 +15,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from contextlib import closing
 import os
 
-from boto.s3.key import Key
 import testtools
 
 from tempest import clients
diff --git a/tempest/tests/boto/test_s3_objects.py b/tempest/tests/boto/test_s3_objects.py
index e7bc4b1..8334b07 100644
--- a/tempest/tests/boto/test_s3_objects.py
+++ b/tempest/tests/boto/test_s3_objects.py
@@ -24,7 +24,6 @@
 from tempest.common.utils.data_utils import rand_name
 from tempest.test import attr
 from tempest.testboto import BotoTestCase
-from tempest.tests import boto
 
 
 @attr("S3")
diff --git a/tempest/tests/compute/admin/test_flavors.py b/tempest/tests/compute/admin/test_flavors.py
index fe977c1..9ad8745 100644
--- a/tempest/tests/compute/admin/test_flavors.py
+++ b/tempest/tests/compute/admin/test_flavors.py
@@ -15,8 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest.common.utils.data_utils import rand_int_id
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
diff --git a/tempest/tests/compute/admin/test_quotas.py b/tempest/tests/compute/admin/test_quotas.py
index 0f46d62..a4b106b 100644
--- a/tempest/tests/compute/admin/test_quotas.py
+++ b/tempest/tests/compute/admin/test_quotas.py
@@ -20,7 +20,6 @@
     import quotas_client as adm_quotas_json
 from tempest.services.compute.admin.xml import quotas_client as adm_quotas_xml
 from tempest.test import attr
-from tempest.tests import compute
 from tempest.tests.compute import base
 
 
diff --git a/tempest/tests/compute/base.py b/tempest/tests/compute/base.py
index f2af1fc..594535f 100644
--- a/tempest/tests/compute/base.py
+++ b/tempest/tests/compute/base.py
@@ -154,7 +154,7 @@
     @classmethod
     def clear_isolated_creds(cls):
         if not cls.isolated_creds:
-            pass
+            return
         admin_client = cls._get_identity_admin_client()
 
         for user, tenant in cls.isolated_creds:
diff --git a/tempest/tests/compute/floating_ips/test_floating_ips_actions.py b/tempest/tests/compute/floating_ips/test_floating_ips_actions.py
index 9f0cda0..165cf79 100644
--- a/tempest/tests/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/tests/compute/floating_ips/test_floating_ips_actions.py
@@ -15,9 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
-from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.test import attr
diff --git a/tempest/tests/compute/floating_ips/test_list_floating_ips.py b/tempest/tests/compute/floating_ips/test_list_floating_ips.py
index e534e3c..42befd0 100644
--- a/tempest/tests/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/tests/compute/floating_ips/test_list_floating_ips.py
@@ -15,8 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.test import attr
diff --git a/tempest/tests/compute/images/test_images.py b/tempest/tests/compute/images/test_images.py
index 446ef50..edc58e7 100644
--- a/tempest/tests/compute/images/test_images.py
+++ b/tempest/tests/compute/images/test_images.py
@@ -20,7 +20,6 @@
 from tempest import clients
 from tempest.common.utils.data_utils import parse_image_id
 from tempest.common.utils.data_utils import rand_name
-import tempest.config
 from tempest import exceptions
 from tempest.test import attr
 from tempest.tests import compute
diff --git a/tempest/tests/compute/images/test_images_oneserver.py b/tempest/tests/compute/images/test_images_oneserver.py
index 5cc921b..08966fd 100644
--- a/tempest/tests/compute/images/test_images_oneserver.py
+++ b/tempest/tests/compute/images/test_images_oneserver.py
@@ -20,7 +20,6 @@
 from tempest import clients
 from tempest.common.utils.data_utils import parse_image_id
 from tempest.common.utils.data_utils import rand_name
-import tempest.config
 from tempest import exceptions
 from tempest.test import attr
 from tempest.tests import compute
diff --git a/tempest/tests/compute/images/test_list_images.py b/tempest/tests/compute/images/test_list_images.py
index b9b57ee..0f661b7 100644
--- a/tempest/tests/compute/images/test_list_images.py
+++ b/tempest/tests/compute/images/test_list_images.py
@@ -15,9 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.common.utils.data_utils import parse_image_id
-from tempest.common.utils.data_utils import rand_name
-from tempest import exceptions
 from tempest.test import attr
 from tempest.tests.compute.base import BaseComputeTest
 
diff --git a/tempest/tests/compute/servers/test_console_output.py b/tempest/tests/compute/servers/test_console_output.py
index 78639f8..bdf449d 100644
--- a/tempest/tests/compute/servers/test_console_output.py
+++ b/tempest/tests/compute/servers/test_console_output.py
@@ -28,7 +28,6 @@
     @classmethod
     def setUpClass(self, cls):
         cls.name = rand_name('server')
-        cls.client = cls.servers_client
         resp, server = cls.servers_client.create_server(cls.name,
                                                         cls.image_ref,
                                                         cls.flavor_ref)
@@ -45,7 +44,8 @@
         # Positive test:Should be able to GET the console output
         # for a given server_id and number of lines
         def get_output():
-            resp, output = self.client.get_console_output(self.server_id, 10)
+            resp, output = self.servers_client.get_console_output(
+                self.server_id, 10)
             self.assertEqual(200, resp.status)
             self.assertNotEqual(output, None)
             lines = len(output.split('\n'))
@@ -57,7 +57,8 @@
         # Negative test: Should not be able to get the console output
         # for an invalid server_id
         try:
-            resp, output = self.client.get_console_output('!@#$%^&*()', 10)
+            resp, output = self.servers_client.get_console_output(
+                '!@#$%^&*()', 10)
         except exceptions.NotFound:
             pass
 
@@ -72,8 +73,8 @@
                                                        'REBOOT')
             resp, server = self.servers_client.get_server(self.server_id)
             if (server['status'] == 'REBOOT'):
-                resp, output = self.client.get_console_output(self.server_id,
-                                                              10)
+                resp, output = self.servers_client.get_console_output(
+                    self.server_id, 10)
                 self.assertEqual(200, resp.status)
                 self.assertNotEqual(output, None)
                 lines = len(output.split('\n'))
diff --git a/tempest/tests/compute/servers/test_disk_config.py b/tempest/tests/compute/servers/test_disk_config.py
index 3987e69..57b95f2 100644
--- a/tempest/tests/compute/servers/test_disk_config.py
+++ b/tempest/tests/compute/servers/test_disk_config.py
@@ -18,7 +18,6 @@
 import testtools
 
 from tempest.common.utils.data_utils import rand_name
-from tempest import exceptions
 from tempest.test import attr
 from tempest.tests import compute
 from tempest.tests.compute.base import BaseComputeTest
diff --git a/tempest/tests/compute/servers/test_list_server_filters.py b/tempest/tests/compute/servers/test_list_server_filters.py
index e07a905..9b061b5 100644
--- a/tempest/tests/compute/servers/test_list_server_filters.py
+++ b/tempest/tests/compute/servers/test_list_server_filters.py
@@ -16,8 +16,6 @@
 #    under the License.
 
 
-import testtools
-
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.test import attr
diff --git a/tempest/tests/compute/servers/test_list_servers_negative.py b/tempest/tests/compute/servers/test_list_servers_negative.py
index eb4ea02..f93bebf 100644
--- a/tempest/tests/compute/servers/test_list_servers_negative.py
+++ b/tempest/tests/compute/servers/test_list_servers_negative.py
@@ -15,13 +15,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import re
-import sys
-
-import testtools
 
 from tempest import clients
-from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.tests import compute
 from tempest.tests.compute.base import BaseComputeTest
diff --git a/tempest/tests/compute/servers/test_server_actions.py b/tempest/tests/compute/servers/test_server_actions.py
index 693b0bf..c30538f 100644
--- a/tempest/tests/compute/servers/test_server_actions.py
+++ b/tempest/tests/compute/servers/test_server_actions.py
@@ -122,13 +122,24 @@
             linux_client = RemoteClient(server, self.ssh_user, password)
             self.assertTrue(linux_client.can_authenticate())
 
+    def _detect_server_image_flavor(self, server_id):
+        # Detects the current server image flavor ref.
+        resp, server = self.client.get_server(self.server_id)
+        current_flavor = server['flavor']['id']
+        new_flavor_ref = self.flavor_ref_alt \
+            if int(current_flavor) == self.flavor_ref else self.flavor_ref
+        return int(current_flavor), int(new_flavor_ref)
+
     @attr(type='smoke')
     @testtools.skipIf(not resize_available, 'Resize not available.')
     def test_resize_server_confirm(self):
         # The server's RAM and disk space should be modified to that of
         # the provided flavor
 
-        resp, server = self.client.resize(self.server_id, self.flavor_ref_alt)
+        previous_flavor_ref, new_flavor_ref = \
+            self._detect_server_image_flavor(self.server_id)
+
+        resp, server = self.client.resize(self.server_id, new_flavor_ref)
         self.assertEqual(202, resp.status)
         self.client.wait_for_server_status(self.server_id, 'VERIFY_RESIZE')
 
@@ -136,7 +147,7 @@
         self.client.wait_for_server_status(self.server_id, 'ACTIVE')
 
         resp, server = self.client.get_server(self.server_id)
-        self.assertEqual(self.flavor_ref_alt, int(server['flavor']['id']))
+        self.assertEqual(new_flavor_ref, int(server['flavor']['id']))
 
     @attr(type='positive')
     @testtools.skipIf(not resize_available, 'Resize not available.')
@@ -144,7 +155,10 @@
         # The server's RAM and disk space should return to its original
         # values after a resize is reverted
 
-        resp, server = self.client.resize(self.server_id, self.flavor_ref_alt)
+        previous_flavor_ref, new_flavor_ref = \
+            self._detect_server_image_flavor(self.server_id)
+
+        resp, server = self.client.resize(self.server_id, new_flavor_ref)
         self.assertEqual(202, resp.status)
         self.client.wait_for_server_status(self.server_id, 'VERIFY_RESIZE')
 
@@ -155,7 +169,7 @@
         resp, server = self.client.get_server(self.server_id)
         start = int(time.time())
 
-        while server['flavor']['id'] != self.flavor_ref:
+        while int(server['flavor']['id']) != previous_flavor_ref:
             time.sleep(self.build_interval)
             resp, server = self.client.get_server(self.server_id)
 
diff --git a/tempest/tests/compute/servers/test_server_metadata.py b/tempest/tests/compute/servers/test_server_metadata.py
index a214d15..ef1b956 100644
--- a/tempest/tests/compute/servers/test_server_metadata.py
+++ b/tempest/tests/compute/servers/test_server_metadata.py
@@ -197,7 +197,6 @@
     def test_delete_nonexistant_server_metadata_item(self):
         # Negative test: Should not be able to delete metadata item from a
         # nonexistant server
-        meta = {'d': 'delvalue'}
 
         #Delete the metadata item
         try:
diff --git a/tempest/tests/compute/servers/test_servers_negative.py b/tempest/tests/compute/servers/test_servers_negative.py
index 55d9581..9b528f6 100644
--- a/tempest/tests/compute/servers/test_servers_negative.py
+++ b/tempest/tests/compute/servers/test_servers_negative.py
@@ -17,8 +17,6 @@
 
 import sys
 
-import testtools
-
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
@@ -275,3 +273,17 @@
 
         self.assertRaises(exceptions.NotFound, self.client.delete_server,
                           sys.maxint + 1)
+
+    @attr(type='negative')
+    def test_create_with_nonexistent_security_group(self):
+        # Create a server with a nonexistent security group
+        try:
+            security_groups = [{'name': 'does_not_exist'}]
+            self.create_server_with_extras('fail',
+                                           self.image_ref,
+                                           self.flavor_ref,
+                                           security_groups=security_groups)
+        except exceptions.BadRequest:
+            pass
+        else:
+            self.fail('Server was created with nonexistent security group')
diff --git a/tempest/tests/compute/test_authorization.py b/tempest/tests/compute/test_authorization.py
index 8f4ad50..d826d40 100644
--- a/tempest/tests/compute/test_authorization.py
+++ b/tempest/tests/compute/test_authorization.py
@@ -243,7 +243,6 @@
             # Reset the base_url...
             self.alt_security_client.base_url = self.saved_base_url
             if resp['status'] is not None:
-                resp, _ = \
                 self.alt_security_client.delete_security_group(body['id'])
                 self.fail("Create Security Group request should not happen if"
                           "the tenant id does not match the current user")
@@ -283,7 +282,6 @@
             # Reset the base_url...
             self.alt_security_client.base_url = self.saved_base_url
             if resp['status'] is not None:
-                resp, _ = \
                 self.alt_security_client.delete_security_group_rule(
                                         body['id'])
                 self.fail("Create security group rule request should not "
diff --git a/tempest/tests/compute/test_live_block_migration.py b/tempest/tests/compute/test_live_block_migration.py
index d22e6b5..6449ddc 100644
--- a/tempest/tests/compute/test_live_block_migration.py
+++ b/tempest/tests/compute/test_live_block_migration.py
@@ -20,7 +20,6 @@
 
 import testtools
 
-from tempest.common.utils.linux.remote_client import RemoteClient
 from tempest import config
 from tempest import exceptions
 from tempest.services.compute.json.hosts_client import HostsClientJSON
@@ -124,8 +123,8 @@
         server_id = self._get_an_active_server()
         target_host = self._get_non_existing_host_name()
 
-        with self.assertRaises(exceptions.BadRequest) as cm:
-            self._migrate_server_to(server_id, target_host)
+        self.assertRaises(exceptions.BadRequest, self._migrate_server_to,
+                          server_id, target_host)
         self.assertEquals('ACTIVE', self._get_server_status(server_id))
 
     @classmethod
diff --git a/tempest/tests/compute/volumes/test_attach_volume.py b/tempest/tests/compute/volumes/test_attach_volume.py
index edf3179..1aed833 100644
--- a/tempest/tests/compute/volumes/test_attach_volume.py
+++ b/tempest/tests/compute/volumes/test_attach_volume.py
@@ -17,7 +17,6 @@
 
 import testtools
 
-from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 from tempest.common.utils.linux.remote_client import RemoteClient
 import tempest.config
diff --git a/tempest/tests/identity/admin/test_roles.py b/tempest/tests/identity/admin/test_roles.py
index 2779b51..3194e7d 100644
--- a/tempest/tests/identity/admin/test_roles.py
+++ b/tempest/tests/identity/admin/test_roles.py
@@ -15,8 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.tests.identity import base
diff --git a/tempest/tests/identity/admin/test_services.py b/tempest/tests/identity/admin/test_services.py
index 0246f8c..16b9fd8 100644
--- a/tempest/tests/identity/admin/test_services.py
+++ b/tempest/tests/identity/admin/test_services.py
@@ -18,7 +18,6 @@
 
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
-from tempest.test import attr
 from tempest.tests.identity import base
 
 
diff --git a/tempest/tests/identity/admin/test_tenants.py b/tempest/tests/identity/admin/test_tenants.py
index 9321b07..594afe8 100644
--- a/tempest/tests/identity/admin/test_tenants.py
+++ b/tempest/tests/identity/admin/test_tenants.py
@@ -15,8 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import testtools
-
 from tempest.common.utils.data_utils import rand_name
 from tempest import exceptions
 from tempest.test import attr
diff --git a/tempest/tests/image/test_images.py b/tempest/tests/image/test_images.py
index b8bc1c5..511f8b0 100644
--- a/tempest/tests/image/test_images.py
+++ b/tempest/tests/image/test_images.py
@@ -23,14 +23,8 @@
 from tempest.test import attr
 
 
-GLANCE_INSTALLED = False
-try:
-    import glanceclient
-    GLANCE_INSTALLED = True
-except ImportError:
-    pass
-
 from tempest import clients
+from tempest import exceptions
 
 
 class CreateRegisterImagesTest(testtools.testcase.WithAttributes,
@@ -42,91 +36,76 @@
 
     @classmethod
     def setUpClass(cls):
-        if not GLANCE_INSTALLED:
-            raise cls.skipException('Glance not installed')
-        cls.os = clients.ServiceManager()
-        cls.client = cls.os.images.get_client()
+        cls.os = clients.Manager()
+        cls.client = cls.os.image_client
         cls.created_images = []
 
     @classmethod
     def tearDownClass(cls):
         for image_id in cls.created_images:
-            cls.client.images.delete(image_id)
+            cls.client.delete(image_id)
 
-    @attr(type='image')
-    def test_register_with_invalid_data(self):
+    @attr(type='negative')
+    def test_register_with_invalid_container_format(self):
         # Negative tests for invalid data supplied to POST /images
+        try:
+            resp, body = self.client.create_image('test', 'wrong', 'vhd')
+        except exceptions.BadRequest:
+            pass
+        else:
+            self.fail('Invalid container format should not be accepted')
 
-        metas = [
-            {
-                'id': '1'
-            },  # Cannot specify ID in registration
-            {
-                'container_format': 'wrong',
-            },  # Invalid container format
-            {
-                'disk_format': 'wrong',
-            },  # Invalid disk format
-        ]
-        for meta in metas:
-            try:
-                self.client.images.create(**meta)
-            except glanceclient.exc.HTTPBadRequest:
-                continue
-            self.fail("Did not raise Invalid for meta %s." % meta)
+    @attr(type='negative')
+    def test_register_with_invalid_disk_format(self):
+        try:
+            resp, body = self.client.create_image('test', 'bare', 'wrong')
+        except exceptions.BadRequest:
+                pass
+        else:
+            self.fail("Invalid disk format should not be accepted")
 
     @attr(type='image')
     def test_register_then_upload(self):
         # Register, then upload an image
-        meta = {
-            'name': 'New Name',
-            'is_public': True,
-            'disk_format': 'vhd',
-            'container_format': 'bare',
-            'properties': {'prop1': 'val1'}
-        }
-        results = self.client.images.create(**meta)
-        self.assertTrue(hasattr(results, 'id'))
-        image_id = results.id
+        properties = {'prop1': 'val1'}
+        resp, body = self.client.create_image('New Name', 'bare', 'raw',
+                                              is_public=True,
+                                              properties=properties)
+        self.assertTrue('id' in body)
+        image_id = body.get('id')
         self.created_images.append(image_id)
-        self.assertTrue(hasattr(results, 'name'))
-        self.assertEqual(meta['name'], results.name)
-        self.assertTrue(hasattr(results, 'is_public'))
-        self.assertEqual(meta['is_public'], results.is_public)
-        self.assertTrue(hasattr(results, 'status'))
-        self.assertEqual('queued', results.status)
-        self.assertTrue(hasattr(results, 'properties'))
-        for key, val in meta['properties'].items():
-            self.assertEqual(val, results.properties[key])
+        self.assertTrue('name' in body)
+        self.assertEqual('New Name', body.get('name'))
+        self.assertTrue('is_public' in body)
+        self.assertTrue(body.get('is_public'))
+        self.assertTrue('status' in body)
+        self.assertEqual('queued', body.get('status'))
+        self.assertTrue('properties' in body)
+        for key, val in properties.items():
+            self.assertEqual(val, body.get('properties')[key])
 
         # Now try uploading an image file
-        image_file = StringIO.StringIO('*' * 1024)
-        results = self.client.images.update(image_id, data=image_file)
-        self.assertTrue(hasattr(results, 'status'))
-        self.assertEqual('active', results.status)
-        self.assertTrue(hasattr(results, 'size'))
-        self.assertEqual(1024, results.size)
+        image_file = StringIO.StringIO(('*' * 1024))
+        resp, body = self.client.update_image(image_id, data=image_file)
+        self.assertTrue('size' in body)
+        self.assertEqual(1024, body.get('size'))
 
     @attr(type='image')
     def test_register_remote_image(self):
         # Register a new remote image
-        meta = {
-            'name': 'New Remote Image',
-            'is_public': True,
-            'disk_format': 'raw',
-            'container_format': 'bare',
-            'location': 'http://example.com/someimage.iso'
-        }
-        results = self.client.images.create(**meta)
-        self.assertTrue(hasattr(results, 'id'))
-        image_id = results.id
+        resp, body = self.client.create_image('New Remote Image', 'bare',
+                                              'raw', is_public=True,
+                                              location='http://example.com'
+                                                       '/someimage.iso')
+        self.assertTrue('id' in body)
+        image_id = body.get('id')
         self.created_images.append(image_id)
-        self.assertTrue(hasattr(results, 'name'))
-        self.assertEqual(meta['name'], results.name)
-        self.assertTrue(hasattr(results, 'is_public'))
-        self.assertEqual(meta['is_public'], results.is_public)
-        self.assertTrue(hasattr(results, 'status'))
-        self.assertEqual('active', results.status)
+        self.assertTrue('name' in body)
+        self.assertEqual('New Remote Image', body.get('name'))
+        self.assertTrue('is_public' in body)
+        self.assertTrue(body.get('is_public'))
+        self.assertTrue('status' in body)
+        self.assertEqual('active', body.get('status'))
 
 
 class ListImagesTest(testtools.testcase.WithAttributes,
@@ -138,10 +117,8 @@
 
     @classmethod
     def setUpClass(cls):
-        if not GLANCE_INSTALLED:
-            raise cls.skipException('Glance not installed')
-        cls.os = clients.ServiceManager()
-        cls.client = cls.os.images.get_client()
+        cls.os = clients.Manager()
+        cls.client = cls.os.image_client
         cls.created_images = []
 
         # We add a few images here to test the listing functionality of
@@ -156,7 +133,8 @@
     @classmethod
     def tearDownClass(cls):
         for image_id in cls.created_images:
-            cls.client.images.delete(image_id)
+            cls.client.delete_image(image_id)
+            cls.client.wait_for_resource_deletion(image_id)
 
     @classmethod
     def _create_remote_image(cls, x):
@@ -164,15 +142,12 @@
         Create a new remote image and return the ID of the newly-registered
         image
         """
-        meta = {
-            'name': 'New Remote Image %s' % x,
-            'is_public': True,
-            'disk_format': 'raw',
-            'container_format': 'bare',
-            'location': 'http://example.com/someimage_%s.iso' % x
-        }
-        results = cls.client.images.create(**meta)
-        image_id = results.id
+        name = 'New Remote Image %s' % x
+        location = 'http://example.com/someimage_%s.iso' % x
+        resp, body = cls.client.create_image(name, 'bare', 'raw',
+                                             is_public=True,
+                                             location=location)
+        image_id = body['id']
         return image_id
 
     @classmethod
@@ -183,19 +158,17 @@
         1024 and 4096
         """
         image_file = StringIO.StringIO('*' * random.randint(1024, 4096))
-        meta = {
-            'name': 'New Standard Image %s' % x,
-            'is_public': True,
-            'disk_format': 'raw',
-            'container_format': 'bare',
-            'data': image_file,
-        }
-        results = cls.client.images.create(**meta)
-        image_id = results.id
+        name = 'New Standard Image %s' % x
+        resp, body = cls.client.create_image(name, 'bare', 'raw',
+                                             is_public=True, data=image_file)
+        image_id = body['id']
         return image_id
 
     @attr(type='image')
     def test_index_no_params(self):
         # Simple test to see all fixture images returned
-        current_images = set(i.id for i in self.client.images.list())
-        self.assertTrue(set(self.created_images) <= current_images)
+        resp, images_list = self.client.image_list()
+        self.assertEqual(resp['status'], '200')
+        image_list = map(lambda x: x['id'], images_list)
+        for image in self.created_images:
+            self.assertTrue(image in image_list)
diff --git a/tempest/tests/network/base.py b/tempest/tests/network/base.py
index 5af7e2c..8606079 100644
--- a/tempest/tests/network/base.py
+++ b/tempest/tests/network/base.py
@@ -29,8 +29,6 @@
     def setUpClass(cls):
         os = clients.Manager()
         client = os.network_client
-        config = os.config
-        networks = []
         enabled = True
 
         # Validate that there is even an endpoint configured
diff --git a/tempest/tests/network/test_network_basic_ops.py b/tempest/tests/network/test_network_basic_ops.py
index d297c98..aed368e 100644
--- a/tempest/tests/network/test_network_basic_ops.py
+++ b/tempest/tests/network/test_network_basic_ops.py
@@ -184,7 +184,6 @@
     def setUpClass(cls):
         super(TestNetworkBasicOps, cls).setUpClass()
         cls.check_preconditions()
-        cfg = cls.config.network
         cls.tenant_id = cls.manager._get_identity_client(
             cls.config.identity.username,
             cls.config.identity.password,
diff --git a/tempest/tests/object_storage/base.py b/tempest/tests/object_storage/base.py
index 376deb7..2492d8b 100644
--- a/tempest/tests/object_storage/base.py
+++ b/tempest/tests/object_storage/base.py
@@ -18,7 +18,6 @@
 import testtools
 
 from tempest import clients
-import tempest.config
 from tempest import exceptions
 from tempest.tests.identity.base import DataGenerator
 
@@ -48,6 +47,5 @@
         try:
             cls.account_client.list_account_containers()
         except exceptions.EndpointNotFound:
-            enabled = False
             skip_msg = "No OpenStack Object Storage API endpoint"
             raise cls.skipException(skip_msg)
diff --git a/tempest/tests/object_storage/test_container_sync.py b/tempest/tests/object_storage/test_container_sync.py
index f087aff..dad6309 100644
--- a/tempest/tests/object_storage/test_container_sync.py
+++ b/tempest/tests/object_storage/test_container_sync.py
@@ -15,7 +15,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.common.utils.data_utils import arbitrary_string
 from tempest.common.utils.data_utils import rand_name
 from tempest.test import attr
 from tempest.tests.object_storage import base
diff --git a/tempest/tests/volume/base.py b/tempest/tests/volume/base.py
index 6625180..c91244f 100644
--- a/tempest/tests/volume/base.py
+++ b/tempest/tests/volume/base.py
@@ -113,7 +113,7 @@
     @classmethod
     def clear_isolated_creds(cls):
         if not cls.isolated_creds:
-            pass
+            return
         admin_client = cls._get_identity_admin_client()
 
         for user, tenant in cls.isolated_creds:
diff --git a/tempest/tests/volume/test_volumes_snapshots.py b/tempest/tests/volume/test_volumes_snapshots.py
index 75ea155..3acc5f6 100644
--- a/tempest/tests/volume/test_volumes_snapshots.py
+++ b/tempest/tests/volume/test_volumes_snapshots.py
@@ -12,7 +12,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.common.utils.data_utils import rand_name
 from tempest.tests.volume import base