Merge "Skip personality max limit tests in case no limit"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 441e17c..b396503 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -750,7 +750,7 @@
 # Catalog type of the Neutron service. (string value)
 #catalog_type = network
 
-# List of dns servers whichs hould be used for subnet creation (list
+# List of dns servers which should be used for subnet creation (list
 # value)
 #dns_servers = 8.8.8.8,8.8.4.4
 
diff --git a/tempest/common/custom_matchers.py b/tempest/common/custom_matchers.py
index 39e3a67..298a94e 100644
--- a/tempest/common/custom_matchers.py
+++ b/tempest/common/custom_matchers.py
@@ -122,33 +122,21 @@
 
     def match(self, actual):
         for key, value in actual.iteritems():
-            if key == 'content-length' and not value.isdigit():
+            if key in ('content-length', 'x-account-bytes-used',
+                       'x-account-container-count', 'x-account-object-count',
+                       'x-container-bytes-used', 'x-container-object-count')\
+                and not value.isdigit():
+                return InvalidFormat(key, value)
+            elif key in ('content-type', 'date', 'last-modified',
+                         'x-copied-from-last-modified') and not value:
                 return InvalidFormat(key, value)
             elif key == 'x-timestamp' and not re.match("^\d+\.?\d*\Z", value):
                 return InvalidFormat(key, value)
-            elif key == 'x-account-bytes-used' and not value.isdigit():
-                return InvalidFormat(key, value)
-            elif key == 'x-account-container-count' and not value.isdigit():
-                return InvalidFormat(key, value)
-            elif key == 'x-account-object-count' and not value.isdigit():
-                return InvalidFormat(key, value)
-            elif key == 'x-container-bytes-used' and not value.isdigit():
-                return InvalidFormat(key, value)
-            elif key == 'x-container-object-count' and not value.isdigit():
-                return InvalidFormat(key, value)
-            elif key == 'content-type' and not value:
-                return InvalidFormat(key, value)
             elif key == 'x-copied-from' and not re.match("\S+/\S+", value):
                 return InvalidFormat(key, value)
-            elif key == 'x-copied-from-last-modified' and not value:
-                return InvalidFormat(key, value)
             elif key == 'x-trans-id' and \
                 not re.match("^tx[0-9a-f]{21}-[0-9a-f]{10}.*", value):
                 return InvalidFormat(key, value)
-            elif key == 'date' and not value:
-                return InvalidFormat(key, value)
-            elif key == 'last-modified' and not value:
-                return InvalidFormat(key, value)
             elif key == 'accept-ranges' and not value == 'bytes':
                 return InvalidFormat(key, value)
             elif key == 'etag' and not value.isalnum():
diff --git a/tempest/config.py b/tempest/config.py
index dbe9bc2..bbfe70b 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -469,7 +469,7 @@
                     "checks."),
     cfg.ListOpt('dns_servers',
                 default=["8.8.8.8", "8.8.4.4"],
-                help="List of dns servers whichs hould be used"
+                help="List of dns servers which should be used"
                      " for subnet creation")
 ]
 
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 61a7d2e..20b95e4 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -556,7 +556,7 @@
         if not client:
             client = self.network_client
         if not tenant_id:
-            tenant_id = client.rest_client.tenant_id
+            tenant_id = client.tenant_id
         name = data_utils.rand_name(namestart)
         result = client.create_network(name=name, tenant_id=tenant_id)
         network = net_resources.DeletableNetwork(client=client,
@@ -791,7 +791,7 @@
         if client is None:
             client = self.network_client
         if tenant_id is None:
-            tenant_id = client.rest_client.tenant_id
+            tenant_id = client.tenant_id
         secgroup = self._create_empty_security_group(namestart=namestart,
                                                      client=client,
                                                      tenant_id=tenant_id)
@@ -817,7 +817,7 @@
         if client is None:
             client = self.network_client
         if not tenant_id:
-            tenant_id = client.rest_client.tenant_id
+            tenant_id = client.tenant_id
         sg_name = data_utils.rand_name(namestart)
         sg_desc = sg_name + " description"
         sg_dict = dict(name=sg_name,
@@ -842,7 +842,7 @@
         if client is None:
             client = self.network_client
         if not tenant_id:
-            tenant_id = client.rest_client.tenant_id
+            tenant_id = client.tenant_id
         sgs = [
             sg for sg in client.list_security_groups().values()[0]
             if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
@@ -874,7 +874,7 @@
         if client is None:
             client = self.network_client
         if not tenant_id:
-            tenant_id = client.rest_client.tenant_id
+            tenant_id = client.tenant_id
         if secgroup is None:
             secgroup = self._default_security_group(client=client,
                                                     tenant_id=tenant_id)
@@ -986,7 +986,7 @@
         if not client:
             client = self.network_client
         if not tenant_id:
-            tenant_id = client.rest_client.tenant_id
+            tenant_id = client.tenant_id
         router_id = CONF.network.public_router_id
         network_id = CONF.network.public_network_id
         if router_id:
@@ -1005,7 +1005,7 @@
         if not client:
             client = self.network_client
         if not tenant_id:
-            tenant_id = client.rest_client.tenant_id
+            tenant_id = client.tenant_id
         name = data_utils.rand_name(namestart)
         result = client.create_router(name=name,
                                       admin_state_up=True,
diff --git a/tempest/services/compute/json/agents_client.py b/tempest/services/compute/json/agents_client.py
index 5b76a56..eacd367 100644
--- a/tempest/services/compute/json/agents_client.py
+++ b/tempest/services/compute/json/agents_client.py
@@ -17,21 +17,14 @@
 
 from tempest.api_schema.response.compute import agents as common_schema
 from tempest.api_schema.response.compute.v2 import agents as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class AgentsClientJSON(rest_client.RestClient):
+class AgentsClientJSON(base.ComputeClient):
     """
     Tests Agents API
     """
 
-    def __init__(self, auth_provider):
-        super(AgentsClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
-
     def list_agents(self, params=None):
         """List all agent builds."""
         url = 'os-agents'
diff --git a/tempest/services/compute/json/aggregates_client.py b/tempest/services/compute/json/aggregates_client.py
index 09927d3..1539259 100644
--- a/tempest/services/compute/json/aggregates_client.py
+++ b/tempest/services/compute/json/aggregates_client.py
@@ -17,18 +17,11 @@
 
 from tempest.api_schema.response.compute import aggregates as schema
 from tempest.api_schema.response.compute.v2 import aggregates as v2_schema
-from tempest.common import rest_client
-from tempest import config
 from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class AggregatesClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(AggregatesClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class AggregatesClientJSON(base.ComputeClient):
 
     def list_aggregates(self):
         """Get aggregate list."""
diff --git a/tempest/services/compute/json/availability_zone_client.py b/tempest/services/compute/json/availability_zone_client.py
index 00f8330..b8bda68 100644
--- a/tempest/services/compute/json/availability_zone_client.py
+++ b/tempest/services/compute/json/availability_zone_client.py
@@ -16,18 +16,10 @@
 import json
 
 from tempest.api_schema.response.compute.v2 import availability_zone as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class AvailabilityZoneClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(AvailabilityZoneClientJSON, self).__init__(
-            auth_provider)
-        self.service = CONF.compute.catalog_type
+class AvailabilityZoneClientJSON(base.ComputeClient):
 
     def get_availability_zone_list(self):
         resp, body = self.get('os-availability-zone')
diff --git a/tempest/services/compute/json/base.py b/tempest/services/compute/json/base.py
new file mode 100644
index 0000000..b712452
--- /dev/null
+++ b/tempest/services/compute/json/base.py
@@ -0,0 +1,36 @@
+# Copyright 2014 NEC Corporation.  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 tempest.common import rest_client
+from tempest import config
+
+CONF = config.CONF
+
+
+class ComputeClient(rest_client.RestClient):
+    """
+    Base compute client class
+    """
+
+    def __init__(self, auth_provider,
+                 build_interval=None, build_timeout=None):
+        if build_interval is None:
+            build_interval = CONF.compute.build_interval
+        if build_timeout is None:
+            build_timeout = CONF.compute.build_timeout
+
+        super(ComputeClient, self).__init__(auth_provider)
+        self.service = CONF.compute.catalog_type
+        self.build_interval = build_interval
+        self.build_timeout = build_timeout
diff --git a/tempest/services/compute/json/certificates_client.py b/tempest/services/compute/json/certificates_client.py
index 356ded2..123f0b9 100644
--- a/tempest/services/compute/json/certificates_client.py
+++ b/tempest/services/compute/json/certificates_client.py
@@ -17,17 +17,10 @@
 
 from tempest.api_schema.response.compute import certificates as schema
 from tempest.api_schema.response.compute.v2 import certificates as v2schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class CertificatesClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(CertificatesClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class CertificatesClientJSON(base.ComputeClient):
 
     def get_certificate(self, id):
         url = "os-certificates/%s" % (id)
diff --git a/tempest/services/compute/json/extensions_client.py b/tempest/services/compute/json/extensions_client.py
index 41d1c4e..69ad7c0 100644
--- a/tempest/services/compute/json/extensions_client.py
+++ b/tempest/services/compute/json/extensions_client.py
@@ -16,17 +16,10 @@
 import json
 
 from tempest.api_schema.response.compute.v2 import extensions as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class ExtensionsClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(ExtensionsClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class ExtensionsClientJSON(base.ComputeClient):
 
     def list_extensions(self):
         url = 'extensions'
diff --git a/tempest/services/compute/json/fixed_ips_client.py b/tempest/services/compute/json/fixed_ips_client.py
index 5903334..8fd24b6 100644
--- a/tempest/services/compute/json/fixed_ips_client.py
+++ b/tempest/services/compute/json/fixed_ips_client.py
@@ -16,17 +16,10 @@
 import json
 
 from tempest.api_schema.response.compute.v2 import fixed_ips as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class FixedIPsClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(FixedIPsClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class FixedIPsClientJSON(base.ComputeClient):
 
     def get_fixed_ip_details(self, fixed_ip):
         url = "os-fixed-ips/%s" % (fixed_ip)
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index 8faf8a7..6276d3c 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -21,17 +21,10 @@
 from tempest.api_schema.response.compute import flavors_extra_specs \
     as schema_extra_specs
 from tempest.api_schema.response.compute.v2 import flavors as v2schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class FlavorsClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(FlavorsClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class FlavorsClientJSON(base.ComputeClient):
 
     def list_flavors(self, params=None):
         url = 'flavors'
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index 0ed1720..788b4d2 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -17,17 +17,11 @@
 import urllib
 
 from tempest.api_schema.response.compute.v2 import floating_ips as schema
-from tempest.common import rest_client
-from tempest import config
 from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class FloatingIPsClientJSON(rest_client.RestClient):
-    def __init__(self, auth_provider):
-        super(FloatingIPsClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class FloatingIPsClientJSON(base.ComputeClient):
 
     def list_floating_ips(self, params=None):
         """Returns a list of all floating IPs filtered by any parameters."""
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index 8644173..5d306f9 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -17,17 +17,10 @@
 
 from tempest.api_schema.response.compute import hosts as schema
 from tempest.api_schema.response.compute.v2 import hosts as v2_schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class HostsClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(HostsClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class HostsClientJSON(base.ComputeClient):
 
     def list_hosts(self, params=None):
         """Lists all hosts."""
diff --git a/tempest/services/compute/json/hypervisor_client.py b/tempest/services/compute/json/hypervisor_client.py
index 8eacf61..52b50c8 100644
--- a/tempest/services/compute/json/hypervisor_client.py
+++ b/tempest/services/compute/json/hypervisor_client.py
@@ -17,17 +17,10 @@
 
 from tempest.api_schema.response.compute import hypervisors as common_schema
 from tempest.api_schema.response.compute.v2 import hypervisors as v2schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class HypervisorClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(HypervisorClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class HypervisorClientJSON(base.ComputeClient):
 
     def get_hypervisor_list(self):
         """List hypervisors information."""
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index 079a91e..a4cfe57 100644
--- a/tempest/services/compute/json/images_client.py
+++ b/tempest/services/compute/json/images_client.py
@@ -17,21 +17,12 @@
 import urllib
 
 from tempest.api_schema.response.compute.v2 import images as schema
-from tempest.common import rest_client
 from tempest.common import waiters
-from tempest import config
 from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class ImagesClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(ImagesClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
-        self.build_interval = CONF.compute.build_interval
-        self.build_timeout = CONF.compute.build_timeout
+class ImagesClientJSON(base.ComputeClient):
 
     def create_image(self, server_id, name, meta=None):
         """Creates an image of the original server."""
diff --git a/tempest/services/compute/json/instance_usage_audit_log_client.py b/tempest/services/compute/json/instance_usage_audit_log_client.py
index 4b0362b..f79c3de 100644
--- a/tempest/services/compute/json/instance_usage_audit_log_client.py
+++ b/tempest/services/compute/json/instance_usage_audit_log_client.py
@@ -17,18 +17,10 @@
 
 from tempest.api_schema.response.compute.v2 import instance_usage_audit_logs \
     as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class InstanceUsagesAuditLogClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(InstanceUsagesAuditLogClientJSON, self).__init__(
-            auth_provider)
-        self.service = CONF.compute.catalog_type
+class InstanceUsagesAuditLogClientJSON(base.ComputeClient):
 
     def list_instance_usage_audit_logs(self):
         url = 'os-instance_usage_audit_log'
diff --git a/tempest/services/compute/json/interfaces_client.py b/tempest/services/compute/json/interfaces_client.py
index 620ed68..f1e2660 100644
--- a/tempest/services/compute/json/interfaces_client.py
+++ b/tempest/services/compute/json/interfaces_client.py
@@ -19,18 +19,11 @@
 from tempest.api_schema.response.compute import interfaces as common_schema
 from tempest.api_schema.response.compute import servers as servers_schema
 from tempest.api_schema.response.compute.v2 import interfaces as schema
-from tempest.common import rest_client
-from tempest import config
 from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class InterfacesClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(InterfacesClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class InterfacesClientJSON(base.ComputeClient):
 
     def list_interfaces(self, server):
         resp, body = self.get('servers/%s/os-interface' % server)
diff --git a/tempest/services/compute/json/keypairs_client.py b/tempest/services/compute/json/keypairs_client.py
index 31c42a5..c4406f5 100644
--- a/tempest/services/compute/json/keypairs_client.py
+++ b/tempest/services/compute/json/keypairs_client.py
@@ -17,17 +17,10 @@
 
 from tempest.api_schema.response.compute import keypairs as common_schema
 from tempest.api_schema.response.compute.v2 import keypairs as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class KeyPairsClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(KeyPairsClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class KeyPairsClientJSON(base.ComputeClient):
 
     def list_keypairs(self):
         resp, body = self.get("os-keypairs")
diff --git a/tempest/services/compute/json/limits_client.py b/tempest/services/compute/json/limits_client.py
index 81c602b..66a0649 100644
--- a/tempest/services/compute/json/limits_client.py
+++ b/tempest/services/compute/json/limits_client.py
@@ -16,17 +16,10 @@
 import json
 
 from tempest.api_schema.response.compute.v2 import limits as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class LimitsClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(LimitsClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class LimitsClientJSON(base.ComputeClient):
 
     def get_absolute_limits(self):
         resp, body = self.get("limits")
diff --git a/tempest/services/compute/json/migrations_client.py b/tempest/services/compute/json/migrations_client.py
index f4abbb2..de183f1 100644
--- a/tempest/services/compute/json/migrations_client.py
+++ b/tempest/services/compute/json/migrations_client.py
@@ -16,17 +16,10 @@
 import urllib
 
 from tempest.api_schema.response.compute import migrations as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class MigrationsClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(MigrationsClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class MigrationsClientJSON(base.ComputeClient):
 
     def list_migrations(self, params=None):
         """Lists all migrations."""
diff --git a/tempest/services/compute/json/networks_client.py b/tempest/services/compute/json/networks_client.py
index 40eb1a6..5a2744d 100644
--- a/tempest/services/compute/json/networks_client.py
+++ b/tempest/services/compute/json/networks_client.py
@@ -15,17 +15,10 @@
 
 import json
 
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class NetworksClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(NetworksClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class NetworksClientJSON(base.ComputeClient):
 
     def list_networks(self):
         resp, body = self.get("os-networks")
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index b691529..0fee57a 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -18,17 +18,10 @@
 from tempest.api_schema.response.compute.v2\
     import quota_classes as classes_schema
 from tempest.api_schema.response.compute.v2 import quotas as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class QuotasClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(QuotasClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class QuotasClientJSON(base.ComputeClient):
 
     def get_quota_set(self, tenant_id, user_id=None):
         """List the quota set for a tenant."""
@@ -122,11 +115,7 @@
         return resp, body
 
 
-class QuotaClassesClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(QuotaClassesClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class QuotaClassesClientJSON(base.ComputeClient):
 
     def get_quota_class_set(self, quota_class_id):
         """List the quota class set for a quota class."""
diff --git a/tempest/services/compute/json/security_group_default_rules_client.py b/tempest/services/compute/json/security_group_default_rules_client.py
index 7743f9c..efaf329 100644
--- a/tempest/services/compute/json/security_group_default_rules_client.py
+++ b/tempest/services/compute/json/security_group_default_rules_client.py
@@ -17,18 +17,10 @@
 
 from tempest.api_schema.response.compute.v2 import \
     security_group_default_rule as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class SecurityGroupDefaultRulesClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(SecurityGroupDefaultRulesClientJSON,
-              self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class SecurityGroupDefaultRulesClientJSON(base.ComputeClient):
 
     def create_security_default_group_rule(self, ip_protocol, from_port,
                                            to_port, **kwargs):
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index 733a50b..a301a0f 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -17,18 +17,11 @@
 import urllib
 
 from tempest.api_schema.response.compute.v2 import security_groups as schema
-from tempest.common import rest_client
-from tempest import config
 from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class SecurityGroupsClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(SecurityGroupsClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class SecurityGroupsClientJSON(base.ComputeClient):
 
     def list_security_groups(self, params=None):
         """List all security groups for a user."""
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 4268b1a..400f9a7 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -20,20 +20,15 @@
 
 from tempest.api_schema.response.compute import servers as common_schema
 from tempest.api_schema.response.compute.v2 import servers as schema
-from tempest.common import rest_client
 from tempest.common import waiters
 from tempest import config
 from tempest import exceptions
+from tempest.services.compute.json import base
 
 CONF = config.CONF
 
 
-class ServersClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(ServersClientJSON, self).__init__(auth_provider)
-
-        self.service = CONF.compute.catalog_type
+class ServersClientJSON(base.ComputeClient):
 
     def create_server(self, name, image_ref, flavor_ref, **kwargs):
         """
diff --git a/tempest/services/compute/json/services_client.py b/tempest/services/compute/json/services_client.py
index e56263c..8d73c37 100644
--- a/tempest/services/compute/json/services_client.py
+++ b/tempest/services/compute/json/services_client.py
@@ -18,17 +18,10 @@
 import urllib
 
 from tempest.api_schema.response.compute import services as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class ServicesClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(ServicesClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class ServicesClientJSON(base.ComputeClient):
 
     def list_services(self, params=None):
         url = 'os-services'
diff --git a/tempest/services/compute/json/tenant_usages_client.py b/tempest/services/compute/json/tenant_usages_client.py
index a0b9b4a..eac23bb 100644
--- a/tempest/services/compute/json/tenant_usages_client.py
+++ b/tempest/services/compute/json/tenant_usages_client.py
@@ -17,17 +17,10 @@
 import urllib
 
 from tempest.api_schema.response.compute.v2 import tenant_usages as schema
-from tempest.common import rest_client
-from tempest import config
-
-CONF = config.CONF
+from tempest.services.compute.json import base
 
 
-class TenantUsagesClientJSON(rest_client.RestClient):
-
-    def __init__(self, auth_provider):
-        super(TenantUsagesClientJSON, self).__init__(auth_provider)
-        self.service = CONF.compute.catalog_type
+class TenantUsagesClientJSON(base.ComputeClient):
 
     def list_tenant_usages(self, params=None):
         url = 'os-simple-tenant-usage'
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index afa6937..69b9bea 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -18,21 +18,20 @@
 import urllib
 
 from tempest.api_schema.response.compute.v2 import volumes as schema
-from tempest.common import rest_client
 from tempest import config
 from tempest import exceptions
+from tempest.services.compute.json import base
 
 CONF = config.CONF
 
 
-class VolumesExtensionsClientJSON(rest_client.RestClient):
+class VolumesExtensionsClientJSON(base.ComputeClient):
 
     def __init__(self, auth_provider):
         super(VolumesExtensionsClientJSON, self).__init__(
-            auth_provider)
-        self.service = CONF.compute.catalog_type
-        self.build_interval = CONF.volume.build_interval
-        self.build_timeout = CONF.volume.build_timeout
+            auth_provider,
+            build_interval=CONF.volume.build_interval,
+            build_timeout=CONF.volume.build_timeout)
 
     def list_volumes(self, params=None):
         """List all the volumes created."""
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 0a9a1fa..c622ee4 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -11,12 +11,18 @@
 #    under the License.
 
 import json
+import time
+import urllib
 
 from tempest.common import rest_client
-from tempest.services.network import network_client_base
+from tempest.common.utils import misc
+from tempest import config
+from tempest import exceptions
+
+CONF = config.CONF
 
 
-class NetworkClientJSON(network_client_base.NetworkClientBase):
+class NetworkClientJSON(rest_client.RestClient):
 
     """
     Tempest REST client for Neutron. Uses v2 of the Neutron API, since the
@@ -31,8 +37,228 @@
     quotas
     """
 
-    def get_rest_client(self, auth_provider):
-        return rest_client.RestClient(auth_provider)
+    def __init__(self, auth_provider):
+        super(NetworkClientJSON, self).__init__(auth_provider)
+        self.service = CONF.network.catalog_type
+        self.build_timeout = CONF.network.build_timeout
+        self.build_interval = CONF.network.build_interval
+        self.version = '2.0'
+        self.uri_prefix = "v%s" % (self.version)
+
+    def get_uri(self, plural_name):
+        # get service prefix from resource name
+
+        # The following list represents resource names that do not require
+        # changing underscore to a hyphen
+        hyphen_exceptions = ["health_monitors", "firewall_rules",
+                             "firewall_policies"]
+        # the following map is used to construct proper URI
+        # for the given neutron resource
+        service_resource_prefix_map = {
+            'networks': '',
+            'subnets': '',
+            'ports': '',
+            'pools': 'lb',
+            'vips': 'lb',
+            'health_monitors': 'lb',
+            'members': 'lb',
+            'ipsecpolicies': 'vpn',
+            'vpnservices': 'vpn',
+            'ikepolicies': 'vpn',
+            'ipsecpolicies': 'vpn',
+            'metering_labels': 'metering',
+            'metering_label_rules': 'metering',
+            'firewall_rules': 'fw',
+            'firewall_policies': 'fw',
+            'firewalls': 'fw'
+        }
+        service_prefix = service_resource_prefix_map.get(
+            plural_name)
+        if plural_name not in hyphen_exceptions:
+            plural_name = plural_name.replace("_", "-")
+        if service_prefix:
+            uri = '%s/%s/%s' % (self.uri_prefix, service_prefix,
+                                plural_name)
+        else:
+            uri = '%s/%s' % (self.uri_prefix, plural_name)
+        return uri
+
+    def pluralize(self, resource_name):
+        # get plural from map or just add 's'
+
+        # map from resource name to a plural name
+        # needed only for those which can't be constructed as name + 's'
+        resource_plural_map = {
+            'security_groups': 'security_groups',
+            'security_group_rules': 'security_group_rules',
+            'ipsecpolicy': 'ipsecpolicies',
+            'ikepolicy': 'ikepolicies',
+            'ipsecpolicy': 'ipsecpolicies',
+            'quotas': 'quotas',
+            'firewall_policy': 'firewall_policies'
+        }
+        return resource_plural_map.get(resource_name, resource_name + 's')
+
+    def _lister(self, plural_name):
+        def _list(**filters):
+            uri = self.get_uri(plural_name)
+            if filters:
+                uri += '?' + urllib.urlencode(filters, doseq=1)
+            resp, body = self.get(uri)
+            result = {plural_name: self.deserialize_list(body)}
+            self.expected_success(200, resp.status)
+            return rest_client.ResponseBody(resp, result)
+
+        return _list
+
+    def _deleter(self, resource_name):
+        def _delete(resource_id):
+            plural = self.pluralize(resource_name)
+            uri = '%s/%s' % (self.get_uri(plural), resource_id)
+            resp, body = self.delete(uri)
+            self.expected_success(204, resp.status)
+            return rest_client.ResponseBody(resp, body)
+
+        return _delete
+
+    def _shower(self, resource_name):
+        def _show(resource_id, **fields):
+            # fields is a dict which key is 'fields' and value is a
+            # list of field's name. An example:
+            # {'fields': ['id', 'name']}
+            plural = self.pluralize(resource_name)
+            uri = '%s/%s' % (self.get_uri(plural), resource_id)
+            if fields:
+                uri += '?' + urllib.urlencode(fields, doseq=1)
+            resp, body = self.get(uri)
+            body = self.deserialize_single(body)
+            self.expected_success(200, resp.status)
+            return rest_client.ResponseBody(resp, body)
+
+        return _show
+
+    def _creater(self, resource_name):
+        def _create(**kwargs):
+            plural = self.pluralize(resource_name)
+            uri = self.get_uri(plural)
+            post_data = self.serialize({resource_name: kwargs})
+            resp, body = self.post(uri, post_data)
+            body = self.deserialize_single(body)
+            self.expected_success(201, resp.status)
+            return rest_client.ResponseBody(resp, body)
+
+        return _create
+
+    def _updater(self, resource_name):
+        def _update(res_id, **kwargs):
+            plural = self.pluralize(resource_name)
+            uri = '%s/%s' % (self.get_uri(plural), res_id)
+            post_data = self.serialize({resource_name: kwargs})
+            resp, body = self.put(uri, post_data)
+            body = self.deserialize_single(body)
+            self.expected_success(200, resp.status)
+            return rest_client.ResponseBody(resp, body)
+
+        return _update
+
+    def __getattr__(self, name):
+        method_prefixes = ["list_", "delete_", "show_", "create_", "update_"]
+        method_functors = [self._lister,
+                           self._deleter,
+                           self._shower,
+                           self._creater,
+                           self._updater]
+        for index, prefix in enumerate(method_prefixes):
+            prefix_len = len(prefix)
+            if name[:prefix_len] == prefix:
+                return method_functors[index](name[prefix_len:])
+        raise AttributeError(name)
+
+    # Common methods that are hard to automate
+    def create_bulk_network(self, names):
+        network_list = [{'name': name} for name in names]
+        post_data = {'networks': network_list}
+        body = self.serialize_list(post_data, "networks", "network")
+        uri = self.get_uri("networks")
+        resp, body = self.post(uri, body)
+        body = {'networks': self.deserialize_list(body)}
+        self.expected_success(201, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_bulk_subnet(self, subnet_list):
+        post_data = {'subnets': subnet_list}
+        body = self.serialize_list(post_data, 'subnets', 'subnet')
+        uri = self.get_uri('subnets')
+        resp, body = self.post(uri, body)
+        body = {'subnets': self.deserialize_list(body)}
+        self.expected_success(201, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def create_bulk_port(self, port_list):
+        post_data = {'ports': port_list}
+        body = self.serialize_list(post_data, 'ports', 'port')
+        uri = self.get_uri('ports')
+        resp, body = self.post(uri, body)
+        body = {'ports': self.deserialize_list(body)}
+        self.expected_success(201, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def wait_for_resource_deletion(self, resource_type, id):
+        """Waits for a resource to be deleted."""
+        start_time = int(time.time())
+        while True:
+            if self.is_resource_deleted(resource_type, id):
+                return
+            if int(time.time()) - start_time >= self.build_timeout:
+                raise exceptions.TimeoutException
+            time.sleep(self.build_interval)
+
+    def is_resource_deleted(self, resource_type, id):
+        method = 'show_' + resource_type
+        try:
+            getattr(self, method)(id)
+        except AttributeError:
+            raise Exception("Unknown resource type %s " % resource_type)
+        except exceptions.NotFound:
+            return True
+        return False
+
+    def wait_for_resource_status(self, fetch, status, interval=None,
+                                 timeout=None):
+        """
+        @summary: Waits for a network resource to reach a status
+        @param fetch: the callable to be used to query the resource status
+        @type fecth: callable that takes no parameters and returns the resource
+        @param status: the status that the resource has to reach
+        @type status: String
+        @param interval: the number of seconds to wait between each status
+          query
+        @type interval: Integer
+        @param timeout: the maximum number of seconds to wait for the resource
+          to reach the desired status
+        @type timeout: Integer
+        """
+        if not interval:
+            interval = self.build_interval
+        if not timeout:
+            timeout = self.build_timeout
+        start_time = time.time()
+
+        while time.time() - start_time <= timeout:
+            resource = fetch()
+            if resource['status'] == status:
+                return
+            time.sleep(interval)
+
+        # At this point, the wait has timed out
+        message = 'Resource %s' % (str(resource))
+        message += ' failed to reach status %s' % status
+        message += ' (current: %s)' % resource['status']
+        message += ' within the required time %s' % timeout
+        caller = misc.find_test_caller()
+        if caller:
+            message = '(%s) %s' % (caller, message)
+        raise exceptions.TimeoutException(message)
 
     def deserialize_single(self, body):
         return json.loads(body)
@@ -59,14 +285,14 @@
         body = json.dumps(put_body)
         uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
         resp, body = self.put(uri, body)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body['quota'])
 
     def reset_quotas(self, tenant_id):
         uri = '%s/quotas/%s' % (self.uri_prefix, tenant_id)
         resp, body = self.delete(uri)
-        self.rest_client.expected_success(204, resp.status)
+        self.expected_success(204, resp.status)
         return rest_client.ResponseBody(resp, body)
 
     def create_router(self, name, admin_state_up=True, **kwargs):
@@ -76,14 +302,14 @@
         body = json.dumps(post_body)
         uri = '%s/routers' % (self.uri_prefix)
         resp, body = self.post(uri, body)
-        self.rest_client.expected_success(201, resp.status)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
     def _update_router(self, router_id, set_enable_snat, **kwargs):
         uri = '%s/routers/%s' % (self.uri_prefix, router_id)
         resp, body = self.get(uri)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         update_body = {}
         update_body['name'] = kwargs.get('name', body['router']['name'])
@@ -103,7 +329,7 @@
         update_body = dict(router=update_body)
         update_body = json.dumps(update_body)
         resp, body = self.put(uri, update_body)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -130,7 +356,7 @@
         update_body = {"subnet_id": subnet_id}
         update_body = json.dumps(update_body)
         resp, body = self.put(uri, update_body)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -140,7 +366,7 @@
         update_body = {"port_id": port_id}
         update_body = json.dumps(update_body)
         resp, body = self.put(uri, update_body)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -150,7 +376,7 @@
         update_body = {"subnet_id": subnet_id}
         update_body = json.dumps(update_body)
         resp, body = self.put(uri, update_body)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -160,7 +386,7 @@
         update_body = {"port_id": port_id}
         update_body = json.dumps(update_body)
         resp, body = self.put(uri, update_body)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -175,7 +401,7 @@
         uri = '%s/lb/pools/%s/health_monitors' % (self.uri_prefix,
                                                   pool_id)
         resp, body = self.post(uri, body)
-        self.rest_client.expected_success(201, resp.status)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -184,13 +410,13 @@
         uri = '%s/lb/pools/%s/health_monitors/%s' % (self.uri_prefix, pool_id,
                                                      health_monitor_id)
         resp, body = self.delete(uri)
-        self.rest_client.expected_success(204, resp.status)
+        self.expected_success(204, resp.status)
         return rest_client.ResponseBody(resp, body)
 
     def list_router_interfaces(self, uuid):
         uri = '%s/ports?device_id=%s' % (self.uri_prefix, uuid)
         resp, body = self.get(uri)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -203,14 +429,14 @@
         agent = {"agent": agent_info}
         body = json.dumps(agent)
         resp, body = self.put(uri, body)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
     def list_pools_hosted_by_one_lbaas_agent(self, agent_id):
         uri = '%s/agents/%s/loadbalancer-pools' % (self.uri_prefix, agent_id)
         resp, body = self.get(uri)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -218,21 +444,21 @@
         uri = ('%s/lb/pools/%s/loadbalancer-agent' %
                (self.uri_prefix, pool_id))
         resp, body = self.get(uri)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
     def list_routers_on_l3_agent(self, agent_id):
         uri = '%s/agents/%s/l3-routers' % (self.uri_prefix, agent_id)
         resp, body = self.get(uri)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
     def list_l3_agents_hosting_router(self, router_id):
         uri = '%s/routers/%s/l3-agents' % (self.uri_prefix, router_id)
         resp, body = self.get(uri)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -241,7 +467,7 @@
         post_body = {"router_id": router_id}
         body = json.dumps(post_body)
         resp, body = self.post(uri, body)
-        self.rest_client.expected_success(201, resp.status)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -249,20 +475,20 @@
         uri = '%s/agents/%s/l3-routers/%s' % (
             self.uri_prefix, agent_id, router_id)
         resp, body = self.delete(uri)
-        self.rest_client.expected_success(204, resp.status)
+        self.expected_success(204, resp.status)
         return rest_client.ResponseBody(resp, body)
 
     def list_dhcp_agent_hosting_network(self, network_id):
         uri = '%s/networks/%s/dhcp-agents' % (self.uri_prefix, network_id)
         resp, body = self.get(uri)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
     def list_networks_hosted_by_one_dhcp_agent(self, agent_id):
         uri = '%s/agents/%s/dhcp-networks' % (self.uri_prefix, agent_id)
         resp, body = self.get(uri)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -270,7 +496,7 @@
         uri = '%s/agents/%s/dhcp-networks/%s' % (self.uri_prefix, agent_id,
                                                  network_id)
         resp, body = self.delete(uri)
-        self.rest_client.expected_success(204, resp.status)
+        self.expected_success(204, resp.status)
         return rest_client.ResponseBody(resp, body)
 
     def create_ikepolicy(self, name, **kwargs):
@@ -284,7 +510,7 @@
         body = json.dumps(post_body)
         uri = '%s/vpn/ikepolicies' % (self.uri_prefix)
         resp, body = self.post(uri, body)
-        self.rest_client.expected_success(201, resp.status)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -298,7 +524,7 @@
         }
         body = json.dumps(put_body)
         resp, body = self.put(uri, body)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -312,14 +538,14 @@
         }
         body = json.dumps(put_body)
         resp, body = self.put(uri, body)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
     def list_lb_pool_stats(self, pool_id):
         uri = '%s/lb/pools/%s/stats' % (self.uri_prefix, pool_id)
         resp, body = self.get(uri)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -328,7 +554,7 @@
         body = json.dumps(post_body)
         uri = '%s/agents/%s/dhcp-networks' % (self.uri_prefix, agent_id)
         resp, body = self.post(uri, body)
-        self.rest_client.expected_success(201, resp.status)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -344,7 +570,7 @@
         }
         body = json.dumps(body)
         resp, body = self.put(uri, body)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
@@ -355,6 +581,6 @@
         update_body = {"firewall_rule_id": firewall_rule_id}
         update_body = json.dumps(update_body)
         resp, body = self.put(uri, update_body)
-        self.rest_client.expected_success(200, resp.status)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/network/network_client_base.py b/tempest/services/network/network_client_base.py
deleted file mode 100644
index 53fd222..0000000
--- a/tempest/services/network/network_client_base.py
+++ /dev/null
@@ -1,268 +0,0 @@
-#    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 time
-import urllib
-
-from tempest.common import rest_client
-from tempest.common.utils import misc
-from tempest import config
-from tempest import exceptions
-
-CONF = config.CONF
-
-# the following map is used to construct proper URI
-# for the given neutron resource
-service_resource_prefix_map = {
-    'networks': '',
-    'subnets': '',
-    'ports': '',
-    'pools': 'lb',
-    'vips': 'lb',
-    'health_monitors': 'lb',
-    'members': 'lb',
-    'ipsecpolicies': 'vpn',
-    'vpnservices': 'vpn',
-    'ikepolicies': 'vpn',
-    'ipsecpolicies': 'vpn',
-    'metering_labels': 'metering',
-    'metering_label_rules': 'metering',
-    'firewall_rules': 'fw',
-    'firewall_policies': 'fw',
-    'firewalls': 'fw'
-}
-
-# The following list represents resource names that do not require
-# changing underscore to a hyphen
-hyphen_exceptions = ["health_monitors", "firewall_rules", "firewall_policies"]
-
-# map from resource name to a plural name
-# needed only for those which can't be constructed as name + 's'
-resource_plural_map = {
-    'security_groups': 'security_groups',
-    'security_group_rules': 'security_group_rules',
-    'ipsecpolicy': 'ipsecpolicies',
-    'ikepolicy': 'ikepolicies',
-    'ipsecpolicy': 'ipsecpolicies',
-    'quotas': 'quotas',
-    'firewall_policy': 'firewall_policies'
-}
-
-
-class NetworkClientBase(object):
-    def __init__(self, auth_provider):
-        self.rest_client = self.get_rest_client(
-            auth_provider)
-        self.rest_client.service = CONF.network.catalog_type
-        self.version = '2.0'
-        self.uri_prefix = "v%s" % (self.version)
-        self.build_timeout = CONF.network.build_timeout
-        self.build_interval = CONF.network.build_interval
-
-    def get_rest_client(self, auth_provider):
-        raise NotImplementedError
-
-    def post(self, uri, body, headers=None):
-        return self.rest_client.post(uri, body, headers)
-
-    def put(self, uri, body, headers=None):
-        return self.rest_client.put(uri, body, headers)
-
-    def get(self, uri, headers=None):
-        return self.rest_client.get(uri, headers)
-
-    def delete(self, uri, headers=None):
-        return self.rest_client.delete(uri, headers)
-
-    def deserialize_list(self, body):
-        raise NotImplementedError
-
-    def deserialize_single(self, body):
-        raise NotImplementedError
-
-    def get_uri(self, plural_name):
-        # get service prefix from resource name
-        service_prefix = service_resource_prefix_map.get(
-            plural_name)
-        if plural_name not in hyphen_exceptions:
-            plural_name = plural_name.replace("_", "-")
-        if service_prefix:
-            uri = '%s/%s/%s' % (self.uri_prefix, service_prefix,
-                                plural_name)
-        else:
-            uri = '%s/%s' % (self.uri_prefix, plural_name)
-        return uri
-
-    def pluralize(self, resource_name):
-        # get plural from map or just add 's'
-        return resource_plural_map.get(resource_name, resource_name + 's')
-
-    def _lister(self, plural_name):
-        def _list(**filters):
-            uri = self.get_uri(plural_name)
-            if filters:
-                uri += '?' + urllib.urlencode(filters, doseq=1)
-            resp, body = self.get(uri)
-            result = {plural_name: self.deserialize_list(body)}
-            self.rest_client.expected_success(200, resp.status)
-            return rest_client.ResponseBody(resp, result)
-
-        return _list
-
-    def _deleter(self, resource_name):
-        def _delete(resource_id):
-            plural = self.pluralize(resource_name)
-            uri = '%s/%s' % (self.get_uri(plural), resource_id)
-            resp, body = self.delete(uri)
-            self.rest_client.expected_success(204, resp.status)
-            return rest_client.ResponseBody(resp, body)
-
-        return _delete
-
-    def _shower(self, resource_name):
-        def _show(resource_id, **fields):
-            # fields is a dict which key is 'fields' and value is a
-            # list of field's name. An example:
-            # {'fields': ['id', 'name']}
-            plural = self.pluralize(resource_name)
-            uri = '%s/%s' % (self.get_uri(plural), resource_id)
-            if fields:
-                uri += '?' + urllib.urlencode(fields, doseq=1)
-            resp, body = self.get(uri)
-            body = self.deserialize_single(body)
-            self.rest_client.expected_success(200, resp.status)
-            return rest_client.ResponseBody(resp, body)
-
-        return _show
-
-    def _creater(self, resource_name):
-        def _create(**kwargs):
-            plural = self.pluralize(resource_name)
-            uri = self.get_uri(plural)
-            post_data = self.serialize({resource_name: kwargs})
-            resp, body = self.post(uri, post_data)
-            body = self.deserialize_single(body)
-            self.rest_client.expected_success(201, resp.status)
-            return rest_client.ResponseBody(resp, body)
-
-        return _create
-
-    def _updater(self, resource_name):
-        def _update(res_id, **kwargs):
-            plural = self.pluralize(resource_name)
-            uri = '%s/%s' % (self.get_uri(plural), res_id)
-            post_data = self.serialize({resource_name: kwargs})
-            resp, body = self.put(uri, post_data)
-            body = self.deserialize_single(body)
-            self.rest_client.expected_success(200, resp.status)
-            return rest_client.ResponseBody(resp, body)
-
-        return _update
-
-    def __getattr__(self, name):
-        method_prefixes = ["list_", "delete_", "show_", "create_", "update_"]
-        method_functors = [self._lister,
-                           self._deleter,
-                           self._shower,
-                           self._creater,
-                           self._updater]
-        for index, prefix in enumerate(method_prefixes):
-            prefix_len = len(prefix)
-            if name[:prefix_len] == prefix:
-                return method_functors[index](name[prefix_len:])
-        raise AttributeError(name)
-
-    # Common methods that are hard to automate
-    def create_bulk_network(self, names):
-        network_list = [{'name': name} for name in names]
-        post_data = {'networks': network_list}
-        body = self.serialize_list(post_data, "networks", "network")
-        uri = self.get_uri("networks")
-        resp, body = self.post(uri, body)
-        body = {'networks': self.deserialize_list(body)}
-        self.rest_client.expected_success(201, resp.status)
-        return rest_client.ResponseBody(resp, body)
-
-    def create_bulk_subnet(self, subnet_list):
-        post_data = {'subnets': subnet_list}
-        body = self.serialize_list(post_data, 'subnets', 'subnet')
-        uri = self.get_uri('subnets')
-        resp, body = self.post(uri, body)
-        body = {'subnets': self.deserialize_list(body)}
-        self.rest_client.expected_success(201, resp.status)
-        return rest_client.ResponseBody(resp, body)
-
-    def create_bulk_port(self, port_list):
-        post_data = {'ports': port_list}
-        body = self.serialize_list(post_data, 'ports', 'port')
-        uri = self.get_uri('ports')
-        resp, body = self.post(uri, body)
-        body = {'ports': self.deserialize_list(body)}
-        self.rest_client.expected_success(201, resp.status)
-        return rest_client.ResponseBody(resp, body)
-
-    def wait_for_resource_deletion(self, resource_type, id):
-        """Waits for a resource to be deleted."""
-        start_time = int(time.time())
-        while True:
-            if self.is_resource_deleted(resource_type, id):
-                return
-            if int(time.time()) - start_time >= self.build_timeout:
-                raise exceptions.TimeoutException
-            time.sleep(self.build_interval)
-
-    def is_resource_deleted(self, resource_type, id):
-        method = 'show_' + resource_type
-        try:
-            getattr(self, method)(id)
-        except AttributeError:
-            raise Exception("Unknown resource type %s " % resource_type)
-        except exceptions.NotFound:
-            return True
-        return False
-
-    def wait_for_resource_status(self, fetch, status, interval=None,
-                                 timeout=None):
-        """
-        @summary: Waits for a network resource to reach a status
-        @param fetch: the callable to be used to query the resource status
-        @type fecth: callable that takes no parameters and returns the resource
-        @param status: the status that the resource has to reach
-        @type status: String
-        @param interval: the number of seconds to wait between each status
-          query
-        @type interval: Integer
-        @param timeout: the maximum number of seconds to wait for the resource
-          to reach the desired status
-        @type timeout: Integer
-        """
-        if not interval:
-            interval = self.build_interval
-        if not timeout:
-            timeout = self.build_timeout
-        start_time = time.time()
-
-        while time.time() - start_time <= timeout:
-            resource = fetch()
-            if resource['status'] == status:
-                return
-            time.sleep(interval)
-
-        # At this point, the wait has timed out
-        message = 'Resource %s' % (str(resource))
-        message += ' failed to reach status %s' % status
-        message += ' (current: %s)' % resource['status']
-        message += ' within the required time %s' % timeout
-        caller = misc.find_test_caller()
-        if caller:
-            message = '(%s) %s' % (caller, message)
-        raise exceptions.TimeoutException(message)
diff --git a/tempest/services/telemetry/json/telemetry_client.py b/tempest/services/telemetry/json/telemetry_client.py
index 996aceb..d2dd375 100644
--- a/tempest/services/telemetry/json/telemetry_client.py
+++ b/tempest/services/telemetry/json/telemetry_client.py
@@ -13,15 +13,22 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import urllib
+
 from tempest.common import rest_client
+from tempest import config
 from tempest.openstack.common import jsonutils as json
-import tempest.services.telemetry.telemetry_client_base as client
+
+CONF = config.CONF
 
 
-class TelemetryClientJSON(client.TelemetryClientBase):
+class TelemetryClientJSON(rest_client.RestClient):
 
-    def get_rest_client(self, auth_provider):
-        return rest_client.RestClient(auth_provider)
+    def __init__(self, auth_provider):
+        super(TelemetryClientJSON, self).__init__(auth_provider)
+        self.service = CONF.telemetry.catalog_type
+        self.version = '2'
+        self.uri_prefix = "v%s" % self.version
 
     def deserialize(self, body):
         return json.loads(body.replace("\n", ""))
@@ -42,4 +49,87 @@
 
     def create_sample(self, meter_name, sample_list):
         uri = "%s/meters/%s" % (self.uri_prefix, meter_name)
-        return self.post(uri, str(sample_list))
+        body = self.serialize(sample_list)
+        resp, body = self.post(uri, body)
+        body = self.deserialize(body)
+        return resp, body
+
+    def helper_list(self, uri, query=None, period=None):
+        uri_dict = {}
+        if query:
+            uri_dict = {'q.field': query[0],
+                        'q.op': query[1],
+                        'q.value': query[2]}
+        if period:
+            uri_dict['period'] = period
+        if uri_dict:
+            uri += "?%s" % urllib.urlencode(uri_dict)
+        resp, body = self.get(uri)
+        body = self.deserialize(body)
+        return resp, body
+
+    def list_resources(self, query=None):
+        uri = '%s/resources' % self.uri_prefix
+        return self.helper_list(uri, query)
+
+    def list_meters(self, query=None):
+        uri = '%s/meters' % self.uri_prefix
+        return self.helper_list(uri, query)
+
+    def list_alarms(self, query=None):
+        uri = '%s/alarms' % self.uri_prefix
+        return self.helper_list(uri, query)
+
+    def list_statistics(self, meter, period=None, query=None):
+        uri = "%s/meters/%s/statistics" % (self.uri_prefix, meter)
+        return self.helper_list(uri, query, period)
+
+    def list_samples(self, meter_id, query=None):
+        uri = '%s/meters/%s' % (self.uri_prefix, meter_id)
+        return self.helper_list(uri, query)
+
+    def get_resource(self, resource_id):
+        uri = '%s/resources/%s' % (self.uri_prefix, resource_id)
+        resp, body = self.get(uri)
+        body = self.deserialize(body)
+        return resp, body
+
+    def get_alarm(self, alarm_id):
+        uri = '%s/alarms/%s' % (self.uri_prefix, alarm_id)
+        resp, body = self.get(uri)
+        body = self.deserialize(body)
+        return resp, body
+
+    def delete_alarm(self, alarm_id):
+        uri = "%s/alarms/%s" % (self.uri_prefix, alarm_id)
+        resp, body = self.delete(uri)
+        if body:
+            body = self.deserialize(body)
+        return resp, body
+
+    def create_alarm(self, **kwargs):
+        uri = "%s/alarms" % self.uri_prefix
+        body = self.serialize(kwargs)
+        resp, body = self.post(uri, body)
+        body = self.deserialize(body)
+        return resp, body
+
+    def update_alarm(self, alarm_id, **kwargs):
+        uri = "%s/alarms/%s" % (self.uri_prefix, alarm_id)
+        body = self.serialize(kwargs)
+        resp, body = self.put(uri, body)
+        body = self.deserialize(body)
+        return resp, body
+
+    def alarm_get_state(self, alarm_id):
+        uri = "%s/alarms/%s/state" % (self.uri_prefix, alarm_id)
+        resp, body = self.get(uri)
+        body = self.deserialize(body)
+        return resp, body
+
+    def alarm_set_state(self, alarm_id, state):
+        uri = "%s/alarms/%s/state" % (self.uri_prefix, alarm_id)
+        body = self.serialize(state)
+        resp, body = self.put(uri, body)
+        body = self.deserialize(body)
+        return resp, body
diff --git a/tempest/services/telemetry/telemetry_client_base.py b/tempest/services/telemetry/telemetry_client_base.py
deleted file mode 100644
index a184a77..0000000
--- a/tempest/services/telemetry/telemetry_client_base.py
+++ /dev/null
@@ -1,151 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# 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 abc
-import urllib
-
-import six
-
-from tempest import config
-
-CONF = config.CONF
-
-
-@six.add_metaclass(abc.ABCMeta)
-class TelemetryClientBase(object):
-
-    """
-    Tempest REST client for Ceilometer V2 API.
-    Implements the following basic Ceilometer abstractions:
-    resources
-    meters
-    alarms
-    queries
-    statistics
-    """
-
-    def __init__(self, auth_provider):
-        self.rest_client = self.get_rest_client(auth_provider)
-        self.rest_client.service = CONF.telemetry.catalog_type
-        self.version = '2'
-        self.uri_prefix = "v%s" % self.version
-
-    @abc.abstractmethod
-    def get_rest_client(self, auth_provider):
-        """
-        :param config:
-        :param username:
-        :param password:
-        :param auth_url:
-        :param tenant_name:
-        :return: RestClient
-        """
-
-    @abc.abstractmethod
-    def deserialize(self, body):
-        """
-        :param body:
-        :return: Deserialize body
-        """
-
-    @abc.abstractmethod
-    def serialize(self, body):
-        """
-        :param body:
-        :return: Serialize body
-        """
-
-    def post(self, uri, body):
-        body = self.serialize(body)
-        resp, body = self.rest_client.post(uri, body)
-        body = self.deserialize(body)
-        return resp, body
-
-    def put(self, uri, body):
-        body = self.serialize(body)
-        resp, body = self.rest_client.put(uri, body)
-        body = self.deserialize(body)
-        return resp, body
-
-    def get(self, uri):
-        resp, body = self.rest_client.get(uri)
-        body = self.deserialize(body)
-        return resp, body
-
-    def delete(self, uri):
-        resp, body = self.rest_client.delete(uri)
-        if body:
-            body = self.deserialize(body)
-        return resp, body
-
-    def helper_list(self, uri, query=None, period=None):
-        uri_dict = {}
-        if query:
-            uri_dict = {'q.field': query[0],
-                        'q.op': query[1],
-                        'q.value': query[2]}
-        if period:
-            uri_dict['period'] = period
-        if uri_dict:
-            uri += "?%s" % urllib.urlencode(uri_dict)
-        return self.get(uri)
-
-    def list_resources(self, query=None):
-        uri = '%s/resources' % self.uri_prefix
-        return self.helper_list(uri, query)
-
-    def list_meters(self, query=None):
-        uri = '%s/meters' % self.uri_prefix
-        return self.helper_list(uri, query)
-
-    def list_alarms(self, query=None):
-        uri = '%s/alarms' % self.uri_prefix
-        return self.helper_list(uri, query)
-
-    def list_statistics(self, meter, period=None, query=None):
-        uri = "%s/meters/%s/statistics" % (self.uri_prefix, meter)
-        return self.helper_list(uri, query, period)
-
-    def list_samples(self, meter_id, query=None):
-        uri = '%s/meters/%s' % (self.uri_prefix, meter_id)
-        return self.helper_list(uri, query)
-
-    def get_resource(self, resource_id):
-        uri = '%s/resources/%s' % (self.uri_prefix, resource_id)
-        return self.get(uri)
-
-    def get_alarm(self, alarm_id):
-        uri = '%s/alarms/%s' % (self.uri_prefix, alarm_id)
-        return self.get(uri)
-
-    def delete_alarm(self, alarm_id):
-        uri = "%s/alarms/%s" % (self.uri_prefix, alarm_id)
-        return self.delete(uri)
-
-    def create_alarm(self, **kwargs):
-        uri = "%s/alarms" % self.uri_prefix
-        return self.post(uri, kwargs)
-
-    def update_alarm(self, alarm_id, **kwargs):
-        uri = "%s/alarms/%s" % (self.uri_prefix, alarm_id)
-        return self.put(uri, kwargs)
-
-    def alarm_get_state(self, alarm_id):
-        uri = "%s/alarms/%s/state" % (self.uri_prefix, alarm_id)
-        return self.get(uri)
-
-    def alarm_set_state(self, alarm_id, state):
-        uri = "%s/alarms/%s/state" % (self.uri_prefix, alarm_id)
-        return self.put(uri, state)
diff --git a/tempest/test.py b/tempest/test.py
index 886e7bb..ff829f3 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -274,8 +274,8 @@
             cls.resource_setup()
         except Exception:
             etype, value, trace = sys.exc_info()
-            LOG.info("%s in %s.setUpClass. Invoking tearDownClass." % (
-                cls.__name__, etype))
+            LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass." % (
+                     etype, cls.__name__))
             cls.tearDownClass()
             try:
                 raise etype, value, trace
diff --git a/tempest/tests/test_tenant_isolation.py b/tempest/tests/test_tenant_isolation.py
index f29ae5a..053dae1 100644
--- a/tempest/tests/test_tenant_isolation.py
+++ b/tempest/tests/test_tenant_isolation.py
@@ -320,8 +320,8 @@
 
         return_values = (fake_http.fake_httplib({}, status=204), {})
         remove_secgroup_mock = self.patch(
-            'tempest.services.network.network_client_base.'
-            'NetworkClientBase.delete', return_value=return_values)
+            'tempest.services.network.json.network_client.'
+            'NetworkClientJSON.delete', return_value=return_values)
         iso_creds.clear_isolated_creds()
         # Verify default security group delete
         calls = remove_secgroup_mock.mock_calls