Merge "Add "capabilities:" to multiple_backends extra-spec key"
diff --git a/README.rst b/README.rst
index 4393ae9..ea36619 100644
--- a/README.rst
+++ b/README.rst
@@ -130,3 +130,57 @@
 unittest2.TestSuite instead. See:
 
 https://code.google.com/p/unittest-ext/issues/detail?id=79
+
+Branchless Tempest Considerations
+---------------------------------
+
+Starting with the OpenStack Icehouse release Tempest no longer has any stable
+branches. This is to better ensure API consistency between releases because
+the API behavior should not change between releases. This means that the stable
+branches are also gated by the Tempest master branch, which also means that
+proposed commits to Tempest must work against both the master and all the
+currently supported stable branches of the projects. As such there are a few
+special considerations that have to be accounted for when pushing new changes
+to tempest.
+
+1. New Tests for new features
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When adding tests for new features that were not in previous releases of the
+projects the new test has to be properly skipped with a feature flag. Whether
+this is just as simple as using the @test.requires_ext() decorator to check
+if the required extension (or discoverable optional API) is enabled or adding
+a new config option to the appropriate section. If there isn't a method of
+selecting the new **feature** from the config file then there won't be a
+mechanism to disable the test with older stable releases and the new test won't
+be able to merge.
+
+2. Bug fix on core project needing Tempest changes
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When trying to land a bug fix which changes a tested API you'll have to use the
+following procedure::
+
+    - Propose change to the project, get a +2 on the change even with failing
+    - Propose skip on Tempest which will only be approved after the
+      corresponding change in the project has a +2 on change
+    - Land project change in master and all open stable branches (if required)
+    - Land changed test in Tempest
+
+Otherwise the bug fix won't be able to land in the project.
+
+3. New Tests for existing features
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If a test is being added for a feature that exists in all the current releases
+of the projects then the only concern is that the API behavior is the same
+across all the versions of the project being tested. If the behavior is not
+consistent the test will not be able to merge.
+
+API Stability
+-------------
+
+For new tests being added to Tempest the assumption is that the API being
+tested is considered stable and adheres to the OpenStack API stability
+guidelines. If an API is still considered experimental or in development then
+it should not be tested by Tempest until it is considered stable.
diff --git a/doc/source/index.rst b/doc/source/index.rst
index c45273e..25bc900 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -1,8 +1,3 @@
-.. Tempest documentation master file, created by
-   sphinx-quickstart on Tue May 21 17:43:32 2013.
-   You can adapt this file completely to your liking, but it should at least
-   contain the root `toctree` directive.
-
 =======================
 Tempest Testing Project
 =======================
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 9f2f924..8a7ad9c 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -23,47 +23,48 @@
 # of default WARNING level). (boolean value)
 #verbose=false
 
-# Log output to standard error (boolean value)
+# Log output to standard error. (boolean value)
 #use_stderr=true
 
-# format string to use for log messages with context (string
+# Format string to use for log messages with context. (string
 # value)
 #logging_context_format_string=%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s
 
-# format string to use for log messages without context
+# Format string to use for log messages without context.
 # (string value)
 #logging_default_format_string=%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s
 
-# data to append to log format when level is DEBUG (string
+# Data to append to log format when level is DEBUG. (string
 # value)
 #logging_debug_format_suffix=%(funcName)s %(pathname)s:%(lineno)d
 
-# prefix each line of exception output with this format
+# Prefix each line of exception output with this format.
 # (string value)
 #logging_exception_prefix=%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s
 
-# list of logger=LEVEL pairs (list value)
-#default_log_levels=amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,iso8601=WARN
+# List of logger=LEVEL pairs. (list value)
+#default_log_levels=amqp=WARN,amqplib=WARN,boto=WARN,qpid=WARN,sqlalchemy=WARN,suds=INFO,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN
 
-# publish error events (boolean value)
+# Enables or disables publication of error events. (boolean
+# value)
 #publish_errors=false
 
-# make deprecations fatal (boolean value)
+# Enables or disables fatal status of deprecations. (boolean
+# value)
 #fatal_deprecations=false
 
-# If an instance is passed with the log message, format it
-# like this (string value)
+# The format for an instance that is passed with the log
+# message. (string value)
 #instance_format="[instance: %(uuid)s] "
 
-# If an instance UUID is passed with the log message, format
-# it like this (string value)
+# The format for an instance UUID that is passed with the log
+# message. (string value)
 #instance_uuid_format="[instance: %(uuid)s] "
 
-# The name of logging configuration file. It does not disable
-# existing loggers, but just appends specified logging
-# configuration to any other existing logging options. Please
-# see the Python logging module documentation for details on
-# logging configuration files. (string value)
+# The name of a logging configuration file. This file is
+# appended to any existing logging configuration files. For
+# details about logging configuration files, see the Python
+# logging module documentation. (string value)
 # Deprecated group/name - [DEFAULT]/log_config
 #log_config_append=<None>
 
@@ -75,7 +76,7 @@
 #log_format=<None>
 
 # Format string for %%(asctime)s in log records. Default:
-# %(default)s (string value)
+# %(default)s . (string value)
 #log_date_format=%Y-%m-%d %H:%M:%S
 
 # (Optional) Name of log file to output to. If no default is
@@ -84,14 +85,23 @@
 #log_file=<None>
 
 # (Optional) The base directory used for relative --log-file
-# paths (string value)
+# paths. (string value)
 # Deprecated group/name - [DEFAULT]/logdir
 #log_dir=<None>
 
-# Use syslog for logging. (boolean value)
+# Use syslog for logging. Existing syslog format is DEPRECATED
+# during I, and will change in J to honor RFC5424. (boolean
+# value)
 #use_syslog=false
 
-# syslog facility to receive log lines (string value)
+# (Optional) Enables or disables syslog rfc5424 format for
+# logging. If enabled, prefixes the MSG part of the syslog
+# message with APP-NAME (RFC5424). The format without the APP-
+# NAME is deprecated in I, and will be removed in J. (boolean
+# value)
+#use_syslog_rfc_format=false
+
+# Syslog facility to receive log lines. (string value)
 #syslog_log_facility=LOG_USER
 
 
@@ -109,6 +119,9 @@
 # value)
 #driver_enabled=false
 
+# Driver name which Ironic uses (string value)
+#driver=fake
+
 # The endpoint type to use for the baremetal provisioning
 # service (string value)
 #endpoint_type=publicURL
@@ -119,13 +132,13 @@
 
 # Timeout for association of Nova instance and Ironic node
 # (integer value)
-#association_timeout=10
+#association_timeout=30
 
 # Timeout for Ironic power transitions. (integer value)
-#power_timeout=20
+#power_timeout=60
 
 # Timeout for unprovisioning an Ironic node. (integer value)
-#unprovision_timeout=20
+#unprovision_timeout=60
 
 
 [boto]
@@ -327,6 +340,11 @@
 # (integer value)
 #shelved_offload_time=0
 
+# Unallocated floating IP range, which will be used to test
+# the floating IP bulk feature for CRUD operation. (string
+# value)
+#floating_ip_range=10.0.0.0/29
+
 # Allows test cases to create/destroy tenants and users. This
 # option enables isolated test cases and better parallel
 # execution, but also requires that OpenStack Identity API
@@ -366,17 +384,19 @@
 #
 
 # If false, skip all nova v3 tests. (boolean value)
-#api_v3=true
+#api_v3=false
 
 # If false, skip disk config tests (boolean value)
 #disk_config=true
 
 # A list of enabled compute extensions with a special entry
-# all which indicates every extension is enabled (list value)
+# all which indicates every extension is enabled. Each
+# extension should be specified with alias name (list value)
 #api_extensions=all
 
 # A list of enabled v3 extensions with a special entry all
-# which indicates every extension is enabled (list value)
+# which indicates every extension is enabled. Each extension
+# should be specified with alias name (list value)
 #api_v3_extensions=all
 
 # Does the test environment support changing the admin
@@ -417,6 +437,10 @@
 # as [nova.rdp]->enabled in nova.conf (boolean value)
 #rdp_console=false
 
+# Does the test environment support instance rescue mode?
+# (boolean value)
+#rescue=true
+
 
 [dashboard]
 
@@ -729,6 +753,11 @@
 # all which indicates every extension is enabled (list value)
 #api_extensions=all
 
+# Allow the execution of IPv6 subnet tests that use the
+# extended IPv6 attributes ipv6_ra_mode and ipv6_address_mode
+# (boolean value)
+#ipv6_subnet_attributes=false
+
 
 [object-storage]
 
@@ -834,6 +863,28 @@
 # queues (integer value)
 #max_queues_per_page=20
 
+# The maximum metadata size for a queue (integer value)
+#max_queue_metadata=65536
+
+# The maximum number of queue message per page when listing
+# (or) posting messages (integer value)
+#max_messages_per_page=20
+
+# The maximum size of a message body (integer value)
+#max_message_size=262144
+
+# The maximum number of messages per claim (integer value)
+#max_messages_per_claim=20
+
+# The maximum ttl for a message (integer value)
+#max_message_ttl=1209600
+
+# The maximum ttl for a claim (integer value)
+#max_claim_ttl=43200
+
+# The maximum grace period for a claim (integer value)
+#max_claim_grace=43200
+
 
 [scenario]
 
diff --git a/openstack-common.conf b/openstack-common.conf
index 38d58ee..a9a6b0b 100644
--- a/openstack-common.conf
+++ b/openstack-common.conf
@@ -7,6 +7,7 @@
 module=log
 module=importlib
 module=fixture
+module=versionutils
 
 # The base module to hold the copy of openstack.common
 base=tempest
diff --git a/requirements.txt b/requirements.txt
index f907e7d..9a3b74d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -7,19 +7,20 @@
 boto>=2.12.0,!=2.13.0
 paramiko>=1.13.0
 netaddr>=0.7.6
-python-glanceclient>=0.9.0
-python-keystoneclient>=0.8.0
+python-ceilometerclient>=1.0.6
+python-glanceclient>=0.13.1
+python-keystoneclient>=0.9.0
 python-novaclient>=2.17.0
-python-neutronclient>=2.3.4,<3
-python-cinderclient>=1.0.6
+python-neutronclient>=2.3.5,<3
+python-cinderclient>=1.0.7
 python-heatclient>=0.2.9
 python-ironicclient
 python-saharaclient>=0.6.0
 python-swiftclient>=2.0.2
 testresources>=0.2.4
 testrepository>=0.0.18
-oslo.config>=1.2.0
-six>=1.6.0
+oslo.config>=1.2.1
+six>=1.7.0
 iso8601>=0.1.9
 fixtures>=0.3.14
 testscenarios>=0.4
diff --git a/run_tempest.sh b/run_tempest.sh
index bdd1f69..5a9b742 100755
--- a/run_tempest.sh
+++ b/run_tempest.sh
@@ -58,7 +58,7 @@
     -l|--logging) logging=1;;
     -L|--logging-config) logging_config=$2; shift;;
     --) [ "yes" == "$first_uu" ] || testrargs="$testrargs $1"; first_uu=no  ;;
-    *) testrargs+="$testrargs $1";;
+    *) testrargs="$testrargs $1";;
   esac
   shift
 done
diff --git a/tempest/README.rst b/tempest/README.rst
index dbac809..18c7cf3 100644
--- a/tempest/README.rst
+++ b/tempest/README.rst
@@ -62,13 +62,10 @@
 stress
 ------
 
-Stress tests are designed to stress an OpenStack environment by
-running a high workload against it and seeing what breaks. Tools may
-be provided to help detect breaks (stack traces in the logs).
-
-TODO: old stress tests deleted, new_stress that david is working on
-moves into here.
-
+Stress tests are designed to stress an OpenStack environment by running a high
+workload against it and seeing what breaks. The stress test framework runs
+several test jobs in parallel and can run any existing test in Tempest as a
+stress job.
 
 thirdparty
 ----------
diff --git a/tempest/api/baremetal/base.py b/tempest/api/baremetal/base.py
index 021adaf..62edd10 100644
--- a/tempest/api/baremetal/base.py
+++ b/tempest/api/baremetal/base.py
@@ -21,19 +21,26 @@
 CONF = config.CONF
 
 
+# NOTE(adam_g): The baremetal API tests exercise operations such as enroll
+# node, power on, power off, etc.  Testing against real drivers (ie, IPMI)
+# will require passing driver-specific data to Tempest (addresses,
+# credentials, etc).  Until then, only support testing against the fake driver,
+# which has no external dependencies.
+SUPPORTED_DRIVERS = ['fake']
+
+
 def creates(resource):
     """Decorator that adds resources to the appropriate cleanup list."""
 
     def decorator(f):
         @functools.wraps(f)
         def wrapper(cls, *args, **kwargs):
-            result = f(cls, *args, **kwargs)
-            body = result[resource]
+            resp, body = f(cls, *args, **kwargs)
 
             if 'uuid' in body:
                 cls.created_objects[resource].add(body['uuid'])
 
-            return result
+            return resp, body
         return wrapper
     return decorator
 
@@ -49,9 +56,16 @@
             skip_msg = ('%s skipped as Ironic is not available' % cls.__name__)
             raise cls.skipException(skip_msg)
 
+        if CONF.baremetal.driver not in SUPPORTED_DRIVERS:
+            skip_msg = ('%s skipped as Ironic driver %s is not supported for '
+                        'testing.' %
+                        (cls.__name__, CONF.baremetal.driver))
+            raise cls.skipException(skip_msg)
+        cls.driver = CONF.baremetal.driver
+
         mgr = clients.AdminManager()
         cls.client = mgr.baremetal_client
-
+        cls.power_timeout = CONF.baremetal.power_timeout
         cls.created_objects = {'chassis': set(),
                                'port': set(),
                                'node': set()}
@@ -81,13 +95,12 @@
         """
         description = description or data_utils.rand_name('test-chassis-')
         resp, body = cls.client.create_chassis(description=description)
-
-        return {'chassis': body, 'response': resp}
+        return resp, body
 
     @classmethod
     @creates('node')
     def create_node(cls, chassis_id, cpu_arch='x86', cpu_num=8, storage=1024,
-                    memory=4096, driver='fake'):
+                    memory=4096):
         """
         Wrapper utility for creating test baremetal nodes.
 
@@ -100,9 +113,9 @@
         """
         resp, body = cls.client.create_node(chassis_id, cpu_arch=cpu_arch,
                                             cpu_num=cpu_num, storage=storage,
-                                            memory=memory, driver=driver)
+                                            memory=memory, driver=cls.driver)
 
-        return {'node': body, 'response': resp}
+        return resp, body
 
     @classmethod
     @creates('port')
@@ -121,7 +134,7 @@
         resp, body = cls.client.create_port(address=address, node_id=node_id,
                                             extra=extra, uuid=uuid)
 
-        return {'port': body, 'response': resp}
+        return resp, body
 
     @classmethod
     def delete_chassis(cls, chassis_id):
diff --git a/tempest/api/baremetal/test_api_discovery.py b/tempest/api/baremetal/test_api_discovery.py
index e594b3e..bee10b9 100644
--- a/tempest/api/baremetal/test_api_discovery.py
+++ b/tempest/api/baremetal/test_api_discovery.py
@@ -20,6 +20,7 @@
     @test.attr(type='smoke')
     def test_api_versions(self):
         resp, descr = self.client.get_api_description()
+        self.assertEqual('200', resp['status'])
         expected_versions = ('v1',)
 
         versions = [version['id'] for version in descr['versions']]
@@ -30,6 +31,7 @@
     @test.attr(type='smoke')
     def test_default_version(self):
         resp, descr = self.client.get_api_description()
+        self.assertEqual('200', resp['status'])
         default_version = descr['default_version']
 
         self.assertEqual(default_version['id'], 'v1')
@@ -37,6 +39,7 @@
     @test.attr(type='smoke')
     def test_version_1_resources(self):
         resp, descr = self.client.get_version_description(version='v1')
+        self.assertEqual('200', resp['status'])
         expected_resources = ('nodes', 'chassis',
                               'ports', 'links', 'media_types')
 
diff --git a/tempest/api/baremetal/test_chassis.py b/tempest/api/baremetal/test_chassis.py
index 7af1336..4ab86c2 100644
--- a/tempest/api/baremetal/test_chassis.py
+++ b/tempest/api/baremetal/test_chassis.py
@@ -20,57 +20,64 @@
 class TestChassis(base.BaseBaremetalTest):
     """Tests for chassis."""
 
+    @classmethod
+    def setUpClass(cls):
+        super(TestChassis, cls).setUpClass()
+        _, cls.chassis = cls.create_chassis()
+
+    def _assertExpected(self, expected, actual):
+        # Check if not expected keys/values exists in actual response body
+        for key, value in expected.iteritems():
+            if key not in ('created_at', 'updated_at'):
+                self.assertIn(key, actual)
+                self.assertEqual(value, actual[key])
+
     @test.attr(type='smoke')
     def test_create_chassis(self):
         descr = data_utils.rand_name('test-chassis-')
-        ch = self.create_chassis(description=descr)['chassis']
-
-        self.assertEqual(ch['description'], descr)
+        resp, chassis = self.create_chassis(description=descr)
+        self.assertEqual('201', resp['status'])
+        self.assertEqual(chassis['description'], descr)
 
     @test.attr(type='smoke')
     def test_create_chassis_unicode_description(self):
         # Use a unicode string for testing:
         # 'We ♡ OpenStack in Ukraine'
         descr = u'В Україні ♡ OpenStack!'
-        ch = self.create_chassis(description=descr)['chassis']
-
-        self.assertEqual(ch['description'], descr)
+        resp, chassis = self.create_chassis(description=descr)
+        self.assertEqual('201', resp['status'])
+        self.assertEqual(chassis['description'], descr)
 
     @test.attr(type='smoke')
     def test_show_chassis(self):
-        descr = data_utils.rand_name('test-chassis-')
-        uuid = self.create_chassis(description=descr)['chassis']['uuid']
-
-        resp, chassis = self.client.show_chassis(uuid)
-
-        self.assertEqual(chassis['uuid'], uuid)
-        self.assertEqual(chassis['description'], descr)
+        resp, chassis = self.client.show_chassis(self.chassis['uuid'])
+        self.assertEqual('200', resp['status'])
+        self._assertExpected(self.chassis, chassis)
 
     @test.attr(type="smoke")
     def test_list_chassis(self):
-        created_ids = [self.create_chassis()['chassis']['uuid']
-                       for i in range(0, 5)]
-
         resp, body = self.client.list_chassis()
-        loaded_ids = [ch['uuid'] for ch in body['chassis']]
-
-        for i in created_ids:
-            self.assertIn(i, loaded_ids)
+        self.assertEqual('200', resp['status'])
+        self.assertIn(self.chassis['uuid'],
+                      [i['uuid'] for i in body['chassis']])
 
     @test.attr(type='smoke')
     def test_delete_chassis(self):
-        uuid = self.create_chassis()['chassis']['uuid']
+        resp, body = self.create_chassis()
+        uuid = body['uuid']
 
-        self.delete_chassis(uuid)
-
+        resp = self.delete_chassis(uuid)
+        self.assertEqual('204', resp['status'])
         self.assertRaises(exc.NotFound, self.client.show_chassis, uuid)
 
     @test.attr(type='smoke')
     def test_update_chassis(self):
-        chassis_id = self.create_chassis()['chassis']['uuid']
+        resp, body = self.create_chassis()
+        uuid = body['uuid']
 
         new_description = data_utils.rand_name('new-description-')
-        self.client.update_chassis(chassis_id, description=new_description)
-
-        resp, chassis = self.client.show_chassis(chassis_id)
+        resp, body = (self.client.update_chassis(uuid,
+                      description=new_description))
+        self.assertEqual('200', resp['status'])
+        resp, chassis = self.client.show_chassis(uuid)
         self.assertEqual(chassis['description'], new_description)
diff --git a/tempest/api/baremetal/test_drivers.py b/tempest/api/baremetal/test_drivers.py
index 445ca60..852b6ab 100644
--- a/tempest/api/baremetal/test_drivers.py
+++ b/tempest/api/baremetal/test_drivers.py
@@ -13,14 +13,29 @@
 #    under the License.
 
 from tempest.api.baremetal import base
+from tempest import config
 from tempest import test
 
+CONF = config.CONF
+
 
 class TestDrivers(base.BaseBaremetalTest):
     """Tests for drivers."""
+    @classmethod
+    @test.safe_setup
+    def setUpClass(cls):
+        super(TestDrivers, cls).setUpClass()
+        cls.driver_name = CONF.baremetal.driver
 
     @test.attr(type="smoke")
     def test_list_drivers(self):
         resp, drivers = self.client.list_drivers()
         self.assertEqual('200', resp['status'])
-        self.assertIn('fake', [d['name'] for d in drivers['drivers']])
+        self.assertIn(self.driver_name,
+                      [d['name'] for d in drivers['drivers']])
+
+    @test.attr(type="smoke")
+    def test_show_driver(self):
+        resp, driver = self.client.show_driver(self.driver_name)
+        self.assertEqual('200', resp['status'])
+        self.assertEqual(self.driver_name, driver['name'])
diff --git a/tempest/api/baremetal/test_nodes.py b/tempest/api/baremetal/test_nodes.py
index 0f585cb..1572840 100644
--- a/tempest/api/baremetal/test_nodes.py
+++ b/tempest/api/baremetal/test_nodes.py
@@ -23,7 +23,15 @@
     def setUp(self):
         super(TestNodes, self).setUp()
 
-        self.chassis = self.create_chassis()['chassis']
+        _, self.chassis = self.create_chassis()
+        _, self.node = self.create_node(self.chassis['uuid'])
+
+    def _assertExpected(self, expected, actual):
+        # Check if not expected keys/values exists in actual response body
+        for key, value in six.iteritems(expected):
+            if key not in ('created_at', 'updated_at'):
+                self.assertIn(key, actual)
+                self.assertEqual(value, actual[key])
 
     @test.attr(type='smoke')
     def test_create_node(self):
@@ -32,45 +40,32 @@
                   'storage': '10240',
                   'memory': '1024'}
 
-        node = self.create_node(self.chassis['uuid'], **params)['node']
-
-        for key in params:
-            self.assertEqual(node['properties'][key], params[key])
+        resp, body = self.create_node(self.chassis['uuid'], **params)
+        self.assertEqual('201', resp['status'])
+        self._assertExpected(params, body['properties'])
 
     @test.attr(type='smoke')
     def test_delete_node(self):
-        node = self.create_node(self.chassis['uuid'])['node']
-        node_id = node['uuid']
+        resp, node = self.create_node(self.chassis['uuid'])
+        self.assertEqual('201', resp['status'])
 
-        resp = self.delete_node(node_id)
+        resp = self.delete_node(node['uuid'])
 
         self.assertEqual(resp['status'], '204')
-        self.assertRaises(exc.NotFound, self.client.show_node, node_id)
+        self.assertRaises(exc.NotFound, self.client.show_node, node['uuid'])
 
     @test.attr(type='smoke')
     def test_show_node(self):
-        params = {'cpu_arch': 'x86_64',
-                  'cpu_num': '4',
-                  'storage': '100',
-                  'memory': '512'}
-
-        created_node = self.create_node(self.chassis['uuid'], **params)['node']
-        resp, loaded_node = self.client.show_node(created_node['uuid'])
-
-        for key, val in created_node.iteritems():
-            if key not in ('created_at', 'updated_at'):
-                self.assertEqual(loaded_node[key], val)
+        resp, loaded_node = self.client.show_node(self.node['uuid'])
+        self.assertEqual('200', resp['status'])
+        self._assertExpected(self.node, loaded_node)
 
     @test.attr(type='smoke')
     def test_list_nodes(self):
-        uuids = [self.create_node(self.chassis['uuid'])['node']['uuid']
-                 for i in range(0, 5)]
-
         resp, body = self.client.list_nodes()
-        loaded_uuids = [n['uuid'] for n in body['nodes']]
-
-        for u in uuids:
-            self.assertIn(u, loaded_uuids)
+        self.assertEqual('200', resp['status'])
+        self.assertIn(self.node['uuid'],
+                      [i['uuid'] for i in body['nodes']])
 
     @test.attr(type='smoke')
     def test_update_node(self):
@@ -79,17 +74,24 @@
                  'storage': '10',
                  'memory': '128'}
 
-        node = self.create_node(self.chassis['uuid'], **props)['node']
-        node_id = node['uuid']
+        resp, node = self.create_node(self.chassis['uuid'], **props)
+        self.assertEqual('201', resp['status'])
 
-        new_props = {'cpu_arch': 'x86',
-                     'cpu_num': '1',
-                     'storage': '10000',
-                     'memory': '12300'}
+        new_p = {'cpu_arch': 'x86',
+                 'cpu_num': '1',
+                 'storage': '10000',
+                 'memory': '12300'}
 
-        self.client.update_node(node_id, properties=new_props)
-        resp, node = self.client.show_node(node_id)
+        resp, body = self.client.update_node(node['uuid'], properties=new_p)
+        self.assertEqual('200', resp['status'])
+        resp, node = self.client.show_node(node['uuid'])
+        self.assertEqual('200', resp['status'])
+        self._assertExpected(new_p, node['properties'])
 
-        for name, value in six.iteritems(new_props):
-            if name not in ('created_at', 'updated_at'):
-                self.assertEqual(node['properties'][name], value)
+    @test.attr(type='smoke')
+    def test_validate_driver_interface(self):
+        resp, body = self.client.validate_driver_interface(self.node['uuid'])
+        self.assertEqual('200', resp['status'])
+        core_interfaces = ['power', 'deploy']
+        for interface in core_interfaces:
+            self.assertIn(interface, body)
diff --git a/tempest/api/baremetal/test_nodestates.py b/tempest/api/baremetal/test_nodestates.py
index c658d7f..3044bc6 100644
--- a/tempest/api/baremetal/test_nodestates.py
+++ b/tempest/api/baremetal/test_nodestates.py
@@ -13,6 +13,8 @@
 #    under the License.
 
 from tempest.api.baremetal import base
+from tempest import exceptions
+from tempest.openstack.common import timeutils
 from tempest import test
 
 
@@ -20,10 +22,25 @@
     """Tests for baremetal NodeStates."""
 
     @classmethod
-    def setUpClass(self):
-        super(TestNodeStates, self).setUpClass()
-        chassis = self.create_chassis()['chassis']
-        self.node = self.create_node(chassis['uuid'])['node']
+    def setUpClass(cls):
+        super(TestNodeStates, cls).setUpClass()
+        resp, cls.chassis = cls.create_chassis()
+        resp, cls.node = cls.create_node(cls.chassis['uuid'])
+
+    def _validate_power_state(self, node_uuid, power_state):
+        # Validate that power state is set within timeout
+        if power_state == 'rebooting':
+            power_state = 'power on'
+        start = timeutils.utcnow()
+        while timeutils.delta_seconds(
+                start, timeutils.utcnow()) < self.power_timeout:
+            resp, node = self.client.show_node(node_uuid)
+            self.assertEqual(200, resp.status)
+            if node['power_state'] == power_state:
+                return
+        message = ('Failed to set power state within '
+                   'the required time: %s sec.' % self.power_timeout)
+        raise exceptions.TimeoutException(message)
 
     @test.attr(type='smoke')
     def test_list_nodestates(self):
@@ -31,3 +48,16 @@
         self.assertEqual('200', resp['status'])
         for key in nodestates:
             self.assertEqual(nodestates[key], self.node[key])
+
+    @test.attr(type='smoke')
+    def test_set_node_power_state(self):
+        resp, node = self.create_node(self.chassis['uuid'])
+        self.assertEqual('201', resp['status'])
+        states = ["power on", "rebooting", "power off"]
+        for state in states:
+            # Set power state
+            resp, _ = self.client.set_node_power_state(node['uuid'],
+                                                       state)
+            self.assertEqual('202', resp['status'])
+            # Check power state after state is set
+            self._validate_power_state(node['uuid'], state)
diff --git a/tempest/api/baremetal/test_ports.py b/tempest/api/baremetal/test_ports.py
index aeb77e3..4ac7e29 100644
--- a/tempest/api/baremetal/test_ports.py
+++ b/tempest/api/baremetal/test_ports.py
@@ -22,25 +22,30 @@
     def setUp(self):
         super(TestPorts, self).setUp()
 
-        chassis = self.create_chassis()['chassis']
-        self.node = self.create_node(chassis['uuid'])['node']
+        _, self.chassis = self.create_chassis()
+        _, self.node = self.create_node(self.chassis['uuid'])
+        _, self.port = self.create_port(self.node['uuid'],
+                                        data_utils.rand_mac_address())
+
+    def _assertExpected(self, expected, actual):
+        # Check if not expected keys/values exists in actual response body
+        for key, value in expected.iteritems():
+            if key not in ('created_at', 'updated_at'):
+                self.assertIn(key, actual)
+                self.assertEqual(value, actual[key])
 
     @test.attr(type='smoke')
     def test_create_port(self):
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
 
-        result = self.create_port(node_id=node_id, address=address)
-
-        port = result['port']
+        resp, port = self.create_port(node_id=node_id, address=address)
+        self.assertEqual(201, resp.status)
 
         resp, body = self.client.show_port(port['uuid'])
 
         self.assertEqual(200, resp.status)
-        self.assertEqual(port['uuid'], body['uuid'])
-        self.assertEqual(address, body['address'])
-        self.assertEqual({}, body['extra'])
-        self.assertEqual(node_id, body['node_uuid'])
+        self._assertExpected(port, body)
 
     @test.attr(type='smoke')
     def test_create_port_specifying_uuid(self):
@@ -48,15 +53,13 @@
         address = data_utils.rand_mac_address()
         uuid = data_utils.rand_uuid()
 
-        self.create_port(node_id=node_id, address=address, uuid=uuid)
+        resp, port = self.create_port(node_id=node_id,
+                                      address=address, uuid=uuid)
+        self.assertEqual(201, resp.status)
 
         resp, body = self.client.show_port(uuid)
-
         self.assertEqual(200, resp.status)
-        self.assertEqual(uuid, body['uuid'])
-        self.assertEqual(address, body['address'])
-        self.assertEqual({}, body['extra'])
-        self.assertEqual(node_id, body['node_uuid'])
+        self._assertExpected(port, body)
 
     @test.attr(type='smoke')
     def test_create_port_with_extra(self):
@@ -64,76 +67,46 @@
         address = data_utils.rand_mac_address()
         extra = {'key': 'value'}
 
-        result = self.create_port(node_id=node_id, address=address,
-                                  extra=extra)
-        port = result['port']
+        resp, port = self.create_port(node_id=node_id, address=address,
+                                      extra=extra)
+        self.assertEqual(201, resp.status)
 
         resp, body = self.client.show_port(port['uuid'])
-
         self.assertEqual(200, resp.status)
-        self.assertEqual(port['uuid'], body['uuid'])
-        self.assertEqual(address, body['address'])
-        self.assertEqual(extra, body['extra'])
-        self.assertEqual(node_id, body['node_uuid'])
+        self._assertExpected(port, body)
 
     @test.attr(type='smoke')
     def test_delete_port(self):
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
-        port_id = self.create_port(node_id=node_id, address=address)['port'][
-            'uuid']
+        resp, port = self.create_port(node_id=node_id, address=address)
+        self.assertEqual(201, resp.status)
 
-        resp = self.delete_port(port_id)
+        resp = self.delete_port(port['uuid'])
 
         self.assertEqual(204, resp.status)
-        self.assertRaises(exc.NotFound, self.client.show_port, port_id)
+        self.assertRaises(exc.NotFound, self.client.show_port, port['uuid'])
 
     @test.attr(type='smoke')
     def test_show_port(self):
-        node_id = self.node['uuid']
-        address = data_utils.rand_mac_address()
-        extra = {'key': 'value'}
-
-        port_id = self.create_port(node_id=node_id, address=address,
-                                   extra=extra)['port']['uuid']
-
-        resp, port = self.client.show_port(port_id)
-
+        resp, port = self.client.show_port(self.port['uuid'])
         self.assertEqual(200, resp.status)
-        self.assertEqual(port_id, port['uuid'])
-        self.assertEqual(address, port['address'])
-        self.assertEqual(extra, port['extra'])
+        self._assertExpected(self.port, port)
 
     @test.attr(type='smoke')
     def test_show_port_with_links(self):
-        node_id = self.node['uuid']
-        address = data_utils.rand_mac_address()
-
-        port_id = self.create_port(node_id=node_id, address=address)['port'][
-            'uuid']
-
-        resp, body = self.client.show_port(port_id)
-
+        resp, port = self.client.show_port(self.port['uuid'])
         self.assertEqual(200, resp.status)
-        self.assertIn('links', body.keys())
-        self.assertEqual(2, len(body['links']))
-        self.assertIn(port_id, body['links'][0]['href'])
+        self.assertIn('links', port.keys())
+        self.assertEqual(2, len(port['links']))
+        self.assertIn(port['uuid'], port['links'][0]['href'])
 
     @test.attr(type='smoke')
     def test_list_ports(self):
-        node_id = self.node['uuid']
-
-        uuids = [self.create_port(node_id=node_id,
-                                  address=data_utils.rand_mac_address())
-                 ['port']['uuid'] for i in xrange(5)]
-
         resp, body = self.client.list_ports()
         self.assertEqual(200, resp.status)
-        loaded_uuids = [p['uuid'] for p in body['ports']]
-
-        for uuid in uuids:
-            self.assertIn(uuid, loaded_uuids)
-
+        self.assertIn(self.port['uuid'],
+                      [i['uuid'] for i in body['ports']])
         # Verify self links.
         for port in body['ports']:
             self.validate_self_link('ports', port['uuid'],
@@ -141,15 +114,8 @@
 
     @test.attr(type='smoke')
     def test_list_with_limit(self):
-        node_id = self.node['uuid']
-
-        for i in xrange(5):
-            self.create_port(node_id=node_id,
-                             address=data_utils.rand_mac_address())
-
         resp, body = self.client.list_ports(limit=3)
         self.assertEqual(200, resp.status)
-        self.assertEqual(3, len(body['ports']))
 
         next_marker = body['ports'][-1]['uuid']
         self.assertIn(next_marker, body['next'])
@@ -160,7 +126,7 @@
         uuids = [
             self.create_port(node_id=node_id,
                              address=data_utils.rand_mac_address())
-            ['port']['uuid'] for i in range(0, 5)]
+            [1]['uuid'] for i in range(0, 5)]
 
         resp, body = self.client.list_ports_detail()
         self.assertEqual(200, resp.status)
@@ -179,14 +145,28 @@
             self.validate_self_link('ports', port['uuid'],
                                     port['links'][0]['href'])
 
+    def test_list_ports_details_with_address(self):
+        node_id = self.node['uuid']
+        address = data_utils.rand_mac_address()
+        self.create_port(node_id=node_id, address=address)
+        for i in range(0, 5):
+            self.create_port(node_id=node_id,
+                             address=data_utils.rand_mac_address())
+
+        resp, body = self.client.list_ports_detail(address=address)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(1, len(body['ports']))
+        self.assertEqual(address, body['ports'][0]['address'])
+
     @test.attr(type='smoke')
     def test_update_port_replace(self):
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
         extra = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
 
-        port_id = self.create_port(node_id=node_id, address=address,
-                                   extra=extra)['port']['uuid']
+        resp, port = self.create_port(node_id=node_id, address=address,
+                                      extra=extra)
+        self.assertEqual(201, resp.status)
 
         new_address = data_utils.rand_mac_address()
         new_extra = {'key1': 'new-value1', 'key2': 'new-value2',
@@ -205,9 +185,10 @@
                   'op': 'replace',
                   'value': new_extra['key3']}]
 
-        self.client.update_port(port_id, patch)
+        resp, _ = self.client.update_port(port['uuid'], patch)
+        self.assertEqual(200, resp.status)
 
-        resp, body = self.client.show_port(port_id)
+        resp, body = self.client.show_port(port['uuid'])
         self.assertEqual(200, resp.status)
         self.assertEqual(new_address, body['address'])
         self.assertEqual(new_extra, body['extra'])
@@ -218,23 +199,25 @@
         address = data_utils.rand_mac_address()
         extra = {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}
 
-        port_id = self.create_port(node_id=node_id, address=address,
-                                   extra=extra)['port']['uuid']
+        resp, port = self.create_port(node_id=node_id, address=address,
+                                      extra=extra)
+        self.assertEqual(201, resp.status)
 
         # Removing one item from the collection
-        resp, _ = self.client.update_port(port_id, [{'path': '/extra/key2',
-                                                     'op': 'remove'}])
+        resp, _ = self.client.update_port(port['uuid'],
+                                          [{'path': '/extra/key2',
+                                           'op': 'remove'}])
         self.assertEqual(200, resp.status)
         extra.pop('key2')
-        resp, body = self.client.show_port(port_id)
+        resp, body = self.client.show_port(port['uuid'])
         self.assertEqual(200, resp.status)
         self.assertEqual(extra, body['extra'])
 
         # Removing the collection
-        resp, _ = self.client.update_port(port_id, [{'path': '/extra',
-                                                     'op': 'remove'}])
+        resp, _ = self.client.update_port(port['uuid'], [{'path': '/extra',
+                                                         'op': 'remove'}])
         self.assertEqual(200, resp.status)
-        resp, body = self.client.show_port(port_id)
+        resp, body = self.client.show_port(port['uuid'])
         self.assertEqual(200, resp.status)
         self.assertEqual({}, body['extra'])
 
@@ -247,8 +230,8 @@
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
 
-        port_id = self.create_port(node_id=node_id, address=address)['port'][
-            'uuid']
+        resp, port = self.create_port(node_id=node_id, address=address)
+        self.assertEqual(201, resp.status)
 
         extra = {'key1': 'value1', 'key2': 'value2'}
 
@@ -259,9 +242,10 @@
                   'op': 'add',
                   'value': extra['key2']}]
 
-        self.client.update_port(port_id, patch)
+        resp, _ = self.client.update_port(port['uuid'], patch)
+        self.assertEqual(200, resp.status)
 
-        resp, body = self.client.show_port(port_id)
+        resp, body = self.client.show_port(port['uuid'])
         self.assertEqual(200, resp.status)
         self.assertEqual(extra, body['extra'])
 
@@ -271,8 +255,9 @@
         address = data_utils.rand_mac_address()
         extra = {'key1': 'value1', 'key2': 'value2'}
 
-        port_id = self.create_port(node_id=node_id, address=address,
-                                   extra=extra)['port']['uuid']
+        resp, port = self.create_port(node_id=node_id, address=address,
+                                      extra=extra)
+        self.assertEqual(201, resp.status)
 
         new_address = data_utils.rand_mac_address()
         new_extra = {'key1': 'new-value1', 'key3': 'new-value3'}
@@ -289,9 +274,10 @@
                   'op': 'add',
                   'value': new_extra['key3']}]
 
-        self.client.update_port(port_id, patch)
+        resp, _ = self.client.update_port(port['uuid'], patch)
+        self.assertEqual(200, resp.status)
 
-        resp, body = self.client.show_port(port_id)
+        resp, body = self.client.show_port(port['uuid'])
         self.assertEqual(200, resp.status)
         self.assertEqual(new_address, body['address'])
         self.assertEqual(new_extra, body['extra'])
diff --git a/tempest/api/baremetal/test_ports_negative.py b/tempest/api/baremetal/test_ports_negative.py
index 4cbe00e..3e77a5f 100644
--- a/tempest/api/baremetal/test_ports_negative.py
+++ b/tempest/api/baremetal/test_ports_negative.py
@@ -22,8 +22,11 @@
     def setUp(self):
         super(TestPortsNegative, self).setUp()
 
-        chassis = self.create_chassis()['chassis']
-        self.node = self.create_node(chassis['uuid'])['node']
+        resp, self.chassis = self.create_chassis()
+        self.assertEqual('201', resp['status'])
+
+        resp, self.node = self.create_node(self.chassis['uuid'])
+        self.assertEqual('201', resp['status'])
 
     @test.attr(type=['negative', 'smoke'])
     def test_create_port_malformed_mac(self):
@@ -134,9 +137,13 @@
         address = data_utils.rand_mac_address()
         extra = {'key': 'value'}
 
-        port_id = self.create_port(node_id=node_id, address=address,
-                                   extra=extra)['port']['uuid']
-        self.client.delete_port(port_id)
+        resp, port = self.create_port(node_id=node_id, address=address,
+                                      extra=extra)
+        self.assertEqual('201', resp['status'])
+        port_id = port['uuid']
+
+        resp, body = self.client.delete_port(port_id)
+        self.assertEqual('204', resp['status'])
 
         patch = [{'path': '/extra/key',
                   'op': 'replace',
@@ -162,8 +169,9 @@
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
 
-        port_id = self.create_port(node_id=node_id, address=address)['port'][
-            'uuid']
+        resp, port = self.create_port(node_id=node_id, address=address)
+        self.assertEqual('201', resp['status'])
+        port_id = port['uuid']
 
         self.assertRaises(exc.BadRequest, self.client.update_port, port_id,
                           [{'path': '/extra/key', ' op': 'add',
@@ -174,8 +182,9 @@
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
 
-        port_id = self.create_port(node_id=node_id, address=address)['port'][
-            'uuid']
+        resp, port = self.create_port(node_id=node_id, address=address)
+        self.assertEqual('201', resp['status'])
+        port_id = port['uuid']
 
         self.assertRaises(exc.BadRequest, self.client.update_port, port_id,
                           [{'path': '/extra',
@@ -187,8 +196,10 @@
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
 
-        port_id = self.create_port(node_id=node_id, address=address)['port'][
-            'uuid']
+        resp, port = self.create_port(node_id=node_id, address=address)
+        self.assertEqual('201', resp['status'])
+        port_id = port['uuid']
+
         self.assertRaises(exc.BadRequest, self.client.update_port, port_id,
                           [{'path': '/nonexistent', ' op': 'add',
                             'value': 'value'}])
@@ -198,8 +209,9 @@
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
 
-        port_id = self.create_port(node_id=node_id,
-                                   address=address)['port']['uuid']
+        resp, port = self.create_port(node_id=node_id, address=address)
+        self.assertEqual('201', resp['status'])
+        port_id = port['uuid']
 
         patch = [{'path': '/node_uuid',
                   'op': 'replace',
@@ -213,9 +225,13 @@
         address1 = data_utils.rand_mac_address()
         address2 = data_utils.rand_mac_address()
 
-        self.create_port(node_id=node_id, address=address1)
-        port_id = self.create_port(node_id=node_id,
-                                   address=address2)['port']['uuid']
+        resp, port1 = self.create_port(node_id=node_id, address=address1)
+        self.assertEqual('201', resp['status'])
+
+        resp, port2 = self.create_port(node_id=node_id, address=address2)
+        self.assertEqual('201', resp['status'])
+        port_id = port2['uuid']
+
         patch = [{'path': '/address',
                   'op': 'replace',
                   'value': address1}]
@@ -227,8 +243,9 @@
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
 
-        port_id = self.create_port(node_id=node_id,
-                                   address=address)['port']['uuid']
+        resp, port = self.create_port(node_id=node_id, address=address)
+        self.assertEqual('201', resp['status'])
+        port_id = port['uuid']
 
         patch = [{'path': '/node_uuid',
                   'op': 'replace',
@@ -241,8 +258,10 @@
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
 
-        port_id = self.create_port(node_id=node_id,
-                                   address=address)['port']['uuid']
+        resp, port = self.create_port(node_id=node_id, address=address)
+        self.assertEqual('201', resp['status'])
+        port_id = port['uuid']
+
         patch = [{'path': '/address',
                   'op': 'replace',
                   'value': 'malformed:mac'}]
@@ -256,13 +275,14 @@
         address = data_utils.rand_mac_address()
         extra = {'key': 'value'}
 
-        port_id = self.create_port(node_id=node_id,
-                                   address=address,
-                                   extra=extra)['port']['uuid']
+        resp, port = self.create_port(node_id=node_id, address=address,
+                                      extra=extra)
+        self.assertEqual('201', resp['status'])
+        port_id = port['uuid']
+
         patch = [{'path': '/extra/key',
                   'op': 'replace',
                   'value': 0.123}]
-
         self.assertRaises(exc.BadRequest,
                           self.client.update_port, port_id, patch)
 
@@ -270,11 +290,11 @@
     def test_update_port_replace_whole_extra_with_malformed(self):
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
-        extra = {'key': 'value'}
 
-        port_id = self.create_port(node_id=node_id,
-                                   address=address,
-                                   extra=extra)['port']['uuid']
+        resp, port = self.create_port(node_id=node_id, address=address)
+        self.assertEqual('201', resp['status'])
+        port_id = port['uuid']
+
         patch = [{'path': '/extra',
                   'op': 'replace',
                   'value': [1, 2, 3, 4, 'a']}]
@@ -287,8 +307,9 @@
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
 
-        port_id = self.create_port(node_id=node_id,
-                                   address=address)['port']['uuid']
+        resp, port = self.create_port(node_id=node_id, address=address)
+        self.assertEqual('201', resp['status'])
+        port_id = port['uuid']
 
         patch = [{'path': '/nonexistent', ' op': 'replace', 'value': 'value'}]
 
@@ -300,8 +321,10 @@
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
 
-        port_id = self.create_port(node_id=node_id, address=address)['port'][
-            'uuid']
+        resp, port = self.create_port(node_id=node_id, address=address)
+        self.assertEqual('201', resp['status'])
+        port_id = port['uuid']
+
         self.assertRaises(exc.BadRequest, self.client.update_port, port_id,
                           [{'path': '/address', 'op': 'remove'}])
 
@@ -310,8 +333,10 @@
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
 
-        port_id = self.create_port(node_id=node_id, address=address)['port'][
-            'uuid']
+        resp, port = self.create_port(node_id=node_id, address=address)
+        self.assertEqual('201', resp['status'])
+        port_id = port['uuid']
+
         self.assertRaises(exc.BadRequest, self.client.update_port, port_id,
                           [{'path': '/uuid', 'op': 'remove'}])
 
@@ -320,8 +345,10 @@
         node_id = self.node['uuid']
         address = data_utils.rand_mac_address()
 
-        port_id = self.create_port(node_id=node_id, address=address)['port'][
-            'uuid']
+        resp, port = self.create_port(node_id=node_id, address=address)
+        self.assertEqual('201', resp['status'])
+        port_id = port['uuid']
+
         self.assertRaises(exc.BadRequest, self.client.update_port, port_id,
                           [{'path': '/nonexistent', 'op': 'remove'}])
 
@@ -339,8 +366,10 @@
         address = data_utils.rand_mac_address()
         extra = {'key1': 'value1', 'key2': 'value2'}
 
-        port_id = self.create_port(node_id=node_id, address=address,
-                                   extra=extra)['port']['uuid']
+        resp, port = self.create_port(node_id=node_id, address=address,
+                                      extra=extra)
+        self.assertEqual('201', resp['status'])
+        port_id = port['uuid']
 
         new_address = data_utils.rand_mac_address()
         new_extra = {'key1': 'new-value1', 'key3': 'new-value3'}
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index 9555367..3a6de36 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -26,7 +26,7 @@
     @classmethod
     def setUpClass(cls):
         super(AZAdminV3Test, cls).setUpClass()
-        cls.client = cls.os_adm.availability_zone_client
+        cls.client = cls.availability_zone_admin_client
 
     @test.attr(type='gate')
     def test_get_availability_zone_list(self):
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index b0692b1..939f1a1 100644
--- a/tempest/api/compute/admin/test_fixed_ips.py
+++ b/tempest/api/compute/admin/test_fixed_ips.py
@@ -40,17 +40,20 @@
                 break
 
     @test.attr(type='gate')
+    @test.services('network')
     def test_list_fixed_ip_details(self):
         resp, fixed_ip = self.client.get_fixed_ip_details(self.ip)
         self.assertEqual(fixed_ip['address'], self.ip)
 
     @test.attr(type='gate')
+    @test.services('network')
     def test_set_reserve(self):
         body = {"reserve": "None"}
         resp, body = self.client.reserve_fixed_ip(self.ip, body)
         self.assertEqual(resp.status, 202)
 
     @test.attr(type='gate')
+    @test.services('network')
     def test_set_unreserve(self):
         body = {"unreserve": "None"}
         resp, body = self.client.reserve_fixed_ip(self.ip, body)
diff --git a/tempest/api/compute/admin/test_fixed_ips_negative.py b/tempest/api/compute/admin/test_fixed_ips_negative.py
index 3fb3829..1caa246 100644
--- a/tempest/api/compute/admin/test_fixed_ips_negative.py
+++ b/tempest/api/compute/admin/test_fixed_ips_negative.py
@@ -41,11 +41,13 @@
                 break
 
     @test.attr(type=['negative', 'gate'])
+    @test.services('network')
     def test_list_fixed_ip_details_with_non_admin_user(self):
         self.assertRaises(exceptions.Unauthorized,
                           self.non_admin_client.get_fixed_ip_details, self.ip)
 
     @test.attr(type=['negative', 'gate'])
+    @test.services('network')
     def test_set_reserve_with_non_admin_user(self):
         body = {"reserve": "None"}
         self.assertRaises(exceptions.Unauthorized,
@@ -53,6 +55,7 @@
                           self.ip, body)
 
     @test.attr(type=['negative', 'gate'])
+    @test.services('network')
     def test_set_unreserve_with_non_admin_user(self):
         body = {"unreserve": "None"}
         self.assertRaises(exceptions.Unauthorized,
@@ -60,6 +63,7 @@
                           self.ip, body)
 
     @test.attr(type=['negative', 'gate'])
+    @test.services('network')
     def test_set_reserve_with_invalid_ip(self):
         # NOTE(maurosr): since this exercises the same code snippet, we do it
         # only for reserve action
@@ -69,6 +73,7 @@
                           "my.invalid.ip", body)
 
     @test.attr(type=['negative', 'gate'])
+    @test.services('network')
     def test_fixed_ip_with_invalid_action(self):
         body = {"invalid_action": "None"}
         self.assertRaises(exceptions.BadRequest,
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 111ac9c..18866e5 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -30,8 +30,8 @@
     @classmethod
     def setUpClass(cls):
         super(FlavorsAdminTestJSON, cls).setUpClass()
-        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
-            msg = "FlavorExtraData extension not enabled."
+        if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
+            msg = "OS-FLV-EXT-DATA extension not enabled."
             raise cls.skipException(msg)
 
         cls.client = cls.os_adm.flavors_client
@@ -231,7 +231,7 @@
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
 
-            # Create the flavor
+        # Create the flavor
         resp, flavor = self.client.create_flavor(flavor_name,
                                                  self.ram, self.vcpus,
                                                  self.disk,
diff --git a/tempest/api/compute/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py
index 3ba7314..f2554ea 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -28,8 +28,8 @@
     @classmethod
     def setUpClass(cls):
         super(FlavorsAccessTestJSON, cls).setUpClass()
-        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
-            msg = "FlavorExtraData extension not enabled."
+        if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
+            msg = "OS-FLV-EXT-DATA extension not enabled."
             raise cls.skipException(msg)
 
         # Compute admin flavor client
diff --git a/tempest/api/compute/admin/test_flavors_access_negative.py b/tempest/api/compute/admin/test_flavors_access_negative.py
index 73834e9..b636ccd 100644
--- a/tempest/api/compute/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/admin/test_flavors_access_negative.py
@@ -31,8 +31,8 @@
     @classmethod
     def setUpClass(cls):
         super(FlavorsAccessNegativeTestJSON, cls).setUpClass()
-        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
-            msg = "FlavorExtraData extension not enabled."
+        if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
+            msg = "OS-FLV-EXT-DATA extension not enabled."
             raise cls.skipException(msg)
 
         cls.client = cls.os_adm.flavors_client
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index 91145ec..56daf96 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -29,8 +29,8 @@
     @classmethod
     def setUpClass(cls):
         super(FlavorsExtraSpecsTestJSON, cls).setUpClass()
-        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
-            msg = "FlavorExtraData extension not enabled."
+        if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
+            msg = "OS-FLV-EXT-DATA extension not enabled."
             raise cls.skipException(msg)
 
         cls.client = cls.os_adm.flavors_client
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
index a139c2f..1e5695f 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
@@ -30,8 +30,8 @@
     @classmethod
     def setUpClass(cls):
         super(FlavorsExtraSpecsNegativeTestJSON, cls).setUpClass()
-        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
-            msg = "FlavorExtraData extension not enabled."
+        if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
+            msg = "OS-FLV-EXT-DATA extension not enabled."
             raise cls.skipException(msg)
 
         cls.client = cls.os_adm.flavors_client
diff --git a/tempest/api/compute/admin/test_flavors_negative.py b/tempest/api/compute/admin/test_flavors_negative.py
index b37d32c..9e4412f 100644
--- a/tempest/api/compute/admin/test_flavors_negative.py
+++ b/tempest/api/compute/admin/test_flavors_negative.py
@@ -32,8 +32,8 @@
     @classmethod
     def setUpClass(cls):
         super(FlavorsAdminNegativeTestJSON, cls).setUpClass()
-        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
-            msg = "FlavorExtraData extension not enabled."
+        if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
+            msg = "OS-FLV-EXT-DATA extension not enabled."
             raise cls.skipException(msg)
 
         cls.client = cls.os_adm.flavors_client
diff --git a/tempest/api/compute/admin/test_floating_ips_bulk.py b/tempest/api/compute/admin/test_floating_ips_bulk.py
new file mode 100644
index 0000000..16c2810
--- /dev/null
+++ b/tempest/api/compute/admin/test_floating_ips_bulk.py
@@ -0,0 +1,83 @@
+# Copyright 2014 NEC Technologies India Ltd.
+# 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 netaddr
+
+from tempest.api.compute import base
+from tempest import config
+from tempest import test
+
+CONF = config.CONF
+
+
+class FloatingIPsBulkAdminTestJSON(base.BaseV2ComputeAdminTest):
+    """
+    Tests Floating IPs Bulk APIs Create, List and  Delete that
+    require admin privileges.
+    API documentation - http://docs.openstack.org/api/openstack-compute/2/
+    content/ext-os-floating-ips-bulk.html
+    """
+
+    @classmethod
+    @test.safe_setup
+    def setUpClass(cls):
+        super(FloatingIPsBulkAdminTestJSON, cls).setUpClass()
+        cls.client = cls.os_adm.floating_ips_client
+        cls.ip_range = CONF.compute.floating_ip_range
+        cls.verify_unallocated_floating_ip_range(cls.ip_range)
+
+    @classmethod
+    def verify_unallocated_floating_ip_range(cls, ip_range):
+        # Verify whether configure floating IP range is not already allocated.
+        _, body = cls.client.list_floating_ips_bulk()
+        allocated_ips_list = map(lambda x: x['address'], body)
+        for ip_addr in netaddr.IPNetwork(ip_range).iter_hosts():
+            if str(ip_addr) in allocated_ips_list:
+                msg = ("Configured unallocated floating IP range is already "
+                       "allocated. Configure the correct unallocated range "
+                       "as 'floating_ip_range'")
+                raise cls.skipException(msg)
+        return
+
+    def _delete_floating_ips_bulk(self, ip_range):
+        try:
+            self.client.delete_floating_ips_bulk(ip_range)
+        except Exception:
+            pass
+
+    @test.attr(type='gate')
+    @test.services('network')
+    def test_create_list_delete_floating_ips_bulk(self):
+        # Create, List  and delete the Floating IPs Bulk
+        pool = 'test_pool'
+        # NOTE(GMann): Reserving the IP range but those are not attached
+        # anywhere. Using the below mentioned interface which is not ever
+        # expected to be used. Clean Up has been done for created IP range
+        interface = 'eth0'
+        resp, body = self.client.create_floating_ips_bulk(self.ip_range,
+                                                          pool,
+                                                          interface)
+
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self._delete_floating_ips_bulk, self.ip_range)
+        self.assertEqual(self.ip_range, body['ip_range'])
+        resp, ips_list = self.client.list_floating_ips_bulk()
+        self.assertEqual(200, resp.status)
+        self.assertNotEqual(0, len(ips_list))
+        for ip in netaddr.IPNetwork(self.ip_range).iter_hosts():
+            self.assertIn(str(ip), map(lambda x: x['address'], ips_list))
+        resp, body = self.client.delete_floating_ips_bulk(self.ip_range)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(self.ip_range, body)
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index 48f9ffb..85b26a1 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -86,8 +86,27 @@
         # Verify that GET shows the specified hypervisor uptime
         hypers = self._list_hypervisors()
 
-        has_valid_uptime = False
+        # Ironic will register each baremetal node as a 'hypervisor',
+        # so the hypervisor list can contain many hypervisors of type
+        # 'ironic'. If they are ALL ironic, skip this test since ironic
+        # doesn't support hypervisor uptime. Otherwise, remove them
+        # from the list of hypervisors to test.
+        ironic_only = True
+        hypers_without_ironic = []
         for hyper in hypers:
+            resp, details = (self.client.
+                             get_hypervisor_show_details(hypers[0]['id']))
+            self.assertEqual(200, resp.status)
+            if details['hypervisor_type'] != 'ironic':
+                hypers_without_ironic.append(hyper)
+                ironic_only = False
+
+        if ironic_only:
+            raise self.skipException(
+                "Ironic does not support hypervisor uptime")
+
+        has_valid_uptime = False
+        for hyper in hypers_without_ironic:
             # because hypervisors might be disabled, this loops looking
             # for any good hit.
             try:
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index 348666d..d27d78b 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -13,14 +13,26 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import six
+from testtools import matchers
+
 from tempest.api.compute import base
+from tempest.common import tempest_fixtures as fixtures
 from tempest.common.utils import data_utils
+from tempest.openstack.common import log as logging
 from tempest import test
 
+LOG = logging.getLogger(__name__)
+
 
 class QuotasAdminTestJSON(base.BaseV2ComputeAdminTest):
     force_tenant_isolation = True
 
+    def setUp(self):
+        # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
+        self.useFixture(fixtures.LockFixture('compute_quotas'))
+        super(QuotasAdminTestJSON, self).setUp()
+
     @classmethod
     def setUpClass(cls):
         super(QuotasAdminTestJSON, cls).setUpClass()
@@ -134,3 +146,55 @@
 
 class QuotasAdminTestXML(QuotasAdminTestJSON):
     _interface = 'xml'
+
+
+class QuotaClassesAdminTestJSON(base.BaseV2ComputeAdminTest):
+    """Tests the os-quota-class-sets API to update default quotas.
+    """
+
+    def setUp(self):
+        # All test cases in this class need to externally lock on doing
+        # anything with default quota values.
+        self.useFixture(fixtures.LockFixture('compute_quotas'))
+        super(QuotaClassesAdminTestJSON, self).setUp()
+
+    @classmethod
+    def setUpClass(cls):
+        super(QuotaClassesAdminTestJSON, cls).setUpClass()
+        cls.adm_client = cls.os_adm.quota_classes_client
+
+    def _restore_default_quotas(self, original_defaults):
+        LOG.debug("restoring quota class defaults")
+        resp, body = self.adm_client.update_quota_class_set(
+            'default', **original_defaults)
+        self.assertEqual(200, resp.status)
+
+    # NOTE(sdague): this test is problematic as it changes
+    # global state, and possibly needs to be part of a set of
+    # tests that get run all by themselves at the end under a
+    # 'danger' flag.
+    def test_update_default_quotas(self):
+        LOG.debug("get the current 'default' quota class values")
+        resp, body = self.adm_client.get_quota_class_set('default')
+        self.assertEqual(200, resp.status)
+        self.assertIn('id', body)
+        self.assertEqual('default', body.pop('id'))
+        # restore the defaults when the test is done
+        self.addCleanup(self._restore_default_quotas, body.copy())
+        # increment all of the values for updating the default quota class
+        for quota, default in six.iteritems(body):
+            # NOTE(sdague): we need to increment a lot, otherwise
+            # there is a real chance that we go from -1 (unlimitted)
+            # to a very small number which causes issues.
+            body[quota] = default + 100
+        LOG.debug("update limits for the default quota class set")
+        resp, update_body = self.adm_client.update_quota_class_set('default',
+                                                                   **body)
+        self.assertEqual(200, resp.status)
+        LOG.debug("assert that the response has all of the changed values")
+        self.assertThat(update_body.items(),
+                        matchers.ContainsAll(body.items()))
+
+
+class QuotaClassesAdminTestXML(QuotaClassesAdminTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_quotas_negative.py b/tempest/api/compute/admin/test_quotas_negative.py
index e1dc685..f147b9c 100644
--- a/tempest/api/compute/admin/test_quotas_negative.py
+++ b/tempest/api/compute/admin/test_quotas_negative.py
@@ -44,6 +44,7 @@
 
     # TODO(afazekas): Add dedicated tenant to the skiped quota tests
     # it can be moved into the setUpClass as well
+    @test.skip_because(bug="1298131")
     @test.attr(type=['negative', 'gate'])
     def test_create_server_when_cpu_quota_is_full(self):
         # Disallow server creation when tenant's vcpu quota is full
@@ -57,8 +58,9 @@
 
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         cores=default_vcpu_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
 
+    @test.skip_because(bug="1298131")
     @test.attr(type=['negative', 'gate'])
     def test_create_server_when_memory_quota_is_full(self):
         # Disallow server creation when tenant's memory quota is full
@@ -72,8 +74,9 @@
 
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         ram=default_mem_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
 
+    @test.skip_because(bug="1298131")
     @test.attr(type=['negative', 'gate'])
     def test_create_server_when_instances_quota_is_full(self):
         # Once instances quota limit is reached, disallow server creation
@@ -86,7 +89,7 @@
                                          instances=instances_quota)
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         instances=default_instances_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
 
     @test.skip_because(bug="1186354",
                        condition=CONF.service_available.neutron)
diff --git a/tempest/api/compute/admin/test_security_groups.py b/tempest/api/compute/admin/test_security_groups.py
index f728d68..004ce8f 100644
--- a/tempest/api/compute/admin/test_security_groups.py
+++ b/tempest/api/compute/admin/test_security_groups.py
@@ -43,6 +43,7 @@
                       "Skipped because neutron do not support all_tenants"
                       "search filter.")
     @test.attr(type='smoke')
+    @test.services('network')
     def test_list_security_groups_list_all_tenants_filter(self):
         # Admin can list security groups of all tenants
         # List of all security groups created
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index 8b3a0b5..f4d010e 100644
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -54,6 +54,9 @@
             flavor_id = data_utils.rand_int_id(start=1000)
         return flavor_id
 
+    @test.skip_because(bug="1298131")
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_server_using_overlimit_ram(self):
         flavor_name = data_utils.rand_name("flavor-")
@@ -67,11 +70,14 @@
                                                              ram, vcpus, disk,
                                                              flavor_id)
         self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
-        self.assertRaises(exceptions.OverLimit,
+        self.assertRaises(exceptions.Unauthorized,
                           self.client.resize,
                           self.servers[0]['id'],
                           flavor_ref['id'])
 
+    @test.skip_because(bug="1298131")
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_server_using_overlimit_vcpus(self):
         flavor_name = data_utils.rand_name("flavor-")
@@ -85,7 +91,7 @@
                                                              ram, vcpus, disk,
                                                              flavor_id)
         self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
-        self.assertRaises(exceptions.OverLimit,
+        self.assertRaises(exceptions.Unauthorized,
                           self.client.resize,
                           self.servers[0]['id'],
                           flavor_ref['id'])
@@ -121,6 +127,8 @@
                           self.client.migrate_server,
                           str(uuid.uuid4()))
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
                           'Suspend is not available.')
     @test.attr(type=['negative', 'gate'])
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py b/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
index d69c43c..1031b24 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
@@ -51,7 +51,6 @@
         # Get usage for tenant with invalid date
         params = {'start': self.end,
                   'end': self.start}
-        resp, tenants = self.identity_client.list_tenants()
         self.assertRaises(exceptions.BadRequest,
                           self.adm_client.get_tenant_usage,
                           self.client.tenant_id, params)
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 7c70aec..70a9604 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -67,6 +67,8 @@
             cls.keypairs_client = cls.os.keypairs_client
             cls.security_groups_client = cls.os.security_groups_client
             cls.quotas_client = cls.os.quotas_client
+            # NOTE(mriedem): os-quota-class-sets is v2 API only
+            cls.quota_classes_client = cls.os.quota_classes_client
             cls.limits_client = cls.os.limits_client
             cls.volumes_extensions_client = cls.os.volumes_extensions_client
             cls.volumes_client = cls.os.volumes_client
@@ -270,7 +272,7 @@
         if not policy:
             policy = ['affinity']
         resp, body = cls.servers_client.create_server_group(name, policy)
-        cls.server_groups.append(body)
+        cls.server_groups.append(body['id'])
         return resp, body
 
     def wait_for(self, condition):
@@ -390,8 +392,11 @@
                 msg = ("Missing Compute Admin API credentials "
                        "in configuration.")
                 raise cls.skipException(msg)
+        if cls._api_version == 2:
+            cls.availability_zone_admin_client = (
+                cls.os_adm.availability_zone_client)
 
-        if cls._api_version == 3:
+        else:
             cls.servers_admin_client = cls.os_adm.servers_v3_client
             cls.services_admin_client = cls.os_adm.services_v3_client
             cls.availability_zone_admin_client = \
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index bfebb5e..c1c2d05 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -67,8 +67,8 @@
     @test.attr(type='gate')
     def test_list_flavors_using_marker(self):
         # The list of flavors should start from the provided marker
-        resp, flavors = self.client.list_flavors()
-        flavor_id = flavors[0]['id']
+        resp, flavor = self.client.get_flavor_details(self.flavor_ref)
+        flavor_id = flavor['id']
 
         params = {'marker': flavor_id}
         resp, flavors = self.client.list_flavors(params)
@@ -78,8 +78,8 @@
     @test.attr(type='gate')
     def test_list_flavors_detailed_using_marker(self):
         # The list of flavors should start from the provided marker
-        resp, flavors = self.client.list_flavors_with_detail()
-        flavor_id = flavors[0]['id']
+        resp, flavor = self.client.get_flavor_details(self.flavor_ref)
+        flavor_id = flavor['id']
 
         params = {'marker': flavor_id}
         resp, flavors = self.client.list_flavors_with_detail(params)
@@ -89,44 +89,40 @@
     @test.attr(type='gate')
     def test_list_flavors_detailed_filter_by_min_disk(self):
         # The detailed list of flavors should be filtered by disk space
-        resp, flavors = self.client.list_flavors_with_detail()
-        flavors = sorted(flavors, key=lambda k: k['disk'])
-        flavor_id = flavors[0]['id']
+        resp, flavor = self.client.get_flavor_details(self.flavor_ref)
+        flavor_id = flavor['id']
 
-        params = {self._min_disk: flavors[0]['disk'] + 1}
+        params = {self._min_disk: flavor['disk'] + 1}
         resp, flavors = self.client.list_flavors_with_detail(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
     @test.attr(type='gate')
     def test_list_flavors_detailed_filter_by_min_ram(self):
         # The detailed list of flavors should be filtered by RAM
-        resp, flavors = self.client.list_flavors_with_detail()
-        flavors = sorted(flavors, key=lambda k: k['ram'])
-        flavor_id = flavors[0]['id']
+        resp, flavor = self.client.get_flavor_details(self.flavor_ref)
+        flavor_id = flavor['id']
 
-        params = {self._min_ram: flavors[0]['ram'] + 1}
+        params = {self._min_ram: flavor['ram'] + 1}
         resp, flavors = self.client.list_flavors_with_detail(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
     @test.attr(type='gate')
     def test_list_flavors_filter_by_min_disk(self):
         # The list of flavors should be filtered by disk space
-        resp, flavors = self.client.list_flavors_with_detail()
-        flavors = sorted(flavors, key=lambda k: k['disk'])
-        flavor_id = flavors[0]['id']
+        resp, flavor = self.client.get_flavor_details(self.flavor_ref)
+        flavor_id = flavor['id']
 
-        params = {self._min_disk: flavors[0]['disk'] + 1}
+        params = {self._min_disk: flavor['disk'] + 1}
         resp, flavors = self.client.list_flavors(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
     @test.attr(type='gate')
     def test_list_flavors_filter_by_min_ram(self):
         # The list of flavors should be filtered by RAM
-        resp, flavors = self.client.list_flavors_with_detail()
-        flavors = sorted(flavors, key=lambda k: k['ram'])
-        flavor_id = flavors[0]['id']
+        resp, flavor = self.client.get_flavor_details(self.flavor_ref)
+        flavor_id = flavor['id']
 
-        params = {self._min_ram: flavors[0]['ram'] + 1}
+        params = {self._min_ram: flavor['ram'] + 1}
         resp, flavors = self.client.list_flavors(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index b3789f8..1eae66f 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -54,6 +54,7 @@
             pass
 
     @test.attr(type='gate')
+    @test.services('network')
     def test_allocate_floating_ip(self):
         # Positive test:Allocation of a new floating IP to a project
         # should be successful
@@ -69,6 +70,7 @@
         self.assertIn(floating_ip_details, body)
 
     @test.attr(type='gate')
+    @test.services('network')
     def test_delete_floating_ip(self):
         # Positive test:Deletion of valid floating IP from project
         # should be successful
@@ -85,6 +87,7 @@
         self.client.wait_for_resource_deletion(floating_ip_body['id'])
 
     @test.attr(type='gate')
+    @test.services('network')
     def test_associate_disassociate_floating_ip(self):
         # Positive test:Associate and disassociate the provided floating IP
         # to a specific server should be successful
@@ -101,6 +104,7 @@
         self.assertEqual(202, resp.status)
 
     @test.attr(type='gate')
+    @test.services('network')
     def test_associate_already_associated_floating_ip(self):
         # positive test:Association of an already associated floating IP
         # to specific server should change the association of the Floating IP
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
index 9fc43e2..042a19a 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions_negative.py
@@ -48,6 +48,7 @@
                 break
 
     @test.attr(type=['negative', 'gate'])
+    @test.services('network')
     def test_allocate_floating_ip_from_nonexistent_pool(self):
         # Negative test:Allocation of a new floating IP from a nonexistent_pool
         # to a project should fail
@@ -56,6 +57,7 @@
                           "non_exist_pool")
 
     @test.attr(type=['negative', 'gate'])
+    @test.services('network')
     def test_delete_nonexistent_floating_ip(self):
         # Negative test:Deletion of a nonexistent floating IP
         # from project should fail
@@ -65,6 +67,7 @@
                           self.non_exist_id)
 
     @test.attr(type=['negative', 'gate'])
+    @test.services('network')
     def test_associate_nonexistent_floating_ip(self):
         # Negative test:Association of a non existent floating IP
         # to specific server should fail
@@ -74,6 +77,7 @@
                           "0.0.0.0", self.server_id)
 
     @test.attr(type=['negative', 'gate'])
+    @test.services('network')
     def test_dissociate_nonexistent_floating_ip(self):
         # Negative test:Dissociation of a non existent floating IP should fail
         # Dissociating non existent floating IP
@@ -82,6 +86,7 @@
                           "0.0.0.0", self.server_id)
 
     @test.attr(type=['negative', 'gate'])
+    @test.services('network')
     def test_associate_ip_to_server_without_passing_floating_ip(self):
         # Negative test:Association of empty floating IP to specific server
         # should raise NotFound exception
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips.py b/tempest/api/compute/floating_ips/test_list_floating_ips.py
index 94dcf61..a6878d9 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -37,6 +37,7 @@
         super(FloatingIPDetailsTestJSON, cls).tearDownClass()
 
     @test.attr(type='gate')
+    @test.services('network')
     def test_list_floating_ips(self):
         # Positive test:Should return the list of floating IPs
         resp, body = self.client.list_floating_ips()
@@ -48,6 +49,7 @@
             self.assertIn(self.floating_ip[i], floating_ips)
 
     @test.attr(type='gate')
+    @test.services('network')
     def test_get_floating_ip_details(self):
         # Positive test:Should be able to GET the details of floatingIP
         # Creating a floating IP for which details are to be checked
@@ -70,6 +72,7 @@
         self.assertEqual(floating_ip_id, body['id'])
 
     @test.attr(type='gate')
+    @test.services('network')
     def test_list_floating_ip_pools(self):
         # Positive test:Should return the list of floating IP Pools
         resp, floating_ip_pools = self.client.list_floating_ip_pools()
diff --git a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
index 8cb2f08..b11ef5b 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips_negative.py
@@ -32,6 +32,7 @@
         cls.client = cls.floating_ips_client
 
     @test.attr(type=['negative', 'gate'])
+    @test.services('network')
     def test_get_nonexistent_floating_ip_details(self):
         # Negative test:Should not be able to GET the details
         # of non-existent floating IP
diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py
index 91eb4c5..9036726 100644
--- a/tempest/api/compute/images/test_image_metadata.py
+++ b/tempest/api/compute/images/test_image_metadata.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import StringIO
+
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest import config
@@ -31,25 +33,21 @@
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
 
+        cls.glance_client = cls.os.image_client
         cls.client = cls.images_client
         cls.image_id = None
 
-        resp, server = cls.create_test_server(wait_until='ACTIVE')
-        cls.server_id = server['id']
-
-        # Snapshot the server once to save time
         name = data_utils.rand_name('image')
-        resp, _ = cls.client.create_image(cls.server_id, name, {})
-        cls.image_id = resp['location'].rsplit('/', 1)[1]
-
+        resp, body = cls.glance_client.create_image(name=name,
+                                                    container_format='bare',
+                                                    disk_format='raw',
+                                                    is_public=False)
+        cls.image_id = body['id']
+        cls.images.append(cls.image_id)
+        image_file = StringIO.StringIO(('*' * 1024))
+        cls.glance_client.update_image(cls.image_id, data=image_file)
         cls.client.wait_for_image_status(cls.image_id, 'ACTIVE')
 
-    @classmethod
-    def tearDownClass(cls):
-        if cls.image_id:
-            cls.client.delete_image(cls.image_id)
-        super(ImagesMetadataTestJSON, cls).tearDownClass()
-
     def setUp(self):
         super(ImagesMetadataTestJSON, self).setUp()
         meta = {'key1': 'value1', 'key2': 'value2'}
diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py
index ae00ae2..6163f4d 100644
--- a/tempest/api/compute/images/test_images_negative.py
+++ b/tempest/api/compute/images/test_images_negative.py
@@ -40,7 +40,7 @@
         # Delete server before trying to create server
         self.servers_client.delete_server(server['id'])
         self.servers_client.wait_for_server_termination(server['id'])
-       # Create a new image after server is deleted
+        # Create a new image after server is deleted
         name = data_utils.rand_name('image')
         meta = {'image_type': 'test'}
         self.assertRaises(exceptions.NotFound,
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index 86ee4a4..f9350e1 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -13,7 +13,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import StringIO
+import time
+
 from tempest.api.compute import base
+from tempest.common.utils import data_utils
 from tempest import config
 from tempest.openstack.common import log as logging
 from tempest import test
@@ -32,7 +36,34 @@
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
         cls.client = cls.images_client
+        cls.glance_client = cls.os.image_client
 
+        def _create_image():
+            name = data_utils.rand_name('image')
+            _, body = cls.glance_client.create_image(name=name,
+                                                     container_format='bare',
+                                                     disk_format='raw',
+                                                     is_public=False)
+            image_id = body['id']
+            cls.images.append(image_id)
+            # Wait 1 second between creation and upload to ensure a delta
+            # between created_at and updated_at.
+            time.sleep(1)
+            image_file = StringIO.StringIO(('*' * 1024))
+            cls.glance_client.update_image(image_id, data=image_file)
+            cls.client.wait_for_image_status(image_id, 'ACTIVE')
+            _, body = cls.client.get_image(image_id)
+            return body
+
+        # Create non-snapshot images via glance
+        cls.image1 = _create_image()
+        cls.image1_id = cls.image1['id']
+        cls.image2 = _create_image()
+        cls.image2_id = cls.image2['id']
+        cls.image3 = _create_image()
+        cls.image3_id = cls.image3['id']
+
+        # Create instances and snapshots via nova
         try:
             resp, cls.server1 = cls.create_test_server()
             resp, cls.server2 = cls.create_test_server(wait_until='ACTIVE')
@@ -41,21 +72,21 @@
                                                       'ACTIVE')
 
             # Create images to be used in the filter tests
-            resp, cls.image1 = cls.create_image_from_server(
+            resp, cls.snapshot1 = cls.create_image_from_server(
                 cls.server1['id'], wait_until='ACTIVE')
-            cls.image1_id = cls.image1['id']
+            cls.snapshot1_id = cls.snapshot1['id']
 
             # Servers have a hidden property for when they are being imaged
             # Performing back-to-back create image calls on a single
             # server will sometimes cause failures
-            resp, cls.image3 = cls.create_image_from_server(
+            resp, cls.snapshot3 = cls.create_image_from_server(
                 cls.server2['id'], wait_until='ACTIVE')
-            cls.image3_id = cls.image3['id']
+            cls.snapshot3_id = cls.snapshot3['id']
 
             # Wait for the server to be active after the image upload
-            resp, cls.image2 = cls.create_image_from_server(
+            resp, cls.snapshot2 = cls.create_image_from_server(
                 cls.server1['id'], wait_until='ACTIVE')
-            cls.image2_id = cls.image2['id']
+            cls.snapshot2_id = cls.snapshot2['id']
         except Exception:
             LOG.exception('setUpClass failed')
             cls.tearDownClass()
@@ -89,11 +120,14 @@
         params = {'server': self.server1['id']}
         resp, images = self.client.list_images(params)
 
-        self.assertTrue(any([i for i in images if i['id'] == self.image1_id]),
+        self.assertTrue(any([i for i in images
+                             if i['id'] == self.snapshot1_id]),
                         "Failed to find image %s in images. Got images %s" %
                         (self.image1_id, images))
-        self.assertTrue(any([i for i in images if i['id'] == self.image2_id]))
-        self.assertFalse(any([i for i in images if i['id'] == self.image3_id]))
+        self.assertTrue(any([i for i in images
+                             if i['id'] == self.snapshot2_id]))
+        self.assertFalse(any([i for i in images
+                              if i['id'] == self.snapshot3_id]))
 
     @test.attr(type='gate')
     def test_list_images_filter_by_server_ref(self):
@@ -106,11 +140,11 @@
             resp, images = self.client.list_images(params)
 
             self.assertFalse(any([i for i in images
-                                  if i['id'] == self.image1_id]))
+                                  if i['id'] == self.snapshot1_id]))
             self.assertFalse(any([i for i in images
-                                  if i['id'] == self.image2_id]))
+                                  if i['id'] == self.snapshot2_id]))
             self.assertTrue(any([i for i in images
-                                 if i['id'] == self.image3_id]))
+                                 if i['id'] == self.snapshot3_id]))
 
     @test.attr(type='gate')
     def test_list_images_filter_by_type(self):
@@ -118,10 +152,14 @@
         params = {'type': 'snapshot'}
         resp, images = self.client.list_images(params)
 
-        self.assertTrue(any([i for i in images if i['id'] == self.image1_id]))
-        self.assertTrue(any([i for i in images if i['id'] == self.image2_id]))
-        self.assertTrue(any([i for i in images if i['id'] == self.image3_id]))
-        self.assertFalse(any([i for i in images if i['id'] == self.image_ref]))
+        self.assertTrue(any([i for i in images
+                             if i['id'] == self.snapshot1_id]))
+        self.assertTrue(any([i for i in images
+                             if i['id'] == self.snapshot2_id]))
+        self.assertTrue(any([i for i in images
+                             if i['id'] == self.snapshot3_id]))
+        self.assertFalse(any([i for i in images
+                              if i['id'] == self.image_ref]))
 
     @test.attr(type='gate')
     def test_list_images_limit_results(self):
@@ -184,11 +222,11 @@
             resp, images = self.client.list_images_with_detail(params)
 
             self.assertFalse(any([i for i in images
-                                  if i['id'] == self.image1_id]))
+                                  if i['id'] == self.snapshot1_id]))
             self.assertFalse(any([i for i in images
-                                  if i['id'] == self.image2_id]))
+                                  if i['id'] == self.snapshot2_id]))
             self.assertTrue(any([i for i in images
-                                 if i['id'] == self.image3_id]))
+                                 if i['id'] == self.snapshot3_id]))
 
     @test.attr(type='gate')
     def test_list_images_with_detail_filter_by_type(self):
@@ -197,10 +235,14 @@
         resp, images = self.client.list_images_with_detail(params)
         resp, image4 = self.client.get_image(self.image_ref)
 
-        self.assertTrue(any([i for i in images if i['id'] == self.image1_id]))
-        self.assertTrue(any([i for i in images if i['id'] == self.image2_id]))
-        self.assertTrue(any([i for i in images if i['id'] == self.image3_id]))
-        self.assertFalse(any([i for i in images if i['id'] == self.image_ref]))
+        self.assertTrue(any([i for i in images
+                             if i['id'] == self.snapshot1_id]))
+        self.assertTrue(any([i for i in images
+                             if i['id'] == self.snapshot2_id]))
+        self.assertTrue(any([i for i in images
+                             if i['id'] == self.snapshot3_id]))
+        self.assertFalse(any([i for i in images
+                              if i['id'] == self.image_ref]))
 
     @test.attr(type='gate')
     def test_list_images_with_detail_filter_by_changes_since(self):
diff --git a/tempest/api/compute/security_groups/test_security_group_rules.py b/tempest/api/compute/security_groups/test_security_group_rules.py
index 35f6fc2..a1808dc 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -29,6 +29,7 @@
         cls.neutron_available = CONF.service_available.neutron
 
     @test.attr(type='smoke')
+    @test.services('network')
     def test_security_group_rules_create(self):
         # Positive test: Creation of Security Group rule
         # should be successful
@@ -48,6 +49,7 @@
         self.assertEqual(200, resp.status)
 
     @test.attr(type='smoke')
+    @test.services('network')
     def test_security_group_rules_create_with_optional_arguments(self):
         # Positive test: Creation of Security Group rule
         # with optional arguments
@@ -78,6 +80,7 @@
         self.assertEqual(200, resp.status)
 
     @test.attr(type='smoke')
+    @test.services('network')
     def test_security_group_rules_list(self):
         # Positive test: Created Security Group rules should be
         # in the list of all rules
@@ -114,6 +117,7 @@
         self.assertTrue(any([i for i in rules if i['id'] == rule2_id]))
 
     @test.attr(type='smoke')
+    @test.services('network')
     def test_security_group_rules_delete_when_peer_group_deleted(self):
         # Positive test:rule will delete when peer group deleting
         # Creating a Security Group to add rules to it
diff --git a/tempest/api/compute/security_groups/test_security_group_rules_negative.py b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
index 0b53037..cfa839a 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules_negative.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules_negative.py
@@ -37,6 +37,7 @@
         cls.client = cls.security_groups_client
 
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_create_security_group_rule_with_non_existent_id(self):
         # Negative test: Creation of Security Group rule should FAIL
         # with non existent Parent group id
@@ -50,6 +51,7 @@
                           parent_group_id, ip_protocol, from_port, to_port)
 
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_create_security_group_rule_with_invalid_id(self):
         # Negative test: Creation of Security Group rule should FAIL
         # with Parent group id which is not integer
@@ -63,6 +65,7 @@
                           parent_group_id, ip_protocol, from_port, to_port)
 
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_create_security_group_rule_duplicate(self):
         # Negative test: Create Security Group rule duplicate should fail
         # Creating a Security Group to add rule to it
@@ -86,6 +89,7 @@
                           parent_group_id, ip_protocol, from_port, to_port)
 
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_create_security_group_rule_with_invalid_ip_protocol(self):
         # Negative test: Creation of Security Group rule should FAIL
         # with invalid ip_protocol
@@ -102,6 +106,7 @@
                           parent_group_id, ip_protocol, from_port, to_port)
 
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_create_security_group_rule_with_invalid_from_port(self):
         # Negative test: Creation of Security Group rule should FAIL
         # with invalid from_port
@@ -117,6 +122,7 @@
                           parent_group_id, ip_protocol, from_port, to_port)
 
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_create_security_group_rule_with_invalid_to_port(self):
         # Negative test: Creation of Security Group rule should FAIL
         # with invalid to_port
@@ -132,6 +138,7 @@
                           parent_group_id, ip_protocol, from_port, to_port)
 
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_create_security_group_rule_with_invalid_port_range(self):
         # Negative test: Creation of Security Group rule should FAIL
         # with invalid port range.
@@ -147,6 +154,7 @@
                           secgroup_id, ip_protocol, from_port, to_port)
 
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_delete_security_group_rule_with_non_existent_id(self):
         # Negative test: Deletion of Security Group rule should be FAIL
         # with non existent id
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index a077943..860aebc 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -27,6 +27,7 @@
         cls.client = cls.security_groups_client
 
     @test.attr(type='smoke')
+    @test.services('network')
     def test_security_groups_create_list_delete(self):
         # Positive test:Should return the list of Security Groups
         # Create 3 Security Groups
@@ -61,6 +62,7 @@
                                             for m_group in deleted_sgs))
 
     @test.attr(type='smoke')
+    @test.services('network')
     def test_security_group_create_get_delete(self):
         # Security Group should be created, fetched and deleted
         # with char space between name along with
@@ -85,6 +87,7 @@
         self.client.wait_for_resource_deletion(securitygroup['id'])
 
     @test.attr(type='smoke')
+    @test.services('network')
     def test_server_security_groups(self):
         # Checks that security groups may be added and linked to a server
         # and not deleted if the server is active.
@@ -131,6 +134,7 @@
         self.assertEqual(202, resp.status)
 
     @test.attr(type='smoke')
+    @test.services('network')
     def test_update_security_groups(self):
         # Update security group name and description
         # Create a security group
diff --git a/tempest/api/compute/security_groups/test_security_groups_negative.py b/tempest/api/compute/security_groups/test_security_groups_negative.py
index aa2d32e..a9cca55 100644
--- a/tempest/api/compute/security_groups/test_security_groups_negative.py
+++ b/tempest/api/compute/security_groups/test_security_groups_negative.py
@@ -47,6 +47,7 @@
         return non_exist_id
 
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_security_group_get_nonexistent_group(self):
         # Negative test:Should not be able to GET the details
         # of non-existent Security Group
@@ -57,6 +58,7 @@
     @test.skip_because(bug="1161411",
                        condition=CONF.service_available.neutron)
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_security_group_create_with_invalid_group_name(self):
         # Negative test: Security Group should not be created with group name
         # as an empty string/with white spaces/chars more than 255
@@ -77,6 +79,7 @@
     @test.skip_because(bug="1161411",
                        condition=CONF.service_available.neutron)
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_security_group_create_with_invalid_group_description(self):
         # Negative test:Security Group should not be created with description
         # as an empty string/with white spaces/chars more than 255
@@ -96,6 +99,7 @@
     @testtools.skipIf(CONF.service_available.neutron,
                       "Neutron allows duplicate names for security groups")
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_security_group_create_with_duplicate_name(self):
         # Negative test:Security Group with duplicate name should not
         # be created
@@ -110,6 +114,7 @@
                           s_description)
 
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_delete_the_default_security_group(self):
         # Negative test:Deletion of the "default" Security Group should Fail
         default_security_group_id = None
@@ -124,6 +129,7 @@
                           default_security_group_id)
 
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_delete_nonexistent_security_group(self):
         # Negative test:Deletion of a non-existent Security Group should fail
         non_exist_id = self._generate_a_non_existent_security_group_id()
@@ -131,6 +137,7 @@
                           self.client.delete_security_group, non_exist_id)
 
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_delete_security_group_without_passing_id(self):
         # Negative test:Deletion of a Security Group with out passing ID
         # should Fail
@@ -140,6 +147,7 @@
     @testtools.skipIf(CONF.service_available.neutron,
                       "Neutron not check the security_group_id")
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_update_security_group_with_invalid_sg_id(self):
         # Update security_group with invalid sg_id should fail
         s_name = data_utils.rand_name('sg-')
@@ -153,6 +161,7 @@
     @testtools.skipIf(CONF.service_available.neutron,
                       "Neutron not check the security_group_name")
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_update_security_group_with_invalid_sg_name(self):
         # Update security_group with invalid sg_name should fail
         resp, securitygroup = self.create_security_group()
@@ -168,6 +177,7 @@
     @testtools.skipIf(CONF.service_available.neutron,
                       "Neutron not check the security_group_description")
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_update_security_group_with_invalid_sg_des(self):
         # Update security_group with invalid sg_des should fail
         resp, securitygroup = self.create_security_group()
@@ -181,6 +191,7 @@
                           securitygroup_id, description=s_new_des)
 
     @test.attr(type=['negative', 'smoke'])
+    @test.services('network')
     def test_update_non_existent_security_group(self):
         # Update a non-existent Security Group should Fail
         non_exist_id = self._generate_a_non_existent_security_group_id()
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 297b300..067d721 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -107,6 +107,7 @@
         self.assertEqual(sorted(list1), sorted(list2))
 
     @test.attr(type='smoke')
+    @test.services('network')
     def test_create_list_show_delete_interfaces(self):
         server, ifs = self._create_server_get_interfaces()
         interface_count = len(ifs)
@@ -128,6 +129,7 @@
         self.assertEqual(len(ifs) - 1, len(_ifs))
 
     @test.attr(type='smoke')
+    @test.services('network')
     def test_add_remove_fixed_ip(self):
         # Add and Remove the fixed IP to server.
         server, ifs = self._create_server_get_interfaces()
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index e135eca..279dc51 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -102,6 +102,28 @@
                                                   self.password)
         self.assertTrue(linux_client.hostname_equals_servername(self.name))
 
+    @test.skip_because(bug="1306367", interface="xml")
+    @test.attr(type='gate')
+    def test_create_server_with_scheduler_hint_group(self):
+        # Create a server with the scheduler hint "group".
+        name = data_utils.rand_name('server_group')
+        policies = ['affinity']
+        resp, body = self.client.create_server_group(name=name,
+                                                     policies=policies)
+        self.assertEqual(200, resp.status)
+        group_id = body['id']
+        self.addCleanup(self.client.delete_server_group, group_id)
+
+        hints = {'group': group_id}
+        resp, server = self.create_test_server(sched_hints=hints,
+                                               wait_until='ACTIVE')
+        self.assertEqual(202, resp.status)
+
+        # Check a server is in the group
+        resp, server_group = self.client.get_server_group(group_id)
+        self.assertEqual(200, resp.status)
+        self.assertIn(server['id'], server_group['members'])
+
 
 class ServersWithSpecificFlavorTestJSON(base.BaseV2ComputeAdminTest):
     disk_config = 'AUTO'
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index f66020c..9d39c9f 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -203,11 +203,13 @@
         params = {'status': 'active'}
         resp, body = self.client.list_servers_with_detail(params)
         servers = body['servers']
+        test_ids = [s['id'] for s in (self.s1, self.s2, self.s3)]
 
         self.assertIn(self.s1['id'], map(lambda x: x['id'], servers))
         self.assertIn(self.s2['id'], map(lambda x: x['id'], servers))
         self.assertIn(self.s3['id'], map(lambda x: x['id'], servers))
-        self.assertEqual(['ACTIVE'] * 3, [x['status'] for x in servers])
+        self.assertEqual(['ACTIVE'] * 3, [x['status'] for x in servers
+                                          if x['id'] in test_ids])
 
     @test.attr(type='gate')
     def test_list_servers_filtered_by_name_wildcard(self):
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index d0fd876..71fcbff 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 import base64
+import logging
 
 import testtools
 import urlparse
@@ -27,6 +28,8 @@
 
 CONF = config.CONF
 
+LOG = logging.getLogger(__name__)
+
 
 class ServerActionsTestJSON(base.BaseV2ComputeTest):
     run_ssh = CONF.compute.run_ssh
@@ -267,7 +270,14 @@
         # the oldest one should be deleted automatically in this test
         def _clean_oldest_backup(oldest_backup):
             if oldest_backup_exist:
-                self.os.image_client.delete_image(oldest_backup)
+                try:
+                    self.os.image_client.delete_image(oldest_backup)
+                except exceptions.NotFound:
+                    pass
+                else:
+                    LOG.warning("Deletion of oldest backup %s should not have "
+                                "been successful as it should have been "
+                                "deleted during rotation." % oldest_backup)
 
         image1_id = data_utils.parse_image_id(resp['location'])
         self.addCleanup(_clean_oldest_backup, image1_id)
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index 0c14dc2..846bf3e 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -34,6 +34,7 @@
     @test.skip_because(bug="1210483",
                        condition=CONF.service_available.neutron)
     @test.attr(type='smoke')
+    @test.services('network')
     def test_list_server_addresses(self):
         # All public and private addresses for
         # a server should be returned
@@ -51,6 +52,7 @@
                 self.assertTrue(address['version'])
 
     @test.attr(type='smoke')
+    @test.services('network')
     def test_list_server_addresses_by_network(self):
         # Providing a network type should filter
         # the addresses return by that type
diff --git a/tempest/api/compute/servers/test_server_addresses_negative.py b/tempest/api/compute/servers/test_server_addresses_negative.py
index d37f7fa..e190161 100644
--- a/tempest/api/compute/servers/test_server_addresses_negative.py
+++ b/tempest/api/compute/servers/test_server_addresses_negative.py
@@ -29,12 +29,14 @@
         resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
 
     @test.attr(type=['negative', 'gate'])
+    @test.services('network')
     def test_list_server_addresses_invalid_server_id(self):
         # List addresses request should fail if server id not in system
         self.assertRaises(exceptions.NotFound, self.client.list_addresses,
                           '999')
 
     @test.attr(type=['negative', 'gate'])
+    @test.services('network')
     def test_list_server_addresses_by_network_neg(self):
         # List addresses by network should fail if network name not valid
         self.assertRaises(exceptions.NotFound,
diff --git a/tempest/api/compute/servers/test_server_group.py b/tempest/api/compute/servers/test_server_group.py
index 0cd23fd..f1ef5d5 100644
--- a/tempest/api/compute/servers/test_server_group.py
+++ b/tempest/api/compute/servers/test_server_group.py
@@ -75,6 +75,7 @@
         policy = ['anti-affinity']
         self._create_delete_server_group(policy)
 
+    @test.skip_because(bug="1324348")
     @test.attr(type='gate')
     def test_create_delete_server_group_with_multiple_policies(self):
         # Create and Delete the server-group with multiple policies
diff --git a/tempest/api/compute/servers/test_server_metadata.py b/tempest/api/compute/servers/test_server_metadata.py
index 448b8ff..01ff6b9 100644
--- a/tempest/api/compute/servers/test_server_metadata.py
+++ b/tempest/api/compute/servers/test_server_metadata.py
@@ -24,10 +24,7 @@
         super(ServerMetadataTestJSON, cls).setUpClass()
         cls.client = cls.servers_client
         cls.quotas = cls.quotas_client
-        cls.admin_client = cls._get_identity_admin_client()
-        resp, tenants = cls.admin_client.list_tenants()
         resp, server = cls.create_test_server(meta={}, wait_until='ACTIVE')
-
         cls.server_id = server['id']
 
     def setUp(self):
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index 093e9e2..ab98d88 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -15,14 +15,21 @@
 
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
+from tempest import config
 from tempest import test
 
+CONF = config.CONF
+
 
 class ServerRescueTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
     @test.safe_setup
     def setUpClass(cls):
+        if not CONF.compute_feature_enabled.rescue:
+            msg = "Server rescue not available."
+            raise cls.skipException(msg)
+
         cls.set_network_resources(network=True, subnet=True, router=True)
         super(ServerRescueTestJSON, cls).setUpClass()
 
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
index dae4709..b35e55c 100644
--- a/tempest/api/compute/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -28,6 +28,10 @@
     @classmethod
     @test.safe_setup
     def setUpClass(cls):
+        if not CONF.compute_feature_enabled.rescue:
+            msg = "Server rescue not available."
+            raise cls.skipException(msg)
+
         cls.set_network_resources(network=True, subnet=True, router=True)
         super(ServerRescueNegativeTestJSON, cls).setUpClass()
         cls.device = 'vdf'
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 6343ead..d3297ce 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -106,6 +106,8 @@
         self.assertRaises(exceptions.BadRequest,
                           self.create_test_server, accessIPv6=IPv6)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_nonexistent_server(self):
         # Resize a non-existent server
@@ -114,6 +116,8 @@
                           self.client.resize,
                           nonexistent_server, self.flavor_ref)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_server_with_non_existent_flavor(self):
         # Resize a server with non-existent flavor
@@ -121,6 +125,8 @@
         self.assertRaises(exceptions.BadRequest, self.client.resize,
                           self.server_id, flavor_ref=nonexistent_flavor)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_server_with_null_flavor(self):
         # Resize a server with null flavor
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index 6354996..421ba8b 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -36,6 +36,7 @@
     @test.skip_because(bug="1183436",
                        condition=CONF.service_available.neutron)
     @test.attr(type='gate')
+    @test.services('network')
     def test_list_virtual_interfaces(self):
         # Positive test:Should be able to GET the virtual interfaces list
         # for a given server_id
diff --git a/tempest/api/compute/servers/test_virtual_interfaces_negative.py b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
index 87289d8..bcb2686 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces_negative.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
@@ -30,6 +30,7 @@
         cls.client = cls.servers_client
 
     @test.attr(type=['negative', 'gate'])
+    @test.services('network')
     def test_list_virtual_interfaces_invalid_server_id(self):
         # Negative test: Should not be able to GET virtual interfaces
         # for an invalid server_id
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index 375ddf8..fb8ded3 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import StringIO
+
 from tempest.api.compute import base
 from tempest import clients
 from tempest.common.utils import data_utils
@@ -27,9 +29,10 @@
 
 
 class AuthorizationTestJSON(base.BaseV2ComputeTest):
-
     @classmethod
     def setUpClass(cls):
+        if not CONF.service_available.glance:
+            raise cls.skipException('Glance is not available.')
         # No network resources required for this test
         cls.set_network_resources()
         super(AuthorizationTestJSON, cls).setUpClass()
@@ -38,6 +41,7 @@
             raise cls.skipException(msg)
         cls.client = cls.os.servers_client
         cls.images_client = cls.os.images_client
+        cls.glance_client = cls.os.image_client
         cls.keypairs_client = cls.os.keypairs_client
         cls.security_client = cls.os.security_groups_client
 
@@ -57,9 +61,14 @@
         resp, cls.server = cls.client.get_server(server['id'])
 
         name = data_utils.rand_name('image')
-        resp, body = cls.images_client.create_image(server['id'], name)
-        image_id = data_utils.parse_image_id(resp['location'])
-        cls.images_client.wait_for_image_status(image_id, 'ACTIVE')
+        resp, body = cls.glance_client.create_image(name=name,
+                                                   container_format='bare',
+                                                   disk_format='raw',
+                                                   is_public=False)
+        image_id = body['id']
+        image_file = StringIO.StringIO(('*' * 1024))
+        resp, body = cls.glance_client.update_image(image_id, data=image_file)
+        cls.glance_client.wait_for_image_status(image_id, 'active')
         resp, cls.image = cls.images_client.get_image(image_id)
 
         cls.keypairname = data_utils.rand_name('keypair')
diff --git a/tempest/api/compute/test_quotas.py b/tempest/api/compute/test_quotas.py
index dc85e76..eeff3ce 100644
--- a/tempest/api/compute/test_quotas.py
+++ b/tempest/api/compute/test_quotas.py
@@ -14,11 +14,17 @@
 #    under the License.
 
 from tempest.api.compute import base
+from tempest.common import tempest_fixtures as fixtures
 from tempest import test
 
 
 class QuotasTestJSON(base.BaseV2ComputeTest):
 
+    def setUp(self):
+        # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
+        self.useFixture(fixtures.LockFixture('compute_quotas'))
+        super(QuotasTestJSON, self).setUp()
+
     @classmethod
     def setUpClass(cls):
         super(QuotasTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_flavors.py b/tempest/api/compute/v3/admin/test_flavors.py
index 2a4fc02..09d76b8 100644
--- a/tempest/api/compute/v3/admin/test_flavors.py
+++ b/tempest/api/compute/v3/admin/test_flavors.py
@@ -229,7 +229,7 @@
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
 
-            # Create the flavor
+        # Create the flavor
         resp, flavor = self.client.create_flavor(flavor_name,
                                                  self.ram, self.vcpus,
                                                  self.disk,
@@ -294,7 +294,7 @@
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
 
-        ram = " 1024 "
+        ram = "1024"
         resp, flavor = self.client.create_flavor(flavor_name,
                                                  ram, self.vcpus,
                                                  self.disk,
diff --git a/tempest/api/compute/v3/admin/test_flavors_negative.py b/tempest/api/compute/v3/admin/test_flavors_negative.py
index 3f8a2da..6d3308e 100644
--- a/tempest/api/compute/v3/admin/test_flavors_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_negative.py
@@ -57,7 +57,7 @@
         resp, flavor = self.client.create_flavor(flavor_name,
                                                  self.ram,
                                                  self.vcpus, self.disk,
-                                                 '',
+                                                 None,
                                                  ephemeral=self.ephemeral,
                                                  swap=self.swap,
                                                  rxtx=self.rxtx)
diff --git a/tempest/api/compute/v3/admin/test_hypervisor.py b/tempest/api/compute/v3/admin/test_hypervisor.py
index f3397a8..9a23789 100644
--- a/tempest/api/compute/v3/admin/test_hypervisor.py
+++ b/tempest/api/compute/v3/admin/test_hypervisor.py
@@ -83,7 +83,27 @@
         # Verify that GET shows the specified hypervisor uptime
         hypers = self._list_hypervisors()
 
-        resp, uptime = self.client.get_hypervisor_uptime(hypers[0]['id'])
+        # Ironic will register each baremetal node as a 'hypervisor',
+        # so the hypervisor list can contain many hypervisors of type
+        # 'ironic'. If they are ALL ironic, skip this test since ironic
+        # doesn't support hypervisor uptime. Otherwise, remove them
+        # from the list of hypervisors to test.
+        ironic_only = True
+        hypers_without_ironic = []
+        for hyper in hypers:
+            resp, details = (self.client.
+                             get_hypervisor_show_details(hypers[0]['id']))
+            self.assertEqual(200, resp.status)
+            if details['hypervisor_type'] != 'ironic':
+                hypers_without_ironic.append(hyper)
+                ironic_only = False
+
+        if ironic_only:
+            raise self.skipException(
+                "Ironic does not support hypervisor uptime")
+
+        resp, uptime = self.client.get_hypervisor_uptime(
+            hypers_without_ironic[0]['id'])
         self.assertEqual(200, resp.status)
         self.assertTrue(len(uptime) > 0)
 
diff --git a/tempest/api/compute/v3/admin/test_quotas_negative.py b/tempest/api/compute/v3/admin/test_quotas_negative.py
index 307462f..7739f09 100644
--- a/tempest/api/compute/v3/admin/test_quotas_negative.py
+++ b/tempest/api/compute/v3/admin/test_quotas_negative.py
@@ -34,6 +34,7 @@
 
     # TODO(afazekas): Add dedicated tenant to the skiped quota tests
     # it can be moved into the setUpClass as well
+    @test.skip_because(bug="1298131")
     @test.attr(type=['negative', 'gate'])
     def test_create_server_when_cpu_quota_is_full(self):
         # Disallow server creation when tenant's vcpu quota is full
@@ -47,8 +48,9 @@
 
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         cores=default_vcpu_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
 
+    @test.skip_because(bug="1298131")
     @test.attr(type=['negative', 'gate'])
     def test_create_server_when_memory_quota_is_full(self):
         # Disallow server creation when tenant's memory quota is full
@@ -62,7 +64,7 @@
 
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         ram=default_mem_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
 
     @test.attr(type=['negative', 'gate'])
     def test_update_quota_normal_user(self):
@@ -71,6 +73,7 @@
                           self.demo_tenant_id,
                           ram=0)
 
+    @test.skip_because(bug="1298131")
     @test.attr(type=['negative', 'gate'])
     def test_create_server_when_instances_quota_is_full(self):
         # Once instances quota limit is reached, disallow server creation
@@ -83,4 +86,4 @@
                                          instances=instances_quota)
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         instances=default_instances_quota)
-        self.assertRaises(exceptions.OverLimit, self.create_test_server)
+        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
diff --git a/tempest/api/compute/v3/admin/test_servers_negative.py b/tempest/api/compute/v3/admin/test_servers_negative.py
index a971463..5eb6395 100644
--- a/tempest/api/compute/v3/admin/test_servers_negative.py
+++ b/tempest/api/compute/v3/admin/test_servers_negative.py
@@ -54,6 +54,7 @@
             flavor_id = data_utils.rand_int_id(start=1000)
         return flavor_id
 
+    @test.skip_because(bug="1298131")
     @test.attr(type=['negative', 'gate'])
     def test_resize_server_using_overlimit_ram(self):
         flavor_name = data_utils.rand_name("flavor-")
@@ -67,11 +68,12 @@
                                                              ram, vcpus, disk,
                                                              flavor_id)
         self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
-        self.assertRaises(exceptions.OverLimit,
+        self.assertRaises(exceptions.Unauthorized,
                           self.client.resize,
                           self.servers[0]['id'],
                           flavor_ref['id'])
 
+    @test.skip_because(bug="1298131")
     @test.attr(type=['negative', 'gate'])
     def test_resize_server_using_overlimit_vcpus(self):
         flavor_name = data_utils.rand_name("flavor-")
@@ -85,7 +87,7 @@
                                                              ram, vcpus, disk,
                                                              flavor_id)
         self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
-        self.assertRaises(exceptions.OverLimit,
+        self.assertRaises(exceptions.Unauthorized,
                           self.client.resize,
                           self.servers[0]['id'],
                           flavor_ref['id'])
diff --git a/tempest/api/compute/v3/servers/test_instance_actions.py b/tempest/api/compute/v3/servers/test_instance_actions.py
index 399541b..4c2dcbe 100644
--- a/tempest/api/compute/v3/servers/test_instance_actions.py
+++ b/tempest/api/compute/v3/servers/test_instance_actions.py
@@ -27,7 +27,6 @@
         cls.resp = resp
         cls.server_id = server['id']
 
-    @test.skip_because(bug="1206032")
     @test.attr(type='gate')
     def test_list_server_actions(self):
         # List actions of the provided server
@@ -40,12 +39,10 @@
         self.assertTrue(any([i for i in body if i['action'] == 'create']))
         self.assertTrue(any([i for i in body if i['action'] == 'reboot']))
 
-    @test.skip_because(bug="1206032")
     @test.attr(type='gate')
-    @test.skip_because(bug="1281915")
     def test_get_server_action(self):
         # Get the action details of the provided server
-        request_id = self.resp['x-compute-request-id']
+        request_id = self.resp['x-openstack-request-id']
         resp, body = self.client.get_server_action(self.server_id,
                                                    request_id)
         self.assertEqual(200, resp.status)
diff --git a/tempest/api/compute/v3/servers/test_server_actions.py b/tempest/api/compute/v3/servers/test_server_actions.py
index e098311..3ee8050 100644
--- a/tempest/api/compute/v3/servers/test_server_actions.py
+++ b/tempest/api/compute/v3/servers/test_server_actions.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import logging
+
 import testtools
 import urlparse
 
@@ -25,6 +27,8 @@
 
 CONF = config.CONF
 
+LOG = logging.getLogger(__name__)
+
 
 class ServerActionsV3Test(base.BaseV3ComputeTest):
     run_ssh = CONF.compute.run_ssh
@@ -260,7 +264,14 @@
         # the oldest one should be deleted automatically in this test
         def _clean_oldest_backup(oldest_backup):
             if oldest_backup_exist:
-                self.images_client.delete_image(oldest_backup)
+                try:
+                    self.images_client.delete_image(oldest_backup)
+                except exceptions.NotFound:
+                    pass
+                else:
+                    LOG.warning("Deletion of oldest backup %s should not have "
+                                "been successful as it should have been "
+                                "deleted during rotation." % oldest_backup)
 
         image1_id = data_utils.parse_image_id(resp['location'])
         self.addCleanup(_clean_oldest_backup, image1_id)
diff --git a/tempest/api/compute/v3/servers/test_server_metadata.py b/tempest/api/compute/v3/servers/test_server_metadata.py
index 298cd3c..c5443ee 100644
--- a/tempest/api/compute/v3/servers/test_server_metadata.py
+++ b/tempest/api/compute/v3/servers/test_server_metadata.py
@@ -24,9 +24,7 @@
         super(ServerMetadataV3Test, cls).setUpClass()
         cls.client = cls.servers_client
         cls.quotas = cls.quotas_client
-        cls.tenant_id = cls.client.tenant_id
         resp, server = cls.create_test_server(meta={}, wait_until='ACTIVE')
-
         cls.server_id = server['id']
 
     def setUp(self):
diff --git a/tempest/api/compute/v3/servers/test_server_rescue.py b/tempest/api/compute/v3/servers/test_server_rescue.py
index b3dcb51..da58f26 100644
--- a/tempest/api/compute/v3/servers/test_server_rescue.py
+++ b/tempest/api/compute/v3/servers/test_server_rescue.py
@@ -14,13 +14,19 @@
 #    under the License.
 
 from tempest.api.compute import base
+from tempest import config
 from tempest import test
 
+CONF = config.CONF
+
 
 class ServerRescueV3Test(base.BaseV3ComputeTest):
 
     @classmethod
     def setUpClass(cls):
+        if not CONF.compute_feature_enabled.rescue:
+            msg = "Server rescue not available."
+            raise cls.skipException(msg)
         super(ServerRescueV3Test, cls).setUpClass()
 
         # Server for positive tests
diff --git a/tempest/api/compute/v3/servers/test_server_rescue_negative.py b/tempest/api/compute/v3/servers/test_server_rescue_negative.py
index eb6bcdd..5eb6c9a 100644
--- a/tempest/api/compute/v3/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/v3/servers/test_server_rescue_negative.py
@@ -28,6 +28,10 @@
     @classmethod
     @test.safe_setup
     def setUpClass(cls):
+        if not CONF.compute_feature_enabled.rescue:
+            msg = "Server rescue not available."
+            raise cls.skipException(msg)
+
         super(ServerRescueNegativeV3Test, cls).setUpClass()
         cls.device = 'vdf'
 
diff --git a/tempest/api/compute/v3/test_quotas.py b/tempest/api/compute/v3/test_quotas.py
index 62a7556..ecf70cf 100644
--- a/tempest/api/compute/v3/test_quotas.py
+++ b/tempest/api/compute/v3/test_quotas.py
@@ -14,11 +14,17 @@
 #    under the License.
 
 from tempest.api.compute import base
+from tempest.common import tempest_fixtures as fixtures
 from tempest import test
 
 
 class QuotasV3Test(base.BaseV3ComputeTest):
 
+    def setUp(self):
+        # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
+        self.useFixture(fixtures.LockFixture('compute_quotas'))
+        super(QuotasV3Test, self).setUp()
+
     @classmethod
     def setUpClass(cls):
         super(QuotasV3Test, cls).setUpClass()
diff --git a/tempest/api/data_processing/base.py b/tempest/api/data_processing/base.py
index cc76880..cfb5a3d 100644
--- a/tempest/api/data_processing/base.py
+++ b/tempest/api/data_processing/base.py
@@ -29,8 +29,8 @@
         if not CONF.service_available.sahara:
             raise cls.skipException('Sahara support is required')
 
-        os = cls.get_client_manager()
-        cls.client = os.data_processing_client
+        cls.os = cls.get_client_manager()
+        cls.client = cls.os.data_processing_client
 
         cls.flavor_ref = CONF.compute.flavor_ref
 
@@ -39,6 +39,7 @@
         cls._cluster_templates = []
         cls._data_sources = []
         cls._job_binary_internals = []
+        cls._job_binaries = []
 
     @classmethod
     def tearDownClass(cls):
@@ -50,6 +51,8 @@
                               cls.client.delete_data_source)
         cls.cleanup_resources(getattr(cls, '_job_binary_internals', []),
                               cls.client.delete_job_binary_internal)
+        cls.cleanup_resources(getattr(cls, '_job_binaries', []),
+                              cls.client.delete_job_binary)
         cls.clear_isolated_creds()
         super(BaseDataProcessingTest, cls).tearDownClass()
 
@@ -72,16 +75,16 @@
         object. All resources created in this method will be automatically
         removed in tearDownClass method.
         """
-        resp, body = cls.client.create_node_group_template(name, plugin_name,
-                                                           hadoop_version,
-                                                           node_processes,
-                                                           flavor_id,
-                                                           node_configs,
-                                                           **kwargs)
+        _, resp_body = cls.client.create_node_group_template(name, plugin_name,
+                                                             hadoop_version,
+                                                             node_processes,
+                                                             flavor_id,
+                                                             node_configs,
+                                                             **kwargs)
         # store id of created node group template
-        cls._node_group_templates.append(body['id'])
+        cls._node_group_templates.append(resp_body['id'])
 
-        return resp, body
+        return resp_body
 
     @classmethod
     def create_cluster_template(cls, name, plugin_name, hadoop_version,
@@ -92,15 +95,15 @@
         object. All resources created in this method will be automatically
         removed in tearDownClass method.
         """
-        resp, body = cls.client.create_cluster_template(name, plugin_name,
-                                                        hadoop_version,
-                                                        node_groups,
-                                                        cluster_configs,
-                                                        **kwargs)
+        _, resp_body = cls.client.create_cluster_template(name, plugin_name,
+                                                          hadoop_version,
+                                                          node_groups,
+                                                          cluster_configs,
+                                                          **kwargs)
         # store id of created cluster template
-        cls._cluster_templates.append(body['id'])
+        cls._cluster_templates.append(resp_body['id'])
 
-        return resp, body
+        return resp_body
 
     @classmethod
     def create_data_source(cls, name, type, url, **kwargs):
@@ -110,11 +113,11 @@
         object. All resources created in this method will be automatically
         removed in tearDownClass method.
         """
-        resp, body = cls.client.create_data_source(name, type, url, **kwargs)
+        _, resp_body = cls.client.create_data_source(name, type, url, **kwargs)
         # store id of created data source
-        cls._data_sources.append(body['id'])
+        cls._data_sources.append(resp_body['id'])
 
-        return resp, body
+        return resp_body
 
     @classmethod
     def create_job_binary_internal(cls, name, data):
@@ -123,8 +126,21 @@
         It returns created object. All resources created in this method will
         be automatically removed in tearDownClass method.
         """
-        resp, body = cls.client.create_job_binary_internal(name, data)
+        _, resp_body = cls.client.create_job_binary_internal(name, data)
         # store id of created job binary internal
-        cls._job_binary_internals.append(body['id'])
+        cls._job_binary_internals.append(resp_body['id'])
 
-        return resp, body
+        return resp_body
+
+    def create_job_binary(cls, name, url, extra=None, **kwargs):
+        """Creates watched job binary with specified params.
+
+        It supports passing additional params using kwargs and returns created
+        object. All resources created in this method will be automatically
+        removed in tearDownClass method.
+        """
+        _, resp_body = cls.client.create_job_binary(name, url, extra, **kwargs)
+        # store id of created job binary
+        cls._job_binaries.append(resp_body['id'])
+
+        return resp_body
diff --git a/tempest/api/data_processing/test_cluster_templates.py b/tempest/api/data_processing/test_cluster_templates.py
index c08d6ba..ff67c1c 100644
--- a/tempest/api/data_processing/test_cluster_templates.py
+++ b/tempest/api/data_processing/test_cluster_templates.py
@@ -22,6 +22,7 @@
     sahara/restapi/rest_api_v1.0.html#cluster-templates
     """
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(ClusterTemplateTest, cls).setUpClass()
         # create node group template
@@ -38,7 +39,8 @@
                 }
             }
         }
-        resp_body = cls.create_node_group_template(**node_group_template)[1]
+        resp_body = cls.create_node_group_template(**node_group_template)
+        node_group_template_id = resp_body['id']
 
         cls.full_cluster_template = {
             'description': 'Test cluster template',
@@ -65,7 +67,7 @@
                 },
                 {
                     'name': 'worker-node',
-                    'node_group_template_id': resp_body['id'],
+                    'node_group_template_id': node_group_template_id,
                     'count': 3
                 }
             ]
@@ -93,23 +95,22 @@
     def _create_cluster_template(self, template_name=None):
         """Creates Cluster Template with optional name specified.
 
-        It creates template and ensures response status, template name and
-        response body. Returns id and name of created template.
+        It creates template, ensures template name and response body.
+        Returns id and name of created template.
         """
         if not template_name:
             # generate random name if it's not specified
             template_name = data_utils.rand_name('sahara-cluster-template')
 
         # create cluster template
-        resp, body = self.create_cluster_template(template_name,
-                                                  **self.full_cluster_template)
+        resp_body = self.create_cluster_template(template_name,
+                                                 **self.full_cluster_template)
 
         # ensure that template created successfully
-        self.assertEqual(202, resp.status)
-        self.assertEqual(template_name, body['name'])
-        self.assertDictContainsSubset(self.cluster_template, body)
+        self.assertEqual(template_name, resp_body['name'])
+        self.assertDictContainsSubset(self.cluster_template, resp_body)
 
-        return body['id'], template_name
+        return resp_body['id'], template_name
 
     @test.attr(type='smoke')
     def test_cluster_template_create(self):
@@ -120,8 +121,7 @@
         template_info = self._create_cluster_template()
 
         # check for cluster template in list
-        resp, templates = self.client.list_cluster_templates()
-        self.assertEqual(200, resp.status)
+        _, templates = self.client.list_cluster_templates()
         templates_info = [(template['id'], template['name'])
                           for template in templates]
         self.assertIn(template_info, templates_info)
@@ -131,16 +131,14 @@
         template_id, template_name = self._create_cluster_template()
 
         # check cluster template fetch by id
-        resp, template = self.client.get_cluster_template(template_id)
-        self.assertEqual(200, resp.status)
+        _, template = self.client.get_cluster_template(template_id)
         self.assertEqual(template_name, template['name'])
         self.assertDictContainsSubset(self.cluster_template, template)
 
     @test.attr(type='smoke')
     def test_cluster_template_delete(self):
-        template_id = self._create_cluster_template()[0]
+        template_id, _ = self._create_cluster_template()
 
         # delete the cluster template by id
-        resp = self.client.delete_cluster_template(template_id)[0]
-        self.assertEqual(204, resp.status)
-        #TODO(ylobankov): check that cluster template is really deleted
+        self.client.delete_cluster_template(template_id)
+        # TODO(ylobankov): check that cluster template is really deleted
diff --git a/tempest/api/data_processing/test_data_sources.py b/tempest/api/data_processing/test_data_sources.py
index c72e828..aae56c4 100644
--- a/tempest/api/data_processing/test_data_sources.py
+++ b/tempest/api/data_processing/test_data_sources.py
@@ -14,11 +14,8 @@
 
 from tempest.api.data_processing import base as dp_base
 from tempest.common.utils import data_utils
-from tempest import config
 from tempest import test
 
-CONF = config.CONF
-
 
 class DataSourceTest(dp_base.BaseDataProcessingTest):
     @classmethod
@@ -28,8 +25,8 @@
             'url': 'swift://sahara-container.sahara/input-source',
             'description': 'Test data source',
             'credentials': {
-                'user': CONF.identity.username,
-                'password': CONF.identity.password
+                'user': cls.os.credentials.username,
+                'password': cls.os.credentials.password
             },
             'type': 'swift'
         }
@@ -51,65 +48,59 @@
     def _create_data_source(self, source_body, source_name=None):
         """Creates Data Source with optional name specified.
 
-        It creates a link to input-source file (it may not exist) and ensures
-        response status and source name. Returns id and name of created source.
+        It creates a link to input-source file (it may not exist), ensures
+        source name and response body. Returns id and name of created source.
         """
         if not source_name:
             # generate random name if it's not specified
             source_name = data_utils.rand_name('sahara-data-source')
 
         # create data source
-        resp, body = self.create_data_source(source_name, **source_body)
+        resp_body = self.create_data_source(source_name, **source_body)
 
         # ensure that source created successfully
-        self.assertEqual(202, resp.status)
-        self.assertEqual(source_name, body['name'])
+        self.assertEqual(source_name, resp_body['name'])
         if source_body['type'] == 'swift':
             source_body = self.swift_data_source
-        self.assertDictContainsSubset(source_body, body)
+        self.assertDictContainsSubset(source_body, resp_body)
 
-        return body['id'], source_name
+        return resp_body['id'], source_name
 
     def _list_data_sources(self, source_info):
         # check for data source in list
-        resp, sources = self.client.list_data_sources()
-        self.assertEqual(200, resp.status)
+        _, sources = self.client.list_data_sources()
         sources_info = [(source['id'], source['name']) for source in sources]
         self.assertIn(source_info, sources_info)
 
     def _get_data_source(self, source_id, source_name, source_body):
         # check data source fetch by id
-        resp, source = self.client.get_data_source(source_id)
-        self.assertEqual(200, resp.status)
+        _, source = self.client.get_data_source(source_id)
         self.assertEqual(source_name, source['name'])
         self.assertDictContainsSubset(source_body, source)
 
-    def _delete_data_source(self, source_id):
-        # delete the data source by id
-        resp = self.client.delete_data_source(source_id)[0]
-        self.assertEqual(204, resp.status)
-
     @test.attr(type='smoke')
     def test_swift_data_source_create(self):
         self._create_data_source(self.swift_data_source_with_creds)
 
     @test.attr(type='smoke')
     def test_swift_data_source_list(self):
-        source_info = self._create_data_source(
-            self.swift_data_source_with_creds)
+        source_info = (
+            self._create_data_source(self.swift_data_source_with_creds))
         self._list_data_sources(source_info)
 
     @test.attr(type='smoke')
     def test_swift_data_source_get(self):
-        source_id, source_name = self._create_data_source(
-            self.swift_data_source_with_creds)
+        source_id, source_name = (
+            self._create_data_source(self.swift_data_source_with_creds))
         self._get_data_source(source_id, source_name, self.swift_data_source)
 
     @test.attr(type='smoke')
     def test_swift_data_source_delete(self):
-        source_id = self._create_data_source(
-            self.swift_data_source_with_creds)[0]
-        self._delete_data_source(source_id)
+        source_id, _ = (
+            self._create_data_source(self.swift_data_source_with_creds))
+
+        # delete the data source by id
+        self.client.delete_data_source(source_id)
 
     @test.attr(type='smoke')
     def test_local_hdfs_data_source_create(self):
@@ -122,15 +113,17 @@
 
     @test.attr(type='smoke')
     def test_local_hdfs_data_source_get(self):
-        source_id, source_name = self._create_data_source(
-            self.local_hdfs_data_source)
+        source_id, source_name = (
+            self._create_data_source(self.local_hdfs_data_source))
         self._get_data_source(
             source_id, source_name, self.local_hdfs_data_source)
 
     @test.attr(type='smoke')
     def test_local_hdfs_data_source_delete(self):
-        source_id = self._create_data_source(self.local_hdfs_data_source)[0]
-        self._delete_data_source(source_id)
+        source_id, _ = self._create_data_source(self.local_hdfs_data_source)
+
+        # delete the data source by id
+        self.client.delete_data_source(source_id)
 
     @test.attr(type='smoke')
     def test_external_hdfs_data_source_create(self):
@@ -143,12 +136,14 @@
 
     @test.attr(type='smoke')
     def test_external_hdfs_data_source_get(self):
-        source_id, source_name = self._create_data_source(
-            self.external_hdfs_data_source)
+        source_id, source_name = (
+            self._create_data_source(self.external_hdfs_data_source))
         self._get_data_source(
             source_id, source_name, self.external_hdfs_data_source)
 
     @test.attr(type='smoke')
     def test_external_hdfs_data_source_delete(self):
-        source_id = self._create_data_source(self.external_hdfs_data_source)[0]
-        self._delete_data_source(source_id)
+        source_id, _ = self._create_data_source(self.external_hdfs_data_source)
+
+        # delete the data source by id
+        self.client.delete_data_source(source_id)
diff --git a/tempest/api/data_processing/test_job_binaries.py b/tempest/api/data_processing/test_job_binaries.py
new file mode 100644
index 0000000..15ee145
--- /dev/null
+++ b/tempest/api/data_processing/test_job_binaries.py
@@ -0,0 +1,140 @@
+# Copyright (c) 2014 Mirantis Inc.
+#
+#    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.api.data_processing import base as dp_base
+from tempest.common.utils import data_utils
+from tempest import test
+
+
+class JobBinaryTest(dp_base.BaseDataProcessingTest):
+    """Link to the API documentation is http://docs.openstack.org/developer/
+    sahara/restapi/rest_api_v1.1_EDP.html#job-binaries
+    """
+    @classmethod
+    @test.safe_setup
+    def setUpClass(cls):
+        super(JobBinaryTest, cls).setUpClass()
+        cls.swift_job_binary_with_extra = {
+            'url': 'swift://sahara-container.sahara/example.jar',
+            'description': 'Test job binary',
+            'extra': {
+                'user': cls.os.credentials.username,
+                'password': cls.os.credentials.password
+            }
+        }
+        # Create extra cls.swift_job_binary variable to use for comparison to
+        # job binary response body because response body has no 'extra' field.
+        cls.swift_job_binary = cls.swift_job_binary_with_extra.copy()
+        del cls.swift_job_binary['extra']
+
+        name = data_utils.rand_name('sahara-internal-job-binary')
+        cls.job_binary_data = 'Some script may be data'
+        job_binary_internal = (
+            cls.create_job_binary_internal(name, cls.job_binary_data))
+        cls.internal_db_job_binary = {
+            'url': 'internal-db://%s' % job_binary_internal['id'],
+            'description': 'Test job binary',
+        }
+
+    def _create_job_binary(self, binary_body, binary_name=None):
+        """Creates Job Binary with optional name specified.
+
+        It creates a link to data (jar, pig files, etc.), ensures job binary
+        name and response body. Returns id and name of created job binary.
+        Data may not exist when using Swift as data storage.
+        In other cases data must exist in storage.
+        """
+        if not binary_name:
+            # generate random name if it's not specified
+            binary_name = data_utils.rand_name('sahara-job-binary')
+
+        # create job binary
+        resp_body = self.create_job_binary(binary_name, **binary_body)
+
+        # ensure that binary created successfully
+        self.assertEqual(binary_name, resp_body['name'])
+        if 'swift' in binary_body['url']:
+            binary_body = self.swift_job_binary
+        self.assertDictContainsSubset(binary_body, resp_body)
+
+        return resp_body['id'], binary_name
+
+    @test.attr(type='smoke')
+    def test_swift_job_binary_create(self):
+        self._create_job_binary(self.swift_job_binary_with_extra)
+
+    @test.attr(type='smoke')
+    def test_swift_job_binary_list(self):
+        binary_info = self._create_job_binary(self.swift_job_binary_with_extra)
+
+        # check for job binary in list
+        _, binaries = self.client.list_job_binaries()
+        binaries_info = [(binary['id'], binary['name']) for binary in binaries]
+        self.assertIn(binary_info, binaries_info)
+
+    @test.attr(type='smoke')
+    def test_swift_job_binary_get(self):
+        binary_id, binary_name = (
+            self._create_job_binary(self.swift_job_binary_with_extra))
+
+        # check job binary fetch by id
+        _, binary = self.client.get_job_binary(binary_id)
+        self.assertEqual(binary_name, binary['name'])
+        self.assertDictContainsSubset(self.swift_job_binary, binary)
+
+    @test.attr(type='smoke')
+    def test_swift_job_binary_delete(self):
+        binary_id, _ = (
+            self._create_job_binary(self.swift_job_binary_with_extra))
+
+        # delete the job binary by id
+        self.client.delete_job_binary(binary_id)
+
+    @test.attr(type='smoke')
+    def test_internal_db_job_binary_create(self):
+        self._create_job_binary(self.internal_db_job_binary)
+
+    @test.attr(type='smoke')
+    def test_internal_db_job_binary_list(self):
+        binary_info = self._create_job_binary(self.internal_db_job_binary)
+
+        # check for job binary in list
+        _, binaries = self.client.list_job_binaries()
+        binaries_info = [(binary['id'], binary['name']) for binary in binaries]
+        self.assertIn(binary_info, binaries_info)
+
+    @test.attr(type='smoke')
+    def test_internal_db_job_binary_get(self):
+        binary_id, binary_name = (
+            self._create_job_binary(self.internal_db_job_binary))
+
+        # check job binary fetch by id
+        _, binary = self.client.get_job_binary(binary_id)
+        self.assertEqual(binary_name, binary['name'])
+        self.assertDictContainsSubset(self.internal_db_job_binary, binary)
+
+    @test.attr(type='smoke')
+    def test_internal_db_job_binary_delete(self):
+        binary_id, _ = self._create_job_binary(self.internal_db_job_binary)
+
+        # delete the job binary by id
+        self.client.delete_job_binary(binary_id)
+
+    @test.attr(type='smoke')
+    def test_job_binary_get_data(self):
+        binary_id, _ = self._create_job_binary(self.internal_db_job_binary)
+
+        # get data of job binary by id
+        _, data = self.client.get_job_binary_data(binary_id)
+        self.assertEqual(data, self.job_binary_data)
diff --git a/tempest/api/data_processing/test_job_binary_internals.py b/tempest/api/data_processing/test_job_binary_internals.py
index 6d59177..45e1140 100644
--- a/tempest/api/data_processing/test_job_binary_internals.py
+++ b/tempest/api/data_processing/test_job_binary_internals.py
@@ -29,23 +29,22 @@
     def _create_job_binary_internal(self, binary_name=None):
         """Creates Job Binary Internal with optional name specified.
 
-        It puts data into Sahara database and ensures response status and
-        job binary internal name. Returns id and name of created job binary
-        internal.
+        It puts data into Sahara database and ensures job binary internal name.
+        Returns id and name of created job binary internal.
         """
         if not binary_name:
             # generate random name if it's not specified
             binary_name = data_utils.rand_name('sahara-job-binary-internal')
 
         # create job binary internal
-        resp, body = self.create_job_binary_internal(
-            binary_name, self.job_binary_internal_data)
+        resp_body = (
+            self.create_job_binary_internal(binary_name,
+                                            self.job_binary_internal_data))
 
         # ensure that job binary internal created successfully
-        self.assertEqual(202, resp.status)
-        self.assertEqual(binary_name, body['name'])
+        self.assertEqual(binary_name, resp_body['name'])
 
-        return body['id'], binary_name
+        return resp_body['id'], binary_name
 
     @test.attr(type='smoke')
     def test_job_binary_internal_create(self):
@@ -56,8 +55,7 @@
         binary_info = self._create_job_binary_internal()
 
         # check for job binary internal in list
-        resp, binaries = self.client.list_job_binary_internals()
-        self.assertEqual(200, resp.status)
+        _, binaries = self.client.list_job_binary_internals()
         binaries_info = [(binary['id'], binary['name']) for binary in binaries]
         self.assertIn(binary_info, binaries_info)
 
@@ -66,23 +64,20 @@
         binary_id, binary_name = self._create_job_binary_internal()
 
         # check job binary internal fetch by id
-        resp, binary = self.client.get_job_binary_internal(binary_id)
-        self.assertEqual(200, resp.status)
+        _, binary = self.client.get_job_binary_internal(binary_id)
         self.assertEqual(binary_name, binary['name'])
 
     @test.attr(type='smoke')
     def test_job_binary_internal_delete(self):
-        binary_id = self._create_job_binary_internal()[0]
+        binary_id, _ = self._create_job_binary_internal()
 
         # delete the job binary internal by id
-        resp = self.client.delete_job_binary_internal(binary_id)[0]
-        self.assertEqual(204, resp.status)
+        self.client.delete_job_binary_internal(binary_id)
 
     @test.attr(type='smoke')
     def test_job_binary_internal_get_data(self):
-        binary_id = self._create_job_binary_internal()[0]
+        binary_id, _ = self._create_job_binary_internal()
 
         # get data of job binary internal by id
-        resp, data = self.client.get_job_binary_internal_data(binary_id)
-        self.assertEqual(200, resp.status)
+        _, data = self.client.get_job_binary_internal_data(binary_id)
         self.assertEqual(data, self.job_binary_internal_data)
diff --git a/tempest/api/data_processing/test_node_group_templates.py b/tempest/api/data_processing/test_node_group_templates.py
index 04f98b4..c2c0075 100644
--- a/tempest/api/data_processing/test_node_group_templates.py
+++ b/tempest/api/data_processing/test_node_group_templates.py
@@ -43,7 +43,7 @@
     def _create_node_group_template(self, template_name=None):
         """Creates Node Group Template with optional name specified.
 
-        It creates template and ensures response status and template name.
+        It creates template, ensures template name and response body.
         Returns id and name of created template.
         """
         if not template_name:
@@ -51,15 +51,14 @@
             template_name = data_utils.rand_name('sahara-ng-template')
 
         # create node group template
-        resp, body = self.create_node_group_template(
-            template_name, **self.node_group_template)
+        resp_body = self.create_node_group_template(template_name,
+                                                    **self.node_group_template)
 
         # ensure that template created successfully
-        self.assertEqual(202, resp.status)
-        self.assertEqual(template_name, body['name'])
-        self.assertDictContainsSubset(self.node_group_template, body)
+        self.assertEqual(template_name, resp_body['name'])
+        self.assertDictContainsSubset(self.node_group_template, resp_body)
 
-        return body['id'], template_name
+        return resp_body['id'], template_name
 
     @test.attr(type='smoke')
     def test_node_group_template_create(self):
@@ -70,8 +69,7 @@
         template_info = self._create_node_group_template()
 
         # check for node group template in list
-        resp, templates = self.client.list_node_group_templates()
-        self.assertEqual(200, resp.status)
+        _, templates = self.client.list_node_group_templates()
         templates_info = [(template['id'], template['name'])
                           for template in templates]
         self.assertIn(template_info, templates_info)
@@ -81,15 +79,13 @@
         template_id, template_name = self._create_node_group_template()
 
         # check node group template fetch by id
-        resp, template = self.client.get_node_group_template(template_id)
-        self.assertEqual(200, resp.status)
+        _, template = self.client.get_node_group_template(template_id)
         self.assertEqual(template_name, template['name'])
         self.assertDictContainsSubset(self.node_group_template, template)
 
     @test.attr(type='smoke')
     def test_node_group_template_delete(self):
-        template_id = self._create_node_group_template()[0]
+        template_id, _ = self._create_node_group_template()
 
         # delete the node group template by id
-        resp = self.client.delete_node_group_template(template_id)[0]
-        self.assertEqual(204, resp.status)
+        self.client.delete_node_group_template(template_id)
diff --git a/tempest/api/data_processing/test_plugins.py b/tempest/api/data_processing/test_plugins.py
index d643f23..9fd7a17 100644
--- a/tempest/api/data_processing/test_plugins.py
+++ b/tempest/api/data_processing/test_plugins.py
@@ -20,10 +20,9 @@
     def _list_all_plugin_names(self):
         """Returns all enabled plugin names.
 
-        It ensures response status and main plugins availability.
+        It ensures main plugins availability.
         """
-        resp, plugins = self.client.list_plugins()
-        self.assertEqual(200, resp.status)
+        _, plugins = self.client.list_plugins()
         plugins_names = [plugin['name'] for plugin in plugins]
         self.assertIn('vanilla', plugins_names)
         self.assertIn('hdp', plugins_names)
@@ -37,14 +36,12 @@
     @test.attr(type='smoke')
     def test_plugin_get(self):
         for plugin_name in self._list_all_plugin_names():
-            resp, plugin = self.client.get_plugin(plugin_name)
-            self.assertEqual(200, resp.status)
+            _, plugin = self.client.get_plugin(plugin_name)
             self.assertEqual(plugin_name, plugin['name'])
 
             for plugin_version in plugin['versions']:
-                resp, detailed_plugin = self.client.get_plugin(plugin_name,
-                                                               plugin_version)
-                self.assertEqual(200, resp.status)
+                _, detailed_plugin = self.client.get_plugin(plugin_name,
+                                                            plugin_version)
                 self.assertEqual(plugin_name, detailed_plugin['name'])
 
                 # check that required image tags contains name and version
diff --git a/tempest/api/database/base.py b/tempest/api/database/base.py
index cf70d11..b68c84a 100644
--- a/tempest/api/database/base.py
+++ b/tempest/api/database/base.py
@@ -41,4 +41,5 @@
         os = cls.get_client_manager()
         cls.os = os
         cls.database_flavors_client = cls.os.database_flavors_client
+        cls.os_flavors_client = cls.os.flavors_client
         cls.database_versions_client = cls.os.database_versions_client
diff --git a/tempest/api/database/flavors/test_flavors.py b/tempest/api/database/flavors/test_flavors.py
index a591e8e..64d71b9 100644
--- a/tempest/api/database/flavors/test_flavors.py
+++ b/tempest/api/database/flavors/test_flavors.py
@@ -28,6 +28,7 @@
     def test_get_db_flavor(self):
         # The expected flavor details should be returned
         resp, flavor = self.client.get_db_flavor_details(self.db_flavor_ref)
+        self.assertEqual(200, resp.status)
         self.assertEqual(self.db_flavor_ref, str(flavor['id']))
         self.assertIn('ram', flavor)
         self.assertIn('links', flavor)
@@ -36,6 +37,36 @@
     @test.attr(type='smoke')
     def test_list_db_flavors(self):
         resp, flavor = self.client.get_db_flavor_details(self.db_flavor_ref)
+        self.assertEqual(200, resp.status)
         # List of all flavors should contain the expected flavor
         resp, flavors = self.client.list_db_flavors()
+        self.assertEqual(200, resp.status)
         self.assertIn(flavor, flavors)
+
+    def _check_values(self, names, db_flavor, os_flavor, in_db=True):
+        for name in names:
+            self.assertIn(name, os_flavor)
+            if in_db:
+                self.assertIn(name, db_flavor)
+                self.assertEqual(str(db_flavor[name]), str(os_flavor[name]),
+                                 "DB flavor differs from OS on '%s' value"
+                                 % name)
+            else:
+                self.assertNotIn(name, db_flavor)
+
+    @test.attr(type='smoke')
+    def test_compare_db_flavors_with_os(self):
+        resp, db_flavors = self.client.list_db_flavors()
+        self.assertEqual(200, resp.status)
+        resp, os_flavors = self.os_flavors_client.list_flavors_with_detail()
+        self.assertEqual(200, resp.status)
+        self.assertEqual(len(os_flavors), len(db_flavors),
+                         "OS flavors %s do not match DB flavors %s" %
+                         (os_flavors, db_flavors))
+        for os_flavor in os_flavors:
+            resp, db_flavor =\
+                self.client.get_db_flavor_details(os_flavor['id'])
+            self.assertEqual(200, resp.status)
+            self._check_values(['id', 'name', 'ram'], db_flavor, os_flavor)
+            self._check_values(['disk', 'vcpus', 'swap'], db_flavor, os_flavor,
+                               in_db=False)
diff --git a/tempest/api/identity/admin/test_roles.py b/tempest/api/identity/admin/test_roles.py
index a29f27e..7a6d07f 100644
--- a/tempest/api/identity/admin/test_roles.py
+++ b/tempest/api/identity/admin/test_roles.py
@@ -29,7 +29,7 @@
         super(RolesTestJSON, cls).setUpClass()
         for _ in moves.xrange(5):
             role_name = data_utils.rand_name(name='role-')
-            resp, role = cls.client.create_role(role_name)
+            _, role = cls.client.create_role(role_name)
             cls.data.roles.append(role)
 
     def _get_role_params(self):
@@ -50,7 +50,7 @@
     @test.attr(type='gate')
     def test_list_roles(self):
         # Return a list of all roles
-        resp, body = self.client.list_roles()
+        _, body = self.client.list_roles()
         found = [role for role in body if role in self.data.roles]
         self.assertTrue(any(found))
         self.assertEqual(len(found), len(self.data.roles))
@@ -59,18 +59,16 @@
     def test_role_create_delete(self):
         # Role should be created, verified, and deleted
         role_name = data_utils.rand_name(name='role-test-')
-        resp, body = self.client.create_role(role_name)
-        self.assertEqual(200, resp.status)
+        _, body = self.client.create_role(role_name)
         self.assertEqual(role_name, body['name'])
 
-        resp, body = self.client.list_roles()
+        _, body = self.client.list_roles()
         found = [role for role in body if role['name'] == role_name]
         self.assertTrue(any(found))
 
-        resp, body = self.client.delete_role(found[0]['id'])
-        self.assertEqual(204, resp.status)
+        _, body = self.client.delete_role(found[0]['id'])
 
-        resp, body = self.client.list_roles()
+        _, body = self.client.list_roles()
         found = [role for role in body if role['name'] == role_name]
         self.assertFalse(any(found))
 
@@ -80,9 +78,7 @@
         self.data.setup_test_role()
         role_id = self.data.role['id']
         role_name = self.data.role['name']
-        resp, body = self.client.get_role(role_id)
-        self.assertIn('status', resp)
-        self.assertTrue('200', resp['status'])
+        _, body = self.client.get_role(role_id)
         self.assertEqual(role_id, body['id'])
         self.assertEqual(role_name, body['name'])
 
@@ -91,25 +87,24 @@
         # Assign a role to a user on a tenant
         (user, tenant, role) = self._get_role_params()
         self.client.assign_user_role(tenant['id'], user['id'], role['id'])
-        resp, roles = self.client.list_user_roles(tenant['id'], user['id'])
+        _, roles = self.client.list_user_roles(tenant['id'], user['id'])
         self.assert_role_in_role_list(role, roles)
 
     @test.attr(type='gate')
     def test_remove_user_role(self):
         # Remove a role assigned to a user on a tenant
         (user, tenant, role) = self._get_role_params()
-        resp, user_role = self.client.assign_user_role(tenant['id'],
-                                                       user['id'], role['id'])
-        resp, body = self.client.remove_user_role(tenant['id'], user['id'],
-                                                  user_role['id'])
-        self.assertEqual(204, resp.status)
+        _, user_role = self.client.assign_user_role(tenant['id'],
+                                                    user['id'], role['id'])
+        self.client.remove_user_role(tenant['id'], user['id'],
+                                     user_role['id'])
 
     @test.attr(type='gate')
     def test_list_user_roles(self):
         # List roles assigned to a user on tenant
         (user, tenant, role) = self._get_role_params()
         self.client.assign_user_role(tenant['id'], user['id'], role['id'])
-        resp, roles = self.client.list_user_roles(tenant['id'], user['id'])
+        _, roles = self.client.list_user_roles(tenant['id'], user['id'])
         self.assert_role_in_role_list(role, roles)
 
 
diff --git a/tempest/api/identity/admin/test_roles_negative.py b/tempest/api/identity/admin/test_roles_negative.py
index 6f8f9b5..37a981e 100644
--- a/tempest/api/identity/admin/test_roles_negative.py
+++ b/tempest/api/identity/admin/test_roles_negative.py
@@ -72,9 +72,8 @@
     def test_role_create_duplicate(self):
         # Role names should be unique
         role_name = data_utils.rand_name(name='role-dup-')
-        resp, body = self.client.create_role(role_name)
+        _, body = self.client.create_role(role_name)
         role1_id = body.get('id')
-        self.assertEqual(200, resp.status)
         self.addCleanup(self.client.delete_role, role1_id)
         self.assertRaises(exceptions.Conflict, self.client.create_role,
                           role_name)
@@ -83,8 +82,7 @@
     def test_delete_role_by_unauthorized_user(self):
         # Non-administrator user should not be able to delete role
         role_name = data_utils.rand_name(name='role-')
-        resp, body = self.client.create_role(role_name)
-        self.assertEqual(200, resp.status)
+        _, body = self.client.create_role(role_name)
         self.data.roles.append(body)
         role_id = body.get('id')
         self.assertRaises(exceptions.Unauthorized,
@@ -94,8 +92,7 @@
     def test_delete_role_request_without_token(self):
         # Request to delete role without a valid token should fail
         role_name = data_utils.rand_name(name='role-')
-        resp, body = self.client.create_role(role_name)
-        self.assertEqual(200, resp.status)
+        _, body = self.client.create_role(role_name)
         self.data.roles.append(body)
         role_id = body.get('id')
         token = self.client.auth_provider.get_token()
diff --git a/tempest/api/identity/admin/test_services.py b/tempest/api/identity/admin/test_services.py
index 0472e07..a9782a9 100644
--- a/tempest/api/identity/admin/test_services.py
+++ b/tempest/api/identity/admin/test_services.py
@@ -26,8 +26,7 @@
 
     def _del_service(self, service_id):
         # Deleting the service created in this method
-        resp, _ = self.client.delete_service(service_id)
-        self.assertEqual(204, resp.status)
+        self.client.delete_service(service_id)
         # Checking whether service is deleted successfully
         self.assertRaises(exceptions.NotFound, self.client.get_service,
                           service_id)
@@ -39,11 +38,10 @@
         name = data_utils.rand_name('service-')
         type = data_utils.rand_name('type--')
         description = data_utils.rand_name('description-')
-        resp, service_data = self.client.create_service(
+        _, service_data = self.client.create_service(
             name, type, description=description)
         self.assertFalse(service_data['id'] is None)
         self.addCleanup(self._del_service, service_data['id'])
-        self.assertEqual(200, resp.status)
         # Verifying response body of create service
         self.assertIn('id', service_data)
         self.assertIn('name', service_data)
@@ -53,8 +51,7 @@
         self.assertIn('description', service_data)
         self.assertEqual(description, service_data['description'])
         # Get service
-        resp, fetched_service = self.client.get_service(service_data['id'])
-        self.assertEqual(200, resp.status)
+        _, fetched_service = self.client.get_service(service_data['id'])
         # verifying the existence of service created
         self.assertIn('id', fetched_service)
         self.assertEqual(fetched_service['id'], service_data['id'])
@@ -71,9 +68,8 @@
         # Create a service only with name and type
         name = data_utils.rand_name('service-')
         type = data_utils.rand_name('type--')
-        resp, service = self.client.create_service(name, type)
+        _, service = self.client.create_service(name, type)
         self.assertIn('id', service)
-        self.assertTrue('200', resp['status'])
         self.addCleanup(self._del_service, service['id'])
         self.assertIn('name', service)
         self.assertEqual(name, service['name'])
@@ -88,7 +84,7 @@
             name = data_utils.rand_name('service-')
             type = data_utils.rand_name('type--')
             description = data_utils.rand_name('description-')
-            resp, service = self.client.create_service(
+            _, service = self.client.create_service(
                 name, type, description=description)
             services.append(service)
         service_ids = map(lambda x: x['id'], services)
@@ -99,9 +95,8 @@
 
         self.addCleanup(delete_services)
         # List and Verify Services
-        resp, body = self.client.list_services()
-        self.assertEqual(200, resp.status)
-        found = [service for service in body if service['id'] in service_ids]
+        _, body = self.client.list_services()
+        found = [serv for serv in body if serv['id'] in service_ids]
         self.assertEqual(len(found), len(services), 'Services not found')
 
 
diff --git a/tempest/api/identity/admin/test_tenant_negative.py b/tempest/api/identity/admin/test_tenant_negative.py
index 622ad81..dcfacee 100644
--- a/tempest/api/identity/admin/test_tenant_negative.py
+++ b/tempest/api/identity/admin/test_tenant_negative.py
@@ -42,8 +42,7 @@
     def test_tenant_delete_by_unauthorized_user(self):
         # Non-administrator user should not be able to delete a tenant
         tenant_name = data_utils.rand_name(name='tenant-')
-        resp, tenant = self.client.create_tenant(tenant_name)
-        self.assertEqual(200, resp.status)
+        _, tenant = self.client.create_tenant(tenant_name)
         self.data.tenants.append(tenant)
         self.assertRaises(exceptions.Unauthorized,
                           self.non_admin_client.delete_tenant, tenant['id'])
@@ -52,8 +51,7 @@
     def test_tenant_delete_request_without_token(self):
         # Request to delete a tenant without a valid token should fail
         tenant_name = data_utils.rand_name(name='tenant-')
-        resp, tenant = self.client.create_tenant(tenant_name)
-        self.assertEqual(200, resp.status)
+        _, tenant = self.client.create_tenant(tenant_name)
         self.data.tenants.append(tenant)
         token = self.client.auth_provider.get_token()
         self.client.delete_token(token)
@@ -71,8 +69,7 @@
     def test_tenant_create_duplicate(self):
         # Tenant names should be unique
         tenant_name = data_utils.rand_name(name='tenant-')
-        resp, body = self.client.create_tenant(tenant_name)
-        self.assertEqual(200, resp.status)
+        _, body = self.client.create_tenant(tenant_name)
         tenant = body
         self.data.tenants.append(tenant)
         tenant1_id = body.get('id')
@@ -122,8 +119,7 @@
     def test_tenant_update_by_unauthorized_user(self):
         # Non-administrator user should not be able to update a tenant
         tenant_name = data_utils.rand_name(name='tenant-')
-        resp, tenant = self.client.create_tenant(tenant_name)
-        self.assertEqual(200, resp.status)
+        _, tenant = self.client.create_tenant(tenant_name)
         self.data.tenants.append(tenant)
         self.assertRaises(exceptions.Unauthorized,
                           self.non_admin_client.update_tenant, tenant['id'])
@@ -132,8 +128,7 @@
     def test_tenant_update_request_without_token(self):
         # Request to update a tenant without a valid token should fail
         tenant_name = data_utils.rand_name(name='tenant-')
-        resp, tenant = self.client.create_tenant(tenant_name)
-        self.assertEqual(200, resp.status)
+        _, tenant = self.client.create_tenant(tenant_name)
         self.data.tenants.append(tenant)
         token = self.client.auth_provider.get_token()
         self.client.delete_token(token)
diff --git a/tempest/api/identity/admin/test_tenants.py b/tempest/api/identity/admin/test_tenants.py
index b989664..8d3b402 100644
--- a/tempest/api/identity/admin/test_tenants.py
+++ b/tempest/api/identity/admin/test_tenants.py
@@ -29,22 +29,19 @@
         tenants = []
         for _ in moves.xrange(3):
             tenant_name = data_utils.rand_name(name='tenant-new')
-            resp, tenant = self.client.create_tenant(tenant_name)
-            self.assertEqual(200, resp.status)
+            _, tenant = self.client.create_tenant(tenant_name)
             self.data.tenants.append(tenant)
             tenants.append(tenant)
         tenant_ids = map(lambda x: x['id'], tenants)
-        resp, body = self.client.list_tenants()
-        self.assertEqual(200, resp.status)
-        found = [tenant for tenant in body if tenant['id'] in tenant_ids]
+        _, body = self.client.list_tenants()
+        found = [t for t in body if t['id'] in tenant_ids]
         self.assertEqual(len(found), len(tenants), 'Tenants not created')
 
         for tenant in tenants:
-            resp, body = self.client.delete_tenant(tenant['id'])
-            self.assertEqual(204, resp.status)
+            self.client.delete_tenant(tenant['id'])
             self.data.tenants.remove(tenant)
 
-        resp, body = self.client.list_tenants()
+        _, body = self.client.list_tenants()
         found = [tenant for tenant in body if tenant['id'] in tenant_ids]
         self.assertFalse(any(found), 'Tenants failed to delete')
 
@@ -53,16 +50,15 @@
         # Create tenant with a description
         tenant_name = data_utils.rand_name(name='tenant-')
         tenant_desc = data_utils.rand_name(name='desc-')
-        resp, body = self.client.create_tenant(tenant_name,
-                                               description=tenant_desc)
+        _, body = self.client.create_tenant(tenant_name,
+                                            description=tenant_desc)
         tenant = body
         self.data.tenants.append(tenant)
         tenant_id = body['id']
         desc1 = body['description']
-        self.assertEqual(200, resp.status)
         self.assertEqual(desc1, tenant_desc, 'Description should have '
                          'been sent in response for create')
-        resp, body = self.client.get_tenant(tenant_id)
+        _, body = self.client.get_tenant(tenant_id)
         desc2 = body['description']
         self.assertEqual(desc2, tenant_desc, 'Description does not appear'
                          'to be set')
@@ -73,14 +69,13 @@
     def test_tenant_create_enabled(self):
         # Create a tenant that is enabled
         tenant_name = data_utils.rand_name(name='tenant-')
-        resp, body = self.client.create_tenant(tenant_name, enabled=True)
+        _, body = self.client.create_tenant(tenant_name, enabled=True)
         tenant = body
         self.data.tenants.append(tenant)
         tenant_id = body['id']
         en1 = body['enabled']
-        self.assertEqual(200, resp.status)
         self.assertTrue(en1, 'Enable should be True in response')
-        resp, body = self.client.get_tenant(tenant_id)
+        _, body = self.client.get_tenant(tenant_id)
         en2 = body['enabled']
         self.assertTrue(en2, 'Enable should be True in lookup')
         self.client.delete_tenant(tenant_id)
@@ -90,15 +85,14 @@
     def test_tenant_create_not_enabled(self):
         # Create a tenant that is not enabled
         tenant_name = data_utils.rand_name(name='tenant-')
-        resp, body = self.client.create_tenant(tenant_name, enabled=False)
+        _, body = self.client.create_tenant(tenant_name, enabled=False)
         tenant = body
         self.data.tenants.append(tenant)
         tenant_id = body['id']
         en1 = body['enabled']
-        self.assertEqual(200, resp.status)
         self.assertEqual('false', str(en1).lower(),
                          'Enable should be False in response')
-        resp, body = self.client.get_tenant(tenant_id)
+        _, body = self.client.get_tenant(tenant_id)
         en2 = body['enabled']
         self.assertEqual('false', str(en2).lower(),
                          'Enable should be False in lookup')
@@ -109,8 +103,7 @@
     def test_tenant_update_name(self):
         # Update name attribute of a tenant
         t_name1 = data_utils.rand_name(name='tenant-')
-        resp, body = self.client.create_tenant(t_name1)
-        self.assertEqual(200, resp.status)
+        _, body = self.client.create_tenant(t_name1)
         tenant = body
         self.data.tenants.append(tenant)
 
@@ -118,12 +111,11 @@
         resp1_name = body['name']
 
         t_name2 = data_utils.rand_name(name='tenant2-')
-        resp, body = self.client.update_tenant(t_id, name=t_name2)
+        _, body = self.client.update_tenant(t_id, name=t_name2)
         resp2_name = body['name']
-        self.assertEqual(200, resp.status)
         self.assertNotEqual(resp1_name, resp2_name)
 
-        resp, body = self.client.get_tenant(t_id)
+        _, body = self.client.get_tenant(t_id)
         resp3_name = body['name']
 
         self.assertNotEqual(resp1_name, resp3_name)
@@ -138,8 +130,7 @@
         # Update description attribute of a tenant
         t_name = data_utils.rand_name(name='tenant-')
         t_desc = data_utils.rand_name(name='desc-')
-        resp, body = self.client.create_tenant(t_name, description=t_desc)
-        self.assertEqual(200, resp.status)
+        _, body = self.client.create_tenant(t_name, description=t_desc)
         tenant = body
         self.data.tenants.append(tenant)
 
@@ -147,12 +138,11 @@
         resp1_desc = body['description']
 
         t_desc2 = data_utils.rand_name(name='desc2-')
-        resp, body = self.client.update_tenant(t_id, description=t_desc2)
+        _, body = self.client.update_tenant(t_id, description=t_desc2)
         resp2_desc = body['description']
-        self.assertEqual(200, resp.status)
         self.assertNotEqual(resp1_desc, resp2_desc)
 
-        resp, body = self.client.get_tenant(t_id)
+        _, body = self.client.get_tenant(t_id)
         resp3_desc = body['description']
 
         self.assertNotEqual(resp1_desc, resp3_desc)
@@ -167,8 +157,7 @@
         # Update the enabled attribute of a tenant
         t_name = data_utils.rand_name(name='tenant-')
         t_en = False
-        resp, body = self.client.create_tenant(t_name, enabled=t_en)
-        self.assertEqual(200, resp.status)
+        _, body = self.client.create_tenant(t_name, enabled=t_en)
         tenant = body
         self.data.tenants.append(tenant)
 
@@ -176,12 +165,11 @@
         resp1_en = body['enabled']
 
         t_en2 = True
-        resp, body = self.client.update_tenant(t_id, enabled=t_en2)
+        _, body = self.client.update_tenant(t_id, enabled=t_en2)
         resp2_en = body['enabled']
-        self.assertEqual(200, resp.status)
         self.assertNotEqual(resp1_en, resp2_en)
 
-        resp, body = self.client.get_tenant(t_id)
+        _, body = self.client.get_tenant(t_id)
         resp3_en = body['enabled']
 
         self.assertNotEqual(resp1_en, resp3_en)
diff --git a/tempest/api/identity/admin/test_tokens.py b/tempest/api/identity/admin/test_tokens.py
index 08e12f0..e1db008 100644
--- a/tempest/api/identity/admin/test_tokens.py
+++ b/tempest/api/identity/admin/test_tokens.py
@@ -28,13 +28,11 @@
         user_password = data_utils.rand_name(name='pass-')
         # first:create a tenant
         tenant_name = data_utils.rand_name(name='tenant-')
-        resp, tenant = self.client.create_tenant(tenant_name)
-        self.assertEqual(200, resp.status)
+        _, tenant = self.client.create_tenant(tenant_name)
         self.data.tenants.append(tenant)
         # second:create a user
-        resp, user = self.client.create_user(user_name, user_password,
-                                             tenant['id'], '')
-        self.assertEqual(200, resp.status)
+        _, user = self.client.create_user(user_name, user_password,
+                                          tenant['id'], '')
         self.data.users.append(user)
         # then get a token for the user
         rsp, body = self.token_client.auth(user_name,
@@ -45,16 +43,14 @@
                          tenant['name'])
         # Perform GET Token
         token_id = body['token']['id']
-        resp, token_details = self.client.get_token(token_id)
-        self.assertEqual(resp['status'], '200')
+        _, token_details = self.client.get_token(token_id)
         self.assertEqual(token_id, token_details['token']['id'])
         self.assertEqual(user['id'], token_details['user']['id'])
         self.assertEqual(user_name, token_details['user']['name'])
         self.assertEqual(tenant['name'],
                          token_details['token']['tenant']['name'])
         # then delete the token
-        resp, body = self.client.delete_token(token_id)
-        self.assertEqual(resp['status'], '204')
+        self.client.delete_token(token_id)
 
     @test.attr(type='gate')
     def test_rescope_token(self):
@@ -67,56 +63,51 @@
         user_password = data_utils.rand_name(name='pass-')
         tenant_id = None  # No default tenant so will get unscoped token.
         email = ''
-        resp, user = self.client.create_user(user_name, user_password,
-                                             tenant_id, email)
-        self.assertEqual(200, resp.status)
+        _, user = self.client.create_user(user_name, user_password,
+                                          tenant_id, email)
         self.data.users.append(user)
 
         # Create a couple tenants.
         tenant1_name = data_utils.rand_name(name='tenant-')
-        resp, tenant1 = self.client.create_tenant(tenant1_name)
-        self.assertEqual(200, resp.status)
+        _, tenant1 = self.client.create_tenant(tenant1_name)
         self.data.tenants.append(tenant1)
 
         tenant2_name = data_utils.rand_name(name='tenant-')
-        resp, tenant2 = self.client.create_tenant(tenant2_name)
-        self.assertEqual(200, resp.status)
+        _, tenant2 = self.client.create_tenant(tenant2_name)
         self.data.tenants.append(tenant2)
 
         # Create a role
         role_name = data_utils.rand_name(name='role-')
-        resp, role = self.client.create_role(role_name)
-        self.assertEqual(200, resp.status)
+        _, role = self.client.create_role(role_name)
         self.data.roles.append(role)
 
         # Grant the user the role on the tenants.
-        resp, _ = self.client.assign_user_role(tenant1['id'], user['id'],
-                                               role['id'])
-        self.assertEqual(200, resp.status)
+        self.client.assign_user_role(tenant1['id'], user['id'],
+                                     role['id'])
 
-        resp, _ = self.client.assign_user_role(tenant2['id'], user['id'],
-                                               role['id'])
-        self.assertEqual(200, resp.status)
+        self.client.assign_user_role(tenant2['id'], user['id'],
+                                     role['id'])
 
         # Get an unscoped token.
-        rsp, body = self.token_client.auth(user_name, user_password)
+        resp, body = self.token_client.auth(user_name, user_password)
         self.assertEqual(200, resp.status)
 
         token_id = body['token']['id']
 
         # Use the unscoped token to get a token scoped to tenant1
-        rsp, body = self.token_client.auth_token(token_id, tenant=tenant1_name)
+        resp, body = self.token_client.auth_token(token_id,
+                                                  tenant=tenant1_name)
         self.assertEqual(200, resp.status)
 
         scoped_token_id = body['token']['id']
 
         # Revoke the scoped token
-        resp, body = self.client.delete_token(scoped_token_id)
-        self.assertEqual(204, resp.status)
+        self.client.delete_token(scoped_token_id)
 
         # Use the unscoped token to get a token scoped to tenant2
-        rsp, body = self.token_client.auth_token(token_id, tenant=tenant2_name)
-        self.assertEqual(204, resp.status)
+        resp, body = self.token_client.auth_token(token_id,
+                                                  tenant=tenant2_name)
+        self.assertEqual(200, resp.status)
 
 
 class TokensTestXML(TokensTestJSON):
diff --git a/tempest/api/identity/admin/test_users.py b/tempest/api/identity/admin/test_users.py
index e2c1066..5838da3 100644
--- a/tempest/api/identity/admin/test_users.py
+++ b/tempest/api/identity/admin/test_users.py
@@ -34,11 +34,10 @@
     def test_create_user(self):
         # Create a user
         self.data.setup_test_tenant()
-        resp, user = self.client.create_user(self.alt_user, self.alt_password,
-                                             self.data.tenant['id'],
-                                             self.alt_email)
+        _, user = self.client.create_user(self.alt_user, self.alt_password,
+                                          self.data.tenant['id'],
+                                          self.alt_email)
         self.data.users.append(user)
-        self.assertEqual('200', resp['status'])
         self.assertEqual(self.alt_user, user['name'])
 
     @test.attr(type='smoke')
@@ -46,11 +45,10 @@
         # Create a user with enabled : False
         self.data.setup_test_tenant()
         name = data_utils.rand_name('test_user_')
-        resp, user = self.client.create_user(name, self.alt_password,
-                                             self.data.tenant['id'],
-                                             self.alt_email, enabled=False)
+        _, user = self.client.create_user(name, self.alt_password,
+                                          self.data.tenant['id'],
+                                          self.alt_email, enabled=False)
         self.data.users.append(user)
-        self.assertEqual('200', resp['status'])
         self.assertEqual(name, user['name'])
         self.assertEqual('false', str(user['enabled']).lower())
         self.assertEqual(self.alt_email, user['email'])
@@ -60,24 +58,22 @@
         # Test case to check if updating of user attributes is successful.
         test_user = data_utils.rand_name('test_user_')
         self.data.setup_test_tenant()
-        resp, user = self.client.create_user(test_user, self.alt_password,
-                                             self.data.tenant['id'],
-                                             self.alt_email)
+        _, user = self.client.create_user(test_user, self.alt_password,
+                                          self.data.tenant['id'],
+                                          self.alt_email)
         # Delete the User at the end of this method
         self.addCleanup(self.client.delete_user, user['id'])
         # Updating user details with new values
         u_name2 = data_utils.rand_name('user2-')
         u_email2 = u_name2 + '@testmail.tm'
-        resp, update_user = self.client.update_user(user['id'], name=u_name2,
-                                                    email=u_email2,
-                                                    enabled=False)
-        # Assert response body of update user.
-        self.assertEqual(200, resp.status)
+        _, update_user = self.client.update_user(user['id'], name=u_name2,
+                                                 email=u_email2,
+                                                 enabled=False)
         self.assertEqual(u_name2, update_user['name'])
         self.assertEqual(u_email2, update_user['email'])
         self.assertEqual('false', str(update_user['enabled']).lower())
         # GET by id after updating
-        resp, updated_user = self.client.get_user(user['id'])
+        _, updated_user = self.client.get_user(user['id'])
         # Assert response body of GET after updating
         self.assertEqual(u_name2, updated_user['name'])
         self.assertEqual(u_email2, updated_user['email'])
@@ -88,12 +84,10 @@
         # Delete a user
         test_user = data_utils.rand_name('test_user_')
         self.data.setup_test_tenant()
-        resp, user = self.client.create_user(test_user, self.alt_password,
-                                             self.data.tenant['id'],
-                                             self.alt_email)
-        self.assertEqual('200', resp['status'])
-        resp, body = self.client.delete_user(user['id'])
-        self.assertEqual('204', resp['status'])
+        _, user = self.client.create_user(test_user, self.alt_password,
+                                          self.data.tenant['id'],
+                                          self.alt_email)
+        self.client.delete_user(user['id'])
 
     @test.attr(type='smoke')
     def test_user_authentication(self):
@@ -129,7 +123,7 @@
     def test_get_users(self):
         # Get a list of users and find the test user
         self.data.setup_test_user()
-        resp, users = self.client.get_users()
+        _, users = self.client.get_users()
         self.assertThat([u['name'] for u in users],
                         matchers.Contains(self.data.test_user),
                         "Could not find %s" % self.data.test_user)
@@ -141,23 +135,20 @@
         user_ids = list()
         fetched_user_ids = list()
         alt_tenant_user1 = data_utils.rand_name('tenant_user1_')
-        resp, user1 = self.client.create_user(alt_tenant_user1, 'password1',
-                                              self.data.tenant['id'],
-                                              'user1@123')
-        self.assertEqual('200', resp['status'])
+        _, user1 = self.client.create_user(alt_tenant_user1, 'password1',
+                                           self.data.tenant['id'],
+                                           'user1@123')
         user_ids.append(user1['id'])
         self.data.users.append(user1)
 
         alt_tenant_user2 = data_utils.rand_name('tenant_user2_')
-        resp, user2 = self.client.create_user(alt_tenant_user2, 'password2',
-                                              self.data.tenant['id'],
-                                              'user2@123')
-        self.assertEqual('200', resp['status'])
+        _, user2 = self.client.create_user(alt_tenant_user2, 'password2',
+                                           self.data.tenant['id'],
+                                           'user2@123')
         user_ids.append(user2['id'])
         self.data.users.append(user2)
         # List of users for the respective tenant ID
-        resp, body = self.client.list_users_for_tenant(self.data.tenant['id'])
-        self.assertIn(resp['status'], ('200', '203'))
+        _, body = self.client.list_users_for_tenant(self.data.tenant['id'])
         for i in body:
             fetched_user_ids.append(i['id'])
         # verifying the user Id in the list
@@ -179,24 +170,20 @@
         user_ids = list()
         fetched_user_ids = list()
         user_ids.append(user['id'])
-        resp, role = self.client.assign_user_role(tenant['id'], user['id'],
-                                                  role['id'])
-        self.assertEqual('200', resp['status'])
+        _, role = self.client.assign_user_role(tenant['id'], user['id'],
+                                               role['id'])
 
         alt_user2 = data_utils.rand_name('second_user_')
-        resp, second_user = self.client.create_user(alt_user2, 'password1',
-                                                    self.data.tenant['id'],
-                                                    'user2@123')
-        self.assertEqual('200', resp['status'])
+        _, second_user = self.client.create_user(alt_user2, 'password1',
+                                                 self.data.tenant['id'],
+                                                 'user2@123')
         user_ids.append(second_user['id'])
         self.data.users.append(second_user)
-        resp, role = self.client.assign_user_role(tenant['id'],
-                                                  second_user['id'],
-                                                  role['id'])
-        self.assertEqual('200', resp['status'])
+        _, role = self.client.assign_user_role(tenant['id'],
+                                               second_user['id'],
+                                               role['id'])
         # List of users with roles for the respective tenant ID
-        resp, body = self.client.list_users_for_tenant(self.data.tenant['id'])
-        self.assertEqual('200', resp['status'])
+        _, body = self.client.list_users_for_tenant(self.data.tenant['id'])
         for i in body:
             fetched_user_ids.append(i['id'])
         # verifying the user Id in the list
@@ -212,10 +199,8 @@
         self.data.setup_test_user()
         # Updating the user with new password
         new_pass = data_utils.rand_name('pass-')
-        resp, update_user = self.client.update_user_password(
+        _, update_user = self.client.update_user_password(
             self.data.user['id'], new_pass)
-        # Assert response body of update user.
-        self.assertEqual(200, resp.status)
         self.assertEqual(update_user['id'], self.data.user['id'])
 
         # Validate the updated password
diff --git a/tempest/api/identity/admin/v3/test_credentials.py b/tempest/api/identity/admin/v3/test_credentials.py
index 6bb0ebe..d40e0f3 100644
--- a/tempest/api/identity/admin/v3/test_credentials.py
+++ b/tempest/api/identity/admin/v3/test_credentials.py
@@ -33,28 +33,20 @@
         u_email = '%s@testmail.tm' % u_name
         u_password = data_utils.rand_name('pass-')
         for i in range(2):
-            resp, cls.project = cls.client.create_project(
+            _, cls.project = cls.client.create_project(
                 data_utils.rand_name('project-'),
                 description=data_utils.rand_name('project-desc-'))
-            assert resp['status'] == '201', (
-                "Expected 201, but got: %s" % resp['status'])
             cls.projects.append(cls.project['id'])
 
-        resp, cls.user_body = cls.client.create_user(
+        _, cls.user_body = cls.client.create_user(
             u_name, description=u_desc, password=u_password,
             email=u_email, project_id=cls.projects[0])
-        assert resp['status'] == '201', (
-            "Expected 201, but got: %s" % resp['status'])
 
     @classmethod
     def tearDownClass(cls):
-        resp, _ = cls.client.delete_user(cls.user_body['id'])
-        assert resp['status'] == '204', (
-            "Expected 204, but got: %s" % resp['status'])
+        cls.client.delete_user(cls.user_body['id'])
         for p in cls.projects:
-            resp, _ = cls.client.delete_project(p)
-            assert resp['status'] == '204', (
-                "Expected 204, but got: %s" % resp['status'])
+            cls.client.delete_project(p)
         super(CredentialsTestJSON, cls).tearDownClass()
 
     def _delete_credential(self, cred_id):
diff --git a/tempest/api/identity/admin/v3/test_domains.py b/tempest/api/identity/admin/v3/test_domains.py
index a1e6cde..5b73df1 100644
--- a/tempest/api/identity/admin/v3/test_domains.py
+++ b/tempest/api/identity/admin/v3/test_domains.py
@@ -25,9 +25,8 @@
     def _delete_domain(self, domain_id):
         # It is necessary to disable the domain before deleting,
         # or else it would result in unauthorized error
-        _, body = self.client.update_domain(domain_id, enabled=False)
-        resp, _ = self.client.delete_domain(domain_id)
-        self.assertEqual(204, resp.status)
+        self.client.update_domain(domain_id, enabled=False)
+        self.client.delete_domain(domain_id)
 
     @test.attr(type='smoke')
     def test_list_domains(self):
@@ -42,8 +41,7 @@
             self.addCleanup(self._delete_domain, domain['id'])
             domain_ids.append(domain['id'])
         # List and Verify Domains
-        resp, body = self.client.list_domains()
-        self.assertEqual(resp['status'], '200')
+        _, body = self.client.list_domains()
         for d in body:
             fetched_ids.append(d['id'])
         missing_doms = [d for d in domain_ids if d not in fetched_ids]
@@ -53,9 +51,8 @@
     def test_create_update_delete_domain(self):
         d_name = data_utils.rand_name('domain-')
         d_desc = data_utils.rand_name('domain-desc-')
-        resp_1, domain = self.client.create_domain(
+        _, domain = self.client.create_domain(
             d_name, description=d_desc)
-        self.assertEqual(resp_1['status'], '201')
         self.addCleanup(self._delete_domain, domain['id'])
         self.assertIn('id', domain)
         self.assertIn('description', domain)
@@ -72,9 +69,8 @@
         new_desc = data_utils.rand_name('new-desc-')
         new_name = data_utils.rand_name('new-name-')
 
-        resp_2, updated_domain = self.client.update_domain(
+        _, updated_domain = self.client.update_domain(
             domain['id'], name=new_name, description=new_desc)
-        self.assertEqual(resp_2['status'], '200')
         self.assertIn('id', updated_domain)
         self.assertIn('description', updated_domain)
         self.assertIn('name', updated_domain)
@@ -85,8 +81,7 @@
         self.assertEqual(new_desc, updated_domain['description'])
         self.assertEqual('true', str(updated_domain['enabled']).lower())
 
-        resp_3, fetched_domain = self.client.get_domain(domain['id'])
-        self.assertEqual(resp_3['status'], '200')
+        _, fetched_domain = self.client.get_domain(domain['id'])
         self.assertEqual(new_name, fetched_domain['name'])
         self.assertEqual(new_desc, fetched_domain['description'])
         self.assertEqual('true', str(fetched_domain['enabled']).lower())
diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py
index dd3b576..6beb8f2 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -31,7 +31,7 @@
         s_name = data_utils.rand_name('service-')
         s_type = data_utils.rand_name('type--')
         s_description = data_utils.rand_name('description-')
-        resp, cls.service_data =\
+        _, cls.service_data =\
             cls.service_client.create_service(s_name, s_type,
                                               description=s_description)
         cls.service_id = cls.service_data['id']
@@ -40,7 +40,7 @@
         cls.setup_endpoints = list()
         for i in range(2):
             region = data_utils.rand_name('region')
-            url = data_utils.rand_name('url')
+            url = data_utils.rand_url()
             interface = 'public'
             resp, endpoint = cls.client.create_endpoint(
                 cls.service_id, interface, url, region=region, enabled=True)
@@ -69,7 +69,7 @@
     @test.attr(type='gate')
     def test_create_list_delete_endpoint(self):
         region = data_utils.rand_name('region')
-        url = data_utils.rand_name('url')
+        url = data_utils.rand_url()
         interface = 'public'
         resp, endpoint =\
             self.client.create_endpoint(self.service_id, interface, url,
@@ -97,7 +97,7 @@
         # Creating an endpoint so as to check update endpoint
         # with new values
         region1 = data_utils.rand_name('region')
-        url1 = data_utils.rand_name('url')
+        url1 = data_utils.rand_url()
         interface1 = 'public'
         resp, endpoint_for_update =\
             self.client.create_endpoint(self.service_id, interface1,
@@ -108,22 +108,22 @@
         s_name = data_utils.rand_name('service-')
         s_type = data_utils.rand_name('type--')
         s_description = data_utils.rand_name('description-')
-        resp, self.service2 =\
+        _, service2 =\
             self.service_client.create_service(s_name, s_type,
                                                description=s_description)
-        self.service_ids.append(self.service2['id'])
+        self.service_ids.append(service2['id'])
         # Updating endpoint with new values
         region2 = data_utils.rand_name('region')
-        url2 = data_utils.rand_name('url')
+        url2 = data_utils.rand_url()
         interface2 = 'internal'
         resp, endpoint = \
             self.client.update_endpoint(endpoint_for_update['id'],
-                                        service_id=self.service2['id'],
+                                        service_id=service2['id'],
                                         interface=interface2, url=url2,
                                         region=region2, enabled=False)
         self.assertEqual(resp['status'], '200')
         # Asserting if the attributes of endpoint are updated
-        self.assertEqual(self.service2['id'], endpoint['service_id'])
+        self.assertEqual(service2['id'], endpoint['service_id'])
         self.assertEqual(interface2, endpoint['interface'])
         self.assertEqual(url2, endpoint['url'])
         self.assertEqual(region2, endpoint['region'])
diff --git a/tempest/api/identity/admin/v3/test_endpoints_negative.py b/tempest/api/identity/admin/v3/test_endpoints_negative.py
index 5b46f89..d728b1d 100644
--- a/tempest/api/identity/admin/v3/test_endpoints_negative.py
+++ b/tempest/api/identity/admin/v3/test_endpoints_negative.py
@@ -33,7 +33,7 @@
         s_name = data_utils.rand_name('service-')
         s_type = data_utils.rand_name('type--')
         s_description = data_utils.rand_name('description-')
-        resp, cls.service_data = (
+        _, cls.service_data = (
             cls.service_client.create_service(s_name, s_type,
                                               description=s_description))
         cls.service_id = cls.service_data['id']
@@ -49,7 +49,7 @@
     def test_create_with_enabled_False(self):
         # Enabled should be a boolean, not a string like 'False'
         interface = 'public'
-        url = data_utils.rand_name('url')
+        url = data_utils.rand_url()
         region = data_utils.rand_name('region')
         self.assertRaises(exceptions.BadRequest, self.client.create_endpoint,
                           self.service_id, interface, url, region=region,
@@ -59,7 +59,7 @@
     def test_create_with_enabled_True(self):
         # Enabled should be a boolean, not a string like 'True'
         interface = 'public'
-        url = data_utils.rand_name('url')
+        url = data_utils.rand_url()
         region = data_utils.rand_name('region')
         self.assertRaises(exceptions.BadRequest, self.client.create_endpoint,
                           self.service_id, interface, url, region=region,
@@ -69,7 +69,7 @@
 
         # Create an endpoint
         region1 = data_utils.rand_name('region')
-        url1 = data_utils.rand_name('url')
+        url1 = data_utils.rand_url()
         interface1 = 'public'
         resp, endpoint_for_update = (
             self.client.create_endpoint(self.service_id, interface1,
diff --git a/tempest/api/identity/admin/v3/test_groups.py b/tempest/api/identity/admin/v3/test_groups.py
index 056f713..4d2cc46 100644
--- a/tempest/api/identity/admin/v3/test_groups.py
+++ b/tempest/api/identity/admin/v3/test_groups.py
@@ -29,24 +29,21 @@
     def test_group_create_update_get(self):
         name = data_utils.rand_name('Group')
         description = data_utils.rand_name('Description')
-        resp, group = self.client.create_group(name,
-                                               description=description)
+        _, group = self.client.create_group(name,
+                                            description=description)
         self.addCleanup(self.client.delete_group, group['id'])
-        self.assertEqual(resp['status'], '201')
         self.assertEqual(group['name'], name)
         self.assertEqual(group['description'], description)
 
         new_name = data_utils.rand_name('UpdateGroup')
         new_desc = data_utils.rand_name('UpdateDescription')
-        resp, updated_group = self.client.update_group(group['id'],
-                                                       name=new_name,
-                                                       description=new_desc)
-        self.assertEqual(resp['status'], '200')
+        _, updated_group = self.client.update_group(group['id'],
+                                                    name=new_name,
+                                                    description=new_desc)
         self.assertEqual(updated_group['name'], new_name)
         self.assertEqual(updated_group['description'], new_desc)
 
-        resp, new_group = self.client.get_group(group['id'])
-        self.assertEqual(resp['status'], '200')
+        _, new_group = self.client.get_group(group['id'])
         self.assertEqual(group['id'], new_group['id'])
         self.assertEqual(new_name, new_group['name'])
         self.assertEqual(new_desc, new_group['description'])
@@ -54,33 +51,31 @@
     @test.attr(type='smoke')
     def test_group_users_add_list_delete(self):
         name = data_utils.rand_name('Group')
-        resp, group = self.client.create_group(name)
+        _, group = self.client.create_group(name)
         self.addCleanup(self.client.delete_group, group['id'])
         # add user into group
         users = []
         for i in range(3):
             name = data_utils.rand_name('User')
-            resp, user = self.client.create_user(name)
+            _, user = self.client.create_user(name)
             users.append(user)
             self.addCleanup(self.client.delete_user, user['id'])
             self.client.add_group_user(group['id'], user['id'])
 
         # list users in group
-        resp, group_users = self.client.list_group_users(group['id'])
-        self.assertEqual(resp['status'], '200')
+        _, group_users = self.client.list_group_users(group['id'])
         self.assertEqual(sorted(users), sorted(group_users))
         # delete user in group
         for user in users:
-            resp, body = self.client.delete_group_user(group['id'],
-                                                       user['id'])
-            self.assertEqual(resp['status'], '204')
-        resp, group_users = self.client.list_group_users(group['id'])
+            self.client.delete_group_user(group['id'],
+                                          user['id'])
+        _, group_users = self.client.list_group_users(group['id'])
         self.assertEqual(len(group_users), 0)
 
     @test.attr(type='smoke')
     def test_list_user_groups(self):
         # create a user
-        resp, user = self.client.create_user(
+        _, user = self.client.create_user(
             data_utils.rand_name('User-'),
             password=data_utils.rand_name('Pass-'))
         self.addCleanup(self.client.delete_user, user['id'])
@@ -88,13 +83,12 @@
         groups = []
         for i in range(2):
             name = data_utils.rand_name('Group-')
-            resp, group = self.client.create_group(name)
+            _, group = self.client.create_group(name)
             groups.append(group)
             self.addCleanup(self.client.delete_group, group['id'])
             self.client.add_group_user(group['id'], user['id'])
         # list groups which user belongs to
-        resp, user_groups = self.client.list_user_groups(user['id'])
-        self.assertEqual('200', resp['status'])
+        _, user_groups = self.client.list_user_groups(user['id'])
         self.assertEqual(sorted(groups), sorted(user_groups))
         self.assertEqual(2, len(user_groups))
 
diff --git a/tempest/api/identity/admin/v3/test_list_users.py b/tempest/api/identity/admin/v3/test_list_users.py
new file mode 100644
index 0000000..497c5ea
--- /dev/null
+++ b/tempest/api/identity/admin/v3/test_list_users.py
@@ -0,0 +1,100 @@
+# Copyright 2014 Hewlett-Packard Development Company, L.P
+# 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.api.identity import base
+from tempest.common.utils import data_utils
+from tempest import test
+
+
+class UsersV3TestJSON(base.BaseIdentityV3AdminTest):
+    _interface = 'json'
+
+    def _list_users_with_params(self, params, key, expected, not_expected):
+        # Helper method to list users filtered with params and
+        # assert the response based on expected and not_expected
+        # expected: user expected in the list response
+        # not_expected: user, which should not be present in list response
+        _, body = self.client.get_users(params)
+        self.assertIn(expected[key], map(lambda x: x[key], body))
+        self.assertNotIn(not_expected[key],
+                         map(lambda x: x[key], body))
+
+    @classmethod
+    def setUpClass(cls):
+        super(UsersV3TestJSON, cls).setUpClass()
+        alt_user = data_utils.rand_name('test_user')
+        alt_password = data_utils.rand_name('pass')
+        cls.alt_email = alt_user + '@testmail.tm'
+        cls.data.setup_test_domain()
+        # Create user with Domain
+        u1_name = data_utils.rand_name('test_user')
+        _, cls.domain_enabled_user = cls.client.create_user(
+            u1_name, password=alt_password,
+            email=cls.alt_email, domain_id=cls.data.domain['id'])
+        cls.data.v3_users.append(cls.domain_enabled_user)
+        # Create default not enabled user
+        u2_name = data_utils.rand_name('test_user')
+        _, cls.non_domain_enabled_user = cls.client.create_user(
+            u2_name, password=alt_password,
+            email=cls.alt_email, enabled=False)
+        cls.data.v3_users.append(cls.non_domain_enabled_user)
+
+    @test.attr(type='gate')
+    def test_list_user_domains(self):
+        # List users with domain
+        params = {'domain_id': self.data.domain['id']}
+        self._list_users_with_params(params, 'domain_id',
+                                     self.domain_enabled_user,
+                                     self.non_domain_enabled_user)
+
+    @test.attr(type='gate')
+    def test_list_users_with_not_enabled(self):
+        # List the users with not enabled
+        params = {'enabled': False}
+        self._list_users_with_params(params, 'enabled',
+                                     self.non_domain_enabled_user,
+                                     self.domain_enabled_user)
+
+    @test.attr(type='gate')
+    def test_list_users_with_name(self):
+        # List users with name
+        params = {'name': self.domain_enabled_user['name']}
+        self._list_users_with_params(params, 'name',
+                                     self.domain_enabled_user,
+                                     self.non_domain_enabled_user)
+
+    @test.attr(type='gate')
+    def test_list_users(self):
+        # List users
+        _, body = self.client.get_users()
+        fetched_ids = [u['id'] for u in body]
+        missing_users = [u['id'] for u in self.data.v3_users
+                         if u['id'] not in fetched_ids]
+        self.assertEqual(0, len(missing_users),
+                         "Failed to find user %s in fetched list" %
+                         ', '.join(m_user for m_user in missing_users))
+
+    @test.attr(type='gate')
+    def test_get_user(self):
+        # Get a user detail
+        _, user = self.client.get_user(self.data.v3_users[0]['id'])
+        self.assertEqual(self.data.v3_users[0]['id'], user['id'])
+        self.assertEqual(self.data.v3_users[0]['name'], user['name'])
+        self.assertEqual(self.alt_email, user['email'])
+        self.assertEqual(self.data.domain['id'], user['domain_id'])
+
+
+class UsersV3TestXML(UsersV3TestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/identity/admin/v3/test_projects.py b/tempest/api/identity/admin/v3/test_projects.py
index 31a0ddd..77acd57 100644
--- a/tempest/api/identity/admin/v3/test_projects.py
+++ b/tempest/api/identity/admin/v3/test_projects.py
@@ -25,8 +25,7 @@
     _interface = 'json'
 
     def _delete_project(self, project_id):
-        resp, _ = self.client.delete_project(project_id)
-        self.assertEqual(resp['status'], '204')
+        self.client.delete_project(project_id)
         self.assertRaises(
             exceptions.NotFound, self.client.get_project, project_id)
 
@@ -34,14 +33,13 @@
     def test_project_list_delete(self):
         # Create several projects and delete them
         for _ in moves.xrange(3):
-            resp, project = self.client.create_project(
+            _, project = self.client.create_project(
                 data_utils.rand_name('project-new'))
             self.addCleanup(self._delete_project, project['id'])
 
-        resp, list_projects = self.client.list_projects()
-        self.assertEqual(resp['status'], '200')
+        _, list_projects = self.client.list_projects()
 
-        resp, get_project = self.client.get_project(project['id'])
+        _, get_project = self.client.get_project(project['id'])
         self.assertIn(get_project, list_projects)
 
     @test.attr(type='gate')
@@ -49,16 +47,14 @@
         # Create project with a description
         project_name = data_utils.rand_name('project-')
         project_desc = data_utils.rand_name('desc-')
-        resp, project = self.client.create_project(
+        _, project = self.client.create_project(
             project_name, description=project_desc)
         self.data.projects.append(project)
-        st1 = resp['status']
         project_id = project['id']
         desc1 = project['description']
-        self.assertEqual(st1, '201')
         self.assertEqual(desc1, project_desc, 'Description should have '
                          'been sent in response for create')
-        resp, body = self.client.get_project(project_id)
+        _, body = self.client.get_project(project_id)
         desc2 = body['description']
         self.assertEqual(desc2, project_desc, 'Description does not appear'
                          'to be set')
@@ -67,15 +63,13 @@
     def test_project_create_enabled(self):
         # Create a project that is enabled
         project_name = data_utils.rand_name('project-')
-        resp, project = self.client.create_project(
+        _, project = self.client.create_project(
             project_name, enabled=True)
         self.data.projects.append(project)
         project_id = project['id']
-        st1 = resp['status']
         en1 = project['enabled']
-        self.assertEqual(st1, '201')
         self.assertTrue(en1, 'Enable should be True in response')
-        resp, body = self.client.get_project(project_id)
+        _, body = self.client.get_project(project_id)
         en2 = body['enabled']
         self.assertTrue(en2, 'Enable should be True in lookup')
 
@@ -83,15 +77,13 @@
     def test_project_create_not_enabled(self):
         # Create a project that is not enabled
         project_name = data_utils.rand_name('project-')
-        resp, project = self.client.create_project(
+        _, project = self.client.create_project(
             project_name, enabled=False)
         self.data.projects.append(project)
-        st1 = resp['status']
         en1 = project['enabled']
-        self.assertEqual(st1, '201')
         self.assertEqual('false', str(en1).lower(),
                          'Enable should be False in response')
-        resp, body = self.client.get_project(project['id'])
+        _, body = self.client.get_project(project['id'])
         en2 = body['enabled']
         self.assertEqual('false', str(en2).lower(),
                          'Enable should be False in lookup')
@@ -100,19 +92,17 @@
     def test_project_update_name(self):
         # Update name attribute of a project
         p_name1 = data_utils.rand_name('project-')
-        resp, project = self.client.create_project(p_name1)
+        _, project = self.client.create_project(p_name1)
         self.data.projects.append(project)
 
         resp1_name = project['name']
 
         p_name2 = data_utils.rand_name('project2-')
-        resp, body = self.client.update_project(project['id'], name=p_name2)
-        st2 = resp['status']
+        _, body = self.client.update_project(project['id'], name=p_name2)
         resp2_name = body['name']
-        self.assertEqual(st2, '200')
         self.assertNotEqual(resp1_name, resp2_name)
 
-        resp, body = self.client.get_project(project['id'])
+        _, body = self.client.get_project(project['id'])
         resp3_name = body['name']
 
         self.assertNotEqual(resp1_name, resp3_name)
@@ -124,20 +114,18 @@
         # Update description attribute of a project
         p_name = data_utils.rand_name('project-')
         p_desc = data_utils.rand_name('desc-')
-        resp, project = self.client.create_project(
+        _, project = self.client.create_project(
             p_name, description=p_desc)
         self.data.projects.append(project)
         resp1_desc = project['description']
 
         p_desc2 = data_utils.rand_name('desc2-')
-        resp, body = self.client.update_project(
+        _, body = self.client.update_project(
             project['id'], description=p_desc2)
-        st2 = resp['status']
         resp2_desc = body['description']
-        self.assertEqual(st2, '200')
         self.assertNotEqual(resp1_desc, resp2_desc)
 
-        resp, body = self.client.get_project(project['id'])
+        _, body = self.client.get_project(project['id'])
         resp3_desc = body['description']
 
         self.assertNotEqual(resp1_desc, resp3_desc)
@@ -149,20 +137,18 @@
         # Update the enabled attribute of a project
         p_name = data_utils.rand_name('project-')
         p_en = False
-        resp, project = self.client.create_project(p_name, enabled=p_en)
+        _, project = self.client.create_project(p_name, enabled=p_en)
         self.data.projects.append(project)
 
         resp1_en = project['enabled']
 
         p_en2 = True
-        resp, body = self.client.update_project(
+        _, body = self.client.update_project(
             project['id'], enabled=p_en2)
-        st2 = resp['status']
         resp2_en = body['enabled']
-        self.assertEqual(st2, '200')
         self.assertNotEqual(resp1_en, resp2_en)
 
-        resp, body = self.client.get_project(project['id'])
+        _, body = self.client.get_project(project['id'])
         resp3_en = body['enabled']
 
         self.assertNotEqual(resp1_en, resp3_en)
@@ -171,27 +157,26 @@
 
     @test.attr(type='gate')
     def test_associate_user_to_project(self):
-        #Associate a user to a project
-        #Create a Project
+        # Associate a user to a project
+        # Create a Project
         p_name = data_utils.rand_name('project-')
-        resp, project = self.client.create_project(p_name)
+        _, project = self.client.create_project(p_name)
         self.data.projects.append(project)
 
-        #Create a User
+        # Create a User
         u_name = data_utils.rand_name('user-')
         u_desc = u_name + 'description'
         u_email = u_name + '@testmail.tm'
         u_password = data_utils.rand_name('pass-')
-        resp, user = self.client.create_user(
+        _, user = self.client.create_user(
             u_name, description=u_desc, password=u_password,
             email=u_email, project_id=project['id'])
-        self.assertEqual(resp['status'], '201')
         # Delete the User at the end of this method
         self.addCleanup(self.client.delete_user, user['id'])
 
         # Get User To validate the user details
-        resp, new_user_get = self.client.get_user(user['id'])
-        #Assert response body of GET
+        _, new_user_get = self.client.get_user(user['id'])
+        # Assert response body of GET
         self.assertEqual(u_name, new_user_get['name'])
         self.assertEqual(u_desc, new_user_get['description'])
         self.assertEqual(project['id'],
diff --git a/tempest/api/identity/admin/v3/test_projects_negative.py b/tempest/api/identity/admin/v3/test_projects_negative.py
index 6b60d04..9e8f613 100644
--- a/tempest/api/identity/admin/v3/test_projects_negative.py
+++ b/tempest/api/identity/admin/v3/test_projects_negative.py
@@ -32,7 +32,7 @@
     def test_project_create_duplicate(self):
         # Project names should be unique
         project_name = data_utils.rand_name('project-dup-')
-        resp, project = self.client.create_project(project_name)
+        _, project = self.client.create_project(project_name)
         self.data.projects.append(project)
 
         self.assertRaises(
@@ -63,7 +63,7 @@
     def test_project_delete_by_unauthorized_user(self):
         # Non-admin user should not be able to delete a project
         project_name = data_utils.rand_name('project-')
-        resp, project = self.client.create_project(project_name)
+        _, project = self.client.create_project(project_name)
         self.data.projects.append(project)
         self.assertRaises(
             exceptions.Unauthorized, self.non_admin_client.delete_project,
diff --git a/tempest/api/identity/admin/v3/test_regions.py b/tempest/api/identity/admin/v3/test_regions.py
index 03974e4..c8b034f 100644
--- a/tempest/api/identity/admin/v3/test_regions.py
+++ b/tempest/api/identity/admin/v3/test_regions.py
@@ -1,4 +1,4 @@
-# Copyright 2014 OpenStack Foundation
+# Copyright 2014 Hewlett-Packard Development Company, L.P
 # All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
index 90dccca..2e732fe 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -25,131 +25,117 @@
     @test.safe_setup
     def setUpClass(cls):
         super(RolesV3TestJSON, cls).setUpClass()
+        for _ in range(3):
+            role_name = data_utils.rand_name(name='role-')
+            _, role = cls.client.create_role(role_name)
+            cls.data.v3_roles.append(role)
         cls.fetched_role_ids = list()
         u_name = data_utils.rand_name('user-')
         u_desc = '%s description' % u_name
         u_email = '%s@testmail.tm' % u_name
         cls.u_password = data_utils.rand_name('pass-')
-        resp = [None] * 5
-        resp[0], cls.domain = cls.client.create_domain(
+        _, cls.domain = cls.client.create_domain(
             data_utils.rand_name('domain-'),
             description=data_utils.rand_name('domain-desc-'))
-        resp[1], cls.project = cls.client.create_project(
+        _, cls.project = cls.client.create_project(
             data_utils.rand_name('project-'),
             description=data_utils.rand_name('project-desc-'),
             domain_id=cls.domain['id'])
-        resp[2], cls.group_body = cls.client.create_group(
+        _, cls.group_body = cls.client.create_group(
             data_utils.rand_name('Group-'), project_id=cls.project['id'],
             domain_id=cls.domain['id'])
-        resp[3], cls.user_body = cls.client.create_user(
+        _, cls.user_body = cls.client.create_user(
             u_name, description=u_desc, password=cls.u_password,
             email=u_email, project_id=cls.project['id'],
             domain_id=cls.domain['id'])
-        resp[4], cls.role = cls.client.create_role(
+        _, cls.role = cls.client.create_role(
             data_utils.rand_name('Role-'))
-        for r in resp:
-            assert r['status'] == '201', (
-                "Expected 201, but got: %s" % r['status'])
 
     @classmethod
     def tearDownClass(cls):
-        resp = [None] * 5
-        resp[0], _ = cls.client.delete_role(cls.role['id'])
-        resp[1], _ = cls.client.delete_group(cls.group_body['id'])
-        resp[2], _ = cls.client.delete_user(cls.user_body['id'])
-        resp[3], _ = cls.client.delete_project(cls.project['id'])
+        cls.client.delete_role(cls.role['id'])
+        cls.client.delete_group(cls.group_body['id'])
+        cls.client.delete_user(cls.user_body['id'])
+        cls.client.delete_project(cls.project['id'])
         # NOTE(harika-vakadi): It is necessary to disable the domain
         # before deleting,or else it would result in unauthorized error
         cls.client.update_domain(cls.domain['id'], enabled=False)
-        resp[4], _ = cls.client.delete_domain(cls.domain['id'])
-        for r in resp:
-            assert r['status'] == '204', (
-                "Expected 204, but got: %s" % r['status'])
+        cls.client.delete_domain(cls.domain['id'])
         super(RolesV3TestJSON, cls).tearDownClass()
 
-    def _list_assertions(self, resp, body, fetched_role_ids, role_id):
-        self.assertEqual(resp['status'], '200')
+    def _list_assertions(self, body, fetched_role_ids, role_id):
         self.assertEqual(len(body), 1)
         self.assertIn(role_id, fetched_role_ids)
 
     @test.attr(type='smoke')
     def test_role_create_update_get_list(self):
         r_name = data_utils.rand_name('Role-')
-        resp, role = self.client.create_role(r_name)
+        _, role = self.client.create_role(r_name)
         self.addCleanup(self.client.delete_role, role['id'])
-        self.assertEqual(resp['status'], '201')
         self.assertIn('name', role)
         self.assertEqual(role['name'], r_name)
 
         new_name = data_utils.rand_name('NewRole-')
-        resp, updated_role = self.client.update_role(new_name, role['id'])
-        self.assertEqual(resp['status'], '200')
+        _, updated_role = self.client.update_role(new_name, role['id'])
         self.assertIn('name', updated_role)
         self.assertIn('id', updated_role)
         self.assertIn('links', updated_role)
         self.assertNotEqual(r_name, updated_role['name'])
 
-        resp, new_role = self.client.get_role(role['id'])
-        self.assertEqual(resp['status'], '200')
+        _, new_role = self.client.get_role(role['id'])
         self.assertEqual(new_name, new_role['name'])
         self.assertEqual(updated_role['id'], new_role['id'])
 
-        resp, roles = self.client.list_roles()
-        self.assertEqual(resp['status'], '200')
+        _, roles = self.client.list_roles()
         self.assertIn(role['id'], [r['id'] for r in roles])
 
     @test.attr(type='smoke')
     def test_grant_list_revoke_role_to_user_on_project(self):
-        resp, _ = self.client.assign_user_role_on_project(
+        self.client.assign_user_role_on_project(
             self.project['id'], self.user_body['id'], self.role['id'])
-        self.assertEqual(resp['status'], '204')
 
-        resp, roles = self.client.list_user_roles_on_project(
+        _, roles = self.client.list_user_roles_on_project(
             self.project['id'], self.user_body['id'])
 
         for i in roles:
             self.fetched_role_ids.append(i['id'])
 
-        self._list_assertions(resp, roles, self.fetched_role_ids,
+        self._list_assertions(roles, self.fetched_role_ids,
                               self.role['id'])
 
-        resp, _ = self.client.revoke_role_from_user_on_project(
+        self.client.revoke_role_from_user_on_project(
             self.project['id'], self.user_body['id'], self.role['id'])
-        self.assertEqual(resp['status'], '204')
 
     @test.attr(type='smoke')
     def test_grant_list_revoke_role_to_user_on_domain(self):
-        resp, _ = self.client.assign_user_role_on_domain(
+        self.client.assign_user_role_on_domain(
             self.domain['id'], self.user_body['id'], self.role['id'])
-        self.assertEqual(resp['status'], '204')
 
-        resp, roles = self.client.list_user_roles_on_domain(
+        _, roles = self.client.list_user_roles_on_domain(
             self.domain['id'], self.user_body['id'])
 
         for i in roles:
             self.fetched_role_ids.append(i['id'])
 
-        self._list_assertions(resp, roles, self.fetched_role_ids,
+        self._list_assertions(roles, self.fetched_role_ids,
                               self.role['id'])
 
-        resp, _ = self.client.revoke_role_from_user_on_domain(
+        self.client.revoke_role_from_user_on_domain(
             self.domain['id'], self.user_body['id'], self.role['id'])
-        self.assertEqual(resp['status'], '204')
 
     @test.attr(type='smoke')
     def test_grant_list_revoke_role_to_group_on_project(self):
         # Grant role to group on project
-        resp, _ = self.client.assign_group_role_on_project(
+        self.client.assign_group_role_on_project(
             self.project['id'], self.group_body['id'], self.role['id'])
-        self.assertEqual(resp['status'], '204')
         # List group roles on project
-        resp, roles = self.client.list_group_roles_on_project(
+        _, roles = self.client.list_group_roles_on_project(
             self.project['id'], self.group_body['id'])
 
         for i in roles:
             self.fetched_role_ids.append(i['id'])
 
-        self._list_assertions(resp, roles, self.fetched_role_ids,
+        self._list_assertions(roles, self.fetched_role_ids,
                               self.role['id'])
         # Add user to group, and insure user has role on project
         self.client.add_group_user(self.group_body['id'], self.user_body['id'])
@@ -163,28 +149,32 @@
         self.assertEqual(len(roles), 1)
         self.assertEqual(roles[0]['id'], self.role['id'])
         # Revoke role to group on project
-        resp, _ = self.client.revoke_role_from_group_on_project(
+        self.client.revoke_role_from_group_on_project(
             self.project['id'], self.group_body['id'], self.role['id'])
-        self.assertEqual(resp['status'], '204')
 
     @test.attr(type='smoke')
     def test_grant_list_revoke_role_to_group_on_domain(self):
-        resp, _ = self.client.assign_group_role_on_domain(
+        self.client.assign_group_role_on_domain(
             self.domain['id'], self.group_body['id'], self.role['id'])
-        self.assertEqual(resp['status'], '204')
 
-        resp, roles = self.client.list_group_roles_on_domain(
+        _, roles = self.client.list_group_roles_on_domain(
             self.domain['id'], self.group_body['id'])
 
         for i in roles:
             self.fetched_role_ids.append(i['id'])
 
-        self._list_assertions(resp, roles, self.fetched_role_ids,
+        self._list_assertions(roles, self.fetched_role_ids,
                               self.role['id'])
 
-        resp, _ = self.client.revoke_role_from_group_on_domain(
+        self.client.revoke_role_from_group_on_domain(
             self.domain['id'], self.group_body['id'], self.role['id'])
-        self.assertEqual(resp['status'], '204')
+
+    @test.attr(type='gate')
+    def test_list_roles(self):
+        # Return a list of all roles
+        _, body = self.client.list_roles()
+        found = [role for role in body if role in self.data.v3_roles]
+        self.assertEqual(len(found), len(self.data.v3_roles))
 
 
 class RolesV3TestXML(RolesV3TestJSON):
diff --git a/tempest/api/identity/admin/v3/test_services.py b/tempest/api/identity/admin/v3/test_services.py
index 36e5327..f6078da 100644
--- a/tempest/api/identity/admin/v3/test_services.py
+++ b/tempest/api/identity/admin/v3/test_services.py
@@ -28,9 +28,8 @@
         name = data_utils.rand_name('service-')
         serv_type = data_utils.rand_name('type--')
         desc = data_utils.rand_name('description-')
-        resp, body = self.service_client.create_service(name, serv_type,
-                                                        description=desc)
-        self.assertEqual('201', resp['status'])
+        _, body = self.service_client.create_service(name, serv_type,
+                                                     description=desc)
         # Deleting the service created in this method
         self.addCleanup(self.service_client.delete_service, body['id'])
 
@@ -38,14 +37,13 @@
         resp1_desc = body['description']
 
         s_desc2 = data_utils.rand_name('desc2-')
-        resp, body = self.service_client.update_service(
+        _, body = self.service_client.update_service(
             s_id, description=s_desc2)
         resp2_desc = body['description']
-        self.assertEqual('200', resp['status'])
         self.assertNotEqual(resp1_desc, resp2_desc)
 
         # Get service
-        resp, body = self.service_client.get_service(s_id)
+        _, body = self.service_client.get_service(s_id)
         resp3_desc = body['description']
 
         self.assertNotEqual(resp1_desc, resp3_desc)
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index fe3eb03..e61b738 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -30,23 +30,21 @@
         u_desc = '%s-description' % u_name
         u_email = '%s@testmail.tm' % u_name
         u_password = data_utils.rand_name('pass-')
-        resp, user = self.client.create_user(
+        _, user = self.client.create_user(
             u_name, description=u_desc, password=u_password,
             email=u_email)
-        self.assertEqual(201, resp.status)
         self.addCleanup(self.client.delete_user, user['id'])
         # Perform Authentication
         resp, body = self.token.auth(user['id'], u_password)
         self.assertEqual(201, resp.status)
         subject_token = resp['x-subject-token']
         # Perform GET Token
-        resp, token_details = self.client.get_token(subject_token)
-        self.assertEqual(200, resp.status)
+        _, token_details = self.client.get_token(subject_token)
         self.assertEqual(resp['x-subject-token'], subject_token)
         self.assertEqual(token_details['user']['id'], user['id'])
         self.assertEqual(token_details['user']['name'], u_name)
         # Perform Delete Token
-        resp, _ = self.client.delete_token(subject_token)
+        self.client.delete_token(subject_token)
         self.assertRaises(exceptions.NotFound, self.client.get_token,
                           subject_token)
 
@@ -63,35 +61,29 @@
         # Create a user.
         user_name = data_utils.rand_name(name='user-')
         user_password = data_utils.rand_name(name='pass-')
-        resp, user = self.client.create_user(user_name, password=user_password)
-        self.assertEqual(201, resp.status)
+        _, user = self.client.create_user(user_name, password=user_password)
         self.addCleanup(self.client.delete_user, user['id'])
 
         # Create a couple projects
         project1_name = data_utils.rand_name(name='project-')
-        resp, project1 = self.client.create_project(project1_name)
-        self.assertEqual(201, resp.status)
+        _, project1 = self.client.create_project(project1_name)
         self.addCleanup(self.client.delete_project, project1['id'])
 
         project2_name = data_utils.rand_name(name='project-')
-        resp, project2 = self.client.create_project(project2_name)
-        self.assertEqual(201, resp.status)
+        _, project2 = self.client.create_project(project2_name)
         self.addCleanup(self.client.delete_project, project2['id'])
 
         # Create a role
         role_name = data_utils.rand_name(name='role-')
-        resp, role = self.client.create_role(role_name)
-        self.assertEqual(201, resp.status)
+        _, role = self.client.create_role(role_name)
         self.addCleanup(self.client.delete_role, role['id'])
 
         # Grant the user the role on both projects.
-        resp, _ = self.client.assign_user_role(project1['id'], user['id'],
-                                               role['id'])
-        self.assertEqual(204, resp.status)
+        self.client.assign_user_role(project1['id'], user['id'],
+                                     role['id'])
 
-        resp, _ = self.client.assign_user_role(project2['id'], user['id'],
-                                               role['id'])
-        self.assertEqual(204, resp.status)
+        self.client.assign_user_role(project2['id'], user['id'],
+                                     role['id'])
 
         # Get an unscoped token.
         resp, token_auth = self.token.auth(user=user['id'],
@@ -145,8 +137,7 @@
         self.assertEqual(role['name'], token_auth['token']['roles'][0]['name'])
 
         # Revoke the unscoped token.
-        resp, _ = self.client.delete_token(token1_id)
-        self.assertEqual(204, resp.status)
+        self.client.delete_token(token1_id)
 
         # Now get another scoped token using the unscoped token.
         resp, token_auth = self.token.auth(token=token_id,
diff --git a/tempest/api/identity/admin/v3/test_trusts.py b/tempest/api/identity/admin/v3/test_trusts.py
index 8e3a7d1..1561a6e 100644
--- a/tempest/api/identity/admin/v3/test_trusts.py
+++ b/tempest/api/identity/admin/v3/test_trusts.py
@@ -54,25 +54,22 @@
         u_desc = self.trustor_username + 'description'
         u_email = self.trustor_username + '@testmail.xx'
         self.trustor_password = data_utils.rand_name('pass-')
-        resp, user = self.client.create_user(
+        _, user = self.client.create_user(
             self.trustor_username,
             description=u_desc,
             password=self.trustor_password,
             email=u_email,
             project_id=self.trustor_project_id)
-        self.assertEqual(resp['status'], '201')
         self.trustor_user_id = user['id']
 
         # And two roles, one we'll delegate and one we won't
         self.delegated_role = data_utils.rand_name('DelegatedRole-')
         self.not_delegated_role = data_utils.rand_name('NotDelegatedRole-')
 
-        resp, role = self.client.create_role(self.delegated_role)
-        self.assertEqual(resp['status'], '201')
+        _, role = self.client.create_role(self.delegated_role)
         self.delegated_role_id = role['id']
 
-        resp, role = self.client.create_role(self.not_delegated_role)
-        self.assertEqual(resp['status'], '201')
+        _, role = self.client.create_role(self.not_delegated_role)
         self.not_delegated_role_id = role['id']
 
         # Assign roles to trustor
@@ -108,14 +105,13 @@
 
     def create_trust(self, impersonate=True, expires=None):
 
-        resp, trust_create = self.trustor_client.create_trust(
+        _, trust_create = self.trustor_client.create_trust(
             trustor_user_id=self.trustor_user_id,
             trustee_user_id=self.trustee_user_id,
             project_id=self.trustor_project_id,
             role_names=[self.delegated_role],
             impersonation=impersonate,
             expires_at=expires)
-        self.assertEqual('201', resp['status'])
         self.trust_id = trust_create['id']
         return trust_create
 
@@ -141,8 +137,7 @@
             self.assertEqual(1, len(trust['roles']))
 
     def get_trust(self):
-        resp, trust_get = self.trustor_client.get_trust(self.trust_id)
-        self.assertEqual('200', resp['status'])
+        _, trust_get = self.trustor_client.get_trust(self.trust_id)
         return trust_get
 
     def validate_role(self, role):
@@ -157,20 +152,17 @@
 
     def check_trust_roles(self):
         # Check we find the delegated role
-        resp, roles_get = self.trustor_client.get_trust_roles(
+        _, roles_get = self.trustor_client.get_trust_roles(
             self.trust_id)
-        self.assertEqual('200', resp['status'])
         self.assertEqual(1, len(roles_get))
         self.validate_role(roles_get[0])
 
-        resp, role_get = self.trustor_client.get_trust_role(
+        _, role_get = self.trustor_client.get_trust_role(
             self.trust_id, self.delegated_role_id)
-        self.assertEqual('200', resp['status'])
         self.validate_role(role_get)
 
-        resp, role_get = self.trustor_client.check_trust_role(
+        _, role_get = self.trustor_client.check_trust_role(
             self.trust_id, self.delegated_role_id)
-        self.assertEqual('204', resp['status'])
 
         # And that we don't find not_delegated_role
         self.assertRaises(exceptions.NotFound,
@@ -184,8 +176,7 @@
                           self.not_delegated_role_id)
 
     def delete_trust(self):
-        resp, trust_delete = self.trustor_client.delete_trust(self.trust_id)
-        self.assertEqual('204', resp['status'])
+        self.trustor_client.delete_trust(self.trust_id)
         self.assertRaises(exceptions.NotFound,
                           self.trustor_client.get_trust,
                           self.trust_id)
@@ -253,17 +244,15 @@
     @test.attr(type='smoke')
     def test_get_trusts_query(self):
         self.create_trust()
-        resp, trusts_get = self.trustor_client.get_trusts(
+        _, trusts_get = self.trustor_client.get_trusts(
             trustor_user_id=self.trustor_user_id)
-        self.assertEqual('200', resp['status'])
         self.assertEqual(1, len(trusts_get))
         self.validate_trust(trusts_get[0], summary=True)
 
     @test.attr(type='smoke')
     def test_get_trusts_all(self):
         self.create_trust()
-        resp, trusts_get = self.client.get_trusts()
-        self.assertEqual('200', resp['status'])
+        _, trusts_get = self.client.get_trusts()
         trusts = [t for t in trusts_get
                   if t['id'] == self.trust_id]
         self.assertEqual(1, len(trusts))
diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py
index 7316c7f..3c25819 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -29,13 +29,13 @@
         u_desc = u_name + 'description'
         u_email = u_name + '@testmail.tm'
         u_password = data_utils.rand_name('pass-')
-        resp, user = self.client.create_user(
+        _, user = self.client.create_user(
             u_name, description=u_desc, password=u_password,
             email=u_email, enabled=False)
         # Delete the User at the end of this method
         self.addCleanup(self.client.delete_user, user['id'])
         # Creating second project for updation
-        resp, project = self.client.create_project(
+        _, project = self.client.create_project(
             data_utils.rand_name('project-'),
             description=data_utils.rand_name('project-desc-'))
         # Delete the Project at the end of this method
@@ -44,12 +44,10 @@
         u_name2 = data_utils.rand_name('user2-')
         u_email2 = u_name2 + '@testmail.tm'
         u_description2 = u_name2 + ' description'
-        resp, update_user = self.client.update_user(
+        _, update_user = self.client.update_user(
             user['id'], name=u_name2, description=u_description2,
             project_id=project['id'],
             email=u_email2, enabled=False)
-        # Assert response body of update user.
-        self.assertEqual(200, resp.status)
         self.assertEqual(u_name2, update_user['name'])
         self.assertEqual(u_description2, update_user['description'])
         self.assertEqual(project['id'],
@@ -57,7 +55,7 @@
         self.assertEqual(u_email2, update_user['email'])
         self.assertEqual('false', str(update_user['enabled']).lower())
         # GET by id after updation
-        resp, new_user_get = self.client.get_user(user['id'])
+        _, new_user_get = self.client.get_user(user['id'])
         # Assert response body of GET after updation
         self.assertEqual(u_name2, new_user_get['name'])
         self.assertEqual(u_description2, new_user_get['description'])
@@ -67,6 +65,28 @@
         self.assertEqual('false', str(new_user_get['enabled']).lower())
 
     @test.attr(type='gate')
+    def test_update_user_password(self):
+        # Creating User to check password updation
+        u_name = data_utils.rand_name('user')
+        original_password = data_utils.rand_name('pass')
+        _, user = self.client.create_user(
+            u_name, password=original_password)
+        # Delete the User at the end all test methods
+        self.addCleanup(self.client.delete_user, user['id'])
+        # Update user with new password
+        new_password = data_utils.rand_name('pass1')
+        self.client.update_user_password(user['id'], new_password,
+                                         original_password)
+        resp, body = self.token.auth(user['id'], new_password)
+        self.assertEqual(201, resp.status)
+        subject_token = resp['x-subject-token']
+        # Perform GET Token to verify and confirm password is updated
+        _, token_details = self.client.get_token(subject_token)
+        self.assertEqual(resp['x-subject-token'], subject_token)
+        self.assertEqual(token_details['user']['id'], user['id'])
+        self.assertEqual(token_details['user']['name'], u_name)
+
+    @test.attr(type='gate')
     def test_list_user_projects(self):
         # List the projects that a user has access upon
         assigned_project_ids = list()
@@ -107,8 +127,7 @@
                                          user['id'],
                                          role['id'])
             assigned_project_ids.append(project['id'])
-        resp, body = self.client.list_user_projects(user['id'])
-        self.assertEqual(200, resp.status)
+        _, body = self.client.list_user_projects(user['id'])
         for i in body:
             fetched_project_ids.append(i['id'])
         # verifying the project ids in list
@@ -124,7 +143,7 @@
     def test_get_user(self):
         # Get a user detail
         self.data.setup_test_v3_user()
-        resp, user = self.client.get_user(self.data.v3_user['id'])
+        _, user = self.client.get_user(self.data.v3_user['id'])
         self.assertEqual(self.data.v3_user['id'], user['id'])
 
 
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 697057f..8eb7d33 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -121,6 +121,7 @@
             self.v3_users = []
             self.projects = []
             self.v3_roles = []
+            self.domains = []
 
         @property
         def test_credentials(self):
@@ -136,17 +137,17 @@
             self.test_user = data_utils.rand_name('test_user_')
             self.test_password = data_utils.rand_name('pass_')
             self.test_email = self.test_user + '@testmail.tm'
-            resp, self.user = self.client.create_user(self.test_user,
-                                                      self.test_password,
-                                                      self.tenant['id'],
-                                                      self.test_email)
+            _, self.user = self.client.create_user(self.test_user,
+                                                   self.test_password,
+                                                   self.tenant['id'],
+                                                   self.test_email)
             self.users.append(self.user)
 
         def setup_test_tenant(self):
             """Set up a test tenant."""
             self.test_tenant = data_utils.rand_name('test_tenant_')
             self.test_description = data_utils.rand_name('desc_')
-            resp, self.tenant = self.client.create_tenant(
+            _, self.tenant = self.client.create_tenant(
                 name=self.test_tenant,
                 description=self.test_description)
             self.tenants.append(self.tenant)
@@ -154,7 +155,7 @@
         def setup_test_role(self):
             """Set up a test role."""
             self.test_role = data_utils.rand_name('role')
-            resp, self.role = self.client.create_role(self.test_role)
+            _, self.role = self.client.create_role(self.test_role)
             self.roles.append(self.role)
 
         def setup_test_v3_user(self):
@@ -163,7 +164,7 @@
             self.test_user = data_utils.rand_name('test_user_')
             self.test_password = data_utils.rand_name('pass_')
             self.test_email = self.test_user + '@testmail.tm'
-            resp, self.v3_user = self.client.create_user(
+            _, self.v3_user = self.client.create_user(
                 self.test_user,
                 password=self.test_password,
                 project_id=self.project['id'],
@@ -174,7 +175,7 @@
             """Set up a test project."""
             self.test_project = data_utils.rand_name('test_project_')
             self.test_description = data_utils.rand_name('desc_')
-            resp, self.project = self.client.create_project(
+            _, self.project = self.client.create_project(
                 name=self.test_project,
                 description=self.test_description)
             self.projects.append(self.project)
@@ -182,9 +183,18 @@
         def setup_test_v3_role(self):
             """Set up a test v3 role."""
             self.test_role = data_utils.rand_name('role')
-            resp, self.v3_role = self.client.create_role(self.test_role)
+            _, self.v3_role = self.client.create_role(self.test_role)
             self.v3_roles.append(self.v3_role)
 
+        def setup_test_domain(self):
+            """Set up a test domain."""
+            self.test_domain = data_utils.rand_name('test_domain')
+            self.test_description = data_utils.rand_name('desc')
+            _, self.domain = self.client.create_domain(
+                name=self.test_domain,
+                description=self.test_description)
+            self.domains.append(self.domain)
+
         def teardown_all(self):
             for user in self.users:
                 self.client.delete_user(user['id'])
@@ -198,3 +208,6 @@
                 self.client.delete_project(v3_project['id'])
             for v3_role in self.v3_roles:
                 self.client.delete_role(v3_role['id'])
+            for domain in self.domains:
+                self.client.update_domain(domain['id'], enabled=False)
+                self.client.delete_domain(domain['id'])
diff --git a/tempest/api/identity/test_extension.py b/tempest/api/identity/test_extension.py
index 67f20f4..a06ee53 100644
--- a/tempest/api/identity/test_extension.py
+++ b/tempest/api/identity/test_extension.py
@@ -23,8 +23,7 @@
     @test.attr(type='gate')
     def test_list_extensions(self):
         # List all the extensions
-        resp, body = self.non_admin_client.list_extensions()
-        self.assertEqual(200, resp.status)
+        _, body = self.non_admin_client.list_extensions()
         self.assertNotEmpty(body)
         keys = ['name', 'updated', 'alias', 'links',
                 'namespace', 'description']
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 9981292..02d391b 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -142,9 +142,9 @@
 
     def _create_image(self):
         name = data_utils.rand_name('image')
-        resp, image = self.os_img_client.create_image(name,
-                                                      container_format='bare',
-                                                      disk_format='raw')
+        _, image = self.os_img_client.create_image(name,
+                                                   container_format='bare',
+                                                   disk_format='raw')
         image_id = image['id']
         self.addCleanup(self.os_img_client.delete_image, image_id)
         return image_id
diff --git a/tempest/api/image/v1/test_image_members.py b/tempest/api/image/v1/test_image_members.py
index 4cbb62f..f91cb69 100644
--- a/tempest/api/image/v1/test_image_members.py
+++ b/tempest/api/image/v1/test_image_members.py
@@ -22,27 +22,21 @@
     @test.attr(type='gate')
     def test_add_image_member(self):
         image = self._create_image()
-        resp = self.client.add_member(self.alt_tenant_id, image)
-        self.assertEqual(204, resp.status)
-        resp, body = self.client.get_image_membership(image)
-        self.assertEqual(200, resp.status)
+        self.client.add_member(self.alt_tenant_id, image)
+        _, body = self.client.get_image_membership(image)
         members = body['members']
         members = map(lambda x: x['member_id'], members)
         self.assertIn(self.alt_tenant_id, members)
         # get image as alt user
-        resp, body = self.alt_img_cli.get_image(image)
-        self.assertEqual(200, resp.status)
+        self.alt_img_cli.get_image(image)
 
     @test.attr(type='gate')
     def test_get_shared_images(self):
         image = self._create_image()
-        resp = self.client.add_member(self.alt_tenant_id, image)
-        self.assertEqual(204, resp.status)
+        self.client.add_member(self.alt_tenant_id, image)
         share_image = self._create_image()
-        resp = self.client.add_member(self.alt_tenant_id, share_image)
-        self.assertEqual(204, resp.status)
-        resp, body = self.client.get_shared_images(self.alt_tenant_id)
-        self.assertEqual(200, resp.status)
+        self.client.add_member(self.alt_tenant_id, share_image)
+        _, body = self.client.get_shared_images(self.alt_tenant_id)
         images = body['shared_images']
         images = map(lambda x: x['image_id'], images)
         self.assertIn(share_image, images)
@@ -51,11 +45,8 @@
     @test.attr(type='gate')
     def test_remove_member(self):
         image_id = self._create_image()
-        resp = self.client.add_member(self.alt_tenant_id, image_id)
-        self.assertEqual(204, resp.status)
-        resp = self.client.delete_member(self.alt_tenant_id, image_id)
-        self.assertEqual(204, resp.status)
-        resp, body = self.client.get_image_membership(image_id)
-        self.assertEqual(200, resp.status)
+        self.client.add_member(self.alt_tenant_id, image_id)
+        self.client.delete_member(self.alt_tenant_id, image_id)
+        _, body = self.client.get_image_membership(image_id)
         members = body['members']
         self.assertEqual(0, len(members), str(members))
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index 2df3f7f..8528e42 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -30,11 +30,11 @@
     def test_register_then_upload(self):
         # Register, then upload an image
         properties = {'prop1': 'val1'}
-        resp, body = self.create_image(name='New Name',
-                                       container_format='bare',
-                                       disk_format='raw',
-                                       is_public=False,
-                                       properties=properties)
+        _, body = self.create_image(name='New Name',
+                                    container_format='bare',
+                                    disk_format='raw',
+                                    is_public=False,
+                                    properties=properties)
         self.assertIn('id', body)
         image_id = body.get('id')
         self.assertEqual('New Name', body.get('name'))
@@ -45,20 +45,19 @@
 
         # Now try uploading an image file
         image_file = StringIO.StringIO(('*' * 1024))
-        resp, body = self.client.update_image(image_id, data=image_file)
+        _, body = self.client.update_image(image_id, data=image_file)
         self.assertIn('size', body)
         self.assertEqual(1024, body.get('size'))
 
     @test.attr(type='gate')
     def test_register_remote_image(self):
         # Register a new remote image
-        resp, body = self.create_image(name='New Remote Image',
-                                       container_format='bare',
-                                       disk_format='raw', is_public=False,
-                                       location='http://example.com'
-                                                '/someimage.iso',
-                                       properties={'key1': 'value1',
-                                                   'key2': 'value2'})
+        _, body = self.create_image(name='New Remote Image',
+                                    container_format='bare',
+                                    disk_format='raw', is_public=False,
+                                    location=CONF.image.http_image,
+                                    properties={'key1': 'value1',
+                                                'key2': 'value2'})
         self.assertIn('id', body)
         self.assertEqual('New Remote Image', body.get('name'))
         self.assertFalse(body.get('is_public'))
@@ -69,28 +68,27 @@
 
     @test.attr(type='gate')
     def test_register_http_image(self):
-        resp, body = self.create_image(name='New Http Image',
-                                       container_format='bare',
-                                       disk_format='raw', is_public=False,
-                                       copy_from=CONF.image.http_image)
+        _, body = self.create_image(name='New Http Image',
+                                    container_format='bare',
+                                    disk_format='raw', is_public=False,
+                                    copy_from=CONF.image.http_image)
         self.assertIn('id', body)
         image_id = body.get('id')
         self.assertEqual('New Http Image', body.get('name'))
         self.assertFalse(body.get('is_public'))
         self.client.wait_for_image_status(image_id, 'active')
-        resp, body = self.client.get_image(image_id)
-        self.assertEqual(resp['status'], '200')
+        self.client.get_image(image_id)
 
     @test.attr(type='gate')
     def test_register_image_with_min_ram(self):
         # Register an image with min ram
         properties = {'prop1': 'val1'}
-        resp, body = self.create_image(name='New_image_with_min_ram',
-                                       container_format='bare',
-                                       disk_format='raw',
-                                       is_public=False,
-                                       min_ram=40,
-                                       properties=properties)
+        _, body = self.create_image(name='New_image_with_min_ram',
+                                    container_format='bare',
+                                    disk_format='raw',
+                                    is_public=False,
+                                    min_ram=40,
+                                    properties=properties)
         self.assertIn('id', body)
         self.assertEqual('New_image_with_min_ram', body.get('name'))
         self.assertFalse(body.get('is_public'))
@@ -98,8 +96,7 @@
         self.assertEqual(40, body.get('min_ram'))
         for key, val in properties.items():
             self.assertEqual(val, body.get('properties')[key])
-        resp, body = self.client.delete_image(body['id'])
-        self.assertEqual('200', resp['status'])
+        self.client.delete_image(body['id'])
 
 
 class ListImagesTest(base.BaseV1ImageTest):
@@ -143,12 +140,12 @@
         image
         """
         name = 'New Remote Image %s' % name
-        location = 'http://example.com/someimage_%s.iso' % name
-        resp, image = cls.create_image(name=name,
-                                       container_format=container_format,
-                                       disk_format=disk_format,
-                                       is_public=False,
-                                       location=location)
+        location = CONF.image.http_image
+        _, image = cls.create_image(name=name,
+                                    container_format=container_format,
+                                    disk_format=disk_format,
+                                    is_public=False,
+                                    location=location)
         image_id = image['id']
         return image_id
 
@@ -162,26 +159,24 @@
         """
         image_file = StringIO.StringIO('*' * size)
         name = 'New Standard Image %s' % name
-        resp, image = cls.create_image(name=name,
-                                       container_format=container_format,
-                                       disk_format=disk_format,
-                                       is_public=False, data=image_file)
+        _, image = cls.create_image(name=name,
+                                    container_format=container_format,
+                                    disk_format=disk_format,
+                                    is_public=False, data=image_file)
         image_id = image['id']
         return image_id
 
     @test.attr(type='gate')
     def test_index_no_params(self):
         # Simple test to see all fixture images returned
-        resp, images_list = self.client.image_list()
-        self.assertEqual(resp['status'], '200')
+        _, images_list = self.client.image_list()
         image_list = map(lambda x: x['id'], images_list)
         for image_id in self.created_images:
             self.assertIn(image_id, image_list)
 
     @test.attr(type='gate')
     def test_index_disk_format(self):
-        resp, images_list = self.client.image_list(disk_format='ami')
-        self.assertEqual(resp['status'], '200')
+        _, images_list = self.client.image_list(disk_format='ami')
         for image in images_list:
             self.assertEqual(image['disk_format'], 'ami')
         result_set = set(map(lambda x: x['id'], images_list))
@@ -190,8 +185,7 @@
 
     @test.attr(type='gate')
     def test_index_container_format(self):
-        resp, images_list = self.client.image_list(container_format='bare')
-        self.assertEqual(resp['status'], '200')
+        _, images_list = self.client.image_list(container_format='bare')
         for image in images_list:
             self.assertEqual(image['container_format'], 'bare')
         result_set = set(map(lambda x: x['id'], images_list))
@@ -200,8 +194,7 @@
 
     @test.attr(type='gate')
     def test_index_max_size(self):
-        resp, images_list = self.client.image_list(size_max=42)
-        self.assertEqual(resp['status'], '200')
+        _, images_list = self.client.image_list(size_max=42)
         for image in images_list:
             self.assertTrue(image['size'] <= 42)
         result_set = set(map(lambda x: x['id'], images_list))
@@ -210,8 +203,7 @@
 
     @test.attr(type='gate')
     def test_index_min_size(self):
-        resp, images_list = self.client.image_list(size_min=142)
-        self.assertEqual(resp['status'], '200')
+        _, images_list = self.client.image_list(size_min=142)
         for image in images_list:
             self.assertTrue(image['size'] >= 142)
         result_set = set(map(lambda x: x['id'], images_list))
@@ -220,10 +212,9 @@
 
     @test.attr(type='gate')
     def test_index_status_active_detail(self):
-        resp, images_list = self.client.image_list_detail(status='active',
-                                                          sort_key='size',
-                                                          sort_dir='desc')
-        self.assertEqual(resp['status'], '200')
+        _, images_list = self.client.image_list_detail(status='active',
+                                                       sort_key='size',
+                                                       sort_dir='desc')
         top_size = images_list[0]['size']  # We have non-zero sized images
         for image in images_list:
             size = image['size']
@@ -233,9 +224,8 @@
 
     @test.attr(type='gate')
     def test_index_name(self):
-        resp, images_list = self.client.image_list_detail(
+        _, images_list = self.client.image_list_detail(
             name='New Remote Image dup')
-        self.assertEqual(resp['status'], '200')
         result_set = set(map(lambda x: x['id'], images_list))
         for image in images_list:
             self.assertEqual(image['name'], 'New Remote Image dup')
@@ -267,10 +257,10 @@
         cls.snapshot_set = set((cls.snapshot,))
 
         image_file = StringIO.StringIO('*' * 42)
-        resp, image = cls.create_image(name="Standard Image",
-                                       container_format='ami',
-                                       disk_format='ami',
-                                       is_public=False, data=image_file)
+        _, image = cls.create_image(name="Standard Image",
+                                    container_format='ami',
+                                    disk_format='ami',
+                                    is_public=False, data=image_file)
         cls.image_id = image['id']
         cls.client.wait_for_image_status(image['id'], 'active')
 
@@ -282,7 +272,7 @@
 
     @classmethod
     def _create_snapshot(cls, name, image_id, flavor, **kwargs):
-        resp, server = cls.servers_client.create_server(
+        _, server = cls.servers_client.create_server(
             name, image_id, flavor, **kwargs)
         cls.servers.append(server)
         cls.servers_client.wait_for_server_status(
@@ -298,9 +288,8 @@
     @test.services('compute')
     def test_index_server_id(self):
         # The images should contain images filtered by server id
-        resp, images = self.client.image_list_detail(
+        _, images = self.client.image_list_detail(
             {'instance_uuid': self.servers[0]['id']})
-        self.assertEqual(200, resp.status)
         result_set = set(map(lambda x: x['id'], images))
         self.assertEqual(self.snapshot_set, result_set)
 
@@ -309,9 +298,8 @@
     def test_index_type(self):
         # The list of servers should be filtered by image type
         params = {'image_type': 'snapshot'}
-        resp, images = self.client.image_list_detail(params)
+        _, images = self.client.image_list_detail(params)
 
-        self.assertEqual(200, resp.status)
         result_set = set(map(lambda x: x['id'], images))
         self.assertIn(self.snapshot, result_set)
 
@@ -319,9 +307,8 @@
     @test.services('compute')
     def test_index_limit(self):
         # Verify only the expected number of results are returned
-        resp, images = self.client.image_list_detail(limit=1)
+        _, images = self.client.image_list_detail(limit=1)
 
-        self.assertEqual(200, resp.status)
         self.assertEqual(1, len(images))
 
     @test.attr(type='gate')
@@ -330,13 +317,11 @@
         # Verify an update image is returned
         # Becoming ACTIVE will modify the updated time
         # Filter by the image's created time
-        resp, image = self.client.get_image_meta(self.snapshot)
-        self.assertEqual(200, resp.status)
+        _, image = self.client.get_image_meta(self.snapshot)
         self.assertEqual(self.snapshot, image['id'])
-        resp, images = self.client.image_list_detail(
+        _, images = self.client.image_list_detail(
             changes_since=image['updated_at'])
 
-        self.assertEqual(200, resp.status)
         result_set = set(map(lambda x: x['id'], images))
         self.assertIn(self.image_id, result_set)
         self.assertNotIn(self.snapshot, result_set)
@@ -358,18 +343,18 @@
         """
         image_file = StringIO.StringIO('*' * size)
         name = 'New Standard Image %s' % name
-        resp, image = cls.create_image(name=name,
-                                       container_format=container_format,
-                                       disk_format=disk_format,
-                                       is_public=False, data=image_file,
-                                       properties={'key1': 'value1'})
+        _, image = cls.create_image(name=name,
+                                    container_format=container_format,
+                                    disk_format=disk_format,
+                                    is_public=False, data=image_file,
+                                    properties={'key1': 'value1'})
         image_id = image['id']
         return image_id
 
     @test.attr(type='gate')
     def test_list_image_metadata(self):
         # All metadata key/value pairs for an image should be returned
-        resp, resp_metadata = self.client.get_image_meta(self.image_id)
+        _, resp_metadata = self.client.get_image_meta(self.image_id)
         expected = {'key1': 'value1'}
         self.assertEqual(expected, resp_metadata['properties'])
 
@@ -377,13 +362,12 @@
     def test_update_image_metadata(self):
         # The metadata for the image should match the updated values
         req_metadata = {'key1': 'alt1', 'key2': 'value2'}
-        resp, metadata = self.client.get_image_meta(self.image_id)
-        self.assertEqual(200, resp.status)
+        _, metadata = self.client.get_image_meta(self.image_id)
         self.assertEqual(metadata['properties'], {'key1': 'value1'})
         metadata['properties'].update(req_metadata)
-        resp, metadata = self.client.update_image(
+        _, metadata = self.client.update_image(
             self.image_id, properties=metadata['properties'])
 
-        resp, resp_metadata = self.client.get_image_meta(self.image_id)
+        _, resp_metadata = self.client.get_image_meta(self.image_id)
         expected = {'key1': 'alt1', 'key2': 'value2'}
         self.assertEqual(expected, resp_metadata['properties'])
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index 37dc163..4226815 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -37,11 +37,11 @@
 
         uuid = '00000000-1111-2222-3333-444455556666'
         image_name = data_utils.rand_name('image')
-        resp, body = self.create_image(name=image_name,
-                                       container_format='bare',
-                                       disk_format='raw',
-                                       visibility='private',
-                                       ramdisk_id=uuid)
+        _, body = self.create_image(name=image_name,
+                                    container_format='bare',
+                                    disk_format='raw',
+                                    visibility='private',
+                                    ramdisk_id=uuid)
         self.assertIn('id', body)
         image_id = body.get('id')
         self.assertIn('name', body)
@@ -54,12 +54,10 @@
         # Now try uploading an image file
         file_content = '*' * 1024
         image_file = StringIO.StringIO(file_content)
-        resp, body = self.client.store_image(image_id, image_file)
-        self.assertEqual(resp.status, 204)
+        self.client.store_image(image_id, image_file)
 
         # Now try to get image details
-        resp, body = self.client.get_image(image_id)
-        self.assertEqual(200, resp.status)
+        _, body = self.client.get_image(image_id)
         self.assertEqual(image_id, body['id'])
         self.assertEqual(image_name, body['name'])
         self.assertEqual(uuid, body['ramdisk_id'])
@@ -67,8 +65,7 @@
         self.assertEqual(1024, body.get('size'))
 
         # Now try get image file
-        resp, body = self.client.get_image_file(image_id)
-        self.assertEqual(200, resp.status)
+        _, body = self.client.get_image_file(image_id)
         self.assertEqual(file_content, body)
 
     @test.attr(type='gate')
@@ -77,11 +74,10 @@
 
         # Create image
         image_name = data_utils.rand_name('image')
-        resp, body = self.client.create_image(name=image_name,
-                                              container_format='bare',
-                                              disk_format='raw',
-                                              visibility='private')
-        self.assertEqual(201, resp.status)
+        _, body = self.client.create_image(name=image_name,
+                                           container_format='bare',
+                                           disk_format='raw',
+                                           visibility='private')
         image_id = body['id']
 
         # Delete Image
@@ -89,9 +85,9 @@
         self.client.wait_for_resource_deletion(image_id)
 
         # Verifying deletion
-        resp, images = self.client.image_list()
-        self.assertEqual(resp.status, 200)
-        self.assertNotIn(image_id, images)
+        _, images = self.client.image_list()
+        images_id = [item['id'] for item in images]
+        self.assertNotIn(image_id, images_id)
 
     @test.attr(type='gate')
     def test_update_image(self):
@@ -99,11 +95,10 @@
 
         # Create image
         image_name = data_utils.rand_name('image')
-        resp, body = self.client.create_image(name=image_name,
-                                              container_format='bare',
-                                              disk_format='iso',
-                                              visibility='private')
-        self.assertEqual(201, resp.status)
+        _, body = self.client.create_image(name=image_name,
+                                           container_format='bare',
+                                           disk_format='iso',
+                                           visibility='private')
         self.addCleanup(self.client.delete_image, body['id'])
         self.assertEqual('queued', body['status'])
         image_id = body['id']
@@ -111,20 +106,16 @@
         # Now try uploading an image file
         file_content = '*' * 1024
         image_file = StringIO.StringIO(file_content)
-        resp, body = self.client.store_image(image_id, image_file)
-        self.assertEqual(204, resp.status)
+        self.client.store_image(image_id, image_file)
 
         # Update Image
         new_image_name = data_utils.rand_name('new-image')
-        resp, body = self.client.update_image(image_id, [
+        _, body = self.client.update_image(image_id, [
             dict(replace='/name', value=new_image_name)])
 
-        self.assertEqual(200, resp.status)
-
         # Verifying updating
 
-        resp, body = self.client.get_image(image_id)
-        self.assertEqual(200, resp.status)
+        _, body = self.client.get_image(image_id)
         self.assertEqual(image_id, body['id'])
         self.assertEqual(new_image_name, body['name'])
 
@@ -157,12 +148,12 @@
         """
         image_file = StringIO.StringIO('*' * random.randint(1024, 4096))
         name = data_utils.rand_name('image-')
-        resp, body = cls.create_image(name=name,
-                                      container_format=container_format,
-                                      disk_format=disk_format,
-                                      visibility='private')
+        _, body = cls.create_image(name=name,
+                                   container_format=container_format,
+                                   disk_format=disk_format,
+                                   visibility='private')
         image_id = body['id']
-        resp, body = cls.client.store_image(image_id, data=image_file)
+        cls.client.store_image(image_id, data=image_file)
 
         return image_id
 
@@ -170,8 +161,7 @@
         """
         Perform list action with given params and validates result.
         """
-        resp, images_list = self.client.image_list(params=params)
-        self.assertEqual(200, resp.status)
+        _, images_list = self.client.image_list(params=params)
         # Validating params of fetched images
         for image in images_list:
             for key in params:
@@ -181,8 +171,7 @@
     @test.attr(type='gate')
     def test_index_no_params(self):
         # Simple test to see all fixture images returned
-        resp, images_list = self.client.image_list()
-        self.assertEqual(resp['status'], '200')
+        _, images_list = self.client.image_list()
         image_list = map(lambda x: x['id'], images_list)
 
         for image in self.created_images:
@@ -211,8 +200,7 @@
         # Test to get all images by size
         image_id = self.created_images[1]
         # Get image metadata
-        resp, image = self.client.get_image(image_id)
-        self.assertEqual(resp['status'], '200')
+        _, image = self.client.get_image(image_id)
 
         params = {"size": image['size']}
         self._list_by_param_value_and_assert(params)
@@ -222,13 +210,11 @@
         # Test to get all images with size between 2000 to 3000
         image_id = self.created_images[1]
         # Get image metadata
-        resp, image = self.client.get_image(image_id)
-        self.assertEqual(resp['status'], '200')
+        _, image = self.client.get_image(image_id)
 
         size = image['size']
         params = {"size_min": size - 500, "size_max": size + 500}
-        resp, images_list = self.client.image_list(params=params)
-        self.assertEqual(resp['status'], '200')
+        _, images_list = self.client.image_list(params=params)
         image_size_list = map(lambda x: x['size'], images_list)
 
         for image_size in image_size_list:
@@ -246,8 +232,7 @@
     def test_list_images_param_limit(self):
         # Test to get images by limit
         params = {"limit": 2}
-        resp, images_list = self.client.image_list(params=params)
-        self.assertEqual(resp['status'], '200')
+        _, images_list = self.client.image_list(params=params)
 
         self.assertEqual(len(images_list), params['limit'],
                          "Failed to get images by limit")
@@ -256,14 +241,12 @@
     def test_get_image_schema(self):
         # Test to get image schema
         schema = "image"
-        resp, body = self.client.get_schema(schema)
-        self.assertEqual(200, resp.status)
+        _, body = self.client.get_schema(schema)
         self.assertEqual("image", body['name'])
 
     @test.attr(type='gate')
     def test_get_images_schema(self):
         # Test to get images schema
         schema = "images"
-        resp, body = self.client.get_schema(schema)
-        self.assertEqual(200, resp.status)
+        _, body = self.client.get_schema(schema)
         self.assertEqual("images", body['name'])
diff --git a/tempest/api/image/v2/test_images_member.py b/tempest/api/image/v2/test_images_member.py
index f80c818..5aaf578 100644
--- a/tempest/api/image/v2/test_images_member.py
+++ b/tempest/api/image/v2/test_images_member.py
@@ -20,9 +20,8 @@
     @test.attr(type='gate')
     def test_image_share_accept(self):
         image_id = self._create_image()
-        resp, member = self.os_img_client.add_member(image_id,
-                                                     self.alt_tenant_id)
-        self.assertEqual(200, resp.status)
+        _, member = self.os_img_client.add_member(image_id,
+                                                  self.alt_tenant_id)
         self.assertEqual(member['member_id'], self.alt_tenant_id)
         self.assertEqual(member['image_id'], image_id)
         self.assertEqual(member['status'], 'pending')
@@ -31,8 +30,7 @@
                                                  self.alt_tenant_id,
                                                  'accepted')
         self.assertIn(image_id, self._list_image_ids_as_alt())
-        resp, body = self.os_img_client.get_image_membership(image_id)
-        self.assertEqual(200, resp.status)
+        _, body = self.os_img_client.get_image_membership(image_id)
         members = body['members']
         member = members[0]
         self.assertEqual(len(members), 1, str(members))
@@ -43,17 +41,15 @@
     @test.attr(type='gate')
     def test_image_share_reject(self):
         image_id = self._create_image()
-        resp, member = self.os_img_client.add_member(image_id,
-                                                     self.alt_tenant_id)
-        self.assertEqual(200, resp.status)
+        _, member = self.os_img_client.add_member(image_id,
+                                                  self.alt_tenant_id)
         self.assertEqual(member['member_id'], self.alt_tenant_id)
         self.assertEqual(member['image_id'], image_id)
         self.assertEqual(member['status'], 'pending')
         self.assertNotIn(image_id, self._list_image_ids_as_alt())
-        resp, _ = self.alt_img_client.update_member_status(image_id,
-                                                           self.alt_tenant_id,
-                                                           'rejected')
-        self.assertEqual(200, resp.status)
+        self.alt_img_client.update_member_status(image_id,
+                                                 self.alt_tenant_id,
+                                                 'rejected')
         self.assertNotIn(image_id, self._list_image_ids_as_alt())
 
     @test.attr(type='gate')
@@ -66,9 +62,8 @@
                                                  'accepted')
 
         self.assertIn(image_id, self._list_image_ids_as_alt())
-        resp, member = self.os_img_client.get_member(image_id,
-                                                     self.alt_tenant_id)
-        self.assertEqual(200, resp.status)
+        _, member = self.os_img_client.get_member(image_id,
+                                                  self.alt_tenant_id)
         self.assertEqual(self.alt_tenant_id, member['member_id'])
         self.assertEqual(image_id, member['image_id'])
         self.assertEqual('accepted', member['status'])
@@ -83,18 +78,15 @@
                                                  'accepted')
 
         self.assertIn(image_id, self._list_image_ids_as_alt())
-        resp = self.os_img_client.remove_member(image_id, self.alt_tenant_id)
-        self.assertEqual(204, resp.status)
+        self.os_img_client.remove_member(image_id, self.alt_tenant_id)
         self.assertNotIn(image_id, self._list_image_ids_as_alt())
 
     @test.attr(type='gate')
     def test_get_image_member_schema(self):
-        resp, body = self.os_img_client.get_schema("member")
-        self.assertEqual(200, resp.status)
+        _, body = self.os_img_client.get_schema("member")
         self.assertEqual("member", body['name'])
 
     @test.attr(type='gate')
     def test_get_image_members_schema(self):
-        resp, body = self.os_img_client.get_schema("members")
-        self.assertEqual(200, resp.status)
+        _, body = self.os_img_client.get_schema("members")
         self.assertEqual("members", body['name'])
diff --git a/tempest/api/image/v2/test_images_member_negative.py b/tempest/api/image/v2/test_images_member_negative.py
index 98ef649..7da6e65 100644
--- a/tempest/api/image/v2/test_images_member_negative.py
+++ b/tempest/api/image/v2/test_images_member_negative.py
@@ -21,8 +21,8 @@
     @test.attr(type=['negative', 'gate'])
     def test_image_share_invalid_status(self):
         image_id = self._create_image()
-        resp, member = self.os_img_client.add_member(image_id,
-                                                     self.alt_tenant_id)
+        _, member = self.os_img_client.add_member(image_id,
+                                                  self.alt_tenant_id)
         self.assertEqual(member['status'], 'pending')
         self.assertRaises(exceptions.BadRequest,
                           self.alt_img_client.update_member_status,
@@ -31,8 +31,8 @@
     @test.attr(type=['negative', 'gate'])
     def test_image_share_owner_cannot_accept(self):
         image_id = self._create_image()
-        resp, member = self.os_img_client.add_member(image_id,
-                                                     self.alt_tenant_id)
+        _, member = self.os_img_client.add_member(image_id,
+                                                  self.alt_tenant_id)
         self.assertEqual(member['status'], 'pending')
         self.assertNotIn(image_id, self._list_image_ids_as_alt())
         self.assertRaises(exceptions.Unauthorized,
diff --git a/tempest/api/image/v2/test_images_negative.py b/tempest/api/image/v2/test_images_negative.py
index 27ba39c..722929e 100644
--- a/tempest/api/image/v2/test_images_negative.py
+++ b/tempest/api/image/v2/test_images_negative.py
@@ -52,11 +52,10 @@
     def test_get_delete_deleted_image(self):
         # get and delete the deleted image
         # create and delete image
-        resp, body = self.client.create_image(name='test',
-                                              container_format='bare',
-                                              disk_format='raw')
+        _, body = self.client.create_image(name='test',
+                                           container_format='bare',
+                                           disk_format='raw')
         image_id = body['id']
-        self.assertEqual(201, resp.status)
         self.client.delete_image(image_id)
         self.client.wait_for_resource_deletion(image_id)
 
diff --git a/tempest/api/image/v2/test_images_tags.py b/tempest/api/image/v2/test_images_tags.py
index dec3353..a9db24b 100644
--- a/tempest/api/image/v2/test_images_tags.py
+++ b/tempest/api/image/v2/test_images_tags.py
@@ -21,23 +21,19 @@
 
     @test.attr(type='gate')
     def test_update_delete_tags_for_image(self):
-        resp, body = self.create_image(container_format='bare',
-                                       disk_format='raw',
-                                       visibility='private')
+        _, body = self.create_image(container_format='bare',
+                                    disk_format='raw',
+                                    visibility='private')
         image_id = body['id']
         tag = data_utils.rand_name('tag-')
         self.addCleanup(self.client.delete_image, image_id)
 
         # Creating image tag and verify it.
-        resp, body = self.client.add_image_tag(image_id, tag)
-        self.assertEqual(resp.status, 204)
-        resp, body = self.client.get_image(image_id)
-        self.assertEqual(resp.status, 200)
+        self.client.add_image_tag(image_id, tag)
+        _, body = self.client.get_image(image_id)
         self.assertIn(tag, body['tags'])
 
         # Deleting image tag and verify it.
-        resp = self.client.delete_image_tag(image_id, tag)
-        self.assertEqual(resp.status, 204)
-        resp, body = self.client.get_image(image_id)
-        self.assertEqual(resp.status, 200)
+        self.client.delete_image_tag(image_id, tag)
+        _, body = self.client.get_image(image_id)
         self.assertNotIn(tag, body['tags'])
diff --git a/tempest/api/image/v2/test_images_tags_negative.py b/tempest/api/image/v2/test_images_tags_negative.py
index 13cfa0a..8e42b7c 100644
--- a/tempest/api/image/v2/test_images_tags_negative.py
+++ b/tempest/api/image/v2/test_images_tags_negative.py
@@ -33,10 +33,10 @@
     @test.attr(type=['negative', 'gate'])
     def test_delete_non_existing_tag(self):
         # Delete non existing tag.
-        resp, body = self.create_image(container_format='bare',
-                                       disk_format='raw',
-                                       visibility='private'
-                                       )
+        _, body = self.create_image(container_format='bare',
+                                    disk_format='raw',
+                                    visibility='private'
+                                    )
         image_id = body['id']
         tag = data_utils.rand_name('non-exist-tag-')
         self.addCleanup(self.client.delete_image, image_id)
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index a307986..9fa54b1 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -46,8 +46,7 @@
             raise cls.skipException(msg)
         cls.identity_admin_client = cls.os_adm.identity_client
 
-    @test.attr(type='gate')
-    def test_quotas(self):
+    def _check_quotas(self, new_quotas):
         # Add a tenant to conduct the test
         test_tenant = data_utils.rand_name('test_tenant_')
         test_description = data_utils.rand_name('desc_')
@@ -56,14 +55,15 @@
             description=test_description)
         tenant_id = tenant['id']
         self.addCleanup(self.identity_admin_client.delete_tenant, tenant_id)
+
         # Change quotas for tenant
-        new_quotas = {'network': 0, 'security_group': 0}
         resp, quota_set = self.admin_client.update_quotas(tenant_id,
                                                           **new_quotas)
         self.assertEqual('200', resp['status'])
         self.addCleanup(self.admin_client.reset_quotas, tenant_id)
-        self.assertEqual(0, quota_set['network'])
-        self.assertEqual(0, quota_set['security_group'])
+        for key, value in new_quotas.iteritems():
+            self.assertEqual(value, quota_set[key])
+
         # Confirm our tenant is listed among tenants with non default quotas
         resp, non_default_quotas = self.admin_client.list_quotas()
         self.assertEqual('200', resp['status'])
@@ -72,12 +72,14 @@
             if qs['tenant_id'] == tenant_id:
                 found = True
         self.assertTrue(found)
-        # Confirm from APi quotas were changed as requested for tenant
+
+        # Confirm from API quotas were changed as requested for tenant
         resp, quota_set = self.admin_client.show_quotas(tenant_id)
         quota_set = quota_set['quota']
         self.assertEqual('200', resp['status'])
-        self.assertEqual(0, quota_set['network'])
-        self.assertEqual(0, quota_set['security_group'])
+        for key, value in new_quotas.iteritems():
+            self.assertEqual(value, quota_set[key])
+
         # Reset quotas to default and confirm
         resp, body = self.admin_client.reset_quotas(tenant_id)
         self.assertEqual('204', resp['status'])
@@ -85,3 +87,15 @@
         self.assertEqual('200', resp['status'])
         for q in non_default_quotas['quotas']:
             self.assertNotEqual(tenant_id, q['tenant_id'])
+
+    @test.attr(type='gate')
+    def test_quotas(self):
+        new_quotas = {'network': 0, 'security_group': 0}
+        self._check_quotas(new_quotas)
+
+    @test.requires_ext(extension='lbaas', service='network')
+    @test.attr(type='gate')
+    def test_lbaas_quotas(self):
+        new_quotas = {'vip': 1, 'pool': 2,
+                      'member': 3, 'health_monitor': 4}
+        self._check_quotas(new_quotas)
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index cc768fd..087b87a 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -149,7 +149,8 @@
         return network
 
     @classmethod
-    def create_subnet(cls, network, gateway=None, cidr=None, mask_bits=None):
+    def create_subnet(cls, network, gateway=None, cidr=None, mask_bits=None,
+                      **kwargs):
         """Wrapper utility that returns a test subnet."""
         # The cidr and mask_bits depend on the ip version.
         if cls._ip_version == 4:
@@ -168,7 +169,8 @@
                     network_id=network['id'],
                     cidr=str(subnet_cidr),
                     ip_version=cls._ip_version,
-                    gateway_ip=gateway)
+                    gateway_ip=gateway,
+                    **kwargs)
                 break
             except exceptions.BadRequest as e:
                 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
diff --git a/tempest/api/network/test_allowed_address_pair.py b/tempest/api/network/test_allowed_address_pair.py
index e0e26da..c897716 100644
--- a/tempest/api/network/test_allowed_address_pair.py
+++ b/tempest/api/network/test_allowed_address_pair.py
@@ -70,6 +70,27 @@
         self.assertTrue(port, msg)
         self._confirm_allowed_address_pair(port[0], self.ip_address)
 
+    @test.attr(type='smoke')
+    def test_update_port_with_address_pair(self):
+        # Create a port without allowed address pair
+        resp, body = self.client.create_port(network_id=self.network['id'])
+        self.assertEqual('201', resp['status'])
+        port_id = body['port']['id']
+        self.addCleanup(self.client.delete_port, port_id)
+
+        # Confirm  port is created
+        resp, body = self.client.show_port(port_id)
+        self.assertEqual('200', resp['status'])
+
+        # Update allowed address pair attribute of port
+        allowed_address_pairs = [{'ip_address': self.ip_address,
+                                  'mac_address': self.mac_address}]
+        resp, body = self.client.update_port(port_id,
+                          allowed_address_pairs=allowed_address_pairs)
+        self.assertEqual('200', resp['status'])
+        newport = body['port']
+        self._confirm_allowed_address_pair(newport, self.ip_address)
+
     def _confirm_allowed_address_pair(self, port, ip):
         msg = 'Port allowed address pairs should not be empty'
         self.assertTrue(port['allowed_address_pairs'], msg)
diff --git a/tempest/api/network/test_load_balancer.py b/tempest/api/network/test_load_balancer.py
index 673fc47..db24e0d 100644
--- a/tempest/api/network/test_load_balancer.py
+++ b/tempest/api/network/test_load_balancer.py
@@ -259,7 +259,7 @@
         self.assertEqual('200', resp['status'])
         member = body['member']
         for key, value in member.iteritems():
-             # 'status' should not be confirmed in api tests
+            # 'status' should not be confirmed in api tests
             if key != 'status':
                 self.assertEqual(self.member[key], value)
 
@@ -340,7 +340,7 @@
         self.assertEqual('200', resp['status'])
         health_monitor = body['health_monitor']
         for key, value in health_monitor.iteritems():
-             # 'status' should not be confirmed in api tests
+            # 'status' should not be confirmed in api tests
             if key != 'status':
                 self.assertEqual(self.health_monitor[key], value)
 
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index ac0fd11..ac3a072 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 import netaddr
+import testtools
 
 from tempest.api.network import base
 from tempest.common.utils import data_utils
@@ -276,13 +277,6 @@
         block defined by tenant-network_cidr
     """
 
-    @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(BulkNetworkOpsTestJSON, cls).setUpClass()
-        cls.network1 = cls.create_network()
-        cls.network2 = cls.create_network()
-
     def _delete_networks(self, created_networks):
         for n in created_networks:
             resp, body = self.client.delete_network(n['id'])
@@ -331,11 +325,11 @@
 
     @test.attr(type='smoke')
     def test_bulk_create_delete_subnet(self):
+        networks = [self.create_network(), self.create_network()]
         # Creates 2 subnets in one request
         cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
         mask_bits = CONF.network.tenant_network_mask_bits
         cidrs = [subnet_cidr for subnet_cidr in cidr.subnet(mask_bits)]
-        networks = [self.network1['id'], self.network2['id']]
         names = [data_utils.rand_name('subnet-') for i in range(len(networks))]
         subnets_list = []
         # TODO(raies): "for IPv6, version list [4, 6] will be used.
@@ -343,7 +337,7 @@
         ip_version = [4, 4]
         for i in range(len(names)):
             p1 = {
-                'network_id': networks[i],
+                'network_id': networks[i]['id'],
                 'cidr': str(cidrs[(i)]),
                 'name': names[i],
                 'ip_version': ip_version[i]
@@ -363,14 +357,14 @@
 
     @test.attr(type='smoke')
     def test_bulk_create_delete_port(self):
+        networks = [self.create_network(), self.create_network()]
         # Creates 2 ports in one request
-        networks = [self.network1['id'], self.network2['id']]
         names = [data_utils.rand_name('port-') for i in range(len(networks))]
         port_list = []
         state = [True, False]
         for i in range(len(names)):
             p1 = {
-                'network_id': networks[i],
+                'network_id': networks[i]['id'],
                 'name': names[i],
                 'admin_state_up': state[i],
             }
@@ -433,6 +427,29 @@
         self.assertEqual('204', resp['status'])
         self.subnets.pop()
 
+    @testtools.skipUnless(CONF.network_feature_enabled.ipv6_subnet_attributes,
+                          "IPv6 extended attributes for subnets not "
+                          "available")
+    @test.attr(type='smoke')
+    def test_create_delete_subnet_with_v6_attributes(self):
+        name = data_utils.rand_name('network-')
+        resp, body = self.client.create_network(name=name)
+        self.assertEqual('201', resp['status'])
+        network = body['network']
+        net_id = network['id']
+        subnet = self.create_subnet(network,
+                                    gateway='fe80::1',
+                                    ipv6_ra_mode='slaac',
+                                    ipv6_address_mode='slaac')
+        # Verifies Subnet GW in IPv6
+        self.assertEqual(subnet['gateway_ip'], 'fe80::1')
+        self.assertEqual(subnet['ipv6_ra_mode'], 'slaac')
+        self.assertEqual(subnet['ipv6_address_mode'], 'slaac')
+        # Delete network and subnet
+        resp, body = self.client.delete_network(net_id)
+        self.assertEqual('204', resp['status'])
+        self.subnets.pop()
+
 
 class NetworksIpV6TestXML(NetworksIpV6TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index 0b86398..53c9d12 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -55,7 +55,7 @@
     def test_create_security_group_rule_with_bad_protocol(self):
         group_create_body, _ = self._create_security_group()
 
-        #Create rule with bad protocol name
+        # Create rule with bad protocol name
         pname = 'bad_protocol_name'
         self.assertRaises(
             exceptions.BadRequest, self.client.create_security_group_rule,
@@ -66,7 +66,7 @@
     def test_create_security_group_rule_with_invalid_ports(self):
         group_create_body, _ = self._create_security_group()
 
-        #Create rule with invalid ports
+        # Create rule with invalid ports
         states = [(-16, 80, 'Invalid value for port -16'),
                   (80, 79, 'port_range_min must be <= port_range_max'),
                   (80, 65536, 'Invalid value for port 65536'),
diff --git a/tempest/api/network/test_vpnaas_extensions.py b/tempest/api/network/test_vpnaas_extensions.py
index d1fe15c..0cc3f19 100644
--- a/tempest/api/network/test_vpnaas_extensions.py
+++ b/tempest/api/network/test_vpnaas_extensions.py
@@ -22,19 +22,15 @@
 CONF = config.CONF
 
 
-class VPNaaSTestJSON(base.BaseNetworkTest):
+class VPNaaSTestJSON(base.BaseAdminNetworkTest):
     _interface = 'json'
 
     """
     Tests the following operations in the Neutron API using the REST client for
     Neutron:
-
-        List VPN Services
-        Show VPN Services
-        Create VPN Services
-        Update VPN Services
-        Delete VPN Services
+        List, Show, Create, Delete, and Update VPN Service
         List, Show, Create, Delete, and Update IKE policy
+        List, Show, Create, Delete, and Update IPSec policy
     """
 
     @classmethod
@@ -47,11 +43,12 @@
         cls.network = cls.create_network()
         cls.subnet = cls.create_subnet(cls.network)
         cls.router = cls.create_router(
-            data_utils.rand_name("router-"),
+            data_utils.rand_name("router"),
             external_network_id=CONF.network.public_network_id)
         cls.create_router_interface(cls.router['id'], cls.subnet['id'])
         cls.vpnservice = cls.create_vpnservice(cls.subnet['id'],
                                                cls.router['id'])
+
         cls.ikepolicy = cls.create_ikepolicy(
             data_utils.rand_name("ike-policy-"))
         cls.ipsecpolicy = cls.create_ipsecpolicy(
@@ -87,6 +84,85 @@
             self.assertIn(key, actual)
             self.assertEqual(value, actual[key])
 
+    def _delete_vpn_service(self, vpn_service_id):
+        resp, _ = self.client.delete_vpnservice(vpn_service_id)
+        self.assertEqual('204', resp['status'])
+        # Asserting if vpn service is found in the list after deletion
+        _, body = self.client.list_vpnservices()
+        vpn_services = [vs['id'] for vs in body['vpnservices']]
+        self.assertNotIn(vpn_service_id, vpn_services)
+
+    def _get_tenant_id(self):
+        """
+        Returns the tenant_id of the client current user
+        """
+        # TODO(jroovers) This is a temporary workaround to get the tenant_id
+        # of the the current client. Replace this once tenant_isolation for
+        # neutron is fixed.
+        _, body = self.client.show_network(self.network['id'])
+        return body['network']['tenant_id']
+
+    @test.attr(type='smoke')
+    def test_admin_create_ipsec_policy_for_tenant(self):
+        tenant_id = self._get_tenant_id()
+        # Create IPSec policy for the newly created tenant
+        name = data_utils.rand_name('ipsec-policy')
+        resp, body = (self.admin_client.
+                      create_ipsecpolicy(name=name, tenant_id=tenant_id))
+        self.assertEqual('201', resp['status'])
+        ipsecpolicy = body['ipsecpolicy']
+        self.assertIsNotNone(ipsecpolicy['id'])
+        self.addCleanup(self.admin_client.delete_ipsecpolicy,
+                        ipsecpolicy['id'])
+
+        # Assert that created ipsec policy is found in API list call
+        _, body = self.client.list_ipsecpolicies()
+        ipsecpolicies = [policy['id'] for policy in body['ipsecpolicies']]
+        self.assertIn(ipsecpolicy['id'], ipsecpolicies)
+
+    @test.attr(type='smoke')
+    def test_admin_create_vpn_service_for_tenant(self):
+        tenant_id = self._get_tenant_id()
+
+        # Create vpn service for the newly created tenant
+        name = data_utils.rand_name('vpn-service')
+        resp, body = self.admin_client.create_vpnservice(
+            subnet_id=self.subnet['id'],
+            router_id=self.router['id'],
+            name=name,
+            admin_state_up=True,
+            tenant_id=tenant_id)
+        self.assertEqual('201', resp['status'])
+        vpnservice = body['vpnservice']
+        self.assertIsNotNone(vpnservice['id'])
+        self.addCleanup(self.admin_client.delete_vpnservice, vpnservice['id'])
+
+        # Assert that created vpnservice is found in API list call
+        _, body = self.client.list_vpnservices()
+        vpn_services = [vs['id'] for vs in body['vpnservices']]
+        self.assertIn(vpnservice['id'], vpn_services)
+
+    @test.attr(type='smoke')
+    def test_admin_create_ike_policy_for_tenant(self):
+        tenant_id = self._get_tenant_id()
+
+        # Create IKE policy for the newly created tenant
+        name = data_utils.rand_name('ike-policy')
+        resp, body = (self.admin_client.
+                      create_ikepolicy(name=name, ike_version="v1",
+                                       encryption_algorithm="aes-128",
+                                       auth_algorithm="sha1",
+                                       tenant_id=tenant_id))
+        self.assertEqual('201', resp['status'])
+        ikepolicy = body['ikepolicy']
+        self.assertIsNotNone(ikepolicy['id'])
+        self.addCleanup(self.admin_client.delete_ikepolicy, ikepolicy['id'])
+
+        # Assert that created ike policy is found in API list call
+        _, body = self.client.list_ikepolicies()
+        ikepolicies = [ikp['id'] for ikp in body['ikepolicies']]
+        self.assertIn(ikepolicy['id'], ikepolicies)
+
     @test.attr(type='smoke')
     def test_list_vpn_services(self):
         # Verify the VPN service exists in the list of all VPN services
@@ -97,14 +173,15 @@
 
     @test.attr(type='smoke')
     def test_create_update_delete_vpn_service(self):
-        # Creates a VPN service
-        name = data_utils.rand_name('vpn-service-')
+        # Creates a VPN service and sets up deletion
+        name = data_utils.rand_name('vpn-service')
         resp, body = self.client.create_vpnservice(subnet_id=self.subnet['id'],
                                                    router_id=self.router['id'],
                                                    name=name,
                                                    admin_state_up=True)
         self.assertEqual('201', resp['status'])
         vpnservice = body['vpnservice']
+        self.addCleanup(self._delete_vpn_service, vpnservice['id'])
         # Assert if created vpnservices are not found in vpnservices list
         resp, body = self.client.list_vpnservices()
         vpn_services = [vs['id'] for vs in body['vpnservices']]
@@ -116,14 +193,6 @@
         # But precondition is that current state of vpnservice
         # should be "ACTIVE" not "PENDING*"
 
-        # Verification of vpn service delete
-        resp, body = self.client.delete_vpnservice(vpnservice['id'])
-        self.assertEqual('204', resp['status'])
-        # Asserting if vpn service is found in the list after deletion
-        resp, body = self.client.list_vpnservices()
-        vpn_services = [vs['id'] for vs in body['vpnservices']]
-        self.assertNotIn(vpnservice['id'], vpn_services)
-
     @test.attr(type='smoke')
     def test_show_vpn_service(self):
         # Verifies the details of a vpn service
@@ -137,6 +206,9 @@
         self.assertEqual(self.vpnservice['router_id'], vpnservice['router_id'])
         self.assertEqual(self.vpnservice['subnet_id'], vpnservice['subnet_id'])
         self.assertEqual(self.vpnservice['tenant_id'], vpnservice['tenant_id'])
+        valid_status = ["ACTIVE", "DOWN", "BUILD", "ERROR", "PENDING_CREATE",
+                        "PENDING_UPDATE", "PENDING_DELETE"]
+        self.assertIn(vpnservice['status'], valid_status)
 
     @test.attr(type='smoke')
     def test_list_ike_policies(self):
@@ -149,7 +221,7 @@
     @test.attr(type='smoke')
     def test_create_update_delete_ike_policy(self):
         # Creates a IKE policy
-        name = data_utils.rand_name('ike-policy-')
+        name = data_utils.rand_name('ike-policy')
         resp, body = (self.client.create_ikepolicy(
                       name=name,
                       ike_version="v1",
@@ -157,19 +229,31 @@
                       auth_algorithm="sha1"))
         self.assertEqual('201', resp['status'])
         ikepolicy = body['ikepolicy']
+        self.assertIsNotNone(ikepolicy['id'])
         self.addCleanup(self._delete_ike_policy, ikepolicy['id'])
-        # Verification of ike policy update
-        description = "Updated ike policy"
-        new_ike = {'description': description, 'pfs': 'group5',
-                   'name': data_utils.rand_name("New-IKE-")}
-        resp, body = self.client.update_ikepolicy(ikepolicy['id'],
-                                                  **new_ike)
+
+        # Update IKE Policy
+        new_ike = {'name': data_utils.rand_name("New-IKE"),
+                   'description': "Updated ike policy",
+                   'encryption_algorithm': "aes-256",
+                   'ike_version': "v2",
+                   'pfs': "group14",
+                   'lifetime': {'units': "seconds", 'value': 2000}}
+        resp, _ = self.client.update_ikepolicy(ikepolicy['id'], **new_ike)
         self.assertEqual('200', resp['status'])
-        updated_ike_policy = body['ikepolicy']
-        self.assertEqual(updated_ike_policy['description'], description)
+        # Confirm that update was successful by verifying using 'show'
+        _, body = self.client.show_ikepolicy(ikepolicy['id'])
+        ike_policy = body['ikepolicy']
+        for key, value in new_ike.iteritems():
+            self.assertIn(key, ike_policy)
+            self.assertEqual(value, ike_policy[key])
+
         # Verification of ike policy delete
-        resp, body = self.client.delete_ikepolicy(ikepolicy['id'])
+        resp, _ = self.client.delete_ikepolicy(ikepolicy['id'])
         self.assertEqual('204', resp['status'])
+        _, body = self.client.list_ikepolicies()
+        ikepolicies = [ikp['id'] for ikp in body['ikepolicies']]
+        self.assertNotIn(ike_policy['id'], ikepolicies)
 
     @test.attr(type='smoke')
     def test_show_ike_policy(self):
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index 6b18182..ccc0067 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -44,9 +44,6 @@
                 cls.isolated_creds.get_admin_creds())
             # Get isolated creds for alt user
             cls.os_alt = clients.Manager(cls.isolated_creds.get_alt_creds())
-            # Add isolated users to operator role so that they can create a
-            # container in swift.
-            cls._assign_member_role()
         else:
             cls.os = clients.Manager()
             cls.os_admin = clients.AdminManager()
@@ -80,22 +77,6 @@
         super(BaseObjectTest, cls).tearDownClass()
 
     @classmethod
-    def _assign_member_role(cls):
-        primary_creds = cls.isolated_creds.get_primary_creds()
-        alt_creds = cls.isolated_creds.get_alt_creds()
-        swift_role = CONF.object_storage.operator_role
-        try:
-            resp, roles = cls.os_admin.identity_client.list_roles()
-            role = next(r for r in roles if r['name'] == swift_role)
-        except StopIteration:
-            msg = "No role named %s found" % swift_role
-            raise exceptions.NotFound(msg)
-        for creds in [primary_creds, alt_creds]:
-            cls.os_admin.identity_client.assign_user_role(creds.tenant_id,
-                                                          creds.user_id,
-                                                          role['id'])
-
-    @classmethod
     def delete_containers(cls, containers, container_client=None,
                           object_client=None):
         """Remove given containers and all objects in them.
diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py
index 53ca20d..73b4f3b 100644
--- a/tempest/api/object_storage/test_object_expiry.py
+++ b/tempest/api/object_storage/test_object_expiry.py
@@ -54,14 +54,18 @@
         self.assertEqual(resp['status'], '200')
         self.assertHeaders(resp, 'Object', 'HEAD')
         self.assertIn('x-delete-at', resp)
+        # we want to ensure that we will sleep long enough for things to
+        # actually expire, so figure out how many secs in the future that is.
+        sleepy_time = int(resp['x-delete-at']) - int(time.time())
+
         resp, body = self.object_client.get_object(self.container_name,
                                                    self.object_name)
         self.assertEqual(resp['status'], '200')
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertIn('x-delete-at', resp)
 
-        # sleep for over 5 seconds, so that object expires
-        time.sleep(5)
+        # add a couple of seconds for safety.
+        time.sleep(sleepy_time + 3)
 
         # object should not be there anymore
         self.assertRaises(exceptions.NotFound, self.object_client.get_object,
@@ -69,10 +73,12 @@
 
     @test.attr(type='gate')
     def test_get_object_after_expiry_time(self):
-        metadata = {'X-Delete-After': '3'}
+        # the 10s is important, because the get calls can take 3s each
+        # some times
+        metadata = {'X-Delete-After': '10'}
         self._test_object_expiry(metadata)
 
     @test.attr(type='gate')
     def test_get_object_at_expiry_time(self):
-        metadata = {'X-Delete-At': str(int(time.time()) + 3)}
+        metadata = {'X-Delete-At': str(int(time.time()) + 10)}
         self._test_object_expiry(metadata)
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 06e63a4..1ef9aa1 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -13,11 +13,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import cStringIO as StringIO
 import hashlib
 import random
 import re
 from six import moves
 import time
+import zlib
 
 from tempest.api.object_storage import base
 from tempest.common import custom_matchers
@@ -61,7 +63,7 @@
 
         return object_name, data_segments
 
-    @test.attr(type='smoke')
+    @test.attr(type='gate')
     def test_create_object(self):
         # create object
         object_name = data_utils.rand_name(name='TestObject')
@@ -76,7 +78,242 @@
         self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
 
-    @test.attr(type='smoke')
+        # check uploaded content
+        _, body = self.object_client.get_object(self.container_name,
+                                                object_name)
+        self.assertEqual(data, body)
+
+    @test.attr(type='gate')
+    def test_create_object_with_content_disposition(self):
+        # create object with content_disposition
+        object_name = data_utils.rand_name(name='TestObject')
+        data = data_utils.arbitrary_string()
+        metadata = {}
+        metadata['content-disposition'] = 'inline'
+        resp, _ = self.object_client.create_object(
+            self.container_name,
+            object_name,
+            data,
+            metadata=metadata)
+        self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
+
+        resp, body = self.object_client.get_object(
+            self.container_name,
+            object_name,
+            metadata=None)
+        self.assertIn('content-disposition', resp)
+        self.assertEqual(resp['content-disposition'], 'inline')
+        self.assertEqual(body, data)
+
+    @test.attr(type='gate')
+    def test_create_object_with_content_encoding(self):
+        # create object with content_encoding
+        object_name = data_utils.rand_name(name='TestObject')
+
+        # put compressed string
+        data_before = 'x' * 2000
+        data = zlib.compress(data_before)
+        metadata = {}
+        metadata['content-encoding'] = 'deflate'
+
+        resp, _ = self.object_client.create_object(
+            self.container_name,
+            object_name,
+            data,
+            metadata=metadata)
+        self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
+
+        # download compressed object
+        metadata = {}
+        metadata['accept-encoding'] = 'deflate'
+        resp, body = self.object_client.get_object(
+            self.container_name,
+            object_name,
+            metadata=metadata)
+        self.assertEqual(body, data_before)
+
+    @test.attr(type='gate')
+    def test_create_object_with_etag(self):
+        # create object with etag
+        object_name = data_utils.rand_name(name='TestObject')
+        data = data_utils.arbitrary_string()
+        md5 = hashlib.md5(data).hexdigest()
+        metadata = {'Etag': md5}
+        resp, _ = self.object_client.create_object(
+            self.container_name,
+            object_name,
+            data,
+            metadata=metadata)
+        self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
+
+        # check uploaded content
+        _, body = self.object_client.get_object(self.container_name,
+                                                object_name)
+        self.assertEqual(data, body)
+
+    @test.attr(type='gate')
+    def test_create_object_with_expect_continue(self):
+        # create object with expect_continue
+        object_name = data_utils.rand_name(name='TestObject')
+        data = data_utils.arbitrary_string()
+        metadata = {'Expect': '100-continue'}
+        resp = self.custom_object_client.create_object_continue(
+            self.container_name,
+            object_name,
+            data,
+            metadata=metadata)
+
+        self.assertIn('status', resp)
+        self.assertEqual(resp['status'], '100')
+
+        self.custom_object_client.create_object_continue(
+            self.container_name,
+            object_name,
+            data,
+            metadata=None)
+
+        # check uploaded content
+        _, body = self.object_client.get_object(self.container_name,
+                                                object_name)
+        self.assertEqual(data, body)
+
+    @test.attr(type='gate')
+    def test_create_object_with_transfer_encoding(self):
+        # create object with transfer_encoding
+        object_name = data_utils.rand_name(name='TestObject')
+        data = data_utils.arbitrary_string(1024)
+        status, _, resp_headers = self.object_client.put_object_with_chunk(
+            container=self.container_name,
+            name=object_name,
+            contents=StringIO.StringIO(data),
+            chunk_size=512)
+        self.assertEqual(status, 201)
+        self.assertHeaders(resp_headers, 'Object', 'PUT')
+
+        # check uploaded content
+        _, body = self.object_client.get_object(self.container_name,
+                                                object_name)
+        self.assertEqual(data, body)
+
+    @test.attr(type='gate')
+    def test_create_object_with_x_fresh_metadata(self):
+        # create object with x_fresh_metadata
+        object_name_base = data_utils.rand_name(name='TestObject')
+        data = data_utils.arbitrary_string()
+        metadata_1 = {'X-Object-Meta-test-meta': 'Meta'}
+        self.object_client.create_object(self.container_name,
+                                         object_name_base,
+                                         data,
+                                         metadata=metadata_1)
+        object_name = data_utils.rand_name(name='TestObject')
+        metadata_2 = {'X-Copy-From': '%s/%s' % (self.container_name,
+                                                object_name_base),
+                      'X-Fresh-Metadata': 'true'}
+        resp, _ = self.object_client.create_object(
+            self.container_name,
+            object_name,
+            '',
+            metadata=metadata_2)
+        self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
+
+        resp, body = self.object_client.get_object(self.container_name,
+                                                   object_name)
+        self.assertNotIn('x-object-meta-test-meta', resp)
+        self.assertEqual(data, body)
+
+    @test.attr(type='gate')
+    def test_create_object_with_x_object_meta(self):
+        # create object with object_meta
+        object_name = data_utils.rand_name(name='TestObject')
+        data = data_utils.arbitrary_string()
+        metadata = {'X-Object-Meta-test-meta': 'Meta'}
+        resp, _ = self.object_client.create_object(
+            self.container_name,
+            object_name,
+            data,
+            metadata=metadata)
+        self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
+
+        resp, body = self.object_client.get_object(self.container_name,
+                                                   object_name)
+        self.assertIn('x-object-meta-test-meta', resp)
+        self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
+        self.assertEqual(data, body)
+
+    @test.attr(type='gate')
+    def test_create_object_with_x_object_metakey(self):
+        # create object with the blank value of metadata
+        object_name = data_utils.rand_name(name='TestObject')
+        data = data_utils.arbitrary_string()
+        metadata = {'X-Object-Meta-test-meta': ''}
+        resp, _ = self.object_client.create_object(
+            self.container_name,
+            object_name,
+            data,
+            metadata=metadata)
+        self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
+
+        resp, body = self.object_client.get_object(self.container_name,
+                                                   object_name)
+        self.assertIn('x-object-meta-test-meta', resp)
+        self.assertEqual(resp['x-object-meta-test-meta'], '')
+        self.assertEqual(data, body)
+
+    @test.attr(type='gate')
+    def test_create_object_with_x_remove_object_meta(self):
+        # create object with x_remove_object_meta
+        object_name = data_utils.rand_name(name='TestObject')
+        data = data_utils.arbitrary_string()
+        metadata_add = {'X-Object-Meta-test-meta': 'Meta'}
+        self.object_client.create_object(self.container_name,
+                                         object_name,
+                                         data,
+                                         metadata=metadata_add)
+        metadata_remove = {'X-Remove-Object-Meta-test-meta': 'Meta'}
+        resp, _ = self.object_client.create_object(
+            self.container_name,
+            object_name,
+            data,
+            metadata=metadata_remove)
+        self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
+
+        resp, body = self.object_client.get_object(self.container_name,
+                                                   object_name)
+        self.assertNotIn('x-object-meta-test-meta', resp)
+        self.assertEqual(data, body)
+
+    @test.attr(type='gate')
+    def test_create_object_with_x_remove_object_metakey(self):
+        # create object with the blank value of remove metadata
+        object_name = data_utils.rand_name(name='TestObject')
+        data = data_utils.arbitrary_string()
+        metadata_add = {'X-Object-Meta-test-meta': 'Meta'}
+        self.object_client.create_object(self.container_name,
+                                         object_name,
+                                         data,
+                                         metadata=metadata_add)
+        metadata_remove = {'X-Remove-Object-Meta-test-meta': ''}
+        resp, _ = self.object_client.create_object(
+            self.container_name,
+            object_name,
+            data,
+            metadata=metadata_remove)
+        self.assertEqual(resp['status'], '201')
+        self.assertHeaders(resp, 'Object', 'PUT')
+
+        resp, body = self.object_client.get_object(self.container_name,
+                                                   object_name)
+        self.assertNotIn('x-object-meta-test-meta', resp)
+        self.assertEqual(data, body)
+
+    @test.attr(type='gate')
     def test_delete_object(self):
         # create object
         object_name = data_utils.rand_name(name='TestObject')
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
index 446f4ab..531df2d 100644
--- a/tempest/api/orchestration/base.py
+++ b/tempest/api/orchestration/base.py
@@ -11,6 +11,7 @@
 #    under the License.
 
 import os.path
+import yaml
 
 from tempest import clients
 from tempest.common.utils import data_utils
@@ -84,11 +85,8 @@
                 pass
 
         for stack_identifier in cls.stacks:
-            try:
-                cls.client.wait_for_stack_status(
-                    stack_identifier, 'DELETE_COMPLETE')
-            except exceptions.NotFound:
-                pass
+            cls.client.wait_for_stack_status(
+                stack_identifier, 'DELETE_COMPLETE')
 
     @classmethod
     def _create_keypair(cls, name_start='keypair-heat-'):
@@ -125,7 +123,7 @@
                 pass
 
     @classmethod
-    def load_template(cls, name, ext='yaml'):
+    def read_template(cls, name, ext='yaml'):
         loc = ["stacks", "templates", "%s.%s" % (name, ext)]
         fullpath = os.path.join(os.path.dirname(__file__), *loc)
 
@@ -134,6 +132,14 @@
             return content
 
     @classmethod
+    def load_template(cls, name, ext='yaml'):
+        loc = ["stacks", "templates", "%s.%s" % (name, ext)]
+        fullpath = os.path.join(os.path.dirname(__file__), *loc)
+
+        with open(fullpath, "r") as f:
+            return yaml.safe_load(f)
+
+    @classmethod
     def tearDownClass(cls):
         cls._clear_stacks()
         cls._clear_keypairs()
diff --git a/tempest/api/orchestration/stacks/test_environment.py b/tempest/api/orchestration/stacks/test_environment.py
index 3911e72..96e1c50 100644
--- a/tempest/api/orchestration/stacks/test_environment.py
+++ b/tempest/api/orchestration/stacks/test_environment.py
@@ -28,7 +28,7 @@
     def test_environment_parameter(self):
         """Test passing a stack parameter via the environment."""
         stack_name = data_utils.rand_name('heat')
-        template = self.load_template('random_string')
+        template = self.read_template('random_string')
         environment = {'parameters': {'random_length': 20}}
 
         stack_identifier = self.create_stack(stack_name, template,
@@ -56,7 +56,7 @@
 '''
         environment = {'resource_registry':
                        {'My:Random::String': 'my_random.yaml'}}
-        files = {'my_random.yaml': self.load_template('random_string')}
+        files = {'my_random.yaml': self.read_template('random_string')}
 
         stack_identifier = self.create_stack(stack_name, template,
                                              environment=environment,
@@ -65,7 +65,10 @@
 
         # random_string.yaml specifies a length of 10
         random_value = self.get_stack_output(stack_identifier, 'random_value')
-        self.assertEqual(10, len(random_value))
+        random_string_template = self.load_template('random_string')
+        expected_length = random_string_template['parameters'][
+            'random_length']['default']
+        self.assertEqual(expected_length, len(random_value))
 
     @test.attr(type='gate')
     def test_files_provider_resource(self):
@@ -82,7 +85,7 @@
     random_value:
         value: {get_attr: [random, random_value]}
 '''
-        files = {'my_random.yaml': self.load_template('random_string')}
+        files = {'my_random.yaml': self.read_template('random_string')}
 
         stack_identifier = self.create_stack(stack_name, template,
                                              files=files)
@@ -90,4 +93,7 @@
 
         # random_string.yaml specifies a length of 10
         random_value = self.get_stack_output(stack_identifier, 'random_value')
-        self.assertEqual(10, len(random_value))
+        random_string_template = self.load_template('random_string')
+        expected_length = random_string_template['parameters'][
+            'random_length']['default']
+        self.assertEqual(expected_length, len(random_value))
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index e92b945..27c6196 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -39,7 +39,7 @@
             raise cls.skipException("Neutron support is required")
         cls.network_client = os.network_client
         cls.stack_name = data_utils.rand_name('heat')
-        template = cls.load_template('neutron_basic')
+        template = cls.read_template('neutron_basic')
         cls.keypair_name = (CONF.orchestration.keypair_name or
                             cls._create_keypair()['name'])
         cls.external_network_id = CONF.network.public_network_id
diff --git a/tempest/api/orchestration/stacks/test_non_empty_stack.py b/tempest/api/orchestration/stacks/test_non_empty_stack.py
index 585c90b..a97c561 100644
--- a/tempest/api/orchestration/stacks/test_non_empty_stack.py
+++ b/tempest/api/orchestration/stacks/test_non_empty_stack.py
@@ -28,7 +28,7 @@
     def setUpClass(cls):
         super(StacksTestJSON, cls).setUpClass()
         cls.stack_name = data_utils.rand_name('heat')
-        template = cls.load_template('non_empty_stack')
+        template = cls.read_template('non_empty_stack')
         image_id = (CONF.orchestration.image_ref or
                     cls._create_image()['id'])
         # create the stack
diff --git a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
index cb70d07..e22a08b 100644
--- a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
+++ b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
@@ -23,12 +23,14 @@
 
 class NovaKeyPairResourcesYAMLTest(base.BaseOrchestrationTest):
     _tpl_type = 'yaml'
+    _resource = 'resources'
+    _type = 'type'
 
     @classmethod
     def setUpClass(cls):
         super(NovaKeyPairResourcesYAMLTest, cls).setUpClass()
         cls.stack_name = data_utils.rand_name('heat')
-        template = cls.load_template('nova_keypair', ext=cls._tpl_type)
+        template = cls.read_template('nova_keypair', ext=cls._tpl_type)
 
         # create the stack, avoid any duplicated key.
         cls.stack_identifier = cls.create_stack(
@@ -49,8 +51,15 @@
     @test.attr(type='slow')
     def test_created_resources(self):
         """Verifies created keypair resource."""
-        resources = [('KeyPairSavePrivate', 'OS::Nova::KeyPair'),
-                     ('KeyPairDontSavePrivate', 'OS::Nova::KeyPair')]
+
+        nova_keypair_template = self.load_template('nova_keypair',
+                                                   ext=self._tpl_type)
+        resources = [('KeyPairSavePrivate',
+                      nova_keypair_template[self._resource][
+                      'KeyPairSavePrivate'][self._type]),
+                     ('KeyPairDontSavePrivate',
+                      nova_keypair_template[self._resource][
+                      'KeyPairDontSavePrivate'][self._type])]
 
         for resource_name, resource_type in resources:
             resource = self.test_resources.get(resource_name, None)
@@ -68,13 +77,13 @@
         output_map = {}
         for outputs in stack['outputs']:
             output_map[outputs['output_key']] = outputs['output_value']
-        #Test that first key generated public and private keys
+        # Test that first key generated public and private keys
         self.assertTrue('KeyPair_PublicKey' in output_map)
         self.assertTrue("Generated" in output_map['KeyPair_PublicKey'])
         self.assertTrue('KeyPair_PrivateKey' in output_map)
         self.assertTrue('-----BEGIN' in output_map['KeyPair_PrivateKey'])
-        #Test that second key generated public key, and private key is not
-        #in the output due to save_private_key = false
+        # Test that second key generated public key, and private key is not
+        # in the output due to save_private_key = false
         self.assertTrue('KeyPairDontSavePrivate_PublicKey' in output_map)
         self.assertTrue('Generated' in
                         output_map['KeyPairDontSavePrivate_PublicKey'])
@@ -85,3 +94,5 @@
 
 class NovaKeyPairResourcesAWSTest(NovaKeyPairResourcesYAMLTest):
     _tpl_type = 'json'
+    _resource = 'Resources'
+    _type = 'Type'
diff --git a/tempest/api/orchestration/stacks/test_soft_conf.py b/tempest/api/orchestration/stacks/test_soft_conf.py
new file mode 100644
index 0000000..8903d4c
--- /dev/null
+++ b/tempest/api/orchestration/stacks/test_soft_conf.py
@@ -0,0 +1,163 @@
+#    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.api.orchestration import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest import exceptions
+from tempest.openstack.common import log as logging
+from tempest import test
+
+LOG = logging.getLogger(__name__)
+CONF = config.CONF
+
+
+class TestSoftwareConfig(base.BaseOrchestrationTest):
+
+    def setUp(self):
+        super(TestSoftwareConfig, self).setUp()
+        self.configs = []
+        # Add 2 sets of software configuration
+        self.configs.append(self._config_create('a'))
+        self.configs.append(self._config_create('b'))
+        # Create a deployment using config a's id
+        self._deployment_create(self.configs[0]['id'])
+
+    def _config_create(self, suffix):
+        configuration = {'group': 'script',
+                         'inputs': [],
+                         'outputs': [],
+                         'options': {}}
+        configuration['name'] = 'heat_soft_config_%s' % suffix
+        configuration['config'] = '#!/bin/bash echo init-%s' % suffix
+        api_config = self.client.create_software_config(**configuration)
+        configuration['id'] = api_config['software_config']['id']
+        self.addCleanup(self._config_delete, configuration['id'])
+        self._validate_config(configuration, api_config)
+        return configuration
+
+    def _validate_config(self, configuration, api_config):
+        # Assert all expected keys are present with matching data
+        for k in configuration.keys():
+            self.assertEqual(configuration[k],
+                             api_config['software_config'][k])
+
+    def _deployment_create(self, config_id):
+        self.server_id = data_utils.rand_name('dummy-server')
+        self.action = 'ACTION_0'
+        self.status = 'STATUS_0'
+        self.input_values = {}
+        self.output_values = []
+        self.status_reason = 'REASON_0'
+        self.signal_transport = 'NO_SIGNAL'
+        self.deployment = self.client.create_software_deploy(
+            self.server_id, config_id, self.action, self.status,
+            self.input_values, self.output_values, self.status_reason,
+            self.signal_transport)
+        self.deployment_id = self.deployment['software_deployment']['id']
+        self.addCleanup(self._deployment_delete, self.deployment_id)
+
+    def _deployment_delete(self, deploy_id):
+        self.client.delete_software_deploy(deploy_id)
+        # Testing that it is really gone
+        self.assertRaises(
+            exceptions.NotFound, self.client.get_software_deploy,
+            self.deployment_id)
+
+    def _config_delete(self, config_id):
+        self.client.delete_software_config(config_id)
+        # Testing that it is really gone
+        self.assertRaises(
+            exceptions.NotFound, self.client.get_software_config, config_id)
+
+    @test.attr(type='smoke')
+    def test_get_software_config(self):
+        """Testing software config get."""
+        for conf in self.configs:
+            api_config = self.client.get_software_config(conf['id'])
+            self._validate_config(conf, api_config)
+
+    @test.attr(type='smoke')
+    def test_get_deployment_list(self):
+        """Getting a list of all deployments"""
+        deploy_list = self.client.get_software_deploy_list()
+        deploy_ids = [deploy['id'] for deploy in
+                      deploy_list['software_deployments']]
+        self.assertIn(self.deployment_id, deploy_ids)
+
+    @test.attr(type='smoke')
+    def test_get_deployment_metadata(self):
+        """Testing deployment metadata get"""
+        metadata = self.client.get_software_deploy_meta(self.server_id)
+        conf_ids = [conf['id'] for conf in metadata['metadata']]
+        self.assertIn(self.configs[0]['id'], conf_ids)
+
+    def _validate_deployment(self, action, status, reason, config_id):
+        deployment = self.client.get_software_deploy(self.deployment_id)
+        self.assertEqual(action, deployment['software_deployment']['action'])
+        self.assertEqual(status, deployment['software_deployment']['status'])
+        self.assertEqual(reason,
+                         deployment['software_deployment']['status_reason'])
+        self.assertEqual(config_id,
+                         deployment['software_deployment']['config_id'])
+
+    @test.attr(type='smoke')
+    def test_software_deployment_create_validate(self):
+        """Testing software deployment was created as expected."""
+        # Asserting that all fields were created
+        self.assert_fields_in_dict(
+            self.deployment['software_deployment'], 'action', 'config_id',
+            'id', 'input_values', 'output_values', 'server_id', 'status',
+            'status_reason')
+        # Testing get for this deployment and verifying parameters
+        self._validate_deployment(self.action, self.status,
+                                  self.status_reason, self.configs[0]['id'])
+
+    @test.attr(type='smoke')
+    def test_software_deployment_update_no_metadata_change(self):
+        """Testing software deployment update without metadata change."""
+        metadata = self.client.get_software_deploy_meta(self.server_id)
+        # Updating values without changing the configuration ID
+        new_action = 'ACTION_1'
+        new_status = 'STATUS_1'
+        new_reason = 'REASON_1'
+        self.client.update_software_deploy(
+            self.deployment_id, self.server_id, self.configs[0]['id'],
+            new_action, new_status, self.input_values, self.output_values,
+            new_reason, self.signal_transport)
+        # Verifying get and that the deployment was updated as expected
+        self._validate_deployment(new_action, new_status,
+                                  new_reason, self.configs[0]['id'])
+
+        # Metadata should not be changed at this point
+        test_metadata = self.client.get_software_deploy_meta(self.server_id)
+        for key in metadata['metadata'][0]:
+            self.assertEqual(
+                metadata['metadata'][0][key],
+                test_metadata['metadata'][0][key])
+
+    @test.attr(type='smoke')
+    def test_software_deployment_update_with_metadata_change(self):
+        """Testing software deployment update with metadata change."""
+        metadata = self.client.get_software_deploy_meta(self.server_id)
+        self.client.update_software_deploy(
+            self.deployment_id, self.server_id, self.configs[1]['id'],
+            self.action, self.status, self.input_values,
+            self.output_values, self.status_reason, self.signal_transport)
+        self._validate_deployment(self.action, self.status,
+                                  self.status_reason, self.configs[1]['id'])
+        # Metadata should now be changed
+        new_metadata = self.client.get_software_deploy_meta(self.server_id)
+        # Its enough to test the ID in this case
+        meta_id = metadata['metadata'][0]['id']
+        test_id = new_metadata['metadata'][0]['id']
+        self.assertNotEqual(meta_id, test_id)
diff --git a/tempest/api/orchestration/stacks/test_swift_resources.py b/tempest/api/orchestration/stacks/test_swift_resources.py
index 6d53fb2..adab8c3 100644
--- a/tempest/api/orchestration/stacks/test_swift_resources.py
+++ b/tempest/api/orchestration/stacks/test_swift_resources.py
@@ -30,7 +30,7 @@
     def setUpClass(cls):
         super(SwiftResourcesTestJSON, cls).setUpClass()
         cls.stack_name = data_utils.rand_name('heat')
-        template = cls.load_template('swift_basic')
+        template = cls.read_template('swift_basic')
         os = clients.Manager()
         if not CONF.service_available.swift:
             raise cls.skipException("Swift support is required")
@@ -49,8 +49,11 @@
 
     def test_created_resources(self):
         """Created stack should be in the list of existing stacks."""
-        resources = [('SwiftContainer', 'OS::Swift::Container'),
-                     ('SwiftContainerWebsite', 'OS::Swift::Container')]
+        swift_basic_template = self.load_template('swift_basic')
+        resources = [('SwiftContainer', swift_basic_template['resources'][
+                      'SwiftContainer']['type']),
+                     ('SwiftContainerWebsite', swift_basic_template[
+                      'resources']['SwiftContainerWebsite']['type'])]
         for resource_name, resource_type in resources:
             resource = self.test_resources.get(resource_name)
             self.assertIsInstance(resource, dict)
@@ -84,10 +87,9 @@
             self.assertIn(h, headers)
 
     def test_metadata(self):
-        metadatas = {
-            "web-index": "index.html",
-            "web-error": "error.html"
-        }
+        swift_basic_template = self.load_template('swift_basic')
+        metadatas = swift_basic_template['resources']['SwiftContainerWebsite'][
+            'properties']['X-Container-Meta']
         swcont_website = self.test_resources.get(
             'SwiftContainerWebsite')['physical_resource_id']
         headers, _ = self.container_client.list_container_metadata(
diff --git a/tempest/api/orchestration/stacks/test_volumes.py b/tempest/api/orchestration/stacks/test_volumes.py
index 5ac2a8d..d422752 100644
--- a/tempest/api/orchestration/stacks/test_volumes.py
+++ b/tempest/api/orchestration/stacks/test_volumes.py
@@ -31,43 +31,44 @@
         if not CONF.service_available.cinder:
             raise cls.skipException('Cinder support is required')
 
-    def _cinder_verify(self, volume_id):
+    def _cinder_verify(self, volume_id, template):
         self.assertIsNotNone(volume_id)
         resp, volume = self.volumes_client.get_volume(volume_id)
         self.assertEqual(200, resp.status)
         self.assertEqual('available', volume.get('status'))
-        self.assertEqual(1, volume.get('size'))
-        self.assertEqual('a descriptive description',
-                         volume.get('display_description'))
-        self.assertEqual('volume_name',
-                         volume.get('display_name'))
+        self.assertEqual(template['resources']['volume']['properties'][
+            'size'], volume.get('size'))
+        self.assertEqual(template['resources']['volume']['properties'][
+            'description'], volume.get('display_description'))
+        self.assertEqual(template['resources']['volume']['properties'][
+            'name'], volume.get('display_name'))
 
-    def _outputs_verify(self, stack_identifier):
+    def _outputs_verify(self, stack_identifier, template):
         self.assertEqual('available',
                          self.get_stack_output(stack_identifier, 'status'))
-        self.assertEqual('1',
-                         self.get_stack_output(stack_identifier, 'size'))
-        self.assertEqual('a descriptive description',
-                         self.get_stack_output(stack_identifier,
-                                               'display_description'))
-        self.assertEqual('volume_name',
-                         self.get_stack_output(stack_identifier,
-                                               'display_name'))
+        self.assertEqual(str(template['resources']['volume']['properties'][
+            'size']), self.get_stack_output(stack_identifier, 'size'))
+        self.assertEqual(template['resources']['volume']['properties'][
+            'description'], self.get_stack_output(stack_identifier,
+                                                  'display_description'))
+        self.assertEqual(template['resources']['volume']['properties'][
+            'name'], self.get_stack_output(stack_identifier, 'display_name'))
 
     @test.attr(type='gate')
     def test_cinder_volume_create_delete(self):
         """Create and delete a volume via OS::Cinder::Volume."""
         stack_name = data_utils.rand_name('heat')
-        template = self.load_template('cinder_basic')
+        template = self.read_template('cinder_basic')
         stack_identifier = self.create_stack(stack_name, template)
         self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
 
         # Verify with cinder that the volume exists, with matching details
         volume_id = self.get_stack_output(stack_identifier, 'volume_id')
-        self._cinder_verify(volume_id)
+        cinder_basic_template = self.load_template('cinder_basic')
+        self._cinder_verify(volume_id, cinder_basic_template)
 
         # Verify the stack outputs are as expected
-        self._outputs_verify(stack_identifier)
+        self._outputs_verify(stack_identifier, cinder_basic_template)
 
         # Delete the stack and ensure the volume is gone
         self.client.delete_stack(stack_identifier)
@@ -86,21 +87,22 @@
     def test_cinder_volume_create_delete_retain(self):
         """Ensure the 'Retain' deletion policy is respected."""
         stack_name = data_utils.rand_name('heat')
-        template = self.load_template('cinder_basic_delete_retain')
+        template = self.read_template('cinder_basic_delete_retain')
         stack_identifier = self.create_stack(stack_name, template)
         self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
 
         # Verify with cinder that the volume exists, with matching details
         volume_id = self.get_stack_output(stack_identifier, 'volume_id')
         self.addCleanup(self._cleanup_volume, volume_id)
-        self._cinder_verify(volume_id)
+        retain_template = self.load_template('cinder_basic_delete_retain')
+        self._cinder_verify(volume_id, retain_template)
 
         # Verify the stack outputs are as expected
-        self._outputs_verify(stack_identifier)
+        self._outputs_verify(stack_identifier, retain_template)
 
         # Delete the stack and ensure the volume is *not* gone
         self.client.delete_stack(stack_identifier)
         self.client.wait_for_stack_status(stack_identifier, 'DELETE_COMPLETE')
-        self._cinder_verify(volume_id)
+        self._cinder_verify(volume_id, retain_template)
 
         # Volume cleanup happens via addCleanup calling _cleanup_volume
diff --git a/tempest/api/queuing/base.py b/tempest/api/queuing/base.py
index 5649619..f4ff7f1 100644
--- a/tempest/api/queuing/base.py
+++ b/tempest/api/queuing/base.py
@@ -13,6 +13,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from tempest.common.utils import data_utils
 from tempest import config
 from tempest.openstack.common import log as logging
 from tempest import test
@@ -89,3 +90,80 @@
         """Wrapper utility that sets the metadata of a queue."""
         resp, body = cls.client.set_queue_metadata(queue_name, rbody)
         return resp, body
+
+    @classmethod
+    def post_messages(cls, queue_name, rbody):
+        '''Wrapper utility that posts messages to a queue.'''
+        resp, body = cls.client.post_messages(queue_name, rbody)
+
+        return resp, body
+
+    @classmethod
+    def list_messages(cls, queue_name):
+        '''Wrapper utility that lists the messages in a queue.'''
+        resp, body = cls.client.list_messages(queue_name)
+
+        return resp, body
+
+    @classmethod
+    def get_single_message(cls, message_uri):
+        '''Wrapper utility that gets a single message.'''
+        resp, body = cls.client.get_single_message(message_uri)
+
+        return resp, body
+
+    @classmethod
+    def get_multiple_messages(cls, message_uri):
+        '''Wrapper utility that gets multiple messages.'''
+        resp, body = cls.client.get_multiple_messages(message_uri)
+
+        return resp, body
+
+    @classmethod
+    def delete_messages(cls, message_uri):
+        '''Wrapper utility that deletes messages.'''
+        resp, body = cls.client.delete_messages(message_uri)
+
+        return resp, body
+
+    @classmethod
+    def post_claims(cls, queue_name, rbody, url_params=False):
+        '''Wrapper utility that claims messages.'''
+        resp, body = cls.client.post_claims(
+            queue_name, rbody, url_params=False)
+
+        return resp, body
+
+    @classmethod
+    def query_claim(cls, claim_uri):
+        '''Wrapper utility that gets a claim.'''
+        resp, body = cls.client.query_claim(claim_uri)
+
+        return resp, body
+
+    @classmethod
+    def update_claim(cls, claim_uri, rbody):
+        '''Wrapper utility that updates a claim.'''
+        resp, body = cls.client.update_claim(claim_uri, rbody)
+
+        return resp, body
+
+    @classmethod
+    def release_claim(cls, claim_uri):
+        '''Wrapper utility that deletes a claim.'''
+        resp, body = cls.client.release_claim(claim_uri)
+
+        return resp, body
+
+    @classmethod
+    def generate_message_body(cls, repeat=1):
+        '''Wrapper utility that sets the metadata of a queue.'''
+        message_ttl = data_utils.rand_int_id(start=60,
+                                             end=CONF.queuing.max_message_ttl)
+
+        key = data_utils.arbitrary_string(size=20, base_text='QueuingKey')
+        value = data_utils.arbitrary_string(size=20, base_text='QueuingValue')
+        message_body = {key: value}
+
+        rbody = ([{'body': message_body, 'ttl': message_ttl}] * repeat)
+        return rbody
diff --git a/tempest/api/queuing/test_claims.py b/tempest/api/queuing/test_claims.py
new file mode 100644
index 0000000..a306623
--- /dev/null
+++ b/tempest/api/queuing/test_claims.py
@@ -0,0 +1,123 @@
+# Copyright (c) 2014 Rackspace, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+import urlparse
+
+from tempest.api.queuing import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest import test
+
+
+LOG = logging.getLogger(__name__)
+CONF = config.CONF
+
+
+class TestClaims(base.BaseQueuingTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestClaims, cls).setUpClass()
+        cls.queue_name = data_utils.rand_name('Queues-Test')
+        # Create Queue
+        cls.create_queue(cls.queue_name)
+
+    def _post_and_claim_messages(self, queue_name, repeat=1):
+        # Post Messages
+        message_body = self.generate_message_body(repeat=repeat)
+        self.client.post_messages(queue_name=self.queue_name,
+                                  rbody=message_body)
+
+        # Post Claim
+        claim_ttl = data_utils.rand_int_id(start=60,
+                                           end=CONF.queuing.max_claim_ttl)
+        claim_grace = data_utils.rand_int_id(start=60,
+                                             end=CONF.queuing.max_claim_grace)
+        claim_body = {"ttl": claim_ttl, "grace": claim_grace}
+        resp, body = self.client.post_claims(queue_name=self.queue_name,
+                                             rbody=claim_body)
+
+        return resp, body
+
+    @test.attr(type='smoke')
+    def test_post_claim(self):
+        _, body = self._post_and_claim_messages(queue_name=self.queue_name)
+        claimed_message_uri = body[0]['href']
+
+        # Skipping this step till bug-1331517  is fixed
+        # Get posted claim
+        # self.client.query_claim(claimed_message_uri)
+
+        # Delete Claimed message
+        self.client.delete_messages(claimed_message_uri)
+
+    @test.skip_because(bug="1331517")
+    @test.attr(type='smoke')
+    def test_query_claim(self):
+        # Post a Claim
+        resp, body = self._post_and_claim_messages(queue_name=self.queue_name)
+
+        # Query Claim
+        claim_uri = resp['location']
+        self.client.query_claim(claim_uri)
+
+        # Delete Claimed message
+        claimed_message_uri = body[0]['href']
+        self.delete_messages(claimed_message_uri)
+
+    @test.skip_because(bug="1328111")
+    @test.attr(type='smoke')
+    def test_update_claim(self):
+        # Post a Claim
+        resp, body = self._post_and_claim_messages(queue_name=self.queue_name)
+
+        claim_uri = resp['location']
+        claimed_message_uri = body[0]['href']
+
+        # Update Claim
+        claim_ttl = data_utils.rand_int_id(start=60,
+                                           end=CONF.queuing.max_claim_ttl)
+        update_rbody = {"ttl": claim_ttl}
+
+        self.client.update_claim(claim_uri, rbody=update_rbody)
+
+        # Verify claim ttl >= updated ttl value
+        _, body = self.client.query_claim(claim_uri)
+        updated_claim_ttl = body["ttl"]
+        self.assertTrue(updated_claim_ttl >= claim_ttl)
+
+        # Delete Claimed message
+        self.client.delete_messages(claimed_message_uri)
+
+    @test.attr(type='smoke')
+    def test_release_claim(self):
+        # Post a Claim
+        resp, body = self._post_and_claim_messages(queue_name=self.queue_name)
+        claim_uri = resp['location']
+
+        # Release Claim
+        self.client.release_claim(claim_uri)
+
+        # Delete Claimed message
+        # This will implicitly verify that the claim is deleted.
+        message_uri = urlparse.urlparse(claim_uri).path
+        self.client.delete_messages(message_uri)
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.delete_queue(cls.queue_name)
+        super(TestClaims, cls).tearDownClass()
diff --git a/tempest/api/queuing/test_messages.py b/tempest/api/queuing/test_messages.py
new file mode 100644
index 0000000..9546c91
--- /dev/null
+++ b/tempest/api/queuing/test_messages.py
@@ -0,0 +1,122 @@
+# Copyright (c) 2014 Rackspace, Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+
+from tempest.api.queuing import base
+from tempest.common.utils import data_utils
+from tempest import config
+from tempest import test
+
+
+LOG = logging.getLogger(__name__)
+CONF = config.CONF
+
+
+class TestMessages(base.BaseQueuingTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(TestMessages, cls).setUpClass()
+        cls.queue_name = data_utils.rand_name('Queues-Test')
+        # Create Queue
+        cls.client.create_queue(cls.queue_name)
+
+    def _post_messages(self, repeat=CONF.queuing.max_messages_per_page):
+        message_body = self.generate_message_body(repeat=repeat)
+        resp, body = self.post_messages(queue_name=self.queue_name,
+                                        rbody=message_body)
+        return resp, body
+
+    @test.attr(type='smoke')
+    def test_post_messages(self):
+        # Post Messages
+        resp, _ = self._post_messages()
+
+        # Get on the posted messages
+        message_uri = resp['location']
+        resp, _ = self.client.get_multiple_messages(message_uri)
+        # The test has an assertion here, because the response cannot be 204
+        # in this case (the client allows 200 or 204 for this API call).
+        self.assertEqual('200', resp['status'])
+
+    @test.attr(type='smoke')
+    def test_list_messages(self):
+        # Post Messages
+        self._post_messages()
+
+        # List Messages
+        resp, _ = self.list_messages(queue_name=self.queue_name)
+        # The test has an assertion here, because the response cannot be 204
+        # in this case (the client allows 200 or 204 for this API call).
+        self.assertEqual('200', resp['status'])
+
+    @test.attr(type='smoke')
+    def test_get_message(self):
+        # Post Messages
+        _, body = self._post_messages()
+        message_uri = body['resources'][0]
+
+        # Get posted message
+        resp, _ = self.client.get_single_message(message_uri)
+        # The test has an assertion here, because the response cannot be 204
+        # in this case (the client allows 200 or 204 for this API call).
+        self.assertEqual('200', resp['status'])
+
+    @test.attr(type='smoke')
+    def test_get_multiple_messages(self):
+        # Post Messages
+        resp, _ = self._post_messages()
+        message_uri = resp['location']
+
+        # Get posted messages
+        resp, _ = self.client.get_multiple_messages(message_uri)
+        # The test has an assertion here, because the response cannot be 204
+        # in this case (the client allows 200 or 204 for this API call).
+        self.assertEqual('200', resp['status'])
+
+    @test.attr(type='smoke')
+    def test_delete_single_message(self):
+        # Post Messages
+        _, body = self._post_messages()
+        message_uri = body['resources'][0]
+
+        # Delete posted message & verify the delete operration
+        self.client.delete_messages(message_uri)
+
+        message_uri = message_uri.replace('/messages/', '/messages?ids=')
+        resp, _ = self.client.get_multiple_messages(message_uri)
+        # The test has an assertion here, because the response has to be 204
+        # in this case (the client allows 200 or 204 for this API call).
+        self.assertEqual('204', resp['status'])
+
+    @test.attr(type='smoke')
+    def test_delete_multiple_messages(self):
+        # Post Messages
+        resp, _ = self._post_messages()
+        message_uri = resp['location']
+
+        # Delete multiple messages
+        self.client.delete_messages(message_uri)
+        resp, _ = self.client.get_multiple_messages(message_uri)
+        # The test has an assertion here, because the response has to be 204
+        # in this case (the client allows 200 or 204 for this API call).
+        self.assertEqual('204', resp['status'])
+
+    @classmethod
+    def tearDownClass(cls):
+        cls.delete_queue(cls.queue_name)
+        super(TestMessages, cls).tearDownClass()
diff --git a/tempest/api/telemetry/test_telemetry_notification_api.py b/tempest/api/telemetry/test_telemetry_notification_api.py
index 148f5a3..f401b9b 100644
--- a/tempest/api/telemetry/test_telemetry_notification_api.py
+++ b/tempest/api/telemetry/test_telemetry_notification_api.py
@@ -32,6 +32,7 @@
     @test.attr(type="gate")
     @testtools.skipIf(not CONF.service_available.nova,
                       "Nova is not available.")
+    @test.skip_because(bug="1336755")
     def test_check_nova_notification(self):
 
         resp, body = self.create_server()
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
index d3a052e..da421dc 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
@@ -29,9 +29,9 @@
         super(ExtraSpecsNegativeTest, cls).setUpClass()
         vol_type_name = data_utils.rand_name('Volume-type-')
         cls.extra_specs = {"spec1": "val1"}
-        resp, cls.volume_type = cls.client.create_volume_type(vol_type_name,
-                                                              extra_specs=
-                                                              cls.extra_specs)
+        resp, cls.volume_type = cls.client.create_volume_type(
+            vol_type_name,
+            extra_specs=cls.extra_specs)
 
     @classmethod
     def tearDownClass(cls):
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 67d0203..c5be1f3 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -16,6 +16,7 @@
 from tempest import clients
 from tempest.common.utils import data_utils
 from tempest import config
+from tempest import exceptions
 from tempest.openstack.common import log as logging
 import tempest.test
 
@@ -25,9 +26,11 @@
 
 
 class BaseVolumeTest(tempest.test.BaseTestCase):
-
     """Base test case class for all Cinder API tests."""
 
+    _api_version = 2
+    _interface = 'json'
+
     @classmethod
     def setUpClass(cls):
         cls.set_network_resources()
@@ -47,6 +50,28 @@
         cls.snapshots = []
         cls.volumes = []
 
+        if cls._api_version == 1:
+            if not CONF.volume_feature_enabled.api_v1:
+                msg = "Volume API v1 is disabled"
+                raise cls.skipException(msg)
+            cls.snapshots_client = cls.os.snapshots_client
+            cls.volumes_client = cls.os.volumes_client
+            cls.backups_client = cls.os.backups_client
+            cls.volume_services_client = cls.os.volume_services_client
+            cls.volumes_extension_client = cls.os.volumes_extension_client
+            cls.availability_zone_client = (
+                cls.os.volume_availability_zone_client)
+
+        elif cls._api_version == 2:
+            if not CONF.volume_feature_enabled.api_v2:
+                msg = "Volume API v2 is disabled"
+                raise cls.skipException(msg)
+            cls.volumes_client = cls.os.volumes_v2_client
+
+        else:
+            msg = ("Invalid Cinder API version (%s)" % cls._api_version)
+            raise exceptions.InvalidConfiguration(message=msg)
+
     @classmethod
     def tearDownClass(cls):
         cls.clear_snapshots()
@@ -55,6 +80,22 @@
         super(BaseVolumeTest, cls).tearDownClass()
 
     @classmethod
+    def create_volume(cls, size=1, **kwargs):
+        """Wrapper utility that returns a test volume."""
+        vol_name = data_utils.rand_name('Volume')
+        if cls._api_version == 1:
+            resp, volume = cls.volumes_client.create_volume(
+                size, display_name=vol_name, **kwargs)
+            assert 200 == resp.status
+        elif cls._api_version == 2:
+            resp, volume = cls.volumes_client.create_volume(
+                size, name=vol_name, **kwargs)
+            assert 202 == resp.status
+        cls.volumes.append(volume)
+        cls.volumes_client.wait_for_volume_status(volume['id'], 'available')
+        return volume
+
+    @classmethod
     def create_snapshot(cls, volume_id=1, **kwargs):
         """Wrapper utility that returns a test snapshot."""
         resp, snapshot = cls.snapshots_client.create_snapshot(volume_id,
@@ -98,30 +139,7 @@
 
 
 class BaseVolumeV1Test(BaseVolumeTest):
-    @classmethod
-    def setUpClass(cls):
-        if not CONF.volume_feature_enabled.api_v1:
-            msg = "Volume API v1 not supported"
-            raise cls.skipException(msg)
-        super(BaseVolumeV1Test, cls).setUpClass()
-        cls.snapshots_client = cls.os.snapshots_client
-        cls.volumes_client = cls.os.volumes_client
-        cls.backups_client = cls.os.backups_client
-        cls.volume_services_client = cls.os.volume_services_client
-        cls.volumes_extension_client = cls.os.volumes_extension_client
-        cls.availability_zone_client = cls.os.volume_availability_zone_client
-
-    @classmethod
-    def create_volume(cls, size=1, **kwargs):
-        """Wrapper utility that returns a test volume."""
-        vol_name = data_utils.rand_name('Volume')
-        resp, volume = cls.volumes_client.create_volume(size,
-                                                        display_name=vol_name,
-                                                        **kwargs)
-        assert 200 == resp.status
-        cls.volumes.append(volume)
-        cls.volumes_client.wait_for_volume_status(volume['id'], 'available')
-        return volume
+    _api_version = 1
 
 
 class BaseVolumeV1AdminTest(BaseVolumeV1Test):
@@ -144,25 +162,3 @@
         cls.client = cls.os_adm.volume_types_client
         cls.hosts_client = cls.os_adm.volume_hosts_client
         cls.quotas_client = cls.os_adm.volume_quotas_client
-
-
-class BaseVolumeV2Test(BaseVolumeTest):
-    @classmethod
-    def setUpClass(cls):
-        if not CONF.volume_feature_enabled.api_v2:
-            msg = "Volume API v2 not supported"
-            raise cls.skipException(msg)
-        super(BaseVolumeV2Test, cls).setUpClass()
-        cls.volumes_client = cls.os.volumes_v2_client
-
-    @classmethod
-    def create_volume(cls, size=1, **kwargs):
-        """Wrapper utility that returns a test volume."""
-        vol_name = data_utils.rand_name('Volume')
-        resp, volume = cls.volumes_client.create_volume(size,
-                                                        name=vol_name,
-                                                        **kwargs)
-        assert 202 == resp.status
-        cls.volumes.append(volume)
-        cls.volumes_client.wait_for_volume_status(volume['id'], 'available')
-        return volume
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 58da440..2745b95 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -39,7 +39,7 @@
     def _is_true(self, val):
         # NOTE(jdg): Temporary conversion method to get cinder patch
         # merged.  Then we'll make this strict again and
-        #specifically check "true" or "false"
+        # specifically check "true" or "false"
         if val in ['true', 'True', True]:
             return True
         else:
@@ -121,19 +121,19 @@
         new_volume = {}
         new_v_desc = data_utils.rand_name('@#$%^* description')
         resp, new_volume = \
-            self.client.create_volume(size=1,
-                                      display_description=new_v_desc,
-                                      availability_zone=
-                                      volume['availability_zone'])
+            self.client.create_volume(
+                size=1,
+                display_description=new_v_desc,
+                availability_zone=volume['availability_zone'])
         self.assertEqual(200, resp.status)
         self.assertIn('id', new_volume)
         self.addCleanup(self._delete_volume, new_volume['id'])
         self.client.wait_for_volume_status(new_volume['id'], 'available')
         resp, update_volume = \
-            self.client.update_volume(new_volume['id'],
-                                      display_name=volume['display_name'],
-                                      display_description=
-                                      volume['display_description'])
+            self.client.update_volume(
+                new_volume['id'],
+                display_name=volume['display_name'],
+                display_description=volume['display_description'])
         self.assertEqual(200, resp.status)
 
         # NOTE(jdg): Revert back to strict true/false checking
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index e2f7a38..b8a2faa 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -23,10 +23,8 @@
 
 LOG = logging.getLogger(__name__)
 
-VOLUME_FIELDS = ('id', 'display_name')
 
-
-class VolumesListTest(base.BaseVolumeV1Test):
+class VolumesV2ListTestJSON(base.BaseVolumeTest):
 
     """
     This test creates a number of 1G volumes. To run successfully,
@@ -36,7 +34,7 @@
     VOLUME_BACKING_FILE_SIZE is at least 4G in your localrc
     """
 
-    _interface = 'json'
+    VOLUME_FIELDS = ('id', 'name')
 
     def assertVolumesIn(self, fetched_list, expected_list, fields=None):
         if fields:
@@ -48,7 +46,7 @@
             return
 
         def str_vol(vol):
-            return "%s:%s" % (vol['id'], vol['display_name'])
+            return "%s:%s" % (vol['id'], vol[self.name])
 
         raw_msg = "Could not find volumes %s in expected list %s; fetched %s"
         self.fail(raw_msg % ([str_vol(v) for v in missing_vols],
@@ -58,8 +56,9 @@
     @classmethod
     @test.safe_setup
     def setUpClass(cls):
-        super(VolumesListTest, cls).setUpClass()
+        super(VolumesV2ListTestJSON, cls).setUpClass()
         cls.client = cls.volumes_client
+        cls.name = cls.VOLUME_FIELDS[1]
 
         # Create 3 test volumes
         cls.volume_list = []
@@ -77,7 +76,7 @@
         for volid in cls.volume_id_list:
             resp, _ = cls.client.delete_volume(volid)
             cls.client.wait_for_resource_deletion(volid)
-        super(VolumesListTest, cls).tearDownClass()
+        super(VolumesV2ListTestJSON, cls).tearDownClass()
 
     def _list_by_param_value_and_assert(self, params, with_detail=False):
         """
@@ -92,16 +91,22 @@
 
         self.assertEqual(200, resp.status)
         # Validating params of fetched volumes
-        for volume in fetched_vol_list:
-            for key in params:
-                msg = "Failed to list volumes %s by %s" % \
-                      ('details' if with_detail else '', key)
-                if key == 'metadata':
-                    self.assertThat(volume[key].items(),
-                                    matchers.ContainsAll(params[key].items()),
-                                    msg)
-                else:
-                    self.assertEqual(params[key], volume[key], msg)
+        # In v2, only list detail view includes items in params.
+        # In v1, list view and list detail view are same. So the
+        # following check should be run when 'with_detail' is True
+        # or v1 tests.
+        if with_detail or self._api_version == 1:
+            for volume in fetched_vol_list:
+                for key in params:
+                    msg = "Failed to list volumes %s by %s" % \
+                          ('details' if with_detail else '', key)
+                    if key == 'metadata':
+                        self.assertThat(
+                            volume[key].items(),
+                            matchers.ContainsAll(params[key].items()),
+                            msg)
+                    else:
+                        self.assertEqual(params[key], volume[key], msg)
 
     @test.attr(type='smoke')
     def test_volume_list(self):
@@ -110,7 +115,7 @@
         resp, fetched_list = self.client.list_volumes()
         self.assertEqual(200, resp.status)
         self.assertVolumesIn(fetched_list, self.volume_list,
-                             fields=VOLUME_FIELDS)
+                             fields=self.VOLUME_FIELDS)
 
     @test.attr(type='gate')
     def test_volume_list_with_details(self):
@@ -123,32 +128,31 @@
     @test.attr(type='gate')
     def test_volume_list_by_name(self):
         volume = self.volume_list[data_utils.rand_int_id(0, 2)]
-        params = {'display_name': volume['display_name']}
+        params = {self.name: volume[self.name]}
         resp, fetched_vol = self.client.list_volumes(params)
         self.assertEqual(200, resp.status)
         self.assertEqual(1, len(fetched_vol), str(fetched_vol))
-        self.assertEqual(fetched_vol[0]['display_name'],
-                         volume['display_name'])
+        self.assertEqual(fetched_vol[0][self.name],
+                         volume[self.name])
 
     @test.attr(type='gate')
     def test_volume_list_details_by_name(self):
         volume = self.volume_list[data_utils.rand_int_id(0, 2)]
-        params = {'display_name': volume['display_name']}
+        params = {self.name: volume[self.name]}
         resp, fetched_vol = self.client.list_volumes_with_detail(params)
         self.assertEqual(200, resp.status)
         self.assertEqual(1, len(fetched_vol), str(fetched_vol))
-        self.assertEqual(fetched_vol[0]['display_name'],
-                         volume['display_name'])
+        self.assertEqual(fetched_vol[0][self.name],
+                         volume[self.name])
 
     @test.attr(type='gate')
     def test_volumes_list_by_status(self):
         params = {'status': 'available'}
         resp, fetched_list = self.client.list_volumes(params)
         self.assertEqual(200, resp.status)
-        for volume in fetched_list:
-            self.assertEqual('available', volume['status'])
+        self._list_by_param_value_and_assert(params)
         self.assertVolumesIn(fetched_list, self.volume_list,
-                             fields=VOLUME_FIELDS)
+                             fields=self.VOLUME_FIELDS)
 
     @test.attr(type='gate')
     def test_volumes_list_details_by_status(self):
@@ -166,10 +170,9 @@
         params = {'availability_zone': zone}
         resp, fetched_list = self.client.list_volumes(params)
         self.assertEqual(200, resp.status)
-        for volume in fetched_list:
-            self.assertEqual(zone, volume['availability_zone'])
+        self._list_by_param_value_and_assert(params)
         self.assertVolumesIn(fetched_list, self.volume_list,
-                             fields=VOLUME_FIELDS)
+                             fields=self.VOLUME_FIELDS)
 
     @test.attr(type='gate')
     def test_volumes_list_details_by_availability_zone(self):
@@ -198,7 +201,7 @@
     def test_volume_list_param_display_name_and_status(self):
         # Test to list volume when display name and status param is given
         volume = self.volume_list[data_utils.rand_int_id(0, 2)]
-        params = {'display_name': volume['display_name'],
+        params = {self.name: volume[self.name],
                   'status': 'available'}
         self._list_by_param_value_and_assert(params)
 
@@ -206,10 +209,19 @@
     def test_volume_list_with_detail_param_display_name_and_status(self):
         # Test to list volume when name and status param is given
         volume = self.volume_list[data_utils.rand_int_id(0, 2)]
-        params = {'display_name': volume['display_name'],
+        params = {self.name: volume[self.name],
                   'status': 'available'}
         self._list_by_param_value_and_assert(params, with_detail=True)
 
 
-class VolumeListTestXML(VolumesListTest):
+class VolumesV2ListTestXML(VolumesV2ListTestJSON):
+    _interface = 'xml'
+
+
+class VolumesV1ListTestJSON(VolumesV2ListTestJSON):
+    _api_version = 1
+    VOLUME_FIELDS = ('id', 'display_name')
+
+
+class VolumesV1ListTestXML(VolumesV1ListTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/volume/v2/test_volumes_list.py b/tempest/api/volume/v2/test_volumes_list.py
index e90c957..7ca8599 100644
--- a/tempest/api/volume/v2/test_volumes_list.py
+++ b/tempest/api/volume/v2/test_volumes_list.py
@@ -13,22 +13,16 @@
 #    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 operator
 
 from tempest.api.volume import base
-from tempest.common.utils import data_utils
-from tempest.openstack.common import log as logging
 from tempest import test
-from testtools import matchers
-
-LOG = logging.getLogger(__name__)
-
-VOLUME_FIELDS = ('id', 'name')
 
 
-class VolumesV2ListTestJSON(base.BaseVolumeV2Test):
+class VolumesV2ListTestJSON(base.BaseVolumeTest):
 
     """
+    volumes v2 specific tests.
+
     This test creates a number of 1G volumes. To run successfully,
     ensure that the backing file for the volume group that Nova uses
     has space for at least 3 1G volumes!
@@ -36,25 +30,6 @@
     VOLUME_BACKING_FILE_SIZE is at least 4G in your localrc
     """
 
-    _interface = 'json'
-
-    def assertVolumesIn(self, fetched_list, expected_list, fields=None):
-        if fields:
-            expected_list = map(operator.itemgetter(*fields), expected_list)
-            fetched_list = map(operator.itemgetter(*fields), fetched_list)
-
-        missing_vols = [v for v in expected_list if v not in fetched_list]
-        if len(missing_vols) == 0:
-            return
-
-        def str_vol(vol):
-            return "%s:%s" % (vol['id'], vol['name'])
-
-        raw_msg = "Could not find volumes %s in expected list %s; fetched %s"
-        self.fail(raw_msg % ([str_vol(v) for v in missing_vols],
-                             [str_vol(v) for v in expected_list],
-                             [str_vol(v) for v in fetched_list]))
-
     @classmethod
     @test.safe_setup
     def setUpClass(cls):
@@ -79,124 +54,6 @@
             cls.client.wait_for_resource_deletion(volid)
         super(VolumesV2ListTestJSON, cls).tearDownClass()
 
-    def _list_by_param_value_and_assert(self, params, expected_list=None,
-                                        with_detail=False):
-        """
-        Perform list or list_details action with given params
-        and validates result.
-        """
-        if with_detail:
-            resp, fetched_vol_list = \
-                self.client.list_volumes_with_detail(params=params)
-        else:
-            resp, fetched_vol_list = self.client.list_volumes(params=params)
-
-        self.assertEqual(200, resp.status)
-        if expected_list is None:
-            expected_list = self.volume_list
-        self.assertVolumesIn(fetched_vol_list, expected_list,
-                             fields=VOLUME_FIELDS)
-        # Validating params of fetched volumes
-        if with_detail:
-            for volume in fetched_vol_list:
-                for key in params:
-                    msg = "Failed to list volumes %s by %s" % \
-                          ('details' if with_detail else '', key)
-                    if key == 'metadata':
-                        self.assertThat(volume[key].items(),
-                                        matchers.ContainsAll(
-                                            params[key].items()), msg)
-                    else:
-                        self.assertEqual(params[key], volume[key], msg)
-
-    @test.attr(type='smoke')
-    def test_volume_list(self):
-        # Get a list of Volumes
-        # Fetch all volumes
-        resp, fetched_list = self.client.list_volumes()
-        self.assertEqual(200, resp.status)
-        self.assertVolumesIn(fetched_list, self.volume_list,
-                             fields=VOLUME_FIELDS)
-
-    @test.attr(type='gate')
-    def test_volume_list_with_details(self):
-        # Get a list of Volumes with details
-        # Fetch all Volumes
-        resp, fetched_list = self.client.list_volumes_with_detail()
-        self.assertEqual(200, resp.status)
-        self.assertVolumesIn(fetched_list, self.volume_list)
-
-    @test.attr(type='gate')
-    def test_volume_list_by_name(self):
-        volume = self.volume_list[data_utils.rand_int_id(0, 2)]
-        params = {'name': volume['name']}
-        resp, fetched_vol = self.client.list_volumes(params)
-        self.assertEqual(200, resp.status)
-        self.assertEqual(1, len(fetched_vol), str(fetched_vol))
-        self.assertEqual(fetched_vol[0]['name'], volume['name'])
-
-    @test.attr(type='gate')
-    def test_volume_list_details_by_name(self):
-        volume = self.volume_list[data_utils.rand_int_id(0, 2)]
-        params = {'name': volume['name']}
-        resp, fetched_vol = self.client.list_volumes_with_detail(params)
-        self.assertEqual(200, resp.status)
-        self.assertEqual(1, len(fetched_vol), str(fetched_vol))
-        self.assertEqual(fetched_vol[0]['name'], volume['name'])
-
-    @test.attr(type='gate')
-    def test_volumes_list_by_status(self):
-        params = {'status': 'available'}
-        self._list_by_param_value_and_assert(params)
-
-    @test.attr(type='gate')
-    def test_volumes_list_details_by_status(self):
-        params = {'status': 'available'}
-        self._list_by_param_value_and_assert(params, with_detail=True)
-
-    @test.attr(type='gate')
-    def test_volumes_list_by_availability_zone(self):
-        volume = self.volume_list[data_utils.rand_int_id(0, 2)]
-        zone = volume['availability_zone']
-        params = {'availability_zone': zone}
-        self._list_by_param_value_and_assert(params)
-
-    @test.attr(type='gate')
-    def test_volumes_list_details_by_availability_zone(self):
-        volume = self.volume_list[data_utils.rand_int_id(0, 2)]
-        zone = volume['availability_zone']
-        params = {'availability_zone': zone}
-        self._list_by_param_value_and_assert(params, with_detail=True)
-
-    @test.attr(type='gate')
-    def test_volume_list_with_param_metadata(self):
-        # Test to list volumes when metadata param is given
-        params = {'metadata': self.metadata}
-        self._list_by_param_value_and_assert(params)
-
-    @test.attr(type='gate')
-    def test_volume_list_with_details_param_metadata(self):
-        # Test to list volumes details when metadata param is given
-        params = {'metadata': self.metadata}
-        self._list_by_param_value_and_assert(params, with_detail=True)
-
-    @test.attr(type='gate')
-    def test_volume_list_param_display_name_and_status(self):
-        # Test to list volume when display name and status param is given
-        volume = self.volume_list[data_utils.rand_int_id(0, 2)]
-        params = {'name': volume['name'],
-                  'status': 'available'}
-        self._list_by_param_value_and_assert(params, expected_list=[volume])
-
-    @test.attr(type='gate')
-    def test_volume_list_with_details_param_display_name_and_status(self):
-        # Test to list volume when name and status param is given
-        volume = self.volume_list[data_utils.rand_int_id(0, 2)]
-        params = {'name': volume['name'],
-                  'status': 'available'}
-        self._list_by_param_value_and_assert(params, expected_list=[volume],
-                                             with_detail=True)
-
     @test.attr(type='gate')
     def test_volume_list_details_with_multiple_params(self):
         # List volumes detail using combined condition
diff --git a/tempest/api_schema/compute/agents.py b/tempest/api_schema/compute/agents.py
index b04cf64..e5f3a8d 100644
--- a/tempest/api_schema/compute/agents.py
+++ b/tempest/api_schema/compute/agents.py
@@ -22,7 +22,7 @@
                 'items': {
                     'type': 'object',
                     'properties': {
-                        'agent_id': {'type': ['integer', 'string']},
+                        'agent_id': {'type': 'integer'},
                         'hypervisor': {'type': 'string'},
                         'os': {'type': 'string'},
                         'architecture': {'type': 'string'},
@@ -38,3 +38,24 @@
         'required': ['agents']
     }
 }
+
+common_create_agent = {
+    'type': 'object',
+    'properties': {
+        'agent': {
+            'type': 'object',
+            'properties': {
+                'agent_id': {'type': ['integer', 'string']},
+                'hypervisor': {'type': 'string'},
+                'os': {'type': 'string'},
+                'architecture': {'type': 'string'},
+                'version': {'type': 'string'},
+                'url': {'type': 'string', 'format': 'uri'},
+                'md5hash': {'type': 'string'}
+            },
+            'required': ['agent_id', 'hypervisor', 'os', 'architecture',
+                         'version', 'url', 'md5hash']
+        }
+    },
+    'required': ['agent']
+}
diff --git a/tempest/api_schema/compute/hypervisors.py b/tempest/api_schema/compute/hypervisors.py
index 630901e..e9e1bc9 100644
--- a/tempest/api_schema/compute/hypervisors.py
+++ b/tempest/api_schema/compute/hypervisors.py
@@ -24,7 +24,7 @@
                 'properties': {
                     'count': {'type': 'integer'},
                     'current_workload': {'type': 'integer'},
-                    'disk_available_least': {'type': 'integer'},
+                    'disk_available_least': {'type': ['integer', 'null']},
                     'free_disk_gb': {'type': 'integer'},
                     'free_ram_mb': {'type': 'integer'},
                     'local_gb': {'type': 'integer'},
@@ -110,7 +110,7 @@
                 'properties': {
                     'cpu_info': {'type': 'string'},
                     'current_workload': {'type': 'integer'},
-                    'disk_available_least': {'type': 'integer'},
+                    'disk_available_least': {'type': ['integer', 'null']},
                     'host_ip': {
                         'type': 'string',
                         'format': 'ip-address'
diff --git a/tempest/api_schema/compute/keypairs.py b/tempest/api_schema/compute/keypairs.py
index b8f905f..2ae410c 100644
--- a/tempest/api_schema/compute/keypairs.py
+++ b/tempest/api_schema/compute/keypairs.py
@@ -49,10 +49,7 @@
                 'fingerprint': {'type': 'string'},
                 'name': {'type': 'string'},
                 'public_key': {'type': 'string'},
-                # NOTE: Now the type of 'user_id' is integer, but here
-                # allows 'string' also because we will be able to change
-                # it to 'uuid' in the future.
-                'user_id': {'type': ['integer', 'string']},
+                'user_id': {'type': 'string'},
                 'private_key': {'type': 'string'}
             },
             # When create keypair API is being called with 'Public key'
diff --git a/tempest/api_schema/compute/migrations.py b/tempest/api_schema/compute/migrations.py
index 6723869..6549272 100644
--- a/tempest/api_schema/compute/migrations.py
+++ b/tempest/api_schema/compute/migrations.py
@@ -22,10 +22,7 @@
                 'items': {
                     'type': 'object',
                     'properties': {
-                        # NOTE: Now the type of 'id' is integer, but here
-                        # allows 'string' also because we will be able to
-                        # change it to 'uuid' in the future.
-                        'id': {'type': ['integer', 'string']},
+                        'id': {'type': 'integer'},
                         'status': {'type': 'string'},
                         'instance_uuid': {'type': 'string'},
                         'source_node': {'type': 'string'},
@@ -33,12 +30,8 @@
                         'dest_node': {'type': 'string'},
                         'dest_compute': {'type': 'string'},
                         'dest_host': {'type': 'string'},
-                        'old_instance_type_id': {
-                            'type': ['integer', 'string']
-                        },
-                        'new_instance_type_id': {
-                            'type': ['integer', 'string']
-                        },
+                        'old_instance_type_id': {'type': 'integer'},
+                        'new_instance_type_id': {'type': 'integer'},
                         'created_at': {'type': 'string'},
                         'updated_at': {'type': ['string', 'null']}
                     },
diff --git a/tempest/api_schema/compute/servers.py b/tempest/api_schema/compute/servers.py
index 4e8c201..a16e425 100644
--- a/tempest/api_schema/compute/servers.py
+++ b/tempest/api_schema/compute/servers.py
@@ -48,51 +48,54 @@
     }
 }
 
-base_update_server = {
+common_show_server = {
+    'type': 'object',
+    'properties': {
+        'id': {'type': 'string'},
+        'name': {'type': 'string'},
+        'status': {'type': 'string'},
+        'image': {
+            'type': 'object',
+            'properties': {
+                'id': {'type': 'string'},
+                'links': parameter_types.links
+            },
+            'required': ['id', 'links']
+        },
+        'flavor': {
+            'type': 'object',
+            'properties': {
+                'id': {'type': 'string'},
+                'links': parameter_types.links
+            },
+            'required': ['id', 'links']
+        },
+        'user_id': {'type': 'string'},
+        'tenant_id': {'type': 'string'},
+        'created': {'type': 'string'},
+        'updated': {'type': 'string'},
+        'progress': {'type': 'integer'},
+        'metadata': {'type': 'object'},
+        'links': parameter_types.links,
+        'addresses': parameter_types.addresses,
+    },
+    # NOTE(GMann): 'progress' attribute is present in the response
+    # only when server's status is one of the progress statuses
+    # ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE")
+    # So it is not defined as 'required'.
+    'required': ['id', 'name', 'status', 'image', 'flavor',
+                 'user_id', 'tenant_id', 'created', 'updated',
+                 'metadata', 'links', 'addresses']
+}
+
+base_update_get_server = {
     'status_code': [200],
     'response_body': {
         'type': 'object',
         'properties': {
-            'server': {
-                'type': 'object',
-                'properties': {
-                    'id': {'type': ['integer', 'string']},
-                    'name': {'type': 'string'},
-                    'status': {'type': 'string'},
-                    'image': {
-                        'type': 'object',
-                        'properties': {
-                            'id': {'type': ['integer', 'string']},
-                            'links': parameter_types.links
-                        },
-                        'required': ['id', 'links']
-                    },
-                    'flavor': {
-                        'type': 'object',
-                        'properties': {
-                            'id': {'type': ['integer', 'string']},
-                            'links': parameter_types.links
-                        },
-                        'required': ['id', 'links']
-                    },
-                    'user_id': {'type': 'string'},
-                    'tenant_id': {'type': 'string'},
-                    'created': {'type': 'string'},
-                    'updated': {'type': 'string'},
-                    'progress': {'type': 'integer'},
-                    'metadata': {'type': 'object'},
-                    'links': parameter_types.links,
-                    'addresses': parameter_types.addresses,
-                },
-                # NOTE(GMann): 'progress' attribute is present in the response
-                # only when server's status is one of the progress statuses
-                # ("ACTIVE","BUILD", "REBUILD", "RESIZE","VERIFY_RESIZE")
-                # So it is not defined as 'required'.
-                'required': ['id', 'name', 'status', 'image', 'flavor',
-                             'user_id', 'tenant_id', 'created', 'updated',
-                             'metadata', 'links', 'addresses']
-            }
-        }
+            'server': common_show_server
+        },
+        'required': ['server']
     }
 }
 
@@ -164,3 +167,54 @@
         'required': ['output']
     }
 }
+
+common_instance_actions = {
+    'type': 'object',
+    'properties': {
+        'action': {'type': 'string'},
+        'request_id': {'type': 'string'},
+        'user_id': {'type': 'string'},
+        'project_id': {'type': 'string'},
+        'start_time': {'type': 'string'},
+        'message': {'type': ['string', 'null']}
+    },
+    'required': ['action', 'request_id', 'user_id', 'project_id',
+                 'start_time', 'message']
+}
+
+instance_action_events = {
+    'type': 'array',
+    'items': {
+        'type': 'object',
+        'properties': {
+            'event': {'type': 'string'},
+            'start_time': {'type': 'string'},
+            'finish_time': {'type': 'string'},
+            'result': {'type': 'string'},
+            'traceback': {'type': ['string', 'null']}
+        },
+        'required': ['event', 'start_time', 'finish_time', 'result',
+                     'traceback']
+    }
+}
+
+common_get_instance_action = copy.deepcopy(common_instance_actions)
+
+common_get_instance_action['properties'].update({
+    'events': instance_action_events})
+# 'events' does not come in response body always so it is not
+# defined as 'required'
+
+base_list_servers_detail = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'servers': {
+                'type': 'array',
+                'items': common_show_server
+            }
+        },
+        'required': ['servers']
+    }
+}
diff --git a/tempest/api_schema/compute/services.py b/tempest/api_schema/compute/services.py
index 4c58013..eaba129 100644
--- a/tempest/api_schema/compute/services.py
+++ b/tempest/api_schema/compute/services.py
@@ -22,10 +22,7 @@
                 'items': {
                     'type': 'object',
                     'properties': {
-                        # NOTE: Now the type of 'id' is integer, but here
-                        # allows 'string' also because we will be able to
-                        # change it to 'uuid' in the future.
-                        'id': {'type': ['integer', 'string']},
+                        'id': {'type': 'integer'},
                         'zone': {'type': 'string'},
                         'host': {'type': 'string'},
                         'state': {'type': 'string'},
diff --git a/tempest/api_schema/compute/v2/agents.py b/tempest/api_schema/compute/v2/agents.py
index 837731f..30f999f 100644
--- a/tempest/api_schema/compute/v2/agents.py
+++ b/tempest/api_schema/compute/v2/agents.py
@@ -12,6 +12,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.api_schema.compute import agents
+
+create_agent = {
+    'status_code': [200],
+    'response_body': agents.common_create_agent
+}
+
 delete_agent = {
     'status_code': [200]
 }
diff --git a/tempest/api_schema/compute/v2/floating_ips.py b/tempest/api_schema/compute/v2/floating_ips.py
index 3ea6320..def0a78 100644
--- a/tempest/api_schema/compute/v2/floating_ips.py
+++ b/tempest/api_schema/compute/v2/floating_ips.py
@@ -27,7 +27,7 @@
                         # able to change it to 'uuid' in the future.
                         'id': {'type': ['integer', 'string']},
                         'pool': {'type': ['string', 'null']},
-                        'instance_id': {'type': ['integer', 'string', 'null']},
+                        'instance_id': {'type': ['string', 'null']},
                         'ip': {
                             'type': 'string',
                             'format': 'ip-address'
@@ -58,7 +58,7 @@
                     # 'uuid' in the future.
                     'id': {'type': ['integer', 'string']},
                     'pool': {'type': ['string', 'null']},
-                    'instance_id': {'type': ['integer', 'string', 'null']},
+                    'instance_id': {'type': ['string', 'null']},
                     'ip': {
                         'type': 'string',
                         'format': 'ip-address'
@@ -98,3 +98,61 @@
 add_remove_floating_ip = {
     'status_code': [202]
 }
+
+create_floating_ips_bulk = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'floating_ips_bulk_create': {
+                'type': 'object',
+                'properties': {
+                    'interface': {'type': ['string', 'null']},
+                    'ip_range': {'type': 'string'},
+                    'pool': {'type': ['string', 'null']},
+                },
+                'required': ['interface', 'ip_range', 'pool']
+            }
+        },
+        'required': ['floating_ips_bulk_create']
+    }
+}
+
+delete_floating_ips_bulk = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'floating_ips_bulk_delete': {'type': 'string'}
+        },
+        'required': ['floating_ips_bulk_delete']
+    }
+}
+
+list_floating_ips_bulk = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'floating_ip_info': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'address': {
+                            'type': 'string',
+                            'format': 'ip-address'
+                        },
+                        'instance_uuid': {'type': ['string', 'null']},
+                        'interface': {'type': ['string', 'null']},
+                        'pool': {'type': ['string', 'null']},
+                        'project_id': {'type': ['string', 'null']}
+                    },
+                    'required': ['address', 'instance_uuid', 'interface',
+                                 'pool', 'project_id']
+                }
+            }
+        },
+        'required': ['floating_ip_info']
+    }
+}
diff --git a/tempest/api_schema/compute/v2/images.py b/tempest/api_schema/compute/v2/images.py
index d121060..90737a2 100644
--- a/tempest/api_schema/compute/v2/images.py
+++ b/tempest/api_schema/compute/v2/images.py
@@ -30,10 +30,7 @@
         'server': {
             'type': 'object',
             'properties': {
-                # NOTE: Now the type of 'id' is integer, but here
-                # allows 'string' also because we will be able to
-                # change it to 'uuid' in the future.
-                'id': {'type': ['integer', 'string']},
+                'id': {'type': 'string'},
                 'links': parameter_types.links
             },
             'required': ['id', 'links']
diff --git a/tempest/api_schema/compute/v2/keypairs.py b/tempest/api_schema/compute/v2/keypairs.py
index 9a025c3..32d8cca 100644
--- a/tempest/api_schema/compute/v2/keypairs.py
+++ b/tempest/api_schema/compute/v2/keypairs.py
@@ -25,10 +25,7 @@
                     'public_key': {'type': 'string'},
                     'name': {'type': 'string'},
                     'fingerprint': {'type': 'string'},
-                    # NOTE: Now the type of 'user_id' is integer, but here
-                    # allows 'string' also because we will be able to change
-                    # it to 'uuid' in the future.
-                    'user_id': {'type': ['integer', 'string']},
+                    'user_id': {'type': 'string'},
                     'deleted': {'type': 'boolean'},
                     'created_at': {'type': 'string'},
                     'updated_at': {'type': ['string', 'null']},
diff --git a/tempest/api_schema/compute/v2/quota_classes.py b/tempest/api_schema/compute/v2/quota_classes.py
new file mode 100644
index 0000000..3464fb4
--- /dev/null
+++ b/tempest/api_schema/compute/v2/quota_classes.py
@@ -0,0 +1,31 @@
+# Copyright 2014 IBM 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.
+
+import copy
+
+from tempest.api_schema.compute.v2 import quotas
+
+# NOTE(mriedem): os-quota-class-sets responses are the same as os-quota-sets
+# except for the key in the response body is quota_class_set instead of
+# quota_set, so update this copy of the schema from os-quota-sets.
+quota_set = copy.deepcopy(quotas.quota_set)
+quota_set['response_body']['properties']['quota_class_set'] = (
+    quota_set['response_body']['properties'].pop('quota_set'))
+quota_set['response_body']['required'] = ['quota_class_set']
+
+quota_set_update = copy.deepcopy(quotas.quota_set_update)
+quota_set_update['response_body']['properties']['quota_class_set'] = (
+    quota_set_update['response_body']['properties'].pop('quota_set'))
+quota_set_update['response_body']['required'] = ['quota_class_set']
diff --git a/tempest/api_schema/compute/v2/servers.py b/tempest/api_schema/compute/v2/servers.py
index 981d8f7..95c5760 100644
--- a/tempest/api_schema/compute/v2/servers.py
+++ b/tempest/api_schema/compute/v2/servers.py
@@ -25,10 +25,7 @@
             'server': {
                 'type': 'object',
                 'properties': {
-                    # NOTE: Now the type of 'id' is uuid, but here allows
-                    # 'integer' also because old OpenStack uses 'integer'
-                    # as a server id.
-                    'id': {'type': ['integer', 'string']},
+                    'id': {'type': 'string'},
                     'security_groups': {'type': 'array'},
                     'links': parameter_types.links,
                     'adminPass': {'type': 'string'},
@@ -46,7 +43,7 @@
     }
 }
 
-update_server = copy.deepcopy(servers.base_update_server)
+update_server = copy.deepcopy(servers.base_update_get_server)
 update_server['response_body']['properties']['server']['properties'].update({
     'hostId': {'type': 'string'},
     'OS-DCF:diskConfig': {'type': 'string'},
@@ -60,6 +57,39 @@
     'hostId'
 )
 
+get_server = copy.deepcopy(servers.base_update_get_server)
+get_server['response_body']['properties']['server']['properties'].update({
+    'key_name': {'type': ['string', 'null']},
+    'hostId': {'type': 'string'},
+
+    # NOTE: Non-admin users also can see "OS-SRV-USG" and "OS-EXT-AZ"
+    # attributes.
+    'OS-SRV-USG:launched_at': {'type': ['string', 'null']},
+    'OS-SRV-USG:terminated_at': {'type': ['string', 'null']},
+    'OS-EXT-AZ:availability_zone': {'type': 'string'},
+
+    # NOTE: Admin users only can see "OS-EXT-STS" and "OS-EXT-SRV-ATTR"
+    # attributes.
+    'OS-EXT-STS:task_state': {'type': ['string', 'null']},
+    'OS-EXT-STS:vm_state': {'type': 'string'},
+    'OS-EXT-STS:power_state': {'type': 'integer'},
+    'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']},
+    'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
+    'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']},
+    'os-extended-volumes:volumes_attached': {'type': 'array'},
+    'OS-DCF:diskConfig': {'type': 'string'},
+    'accessIPv4': parameter_types.access_ip_v4,
+    'accessIPv6': parameter_types.access_ip_v6,
+    'config_drive': {'type': 'string'}
+})
+get_server['response_body']['properties']['server']['required'].append(
+    # NOTE: OS-SRV-USG, OS-EXT-AZ, OS-EXT-STS, OS-EXT-SRV-ATTR,
+    # os-extended-volumes, OS-DCF and accessIPv4/v6 are API
+    # extension, and some environments return a response without
+    # these attributes. So they are not 'required'.
+    'hostId'
+)
+
 list_virtual_interfaces = {
     'status_code': [200],
     'response_body': {
@@ -142,3 +172,101 @@
         'required': ['addresses']
     }
 }
+
+common_server_group = {
+    'type': 'object',
+    'properties': {
+        'id': {'type': 'string'},
+        'name': {'type': 'string'},
+        'policies': {
+            'type': 'array',
+            'items': {'type': 'string'}
+        },
+        # 'members' attribute contains the array of instance's UUID of
+        # instances present in server group
+        'members': {
+            'type': 'array',
+            'items': {'type': 'string'}
+        },
+        'metadata': {'type': 'object'}
+    },
+    'required': ['id', 'name', 'policies', 'members', 'metadata']
+}
+
+create_get_server_group = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'server_group': common_server_group
+        },
+        'required': ['server_group']
+    }
+}
+
+delete_server_group = {
+    'status_code': [204]
+}
+
+list_server_groups = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'server_groups': {
+                'type': 'array',
+                'items': common_server_group
+            }
+        },
+        'required': ['server_groups']
+    }
+}
+
+instance_actions_object = copy.deepcopy(servers.common_instance_actions)
+instance_actions_object[
+    'properties'].update({'instance_uuid': {'type': 'string'}})
+instance_actions_object['required'].extend(['instance_uuid'])
+
+list_instance_actions = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'instanceActions': {
+                'type': 'array',
+                'items': instance_actions_object
+            }
+        },
+        'required': ['instanceActions']
+    }
+}
+
+get_instance_actions_object = copy.deepcopy(servers.common_get_instance_action)
+get_instance_actions_object[
+    'properties'].update({'instance_uuid': {'type': 'string'}})
+get_instance_actions_object['required'].extend(['instance_uuid'])
+
+get_instance_action = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'instanceAction': get_instance_actions_object
+        },
+        'required': ['instanceAction']
+    }
+}
+
+list_servers_detail = copy.deepcopy(servers.base_list_servers_detail)
+list_servers_detail['response_body']['properties']['servers']['items'][
+    'properties'].update({
+        'hostId': {'type': 'string'},
+        'OS-DCF:diskConfig': {'type': 'string'},
+        'accessIPv4': parameter_types.access_ip_v4,
+        'accessIPv6': parameter_types.access_ip_v6
+    })
+# NOTE(GMann): OS-DCF:diskConfig and accessIPv4/v6 are API
+# extensions, and some environments return a response
+# without these attributes. So they are not 'required'.
+list_servers_detail['response_body']['properties']['servers']['items'][
+    'required'].append('hostId')
diff --git a/tempest/api_schema/compute/v2/volumes.py b/tempest/api_schema/compute/v2/volumes.py
index 84a659c..541d3ff 100644
--- a/tempest/api_schema/compute/v2/volumes.py
+++ b/tempest/api_schema/compute/v2/volumes.py
@@ -26,7 +26,7 @@
                     'availabilityZone': {'type': 'string'},
                     'createdAt': {'type': 'string'},
                     'displayDescription': {'type': ['string', 'null']},
-                    'volumeType': {'type': 'string'},
+                    'volumeType': {'type': ['string', 'null']},
                     'snapshotId': {'type': ['string', 'null']},
                     'metadata': {'type': 'object'},
                     'size': {'type': 'integer'},
@@ -38,7 +38,7 @@
                                 'id': {'type': 'string'},
                                 'device': {'type': 'string'},
                                 'volumeId': {'type': 'string'},
-                                'serverId': {'type': ['integer', 'string']}
+                                'serverId': {'type': 'string'}
                             }
                             # NOTE- If volume is not attached to any server
                             # then, 'attachments' attributes comes as array
@@ -74,7 +74,7 @@
                         'availabilityZone': {'type': 'string'},
                         'createdAt': {'type': 'string'},
                         'displayDescription': {'type': ['string', 'null']},
-                        'volumeType': {'type': 'string'},
+                        'volumeType': {'type': ['string', 'null']},
                         'snapshotId': {'type': ['string', 'null']},
                         'metadata': {'type': 'object'},
                         'size': {'type': 'integer'},
@@ -86,7 +86,7 @@
                                     'id': {'type': 'string'},
                                     'device': {'type': 'string'},
                                     'volumeId': {'type': 'string'},
-                                    'serverId': {'type': ['integer', 'string']}
+                                    'serverId': {'type': 'string'}
                                 }
                                 # NOTE- If volume is not attached to any server
                                 # then, 'attachments' attributes comes as array
diff --git a/tempest/api_schema/compute/v3/agents.py b/tempest/api_schema/compute/v3/agents.py
index 63d1c46..597a089 100644
--- a/tempest/api_schema/compute/v3/agents.py
+++ b/tempest/api_schema/compute/v3/agents.py
@@ -12,6 +12,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.api_schema.compute import agents
+
+create_agent = {
+    'status_code': [201],
+    'response_body': agents.common_create_agent
+}
+
 delete_agent = {
     'status_code': [204]
 }
diff --git a/tempest/api_schema/compute/v3/servers.py b/tempest/api_schema/compute/v3/servers.py
index 6716249..dc800cd 100644
--- a/tempest/api_schema/compute/v3/servers.py
+++ b/tempest/api_schema/compute/v3/servers.py
@@ -25,10 +25,7 @@
             'server': {
                 'type': 'object',
                 'properties': {
-                    # NOTE: Now the type of 'id' is uuid, but here allows
-                    # 'integer' also because old OpenStack uses 'integer'
-                    # as a server id.
-                    'id': {'type': ['integer', 'string']},
+                    'id': {'type': 'string'},
                     'os-security-groups:security_groups': {'type': 'array'},
                     'links': parameter_types.links,
                     'admin_password': {'type': 'string'},
@@ -57,7 +54,7 @@
         ['type', 'mac_addr']
     )
 
-update_server = copy.deepcopy(servers.base_update_server)
+update_server = copy.deepcopy(servers.base_update_get_server)
 update_server['response_body']['properties']['server']['properties'].update({
     'addresses': addresses_v3,
     'host_id': {'type': 'string'},
@@ -71,6 +68,43 @@
     'host_id'
 )
 
+get_server = copy.deepcopy(servers.base_update_get_server)
+get_server['response_body']['properties']['server']['properties'].update({
+    'key_name': {'type': ['string', 'null']},
+    'host_id': {'type': 'string'},
+
+    # NOTE: Non-admin users also can see "os-server-usage" and
+    # "os-extended-availability-zone" attributes.
+    'os-server-usage:launched_at': {'type': ['string', 'null']},
+    'os-server-usage:terminated_at': {'type': ['string', 'null']},
+    'os-extended-availability-zone:availability_zone': {'type': 'string'},
+
+    # NOTE: Admin users only can see "os-extended-status" and
+    # "os-extended-server-attributes" attributes.
+    'os-extended-status:task_state': {'type': ['string', 'null']},
+    'os-extended-status:vm_state': {'type': 'string'},
+    'os-extended-status:power_state': {'type': 'integer'},
+    'os-extended-status:locked_by': {'type': ['string', 'null']},
+    'os-extended-server-attributes:host': {'type': ['string', 'null']},
+    'os-extended-server-attributes:instance_name': {'type': 'string'},
+    'os-extended-server-attributes:hypervisor_hostname': {
+        'type': ['string', 'null']
+    },
+    'os-extended-volumes:volumes_attached': {'type': 'array'},
+    'os-pci:pci_devices': {'type': 'array'},
+    'os-access-ips:access_ip_v4': parameter_types.access_ip_v4,
+    'os-access-ips:access_ip_v6': parameter_types.access_ip_v6,
+    'os-config-drive:config_drive': {'type': 'string'}
+})
+get_server['response_body']['properties']['server']['required'].append(
+    # NOTE: os-server-usage, os-extended-availability-zone,
+    # os-extended-status, os-extended-server-attributes,
+    # os-extended-volumes, os-pci, os-access-ips and
+    # os-config-driveare API extension, and some environments
+    # return a response without these attributes. So they are not 'required'.
+    'host_id'
+)
+
 attach_detach_volume = {
     'status_code': [202]
 }
@@ -99,3 +133,51 @@
 update_server_metadata = copy.deepcopy(servers.update_server_metadata)
 # V3 API's response status_code is 201
 update_server_metadata['status_code'] = [201]
+
+server_actions_object = copy.deepcopy(servers.common_instance_actions)
+server_actions_object['properties'].update({'server_uuid': {'type': 'string'}})
+server_actions_object['required'].extend(['server_uuid'])
+
+list_server_actions = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'server_actions': {
+                'type': 'array',
+                'items': server_actions_object
+            }
+        },
+        'required': ['server_actions']
+    }
+}
+
+get_server_actions_object = copy.deepcopy(servers.common_get_instance_action)
+get_server_actions_object[
+    'properties'].update({'server_uuid': {'type': 'string'}})
+get_server_actions_object['required'].extend(['server_uuid'])
+
+get_server_action = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'server_action': get_server_actions_object
+        },
+        'required': ['server_action']
+    }
+}
+
+list_servers_detail = copy.deepcopy(servers.base_list_servers_detail)
+list_servers_detail['response_body']['properties']['servers']['items'][
+    'properties'].update({
+        'addresses': addresses_v3,
+        'host_id': {'type': 'string'},
+        'os-access-ips:access_ip_v4': parameter_types.access_ip_v4,
+        'os-access-ips:access_ip_v6': parameter_types.access_ip_v6
+    })
+# NOTE(GMann): os-access-ips:access_ip_v4/v6 are API extension,
+# and some environments return a response without these
+# attributes. So they are not 'required'.
+list_servers_detail['response_body']['properties']['servers']['items'][
+    'required'].append('host_id')
diff --git a/tempest/api_schema/queuing/v1/queues.py b/tempest/api_schema/queuing/v1/queues.py
index 4630e1c..f0b2691 100644
--- a/tempest/api_schema/queuing/v1/queues.py
+++ b/tempest/api_schema/queuing/v1/queues.py
@@ -14,6 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+
 list_link = {
     'type': 'object',
     'properties': {
@@ -58,6 +59,11 @@
     }
 }
 
+age = {
+    'type': 'number',
+    'minimum': 0
+}
+
 message_link = {
     'type': 'object',
     'properties': {
@@ -65,7 +71,7 @@
             'type': 'string',
             'format': 'uri'
         },
-        'age': {'type': 'number'},
+        'age': age,
         'created': {
             'type': 'string',
             'format': 'date-time'
@@ -96,3 +102,136 @@
         'required': ['messages']
     }
 }
+
+resource_schema = {
+    'type': 'array',
+    'items': 'string',
+    'minItems': 1
+}
+
+post_messages = {
+    'status_code': [201],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'resources': resource_schema,
+            'partial': {'type': 'boolean'}
+        }
+    },
+    'required': ['resources', 'partial']
+}
+
+message_ttl = {
+    'type': 'number',
+    'minimum': 1
+}
+
+list_messages_links = {
+    'type': 'array',
+    'maxItems': 1,
+    'minItems': 1,
+    'items': {
+        'type': 'object',
+        'properties': {
+            'rel': {'type': 'string'},
+            'href': {'type': 'string'}
+        },
+        'required': ['rel', 'href']
+    }
+}
+
+list_messages_response = {
+    'type': 'array',
+    'minItems': 1,
+    'items': {
+        'type': 'object',
+        'properties': {
+            'href': {'type': 'string'},
+            'ttl': message_ttl,
+            'age': age,
+            'body': {'type': 'object'}
+        },
+        'required': ['href', 'ttl', 'age', 'body']
+    }
+}
+
+list_messages = {
+    'status_code': [200, 204],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'links': list_messages_links,
+            'messages': list_messages_response
+        }
+    },
+    'required': ['links', 'messages']
+}
+
+single_message = {
+    'type': 'object',
+    'properties': {
+        'href': {'type': 'string'},
+        'ttl': message_ttl,
+        'age': age,
+        'body': {'type': 'object'}
+    },
+    'required': ['href', 'ttl', 'age', 'body']
+}
+
+get_single_message = {
+    'status_code': [200],
+    'response_body': single_message
+}
+
+get_multiple_messages = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'array',
+        'items': single_message,
+        'minItems': 1
+    }
+}
+
+messages_claimed = {
+    'type': 'object',
+    'properties': {
+        'href': {
+            'type': 'string',
+            'format': 'uri'
+        },
+        'ttl': message_ttl,
+        'age': {'type': 'number'},
+        'body': {'type': 'object'}
+    },
+    'required': ['href', 'ttl', 'age', 'body']
+}
+
+claim_messages = {
+    'status_code': [201, 204],
+    'response_body': {
+        'type': 'array',
+        'items': messages_claimed,
+        'minItems': 1
+    }
+}
+
+claim_ttl = {
+    'type': 'number',
+    'minimum': 1
+}
+
+query_claim = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'age': {'type': 'number'},
+            'ttl': claim_ttl,
+            'messages': {
+                'type': 'array',
+                'minItems': 1
+            }
+        },
+        'required': ['ttl', 'age', 'messages']
+    }
+}
diff --git a/tempest/auth.py b/tempest/auth.py
index 9c51edb..830dca9 100644
--- a/tempest/auth.py
+++ b/tempest/auth.py
@@ -213,7 +213,7 @@
         # build authenticated request
         # returns new request, it does not touch the original values
         _headers = copy.deepcopy(headers) if headers is not None else {}
-        _headers['X-Auth-Token'] = token
+        _headers['X-Auth-Token'] = str(token)
         if url is None or url == "":
             _url = base_url
         else:
@@ -223,7 +223,7 @@
             parts[2] = re.sub("/{2,}", "/", parts[2])
             _url = urlparse.urlunparse(parts)
         # no change to method or body
-        return _url, _headers, body
+        return str(_url), _headers, body
 
     def _auth_client(self):
         raise NotImplementedError
diff --git a/tempest/cli/__init__.py b/tempest/cli/__init__.py
index 6aa98c4..d7b4a16 100644
--- a/tempest/cli/__init__.py
+++ b/tempest/cli/__init__.py
@@ -83,20 +83,27 @@
         return self.cmd_with_auth(
             'cinder', action, flags, params, admin, fail_ok)
 
+    def swift(self, action, flags='', params='', admin=True, fail_ok=False):
+        """Executes swift command for the given action."""
+        flags += ' --os-endpoint-type %s' % CONF.object_storage.endpoint_type
+        return self.cmd_with_auth(
+            'swift', action, flags, params, admin, fail_ok)
+
     def neutron(self, action, flags='', params='', admin=True, fail_ok=False):
         """Executes neutron command for the given action."""
         flags += ' --endpoint-type %s' % CONF.network.endpoint_type
         return self.cmd_with_auth(
             'neutron', action, flags, params, admin, fail_ok)
 
-    def sahara(self, action, flags='', params='', admin=True, fail_ok=False):
+    def sahara(self, action, flags='', params='', admin=True,
+               fail_ok=False, merge_stderr=True):
         """Executes sahara command for the given action."""
         flags += ' --endpoint-type %s' % CONF.data_processing.endpoint_type
         return self.cmd_with_auth(
-            'sahara', action, flags, params, admin, fail_ok)
+            'sahara', action, flags, params, admin, fail_ok, merge_stderr)
 
     def cmd_with_auth(self, cmd, action, flags='', params='',
-                      admin=True, fail_ok=False):
+                      admin=True, fail_ok=False, merge_stderr=False):
         """Executes given command with auth attributes appended."""
         # TODO(jogo) make admin=False work
         creds = ('--os-username %s --os-tenant-name %s --os-password %s '
@@ -106,7 +113,7 @@
                   CONF.identity.admin_password,
                   CONF.identity.uri))
         flags = creds + ' ' + flags
-        return self.cmd(cmd, action, flags, params, fail_ok)
+        return self.cmd(cmd, action, flags, params, fail_ok, merge_stderr)
 
     def cmd(self, cmd, action, flags='', params='', fail_ok=False,
             merge_stderr=False):
@@ -114,7 +121,7 @@
         cmd = ' '.join([os.path.join(CONF.cli.cli_dir, cmd),
                         flags, action, params])
         LOG.info("running: '%s'" % cmd)
-        cmd = shlex.split(cmd)
+        cmd = shlex.split(cmd.encode('utf-8'))
         result = ''
         result_err = ''
         stdout = subprocess.PIPE
@@ -126,7 +133,7 @@
             raise CommandFailed(proc.returncode,
                                 cmd,
                                 result,
-                                stderr=result_err)
+                                result_err)
         return result
 
     def assertTableStruct(self, items, field_names):
@@ -141,9 +148,15 @@
                              % lines[:3]))
 
 
-class CommandFailed(subprocess.CalledProcessError):
-    # adds output attribute for python2.6
-    def __init__(self, returncode, cmd, output, stderr=""):
-        super(CommandFailed, self).__init__(returncode, cmd)
-        self.output = output
+class CommandFailed(Exception):
+    def __init__(self, returncode, cmd, output, stderr):
+        super(CommandFailed, self).__init__()
+        self.returncode = returncode
+        self.cmd = cmd
+        self.stdout = output
         self.stderr = stderr
+
+    def __str__(self):
+        return ("Command '%s' returned non-zero exit status %d.\n"
+        "stdout:\n%s\n"
+        "stderr:\n%s" % (self.cmd, self.returncode, self.stdout, self.stderr))
diff --git a/tempest/cli/simple_read_only/test_cinder.py b/tempest/cli/simple_read_only/test_cinder.py
index 723333b..9a6b159 100644
--- a/tempest/cli/simple_read_only/test_cinder.py
+++ b/tempest/cli/simple_read_only/test_cinder.py
@@ -15,17 +15,16 @@
 
 import logging
 import re
-import subprocess
 import testtools
 
-import tempest.cli
+from tempest import cli
 from tempest import config
 
 CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
 
-class SimpleReadOnlyCinderClientTest(tempest.cli.ClientTestBase):
+class SimpleReadOnlyCinderClientTest(cli.ClientTestBase):
     """Basic, read-only tests for Cinder CLI client.
 
     Checks return values and output of read-only commands.
@@ -41,7 +40,7 @@
         super(SimpleReadOnlyCinderClientTest, cls).setUpClass()
 
     def test_cinder_fake_action(self):
-        self.assertRaises(subprocess.CalledProcessError,
+        self.assertRaises(cli.CommandFailed,
                           self.cinder,
                           'this-does-not-exist')
 
@@ -50,16 +49,23 @@
         self.assertTableStruct(roles, ['Name', 'Value'])
 
     def test_cinder_backup_list(self):
-        self.cinder('backup-list')
+        backup_list = self.parser.listing(self.cinder('backup-list'))
+        self.assertTableStruct(backup_list, ['ID', 'Volume ID', 'Status',
+                                             'Name', 'Size', 'Object Count',
+                                             'Container'])
 
     def test_cinder_extra_specs_list(self):
-        self.cinder('extra-specs-list')
+        extra_specs_list = self.parser.listing(self.cinder('extra-specs-list'))
+        self.assertTableStruct(extra_specs_list, ['ID', 'Name', 'extra_specs'])
 
     def test_cinder_volumes_list(self):
-        self.cinder('list')
+        list = self.parser.listing(self.cinder('list'))
+        self.assertTableStruct(list, ['ID', 'Status', 'Name', 'Size',
+                                      'Volume Type', 'Bootable',
+                                      'Attached to'])
         self.cinder('list', params='--all-tenants 1')
         self.cinder('list', params='--all-tenants 0')
-        self.assertRaises(subprocess.CalledProcessError,
+        self.assertRaises(cli.CommandFailed,
                           self.cinder,
                           'list',
                           params='--all-tenants bad')
@@ -85,39 +91,60 @@
         self.assertTableStruct(roles, ['Property', 'Value'])
 
     def test_cinder_rate_limits(self):
-        self.cinder('rate-limits')
+        rate_limits = self.parser.listing(self.cinder('rate-limits'))
+        self.assertTableStruct(rate_limits, ['Verb', 'URI', 'Value', 'Remain',
+                                             'Unit', 'Next_Available'])
 
     @testtools.skipUnless(CONF.volume_feature_enabled.snapshot,
                           'Volume snapshot not available.')
     def test_cinder_snapshot_list(self):
-        self.cinder('snapshot-list')
+        snapshot_list = self.parser.listing(self.cinder('snapshot-list'))
+        self.assertTableStruct(snapshot_list, ['ID', 'Volume ID', 'Status',
+                                               'Name', 'Size'])
 
     def test_cinder_type_list(self):
-        self.cinder('type-list')
+        type_list = self.parser.listing(self.cinder('type-list'))
+        self.assertTableStruct(type_list, ['ID', 'Name'])
 
     def test_cinder_list_extensions(self):
-        self.cinder('list-extensions')
         roles = self.parser.listing(self.cinder('list-extensions'))
         self.assertTableStruct(roles, ['Name', 'Summary', 'Alias', 'Updated'])
 
     def test_cinder_credentials(self):
-        self.cinder('credentials')
+        credentials = self.parser.listing(self.cinder('credentials'))
+        self.assertTableStruct(credentials, ['User Credentials', 'Value'])
 
     def test_cinder_availability_zone_list(self):
-        self.cinder('availability-zone-list')
+        zone_list = self.parser.listing(self.cinder('availability-zone-list'))
+        self.assertTableStruct(zone_list, ['Name', 'Status'])
 
     def test_cinder_endpoints(self):
-        self.cinder('endpoints')
+        endpoints = self.parser.listing(self.cinder('endpoints'))
+        self.assertTableStruct(endpoints, ['nova', 'Value'])
 
     def test_cinder_service_list(self):
-        self.cinder('service-list')
+        service_list = self.parser.listing(self.cinder('service-list'))
+        self.assertTableStruct(service_list, ['Binary', 'Host', 'Zone',
+                                              'Status', 'State', 'Updated_at',
+                                              'Disabled Reason'])
 
     def test_cinder_transfer_list(self):
-        self.cinder('transfer-list')
+        transfer_list = self.parser.listing(self.cinder('transfer-list'))
+        self.assertTableStruct(transfer_list, ['ID', 'Volume ID', 'Name'])
 
     def test_cinder_bash_completion(self):
         self.cinder('bash-completion')
 
+    def test_cinder_qos_list(self):
+        qos_list = self.parser.listing(self.cinder('qos-list'))
+        self.assertTableStruct(qos_list, ['ID', 'Name', 'Consumer', 'specs'])
+
+    def test_cinder_encryption_type_list(self):
+        encrypt_list = self.parser.listing(self.cinder('encryption-type-list'))
+        self.assertTableStruct(encrypt_list, ['Volume Type ID', 'Provider',
+                                              'Cipher', 'Key Size',
+                                              'Control Location'])
+
     def test_admin_help(self):
         help_text = self.cinder('help')
         lines = help_text.split('\n')
@@ -136,7 +163,7 @@
                                'quota-show', 'type-list', 'snapshot-list'))
         self.assertFalse(wanted_commands - commands)
 
-     # Optional arguments:
+    # Optional arguments:
 
     def test_cinder_version(self):
         self.cinder('', flags='--version')
diff --git a/tempest/cli/simple_read_only/test_glance.py b/tempest/cli/simple_read_only/test_glance.py
index 9869483..3fb1120 100644
--- a/tempest/cli/simple_read_only/test_glance.py
+++ b/tempest/cli/simple_read_only/test_glance.py
@@ -14,9 +14,8 @@
 #    under the License.
 
 import re
-import subprocess
 
-import tempest.cli
+from tempest import cli
 from tempest import config
 from tempest.openstack.common import log as logging
 
@@ -25,7 +24,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class SimpleReadOnlyGlanceClientTest(tempest.cli.ClientTestBase):
+class SimpleReadOnlyGlanceClientTest(cli.ClientTestBase):
     """Basic, read-only tests for Glance CLI client.
 
     Checks return values and output of read-only commands.
@@ -41,7 +40,7 @@
         super(SimpleReadOnlyGlanceClientTest, cls).setUpClass()
 
     def test_glance_fake_action(self):
-        self.assertRaises(subprocess.CalledProcessError,
+        self.assertRaises(cli.CommandFailed,
                           self.glance,
                           'this-does-not-exist')
 
@@ -76,7 +75,7 @@
         commands = set(commands)
         wanted_commands = set(('image-create', 'image-delete', 'help',
                                'image-download', 'image-show', 'image-update',
-                               'member-add', 'member-create', 'member-delete',
+                               'member-create', 'member-delete',
                                'member-list'))
         self.assertFalse(wanted_commands - commands)
 
diff --git a/tempest/cli/simple_read_only/test_keystone.py b/tempest/cli/simple_read_only/test_keystone.py
index 1efbede..f8dcdba 100644
--- a/tempest/cli/simple_read_only/test_keystone.py
+++ b/tempest/cli/simple_read_only/test_keystone.py
@@ -14,9 +14,8 @@
 #    under the License.
 
 import re
-import subprocess
 
-import tempest.cli
+from tempest import cli
 from tempest import config
 from tempest.openstack.common import log as logging
 
@@ -26,7 +25,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class SimpleReadOnlyKeystoneClientTest(tempest.cli.ClientTestBase):
+class SimpleReadOnlyKeystoneClientTest(cli.ClientTestBase):
     """Basic, read-only tests for Keystone CLI client.
 
     Checks return values and output of read-only commands.
@@ -35,7 +34,7 @@
     """
 
     def test_admin_fake_action(self):
-        self.assertRaises(subprocess.CalledProcessError,
+        self.assertRaises(cli.CommandFailed,
                           self.keystone,
                           'this-does-not-exist')
 
@@ -117,6 +116,11 @@
     def test_admin_bashcompletion(self):
         self.keystone('bash-completion')
 
+    def test_admin_ec2_credentials_list(self):
+        creds = self.keystone('ec2-credentials-list')
+        creds = self.parser.listing(creds)
+        self.assertTableStruct(creds, ['tenant', 'access', 'secret'])
+
     # Optional arguments:
 
     def test_admin_version(self):
diff --git a/tempest/cli/simple_read_only/test_neutron.py b/tempest/cli/simple_read_only/test_neutron.py
index c1d58b5..2643596 100644
--- a/tempest/cli/simple_read_only/test_neutron.py
+++ b/tempest/cli/simple_read_only/test_neutron.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 import re
-import subprocess
 
 from tempest import cli
 from tempest import config
@@ -43,13 +42,14 @@
 
     @test.attr(type='smoke')
     def test_neutron_fake_action(self):
-        self.assertRaises(subprocess.CalledProcessError,
+        self.assertRaises(cli.CommandFailed,
                           self.neutron,
                           'this-does-not-exist')
 
     @test.attr(type='smoke')
     def test_neutron_net_list(self):
-        self.neutron('net-list')
+        net_list = self.parser.listing(self.neutron('net-list'))
+        self.assertTableStruct(net_list, ['id', 'name', 'subnets'])
 
     @test.attr(type='smoke')
     def test_neutron_ext_list(self):
@@ -111,11 +111,14 @@
     @test.attr(type='smoke')
     @test.requires_ext(extension='external-net', service='network')
     def test_neutron_net_external_list(self):
-        self.neutron('net-external-list')
+        net_ext_list = self.parser.listing(self.neutron('net-external-list'))
+        self.assertTableStruct(net_ext_list, ['id', 'name', 'subnets'])
 
     @test.attr(type='smoke')
     def test_neutron_port_list(self):
-        self.neutron('port-list')
+        port_list = self.parser.listing(self.neutron('port-list'))
+        self.assertTableStruct(port_list, ['id', 'name', 'mac_address',
+                                           'fixed_ips'])
 
     @test.attr(type='smoke')
     @test.requires_ext(extension='quotas', service='network')
@@ -125,7 +128,9 @@
     @test.attr(type='smoke')
     @test.requires_ext(extension='router', service='network')
     def test_neutron_router_list(self):
-        self.neutron('router-list')
+        router_list = self.parser.listing(self.neutron('router-list'))
+        self.assertTableStruct(router_list, ['id', 'name',
+                                             'external_gateway_info'])
 
     @test.attr(type='smoke')
     @test.requires_ext(extension='security-group', service='network')
@@ -136,11 +141,18 @@
     @test.attr(type='smoke')
     @test.requires_ext(extension='security-group', service='network')
     def test_neutron_security_group_rule_list(self):
-        self.neutron('security-group-rule-list')
+        security_grp = self.parser.listing(self.neutron
+                                           ('security-group-rule-list'))
+        self.assertTableStruct(security_grp, ['id', 'security_group',
+                                              'direction', 'protocol',
+                                              'remote_ip_prefix',
+                                              'remote_group'])
 
     @test.attr(type='smoke')
     def test_neutron_subnet_list(self):
-        self.neutron('subnet-list')
+        subnet_list = self.parser.listing(self.neutron('subnet-list'))
+        self.assertTableStruct(subnet_list, ['id', 'name', 'cidr',
+                                             'allocation_pools'])
 
     @test.attr(type='smoke')
     def test_neutron_help(self):
diff --git a/tempest/cli/simple_read_only/test_nova.py b/tempest/cli/simple_read_only/test_nova.py
index 1c1ddf1..70eb9ef 100644
--- a/tempest/cli/simple_read_only/test_nova.py
+++ b/tempest/cli/simple_read_only/test_nova.py
@@ -13,11 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import subprocess
-
 import testtools
 
-import tempest.cli
+from tempest import cli
 from tempest import config
 from tempest.openstack.common import log as logging
 import tempest.test
@@ -27,7 +25,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class SimpleReadOnlyNovaClientTest(tempest.cli.ClientTestBase):
+class SimpleReadOnlyNovaClientTest(cli.ClientTestBase):
 
     """
     This is a first pass at a simple read only python-novaclient test. This
@@ -49,7 +47,7 @@
         super(SimpleReadOnlyNovaClientTest, cls).setUpClass()
 
     def test_admin_fake_action(self):
-        self.assertRaises(subprocess.CalledProcessError,
+        self.assertRaises(cli.CommandFailed,
                           self.nova,
                           'this-does-nova-exist')
 
@@ -86,11 +84,11 @@
         self.nova('endpoints')
 
     def test_admin_flavor_acces_list(self):
-        self.assertRaises(subprocess.CalledProcessError,
+        self.assertRaises(cli.CommandFailed,
                           self.nova,
                           'flavor-access-list')
         # Failed to get access list for public flavor type
-        self.assertRaises(subprocess.CalledProcessError,
+        self.assertRaises(cli.CommandFailed,
                           self.nova,
                           'flavor-access-list',
                           params='--flavor m1.tiny')
@@ -127,7 +125,7 @@
         self.nova('list')
         self.nova('list', params='--all-tenants 1')
         self.nova('list', params='--all-tenants 0')
-        self.assertRaises(subprocess.CalledProcessError,
+        self.assertRaises(cli.CommandFailed,
                           self.nova,
                           'list',
                           params='--all-tenants bad')
diff --git a/tempest/cli/simple_read_only/test_nova_manage.py b/tempest/cli/simple_read_only/test_nova_manage.py
index f1fee2e..67c19d8 100644
--- a/tempest/cli/simple_read_only/test_nova_manage.py
+++ b/tempest/cli/simple_read_only/test_nova_manage.py
@@ -13,9 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import subprocess
-
-import tempest.cli
+from tempest import cli
 from tempest import config
 from tempest.openstack.common import log as logging
 
@@ -24,7 +22,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class SimpleReadOnlyNovaManageTest(tempest.cli.ClientTestBase):
+class SimpleReadOnlyNovaManageTest(cli.ClientTestBase):
 
     """
     This is a first pass at a simple read only nova-manage test. This
@@ -48,7 +46,7 @@
         super(SimpleReadOnlyNovaManageTest, cls).setUpClass()
 
     def test_admin_fake_action(self):
-        self.assertRaises(subprocess.CalledProcessError,
+        self.assertRaises(cli.CommandFailed,
                           self.nova_manage,
                           'this-does-nova-exist')
 
diff --git a/tempest/cli/simple_read_only/test_sahara.py b/tempest/cli/simple_read_only/test_sahara.py
index 36cc324..773921a 100644
--- a/tempest/cli/simple_read_only/test_sahara.py
+++ b/tempest/cli/simple_read_only/test_sahara.py
@@ -12,9 +12,8 @@
 # implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-
 import logging
-import subprocess
+import re
 
 from tempest import cli
 from tempest import config
@@ -42,7 +41,7 @@
 
     @test.attr(type='negative')
     def test_sahara_fake_action(self):
-        self.assertRaises(subprocess.CalledProcessError,
+        self.assertRaises(cli.CommandFailed,
                           self.sahara,
                           'this-does-not-exist')
 
@@ -138,3 +137,30 @@
             'cluster_id',
             'status'
         ])
+
+    def test_sahara_bash_completion(self):
+        self.sahara('bash-completion')
+
+    # Optional arguments
+    def test_sahara_help(self):
+        help_text = self.sahara('help')
+        lines = help_text.split('\n')
+        self.assertFirstLineStartsWith(lines, 'usage: sahara')
+
+        commands = []
+        cmds_start = lines.index('Positional arguments:')
+        cmds_end = lines.index('Optional arguments:')
+        command_pattern = re.compile('^ {4}([a-z0-9\-\_]+)')
+        for line in lines[cmds_start:cmds_end]:
+            match = command_pattern.match(line)
+            if match:
+                commands.append(match.group(1))
+        commands = set(commands)
+        wanted_commands = set(('cluster-create', 'data-source-create',
+                               'image-unregister', 'job-binary-create',
+                               'plugin-list', 'job-binary-create', 'help'))
+        self.assertFalse(wanted_commands - commands)
+
+    def test_sahara_version(self):
+        version = self.sahara('', flags='--version')
+        self.assertTrue(re.search('[0-9.]+', version))
diff --git a/tempest/cli/simple_read_only/test_swift.py b/tempest/cli/simple_read_only/test_swift.py
new file mode 100644
index 0000000..c778542
--- /dev/null
+++ b/tempest/cli/simple_read_only/test_swift.py
@@ -0,0 +1,94 @@
+# Copyright 2014 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 re
+
+from tempest import cli
+from tempest import config
+
+CONF = config.CONF
+
+
+class SimpleReadOnlySwiftClientTest(cli.ClientTestBase):
+    """Basic, read-only tests for Swift CLI client.
+
+    Checks return values and output of read-only commands.
+    These tests do not presume any content, nor do they create
+    their own. They only verify the structure of output if present.
+    """
+
+    @classmethod
+    def setUpClass(cls):
+        if not CONF.service_available.swift:
+            msg = ("%s skipped as Swift is not available" % cls.__name__)
+            raise cls.skipException(msg)
+        super(SimpleReadOnlySwiftClientTest, cls).setUpClass()
+
+    def test_swift_fake_action(self):
+        self.assertRaises(cli.CommandFailed,
+                          self.swift,
+                          'this-does-not-exist')
+
+    def test_swift_list(self):
+        self.swift('list')
+
+    def test_swift_stat(self):
+        output = self.swift('stat')
+        entries = ['Account', 'Containers', 'Objects', 'Bytes', 'Content-Type',
+                   'X-Timestamp', 'X-Trans-Id']
+        for entry in entries:
+            self.assertTrue(entry in output)
+
+    def test_swift_capabilities(self):
+        output = self.swift('capabilities')
+        entries = ['account_listing_limit', 'container_listing_limit',
+                   'max_file_size', 'Additional middleware']
+        for entry in entries:
+            self.assertTrue(entry in output)
+
+    def test_swift_help(self):
+        help_text = self.swift('', flags='--help')
+        lines = help_text.split('\n')
+        self.assertFirstLineStartsWith(lines, 'Usage: swift')
+
+        commands = []
+        cmds_start = lines.index('Positional arguments:')
+        cmds_end = lines.index('Examples:')
+        command_pattern = re.compile('^ {4}([a-z0-9\-\_]+)')
+        for line in lines[cmds_start:cmds_end]:
+            match = command_pattern.match(line)
+            if match:
+                commands.append(match.group(1))
+        commands = set(commands)
+        wanted_commands = set(('stat', 'list', 'delete',
+                               'download', 'post', 'upload'))
+        self.assertFalse(wanted_commands - commands)
+
+    # Optional arguments:
+
+    def test_swift_version(self):
+        self.swift('', flags='--version')
+
+    def test_swift_debug_list(self):
+        self.swift('list', flags='--debug')
+
+    def test_swift_retries_list(self):
+        self.swift('list', flags='--retries 3')
+
+    def test_swift_region_list(self):
+        region = CONF.object_storage.region
+        if not region:
+            region = CONF.identity.region
+        self.swift('list', flags='--os-region-name ' + region)
diff --git a/tempest/clients.py b/tempest/clients.py
index 7532bf2..4e2205e 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -50,6 +50,7 @@
 from tempest.services.compute.json.limits_client import LimitsClientJSON
 from tempest.services.compute.json.migrations_client import \
     MigrationsClientJSON
+from tempest.services.compute.json.quotas_client import QuotaClassesClientJSON
 from tempest.services.compute.json.quotas_client import QuotasClientJSON
 from tempest.services.compute.json.security_groups_client import \
     SecurityGroupsClientJSON
@@ -105,6 +106,7 @@
     InterfacesClientXML
 from tempest.services.compute.xml.keypairs_client import KeyPairsClientXML
 from tempest.services.compute.xml.limits_client import LimitsClientXML
+from tempest.services.compute.xml.quotas_client import QuotaClassesClientXML
 from tempest.services.compute.xml.quotas_client import QuotasClientXML
 from tempest.services.compute.xml.security_groups_client \
     import SecurityGroupsClientXML
@@ -220,6 +222,8 @@
             self.images_client = ImagesClientXML(self.auth_provider)
             self.keypairs_client = KeyPairsClientXML(self.auth_provider)
             self.quotas_client = QuotasClientXML(self.auth_provider)
+            self.quota_classes_client = QuotaClassesClientXML(
+                self.auth_provider)
             self.flavors_client = FlavorsClientXML(self.auth_provider)
             self.extensions_client = ExtensionsClientXML(self.auth_provider)
             self.volumes_extensions_client = VolumesExtensionsClientXML(
@@ -288,6 +292,8 @@
             self.keypairs_v3_client = KeyPairsV3ClientJSON(
                 self.auth_provider)
             self.quotas_client = QuotasClientJSON(self.auth_provider)
+            self.quota_classes_client = QuotaClassesClientJSON(
+                self.auth_provider)
             self.quotas_v3_client = QuotasV3ClientJSON(self.auth_provider)
             self.flavors_client = FlavorsClientJSON(self.auth_provider)
             self.flavors_v3_client = FlavorsV3ClientJSON(self.auth_provider)
@@ -456,6 +462,7 @@
     HEATCLIENT_VERSION = '1'
     IRONICCLIENT_VERSION = '1'
     SAHARACLIENT_VERSION = '1.1'
+    CEILOMETERCLIENT_VERSION = '2'
 
     def __init__(self, credentials):
         # FIXME(andreaf) Auth provider for client_type 'official' is
@@ -476,6 +483,8 @@
             credentials)
         self.data_processing_client = self._get_data_processing_client(
             credentials)
+        self.ceilometer_client = self._get_ceilometer_client(
+            credentials)
 
     def _get_roles(self):
         admin_credentials = auth.get_default_credentials('identity_admin')
@@ -696,3 +705,34 @@
             auth_url=auth_url)
 
         return client
+
+    def _get_ceilometer_client(self, credentials):
+        if not CONF.service_available.ceilometer:
+            return None
+
+        import ceilometerclient.client
+
+        keystone = self._get_identity_client(credentials)
+        region = CONF.identity.region
+
+        endpoint_type = CONF.telemetry.endpoint_type
+        service_type = CONF.telemetry.catalog_type
+        auth_url = CONF.identity.uri
+
+        try:
+            keystone.service_catalog.url_for(
+                attr='region',
+                filter_value=region,
+                service_type=service_type,
+                endpoint_type=endpoint_type)
+        except keystoneclient.exceptions.EndpointNotFound:
+            return None
+        else:
+            return ceilometerclient.client.get_client(
+                self.CEILOMETERCLIENT_VERSION,
+                os_username=credentials.username,
+                os_password=credentials.password,
+                os_tenant_name=credentials.tenant_name,
+                os_auth_url=auth_url,
+                os_service_type=service_type,
+                os_endpoint_type=endpoint_type)
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index 20ee63e..c1a2e46 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -28,6 +28,7 @@
 import argparse
 
 import tempest.auth
+from tempest import config
 from tempest import exceptions
 from tempest.services.compute.json import flavors_client
 from tempest.services.compute.json import servers_client
@@ -35,6 +36,7 @@
 from tempest.services.image.v2.json import image_client
 from tempest.services.object_storage import container_client
 from tempest.services.object_storage import object_client
+from tempest.services.volume.json import volumes_client
 
 OPTS = {}
 USERS = {}
@@ -60,6 +62,7 @@
         self.containers = container_client.ContainerClient(_auth)
         self.images = image_client.ImageClientV2JSON(_auth)
         self.flavors = flavors_client.FlavorsClientJSON(_auth)
+        self.volumes = volumes_client.VolumesClientJSON(_auth)
 
 
 def load_resources(fname):
@@ -167,7 +170,7 @@
 
 def collect_users(users):
     global USERS
-    LOG.info("Creating users")
+    LOG.info("Collecting users")
     admin = keystone_admin()
     for u in users:
         tenant = admin.identity.get_tenant_by_name(u['tenant'])
@@ -190,6 +193,9 @@
         self.check_users()
         self.check_objects()
         self.check_servers()
+        # TODO(sdague): Volumes not yet working, bring it back once the
+        # code is self testing.
+        # self.check_volumes()
 
     def check_users(self):
         """Check that the users we expect to exist, do.
@@ -197,6 +203,7 @@
         We don't use the resource list for this because we need to validate
         that things like tenantId didn't drift across versions.
         """
+        LOG.info("checking users")
         for name, user in self.users.iteritems():
             client = keystone_admin()
             _, found = client.identity.get_user(user['id'])
@@ -212,6 +219,9 @@
 
     def check_objects(self):
         """Check that the objects created are still there."""
+        if 'objects' not in self.res:
+            return
+        LOG.info("checking objects")
         for obj in self.res['objects']:
             client = client_for_user(obj['owner'])
             r, contents = client.objects.get_object(
@@ -221,6 +231,9 @@
 
     def check_servers(self):
         """Check that the servers are still up and running."""
+        if 'servers' not in self.res:
+            return
+        LOG.info("checking servers")
         for server in self.res['servers']:
             client = client_for_user(server['owner'])
             found = _get_server_by_name(client, server['name'])
@@ -231,9 +244,31 @@
             r, found = client.servers.get_server(found['id'])
             # get the ipv4 address
             addr = found['addresses']['private'][0]['addr']
-            self.assertEqual(os.system("ping -c 1 " + addr), 0,
-                             "Server %s is not pingable at %s" % (
-                                 server['name'], addr))
+            for count in range(60):
+                return_code = os.system("ping -c1 " + addr)
+                if return_code is 0:
+                    break
+            self.assertNotEqual(count, 59,
+                               "Server %s is not pingable at %s" % (
+                               server['name'], addr))
+
+    def check_volumes(self):
+        """Check that the volumes are still there and attached."""
+        if 'volumes' not in self.res:
+            return
+        LOG.info("checking volumes")
+        for volume in self.res['volumes']:
+            client = client_for_user(volume['owner'])
+            found = _get_volume_by_name(client, volume['name'])
+            self.assertIsNotNone(
+                found,
+                "Couldn't find expected volume %s" % volume['name'])
+
+            # Verify that a volume's attachment retrieved
+            server_id = _get_server_by_name(client, volume['server'])['id']
+            attachment = self.client.get_attachment_from_volume(volume)
+            self.assertEqual(volume['id'], attachment['volume_id'])
+            self.assertEqual(server_id, attachment['server_id'])
 
 
 #######################
@@ -249,6 +284,8 @@
 
 
 def create_objects(objects):
+    if not objects:
+        return
     LOG.info("Creating objects")
     for obj in objects:
         LOG.debug("Object %s" % obj)
@@ -266,7 +303,16 @@
 #######################
 
 
+def _resolve_image(image, imgtype):
+    name = image[imgtype]
+    fname = os.path.join(OPTS.devstack_base, image['imgdir'], name)
+    return name, fname
+
+
 def create_images(images):
+    if not images:
+        return
+    LOG.info("Creating images")
     for image in images:
         client = client_for_user(image['owner'])
 
@@ -274,25 +320,29 @@
         r, body = client.images.image_list()
         names = [x['name'] for x in body]
         if image['name'] in names:
+            LOG.info("Image '%s' already exists" % image['name'])
             continue
 
         # special handling for 3 part image
         extras = {}
         if image['format'] == 'ami':
+            name, fname = _resolve_image(image, 'aki')
             r, aki = client.images.create_image(
-                'javelin_' + image['aki'], 'aki', 'aki')
-            client.images.store_image(aki.get('id'), open(image['aki'], 'r'))
+                'javelin_' + name, 'aki', 'aki')
+            client.images.store_image(aki.get('id'), open(fname, 'r'))
             extras['kernel_id'] = aki.get('id')
 
+            name, fname = _resolve_image(image, 'ari')
             r, ari = client.images.create_image(
-                'javelin_' + image['ari'], 'ari', 'ari')
-            client.images.store_image(ari.get('id'), open(image['ari'], 'r'))
+                'javelin_' + name, 'ari', 'ari')
+            client.images.store_image(ari.get('id'), open(fname, 'r'))
             extras['ramdisk_id'] = ari.get('id')
 
+        _, fname = _resolve_image(image, 'file')
         r, body = client.images.create_image(
             image['name'], image['format'], image['format'], **extras)
         image_id = body.get('id')
-        client.images.store_image(image_id, open(image['file'], 'r'))
+        client.images.store_image(image_id, open(fname, 'r'))
 
 
 #######################
@@ -326,15 +376,73 @@
 
 
 def create_servers(servers):
+    if not servers:
+        return
+    LOG.info("Creating servers")
     for server in servers:
         client = client_for_user(server['owner'])
 
         if _get_server_by_name(client, server['name']):
+            LOG.info("Server '%s' already exists" % server['name'])
             continue
 
         image_id = _get_image_by_name(client, server['image'])['id']
         flavor_id = _get_flavor_by_name(client, server['flavor'])['id']
-        client.servers.create_server(server['name'], image_id, flavor_id)
+        resp, body = client.servers.create_server(server['name'], image_id,
+                                                 flavor_id)
+        server_id = body['id']
+        client.servers.wait_for_server_status(server_id, 'ACTIVE')
+
+
+def destroy_servers(servers):
+    if not servers:
+        return
+    LOG.info("Destroying servers")
+    for server in servers:
+        client = client_for_user(server['owner'])
+
+        response = _get_server_by_name(client, server['name'])
+        if not response:
+            LOG.info("Server '%s' does not exist" % server['name'])
+            continue
+
+        client.servers.delete_server(response['id'])
+        client.servers.wait_for_server_termination(response['id'],
+                ignore_error=True)
+
+
+#######################
+#
+# VOLUMES
+#
+#######################
+
+def _get_volume_by_name(client, name):
+    r, body = client.volumes.list_volumes()
+    for volume in body['volumes']:
+        if name == volume['name']:
+            return volume
+    return None
+
+
+def create_volumes(volumes):
+    for volume in volumes:
+        client = client_for_user(volume['owner'])
+
+        # only create a volume if the name isn't here
+        r, body = client.volumes.list_volumes()
+        if any(item['name'] == volume['name'] for item in body):
+            continue
+
+        client.volumes.create_volume(volume['name'], volume['size'])
+
+
+def attach_volumes(volumes):
+    for volume in volumes:
+        client = client_for_user(volume['owner'])
+
+        server_id = _get_server_by_name(client, volume['server'])['id']
+        client.volumes.attach_volume(volume['name'], server_id)
 
 
 #######################
@@ -355,6 +463,27 @@
     create_objects(RES['objects'])
     create_images(RES['images'])
     create_servers(RES['servers'])
+    # TODO(sdague): volumes definition doesn't work yet, bring it
+    # back once we're actually executing the code
+    # create_volumes(RES['volumes'])
+    # attach_volumes(RES['volumes'])
+
+
+def destroy_resources():
+    LOG.info("Destroying Resources")
+    # Destroy in inverse order of create
+
+    # Future
+    # detach_volumes
+    # destroy_volumes
+
+    destroy_servers(RES['servers'])
+    LOG.warn("Destroy mode incomplete")
+    # destroy_images
+    # destroy_objects
+
+    # destroy_users
+    # destroy_tenants
 
 
 def get_options():
@@ -369,6 +498,17 @@
                         required=True,
                         metavar='resourcefile.yaml',
                         help='Resources definition yaml file')
+
+    parser.add_argument(
+        '-d', '--devstack-base',
+        required=True,
+        metavar='/opt/stack/old',
+        help='Devstack base directory for retrieving artifacts')
+    parser.add_argument(
+        '-c', '--config-file',
+        metavar='/etc/tempest.conf',
+        help='path to javelin2(tempest) config file')
+
     # auth bits, letting us also just source the devstack openrc
     parser.add_argument('--os-username',
                         metavar='<auth-user-name>',
@@ -388,6 +528,8 @@
         print("ERROR: Unknown mode -m %s\n" % OPTS.mode)
         parser.print_help()
         sys.exit(1)
+    if OPTS.config_file:
+        config.CONF.set_config_path(OPTS.config_file)
 
 
 def setup_logging(debug=True):
@@ -415,15 +557,20 @@
 
     if OPTS.mode == 'create':
         create_resources()
+        # Make sure the resources we just created actually work
+        checker = JavelinCheck(USERS, RES)
+        checker.check()
     elif OPTS.mode == 'check':
         collect_users(RES['users'])
         checker = JavelinCheck(USERS, RES)
         checker.check()
     elif OPTS.mode == 'destroy':
-        LOG.warn("Destroy mode not yet implemented")
+        collect_users(RES['users'])
+        destroy_resources()
     else:
         LOG.error('Unknown mode %s' % OPTS.mode)
         return 1
+    LOG.info('javelin2 successfully finished')
     return 0
 
 if __name__ == "__main__":
diff --git a/tempest/cmd/resources.yaml b/tempest/cmd/resources.yaml
index f7cb8a9..3450e1f 100644
--- a/tempest/cmd/resources.yaml
+++ b/tempest/cmd/resources.yaml
@@ -27,14 +27,20 @@
 images:
   - name: javelin_cirros
     owner: javelin
+    imgdir: files/images/cirros-0.3.2-x86_64-uec
     file: cirros-0.3.2-x86_64-blank.img
     format: ami
     aki: cirros-0.3.2-x86_64-vmlinuz
     ari: cirros-0.3.2-x86_64-initrd
 volumes:
-  - assegai:
-    - owner: javelin
-    - gb: 1
+  - name: assegai
+    server: peltast
+    owner: javelin
+    size: 1
+  - name: pifpouf
+    server: hoplite
+    owner: javelin
+    size: 2
 servers:
   - name: peltast
     owner: javelin
diff --git a/tempest/cmd/run_stress.py b/tempest/cmd/run_stress.py
index f773996..07f3f66 100755
--- a/tempest/cmd/run_stress.py
+++ b/tempest/cmd/run_stress.py
@@ -51,7 +51,7 @@
         except Exception:
             next
         if 'stress' in attrs:
-            if filter_attr is not None and not filter_attr in attrs:
+            if filter_attr is not None and filter_attr not in attrs:
                 continue
             class_setup_per = getattr(test_func, "st_class_setup_per")
 
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 7b2e60b..673da4f 100755
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -21,7 +21,7 @@
 import urlparse
 
 import httplib2
-from six.moves import configparser
+from six import moves
 
 from tempest import clients
 from tempest import config
@@ -29,13 +29,12 @@
 
 CONF = config.CONF
 RAW_HTTP = httplib2.Http()
-CONF_FILE = None
-OUTFILE = sys.stdout
+CONF_PARSER = None
 
 
 def _get_config_file():
     default_config_dir = os.path.join(os.path.abspath(
-        os.path.dirname(os.path.dirname(__file__))), "etc")
+        os.path.dirname(os.path.dirname(os.path.dirname(__file__)))), "etc")
     default_config_file = "tempest.conf"
 
     conf_dir = os.environ.get('TEMPEST_CONFIG_DIR', default_config_dir)
@@ -46,14 +45,9 @@
 
 
 def change_option(option, group, value):
-    config_parse = configparser.SafeConfigParser()
-    config_parse.optionxform = str
-    config_parse.readfp(CONF_FILE)
-    if not config_parse.has_section(group):
-        config_parse.add_section(group)
-    config_parse.set(group, option, str(value))
-    global OUTFILE
-    config_parse.write(OUTFILE)
+    if not CONF_PARSER.has_section(group):
+        CONF_PARSER.add_section(group)
+    CONF_PARSER.set(group, option, str(value))
 
 
 def print_and_or_update(option, group, value, update):
@@ -160,11 +154,10 @@
     extensions_client = get_extension_client(os, service)
     __, resp = extensions_client.list_extensions()
     if isinstance(resp, dict):
-        # Neutron's extension 'name' field has is not a single word (it has
-        # spaces in the string) Since that can't be used for list option the
-        # api_extension option in the network-feature-enabled group uses alias
-        # instead of name.
-        if service == 'neutron':
+        # For both Nova and Neutron we use the alias name rather than the
+        # 'name' field because the alias is considered to be the canonical
+        # name.
+        if service in ['nova', 'nova_v3', 'neutron']:
             extensions = map(lambda x: x['alias'], resp['extensions'])
         elif service == 'swift':
             # Remove Swift general information from extensions list
@@ -289,6 +282,9 @@
                     if update:
                         change_option(codename_match[cfgname],
                                       'service_available', True)
+                        # If we are going to enable this we should allow
+                        # extension checks.
+                        avail_services.append(codename_match[cfgname])
                 else:
                     avail_services.append(codename_match[cfgname])
     return avail_services
@@ -322,12 +318,16 @@
     opts = parse_args()
     update = opts.update
     replace = opts.replace_ext
-    global CONF_FILE
-    global OUTFILE
+    global CONF_PARSER
+
+    outfile = sys.stdout
     if update:
-        CONF_FILE = _get_config_file()
+        conf_file = _get_config_file()
         if opts.output:
-            OUTFILE = open(opts.output, 'w+')
+            outfile = open(opts.output, 'w+')
+        CONF_PARSER = moves.configparser.SafeConfigParser()
+        CONF_PARSER.optionxform = str
+        CONF_PARSER.readfp(conf_file)
     os = clients.ComputeAdminManager(interface='json')
     services = check_service_availability(os, update)
     results = {}
@@ -342,9 +342,10 @@
     verify_nova_api_versions(os, update)
     verify_cinder_api_versions(os, update)
     display_results(results, update, replace)
-    if CONF_FILE:
-        CONF_FILE.close()
-    OUTFILE.close()
+    if update:
+        conf_file.close()
+        CONF_PARSER.write(outfile)
+    outfile.close()
 
 
 if __name__ == "__main__":
diff --git a/tempest/common/commands.py b/tempest/common/commands.py
index 6720847..6583475 100644
--- a/tempest/common/commands.py
+++ b/tempest/common/commands.py
@@ -25,7 +25,7 @@
 
 
 def sudo_cmd_call(cmd):
-    args = shlex.split(cmd)
+    args = shlex.split(cmd.encode('utf-8'))
     subprocess_args = {'stdout': subprocess.PIPE,
                        'stderr': subprocess.STDOUT}
     proc = subprocess.Popen(['/usr/bin/sudo', '-n'] + args,
@@ -50,7 +50,7 @@
 
 
 def iptables_raw(table):
-    return sudo_cmd_call("iptables -v -S -t " + table)
+    return sudo_cmd_call("iptables --line-numbers -L -nv -t " + table)
 
 
 def ip_ns_list():
@@ -84,7 +84,7 @@
           "-i %(pkey)s %(file1)s %(dest)s" % {'pkey': pkey,
                                               'file1': file_from,
                                               'dest': dest}
-    args = shlex.split(cmd)
+    args = shlex.split(cmd.encode('utf-8'))
     subprocess_args = {'stdout': subprocess.PIPE,
                        'stderr': subprocess.STDOUT}
     proc = subprocess.Popen(args, **subprocess_args)
diff --git a/tempest/common/cred_provider.py b/tempest/common/cred_provider.py
new file mode 100644
index 0000000..dc4f049
--- /dev/null
+++ b/tempest/common/cred_provider.py
@@ -0,0 +1,44 @@
+# (c) 2014 Deutsche Telekom AG
+#    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 six
+
+from tempest import config
+from tempest.openstack.common import log as logging
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+@six.add_metaclass(abc.ABCMeta)
+class CredentialProvider(object):
+    def __init__(self, name, tempest_client=True, interface='json',
+                 password='pass', network_resources=None):
+        self.name = name
+
+    @abc.abstractmethod
+    def get_primary_creds(self):
+        return
+
+    @abc.abstractmethod
+    def get_admin_creds(self):
+        return
+
+    @abc.abstractmethod
+    def get_alt_creds(self):
+        return
+
+    @abc.abstractmethod
+    def clear_isolated_creds(self):
+        return
diff --git a/tempest/common/glance_http.py b/tempest/common/glance_http.py
index 9358851..55aca5a 100644
--- a/tempest/common/glance_http.py
+++ b/tempest/common/glance_http.py
@@ -160,6 +160,9 @@
     def json_request(self, method, url, **kwargs):
         kwargs.setdefault('headers', {})
         kwargs['headers'].setdefault('Content-Type', 'application/json')
+        if kwargs['headers']['Content-Type'] != 'application/json':
+            msg = "Only application/json content-type is supported."
+            raise exc.InvalidContentType(msg)
 
         if 'body' in kwargs:
             kwargs['body'] = json.dumps(kwargs['body'])
@@ -173,7 +176,8 @@
             except ValueError:
                 LOG.error('Could not decode response body as JSON')
         else:
-            body = None
+            msg = "Only json/application content-type is supported."
+            raise exc.InvalidContentType(msg)
 
         return resp, body
 
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index b4618ed..98b0116 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -16,6 +16,7 @@
 
 from tempest import auth
 from tempest import clients
+from tempest.common import cred_provider
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
@@ -25,15 +26,16 @@
 LOG = logging.getLogger(__name__)
 
 
-class IsolatedCreds(object):
+class IsolatedCreds(cred_provider.CredentialProvider):
 
     def __init__(self, name, tempest_client=True, interface='json',
                  password='pass', network_resources=None):
+        super(IsolatedCreds, self).__init__(name, tempest_client, interface,
+                                            password, network_resources)
         self.network_resources = network_resources
         self.isolated_creds = {}
         self.isolated_net_resources = {}
         self.ports = []
-        self.name = name
         self.tempest_client = tempest_client
         self.interface = interface
         self.password = password
@@ -57,7 +59,7 @@
 
     def _create_tenant(self, name, description):
         if self.tempest_client:
-            resp, tenant = self.identity_admin_client.create_tenant(
+            _, tenant = self.identity_admin_client.create_tenant(
                 name=name, description=description)
         else:
             tenant = self.identity_admin_client.tenants.create(
@@ -67,7 +69,7 @@
 
     def _get_tenant_by_name(self, name):
         if self.tempest_client:
-            resp, tenant = self.identity_admin_client.get_tenant_by_name(name)
+            _, tenant = self.identity_admin_client.get_tenant_by_name(name)
         else:
             tenants = self.identity_admin_client.tenants.list()
             for ten in tenants:
@@ -80,10 +82,10 @@
 
     def _create_user(self, username, password, tenant, email):
         if self.tempest_client:
-            resp, user = self.identity_admin_client.create_user(username,
-                                                                password,
-                                                                tenant['id'],
-                                                                email)
+            _, user = self.identity_admin_client.create_user(username,
+                                                             password,
+                                                             tenant['id'],
+                                                             email)
         else:
             user = self.identity_admin_client.users.create(username, password,
                                                            email,
@@ -92,7 +94,7 @@
 
     def _get_user(self, tenant, username):
         if self.tempest_client:
-            resp, user = self.identity_admin_client.get_user_by_username(
+            _, user = self.identity_admin_client.get_user_by_username(
                 tenant['id'],
                 username)
         else:
@@ -101,17 +103,28 @@
 
     def _list_roles(self):
         if self.tempest_client:
-            resp, roles = self.identity_admin_client.list_roles()
+            _, roles = self.identity_admin_client.list_roles()
         else:
             roles = self.identity_admin_client.roles.list()
         return roles
 
-    def _assign_user_role(self, tenant, user, role):
+    def _assign_user_role(self, tenant, user, role_name):
+        role = None
+        try:
+            roles = self._list_roles()
+            if self.tempest_client:
+                role = next(r for r in roles if r['name'] == role_name)
+            else:
+                role = next(r for r in roles if r.name == role_name)
+        except StopIteration:
+            msg = 'No "%s" role found' % role_name
+            raise exceptions.NotFound(msg)
         if self.tempest_client:
-            self.identity_admin_client.assign_user_role(tenant, user, role)
+            self.identity_admin_client.assign_user_role(tenant['id'],
+                                                        user['id'], role['id'])
         else:
-            self.identity_admin_client.roles.add_user_role(user,
-                                                           role, tenant=tenant)
+            self.identity_admin_client.roles.add_user_role(user.id, role.id,
+                                                           tenant.id)
 
     def _delete_user(self, user):
         if self.tempest_client:
@@ -149,22 +162,11 @@
         email = data_utils.rand_name(root) + suffix + "@example.com"
         user = self._create_user(username, self.password,
                                  tenant, email)
+        # NOTE(andrey-mp): user needs this role to create containers in swift
+        swift_operator_role = CONF.object_storage.operator_role
+        self._assign_user_role(tenant, user, swift_operator_role)
         if admin:
-            role = None
-            try:
-                roles = self._list_roles()
-                admin_role = CONF.identity.admin_role
-                if self.tempest_client:
-                    role = next(r for r in roles if r['name'] == admin_role)
-                else:
-                    role = next(r for r in roles if r.name == admin_role)
-            except StopIteration:
-                msg = "No admin role found"
-                raise exceptions.NotFound(msg)
-            if self.tempest_client:
-                self._assign_user_role(tenant['id'], user['id'], role['id'])
-            else:
-                self._assign_user_role(tenant.id, user.id, role.id)
+            self._assign_user_role(tenant, user, CONF.identity.admin_role)
         return self._get_credentials(user, tenant)
 
     def _get_credentials(self, user, tenant):
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 3c527f5..9e0f4d3 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -18,6 +18,7 @@
 import json
 from lxml import etree
 import re
+import string
 import time
 
 import jsonschema
@@ -191,17 +192,25 @@
         """
         self._skip_path = False
 
-    def expected_success(self, expected_code, read_code):
+    @classmethod
+    def expected_success(cls, expected_code, read_code):
         assert_msg = ("This function only allowed to use for HTTP status"
                       "codes which explicitly defined in the RFC 2616. {0}"
                       " is not a defined Success Code!").format(expected_code)
-        assert expected_code in HTTP_SUCCESS, assert_msg
+        if isinstance(expected_code, list):
+            for code in expected_code:
+                assert code in HTTP_SUCCESS, assert_msg
+        else:
+            assert expected_code in HTTP_SUCCESS, assert_msg
 
         # NOTE(afazekas): the http status code above 400 is processed by
         # the _error_checker method
-        if read_code < 400 and read_code != expected_code:
-                pattern = """Unexpected http success status code {0},
-                             The expected status code is {1}"""
+        if read_code < 400:
+            pattern = """Unexpected http success status code {0},
+                         The expected status code is {1}"""
+            if ((not isinstance(expected_code, list) and
+                (read_code != expected_code)) or (isinstance(expected_code,
+                list) and (read_code not in expected_code))):
                 details = pattern.format(read_code, expected_code)
                 raise exceptions.InvalidHttpSuccessCode(details)
 
@@ -287,9 +296,11 @@
                     req_url,
                     secs,
                     str(req_headers),
-                    str(req_body)[:2048],
+                    filter(lambda x: x in string.printable,
+                           str(req_body)[:2048]),
                     str(resp),
-                    str(resp_body)[:2048]),
+                    filter(lambda x: x in string.printable,
+                           str(resp_body)[:2048])),
                 extra=extra)
 
     def _parse_resp(self, body):
@@ -361,7 +372,7 @@
         # The warning is normal for SHOULD/SHOULD NOT case
 
         # Likely it will cause an error
-        if not resp_body and resp.status >= 400:
+        if method != 'HEAD' and not resp_body and resp.status >= 400:
             self.LOG.warning("status >= 400 response with empty body")
 
     def _request(self, method, url, headers=None, body=None):
@@ -555,11 +566,7 @@
         # declared in the V3 API and so we should be able to export this in
         # the response schema. For now we'll ignore it.
         if resp.status in HTTP_SUCCESS:
-            response_code = schema['status_code']
-            if resp.status not in response_code:
-                msg = ("The status code(%s) is different than the expected "
-                       "one(%s)") % (resp.status, response_code)
-                raise exceptions.InvalidHttpSuccessCode(msg)
+            cls.expected_success(schema['status_code'], resp.status)
 
             # Check the body of a response
             body_schema = schema.get('response_body')
diff --git a/tempest/common/utils/data_utils.py b/tempest/common/utils/data_utils.py
index a0a88dd..174e557 100644
--- a/tempest/common/utils/data_utils.py
+++ b/tempest/common/utils/data_utils.py
@@ -34,6 +34,11 @@
         return randbits
 
 
+def rand_url():
+    randbits = str(random.randint(1, 0x7fffffff))
+    return 'https://url-' + randbits + '.com'
+
+
 def rand_int_id(start=0, end=0x7fffffff):
     return random.randint(start, end)
 
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 95b6833..57a14a2 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -57,11 +57,6 @@
         actual_hostname = self.exec_command("hostname").rstrip()
         return expected_hostname == actual_hostname
 
-    def get_files(self, path):
-        # Return a list of comma separated files
-        command = "ls -m " + path
-        return self.exec_command(command).rstrip('\n').split(', ')
-
     def get_ram_size_in_mb(self):
         output = self.exec_command('free -m | grep Mem')
         if output:
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index d8474a0..d242c14 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -22,16 +22,6 @@
 LOG = logging.getLogger(__name__)
 
 
-def _console_dump(client, server_id):
-    try:
-        resp, output = client.get_console_output(server_id, None)
-        LOG.debug("Console Output for Server %s:\n%s" % (
-            server_id, output))
-    except exceptions.NotFound:
-        LOG.debug("Server %s: doesn't have a console" % server_id)
-        pass
-
-
 # NOTE(afazekas): This function needs to know a token and a subject.
 def wait_for_server_status(client, server_id, status, ready_wait=True,
                            extra_timeout=0, raise_on_error=True):
@@ -81,10 +71,12 @@
                      '/'.join((old_status, str(old_task_state))),
                      '/'.join((server_status, str(task_state))),
                      time.time() - start_time)
-
         if (server_status == 'ERROR') and raise_on_error:
-            _console_dump(client, server_id)
-            raise exceptions.BuildErrorException(server_id=server_id)
+            if 'fault' in body:
+                raise exceptions.BuildErrorException(body['fault'],
+                                                    server_id=server_id)
+            else:
+                raise exceptions.BuildErrorException(server_id=server_id)
 
         timed_out = int(time.time()) - start_time >= timeout
 
@@ -99,11 +91,9 @@
                         'timeout': timeout})
             message += ' Current status: %s.' % server_status
             message += ' Current task state: %s.' % task_state
-
             caller = misc_utils.find_test_caller()
             if caller:
                 message = '(%s) %s' % (caller, message)
-            _console_dump(client, server_id)
             raise exceptions.TimeoutException(message)
         old_status = server_status
         old_task_state = task_state
diff --git a/tempest/config.py b/tempest/config.py
index 6d9fda6..c83f500 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -247,7 +247,11 @@
                     'for removing from a host.  -1 never offload, 0 offload '
                     'when shelved. This time should be the same as the time '
                     'of nova.conf, and some tests will run for as long as the '
-                    'time.')
+                    'time.'),
+    cfg.StrOpt('floating_ip_range',
+               default='10.0.0.0/29',
+               help='Unallocated floating IP range, which will be used to '
+                    'test the floating IP bulk feature for CRUD operation.')
 ]
 
 compute_features_group = cfg.OptGroup(name='compute-feature-enabled',
@@ -255,7 +259,7 @@
 
 ComputeFeaturesGroup = [
     cfg.BoolOpt('api_v3',
-                default=True,
+                default=False,
                 help="If false, skip all nova v3 tests."),
     cfg.BoolOpt('disk_config',
                 default=True,
@@ -263,11 +267,13 @@
     cfg.ListOpt('api_extensions',
                 default=['all'],
                 help='A list of enabled compute extensions with a special '
-                     'entry all which indicates every extension is enabled'),
+                     'entry all which indicates every extension is enabled. '
+                     'Each extension should be specified with alias name'),
     cfg.ListOpt('api_v3_extensions',
                 default=['all'],
                 help='A list of enabled v3 extensions with a special entry all'
-                     ' which indicates every extension is enabled'),
+                     ' which indicates every extension is enabled. '
+                     'Each extension should be specified with alias name'),
     cfg.BoolOpt('change_password',
                 default=False,
                 help="Does the test environment support changing the admin "
@@ -304,7 +310,11 @@
     cfg.BoolOpt('rdp_console',
                 default=False,
                 help='Enable RDP console. This configuration value should '
-                     'be same as [nova.rdp]->enabled in nova.conf')
+                     'be same as [nova.rdp]->enabled in nova.conf'),
+    cfg.BoolOpt('rescue',
+                default=True,
+                help='Does the test environment support instance rescue '
+                     'mode?')
 ]
 
 
@@ -432,6 +442,12 @@
                 default=['all'],
                 help='A list of enabled network extensions with a special '
                      'entry all which indicates every extension is enabled'),
+    cfg.BoolOpt('ipv6_subnet_attributes',
+                default=False,
+                help="Allow the execution of IPv6 subnet tests that use "
+                     "the extended IPv6 attributes ipv6_ra_mode "
+                     "and ipv6_address_mode"
+                )
 ]
 
 queuing_group = cfg.OptGroup(name='queuing',
@@ -445,6 +461,28 @@
                default=20,
                help='The maximum number of queue records per page when '
                     'listing queues'),
+    cfg.IntOpt('max_queue_metadata',
+               default=65536,
+               help='The maximum metadata size for a queue'),
+    cfg.IntOpt('max_messages_per_page',
+               default=20,
+               help='The maximum number of queue message per page when '
+                    'listing (or) posting messages'),
+    cfg.IntOpt('max_message_size',
+               default=262144,
+               help='The maximum size of a message body'),
+    cfg.IntOpt('max_messages_per_claim',
+               default=20,
+               help='The maximum number of messages per claim'),
+    cfg.IntOpt('max_message_ttl',
+               default=1209600,
+               help='The maximum ttl for a message'),
+    cfg.IntOpt('max_claim_ttl',
+               default=43200,
+               help='The maximum ttl for a claim'),
+    cfg.IntOpt('max_claim_grace',
+               default=43200,
+               help='The maximum grace period for a claim'),
 ]
 
 volume_group = cfg.OptGroup(name='volume',
@@ -904,6 +942,9 @@
     cfg.BoolOpt('driver_enabled',
                 default=False,
                 help="Whether the Ironic nova-compute driver is enabled"),
+    cfg.StrOpt('driver',
+               default='fake',
+               help="Driver name which Ironic uses"),
     cfg.StrOpt('endpoint_type',
                default='publicURL',
                choices=['public', 'admin', 'internal',
@@ -914,14 +955,14 @@
                default=300,
                help="Timeout for Ironic node to completely provision"),
     cfg.IntOpt('association_timeout',
-               default=10,
+               default=30,
                help="Timeout for association of Nova instance and Ironic "
                     "node"),
     cfg.IntOpt('power_timeout',
-               default=20,
+               default=60,
                help="Timeout for Ironic power transitions."),
     cfg.IntOpt('unprovision_timeout',
-               default=20,
+               default=60,
                help="Timeout for unprovisioning an Ironic node.")
 ]
 
@@ -1044,18 +1085,22 @@
         cfg.CONF.set_default('domain_name', self.identity.admin_domain_name,
                              group='compute-admin')
 
-    def __init__(self, parse_conf=True):
+    def __init__(self, parse_conf=True, config_path=None):
         """Initialize a configuration from a conf directory and conf file."""
         super(TempestConfigPrivate, self).__init__()
         config_files = []
         failsafe_path = "/etc/tempest/" + self.DEFAULT_CONFIG_FILE
 
-        # Environment variables override defaults...
-        conf_dir = os.environ.get('TEMPEST_CONFIG_DIR',
-                                  self.DEFAULT_CONFIG_DIR)
-        conf_file = os.environ.get('TEMPEST_CONFIG', self.DEFAULT_CONFIG_FILE)
+        if config_path:
+            path = config_path
+        else:
+            # Environment variables override defaults...
+            conf_dir = os.environ.get('TEMPEST_CONFIG_DIR',
+                                      self.DEFAULT_CONFIG_DIR)
+            conf_file = os.environ.get('TEMPEST_CONFIG',
+                                       self.DEFAULT_CONFIG_FILE)
 
-        path = os.path.join(conf_dir, conf_file)
+            path = os.path.join(conf_dir, conf_file)
 
         if not os.path.isfile(path):
             path = failsafe_path
@@ -1077,6 +1122,7 @@
 
 class TempestConfigProxy(object):
     _config = None
+    _path = None
 
     _extra_log_defaults = [
         'keystoneclient.session=INFO',
@@ -1093,9 +1139,12 @@
     def __getattr__(self, attr):
         if not self._config:
             self._fix_log_levels()
-            self._config = TempestConfigPrivate()
+            self._config = TempestConfigPrivate(config_path=self._path)
 
         return getattr(self._config, attr)
 
+    def set_config_path(self, path):
+        self._path = path
+
 
 CONF = TempestConfigProxy()
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 183d422..93329bc 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -50,7 +50,7 @@
     T104: Scenario tests require a services decorator
     """
 
-    if 'tempest/scenario/test_' in filename:
+    if 'tempest/scenario/' in filename and '/test_' in filename:
         if TEST_DEFINITION.match(physical_line):
             if not SCENARIO_DECORATOR.match(previous_logical):
                 return (physical_line.find('def'),
@@ -105,9 +105,24 @@
                             "T107: service tag should not be in path")
 
 
+def no_official_client_manager_in_api_tests(physical_line, filename):
+    """Check that the OfficialClientManager isn't used in the api tests
+
+    The api tests should not use the official clients.
+
+    T108: Can not use OfficialClientManager in the API tests
+    """
+    if 'tempest/api' in filename:
+        if 'OfficialClientManager' in physical_line:
+            return (physical_line.find('OfficialClientManager'),
+                    'T108: OfficialClientManager can not be used in the api '
+                    'tests')
+
+
 def factory(register):
     register(import_no_clients_in_api)
     register(scenario_tests_need_service_tags)
     register(no_setupclass_for_unit_tests)
     register(no_vi_headers)
     register(service_tags_not_in_module_path)
+    register(no_official_client_manager_in_api_tests)
diff --git a/tempest/openstack/common/config/generator.py b/tempest/openstack/common/config/generator.py
index 8156cc5..664200e 100644
--- a/tempest/openstack/common/config/generator.py
+++ b/tempest/openstack/common/config/generator.py
@@ -150,7 +150,7 @@
 
 
 def _is_in_group(opt, group):
-    "Check if opt is in group."
+    """Check if opt is in group."""
     for value in group._opts.values():
         # NOTE(llu): Temporary workaround for bug #1262148, wait until
         # newly released oslo.config support '==' operator.
@@ -159,7 +159,7 @@
     return False
 
 
-def _guess_groups(opt, mod_obj):
+def _guess_groups(opt):
     # is it in the DEFAULT group?
     if _is_in_group(opt, cfg.CONF):
         return 'DEFAULT'
@@ -193,7 +193,7 @@
 
     ret = {}
     for opt in opts:
-        ret.setdefault(_guess_groups(opt, obj), []).append(opt)
+        ret.setdefault(_guess_groups(opt), []).append(opt)
     return ret.items()
 
 
@@ -223,6 +223,8 @@
 
 def _sanitize_default(name, value):
     """Set up a reasonably sensible default for pybasedir, my_ip and host."""
+    hostname = socket.gethostname()
+    fqdn = socket.getfqdn()
     if value.startswith(sys.prefix):
         # NOTE(jd) Don't use os.path.join, because it is likely to think the
         # second part is an absolute pathname and therefore drop the first
@@ -234,8 +236,13 @@
         return value.replace(BASEDIR, '')
     elif value == _get_my_ip():
         return '10.0.0.1'
-    elif value in (socket.gethostname(), socket.getfqdn()) and 'host' in name:
-        return 'tempest'
+    elif value in (hostname, fqdn):
+        if 'host' in name:
+            return 'tempest'
+    elif value.endswith(hostname):
+        return value.replace(hostname, 'tempest')
+    elif value.endswith(fqdn):
+        return value.replace(fqdn, 'tempest')
     elif value.strip() != value:
         return '"%s"' % value
     return value
@@ -246,7 +253,6 @@
     if not opt_help:
         sys.stderr.write('WARNING: "%s" is missing help string.\n' % opt_name)
         opt_help = ""
-    opt_type = None
     try:
         opt_type = OPTION_REGEX.search(str(type(opt))).group(0)
     except (ValueError, AttributeError) as err:
diff --git a/tempest/openstack/common/gettextutils.py b/tempest/openstack/common/gettextutils.py
index 17f66f7..872d58e 100644
--- a/tempest/openstack/common/gettextutils.py
+++ b/tempest/openstack/common/gettextutils.py
@@ -23,7 +23,6 @@
 """
 
 import copy
-import functools
 import gettext
 import locale
 from logging import handlers
@@ -32,24 +31,115 @@
 from babel import localedata
 import six
 
-_localedir = os.environ.get('tempest'.upper() + '_LOCALEDIR')
-_t = gettext.translation('tempest', localedir=_localedir, fallback=True)
-
-# We use separate translation catalogs for each log level, so set up a
-# mapping between the log level name and the translator. The domain
-# for the log level is project_name + "-log-" + log_level so messages
-# for each level end up in their own catalog.
-_t_log_levels = dict(
-    (level, gettext.translation('tempest' + '-log-' + level,
-                                localedir=_localedir,
-                                fallback=True))
-    for level in ['info', 'warning', 'error', 'critical']
-)
-
 _AVAILABLE_LANGUAGES = {}
+
+# FIXME(dhellmann): Remove this when moving to oslo.i18n.
 USE_LAZY = False
 
 
+class TranslatorFactory(object):
+    """Create translator functions
+    """
+
+    def __init__(self, domain, localedir=None):
+        """Establish a set of translation functions for the domain.
+
+        :param domain: Name of translation domain,
+                       specifying a message catalog.
+        :type domain: str
+        :param lazy: Delays translation until a message is emitted.
+                     Defaults to False.
+        :type lazy: Boolean
+        :param localedir: Directory with translation catalogs.
+        :type localedir: str
+        """
+        self.domain = domain
+        if localedir is None:
+            localedir = os.environ.get(domain.upper() + '_LOCALEDIR')
+        self.localedir = localedir
+
+    def _make_translation_func(self, domain=None):
+        """Return a new translation function ready for use.
+
+        Takes into account whether or not lazy translation is being
+        done.
+
+        The domain can be specified to override the default from the
+        factory, but the localedir from the factory is always used
+        because we assume the log-level translation catalogs are
+        installed in the same directory as the main application
+        catalog.
+
+        """
+        if domain is None:
+            domain = self.domain
+        t = gettext.translation(domain,
+                                localedir=self.localedir,
+                                fallback=True)
+        # Use the appropriate method of the translation object based
+        # on the python version.
+        m = t.gettext if six.PY3 else t.ugettext
+
+        def f(msg):
+            """oslo.i18n.gettextutils translation function."""
+            if USE_LAZY:
+                return Message(msg, domain=domain)
+            return m(msg)
+        return f
+
+    @property
+    def primary(self):
+        "The default translation function."
+        return self._make_translation_func()
+
+    def _make_log_translation_func(self, level):
+        return self._make_translation_func(self.domain + '-log-' + level)
+
+    @property
+    def log_info(self):
+        "Translate info-level log messages."
+        return self._make_log_translation_func('info')
+
+    @property
+    def log_warning(self):
+        "Translate warning-level log messages."
+        return self._make_log_translation_func('warning')
+
+    @property
+    def log_error(self):
+        "Translate error-level log messages."
+        return self._make_log_translation_func('error')
+
+    @property
+    def log_critical(self):
+        "Translate critical-level log messages."
+        return self._make_log_translation_func('critical')
+
+
+# NOTE(dhellmann): When this module moves out of the incubator into
+# oslo.i18n, these global variables can be moved to an integration
+# module within each application.
+
+# Create the global translation functions.
+_translators = TranslatorFactory('tempest')
+
+# The primary translation function using the well-known name "_"
+_ = _translators.primary
+
+# Translators for log levels.
+#
+# The abbreviated names are meant to reflect the usual use of a short
+# name like '_'. The "L" is for "log" and the other letter comes from
+# the level.
+_LI = _translators.log_info
+_LW = _translators.log_warning
+_LE = _translators.log_error
+_LC = _translators.log_critical
+
+# NOTE(dhellmann): End of globals that will move to the application's
+# integration module.
+
+
 def enable_lazy():
     """Convenience function for configuring _() to use lazy gettext
 
@@ -62,38 +152,7 @@
     USE_LAZY = True
 
 
-def _(msg):
-    if USE_LAZY:
-        return Message(msg, domain='tempest')
-    else:
-        if six.PY3:
-            return _t.gettext(msg)
-        return _t.ugettext(msg)
-
-
-def _log_translation(msg, level):
-    """Build a single translation of a log message
-    """
-    if USE_LAZY:
-        return Message(msg, domain='tempest' + '-log-' + level)
-    else:
-        translator = _t_log_levels[level]
-        if six.PY3:
-            return translator.gettext(msg)
-        return translator.ugettext(msg)
-
-# Translators for log levels.
-#
-# The abbreviated names are meant to reflect the usual use of a short
-# name like '_'. The "L" is for "log" and the other letter comes from
-# the level.
-_LI = functools.partial(_log_translation, level='info')
-_LW = functools.partial(_log_translation, level='warning')
-_LE = functools.partial(_log_translation, level='error')
-_LC = functools.partial(_log_translation, level='critical')
-
-
-def install(domain, lazy=False):
+def install(domain):
     """Install a _() function using the given translation domain.
 
     Given a translation domain, install a _() function using gettext's
@@ -104,43 +163,14 @@
     a translation-domain-specific environment variable (e.g.
     NOVA_LOCALEDIR).
 
+    Note that to enable lazy translation, enable_lazy must be
+    called.
+
     :param domain: the translation domain
-    :param lazy: indicates whether or not to install the lazy _() function.
-                 The lazy _() introduces a way to do deferred translation
-                 of messages by installing a _ that builds Message objects,
-                 instead of strings, which can then be lazily translated into
-                 any available locale.
     """
-    if lazy:
-        # NOTE(mrodden): Lazy gettext functionality.
-        #
-        # The following introduces a deferred way to do translations on
-        # messages in OpenStack. We override the standard _() function
-        # and % (format string) operation to build Message objects that can
-        # later be translated when we have more information.
-        def _lazy_gettext(msg):
-            """Create and return a Message object.
-
-            Lazy gettext function for a given domain, it is a factory method
-            for a project/module to get a lazy gettext function for its own
-            translation domain (i.e. nova, glance, cinder, etc.)
-
-            Message encapsulates a string so that we can translate
-            it later when needed.
-            """
-            return Message(msg, domain=domain)
-
-        from six import moves
-        moves.builtins.__dict__['_'] = _lazy_gettext
-    else:
-        localedir = '%s_LOCALEDIR' % domain.upper()
-        if six.PY3:
-            gettext.install(domain,
-                            localedir=os.environ.get(localedir))
-        else:
-            gettext.install(domain,
-                            localedir=os.environ.get(localedir),
-                            unicode=True)
+    from six import moves
+    tf = TranslatorFactory(domain)
+    moves.builtins.__dict__['_'] = tf.primary
 
 
 class Message(six.text_type):
@@ -274,13 +304,14 @@
     def __radd__(self, other):
         return self.__add__(other)
 
-    def __str__(self):
-        # NOTE(luisg): Logging in python 2.6 tries to str() log records,
-        # and it expects specifically a UnicodeError in order to proceed.
-        msg = _('Message objects do not support str() because they may '
-                'contain non-ascii characters. '
-                'Please use unicode() or translate() instead.')
-        raise UnicodeError(msg)
+    if six.PY2:
+        def __str__(self):
+            # NOTE(luisg): Logging in python 2.6 tries to str() log records,
+            # and it expects specifically a UnicodeError in order to proceed.
+            msg = _('Message objects do not support str() because they may '
+                    'contain non-ascii characters. '
+                    'Please use unicode() or translate() instead.')
+            raise UnicodeError(msg)
 
 
 def get_available_languages(domain):
@@ -323,8 +354,8 @@
                'zh_Hant_HK': 'zh_HK',
                'zh_Hant': 'zh_TW',
                'fil': 'tl_PH'}
-    for (locale, alias) in six.iteritems(aliases):
-        if locale in language_list and alias not in language_list:
+    for (locale_, alias) in six.iteritems(aliases):
+        if locale_ in language_list and alias not in language_list:
             language_list.append(alias)
 
     _AVAILABLE_LANGUAGES[domain] = language_list
diff --git a/tempest/openstack/common/importutils.py b/tempest/openstack/common/importutils.py
index 6c0d3b2..d5dd22f 100644
--- a/tempest/openstack/common/importutils.py
+++ b/tempest/openstack/common/importutils.py
@@ -24,10 +24,10 @@
 def import_class(import_str):
     """Returns a class from a string including module and class."""
     mod_str, _sep, class_str = import_str.rpartition('.')
+    __import__(mod_str)
     try:
-        __import__(mod_str)
         return getattr(sys.modules[mod_str], class_str)
-    except (ValueError, AttributeError):
+    except AttributeError:
         raise ImportError('Class %s cannot be found (%s)' %
                           (class_str,
                            traceback.format_exception(*sys.exc_info())))
diff --git a/tempest/openstack/common/jsonutils.py b/tempest/openstack/common/jsonutils.py
index 53c0ad4..cb83557 100644
--- a/tempest/openstack/common/jsonutils.py
+++ b/tempest/openstack/common/jsonutils.py
@@ -31,25 +31,29 @@
 '''
 
 
+import codecs
 import datetime
 import functools
 import inspect
 import itertools
-import json
-try:
-    import xmlrpclib
-except ImportError:
-    # NOTE(jaypipes): xmlrpclib was renamed to xmlrpc.client in Python3
-    #                 however the function and object call signatures
-    #                 remained the same. This whole try/except block should
-    #                 be removed and replaced with a call to six.moves once
-    #                 six 1.4.2 is released. See http://bit.ly/1bqrVzu
-    import xmlrpc.client as xmlrpclib
+import sys
+
+if sys.version_info < (2, 7):
+    # On Python <= 2.6, json module is not C boosted, so try to use
+    # simplejson module if available
+    try:
+        import simplejson as json
+    except ImportError:
+        import json
+else:
+    import json
 
 import six
+import six.moves.xmlrpc_client as xmlrpclib
 
 from tempest.openstack.common import gettextutils
 from tempest.openstack.common import importutils
+from tempest.openstack.common import strutils
 from tempest.openstack.common import timeutils
 
 netaddr = importutils.try_import("netaddr")
@@ -164,12 +168,16 @@
     return json.dumps(value, default=default, **kwargs)
 
 
-def loads(s):
-    return json.loads(s)
+def dump(obj, fp, *args, **kwargs):
+    return json.dump(obj, fp, *args, **kwargs)
 
 
-def load(s):
-    return json.load(s)
+def loads(s, encoding='utf-8', **kwargs):
+    return json.loads(strutils.safe_decode(s, encoding), **kwargs)
+
+
+def load(fp, encoding='utf-8', **kwargs):
+    return json.load(codecs.getreader(encoding)(fp), **kwargs)
 
 
 try:
diff --git a/tempest/openstack/common/log.py b/tempest/openstack/common/log.py
index 7bebfdb..44102c0 100644
--- a/tempest/openstack/common/log.py
+++ b/tempest/openstack/common/log.py
@@ -15,7 +15,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-"""Openstack logging handler.
+"""OpenStack logging handler.
 
 This module adds to logging functionality by adding the option to specify
 a context object when calling the various log methods.  If the context object
@@ -33,7 +33,6 @@
 import logging.config
 import logging.handlers
 import os
-import re
 import sys
 import traceback
 
@@ -45,27 +44,13 @@
 from tempest.openstack.common import importutils
 from tempest.openstack.common import jsonutils
 from tempest.openstack.common import local
+# NOTE(flaper87): Pls, remove when graduating this module
+# from the incubator.
+from tempest.openstack.common.strutils import mask_password  # noqa
 
 
 _DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
 
-_SANITIZE_KEYS = ['adminPass', 'admin_pass', 'password', 'admin_password']
-
-# NOTE(ldbragst): Let's build a list of regex objects using the list of
-# _SANITIZE_KEYS we already have. This way, we only have to add the new key
-# to the list of _SANITIZE_KEYS and we can generate regular expressions
-# for XML and JSON automatically.
-_SANITIZE_PATTERNS = []
-_FORMAT_PATTERNS = [r'(%(key)s\s*[=]\s*[\"\']).*?([\"\'])',
-                    r'(<%(key)s>).*?(</%(key)s>)',
-                    r'([\"\']%(key)s[\"\']\s*:\s*[\"\']).*?([\"\'])',
-                    r'([\'"].*?%(key)s[\'"]\s*:\s*u?[\'"]).*?([\'"])']
-
-for key in _SANITIZE_KEYS:
-    for pattern in _FORMAT_PATTERNS:
-        reg_ex = re.compile(pattern % {'key': key}, re.DOTALL)
-        _SANITIZE_PATTERNS.append(reg_ex)
-
 
 common_cli_opts = [
     cfg.BoolOpt('debug',
@@ -84,14 +69,11 @@
     cfg.StrOpt('log-config-append',
                metavar='PATH',
                deprecated_name='log-config',
-               help='The name of logging configuration file. It does not '
-                    'disable existing loggers, but just appends specified '
-                    'logging configuration to any other existing logging '
-                    'options. Please see the Python logging module '
-                    'documentation for details on logging configuration '
-                    'files.'),
+               help='The name of a logging configuration file. This file '
+                    'is appended to any existing logging configuration '
+                    'files. For details about logging configuration files, '
+                    'see the Python logging module documentation.'),
     cfg.StrOpt('log-format',
-               default=None,
                metavar='FORMAT',
                help='DEPRECATED. '
                     'A logging.Formatter log message format string which may '
@@ -103,7 +85,7 @@
                default=_DEFAULT_LOG_DATE_FORMAT,
                metavar='DATE_FORMAT',
                help='Format string for %%(asctime)s in log records. '
-                    'Default: %(default)s'),
+                    'Default: %(default)s .'),
     cfg.StrOpt('log-file',
                metavar='PATH',
                deprecated_name='logfile',
@@ -112,67 +94,76 @@
     cfg.StrOpt('log-dir',
                deprecated_name='logdir',
                help='(Optional) The base directory used for relative '
-                    '--log-file paths'),
+                    '--log-file paths.'),
     cfg.BoolOpt('use-syslog',
                 default=False,
-                help='Use syslog for logging.'),
+                help='Use syslog for logging. '
+                     'Existing syslog format is DEPRECATED during I, '
+                     'and will change in J to honor RFC5424.'),
+    cfg.BoolOpt('use-syslog-rfc-format',
+                # TODO(bogdando) remove or use True after existing
+                #    syslog format deprecation in J
+                default=False,
+                help='(Optional) Enables or disables syslog rfc5424 format '
+                     'for logging. If enabled, prefixes the MSG part of the '
+                     'syslog message with APP-NAME (RFC5424). The '
+                     'format without the APP-NAME is deprecated in I, '
+                     'and will be removed in J.'),
     cfg.StrOpt('syslog-log-facility',
                default='LOG_USER',
-               help='syslog facility to receive log lines')
+               help='Syslog facility to receive log lines.')
 ]
 
 generic_log_opts = [
     cfg.BoolOpt('use_stderr',
                 default=True,
-                help='Log output to standard error')
+                help='Log output to standard error.')
 ]
 
+DEFAULT_LOG_LEVELS = ['amqp=WARN', 'amqplib=WARN', 'boto=WARN',
+                      'qpid=WARN', 'sqlalchemy=WARN', 'suds=INFO',
+                      'oslo.messaging=INFO', 'iso8601=WARN',
+                      'requests.packages.urllib3.connectionpool=WARN',
+                      'urllib3.connectionpool=WARN']
+
 log_opts = [
     cfg.StrOpt('logging_context_format_string',
                default='%(asctime)s.%(msecs)03d %(process)d %(levelname)s '
                        '%(name)s [%(request_id)s %(user_identity)s] '
                        '%(instance)s%(message)s',
-               help='format string to use for log messages with context'),
+               help='Format string to use for log messages with context.'),
     cfg.StrOpt('logging_default_format_string',
                default='%(asctime)s.%(msecs)03d %(process)d %(levelname)s '
                        '%(name)s [-] %(instance)s%(message)s',
-               help='format string to use for log messages without context'),
+               help='Format string to use for log messages without context.'),
     cfg.StrOpt('logging_debug_format_suffix',
                default='%(funcName)s %(pathname)s:%(lineno)d',
-               help='data to append to log format when level is DEBUG'),
+               help='Data to append to log format when level is DEBUG.'),
     cfg.StrOpt('logging_exception_prefix',
                default='%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s '
                '%(instance)s',
-               help='prefix each line of exception output with this format'),
+               help='Prefix each line of exception output with this format.'),
     cfg.ListOpt('default_log_levels',
-                default=[
-                    'amqp=WARN',
-                    'amqplib=WARN',
-                    'boto=WARN',
-                    'qpid=WARN',
-                    'sqlalchemy=WARN',
-                    'suds=INFO',
-                    'iso8601=WARN',
-                ],
-                help='list of logger=LEVEL pairs'),
+                default=DEFAULT_LOG_LEVELS,
+                help='List of logger=LEVEL pairs.'),
     cfg.BoolOpt('publish_errors',
                 default=False,
-                help='publish error events'),
+                help='Enables or disables publication of error events.'),
     cfg.BoolOpt('fatal_deprecations',
                 default=False,
-                help='make deprecations fatal'),
+                help='Enables or disables fatal status of deprecations.'),
 
     # NOTE(mikal): there are two options here because sometimes we are handed
     # a full instance (and could include more information), and other times we
     # are just handed a UUID for the instance.
     cfg.StrOpt('instance_format',
                default='[instance: %(uuid)s] ',
-               help='If an instance is passed with the log message, format '
-                    'it like this'),
+               help='The format for an instance that is passed with the log '
+                    'message.'),
     cfg.StrOpt('instance_uuid_format',
                default='[instance: %(uuid)s] ',
-               help='If an instance UUID is passed with the log message, '
-                    'format it like this'),
+               help='The format for an instance UUID that is passed with the '
+                    'log message.'),
 ]
 
 CONF = cfg.CONF
@@ -231,40 +222,6 @@
     return None
 
 
-def mask_password(message, secret="***"):
-    """Replace password with 'secret' in message.
-
-    :param message: The string which includes security information.
-    :param secret: value with which to replace passwords.
-    :returns: The unicode value of message with the password fields masked.
-
-    For example:
-
-    >>> mask_password("'adminPass' : 'aaaaa'")
-    "'adminPass' : '***'"
-    >>> mask_password("'admin_pass' : 'aaaaa'")
-    "'admin_pass' : '***'"
-    >>> mask_password('"password" : "aaaaa"')
-    '"password" : "***"'
-    >>> mask_password("'original_password' : 'aaaaa'")
-    "'original_password' : '***'"
-    >>> mask_password("u'original_password' :   u'aaaaa'")
-    "u'original_password' :   u'***'"
-    """
-    message = six.text_type(message)
-
-    # NOTE(ldbragst): Check to see if anything in message contains any key
-    # specified in _SANITIZE_KEYS, if not then just return the message since
-    # we don't have to mask any passwords.
-    if not any(key in message for key in _SANITIZE_KEYS):
-        return message
-
-    secret = r'\g<1>' + secret + r'\g<2>'
-    for pattern in _SANITIZE_PATTERNS:
-        message = re.sub(pattern, secret, message)
-    return message
-
-
 class BaseLoggerAdapter(logging.LoggerAdapter):
 
     def audit(self, msg, *args, **kwargs):
@@ -282,6 +239,11 @@
     def logger(self):
         if not self._logger:
             self._logger = getLogger(self.name, self.version)
+            if six.PY3:
+                # In Python 3, the code fails because the 'manager' attribute
+                # cannot be found when using a LoggerAdapter as the
+                # underlying logger. Work around this issue.
+                self._logger.manager = self._logger.logger.manager
         return self._logger
 
 
@@ -292,18 +254,39 @@
         self.logger = logger
         self.project = project_name
         self.version = version_string
+        self._deprecated_messages_sent = dict()
 
     @property
     def handlers(self):
         return self.logger.handlers
 
     def deprecated(self, msg, *args, **kwargs):
+        """Call this method when a deprecated feature is used.
+
+        If the system is configured for fatal deprecations then the message
+        is logged at the 'critical' level and :class:`DeprecatedConfig` will
+        be raised.
+
+        Otherwise, the message will be logged (once) at the 'warn' level.
+
+        :raises: :class:`DeprecatedConfig` if the system is configured for
+                 fatal deprecations.
+
+        """
         stdmsg = _("Deprecated: %s") % msg
         if CONF.fatal_deprecations:
             self.critical(stdmsg, *args, **kwargs)
             raise DeprecatedConfig(msg=stdmsg)
-        else:
-            self.warn(stdmsg, *args, **kwargs)
+
+        # Using a list because a tuple with dict can't be stored in a set.
+        sent_args = self._deprecated_messages_sent.setdefault(msg, list())
+
+        if args in sent_args:
+            # Already logged this message, so don't log it again.
+            return
+
+        sent_args.append(args)
+        self.warn(stdmsg, *args, **kwargs)
 
     def process(self, msg, kwargs):
         # NOTE(mrodden): catch any Message/other object and
@@ -324,7 +307,7 @@
             extra.update(_dictify_context(context))
 
         instance = kwargs.pop('instance', None)
-        instance_uuid = (extra.get('instance_uuid', None) or
+        instance_uuid = (extra.get('instance_uuid') or
                          kwargs.pop('instance_uuid', None))
         instance_extra = ''
         if instance:
@@ -390,10 +373,10 @@
 
 def _create_logging_excepthook(product_name):
     def logging_excepthook(exc_type, value, tb):
-        extra = {}
-        if CONF.verbose:
-            extra['exc_info'] = (exc_type, value, tb)
-        getLogger(product_name).critical(str(value), **extra)
+        extra = {'exc_info': (exc_type, value, tb)}
+        getLogger(product_name).critical(
+            "".join(traceback.format_exception_only(exc_type, value)),
+            **extra)
     return logging_excepthook
 
 
@@ -414,23 +397,31 @@
     try:
         logging.config.fileConfig(log_config_append,
                                   disable_existing_loggers=False)
-    except moves.configparser.Error as exc:
-        raise LogConfigError(log_config_append, str(exc))
+    except (moves.configparser.Error, KeyError) as exc:
+        raise LogConfigError(log_config_append, six.text_type(exc))
 
 
-def setup(product_name):
+def setup(product_name, version='unknown'):
     """Setup logging."""
     if CONF.log_config_append:
         _load_log_config(CONF.log_config_append)
     else:
-        _setup_logging_from_conf()
+        _setup_logging_from_conf(product_name, version)
     sys.excepthook = _create_logging_excepthook(product_name)
 
 
-def set_defaults(logging_context_format_string):
-    cfg.set_defaults(log_opts,
-                     logging_context_format_string=
-                     logging_context_format_string)
+def set_defaults(logging_context_format_string,
+                 default_log_levels=None):
+    # Just in case the caller is not setting the
+    # default_log_level. This is insurance because
+    # we introduced the default_log_level parameter
+    # later in a backwards in-compatible change
+    if default_log_levels is None:
+        default_log_levels = DEFAULT_LOG_LEVELS
+    cfg.set_defaults(
+            log_opts,
+            logging_context_format_string=logging_context_format_string,
+            default_log_levels=default_log_levels)
 
 
 def _find_facility_from_conf():
@@ -457,15 +448,38 @@
     return facility
 
 
-def _setup_logging_from_conf():
+class RFCSysLogHandler(logging.handlers.SysLogHandler):
+    def __init__(self, *args, **kwargs):
+        self.binary_name = _get_binary_name()
+        # Do not use super() unless type(logging.handlers.SysLogHandler)
+        #  is 'type' (Python 2.7).
+        # Use old style calls, if the type is 'classobj' (Python 2.6)
+        logging.handlers.SysLogHandler.__init__(self, *args, **kwargs)
+
+    def format(self, record):
+        # Do not use super() unless type(logging.handlers.SysLogHandler)
+        #  is 'type' (Python 2.7).
+        # Use old style calls, if the type is 'classobj' (Python 2.6)
+        msg = logging.handlers.SysLogHandler.format(self, record)
+        msg = self.binary_name + ' ' + msg
+        return msg
+
+
+def _setup_logging_from_conf(project, version):
     log_root = getLogger(None).logger
     for handler in log_root.handlers:
         log_root.removeHandler(handler)
 
     if CONF.use_syslog:
         facility = _find_facility_from_conf()
-        syslog = logging.handlers.SysLogHandler(address='/dev/log',
-                                                facility=facility)
+        # TODO(bogdando) use the format provided by RFCSysLogHandler
+        #   after existing syslog format deprecation in J
+        if CONF.use_syslog_rfc_format:
+            syslog = RFCSysLogHandler(address='/dev/log',
+                                      facility=facility)
+        else:
+            syslog = logging.handlers.SysLogHandler(address='/dev/log',
+                                                    facility=facility)
         log_root.addHandler(syslog)
 
     logpath = _get_log_file_path()
@@ -484,9 +498,14 @@
         log_root.addHandler(streamlog)
 
     if CONF.publish_errors:
-        handler = importutils.import_object(
-            "tempest.openstack.common.log_handler.PublishErrorsHandler",
-            logging.ERROR)
+        try:
+            handler = importutils.import_object(
+                "tempest.openstack.common.log_handler.PublishErrorsHandler",
+                logging.ERROR)
+        except ImportError:
+            handler = importutils.import_object(
+                "oslo.messaging.notify.log_handler.PublishErrorsHandler",
+                logging.ERROR)
         log_root.addHandler(handler)
 
     datefmt = CONF.log_date_format
@@ -499,7 +518,9 @@
             log_root.info('Deprecated: log_format is now deprecated and will '
                           'be removed in the next release')
         else:
-            handler.setFormatter(ContextFormatter(datefmt=datefmt))
+            handler.setFormatter(ContextFormatter(project=project,
+                                                  version=version,
+                                                  datefmt=datefmt))
 
     if CONF.debug:
         log_root.setLevel(logging.DEBUG)
@@ -510,9 +531,15 @@
 
     for pair in CONF.default_log_levels:
         mod, _sep, level_name = pair.partition('=')
-        level = logging.getLevelName(level_name)
         logger = logging.getLogger(mod)
-        logger.setLevel(level)
+        # NOTE(AAzza) in python2.6 Logger.setLevel doesn't convert string name
+        # to integer code.
+        if sys.version_info < (2, 7):
+            level = logging.getLevelName(level_name)
+            logger.setLevel(level)
+        else:
+            logger.setLevel(level_name)
+
 
 _loggers = {}
 
@@ -543,7 +570,7 @@
         self.level = level
 
     def write(self, msg):
-        self.logger.log(self.level, msg)
+        self.logger.log(self.level, msg.rstrip())
 
 
 class ContextFormatter(logging.Formatter):
@@ -557,27 +584,64 @@
     For information about what variables are available for the formatter see:
     http://docs.python.org/library/logging.html#formatter
 
+    If available, uses the context value stored in TLS - local.store.context
+
     """
 
+    def __init__(self, *args, **kwargs):
+        """Initialize ContextFormatter instance
+
+        Takes additional keyword arguments which can be used in the message
+        format string.
+
+        :keyword project: project name
+        :type project: string
+        :keyword version: project version
+        :type version: string
+
+        """
+
+        self.project = kwargs.pop('project', 'unknown')
+        self.version = kwargs.pop('version', 'unknown')
+
+        logging.Formatter.__init__(self, *args, **kwargs)
+
     def format(self, record):
         """Uses contextstring if request_id is set, otherwise default."""
-        # NOTE(sdague): default the fancier formating params
+
+        # store project info
+        record.project = self.project
+        record.version = self.version
+
+        # store request info
+        context = getattr(local.store, 'context', None)
+        if context:
+            d = _dictify_context(context)
+            for k, v in d.items():
+                setattr(record, k, v)
+
+        # NOTE(sdague): default the fancier formatting params
         # to an empty string so we don't throw an exception if
         # they get used
-        for key in ('instance', 'color'):
+        for key in ('instance', 'color', 'user_identity'):
             if key not in record.__dict__:
                 record.__dict__[key] = ''
 
-        if record.__dict__.get('request_id', None):
-            self._fmt = CONF.logging_context_format_string
+        if record.__dict__.get('request_id'):
+            fmt = CONF.logging_context_format_string
         else:
-            self._fmt = CONF.logging_default_format_string
+            fmt = CONF.logging_default_format_string
 
         if (record.levelno == logging.DEBUG and
                 CONF.logging_debug_format_suffix):
-            self._fmt += " " + CONF.logging_debug_format_suffix
+            fmt += " " + CONF.logging_debug_format_suffix
 
-        # Cache this on the record, Logger will respect our formated copy
+        if sys.version_info < (3, 2):
+            self._fmt = fmt
+        else:
+            self._style = logging.PercentStyle(fmt)
+            self._fmt = self._style._fmt
+        # Cache this on the record, Logger will respect our formatted copy
         if record.exc_info:
             record.exc_text = self.formatException(record.exc_info, record)
         return logging.Formatter.format(self, record)
diff --git a/tempest/openstack/common/strutils.py b/tempest/openstack/common/strutils.py
new file mode 100644
index 0000000..605cc02
--- /dev/null
+++ b/tempest/openstack/common/strutils.py
@@ -0,0 +1,295 @@
+# Copyright 2011 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.
+
+"""
+System-level utilities and helper functions.
+"""
+
+import math
+import re
+import sys
+import unicodedata
+
+import six
+
+from tempest.openstack.common.gettextutils import _
+
+
+UNIT_PREFIX_EXPONENT = {
+    'k': 1,
+    'K': 1,
+    'Ki': 1,
+    'M': 2,
+    'Mi': 2,
+    'G': 3,
+    'Gi': 3,
+    'T': 4,
+    'Ti': 4,
+}
+UNIT_SYSTEM_INFO = {
+    'IEC': (1024, re.compile(r'(^[-+]?\d*\.?\d+)([KMGT]i?)?(b|bit|B)$')),
+    'SI': (1000, re.compile(r'(^[-+]?\d*\.?\d+)([kMGT])?(b|bit|B)$')),
+}
+
+TRUE_STRINGS = ('1', 't', 'true', 'on', 'y', 'yes')
+FALSE_STRINGS = ('0', 'f', 'false', 'off', 'n', 'no')
+
+SLUGIFY_STRIP_RE = re.compile(r"[^\w\s-]")
+SLUGIFY_HYPHENATE_RE = re.compile(r"[-\s]+")
+
+
+# NOTE(flaper87): The following 3 globals are used by `mask_password`
+_SANITIZE_KEYS = ['adminPass', 'admin_pass', 'password', 'admin_password']
+
+# NOTE(ldbragst): Let's build a list of regex objects using the list of
+# _SANITIZE_KEYS we already have. This way, we only have to add the new key
+# to the list of _SANITIZE_KEYS and we can generate regular expressions
+# for XML and JSON automatically.
+_SANITIZE_PATTERNS = []
+_FORMAT_PATTERNS = [r'(%(key)s\s*[=]\s*[\"\']).*?([\"\'])',
+                    r'(<%(key)s>).*?(</%(key)s>)',
+                    r'([\"\']%(key)s[\"\']\s*:\s*[\"\']).*?([\"\'])',
+                    r'([\'"].*?%(key)s[\'"]\s*:\s*u?[\'"]).*?([\'"])',
+                    r'([\'"].*?%(key)s[\'"]\s*,\s*\'--?[A-z]+\'\s*,\s*u?[\'"])'
+                    '.*?([\'"])',
+                    r'(%(key)s\s*--?[A-z]+\s*)\S+(\s*)']
+
+for key in _SANITIZE_KEYS:
+    for pattern in _FORMAT_PATTERNS:
+        reg_ex = re.compile(pattern % {'key': key}, re.DOTALL)
+        _SANITIZE_PATTERNS.append(reg_ex)
+
+
+def int_from_bool_as_string(subject):
+    """Interpret a string as a boolean and return either 1 or 0.
+
+    Any string value in:
+
+        ('True', 'true', 'On', 'on', '1')
+
+    is interpreted as a boolean True.
+
+    Useful for JSON-decoded stuff and config file parsing
+    """
+    return bool_from_string(subject) and 1 or 0
+
+
+def bool_from_string(subject, strict=False, default=False):
+    """Interpret a string as a boolean.
+
+    A case-insensitive match is performed such that strings matching 't',
+    'true', 'on', 'y', 'yes', or '1' are considered True and, when
+    `strict=False`, anything else returns the value specified by 'default'.
+
+    Useful for JSON-decoded stuff and config file parsing.
+
+    If `strict=True`, unrecognized values, including None, will raise a
+    ValueError which is useful when parsing values passed in from an API call.
+    Strings yielding False are 'f', 'false', 'off', 'n', 'no', or '0'.
+    """
+    if not isinstance(subject, six.string_types):
+        subject = six.text_type(subject)
+
+    lowered = subject.strip().lower()
+
+    if lowered in TRUE_STRINGS:
+        return True
+    elif lowered in FALSE_STRINGS:
+        return False
+    elif strict:
+        acceptable = ', '.join(
+            "'%s'" % s for s in sorted(TRUE_STRINGS + FALSE_STRINGS))
+        msg = _("Unrecognized value '%(val)s', acceptable values are:"
+                " %(acceptable)s") % {'val': subject,
+                                      'acceptable': acceptable}
+        raise ValueError(msg)
+    else:
+        return default
+
+
+def safe_decode(text, incoming=None, errors='strict'):
+    """Decodes incoming text/bytes string using `incoming` if they're not
+       already unicode.
+
+    :param incoming: Text's current encoding
+    :param errors: Errors handling policy. See here for valid
+        values http://docs.python.org/2/library/codecs.html
+    :returns: text or a unicode `incoming` encoded
+                representation of it.
+    :raises TypeError: If text is not an instance of str
+    """
+    if not isinstance(text, (six.string_types, six.binary_type)):
+        raise TypeError("%s can't be decoded" % type(text))
+
+    if isinstance(text, six.text_type):
+        return text
+
+    if not incoming:
+        incoming = (sys.stdin.encoding or
+                    sys.getdefaultencoding())
+
+    try:
+        return text.decode(incoming, errors)
+    except UnicodeDecodeError:
+        # Note(flaper87) If we get here, it means that
+        # sys.stdin.encoding / sys.getdefaultencoding
+        # didn't return a suitable encoding to decode
+        # text. This happens mostly when global LANG
+        # var is not set correctly and there's no
+        # default encoding. In this case, most likely
+        # python will use ASCII or ANSI encoders as
+        # default encodings but they won't be capable
+        # of decoding non-ASCII characters.
+        #
+        # Also, UTF-8 is being used since it's an ASCII
+        # extension.
+        return text.decode('utf-8', errors)
+
+
+def safe_encode(text, incoming=None,
+                encoding='utf-8', errors='strict'):
+    """Encodes incoming text/bytes string using `encoding`.
+
+    If incoming is not specified, text is expected to be encoded with
+    current python's default encoding. (`sys.getdefaultencoding`)
+
+    :param incoming: Text's current encoding
+    :param encoding: Expected encoding for text (Default UTF-8)
+    :param errors: Errors handling policy. See here for valid
+        values http://docs.python.org/2/library/codecs.html
+    :returns: text or a bytestring `encoding` encoded
+                representation of it.
+    :raises TypeError: If text is not an instance of str
+    """
+    if not isinstance(text, (six.string_types, six.binary_type)):
+        raise TypeError("%s can't be encoded" % type(text))
+
+    if not incoming:
+        incoming = (sys.stdin.encoding or
+                    sys.getdefaultencoding())
+
+    if isinstance(text, six.text_type):
+        return text.encode(encoding, errors)
+    elif text and encoding != incoming:
+        # Decode text before encoding it with `encoding`
+        text = safe_decode(text, incoming, errors)
+        return text.encode(encoding, errors)
+    else:
+        return text
+
+
+def string_to_bytes(text, unit_system='IEC', return_int=False):
+    """Converts a string into an float representation of bytes.
+
+    The units supported for IEC ::
+
+        Kb(it), Kib(it), Mb(it), Mib(it), Gb(it), Gib(it), Tb(it), Tib(it)
+        KB, KiB, MB, MiB, GB, GiB, TB, TiB
+
+    The units supported for SI ::
+
+        kb(it), Mb(it), Gb(it), Tb(it)
+        kB, MB, GB, TB
+
+    Note that the SI unit system does not support capital letter 'K'
+
+    :param text: String input for bytes size conversion.
+    :param unit_system: Unit system for byte size conversion.
+    :param return_int: If True, returns integer representation of text
+                       in bytes. (default: decimal)
+    :returns: Numerical representation of text in bytes.
+    :raises ValueError: If text has an invalid value.
+
+    """
+    try:
+        base, reg_ex = UNIT_SYSTEM_INFO[unit_system]
+    except KeyError:
+        msg = _('Invalid unit system: "%s"') % unit_system
+        raise ValueError(msg)
+    match = reg_ex.match(text)
+    if match:
+        magnitude = float(match.group(1))
+        unit_prefix = match.group(2)
+        if match.group(3) in ['b', 'bit']:
+            magnitude /= 8
+    else:
+        msg = _('Invalid string format: %s') % text
+        raise ValueError(msg)
+    if not unit_prefix:
+        res = magnitude
+    else:
+        res = magnitude * pow(base, UNIT_PREFIX_EXPONENT[unit_prefix])
+    if return_int:
+        return int(math.ceil(res))
+    return res
+
+
+def to_slug(value, incoming=None, errors="strict"):
+    """Normalize string.
+
+    Convert to lowercase, remove non-word characters, and convert spaces
+    to hyphens.
+
+    Inspired by Django's `slugify` filter.
+
+    :param value: Text to slugify
+    :param incoming: Text's current encoding
+    :param errors: Errors handling policy. See here for valid
+        values http://docs.python.org/2/library/codecs.html
+    :returns: slugified unicode representation of `value`
+    :raises TypeError: If text is not an instance of str
+    """
+    value = safe_decode(value, incoming, errors)
+    # NOTE(aababilov): no need to use safe_(encode|decode) here:
+    # encodings are always "ascii", error handling is always "ignore"
+    # and types are always known (first: unicode; second: str)
+    value = unicodedata.normalize("NFKD", value).encode(
+        "ascii", "ignore").decode("ascii")
+    value = SLUGIFY_STRIP_RE.sub("", value).strip().lower()
+    return SLUGIFY_HYPHENATE_RE.sub("-", value)
+
+
+def mask_password(message, secret="***"):
+    """Replace password with 'secret' in message.
+
+    :param message: The string which includes security information.
+    :param secret: value with which to replace passwords.
+    :returns: The unicode value of message with the password fields masked.
+
+    For example:
+
+    >>> mask_password("'adminPass' : 'aaaaa'")
+    "'adminPass' : '***'"
+    >>> mask_password("'admin_pass' : 'aaaaa'")
+    "'admin_pass' : '***'"
+    >>> mask_password('"password" : "aaaaa"')
+    '"password" : "***"'
+    >>> mask_password("'original_password' : 'aaaaa'")
+    "'original_password' : '***'"
+    >>> mask_password("u'original_password' :   u'aaaaa'")
+    "u'original_password' :   u'***'"
+    """
+    message = six.text_type(message)
+
+    # NOTE(ldbragst): Check to see if anything in message contains any key
+    # specified in _SANITIZE_KEYS, if not then just return the message since
+    # we don't have to mask any passwords.
+    if not any(key in message for key in _SANITIZE_KEYS):
+        return message
+
+    secret = r'\g<1>' + secret + r'\g<2>'
+    for pattern in _SANITIZE_PATTERNS:
+        message = re.sub(pattern, secret, message)
+    return message
diff --git a/tempest/openstack/common/timeutils.py b/tempest/openstack/common/timeutils.py
index d5ed81d..c48da95 100644
--- a/tempest/openstack/common/timeutils.py
+++ b/tempest/openstack/common/timeutils.py
@@ -114,7 +114,7 @@
 
 
 def iso8601_from_timestamp(timestamp):
-    """Returns a iso8601 formated date from timestamp."""
+    """Returns an iso8601 formatted date from timestamp."""
     return isotime(datetime.datetime.utcfromtimestamp(timestamp))
 
 
@@ -134,7 +134,7 @@
 
 def advance_time_delta(timedelta):
     """Advance overridden time using a datetime.timedelta."""
-    assert(not utcnow.override_time is None)
+    assert utcnow.override_time is not None
     try:
         for dt in utcnow.override_time:
             dt += timedelta
diff --git a/tempest/openstack/common/versionutils.py b/tempest/openstack/common/versionutils.py
new file mode 100644
index 0000000..131046e
--- /dev/null
+++ b/tempest/openstack/common/versionutils.py
@@ -0,0 +1,148 @@
+# Copyright (c) 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.
+
+"""
+Helpers for comparing version strings.
+"""
+
+import functools
+import pkg_resources
+
+from tempest.openstack.common.gettextutils import _
+from tempest.openstack.common import log as logging
+
+
+LOG = logging.getLogger(__name__)
+
+
+class deprecated(object):
+    """A decorator to mark callables as deprecated.
+
+    This decorator logs a deprecation message when the callable it decorates is
+    used. The message will include the release where the callable was
+    deprecated, the release where it may be removed and possibly an optional
+    replacement.
+
+    Examples:
+
+    1. Specifying the required deprecated release
+
+    >>> @deprecated(as_of=deprecated.ICEHOUSE)
+    ... def a(): pass
+
+    2. Specifying a replacement:
+
+    >>> @deprecated(as_of=deprecated.ICEHOUSE, in_favor_of='f()')
+    ... def b(): pass
+
+    3. Specifying the release where the functionality may be removed:
+
+    >>> @deprecated(as_of=deprecated.ICEHOUSE, remove_in=+1)
+    ... def c(): pass
+
+    """
+
+    FOLSOM = 'F'
+    GRIZZLY = 'G'
+    HAVANA = 'H'
+    ICEHOUSE = 'I'
+
+    _RELEASES = {
+        'F': 'Folsom',
+        'G': 'Grizzly',
+        'H': 'Havana',
+        'I': 'Icehouse',
+    }
+
+    _deprecated_msg_with_alternative = _(
+        '%(what)s is deprecated as of %(as_of)s in favor of '
+        '%(in_favor_of)s and may be removed in %(remove_in)s.')
+
+    _deprecated_msg_no_alternative = _(
+        '%(what)s is deprecated as of %(as_of)s and may be '
+        'removed in %(remove_in)s. It will not be superseded.')
+
+    def __init__(self, as_of, in_favor_of=None, remove_in=2, what=None):
+        """Initialize decorator
+
+        :param as_of: the release deprecating the callable. Constants
+            are define in this class for convenience.
+        :param in_favor_of: the replacement for the callable (optional)
+        :param remove_in: an integer specifying how many releases to wait
+            before removing (default: 2)
+        :param what: name of the thing being deprecated (default: the
+            callable's name)
+
+        """
+        self.as_of = as_of
+        self.in_favor_of = in_favor_of
+        self.remove_in = remove_in
+        self.what = what
+
+    def __call__(self, func):
+        if not self.what:
+            self.what = func.__name__ + '()'
+
+        @functools.wraps(func)
+        def wrapped(*args, **kwargs):
+            msg, details = self._build_message()
+            LOG.deprecated(msg, details)
+            return func(*args, **kwargs)
+        return wrapped
+
+    def _get_safe_to_remove_release(self, release):
+        # TODO(dstanek): this method will have to be reimplemented once
+        #    when we get to the X release because once we get to the Y
+        #    release, what is Y+2?
+        new_release = chr(ord(release) + self.remove_in)
+        if new_release in self._RELEASES:
+            return self._RELEASES[new_release]
+        else:
+            return new_release
+
+    def _build_message(self):
+        details = dict(what=self.what,
+                       as_of=self._RELEASES[self.as_of],
+                       remove_in=self._get_safe_to_remove_release(self.as_of))
+
+        if self.in_favor_of:
+            details['in_favor_of'] = self.in_favor_of
+            msg = self._deprecated_msg_with_alternative
+        else:
+            msg = self._deprecated_msg_no_alternative
+        return msg, details
+
+
+def is_compatible(requested_version, current_version, same_major=True):
+    """Determine whether `requested_version` is satisfied by
+    `current_version`; in other words, `current_version` is >=
+    `requested_version`.
+
+    :param requested_version: version to check for compatibility
+    :param current_version: version to check against
+    :param same_major: if True, the major version must be identical between
+        `requested_version` and `current_version`. This is used when a
+        major-version difference indicates incompatibility between the two
+        versions. Since this is the common-case in practice, the default is
+        True.
+    :returns: True if compatible, False if not
+    """
+    requested_parts = pkg_resources.parse_version(requested_version)
+    current_parts = pkg_resources.parse_version(current_version)
+
+    if same_major and (requested_parts[0] != current_parts[0]):
+        return False
+
+    return current_parts >= requested_parts
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 7703d4d..aa24c31 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -21,6 +21,8 @@
 import subprocess
 import time
 
+from cinderclient import exceptions as cinder_exceptions
+import glanceclient
 from heatclient import exc as heat_exceptions
 import netaddr
 from neutronclient.common import exceptions as exc
@@ -51,6 +53,32 @@
 LOG_cinder_client.addHandler(log.NullHandler())
 
 
+class ScenarioTest(tempest.test.BaseTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        super(ScenarioTest, cls).setUpClass()
+        cls.isolated_creds = isolated_creds.IsolatedCreds(
+            cls.__name__, tempest_client=True,
+            network_resources=cls.network_resources)
+        cls.manager = clients.Manager(
+            credentials=cls.credentials()
+        )
+
+    @classmethod
+    def _get_credentials(cls, get_creds, ctype):
+        if CONF.compute.allow_tenant_isolation:
+            creds = get_creds()
+        else:
+            creds = auth.get_default_credentials(ctype)
+        return creds
+
+    @classmethod
+    def credentials(cls):
+        return cls._get_credentials(cls.isolated_creds.get_primary_creds,
+                                    'user')
+
+
 class OfficialClientTest(tempest.test.BaseTestCase):
     """
     Official Client test base class for scenario testing.
@@ -82,8 +110,7 @@
         cls.object_storage_client = cls.manager.object_storage_client
         cls.orchestration_client = cls.manager.orchestration_client
         cls.data_processing_client = cls.manager.data_processing_client
-        cls.resource_keys = {}
-        cls.os_resources = []
+        cls.ceilometer_client = cls.manager.ceilometer_client
 
     @classmethod
     def _get_credentials(cls, get_creds, ctype):
@@ -108,72 +135,85 @@
         return cls._get_credentials(cls.isolated_creds.get_admin_creds,
                                     'identity_admin')
 
-    @staticmethod
-    def cleanup_resource(resource, test_name):
+    def setUp(self):
+        super(OfficialClientTest, self).setUp()
+        self.cleanup_waits = []
+        # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
+        # because scenario tests in the same test class should not share
+        # resources. If resources were shared between test cases then it
+        # should be a single scenario test instead of multiples.
 
-        LOG.debug("Deleting %r from shared resources of %s" %
-                  (resource, test_name))
+        # NOTE(yfried): this list is cleaned at the end of test_methods and
+        # not at the end of the class
+        self.addCleanup(self._wait_for_cleanups)
+
+    @staticmethod
+    def not_found_exception(exception):
+        """
+        @return: True if exception is of NotFound type
+        """
+        NOT_FOUND_LIST = ['NotFound', 'HTTPNotFound']
+        return (exception.__class__.__name__ in NOT_FOUND_LIST
+                or
+                hasattr(exception, 'status_code') and
+                exception.status_code == 404)
+
+    def delete_wrapper(self, thing):
+        """Ignores NotFound exceptions for delete operations.
+
+        @param thing: object with delete() method.
+            OpenStack resources are assumed to have a delete() method which
+            destroys the resource
+        """
+
         try:
-            # OpenStack resources are assumed to have a delete()
-            # method which destroys the resource...
-            resource.delete()
+            thing.delete()
         except Exception as e:
             # If the resource is already missing, mission accomplished.
-            # - Status code tolerated as a workaround for bug 1247568
-            # - HTTPNotFound tolerated as this is currently raised when
-            # attempting to delete an already-deleted heat stack.
-            if (e.__class__.__name__ in ('NotFound', 'HTTPNotFound') or
-                    (hasattr(e, 'status_code') and e.status_code == 404)):
-                return
-            raise
-
-        def is_deletion_complete():
-            # Deletion testing is only required for objects whose
-            # existence cannot be checked via retrieval.
-            if isinstance(resource, dict):
-                return True
-            try:
-                resource.get()
-            except Exception as e:
-                # Clients are expected to return an exception
-                # called 'NotFound' if retrieval fails.
-                if e.__class__.__name__ == 'NotFound':
-                    return True
+            if not self.not_found_exception(e):
                 raise
-            return False
 
-        # Block until resource deletion has completed or timed-out
-        tempest.test.call_until_true(is_deletion_complete, 10, 1)
+    def _wait_for_cleanups(self):
+        """To handle async delete actions, a list of waits is added
+        which will be iterated over as the last step of clearing the
+        cleanup queue. That way all the delete calls are made up front
+        and the tests won't succeed unless the deletes are eventually
+        successful. This is the same basic approach used in the api tests to
+        limit cleanup execution time except here it is multi-resource,
+        because of the nature of the scenario tests.
+        """
+        for wait in self.cleanup_waits:
+            self.delete_timeout(**wait)
 
-    @classmethod
-    def tearDownClass(cls):
-        # NOTE(jaypipes): Because scenario tests are typically run in a
-        # specific order, and because test methods in scenario tests
-        # generally create resources in a particular order, we destroy
-        # resources in the reverse order in which resources are added to
-        # the scenario test class object
-        while cls.os_resources:
-            thing = cls.os_resources.pop()
-            cls.cleanup_resource(thing, cls.__name__)
-        cls.isolated_creds.clear_isolated_creds()
-        super(OfficialClientTest, cls).tearDownClass()
+    def addCleanup_with_wait(self, things, thing_id,
+                             error_status='ERROR',
+                             exc_type=nova_exceptions.NotFound,
+                             cleanup_callable=None, cleanup_args=[],
+                             cleanup_kwargs={}):
+        """Adds wait for ansyc resource deletion at the end of cleanups
 
-    @classmethod
-    def set_resource(cls, key, thing):
-        LOG.debug("Adding %r to shared resources of %s" %
-                  (thing, cls.__name__))
-        cls.resource_keys[key] = thing
-        cls.os_resources.append(thing)
-
-    @classmethod
-    def get_resource(cls, key):
-        return cls.resource_keys[key]
-
-    @classmethod
-    def remove_resource(cls, key):
-        thing = cls.resource_keys[key]
-        cls.os_resources.remove(thing)
-        del cls.resource_keys[key]
+        @param things: type of the resource to delete
+        @param thing_id:
+        @param error_status: see manager.delete_timeout()
+        @param exc_type: see manager.delete_timeout()
+        @param cleanup_callable: method to load pass to self.addCleanup with
+            the following *cleanup_args, **cleanup_kwargs.
+            usually a delete method. if not used, will try to use:
+            things.delete(thing_id)
+        """
+        if cleanup_callable is None:
+            LOG.debug("no delete method passed. using {rclass}.delete({id}) as"
+                      " default".format(rclass=things, id=thing_id))
+            self.addCleanup(things.delete, thing_id)
+        else:
+            self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
+        wait_dict = {
+            'things': things,
+            'thing_id': thing_id,
+            'error_status': error_status,
+            'not_found_exception': exc_type,
+        }
+        self.cleanup_waits.append(wait_dict)
 
     def status_timeout(self, things, thing_id, expected_status,
                        error_status='ERROR',
@@ -225,8 +265,11 @@
             except not_found_exception:
                 if allow_notfound:
                     return True
-                else:
-                    raise
+                raise
+            except Exception as e:
+                if allow_notfound and self.not_found_exception(e):
+                    return True
+                raise
 
             new_status = thing.status
 
@@ -286,11 +329,39 @@
         for ruleset in rulesets:
             sg_rule = client.security_group_rules.create(secgroup_id,
                                                          **ruleset)
+            self.addCleanup(self.delete_wrapper, sg_rule)
             rules.append(sg_rule)
         return rules
 
+    def _create_security_group_nova(self, client=None,
+                                    namestart='secgroup-smoke-'):
+        if client is None:
+            client = self.compute_client
+        # Create security group
+        sg_name = data_utils.rand_name(namestart)
+        sg_desc = sg_name + " description"
+        secgroup = client.security_groups.create(sg_name, sg_desc)
+        self.assertEqual(secgroup.name, sg_name)
+        self.assertEqual(secgroup.description, sg_desc)
+        self.addCleanup(self.delete_wrapper, secgroup)
+
+        # Add rules to the security group
+        self._create_loginable_secgroup_rule_nova(client, secgroup.id)
+
+        return secgroup
+
     def create_server(self, client=None, name=None, image=None, flavor=None,
-                      wait=True, create_kwargs={}):
+                      wait_on_boot=True, wait_on_delete=True,
+                      create_kwargs={}):
+        """Creates VM instance.
+
+        @param client: compute client to create the instance
+        @param image: image from which to create the instance
+        @param wait_on_boot: wait for status ACTIVE before continue
+        @param wait_on_delete: force synchronous delete on cleanup
+        @param create_kwargs: additional details for instance creation
+        @return: client.server object
+        """
         if client is None:
             client = self.compute_client
         if name is None:
@@ -324,19 +395,25 @@
                   name, image, flavor)
         server = client.servers.create(name, image, flavor, **create_kwargs)
         self.assertEqual(server.name, name)
-        self.set_resource(name, server)
-        if wait:
+        if wait_on_delete:
+            self.addCleanup(self.delete_timeout,
+                            self.compute_client.servers,
+                            server.id)
+        self.addCleanup_with_wait(self.compute_client.servers, server.id,
+                                  cleanup_callable=self.delete_wrapper,
+                                  cleanup_args=[server])
+        if wait_on_boot:
             self.status_timeout(client.servers, server.id, 'ACTIVE')
         # The instance retrieved on creation is missing network
         # details, necessitating retrieval after it becomes active to
         # ensure correct details.
         server = client.servers.get(server.id)
-        self.set_resource(name, server)
         LOG.debug("Created server: %s", server)
         return server
 
     def create_volume(self, client=None, size=1, name=None,
-                      snapshot_id=None, imageRef=None):
+                      snapshot_id=None, imageRef=None, volume_type=None,
+                      wait_on_delete=True):
         if client is None:
             client = self.volume_client
         if name is None:
@@ -344,8 +421,14 @@
         LOG.debug("Creating a volume (size: %s, name: %s)", size, name)
         volume = client.volumes.create(size=size, display_name=name,
                                        snapshot_id=snapshot_id,
-                                       imageRef=imageRef)
-        self.set_resource(name, volume)
+                                       imageRef=imageRef,
+                                       volume_type=volume_type)
+        if wait_on_delete:
+            self.addCleanup(self.delete_timeout,
+                            self.volume_client.volumes,
+                            volume.id)
+        self.addCleanup_with_wait(self.volume_client.volumes, volume.id,
+                                  exc_type=cinder_exceptions.NotFound)
         self.assertEqual(name, volume.display_name)
         self.status_timeout(client.volumes, volume.id, 'available')
         LOG.debug("Created volume: %s", volume)
@@ -361,7 +444,8 @@
             name = data_utils.rand_name('scenario-snapshot-')
         LOG.debug("Creating a snapshot image for server: %s", server.name)
         image_id = compute_client.servers.create_image(server, name)
-        self.addCleanup(image_client.images.delete, image_id)
+        self.addCleanup_with_wait(self.image_client.images, image_id,
+                                  exc_type=glanceclient.exc.HTTPNotFound)
         self.status_timeout(image_client.images, image_id, 'active')
         snapshot_image = image_client.images.get(image_id)
         self.assertEqual(name, snapshot_image.name)
@@ -376,7 +460,7 @@
             name = data_utils.rand_name('scenario-keypair-')
         keypair = client.keypairs.create(name)
         self.assertEqual(keypair.name, name)
-        self.set_resource(name, keypair)
+        self.addCleanup(self.delete_wrapper, keypair)
         return keypair
 
     def get_remote_client(self, server_or_ip, username=None, private_key=None):
@@ -389,7 +473,16 @@
             username = CONF.scenario.ssh_user
         if private_key is None:
             private_key = self.keypair.private_key
-        return remote_client.RemoteClient(ip, username, pkey=private_key)
+        linux_client = remote_client.RemoteClient(ip, username,
+                                                  pkey=private_key)
+        try:
+            linux_client.validate_authentication()
+        except exceptions.SSHTimeout:
+            LOG.exception('ssh connection to %s failed' % ip)
+            debug.log_net_debug()
+            raise
+
+        return linux_client
 
     def _log_console_output(self, servers=None):
         if not servers:
@@ -561,9 +654,12 @@
             'key_name': self.keypair.id
         }
         self.instance = self.create_server(
-            wait=False, create_kwargs=create_kwargs)
+            wait_on_boot=False, create_kwargs=create_kwargs)
 
-        self.set_resource('instance', self.instance)
+        self.addCleanup_with_wait(self.compute_client.servers,
+                                  self.instance.id,
+                                  cleanup_callable=self.delete_wrapper,
+                                  cleanup_args=[self.instance])
 
         self.wait_node(self.instance.id)
         self.node = self.get_node(instance_id=self.instance.id)
@@ -588,7 +684,6 @@
 
     def terminate_instance(self):
         self.instance.delete()
-        self.remove_resource('instance')
         self.wait_power_state(self.node.uuid, BaremetalPowerStates.POWER_OFF)
         self.wait_provisioning_state(
             self.node.uuid,
@@ -596,6 +691,75 @@
             timeout=CONF.baremetal.unprovision_timeout)
 
 
+class EncryptionScenarioTest(OfficialClientTest):
+    """
+    Base class for encryption scenario tests
+    """
+
+    @classmethod
+    def setUpClass(cls):
+        super(EncryptionScenarioTest, cls).setUpClass()
+
+        # use admin credentials to create encrypted volume types
+        admin_creds = cls.admin_credentials()
+        manager = clients.OfficialClientManager(credentials=admin_creds)
+        cls.admin_volume_client = manager.volume_client
+
+    def _wait_for_volume_status(self, status):
+        self.status_timeout(
+            self.volume_client.volumes, self.volume.id, status)
+
+    def nova_boot(self):
+        self.keypair = self.create_keypair()
+        create_kwargs = {'key_name': self.keypair.name}
+        self.server = self.create_server(self.compute_client,
+                                         image=self.image,
+                                         create_kwargs=create_kwargs)
+
+    def create_volume_type(self, client=None, name=None):
+        if not client:
+            client = self.admin_volume_client
+        if not name:
+            name = 'generic'
+        randomized_name = data_utils.rand_name('scenario-type-' + name + '-')
+        LOG.debug("Creating a volume type: %s", randomized_name)
+        volume_type = client.volume_types.create(randomized_name)
+        self.addCleanup(client.volume_types.delete, volume_type.id)
+        return volume_type
+
+    def create_encryption_type(self, client=None, type_id=None, provider=None,
+                               key_size=None, cipher=None,
+                               control_location=None):
+        if not client:
+            client = self.admin_volume_client
+        if not type_id:
+            volume_type = self.create_volume_type()
+            type_id = volume_type.id
+        LOG.debug("Creating an encryption type for volume type: %s", type_id)
+        client.volume_encryption_types.create(type_id,
+                                              {'provider': provider,
+                                               'key_size': key_size,
+                                               'cipher': cipher,
+                                               'control_location':
+                                               control_location})
+
+    def nova_volume_attach(self):
+        attach_volume_client = self.compute_client.volumes.create_server_volume
+        volume = attach_volume_client(self.server.id,
+                                      self.volume.id,
+                                      '/dev/vdb')
+        self.assertEqual(self.volume.id, volume.id)
+        self._wait_for_volume_status('in-use')
+
+    def nova_volume_detach(self):
+        detach_volume_client = self.compute_client.volumes.delete_server_volume
+        detach_volume_client(self.server.id, self.volume.id)
+        self._wait_for_volume_status('available')
+
+        volume = self.volume_client.volumes.get(self.volume.id)
+        self.assertEqual('available', volume.status)
+
+
 class NetworkScenarioTest(OfficialClientTest):
     """
     Base class for network scenario tests
@@ -633,7 +797,7 @@
         network = net_common.DeletableNetwork(client=self.network_client,
                                               **result['network'])
         self.assertEqual(network.name, name)
-        self.set_resource(name, network)
+        self.addCleanup(self.delete_wrapper, network)
         return network
 
     def _list_networks(self, **kwargs):
@@ -709,7 +873,7 @@
         subnet = net_common.DeletableSubnet(client=self.network_client,
                                             **result['subnet'])
         self.assertEqual(subnet.cidr, str_cidr)
-        self.set_resource(data_utils.rand_name(namestart), subnet)
+        self.addCleanup(self.delete_wrapper, subnet)
         return subnet
 
     def _create_port(self, network, namestart='port-quotatest-'):
@@ -722,7 +886,7 @@
         self.assertIsNotNone(result, 'Unable to allocate port')
         port = net_common.DeletablePort(client=self.network_client,
                                         **result['port'])
-        self.set_resource(name, port)
+        self.addCleanup(self.delete_wrapper, port)
         return port
 
     def _get_server_port_id(self, server, ip_addr=None):
@@ -745,7 +909,7 @@
         floating_ip = net_common.DeletableFloatingIp(
             client=self.network_client,
             **result['floatingip'])
-        self.set_resource(data_utils.rand_name('floatingip-'), floating_ip)
+        self.addCleanup(self.delete_wrapper, floating_ip)
         return floating_ip
 
     def _associate_floating_ip(self, floating_ip, server):
@@ -790,7 +954,7 @@
         pool = net_common.DeletablePool(client=self.network_client,
                                         **resp['pool'])
         self.assertEqual(pool['name'], name)
-        self.set_resource(name, pool)
+        self.addCleanup(self.delete_wrapper, pool)
         return pool
 
     def _create_member(self, address, protocol_port, pool_id):
@@ -805,7 +969,7 @@
         resp = self.network_client.create_member(body)
         member = net_common.DeletableMember(client=self.network_client,
                                             **resp['member'])
-        self.set_resource(data_utils.rand_name('member-'), member)
+        self.addCleanup(self.delete_wrapper, member)
         return member
 
     def _create_vip(self, protocol, protocol_port, subnet_id, pool_id):
@@ -824,7 +988,7 @@
         vip = net_common.DeletableVip(client=self.network_client,
                                       **resp['vip'])
         self.assertEqual(vip['name'], name)
-        self.set_resource(name, vip)
+        self.addCleanup(self.delete_wrapper, vip)
         return vip
 
     def _check_vm_connectivity(self, ip_address,
@@ -851,9 +1015,7 @@
                         msg=msg)
         if should_connect:
             # no need to check ssh for negative connectivity
-            linux_client = self.get_remote_client(ip_address, username,
-                                                  private_key)
-            linux_client.validate_authentication()
+            self.get_remote_client(ip_address, username, private_key)
 
     def _check_public_network_connectivity(self, ip_address, username,
                                            private_key, should_connect=True,
@@ -867,13 +1029,15 @@
                                         username,
                                         private_key,
                                         should_connect=should_connect)
-        except Exception:
+        except Exception as e:
             ex_msg = 'Public network connectivity check failed'
             if msg:
                 ex_msg += ": " + msg
             LOG.exception(ex_msg)
             self._log_console_output(servers)
-            debug.log_net_debug()
+            # network debug is called as part of ssh init
+            if not isinstance(e, exceptions.SSHTimeout):
+                debug.log_net_debug()
             raise
 
     def _check_tenant_network_connectivity(self, server,
@@ -894,10 +1058,12 @@
                                                 username,
                                                 private_key,
                                                 should_connect=should_connect)
-        except Exception:
+        except Exception as e:
             LOG.exception('Tenant network connectivity check failed')
             self._log_console_output(servers_for_debug)
-            debug.log_net_debug()
+            # network debug is called as part of ssh init
+            if not isinstance(e, exceptions.SSHTimeout):
+                debug.log_net_debug()
             raise
 
     def _check_remote_connectivity(self, source, dest, should_succeed=True):
@@ -922,24 +1088,6 @@
                                             CONF.compute.ping_timeout,
                                             1)
 
-    def _create_security_group_nova(self, client=None,
-                                    namestart='secgroup-smoke-',
-                                    tenant_id=None):
-        if client is None:
-            client = self.compute_client
-        # Create security group
-        sg_name = data_utils.rand_name(namestart)
-        sg_desc = sg_name + " description"
-        secgroup = client.security_groups.create(sg_name, sg_desc)
-        self.assertEqual(secgroup.name, sg_name)
-        self.assertEqual(secgroup.description, sg_desc)
-        self.set_resource(sg_name, secgroup)
-
-        # Add rules to the security group
-        self._create_loginable_secgroup_rule_nova(client, secgroup.id)
-
-        return secgroup
-
     def _create_security_group_neutron(self, tenant_id, client=None,
                                        namestart='secgroup-smoke-'):
         if client is None:
@@ -982,7 +1130,7 @@
         self.assertEqual(secgroup.name, sg_name)
         self.assertEqual(tenant_id, secgroup.tenant_id)
         self.assertEqual(secgroup.description, sg_desc)
-        self.set_resource(sg_name, secgroup)
+        self.addCleanup(self.delete_wrapper, secgroup)
         return secgroup
 
     def _default_security_group(self, tenant_id, client=None):
@@ -1041,6 +1189,7 @@
             client=client,
             **sg_rule['security_group_rule']
         )
+        self.addCleanup(self.delete_wrapper, sg_rule)
         self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
         self.assertEqual(secgroup.id, sg_rule.security_group_id)
 
@@ -1139,7 +1288,7 @@
         router = net_common.DeletableRouter(client=self.network_client,
                                             **result['router'])
         self.assertEqual(router.name, name)
-        self.set_resource(name, router)
+        self.addCleanup(self.delete_wrapper, router)
         return router
 
     def _create_networks(self, tenant_id=None):
diff --git a/tempest/scenario/orchestration/test_autoscaling.py b/tempest/scenario/orchestration/test_autoscaling.py
index 82ba3c5..aa7b6f8 100644
--- a/tempest/scenario/orchestration/test_autoscaling.py
+++ b/tempest/scenario/orchestration/test_autoscaling.py
@@ -59,7 +59,7 @@
         # if a keypair was set, do not delete the stack on exit to allow
         # for manual post-mortums
         if not CONF.orchestration.keypair_name:
-            self.set_resource('stack', self.stack)
+            self.addCleanup(self.client.stacks.delete, self.stack)
 
     @test.skip_because(bug="1257575")
     @test.attr(type='slow')
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index 6817c48..0059619 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -42,13 +42,12 @@
         availability_zone = kwargs['availability_zone']
         self.assertEqual(aggregate.name, aggregate_name)
         self.assertEqual(aggregate.availability_zone, availability_zone)
-        self.set_resource(aggregate.id, aggregate)
+        self.addCleanup(self._delete_aggregate, aggregate)
         LOG.debug("Aggregate %s created." % (aggregate.name))
         return aggregate
 
     def _delete_aggregate(self, aggregate):
         self.compute_client.aggregates.delete(aggregate.id)
-        self.remove_resource(aggregate.id)
         LOG.debug("Aggregate %s deleted. " % (aggregate.name))
 
     def _get_host_name(self):
@@ -60,6 +59,7 @@
     def _add_host(self, aggregate_name, host):
         aggregate = self.compute_client.aggregates.add_host(aggregate_name,
                                                             host)
+        self.addCleanup(self._remove_host, aggregate, host)
         self.assertIn(host, aggregate.hosts)
         LOG.debug("Host %s added to Aggregate %s." % (host, aggregate.name))
 
@@ -128,6 +128,3 @@
         metadata.update(additional_metadata)
         self._check_aggregate_details(aggregate, aggregate.name, az, [host],
                                       metadata)
-
-        self._remove_host(aggregate, host)
-        self._delete_aggregate(aggregate)
diff --git a/tempest/scenario/test_baremetal_basic_ops.py b/tempest/scenario/test_baremetal_basic_ops.py
index 82c6b5d..f197c15 100644
--- a/tempest/scenario/test_baremetal_basic_ops.py
+++ b/tempest/scenario/test_baremetal_basic_ops.py
@@ -31,8 +31,6 @@
         * Boots an instance using the keypair
         * Monitors the associated Ironic node for power and
           expected state transitions
-        * Validates Ironic node's driver_info has been properly
-          updated
         * Validates Ironic node's port data has been properly updated
         * Verifies SSH connectivity using created keypair via fixed IP
         * Associates a floating ip
@@ -46,17 +44,6 @@
         self.instance.add_floating_ip(floating_ip)
         return floating_ip.ip
 
-    def validate_driver_info(self):
-        f_id = self.instance.flavor['id']
-        flavor_extra = self.compute_client.flavors.get(f_id).get_keys()
-        driver_info = self.node.driver_info
-        self.assertEqual(driver_info['pxe_deploy_kernel'],
-                         flavor_extra['baremetal:deploy_kernel_id'])
-        self.assertEqual(driver_info['pxe_deploy_ramdisk'],
-                         flavor_extra['baremetal:deploy_ramdisk_id'])
-        self.assertEqual(driver_info['pxe_image_source'],
-                         self.instance.image['id'])
-
     def validate_ports(self):
         for port in self.get_ports(self.node.uuid):
             n_port_id = port.extra['vif_port_id']
@@ -68,7 +55,6 @@
     def test_baremetal_server_ops(self):
         self.add_keypair()
         self.boot_instance()
-        self.validate_driver_info()
         self.validate_ports()
         self.verify_connectivity()
         floating_ip = self.add_floating_ip()
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
index 6418a73..4fcc70a 100644
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ b/tempest/scenario/test_dashboard_basic_ops.py
@@ -24,7 +24,7 @@
 CONF = config.CONF
 
 
-class TestDashboardBasicOps(manager.OfficialClientTest):
+class TestDashboardBasicOps(manager.ScenarioTest):
 
     """
     This is a basic scenario test:
diff --git a/tempest/scenario/test_encrypted_cinder_volumes.py b/tempest/scenario/test_encrypted_cinder_volumes.py
new file mode 100644
index 0000000..366cd93
--- /dev/null
+++ b/tempest/scenario/test_encrypted_cinder_volumes.py
@@ -0,0 +1,63 @@
+# Copyright (c) 2014 The Johns Hopkins University/Applied Physics Laboratory
+# 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.scenario import manager
+from tempest import test
+
+
+class TestEncryptedCinderVolumes(manager.EncryptionScenarioTest):
+
+    """
+    This test is for verifying the functionality of encrypted cinder volumes.
+
+    For both LUKS and cryptsetup encryption types, this test performs
+    the following:
+        * Creates an image in Glance
+        * Boots an instance from the image
+        * Creates an encryption type (as admin)
+        * Creates a volume of that encryption type (as a regular user)
+        * Attaches and detaches the encrypted volume to the instance
+    """
+
+    def launch_instance(self):
+        self.glance_image_create()
+        self.nova_boot()
+
+    def create_encrypted_volume(self, encryption_provider):
+        volume_type = self.create_volume_type(name='luks')
+        self.create_encryption_type(type_id=volume_type.id,
+                                    provider=encryption_provider,
+                                    key_size=512,
+                                    cipher='aes-xts-plain64',
+                                    control_location='front-end')
+        self.volume = self.create_volume(volume_type=volume_type.name)
+
+    def attach_detach_volume(self):
+        self.nova_volume_attach()
+        self.nova_volume_detach()
+
+    @test.services('compute', 'volume', 'image')
+    def test_encrypted_cinder_volumes_luks(self):
+        self.launch_instance()
+        self.create_encrypted_volume('nova.volume.encryptors.'
+                                     'luks.LuksEncryptor')
+        self.attach_detach_volume()
+
+    @test.services('compute', 'volume', 'image')
+    def test_encrypted_cinder_volumes_cryptsetup(self):
+        self.launch_instance()
+        self.create_encrypted_volume('nova.volume.encryptors.'
+                                     'cryptsetup.CryptsetupEncryptor')
+        self.attach_detach_volume()
\ No newline at end of file
diff --git a/tempest/scenario/test_large_ops.py b/tempest/scenario/test_large_ops.py
index ed5743c..15cf13b 100644
--- a/tempest/scenario/test_large_ops.py
+++ b/tempest/scenario/test_large_ops.py
@@ -60,7 +60,13 @@
         # needed because of bug 1199788
         self.servers = [x for x in client.servers.list() if name in x.name]
         for server in self.servers:
-            self.set_resource(server.name, server)
+            # after deleting all servers - wait for all servers to clear
+            # before cleanup continues
+            self.addCleanup(self.delete_timeout,
+                            self.compute_client.servers,
+                            server.id)
+        for server in self.servers:
+            self.addCleanup_with_wait(self.compute_client.servers, server.id)
         self._wait_for_server_status('ACTIVE')
 
     def _large_ops_scenario(self):
diff --git a/tempest/scenario/test_load_balancer_basic.py b/tempest/scenario/test_load_balancer_basic.py
index 1c24b5c..8191984 100644
--- a/tempest/scenario/test_load_balancer_basic.py
+++ b/tempest/scenario/test_load_balancer_basic.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 
-import httplib
 import tempfile
 import time
 import urllib2
@@ -75,15 +74,11 @@
         self.server_fixed_ips = {}
         self._create_security_group()
 
-    def cleanup_wrapper(self, resource):
-        self.cleanup_resource(resource, self.__class__.__name__)
-
     def _create_security_group(self):
         self.security_group = self._create_security_group_neutron(
             tenant_id=self.tenant_id)
         self._create_security_group_rules_for_port(self.port1)
         self._create_security_group_rules_for_port(self.port2)
-        self.addCleanup(self.cleanup_wrapper, self.security_group)
 
     def _create_security_group_rules_for_port(self, port):
         rule = {
@@ -100,7 +95,6 @@
 
     def _create_server(self, name):
         keypair = self.create_keypair(name='keypair-%s' % name)
-        self.addCleanup(self.cleanup_wrapper, keypair)
         security_groups = [self.security_group.name]
         net = self._list_networks(tenant_id=self.tenant_id)[0]
         create_kwargs = {
@@ -112,14 +106,12 @@
         }
         server = self.create_server(name=name,
                                     create_kwargs=create_kwargs)
-        self.addCleanup(self.cleanup_wrapper, server)
         self.servers_keypairs[server.id] = keypair
         if (config.network.public_network_id and not
                 config.network.tenant_networks_reachable):
             public_network_id = config.network.public_network_id
             floating_ip = self._create_floating_ip(
                 server, public_network_id)
-            self.addCleanup(self.cleanup_wrapper, floating_ip)
             self.floating_ips[floating_ip] = server
             self.server_ips[server.id] = floating_ip.floating_ip_address
         else:
@@ -148,10 +140,12 @@
             ssh_client = self.get_remote_client(
                 server_or_ip=ip,
                 private_key=private_key)
-            ssh_client.validate_authentication()
 
-            # Write a backend's responce into a file
-            resp = """HTTP/1.0 200 OK\r\nContent-Length: 8\r\n\r\n%s"""
+            # Write a backend's response into a file
+            resp = """echo -ne "HTTP/1.1 200 OK\r\nContent-Length: 7\r\n""" \
+                   """Connection: close\r\nContent-Type: text/html; """ \
+                   """charset=UTF-8\r\n\r\n%s"; cat >/dev/null"""
+
             with tempfile.NamedTemporaryFile() as script:
                 script.write(resp % server_name)
                 script.flush()
@@ -159,15 +153,17 @@
                     key.write(private_key)
                     key.flush()
                     commands.copy_file_to_host(script.name,
-                                               "~/script1",
+                                               "/tmp/script1",
                                                ip,
                                                username, key.name)
+
             # Start netcat
-            start_server = """sudo nc -ll -p %(port)s -e cat """ \
-                           """~/%(script)s &"""
+            start_server = """sudo nc -ll -p %(port)s -e sh """ \
+                           """/tmp/%(script)s &"""
             cmd = start_server % {'port': self.port1,
                                   'script': 'script1'}
             ssh_client.exec_command(cmd)
+
             if len(self.server_ips) == 1:
                 with tempfile.NamedTemporaryFile() as script:
                     script.write(resp % 'server2')
@@ -176,7 +172,7 @@
                         key.write(private_key)
                         key.flush()
                         commands.copy_file_to_host(script.name,
-                                                   "~/script2", ip,
+                                                   "/tmp/script2", ip,
                                                    username, key.name)
                 cmd = start_server % {'port': self.port2,
                                       'script': 'script2'}
@@ -208,7 +204,6 @@
             lb_method='ROUND_ROBIN',
             protocol='HTTP',
             subnet_id=self.subnet.id)
-        self.addCleanup(self.cleanup_wrapper, self.pool)
         self.assertTrue(self.pool)
 
     def _create_members(self):
@@ -224,17 +219,14 @@
                 member1 = self._create_member(address=ip,
                                               protocol_port=self.port1,
                                               pool_id=self.pool.id)
-                self.addCleanup(self.cleanup_wrapper, member1)
                 member2 = self._create_member(address=ip,
                                               protocol_port=self.port2,
                                               pool_id=self.pool.id)
-                self.addCleanup(self.cleanup_wrapper, member2)
                 self.members.extend([member1, member2])
             else:
                 member = self._create_member(address=ip,
                                              protocol_port=self.port1,
                                              pool_id=self.pool.id)
-                self.addCleanup(self.cleanup_wrapper, member)
                 self.members.append(member)
         self.assertTrue(self.members)
 
@@ -243,7 +235,6 @@
         port_id = vip.port_id
         floating_ip = self._create_floating_ip(vip, public_network_id,
                                                port_id=port_id)
-        self.addCleanup(self.cleanup_wrapper, floating_ip)
         self.floating_ips.setdefault(vip.id, [])
         self.floating_ips[vip.id].append(floating_ip)
 
@@ -254,7 +245,6 @@
                                     protocol_port=80,
                                     subnet_id=self.subnet.id,
                                     pool_id=self.pool.id)
-        self.addCleanup(self.cleanup_wrapper, self.vip)
         self.status_timeout(NeutronRetriever(self.network_client,
                                              self.network_client.vip_path,
                                              net_common.DeletableVip),
@@ -268,6 +258,13 @@
         else:
             self.vip_ip = self.vip.address
 
+        # Currently the ovs-agent is not enforcing security groups on the
+        # vip port - see https://bugs.launchpad.net/neutron/+bug/1163569
+        # However the linuxbridge-agent does, and it is necessary to add a
+        # security group with a rule that allows tcp port 80 to the vip port.
+        body = {'port': {'security_groups': [self.security_group.id]}}
+        self.network_client.update_port(self.vip.port_id, body)
+
     def _check_load_balancing(self):
         """
         1. Send 10 requests on the floating ip associated with the VIP
@@ -282,19 +279,14 @@
     def _send_requests(self, vip_ip, expected, num_req=10):
         count = 0
         while count < num_req:
-            try:
-                resp = []
-                for i in range(len(self.members)):
-                    resp.append(
-                        urllib2.urlopen(
-                            "http://{0}/".format(vip_ip)).read())
-                count += 1
-                self.assertEqual(expected,
-                                 set(resp))
-            # NOTE: There always is a slim chance of getting this exception
-            #       due to special aspects of haproxy internal behavior.
-            except httplib.BadStatusLine:
-                pass
+            resp = []
+            for i in range(len(self.members)):
+                resp.append(
+                    urllib2.urlopen(
+                        "http://{0}/".format(vip_ip)).read())
+            count += 1
+            self.assertEqual(expected,
+                             set(resp))
 
     @test.attr(type='smoke')
     @test.services('compute', 'network')
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 24d2677..29fdc74 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -85,7 +85,7 @@
 
     def nova_floating_ip_create(self):
         self.floating_ip = self.compute_client.floating_ips.create()
-        self.addCleanup(self.floating_ip.delete)
+        self.addCleanup(self.delete_wrapper, self.floating_ip)
 
     def nova_floating_ip_add(self):
         self.server.add_floating_ip(self.floating_ip)
@@ -93,11 +93,12 @@
     def ssh_to_server(self):
         try:
             self.linux_client = self.get_remote_client(self.floating_ip.ip)
-            self.linux_client.validate_authentication()
-        except Exception:
+        except Exception as e:
             LOG.exception('ssh to server failed')
             self._log_console_output()
-            debug.log_net_debug()
+            # network debug is called as part of ssh init
+            if not isinstance(e, test.exceptions.SSHTimeout):
+                debug.log_net_debug()
             raise
 
     def check_partitions(self):
@@ -112,6 +113,11 @@
         volume = self.volume_client.volumes.get(self.volume.id)
         self.assertEqual('available', volume.status)
 
+    def create_and_add_security_group(self):
+        secgroup = self._create_security_group_nova()
+        self.server.add_security_group(secgroup.name)
+        self.addCleanup(self.server.remove_security_group, secgroup.name)
+
     @test.services('compute', 'volume', 'image', 'network')
     def test_minimum_basic_scenario(self):
         self.glance_image_create()
@@ -128,7 +134,7 @@
 
         self.nova_floating_ip_create()
         self.nova_floating_ip_add()
-        self._create_loginable_secgroup_rule_nova()
+        self.create_and_add_security_group()
         self.ssh_to_server()
         self.nova_reboot()
         self.ssh_to_server()
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index f1cd320..431de9a 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -50,23 +50,15 @@
             cls.enabled = False
             raise cls.skipException(msg)
 
-    def cleanup_wrapper(self, resource):
-        self.cleanup_resource(resource, self.__class__.__name__)
-
     def setUp(self):
         super(TestNetworkAdvancedServerOps, self).setUp()
         key_name = data_utils.rand_name('keypair-smoke-')
         self.keypair = self.create_keypair(name=key_name)
-        self.addCleanup(self.cleanup_wrapper, self.keypair)
         security_group =\
             self._create_security_group_neutron(tenant_id=self.tenant_id)
-        self.addCleanup(self.cleanup_wrapper, security_group)
         network = self._create_network(self.tenant_id)
-        self.addCleanup(self.cleanup_wrapper, network)
         router = self._get_router(self.tenant_id)
-        self.addCleanup(self.cleanup_wrapper, router)
         subnet = self._create_subnet(network)
-        self.addCleanup(self.cleanup_wrapper, subnet)
         subnet.add_to_router(router.id)
         public_network_id = CONF.network.public_network_id
         create_kwargs = {
@@ -79,10 +71,8 @@
         server_name = data_utils.rand_name('server-smoke-%d-')
         self.server = self.create_server(name=server_name,
                                          create_kwargs=create_kwargs)
-        self.addCleanup(self.cleanup_wrapper, self.server)
         self.floating_ip = self._create_floating_ip(self.server,
                                                     public_network_id)
-        self.addCleanup(self.cleanup_wrapper, self.floating_ip)
 
     def _check_network_connectivity(self, should_connect=True):
         username = CONF.compute.image_ssh_user
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 21782ee..7dc817d 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -87,6 +87,8 @@
 
     @classmethod
     def setUpClass(cls):
+        # Create no network resources for these tests.
+        cls.set_network_resources()
         super(TestNetworkBasicOps, cls).setUpClass()
         for ext in ['router', 'security-group']:
             if not test.is_extension_enabled(ext, 'network'):
@@ -94,17 +96,11 @@
                 raise cls.skipException(msg)
         cls.check_preconditions()
 
-    def cleanup_wrapper(self, resource):
-        self.cleanup_resource(resource, self.__class__.__name__)
-
     def setUp(self):
         super(TestNetworkBasicOps, self).setUp()
         self.security_group = \
             self._create_security_group_neutron(tenant_id=self.tenant_id)
-        self.addCleanup(self.cleanup_wrapper, self.security_group)
         self.network, self.subnet, self.router = self._create_networks()
-        for r in [self.network, self.router, self.subnet]:
-            self.addCleanup(self.cleanup_wrapper, r)
         self.check_networks()
         self.servers = {}
         name = data_utils.rand_name('server-smoke')
@@ -142,7 +138,6 @@
 
     def _create_server(self, name, network):
         keypair = self.create_keypair(name='keypair-%s' % name)
-        self.addCleanup(self.cleanup_wrapper, keypair)
         security_groups = [self.security_group.name]
         create_kwargs = {
             'nics': [
@@ -152,7 +147,6 @@
             'security_groups': security_groups,
         }
         server = self.create_server(name=name, create_kwargs=create_kwargs)
-        self.addCleanup(self.cleanup_wrapper, server)
         return dict(server=server, keypair=keypair)
 
     def _check_tenant_network_connectivity(self):
@@ -169,7 +163,6 @@
         for server in self.servers.keys():
             floating_ip = self._create_floating_ip(server, public_network_id)
             self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
-            self.addCleanup(self.cleanup_wrapper, floating_ip)
 
     def _check_public_network_connectivity(self, should_connect=True,
                                            msg=None):
@@ -202,11 +195,9 @@
 
     def _create_new_network(self):
         self.new_net = self._create_network(self.tenant_id)
-        self.addCleanup(self.cleanup_wrapper, self.new_net)
         self.new_subnet = self._create_subnet(
             network=self.new_net,
             gateway_ip=None)
-        self.addCleanup(self.cleanup_wrapper, self.new_subnet)
 
     def _hotplug_server(self):
         old_floating_ip, server = self.floating_ip_tuple
@@ -224,7 +215,10 @@
                                                      port_id=None,
                                                      fixed_ip=None)
         # move server to the head of the cleanup list
-        self.addCleanup(self.cleanup_wrapper, server)
+        self.addCleanup(self.delete_timeout,
+                        self.compute_client.servers,
+                        server.id)
+        self.addCleanup(self.delete_wrapper, server)
 
         def check_ports():
             port_list = [port for port in
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index 4616b82..8058b3d 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -134,6 +134,8 @@
 
     @classmethod
     def setUpClass(cls):
+        # Create no network resources for these tests.
+        cls.set_network_resources()
         super(TestSecurityGroupsBasicOps, cls).setUpClass()
         cls.alt_creds = cls.alt_credentials()
         cls.alt_manager = clients.OfficialClientManager(cls.alt_creds)
@@ -163,7 +165,6 @@
     def _create_tenant_keypairs(self, tenant_id):
         keypair = self.create_keypair(
             name=data_utils.rand_name('keypair-smoke-'))
-        self.addCleanup(self.cleanup_wrapper, keypair)
         self.tenants[tenant_id].keypair = keypair
 
     def _create_tenant_security_groups(self, tenant):
@@ -171,14 +172,12 @@
             namestart='secgroup_access-',
             tenant_id=tenant.creds.tenant_id
         )
-        self.addCleanup(self.cleanup_wrapper, access_sg)
 
         # don't use default secgroup since it allows in-tenant traffic
         def_sg = self._create_empty_security_group(
             namestart='secgroup_general-',
             tenant_id=tenant.creds.tenant_id
         )
-        self.addCleanup(self.cleanup_wrapper, def_sg)
         tenant.security_groups.update(access=access_sg, default=def_sg)
         ssh_rule = dict(
             protocol='tcp',
@@ -186,9 +185,7 @@
             port_range_max=22,
             direction='ingress',
         )
-        rule = self._create_security_group_rule(secgroup=access_sg,
-                                                **ssh_rule)
-        self.addCleanup(self.cleanup_wrapper, rule)
+        self._create_security_group_rule(secgroup=access_sg, **ssh_rule)
 
     def _verify_network_details(self, tenant):
         # Checks that we see the newly created network/subnet/router via
@@ -236,7 +233,6 @@
             'tenant_id': tenant.creds.tenant_id
         }
         server = self.create_server(name=name, create_kwargs=create_kwargs)
-        self.addCleanup(self.cleanup_wrapper, server)
         return server
 
     def _create_tenant_servers(self, tenant, num=1):
@@ -267,13 +263,10 @@
     def _assign_floating_ips(self, server):
         public_network_id = CONF.network.public_network_id
         floating_ip = self._create_floating_ip(server, public_network_id)
-        self.addCleanup(self.cleanup_wrapper, floating_ip)
         self.floating_ips.setdefault(server, floating_ip)
 
     def _create_tenant_network(self, tenant):
         network, subnet, router = self._create_networks(tenant.creds.tenant_id)
-        for r in [network, router, subnet]:
-            self.addCleanup(self.cleanup_wrapper, r)
         tenant.set_network(network, subnet, router)
 
     def _set_compute_context(self, tenant):
@@ -334,6 +327,8 @@
             self.assertTrue(self._check_remote_connectivity(access_point, ip,
                                                             should_succeed),
                             msg)
+        except test.exceptions.SSHTimeout:
+            raise
         except Exception:
             debug.log_net_debug()
             raise
@@ -351,11 +346,10 @@
             remote_group_id=tenant.security_groups['default'].id,
             direction='ingress'
         )
-        rule = self._create_security_group_rule(
+        self._create_security_group_rule(
             secgroup=tenant.security_groups['default'],
             **ruleset
         )
-        self.addCleanup(self.cleanup_wrapper, rule)
         access_point_ssh = self._connect_to_access_point(tenant)
         for server in tenant.servers:
             self._check_connectivity(access_point=access_point_ssh,
@@ -381,11 +375,10 @@
             protocol='icmp',
             direction='ingress'
         )
-        rule_s2d = self._create_security_group_rule(
+        self._create_security_group_rule(
             secgroup=dest_tenant.security_groups['default'],
             **ruleset
         )
-        self.addCleanup(self.cleanup_wrapper, rule_s2d)
         access_point_ssh = self._connect_to_access_point(source_tenant)
         ip = self._get_server_ip(dest_tenant.access_point,
                                  floating=self.floating_ip_access)
@@ -395,11 +388,10 @@
         self._test_cross_tenant_block(dest_tenant, source_tenant)
 
         # allow reverse traffic and check
-        rule_d2s = self._create_security_group_rule(
+        self._create_security_group_rule(
             secgroup=source_tenant.security_groups['default'],
             **ruleset
         )
-        self.addCleanup(self.cleanup_wrapper, rule_d2s)
 
         access_point_ssh_2 = self._connect_to_access_point(dest_tenant)
         ip = self._get_server_ip(source_tenant.access_point,
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 13e00a5..38686d9 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -13,7 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.common.utils import data_utils
 from tempest import config
 from tempest.openstack.common import log as logging
 from tempest.scenario import manager
@@ -68,47 +67,30 @@
     def add_keypair(self):
         self.keypair = self.create_keypair()
 
-    def create_security_group(self):
-        sg_name = data_utils.rand_name('secgroup-smoke')
-        sg_desc = sg_name + " description"
-        self.secgroup = self.compute_client.security_groups.create(sg_name,
-                                                                   sg_desc)
-        self.assertEqual(self.secgroup.name, sg_name)
-        self.assertEqual(self.secgroup.description, sg_desc)
-        self.set_resource('secgroup', self.secgroup)
-
-        # Add rules to the security group
-        self._create_loginable_secgroup_rule_nova(secgroup_id=self.secgroup.id)
-
     def boot_instance(self):
         # Create server with image and flavor from input scenario
+        security_groups = [self.security_group.name]
         create_kwargs = {
-            'key_name': self.keypair.id
+            'key_name': self.keypair.id,
+            'security_groups': security_groups
         }
-        instance = self.create_server(image=self.image_ref,
-                                      flavor=self.flavor_ref,
-                                      create_kwargs=create_kwargs)
-        self.set_resource('instance', instance)
-
-    def terminate_instance(self):
-        instance = self.get_resource('instance')
-        instance.delete()
-        self.remove_resource('instance')
+        self.instance = self.create_server(image=self.image_ref,
+                                           flavor=self.flavor_ref,
+                                           create_kwargs=create_kwargs)
 
     def verify_ssh(self):
         if self.run_ssh:
             # Obtain a floating IP
             floating_ip = self.compute_client.floating_ips.create()
+            self.addCleanup(self.delete_wrapper, floating_ip)
             # Attach a floating IP
-            instance = self.get_resource('instance')
-            instance.add_floating_ip(floating_ip)
+            self.instance.add_floating_ip(floating_ip)
             # Check ssh
             try:
-                linux_client = self.get_remote_client(
+                self.get_remote_client(
                     server_or_ip=floating_ip.ip,
                     username=self.image_utils.ssh_user(self.image_ref),
                     private_key=self.keypair.private_key)
-                linux_client.validate_authentication()
             except Exception:
                 LOG.exception('ssh to server failed')
                 self._log_console_output()
@@ -117,7 +99,7 @@
     @test.services('compute', 'network')
     def test_server_basicops(self):
         self.add_keypair()
-        self.create_security_group()
+        self.security_group = self._create_security_group_nova()
         self.boot_instance()
         self.verify_ssh()
-        self.terminate_instance()
+        self.instance.delete()
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index 562020a..7dd662d 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -35,8 +35,10 @@
     """
 
     def _boot_image(self, image_id):
+        security_groups = [self.security_group.name]
         create_kwargs = {
-            'key_name': self.keypair.name
+            'key_name': self.keypair.name,
+            'security_groups': security_groups
         }
         return self.create_server(image=image_id, create_kwargs=create_kwargs)
 
@@ -47,8 +49,9 @@
         try:
             return self.get_remote_client(server_or_ip)
         except Exception:
-            LOG.exception()
+            LOG.exception('Initializing SSH connection failed')
             self._log_console_output()
+            raise
 
     def _write_timestamp(self, server_or_ip):
         ssh_client = self._ssh_to_server(server_or_ip)
@@ -62,7 +65,7 @@
 
     def _create_floating_ip(self):
         floating_ip = self.compute_client.floating_ips.create()
-        self.addCleanup(floating_ip.delete)
+        self.addCleanup(self.delete_wrapper, floating_ip)
         return floating_ip
 
     def _set_floating_ip_to_server(self, server, floating_ip):
@@ -72,7 +75,7 @@
     def test_snapshot_pattern(self):
         # prepare for booting a instance
         self._add_keypair()
-        self._create_loginable_secgroup_rule_nova()
+        self.security_group = self._create_security_group_nova()
 
         # boot a instance and create a timestamp file in it
         server = self._boot_image(CONF.compute.image_ref)
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 5235871..be27024 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -62,8 +62,10 @@
                             volume_snapshot.id, status)
 
     def _boot_image(self, image_id):
+        security_groups = [self.security_group.name]
         create_kwargs = {
-            'key_name': self.keypair.name
+            'key_name': self.keypair.name,
+            'security_groups': security_groups
         }
         return self.create_server(image=image_id, create_kwargs=create_kwargs)
 
@@ -72,7 +74,7 @@
 
     def _create_floating_ip(self):
         floating_ip = self.compute_client.floating_ips.create()
-        self.addCleanup(floating_ip.delete)
+        self.addCleanup(self.delete_wrapper, floating_ip)
         return floating_ip
 
     def _add_floating_ip(self, server, floating_ip):
@@ -152,7 +154,7 @@
     def test_stamp_pattern(self):
         # prepare for booting a instance
         self._add_keypair()
-        self._create_loginable_secgroup_rule_nova()
+        self.security_group = self._create_security_group_nova()
 
         # boot an instance and create a timestamp file in it
         volume = self._create_volume()
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index faca31f..bf5d1f6 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -10,6 +10,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from cinderclient import exceptions as cinder_exc
+
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest.openstack.common import log
@@ -55,9 +57,11 @@
         bd_map = {
             'vda': vol_id + ':::0'
         }
+        security_groups = [self.security_group.name]
         create_kwargs = {
             'block_device_mapping': bd_map,
-            'key_name': keypair.name
+            'key_name': keypair.name,
+            'security_groups': security_groups
         }
         return self.create_server(image='', create_kwargs=create_kwargs)
 
@@ -67,7 +71,8 @@
         snap = volume_snapshots.create(volume_id=vol_id,
                                        force=True,
                                        display_name=snap_name)
-        self.set_resource(snap.id, snap)
+        self.addCleanup_with_wait(self.volume_client.volume_snapshots, snap.id,
+                                  exc_type=cinder_exc.NotFound)
         self.status_timeout(volume_snapshots,
                             snap.id,
                             'available')
@@ -98,8 +103,7 @@
     def _ssh_to_server(self, server, keypair):
         if CONF.compute.use_floatingip_for_ssh:
             floating_ip = self.compute_client.floating_ips.create()
-            fip_name = data_utils.rand_name('scenario-fip')
-            self.set_resource(fip_name, floating_ip)
+            self.addCleanup(self.delete_wrapper, floating_ip)
             server.add_floating_ip(floating_ip)
             ip = floating_ip.ip
         else:
@@ -135,7 +139,7 @@
     @test.services('compute', 'volume', 'image')
     def test_volume_boot_pattern(self):
         keypair = self.create_keypair()
-        self._create_loginable_secgroup_rule_nova()
+        self.security_group = self._create_security_group_nova()
 
         # create an instance from volume
         volume_origin = self._create_volume_from_image()
@@ -182,8 +186,10 @@
         bdms = [{'uuid': vol_id, 'source_type': 'volume',
                  'destination_type': 'volume', 'boot_index': 0,
                  'delete_on_termination': False}]
+        security_groups = [self.security_group.name]
         create_kwargs = {
             'block_device_mapping_v2': bdms,
-            'key_name': keypair.name
+            'key_name': keypair.name,
+            'security_groups': security_groups
         }
         return self.create_server(image='', create_kwargs=create_kwargs)
diff --git a/tempest/services/__init__.py b/tempest/services/__init__.py
index e7bec60..e69de29 100644
--- a/tempest/services/__init__.py
+++ b/tempest/services/__init__.py
@@ -1,37 +0,0 @@
-# Copyright 2012 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.
-
-"""
-Base Service class, which acts as a descriptor for an OpenStack service
-in the test environment
-"""
-
-
-class Service(object):
-
-    def __init__(self, config):
-        """
-        Initializes the service.
-
-        :param config: `tempest.config.Config` object
-        """
-        self.config = config
-
-    def get_client(self):
-        """
-        Returns a client object that may be used to query
-        the service API.
-        """
-        raise NotImplementedError
diff --git a/tempest/services/baremetal/base.py b/tempest/services/baremetal/base.py
index 2af287f..f98ecff 100644
--- a/tempest/services/baremetal/base.py
+++ b/tempest/services/baremetal/base.py
@@ -122,7 +122,7 @@
 
         return resp, self.deserialize(body)
 
-    def _show_request(self, resource, uuid, permanent=False):
+    def _show_request(self, resource, uuid, permanent=False, **kwargs):
         """
         Gets a specific object of the specified type.
 
@@ -130,7 +130,10 @@
         :return: Serialized object as a dictionary.
 
         """
-        uri = self._get_uri(resource, uuid=uuid, permanent=permanent)
+        if 'uri' in kwargs:
+            uri = kwargs['uri']
+        else:
+            uri = self._get_uri(resource, uuid=uuid, permanent=permanent)
         resp, body = self.get(uri)
 
         return resp, self.deserialize(body)
@@ -199,3 +202,14 @@
 
         """
         return self._list_request(version, permanent=True)
+
+    def _put_request(self, resource, put_object):
+        """
+        Update specified object with JSON-patch.
+
+        """
+        uri = self._get_uri(resource)
+        put_body = json.dumps(put_object)
+
+        resp, body = self.put(uri, body=put_body)
+        return resp, body
diff --git a/tempest/services/baremetal/v1/base_v1.py b/tempest/services/baremetal/v1/base_v1.py
index 296a199..9c753c2 100644
--- a/tempest/services/baremetal/v1/base_v1.py
+++ b/tempest/services/baremetal/v1/base_v1.py
@@ -47,9 +47,9 @@
         return self._list_request('/nodes/%s/states' % uuid)
 
     @base.handle_errors
-    def list_ports_detail(self):
+    def list_ports_detail(self, **kwargs):
         """Details list all existing ports."""
-        return self._list_request('/ports/detail')
+        return self._list_request('/ports/detail', **kwargs)
 
     @base.handle_errors
     def list_drivers(self):
@@ -89,6 +89,15 @@
         """
         return self._show_request('ports', uuid)
 
+    def show_driver(self, driver_name):
+        """
+        Gets a specific driver.
+
+        :param driver_name: Name of driver.
+        :return: Serialized driver as a dictionary.
+        """
+        return self._show_request('drivers', driver_name)
+
     @base.handle_errors
     def create_node(self, chassis_id, **kwargs):
         """
@@ -226,3 +235,32 @@
         """
 
         return self._patch_request('ports', uuid, patch)
+
+    @base.handle_errors
+    def set_node_power_state(self, node_uuid, state):
+        """
+        Set power state of the specified node.
+
+        :param node_uuid: The unique identifier of the node.
+        :state: desired state to set (on/off/reboot).
+
+        """
+        target = {'target': state}
+        return self._put_request('nodes/%s/states/power' % node_uuid,
+                                 target)
+
+    @base.handle_errors
+    def validate_driver_interface(self, node_uuid):
+        """
+        Get all driver interfaces of a specific node.
+
+        :param uuid: Unique identifier of the node in UUID format.
+
+        """
+
+        uri = '{pref}/{res}/{uuid}/{postf}'.format(pref=self.uri_prefix,
+                                                   res='nodes',
+                                                   uuid=node_uuid,
+                                                   postf='validate')
+
+        return self._show_request('nodes', node_uuid, uri=uri)
diff --git a/tempest/services/botoclients.py b/tempest/services/botoclients.py
index 7616a99..7af904b 100644
--- a/tempest/services/botoclients.py
+++ b/tempest/services/botoclients.py
@@ -37,13 +37,16 @@
                  *args, **kwargs):
         # FIXME(andreaf) replace credentials and auth_url with auth_provider
 
+        insecure_ssl = CONF.identity.disable_ssl_certificate_validation
+
         self.connection_timeout = str(CONF.boto.http_socket_timeout)
         self.num_retries = str(CONF.boto.num_retries)
         self.build_timeout = CONF.boto.build_timeout
         self.ks_cred = {"username": username,
                         "password": password,
                         "auth_url": auth_url,
-                        "tenant_name": tenant_name}
+                        "tenant_name": tenant_name,
+                        "insecure": insecure_ssl}
 
     def _keystone_aws_get(self):
         # FIXME(andreaf) Move EC2 credentials to AuthProvider
@@ -90,7 +93,10 @@
         self._config_boto_timeout(self.connection_timeout, self.num_retries)
         if not all((self.connection_data["aws_access_key_id"],
                    self.connection_data["aws_secret_access_key"])):
-            if all(self.ks_cred.itervalues()):
+            if all([self.ks_cred.get('auth_url'),
+                    self.ks_cred.get('username'),
+                    self.ks_cred.get('tenant_name'),
+                    self.ks_cred.get('password')]):
                 ec2_cred = self._keystone_aws_get()
                 self.connection_data["aws_access_key_id"] = \
                     ec2_cred.access
@@ -109,6 +115,7 @@
 
     def __init__(self, *args, **kwargs):
         super(APIClientEC2, self).__init__(*args, **kwargs)
+        insecure_ssl = CONF.identity.disable_ssl_certificate_validation
         aws_access = CONF.boto.aws_access
         aws_secret = CONF.boto.aws_secret
         purl = urlparse.urlparse(CONF.boto.ec2_url)
@@ -129,6 +136,7 @@
         self.connection_data = {"aws_access_key_id": aws_access,
                                 "aws_secret_access_key": aws_secret,
                                 "is_secure": purl.scheme == "https",
+                                "validate_certs": not insecure_ssl,
                                 "region": region,
                                 "host": purl.hostname,
                                 "port": port,
@@ -187,6 +195,7 @@
 
     def __init__(self, *args, **kwargs):
         super(ObjectClientS3, self).__init__(*args, **kwargs)
+        insecure_ssl = CONF.identity.disable_ssl_certificate_validation
         aws_access = CONF.boto.aws_access
         aws_secret = CONF.boto.aws_secret
         purl = urlparse.urlparse(CONF.boto.s3_url)
@@ -201,6 +210,7 @@
         self.connection_data = {"aws_access_key_id": aws_access,
                                 "aws_secret_access_key": aws_secret,
                                 "is_secure": purl.scheme == "https",
+                                "validate_certs": not insecure_ssl,
                                 "host": purl.hostname,
                                 "port": port,
                                 "calling_format": boto.s3.connection.
diff --git a/tempest/services/compute/json/agents_client.py b/tempest/services/compute/json/agents_client.py
index 98d8896..4f6602f 100644
--- a/tempest/services/compute/json/agents_client.py
+++ b/tempest/services/compute/json/agents_client.py
@@ -46,7 +46,9 @@
         """Create an agent build."""
         post_body = json.dumps({'agent': kwargs})
         resp, body = self.post('os-agents', post_body)
-        return resp, self._parse_resp(body)
+        body = json.loads(body)
+        self.validate_response(schema.create_agent, resp, body)
+        return resp, body['agent']
 
     def delete_agent(self, agent_id):
         """Delete an existing agent build."""
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index e2e12d5..cd195f4 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -112,3 +112,31 @@
         body = json.loads(body)
         self.validate_response(schema.floating_ip_pools, resp, body)
         return resp, body['floating_ip_pools']
+
+    def create_floating_ips_bulk(self, ip_range, pool, interface):
+        """Allocate floating IPs in bulk."""
+        post_body = {
+            'ip_range': ip_range,
+            'pool': pool,
+            'interface': interface
+        }
+        post_body = json.dumps({'floating_ips_bulk_create': post_body})
+        resp, body = self.post('os-floating-ips-bulk', post_body)
+        body = json.loads(body)
+        self.validate_response(schema.create_floating_ips_bulk, resp, body)
+        return resp, body['floating_ips_bulk_create']
+
+    def list_floating_ips_bulk(self):
+        """Returns a list of all floating IPs bulk."""
+        resp, body = self.get('os-floating-ips-bulk')
+        body = json.loads(body)
+        self.validate_response(schema.list_floating_ips_bulk, resp, body)
+        return resp, body['floating_ip_info']
+
+    def delete_floating_ips_bulk(self, ip_range):
+        """Deletes the provided floating IPs bulk."""
+        post_body = json.dumps({'ip_range': ip_range})
+        resp, body = self.put('os-floating-ips-bulk/delete', post_body)
+        body = json.loads(body)
+        self.validate_response(schema.delete_floating_ips_bulk, resp, body)
+        return resp, body['floating_ips_bulk_delete']
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index 7e828d8..14b7100 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -15,6 +15,7 @@
 
 import json
 
+from tempest.api_schema.compute.v2 import quota_classes as classes_schema
 from tempest.api_schema.compute.v2 import quotas as schema
 from tempest.common import rest_client
 from tempest import config
@@ -118,3 +119,32 @@
         resp, body = self.delete('os-quota-sets/%s' % str(tenant_id))
         self.validate_response(schema.delete_quota, resp, body)
         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
+
+    def get_quota_class_set(self, quota_class_id):
+        """List the quota class set for a quota class."""
+
+        url = 'os-quota-class-sets/%s' % str(quota_class_id)
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(classes_schema.quota_set, resp, body)
+        return resp, body['quota_class_set']
+
+    def update_quota_class_set(self, quota_class_id, **kwargs):
+        """
+        Updates the quota class's limits for one or more resources.
+        """
+        post_body = json.dumps({'quota_class_set': kwargs})
+
+        resp, body = self.put('os-quota-class-sets/%s' % str(quota_class_id),
+                              post_body)
+
+        body = json.loads(body)
+        self.validate_response(classes_schema.quota_set_update, resp, body)
+        return resp, body['quota_class_set']
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 36bb02f..80bb711 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -57,6 +57,7 @@
         max_count: Count of maximum number of instances to launch.
         disk_config: Determines if user or admin controls disk configuration.
         return_reservation_id: Enable/Disable the return of reservation id
+        block_device_mapping: Block device mapping for the server.
         """
         post_body = {
             'name': name,
@@ -69,7 +70,7 @@
                        'availability_zone', 'accessIPv4', 'accessIPv6',
                        'min_count', 'max_count', ('metadata', 'meta'),
                        ('OS-DCF:diskConfig', 'disk_config'),
-                       'return_reservation_id']:
+                       'return_reservation_id', 'block_device_mapping']:
             if isinstance(option, tuple):
                 post_param = option[0]
                 key = option[1]
@@ -133,6 +134,7 @@
         """Returns the details of an existing server."""
         resp, body = self.get("servers/%s" % str(server_id))
         body = json.loads(body)
+        self.validate_response(schema.get_server, resp, body)
         return resp, body['server']
 
     def delete_server(self, server_id):
@@ -162,6 +164,7 @@
 
         resp, body = self.get(url)
         body = json.loads(body)
+        self.validate_response(schema.list_servers_detail, resp, body)
         return resp, body
 
     def wait_for_server_status(self, server_id, status, extra_timeout=0,
@@ -431,8 +434,9 @@
         return self.action(server_id, 'shelveOffload', None, **kwargs)
 
     def get_console_output(self, server_id, length):
+        kwargs = {'length': length} if length else {}
         return self.action(server_id, 'os-getConsoleOutput', 'output',
-                           common_schema.get_console_output, length=length)
+                           common_schema.get_console_output, **kwargs)
 
     def list_virtual_interfaces(self, server_id):
         """
@@ -462,6 +466,7 @@
         resp, body = self.get("servers/%s/os-instance-actions" %
                               str(server_id))
         body = json.loads(body)
+        self.validate_response(schema.list_instance_actions, resp, body)
         return resp, body['instanceActions']
 
     def get_instance_action(self, server_id, request_id):
@@ -469,6 +474,7 @@
         resp, body = self.get("servers/%s/os-instance-actions/%s" %
                               (str(server_id), str(request_id)))
         body = json.loads(body)
+        self.validate_response(schema.get_instance_action, resp, body)
         return resp, body['instanceAction']
 
     def force_delete_server(self, server_id, **kwargs):
@@ -508,20 +514,25 @@
         resp, body = self.post('os-server-groups', post_body)
 
         body = json.loads(body)
+        self.validate_response(schema.create_get_server_group, resp, body)
         return resp, body['server_group']
 
     def delete_server_group(self, server_group_id):
         """Delete the given server-group."""
-        return self.delete("os-server-groups/%s" % str(server_group_id))
+        resp, body = self.delete("os-server-groups/%s" % str(server_group_id))
+        self.validate_response(schema.delete_server_group, resp, body)
+        return resp, body
 
     def list_server_groups(self):
         """List the server-groups."""
         resp, body = self.get("os-server-groups")
         body = json.loads(body)
+        self.validate_response(schema.list_server_groups, resp, body)
         return resp, body['server_groups']
 
     def get_server_group(self, server_group_id):
         """Get the details of given server_group."""
         resp, body = self.get("os-server-groups/%s" % str(server_group_id))
         body = json.loads(body)
+        self.validate_response(schema.create_get_server_group, resp, body)
         return resp, body['server_group']
diff --git a/tempest/services/compute/v3/json/agents_client.py b/tempest/services/compute/v3/json/agents_client.py
index 48be54c..31314b7 100644
--- a/tempest/services/compute/v3/json/agents_client.py
+++ b/tempest/services/compute/v3/json/agents_client.py
@@ -43,7 +43,9 @@
         """Create an agent build."""
         post_body = json.dumps({'agent': kwargs})
         resp, body = self.post('os-agents', post_body)
-        return resp, self._parse_resp(body)
+        body = json.loads(body)
+        self.validate_response(schema.create_agent, resp, body)
+        return resp, body['agent']
 
     def delete_agent(self, agent_id):
         """Delete an existing agent build."""
diff --git a/tempest/services/compute/v3/json/servers_client.py b/tempest/services/compute/v3/json/servers_client.py
index f15f370..a5b31d3 100644
--- a/tempest/services/compute/v3/json/servers_client.py
+++ b/tempest/services/compute/v3/json/servers_client.py
@@ -55,6 +55,7 @@
         max_count: Count of maximum number of instances to launch.
         disk_config: Determines if user or admin controls disk configuration.
         return_reservation_id: Enable/Disable the return of reservation id
+        block_device_mapping: Block device mapping for the server.
         """
         post_body = {
             'name': name,
@@ -75,7 +76,9 @@
                        ('metadata', 'meta'),
                        ('os-disk-config:disk_config', 'disk_config'),
                        ('os-multiple-create:return_reservation_id',
-                        'return_reservation_id')]:
+                        'return_reservation_id'),
+                       ('os-block-device-mapping:block_device_mapping',
+                        'block_device_mapping')]:
             if isinstance(option, tuple):
                 post_param = option[0]
                 key = option[1]
@@ -133,6 +136,7 @@
         """Returns the details of an existing server."""
         resp, body = self.get("servers/%s" % str(server_id))
         body = json.loads(body)
+        self.validate_response(schema.get_server, resp, body)
         return resp, body['server']
 
     def delete_server(self, server_id):
@@ -162,6 +166,7 @@
 
         resp, body = self.get(url)
         body = json.loads(body)
+        self.validate_response(schema.list_servers_detail, resp, body)
         return resp, body
 
     def wait_for_server_status(self, server_id, status, extra_timeout=0,
@@ -458,6 +463,7 @@
         resp, body = self.get("servers/%s/os-server-actions" %
                               str(server_id))
         body = json.loads(body)
+        self.validate_response(schema.list_server_actions, resp, body)
         return resp, body['server_actions']
 
     def get_server_action(self, server_id, request_id):
@@ -465,6 +471,7 @@
         resp, body = self.get("servers/%s/os-server-actions/%s" %
                               (str(server_id), str(request_id)))
         body = json.loads(body)
+        self.validate_response(schema.get_server_action, resp, body)
         return resp, body['server_action']
 
     def force_delete_server(self, server_id, **kwargs):
diff --git a/tempest/services/compute/xml/quotas_client.py b/tempest/services/compute/xml/quotas_client.py
index 5502fcc..7f87248 100644
--- a/tempest/services/compute/xml/quotas_client.py
+++ b/tempest/services/compute/xml/quotas_client.py
@@ -22,6 +22,19 @@
 CONF = config.CONF
 
 
+def format_quota(q):
+    quota = {}
+    for k, v in q.items():
+        try:
+            v = int(v)
+        except ValueError:
+            pass
+
+        quota[k] = v
+
+    return quota
+
+
 class QuotasClientXML(rest_client.RestClient):
     TYPE = "xml"
 
@@ -29,18 +42,6 @@
         super(QuotasClientXML, self).__init__(auth_provider)
         self.service = CONF.compute.catalog_type
 
-    def _format_quota(self, q):
-        quota = {}
-        for k, v in q.items():
-            try:
-                v = int(v)
-            except ValueError:
-                pass
-
-            quota[k] = v
-
-        return quota
-
     def get_quota_set(self, tenant_id, user_id=None):
         """List the quota set for a tenant."""
 
@@ -49,7 +50,7 @@
             url += '?user_id=%s' % str(user_id)
         resp, body = self.get(url)
         body = xml_utils.xml_to_json(etree.fromstring(body))
-        body = self._format_quota(body)
+        body = format_quota(body)
         return resp, body
 
     def get_default_quota_set(self, tenant_id):
@@ -58,7 +59,7 @@
         url = 'os-quota-sets/%s/defaults' % str(tenant_id)
         resp, body = self.get(url)
         body = xml_utils.xml_to_json(etree.fromstring(body))
-        body = self._format_quota(body)
+        body = format_quota(body)
         return resp, body
 
     def update_quota_set(self, tenant_id, user_id=None,
@@ -124,9 +125,41 @@
                                   str(xml_utils.Document(post_body)))
 
         body = xml_utils.xml_to_json(etree.fromstring(body))
-        body = self._format_quota(body)
+        body = format_quota(body)
         return resp, body
 
     def delete_quota_set(self, tenant_id):
         """Delete the tenant's quota set."""
         return self.delete('os-quota-sets/%s' % str(tenant_id))
+
+
+class QuotaClassesClientXML(rest_client.RestClient):
+    TYPE = "xml"
+
+    def __init__(self, auth_provider):
+        super(QuotaClassesClientXML, self).__init__(auth_provider)
+        self.service = CONF.compute.catalog_type
+
+    def get_quota_class_set(self, quota_class_id):
+        """List the quota class set for a quota class."""
+
+        url = 'os-quota-class-sets/%s' % str(quota_class_id)
+        resp, body = self.get(url)
+        body = xml_utils.xml_to_json(etree.fromstring(body))
+        body = format_quota(body)
+        return resp, body
+
+    def update_quota_class_set(self, quota_class_id, **kwargs):
+        """
+        Updates the quota class's limits for one or more resources.
+        """
+        post_body = xml_utils.Element("quota_class_set",
+                                      xmlns=xml_utils.XMLNS_11,
+                                      **kwargs)
+
+        resp, body = self.put('os-quota-class-sets/%s' % str(quota_class_id),
+                              str(xml_utils.Document(post_body)))
+
+        body = xml_utils.xml_to_json(etree.fromstring(body))
+        body = format_quota(body)
+        return resp, body
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index c1105f9..156d889 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -318,6 +318,7 @@
         min_count: Count of minimum number of instances to launch.
         max_count: Count of maximum number of instances to launch.
         disk_config: Determines if user or admin controls disk configuration.
+        block_device_mapping: Block device mapping for the server.
         """
         server = xml_utils.Element("server",
                                    xmlns=xml_utils.XMLNS_11,
@@ -327,7 +328,8 @@
 
         for attr in ["adminPass", "accessIPv4", "accessIPv6", "key_name",
                      "user_data", "availability_zone", "min_count",
-                     "max_count", "return_reservation_id"]:
+                     "max_count", "return_reservation_id",
+                     "block_device_mapping"]:
             if attr in kwargs:
                 server.add_attr(attr, kwargs[attr])
 
@@ -592,8 +594,9 @@
         return resp, body
 
     def get_console_output(self, server_id, length):
+        kwargs = {'length': length} if length else {}
         return self.action(server_id, 'os-getConsoleOutput', 'output',
-                           length=length)
+                           **kwargs)
 
     def list_virtual_interfaces(self, server_id):
         """
diff --git a/tempest/services/data_processing/v1_1/client.py b/tempest/services/data_processing/v1_1/client.py
index 4465968..1fe0cf1 100644
--- a/tempest/services/data_processing/v1_1/client.py
+++ b/tempest/services/data_processing/v1_1/client.py
@@ -25,29 +25,42 @@
         super(DataProcessingClient, self).__init__(auth_provider)
         self.service = CONF.data_processing.catalog_type
 
-    @classmethod
-    def _request_and_parse(cls, req_fun, uri, res_name, *args, **kwargs):
-        """Make a request using specified req_fun and parse response.
+    def _request_and_check_resp(self, request_func, uri, resp_status):
+        """Make a request using specified request_func and check response
+        status code.
+
+        It returns pair: resp and response body.
+        """
+        resp, body = request_func(uri)
+        self.expected_success(resp_status, resp.status)
+        return resp, body
+
+    def _request_check_and_parse_resp(self, request_func, uri, resp_status,
+                                      resource_name, *args, **kwargs):
+        """Make a request using specified request_func, check response status
+        code and parse response body.
 
         It returns pair: resp and parsed resource(s) body.
         """
-        resp, body = req_fun(uri, headers={
-            'Content-Type': 'application/json'
-        }, *args, **kwargs)
+        headers = {'Content-Type': 'application/json'}
+        resp, body = request_func(uri, headers=headers, *args, **kwargs)
+        self.expected_success(resp_status, resp.status)
         body = json.loads(body)
-        return resp, body[res_name]
+        return resp, body[resource_name]
 
     def list_node_group_templates(self):
         """List all node group templates for a user."""
 
         uri = 'node-group-templates'
-        return self._request_and_parse(self.get, uri, 'node_group_templates')
+        return self._request_check_and_parse_resp(self.get, uri,
+                                                  200, 'node_group_templates')
 
     def get_node_group_template(self, tmpl_id):
         """Returns the details of a single node group template."""
 
         uri = 'node-group-templates/%s' % tmpl_id
-        return self._request_and_parse(self.get, uri, 'node_group_template')
+        return self._request_check_and_parse_resp(self.get, uri,
+                                                  200, 'node_group_template')
 
     def create_node_group_template(self, name, plugin_name, hadoop_version,
                                    node_processes, flavor_id,
@@ -67,20 +80,22 @@
             'flavor_id': flavor_id,
             'node_configs': node_configs or dict(),
         })
-        return self._request_and_parse(self.post, uri, 'node_group_template',
-                                       body=json.dumps(body))
+        return self._request_check_and_parse_resp(self.post, uri, 202,
+                                                  'node_group_template',
+                                                  body=json.dumps(body))
 
     def delete_node_group_template(self, tmpl_id):
         """Deletes the specified node group template by id."""
 
         uri = 'node-group-templates/%s' % tmpl_id
-        return self.delete(uri)
+        return self._request_and_check_resp(self.delete, uri, 204)
 
     def list_plugins(self):
         """List all enabled plugins."""
 
         uri = 'plugins'
-        return self._request_and_parse(self.get, uri, 'plugins')
+        return self._request_check_and_parse_resp(self.get,
+                                                  uri, 200, 'plugins')
 
     def get_plugin(self, plugin_name, plugin_version=None):
         """Returns the details of a single plugin."""
@@ -88,19 +103,21 @@
         uri = 'plugins/%s' % plugin_name
         if plugin_version:
             uri += '/%s' % plugin_version
-        return self._request_and_parse(self.get, uri, 'plugin')
+        return self._request_check_and_parse_resp(self.get, uri, 200, 'plugin')
 
     def list_cluster_templates(self):
         """List all cluster templates for a user."""
 
         uri = 'cluster-templates'
-        return self._request_and_parse(self.get, uri, 'cluster_templates')
+        return self._request_check_and_parse_resp(self.get, uri,
+                                                  200, 'cluster_templates')
 
     def get_cluster_template(self, tmpl_id):
         """Returns the details of a single cluster template."""
 
         uri = 'cluster-templates/%s' % tmpl_id
-        return self._request_and_parse(self.get, uri, 'cluster_template')
+        return self._request_check_and_parse_resp(self.get,
+                                                  uri, 200, 'cluster_template')
 
     def create_cluster_template(self, name, plugin_name, hadoop_version,
                                 node_groups, cluster_configs=None,
@@ -119,26 +136,29 @@
             'node_groups': node_groups,
             'cluster_configs': cluster_configs or dict(),
         })
-        return self._request_and_parse(self.post, uri, 'cluster_template',
-                                       body=json.dumps(body))
+        return self._request_check_and_parse_resp(self.post, uri, 202,
+                                                  'cluster_template',
+                                                  body=json.dumps(body))
 
     def delete_cluster_template(self, tmpl_id):
         """Deletes the specified cluster template by id."""
 
         uri = 'cluster-templates/%s' % tmpl_id
-        return self.delete(uri)
+        return self._request_and_check_resp(self.delete, uri, 204)
 
     def list_data_sources(self):
         """List all data sources for a user."""
 
         uri = 'data-sources'
-        return self._request_and_parse(self.get, uri, 'data_sources')
+        return self._request_check_and_parse_resp(self.get,
+                                                  uri, 200, 'data_sources')
 
     def get_data_source(self, source_id):
         """Returns the details of a single data source."""
 
         uri = 'data-sources/%s' % source_id
-        return self._request_and_parse(self.get, uri, 'data_source')
+        return self._request_check_and_parse_resp(self.get,
+                                                  uri, 200, 'data_source')
 
     def create_data_source(self, name, data_source_type, url, **kwargs):
         """Creates data source with specified params.
@@ -153,42 +173,88 @@
             'type': data_source_type,
             'url': url
         })
-        return self._request_and_parse(self.post, uri, 'data_source',
-                                       body=json.dumps(body))
+        return self._request_check_and_parse_resp(self.post, uri,
+                                                  202, 'data_source',
+                                                  body=json.dumps(body))
 
     def delete_data_source(self, source_id):
         """Deletes the specified data source by id."""
 
         uri = 'data-sources/%s' % source_id
-        return self.delete(uri)
+        return self._request_and_check_resp(self.delete, uri, 204)
 
     def list_job_binary_internals(self):
         """List all job binary internals for a user."""
 
         uri = 'job-binary-internals'
-        return self._request_and_parse(self.get, uri, 'binaries')
+        return self._request_check_and_parse_resp(self.get,
+                                                  uri, 200, 'binaries')
 
     def get_job_binary_internal(self, job_binary_id):
         """Returns the details of a single job binary internal."""
 
         uri = 'job-binary-internals/%s' % job_binary_id
-        return self._request_and_parse(self.get, uri, 'job_binary_internal')
+        return self._request_check_and_parse_resp(self.get, uri,
+                                                  200, 'job_binary_internal')
 
     def create_job_binary_internal(self, name, data):
         """Creates job binary internal with specified params."""
 
         uri = 'job-binary-internals/%s' % name
-        return self._request_and_parse(self.put, uri, 'job_binary_internal',
-                                       data)
+        return self._request_check_and_parse_resp(self.put, uri, 202,
+                                                  'job_binary_internal', data)
 
     def delete_job_binary_internal(self, job_binary_id):
         """Deletes the specified job binary internal by id."""
 
         uri = 'job-binary-internals/%s' % job_binary_id
-        return self.delete(uri)
+        return self._request_and_check_resp(self.delete, uri, 204)
 
     def get_job_binary_internal_data(self, job_binary_id):
         """Returns data of a single job binary internal."""
 
         uri = 'job-binary-internals/%s/data' % job_binary_id
-        return self.get(uri)
+        return self._request_and_check_resp(self.get, uri, 200)
+
+    def list_job_binaries(self):
+        """List all job binaries for a user."""
+
+        uri = 'job-binaries'
+        return self._request_check_and_parse_resp(self.get,
+                                                  uri, 200, 'binaries')
+
+    def get_job_binary(self, job_binary_id):
+        """Returns the details of a single job binary."""
+
+        uri = 'job-binaries/%s' % job_binary_id
+        return self._request_check_and_parse_resp(self.get,
+                                                  uri, 200, 'job_binary')
+
+    def create_job_binary(self, name, url, extra=None, **kwargs):
+        """Creates job binary with specified params.
+
+        It supports passing additional params using kwargs and returns created
+        object.
+        """
+        uri = 'job-binaries'
+        body = kwargs.copy()
+        body.update({
+            'name': name,
+            'url': url,
+            'extra': extra or dict(),
+        })
+        return self._request_check_and_parse_resp(self.post, uri,
+                                                  202, 'job_binary',
+                                                  body=json.dumps(body))
+
+    def delete_job_binary(self, job_binary_id):
+        """Deletes the specified job binary by id."""
+
+        uri = 'job-binaries/%s' % job_binary_id
+        return self._request_and_check_resp(self.delete, uri, 204)
+
+    def get_job_binary_data(self, job_binary_id):
+        """Returns data of a single job binary."""
+
+        uri = 'job-binaries/%s/data' % job_binary_id
+        return self._request_and_check_resp(self.get, uri, 200)
diff --git a/tempest/services/identity/json/identity_client.py b/tempest/services/identity/json/identity_client.py
index b0cab8e..ac65f81 100644
--- a/tempest/services/identity/json/identity_client.py
+++ b/tempest/services/identity/json/identity_client.py
@@ -37,8 +37,12 @@
         """
         if hasattr(self, '_has_admin_extensions'):
             return self._has_admin_extensions
-        resp, body = self.list_roles()
-        self._has_admin_extensions = ('status' in resp and resp.status != 503)
+        # Try something that requires admin
+        try:
+            self.list_roles()
+            self._has_admin_extensions = True
+        except Exception:
+            self._has_admin_extensions = False
         return self._has_admin_extensions
 
     def create_role(self, name):
@@ -48,11 +52,13 @@
         }
         post_body = json.dumps({'role': post_body})
         resp, body = self.post('OS-KSADM/roles', post_body)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def get_role(self, role_id):
         """Get a role by its id."""
         resp, body = self.get('OS-KSADM/roles/%s' % role_id)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['role']
 
@@ -70,51 +76,63 @@
         }
         post_body = json.dumps({'tenant': post_body})
         resp, body = self.post('tenants', post_body)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def delete_role(self, role_id):
         """Delete a role."""
-        return self.delete('OS-KSADM/roles/%s' % str(role_id))
+        resp, body = self.delete('OS-KSADM/roles/%s' % str(role_id))
+        self.expected_success(204, resp.status)
+        return resp, body
 
     def list_user_roles(self, tenant_id, user_id):
         """Returns a list of roles assigned to a user for a tenant."""
         url = '/tenants/%s/users/%s/roles' % (tenant_id, user_id)
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def assign_user_role(self, tenant_id, user_id, role_id):
         """Add roles to a user on a tenant."""
         resp, body = self.put('/tenants/%s/users/%s/roles/OS-KSADM/%s' %
                               (tenant_id, user_id, role_id), "")
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def remove_user_role(self, tenant_id, user_id, role_id):
         """Removes a role assignment for a user on a tenant."""
-        return self.delete('/tenants/%s/users/%s/roles/OS-KSADM/%s' %
-                           (tenant_id, user_id, role_id))
+        resp, body = self.delete('/tenants/%s/users/%s/roles/OS-KSADM/%s' %
+                                 (tenant_id, user_id, role_id))
+        self.expected_success(204, resp.status)
+        return resp, body
 
     def delete_tenant(self, tenant_id):
         """Delete a tenant."""
-        return self.delete('tenants/%s' % str(tenant_id))
+        resp, body = self.delete('tenants/%s' % str(tenant_id))
+        self.expected_success(204, resp.status)
+        return resp, body
 
     def get_tenant(self, tenant_id):
         """Get tenant details."""
         resp, body = self.get('tenants/%s' % str(tenant_id))
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def list_roles(self):
         """Returns roles."""
         resp, body = self.get('OS-KSADM/roles')
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def list_tenants(self):
         """Returns tenants."""
         resp, body = self.get('tenants')
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['tenants']
 
     def get_tenant_by_name(self, tenant_name):
-        resp, tenants = self.list_tenants()
+        _, tenants = self.list_tenants()
         for tenant in tenants:
             if tenant['name'] == tenant_name:
                 return tenant
@@ -122,7 +140,7 @@
 
     def update_tenant(self, tenant_id, **kwargs):
         """Updates a tenant."""
-        resp, body = self.get_tenant(tenant_id)
+        _, body = self.get_tenant(tenant_id)
         name = kwargs.get('name', body['name'])
         desc = kwargs.get('description', body['description'])
         en = kwargs.get('enabled', body['enabled'])
@@ -134,6 +152,7 @@
         }
         post_body = json.dumps({'tenant': post_body})
         resp, body = self.post('tenants/%s' % tenant_id, post_body)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def create_user(self, name, password, tenant_id, email, **kwargs):
@@ -149,26 +168,32 @@
             post_body['enabled'] = kwargs.get('enabled')
         post_body = json.dumps({'user': post_body})
         resp, body = self.post('users', post_body)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def update_user(self, user_id, **kwargs):
         """Updates a user."""
         put_body = json.dumps({'user': kwargs})
         resp, body = self.put('users/%s' % user_id, put_body)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def get_user(self, user_id):
         """GET a user."""
         resp, body = self.get("users/%s" % user_id)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def delete_user(self, user_id):
         """Delete a user."""
-        return self.delete("users/%s" % user_id)
+        resp, body = self.delete("users/%s" % user_id)
+        self.expected_success(204, resp.status)
+        return resp, body
 
     def get_users(self):
         """Get the list of users."""
         resp, body = self.get("users")
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def enable_disable_user(self, user_id, enabled):
@@ -178,24 +203,29 @@
         }
         put_body = json.dumps({'user': put_body})
         resp, body = self.put('users/%s/enabled' % user_id, put_body)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def get_token(self, token_id):
         """Get token details."""
         resp, body = self.get("tokens/%s" % token_id)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def delete_token(self, token_id):
         """Delete a token."""
-        return self.delete("tokens/%s" % token_id)
+        resp, body = self.delete("tokens/%s" % token_id)
+        self.expected_success(204, resp.status)
+        return resp, body
 
     def list_users_for_tenant(self, tenant_id):
         """List users for a Tenant."""
         resp, body = self.get('/tenants/%s/users' % tenant_id)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def get_user_by_username(self, tenant_id, username):
-        resp, users = self.list_users_for_tenant(tenant_id)
+        _, users = self.list_users_for_tenant(tenant_id)
         for user in users:
             if user['name'] == username:
                 return user
@@ -210,23 +240,28 @@
         }
         post_body = json.dumps({'OS-KSADM:service': post_body})
         resp, body = self.post('/OS-KSADM/services', post_body)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def get_service(self, service_id):
         """Get Service."""
         url = '/OS-KSADM/services/%s' % service_id
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def list_services(self):
         """List Service - Returns Services."""
         resp, body = self.get('/OS-KSADM/services')
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def delete_service(self, service_id):
         """Delete Service."""
         url = '/OS-KSADM/services/%s' % service_id
-        return self.delete(url)
+        resp, body = self.delete(url)
+        self.expected_success(204, resp.status)
+        return resp, body
 
     def update_user_password(self, user_id, new_pass):
         """Update User Password."""
@@ -236,11 +271,13 @@
         }
         put_body = json.dumps({'user': put_body})
         resp, body = self.put('users/%s/OS-KSADM/password' % user_id, put_body)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def list_extensions(self):
         """List all the extensions."""
         resp, body = self.get('/extensions')
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['extensions']['values']
 
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index 6829333..0188c2a 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 import json
+import urllib
 
 from tempest.common import rest_client
 from tempest import config
@@ -49,12 +50,13 @@
         }
         post_body = json.dumps({'user': post_body})
         resp, body = self.post('users', post_body)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return resp, body['user']
 
     def update_user(self, user_id, name, **kwargs):
         """Updates a user."""
-        resp, body = self.get_user(user_id)
+        _, body = self.get_user(user_id)
         email = kwargs.get('email', body['email'])
         en = kwargs.get('enabled', body['enabled'])
         project_id = kwargs.get('project_id', body['project_id'])
@@ -71,30 +73,49 @@
         }
         post_body = json.dumps({'user': post_body})
         resp, body = self.patch('users/%s' % user_id, post_body)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['user']
 
+    def update_user_password(self, user_id, password, original_password):
+        """Updates a user password."""
+        update_user = {
+            'password': password,
+            'original_password': original_password
+        }
+        update_user = json.dumps({'user': update_user})
+        resp, _ = self.post('users/%s/password' % user_id, update_user)
+        self.expected_success(204, resp.status)
+        return resp
+
     def list_user_projects(self, user_id):
         """Lists the projects on which a user has roles assigned."""
         resp, body = self.get('users/%s/projects' % user_id)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['projects']
 
-    def get_users(self):
+    def get_users(self, params=None):
         """Get the list of users."""
-        resp, body = self.get("users")
+        url = 'users'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['users']
 
     def get_user(self, user_id):
         """GET a user."""
         resp, body = self.get("users/%s" % user_id)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['user']
 
     def delete_user(self, user_id):
         """Deletes a User."""
         resp, body = self.delete("users/%s" % user_id)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def create_project(self, name, **kwargs):
@@ -110,16 +131,18 @@
         }
         post_body = json.dumps({'project': post_body})
         resp, body = self.post('projects', post_body)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return resp, body['project']
 
     def list_projects(self):
         resp, body = self.get("projects")
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['projects']
 
     def update_project(self, project_id, **kwargs):
-        resp, body = self.get_project(project_id)
+        _, body = self.get_project(project_id)
         name = kwargs.get('name', body['name'])
         desc = kwargs.get('description', body['description'])
         en = kwargs.get('enabled', body['enabled'])
@@ -133,18 +156,21 @@
         }
         post_body = json.dumps({'project': post_body})
         resp, body = self.patch('projects/%s' % project_id, post_body)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['project']
 
     def get_project(self, project_id):
         """GET a Project."""
         resp, body = self.get("projects/%s" % project_id)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['project']
 
     def delete_project(self, project_id):
         """Delete a project."""
         resp, body = self.delete('projects/%s' % str(project_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def create_role(self, name):
@@ -154,18 +180,21 @@
         }
         post_body = json.dumps({'role': post_body})
         resp, body = self.post('roles', post_body)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return resp, body['role']
 
     def get_role(self, role_id):
         """GET a Role."""
         resp, body = self.get('roles/%s' % str(role_id))
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['role']
 
     def list_roles(self):
         """Get the list of Roles."""
         resp, body = self.get("roles")
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['roles']
 
@@ -176,18 +205,21 @@
         }
         post_body = json.dumps({'role': post_body})
         resp, body = self.patch('roles/%s' % str(role_id), post_body)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['role']
 
     def delete_role(self, role_id):
         """Delete a role."""
         resp, body = self.delete('roles/%s' % str(role_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def assign_user_role(self, project_id, user_id, role_id):
         """Add roles to a user on a project."""
         resp, body = self.put('projects/%s/users/%s/roles/%s' %
                               (project_id, user_id, role_id), None)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def create_domain(self, name, **kwargs):
@@ -201,23 +233,26 @@
         }
         post_body = json.dumps({'domain': post_body})
         resp, body = self.post('domains', post_body)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return resp, body['domain']
 
     def delete_domain(self, domain_id):
         """Delete a domain."""
         resp, body = self.delete('domains/%s' % str(domain_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def list_domains(self):
         """List Domains."""
         resp, body = self.get('domains')
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['domains']
 
     def update_domain(self, domain_id, **kwargs):
         """Updates a domain."""
-        resp, body = self.get_domain(domain_id)
+        _, body = self.get_domain(domain_id)
         description = kwargs.get('description', body['description'])
         en = kwargs.get('enabled', body['enabled'])
         name = kwargs.get('name', body['name'])
@@ -228,12 +263,14 @@
         }
         post_body = json.dumps({'domain': post_body})
         resp, body = self.patch('domains/%s' % domain_id, post_body)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['domain']
 
     def get_domain(self, domain_id):
         """Get Domain details."""
         resp, body = self.get('domains/%s' % domain_id)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['domain']
 
@@ -241,6 +278,7 @@
         """Get token details."""
         headers = {'X-Subject-Token': resp_token}
         resp, body = self.get("auth/tokens", headers=headers)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['token']
 
@@ -248,6 +286,7 @@
         """Deletes token."""
         headers = {'X-Subject-Token': resp_token}
         resp, body = self.delete("auth/tokens", headers=headers)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def create_group(self, name, **kwargs):
@@ -263,18 +302,20 @@
         }
         post_body = json.dumps({'group': post_body})
         resp, body = self.post('groups', post_body)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return resp, body['group']
 
     def get_group(self, group_id):
         """Get group details."""
         resp, body = self.get('groups/%s' % group_id)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['group']
 
     def update_group(self, group_id, **kwargs):
         """Updates a group."""
-        resp, body = self.get_group(group_id)
+        _, body = self.get_group(group_id)
         name = kwargs.get('name', body['name'])
         description = kwargs.get('description', body['description'])
         post_body = {
@@ -283,53 +324,62 @@
         }
         post_body = json.dumps({'group': post_body})
         resp, body = self.patch('groups/%s' % group_id, post_body)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['group']
 
     def delete_group(self, group_id):
         """Delete a group."""
         resp, body = self.delete('groups/%s' % str(group_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def add_group_user(self, group_id, user_id):
         """Add user into group."""
         resp, body = self.put('groups/%s/users/%s' % (group_id, user_id),
                               None)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def list_group_users(self, group_id):
         """List users in group."""
         resp, body = self.get('groups/%s/users' % group_id)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['users']
 
     def list_user_groups(self, user_id):
         """Lists groups which a user belongs to."""
         resp, body = self.get('users/%s/groups' % user_id)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['groups']
 
     def delete_group_user(self, group_id, user_id):
         """Delete user in group."""
         resp, body = self.delete('groups/%s/users/%s' % (group_id, user_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def assign_user_role_on_project(self, project_id, user_id, role_id):
         """Add roles to a user on a project."""
         resp, body = self.put('projects/%s/users/%s/roles/%s' %
                               (project_id, user_id, role_id), None)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def assign_user_role_on_domain(self, domain_id, user_id, role_id):
         """Add roles to a user on a domain."""
         resp, body = self.put('domains/%s/users/%s/roles/%s' %
                               (domain_id, user_id, role_id), None)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def list_user_roles_on_project(self, project_id, user_id):
         """list roles of a user on a project."""
         resp, body = self.get('projects/%s/users/%s/roles' %
                               (project_id, user_id))
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['roles']
 
@@ -337,6 +387,7 @@
         """list roles of a user on a domain."""
         resp, body = self.get('domains/%s/users/%s/roles' %
                               (domain_id, user_id))
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['roles']
 
@@ -344,30 +395,35 @@
         """Delete role of a user on a project."""
         resp, body = self.delete('projects/%s/users/%s/roles/%s' %
                                  (project_id, user_id, role_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def revoke_role_from_user_on_domain(self, domain_id, user_id, role_id):
         """Delete role of a user on a domain."""
         resp, body = self.delete('domains/%s/users/%s/roles/%s' %
                                  (domain_id, user_id, role_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def assign_group_role_on_project(self, project_id, group_id, role_id):
         """Add roles to a user on a project."""
         resp, body = self.put('projects/%s/groups/%s/roles/%s' %
                               (project_id, group_id, role_id), None)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def assign_group_role_on_domain(self, domain_id, group_id, role_id):
         """Add roles to a user on a domain."""
         resp, body = self.put('domains/%s/groups/%s/roles/%s' %
                               (domain_id, group_id, role_id), None)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def list_group_roles_on_project(self, project_id, group_id):
         """list roles of a user on a project."""
         resp, body = self.get('projects/%s/groups/%s/roles' %
                               (project_id, group_id))
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['roles']
 
@@ -375,6 +431,7 @@
         """list roles of a user on a domain."""
         resp, body = self.get('domains/%s/groups/%s/roles' %
                               (domain_id, group_id))
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['roles']
 
@@ -382,12 +439,14 @@
         """Delete role of a user on a project."""
         resp, body = self.delete('projects/%s/groups/%s/roles/%s' %
                                  (project_id, group_id, role_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def revoke_role_from_group_on_domain(self, domain_id, group_id, role_id):
         """Delete role of a user on a domain."""
         resp, body = self.delete('domains/%s/groups/%s/roles/%s' %
                                  (domain_id, group_id, role_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def create_trust(self, trustor_user_id, trustee_user_id, project_id,
@@ -404,12 +463,14 @@
         }
         post_body = json.dumps({'trust': post_body})
         resp, body = self.post('OS-TRUST/trusts', post_body)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return resp, body['trust']
 
     def delete_trust(self, trust_id):
         """Deletes a trust."""
         resp, body = self.delete("OS-TRUST/trusts/%s" % trust_id)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def get_trusts(self, trustor_user_id=None, trustee_user_id=None):
@@ -422,18 +483,21 @@
                                   % trustee_user_id)
         else:
             resp, body = self.get("OS-TRUST/trusts")
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['trusts']
 
     def get_trust(self, trust_id):
         """GET trust."""
         resp, body = self.get("OS-TRUST/trusts/%s" % trust_id)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['trust']
 
     def get_trust_roles(self, trust_id):
         """GET roles delegated by a trust."""
         resp, body = self.get("OS-TRUST/trusts/%s/roles" % trust_id)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['roles']
 
@@ -441,6 +505,7 @@
         """GET role delegated by a trust."""
         resp, body = self.get("OS-TRUST/trusts/%s/roles/%s"
                               % (trust_id, role_id))
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['role']
 
@@ -448,6 +513,7 @@
         """HEAD Check if role is delegated by a trust."""
         resp, body = self.head("OS-TRUST/trusts/%s/roles/%s"
                                % (trust_id, role_id))
+        self.expected_success(200, resp.status)
         return resp, body
 
 
diff --git a/tempest/services/identity/v3/json/region_client.py b/tempest/services/identity/v3/json/region_client.py
index f95d00f..c078765 100644
--- a/tempest/services/identity/v3/json/region_client.py
+++ b/tempest/services/identity/v3/json/region_client.py
@@ -1,4 +1,4 @@
-# Copyright 2014 OpenStack Foundation
+# Copyright 2014 Hewlett-Packard Development Company, L.P
 # All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
diff --git a/tempest/services/identity/v3/json/service_client.py b/tempest/services/identity/v3/json/service_client.py
index b66fb4a..82e8aad 100644
--- a/tempest/services/identity/v3/json/service_client.py
+++ b/tempest/services/identity/v3/json/service_client.py
@@ -42,6 +42,7 @@
         }
         patch_body = json.dumps({'service': patch_body})
         resp, body = self.patch('services/%s' % service_id, patch_body)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['service']
 
@@ -49,6 +50,7 @@
         """Get Service."""
         url = 'services/%s' % service_id
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['service']
 
@@ -62,10 +64,12 @@
         }
         body = json.dumps({'service': body_dict})
         resp, body = self.post("services", body)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return resp, body["service"]
 
     def delete_service(self, serv_id):
         url = "services/" + serv_id
         resp, body = self.delete(url)
+        self.expected_success(204, resp.status)
         return resp, body
diff --git a/tempest/services/identity/v3/xml/identity_client.py b/tempest/services/identity/v3/xml/identity_client.py
index 35295d7..f3e084e 100644
--- a/tempest/services/identity/v3/xml/identity_client.py
+++ b/tempest/services/identity/v3/xml/identity_client.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 import json
+import urllib
 
 from lxml import etree
 
@@ -76,6 +77,14 @@
                 array.append(common.xml_to_json(child))
         return array
 
+    def _parse_users(self, node):
+        array = []
+        for child in node.getchildren():
+            tag_list = child.tag.split('}', 1)
+            if tag_list[1] == "user":
+                array.append(common.xml_to_json(child))
+        return array
+
     def _parse_array(self, node):
         array = []
         for child in node.getchildren():
@@ -104,12 +113,13 @@
                                    project_id=project_id,
                                    domain_id=domain_id)
         resp, body = self.post('users', str(common.Document(post_body)))
+        self.expected_success(201, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def update_user(self, user_id, name, **kwargs):
         """Updates a user."""
-        resp, body = self.get_user(user_id)
+        _, body = self.get_user(user_id)
         email = kwargs.get('email', body['email'])
         en = kwargs.get('enabled', body['enabled'])
         project_id = kwargs.get('project_id', body['project_id'])
@@ -125,30 +135,49 @@
                                      enabled=str(en).lower())
         resp, body = self.patch('users/%s' % user_id,
                                 str(common.Document(update_user)))
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
+    def update_user_password(self, user_id, password, original_password):
+        """Updates a user password."""
+        update_user = common.Element("user",
+                                     xmlns=XMLNS,
+                                     password=password,
+                                     original_password=original_password)
+        resp, _ = self.post('users/%s/password' % user_id,
+                            str(common.Document(update_user)))
+        self.expected_success(204, resp.status)
+        return resp
+
     def list_user_projects(self, user_id):
         """Lists the projects on which a user has roles assigned."""
         resp, body = self.get('users/%s/projects' % user_id)
+        self.expected_success(200, resp.status)
         body = self._parse_projects(etree.fromstring(body))
         return resp, body
 
-    def get_users(self):
+    def get_users(self, params=None):
         """Get the list of users."""
-        resp, body = self.get("users")
-        body = self._parse_array(etree.fromstring(body))
+        url = 'users'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+        resp, body = self.get(url)
+        self.expected_success(200, resp.status)
+        body = self._parse_users(etree.fromstring(body))
         return resp, body
 
     def get_user(self, user_id):
         """GET a user."""
         resp, body = self.get("users/%s" % user_id)
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def delete_user(self, user_id):
         """Deletes a User."""
         resp, body = self.delete("users/%s" % user_id)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def create_project(self, name, **kwargs):
@@ -164,12 +193,14 @@
                                    name=name)
         resp, body = self.post('projects',
                                str(common.Document(post_body)))
+        self.expected_success(201, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def list_projects(self):
         """Get the list of projects."""
         resp, body = self.get("projects")
+        self.expected_success(200, resp.status)
         body = self._parse_projects(etree.fromstring(body))
         return resp, body
 
@@ -188,18 +219,21 @@
                                    domain_id=domain_id)
         resp, body = self.patch('projects/%s' % project_id,
                                 str(common.Document(post_body)))
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def get_project(self, project_id):
         """GET a Project."""
         resp, body = self.get("projects/%s" % project_id)
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def delete_project(self, project_id):
         """Delete a project."""
         resp, body = self.delete('projects/%s' % str(project_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def create_role(self, name):
@@ -208,18 +242,21 @@
                                    xmlns=XMLNS,
                                    name=name)
         resp, body = self.post('roles', str(common.Document(post_body)))
+        self.expected_success(201, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def get_role(self, role_id):
         """GET a Role."""
         resp, body = self.get('roles/%s' % str(role_id))
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def list_roles(self):
         """Get the list of Roles."""
         resp, body = self.get("roles")
+        self.expected_success(200, resp.status)
         body = self._parse_roles(etree.fromstring(body))
         return resp, body
 
@@ -230,18 +267,21 @@
                                    name=name)
         resp, body = self.patch('roles/%s' % str(role_id),
                                 str(common.Document(post_body)))
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def delete_role(self, role_id):
         """Delete a role."""
         resp, body = self.delete('roles/%s' % str(role_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def assign_user_role(self, project_id, user_id, role_id):
         """Add roles to a user on a tenant."""
         resp, body = self.put('projects/%s/users/%s/roles/%s' %
                               (project_id, user_id, role_id), '')
+        self.expected_success(204, resp.status)
         return resp, body
 
     def create_domain(self, name, **kwargs):
@@ -254,23 +294,26 @@
                                    description=description,
                                    enabled=str(en).lower())
         resp, body = self.post('domains', str(common.Document(post_body)))
+        self.expected_success(201, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def list_domains(self):
         """Get the list of domains."""
         resp, body = self.get("domains")
+        self.expected_success(200, resp.status)
         body = self._parse_domains(etree.fromstring(body))
         return resp, body
 
     def delete_domain(self, domain_id):
         """Delete a domain."""
         resp, body = self.delete('domains/%s' % domain_id)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def update_domain(self, domain_id, **kwargs):
         """Updates a domain."""
-        resp, body = self.get_domain(domain_id)
+        _, body = self.get_domain(domain_id)
         description = kwargs.get('description', body['description'])
         en = kwargs.get('enabled', body['enabled'])
         name = kwargs.get('name', body['name'])
@@ -281,12 +324,14 @@
                                    enabled=str(en).lower())
         resp, body = self.patch('domains/%s' % domain_id,
                                 str(common.Document(post_body)))
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def get_domain(self, domain_id):
         """Get Domain details."""
         resp, body = self.get('domains/%s' % domain_id)
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
@@ -296,6 +341,7 @@
                    'Accept': 'application/xml',
                    'X-Subject-Token': resp_token}
         resp, body = self.get("auth/tokens", headers=headers)
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
@@ -303,6 +349,7 @@
         """Delete a Given Token."""
         headers = {'X-Subject-Token': resp_token}
         resp, body = self.delete("auth/tokens", headers=headers)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def create_group(self, name, **kwargs):
@@ -317,18 +364,20 @@
                                    domain_id=domain_id,
                                    project_id=project_id)
         resp, body = self.post('groups', str(common.Document(post_body)))
+        self.expected_success(201, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def get_group(self, group_id):
         """Get group details."""
         resp, body = self.get('groups/%s' % group_id)
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def update_group(self, group_id, **kwargs):
         """Updates a group."""
-        resp, body = self.get_group(group_id)
+        _, body = self.get_group(group_id)
         name = kwargs.get('name', body['name'])
         description = kwargs.get('description', body['description'])
         post_body = common.Element("group",
@@ -337,52 +386,61 @@
                                    description=description)
         resp, body = self.patch('groups/%s' % group_id,
                                 str(common.Document(post_body)))
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def delete_group(self, group_id):
         """Delete a group."""
         resp, body = self.delete('groups/%s' % group_id)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def add_group_user(self, group_id, user_id):
         """Add user into group."""
         resp, body = self.put('groups/%s/users/%s' % (group_id, user_id), '')
+        self.expected_success(204, resp.status)
         return resp, body
 
     def list_group_users(self, group_id):
         """List users in group."""
         resp, body = self.get('groups/%s/users' % group_id)
+        self.expected_success(200, resp.status)
         body = self._parse_group_users(etree.fromstring(body))
         return resp, body
 
     def list_user_groups(self, user_id):
         """Lists the groups which a user belongs to."""
         resp, body = self.get('users/%s/groups' % user_id)
+        self.expected_success(200, resp.status)
         body = self._parse_groups(etree.fromstring(body))
         return resp, body
 
     def delete_group_user(self, group_id, user_id):
         """Delete user in group."""
         resp, body = self.delete('groups/%s/users/%s' % (group_id, user_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def assign_user_role_on_project(self, project_id, user_id, role_id):
         """Add roles to a user on a project."""
         resp, body = self.put('projects/%s/users/%s/roles/%s' %
                               (project_id, user_id, role_id), '')
+        self.expected_success(204, resp.status)
         return resp, body
 
     def assign_user_role_on_domain(self, domain_id, user_id, role_id):
         """Add roles to a user on a domain."""
         resp, body = self.put('domains/%s/users/%s/roles/%s' %
                               (domain_id, user_id, role_id), '')
+        self.expected_success(204, resp.status)
         return resp, body
 
     def list_user_roles_on_project(self, project_id, user_id):
         """list roles of a user on a project."""
         resp, body = self.get('projects/%s/users/%s/roles' %
                               (project_id, user_id))
+        self.expected_success(200, resp.status)
         body = self._parse_roles(etree.fromstring(body))
         return resp, body
 
@@ -390,6 +448,7 @@
         """list roles of a user on a domain."""
         resp, body = self.get('domains/%s/users/%s/roles' %
                               (domain_id, user_id))
+        self.expected_success(200, resp.status)
         body = self._parse_roles(etree.fromstring(body))
         return resp, body
 
@@ -397,30 +456,35 @@
         """Delete role of a user on a project."""
         resp, body = self.delete('projects/%s/users/%s/roles/%s' %
                                  (project_id, user_id, role_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def revoke_role_from_user_on_domain(self, domain_id, user_id, role_id):
         """Delete role of a user on a domain."""
         resp, body = self.delete('domains/%s/users/%s/roles/%s' %
                                  (domain_id, user_id, role_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def assign_group_role_on_project(self, project_id, group_id, role_id):
         """Add roles to a user on a project."""
         resp, body = self.put('projects/%s/groups/%s/roles/%s' %
                               (project_id, group_id, role_id), '')
+        self.expected_success(204, resp.status)
         return resp, body
 
     def assign_group_role_on_domain(self, domain_id, group_id, role_id):
         """Add roles to a user on a domain."""
         resp, body = self.put('domains/%s/groups/%s/roles/%s' %
                               (domain_id, group_id, role_id), '')
+        self.expected_success(204, resp.status)
         return resp, body
 
     def list_group_roles_on_project(self, project_id, group_id):
         """list roles of a user on a project."""
         resp, body = self.get('projects/%s/groups/%s/roles' %
                               (project_id, group_id))
+        self.expected_success(200, resp.status)
         body = self._parse_roles(etree.fromstring(body))
         return resp, body
 
@@ -428,6 +492,7 @@
         """list roles of a user on a domain."""
         resp, body = self.get('domains/%s/groups/%s/roles' %
                               (domain_id, group_id))
+        self.expected_success(200, resp.status)
         body = self._parse_roles(etree.fromstring(body))
         return resp, body
 
@@ -435,12 +500,14 @@
         """Delete role of a user on a project."""
         resp, body = self.delete('projects/%s/groups/%s/roles/%s' %
                                  (project_id, group_id, role_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def revoke_role_from_group_on_domain(self, domain_id, group_id, role_id):
         """Delete role of a user on a domain."""
         resp, body = self.delete('domains/%s/groups/%s/roles/%s' %
                                  (domain_id, group_id, role_id))
+        self.expected_success(204, resp.status)
         return resp, body
 
 
diff --git a/tempest/services/identity/v3/xml/region_client.py b/tempest/services/identity/v3/xml/region_client.py
index 9f9161d..f854138 100644
--- a/tempest/services/identity/v3/xml/region_client.py
+++ b/tempest/services/identity/v3/xml/region_client.py
@@ -1,4 +1,4 @@
-# Copyright 2014 OpenStack Foundation
+# Copyright 2014 Hewlett-Packard Development Company, L.P
 # All Rights Reserved.
 #
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
diff --git a/tempest/services/identity/v3/xml/service_client.py b/tempest/services/identity/v3/xml/service_client.py
index 37ed892..3beeb89 100644
--- a/tempest/services/identity/v3/xml/service_client.py
+++ b/tempest/services/identity/v3/xml/service_client.py
@@ -51,6 +51,7 @@
                                         type=type)
         resp, body = self.patch('services/%s' % service_id,
                                 str(common.Document(update_service)))
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
@@ -58,6 +59,7 @@
         """Get Service."""
         url = 'services/%s' % service_id
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
@@ -68,10 +70,12 @@
                                    description=description,
                                    type=serv_type)
         resp, body = self.post("services", str(common.Document(post_body)))
+        self.expected_success(201, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def delete_service(self, serv_id):
         url = "services/" + serv_id
         resp, body = self.delete(url)
+        self.expected_success(204, resp.status)
         return resp, body
diff --git a/tempest/services/identity/xml/identity_client.py b/tempest/services/identity/xml/identity_client.py
index 886ce7b..4ada46c 100644
--- a/tempest/services/identity/xml/identity_client.py
+++ b/tempest/services/identity/xml/identity_client.py
@@ -29,11 +29,13 @@
         create_role = xml.Element("role", xmlns=XMLNS, name=name)
         resp, body = self.post('OS-KSADM/roles',
                                str(xml.Document(create_role)))
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def get_role(self, role_id):
         """Get a role by its id."""
         resp, body = self.get('OS-KSADM/roles/%s' % role_id)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def create_tenant(self, name, **kwargs):
@@ -50,16 +52,18 @@
                                     description=kwargs.get('description', ''),
                                     enabled=str(en).lower())
         resp, body = self.post('tenants', str(xml.Document(create_tenant)))
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def list_tenants(self):
         """Returns tenants."""
         resp, body = self.get('tenants')
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def update_tenant(self, tenant_id, **kwargs):
         """Updates a tenant."""
-        resp, body = self.get_tenant(tenant_id)
+        _, body = self.get_tenant(tenant_id)
         name = kwargs.get('name', body['name'])
         desc = kwargs.get('description', body['description'])
         en = kwargs.get('enabled', body['enabled'])
@@ -72,6 +76,7 @@
 
         resp, body = self.post('tenants/%s' % tenant_id,
                                str(xml.Document(update_tenant)))
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def create_user(self, name, password, tenant_id, email, **kwargs):
@@ -87,6 +92,7 @@
             create_user.add_attr('enabled', str(kwargs['enabled']).lower())
 
         resp, body = self.post('users', str(xml.Document(create_user)))
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def update_user(self, user_id, **kwargs):
@@ -97,6 +103,7 @@
 
         resp, body = self.put('users/%s' % user_id,
                               str(xml.Document(update_user)))
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def enable_disable_user(self, user_id, enabled):
@@ -104,6 +111,7 @@
         enable_user = xml.Element("user", enabled=str(enabled).lower())
         resp, body = self.put('users/%s/enabled' % user_id,
                               str(xml.Document(enable_user)))
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def create_service(self, name, service_type, **kwargs):
@@ -116,6 +124,7 @@
                                      description=kwargs.get('description'))
         resp, body = self.post('OS-KSADM/services',
                                str(xml.Document(create_service)))
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def update_user_password(self, user_id, new_pass):
@@ -125,11 +134,13 @@
                                password=new_pass)
         resp, body = self.put('users/%s/OS-KSADM/password' % user_id,
                               str(xml.Document(put_body)))
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def list_extensions(self):
         """List all the extensions."""
         resp, body = self.get('/extensions')
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
 
diff --git a/tempest/services/image/v1/json/image_client.py b/tempest/services/image/v1/json/image_client.py
index e22cd9c..4a7c163 100644
--- a/tempest/services/image/v1/json/image_client.py
+++ b/tempest/services/image/v1/json/image_client.py
@@ -22,6 +22,7 @@
 
 from tempest.common import glance_http
 from tempest.common import rest_client
+from tempest.common.utils import misc as misc_utils
 from tempest import config
 from tempest import exceptions
 from tempest.openstack.common import log as logging
@@ -153,6 +154,7 @@
             return self._create_with_data(headers, kwargs.get('data'))
 
         resp, body = self.post('v1/images', None, headers)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return resp, body['image']
 
@@ -176,12 +178,15 @@
 
         url = 'v1/images/%s' % image_id
         resp, body = self.put(url, data, headers)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['image']
 
     def delete_image(self, image_id):
         url = 'v1/images/%s' % image_id
-        return self.delete(url)
+        resp, body = self.delete(url)
+        self.expected_success(200, resp.status)
+        return resp, body
 
     def image_list(self, **kwargs):
         url = 'v1/images'
@@ -190,6 +195,7 @@
             url += '?%s' % urllib.urlencode(kwargs)
 
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['images']
 
@@ -210,18 +216,21 @@
             url += '?%s' % urllib.urlencode(kwargs)
 
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['images']
 
     def get_image_meta(self, image_id):
         url = 'v1/images/%s' % image_id
         resp, __ = self.head(url)
+        self.expected_success(200, resp.status)
         body = self._image_meta_from_headers(resp)
         return resp, body
 
     def get_image(self, image_id):
         url = 'v1/images/%s' % image_id
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         return resp, body
 
     def is_resource_deleted(self, id):
@@ -234,12 +243,14 @@
     def get_image_membership(self, image_id):
         url = 'v1/images/%s/members' % image_id
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body
 
     def get_shared_images(self, member_id):
         url = 'v1/shared-images/%s' % member_id
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body
 
@@ -249,20 +260,15 @@
         if can_share:
             body = json.dumps({'member': {'can_share': True}})
         resp, __ = self.put(url, body)
+        self.expected_success(204, resp.status)
         return resp
 
     def delete_member(self, member_id, image_id):
         url = 'v1/images/%s/members/%s' % (image_id, member_id)
         resp, __ = self.delete(url)
+        self.expected_success(204, resp.status)
         return resp
 
-    def replace_membership_list(self, image_id, member_list):
-        url = 'v1/images/%s/members' % image_id
-        body = json.dumps({'membership': member_list})
-        resp, data = self.put(url, body)
-        data = json.loads(data)
-        return resp, data
-
     # NOTE(afazekas): just for the wait function
     def _get_image_status(self, image_id):
         resp, meta = self.get_image_meta(image_id)
@@ -292,6 +298,9 @@
                            'while waiting for %s, '
                            'but we got %s.' %
                            (self.build_timeout, status, value))
+                caller = misc_utils.find_test_caller()
+                if caller:
+                    message = '(%s) %s' % (caller, message)
                 raise exceptions.TimeoutException(message)
             time.sleep(self.build_interval)
             old_value = value
diff --git a/tempest/services/image/v2/json/image_client.py b/tempest/services/image/v2/json/image_client.py
index 201869e..c420df9 100644
--- a/tempest/services/image/v2/json/image_client.py
+++ b/tempest/services/image/v2/json/image_client.py
@@ -61,6 +61,7 @@
         headers = {"Content-Type": "application/openstack-images-v2.0"
                                    "-json-patch"}
         resp, body = self.patch('v2/images/%s' % image_id, data, headers)
+        self.expected_success(200, resp.status)
         return resp, self._parse_resp(body)
 
     def create_image(self, name, container_format, disk_format, **kwargs):
@@ -81,12 +82,14 @@
         self._validate_schema(data)
 
         resp, body = self.post('v2/images', data)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return resp, body
 
     def delete_image(self, image_id):
         url = 'v2/images/%s' % image_id
-        self.delete(url)
+        resp, _ = self.delete(url)
+        self.expected_success(204, resp.status)
 
     def image_list(self, params=None):
         url = 'v2/images'
@@ -95,6 +98,7 @@
             url += '?%s' % urllib.urlencode(params)
 
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         self._validate_schema(body, type='images')
         return resp, body['images']
@@ -102,6 +106,7 @@
     def get_image(self, image_id):
         url = 'v2/images/%s' % image_id
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body
 
@@ -117,36 +122,40 @@
         headers = {'Content-Type': 'application/octet-stream'}
         resp, body = self.http.raw_request('PUT', url, headers=headers,
                                            body=data)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def get_image_file(self, image_id):
         url = 'v2/images/%s/file' % image_id
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         return resp, body
 
     def add_image_tag(self, image_id, tag):
         url = 'v2/images/%s/tags/%s' % (image_id, tag)
         resp, body = self.put(url, body=None)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def delete_image_tag(self, image_id, tag):
         url = 'v2/images/%s/tags/%s' % (image_id, tag)
         resp, _ = self.delete(url)
+        self.expected_success(204, resp.status)
         return resp
 
     def get_image_membership(self, image_id):
         url = 'v2/images/%s/members' % image_id
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
-        self.expected_success(200, resp)
         return resp, body
 
     def add_member(self, image_id, member_id):
         url = 'v2/images/%s/members' % image_id
         data = json.dumps({'member': member_id})
         resp, body = self.post(url, data)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
-        self.expected_success(200, resp)
         return resp, body
 
     def update_member_status(self, image_id, member_id, status):
@@ -154,24 +163,25 @@
         url = 'v2/images/%s/members/%s' % (image_id, member_id)
         data = json.dumps({'status': status})
         resp, body = self.put(url, data)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
-        self.expected_success(200, resp)
         return resp, body
 
     def get_member(self, image_id, member_id):
         url = 'v2/images/%s/members/%s' % (image_id, member_id)
         resp, body = self.get(url)
-        self.expected_success(200, resp)
+        self.expected_success(200, resp.status)
         return resp, json.loads(body)
 
     def remove_member(self, image_id, member_id):
         url = 'v2/images/%s/members/%s' % (image_id, member_id)
         resp, _ = self.delete(url)
-        self.expected_success(204, resp)
+        self.expected_success(204, resp.status)
         return resp
 
     def get_schema(self, schema):
         url = 'v2/schemas/%s' % schema
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body
diff --git a/tempest/services/network/network_client_base.py b/tempest/services/network/network_client_base.py
index 81792c4..4ee8302 100644
--- a/tempest/services/network/network_client_base.py
+++ b/tempest/services/network/network_client_base.py
@@ -28,6 +28,7 @@
     'vips': 'lb',
     'health_monitors': 'lb',
     'members': 'lb',
+    'ipsecpolicies': 'vpn',
     'vpnservices': 'vpn',
     'ikepolicies': 'vpn',
     'ipsecpolicies': 'vpn',
@@ -47,6 +48,7 @@
 resource_plural_map = {
     'security_groups': 'security_groups',
     'security_group_rules': 'security_group_rules',
+    'ipsecpolicy': 'ipsecpolicies',
     'ikepolicy': 'ikepolicies',
     'ipsecpolicy': 'ipsecpolicies',
     'quotas': 'quotas',
diff --git a/tempest/services/network/xml/network_client.py b/tempest/services/network/xml/network_client.py
index a7a6b2c..22cc948 100644
--- a/tempest/services/network/xml/network_client.py
+++ b/tempest/services/network/xml/network_client.py
@@ -38,7 +38,7 @@
         return _root_tag_fetcher_and_xml_to_json_parse(body)
 
     def serialize(self, body):
-        #TODO(enikanorov): implement better json to xml conversion
+        # TODO(enikanorov): implement better json to xml conversion
         # expecting the dict with single key
         root = body.keys()[0]
         post_body = common.Element(root)
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index f3f4eb6..b2f8205 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -13,7 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import httplib
 import urllib
+import urlparse
 
 from tempest.common import http
 from tempest.common import rest_client
@@ -143,6 +145,31 @@
         resp, body = self.put(url, data)
         return resp, body
 
+    def put_object_with_chunk(self, container, name, contents, chunk_size):
+        """
+        Put an object with Transfer-Encoding header
+        """
+        if self.base_url is None:
+            self._set_auth()
+
+        headers = {'Transfer-Encoding': 'chunked'}
+        if self.token:
+            headers['X-Auth-Token'] = self.token
+
+        conn = put_object_connection(self.base_url, container, name, contents,
+                                     chunk_size, headers)
+
+        resp = conn.getresponse()
+        body = resp.read()
+
+        resp_headers = {}
+        for header, value in resp.getheaders():
+            resp_headers[header.lower()] = value
+
+        self._error_checker('PUT', None, headers, contents, resp, body)
+
+        return resp.status, resp.reason, resp_headers
+
 
 class ObjectClientCustomizedHeader(rest_client.RestClient):
 
@@ -220,3 +247,89 @@
         url = "%s/%s" % (str(container), str(object_name))
         resp, body = self.delete(url, headers=headers)
         return resp, body
+
+    def create_object_continue(self, container, object_name,
+                               data, metadata=None):
+        """Create storage object."""
+        headers = {}
+        if metadata:
+            for key in metadata:
+                headers[str(key)] = metadata[key]
+
+        if not data:
+            headers['content-length'] = '0'
+
+        if self.base_url is None:
+            self._set_auth()
+        headers['X-Auth-Token'] = self.token
+
+        conn = put_object_connection(self.base_url, str(container),
+                                     str(object_name), data, None, headers)
+
+        response = conn.response_class(conn.sock,
+                                       strict=conn.strict,
+                                       method=conn._method)
+        version, status, reason = response._read_status()
+        resp = {'version': version,
+                'status': str(status),
+                'reason': reason}
+
+        return resp
+
+
+def put_object_connection(base_url, container, name, contents=None,
+                          chunk_size=65536, headers=None, query_string=None):
+    """
+    Helper function to make connection to put object with httplib
+    :param base_url: base_url of an object client
+    :param container: container name that the object is in
+    :param name: object name to put
+    :param contents: a string or a file like object to read object data
+                     from; if None, a zero-byte put will be done
+    :param chunk_size: chunk size of data to write; it defaults to 65536;
+                       used only if the the contents object has a 'read'
+                       method, eg. file-like objects, ignored otherwise
+    :param headers: additional headers to include in the request, if any
+    :param query_string: if set will be appended with '?' to generated path
+    """
+    parsed = urlparse.urlparse(base_url)
+    if parsed.scheme == 'https':
+        conn = httplib.HTTPSConnection(parsed.netloc)
+    else:
+        conn = httplib.HTTPConnection(parsed.netloc)
+    path = str(parsed.path) + "/"
+    path += "%s/%s" % (str(container), str(name))
+
+    if query_string:
+        path += '?' + query_string
+    if headers:
+        headers = dict(headers)
+    else:
+        headers = {}
+    if hasattr(contents, 'read'):
+        conn.putrequest('PUT', path)
+        for header, value in headers.iteritems():
+            conn.putheader(header, value)
+        if 'Content-Length' not in headers:
+            if 'Transfer-Encoding' not in headers:
+                conn.putheader('Transfer-Encoding', 'chunked')
+            conn.endheaders()
+            chunk = contents.read(chunk_size)
+            while chunk:
+                conn.send('%x\r\n%s\r\n' % (len(chunk), chunk))
+                chunk = contents.read(chunk_size)
+            conn.send('0\r\n\r\n')
+        else:
+            conn.endheaders()
+            left = headers['Content-Length']
+            while left > 0:
+                size = chunk_size
+                if size > left:
+                    size = left
+                chunk = contents.read(size)
+                conn.send(chunk)
+                left -= len(chunk)
+    else:
+        conn.request('PUT', path, contents, headers)
+
+    return conn
diff --git a/tempest/services/orchestration/json/orchestration_client.py b/tempest/services/orchestration/json/orchestration_client.py
index c459f28..46b0ec4 100644
--- a/tempest/services/orchestration/json/orchestration_client.py
+++ b/tempest/services/orchestration/json/orchestration_client.py
@@ -181,7 +181,11 @@
         fail_regexp = re.compile(failure_pattern)
 
         while True:
-            resp, body = self.get_stack(stack_identifier)
+            try:
+                resp, body = self.get_stack(stack_identifier)
+            except exceptions.NotFound:
+                if status == 'DELETE_COMPLETE':
+                    return
             stack_name = body['stack_name']
             stack_status = body['stack_status']
             if stack_status == status:
@@ -259,3 +263,140 @@
             'parameters': parameters,
         }
         return self._validate_template(post_body)
+
+    def create_software_config(self, name=None, config=None, group=None,
+                               inputs=None, outputs=None, options=None):
+        headers, body = self._prep_software_config_create(
+            name, config, group, inputs, outputs, options)
+
+        url = 'software_configs'
+        resp, body = self.post(url, headers=headers, body=body)
+        self.expected_success(200, resp)
+        body = json.loads(body)
+        return body
+
+    def get_software_config(self, conf_id):
+        """Returns a software configuration resource."""
+        url = 'software_configs/%s' % str(conf_id)
+        resp, body = self.get(url)
+        self.expected_success(200, resp)
+        body = json.loads(body)
+        return body
+
+    def delete_software_config(self, conf_id):
+        """Deletes a specific software configuration."""
+        url = 'software_configs/%s' % str(conf_id)
+        resp, _ = self.delete(url)
+        self.expected_success(204, resp)
+
+    def create_software_deploy(self, server_id=None, config_id=None,
+                               action=None, status=None,
+                               input_values=None, output_values=None,
+                               status_reason=None, signal_transport=None):
+        """Creates or updates a software deployment."""
+        headers, body = self._prep_software_deploy_update(
+            None, server_id, config_id, action, status, input_values,
+            output_values, status_reason, signal_transport)
+
+        url = 'software_deployments'
+        resp, body = self.post(url, headers=headers, body=body)
+        self.expected_success(200, resp)
+        body = json.loads(body)
+        return body
+
+    def update_software_deploy(self, deploy_id=None, server_id=None,
+                               config_id=None, action=None, status=None,
+                               input_values=None, output_values=None,
+                               status_reason=None, signal_transport=None):
+        """Creates or updates a software deployment."""
+        headers, body = self._prep_software_deploy_update(
+            deploy_id, server_id, config_id, action, status, input_values,
+            output_values, status_reason, signal_transport)
+
+        url = 'software_deployments/%s' % str(deploy_id)
+        resp, body = self.put(url, headers=headers, body=body)
+        self.expected_success(200, resp)
+        body = json.loads(body)
+        return body
+
+    def get_software_deploy_list(self):
+        """Returns a list of all deployments."""
+        url = 'software_deployments'
+        resp, body = self.get(url)
+        self.expected_success(200, resp)
+        body = json.loads(body)
+        return body
+
+    def get_software_deploy(self, deploy_id):
+        """Returns a specific software deployment."""
+        url = 'software_deployments/%s' % str(deploy_id)
+        resp, body = self.get(url)
+        self.expected_success(200, resp)
+        body = json.loads(body)
+        return body
+
+    def get_software_deploy_meta(self, server_id):
+        """Return a config metadata for a specific server."""
+        url = 'software_deployments/metadata/%s' % server_id
+        resp, body = self.get(url)
+        self.expected_success(200, resp)
+        body = json.loads(body)
+        return body
+
+    def delete_software_deploy(self, deploy_id):
+        """Deletes a specific software deployment."""
+        url = 'software_deployments/%s' % str(deploy_id)
+        resp, _ = self.delete(url)
+        self.expected_success(204, resp)
+
+    def _prep_software_config_create(self, name=None, conf=None, group=None,
+                                     inputs=None, outputs=None, options=None):
+        """Prepares a software configuration body."""
+        post_body = {}
+        if name is not None:
+            post_body["name"] = name
+        if conf is not None:
+            post_body["config"] = conf
+        if group is not None:
+            post_body["group"] = group
+        if inputs is not None:
+            post_body["inputs"] = inputs
+        if outputs is not None:
+            post_body["outputs"] = outputs
+        if options is not None:
+            post_body["options"] = options
+        body = json.dumps(post_body)
+
+        headers = self.get_headers()
+        return headers, body
+
+    def _prep_software_deploy_update(self, deploy_id=None, server_id=None,
+                                     config_id=None, action=None, status=None,
+                                     input_values=None, output_values=None,
+                                     status_reason=None,
+                                     signal_transport=None):
+        """Prepares a deployment create or update (if an id was given)."""
+        post_body = {}
+
+        if deploy_id is not None:
+            post_body["id"] = deploy_id
+        if server_id is not None:
+            post_body["server_id"] = server_id
+        if config_id is not None:
+            post_body["config_id"] = config_id
+        if action is not None:
+            post_body["action"] = action
+        if status is not None:
+            post_body["status"] = status
+        if input_values is not None:
+            post_body["input_values"] = input_values
+        if output_values is not None:
+            post_body["output_values"] = output_values
+        if status_reason is not None:
+            post_body["status_reason"] = status_reason
+        if signal_transport is not None:
+            post_body["signal_transport"] = signal_transport
+        body = json.dumps(post_body)
+
+        headers = self.get_headers()
+        return headers, body
diff --git a/tempest/services/queuing/json/queuing_client.py b/tempest/services/queuing/json/queuing_client.py
index e5978f5..031c9c6 100644
--- a/tempest/services/queuing/json/queuing_client.py
+++ b/tempest/services/queuing/json/queuing_client.py
@@ -14,11 +14,14 @@
 # limitations under the License.
 
 import json
+import urllib
 
 from tempest.api_schema.queuing.v1 import queues as queues_schema
 from tempest.common import rest_client
+from tempest.common.utils import data_utils
 from tempest import config
 
+
 CONF = config.CONF
 
 
@@ -30,11 +33,16 @@
         self.version = '1'
         self.uri_prefix = 'v{0}'.format(self.version)
 
+        client_id = data_utils.rand_uuid_hex()
+        self.headers = {'Client-ID': client_id}
+
     def list_queues(self):
         uri = '{0}/queues'.format(self.uri_prefix)
         resp, body = self.get(uri)
-        body = json.loads(body)
-        self.validate_response(queues_schema.list_queues, resp, body)
+
+        if resp['status'] != '204':
+            body = json.loads(body)
+            self.validate_response(queues_schema.list_queues, resp, body)
         return resp, body
 
     def create_queue(self, queue_name):
@@ -74,3 +82,80 @@
         uri = '{0}/queues/{1}/metadata'.format(self.uri_prefix, queue_name)
         resp, body = self.put(uri, body=json.dumps(rbody))
         return resp, body
+
+    def post_messages(self, queue_name, rbody):
+        uri = '{0}/queues/{1}/messages'.format(self.uri_prefix, queue_name)
+        resp, body = self.post(uri, body=json.dumps(rbody),
+                               extra_headers=True,
+                               headers=self.headers)
+
+        body = json.loads(body)
+        return resp, body
+
+    def list_messages(self, queue_name):
+        uri = '{0}/queues/{1}/messages?echo=True'.format(self.uri_prefix,
+                                                         queue_name)
+        resp, body = self.get(uri, extra_headers=True, headers=self.headers)
+
+        if resp['status'] != '204':
+            body = json.loads(body)
+            self.validate_response(queues_schema.list_messages, resp, body)
+
+        return resp, body
+
+    def get_single_message(self, message_uri):
+        resp, body = self.get(message_uri, extra_headers=True,
+                              headers=self.headers)
+        if resp['status'] != '204':
+            body = json.loads(body)
+            self.validate_response(queues_schema.get_single_message, resp,
+                                   body)
+        return resp, body
+
+    def get_multiple_messages(self, message_uri):
+        resp, body = self.get(message_uri, extra_headers=True,
+                              headers=self.headers)
+
+        if resp['status'] != '204':
+            body = json.loads(body)
+            self.validate_response(queues_schema.get_multiple_messages,
+                                   resp,
+                                   body)
+
+        return resp, body
+
+    def delete_messages(self, message_uri):
+        resp, body = self.delete(message_uri)
+        assert(resp['status'] == '204')
+        return resp, body
+
+    def post_claims(self, queue_name, rbody, url_params=False):
+        uri = '{0}/queues/{1}/claims'.format(self.uri_prefix, queue_name)
+        if url_params:
+            uri += '?%s' % urllib.urlencode(url_params)
+
+        resp, body = self.post(uri, body=json.dumps(rbody),
+                               extra_headers=True,
+                               headers=self.headers)
+
+        body = json.loads(body)
+        self.validate_response(queues_schema.claim_messages, resp, body)
+        return resp, body
+
+    def query_claim(self, claim_uri):
+        resp, body = self.get(claim_uri)
+
+        if resp['status'] != '204':
+            body = json.loads(body)
+            self.validate_response(queues_schema.query_claim, resp, body)
+        return resp, body
+
+    def update_claim(self, claim_uri, rbody):
+        resp, body = self.patch(claim_uri, body=json.dumps(rbody))
+        assert(resp['status'] == '204')
+        return resp, body
+
+    def release_claim(self, claim_uri):
+        resp, body = self.delete(claim_uri)
+        assert(resp['status'] == '204')
+        return resp, body
diff --git a/tempest/services/telemetry/telemetry_client_base.py b/tempest/services/telemetry/telemetry_client_base.py
index a073f54..b45c239 100644
--- a/tempest/services/telemetry/telemetry_client_base.py
+++ b/tempest/services/telemetry/telemetry_client_base.py
@@ -101,17 +101,17 @@
             uri += "?%s" % urllib.urlencode(uri_dict)
         return self.get(uri)
 
-    def list_resources(self):
+    def list_resources(self, query=None):
         uri = '%s/resources' % self.uri_prefix
-        return self.get(uri)
+        return self.helper_list(uri, query)
 
-    def list_meters(self):
+    def list_meters(self, query=None):
         uri = '%s/meters' % self.uri_prefix
-        return self.get(uri)
+        return self.helper_list(uri, query)
 
-    def list_alarms(self):
+    def list_alarms(self, query=None):
         uri = '%s/alarms' % self.uri_prefix
-        return self.get(uri)
+        return self.helper_list(uri, query)
 
     def list_statistics(self, meter, period=None, query=None):
         uri = "%s/meters/%s/statistics" % (self.uri_prefix, meter)
diff --git a/tempest/services/volume/json/volumes_client.py b/tempest/services/volume/json/volumes_client.py
index b55a037..6c97497 100644
--- a/tempest/services/volume/json/volumes_client.py
+++ b/tempest/services/volume/json/volumes_client.py
@@ -24,13 +24,13 @@
 CONF = config.CONF
 
 
-class VolumesClientJSON(rest_client.RestClient):
+class BaseVolumesClientJSON(rest_client.RestClient):
     """
-    Client class to send CRUD Volume API requests to a Cinder endpoint
+    Base client class to send CRUD Volume API requests to a Cinder endpoint
     """
 
     def __init__(self, auth_provider):
-        super(VolumesClientJSON, self).__init__(auth_provider)
+        super(BaseVolumesClientJSON, self).__init__(auth_provider)
 
         self.service = CONF.volume.catalog_type
         self.build_interval = CONF.volume.build_interval
@@ -72,7 +72,8 @@
         Creates a new Volume.
         size: Size of volume in GB.
         Following optional keyword arguments are accepted:
-        display_name: Optional Volume Name.
+        display_name: Optional Volume Name(only for V1).
+        name: Optional Volume Name(only for V2).
         metadata: A dictionary of values to be used as metadata.
         volume_type: Optional Name of volume_type for the volume
         snapshot_id: When specified the volume is created from this snapshot
@@ -150,7 +151,6 @@
     def wait_for_volume_status(self, volume_id, status):
         """Waits for a Volume to reach a given status."""
         resp, body = self.get_volume(volume_id)
-        volume_name = body['display_name']
         volume_status = body['status']
         start = int(time.time())
 
@@ -162,9 +162,10 @@
                 raise exceptions.VolumeBuildErrorException(volume_id=volume_id)
 
             if int(time.time()) - start >= self.build_timeout:
-                message = ('Volume %s failed to reach %s status within '
-                           'the required time (%s s).' %
-                           (volume_name, status, self.build_timeout))
+                message = 'Volume %s failed to reach %s status within '\
+                          'the required time (%s s).' % (volume_id,
+                                                         status,
+                                                         self.build_timeout)
                 raise exceptions.TimeoutException(message)
 
     def is_resource_deleted(self, id):
@@ -297,3 +298,9 @@
         url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
         resp, body = self.delete(url)
         return resp, body
+
+
+class VolumesClientJSON(BaseVolumesClientJSON):
+    """
+    Client class to send CRUD Volume V1 API requests to a Cinder endpoint
+    """
diff --git a/tempest/services/volume/v2/json/volumes_client.py b/tempest/services/volume/v2/json/volumes_client.py
index df20a2a..1f16ead 100644
--- a/tempest/services/volume/v2/json/volumes_client.py
+++ b/tempest/services/volume/v2/json/volumes_client.py
@@ -13,18 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import json
-import time
-import urllib
-
-from tempest.common import rest_client
-from tempest import config
-from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.volume.json import volumes_client
 
 
-class VolumesV2ClientJSON(rest_client.RestClient):
+class VolumesV2ClientJSON(volumes_client.BaseVolumesClientJSON):
     """
     Client class to send CRUD Volume V2 API requests to a Cinder endpoint
     """
@@ -33,268 +25,3 @@
         super(VolumesV2ClientJSON, self).__init__(auth_provider)
 
         self.api_version = "v2"
-        self.service = CONF.volume.catalog_type
-        self.build_interval = CONF.volume.build_interval
-        self.build_timeout = CONF.volume.build_timeout
-
-    def get_attachment_from_volume(self, volume):
-        """Return the element 'attachment' from input volumes."""
-        return volume['attachments'][0]
-
-    def list_volumes(self, params=None):
-        """List all the volumes created."""
-        url = 'volumes'
-        if params:
-                url += '?%s' % urllib.urlencode(params)
-
-        resp, body = self.get(url)
-        body = json.loads(body)
-        return resp, body['volumes']
-
-    def list_volumes_with_detail(self, params=None):
-        """List the details of all volumes."""
-        url = 'volumes/detail'
-        if params:
-                url += '?%s' % urllib.urlencode(params)
-
-        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 = "volumes/%s" % str(volume_id)
-        resp, body = self.get(url)
-        body = json.loads(body)
-        return resp, body['volume']
-
-    def create_volume(self, size=None, **kwargs):
-        """
-        Creates a new Volume.
-        size: Size of volume in GB.
-        Following optional keyword arguments are accepted:
-        name: Optional Volume Name.
-        metadata: A dictionary of values to be used as metadata.
-        volume_type: Optional Name of volume_type for the volume
-        snapshot_id: When specified the volume is created from this snapshot
-        imageRef: When specified the volume is created from this image
-        """
-        # for bug #1293885:
-        # If no size specified, read volume size from CONF
-        if size is None:
-            size = CONF.volume.volume_size
-        post_body = {'size': size}
-        post_body.update(kwargs)
-        post_body = json.dumps({'volume': post_body})
-        resp, body = self.post('volumes', post_body)
-        body = json.loads(body)
-        return resp, body['volume']
-
-    def update_volume(self, volume_id, **kwargs):
-        """Updates the Specified Volume."""
-        put_body = json.dumps({'volume': kwargs})
-        resp, body = self.put('volumes/%s' % volume_id, put_body)
-        body = json.loads(body)
-        return resp, body['volume']
-
-    def delete_volume(self, volume_id):
-        """Deletes the Specified Volume."""
-        return self.delete("volumes/%s" % str(volume_id))
-
-    def upload_volume(self, volume_id, image_name, disk_format):
-        """Uploads a volume in Glance."""
-        post_body = {
-            'image_name': image_name,
-            'disk_format': disk_format
-        }
-        post_body = json.dumps({'os-volume_upload_image': post_body})
-        url = 'volumes/%s/action' % (volume_id)
-        resp, body = self.post(url, post_body)
-        body = json.loads(body)
-        return resp, body['os-volume_upload_image']
-
-    def attach_volume(self, volume_id, instance_uuid, mountpoint):
-        """Attaches a volume to a given instance on a given mountpoint."""
-        post_body = {
-            'instance_uuid': instance_uuid,
-            'mountpoint': mountpoint,
-        }
-        post_body = json.dumps({'os-attach': post_body})
-        url = 'volumes/%s/action' % (volume_id)
-        resp, body = self.post(url, post_body)
-        return resp, body
-
-    def detach_volume(self, volume_id):
-        """Detaches a volume from an instance."""
-        post_body = {}
-        post_body = json.dumps({'os-detach': post_body})
-        url = 'volumes/%s/action' % (volume_id)
-        resp, body = self.post(url, post_body)
-        return resp, body
-
-    def reserve_volume(self, volume_id):
-        """Reserves a volume."""
-        post_body = {}
-        post_body = json.dumps({'os-reserve': post_body})
-        url = 'volumes/%s/action' % (volume_id)
-        resp, body = self.post(url, post_body)
-        return resp, body
-
-    def unreserve_volume(self, volume_id):
-        """Restore a reserved volume ."""
-        post_body = {}
-        post_body = json.dumps({'os-unreserve': post_body})
-        url = 'volumes/%s/action' % (volume_id)
-        resp, body = self.post(url, post_body)
-        return resp, body
-
-    def wait_for_volume_status(self, volume_id, status):
-        """Waits for a Volume to reach a given status."""
-        resp, body = self.get_volume(volume_id)
-        volume_name = body['name']
-        volume_status = body['status']
-        start = int(time.time())
-
-        while volume_status != status:
-            time.sleep(self.build_interval)
-            resp, body = self.get_volume(volume_id)
-            volume_status = body['status']
-            if volume_status == 'error':
-                raise exceptions.VolumeBuildErrorException(volume_id=volume_id)
-
-            if int(time.time()) - start >= self.build_timeout:
-                message = ('Volume %s failed to reach %s status within '
-                           'the required time (%s s).' %
-                           (volume_name, status, self.build_timeout))
-                raise exceptions.TimeoutException(message)
-
-    def is_resource_deleted(self, id):
-        try:
-            self.get_volume(id)
-        except exceptions.NotFound:
-            return True
-        return False
-
-    def extend_volume(self, volume_id, extend_size):
-        """Extend a volume."""
-        post_body = {
-            'new_size': extend_size
-        }
-        post_body = json.dumps({'os-extend': post_body})
-        url = 'volumes/%s/action' % (volume_id)
-        resp, body = self.post(url, post_body)
-        return resp, body
-
-    def reset_volume_status(self, volume_id, status):
-        """Reset the Specified Volume's Status."""
-        post_body = json.dumps({'os-reset_status': {"status": status}})
-        resp, body = self.post('volumes/%s/action' % volume_id, post_body)
-        return resp, body
-
-    def volume_begin_detaching(self, volume_id):
-        """Volume Begin Detaching."""
-        post_body = json.dumps({'os-begin_detaching': {}})
-        resp, body = self.post('volumes/%s/action' % volume_id, post_body)
-        return resp, body
-
-    def volume_roll_detaching(self, volume_id):
-        """Volume Roll Detaching."""
-        post_body = json.dumps({'os-roll_detaching': {}})
-        resp, body = self.post('volumes/%s/action' % volume_id, post_body)
-        return resp, body
-
-    def create_volume_transfer(self, vol_id, name=None):
-        """Create a volume transfer."""
-        post_body = {
-            'volume_id': vol_id
-        }
-        if name:
-            post_body['name'] = name
-        post_body = json.dumps({'transfer': post_body})
-        resp, body = self.post('os-volume-transfer', post_body)
-        body = json.loads(body)
-        return resp, body['transfer']
-
-    def get_volume_transfer(self, transfer_id):
-        """Returns the details of a volume transfer."""
-        url = "os-volume-transfer/%s" % str(transfer_id)
-        resp, body = self.get(url)
-        body = json.loads(body)
-        return resp, body['transfer']
-
-    def list_volume_transfers(self, params=None):
-        """List all the volume transfers created."""
-        url = 'os-volume-transfer'
-        if params:
-            url += '?%s' % urllib.urlencode(params)
-        resp, body = self.get(url)
-        body = json.loads(body)
-        return resp, body['transfers']
-
-    def delete_volume_transfer(self, transfer_id):
-        """Delete a volume transfer."""
-        return self.delete("os-volume-transfer/%s" % str(transfer_id))
-
-    def accept_volume_transfer(self, transfer_id, transfer_auth_key):
-        """Accept a volume transfer."""
-        post_body = {
-            'auth_key': transfer_auth_key,
-        }
-        url = 'os-volume-transfer/%s/accept' % transfer_id
-        post_body = json.dumps({'accept': post_body})
-        resp, body = self.post(url, post_body)
-        body = json.loads(body)
-        return resp, body['transfer']
-
-    def update_volume_readonly(self, volume_id, readonly):
-        """Update the Specified Volume readonly."""
-        post_body = {
-            'readonly': readonly
-        }
-        post_body = json.dumps({'os-update_readonly_flag': post_body})
-        url = 'volumes/%s/action' % (volume_id)
-        resp, body = self.post(url, post_body)
-        return resp, body
-
-    def force_delete_volume(self, volume_id):
-        """Force Delete Volume."""
-        post_body = json.dumps({'os-force_delete': {}})
-        resp, body = self.post('volumes/%s/action' % volume_id, post_body)
-        return resp, body
-
-    def create_volume_metadata(self, volume_id, metadata):
-        """Create metadata for the volume."""
-        put_body = json.dumps({'metadata': metadata})
-        url = "volumes/%s/metadata" % str(volume_id)
-        resp, body = self.post(url, put_body)
-        body = json.loads(body)
-        return resp, body['metadata']
-
-    def get_volume_metadata(self, volume_id):
-        """Get metadata of the volume."""
-        url = "volumes/%s/metadata" % str(volume_id)
-        resp, body = self.get(url)
-        body = json.loads(body)
-        return resp, body['metadata']
-
-    def update_volume_metadata(self, volume_id, metadata):
-        """Update metadata for the volume."""
-        put_body = json.dumps({'metadata': metadata})
-        url = "volumes/%s/metadata" % str(volume_id)
-        resp, body = self.put(url, put_body)
-        body = json.loads(body)
-        return resp, body['metadata']
-
-    def update_volume_metadata_item(self, volume_id, id, meta_item):
-        """Update metadata item for the volume."""
-        put_body = json.dumps({'meta': meta_item})
-        url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
-        resp, body = self.put(url, put_body)
-        body = json.loads(body)
-        return resp, body['meta']
-
-    def delete_volume_metadata_item(self, volume_id, id):
-        """Delete metadata item for the volume."""
-        url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
-        resp, body = self.delete(url)
-        return resp, body
diff --git a/tempest/services/volume/v2/xml/volumes_client.py b/tempest/services/volume/v2/xml/volumes_client.py
index 1fdaf19..c1bcf6e 100644
--- a/tempest/services/volume/v2/xml/volumes_client.py
+++ b/tempest/services/volume/v2/xml/volumes_client.py
@@ -13,32 +13,23 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import time
 import urllib
 
 from lxml import etree
 
-from tempest.common import rest_client
 from tempest.common import xml_utils as common
-from tempest import config
-from tempest import exceptions
-
-CONF = config.CONF
+from tempest.services.volume.xml import volumes_client
 
 
-class VolumesV2ClientXML(rest_client.RestClient):
+class VolumesV2ClientXML(volumes_client.BaseVolumesClientXML):
     """
-    Client class to send CRUD Volume API requests to a Cinder endpoint
+    Client class to send CRUD Volume API V2 requests to a Cinder endpoint
     """
-    TYPE = "xml"
 
     def __init__(self, auth_provider):
         super(VolumesV2ClientXML, self).__init__(auth_provider)
 
         self.api_version = "v2"
-        self.service = CONF.volume.catalog_type
-        self.build_interval = CONF.compute.build_interval
-        self.build_timeout = CONF.compute.build_timeout
 
     def _parse_volume(self, body):
         vol = dict((attr, body.get(attr)) for attr in body.keys())
@@ -53,46 +44,9 @@
                                        child.getchildren())
             else:
                 vol[tag] = common.xml_to_json(child)
+        self._translate_attributes_to_json(vol)
         return vol
 
-    def get_attachment_from_volume(self, volume):
-        """Return the element 'attachment' from input volumes."""
-        return volume['attachments']['attachment']
-
-    def _check_if_bootable(self, volume):
-        """
-        Check if the volume is bootable, also change the value
-        of 'bootable' from string to boolean.
-        """
-
-        # NOTE(jdg): Version 1 of Cinder API uses lc strings
-        # We should consider being explicit in this check to
-        # avoid introducing bugs like: LP #1227837
-
-        if volume['bootable'].lower() == 'true':
-            volume['bootable'] = True
-        elif volume['bootable'].lower() == 'false':
-            volume['bootable'] = False
-        else:
-            raise ValueError(
-                'bootable flag is supposed to be either True or False,'
-                'it is %s' % volume['bootable'])
-        return volume
-
-    def list_volumes(self, params=None):
-        """List all the volumes created."""
-        url = 'volumes'
-
-        if params:
-            url += '?%s' % urllib.urlencode(params)
-
-        resp, body = self.get(url)
-        body = etree.fromstring(body)
-        volumes = []
-        if body is not None:
-            volumes += [self._parse_volume(vol) for vol in list(body)]
-        return resp, volumes
-
     def list_volumes_with_detail(self, params=None):
         """List all the details of volumes."""
         url = 'volumes/detail'
@@ -116,293 +70,3 @@
         body = self._parse_volume(etree.fromstring(body))
         body = self._check_if_bootable(body)
         return resp, body
-
-    def create_volume(self, size=None, **kwargs):
-        """Creates a new Volume.
-
-        :param size: Size of volume in GB.
-        :param name: Optional Volume Name.
-        :param metadata: An optional dictionary of values for metadata.
-        :param volume_type: Optional Name of volume_type for the volume
-        :param snapshot_id: When specified the volume is created from
-                            this snapshot
-        :param imageRef: When specified the volume is created from this
-                         image
-        """
-        # for bug #1293885:
-        # If no size specified, read volume size from CONF
-        if size is None:
-            size = CONF.volume.volume_size
-        # NOTE(afazekas): it should use a volume namespace
-        volume = common.Element("volume", xmlns=common.XMLNS_11, size=size)
-
-        if 'metadata' in kwargs:
-            _metadata = common.Element('metadata')
-            volume.append(_metadata)
-            for key, value in kwargs['metadata'].items():
-                meta = common.Element('meta')
-                meta.add_attr('key', key)
-                meta.append(common.Text(value))
-                _metadata.append(meta)
-            attr_to_add = kwargs.copy()
-            del attr_to_add['metadata']
-        else:
-            attr_to_add = kwargs
-
-        for key, value in attr_to_add.items():
-            volume.add_attr(key, value)
-
-        resp, body = self.post('volumes', str(common.Document(volume)))
-        body = common.xml_to_json(etree.fromstring(body))
-        return resp, body
-
-    def update_volume(self, volume_id, **kwargs):
-        """Updates the Specified Volume."""
-        put_body = common.Element("volume", xmlns=common.XMLNS_11, **kwargs)
-
-        resp, body = self.put('volumes/%s' % volume_id,
-                              str(common.Document(put_body)))
-        body = common.xml_to_json(etree.fromstring(body))
-        return resp, body
-
-    def delete_volume(self, volume_id):
-        """Deletes the Specified Volume."""
-        return self.delete("volumes/%s" % str(volume_id))
-
-    def wait_for_volume_status(self, volume_id, status):
-        """Waits for a Volume to reach a given status."""
-        resp, body = self.get_volume(volume_id)
-        volume_status = body['status']
-        start = int(time.time())
-
-        while volume_status != status:
-            time.sleep(self.build_interval)
-            resp, body = self.get_volume(volume_id)
-            volume_status = body['status']
-            if volume_status == 'error':
-                raise exceptions.VolumeBuildErrorException(volume_id=volume_id)
-
-            if int(time.time()) - start >= self.build_timeout:
-                message = 'Volume %s failed to reach %s status within '\
-                          'the required time (%s s).' % (volume_id,
-                                                         status,
-                                                         self.build_timeout)
-                raise exceptions.TimeoutException(message)
-
-    def is_resource_deleted(self, id):
-        try:
-            self.get_volume(id)
-        except exceptions.NotFound:
-            return True
-        return False
-
-    def attach_volume(self, volume_id, instance_uuid, mountpoint):
-        """Attaches a volume to a given instance on a given mountpoint."""
-        post_body = common.Element("os-attach",
-                                   instance_uuid=instance_uuid,
-                                   mountpoint=mountpoint
-                                   )
-        url = 'volumes/%s/action' % str(volume_id)
-        resp, body = self.post(url, str(common.Document(post_body)))
-        if body:
-            body = common.xml_to_json(etree.fromstring(body))
-        return resp, body
-
-    def detach_volume(self, volume_id):
-        """Detaches a volume from an instance."""
-        post_body = common.Element("os-detach")
-        url = 'volumes/%s/action' % str(volume_id)
-        resp, body = self.post(url, str(common.Document(post_body)))
-        if body:
-            body = common.xml_to_json(etree.fromstring(body))
-        return resp, body
-
-    def upload_volume(self, volume_id, image_name, disk_format):
-        """Uploads a volume in Glance."""
-        post_body = common.Element("os-volume_upload_image",
-                                   image_name=image_name,
-                                   disk_format=disk_format)
-        url = 'volumes/%s/action' % str(volume_id)
-        resp, body = self.post(url, str(common.Document(post_body)))
-        volume = common.xml_to_json(etree.fromstring(body))
-        return resp, volume
-
-    def extend_volume(self, volume_id, extend_size):
-        """Extend a volume."""
-        post_body = common.Element("os-extend",
-                                   new_size=extend_size)
-        url = 'volumes/%s/action' % str(volume_id)
-        resp, body = self.post(url, str(common.Document(post_body)))
-        if body:
-            body = common.xml_to_json(etree.fromstring(body))
-        return resp, body
-
-    def reset_volume_status(self, volume_id, status):
-        """Reset the Specified Volume's Status."""
-        post_body = common.Element("os-reset_status",
-                                   status=status
-                                   )
-        url = 'volumes/%s/action' % str(volume_id)
-        resp, body = self.post(url, str(common.Document(post_body)))
-        if body:
-            body = common.xml_to_json(etree.fromstring(body))
-        return resp, body
-
-    def volume_begin_detaching(self, volume_id):
-        """Volume Begin Detaching."""
-        post_body = common.Element("os-begin_detaching")
-        url = 'volumes/%s/action' % str(volume_id)
-        resp, body = self.post(url, str(common.Document(post_body)))
-        if body:
-            body = common.xml_to_json(etree.fromstring(body))
-        return resp, body
-
-    def volume_roll_detaching(self, volume_id):
-        """Volume Roll Detaching."""
-        post_body = common.Element("os-roll_detaching")
-        url = 'volumes/%s/action' % str(volume_id)
-        resp, body = self.post(url, str(common.Document(post_body)))
-        if body:
-            body = common.xml_to_json(etree.fromstring(body))
-        return resp, body
-
-    def reserve_volume(self, volume_id):
-        """Reserves a volume."""
-        post_body = common.Element("os-reserve")
-        url = 'volumes/%s/action' % str(volume_id)
-        resp, body = self.post(url, str(common.Document(post_body)))
-        if body:
-            body = common.xml_to_json(etree.fromstring(body))
-        return resp, body
-
-    def unreserve_volume(self, volume_id):
-        """Restore a reserved volume ."""
-        post_body = common.Element("os-unreserve")
-        url = 'volumes/%s/action' % str(volume_id)
-        resp, body = self.post(url, str(common.Document(post_body)))
-        if body:
-            body = common.xml_to_json(etree.fromstring(body))
-        return resp, body
-
-    def create_volume_transfer(self, vol_id, name=None):
-        """Create a volume transfer."""
-        post_body = common.Element("transfer", volume_id=vol_id)
-        if name:
-            post_body.add_attr('name', name)
-        resp, body = self.post('os-volume-transfer',
-                               str(common.Document(post_body)))
-        volume = common.xml_to_json(etree.fromstring(body))
-        return resp, volume
-
-    def get_volume_transfer(self, transfer_id):
-        """Returns the details of a volume transfer."""
-        url = "os-volume-transfer/%s" % str(transfer_id)
-        resp, body = self.get(url)
-        volume = common.xml_to_json(etree.fromstring(body))
-        return resp, volume
-
-    def list_volume_transfers(self, params=None):
-        """List all the volume transfers created."""
-        url = 'os-volume-transfer'
-        if params:
-            url += '?%s' % urllib.urlencode(params)
-
-        resp, body = self.get(url)
-        body = etree.fromstring(body)
-        volumes = []
-        if body is not None:
-            volumes += [self._parse_volume_transfer(vol) for vol in list(body)]
-        return resp, volumes
-
-    def _parse_volume_transfer(self, body):
-        vol = dict((attr, body.get(attr)) for attr in body.keys())
-        for child in body.getchildren():
-            tag = child.tag
-            if tag.startswith("{"):
-                tag = tag.split("}", 1)
-            vol[tag] = common.xml_to_json(child)
-        return vol
-
-    def delete_volume_transfer(self, transfer_id):
-        """Delete a volume transfer."""
-        return self.delete("os-volume-transfer/%s" % str(transfer_id))
-
-    def accept_volume_transfer(self, transfer_id, transfer_auth_key):
-        """Accept a volume transfer."""
-        post_body = common.Element("accept", auth_key=transfer_auth_key)
-        url = 'os-volume-transfer/%s/accept' % transfer_id
-        resp, body = self.post(url, str(common.Document(post_body)))
-        volume = common.xml_to_json(etree.fromstring(body))
-        return resp, volume
-
-    def update_volume_readonly(self, volume_id, readonly):
-        """Update the Specified Volume readonly."""
-        post_body = common.Element("os-update_readonly_flag",
-                                   readonly=readonly)
-        url = 'volumes/%s/action' % str(volume_id)
-        resp, body = self.post(url, str(common.Document(post_body)))
-        if body:
-            body = common.xml_to_json(etree.fromstring(body))
-        return resp, body
-
-    def force_delete_volume(self, volume_id):
-        """Force Delete Volume."""
-        post_body = common.Element("os-force_delete")
-        url = 'volumes/%s/action' % str(volume_id)
-        resp, body = self.post(url, str(common.Document(post_body)))
-        if body:
-            body = common.xml_to_json(etree.fromstring(body))
-        return resp, body
-
-    def _metadata_body(self, meta):
-        post_body = common.Element('metadata')
-        for k, v in meta.items():
-            data = common.Element('meta', key=k)
-            data.append(common.Text(v))
-            post_body.append(data)
-        return post_body
-
-    def _parse_key_value(self, node):
-        """Parse <foo key='key'>value</foo> data into {'key': 'value'}."""
-        data = {}
-        for node in node.getchildren():
-            data[node.get('key')] = node.text
-        return data
-
-    def create_volume_metadata(self, volume_id, metadata):
-        """Create metadata for the volume."""
-        post_body = self._metadata_body(metadata)
-        resp, body = self.post('volumes/%s/metadata' % volume_id,
-                               str(common.Document(post_body)))
-        body = self._parse_key_value(etree.fromstring(body))
-        return resp, body
-
-    def get_volume_metadata(self, volume_id):
-        """Get metadata of the volume."""
-        url = "volumes/%s/metadata" % str(volume_id)
-        resp, body = self.get(url)
-        body = self._parse_key_value(etree.fromstring(body))
-        return resp, body
-
-    def update_volume_metadata(self, volume_id, metadata):
-        """Update metadata for the volume."""
-        put_body = self._metadata_body(metadata)
-        url = "volumes/%s/metadata" % str(volume_id)
-        resp, body = self.put(url, str(common.Document(put_body)))
-        body = self._parse_key_value(etree.fromstring(body))
-        return resp, body
-
-    def update_volume_metadata_item(self, volume_id, id, meta_item):
-        """Update metadata item for the volume."""
-        for k, v in meta_item.items():
-            put_body = common.Element('meta', key=k)
-            put_body.append(common.Text(v))
-        url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
-        resp, body = self.put(url, str(common.Document(put_body)))
-        body = common.xml_to_json(etree.fromstring(body))
-        return resp, body
-
-    def delete_volume_metadata_item(self, volume_id, id):
-        """Delete metadata item for the volume."""
-        url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
-        return self.delete(url)
diff --git a/tempest/services/volume/xml/backups_client.py b/tempest/services/volume/xml/backups_client.py
index 81caaee..a691a25 100644
--- a/tempest/services/volume/xml/backups_client.py
+++ b/tempest/services/volume/xml/backups_client.py
@@ -22,5 +22,5 @@
     """
     TYPE = "xml"
 
-    #TODO(gfidente): XML client isn't yet implemented because of bug 1270589
+    # TODO(gfidente): XML client isn't yet implemented because of bug 1270589
     pass
diff --git a/tempest/services/volume/xml/volumes_client.py b/tempest/services/volume/xml/volumes_client.py
index 9799e55..2d4a9e9 100644
--- a/tempest/services/volume/xml/volumes_client.py
+++ b/tempest/services/volume/xml/volumes_client.py
@@ -32,14 +32,14 @@
 VOLUMES_TENANT_NS = VOLUME_NS_BASE + 'volume_tenant_attribute/api/v1'
 
 
-class VolumesClientXML(rest_client.RestClient):
+class BaseVolumesClientXML(rest_client.RestClient):
     """
-    Client class to send CRUD Volume API requests to a Cinder endpoint
+    Base client class to send CRUD Volume API requests to a Cinder endpoint
     """
     TYPE = "xml"
 
     def __init__(self, auth_provider):
-        super(VolumesClientXML, self).__init__(auth_provider)
+        super(BaseVolumesClientXML, self).__init__(auth_provider)
         self.service = CONF.volume.catalog_type
         self.build_interval = CONF.compute.build_interval
         self.build_timeout = CONF.compute.build_timeout
@@ -141,6 +141,8 @@
         """Creates a new Volume.
 
         :param size: Size of volume in GB.
+        :param display_name: Optional Volume Name(only for V1).
+        :param name: Optional Volume Name(only for V2).
         :param display_name: Optional Volume Name.
         :param metadata: An optional dictionary of values for metadata.
         :param volume_type: Optional Name of volume_type for the volume
@@ -428,3 +430,9 @@
         """Delete metadata item for the volume."""
         url = "volumes/%s/metadata/%s" % (str(volume_id), str(id))
         return self.delete(url)
+
+
+class VolumesClientXML(BaseVolumesClientXML):
+    """
+    Client class to send CRUD Volume API V1 requests to a Cinder endpoint
+    """
diff --git a/tempest/stress/actions/volume_attach_delete.py b/tempest/stress/actions/volume_attach_delete.py
index c2e6072..b438f52 100644
--- a/tempest/stress/actions/volume_attach_delete.py
+++ b/tempest/stress/actions/volume_attach_delete.py
@@ -28,9 +28,9 @@
         # Step 1: create volume
         name = data_utils.rand_name("volume")
         self.logger.info("creating volume: %s" % name)
-        resp, volume = self.manager.volumes_client.create_volume(size=1,
-                                                                 display_name=
-                                                                 name)
+        resp, volume = self.manager.volumes_client.create_volume(
+            size=1,
+            display_name=name)
         assert(resp.status == 200)
         self.manager.volumes_client.wait_for_volume_status(volume['id'],
                                                            'available')
diff --git a/tempest/stress/actions/volume_attach_verify.py b/tempest/stress/actions/volume_attach_verify.py
index 1bc3b06..a3ca0b7 100644
--- a/tempest/stress/actions/volume_attach_verify.py
+++ b/tempest/stress/actions/volume_attach_verify.py
@@ -81,9 +81,9 @@
         name = data_utils.rand_name("volume")
         self.logger.info("creating volume: %s" % name)
         volumes_client = self.manager.volumes_client
-        resp, self.volume = volumes_client.create_volume(size=1,
-                                                         display_name=
-                                                         name)
+        resp, self.volume = volumes_client.create_volume(
+            size=1,
+            display_name=name)
         assert(resp.status == 200)
         volumes_client.wait_for_volume_status(self.volume['id'],
                                               'available')
diff --git a/tempest/test.py b/tempest/test.py
index 748a98c..afe7a96 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -107,6 +107,8 @@
         'identity': True,
         'object_storage': CONF.service_available.swift,
         'dashboard': CONF.service_available.horizon,
+        'ceilometer': CONF.service_available.ceilometer,
+        'data_processing': CONF.service_available.sahara
     }
 
     def decorator(f):
@@ -256,6 +258,12 @@
 
     network_resources = {}
 
+    # NOTE(sdague): log_format is defined inline here instead of using the oslo
+    # default because going through the config path recouples config to the
+    # stress tests too early, and depending on testr order will fail unit tests
+    log_format = ('%(asctime)s %(process)d %(levelname)-8s '
+                  '[%(name)s] %(message)s')
+
     @classmethod
     def setUpClass(cls):
         if hasattr(super(BaseTestCase, cls), 'setUpClass'):
@@ -293,9 +301,8 @@
             self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
         if (os.environ.get('OS_LOG_CAPTURE') != 'False' and
             os.environ.get('OS_LOG_CAPTURE') != '0'):
-            log_format = '%(asctime)-15s %(message)s'
             self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
-                                                   format=log_format,
+                                                   format=self.log_format,
                                                    level=None))
 
     @classmethod
@@ -396,7 +403,7 @@
 
         :param file: the file name
         """
-        #NOTE(mkoderer): must be extended for xml support
+        # NOTE(mkoderer): must be extended for xml support
         fn = os.path.join(
             os.path.abspath(os.path.dirname(os.path.dirname(__file__))),
             "etc", "schemas", file)
diff --git a/tempest/tests/cli/test_command_failed.py b/tempest/tests/cli/test_command_failed.py
new file mode 100644
index 0000000..c539ac6
--- /dev/null
+++ b/tempest/tests/cli/test_command_failed.py
@@ -0,0 +1,30 @@
+#    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 import cli
+from tempest.tests import base
+
+
+class TestOutputParser(base.TestCase):
+
+    def test_command_failed_exception(self):
+        returncode = 1
+        cmd = "foo"
+        stdout = "output"
+        stderr = "error"
+        try:
+            raise cli.CommandFailed(returncode, cmd, stdout, stderr)
+        except cli.CommandFailed as e:
+            self.assertIn(str(returncode), str(e))
+            self.assertIn(cmd, str(e))
+            self.assertIn(stdout, str(e))
+            self.assertIn(stderr, str(e))
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index 40caf30..d0140dd 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -15,6 +15,7 @@
 import json
 
 import mock
+from oslo.config import cfg
 
 from tempest.cmd import verify_tempest_config
 from tempest import config
@@ -152,6 +153,7 @@
                                            False, True)
 
     def test_verify_nova_versions(self):
+        cfg.CONF.set_default('api_v3', True, 'compute-feature-enabled')
         self.useFixture(mockpatch.PatchObject(
             verify_tempest_config, '_get_unversioned_endpoint',
             return_value='http://fake_endpoint:5000'))
@@ -280,9 +282,9 @@
 
     def test_verify_extensions_nova(self):
         def fake_list_extensions():
-            return (None, {'extensions': [{'name': 'fake1'},
-                                          {'name': 'fake2'},
-                                          {'name': 'not_fake'}]})
+            return (None, {'extensions': [{'alias': 'fake1'},
+                                          {'alias': 'fake2'},
+                                          {'alias': 'not_fake'}]})
         fake_os = mock.MagicMock()
         fake_os.extensions_client.list_extensions = fake_list_extensions
         self.useFixture(mockpatch.PatchObject(
@@ -302,9 +304,9 @@
 
     def test_verify_extensions_nova_all(self):
         def fake_list_extensions():
-            return (None, {'extensions': [{'name': 'fake1'},
-                                          {'name': 'fake2'},
-                                          {'name': 'not_fake'}]})
+            return (None, {'extensions': [{'alias': 'fake1'},
+                                          {'alias': 'fake2'},
+                                          {'alias': 'not_fake'}]})
         fake_os = mock.MagicMock()
         fake_os.extensions_client.list_extensions = fake_list_extensions
         self.useFixture(mockpatch.PatchObject(
@@ -319,9 +321,9 @@
 
     def test_verify_extensions_nova_v3(self):
         def fake_list_extensions():
-            return (None, {'extensions': [{'name': 'fake1'},
-                                          {'name': 'fake2'},
-                                          {'name': 'not_fake'}]})
+            return (None, {'extensions': [{'alias': 'fake1'},
+                                          {'alias': 'fake2'},
+                                          {'alias': 'not_fake'}]})
         fake_os = mock.MagicMock()
         fake_os.extensions_v3_client.list_extensions = fake_list_extensions
         self.useFixture(mockpatch.PatchObject(
@@ -341,9 +343,9 @@
 
     def test_verify_extensions_nova_v3_all(self):
         def fake_list_extensions():
-            return (None, {'extensions': [{'name': 'fake1'},
-                                          {'name': 'fake2'},
-                                          {'name': 'not_fake'}]})
+            return (None, {'extensions': [{'alias': 'fake1'},
+                                          {'alias': 'fake2'},
+                                          {'alias': 'not_fake'}]})
         fake_os = mock.MagicMock()
         fake_os.extensions_v3_client.list_extensions = fake_list_extensions
         self.useFixture(mockpatch.PatchObject(
diff --git a/tempest/tests/common/utils/linux/__init__.py b/tempest/tests/common/utils/linux/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tempest/tests/common/utils/linux/__init__.py
diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py
new file mode 100644
index 0000000..0db4cfa
--- /dev/null
+++ b/tempest/tests/common/utils/linux/test_remote_client.py
@@ -0,0 +1,150 @@
+# Copyright 2014 IBM Corp.
+#
+#    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
+
+from oslo.config import cfg
+
+from tempest.common.utils.linux import remote_client
+from tempest import config
+from tempest.openstack.common.fixture import mockpatch
+from tempest.tests import base
+from tempest.tests import fake_config
+
+
+class TestRemoteClient(base.TestCase):
+    def setUp(self):
+        super(TestRemoteClient, self).setUp()
+        self.useFixture(fake_config.ConfigFixture())
+        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
+        cfg.CONF.set_default('ip_version_for_ssh', 4, group='compute')
+        cfg.CONF.set_default('network_for_ssh', 'public', group='compute')
+        cfg.CONF.set_default('ssh_channel_timeout', 1, group='compute')
+
+        self.conn = remote_client.RemoteClient('127.0.0.1', 'user', 'pass')
+        self.ssh_mock = self.useFixture(mockpatch.PatchObject(self.conn,
+                                                              'ssh_client'))
+
+    def test_hostname_equals_servername_for_expected_names(self):
+        self.ssh_mock.mock.exec_command.return_value = 'fake_hostname'
+        self.assertTrue(self.conn.hostname_equals_servername('fake_hostname'))
+
+    def test_hostname_equals_servername_for_unexpected_names(self):
+        self.ssh_mock.mock.exec_command.return_value = 'fake_hostname'
+        self.assertFalse(
+            self.conn.hostname_equals_servername('unexpected_hostname'))
+
+    def test_get_ram_size(self):
+        free_output = "Mem:         48294      45738       2555          0" \
+                      "402      40346"
+        self.ssh_mock.mock.exec_command.return_value = free_output
+        self.assertEqual(self.conn.get_ram_size_in_mb(), '48294')
+
+    def test_write_to_console_regular_str(self):
+        self.conn.write_to_console('test')
+        self._assert_exec_called_with(
+            'sudo sh -c "echo \\"test\\" >/dev/console"')
+
+    def _test_write_to_console_helper(self, message, expected_call):
+        self.conn.write_to_console(message)
+        self._assert_exec_called_with(expected_call)
+
+    def test_write_to_console_special_chars(self):
+        self._test_write_to_console_helper(
+            '\`',
+            'sudo sh -c "echo \\"\\\\\\`\\" >/dev/console"')
+        self.conn.write_to_console('$')
+        self._assert_exec_called_with(
+            'sudo sh -c "echo \\"\\\\$\\" >/dev/console"')
+
+    # NOTE(maurosr): The tests below end up closer to an output format
+    # assurance than a test since it's basically using comand_exec to format
+    # the information using gnu/linux tools.
+
+    def _assert_exec_called_with(self, cmd):
+        self.ssh_mock.mock.exec_command.assert_called_with(cmd)
+
+    def test_get_number_of_vcpus(self):
+        self.ssh_mock.mock.exec_command.return_value = '16'
+        self.assertEqual(self.conn.get_number_of_vcpus(), 16)
+        self._assert_exec_called_with(
+            'cat /proc/cpuinfo | grep processor | wc -l')
+
+    def test_get_partitions(self):
+        proc_partitions = """major minor  #blocks  name
+
+8        0  1048576 vda"""
+        self.ssh_mock.mock.exec_command.return_value = proc_partitions
+        self.assertEqual(self.conn.get_partitions(), proc_partitions)
+        self._assert_exec_called_with('cat /proc/partitions')
+
+    def test_get_boot_time(self):
+        booted_at = 10000
+        uptime_sec = 5000.02
+        self.ssh_mock.mock.exec_command.return_value = uptime_sec
+        self.useFixture(mockpatch.PatchObject(
+            time, 'time', return_value=booted_at + uptime_sec))
+        self.assertEqual(self.conn.get_boot_time(),
+                         time.localtime(booted_at))
+        self._assert_exec_called_with('cut -f1 -d. /proc/uptime')
+
+    def test_ping_host(self):
+        ping_response = """PING localhost (127.0.0.1) 56(84) bytes of data.
+64 bytes from localhost (127.0.0.1): icmp_req=1 ttl=64 time=0.048 ms
+
+--- localhost ping statistics ---
+1 packets transmitted, 1 received, 0% packet loss, time 0ms
+rtt min/avg/max/mdev = 0.048/0.048/0.048/0.000 ms"""
+        self.ssh_mock.mock.exec_command.return_value = ping_response
+        self.assertEqual(self.conn.ping_host('127.0.0.1'), ping_response)
+        self._assert_exec_called_with('ping -c1 -w1 127.0.0.1')
+
+    def test_get_mac_address(self):
+        macs = """0a:0b:0c:0d:0e:0f
+a0:b0:c0:d0:e0:f0"""
+        self.ssh_mock.mock.exec_command.return_value = macs
+
+        self.assertEqual(self.conn.get_mac_address(), macs)
+        self._assert_exec_called_with(
+            "/sbin/ifconfig | awk '/HWaddr/ {print $5}'")
+
+    def test_get_ip_list(self):
+        ips = """1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue
+    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
+    inet 127.0.0.1/8 scope host lo
+    inet6 ::1/128 scope host
+       valid_lft forever preferred_lft forever
+2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast qlen 1000
+    link/ether fa:16:3e:6e:26:3b brd ff:ff:ff:ff:ff:ff
+    inet 10.0.0.4/24 brd 10.0.0.255 scope global eth0
+    inet6 fd55:faaf:e1ab:3d9:f816:3eff:fe6e:263b/64 scope global dynamic
+       valid_lft 2591936sec preferred_lft 604736sec
+    inet6 fe80::f816:3eff:fe6e:263b/64 scope link
+       valid_lft forever preferred_lft forever"""
+        self.ssh_mock.mock.exec_command.return_value = ips
+        self.assertEqual(self.conn.get_ip_list(), ips)
+        self._assert_exec_called_with('/bin/ip address')
+
+    def test_assign_static_ip(self):
+        self.ssh_mock.mock.exec_command.return_value = ''
+        ip = '10.0.0.2'
+        nic = 'eth0'
+        self.assertEqual(self.conn.assign_static_ip(nic, ip), '')
+        self._assert_exec_called_with(
+            "sudo /bin/ip addr add %s/%s dev %s" % (ip, '28', nic))
+
+    def test_turn_nic_on(self):
+        nic = 'eth0'
+        self.conn.turn_nic_on(nic)
+        self._assert_exec_called_with('sudo /bin/ip link set %s up' % nic)
diff --git a/tempest/tests/fake_config.py b/tempest/tests/fake_config.py
index 4bed0c2..536cbcf 100644
--- a/tempest/tests/fake_config.py
+++ b/tempest/tests/fake_config.py
@@ -58,6 +58,6 @@
 
 
 class FakePrivate(config.TempestConfigPrivate):
-    def __init__(self):
+    def __init__(self, parse_conf=True, config_path=None):
         cfg.CONF([], default_config_files=[])
         self._set_attrs()
diff --git a/tempest/tests/fake_http.py b/tempest/tests/fake_http.py
index 7b878af..ce2b2c0 100644
--- a/tempest/tests/fake_http.py
+++ b/tempest/tests/fake_http.py
@@ -32,7 +32,6 @@
                 'headers': headers
             }
             return (fake_headers, return_obj)
-           # return (headers, return_obj)
         elif isinstance(self.return_type, int):
             body = "fake_body"
             header_info = {
diff --git a/tempest/tests/negative/test_negative_generators.py b/tempest/tests/negative/test_negative_generators.py
index c77faca..a7af619 100644
--- a/tempest/tests/negative/test_negative_generators.py
+++ b/tempest/tests/negative/test_negative_generators.py
@@ -102,7 +102,7 @@
                                      }
                       }
 
-    unkown_type_schema = {
+    unknown_type_schema = {
         "type": "not_defined"
     }
 
@@ -131,7 +131,7 @@
 
     def test_generate_with_unknown_type(self):
         self.assertRaises(TypeError, self.generator.generate,
-                          self.unkown_type_schema)
+                          self.unknown_type_schema)
 
 
 class TestNegativeValidGenerator(base.TestCase, BaseNegativeGenerator):
diff --git a/tempest/tests/stress/test_stress.py b/tempest/tests/stress/test_stress.py
index 5a334c5..3dc2199 100644
--- a/tempest/tests/stress/test_stress.py
+++ b/tempest/tests/stress/test_stress.py
@@ -32,7 +32,7 @@
         cmd = ' '.join([cmd, param])
         LOG.info("running: '%s'" % cmd)
         cmd_str = cmd
-        cmd = shlex.split(cmd)
+        cmd = shlex.split(cmd.encode('utf-8'))
         result = ''
         result_err = ''
         try:
diff --git a/tempest/tests/test_commands.py b/tempest/tests/test_commands.py
index bdb9269..1e2925b 100644
--- a/tempest/tests/test_commands.py
+++ b/tempest/tests/test_commands.py
@@ -47,7 +47,8 @@
     @mock.patch('subprocess.Popen')
     def test_iptables_raw(self, mock):
         table = 'filter'
-        expected = ['/usr/bin/sudo', '-n', 'iptables', '-v', '-S', '-t',
+        expected = ['/usr/bin/sudo', '-n', 'iptables', '--line-numbers',
+                    '-L', '-nv', '-t',
                     '%s' % table]
         commands.iptables_raw(table)
         mock.assert_called_once_with(expected, **self.subprocess_args)
diff --git a/tempest/tests/test_glance_http.py b/tempest/tests/test_glance_http.py
index bb2df43..88b8129 100644
--- a/tempest/tests/test_glance_http.py
+++ b/tempest/tests/test_glance_http.py
@@ -54,26 +54,37 @@
                         return_value=resp))
         return resp
 
-    def test_json_request_without_content_type_header(self):
+    def test_json_request_without_content_type_header_in_response(self):
         self._set_response_fixture({}, 200, 'fake_response_body')
-        resp, body = self.client.json_request('GET', '/images')
-        self.assertEqual(200, resp.status)
-        self.assertIsNone(body)
+        self.assertRaises(exceptions.InvalidContentType,
+                          self.client.json_request, 'GET', '/images')
 
-    def test_json_request_with_xml_content_type_header(self):
+    def test_json_request_with_xml_content_type_header_in_request(self):
+        self.assertRaises(exceptions.InvalidContentType,
+                          self.client.json_request, 'GET', '/images',
+                          headers={'Content-Type': 'application/xml'})
+
+    def test_json_request_with_xml_content_type_header_in_response(self):
         self._set_response_fixture({'content-type': 'application/xml'},
                                    200, 'fake_response_body')
-        resp, body = self.client.json_request('GET', '/images')
-        self.assertEqual(200, resp.status)
-        self.assertIsNone(body)
+        self.assertRaises(exceptions.InvalidContentType,
+                          self.client.json_request, 'GET', '/images')
 
-    def test_json_request_with_content_type_header(self):
+    def test_json_request_with_json_content_type_header_only_in_resp(self):
         self._set_response_fixture({'content-type': 'application/json'},
                                    200, 'fake_response_body')
         resp, body = self.client.json_request('GET', '/images')
         self.assertEqual(200, resp.status)
         self.assertEqual('fake_response_body', body)
 
+    def test_json_request_with_json_content_type_header_in_req_and_resp(self):
+        self._set_response_fixture({'content-type': 'application/json'},
+                                   200, 'fake_response_body')
+        resp, body = self.client.json_request('GET', '/images', headers={
+            'Content-Type': 'application/json'})
+        self.assertEqual(200, resp.status)
+        self.assertEqual('fake_response_body', body)
+
     def test_json_request_fails_to_json_loads(self):
         self._set_response_fixture({'content-type': 'application/json'},
                                    200, 'fake_response_body')
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index ab81836..52fdf7e 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -70,9 +70,15 @@
         self.assertFalse(checks.scenario_tests_need_service_tags(
             'def test_fake_test:', './tempest/api/compute/test_fake.py',
             "@test.services('image')"))
+        self.assertFalse(checks.scenario_tests_need_service_tags(
+            'def test_fake:', './tempest/scenario/orchestration/test_fake.py',
+            "@test.services('compute')"))
         self.assertTrue(checks.scenario_tests_need_service_tags(
             'def test_fake_test:', './tempest/scenario/test_fake.py',
             '\n'))
+        self.assertTrue(checks.scenario_tests_need_service_tags(
+            'def test_fake:', './tempest/scenario/orchestration/test_fake.py',
+            "\n"))
 
     def test_no_vi_headers(self):
         # NOTE(mtreinish)  The lines parameter is used only for finding the
@@ -93,3 +99,11 @@
             './tempest/scenario/compute/fake_test.py'))
         self.assertFalse(checks.service_tags_not_in_module_path(
             "@test.services('compute')", './tempest/api/image/fake_test.py'))
+
+    def test_no_official_client_manager_in_api_tests(self):
+        self.assertTrue(checks.no_official_client_manager_in_api_tests(
+            "cls.official_client = clients.OfficialClientManager(credentials)",
+            "tempest/api/compute/base.py"))
+        self.assertFalse(checks.no_official_client_manager_in_api_tests(
+            "cls.official_client = clients.OfficialClientManager(credentials)",
+            "tempest/scenario/fake_test.py"))
diff --git a/tempest/tests/test_rest_client.py b/tempest/tests/test_rest_client.py
index d20520c..a351bd5 100644
--- a/tempest/tests/test_rest_client.py
+++ b/tempest/tests/test_rest_client.py
@@ -541,3 +541,50 @@
         self.assertRaises(AssertionError,
                           self.negative_rest_client.send_request,
                           'OTHER', self.url, [])
+
+
+class TestExpectedSuccess(BaseRestClientTestClass):
+
+    def setUp(self):
+        self.fake_http = fake_http.fake_httplib2()
+        super(TestExpectedSuccess, self).setUp()
+
+    def test_expected_succes_int_match(self):
+        expected_code = 202
+        read_code = 202
+        resp = self.rest_client.expected_success(expected_code, read_code)
+        # Assert None resp on success
+        self.assertFalse(resp)
+
+    def test_expected_succes_int_no_match(self):
+        expected_code = 204
+        read_code = 202
+        self.assertRaises(exceptions.InvalidHttpSuccessCode,
+                          self.rest_client.expected_success,
+                          expected_code, read_code)
+
+    def test_expected_succes_list_match(self):
+        expected_code = [202, 204]
+        read_code = 202
+        resp = self.rest_client.expected_success(expected_code, read_code)
+        # Assert None resp on success
+        self.assertFalse(resp)
+
+    def test_expected_succes_list_no_match(self):
+        expected_code = [202, 204]
+        read_code = 200
+        self.assertRaises(exceptions.InvalidHttpSuccessCode,
+                          self.rest_client.expected_success,
+                          expected_code, read_code)
+
+    def test_non_success_expected_int(self):
+        expected_code = 404
+        read_code = 202
+        self.assertRaises(AssertionError, self.rest_client.expected_success,
+                          expected_code, read_code)
+
+    def test_non_success_expected_list(self):
+        expected_code = [404, 202]
+        read_code = 202
+        self.assertRaises(AssertionError, self.rest_client.expected_success,
+                          expected_code, read_code)
diff --git a/tempest/tests/test_ssh.py b/tempest/tests/test_ssh.py
index 0da52dc..27cd6b5 100644
--- a/tempest/tests/test_ssh.py
+++ b/tempest/tests/test_ssh.py
@@ -36,13 +36,13 @@
             rsa_mock.assert_called_once_with(mock.sentinel.csio)
             cs_mock.assert_called_once_with('mykey')
             rsa_mock.reset_mock()
-            cs_mock.rest_mock()
+            cs_mock.reset_mock()
             pkey = mock.sentinel.pkey
             # Shouldn't call out to load a file from RSAKey, since
             # a sentinel isn't a basestring...
             ssh.Client('localhost', 'root', pkey=pkey)
-            rsa_mock.assert_not_called()
-            cs_mock.assert_not_called()
+            self.assertEqual(0, rsa_mock.call_count)
+            self.assertEqual(0, cs_mock.call_count)
 
     def _set_ssh_connection_mocks(self):
         client_mock = mock.MagicMock()
@@ -75,7 +75,7 @@
             password=None
         )]
         self.assertEqual(expected_connect, client_mock.connect.mock_calls)
-        s_mock.assert_not_called()
+        self.assertEqual(0, s_mock.call_count)
 
     def test_get_ssh_connection_two_attemps(self):
         c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
@@ -90,8 +90,8 @@
         start_time = int(time.time())
         client._get_ssh_connection(sleep=1)
         end_time = int(time.time())
-        self.assertTrue((end_time - start_time) < 3)
-        self.assertTrue((end_time - start_time) > 1)
+        self.assertLess((end_time - start_time), 4)
+        self.assertGreater((end_time - start_time), 1)
 
     def test_get_ssh_connection_timeout(self):
         c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()
@@ -108,8 +108,8 @@
         with testtools.ExpectedException(exceptions.SSHTimeout):
             client._get_ssh_connection()
         end_time = int(time.time())
-        self.assertTrue((end_time - start_time) < 4)
-        self.assertTrue((end_time - start_time) >= 2)
+        self.assertLess((end_time - start_time), 5)
+        self.assertGreaterEqual((end_time - start_time), 2)
 
     def test_exec_command(self):
         gsc_mock = self.patch('tempest.common.ssh.Client._get_ssh_connection')
diff --git a/tempest/tests/test_tenant_isolation.py b/tempest/tests/test_tenant_isolation.py
index 7a9b6be..bbc3d15 100644
--- a/tempest/tests/test_tenant_isolation.py
+++ b/tempest/tests/test_tenant_isolation.py
@@ -42,6 +42,8 @@
         self.fake_http = fake_http.fake_httplib2(return_type=200)
         self.stubs.Set(http.ClosingHttp, 'request',
                        fake_identity._fake_v2_response)
+        cfg.CONF.set_default('operator_role', 'FakeRole',
+                             group='object-storage')
 
     def test_tempest_client(self):
         iso_creds = isolated_creds.IsolatedCreds('test class')
@@ -59,6 +61,8 @@
                                               '_get_object_storage_client'))
         self.useFixture(mockpatch.PatchObject(clients.OfficialClientManager,
                                               '_get_orchestration_client'))
+        self.useFixture(mockpatch.PatchObject(clients.OfficialClientManager,
+                                              '_get_ceilometer_client'))
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  tempest_client=False)
         self.assertTrue(isinstance(iso_creds.identity_admin_client,
@@ -90,6 +94,31 @@
                           {'id': id, 'name': name})))
         return tenant_fix
 
+    def _mock_list_roles(self, id, name):
+        roles_fix = self.useFixture(mockpatch.PatchObject(
+            json_iden_client.IdentityClientJSON,
+            'list_roles',
+            return_value=({'status': 200},
+                          [{'id': id, 'name': name},
+                           {'id': '1', 'name': 'FakeRole'}])))
+        return roles_fix
+
+    def _mock_assign_user_role(self):
+        tenant_fix = self.useFixture(mockpatch.PatchObject(
+            json_iden_client.IdentityClientJSON,
+            'assign_user_role',
+            return_value=({'status': 200},
+                          {})))
+        return tenant_fix
+
+    def _mock_list_role(self):
+        roles_fix = self.useFixture(mockpatch.PatchObject(
+            json_iden_client.IdentityClientJSON,
+            'list_roles',
+            return_value=({'status': 200},
+                          [{'id': '1', 'name': 'FakeRole'}])))
+        return roles_fix
+
     def _mock_network_create(self, iso_creds, id, name):
         net_fix = self.useFixture(mockpatch.PatchObject(
             iso_creds.network_admin_client,
@@ -119,6 +148,8 @@
         cfg.CONF.set_default('neutron', False, 'service_available')
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_tenant_create('1234', 'fake_prim_tenant')
         self._mock_user_create('1234', 'fake_prim_user')
         primary_creds = iso_creds.get_primary_creds()
@@ -133,13 +164,9 @@
         cfg.CONF.set_default('neutron', False, 'service_available')
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
+        self._mock_list_roles('1234', 'admin')
         self._mock_user_create('1234', 'fake_admin_user')
         self._mock_tenant_create('1234', 'fake_admin_tenant')
-        self.useFixture(mockpatch.PatchObject(
-            json_iden_client.IdentityClientJSON,
-            'list_roles',
-            return_value=({'status': 200},
-                          [{'id': '1234', 'name': 'admin'}])))
 
         user_mock = mock.patch.object(json_iden_client.IdentityClientJSON,
                                       'assign_user_role')
@@ -148,7 +175,9 @@
         with mock.patch.object(json_iden_client.IdentityClientJSON,
                                'assign_user_role') as user_mock:
             admin_creds = iso_creds.get_admin_creds()
-        user_mock.assert_called_once_with('1234', '1234', '1234')
+        user_mock.assert_has_calls([
+            mock.call('1234', '1234', '1'),
+            mock.call('1234', '1234', '1234')])
         self.assertEqual(admin_creds.username, 'fake_admin_user')
         self.assertEqual(admin_creds.tenant_name, 'fake_admin_tenant')
         # Verify IDs
@@ -160,6 +189,8 @@
         cfg.CONF.set_default('neutron', False, 'service_available')
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
+        self._mock_assign_user_role()
+        roles_fix = self._mock_list_role()
         tenant_fix = self._mock_tenant_create('1234', 'fake_prim_tenant')
         user_fix = self._mock_user_create('1234', 'fake_prim_user')
         iso_creds.get_primary_creds()
@@ -170,16 +201,11 @@
         iso_creds.get_alt_creds()
         tenant_fix.cleanUp()
         user_fix.cleanUp()
+        roles_fix.cleanUp()
         tenant_fix = self._mock_tenant_create('123456', 'fake_admin_tenant')
         user_fix = self._mock_user_create('123456', 'fake_admin_user')
-        self.useFixture(mockpatch.PatchObject(
-            json_iden_client.IdentityClientJSON,
-            'list_roles',
-            return_value=({'status': 200},
-                          [{'id': '123456', 'name': 'admin'}])))
-        with mock.patch.object(json_iden_client.IdentityClientJSON,
-                               'assign_user_role'):
-            iso_creds.get_admin_creds()
+        self._mock_list_roles('123456', 'admin')
+        iso_creds.get_admin_creds()
         user_mock = self.patch(
             'tempest.services.identity.json.identity_client.'
             'IdentityClientJSON.delete_user')
@@ -207,6 +233,8 @@
         cfg.CONF.set_default('neutron', False, 'service_available')
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_user_create('1234', 'fake_alt_user')
         self._mock_tenant_create('1234', 'fake_alt_tenant')
         alt_creds = iso_creds.get_alt_creds()
@@ -220,6 +248,8 @@
     def test_network_creation(self, MockRestClient):
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_user_create('1234', 'fake_prim_user')
         self._mock_tenant_create('1234', 'fake_prim_tenant')
         self._mock_network_create(iso_creds, '1234', 'fake_net')
@@ -245,6 +275,8 @@
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
         # Create primary tenant and network
+        self._mock_assign_user_role()
+        roles_fix = self._mock_list_role()
         user_fix = self._mock_user_create('1234', 'fake_prim_user')
         tenant_fix = self._mock_tenant_create('1234', 'fake_prim_tenant')
         net_fix = self._mock_network_create(iso_creds, '1234', 'fake_net')
@@ -276,6 +308,7 @@
         net_fix.cleanUp()
         subnet_fix.cleanUp()
         router_fix.cleanUp()
+        roles_fix.cleanUp()
         # Create admin tenant and networks
         user_fix = self._mock_user_create('123456', 'fake_admin_user')
         tenant_fix = self._mock_tenant_create('123456', 'fake_admin_tenant')
@@ -284,14 +317,8 @@
         subnet_fix = self._mock_subnet_create(iso_creds, '123456',
                                               'fake_admin_subnet')
         router_fix = self._mock_router_create('123456', 'fake_admin_router')
-        self.useFixture(mockpatch.PatchObject(
-            json_iden_client.IdentityClientJSON,
-            'list_roles',
-            return_value=({'status': 200},
-                          [{'id': '123456', 'name': 'admin'}])))
-        with mock.patch.object(json_iden_client.IdentityClientJSON,
-                               'assign_user_role'):
-            iso_creds.get_admin_creds()
+        self._mock_list_roles('123456', 'admin')
+        iso_creds.get_admin_creds()
         self.patch('tempest.services.identity.json.identity_client.'
                    'IdentityClientJSON.delete_user')
         self.patch('tempest.services.identity.json.identity_client.'
@@ -346,6 +373,8 @@
     def test_network_alt_creation(self, MockRestClient):
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_user_create('1234', 'fake_alt_user')
         self._mock_tenant_create('1234', 'fake_alt_tenant')
         self._mock_network_create(iso_creds, '1234', 'fake_alt_net')
@@ -370,6 +399,7 @@
     def test_network_admin_creation(self, MockRestClient):
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
+        self._mock_assign_user_role()
         self._mock_user_create('1234', 'fake_admin_user')
         self._mock_tenant_create('1234', 'fake_admin_tenant')
         self._mock_network_create(iso_creds, '1234', 'fake_admin_net')
@@ -378,14 +408,8 @@
         router_interface_mock = self.patch(
             'tempest.services.network.json.network_client.NetworkClientJSON.'
             'add_router_interface_with_subnet_id')
-        self.useFixture(mockpatch.PatchObject(
-            json_iden_client.IdentityClientJSON,
-            'list_roles',
-            return_value=({'status': 200},
-                          [{'id': '123456', 'name': 'admin'}])))
-        with mock.patch.object(json_iden_client.IdentityClientJSON,
-                               'assign_user_role'):
-            iso_creds.get_admin_creds()
+        self._mock_list_roles('123456', 'admin')
+        iso_creds.get_admin_creds()
         router_interface_mock.called_once_with('1234', '1234')
         network = iso_creds.get_admin_network()
         subnet = iso_creds.get_admin_subnet()
@@ -408,6 +432,8 @@
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password',
                                                  network_resources=net_dict)
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_user_create('1234', 'fake_prim_user')
         self._mock_tenant_create('1234', 'fake_prim_tenant')
         net = mock.patch.object(iso_creds.network_admin_client,
@@ -442,6 +468,8 @@
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password',
                                                  network_resources=net_dict)
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_user_create('1234', 'fake_prim_user')
         self._mock_tenant_create('1234', 'fake_prim_tenant')
         self.assertRaises(exceptions.InvalidConfiguration,
@@ -458,6 +486,8 @@
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password',
                                                  network_resources=net_dict)
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_user_create('1234', 'fake_prim_user')
         self._mock_tenant_create('1234', 'fake_prim_tenant')
         self.assertRaises(exceptions.InvalidConfiguration,
@@ -474,6 +504,8 @@
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password',
                                                  network_resources=net_dict)
+        self._mock_assign_user_role()
+        self._mock_list_role()
         self._mock_user_create('1234', 'fake_prim_user')
         self._mock_tenant_create('1234', 'fake_prim_tenant')
         self.assertRaises(exceptions.InvalidConfiguration,
diff --git a/tempest/thirdparty/boto/test.py b/tempest/thirdparty/boto/test.py
index 4c39f78..d3cbc4b 100644
--- a/tempest/thirdparty/boto/test.py
+++ b/tempest/thirdparty/boto/test.py
@@ -56,8 +56,8 @@
     A_I_IMAGES_READY = all_read(ami_path, aki_path, ari_path)
     boto_logger = logging.getLogger('boto')
     level = boto_logger.logger.level
-    boto_logger.logger.setLevel(orig_logging.CRITICAL)  # suppress logging
-                                                        # for these
+    # suppress logging for boto
+    boto_logger.logger.setLevel(orig_logging.CRITICAL)
 
     def _cred_sub_check(connection_data):
         if not id_matcher.match(connection_data["aws_access_key_id"]):
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index b2eb18d..2c68d6b 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -20,7 +20,6 @@
 from tempest import config
 from tempest import exceptions
 from tempest.openstack.common import log as logging
-from tempest import test
 from tempest.thirdparty.boto import test as boto_test
 from tempest.thirdparty.boto.utils import s3
 from tempest.thirdparty.boto.utils import wait
@@ -80,10 +79,9 @@
             if state != "available":
                 for _image in cls.images.itervalues():
                     cls.ec2_client.deregister_image(_image["image_id"])
-                raise exceptions.EC2RegisterImageException(image_id=
-                                                           image["image_id"])
+                raise exceptions.EC2RegisterImageException(
+                    image_id=image["image_id"])
 
-    @test.attr(type='smoke')
     def test_run_idempotent_instances(self):
         # EC2 run instances idempotently
 
@@ -121,7 +119,6 @@
         _terminate_reservation(reservation_1, rcuk_1)
         _terminate_reservation(reservation_2, rcuk_2)
 
-    @test.attr(type='smoke')
     def test_run_stop_terminate_instance(self):
         # EC2 run, stop and terminate instance
         image_ami = self.ec2_client.get_image(self.images["ami"]
@@ -146,7 +143,6 @@
             instance.terminate()
         self.cancelResourceCleanUp(rcuk)
 
-    @test.attr(type='smoke')
     def test_run_stop_terminate_instance_with_tags(self):
         # EC2 run, stop and terminate instance with tags
         image_ami = self.ec2_client.get_image(self.images["ami"]
@@ -181,7 +177,10 @@
             instance.remove_tag('key1', value='value1')
 
         tags = self.ec2_client.get_all_tags()
-        self.assertEqual(len(tags), 0, str(tags))
+
+        # NOTE: Volume-attach and detach causes metadata (tags) to be created
+        # for the volume. So exclude them while asserting.
+        self.assertNotIn('key1', tags)
 
         for instance in reservation.instances:
             instance.stop()
@@ -193,7 +192,6 @@
             instance.terminate()
         self.cancelResourceCleanUp(rcuk)
 
-    @test.attr(type='smoke')
     def test_run_terminate_instance(self):
         # EC2 run, terminate immediately
         image_ami = self.ec2_client.get_image(self.images["ami"]
@@ -217,7 +215,6 @@
         else:
             self.assertNotEqual(instance.state, "running")
 
-    @test.attr(type='smoke')
     def test_compute_with_volumes(self):
         # EC2 1. integration test (not strict)
         image_ami = self.ec2_client.get_image(self.images["ami"]["image_id"])
diff --git a/tempest/thirdparty/boto/test_ec2_keys.py b/tempest/thirdparty/boto/test_ec2_keys.py
index dec0170..698e3e1 100644
--- a/tempest/thirdparty/boto/test_ec2_keys.py
+++ b/tempest/thirdparty/boto/test_ec2_keys.py
@@ -32,7 +32,6 @@
         cls.ec = cls.ec2_error_code
 
 # TODO(afazekas): merge create, delete, get test cases
-    @test.attr(type='smoke')
     def test_create_ec2_keypair(self):
         # EC2 create KeyPair
         key_name = data_utils.rand_name("keypair-")
@@ -42,7 +41,6 @@
                         self.client.get_key_pair(key_name)))
 
     @test.skip_because(bug="1072318")
-    @test.attr(type='smoke')
     def test_delete_ec2_keypair(self):
         # EC2 delete KeyPair
         key_name = data_utils.rand_name("keypair-")
@@ -50,7 +48,6 @@
         self.client.delete_key_pair(key_name)
         self.assertIsNone(self.client.get_key_pair(key_name))
 
-    @test.attr(type='smoke')
     def test_get_ec2_keypair(self):
         # EC2 get KeyPair
         key_name = data_utils.rand_name("keypair-")
@@ -59,7 +56,6 @@
         self.assertTrue(compare_key_pairs(keypair,
                         self.client.get_key_pair(key_name)))
 
-    @test.attr(type='smoke')
     def test_duplicate_ec2_keypair(self):
         # EC2 duplicate KeyPair
         key_name = data_utils.rand_name("keypair-")
diff --git a/tempest/thirdparty/boto/test_ec2_network.py b/tempest/thirdparty/boto/test_ec2_network.py
index d508c07..792dde3 100644
--- a/tempest/thirdparty/boto/test_ec2_network.py
+++ b/tempest/thirdparty/boto/test_ec2_network.py
@@ -26,7 +26,6 @@
 
     # Note(afazekas): these tests for things duable without an instance
     @test.skip_because(bug="1080406")
-    @test.attr(type='smoke')
     def test_disassociate_not_associated_floating_ip(self):
         # EC2 disassociate not associated floating ip
         ec2_codes = self.ec2_error_code
diff --git a/tempest/thirdparty/boto/test_ec2_security_groups.py b/tempest/thirdparty/boto/test_ec2_security_groups.py
index 86140ec..7d9bdab 100644
--- a/tempest/thirdparty/boto/test_ec2_security_groups.py
+++ b/tempest/thirdparty/boto/test_ec2_security_groups.py
@@ -14,7 +14,6 @@
 #    under the License.
 
 from tempest.common.utils import data_utils
-from tempest import test
 from tempest.thirdparty.boto import test as boto_test
 
 
@@ -25,7 +24,6 @@
         super(EC2SecurityGroupTest, cls).setUpClass()
         cls.client = cls.os.ec2api_client
 
-    @test.attr(type='smoke')
     def test_create_authorize_security_group(self):
         # EC2 Create, authorize/revoke security group
         group_name = data_utils.rand_name("securty_group-")
diff --git a/tempest/thirdparty/boto/test_ec2_volumes.py b/tempest/thirdparty/boto/test_ec2_volumes.py
index 12dea18..b50c6b0 100644
--- a/tempest/thirdparty/boto/test_ec2_volumes.py
+++ b/tempest/thirdparty/boto/test_ec2_volumes.py
@@ -15,7 +15,6 @@
 
 from tempest import config
 from tempest.openstack.common import log as logging
-from tempest import test
 from tempest.thirdparty.boto import test as boto_test
 
 CONF = config.CONF
@@ -40,7 +39,6 @@
         cls.client = cls.os.ec2api_client
         cls.zone = CONF.boto.aws_zone
 
-    @test.attr(type='smoke')
     def test_create_get_delete(self):
         # EC2 Create, get, delete Volume
         volume = self.client.create_volume(1, self.zone)
@@ -53,7 +51,6 @@
         self.client.delete_volume(volume.id)
         self.cancelResourceCleanUp(cuk)
 
-    @test.attr(type='smoke')
     def test_create_volume_from_snapshot(self):
         # EC2 Create volume from snapshot
         volume = self.client.create_volume(1, self.zone)
diff --git a/tempest/thirdparty/boto/test_s3_buckets.py b/tempest/thirdparty/boto/test_s3_buckets.py
index af6aa8b..3a8dc89 100644
--- a/tempest/thirdparty/boto/test_s3_buckets.py
+++ b/tempest/thirdparty/boto/test_s3_buckets.py
@@ -26,7 +26,6 @@
         cls.client = cls.os.s3_client
 
     @test.skip_because(bug="1076965")
-    @test.attr(type='smoke')
     def test_create_and_get_delete_bucket(self):
         # S3 Create, get and delete bucket
         bucket_name = data_utils.rand_name("s3bucket-")
diff --git a/tempest/thirdparty/boto/test_s3_ec2_images.py b/tempest/thirdparty/boto/test_s3_ec2_images.py
index d2300ee..389e25c 100644
--- a/tempest/thirdparty/boto/test_s3_ec2_images.py
+++ b/tempest/thirdparty/boto/test_s3_ec2_images.py
@@ -17,7 +17,6 @@
 
 from tempest.common.utils import data_utils
 from tempest import config
-from tempest import test
 from tempest.thirdparty.boto import test as boto_test
 from tempest.thirdparty.boto.utils import s3
 
@@ -48,7 +47,6 @@
                                cls.bucket_name)
         s3.s3_upload_dir(bucket, cls.materials_path)
 
-    @test.attr(type='smoke')
     def test_register_get_deregister_ami_image(self):
         # Register and deregister ami image
         image = {"name": data_utils.rand_name("ami-name-"),
diff --git a/tempest/thirdparty/boto/test_s3_objects.py b/tempest/thirdparty/boto/test_s3_objects.py
index 1ae46de..db3c1cf 100644
--- a/tempest/thirdparty/boto/test_s3_objects.py
+++ b/tempest/thirdparty/boto/test_s3_objects.py
@@ -18,7 +18,6 @@
 import boto.s3.key
 
 from tempest.common.utils import data_utils
-from tempest import test
 from tempest.thirdparty.boto import test as boto_test
 
 
@@ -29,7 +28,6 @@
         super(S3BucketsTest, cls).setUpClass()
         cls.client = cls.os.s3_client
 
-    @test.attr(type='smoke')
     def test_create_get_delete_object(self):
         # S3 Create, get and delete object
         bucket_name = data_utils.rand_name("s3bucket-")
diff --git a/test-requirements.txt b/test-requirements.txt
index b9c75c8..cd8154b 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,10 +1,10 @@
-hacking>=0.8.0,<0.9
+hacking>=0.9.2,<0.10
 # needed for doc build
-docutils==0.9.1
-sphinx>=1.2.1,<1.3
+sphinx>=1.1.2,!=1.2.0,<1.3
 python-subunit>=0.0.18
 oslosphinx
 mox>=0.5.3
 mock>=1.0
 coverage>=3.6
 oslotest
+stevedore>=0.14
diff --git a/tools/config/check_uptodate.sh b/tools/config/check_uptodate.sh
index 528bd5b..0f0d77e 100755
--- a/tools/config/check_uptodate.sh
+++ b/tools/config/check_uptodate.sh
@@ -16,6 +16,10 @@
 trap "rm -rf $TEMPDIR" EXIT
 
 tools/config/generate_sample.sh -b ./ -p ${PROJECT_NAME} -o ${TEMPDIR}
+if [ $? != 0 ]
+then
+    exit 1
+fi
 
 if ! diff -u ${TEMPDIR}/${CFGFILE_NAME} ${CFGFILE}
 then
diff --git a/tools/config/generate_sample.sh b/tools/config/generate_sample.sh
index 20ddfbb..d22b2f0 100755
--- a/tools/config/generate_sample.sh
+++ b/tools/config/generate_sample.sh
@@ -1,5 +1,15 @@
 #!/usr/bin/env bash
 
+# Generate sample configuration for your project.
+#
+# Aside from the command line flags, it also respects a config file which
+# should be named oslo.config.generator.rc and be placed in the same directory.
+#
+# You can then export the following variables:
+# TEMPEST_CONFIG_GENERATOR_EXTRA_MODULES: list of modules to interrogate for options.
+# TEMPEST_CONFIG_GENERATOR_EXTRA_LIBRARIES: list of libraries to discover.
+# TEMPEST_CONFIG_GENERATOR_EXCLUDED_FILES: list of files to remove from automatic listing.
+
 print_hint() {
     echo "Try \`${0##*/} --help' for more information." >&2
 }
@@ -95,6 +105,10 @@
     source "$RC_FILE"
 fi
 
+for filename in ${TEMPEST_CONFIG_GENERATOR_EXCLUDED_FILES}; do
+    FILES="${FILES[@]/$filename/}"
+done
+
 for mod in ${TEMPEST_CONFIG_GENERATOR_EXTRA_MODULES}; do
     MODULES="$MODULES -m $mod"
 done
@@ -111,6 +125,11 @@
 MODULEPATH=${MODULEPATH:-$DEFAULT_MODULEPATH}
 OUTPUTFILE=$OUTPUTDIR/$PACKAGENAME.conf.sample
 python -m $MODULEPATH $MODULES $LIBRARIES $FILES > $OUTPUTFILE
+if [ $? != 0 ]
+then
+    echo "Can not generate $OUTPUTFILE"
+    exit 1
+fi
 
 # Hook to allow projects to append custom config file snippets
 CONCAT_FILES=$(ls $BASEDIR/tools/config/*.conf.sample 2>/dev/null)
diff --git a/tools/config/oslo.config.generator.rc b/tools/config/oslo.config.generator.rc
new file mode 100644
index 0000000..303e156
--- /dev/null
+++ b/tools/config/oslo.config.generator.rc
@@ -0,0 +1 @@
+MODULEPATH=tempest.common.generate_sample_tempest
diff --git a/tools/generate_sample.sh b/tools/generate_sample.sh
deleted file mode 100755
index 9b312c9..0000000
--- a/tools/generate_sample.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-MODULEPATH=tempest.common.generate_sample_tempest tools/config/generate_sample.sh $@
diff --git a/tools/subunit-trace.py b/tools/subunit-trace.py
index 9bfefe1..8ad59bb 100755
--- a/tools/subunit-trace.py
+++ b/tools/subunit-trace.py
@@ -221,6 +221,14 @@
     return count
 
 
+def run_time():
+    runtime = 0.0
+    for k, v in RESULTS.items():
+        for test in v:
+            runtime += float(get_duration(test['timestamps']).strip('s'))
+    return runtime
+
+
 def worker_stats(worker):
     tests = RESULTS[worker]
     num_tests = len(tests)
@@ -230,7 +238,8 @@
 
 def print_summary(stream):
     stream.write("\n======\nTotals\n======\n")
-    stream.write("Run: %s\n" % count_tests('status', '.*'))
+    stream.write("Run: %s in %s sec.\n" % (count_tests('status', '.*'),
+                                           run_time()))
     stream.write(" - Passed: %s\n" % count_tests('status', 'success'))
     stream.write(" - Skipped: %s\n" % count_tests('status', 'skip'))
     stream.write(" - Failed: %s\n" % count_tests('status', 'fail'))
@@ -254,7 +263,7 @@
     parser = argparse.ArgumentParser()
     parser.add_argument('--no-failure-debug', '-n', action='store_true',
                         dest='print_failures', help='Disable printing failure '
-                        'debug infomation in realtime')
+                        'debug information in realtime')
     parser.add_argument('--fails', '-f', action='store_true',
                         dest='post_fails', help='Print failure debug '
                         'information after the stream is proccesed')
diff --git a/tox.ini b/tox.ini
index 6b4acc6..4f2465a 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,5 +1,5 @@
 [tox]
-envlist = pep8
+envlist = pep8,py27
 minversion = 1.6
 skipsdist = True
 
@@ -84,8 +84,12 @@
 deps = -r{toxinidir}/requirements.txt
        -r{toxinidir}/test-requirements.txt
 
+[testenv:docs]
+commands = python setup.py build_sphinx {posargs}
+deps = -r{toxinidir}/requirements.txt
+       -r{toxinidir}/test-requirements.txt
+
 [testenv:pep8]
-setenv = MODULEPATH=tempest.common.generate_sample_tempest
 commands =
    flake8 {posargs}
    {toxinidir}/tools/config/check_uptodate.sh
@@ -99,6 +103,8 @@
 
 [flake8]
 # E125 is a won't fix until https://github.com/jcrocholl/pep8/issues/126 is resolved.  For further detail see https://review.openstack.org/#/c/36788/
-ignore = E125,H404
+# H402 skipped because some docstrings aren't sentences
+# Skipped because of new hacking 0.9: H407,H405,H904,H305,E123,H307,E122,E129,E128
+ignore = E125,H402,H404,H407,H405,H904,H305,E123,H307,E122,E129,E128
 show-source = True
 exclude = .git,.venv,.tox,dist,doc,openstack,*egg