Clients subclass the RestClient to allow attributes to be
overrided by each client and allow better code reuse.

Changes the RestClient to set the token and base_url when
it is needed for a request. Also allows for it to be cleared
so that it can be renewed.

Fixes lp#977594

Change-Id: I040d1c171a4018326a5b700e303652c95a3b3542
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index c8af2ca..e9741bf 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -30,21 +30,49 @@
 
 class RestClient(object):
 
-    def __init__(self, config, user, password, auth_url, service,
-                 tenant_name=None):
+    def __init__(self, config, user, password, auth_url, tenant_name=None):
         self.log = logging.getLogger(__name__)
         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,
-                                                           password,
-                                                           auth_url,
-                                                           service,
-                                                           tenant_name)
+        self.user = user
+        self.password = password
+        self.auth_url = auth_url
+        self.tenant_name = tenant_name
+
+        self.service = None
+        self.token = None
+        self.base_url = None
+        self.config = config
+        self.region = 0
+        self.endpoint_url = 'publicURL'
+        self.strategy = self.config.identity.strategy
+        self.headers = {'Content-Type': 'application/json',
+                        'Accept': 'application/json'}
+
+    def _set_auth(self):
+        """
+        Sets the token and base_url used in requests based on the strategy type
+        """
+
+        if self.strategy == 'keystone':
+            self.token, self.base_url = self.keystone_auth(self.user,
+                                                           self.password,
+                                                           self.auth_url,
+                                                           self.service,
+                                                           self.tenant_name)
         else:
-            self.token, self.base_url = self.basic_auth(user,
-                                                        password,
-                                                        auth_url)
+            self.token, self.base_url = self.basic_auth(self.user,
+                                                        self.password,
+                                                        self.auth_url)
+
+    def clear_auth(self):
+        """
+        Can be called to clear the token and base_url so that the next request
+        will fetch a new token and base_url
+        """
+
+        self.token = None
+        self.base_url = None
 
     def basic_auth(self, user, password, auth_url):
         """
@@ -93,7 +121,7 @@
             mgmt_url = None
             for ep in auth_data['serviceCatalog']:
                 if ep["type"] == service:
-                    mgmt_url = ep['endpoints'][0]['publicURL']
+                    mgmt_url = ep['endpoints'][self.region][self.endpoint_url]
                     # See LP#920817. The tenantId is *supposed*
                     # to be returned for each endpoint accorsing to the
                     # Keystone spec. But... it isn't, so we have to parse
@@ -135,6 +163,9 @@
     def request(self, method, url, headers=None, body=None, depth=0):
         """A simple HTTP request interface."""
 
+        if (self.token is None) or (self.base_url is None):
+            self._set_auth()
+
         self.http_obj = httplib2.Http()
         if headers == None:
             headers = {}
diff --git a/tempest/services/nova/json/extensions_client.py b/tempest/services/nova/json/extensions_client.py
index f216f3c..5627afc 100644
--- a/tempest/services/nova/json/extensions_client.py
+++ b/tempest/services/nova/json/extensions_client.py
@@ -1,19 +1,17 @@
-from tempest.common import rest_client
+from tempest.common.rest_client import RestClient
 import json
 
 
-class ExtensionsClient(object):
+class ExtensionsClient(RestClient):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        self.config = config
-        catalog_type = self.config.compute.catalog_type
-        self.client = rest_client.RestClient(config, username, password,
-                                             auth_url, catalog_type,
-                                             tenant_name)
+        super(ExtensionsClient, self).__init__(config, username, password,
+                                               auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
 
     def list_extensions(self):
         url = 'extensions'
-        resp, body = self.client.get(url)
+        resp, body = self.get(url)
         body = json.loads(body)
         return resp, body
 
diff --git a/tempest/services/nova/json/flavors_client.py b/tempest/services/nova/json/flavors_client.py
index 7d612d7..84fa9ff 100644
--- a/tempest/services/nova/json/flavors_client.py
+++ b/tempest/services/nova/json/flavors_client.py
@@ -1,15 +1,13 @@
-from tempest.common import rest_client
+from tempest.common.rest_client import RestClient
 import json
 
 
-class FlavorsClient(object):
+class FlavorsClient(RestClient):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        self.config = config
-        catalog_type = self.config.compute.catalog_type
-        self.client = rest_client.RestClient(config, username, password,
-                                             auth_url, catalog_type,
-                                             tenant_name)
+        super(FlavorsClient, self).__init__(config, username, password,
+                                            auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
 
     def list_flavors(self, params=None):
         url = 'flavors'
@@ -20,7 +18,7 @@
 
             url = "flavors?" + "".join(param_list)
 
-        resp, body = self.client.get(url)
+        resp, body = self.get(url)
         body = json.loads(body)
         return resp, body['flavors']
 
@@ -33,11 +31,11 @@
 
             url = "flavors/detail?" + "".join(param_list)
 
-        resp, body = self.client.get(url)
+        resp, body = self.get(url)
         body = json.loads(body)
         return resp, body['flavors']
 
     def get_flavor_details(self, flavor_id):
-        resp, body = self.client.get("flavors/%s" % str(flavor_id))
+        resp, body = self.get("flavors/%s" % str(flavor_id))
         body = json.loads(body)
         return resp, body['flavor']
diff --git a/tempest/services/nova/json/floating_ips_client.py b/tempest/services/nova/json/floating_ips_client.py
index 3ab8f28..5b5b538 100644
--- a/tempest/services/nova/json/floating_ips_client.py
+++ b/tempest/services/nova/json/floating_ips_client.py
@@ -1,17 +1,13 @@
-from tempest.common import rest_client
+from tempest.common.rest_client import RestClient
 from tempest import exceptions
 import json
 
 
-class FloatingIPsClient(object):
+class FloatingIPsClient(RestClient):
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        self.config = config
-        catalog_type = self.config.compute.catalog_type
-        self.client = rest_client.RestClient(config, username, password,
-                                             auth_url, catalog_type,
-                                             tenant_name)
-        self.headers = {'Content-Type': 'application/json',
-                        'Accept': 'application/json'}
+        super(FloatingIPsClient, self).__init__(config, username, password,
+                                                auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
 
     def list_floating_ips(self, params=None):
         """Returns a list of all floating IPs filtered by any parameters"""
@@ -21,14 +17,14 @@
             for param, value in params.iteritems():
                 param_list.append("%s=%s&" % (param, value))
             url += '?' + ' '.join(param_list)
-        resp, body = self.client.get(url)
+        resp, body = self.get(url)
         body = json.loads(body)
         return resp, body['floating_ips']
 
     def get_floating_ip_details(self, floating_ip_id):
         """Get the details of a floating IP"""
         url = "os-floating-ips/%s" % str(floating_ip_id)
-        resp, body = self.client.get(url)
+        resp, body = self.get(url)
         body = json.loads(body)
         if resp.status == 404:
             raise exceptions.NotFound(body)
@@ -37,14 +33,14 @@
     def create_floating_ip(self):
         """Allocate a floating IP to the project"""
         url = 'os-floating-ips'
-        resp, body = self.client.post(url, None, None)
+        resp, body = self.post(url, None, None)
         body = json.loads(body)
         return resp, body['floating_ip']
 
     def delete_floating_ip(self, floating_ip_id):
         """Deletes the provided floating IP from the project"""
         url = "os-floating-ips/%s" % str(floating_ip_id)
-        resp, body = self.client.delete(url)
+        resp, body = self.delete(url)
         return resp, body
 
     def associate_floating_ip_to_server(self, floating_ip, server_id):
@@ -57,7 +53,7 @@
         }
 
         post_body = json.dumps(post_body)
-        resp, body = self.client.post(url, post_body, self.headers)
+        resp, body = self.post(url, post_body, self.headers)
         return resp, body
 
     def disassociate_floating_ip_from_server(self, floating_ip, server_id):
@@ -70,5 +66,5 @@
         }
 
         post_body = json.dumps(post_body)
-        resp, body = self.client.post(url, post_body, self.headers)
+        resp, body = self.post(url, post_body, self.headers)
         return resp, body
diff --git a/tempest/services/nova/json/images_client.py b/tempest/services/nova/json/images_client.py
index 5bf10ef..c9a0370 100644
--- a/tempest/services/nova/json/images_client.py
+++ b/tempest/services/nova/json/images_client.py
@@ -1,22 +1,17 @@
-from tempest.common import rest_client
+from tempest.common.rest_client import RestClient
 from tempest import exceptions
 import json
 import time
 
 
-class ImagesClient(object):
+class ImagesClient(RestClient):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        self.config = config
-        catalog_type = self.config.compute.catalog_type
-        self.client = rest_client.RestClient(config, username, password,
-                                             auth_url, catalog_type,
-                                             tenant_name)
-
+        super(ImagesClient, self).__init__(config, username, password,
+                                            auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
         self.build_interval = self.config.compute.build_interval
         self.build_timeout = self.config.compute.build_timeout
-        self.headers = {'Content-Type': 'application/json',
-                        'Accept': 'application/json'}
 
     def create_image(self, server_id, name, meta=None):
         """Creates an image of the original server"""
@@ -31,7 +26,7 @@
             post_body['createImage']['metadata'] = meta
 
         post_body = json.dumps(post_body)
-        resp, body = self.client.post('servers/%s/action' %
+        resp, body = self.post('servers/%s/action' %
                                       str(server_id), post_body, self.headers)
         return resp, body
 
@@ -45,7 +40,7 @@
 
             url = "images?" + "".join(param_list)
 
-        resp, body = self.client.get(url)
+        resp, body = self.get(url)
         body = json.loads(body)
         return resp, body['images']
 
@@ -59,31 +54,31 @@
 
             url = "images/detail?" + "".join(param_list)
 
-        resp, body = self.client.get(url)
+        resp, body = self.get(url)
         body = json.loads(body)
         return resp, body['images']
 
     def get_image(self, image_id):
         """Returns the details of a single image"""
-        resp, body = self.client.get("images/%s" % str(image_id))
+        resp, body = self.get("images/%s" % str(image_id))
         body = json.loads(body)
         return resp, body['image']
 
     def delete_image(self, image_id):
         """Deletes the provided image"""
-        return self.client.delete("images/%s" % str(image_id))
+        return self.delete("images/%s" % str(image_id))
 
     def wait_for_image_resp_code(self, image_id, code):
         """
         Waits until the HTTP response code for the request matches the
         expected value
         """
-        resp, body = self.client.get("images/%s" % str(image_id))
+        resp, body = self.get("images/%s" % str(image_id))
         start = int(time.time())
 
         while resp.status != code:
             time.sleep(self.build_interval)
-            resp, body = self.client.get("images/%s" % str(image_id))
+            resp, body = self.get("images/%s" % str(image_id))
 
             if int(time.time()) - start >= self.build_timeout:
                 raise exceptions.BuildErrorException
@@ -105,14 +100,14 @@
 
     def list_image_metadata(self, image_id):
         """Lists all metadata items for an image"""
-        resp, body = self.client.get("images/%s/metadata" % str(image_id))
+        resp, body = self.get("images/%s/metadata" % str(image_id))
         body = json.loads(body)
         return resp, body['metadata']
 
     def set_image_metadata(self, image_id, meta):
         """Sets the metadata for an image"""
         post_body = json.dumps({'metadata': meta})
-        resp, body = self.client.put('images/%s/metadata' %
+        resp, body = self.put('images/%s/metadata' %
                                       str(image_id), post_body, self.headers)
         body = json.loads(body)
         return resp, body['metadata']
@@ -120,14 +115,14 @@
     def update_image_metadata(self, image_id, meta):
         """Updates the metadata for an image"""
         post_body = json.dumps({'metadata': meta})
-        resp, body = self.client.post('images/%s/metadata' %
+        resp, body = self.post('images/%s/metadata' %
                                       str(image_id), post_body, self.headers)
         body = json.loads(body)
         return resp, body['metadata']
 
     def get_image_metadata_item(self, image_id, key):
         """Returns the value for a specific image metadata key"""
-        resp, body = self.client.get("images/%s/metadata/%s" %
+        resp, body = self.get("images/%s/metadata/%s" %
                                      (str(image_id), key))
         body = json.loads(body)
         return resp, body['meta']
@@ -135,7 +130,7 @@
     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})
-        resp, body = self.client.put('images/%s/metadata/%s' %
+        resp, body = self.put('images/%s/metadata/%s' %
                                      (str(image_id), key), post_body,
                                      self.headers)
         body = json.loads(body)
@@ -143,6 +138,6 @@
 
     def delete_image_metadata_item(self, image_id, key):
         """Deletes a single image metadata key/value pair"""
-        resp, body = self.client.delete("images/%s/metadata/%s" %
+        resp, body = self.delete("images/%s/metadata/%s" %
                                      (str(image_id), key))
         return resp, body
diff --git a/tempest/services/nova/json/keypairs_client.py b/tempest/services/nova/json/keypairs_client.py
index a0bef15..4e72a01 100644
--- a/tempest/services/nova/json/keypairs_client.py
+++ b/tempest/services/nova/json/keypairs_client.py
@@ -1,20 +1,16 @@
-from tempest.common import rest_client
+from tempest.common.rest_client import RestClient
 import json
 
 
-class KeyPairsClient(object):
+class KeyPairsClient(RestClient):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        self.config = config
-        catalog_type = self.config.compute.catalog_type
-        self.client = rest_client.RestClient(config, username, password,
-                                             auth_url, catalog_type,
-                                             tenant_name)
-        self.headers = {'Content-Type': 'application/json',
-                        'Accept': 'application/json'}
+        super(KeyPairsClient, self).__init__(config, username, password,
+                                             auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
 
     def list_keypairs(self):
-        resp, body = self.client.get("os-keypairs")
+        resp, body = self.get("os-keypairs")
         body = json.loads(body)
         #Each returned keypair is embedded within an unnecessary 'keypair'
         #element which is a deviation from other resources like floating-ips,
@@ -24,7 +20,7 @@
         return resp, body['keypairs']
 
     def get_keypair(self, key_name):
-        resp, body = self.client.get("os-keypairs/%s" % str(key_name))
+        resp, body = self.get("os-keypairs/%s" % str(key_name))
         body = json.loads(body)
         return resp, body['keypair']
 
@@ -33,10 +29,10 @@
         if pub_key:
             post_body['keypair']['public_key'] = pub_key
         post_body = json.dumps(post_body)
-        resp, body = self.client.post("os-keypairs",
+        resp, body = self.post("os-keypairs",
                                 headers=self.headers, body=post_body)
         body = json.loads(body)
         return resp, body['keypair']
 
     def delete_keypair(self, key_name):
-        return self.client.delete("os-keypairs/%s" % str(key_name))
+        return self.delete("os-keypairs/%s" % str(key_name))
diff --git a/tempest/services/nova/json/limits_client.py b/tempest/services/nova/json/limits_client.py
index 6f5f57a..163b685 100644
--- a/tempest/services/nova/json/limits_client.py
+++ b/tempest/services/nova/json/limits_client.py
@@ -1,18 +1,16 @@
 import json
-from tempest.common import rest_client
+from tempest.common.rest_client import RestClient
 
 
-class LimitsClient(object):
+class LimitsClient(RestClient):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        self.config = config
-        catalog_type = self.config.compute.catalog_type
-        self.client = rest_client.RestClient(config, username, password,
-                                             auth_url, catalog_type,
-                                             tenant_name)
+        super(LimitsClient, self).__init__(config, username, password,
+                                           auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
 
     def get_limits(self):
-        resp, body = self.client.get("limits")
+        resp, body = self.get("limits")
         body = json.loads(body)
         return resp, body['limits']
 
diff --git a/tempest/services/nova/json/security_groups_client.py b/tempest/services/nova/json/security_groups_client.py
index 29223ea..6fa1a8c 100644
--- a/tempest/services/nova/json/security_groups_client.py
+++ b/tempest/services/nova/json/security_groups_client.py
@@ -1,17 +1,13 @@
-from tempest.common import rest_client
+from tempest.common.rest_client import RestClient
 import json
 
 
-class SecurityGroupsClient(object):
+class SecurityGroupsClient(RestClient):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        self.config = config
-        catalog_type = self.config.compute.catalog_type
-        self.client = rest_client.RestClient(config, username, password,
-                                             auth_url, catalog_type,
-                                             tenant_name)
-        self.headers = {'Content-Type': 'application/json',
-                        'Accept': 'application/json'}
+        super(SecurityGroupsClient, self).__init__(config, username, password,
+                                           auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
 
     def list_security_groups(self, params=None):
         """List all security groups for a user"""
@@ -24,14 +20,14 @@
 
             url += '?' + ' '.join(param_list)
 
-        resp, body = self.client.get(url)
+        resp, body = self.get(url)
         body = json.loads(body)
         return resp, body['security_groups']
 
     def get_security_group(self, security_group_id):
         """Get the details of a Security Group"""
         url = "os-security-groups/%s" % str(security_group_id)
-        resp, body = self.client.get(url)
+        resp, body = self.get(url)
         body = json.loads(body)
         return resp, body['security_group']
 
@@ -46,14 +42,14 @@
             'description': description,
         }
         post_body = json.dumps({'security_group': post_body})
-        resp, body = self.client.post('os-security-groups',
+        resp, body = self.post('os-security-groups',
                                         post_body, self.headers)
         body = json.loads(body)
         return resp, body['security_group']
 
     def delete_security_group(self, security_group_id):
         """Deletes the provided Security Group"""
-        return self.client.delete('os-security-groups/%s'
+        return self.delete('os-security-groups/%s'
                                    % str(security_group_id))
 
     def create_security_group_rule(self, parent_group_id, ip_proto, from_port,
@@ -78,11 +74,11 @@
         }
         post_body = json.dumps({'security_group_rule': post_body})
         url = 'os-security-group-rules'
-        resp, body = self.client.post(url, post_body, self.headers)
+        resp, body = self.post(url, post_body, self.headers)
         body = json.loads(body)
         return resp, body['security_group_rule']
 
     def delete_security_group_rule(self, group_rule_id):
         """Deletes the provided Security Group rule"""
-        return self.client.delete('os-security-group-rules/%s'
+        return self.delete('os-security-group-rules/%s'
                                       % str(group_rule_id))
diff --git a/tempest/services/nova/json/servers_client.py b/tempest/services/nova/json/servers_client.py
index c02320e..08ac6df 100644
--- a/tempest/services/nova/json/servers_client.py
+++ b/tempest/services/nova/json/servers_client.py
@@ -1,22 +1,17 @@
 from tempest import exceptions
-from tempest.common import rest_client
+from tempest.common.rest_client import RestClient
 import json
 import time
 
 
-class ServersClient(object):
+class ServersClient(RestClient):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        self.config = config
-        catalog_type = self.config.compute.catalog_type
-        self.client = rest_client.RestClient(config, username, password,
-                                             auth_url, catalog_type,
-                                             tenant_name)
-
+        super(ServersClient, self).__init__(config, username, password,
+                                           auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
         self.build_interval = self.config.compute.build_interval
         self.build_timeout = self.config.compute.build_timeout
-        self.headers = {'Content-Type': 'application/json',
-                        'Accept': 'application/json'}
 
     def create_server(self, name, image_ref, flavor_ref, **kwargs):
         """
@@ -60,7 +55,7 @@
             if value != None:
                 post_body[post_param] = value
         post_body = json.dumps({'server': post_body})
-        resp, body = self.client.post('servers', post_body, self.headers)
+        resp, body = self.post('servers', post_body, self.headers)
 
         body = json.loads(body)
         return resp, body['server']
@@ -91,20 +86,20 @@
             post_body['accessIPv6'] = accessIPv6
 
         post_body = json.dumps({'server': post_body})
-        resp, body = self.client.put("servers/%s" % str(server_id),
+        resp, body = self.put("servers/%s" % str(server_id),
                                      post_body, self.headers)
         body = json.loads(body)
         return resp, body['server']
 
     def get_server(self, server_id):
         """Returns the details of an existing server"""
-        resp, body = self.client.get("servers/%s" % str(server_id))
+        resp, body = self.get("servers/%s" % str(server_id))
         body = json.loads(body)
         return resp, body['server']
 
     def delete_server(self, server_id):
         """Deletes the given server"""
-        return self.client.delete("servers/%s" % str(server_id))
+        return self.delete("servers/%s" % str(server_id))
 
     def list_servers(self, params=None):
         """Lists all servers for a user"""
@@ -117,7 +112,7 @@
 
             url = "servers?" + "".join(param_list)
 
-        resp, body = self.client.get(url)
+        resp, body = self.get(url)
         body = json.loads(body)
         return resp, body
 
@@ -132,7 +127,7 @@
 
             url = "servers/detail?" + "".join(param_list)
 
-        resp, body = self.client.get(url)
+        resp, body = self.get(url)
         body = json.loads(body)
         return resp, body
 
@@ -161,13 +156,13 @@
 
     def list_addresses(self, server_id):
         """Lists all addresses for a server"""
-        resp, body = self.client.get("servers/%s/ips" % str(server_id))
+        resp, body = self.get("servers/%s/ips" % str(server_id))
         body = json.loads(body)
         return resp, body['addresses']
 
     def list_addresses_by_network(self, server_id, network_id):
         """Lists all addresses of a specific network type for a server"""
-        resp, body = self.client.get("servers/%s/ips/%s" %
+        resp, body = self.get("servers/%s/ips/%s" %
                                     (str(server_id), network_id))
         body = json.loads(body)
         return resp, body
@@ -181,7 +176,7 @@
         }
 
         post_body = json.dumps(post_body)
-        return self.client.post('servers/%s/action' % str(server_id),
+        return self.post('servers/%s/action' % str(server_id),
                                 post_body, self.headers)
 
     def reboot(self, server_id, reboot_type):
@@ -193,7 +188,7 @@
         }
 
         post_body = json.dumps(post_body)
-        return self.client.post('servers/%s/action' % str(server_id),
+        return self.post('servers/%s/action' % str(server_id),
                                 post_body, self.headers)
 
     def rebuild(self, server_id, image_ref, name=None, meta=None,
@@ -219,7 +214,7 @@
             post_body['OS-DCF:diskConfig'] = disk_config
 
         post_body = json.dumps({'rebuild': post_body})
-        resp, body = self.client.post('servers/%s/action' %
+        resp, body = self.post('servers/%s/action' %
                                       str(server_id), post_body,
                                       self.headers)
         body = json.loads(body)
@@ -237,7 +232,7 @@
             post_body['resize']['OS-DCF:diskConfig'] = disk_config
 
         post_body = json.dumps(post_body)
-        resp, body = self.client.post('servers/%s/action' %
+        resp, body = self.post('servers/%s/action' %
                                       str(server_id), post_body, self.headers)
         return resp, body
 
@@ -248,7 +243,7 @@
         }
 
         post_body = json.dumps(post_body)
-        resp, body = self.client.post('servers/%s/action' %
+        resp, body = self.post('servers/%s/action' %
                                       str(server_id), post_body, self.headers)
         return resp, body
 
@@ -259,7 +254,7 @@
         }
 
         post_body = json.dumps(post_body)
-        resp, body = self.client.post('servers/%s/action' %
+        resp, body = self.post('servers/%s/action' %
                                       str(server_id), post_body, self.headers)
         return resp, body
 
@@ -272,44 +267,44 @@
         }
 
         post_body = json.dumps(post_body)
-        resp, body = self.client.post('servers/%s/action' %
+        resp, body = self.post('servers/%s/action' %
                                       str(server_id), post_body, self.headers)
         return resp, body
 
     def list_server_metadata(self, server_id):
-        resp, body = self.client.get("servers/%s/metadata" % str(server_id))
+        resp, body = self.get("servers/%s/metadata" % str(server_id))
         body = json.loads(body)
         return resp, body['metadata']
 
     def set_server_metadata(self, server_id, meta):
         post_body = json.dumps({'metadata': meta})
-        resp, body = self.client.put('servers/%s/metadata' %
+        resp, body = self.put('servers/%s/metadata' %
                                      str(server_id), post_body, self.headers)
         body = json.loads(body)
         return resp, body['metadata']
 
     def update_server_metadata(self, server_id, meta):
         post_body = json.dumps({'metadata': meta})
-        resp, body = self.client.post('servers/%s/metadata' %
+        resp, body = self.post('servers/%s/metadata' %
                                      str(server_id), post_body, self.headers)
         body = json.loads(body)
         return resp, body['metadata']
 
     def get_server_metadata_item(self, server_id, key):
-        resp, body = self.client.get("servers/%s/metadata/%s" %
+        resp, body = self.get("servers/%s/metadata/%s" %
                                     (str(server_id), key))
         body = json.loads(body)
         return resp, body['meta']
 
     def set_server_metadata_item(self, server_id, key, meta):
         post_body = json.dumps({'meta': meta})
-        resp, body = self.client.put('servers/%s/metadata/%s' %
+        resp, body = self.put('servers/%s/metadata/%s' %
                                     (str(server_id), key),
                                     post_body, self.headers)
         body = json.loads(body)
         return resp, body['meta']
 
     def delete_server_metadata_item(self, server_id, key):
-        resp, body = self.client.delete("servers/%s/metadata/%s" %
+        resp, body = self.delete("servers/%s/metadata/%s" %
                                     (str(server_id), key))
         return resp, body
diff --git a/tempest/services/nova/json/volumes_client.py b/tempest/services/nova/json/volumes_client.py
index c935621..ce212ff 100644
--- a/tempest/services/nova/json/volumes_client.py
+++ b/tempest/services/nova/json/volumes_client.py
@@ -1,20 +1,17 @@
 from tempest import exceptions
-from tempest.common import rest_client
+from tempest.common.rest_client import RestClient
 import json
 import time
 
 
-class VolumesClient(object):
+class VolumesClient(RestClient):
 
-    def __init__(self, config, username, key, auth_url, tenant_name=None):
-        self.config = config
-        catalog_type = self.config.compute.catalog_type
-        self.client = rest_client.RestClient(config, username, key, auth_url,
-                                             catalog_type, tenant_name)
+    def __init__(self, config, username, password, auth_url, tenant_name=None):
+        super(VolumesClient, self).__init__(config, username, password,
+                                           auth_url, tenant_name)
+        self.service = self.config.compute.catalog_type
         self.build_interval = self.config.compute.build_interval
         self.build_timeout = self.config.compute.build_timeout
-        self.headers = {'Content-Type': 'application/json',
-                        'Accept': 'application/json'}
 
     def list_volumes(self, params=None):
         """List all the volumes created"""
@@ -26,7 +23,7 @@
 
             url += '?' + ' '.join(param_list)
 
-        resp, body = self.client.get(url)
+        resp, body = self.get(url)
         body = json.loads(body)
         return resp, body['volumes']
 
@@ -40,14 +37,14 @@
 
             url = '?' + ' '.join(param_list)
 
-        resp, body = self.client.get(url)
+        resp, body = self.get(url)
         body = json.loads(body)
         return resp, body['volumes']
 
     def get_volume(self, volume_id):
         """Returns the details of a single volume"""
         url = "os-volumes/%s" % str(volume_id)
-        resp, body = self.client.get(url)
+        resp, body = self.get(url)
         body = json.loads(body)
         return resp, body['volume']
 
@@ -66,13 +63,13 @@
             }
 
         post_body = json.dumps({'volume': post_body})
-        resp, body = self.client.post('os-volumes', post_body, self.headers)
+        resp, body = self.post('os-volumes', post_body, self.headers)
         body = json.loads(body)
         return resp, body['volume']
 
     def delete_volume(self, volume_id):
         """Deletes the Specified Volume"""
-        return self.client.delete("os-volumes/%s" % str(volume_id))
+        return self.delete("os-volumes/%s" % str(volume_id))
 
     def wait_for_volume_status(self, volume_id, status):
         """Waits for a Volume to reach a given status"""