Merge "Security Groups  API Tests Enhancements"
diff --git a/HACKING.rst b/HACKING.rst
index 025bf74..e57b670 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -36,11 +36,11 @@
 
 In most cases the very first issue is the most important information.
 
-Try to avoid using ``try`` blocks in the test cases, both the ``except``
-and ``finally`` block could replace the original exception,
+Try to avoid using ``try`` blocks in the test cases, as both the ``except``
+and ``finally`` blocks could replace the original exception,
 when the additional operations leads to another exception.
 
-Just letting an exception to propagate, is not bad idea in a test case,
+Just letting an exception to propagate, is not a bad idea in a test case,
 at all.
 
 Try to avoid using any exception handling construct which can hide the errors
@@ -54,10 +54,10 @@
 exceptions and still ensure resources are correctly cleaned up if the
 test fails part way through.
 
-Use the ``self.assert*`` methods provided by the unit test framework
-the signal failures early.
+Use the ``self.assert*`` methods provided by the unit test framework.
+This signals the failures early on.
 
-Avoid using the ``self.fail`` alone, it's stack trace will signal
+Avoid using the ``self.fail`` alone, its stack trace will signal
 the ``self.fail`` line as the origin of the error.
 
 Avoid constructing complex boolean expressions for assertion.
@@ -69,7 +69,7 @@
 Most other assert method can include more information by default.
 For example ``self.assertIn`` can include the whole set.
 
-Recommended to use testtools matcher for more tricky assertion.
+It is recommended to use testtools matcher for the more tricky assertions.
 `[doc] <http://testtools.readthedocs.org/en/latest/for-test-authors.html#matchers>`_
 
 You can implement your own specific matcher as well.
@@ -77,8 +77,8 @@
 
 If the test case fails you can see the related logs and the information
 carried by the exception (exception class, backtrack and exception info).
-This and the service logs are your only guide to find the root cause of flaky
-issue.
+This and the service logs are your only guide to finding the root cause of flaky
+issues.
 
 Test cases are independent
 --------------------------
@@ -87,7 +87,7 @@
 
 Test cases MAY depend on commonly initialized resources/facilities, like
 credentials management, testresources and so on. These facilities, MUST be able
-to work even if just one ``test_method`` selected for execution.
+to work even if just one ``test_method`` is selected for execution.
 
 Service Tagging
 ---------------
@@ -213,8 +213,10 @@
 Sample Configuration File
 -------------------------
 The sample config file is autogenerated using a script. If any changes are made
-to the config variables in tempest then the sample config file must be
-regenerated. This can be done running the script: tools/generate_sample.sh
+to the config variables in tempest/config.py then the sample config file must be
+regenerated. This can be done running::
+
+  tox -egenconfig
 
 Unit Tests
 ----------
@@ -227,3 +229,48 @@
 
 2. The unit tests cannot use setUpClass, instead fixtures and testresources
    should be used for shared state between tests.
+
+
+.. _TestDocumentation:
+
+Test Documentation
+------------------
+For tests being added we need to require inline documentation in the form of
+docstings to explain what is being tested. In API tests for a new API a class
+level docstring should be added to an API reference doc. If one doesn't exist
+a TODO comment should be put indicating that the reference needs to be added.
+For individual API test cases a method level docstring should be used to
+explain the functionality being tested if the test name isn't descriptive
+enough. For example::
+
+    def test_get_role_by_id(self):
+        """Get a role by its id."""
+
+the docstring there is superfluous and shouldn't be added. but for a method
+like::
+
+    def test_volume_backup_create_get_detailed_list_restore_delete(self):
+        pass
+
+a docstring would be useful because while the test title is fairly descriptive
+the operations being performed are complex enough that a bit more explanation
+will help people figure out the intent of the test.
+
+For scenario tests a class level docstring describing the steps in the scenario
+is required. If there is more than one test case in the class individual
+docstrings for the workflow in each test methods can be used instead. A good
+example of this would be::
+
+    class TestVolumeBootPattern(manager.ScenarioTest):
+        """
+        This test case attempts to reproduce the following steps:
+
+         * Create in Cinder some bootable volume importing a Glance image
+         * Boot an instance from the bootable volume
+         * Write content to the volume
+         * Delete an instance and Boot a new instance from the volume
+         * Check written content in the instance
+         * Create a volume snapshot while the instance is running
+         * Boot an additional instance from the new snapshot based volume
+         * Check written content in the instance booted from snapshot
+        """
diff --git a/README.rst b/README.rst
index ea36619..5284bbf 100644
--- a/README.rst
+++ b/README.rst
@@ -79,8 +79,10 @@
 document. The etc/tempest.conf.sample attempts to be a self
 documenting version of the configuration.
 
-The sample config file is auto generated using the script:
-tools/generate_sample.sh
+To generate the sample tempest.conf file, run the following
+command from the top level of the tempest directory:
+
+  tox -egenconfig
 
 The most important pieces that are needed are the user ids, openstack
 endpoints, and basic flavors and images needed to run tests.
diff --git a/REVIEWING.rst b/REVIEWING.rst
index d6dc83e..74bd2ad 100644
--- a/REVIEWING.rst
+++ b/REVIEWING.rst
@@ -51,6 +51,15 @@
 whether to skip or not.
 
 
+Test Documentation
+------------------
+When a new test is being added refer to the :ref:`TestDocumentation` section in
+hacking to see if the requirements are being met. With the exception of a class
+level docstring linking to the API ref doc in the API tests and a docstring for
+scenario tests this is up to the reviewers discretion whether a docstring is
+required or not.
+
+
 When to approve
 ---------------
  * Every patch needs two +2s before being approved.
diff --git a/doc/source/cleanup.rst b/doc/source/cleanup.rst
new file mode 100644
index 0000000..acd016c
--- /dev/null
+++ b/doc/source/cleanup.rst
@@ -0,0 +1,5 @@
+--------------------------------
+Post Tempest Run Cleanup Utility
+--------------------------------
+
+.. automodule:: tempest.cmd.cleanup
\ No newline at end of file
diff --git a/doc/source/conf.py b/doc/source/conf.py
index bd4e553..daa293c 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -27,7 +27,6 @@
 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
 extensions = ['sphinx.ext.autodoc',
-              'sphinx.ext.intersphinx',
               'sphinx.ext.todo',
               'sphinx.ext.viewcode',
               'oslosphinx'
diff --git a/doc/source/index.rst b/doc/source/index.rst
index d3118ac..bc4fc46 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -29,6 +29,15 @@
    field_guide/thirdparty
    field_guide/unit_tests
 
+---------------------
+Command Documentation
+---------------------
+
+.. toctree::
+   :maxdepth: 1
+
+   cleanup
+
 ==================
 Indices and tables
 ==================
diff --git a/etc/accounts.yaml.sample b/etc/accounts.yaml.sample
index d191769..54fdcad 100644
--- a/etc/accounts.yaml.sample
+++ b/etc/accounts.yaml.sample
@@ -1,3 +1,7 @@
+# The number of accounts required can be estimated as CONCURRENCY x 2
+# Valid fields for credentials are defined in the descendants of
+# auth.Credentials - see KeystoneV[2|3]Credentials.CONF_ATTRIBUTES
+
 - username: 'user_1'
   tenant_name: 'test_tenant_1'
   password: 'test_password'
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index ef56ab3..13ee8fe 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -1,1163 +1,1125 @@
 [DEFAULT]
 
 #
-# Options defined in tempest.openstack.common.lockutils
+# From tempest.config
 #
 
 # Whether to disable inter-process locks (boolean value)
-#disable_process_locking=false
+#disable_process_locking = false
 
 # Directory to use for lock files. (string value)
-#lock_path=<None>
-
+#lock_path = <None>
 
 #
-# Options defined in tempest.openstack.common.log
+# From tempest.config
 #
 
-# Print debugging output (set logging level to DEBUG instead
-# of default WARNING level). (boolean value)
-#debug=false
+# Print debugging output (set logging level to DEBUG instead of
+# default WARNING level). (boolean value)
+#debug = false
 
-# Print more verbose output (set logging level to INFO instead
-# of default WARNING level). (boolean value)
-#verbose=false
+# Print more verbose output (set logging level to INFO instead of
+# default WARNING level). (boolean value)
+#verbose = false
 
-# Log output to standard error. (boolean value)
-#use_stderr=true
+#
+# From tempest.config
+#
 
-# 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.
+# 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)
-#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
-# value)
-#logging_debug_format_suffix=%(funcName)s %(pathname)s:%(lineno)d
-
-# 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,oslo.messaging=INFO,iso8601=WARN,requests.packages.urllib3.connectionpool=WARN,urllib3.connectionpool=WARN
-
-# Enables or disables publication of error events. (boolean
-# value)
-#publish_errors=false
-
-# Enables or disables fatal status of deprecations. (boolean
-# value)
-#fatal_deprecations=false
-
-# The format for an instance that is passed with the log
-# message. (string value)
-#instance_format="[instance: %(uuid)s] "
-
-# The format for an instance UUID that is passed with the log
-# message. (string value)
-#instance_uuid_format="[instance: %(uuid)s] "
-
-# 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>
+#log_config_append = <None>
 
-# DEPRECATED. A logging.Formatter log message format string
-# which may use any of the available logging.LogRecord
-# attributes. This option is deprecated.  Please use
-# logging_context_format_string and
-# logging_default_format_string instead. (string value)
-#log_format=<None>
+# Format string for %%(asctime)s in log records. Default: %(default)s
+# . (string value)
+#log_date_format = %Y-%m-%d %H:%M:%S
 
-# Format string for %%(asctime)s in log records. Default:
-# %(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
-# set, logging will go to stdout. (string value)
-# Deprecated group/name - [DEFAULT]/logfile
-#log_file=<None>
-
-# (Optional) The base directory used for relative --log-file
-# paths. (string value)
+# (Optional) The base directory used for relative --log-file paths.
+# (string value)
 # Deprecated group/name - [DEFAULT]/logdir
-#log_dir=<None>
+#log_dir = <None>
 
-# Use syslog for logging. Existing syslog format is DEPRECATED
-# during I, and will change in J to honor RFC5424. (boolean
-# value)
-#use_syslog=false
+# (Optional) Name of log file to output to. If no default is set,
+# logging will go to stdout. (string value)
+# Deprecated group/name - [DEFAULT]/logfile
+#log_file = <None>
 
-# (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
+# DEPRECATED. A logging.Formatter log message format string which may
+# use any of the available logging.LogRecord attributes. This option
+# is deprecated.  Please use logging_context_format_string and
+# logging_default_format_string instead. (string value)
+#log_format = <None>
 
 # Syslog facility to receive log lines. (string value)
-#syslog_log_facility=LOG_USER
+#syslog_log_facility = LOG_USER
+
+# Use syslog for logging. Existing syslog format is DEPRECATED during
+# I, and will change in J to honor RFC5424. (boolean value)
+#use_syslog = false
+
+# (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
+
+#
+# From tempest.config
+#
+
+# Log output to standard error. (boolean value)
+#use_stderr = true
+
+#
+# From tempest.config
+#
+
+# 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,websocket=WARN,keystonemiddleware=WARN,routes.middleware=WARN,stevedore=WARN
+
+# Enables or disables fatal status of deprecations. (boolean value)
+#fatal_deprecations = false
+
+# The format for an instance that is passed with the log message.
+# (string value)
+#instance_format = "[instance: %(uuid)s] "
+
+# The format for an instance UUID that is passed with the log message.
+# (string value)
+#instance_uuid_format = "[instance: %(uuid)s] "
+
+# 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
+
+# Data to append to log format when level is DEBUG. (string value)
+#logging_debug_format_suffix = %(funcName)s %(pathname)s:%(lineno)d
+
+# 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
+
+# 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
+
+# Enables or disables publication of error events. (boolean value)
+#publish_errors = false
 
 
 [auth]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# Path to the yaml file that contains the list of credentials
-# to use for running tests (string value)
-#test_accounts_file=etc/accounts.yaml
+# Allows test cases to create/destroy tenants and users. This option
+# requires that OpenStack Identity API admin credentials are known. If
+# false, isolated test cases and parallel execution, can still be
+# achieved configuring a list of test accounts (boolean value)
+# Deprecated group/name - [compute]/allow_tenant_isolation
+# Deprecated group/name - [orchestration]/allow_tenant_isolation
+#allow_tenant_isolation = false
+
+# If set to True it enables the Accounts provider, which locks
+# credentials to allow for parallel execution with pre-provisioned
+# accounts. It can only be used to run tests that ensure credentials
+# cleanup happens. It requires at least `2 * CONC` distinct accounts
+# configured in `test_accounts_file`, with CONC == the number of
+# concurrent test processes. (boolean value)
+#locking_credentials_provider = false
+
+# Path to the yaml file that contains the list of credentials to use
+# for running tests (string value)
+#test_accounts_file = etc/accounts.yaml
 
 
 [baremetal]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# Catalog type of the baremetal provisioning service (string
-# value)
-#catalog_type=baremetal
+# Timeout for Ironic node to completely provision (integer value)
+#active_timeout = 300
 
-# Whether the Ironic nova-compute driver is enabled (boolean
+# Timeout for association of Nova instance and Ironic node (integer
 # value)
-#driver_enabled=false
+#association_timeout = 30
+
+# Catalog type of the baremetal provisioning service (string value)
+#catalog_type = baremetal
 
 # Driver name which Ironic uses (string value)
-#driver=fake
+#driver = fake
 
-# The endpoint type to use for the baremetal provisioning
-# service (string value)
-#endpoint_type=publicURL
+# Whether the Ironic nova-compute driver is enabled (boolean value)
+#driver_enabled = false
 
-# Timeout for Ironic node to completely provision (integer
-# value)
-#active_timeout=300
-
-# Timeout for association of Nova instance and Ironic node
-# (integer value)
-#association_timeout=30
+# The endpoint type to use for the baremetal provisioning service
+# (string value)
+#endpoint_type = publicURL
 
 # Timeout for Ironic power transitions. (integer value)
-#power_timeout=60
+#power_timeout = 60
 
 # Timeout for unprovisioning an Ironic node. (integer value)
-#unprovision_timeout=60
+#unprovision_timeout = 60
 
 
 [boto]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# EC2 URL (string value)
-#ec2_url=http://localhost:8773/services/Cloud
-
-# S3 URL (string value)
-#s3_url=http://localhost:8080
-
-# AWS Secret Key (string value)
-#aws_secret=<None>
-
-# AWS Access Key (string value)
-#aws_access=<None>
-
-# AWS Zone for EC2 tests (string value)
-#aws_zone=nova
-
-# S3 Materials Path (string value)
-#s3_materials_path=/opt/stack/devstack/files/images/s3-materials/cirros-0.3.0
-
-# ARI Ramdisk Image manifest (string value)
-#ari_manifest=cirros-0.3.0-x86_64-initrd.manifest.xml
+# AKI Kernel Image manifest (string value)
+#aki_manifest = cirros-0.3.0-x86_64-vmlinuz.manifest.xml
 
 # AMI Machine Image manifest (string value)
-#ami_manifest=cirros-0.3.0-x86_64-blank.img.manifest.xml
+#ami_manifest = cirros-0.3.0-x86_64-blank.img.manifest.xml
 
-# AKI Kernel Image manifest (string value)
-#aki_manifest=cirros-0.3.0-x86_64-vmlinuz.manifest.xml
+# ARI Ramdisk Image manifest (string value)
+#ari_manifest = cirros-0.3.0-x86_64-initrd.manifest.xml
 
-# Instance type (string value)
-#instance_type=m1.tiny
+# AWS Access Key (string value)
+#aws_access = <None>
 
-# boto Http socket timeout (integer value)
-#http_socket_timeout=3
+# AWS Secret Key (string value)
+#aws_secret = <None>
 
-# boto num_retries on error (integer value)
-#num_retries=1
-
-# Status Change Timeout (integer value)
-#build_timeout=60
+# AWS Zone for EC2 tests (string value)
+#aws_zone = nova
 
 # Status Change Test Interval (integer value)
-#build_interval=1
+#build_interval = 1
+
+# Status Change Timeout (integer value)
+#build_timeout = 60
+
+# EC2 URL (string value)
+#ec2_url = http://localhost:8773/services/Cloud
+
+# boto Http socket timeout (integer value)
+#http_socket_timeout = 3
+
+# Instance type (string value)
+#instance_type = m1.tiny
+
+# boto num_retries on error (integer value)
+#num_retries = 1
+
+# S3 Materials Path (string value)
+#s3_materials_path = /opt/stack/devstack/files/images/s3-materials/cirros-0.3.0
+
+# S3 URL (string value)
+#s3_url = http://localhost:8080
 
 
 [cli]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# enable cli tests (boolean value)
-#enabled=true
+# directory where python client binaries are located (string value)
+#cli_dir = /usr/local/bin
 
-# directory where python client binaries are located (string
-# value)
-#cli_dir=/usr/local/bin
+# enable cli tests (boolean value)
+#enabled = true
 
 # Whether the tempest run location has access to the *-manage
-# commands. In a pure blackbox environment it will not.
-# (boolean value)
-#has_manage=true
+# commands. In a pure blackbox environment it will not. (boolean
+# value)
+#has_manage = true
 
 # Number of seconds to wait on a CLI timeout (integer value)
-#timeout=15
+#timeout = 15
 
 
 [compute]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# 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
-# admin credentials are known. (boolean value)
-#allow_tenant_isolation=false
+# Time in seconds between build status checks. (integer value)
+#build_interval = 1
+
+# Timeout in seconds to wait for an instance to build. (integer value)
+#build_timeout = 300
+
+# Catalog type of the Compute service. (string value)
+#catalog_type = compute
+
+# Catalog type of the Compute v3 service. (string value)
+#catalog_v3_type = computev3
+
+# The endpoint type to use for the compute service. (string value)
+#endpoint_type = publicURL
+
+# Name of the fixed network that is visible to all test tenants.
+# (string value)
+#fixed_network_name = private
+
+# Valid primary flavor to use in tests. (string value)
+#flavor_ref = 1
+
+# Valid secondary flavor to be used in tests. (string value)
+#flavor_ref_alt = 2
+
+# Unallocated floating IP range, which will be used to test the
+# floating IP bulk feature for CRUD operation. This block must not
+# overlap an existing floating IP pool. (string value)
+#floating_ip_range = 10.0.0.0/29
+
+# Password used to authenticate to an instance using the alternate
+# image. (string value)
+#image_alt_ssh_password = password
+
+# User name used to authenticate to an instance using the alternate
+# image. (string value)
+#image_alt_ssh_user = root
 
 # Valid primary image reference to be used in tests. This is a
 # required option (string value)
-#image_ref=<None>
+#image_ref = <None>
 
-# Valid secondary image reference to be used in tests. This is
-# a required option, but if only one image is available
-# duplicate the value of image_ref above (string value)
-#image_ref_alt=<None>
-
-# Valid primary flavor to use in tests. (string value)
-#flavor_ref=1
-
-# Valid secondary flavor to be used in tests. (string value)
-#flavor_ref_alt=2
-
-# User name used to authenticate to an instance. (string
-# value)
-#image_ssh_user=root
+# Valid secondary image reference to be used in tests. This is a
+# required option, but if only one image is available duplicate the
+# value of image_ref above (string value)
+#image_ref_alt = <None>
 
 # Password used to authenticate to an instance. (string value)
-#image_ssh_password=password
+#image_ssh_password = password
 
-# User name used to authenticate to an instance using the
-# alternate image. (string value)
-#image_alt_ssh_user=root
-
-# Password used to authenticate to an instance using the
-# alternate image. (string value)
-#image_alt_ssh_password=password
-
-# Time in seconds between build status checks. (integer value)
-#build_interval=1
-
-# Timeout in seconds to wait for an instance to build.
-# (integer value)
-#build_timeout=300
-
-# Should the tests ssh to instances? (boolean value)
-#run_ssh=false
-
-# Auth method used for authenticate to the instance. Valid
-# choices are: keypair, configured, adminpass. keypair: start
-# the servers with an ssh keypair. configured: use the
-# configured user and password. adminpass: use the injected
-# adminPass. disabled: avoid using ssh when it is an option.
-# (string value)
-#ssh_auth_method=keypair
-
-# How to connect to the instance? fixed: using the first ip
-# belongs the fixed network floating: creating and using a
-# floating ip (string value)
-#ssh_connect_method=fixed
-
-# User name used to authenticate to an instance. (string
-# value)
-#ssh_user=root
-
-# Timeout in seconds to wait for ping to succeed. (integer
-# value)
-#ping_timeout=120
-
-# Timeout in seconds to wait for authentication to succeed.
-# (integer value)
-#ssh_timeout=300
-
-# Additional wait time for clean state, when there is no OS-
-# EXT-STS extension available (integer value)
-#ready_wait=0
-
-# Timeout in seconds to wait for output from ssh channel.
-# (integer value)
-#ssh_channel_timeout=60
-
-# Visible fixed network name  (string value)
-#fixed_network_name=private
-
-# Network used for SSH connections. (string value)
-#network_for_ssh=public
+# User name used to authenticate to an instance. (string value)
+#image_ssh_user = root
 
 # IP version used for SSH connections. (integer value)
-#ip_version_for_ssh=4
+#ip_version_for_ssh = 4
 
-# Does SSH use Floating IPs? (boolean value)
-#use_floatingip_for_ssh=true
+# Network used for SSH connections. Ignored if
+# use_floatingip_for_ssh=true or run_ssh=false. (string value)
+#network_for_ssh = public
 
-# Catalog type of the Compute service. (string value)
-#catalog_type=compute
+# Path to a private key file for SSH access to remote hosts (string
+# value)
+#path_to_private_key = <None>
+
+# Timeout in seconds to wait for ping to succeed. (integer value)
+#ping_timeout = 120
+
+# Additional wait time for clean state, when there is no OS-EXT-STS
+# extension available (integer value)
+#ready_wait = 0
 
 # The compute region name to use. If empty, the value of
-# identity.region is used instead. If no such region is found
-# in the service catalog, the first found one is used. (string
+# identity.region is used instead. If no such region is found in the
+# service catalog, the first found one is used. (string value)
+#region =
+
+# Should the tests ssh to instances? (boolean value)
+#run_ssh = false
+
+# Time in seconds before a shelved instance is eligible 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. (integer value)
+#shelved_offload_time = 0
+
+# Auth method used for authenticate to the instance. Valid choices
+# are: keypair, configured, adminpass. keypair: start the servers with
+# an ssh keypair. configured: use the configured user and password.
+# adminpass: use the injected adminPass. disabled: avoid using ssh
+# when it is an option. (string value)
+#ssh_auth_method = keypair
+
+# Timeout in seconds to wait for output from ssh channel. (integer
 # value)
-#region=
+#ssh_channel_timeout = 60
 
-# The endpoint type to use for the compute service. (string
+# How to connect to the instance? fixed: using the first ip belongs
+# the fixed network floating: creating and using a floating ip (string
 # value)
-#endpoint_type=publicURL
+#ssh_connect_method = fixed
 
-# Catalog type of the Compute v3 service. (string value)
-#catalog_v3_type=computev3
+# Timeout in seconds to wait for authentication to succeed. (integer
+# value)
+#ssh_timeout = 300
 
-# Path to a private key file for SSH access to remote hosts
+# User name used to authenticate to an instance. (string value)
+#ssh_user = root
+
+# Does SSH use Floating IPs? (boolean value)
+#use_floatingip_for_ssh = true
+
+# Expected device name when a volume is attached to an instance
 # (string value)
-#path_to_private_key=<None>
-
-# Expected device name when a volume is attached to an
-# instance (string value)
-#volume_device_name=vdb
-
-# Time in seconds before a shelved instance is eligible 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.
-# (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
-# admin credentials are known. (boolean value)
-#allow_tenant_isolation=false
-
-# Time in seconds between build status checks. (integer value)
-#build_interval=1
+#volume_device_name = vdb
 
 
 [compute-admin]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# Administrative Username to use for Nova API requests.
-# (string value)
-#username=<None>
-
-# Administrative Tenant name to use for Nova API requests.
-# (string value)
-#tenant_name=<None>
+# Domain name for authentication as admin (Keystone V3).The same
+# domain applies to user and project (string value)
+#domain_name = <None>
 
 # API key to use when authenticating as admin. (string value)
-#password=<None>
+#password = <None>
 
-# Domain name for authentication as admin (Keystone V3).The
-# same domain applies to user and project (string value)
-#domain_name=<None>
+# Administrative Tenant name to use for Nova API requests. (string
+# value)
+#tenant_name = <None>
+
+# Administrative Username to use for Nova API requests. (string value)
+#username = <None>
 
 
 [compute-feature-enabled]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# If false, skip all nova v3 tests. (boolean value)
-#api_v3=false
+# A list of enabled compute extensions with a special entry all which
+# indicates every extension is enabled. Each extension should be
+# specified with alias name. Empty list indicates all extensions are
+# disabled (list value)
+#api_extensions = all
 
-# If false skip all v2 api tests with xml (boolean value)
-#xml_api_v2=true
+# If false, skip all nova v3 tests. (boolean value)
+#api_v3 = false
+
+# A list of enabled v3 extensions with a special entry all which
+# indicates every extension is enabled. Each extension should be
+# specified with alias name. Empty list indicates all extensions are
+# disabled (list value)
+#api_v3_extensions = all
+
+# Does the test environment block migration support cinder iSCSI
+# volumes (boolean value)
+#block_migrate_cinder_iscsi = false
+
+# Does the test environment use block devices for live migration
+# (boolean value)
+#block_migration_for_live_migration = false
+
+# Does the test environment support changing the admin password?
+# (boolean value)
+#change_password = false
+
+# Does the test environment support obtaining instance serial console
+# output? (boolean value)
+#console_output = true
 
 # If false, skip disk config tests (boolean value)
-#disk_config=true
+#disk_config = true
 
-# A list of enabled compute extensions with a special entry
-# all which indicates every extension is enabled. Each
-# extension should be specified with alias name. Empty list
-# indicates all extensions are disabled (list value)
-#api_extensions=all
-
-# A list of enabled v3 extensions with a special entry all
-# which indicates every extension is enabled. Each extension
-# should be specified with alias name. Empty list indicates
-# all extensions are disabled (list value)
-#api_v3_extensions=all
-
-# Does the test environment support changing the admin
-# password? (boolean value)
-#change_password=false
-
-# Does the test environment support obtaining instance serial
-# console output? (boolean value)
-#console_output=true
-
-# Does the test environment support resizing? (boolean value)
-#resize=false
-
-# Does the test environment support pausing? (boolean value)
-#pause=true
-
-# Does the test environment support shelving/unshelving?
-# (boolean value)
-#shelve=true
-
-# Does the test environment support suspend/resume? (boolean
-# value)
-#suspend=true
-
-# Does the test environment support live migration available?
-# (boolean value)
-#live_migration=false
-
-# Does the test environment use block devices for live
-# migration (boolean value)
-#block_migration_for_live_migration=false
-
-# Does the test environment block migration support cinder
-# iSCSI volumes (boolean value)
-#block_migrate_cinder_iscsi=false
-
-# Enable VNC console. This configuration value should be same
-# as [nova.vnc]->vnc_enabled in nova.conf (boolean value)
-#vnc_console=false
-
-# Enable Spice console. This configuration value should be
-# same as [nova.spice]->enabled in nova.conf (boolean value)
-#spice_console=false
-
-# Enable RDP console. This configuration value should be same
-# as [nova.rdp]->enabled in nova.conf (boolean value)
-#rdp_console=false
-
-# Does the test environment support instance rescue mode?
-# (boolean value)
-#rescue=true
-
-# Enables returning of the instance password by the relevant
-# server API calls such as create, rebuild or rescue. (boolean
-# value)
-#enable_instance_password=true
+# Enables returning of the instance password by the relevant server
+# API calls such as create, rebuild or rescue. (boolean value)
+#enable_instance_password = true
 
 # Does the test environment support dynamic network interface
 # attachment? (boolean value)
-#interface_attach=true
+#interface_attach = true
 
-# Does the test environment support creating snapshot images
-# of running instances? (boolean value)
-#snapshot=true
+# Does the test environment support live migration available? (boolean
+# value)
+#live_migration = true
+
+# Does the test environment support pausing? (boolean value)
+#pause = true
+
+# Enable RDP console. This configuration value should be same as
+# [nova.rdp]->enabled in nova.conf (boolean value)
+#rdp_console = false
+
+# Does the test environment support instance rescue mode? (boolean
+# value)
+#rescue = true
+
+# Does the test environment support resizing? (boolean value)
+#resize = false
+
+# Does the test environment support shelving/unshelving? (boolean
+# value)
+#shelve = true
+
+# Does the test environment support creating snapshot images of
+# running instances? (boolean value)
+#snapshot = true
+
+# Enable Spice console. This configuration value should be same as
+# [nova.spice]->enabled in nova.conf (boolean value)
+#spice_console = false
+
+# Does the test environment support suspend/resume? (boolean value)
+#suspend = true
+
+# Enable VNC console. This configuration value should be same as
+# [nova.vnc]->vnc_enabled in nova.conf (boolean value)
+#vnc_console = false
+
+# If false skip all v2 api tests with xml (boolean value)
+#xml_api_v2 = true
 
 
 [dashboard]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
 # Where the dashboard can be found (string value)
-#dashboard_url=http://localhost/
+#dashboard_url = http://localhost/
 
 # Login page for the dashboard (string value)
-#login_url=http://localhost/auth/login/
+#login_url = http://localhost/auth/login/
 
 
 [data_processing]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
 # Catalog type of the data processing service. (string value)
-#catalog_type=data_processing
+#catalog_type = data_processing
 
-# The endpoint type to use for the data processing service.
-# (string value)
-#endpoint_type=publicURL
+# The endpoint type to use for the data processing service. (string
+# value)
+#endpoint_type = publicURL
 
 
 [database]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
 # Catalog type of the Database service. (string value)
-#catalog_type=database
+#catalog_type = database
 
-# Valid primary flavor to use in database tests. (string
-# value)
-#db_flavor_ref=1
+# Current database version to use in database tests. (string value)
+#db_current_version = v1.0
 
-# Current database version to use in database tests. (string
-# value)
-#db_current_version=v1.0
+# Valid primary flavor to use in database tests. (string value)
+#db_flavor_ref = 1
 
 
 [debug]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
 # Enable diagnostic commands (boolean value)
-#enable=true
+#enable = true
 
-# A regex to determine which requests should be traced.  This
-# is a regex to match the caller for rest client requests to
-# be able to selectively trace calls out of specific classes
-# and methods. It largely exists for test development, and is
-# not expected to be used in a real deploy of tempest. This
-# will be matched against the discovered ClassName:method in
-# the test environment.  Expected values for this field are:
-# * ClassName:test_method_name - traces one test_method  *
-# ClassName:setUp(Class) - traces specific setup functions  *
-# ClassName:tearDown(Class) - traces specific teardown
-# functions  * ClassName:_run_cleanups - traces the cleanup
-# functions  If nothing is specified, this feature is not
-# enabled. To trace everything specify .* as the regex.
-# (string value)
-#trace_requests=
+# A regex to determine which requests should be traced.  This is a
+# regex to match the caller for rest client requests to be able to
+# selectively trace calls out of specific classes and methods. It
+# largely exists for test development, and is not expected to be used
+# in a real deploy of tempest. This will be matched against the
+# discovered ClassName:method in the test environment.  Expected
+# values for this field are:   * ClassName:test_method_name - traces
+# one test_method  * ClassName:setUp(Class) - traces specific setup
+# functions  * ClassName:tearDown(Class) - traces specific teardown
+# functions  * ClassName:_run_cleanups - traces the cleanup functions
+# If nothing is specified, this feature is not enabled. To trace
+# everything specify .* as the regex.  (string value)
+#trace_requests =
 
 
 [identity]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# Catalog type of the Identity service. (string value)
-#catalog_type=identity
-
-# Set to True if using self-signed SSL certificates. (boolean
-# value)
-#disable_ssl_certificate_validation=false
-
-# Full URI of the OpenStack Identity API (Keystone), v2
-# (string value)
-#uri=<None>
-
-# Full URI of the OpenStack Identity API (Keystone), v3
-# (string value)
-#uri_v3=<None>
-
-# Identity API version to be used for authentication for API
-# tests. (string value)
-#auth_version=v2
-
-# The identity region name to use. Also used as the other
-# services' region name unless they are set explicitly. If no
-# such region is found in the service catalog, the first found
-# one is used. (string value)
-#region=RegionOne
-
-# The endpoint type to use for the identity service. (string
-# value)
-#endpoint_type=publicURL
-
-# Username to use for Nova API requests. (string value)
-#username=<None>
-
-# Tenant name to use for Nova API requests. (string value)
-#tenant_name=<None>
-
-# Role required to administrate keystone. (string value)
-#admin_role=admin
-
-# API key to use when authenticating. (string value)
-#password=<None>
-
-# Domain name for authentication (Keystone V3).The same domain
+# Admin domain name for authentication (Keystone V3).The same domain
 # applies to user and project (string value)
-#domain_name=<None>
-
-# Username of alternate user to use for Nova API requests.
-# (string value)
-#alt_username=<None>
-
-# Alternate user's Tenant name to use for Nova API requests.
-# (string value)
-#alt_tenant_name=<None>
-
-# API key to use when authenticating as alternate user.
-# (string value)
-#alt_password=<None>
-
-# Alternate domain name for authentication (Keystone V3).The
-# same domain applies to user and project (string value)
-#alt_domain_name=<None>
-
-# Administrative Username to use for Keystone API requests.
-# (string value)
-#admin_username=<None>
-
-# Administrative Tenant name to use for Keystone API requests.
-# (string value)
-#admin_tenant_name=<None>
+#admin_domain_name = <None>
 
 # API key to use when authenticating as admin. (string value)
-#admin_password=<None>
+#admin_password = <None>
 
-# Admin domain name for authentication (Keystone V3).The same
+# Role required to administrate keystone. (string value)
+#admin_role = admin
+
+# Administrative Tenant name to use for Keystone API requests. (string
+# value)
+#admin_tenant_name = <None>
+
+# Administrative Username to use for Keystone API requests. (string
+# value)
+#admin_username = <None>
+
+# Alternate domain name for authentication (Keystone V3).The same
 # domain applies to user and project (string value)
-#admin_domain_name=<None>
+#alt_domain_name = <None>
+
+# API key to use when authenticating as alternate user. (string value)
+#alt_password = <None>
+
+# Alternate user's Tenant name to use for Nova API requests. (string
+# value)
+#alt_tenant_name = <None>
+
+# Username of alternate user to use for Nova API requests. (string
+# value)
+#alt_username = <None>
+
+# Identity API version to be used for authentication for API tests.
+# (string value)
+#auth_version = v2
+
+# Catalog type of the Identity service. (string value)
+#catalog_type = identity
+
+# Set to True if using self-signed SSL certificates. (boolean value)
+#disable_ssl_certificate_validation = false
+
+# Domain name for authentication (Keystone V3).The same domain applies
+# to user and project (string value)
+#domain_name = <None>
+
+# The endpoint type to use for the identity service. (string value)
+#endpoint_type = publicURL
+
+# API key to use when authenticating. (string value)
+#password = <None>
+
+# The identity region name to use. Also used as the other services'
+# region name unless they are set explicitly. If no such region is
+# found in the service catalog, the first found one is used. (string
+# value)
+#region = RegionOne
+
+# Tenant name to use for Nova API requests. (string value)
+#tenant_name = <None>
+
+# Full URI of the OpenStack Identity API (Keystone), v2 (string value)
+#uri = <None>
+
+# Full URI of the OpenStack Identity API (Keystone), v3 (string value)
+#uri_v3 = <None>
+
+# Username to use for Nova API requests. (string value)
+#username = <None>
 
 
 [identity-feature-enabled]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# Does the identity service have delegation and impersonation
-# enabled (boolean value)
-#trust=true
-
 # Is the v2 identity API enabled (boolean value)
-#api_v2=true
+#api_v2 = true
 
 # Is the v3 identity API enabled (boolean value)
-#api_v3=true
+#api_v3 = true
+
+# Does the identity service have delegation and impersonation enabled
+# (boolean value)
+#trust = true
+
+# If false, skip all identity api tests with xml (boolean value)
+#xml_api = false
 
 
 [image]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
 # Catalog type of the Image service. (string value)
-#catalog_type=image
+#catalog_type = image
 
-# The image region name to use. If empty, the value of
-# identity.region is used instead. If no such region is found
-# in the service catalog, the first found one is used. (string
-# value)
-#region=
-
-# The endpoint type to use for the image service. (string
-# value)
-#endpoint_type=publicURL
+# The endpoint type to use for the image service. (string value)
+#endpoint_type = publicURL
 
 # http accessible image (string value)
-#http_image=http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-uec.tar.gz
+#http_image = http://download.cirros-cloud.net/0.3.1/cirros-0.3.1-x86_64-uec.tar.gz
+
+# The image region name to use. If empty, the value of identity.region
+# is used instead. If no such region is found in the service catalog,
+# the first found one is used. (string value)
+#region =
 
 
 [image-feature-enabled]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# Is the v2 image API enabled (boolean value)
-#api_v2=true
-
 # Is the v1 image API enabled (boolean value)
-#api_v1=true
+#api_v1 = true
+
+# Is the v2 image API enabled (boolean value)
+#api_v2 = true
 
 
 [input-scenario]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# Matching images become parameters for scenario tests (string
+# Matching flavors become parameters for scenario tests (string value)
+#flavor_regex = ^m1.nano$
+
+# Matching images become parameters for scenario tests (string value)
+#image_regex = ^cirros-0.3.1-x86_64-uec$
+
+# SSH verification in tests is skippedfor matching images (string
 # value)
-#image_regex=^cirros-0.3.1-x86_64-uec$
+#non_ssh_image_regex = ^.*[Ww]in.*$
 
-# Matching flavors become parameters for scenario tests
-# (string value)
-#flavor_regex=^m1.nano$
+# List of user mapped to regex to matching image names. (string value)
+#ssh_user_regex = [["^.*[Cc]irros.*$", "root"]]
 
-# SSH verification in tests is skippedfor matching images
-# (string value)
-#non_ssh_image_regex=^.*[Ww]in.*$
 
-# List of user mapped to regex to matching image names.
-# (string value)
-#ssh_user_regex=[["^.*[Cc]irros.*$", "root"]]
+[messaging]
+
+#
+# From tempest.config
+#
+
+# Catalog type of the Messaging service. (string value)
+#catalog_type = messaging
+
+# The maximum grace period for a claim (integer value)
+#max_claim_grace = 43200
+
+# The maximum ttl for a claim (integer value)
+#max_claim_ttl = 43200
+
+# The maximum size of a message body (integer value)
+#max_message_size = 262144
+
+# The maximum ttl for a message (integer value)
+#max_message_ttl = 1209600
+
+# The maximum number of messages per claim (integer value)
+#max_messages_per_claim = 20
+
+# The maximum number of queue message per page when listing (or)
+# posting messages (integer value)
+#max_messages_per_page = 20
+
+# The maximum metadata size for a queue (integer value)
+#max_queue_metadata = 65536
+
+# The maximum number of queue records per page when listing queues
+# (integer value)
+#max_queues_per_page = 20
 
 
 [negative]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
 # Test generator class for all negative tests (string value)
-#test_generator=tempest.common.generator.negative_generator.NegativeTestGenerator
+#test_generator = tempest.common.generator.negative_generator.NegativeTestGenerator
 
 
 [network]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
+# Time in seconds between network operation status checks. (integer
+# value)
+#build_interval = 1
+
+# Timeout in seconds to wait for network operation to complete.
+# (integer value)
+#build_timeout = 300
+
 # Catalog type of the Neutron service. (string value)
-#catalog_type=network
+#catalog_type = network
+
+# List of dns servers whichs hould be used for subnet creation (list
+# value)
+#dns_servers = 8.8.8.8,8.8.4.4
+
+# The endpoint type to use for the network service. (string value)
+#endpoint_type = publicURL
+
+# Id of the public network that provides external connectivity (string
+# value)
+#public_network_id =
+
+# Id of the public router that provides external connectivity. This
+# should only be used when Neutron's 'allow_overlapping_ips' is set to
+# 'False' in neutron.conf. usually not needed past 'Grizzly' release
+# (string value)
+#public_router_id =
 
 # The network region name to use. If empty, the value of
-# identity.region is used instead. If no such region is found
-# in the service catalog, the first found one is used. (string
-# value)
-#region=
+# identity.region is used instead. If no such region is found in the
+# service catalog, the first found one is used. (string value)
+#region =
 
-# The endpoint type to use for the network service. (string
-# value)
-#endpoint_type=publicURL
-
-# The cidr block to allocate tenant ipv4 subnets from (string
-# value)
-#tenant_network_cidr=10.100.0.0/16
+# The cidr block to allocate tenant ipv4 subnets from (string value)
+#tenant_network_cidr = 10.100.0.0/16
 
 # The mask bits for tenant ipv4 subnets (integer value)
-#tenant_network_mask_bits=28
+#tenant_network_mask_bits = 28
 
-# The cidr block to allocate tenant ipv6 subnets from (string
-# value)
-#tenant_network_v6_cidr=2003::/64
+# The cidr block to allocate tenant ipv6 subnets from (string value)
+#tenant_network_v6_cidr = 2003::/48
 
 # The mask bits for tenant ipv6 subnets (integer value)
-#tenant_network_v6_mask_bits=96
+#tenant_network_v6_mask_bits = 64
 
-# Whether tenant network connectivity should be evaluated
-# directly (boolean value)
-#tenant_networks_reachable=false
-
-# Id of the public network that provides external connectivity
-# (string value)
-#public_network_id=
-
-# Id of the public router that provides external connectivity
-# (string value)
-#public_router_id=
-
-# Timeout in seconds to wait for network operation to
-# complete. (integer value)
-#build_timeout=300
-
-# Time in seconds between network operation status checks.
-# (integer value)
-#build_interval=1
-
-# List of dns servers whichs hould be used for subnet creation
-# (list value)
-#dns_servers=8.8.8.8,8.8.4.4
+# Whether tenant network connectivity should be evaluated directly
+# (boolean value)
+#tenant_networks_reachable = false
 
 
 [network-feature-enabled]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
+# A list of enabled network extensions with a special entry all which
+# indicates every extension is enabled. Empty list indicates all
+# extensions are disabled (list value)
+#api_extensions = all
+
 # Allow the execution of IPv6 tests (boolean value)
-#ipv6=true
+#ipv6 = true
 
-# A list of enabled network extensions with a special entry
-# all which indicates every extension is enabled. Empty list
-# indicates all extensions are disabled (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
 
-# 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
+# If false, skip all network api tests with xml (boolean value)
+#xml_api = false
 
 
 [object-storage]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
 # Catalog type of the Object-Storage service. (string value)
-#catalog_type=object-store
+#catalog_type = object-store
 
-# The object-storage region name to use. If empty, the value
-# of identity.region is used instead. If no such region is
-# found in the service catalog, the first found one is used.
-# (string value)
-#region=
+# Number of seconds to wait while looping to check the status of a
+# container to container synchronization (integer value)
+#container_sync_interval = 5
 
-# The endpoint type to use for the object-store service.
-# (string value)
-#endpoint_type=publicURL
+# Number of seconds to time on waiting for a container to container
+# synchronization complete. (integer value)
+#container_sync_timeout = 120
 
-# Number of seconds to time on waiting for a container to
-# container synchronization complete. (integer value)
-#container_sync_timeout=120
+# The endpoint type to use for the object-store service. (string
+# value)
+#endpoint_type = publicURL
 
-# Number of seconds to wait while looping to check the status
-# of a container to container synchronization (integer value)
-#container_sync_interval=5
+# Role to add to users created for swift tests to enable creating
+# containers (string value)
+#operator_role = Member
 
-# Role to add to users created for swift tests to enable
-# creating containers (string value)
-#operator_role=Member
+# The object-storage region name to use. If empty, the value of
+# identity.region is used instead. If no such region is found in the
+# service catalog, the first found one is used. (string value)
+#region =
 
 # User role that has reseller admin (string value)
-#reseller_admin_role=ResellerAdmin
+#reseller_admin_role = ResellerAdmin
 
 
 [object-storage-feature-enabled]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# A list of the enabled optional discoverable apis. A single
-# entry, all, indicates that all of these features are
-# expected to be enabled (list value)
-#discoverable_apis=all
+# Execute (old style) container-sync tests (boolean value)
+#container_sync = true
+
+# Execute discoverability tests (boolean value)
+#discoverability = true
+
+# A list of the enabled optional discoverable apis. A single entry,
+# all, indicates that all of these features are expected to be enabled
+# (list value)
+#discoverable_apis = all
+
+# Execute object-versioning tests (boolean value)
+#object_versioning = true
 
 
 [orchestration]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
+# Time in seconds between build status checks. (integer value)
+#build_interval = 1
+
+# Timeout in seconds to wait for a stack to build. (integer value)
+#build_timeout = 1200
+
 # Catalog type of the Orchestration service. (string value)
-#catalog_type=orchestration
+#catalog_type = orchestration
+
+# The endpoint type to use for the orchestration service. (string
+# value)
+#endpoint_type = publicURL
+
+# Name of heat-cfntools enabled image to use when launching test
+# instances. (string value)
+#image_ref = <None>
+
+# Instance type for tests. Needs to be big enough for a full OS plus
+# the test workload (string value)
+#instance_type = m1.micro
+
+# Name of existing keypair to launch servers with. (string value)
+#keypair_name = <None>
+
+# Value must match heat configuration of the same name. (integer
+# value)
+#max_resources_per_stack = 1000
+
+# Value must match heat configuration of the same name. (integer
+# value)
+#max_template_size = 524288
 
 # The orchestration region name to use. If empty, the value of
-# identity.region is used instead. If no such region is found
-# in the service catalog, the first found one is used. (string
-# value)
-#region=
-
-# The endpoint type to use for the orchestration service.
-# (string value)
-#endpoint_type=publicURL
-
-# Timeout in seconds to wait for a stack to build. (integer
-# value)
-#build_timeout=1200
-
-# Instance type for tests. Needs to be big enough for a full
-# OS plus the test workload (string value)
-#instance_type=m1.micro
-
-# Name of heat-cfntools enabled image to use when launching
-# test instances. (string value)
-#image_ref=<None>
-
-# Name of existing keypair to launch servers with. (string
-# value)
-#keypair_name=<None>
-
-# Value must match heat configuration of the same name.
-# (integer value)
-#max_template_size=524288
-
-# Value must match heat configuration of the same name.
-# (integer value)
-#max_resources_per_stack=1000
-
-
-[queuing]
-
-#
-# Options defined in tempest.config
-#
-
-# Catalog type of the Queuing service. (string value)
-#catalog_type=queuing
-
-# The maximum number of queue records per page when listing
-# 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
+# identity.region is used instead. If no such region is found in the
+# service catalog, the first found one is used. (string value)
+#region =
 
 
 [scenario]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
+# AKI image file name (string value)
+#aki_img_file = cirros-0.3.1-x86_64-vmlinuz
+
+# AMI image file name (string value)
+#ami_img_file = cirros-0.3.1-x86_64-blank.img
+
+# ARI image file name (string value)
+#ari_img_file = cirros-0.3.1-x86_64-initrd
+
+# Image container format (string value)
+#img_container_format = bare
+
 # Directory containing image files (string value)
-#img_dir=/opt/stack/new/devstack/files/images/cirros-0.3.1-x86_64-uec
+#img_dir = /opt/stack/new/devstack/files/images/cirros-0.3.1-x86_64-uec
+
+# Image disk format (string value)
+#img_disk_format = qcow2
 
 # Image file name (string value)
 # Deprecated group/name - [DEFAULT]/qcow2_img_file
-#img_file=cirros-0.3.1-x86_64-disk.img
+#img_file = cirros-0.3.1-x86_64-disk.img
 
-# Image disk format (string value)
-#img_disk_format=qcow2
-
-# Image container format (string value)
-#img_container_format=bare
-
-# AMI image file name (string value)
-#ami_img_file=cirros-0.3.1-x86_64-blank.img
-
-# ARI image file name (string value)
-#ari_img_file=cirros-0.3.1-x86_64-initrd
-
-# AKI image file name (string value)
-#aki_img_file=cirros-0.3.1-x86_64-vmlinuz
+# specifies how many resources to request at once. Used for large
+# operations testing. (integer value)
+#large_ops_number = 0
 
 # ssh username for the image file (string value)
-#ssh_user=cirros
-
-# specifies how many resources to request at once. Used for
-# large operations testing. (integer value)
-#large_ops_number=0
+#ssh_user = cirros
 
 
 [service_available]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# Whether or not cinder is expected to be available (boolean
+# Whether or not Ceilometer is expected to be available (boolean
 # value)
-#cinder=true
+#ceilometer = true
 
-# Whether or not neutron is expected to be available (boolean
-# value)
-#neutron=false
+# Whether or not cinder is expected to be available (boolean value)
+#cinder = true
 
-# Whether or not glance is expected to be available (boolean
-# value)
-#glance=true
+# Whether or not glance is expected to be available (boolean value)
+#glance = true
 
-# Whether or not swift is expected to be available (boolean
-# value)
-#swift=true
+# Whether or not Heat is expected to be available (boolean value)
+#heat = false
 
-# Whether or not nova is expected to be available (boolean
-# value)
-#nova=true
+# Whether or not Horizon is expected to be available (boolean value)
+#horizon = true
 
-# Whether or not Heat is expected to be available (boolean
-# value)
-#heat=false
+# Whether or not Ironic is expected to be available (boolean value)
+#ironic = false
 
-# Whether or not Ceilometer is expected to be available
-# (boolean value)
-#ceilometer=true
+# Whether or not neutron is expected to be available (boolean value)
+#neutron = false
 
-# Whether or not Horizon is expected to be available (boolean
-# value)
-#horizon=true
+# Whether or not nova is expected to be available (boolean value)
+#nova = true
 
-# Whether or not Sahara is expected to be available (boolean
-# value)
-#sahara=false
+# Whether or not Sahara is expected to be available (boolean value)
+#sahara = false
 
-# Whether or not Ironic is expected to be available (boolean
-# value)
-#ironic=false
+# Whether or not swift is expected to be available (boolean value)
+#swift = true
 
-# Whether or not Trove is expected to be available (boolean
-# value)
-#trove=false
+# Whether or not Trove is expected to be available (boolean value)
+#trove = false
 
-# Whether or not Zaqar is expected to be available (boolean
-# value)
-#zaqar=false
+# Whether or not Zaqar is expected to be available (boolean value)
+#zaqar = false
 
 
 [stress]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# Directory containing log files on the compute nodes (string
-# value)
-#nova_logdir=<None>
+# Controller host. (string value)
+#controller = <None>
 
-# Maximum number of instances to create during test. (integer
-# value)
-#max_instances=16
+# The number of threads created while stress test. (integer value)
+#default_thread_number_per_action = 4
+
+# Allows a full cleaning process after a stress test. Caution : this
+# cleanup will remove every objects of every tenant. (boolean value)
+#full_clean_stack = false
+
+# Prevent the cleaning (tearDownClass()) between each stress test run
+# if an exception occurs during this run. (boolean value)
+#leave_dirty_stack = false
+
+# time (in seconds) between log file error checks. (integer value)
+#log_check_interval = 60
+
+# Maximum number of instances to create during test. (integer value)
+#max_instances = 16
+
+# Directory containing log files on the compute nodes (string value)
+#nova_logdir = <None>
 
 # Controller host. (string value)
-#controller=<None>
-
-# Controller host. (string value)
-#target_controller=<None>
-
-# ssh user. (string value)
-#target_ssh_user=<None>
-
-# Path to private key. (string value)
-#target_private_key_path=<None>
+#target_controller = <None>
 
 # regexp for list of log files. (string value)
-#target_logfiles=<None>
+#target_logfiles = <None>
 
-# time (in seconds) between log file error checks. (integer
-# value)
-#log_check_interval=60
+# Path to private key. (string value)
+#target_private_key_path = <None>
 
-# The number of threads created while stress test. (integer
-# value)
-#default_thread_number_per_action=4
-
-# Prevent the cleaning (tearDownClass()) between each stress
-# test run if an exception occurs during this run. (boolean
-# value)
-#leave_dirty_stack=false
-
-# Allows a full cleaning process after a stress test. Caution
-# : this cleanup will remove every objects of every tenant.
-# (boolean value)
-#full_clean_stack=false
+# ssh user. (string value)
+#target_ssh_user = <None>
 
 
 [telemetry]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
 # Catalog type of the Telemetry service. (string value)
-#catalog_type=metering
+#catalog_type = metering
 
-# The endpoint type to use for the telemetry service. (string
+# The endpoint type to use for the telemetry service. (string value)
+#endpoint_type = publicURL
+
+# This variable is used as flag to enable notification tests (boolean
 # value)
-#endpoint_type=publicURL
-
-# This variable is used as flag to enable notification tests
-# (boolean value)
-#too_slow_to_test=true
+#too_slow_to_test = true
 
 
 [volume]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# Time in seconds between volume availability checks. (integer
+# Name of the backend1 (must be declared in cinder.conf) (string
 # value)
-#build_interval=1
+#backend1_name = BACKEND_1
 
-# Timeout in seconds to wait for a volume to becomeavailable.
+# Name of the backend2 (must be declared in cinder.conf) (string
+# value)
+#backend2_name = BACKEND_2
+
+# Time in seconds between volume availability checks. (integer value)
+#build_interval = 1
+
+# Timeout in seconds to wait for a volume to become available.
 # (integer value)
-#build_timeout=300
+#build_timeout = 300
 
 # Catalog type of the Volume Service (string value)
-#catalog_type=volume
+#catalog_type = volume
+
+# Disk format to use when copying a volume to image (string value)
+#disk_format = raw
+
+# The endpoint type to use for the volume service. (string value)
+#endpoint_type = publicURL
 
 # The volume region name to use. If empty, the value of
-# identity.region is used instead. If no such region is found
-# in the service catalog, the first found one is used. (string
+# identity.region is used instead. If no such region is found in the
+# service catalog, the first found one is used. (string value)
+#region =
+
+# Backend protocol to target when creating volume types (string value)
+#storage_protocol = iSCSI
+
+# Backend vendor to target when creating volume types (string value)
+#vendor_name = Open Source
+
+# Default size in GB for volumes created by volumes tests (integer
 # value)
-#region=
-
-# The endpoint type to use for the volume service. (string
-# value)
-#endpoint_type=publicURL
-
-# Name of the backend1 (must be declared in cinder.conf)
-# (string value)
-#backend1_name=BACKEND_1
-
-# Name of the backend2 (must be declared in cinder.conf)
-# (string value)
-#backend2_name=BACKEND_2
-
-# Backend protocol to target when creating volume types
-# (string value)
-#storage_protocol=iSCSI
-
-# Backend vendor to target when creating volume types (string
-# value)
-#vendor_name=Open Source
-
-# Disk format to use when copying a volume to image (string
-# value)
-#disk_format=raw
-
-# Default size in GB for volumes created by volumes tests
-# (integer value)
-#volume_size=1
+#volume_size = 1
 
 
 [volume-feature-enabled]
 
 #
-# Options defined in tempest.config
+# From tempest.config
 #
 
-# Runs Cinder multi-backend test (requires 2 backends)
-# (boolean value)
-#multi_backend=false
-
-# Runs Cinder volumes backup test (boolean value)
-#backup=true
-
-# Runs Cinder volume snapshot test (boolean value)
-#snapshot=true
-
-# A list of enabled volume extensions with a special entry all
-# which indicates every extension is enabled. Empty list
-# indicates all extensions are disabled (list value)
-#api_extensions=all
+# A list of enabled volume extensions with a special entry all which
+# indicates every extension is enabled. Empty list indicates all
+# extensions are disabled (list value)
+#api_extensions = all
 
 # Is the v1 volume API enabled (boolean value)
-#api_v1=true
+#api_v1 = true
 
 # Is the v2 volume API enabled (boolean value)
-#api_v2=true
+#api_v2 = true
 
+# Runs Cinder volumes backup test (boolean value)
+#backup = true
 
+# Runs Cinder multi-backend test (requires 2 backends) (boolean value)
+#multi_backend = false
+
+# Runs Cinder volume snapshot test (boolean value)
+#snapshot = true
diff --git a/openstack-common.conf b/openstack-common.conf
index a9a6b0b..5ae2089 100644
--- a/openstack-common.conf
+++ b/openstack-common.conf
@@ -1,7 +1,6 @@
 [DEFAULT]
 
 # The list of modules to copy from openstack-common
-module=config
 module=install_venv_common
 module=lockutils
 module=log
diff --git a/requirements.txt b/requirements.txt
index 9a3b74d..1e4c40b 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,26 +1,29 @@
+# The order of packages is significant, because pip processes them in the order
+# of appearance. Changing the order has an impact on the overall integration
+# process, which may cause wedges in the gate later.
 pbr>=0.6,!=0.7,<1.0
 anyjson>=0.3.3
 httplib2>=0.7.5
 jsonschema>=2.0.0,<3.0.0
-testtools>=0.9.34
+testtools>=0.9.36,!=1.2.0,!=1.4.0
 lxml>=2.3
-boto>=2.12.0,!=2.13.0
+boto>=2.32.1
 paramiko>=1.13.0
-netaddr>=0.7.6
+netaddr>=0.7.12
 python-ceilometerclient>=1.0.6
-python-glanceclient>=0.13.1
-python-keystoneclient>=0.9.0
-python-novaclient>=2.17.0
-python-neutronclient>=2.3.5,<3
-python-cinderclient>=1.0.7
+python-glanceclient>=0.14.0
+python-keystoneclient>=0.11.1
+python-novaclient>=2.18.0
+python-neutronclient>=2.3.6,<3
+python-cinderclient>=1.1.0
 python-heatclient>=0.2.9
-python-ironicclient
-python-saharaclient>=0.6.0
-python-swiftclient>=2.0.2
-testresources>=0.2.4
+python-ironicclient>=0.2.1
+python-saharaclient>=0.7.5
+python-swiftclient>=2.2.0
 testrepository>=0.0.18
-oslo.config>=1.2.1
+oslo.config>=1.4.0  # Apache-2.0
 six>=1.7.0
 iso8601>=0.1.9
 fixtures>=0.3.14
 testscenarios>=0.4
+tempest-lib
diff --git a/run_tests.sh b/run_tests.sh
index a12bf46..971f89b 100755
--- a/run_tests.sh
+++ b/run_tests.sh
@@ -103,8 +103,6 @@
       echo "Running flake8 without virtual env may miss OpenStack HACKING detection" >&2
   fi
   ${wrapper} flake8
-  export MODULEPATH=tempest.common.generate_sample_tempest
-  ${wrapper} tools/config/check_uptodate.sh
 }
 
 if [ $never_venv -eq 0 ]
diff --git a/setup.cfg b/setup.cfg
index 5c62710..90ea944 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,6 +1,6 @@
 [metadata]
 name = tempest
-version = 2
+version = 3
 summary = OpenStack Integration Testing
 description-file =
     README.rst
@@ -22,6 +22,10 @@
     verify-tempest-config = tempest.cmd.verify_tempest_config:main
     javelin2 = tempest.cmd.javelin:main
     run-tempest-stress = tempest.cmd.run_stress:main
+    tempest-cleanup = tempest.cmd.cleanup:main
+
+oslo.config.opts =
+    tempest.config = tempest.config:list_opts
 
 [build_sphinx]
 all_files = 1
diff --git a/tempest/api/baremetal/admin/base.py b/tempest/api/baremetal/admin/base.py
index 62edd10..3b12b8e 100644
--- a/tempest/api/baremetal/admin/base.py
+++ b/tempest/api/baremetal/admin/base.py
@@ -28,6 +28,10 @@
 # which has no external dependencies.
 SUPPORTED_DRIVERS = ['fake']
 
+# NOTE(jroll): resources must be deleted in a specific order, this list
+# defines the resource types to clean up, and the correct order.
+RESOURCE_TYPES = ['port', 'node', 'chassis']
+
 
 def creates(resource):
     """Decorator that adds resources to the appropriate cleanup list."""
@@ -49,8 +53,8 @@
     """Base class for Baremetal API tests."""
 
     @classmethod
-    def setUpClass(cls):
-        super(BaseBaremetalTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(BaseBaremetalTest, cls).resource_setup()
 
         if not CONF.service_available.ironic:
             skip_msg = ('%s skipped as Ironic is not available' % cls.__name__)
@@ -66,21 +70,22 @@
         mgr = clients.AdminManager()
         cls.client = mgr.baremetal_client
         cls.power_timeout = CONF.baremetal.power_timeout
-        cls.created_objects = {'chassis': set(),
-                               'port': set(),
-                               'node': set()}
+        cls.created_objects = {}
+        for resource in RESOURCE_TYPES:
+            cls.created_objects[resource] = set()
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         """Ensure that all created objects get destroyed."""
 
         try:
-            for resource, uuids in cls.created_objects.iteritems():
+            for resource in RESOURCE_TYPES:
+                uuids = cls.created_objects[resource]
                 delete_method = getattr(cls.client, 'delete_%s' % resource)
                 for u in uuids:
                     delete_method(u, ignore_errors=exc.NotFound)
         finally:
-            super(BaseBaremetalTest, cls).tearDownClass()
+            super(BaseBaremetalTest, cls).resource_cleanup()
 
     @classmethod
     @creates('chassis')
diff --git a/tempest/api/baremetal/admin/test_chassis.py b/tempest/api/baremetal/admin/test_chassis.py
index 254a969..6f83412 100644
--- a/tempest/api/baremetal/admin/test_chassis.py
+++ b/tempest/api/baremetal/admin/test_chassis.py
@@ -21,8 +21,8 @@
     """Tests for chassis."""
 
     @classmethod
-    def setUpClass(cls):
-        super(TestChassis, cls).setUpClass()
+    def resource_setup(cls):
+        super(TestChassis, cls).resource_setup()
         _, cls.chassis = cls.create_chassis()
 
     def _assertExpected(self, expected, actual):
@@ -75,3 +75,9 @@
                    description=new_description))
         _, chassis = self.client.show_chassis(uuid)
         self.assertEqual(chassis['description'], new_description)
+
+    @test.attr(type='smoke')
+    def test_chassis_node_list(self):
+        _, node = self.create_node(self.chassis['uuid'])
+        _, body = self.client.list_chassis_nodes(self.chassis['uuid'])
+        self.assertIn(node['uuid'], [n['uuid'] for n in body['nodes']])
diff --git a/tempest/api/baremetal/admin/test_drivers.py b/tempest/api/baremetal/admin/test_drivers.py
index 9e215dc..9d99295 100644
--- a/tempest/api/baremetal/admin/test_drivers.py
+++ b/tempest/api/baremetal/admin/test_drivers.py
@@ -22,9 +22,8 @@
 class TestDrivers(base.BaseBaremetalTest):
     """Tests for drivers."""
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(TestDrivers, cls).setUpClass()
+    def resource_setup(cls):
+        super(TestDrivers, cls).resource_setup()
         cls.driver_name = CONF.baremetal.driver
 
     @test.attr(type="smoke")
diff --git a/tempest/api/baremetal/admin/test_nodes.py b/tempest/api/baremetal/admin/test_nodes.py
index ab6aed3..41c12c6 100644
--- a/tempest/api/baremetal/admin/test_nodes.py
+++ b/tempest/api/baremetal/admin/test_nodes.py
@@ -13,6 +13,8 @@
 import six
 
 from tempest.api.baremetal.admin import base
+from tempest.common.utils import data_utils
+from tempest.common import waiters
 from tempest import exceptions as exc
 from tempest import test
 
@@ -33,6 +35,17 @@
                 self.assertIn(key, actual)
                 self.assertEqual(value, actual[key])
 
+    def _associate_node_with_instance(self):
+        self.client.set_node_power_state(self.node['uuid'], 'power off')
+        waiters.wait_for_bm_node_status(self.client, self.node['uuid'],
+                                        'power_state', 'power off')
+        instance_uuid = data_utils.rand_uuid()
+        self.client.update_node(self.node['uuid'],
+                                instance_uuid=instance_uuid)
+        self.addCleanup(self.client.update_node,
+                        uuid=self.node['uuid'], instance_uuid=None)
+        return instance_uuid
+
     @test.attr(type='smoke')
     def test_create_node(self):
         params = {'cpu_arch': 'x86_64',
@@ -63,6 +76,34 @@
                       [i['uuid'] for i in body['nodes']])
 
     @test.attr(type='smoke')
+    def test_list_nodes_association(self):
+        _, body = self.client.list_nodes(associated=True)
+        self.assertNotIn(self.node['uuid'],
+                         [n['uuid'] for n in body['nodes']])
+
+        self._associate_node_with_instance()
+
+        _, body = self.client.list_nodes(associated=True)
+        self.assertIn(self.node['uuid'], [n['uuid'] for n in body['nodes']])
+
+        _, body = self.client.list_nodes(associated=False)
+        self.assertNotIn(self.node['uuid'], [n['uuid'] for n in body['nodes']])
+
+    @test.attr(type='smoke')
+    def test_node_port_list(self):
+        _, port = self.create_port(self.node['uuid'],
+                                   data_utils.rand_mac_address())
+        _, body = self.client.list_node_ports(self.node['uuid'])
+        self.assertIn(port['uuid'],
+                      [p['uuid'] for p in body['ports']])
+
+    @test.attr(type='smoke')
+    def test_node_port_list_no_ports(self):
+        _, node = self.create_node(self.chassis['uuid'])
+        _, body = self.client.list_node_ports(node['uuid'])
+        self.assertEmpty(body['ports'])
+
+    @test.attr(type='smoke')
     def test_update_node(self):
         props = {'cpu_arch': 'x86_64',
                  'cpu_num': '12',
@@ -89,9 +130,7 @@
 
     @test.attr(type='smoke')
     def test_set_node_boot_device(self):
-        body = self.client.set_node_boot_device(self.node['uuid'], 'pxe')
-        # No content
-        self.assertEqual('', body)
+        self.client.set_node_boot_device(self.node['uuid'], 'pxe')
 
     @test.attr(type='smoke')
     def test_get_node_boot_device(self):
@@ -106,3 +145,24 @@
         body = self.client.get_node_supported_boot_devices(self.node['uuid'])
         self.assertIn('supported_boot_devices', body)
         self.assertTrue(isinstance(body['supported_boot_devices'], list))
+
+    @test.attr(type='smoke')
+    def test_get_console(self):
+        _, body = self.client.get_console(self.node['uuid'])
+        con_info = ['console_enabled', 'console_info']
+        for key in con_info:
+            self.assertIn(key, body)
+
+    @test.attr(type='smoke')
+    def test_set_console_mode(self):
+        self.client.set_console_mode(self.node['uuid'], True)
+
+        _, body = self.client.get_console(self.node['uuid'])
+        self.assertEqual(True, body['console_enabled'])
+
+    @test.attr(type='smoke')
+    def test_get_node_by_instance_uuid(self):
+        instance_uuid = self._associate_node_with_instance()
+        _, body = self.client.show_node_by_instance_uuid(instance_uuid)
+        self.assertEqual(len(body['nodes']), 1)
+        self.assertIn(self.node['uuid'], [n['uuid'] for n in body['nodes']])
diff --git a/tempest/api/baremetal/admin/test_nodestates.py b/tempest/api/baremetal/admin/test_nodestates.py
index 76f47f9..f4f8054 100644
--- a/tempest/api/baremetal/admin/test_nodestates.py
+++ b/tempest/api/baremetal/admin/test_nodestates.py
@@ -22,8 +22,8 @@
     """Tests for baremetal NodeStates."""
 
     @classmethod
-    def setUpClass(cls):
-        super(TestNodeStates, cls).setUpClass()
+    def resource_setup(cls):
+        super(TestNodeStates, cls).resource_setup()
         _, cls.chassis = cls.create_chassis()
         _, cls.node = cls.create_node(cls.chassis['uuid'])
 
diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py
index 4808601..3bdcfd6 100644
--- a/tempest/api/compute/admin/test_agents.py
+++ b/tempest/api/compute/admin/test_agents.py
@@ -27,8 +27,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(AgentsAdminTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(AgentsAdminTestJSON, cls).resource_setup()
         cls.client = cls.os_adm.agents_client
 
     def setUp(self):
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index 3485943..f33089c 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -29,8 +29,8 @@
     _host_key = 'OS-EXT-SRV-ATTR:host'
 
     @classmethod
-    def setUpClass(cls):
-        super(AggregatesAdminTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(AggregatesAdminTestJSON, cls).resource_setup()
         cls.client = cls.os_adm.aggregates_client
         cls.aggregate_name_prefix = 'test_aggregate_'
         cls.az_name_prefix = 'test_az_'
diff --git a/tempest/api/compute/admin/test_aggregates_negative.py b/tempest/api/compute/admin/test_aggregates_negative.py
index 690f2ab..ef6752b 100644
--- a/tempest/api/compute/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/admin/test_aggregates_negative.py
@@ -27,8 +27,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(AggregatesAdminNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(AggregatesAdminNegativeTestJSON, cls).resource_setup()
         cls.client = cls.os_adm.aggregates_client
         cls.user_client = cls.aggregates_client
         cls.aggregate_name_prefix = 'test_aggregate_'
diff --git a/tempest/api/compute/admin/test_availability_zone.py b/tempest/api/compute/admin/test_availability_zone.py
index 3a6de36..0a040d7 100644
--- a/tempest/api/compute/admin/test_availability_zone.py
+++ b/tempest/api/compute/admin/test_availability_zone.py
@@ -24,8 +24,8 @@
     _api_version = 3
 
     @classmethod
-    def setUpClass(cls):
-        super(AZAdminV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(AZAdminV3Test, cls).resource_setup()
         cls.client = cls.availability_zone_admin_client
 
     @test.attr(type='gate')
diff --git a/tempest/api/compute/admin/test_availability_zone_negative.py b/tempest/api/compute/admin/test_availability_zone_negative.py
index ce97491..ea157b3 100644
--- a/tempest/api/compute/admin/test_availability_zone_negative.py
+++ b/tempest/api/compute/admin/test_availability_zone_negative.py
@@ -24,8 +24,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(AZAdminNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(AZAdminNegativeTestJSON, cls).resource_setup()
         cls.non_adm_client = cls.availability_zone_client
 
     @test.attr(type=['negative', 'gate'])
diff --git a/tempest/api/compute/admin/test_fixed_ips.py b/tempest/api/compute/admin/test_fixed_ips.py
index 939f1a1..e7f269d 100644
--- a/tempest/api/compute/admin/test_fixed_ips.py
+++ b/tempest/api/compute/admin/test_fixed_ips.py
@@ -23,8 +23,8 @@
 class FixedIPsTestJson(base.BaseV2ComputeAdminTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(FixedIPsTestJson, cls).setUpClass()
+    def resource_setup(cls):
+        super(FixedIPsTestJson, cls).resource_setup()
         if CONF.service_available.neutron:
             msg = ("%s skipped as neutron is available" % cls.__name__)
             raise cls.skipException(msg)
diff --git a/tempest/api/compute/admin/test_fixed_ips_negative.py b/tempest/api/compute/admin/test_fixed_ips_negative.py
index 1caa246..8d6a7fc 100644
--- a/tempest/api/compute/admin/test_fixed_ips_negative.py
+++ b/tempest/api/compute/admin/test_fixed_ips_negative.py
@@ -23,8 +23,8 @@
 class FixedIPsNegativeTestJson(base.BaseV2ComputeAdminTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(FixedIPsNegativeTestJson, cls).setUpClass()
+    def resource_setup(cls):
+        super(FixedIPsNegativeTestJson, cls).resource_setup()
         if CONF.service_available.neutron:
             msg = ("%s skipped as neutron is available" % cls.__name__)
             raise cls.skipException(msg)
@@ -68,7 +68,10 @@
         # NOTE(maurosr): since this exercises the same code snippet, we do it
         # only for reserve action
         body = {"reserve": "None"}
-        self.assertRaises(exceptions.NotFound,
+        # NOTE(eliqiao): in Juno, the exception is NotFound, but in master, we
+        # change the error code to BadRequest, both exceptions should be
+        # accepted by tempest
+        self.assertRaises((exceptions.NotFound, exceptions.BadRequest),
                           self.client.reserve_fixed_ip,
                           "my.invalid.ip", body)
 
diff --git a/tempest/api/compute/admin/test_flavors.py b/tempest/api/compute/admin/test_flavors.py
index 18866e5..3307159 100644
--- a/tempest/api/compute/admin/test_flavors.py
+++ b/tempest/api/compute/admin/test_flavors.py
@@ -28,8 +28,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorsAdminTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorsAdminTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
             msg = "OS-FLV-EXT-DATA extension not enabled."
             raise cls.skipException(msg)
@@ -296,7 +296,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/admin/test_flavors_access.py b/tempest/api/compute/admin/test_flavors_access.py
index f2554ea..176a134 100644
--- a/tempest/api/compute/admin/test_flavors_access.py
+++ b/tempest/api/compute/admin/test_flavors_access.py
@@ -26,8 +26,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorsAccessTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorsAccessTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
             msg = "OS-FLV-EXT-DATA extension not enabled."
             raise cls.skipException(msg)
diff --git a/tempest/api/compute/admin/test_flavors_access_negative.py b/tempest/api/compute/admin/test_flavors_access_negative.py
index b636ccd..9cc2a92 100644
--- a/tempest/api/compute/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/admin/test_flavors_access_negative.py
@@ -29,8 +29,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorsAccessNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorsAccessNegativeTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
             msg = "OS-FLV-EXT-DATA extension not enabled."
             raise cls.skipException(msg)
diff --git a/tempest/api/compute/admin/test_flavors_extra_specs.py b/tempest/api/compute/admin/test_flavors_extra_specs.py
index 56daf96..c05abe2 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs.py
@@ -27,8 +27,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorsExtraSpecsTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorsExtraSpecsTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
             msg = "OS-FLV-EXT-DATA extension not enabled."
             raise cls.skipException(msg)
@@ -51,10 +51,10 @@
                                                     swap=swap, rxtx=rxtx)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         resp, body = cls.client.delete_flavor(cls.flavor['id'])
         cls.client.wait_for_resource_deletion(cls.flavor['id'])
-        super(FlavorsExtraSpecsTestJSON, cls).tearDownClass()
+        super(FlavorsExtraSpecsTestJSON, cls).resource_cleanup()
 
     @test.attr(type='gate')
     def test_flavor_set_get_update_show_unset_keys(self):
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 1e5695f..30adf73 100644
--- a/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/admin/test_flavors_extra_specs_negative.py
@@ -28,8 +28,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorsExtraSpecsNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorsExtraSpecsNegativeTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
             msg = "OS-FLV-EXT-DATA extension not enabled."
             raise cls.skipException(msg)
@@ -52,10 +52,10 @@
                                                     swap=swap, rxtx=rxtx)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         resp, body = cls.client.delete_flavor(cls.flavor['id'])
         cls.client.wait_for_resource_deletion(cls.flavor['id'])
-        super(FlavorsExtraSpecsNegativeTestJSON, cls).tearDownClass()
+        super(FlavorsExtraSpecsNegativeTestJSON, cls).resource_cleanup()
 
     @test.attr(type=['negative', 'gate'])
     def test_flavor_non_admin_set_keys(self):
diff --git a/tempest/api/compute/admin/test_flavors_negative.py b/tempest/api/compute/admin/test_flavors_negative.py
index eece096..5bc3d10 100644
--- a/tempest/api/compute/admin/test_flavors_negative.py
+++ b/tempest/api/compute/admin/test_flavors_negative.py
@@ -31,8 +31,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorsAdminNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorsAdminNegativeTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
             msg = "OS-FLV-EXT-DATA extension not enabled."
             raise cls.skipException(msg)
@@ -58,7 +58,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/admin/test_floating_ips_bulk.py b/tempest/api/compute/admin/test_floating_ips_bulk.py
index 16c2810..c1263ea 100644
--- a/tempest/api/compute/admin/test_floating_ips_bulk.py
+++ b/tempest/api/compute/admin/test_floating_ips_bulk.py
@@ -31,9 +31,8 @@
     """
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(FloatingIPsBulkAdminTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FloatingIPsBulkAdminTestJSON, cls).resource_setup()
         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)
diff --git a/tempest/api/compute/admin/test_hosts.py b/tempest/api/compute/admin/test_hosts.py
index e612566..bcae492 100644
--- a/tempest/api/compute/admin/test_hosts.py
+++ b/tempest/api/compute/admin/test_hosts.py
@@ -24,8 +24,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(HostsAdminTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(HostsAdminTestJSON, cls).resource_setup()
         cls.client = cls.os_adm.hosts_client
 
     @test.attr(type='gate')
diff --git a/tempest/api/compute/admin/test_hosts_negative.py b/tempest/api/compute/admin/test_hosts_negative.py
index 0f26e84..4111aba 100644
--- a/tempest/api/compute/admin/test_hosts_negative.py
+++ b/tempest/api/compute/admin/test_hosts_negative.py
@@ -25,8 +25,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(HostsAdminNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(HostsAdminNegativeTestJSON, cls).resource_setup()
         cls.client = cls.os_adm.hosts_client
         cls.non_admin_client = cls.os.hosts_client
 
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index 85b26a1..c51d0a5 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -24,8 +24,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(HypervisorAdminTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(HypervisorAdminTestJSON, cls).resource_setup()
         cls.client = cls.os_adm.hypervisor_client
 
     def _list_hypervisors(self):
diff --git a/tempest/api/compute/admin/test_hypervisor_negative.py b/tempest/api/compute/admin/test_hypervisor_negative.py
index 4ba8d30..d3804e8 100644
--- a/tempest/api/compute/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/admin/test_hypervisor_negative.py
@@ -28,8 +28,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(HypervisorAdminNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(HypervisorAdminNegativeTestJSON, cls).resource_setup()
         cls.client = cls.os_adm.hypervisor_client
         cls.non_adm_client = cls.hypervisor_client
 
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log.py b/tempest/api/compute/admin/test_instance_usage_audit_log.py
index 055a177..91f0b02 100644
--- a/tempest/api/compute/admin/test_instance_usage_audit_log.py
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log.py
@@ -23,8 +23,8 @@
 class InstanceUsageAuditLogTestJSON(base.BaseV2ComputeAdminTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(InstanceUsageAuditLogTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(InstanceUsageAuditLogTestJSON, cls).resource_setup()
         cls.adm_client = cls.os_adm.instance_usages_audit_log_client
 
     @test.attr(type='gate')
diff --git a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
index 6a5fc96..1af340d 100644
--- a/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
+++ b/tempest/api/compute/admin/test_instance_usage_audit_log_negative.py
@@ -24,8 +24,8 @@
 class InstanceUsageAuditLogNegativeTestJSON(base.BaseV2ComputeAdminTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(InstanceUsageAuditLogNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(InstanceUsageAuditLogNegativeTestJSON, cls).resource_setup()
         cls.adm_client = cls.os_adm.instance_usages_audit_log_client
 
     @test.attr(type=['negative', 'gate'])
diff --git a/tempest/api/compute/admin/test_migrations.py b/tempest/api/compute/admin/test_migrations.py
index 514f1fa..7ba05ef 100644
--- a/tempest/api/compute/admin/test_migrations.py
+++ b/tempest/api/compute/admin/test_migrations.py
@@ -24,8 +24,8 @@
 class MigrationsAdminTest(base.BaseV2ComputeAdminTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(MigrationsAdminTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(MigrationsAdminTest, cls).resource_setup()
         cls.client = cls.os_adm.migrations_client
 
     @test.attr(type='gate')
diff --git a/tempest/api/compute/admin/test_networks.py b/tempest/api/compute/admin/test_networks.py
index 032e2f5..75f3199 100644
--- a/tempest/api/compute/admin/test_networks.py
+++ b/tempest/api/compute/admin/test_networks.py
@@ -29,8 +29,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(NetworksTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(NetworksTest, cls).resource_setup()
         cls.client = cls.os_adm.networks_client
 
     def test_get_network(self):
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index d27d78b..701e1c2 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -34,8 +34,8 @@
         super(QuotasAdminTestJSON, self).setUp()
 
     @classmethod
-    def setUpClass(cls):
-        super(QuotasAdminTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(QuotasAdminTestJSON, cls).resource_setup()
         cls.adm_client = cls.os_adm.quotas_client
 
         # NOTE(afazekas): these test cases should always create and use a new
@@ -57,9 +57,9 @@
         resp, quota_set = self.adm_client.get_default_quota_set(
             self.demo_tenant_id)
         self.assertEqual(200, resp.status)
-        self.assertEqual(sorted(expected_quota_set),
-                         sorted(quota_set.keys()))
         self.assertEqual(quota_set['id'], self.demo_tenant_id)
+        for quota in expected_quota_set:
+            self.assertIn(quota, quota_set.keys())
 
     @test.attr(type='gate')
     def test_update_all_quota_resources_for_tenant(self):
@@ -79,10 +79,18 @@
             **new_quota_set)
 
         default_quota_set.pop('id')
+        # NOTE(PhilDay) The following is safe as we're not updating these
+        # two quota values yet.  Once the Nova change to add these is merged
+        # and the client updated to support them this can be removed
+        if 'server_groups' in default_quota_set:
+            default_quota_set.pop('server_groups')
+        if 'server_group_members' in default_quota_set:
+            default_quota_set.pop('server_group_members')
         self.addCleanup(self.adm_client.update_quota_set,
                         self.demo_tenant_id, **default_quota_set)
         self.assertEqual(200, resp.status)
-        self.assertEqual(new_quota_set, quota_set)
+        for quota in new_quota_set:
+            self.assertIn(quota, quota_set.keys())
 
     # TODO(afazekas): merge these test cases
     @test.attr(type='gate')
@@ -159,8 +167,8 @@
         super(QuotaClassesAdminTestJSON, self).setUp()
 
     @classmethod
-    def setUpClass(cls):
-        super(QuotaClassesAdminTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(QuotaClassesAdminTestJSON, cls).resource_setup()
         cls.adm_client = cls.os_adm.quota_classes_client
 
     def _restore_default_quotas(self, original_defaults):
diff --git a/tempest/api/compute/admin/test_quotas_negative.py b/tempest/api/compute/admin/test_quotas_negative.py
index 4afda03..a9ed7ce 100644
--- a/tempest/api/compute/admin/test_quotas_negative.py
+++ b/tempest/api/compute/admin/test_quotas_negative.py
@@ -25,8 +25,8 @@
     force_tenant_isolation = True
 
     @classmethod
-    def setUpClass(cls):
-        super(QuotasAdminNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(QuotasAdminNegativeTestJSON, cls).resource_setup()
         cls.client = cls.os.quotas_client
         cls.adm_client = cls.os_adm.quotas_client
         cls.sg_client = cls.security_groups_client
@@ -44,7 +44,6 @@
 
     # 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
@@ -58,9 +57,9 @@
 
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         cores=default_vcpu_quota)
-        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
+        self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
+                          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
@@ -74,9 +73,9 @@
 
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         ram=default_mem_quota)
-        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
+        self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
+                          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
@@ -89,7 +88,8 @@
                                          instances=instances_quota)
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         instances=default_instances_quota)
-        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
+        self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
+                          self.create_test_server)
 
     @test.skip_because(bug="1186354",
                        condition=CONF.service_available.neutron)
diff --git a/tempest/api/compute/admin/test_security_group_default_rules.py b/tempest/api/compute/admin/test_security_group_default_rules.py
index a07d270..4c0bd47 100644
--- a/tempest/api/compute/admin/test_security_group_default_rules.py
+++ b/tempest/api/compute/admin/test_security_group_default_rules.py
@@ -30,11 +30,10 @@
     @testtools.skipIf(CONF.service_available.neutron,
                       "Skip as this functionality is not yet "
                       "implemented in Neutron. Related Bug#1311500")
-    @test.safe_setup
-    def setUpClass(cls):
+    def resource_setup(cls):
         # A network and a subnet will be created for these tests
         cls.set_network_resources(network=True, subnet=True)
-        super(SecurityGroupDefaultRulesTest, cls).setUpClass()
+        super(SecurityGroupDefaultRulesTest, cls).resource_setup()
         cls.adm_client = cls.os_adm.security_group_default_rules_client
 
     def _create_security_group_default_rules(self, ip_protocol='tcp',
diff --git a/tempest/api/compute/admin/test_security_groups.py b/tempest/api/compute/admin/test_security_groups.py
index 004ce8f..40ae236 100644
--- a/tempest/api/compute/admin/test_security_groups.py
+++ b/tempest/api/compute/admin/test_security_groups.py
@@ -26,8 +26,8 @@
 class SecurityGroupsTestAdminJSON(base.BaseV2ComputeAdminTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(SecurityGroupsTestAdminJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(SecurityGroupsTestAdminJSON, cls).resource_setup()
         cls.adm_client = cls.os_adm.security_groups_client
         cls.client = cls.security_groups_client
 
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 49af645..47aaee3 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -26,9 +26,8 @@
     _host_key = 'OS-EXT-SRV-ATTR:host'
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(ServersAdminTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServersAdminTestJSON, cls).resource_setup()
         cls.client = cls.os_adm.servers_client
         cls.non_admin_client = cls.servers_client
         cls.flavors_client = cls.os_adm.flavors_client
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index f4d010e..9aa489c 100644
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -17,6 +17,7 @@
 import testtools
 
 from tempest.api.compute import base
+from tempest.common import tempest_fixtures as fixtures
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
@@ -32,8 +33,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(ServersAdminNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServersAdminNegativeTestJSON, cls).resource_setup()
         cls.client = cls.os_adm.servers_client
         cls.non_adm_client = cls.servers_client
         cls.flavors_client = cls.os_adm.flavors_client
@@ -54,11 +55,12 @@
             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):
+        # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
+        self.useFixture(fixtures.LockFixture('compute_quotas'))
         flavor_name = data_utils.rand_name("flavor-")
         flavor_id = self._get_unused_flavor_id()
         resp, quota_set = self.quotas_client.get_default_quota_set(
@@ -70,16 +72,17 @@
                                                              ram, vcpus, disk,
                                                              flavor_id)
         self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
-        self.assertRaises(exceptions.Unauthorized,
+        self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
                           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):
+        # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
+        self.useFixture(fixtures.LockFixture('compute_quotas'))
         flavor_name = data_utils.rand_name("flavor-")
         flavor_id = self._get_unused_flavor_id()
         ram = 512
@@ -91,7 +94,7 @@
                                                              ram, vcpus, disk,
                                                              flavor_id)
         self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
-        self.assertRaises(exceptions.Unauthorized,
+        self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
                           self.client.resize,
                           self.servers[0]['id'],
                           flavor_ref['id'])
diff --git a/tempest/api/compute/admin/test_services.py b/tempest/api/compute/admin/test_services.py
index 2feb825..76153e7 100644
--- a/tempest/api/compute/admin/test_services.py
+++ b/tempest/api/compute/admin/test_services.py
@@ -25,8 +25,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(ServicesAdminTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServicesAdminTestJSON, cls).resource_setup()
         cls.client = cls.os_adm.services_client
 
     @test.attr(type='gate')
diff --git a/tempest/api/compute/admin/test_services_negative.py b/tempest/api/compute/admin/test_services_negative.py
index c78d70d..5331097 100644
--- a/tempest/api/compute/admin/test_services_negative.py
+++ b/tempest/api/compute/admin/test_services_negative.py
@@ -24,8 +24,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(ServicesAdminNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServicesAdminNegativeTestJSON, cls).resource_setup()
         cls.client = cls.os_adm.services_client
         cls.non_admin_client = cls.services_client
 
diff --git a/tempest/api/compute/admin/test_simple_tenant_usage.py b/tempest/api/compute/admin/test_simple_tenant_usage.py
index f3a81d1..5d596ba 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage.py
@@ -23,8 +23,8 @@
 class TenantUsagesTestJSON(base.BaseV2ComputeAdminTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(TenantUsagesTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(TenantUsagesTestJSON, cls).resource_setup()
         cls.adm_client = cls.os_adm.tenant_usages_client
         cls.client = cls.os.tenant_usages_client
         cls.tenant_id = cls.client.tenant_id
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 1031b24..5e2c593 100644
--- a/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
+++ b/tempest/api/compute/admin/test_simple_tenant_usage_negative.py
@@ -23,8 +23,8 @@
 class TenantUsagesNegativeTestJSON(base.BaseV2ComputeAdminTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(TenantUsagesNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(TenantUsagesNegativeTestJSON, cls).resource_setup()
         cls.adm_client = cls.os_adm.tenant_usages_client
         cls.client = cls.os.tenant_usages_client
         cls.identity_client = cls._get_identity_admin_client()
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 47d1254..2f53a0b 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -19,6 +19,7 @@
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
+from tempest.openstack.common import excutils
 from tempest.openstack.common import log as logging
 import tempest.test
 
@@ -34,18 +35,18 @@
     force_tenant_isolation = False
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.set_network_resources()
-        super(BaseComputeTest, cls).setUpClass()
+        super(BaseComputeTest, cls).resource_setup()
         if getattr(cls, '_interface', None) == 'xml' and cls._api_version == 2:
             if not CONF.compute_feature_enabled.xml_api_v2:
                 raise cls.skipException('XML API is not enabled')
 
         # TODO(andreaf) WE should care also for the alt_manager here
         # but only once client lazy load in the manager is done
-        os = cls.get_client_manager()
+        cls.os = cls.get_client_manager()
+        cls.multi_user = cls.check_multi_user()
 
-        cls.os = os
         cls.build_interval = CONF.compute.build_interval
         cls.build_timeout = CONF.compute.build_timeout
         cls.ssh_user = CONF.compute.ssh_user
@@ -57,7 +58,6 @@
         cls.image_ssh_password = CONF.compute.image_ssh_password
         cls.servers = []
         cls.images = []
-        cls.multi_user = cls.get_multi_user()
         cls.security_groups = []
         cls.server_groups = []
 
@@ -72,6 +72,8 @@
             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
+            # NOTE(mriedem): os-networks is v2 API only
+            cls.networks_client = cls.os.networks_client
             cls.limits_client = cls.os.limits_client
             cls.volumes_extensions_client = cls.os.volumes_extensions_client
             cls.volumes_client = cls.os.volumes_client
@@ -117,41 +119,33 @@
             raise exceptions.InvalidConfiguration(message=msg)
 
     @classmethod
-    def get_multi_user(cls):
-        multi_user = True
-        # Determine if there are two regular users that can be
-        # used in testing. If the test cases are allowed to create
-        # users (config.compute.allow_tenant_isolation is true,
-        # then we allow multi-user.
-        if not CONF.compute.allow_tenant_isolation:
-            user1 = CONF.identity.username
-            user2 = CONF.identity.alt_username
-            if not user2 or user1 == user2:
-                multi_user = False
-            else:
-                user2_password = CONF.identity.alt_password
-                user2_tenant_name = CONF.identity.alt_tenant_name
-                if not user2_password or not user2_tenant_name:
-                    msg = ("Alternate user specified but not alternate "
-                           "tenant or password: alt_tenant_name=%s "
-                           "alt_password=%s"
-                           % (user2_tenant_name, user2_password))
-                    raise exceptions.InvalidConfiguration(msg)
-        return multi_user
+    def check_multi_user(cls):
+        # We have a list of accounts now, so just checking if the list is gt 2
+        if not cls.isolated_creds.is_multi_user():
+            msg = "Not enough users available for multi-user testing"
+            raise exceptions.InvalidConfiguration(msg)
+        return True
 
     @classmethod
     def clear_servers(cls):
+        LOG.debug('Clearing servers: %s', ','.join(
+            server['id'] for server in cls.servers))
         for server in cls.servers:
             try:
                 cls.servers_client.delete_server(server['id'])
-            except Exception:
+            except exceptions.NotFound:
+                # Something else already cleaned up the server, nothing to be
+                # worried about
                 pass
+            except Exception:
+                LOG.exception('Deleting server %s failed' % server['id'])
 
         for server in cls.servers:
             try:
                 cls.servers_client.wait_for_server_termination(server['id'])
             except Exception:
-                pass
+                LOG.exception('Waiting for deletion of server %s failed'
+                              % server['id'])
 
     @classmethod
     def server_check_teardown(cls):
@@ -175,6 +169,7 @@
 
     @classmethod
     def clear_images(cls):
+        LOG.debug('Clearing images: %s', ','.join(cls.images))
         for image_id in cls.images:
             try:
                 cls.images_client.delete_image(image_id)
@@ -186,6 +181,8 @@
 
     @classmethod
     def clear_security_groups(cls):
+        LOG.debug('Clearing security groups: %s', ','.join(
+            str(sg['id']) for sg in cls.security_groups))
         for sg in cls.security_groups:
             try:
                 resp, body =\
@@ -200,6 +197,7 @@
 
     @classmethod
     def clear_server_groups(cls):
+        LOG.debug('Clearing server groups: %s', ','.join(cls.server_groups))
         for server_group_id in cls.server_groups:
             try:
                 cls.client.delete_server_group(server_group_id)
@@ -211,13 +209,12 @@
                               server_group_id)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.clear_images()
         cls.clear_servers()
         cls.clear_security_groups()
-        cls.clear_isolated_creds()
         cls.clear_server_groups()
-        super(BaseComputeTest, cls).tearDownClass()
+        super(BaseComputeTest, cls).resource_cleanup()
 
     @classmethod
     def create_test_server(cls, **kwargs):
@@ -243,15 +240,16 @@
                 try:
                     cls.servers_client.wait_for_server_status(
                         server['id'], kwargs['wait_until'])
-                except Exception as ex:
-                    if ('preserve_server_on_error' not in kwargs
-                        or kwargs['preserve_server_on_error'] is False):
-                        for server in servers:
-                            try:
-                                cls.servers_client.delete_server(server['id'])
-                            except Exception:
-                                pass
-                    raise ex
+                except Exception:
+                    with excutils.save_and_reraise_exception():
+                        if ('preserve_server_on_error' not in kwargs
+                            or kwargs['preserve_server_on_error'] is False):
+                            for server in servers:
+                                try:
+                                    cls.servers_client.delete_server(
+                                        server['id'])
+                                except Exception:
+                                    pass
 
         cls.servers.extend(servers)
 
@@ -382,21 +380,16 @@
     _interface = "json"
 
     @classmethod
-    def setUpClass(cls):
-        super(BaseComputeAdminTest, cls).setUpClass()
-        if (CONF.compute.allow_tenant_isolation or
-            cls.force_tenant_isolation is True):
+    def resource_setup(cls):
+        super(BaseComputeAdminTest, cls).resource_setup()
+        try:
             creds = cls.isolated_creds.get_admin_creds()
-            cls.os_adm = clients.Manager(credentials=creds,
-                                         interface=cls._interface)
-        else:
-            try:
-                cls.os_adm = clients.ComputeAdminManager(
-                    interface=cls._interface)
-            except exceptions.InvalidCredentials:
-                msg = ("Missing Compute Admin API credentials "
-                       "in configuration.")
-                raise cls.skipException(msg)
+            cls.os_adm = clients.Manager(
+                credentials=creds, interface=cls._interface)
+        except NotImplementedError:
+            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)
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index c1c2d05..7beef23 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -24,8 +24,8 @@
     _min_ram = 'min_ram'
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorsV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorsV3Test, cls).resource_setup()
         cls.client = cls.flavors_client
 
     @test.attr(type='smoke')
diff --git a/tempest/api/compute/flavors/test_flavors_negative.py b/tempest/api/compute/flavors/test_flavors_negative.py
index 7672fc6..cae1ac4 100644
--- a/tempest/api/compute/flavors/test_flavors_negative.py
+++ b/tempest/api/compute/flavors/test_flavors_negative.py
@@ -35,6 +35,6 @@
     _schema = flavors.flavors_details
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorDetailsNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorDetailsNegativeTestJSON, cls).resource_setup()
         cls.set_resource("flavor", cls.flavor_ref)
diff --git a/tempest/api/compute/flavors/test_flavors_negative_xml.py b/tempest/api/compute/flavors/test_flavors_negative_xml.py
index bf73c0e..299b18a 100644
--- a/tempest/api/compute/flavors/test_flavors_negative_xml.py
+++ b/tempest/api/compute/flavors/test_flavors_negative_xml.py
@@ -24,8 +24,8 @@
     _interface = 'xml'
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorsNegativeTestXML, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorsNegativeTestXML, cls).resource_setup()
         cls.client = cls.flavors_client
 
     @test.attr(type=['negative', 'gate'])
diff --git a/tempest/api/compute/floating_ips/base.py b/tempest/api/compute/floating_ips/base.py
index fd76e62..19b6a50 100644
--- a/tempest/api/compute/floating_ips/base.py
+++ b/tempest/api/compute/floating_ips/base.py
@@ -19,8 +19,8 @@
 class BaseFloatingIPsTest(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         # Floating IP actions might need a full network configuration
         cls.set_network_resources(network=True, subnet=True,
                                   router=True, dhcp=True)
-        super(BaseFloatingIPsTest, cls).setUpClass()
+        super(BaseFloatingIPsTest, cls).resource_setup()
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 1eae66f..3bb7d19 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -24,9 +24,8 @@
     floating_ip = None
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(FloatingIPsTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FloatingIPsTestJSON, cls).resource_setup()
         cls.client = cls.floating_ips_client
         cls.floating_ip_id = None
 
@@ -39,11 +38,11 @@
         cls.floating_ip = body['ip']
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         # Deleting the floating IP which is created in this method
         if cls.floating_ip_id:
             resp, body = cls.client.delete_floating_ip(cls.floating_ip_id)
-        super(FloatingIPsTestJSON, cls).tearDownClass()
+        super(FloatingIPsTestJSON, cls).resource_cleanup()
 
     def _try_delete_floating_ip(self, floating_ip_id):
         # delete floating ip, if it exists
@@ -131,7 +130,8 @@
 
         # Make sure no longer associated with old server
         self.assertRaises((exceptions.NotFound,
-                           exceptions.UnprocessableEntity),
+                           exceptions.UnprocessableEntity,
+                           exceptions.Conflict),
                           self.client.disassociate_floating_ip_from_server,
                           self.floating_ip, self.server_id)
 
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 042a19a..104d130 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
@@ -28,8 +28,8 @@
     server_id = None
 
     @classmethod
-    def setUpClass(cls):
-        super(FloatingIPsNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FloatingIPsNegativeTestJSON, cls).resource_setup()
         cls.client = cls.floating_ips_client
 
         # Server creation
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 a6878d9..cb93177 100644
--- a/tempest/api/compute/floating_ips/test_list_floating_ips.py
+++ b/tempest/api/compute/floating_ips/test_list_floating_ips.py
@@ -20,8 +20,8 @@
 class FloatingIPDetailsTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(FloatingIPDetailsTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FloatingIPDetailsTestJSON, cls).resource_setup()
         cls.client = cls.floating_ips_client
         cls.floating_ip = []
         cls.floating_ip_id = []
@@ -31,10 +31,10 @@
             cls.floating_ip_id.append(body['id'])
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         for i in range(3):
             cls.client.delete_floating_ip(cls.floating_ip_id[i])
-        super(FloatingIPDetailsTestJSON, cls).tearDownClass()
+        super(FloatingIPDetailsTestJSON, cls).resource_cleanup()
 
     @test.attr(type='gate')
     @test.services('network')
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 b11ef5b..08819c2 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
@@ -27,8 +27,8 @@
 class FloatingIPDetailsNegativeTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(FloatingIPDetailsNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FloatingIPDetailsNegativeTestJSON, cls).resource_setup()
         cls.client = cls.floating_ips_client
 
     @test.attr(type=['negative', 'gate'])
diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py
index 9036726..1fa591f 100644
--- a/tempest/api/compute/images/test_image_metadata.py
+++ b/tempest/api/compute/images/test_image_metadata.py
@@ -26,9 +26,8 @@
 class ImagesMetadataTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(ImagesMetadataTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ImagesMetadataTestJSON, cls).resource_setup()
         if not CONF.service_available.glance:
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
diff --git a/tempest/api/compute/images/test_image_metadata_negative.py b/tempest/api/compute/images/test_image_metadata_negative.py
index 15bb66a..7f0bc4e 100644
--- a/tempest/api/compute/images/test_image_metadata_negative.py
+++ b/tempest/api/compute/images/test_image_metadata_negative.py
@@ -22,8 +22,8 @@
 class ImagesMetadataTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ImagesMetadataTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ImagesMetadataTestJSON, cls).resource_setup()
         cls.client = cls.images_client
 
     @test.attr(type=['negative', 'gate'])
diff --git a/tempest/api/compute/images/test_images.py b/tempest/api/compute/images/test_images.py
index bbb887f..68f793a 100644
--- a/tempest/api/compute/images/test_images.py
+++ b/tempest/api/compute/images/test_images.py
@@ -23,8 +23,8 @@
 class ImagesTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ImagesTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ImagesTestJSON, cls).resource_setup()
         if not CONF.service_available.glance:
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
diff --git a/tempest/api/compute/images/test_images_negative.py b/tempest/api/compute/images/test_images_negative.py
index 771040b..e406374 100644
--- a/tempest/api/compute/images/test_images_negative.py
+++ b/tempest/api/compute/images/test_images_negative.py
@@ -24,8 +24,8 @@
 class ImagesNegativeTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ImagesNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ImagesNegativeTestJSON, cls).resource_setup()
         if not CONF.service_available.glance:
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
diff --git a/tempest/api/compute/images/test_images_oneserver.py b/tempest/api/compute/images/test_images_oneserver.py
index 187c0d4..459d78b 100644
--- a/tempest/api/compute/images/test_images_oneserver.py
+++ b/tempest/api/compute/images/test_images_oneserver.py
@@ -47,8 +47,8 @@
             self.__class__.server_id = self.rebuild_server(self.server_id)
 
     @classmethod
-    def setUpClass(cls):
-        super(ImagesOneServerTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ImagesOneServerTestJSON, cls).resource_setup()
         cls.client = cls.images_client
         if not CONF.service_available.glance:
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
@@ -59,12 +59,8 @@
                         % cls.__name__)
             raise cls.skipException(skip_msg)
 
-        try:
-            resp, server = cls.create_test_server(wait_until='ACTIVE')
-            cls.server_id = server['id']
-        except Exception:
-            cls.tearDownClass()
-            raise
+        resp, server = cls.create_test_server(wait_until='ACTIVE')
+        cls.server_id = server['id']
 
     def _get_default_flavor_disk_size(self, flavor_id):
         resp, flavor = self.flavors_client.get_flavor_details(flavor_id)
@@ -109,7 +105,11 @@
             raise self.skipException("Not testable in XML")
         # prefix character is:
         # http://www.fileformat.info/info/unicode/char/1F4A9/index.htm
-        utf8_name = data_utils.rand_name(u'\xF0\x9F\x92\xA9')
+
+        # We use a string with 3 byte utf-8 character due to bug
+        # #1370954 in glance which will 500 if mysql is used as the
+        # backend and it attempts to store a 4 byte utf-8 character
+        utf8_name = data_utils.rand_name('\xe2\x82\xa1')
         resp, body = self.client.create_image(self.server_id, utf8_name)
         image_id = data_utils.parse_image_id(resp['location'])
         self.addCleanup(self.client.delete_image, image_id)
diff --git a/tempest/api/compute/images/test_images_oneserver_negative.py b/tempest/api/compute/images/test_images_oneserver_negative.py
index 4e84e08..dc3d6bc 100644
--- a/tempest/api/compute/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/images/test_images_oneserver_negative.py
@@ -55,8 +55,8 @@
         self.__class__.server_id = self.rebuild_server(self.server_id)
 
     @classmethod
-    def setUpClass(cls):
-        super(ImagesOneServerNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ImagesOneServerNegativeTestJSON, cls).resource_setup()
         cls.client = cls.images_client
         if not CONF.service_available.glance:
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
@@ -67,28 +67,11 @@
                         % cls.__name__)
             raise cls.skipException(skip_msg)
 
-        try:
-            resp, server = cls.create_test_server(wait_until='ACTIVE')
-            cls.server_id = server['id']
-        except Exception:
-            cls.tearDownClass()
-            raise
+        resp, server = cls.create_test_server(wait_until='ACTIVE')
+        cls.server_id = server['id']
 
         cls.image_ids = []
 
-    @test.skip_because(bug="1006725")
-    @test.attr(type=['negative', 'gate'])
-    def test_create_image_specify_multibyte_character_image_name(self):
-        if self.__class__._interface == "xml":
-            raise self.skipException("Not testable in XML")
-        # invalid multibyte sequence from:
-        # http://stackoverflow.com/questions/1301402/
-        #     example-invalid-utf8-string
-        invalid_name = data_utils.rand_name(u'\xc3\x28')
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.create_image, self.server_id,
-                          invalid_name)
-
     @test.attr(type=['negative', 'gate'])
     def test_create_image_specify_invalid_metadata(self):
         # Return an error when creating image with invalid metadata
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index 68794b1..30a99dd 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -32,8 +32,8 @@
 class ListImageFiltersTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ListImageFiltersTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ListImageFiltersTestJSON, cls).resource_setup()
         if not CONF.service_available.glance:
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
@@ -69,33 +69,28 @@
             return
 
         # Create instances and snapshots via nova
-        try:
-            resp, cls.server1 = cls.create_test_server()
-            resp, cls.server2 = cls.create_test_server(wait_until='ACTIVE')
-            # NOTE(sdague) this is faster than doing the sync wait_util on both
-            cls.servers_client.wait_for_server_status(cls.server1['id'],
-                                                      'ACTIVE')
+        resp, cls.server1 = cls.create_test_server()
+        resp, cls.server2 = cls.create_test_server(wait_until='ACTIVE')
+        # NOTE(sdague) this is faster than doing the sync wait_util on both
+        cls.servers_client.wait_for_server_status(cls.server1['id'],
+                                                  'ACTIVE')
 
-            # Create images to be used in the filter tests
-            resp, cls.snapshot1 = cls.create_image_from_server(
-                cls.server1['id'], wait_until='ACTIVE')
-            cls.snapshot1_id = cls.snapshot1['id']
+        # Create images to be used in the filter tests
+        resp, cls.snapshot1 = cls.create_image_from_server(
+            cls.server1['id'], wait_until='ACTIVE')
+        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.snapshot3 = cls.create_image_from_server(
-                cls.server2['id'], wait_until='ACTIVE')
-            cls.snapshot3_id = cls.snapshot3['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.snapshot3 = cls.create_image_from_server(
+            cls.server2['id'], wait_until='ACTIVE')
+        cls.snapshot3_id = cls.snapshot3['id']
 
-            # Wait for the server to be active after the image upload
-            resp, cls.snapshot2 = cls.create_image_from_server(
-                cls.server1['id'], wait_until='ACTIVE')
-            cls.snapshot2_id = cls.snapshot2['id']
-        except Exception:
-            LOG.exception('setUpClass failed')
-            cls.tearDownClass()
-            raise
+        # Wait for the server to be active after the image upload
+        resp, cls.snapshot2 = cls.create_image_from_server(
+            cls.server1['id'], wait_until='ACTIVE')
+        cls.snapshot2_id = cls.snapshot2['id']
 
     @test.attr(type='gate')
     def test_list_images_filter_by_status(self):
diff --git a/tempest/api/compute/images/test_list_image_filters_negative.py b/tempest/api/compute/images/test_list_image_filters_negative.py
index 80d59a7..53a21a0 100644
--- a/tempest/api/compute/images/test_list_image_filters_negative.py
+++ b/tempest/api/compute/images/test_list_image_filters_negative.py
@@ -24,8 +24,8 @@
 class ListImageFiltersNegativeTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ListImageFiltersNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ListImageFiltersNegativeTestJSON, cls).resource_setup()
         if not CONF.service_available.glance:
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
diff --git a/tempest/api/compute/images/test_list_images.py b/tempest/api/compute/images/test_list_images.py
index eba331f..eceac82 100644
--- a/tempest/api/compute/images/test_list_images.py
+++ b/tempest/api/compute/images/test_list_images.py
@@ -23,8 +23,8 @@
 class ListImagesTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ListImagesTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ListImagesTestJSON, cls).resource_setup()
         if not CONF.service_available.glance:
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
diff --git a/tempest/api/compute/keypairs/test_keypairs.py b/tempest/api/compute/keypairs/test_keypairs.py
index 01979c0..2f0febf 100644
--- a/tempest/api/compute/keypairs/test_keypairs.py
+++ b/tempest/api/compute/keypairs/test_keypairs.py
@@ -23,8 +23,8 @@
     _api_version = 3
 
     @classmethod
-    def setUpClass(cls):
-        super(KeyPairsV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(KeyPairsV3Test, cls).resource_setup()
         cls.client = cls.keypairs_client
 
     def _delete_keypair(self, keypair_name):
diff --git a/tempest/api/compute/keypairs/test_keypairs_negative.py b/tempest/api/compute/keypairs/test_keypairs_negative.py
index a91a9c2..0da449b 100644
--- a/tempest/api/compute/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/keypairs/test_keypairs_negative.py
@@ -23,8 +23,8 @@
 class KeyPairsNegativeTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(KeyPairsNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(KeyPairsNegativeTestJSON, cls).resource_setup()
         cls.client = cls.keypairs_client
 
     def _create_keypair(self, keypair_name, pub_key=None):
diff --git a/tempest/api/compute/limits/test_absolute_limits.py b/tempest/api/compute/limits/test_absolute_limits.py
index d64fd57..bac1a39 100644
--- a/tempest/api/compute/limits/test_absolute_limits.py
+++ b/tempest/api/compute/limits/test_absolute_limits.py
@@ -20,8 +20,8 @@
 class AbsoluteLimitsTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(AbsoluteLimitsTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(AbsoluteLimitsTestJSON, cls).resource_setup()
         cls.client = cls.limits_client
 
     @test.attr(type='gate')
diff --git a/tempest/api/compute/limits/test_absolute_limits_negative.py b/tempest/api/compute/limits/test_absolute_limits_negative.py
index b2e2981..2b41ea0 100644
--- a/tempest/api/compute/limits/test_absolute_limits_negative.py
+++ b/tempest/api/compute/limits/test_absolute_limits_negative.py
@@ -21,8 +21,8 @@
 class AbsoluteLimitsNegativeTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(AbsoluteLimitsNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(AbsoluteLimitsNegativeTestJSON, cls).resource_setup()
         cls.client = cls.limits_client
         cls.server_client = cls.servers_client
 
diff --git a/tempest/api/compute/security_groups/base.py b/tempest/api/compute/security_groups/base.py
index 6838ce1..05cad9a 100644
--- a/tempest/api/compute/security_groups/base.py
+++ b/tempest/api/compute/security_groups/base.py
@@ -19,7 +19,7 @@
 class BaseSecurityGroupsTest(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         # A network and a subnet will be created for these tests
         cls.set_network_resources(network=True, subnet=True)
-        super(BaseSecurityGroupsTest, cls).setUpClass()
+        super(BaseSecurityGroupsTest, cls).resource_setup()
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 a1808dc..4fd5c02 100644
--- a/tempest/api/compute/security_groups/test_security_group_rules.py
+++ b/tempest/api/compute/security_groups/test_security_group_rules.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import six
+
 from tempest.api.compute.security_groups import base
 from tempest import config
 from tempest import test
@@ -23,10 +25,44 @@
 class SecurityGroupRulesTestJSON(base.BaseSecurityGroupsTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(SecurityGroupRulesTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(SecurityGroupRulesTestJSON, cls).resource_setup()
         cls.client = cls.security_groups_client
         cls.neutron_available = CONF.service_available.neutron
+        cls.ip_protocol = 'tcp'
+        cls.from_port = 22
+        cls.to_port = 22
+
+    def setUp(cls):
+        super(SecurityGroupRulesTestJSON, cls).setUp()
+
+        from_port = cls.from_port
+        to_port = cls.to_port
+        group = {}
+        ip_range = {}
+        if cls._interface == 'xml':
+            # NOTE: An XML response is different from the one of JSON
+            # like the following.
+            from_port = six.text_type(from_port)
+            to_port = six.text_type(to_port)
+            group = {'tenant_id': 'None', 'name': 'None'}
+            ip_range = {'cidr': 'None'}
+        cls.expected = {
+            'id': None,
+            'parent_group_id': None,
+            'ip_protocol': cls.ip_protocol,
+            'from_port': from_port,
+            'to_port': to_port,
+            'ip_range': ip_range,
+            'group': group
+        }
+
+    def _check_expected_response(self, actual_rule):
+        for key in self.expected:
+            if key == 'id':
+                continue
+            self.assertEqual(self.expected[key], actual_rule[key],
+                             "Miss-matched key is %s" % key)
 
     @test.attr(type='smoke')
     @test.services('network')
@@ -34,50 +70,68 @@
         # Positive test: Creation of Security Group rule
         # should be successful
         # Creating a Security Group to add rules to it
-        resp, security_group = self.create_security_group()
+        _, security_group = self.create_security_group()
         securitygroup_id = security_group['id']
         # Adding rules to the created Security Group
-        ip_protocol = 'tcp'
-        from_port = 22
-        to_port = 22
-        resp, rule = \
+        _, rule = \
             self.client.create_security_group_rule(securitygroup_id,
-                                                   ip_protocol,
-                                                   from_port,
-                                                   to_port)
-        self.addCleanup(self.client.delete_security_group_rule, rule['id'])
-        self.assertEqual(200, resp.status)
+                                                   self.ip_protocol,
+                                                   self.from_port,
+                                                   self.to_port)
+        self.expected['parent_group_id'] = securitygroup_id
+        self.expected['ip_range'] = {'cidr': '0.0.0.0/0'}
+        self._check_expected_response(rule)
 
     @test.attr(type='smoke')
     @test.services('network')
-    def test_security_group_rules_create_with_optional_arguments(self):
+    def test_security_group_rules_create_with_optional_cidr(self):
         # Positive test: Creation of Security Group rule
-        # with optional arguments
+        # with optional argument cidr
         # should be successful
 
-        secgroup1 = None
-        secgroup2 = None
         # Creating a Security Group to add rules to it
-        resp, security_group = self.create_security_group()
-        secgroup1 = security_group['id']
-        # Creating a Security Group so as to assign group_id to the rule
-        resp, security_group = self.create_security_group()
-        secgroup2 = security_group['id']
-        # Adding rules to the created Security Group with optional arguments
-        parent_group_id = secgroup1
-        ip_protocol = 'tcp'
-        from_port = 22
-        to_port = 22
+        _, security_group = self.create_security_group()
+        parent_group_id = security_group['id']
+
+        # Adding rules to the created Security Group with optional cidr
         cidr = '10.2.3.124/24'
-        group_id = secgroup2
-        resp, rule = \
+        _, rule = \
             self.client.create_security_group_rule(parent_group_id,
-                                                   ip_protocol,
-                                                   from_port,
-                                                   to_port,
-                                                   cidr=cidr,
+                                                   self.ip_protocol,
+                                                   self.from_port,
+                                                   self.to_port,
+                                                   cidr=cidr)
+        self.expected['parent_group_id'] = parent_group_id
+        self.expected['ip_range'] = {'cidr': cidr}
+        self._check_expected_response(rule)
+
+    @test.attr(type='smoke')
+    @test.services('network')
+    def test_security_group_rules_create_with_optional_group_id(self):
+        # Positive test: Creation of Security Group rule
+        # with optional argument group_id
+        # should be successful
+
+        # Creating a Security Group to add rules to it
+        _, security_group = self.create_security_group()
+        parent_group_id = security_group['id']
+
+        # Creating a Security Group so as to assign group_id to the rule
+        _, security_group = self.create_security_group()
+        group_id = security_group['id']
+        group_name = security_group['name']
+
+        # Adding rules to the created Security Group with optional group_id
+        _, rule = \
+            self.client.create_security_group_rule(parent_group_id,
+                                                   self.ip_protocol,
+                                                   self.from_port,
+                                                   self.to_port,
                                                    group_id=group_id)
-        self.assertEqual(200, resp.status)
+        self.expected['parent_group_id'] = parent_group_id
+        self.expected['group'] = {'tenant_id': self.client.tenant_id,
+                                  'name': group_name}
+        self._check_expected_response(rule)
 
     @test.attr(type='smoke')
     @test.services('network')
@@ -89,13 +143,11 @@
         securitygroup_id = security_group['id']
 
         # Add a first rule to the created Security Group
-        ip_protocol1 = 'tcp'
-        from_port1 = 22
-        to_port1 = 22
         resp, rule = \
             self.client.create_security_group_rule(securitygroup_id,
-                                                   ip_protocol1,
-                                                   from_port1, to_port1)
+                                                   self.ip_protocol,
+                                                   self.from_port,
+                                                   self.to_port)
         rule1_id = rule['id']
 
         # Add a second rule to the created Security Group
@@ -127,14 +179,11 @@
         resp, security_group = self.create_security_group()
         sg2_id = security_group['id']
         # Adding rules to the Group1
-        ip_protocol = 'tcp'
-        from_port = 22
-        to_port = 22
         resp, rule = \
             self.client.create_security_group_rule(sg1_id,
-                                                   ip_protocol,
-                                                   from_port,
-                                                   to_port,
+                                                   self.ip_protocol,
+                                                   self.from_port,
+                                                   self.to_port,
                                                    group_id=sg2_id)
 
         self.assertEqual(200, resp.status)
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 cfa839a..7850909 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
@@ -32,8 +32,8 @@
 class SecurityGroupRulesNegativeTestJSON(base.BaseSecurityGroupsTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(SecurityGroupRulesNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(SecurityGroupRulesNegativeTestJSON, cls).resource_setup()
         cls.client = cls.security_groups_client
 
     @test.attr(type=['negative', 'smoke'])
diff --git a/tempest/api/compute/security_groups/test_security_groups.py b/tempest/api/compute/security_groups/test_security_groups.py
index 860aebc..82dd4f0 100644
--- a/tempest/api/compute/security_groups/test_security_groups.py
+++ b/tempest/api/compute/security_groups/test_security_groups.py
@@ -22,8 +22,8 @@
 class SecurityGroupsTestJSON(base.BaseSecurityGroupsTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(SecurityGroupsTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(SecurityGroupsTestJSON, cls).resource_setup()
         cls.client = cls.security_groups_client
 
     @test.attr(type='smoke')
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 a9cca55..3101052 100644
--- a/tempest/api/compute/security_groups/test_security_groups_negative.py
+++ b/tempest/api/compute/security_groups/test_security_groups_negative.py
@@ -27,8 +27,8 @@
 class SecurityGroupsNegativeTestJSON(base.BaseSecurityGroupsTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(SecurityGroupsNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(SecurityGroupsNegativeTestJSON, cls).resource_setup()
         cls.client = cls.security_groups_client
         cls.neutron_available = CONF.service_available.neutron
 
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index d1192c0..d62d19f 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -26,14 +26,14 @@
 class AttachInterfacesTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.service_available.neutron:
             raise cls.skipException("Neutron is required")
         if not CONF.compute_feature_enabled.interface_attach:
             raise cls.skipException("Interface attachment is not available.")
         # This test class requires network and subnet
         cls.set_network_resources(network=True, subnet=True)
-        super(AttachInterfacesTestJSON, cls).setUpClass()
+        super(AttachInterfacesTestJSON, cls).resource_setup()
         cls.client = cls.os.interfaces_client
 
     def _check_interface(self, iface, port_id=None, network_id=None,
diff --git a/tempest/api/compute/servers/test_availability_zone.py b/tempest/api/compute/servers/test_availability_zone.py
index cf9837f..44bd7d3 100644
--- a/tempest/api/compute/servers/test_availability_zone.py
+++ b/tempest/api/compute/servers/test_availability_zone.py
@@ -24,8 +24,8 @@
     _api_version = 3
 
     @classmethod
-    def setUpClass(cls):
-        super(AZV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(AZV3Test, cls).resource_setup()
         cls.client = cls.availability_zone_client
 
     @test.attr(type='gate')
diff --git a/tempest/api/compute/servers/test_create_server.py b/tempest/api/compute/servers/test_create_server.py
index 279dc51..d954c01 100644
--- a/tempest/api/compute/servers/test_create_server.py
+++ b/tempest/api/compute/servers/test_create_server.py
@@ -31,9 +31,9 @@
     disk_config = 'AUTO'
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.prepare_instance_network()
-        super(ServersTestJSON, cls).setUpClass()
+        super(ServersTestJSON, cls).resource_setup()
         cls.meta = {'hello': 'world'}
         cls.accessIPv4 = '1.1.1.1'
         cls.accessIPv6 = '0000:0000:0000:0000:0000:babe:220.12.22.2'
@@ -42,6 +42,7 @@
         personality = [{'path': '/test.txt',
                        'contents': base64.b64encode(file_contents)}]
         cls.client = cls.servers_client
+        cls.network_client = cls.os.network_client
         cli_resp = cls.create_test_server(name=cls.name,
                                           meta=cls.meta,
                                           accessIPv4=cls.accessIPv4,
@@ -124,14 +125,73 @@
         self.assertEqual(200, resp.status)
         self.assertIn(server['id'], server_group['members'])
 
+    @testtools.skipUnless(CONF.service_available.neutron,
+                          'Neutron service must be available.')
+    def test_verify_multiple_nics_order(self):
+        if getattr(self, '_interface',
+                   None) == 'xml' and not CONF.network_feature_enabled.xml_api:
+            raise self.skipException('Neutron XML API is not enabled')
+        # Verify that the networks order given at the server creation is
+        # preserved within the server.
+        name_net1 = data_utils.rand_name(self.__class__.__name__)
+        _, net1 = self.network_client.create_network(name=name_net1)
+        self.addCleanup(self.network_client.delete_network,
+                        net1['network']['id'])
+
+        name_net2 = data_utils.rand_name(self.__class__.__name__)
+        _, net2 = self.network_client.create_network(name=name_net2)
+        self.addCleanup(self.network_client.delete_network,
+                        net2['network']['id'])
+
+        _, subnet1 = self.network_client.create_subnet(
+            network_id=net1['network']['id'],
+            cidr='19.80.0.0/24',
+            ip_version=4)
+        self.addCleanup(self.network_client.delete_subnet,
+                        subnet1['subnet']['id'])
+
+        _, subnet2 = self.network_client.create_subnet(
+            network_id=net2['network']['id'],
+            cidr='19.86.0.0/24',
+            ip_version=4)
+        self.addCleanup(self.network_client.delete_subnet,
+                        subnet2['subnet']['id'])
+
+        networks = [{'uuid': net1['network']['id']},
+                    {'uuid': net2['network']['id']}]
+
+        _, server_multi_nics = self.create_test_server(
+            networks=networks, wait_until='ACTIVE')
+
+        # Cleanup server; this is needed in the test case because with the LIFO
+        # nature of the cleanups, if we don't delete the server first, the port
+        # will still be part of the subnet and we'll get a 409 from Neutron
+        # when trying to delete the subnet. The tear down in the base class
+        # will try to delete the server and get a 404 but it's ignored so
+        # we're OK.
+        def cleanup_server():
+            self.client.delete_server(server_multi_nics['id'])
+            self.client.wait_for_server_termination(server_multi_nics['id'])
+
+        self.addCleanup(cleanup_server)
+
+        _, addresses = self.client.list_addresses(server_multi_nics['id'])
+
+        expected_addr = ['19.80.0.2', '19.86.0.2']
+
+        addr = [addresses[name_net1][0]['addr'],
+                addresses[name_net2][0]['addr']]
+
+        self.assertEqual(expected_addr, addr)
+
 
 class ServersWithSpecificFlavorTestJSON(base.BaseV2ComputeAdminTest):
     disk_config = 'AUTO'
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.prepare_instance_network()
-        super(ServersWithSpecificFlavorTestJSON, cls).setUpClass()
+        super(ServersWithSpecificFlavorTestJSON, cls).resource_setup()
         cls.flavor_client = cls.os_adm.flavors_client
         cls.client = cls.servers_client
 
@@ -214,11 +274,11 @@
     disk_config = 'MANUAL'
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.compute_feature_enabled.disk_config:
             msg = "DiskConfig extension not enabled."
             raise cls.skipException(msg)
-        super(ServersTestManualDisk, cls).setUpClass()
+        super(ServersTestManualDisk, cls).resource_setup()
 
 
 class ServersTestXML(ServersTestJSON):
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index 9c8271f..55931a4 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -28,8 +28,8 @@
     # for preventing "Quota exceeded for instances"
 
     @classmethod
-    def setUpClass(cls):
-        super(DeleteServersTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(DeleteServersTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
 
     @test.attr(type='gate')
@@ -70,6 +70,18 @@
         self.assertEqual('204', resp['status'])
         self.client.wait_for_server_termination(server['id'])
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
+                          'Suspend is not available.')
+    @test.attr(type='gate')
+    def test_delete_server_while_in_suspended_state(self):
+        # Delete a server while it's VM state is Suspended
+        _, server = self.create_test_server(wait_until='ACTIVE')
+        self.client.suspend_server(server['id'])
+        self.client.wait_for_server_status(server['id'], 'SUSPENDED')
+        resp, _ = self.client.delete_server(server['id'])
+        self.assertEqual('204', resp['status'])
+        self.client.wait_for_server_termination(server['id'])
+
     @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
                           'Shelve is not available.')
     @test.attr(type='gate')
@@ -104,6 +116,7 @@
         self.assertEqual('204', resp['status'])
         self.client.wait_for_server_termination(server['id'])
 
+    @test.services('volume')
     @test.attr(type='gate')
     def test_delete_server_while_in_attached_volume(self):
         # Delete a server while a volume is attached to it
@@ -130,8 +143,8 @@
     # for preventing "Quota exceeded for instances".
 
     @classmethod
-    def setUpClass(cls):
-        super(DeleteServersAdminTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(DeleteServersAdminTestJSON, cls).resource_setup()
         cls.non_admin_client = cls.servers_client
         cls.admin_client = cls.os_adm.servers_client
 
diff --git a/tempest/api/compute/servers/test_disk_config.py b/tempest/api/compute/servers/test_disk_config.py
index 332358c..51f2eb4 100644
--- a/tempest/api/compute/servers/test_disk_config.py
+++ b/tempest/api/compute/servers/test_disk_config.py
@@ -25,11 +25,11 @@
 class ServerDiskConfigTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.compute_feature_enabled.disk_config:
             msg = "DiskConfig extension not enabled."
             raise cls.skipException(msg)
-        super(ServerDiskConfigTestJSON, cls).setUpClass()
+        super(ServerDiskConfigTestJSON, cls).resource_setup()
         cls.client = cls.os.servers_client
         resp, server = cls.create_test_server(wait_until='ACTIVE')
         cls.server_id = server['id']
diff --git a/tempest/api/compute/servers/test_instance_actions.py b/tempest/api/compute/servers/test_instance_actions.py
index dd31165..d11ce25 100644
--- a/tempest/api/compute/servers/test_instance_actions.py
+++ b/tempest/api/compute/servers/test_instance_actions.py
@@ -20,8 +20,8 @@
 class InstanceActionsTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(InstanceActionsTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(InstanceActionsTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
         resp, server = cls.create_test_server(wait_until='ACTIVE')
         cls.request_id = resp['x-compute-request-id']
diff --git a/tempest/api/compute/servers/test_instance_actions_negative.py b/tempest/api/compute/servers/test_instance_actions_negative.py
index e67b69d..c706ad5 100644
--- a/tempest/api/compute/servers/test_instance_actions_negative.py
+++ b/tempest/api/compute/servers/test_instance_actions_negative.py
@@ -22,8 +22,8 @@
 class InstanceActionsNegativeTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(InstanceActionsNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(InstanceActionsNegativeTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
         resp, server = cls.create_test_server(wait_until='ACTIVE')
         cls.server_id = server['id']
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index 9d39c9f..e660f00 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -26,10 +26,9 @@
 class ListServerFiltersTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.set_network_resources(network=True, subnet=True, dhcp=True)
-        super(ListServerFiltersTestJSON, cls).setUpClass()
+        super(ListServerFiltersTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
 
         # Check to see if the alternate image ref actually exists...
@@ -70,12 +69,12 @@
         resp, cls.s3 = cls.create_test_server(name=cls.s3_name,
                                               flavor=cls.flavor_ref_alt,
                                               wait_until='ACTIVE')
-        if (CONF.service_available.neutron and
-                CONF.compute.allow_tenant_isolation):
-            network = cls.isolated_creds.get_primary_network()
-            cls.fixed_network_name = network['name']
-        else:
-            cls.fixed_network_name = CONF.compute.fixed_network_name
+
+        cls.fixed_network_name = CONF.compute.fixed_network_name
+        if CONF.service_available.neutron:
+            if hasattr(cls.isolated_creds, 'get_primary_network'):
+                network = cls.isolated_creds.get_primary_network()
+                cls.fixed_network_name = network['name']
 
     @utils.skip_unless_attr('multiple_images', 'Only one image found')
     @test.attr(type='gate')
@@ -234,6 +233,30 @@
         self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
 
     @test.attr(type='gate')
+    def test_list_servers_filtered_by_name_regex(self):
+        # list of regex that should match s1, s2 and s3
+        regexes = ['^.*\-instance\-[0-9]+$', '^.*\-instance\-.*$']
+        for regex in regexes:
+            params = {'name': regex}
+            resp, body = self.client.list_servers(params)
+            servers = body['servers']
+
+            self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
+            self.assertIn(self.s2_name, map(lambda x: x['name'], servers))
+            self.assertIn(self.s3_name, map(lambda x: x['name'], servers))
+
+        # Let's take random part of name and try to search it
+        part_name = self.s1_name[-10:]
+
+        params = {'name': part_name}
+        resp, body = self.client.list_servers(params)
+        servers = body['servers']
+
+        self.assertIn(self.s1_name, map(lambda x: x['name'], servers))
+        self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
+        self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
+
+    @test.attr(type='gate')
     def test_list_servers_filtered_by_ip(self):
         # Filter servers by ip
         # Here should be listed 1 server
diff --git a/tempest/api/compute/servers/test_list_servers_negative.py b/tempest/api/compute/servers/test_list_servers_negative.py
index 28d64fb..f4d8dda 100644
--- a/tempest/api/compute/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/servers/test_list_servers_negative.py
@@ -24,9 +24,8 @@
     force_tenant_isolation = True
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(ListServersNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ListServersNegativeTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
 
         # The following servers are created for use
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index fd6df3e..b51b46e 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -52,9 +52,9 @@
         super(ServerActionsTestJSON, self).tearDown()
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.prepare_instance_network()
-        super(ServerActionsTestJSON, cls).setUpClass()
+        super(ServerActionsTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
         cls.server_id = cls.rebuild_server(None)
 
@@ -75,9 +75,7 @@
                                                       new_password)
             linux_client.validate_authentication()
 
-    @test.attr(type='smoke')
-    def test_reboot_server_hard(self):
-        # The server should be power cycled
+    def _test_reboot_server(self, reboot_type):
         if self.run_ssh:
             # Get the time the server was last rebooted,
             resp, server = self.client.get_server(self.server_id)
@@ -85,7 +83,7 @@
                                                       self.password)
             boot_time = linux_client.get_boot_time()
 
-        resp, body = self.client.reboot(self.server_id, 'HARD')
+        resp, body = self.client.reboot(self.server_id, reboot_type)
         self.assertEqual(202, resp.status)
         self.client.wait_for_server_status(self.server_id, 'ACTIVE')
 
@@ -97,28 +95,16 @@
             self.assertTrue(new_boot_time > boot_time,
                             '%s > %s' % (new_boot_time, boot_time))
 
+    @test.attr(type='smoke')
+    def test_reboot_server_hard(self):
+        # The server should be power cycled
+        self._test_reboot_server('HARD')
+
     @test.skip_because(bug="1014647")
     @test.attr(type='smoke')
     def test_reboot_server_soft(self):
         # The server should be signaled to reboot gracefully
-        if self.run_ssh:
-            # Get the time the server was last rebooted,
-            resp, server = self.client.get_server(self.server_id)
-            linux_client = remote_client.RemoteClient(server, self.ssh_user,
-                                                      self.password)
-            boot_time = linux_client.get_boot_time()
-
-        resp, body = self.client.reboot(self.server_id, 'SOFT')
-        self.assertEqual(202, resp.status)
-        self.client.wait_for_server_status(self.server_id, 'ACTIVE')
-
-        if self.run_ssh:
-            # Log in and verify the boot time has changed
-            linux_client = remote_client.RemoteClient(server, self.ssh_user,
-                                                      self.password)
-            new_boot_time = linux_client.get_boot_time()
-            self.assertTrue(new_boot_time > boot_time,
-                            '%s > %s' % (new_boot_time, boot_time))
+        self._test_reboot_server('SOFT')
 
     @test.attr(type='smoke')
     def test_rebuild_server(self):
@@ -372,6 +358,25 @@
     @testtools.skipUnless(CONF.compute_feature_enabled.console_output,
                           'Console output not supported.')
     @test.attr(type='gate')
+    def test_get_console_output_with_unlimited_size(self):
+        _, server = self.create_test_server(wait_until='ACTIVE')
+
+        def _check_full_length_console_log():
+            _, output = self.servers_client.get_console_output(server['id'],
+                                                               None)
+            self.assertTrue(output, "Console output was empty.")
+            lines = len(output.split('\n'))
+
+            # NOTE: This test tries to get full length console log, and the
+            # length should be bigger than the one of test_get_console_output.
+            self.assertTrue(lines > 10, "Cannot get enough console log length."
+                                        " (lines: %s)" % lines)
+
+        self.wait_for(_check_full_length_console_log)
+
+    @testtools.skipUnless(CONF.compute_feature_enabled.console_output,
+                          'Console output not supported.')
+    @test.attr(type='gate')
     def test_get_console_output_server_id_in_shutoff_status(self):
         # Positive test:Should be able to GET the console output
         # for a given server_id in SHUTOFF status
diff --git a/tempest/api/compute/servers/test_server_addresses.py b/tempest/api/compute/servers/test_server_addresses.py
index 846bf3e..a494896 100644
--- a/tempest/api/compute/servers/test_server_addresses.py
+++ b/tempest/api/compute/servers/test_server_addresses.py
@@ -14,25 +14,20 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import config
 from tempest import test
 
-CONF = config.CONF
-
 
 class ServerAddressesTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         # This test module might use a network and a subnet
         cls.set_network_resources(network=True, subnet=True)
-        super(ServerAddressesTestJSON, cls).setUpClass()
+        super(ServerAddressesTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
 
         resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
 
-    @test.skip_because(bug="1210483",
-                       condition=CONF.service_available.neutron)
     @test.attr(type='smoke')
     @test.services('network')
     def test_list_server_addresses(self):
diff --git a/tempest/api/compute/servers/test_server_addresses_negative.py b/tempest/api/compute/servers/test_server_addresses_negative.py
index e190161..c7e4c89 100644
--- a/tempest/api/compute/servers/test_server_addresses_negative.py
+++ b/tempest/api/compute/servers/test_server_addresses_negative.py
@@ -21,9 +21,9 @@
 class ServerAddressesNegativeTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.set_network_resources(network=True, subnet=True)
-        super(ServerAddressesNegativeTestJSON, cls).setUpClass()
+        super(ServerAddressesNegativeTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
 
         resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
diff --git a/tempest/api/compute/servers/test_server_group.py b/tempest/api/compute/servers/test_server_group.py
index f1ef5d5..0af19c0 100644
--- a/tempest/api/compute/servers/test_server_group.py
+++ b/tempest/api/compute/servers/test_server_group.py
@@ -26,9 +26,8 @@
     It also adds the tests for list and get details of server-groups
     """
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(ServerGroupTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServerGroupTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('os-server-groups', 'compute'):
             msg = "os-server-groups extension is not enabled."
             raise cls.skipException(msg)
diff --git a/tempest/api/compute/servers/test_server_metadata.py b/tempest/api/compute/servers/test_server_metadata.py
index 01ff6b9..c265352 100644
--- a/tempest/api/compute/servers/test_server_metadata.py
+++ b/tempest/api/compute/servers/test_server_metadata.py
@@ -20,8 +20,8 @@
 class ServerMetadataTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ServerMetadataTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServerMetadataTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
         cls.quotas = cls.quotas_client
         resp, server = cls.create_test_server(meta={}, wait_until='ACTIVE')
diff --git a/tempest/api/compute/servers/test_server_metadata_negative.py b/tempest/api/compute/servers/test_server_metadata_negative.py
index fbda401..497b94b 100644
--- a/tempest/api/compute/servers/test_server_metadata_negative.py
+++ b/tempest/api/compute/servers/test_server_metadata_negative.py
@@ -22,8 +22,8 @@
 class ServerMetadataNegativeTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ServerMetadataNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServerMetadataNegativeTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
         cls.quotas = cls.quotas_client
         cls.tenant_id = cls.client.tenant_id
diff --git a/tempest/api/compute/servers/test_server_password.py b/tempest/api/compute/servers/test_server_password.py
index 50c881a..aba9bb6 100644
--- a/tempest/api/compute/servers/test_server_password.py
+++ b/tempest/api/compute/servers/test_server_password.py
@@ -21,8 +21,8 @@
 class ServerPasswordTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ServerPasswordTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServerPasswordTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
         resp, cls.server = cls.create_test_server(wait_until="ACTIVE")
 
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index 6cc463d..effb52f 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -23,8 +23,8 @@
 class ServerPersonalityTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ServerPersonalityTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServerPersonalityTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
         cls.user_client = cls.limits_client
 
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index b737888..5986f41 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -24,14 +24,13 @@
 class ServerRescueTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
+    def resource_setup(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()
+        super(ServerRescueTestJSON, cls).resource_setup()
 
         # Floating IP creation
         resp, body = cls.floating_ips_client.create_floating_ip()
@@ -46,12 +45,6 @@
                                                              cls.sg_desc)
         cls.sg_id = cls.sg['id']
 
-        # Create a volume and wait for it to become ready for attach
-        resp, cls.volume = cls.volumes_extensions_client.create_volume(
-            1, display_name=data_utils.rand_name(cls.__name__ + '_volume'))
-        cls.volumes_extensions_client.wait_for_volume_status(
-            cls.volume['id'], 'available')
-
         # Server for positive tests
         resp, server = cls.create_test_server(wait_until='BUILD')
         cls.server_id = server['id']
@@ -62,13 +55,12 @@
         super(ServerRescueTestJSON, self).setUp()
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         # Deleting the floating IP which is created in this method
         cls.floating_ips_client.delete_floating_ip(cls.floating_ip_id)
-        cls.delete_volume(cls.volume['id'])
         resp, cls.sg = cls.security_groups_client.delete_security_group(
             cls.sg_id)
-        super(ServerRescueTestJSON, cls).tearDownClass()
+        super(ServerRescueTestJSON, cls).resource_cleanup()
 
     def tearDown(self):
         super(ServerRescueTestJSON, self).tearDown()
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
index 4582a46..de43164 100644
--- a/tempest/api/compute/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -26,22 +26,15 @@
 class ServerRescueNegativeTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
+    def resource_setup(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()
+        super(ServerRescueNegativeTestJSON, cls).resource_setup()
         cls.device = CONF.compute.volume_device_name
 
-        # Create a volume and wait for it to become ready for attach
-        resp, cls.volume = cls.volumes_extensions_client.create_volume(
-            1, display_name=data_utils.rand_name(cls.__name__ + '_volume'))
-        cls.volumes_extensions_client.wait_for_volume_status(
-            cls.volume['id'], 'available')
-
         # Server for negative tests
         resp, server = cls.create_test_server(wait_until='BUILD')
         resp, resc_server = cls.create_test_server(wait_until='ACTIVE')
@@ -55,10 +48,14 @@
         cls.servers_client.wait_for_server_status(cls.rescue_id, 'RESCUE')
         cls.servers_client.wait_for_server_status(cls.server_id, 'ACTIVE')
 
-    @classmethod
-    def tearDownClass(cls):
-        cls.delete_volume(cls.volume['id'])
-        super(ServerRescueNegativeTestJSON, cls).tearDownClass()
+    def _create_volume(self):
+        resp, volume = self.volumes_extensions_client.create_volume(
+            1, display_name=data_utils.rand_name(
+                self.__class__.__name__ + '_volume'))
+        self.addCleanup(self.delete_volume, volume['id'])
+        self.volumes_extensions_client.wait_for_volume_status(
+            volume['id'], 'available')
+        return volume
 
     def _detach(self, server_id, volume_id):
         self.servers_client.detach_volume(server_id, volume_id)
@@ -108,8 +105,11 @@
                           self.rescue_id,
                           self.image_ref_alt)
 
+    @test.services('volume')
     @test.attr(type=['negative', 'gate'])
     def test_rescued_vm_attach_volume(self):
+        volume = self._create_volume()
+
         # Rescue the server
         self.servers_client.rescue_server(self.server_id,
                                           adminPass=self.password)
@@ -120,31 +120,34 @@
         self.assertRaises(exceptions.Conflict,
                           self.servers_client.attach_volume,
                           self.server_id,
-                          self.volume['id'],
+                          volume['id'],
                           device='/dev/%s' % self.device)
 
+    @test.services('volume')
     @test.attr(type=['negative', 'gate'])
     def test_rescued_vm_detach_volume(self):
+        volume = self._create_volume()
+
         # Attach the volume to the server
         self.servers_client.attach_volume(self.server_id,
-                                          self.volume['id'],
+                                          volume['id'],
                                           device='/dev/%s' % self.device)
         self.volumes_extensions_client.wait_for_volume_status(
-            self.volume['id'], 'in-use')
+            volume['id'], 'in-use')
 
         # Rescue the server
         self.servers_client.rescue_server(self.server_id,
                                           adminPass=self.password)
         self.servers_client.wait_for_server_status(self.server_id, 'RESCUE')
         # addCleanup is a LIFO queue
-        self.addCleanup(self._detach, self.server_id, self.volume['id'])
+        self.addCleanup(self._detach, self.server_id, volume['id'])
         self.addCleanup(self._unrescue, self.server_id)
 
         # Detach the volume from the server expecting failure
         self.assertRaises(exceptions.Conflict,
                           self.servers_client.detach_volume,
                           self.server_id,
-                          self.volume['id'])
+                          volume['id'])
 
 
 class ServerRescueNegativeTestXML(ServerRescueNegativeTestJSON):
diff --git a/tempest/api/compute/servers/test_servers.py b/tempest/api/compute/servers/test_servers.py
index 936b871..d501839 100644
--- a/tempest/api/compute/servers/test_servers.py
+++ b/tempest/api/compute/servers/test_servers.py
@@ -21,8 +21,8 @@
 class ServersTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ServersTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServersTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
 
     def tearDown(self):
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index b9ec29e..0349260 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -42,13 +42,10 @@
         super(ServersNegativeTestJSON, self).tearDown()
 
     @classmethod
-    def setUpClass(cls):
-        super(ServersNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServersNegativeTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
-        if CONF.compute.allow_tenant_isolation:
-            cls.alt_os = clients.Manager(cls.isolated_creds.get_alt_creds())
-        else:
-            cls.alt_os = clients.AltManager()
+        cls.alt_os = clients.Manager(cls.isolated_creds.get_alt_creds())
         cls.alt_client = cls.alt_os.servers_client
         resp, server = cls.create_test_server(wait_until='ACTIVE')
         cls.server_id = server['id']
diff --git a/tempest/api/compute/servers/test_servers_negative_new.py b/tempest/api/compute/servers/test_servers_negative_new.py
deleted file mode 100644
index c5f9fdd..0000000
--- a/tempest/api/compute/servers/test_servers_negative_new.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2014 Red Hat, Inc & Deutsche Telekom AG
-# 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.compute import base
-from tempest.api_schema.request.compute.v2 import servers
-from tempest import test
-
-
-load_tests = test.NegativeAutoTest.load_tests
-
-
-@test.SimpleNegativeAutoTest
-class GetConsoleOutputNegativeTestJSON(base.BaseV2ComputeTest,
-                                       test.NegativeAutoTest):
-    _service = 'compute'
-    _schema = servers.get_console_output
-
-    @classmethod
-    def setUpClass(cls):
-        super(GetConsoleOutputNegativeTestJSON, cls).setUpClass()
-        _resp, server = cls.create_test_server()
-        cls.set_resource("server", server['id'])
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index 421ba8b..f205761 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -25,10 +25,10 @@
 class VirtualInterfacesTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         # This test needs a network and a subnet
         cls.set_network_resources(network=True, subnet=True)
-        super(VirtualInterfacesTestJSON, cls).setUpClass()
+        super(VirtualInterfacesTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
         resp, server = cls.create_test_server(wait_until='ACTIVE')
         cls.server_id = 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 bcb2686..1f4a20e 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces_negative.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
@@ -23,10 +23,10 @@
 class VirtualInterfacesNegativeTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         # For this test no network resources are needed
         cls.set_network_resources()
-        super(VirtualInterfacesNegativeTestJSON, cls).setUpClass()
+        super(VirtualInterfacesNegativeTestJSON, cls).resource_setup()
         cls.client = cls.servers_client
 
     @test.attr(type=['negative', 'gate'])
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index 3fa4a89..175f008 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -30,12 +30,12 @@
 
 class AuthorizationTestJSON(base.BaseV2ComputeTest):
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(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()
+        super(AuthorizationTestJSON, cls).resource_setup()
         if not cls.multi_user:
             msg = "Need >1 user"
             raise cls.skipException(msg)
@@ -45,12 +45,8 @@
         cls.keypairs_client = cls.os.keypairs_client
         cls.security_client = cls.os.security_groups_client
 
-        if CONF.compute.allow_tenant_isolation:
-            creds = cls.isolated_creds.get_alt_creds()
-            cls.alt_manager = clients.Manager(credentials=creds)
-        else:
-            # Use the alt_XXX credentials in the config file
-            cls.alt_manager = clients.AltManager()
+        creds = cls.isolated_creds.get_alt_creds()
+        cls.alt_manager = clients.Manager(credentials=creds)
 
         cls.alt_client = cls.alt_manager.servers_client
         cls.alt_images_client = cls.alt_manager.images_client
@@ -88,12 +84,12 @@
             parent_group_id, ip_protocol, from_port, to_port)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         if cls.multi_user:
             cls.images_client.delete_image(cls.image['id'])
             cls.keypairs_client.delete_keypair(cls.keypairname)
             cls.security_client.delete_security_group(cls.security_group['id'])
-        super(AuthorizationTestJSON, cls).tearDownClass()
+        super(AuthorizationTestJSON, cls).resource_cleanup()
 
     @test.attr(type='gate')
     def test_get_server_for_alt_account_fails(self):
diff --git a/tempest/api/compute/test_live_block_migration.py b/tempest/api/compute/test_live_block_migration.py
index 93ff4b0..86b8395 100644
--- a/tempest/api/compute/test_live_block_migration.py
+++ b/tempest/api/compute/test_live_block_migration.py
@@ -27,8 +27,8 @@
     _host_key = 'OS-EXT-SRV-ATTR:host'
 
     @classmethod
-    def setUpClass(cls):
-        super(LiveBlockMigrationTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(LiveBlockMigrationTestJSON, cls).resource_setup()
 
         cls.admin_hosts_client = cls.os_adm.hosts_client
         cls.admin_servers_client = cls.os_adm.servers_client
diff --git a/tempest/api/compute/test_live_block_migration_negative.py b/tempest/api/compute/test_live_block_migration_negative.py
index c10818e..95eea19 100644
--- a/tempest/api/compute/test_live_block_migration_negative.py
+++ b/tempest/api/compute/test_live_block_migration_negative.py
@@ -27,8 +27,8 @@
     _host_key = 'OS-EXT-SRV-ATTR:host'
 
     @classmethod
-    def setUpClass(cls):
-        super(LiveBlockMigrationNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(LiveBlockMigrationNegativeTestJSON, cls).resource_setup()
         if not CONF.compute_feature_enabled.live_migration:
             raise cls.skipException("Live migration is not enabled")
         cls.admin_hosts_client = cls.os_adm.hosts_client
diff --git a/tempest/api/compute/test_networks.py b/tempest/api/compute/test_networks.py
new file mode 100644
index 0000000..86779b3
--- /dev/null
+++ b/tempest/api/compute/test_networks.py
@@ -0,0 +1,33 @@
+# 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.
+
+from tempest.api.compute import base
+from tempest import config
+from tempest import test
+
+CONF = config.CONF
+
+
+class NetworksTestJSON(base.BaseV2ComputeTest):
+    @classmethod
+    def resource_setup(cls):
+        if CONF.service_available.neutron:
+            raise cls.skipException('nova-network is not available.')
+        super(NetworksTestJSON, cls).resource_setup()
+        cls.client = cls.os.networks_client
+
+    @test.attr(type='gate')
+    def test_list_networks(self):
+        _, networks = self.client.list_networks()
+        self.assertNotEmpty(networks, "No networks found.")
diff --git a/tempest/api/compute/test_quotas.py b/tempest/api/compute/test_quotas.py
index eeff3ce..e66b652 100644
--- a/tempest/api/compute/test_quotas.py
+++ b/tempest/api/compute/test_quotas.py
@@ -26,8 +26,8 @@
         super(QuotasTestJSON, self).setUp()
 
     @classmethod
-    def setUpClass(cls):
-        super(QuotasTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(QuotasTestJSON, cls).resource_setup()
         cls.client = cls.quotas_client
         cls.tenant_id = cls.client.tenant_id
         cls.user_id = cls.client.user_id
@@ -45,17 +45,17 @@
         expected_quota_set = self.default_quota_set | set(['id'])
         resp, quota_set = self.client.get_quota_set(self.tenant_id)
         self.assertEqual(200, resp.status)
-        self.assertEqual(sorted(expected_quota_set),
-                         sorted(quota_set.keys()))
         self.assertEqual(quota_set['id'], self.tenant_id)
+        for quota in expected_quota_set:
+            self.assertIn(quota, quota_set.keys())
 
         # get the quota set using user id
         resp, quota_set = self.client.get_quota_set(self.tenant_id,
                                                     self.user_id)
         self.assertEqual(200, resp.status)
-        self.assertEqual(sorted(expected_quota_set),
-                         sorted(quota_set.keys()))
         self.assertEqual(quota_set['id'], self.tenant_id)
+        for quota in expected_quota_set:
+            self.assertIn(quota, quota_set.keys())
 
     @test.attr(type='smoke')
     def test_get_default_quotas(self):
@@ -63,9 +63,9 @@
         expected_quota_set = self.default_quota_set | set(['id'])
         resp, quota_set = self.client.get_default_quota_set(self.tenant_id)
         self.assertEqual(200, resp.status)
-        self.assertEqual(sorted(expected_quota_set),
-                         sorted(quota_set.keys()))
         self.assertEqual(quota_set['id'], self.tenant_id)
+        for quota in expected_quota_set:
+            self.assertIn(quota, quota_set.keys())
 
     @test.attr(type='smoke')
     def test_compare_tenant_quotas_with_default_quotas(self):
diff --git a/tempest/api/compute/v3/admin/test_agents.py b/tempest/api/compute/v3/admin/test_agents.py
index 9d01b71..b7c0011 100644
--- a/tempest/api/compute/v3/admin/test_agents.py
+++ b/tempest/api/compute/v3/admin/test_agents.py
@@ -23,8 +23,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(AgentsAdminV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(AgentsAdminV3Test, cls).resource_setup()
         cls.client = cls.agents_admin_client
 
     @test.attr(type='gate')
diff --git a/tempest/api/compute/v3/admin/test_aggregates.py b/tempest/api/compute/v3/admin/test_aggregates.py
index 886b6a7..1beeb13 100644
--- a/tempest/api/compute/v3/admin/test_aggregates.py
+++ b/tempest/api/compute/v3/admin/test_aggregates.py
@@ -28,8 +28,8 @@
     _host_key = 'os-extended-server-attributes:host'
 
     @classmethod
-    def setUpClass(cls):
-        super(AggregatesAdminV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(AggregatesAdminV3Test, cls).resource_setup()
         cls.client = cls.aggregates_admin_client
         cls.aggregate_name_prefix = 'test_aggregate_'
         cls.az_name_prefix = 'test_az_'
diff --git a/tempest/api/compute/v3/admin/test_aggregates_negative.py b/tempest/api/compute/v3/admin/test_aggregates_negative.py
index 1505f74..093963f 100644
--- a/tempest/api/compute/v3/admin/test_aggregates_negative.py
+++ b/tempest/api/compute/v3/admin/test_aggregates_negative.py
@@ -27,8 +27,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(AggregatesAdminNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(AggregatesAdminNegativeV3Test, cls).resource_setup()
         cls.client = cls.aggregates_admin_client
         cls.user_client = cls.aggregates_client
         cls.aggregate_name_prefix = 'test_aggregate_'
diff --git a/tempest/api/compute/v3/admin/test_availability_zone_negative.py b/tempest/api/compute/v3/admin/test_availability_zone_negative.py
index b012e65..56cdd6c 100644
--- a/tempest/api/compute/v3/admin/test_availability_zone_negative.py
+++ b/tempest/api/compute/v3/admin/test_availability_zone_negative.py
@@ -25,8 +25,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(AZAdminNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(AZAdminNegativeV3Test, cls).resource_setup()
         cls.client = cls.availability_zone_admin_client
         cls.non_adm_client = cls.availability_zone_client
 
diff --git a/tempest/api/compute/v3/admin/test_flavors.py b/tempest/api/compute/v3/admin/test_flavors.py
index 09d76b8..f307907 100644
--- a/tempest/api/compute/v3/admin/test_flavors.py
+++ b/tempest/api/compute/v3/admin/test_flavors.py
@@ -28,8 +28,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorsAdminV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorsAdminV3Test, cls).resource_setup()
 
         cls.client = cls.flavors_admin_client
         cls.user_client = cls.flavors_client
diff --git a/tempest/api/compute/v3/admin/test_flavors_access.py b/tempest/api/compute/v3/admin/test_flavors_access.py
index 09b6ebd..c79e591 100644
--- a/tempest/api/compute/v3/admin/test_flavors_access.py
+++ b/tempest/api/compute/v3/admin/test_flavors_access.py
@@ -26,8 +26,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorsAccessV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorsAccessV3Test, cls).resource_setup()
 
         cls.client = cls.flavors_admin_client
         admin_client = cls._get_identity_admin_client()
diff --git a/tempest/api/compute/v3/admin/test_flavors_access_negative.py b/tempest/api/compute/v3/admin/test_flavors_access_negative.py
index 0fdfabd..87e8cbf 100644
--- a/tempest/api/compute/v3/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_access_negative.py
@@ -29,8 +29,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorsAccessNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorsAccessNegativeV3Test, cls).resource_setup()
 
         cls.client = cls.flavors_admin_client
         cls.tenant_id = cls.client.tenant_id
diff --git a/tempest/api/compute/v3/admin/test_flavors_extra_specs.py b/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
index 29cd8db..24844b1 100644
--- a/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
@@ -27,8 +27,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorsExtraSpecsV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorsExtraSpecsV3Test, cls).resource_setup()
 
         cls.client = cls.flavors_admin_client
         flavor_name = data_utils.rand_name('test_flavor')
@@ -48,10 +48,10 @@
                                                     swap=swap, rxtx=rxtx)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         resp, body = cls.client.delete_flavor(cls.flavor['id'])
         cls.client.wait_for_resource_deletion(cls.flavor['id'])
-        super(FlavorsExtraSpecsV3Test, cls).tearDownClass()
+        super(FlavorsExtraSpecsV3Test, cls).resource_cleanup()
 
     @test.attr(type='gate')
     def test_flavor_set_get_update_show_unset_keys(self):
diff --git a/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
index e9c04a3..5fcd7a4 100644
--- a/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
@@ -28,8 +28,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorsExtraSpecsNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorsExtraSpecsNegativeV3Test, cls).resource_setup()
 
         cls.client = cls.flavors_admin_client
         flavor_name = data_utils.rand_name('test_flavor')
@@ -49,10 +49,10 @@
                                                     swap=swap, rxtx=rxtx)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         resp, body = cls.client.delete_flavor(cls.flavor['id'])
         cls.client.wait_for_resource_deletion(cls.flavor['id'])
-        super(FlavorsExtraSpecsNegativeV3Test, cls).tearDownClass()
+        super(FlavorsExtraSpecsNegativeV3Test, cls).resource_cleanup()
 
     @test.attr(type=['negative', 'gate'])
     def test_flavor_non_admin_set_keys(self):
diff --git a/tempest/api/compute/v3/admin/test_flavors_negative.py b/tempest/api/compute/v3/admin/test_flavors_negative.py
index 6d3308e..426d13e 100644
--- a/tempest/api/compute/v3/admin/test_flavors_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_negative.py
@@ -28,8 +28,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorsAdminNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorsAdminNegativeV3Test, cls).resource_setup()
 
         cls.client = cls.flavors_admin_client
         cls.user_client = cls.flavors_client
diff --git a/tempest/api/compute/v3/admin/test_hosts.py b/tempest/api/compute/v3/admin/test_hosts.py
index 8cb1f23..898a704 100644
--- a/tempest/api/compute/v3/admin/test_hosts.py
+++ b/tempest/api/compute/v3/admin/test_hosts.py
@@ -24,8 +24,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(HostsAdminV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(HostsAdminV3Test, cls).resource_setup()
         cls.client = cls.hosts_admin_client
 
     @test.attr(type='gate')
diff --git a/tempest/api/compute/v3/admin/test_hosts_negative.py b/tempest/api/compute/v3/admin/test_hosts_negative.py
index 79cd97f..2b82baa 100644
--- a/tempest/api/compute/v3/admin/test_hosts_negative.py
+++ b/tempest/api/compute/v3/admin/test_hosts_negative.py
@@ -25,8 +25,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(HostsAdminNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(HostsAdminNegativeV3Test, cls).resource_setup()
         cls.client = cls.hosts_admin_client
         cls.non_admin_client = cls.hosts_client
 
diff --git a/tempest/api/compute/v3/admin/test_hypervisor.py b/tempest/api/compute/v3/admin/test_hypervisor.py
index 9a23789..831e20f 100644
--- a/tempest/api/compute/v3/admin/test_hypervisor.py
+++ b/tempest/api/compute/v3/admin/test_hypervisor.py
@@ -24,8 +24,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(HypervisorAdminV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(HypervisorAdminV3Test, cls).resource_setup()
         cls.client = cls.hypervisor_admin_client
 
     def _list_hypervisors(self):
diff --git a/tempest/api/compute/v3/admin/test_hypervisor_negative.py b/tempest/api/compute/v3/admin/test_hypervisor_negative.py
index ae4df15..df23b46 100644
--- a/tempest/api/compute/v3/admin/test_hypervisor_negative.py
+++ b/tempest/api/compute/v3/admin/test_hypervisor_negative.py
@@ -28,8 +28,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(HypervisorAdminNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(HypervisorAdminNegativeV3Test, cls).resource_setup()
         cls.client = cls.hypervisor_admin_client
         cls.non_adm_client = cls.hypervisor_client
 
diff --git a/tempest/api/compute/v3/admin/test_quotas.py b/tempest/api/compute/v3/admin/test_quotas.py
index 19c31fe..3dad45c 100644
--- a/tempest/api/compute/v3/admin/test_quotas.py
+++ b/tempest/api/compute/v3/admin/test_quotas.py
@@ -25,8 +25,8 @@
     force_tenant_isolation = True
 
     @classmethod
-    def setUpClass(cls):
-        super(QuotasAdminV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(QuotasAdminV3Test, cls).resource_setup()
         cls.client = cls.quotas_client
         cls.adm_client = cls.quotas_admin_client
 
diff --git a/tempest/api/compute/v3/admin/test_quotas_negative.py b/tempest/api/compute/v3/admin/test_quotas_negative.py
index 7739f09..86abcab 100644
--- a/tempest/api/compute/v3/admin/test_quotas_negative.py
+++ b/tempest/api/compute/v3/admin/test_quotas_negative.py
@@ -23,8 +23,8 @@
     force_tenant_isolation = True
 
     @classmethod
-    def setUpClass(cls):
-        super(QuotasAdminNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(QuotasAdminNegativeV3Test, cls).resource_setup()
         cls.client = cls.quotas_client
         cls.adm_client = cls.quotas_admin_client
 
@@ -34,7 +34,6 @@
 
     # 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
@@ -48,9 +47,9 @@
 
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         cores=default_vcpu_quota)
-        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
+        self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
+                          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
@@ -64,7 +63,8 @@
 
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         ram=default_mem_quota)
-        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
+        self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
+                          self.create_test_server)
 
     @test.attr(type=['negative', 'gate'])
     def test_update_quota_normal_user(self):
@@ -73,7 +73,6 @@
                           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
@@ -86,4 +85,5 @@
                                          instances=instances_quota)
         self.addCleanup(self.adm_client.update_quota_set, self.demo_tenant_id,
                         instances=default_instances_quota)
-        self.assertRaises(exceptions.Unauthorized, self.create_test_server)
+        self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
+                          self.create_test_server)
diff --git a/tempest/api/compute/v3/admin/test_servers.py b/tempest/api/compute/v3/admin/test_servers.py
index d99c329..36ea7ba 100644
--- a/tempest/api/compute/v3/admin/test_servers.py
+++ b/tempest/api/compute/v3/admin/test_servers.py
@@ -26,9 +26,8 @@
     _host_key = 'os-extended-server-attributes:host'
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(ServersAdminV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServersAdminV3Test, cls).resource_setup()
         cls.client = cls.servers_admin_client
         cls.non_admin_client = cls.servers_client
         cls.flavors_client = cls.flavors_admin_client
diff --git a/tempest/api/compute/v3/admin/test_servers_negative.py b/tempest/api/compute/v3/admin/test_servers_negative.py
index 5eb6395..f561ed3 100644
--- a/tempest/api/compute/v3/admin/test_servers_negative.py
+++ b/tempest/api/compute/v3/admin/test_servers_negative.py
@@ -17,6 +17,7 @@
 import testtools
 
 from tempest.api.compute import base
+from tempest.common import tempest_fixtures as fixtures
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
@@ -32,8 +33,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(ServersAdminNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServersAdminNegativeV3Test, cls).resource_setup()
         cls.client = cls.servers_admin_client
         cls.non_adm_client = cls.servers_client
         cls.flavors_client = cls.flavors_admin_client
@@ -54,9 +55,10 @@
             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):
+        # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
+        self.useFixture(fixtures.LockFixture('compute_quotas'))
         flavor_name = data_utils.rand_name("flavor-")
         flavor_id = self._get_unused_flavor_id()
         resp, quota_set = self.quotas_client.get_default_quota_set(
@@ -68,14 +70,15 @@
                                                              ram, vcpus, disk,
                                                              flavor_id)
         self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
-        self.assertRaises(exceptions.Unauthorized,
+        self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
                           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):
+        # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
+        self.useFixture(fixtures.LockFixture('compute_quotas'))
         flavor_name = data_utils.rand_name("flavor-")
         flavor_id = self._get_unused_flavor_id()
         ram = 512
@@ -87,7 +90,7 @@
                                                              ram, vcpus, disk,
                                                              flavor_id)
         self.addCleanup(self.flavors_client.delete_flavor, flavor_id)
-        self.assertRaises(exceptions.Unauthorized,
+        self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
                           self.client.resize,
                           self.servers[0]['id'],
                           flavor_ref['id'])
diff --git a/tempest/api/compute/v3/admin/test_services.py b/tempest/api/compute/v3/admin/test_services.py
index e6efb70..f1c3b9a 100644
--- a/tempest/api/compute/v3/admin/test_services.py
+++ b/tempest/api/compute/v3/admin/test_services.py
@@ -25,8 +25,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(ServicesAdminV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServicesAdminV3Test, cls).resource_setup()
         cls.client = cls.services_admin_client
 
     @test.attr(type='gate')
diff --git a/tempest/api/compute/v3/admin/test_services_negative.py b/tempest/api/compute/v3/admin/test_services_negative.py
index 6ac78d4..1f9f2b1 100644
--- a/tempest/api/compute/v3/admin/test_services_negative.py
+++ b/tempest/api/compute/v3/admin/test_services_negative.py
@@ -26,8 +26,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(ServicesAdminNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServicesAdminNegativeV3Test, cls).resource_setup()
         cls.client = cls.services_admin_client
         cls.non_admin_client = cls.services_client
 
diff --git a/tempest/api/compute/v3/flavors/test_flavors_negative.py b/tempest/api/compute/v3/flavors/test_flavors_negative.py
index cdf018f..2dd7b71 100644
--- a/tempest/api/compute/v3/flavors/test_flavors_negative.py
+++ b/tempest/api/compute/v3/flavors/test_flavors_negative.py
@@ -35,6 +35,6 @@
     _schema = flavors.flavors_details
 
     @classmethod
-    def setUpClass(cls):
-        super(FlavorDetailsNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(FlavorDetailsNegativeV3Test, cls).resource_setup()
         cls.set_resource("flavor", cls.flavor_ref)
diff --git a/tempest/api/compute/v3/images/test_images.py b/tempest/api/compute/v3/images/test_images.py
index bb81626..a234a22 100644
--- a/tempest/api/compute/v3/images/test_images.py
+++ b/tempest/api/compute/v3/images/test_images.py
@@ -23,8 +23,8 @@
 class ImagesV3Test(base.BaseV3ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ImagesV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(ImagesV3Test, cls).resource_setup()
         if not CONF.service_available.glance:
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
diff --git a/tempest/api/compute/v3/images/test_images_negative.py b/tempest/api/compute/v3/images/test_images_negative.py
index 0705bdc..83e9436 100644
--- a/tempest/api/compute/v3/images/test_images_negative.py
+++ b/tempest/api/compute/v3/images/test_images_negative.py
@@ -24,8 +24,8 @@
 class ImagesNegativeV3Test(base.BaseV3ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ImagesNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(ImagesNegativeV3Test, cls).resource_setup()
         if not CONF.service_available.glance:
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
diff --git a/tempest/api/compute/v3/images/test_images_oneserver.py b/tempest/api/compute/v3/images/test_images_oneserver.py
index 795437b..87e730c 100644
--- a/tempest/api/compute/v3/images/test_images_oneserver.py
+++ b/tempest/api/compute/v3/images/test_images_oneserver.py
@@ -47,19 +47,15 @@
         super(ImagesOneServerV3Test, self).tearDown()
 
     @classmethod
-    def setUpClass(cls):
-        super(ImagesOneServerV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(ImagesOneServerV3Test, cls).resource_setup()
         cls.client = cls.images_client
         if not CONF.service_available.glance:
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
 
-        try:
-            resp, server = cls.create_test_server(wait_until='ACTIVE')
-            cls.server_id = server['id']
-        except Exception:
-            cls.tearDownClass()
-            raise
+        resp, server = cls.create_test_server(wait_until='ACTIVE')
+        cls.server_id = server['id']
 
     def _get_default_flavor_disk_size(self, flavor_id):
         resp, flavor = self.flavors_client.get_flavor_details(flavor_id)
diff --git a/tempest/api/compute/v3/images/test_images_oneserver_negative.py b/tempest/api/compute/v3/images/test_images_oneserver_negative.py
index eed81c6..5892cd7 100644
--- a/tempest/api/compute/v3/images/test_images_oneserver_negative.py
+++ b/tempest/api/compute/v3/images/test_images_oneserver_negative.py
@@ -55,19 +55,15 @@
         self.__class__.server_id = self.rebuild_server(self.server_id)
 
     @classmethod
-    def setUpClass(cls):
-        super(ImagesOneServerNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(ImagesOneServerNegativeV3Test, cls).resource_setup()
         cls.client = cls.images_client
         if not CONF.service_available.glance:
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
 
-        try:
-            resp, server = cls.create_test_server(wait_until='ACTIVE')
-            cls.server_id = server['id']
-        except Exception:
-            cls.tearDownClass()
-            raise
+        resp, server = cls.create_test_server(wait_until='ACTIVE')
+        cls.server_id = server['id']
 
         cls.image_ids = []
 
diff --git a/tempest/api/compute/v3/keypairs/test_keypairs_negative.py b/tempest/api/compute/v3/keypairs/test_keypairs_negative.py
index e426b85..1f7206a 100644
--- a/tempest/api/compute/v3/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/v3/keypairs/test_keypairs_negative.py
@@ -23,8 +23,8 @@
 class KeyPairsNegativeV3Test(base.BaseV3ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(KeyPairsNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(KeyPairsNegativeV3Test, cls).resource_setup()
         cls.client = cls.keypairs_client
 
     def _create_keypair(self, keypair_name, pub_key=None):
diff --git a/tempest/api/compute/v3/servers/test_attach_interfaces.py b/tempest/api/compute/v3/servers/test_attach_interfaces.py
index c2cf7e0..d4d4fca 100644
--- a/tempest/api/compute/v3/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/v3/servers/test_attach_interfaces.py
@@ -26,14 +26,14 @@
 class AttachInterfacesV3Test(base.BaseV3ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.service_available.neutron:
             raise cls.skipException("Neutron is required")
         if not CONF.compute_feature_enabled.interface_attach:
             raise cls.skipException("Interface attachment is not available.")
         # This test class requires network and subnet
         cls.set_network_resources(network=True, subnet=True)
-        super(AttachInterfacesV3Test, cls).setUpClass()
+        super(AttachInterfacesV3Test, cls).resource_setup()
         cls.client = cls.interfaces_client
 
     def _check_interface(self, iface, port_id=None, network_id=None,
diff --git a/tempest/api/compute/v3/servers/test_attach_volume.py b/tempest/api/compute/v3/servers/test_attach_volume.py
index e994c7f..76b5549 100644
--- a/tempest/api/compute/v3/servers/test_attach_volume.py
+++ b/tempest/api/compute/v3/servers/test_attach_volume.py
@@ -32,9 +32,9 @@
         self.attached = False
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.prepare_instance_network()
-        super(AttachVolumeV3Test, cls).setUpClass()
+        super(AttachVolumeV3Test, cls).resource_setup()
         cls.device = CONF.compute.volume_device_name
         if not CONF.service_available.cinder:
             skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
diff --git a/tempest/api/compute/v3/servers/test_create_server.py b/tempest/api/compute/v3/servers/test_create_server.py
index c59fe91..bcd6176 100644
--- a/tempest/api/compute/v3/servers/test_create_server.py
+++ b/tempest/api/compute/v3/servers/test_create_server.py
@@ -31,9 +31,9 @@
     disk_config = 'AUTO'
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.prepare_instance_network()
-        super(ServersV3Test, cls).setUpClass()
+        super(ServersV3Test, cls).resource_setup()
         cls.meta = {'hello': 'world'}
         cls.accessIPv4 = '1.1.1.1'
         cls.accessIPv6 = '0000:0000:0000:0000:0000:babe:220.12.22.2'
@@ -108,9 +108,9 @@
     disk_config = 'AUTO'
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.prepare_instance_network()
-        super(ServersWithSpecificFlavorV3Test, cls).setUpClass()
+        super(ServersWithSpecificFlavorV3Test, cls).resource_setup()
         cls.client = cls.servers_client
         cls.flavor_client = cls.flavors_admin_client
 
@@ -192,8 +192,8 @@
     disk_config = 'MANUAL'
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.compute_feature_enabled.disk_config:
             msg = "DiskConfig extension not enabled."
             raise cls.skipException(msg)
-        super(ServersV3TestManualDisk, cls).setUpClass()
+        super(ServersV3TestManualDisk, cls).resource_setup()
diff --git a/tempest/api/compute/v3/servers/test_delete_server.py b/tempest/api/compute/v3/servers/test_delete_server.py
index e2b47ee..ab10b4c 100644
--- a/tempest/api/compute/v3/servers/test_delete_server.py
+++ b/tempest/api/compute/v3/servers/test_delete_server.py
@@ -26,8 +26,8 @@
     # for preventing "Quota exceeded for instances".
 
     @classmethod
-    def setUpClass(cls):
-        super(DeleteServersV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(DeleteServersV3Test, cls).resource_setup()
         cls.client = cls.servers_client
 
     @test.attr(type='gate')
@@ -128,8 +128,8 @@
     # for preventing "Quota exceeded for instances".
 
     @classmethod
-    def setUpClass(cls):
-        super(DeleteServersAdminV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(DeleteServersAdminV3Test, cls).resource_setup()
         cls.non_admin_client = cls.servers_client
         cls.admin_client = cls.servers_admin_client
 
diff --git a/tempest/api/compute/v3/servers/test_instance_actions.py b/tempest/api/compute/v3/servers/test_instance_actions.py
index 4c2dcbe..227f6cd 100644
--- a/tempest/api/compute/v3/servers/test_instance_actions.py
+++ b/tempest/api/compute/v3/servers/test_instance_actions.py
@@ -20,8 +20,8 @@
 class InstanceActionsV3Test(base.BaseV3ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(InstanceActionsV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(InstanceActionsV3Test, cls).resource_setup()
         cls.client = cls.servers_client
         resp, server = cls.create_test_server(wait_until='ACTIVE')
         cls.resp = resp
diff --git a/tempest/api/compute/v3/servers/test_instance_actions_negative.py b/tempest/api/compute/v3/servers/test_instance_actions_negative.py
index 0b2c6f9..b9d4be2 100644
--- a/tempest/api/compute/v3/servers/test_instance_actions_negative.py
+++ b/tempest/api/compute/v3/servers/test_instance_actions_negative.py
@@ -22,8 +22,8 @@
 class InstanceActionsNegativeV3Test(base.BaseV3ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(InstanceActionsNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(InstanceActionsNegativeV3Test, cls).resource_setup()
         cls.client = cls.servers_client
         resp, server = cls.create_test_server(wait_until='ACTIVE')
         cls.server_id = server['id']
diff --git a/tempest/api/compute/v3/servers/test_list_server_filters.py b/tempest/api/compute/v3/servers/test_list_server_filters.py
index 778b033..73844cf 100644
--- a/tempest/api/compute/v3/servers/test_list_server_filters.py
+++ b/tempest/api/compute/v3/servers/test_list_server_filters.py
@@ -26,10 +26,9 @@
 class ListServerFiltersV3Test(base.BaseV3ComputeTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.set_network_resources(network=True, subnet=True, dhcp=True)
-        super(ListServerFiltersV3Test, cls).setUpClass()
+        super(ListServerFiltersV3Test, cls).resource_setup()
         cls.client = cls.servers_client
 
         # Check to see if the alternate image ref actually exists...
@@ -71,12 +70,11 @@
                                               flavor=cls.flavor_ref_alt,
                                               wait_until='ACTIVE')
 
-        if (CONF.service_available.neutron and
-                CONF.compute.allow_tenant_isolation):
-            network = cls.isolated_creds.get_primary_network()
-            cls.fixed_network_name = network['name']
-        else:
-            cls.fixed_network_name = CONF.compute.fixed_network_name
+        cls.fixed_network_name = CONF.compute.fixed_network_name
+        if CONF.service_available.neutron:
+            if hasattr(cls.isolated_creds, 'get_primary_network'):
+                network = cls.isolated_creds.get_primary_network()
+                cls.fixed_network_name = network['name']
 
     @utils.skip_unless_attr('multiple_images', 'Only one image found')
     @test.attr(type='gate')
diff --git a/tempest/api/compute/v3/servers/test_list_servers_negative.py b/tempest/api/compute/v3/servers/test_list_servers_negative.py
index 18e5c67..67e1155 100644
--- a/tempest/api/compute/v3/servers/test_list_servers_negative.py
+++ b/tempest/api/compute/v3/servers/test_list_servers_negative.py
@@ -26,9 +26,8 @@
     force_tenant_isolation = True
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(ListServersNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(ListServersNegativeV3Test, cls).resource_setup()
         cls.client = cls.servers_client
 
         # The following servers are created for use
diff --git a/tempest/api/compute/v3/servers/test_server_actions.py b/tempest/api/compute/v3/servers/test_server_actions.py
index 538507f..a4e8dba 100644
--- a/tempest/api/compute/v3/servers/test_server_actions.py
+++ b/tempest/api/compute/v3/servers/test_server_actions.py
@@ -51,9 +51,9 @@
         super(ServerActionsV3Test, self).tearDown()
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.prepare_instance_network()
-        super(ServerActionsV3Test, cls).setUpClass()
+        super(ServerActionsV3Test, cls).resource_setup()
         cls.client = cls.servers_client
         cls.server_id = cls.rebuild_server(None)
 
diff --git a/tempest/api/compute/v3/servers/test_server_addresses.py b/tempest/api/compute/v3/servers/test_server_addresses.py
index efd7500..7b41d71 100644
--- a/tempest/api/compute/v3/servers/test_server_addresses.py
+++ b/tempest/api/compute/v3/servers/test_server_addresses.py
@@ -14,25 +14,20 @@
 #    under the License.
 
 from tempest.api.compute import base
-from tempest import config
 from tempest import test
 
-CONF = config.CONF
-
 
 class ServerAddressesV3Test(base.BaseV3ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         # This test module might use a network and a subnet
         cls.set_network_resources(network=True, subnet=True)
-        super(ServerAddressesV3Test, cls).setUpClass()
+        super(ServerAddressesV3Test, cls).resource_setup()
         cls.client = cls.servers_client
 
         resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
 
-    @test.skip_because(bug="1210483",
-                       condition=CONF.service_available.neutron)
     @test.attr(type='smoke')
     def test_list_server_addresses(self):
         # All public and private addresses for
diff --git a/tempest/api/compute/v3/servers/test_server_addresses_negative.py b/tempest/api/compute/v3/servers/test_server_addresses_negative.py
index 8a9877b..7a1b6fc 100644
--- a/tempest/api/compute/v3/servers/test_server_addresses_negative.py
+++ b/tempest/api/compute/v3/servers/test_server_addresses_negative.py
@@ -23,10 +23,10 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         # This test module might use a network and a subnet
         cls.set_network_resources(network=True, subnet=True)
-        super(ServerAddressesV3NegativeTest, cls).setUpClass()
+        super(ServerAddressesV3NegativeTest, cls).resource_setup()
         cls.client = cls.servers_client
 
         resp, cls.server = cls.create_test_server(wait_until='ACTIVE')
diff --git a/tempest/api/compute/v3/servers/test_server_metadata.py b/tempest/api/compute/v3/servers/test_server_metadata.py
index c5443ee..ccdfbad 100644
--- a/tempest/api/compute/v3/servers/test_server_metadata.py
+++ b/tempest/api/compute/v3/servers/test_server_metadata.py
@@ -20,8 +20,8 @@
 class ServerMetadataV3Test(base.BaseV3ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ServerMetadataV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServerMetadataV3Test, cls).resource_setup()
         cls.client = cls.servers_client
         cls.quotas = cls.quotas_client
         resp, server = cls.create_test_server(meta={}, wait_until='ACTIVE')
diff --git a/tempest/api/compute/v3/servers/test_server_metadata_negative.py b/tempest/api/compute/v3/servers/test_server_metadata_negative.py
index f746be3..036b126 100644
--- a/tempest/api/compute/v3/servers/test_server_metadata_negative.py
+++ b/tempest/api/compute/v3/servers/test_server_metadata_negative.py
@@ -21,8 +21,8 @@
 class ServerMetadataV3NegativeTest(base.BaseV3ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ServerMetadataV3NegativeTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServerMetadataV3NegativeTest, cls).resource_setup()
         cls.client = cls.servers_client
         cls.quotas = cls.quotas_client
         cls.tenant_id = cls.client.tenant_id
diff --git a/tempest/api/compute/v3/servers/test_server_password.py b/tempest/api/compute/v3/servers/test_server_password.py
index fc0b145..bb0e310 100644
--- a/tempest/api/compute/v3/servers/test_server_password.py
+++ b/tempest/api/compute/v3/servers/test_server_password.py
@@ -21,8 +21,8 @@
 class ServerPasswordV3Test(base.BaseV3ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ServerPasswordV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServerPasswordV3Test, cls).resource_setup()
         cls.client = cls.servers_client
         resp, cls.server = cls.create_test_server(wait_until="ACTIVE")
 
diff --git a/tempest/api/compute/v3/servers/test_server_rescue.py b/tempest/api/compute/v3/servers/test_server_rescue.py
index da58f26..ae21a7e 100644
--- a/tempest/api/compute/v3/servers/test_server_rescue.py
+++ b/tempest/api/compute/v3/servers/test_server_rescue.py
@@ -23,11 +23,11 @@
 class ServerRescueV3Test(base.BaseV3ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.compute_feature_enabled.rescue:
             msg = "Server rescue not available."
             raise cls.skipException(msg)
-        super(ServerRescueV3Test, cls).setUpClass()
+        super(ServerRescueV3Test, cls).resource_setup()
 
         # Server for positive tests
         resp, server = cls.create_test_server(wait_until='BUILD')
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 6d192a3..db26298 100644
--- a/tempest/api/compute/v3/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/v3/servers/test_server_rescue_negative.py
@@ -26,13 +26,12 @@
 class ServerRescueNegativeV3Test(base.BaseV3ComputeTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.compute_feature_enabled.rescue:
             msg = "Server rescue not available."
             raise cls.skipException(msg)
 
-        super(ServerRescueNegativeV3Test, cls).setUpClass()
+        super(ServerRescueNegativeV3Test, cls).resource_setup()
         cls.device = CONF.compute.volume_device_name
 
         # Create a volume and wait for it to become ready for attach
@@ -55,10 +54,10 @@
         cls.servers_client.wait_for_server_status(cls.server_id, 'ACTIVE')
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         if hasattr(cls, 'volume'):
             cls.delete_volume(cls.volume['id'])
-        super(ServerRescueNegativeV3Test, cls).tearDownClass()
+        super(ServerRescueNegativeV3Test, cls).resource_cleanup()
 
     def _detach(self, server_id, volume_id):
         self.servers_client.detach_volume(server_id, volume_id)
diff --git a/tempest/api/compute/v3/servers/test_servers.py b/tempest/api/compute/v3/servers/test_servers.py
index 426ee8d..e09f4a8 100644
--- a/tempest/api/compute/v3/servers/test_servers.py
+++ b/tempest/api/compute/v3/servers/test_servers.py
@@ -21,8 +21,8 @@
 class ServersV3Test(base.BaseV3ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ServersV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServersV3Test, cls).resource_setup()
         cls.client = cls.servers_client
 
     def tearDown(self):
diff --git a/tempest/api/compute/v3/servers/test_servers_negative.py b/tempest/api/compute/v3/servers/test_servers_negative.py
index f8ff7c8..4b1fe04 100644
--- a/tempest/api/compute/v3/servers/test_servers_negative.py
+++ b/tempest/api/compute/v3/servers/test_servers_negative.py
@@ -42,13 +42,10 @@
             super(ServersNegativeV3Test, self).tearDown()
 
     @classmethod
-    def setUpClass(cls):
-        super(ServersNegativeV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServersNegativeV3Test, cls).resource_setup()
         cls.client = cls.servers_client
-        if CONF.compute.allow_tenant_isolation:
-            cls.alt_os = clients.Manager(cls.isolated_creds.get_alt_creds())
-        else:
-            cls.alt_os = clients.AltManager()
+        cls.alt_os = clients.Manager(cls.isolated_creds.get_alt_creds())
         cls.alt_client = cls.alt_os.servers_v3_client
         resp, server = cls.create_test_server(wait_until='ACTIVE')
         cls.server_id = server['id']
diff --git a/tempest/api/compute/v3/test_live_block_migration.py b/tempest/api/compute/v3/test_live_block_migration.py
index 6ca37e6..d6231b7 100644
--- a/tempest/api/compute/v3/test_live_block_migration.py
+++ b/tempest/api/compute/v3/test_live_block_migration.py
@@ -26,8 +26,8 @@
     _host_key = 'os-extended-server-attributes:host'
 
     @classmethod
-    def setUpClass(cls):
-        super(LiveBlockMigrationV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(LiveBlockMigrationV3Test, cls).resource_setup()
 
         cls.admin_hosts_client = cls.hosts_admin_client
         cls.admin_servers_client = cls.servers_admin_client
diff --git a/tempest/api/compute/v3/test_live_block_migration_negative.py b/tempest/api/compute/v3/test_live_block_migration_negative.py
index b4ec505..93127f3 100644
--- a/tempest/api/compute/v3/test_live_block_migration_negative.py
+++ b/tempest/api/compute/v3/test_live_block_migration_negative.py
@@ -27,8 +27,8 @@
     _host_key = 'os-extended-server-attributes:host'
 
     @classmethod
-    def setUpClass(cls):
-        super(LiveBlockMigrationV3NegativeTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(LiveBlockMigrationV3NegativeTest, cls).resource_setup()
         if not CONF.compute_feature_enabled.live_migration:
             raise cls.skipException("Live migration is not enabled")
 
diff --git a/tempest/api/compute/v3/test_quotas.py b/tempest/api/compute/v3/test_quotas.py
index ecf70cf..f6d8b3f 100644
--- a/tempest/api/compute/v3/test_quotas.py
+++ b/tempest/api/compute/v3/test_quotas.py
@@ -26,8 +26,8 @@
         super(QuotasV3Test, self).setUp()
 
     @classmethod
-    def setUpClass(cls):
-        super(QuotasV3Test, cls).setUpClass()
+    def resource_setup(cls):
+        super(QuotasV3Test, cls).resource_setup()
         cls.client = cls.quotas_client
         cls.tenant_id = cls.client.tenant_id
         cls.user_id = cls.client.user_id
diff --git a/tempest/api/compute/volumes/test_attach_volume.py b/tempest/api/compute/volumes/test_attach_volume.py
index 5a64544..75f9795 100644
--- a/tempest/api/compute/volumes/test_attach_volume.py
+++ b/tempest/api/compute/volumes/test_attach_volume.py
@@ -27,27 +27,27 @@
 
     def __init__(self, *args, **kwargs):
         super(AttachVolumeTestJSON, self).__init__(*args, **kwargs)
-        self.server = None
-        self.volume = None
-        self.attached = False
+        self.attachment = None
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.prepare_instance_network()
-        super(AttachVolumeTestJSON, cls).setUpClass()
+        super(AttachVolumeTestJSON, cls).resource_setup()
         cls.device = CONF.compute.volume_device_name
         if not CONF.service_available.cinder:
             skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
 
     def _detach(self, server_id, volume_id):
-        if self.attached:
+        if self.attachment:
             self.servers_client.detach_volume(server_id, volume_id)
             self.volumes_client.wait_for_volume_status(volume_id, 'available')
 
     def _delete_volume(self):
+        # Delete the created Volumes
         if self.volume:
             self.volumes_client.delete_volume(self.volume['id'])
+            self.volumes_client.wait_for_resource_deletion(self.volume['id'])
             self.volume = None
 
     def _create_and_attach(self):
@@ -57,8 +57,8 @@
                                                  adminPass=admin_pass)
 
         # Record addresses so that we can ssh later
-        _, self.server['addresses'] = \
-            self.servers_client.list_addresses(self.server['id'])
+        _, self.server['addresses'] = (
+            self.servers_client.list_addresses(self.server['id']))
 
         # Create a volume and wait for it to become ready
         _, self.volume = self.volumes_client.create_volume(
@@ -68,12 +68,12 @@
                                                    'available')
 
         # Attach the volume to the server
-        self.servers_client.attach_volume(self.server['id'],
-                                          self.volume['id'],
-                                          device='/dev/%s' % self.device)
+        _, self.attachment = self.servers_client.attach_volume(
+            self.server['id'],
+            self.volume['id'],
+            device='/dev/%s' % self.device)
         self.volumes_client.wait_for_volume_status(self.volume['id'], 'in-use')
 
-        self.attached = True
         self.addCleanup(self._detach, self.server['id'], self.volume['id'])
 
     @testtools.skipUnless(CONF.compute.run_ssh, 'SSH required for this test')
@@ -97,8 +97,7 @@
         self.assertIn(self.device, partitions)
 
         self._detach(self.server['id'], self.volume['id'])
-        self.attached = False
-
+        self.attachment = None
         self.servers_client.stop(self.server['id'])
         self.servers_client.wait_for_server_status(self.server['id'],
                                                    'SHUTOFF')
@@ -112,6 +111,25 @@
         partitions = linux_client.get_partitions()
         self.assertNotIn(self.device, partitions)
 
+    @test.skip_because(bug="1323591", interface="xml")
+    @test.attr(type='gate')
+    def test_list_get_volume_attachments(self):
+        # Create Server, Volume and attach that Volume to Server
+        self._create_and_attach()
+        # List Volume attachment of the server
+        _, body = self.servers_client.list_volume_attachments(
+            self.server['id'])
+        self.assertEqual(1, len(body))
+        self.assertIn(self.attachment, body)
+
+        # Get Volume attachment of the server
+        _, body = self.servers_client.get_volume_attachment(
+            self.server['id'],
+            self.attachment['id'])
+        self.assertEqual(self.server['id'], body['serverId'])
+        self.assertEqual(self.volume['id'], body['volumeId'])
+        self.assertEqual(self.attachment['id'], body['id'])
+
 
 class AttachVolumeTestXML(AttachVolumeTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/volumes/test_volumes_get.py b/tempest/api/compute/volumes/test_volumes_get.py
index 708524c..4f77fa7 100644
--- a/tempest/api/compute/volumes/test_volumes_get.py
+++ b/tempest/api/compute/volumes/test_volumes_get.py
@@ -27,8 +27,8 @@
 class VolumesGetTestJSON(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(VolumesGetTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesGetTestJSON, cls).resource_setup()
         cls.client = cls.volumes_extensions_client
         if not CONF.service_available.cinder:
             skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
diff --git a/tempest/api/compute/volumes/test_volumes_list.py b/tempest/api/compute/volumes/test_volumes_list.py
index 25a8547..dc54c67 100644
--- a/tempest/api/compute/volumes/test_volumes_list.py
+++ b/tempest/api/compute/volumes/test_volumes_list.py
@@ -32,8 +32,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(VolumesTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesTestJSON, cls).resource_setup()
         cls.client = cls.volumes_extensions_client
         if not CONF.service_available.cinder:
             skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
@@ -69,11 +69,11 @@
                 raise
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         # Delete the created Volumes
         for volume in cls.volume_list:
             cls.delete_volume(volume['id'])
-        super(VolumesTestJSON, cls).tearDownClass()
+        super(VolumesTestJSON, cls).resource_cleanup()
 
     @test.attr(type='gate')
     def test_volume_list(self):
diff --git a/tempest/api/compute/volumes/test_volumes_negative.py b/tempest/api/compute/volumes/test_volumes_negative.py
index 5dfbad7..ad94ea7 100644
--- a/tempest/api/compute/volumes/test_volumes_negative.py
+++ b/tempest/api/compute/volumes/test_volumes_negative.py
@@ -27,8 +27,8 @@
 class VolumesNegativeTest(base.BaseV2ComputeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(VolumesNegativeTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesNegativeTest, cls).resource_setup()
         cls.client = cls.volumes_extensions_client
         if not CONF.service_available.cinder:
             skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
diff --git a/tempest/api/data_processing/base.py b/tempest/api/data_processing/base.py
index 65085b9..2ec1017 100644
--- a/tempest/api/data_processing/base.py
+++ b/tempest/api/data_processing/base.py
@@ -24,8 +24,8 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(BaseDataProcessingTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(BaseDataProcessingTest, cls).resource_setup()
         if not CONF.service_available.sahara:
             raise cls.skipException('Sahara support is required')
 
@@ -43,7 +43,7 @@
         cls._jobs = []
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.cleanup_resources(getattr(cls, '_cluster_templates', []),
                               cls.client.delete_cluster_template)
         cls.cleanup_resources(getattr(cls, '_node_group_templates', []),
@@ -56,7 +56,7 @@
         cls.cleanup_resources(getattr(cls, '_data_sources', []),
                               cls.client.delete_data_source)
         cls.clear_isolated_creds()
-        super(BaseDataProcessingTest, cls).tearDownClass()
+        super(BaseDataProcessingTest, cls).resource_cleanup()
 
     @staticmethod
     def cleanup_resources(resource_id_list, method):
diff --git a/tempest/api/data_processing/test_cluster_templates.py b/tempest/api/data_processing/test_cluster_templates.py
index ff67c1c..537f90c 100644
--- a/tempest/api/data_processing/test_cluster_templates.py
+++ b/tempest/api/data_processing/test_cluster_templates.py
@@ -22,9 +22,8 @@
     sahara/restapi/rest_api_v1.0.html#cluster-templates
     """
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(ClusterTemplateTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(ClusterTemplateTest, cls).resource_setup()
         # create node group template
         node_group_template = {
             'name': data_utils.rand_name('sahara-ng-template'),
diff --git a/tempest/api/data_processing/test_data_sources.py b/tempest/api/data_processing/test_data_sources.py
index aae56c4..3650751 100644
--- a/tempest/api/data_processing/test_data_sources.py
+++ b/tempest/api/data_processing/test_data_sources.py
@@ -19,8 +19,8 @@
 
 class DataSourceTest(dp_base.BaseDataProcessingTest):
     @classmethod
-    def setUpClass(cls):
-        super(DataSourceTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(DataSourceTest, cls).resource_setup()
         cls.swift_data_source_with_creds = {
             'url': 'swift://sahara-container.sahara/input-source',
             'description': 'Test data source',
diff --git a/tempest/api/data_processing/test_job_binaries.py b/tempest/api/data_processing/test_job_binaries.py
index 15ee145..d006991 100644
--- a/tempest/api/data_processing/test_job_binaries.py
+++ b/tempest/api/data_processing/test_job_binaries.py
@@ -22,9 +22,8 @@
     sahara/restapi/rest_api_v1.1_EDP.html#job-binaries
     """
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(JobBinaryTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(JobBinaryTest, cls).resource_setup()
         cls.swift_job_binary_with_extra = {
             'url': 'swift://sahara-container.sahara/example.jar',
             'description': 'Test job binary',
diff --git a/tempest/api/data_processing/test_job_binary_internals.py b/tempest/api/data_processing/test_job_binary_internals.py
index 45e1140..7e99867 100644
--- a/tempest/api/data_processing/test_job_binary_internals.py
+++ b/tempest/api/data_processing/test_job_binary_internals.py
@@ -22,8 +22,8 @@
     sahara/restapi/rest_api_v1.1_EDP.html#job-binary-internals
     """
     @classmethod
-    def setUpClass(cls):
-        super(JobBinaryInternalTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(JobBinaryInternalTest, cls).resource_setup()
         cls.job_binary_internal_data = 'Some script may be data'
 
     def _create_job_binary_internal(self, binary_name=None):
diff --git a/tempest/api/data_processing/test_jobs.py b/tempest/api/data_processing/test_jobs.py
index 8591dbd..5af2eef 100644
--- a/tempest/api/data_processing/test_jobs.py
+++ b/tempest/api/data_processing/test_jobs.py
@@ -22,9 +22,8 @@
     sahara/restapi/rest_api_v1.1_EDP.html#jobs
     """
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(JobTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(JobTest, cls).resource_setup()
         # create job binary
         job_binary = {
             'name': data_utils.rand_name('sahara-job-binary'),
diff --git a/tempest/api/data_processing/test_node_group_templates.py b/tempest/api/data_processing/test_node_group_templates.py
index c2c0075..f3f59fc 100644
--- a/tempest/api/data_processing/test_node_group_templates.py
+++ b/tempest/api/data_processing/test_node_group_templates.py
@@ -19,8 +19,8 @@
 
 class NodeGroupTemplateTest(dp_base.BaseDataProcessingTest):
     @classmethod
-    def setUpClass(cls):
-        super(NodeGroupTemplateTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(NodeGroupTemplateTest, cls).resource_setup()
         cls.node_group_template = {
             'description': 'Test node group template',
             'plugin_name': 'vanilla',
diff --git a/tempest/api/database/base.py b/tempest/api/database/base.py
index b68c84a..c9f16ca 100644
--- a/tempest/api/database/base.py
+++ b/tempest/api/database/base.py
@@ -25,11 +25,10 @@
     """Base test case class for all Database API tests."""
 
     _interface = 'json'
-    force_tenant_isolation = False
 
     @classmethod
-    def setUpClass(cls):
-        super(BaseDatabaseTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(BaseDatabaseTest, cls).resource_setup()
         if not CONF.service_available.trove:
             skip_msg = ("%s skipped as trove is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
diff --git a/tempest/api/database/flavors/test_flavors.py b/tempest/api/database/flavors/test_flavors.py
index a5c8caa..aed1abe 100644
--- a/tempest/api/database/flavors/test_flavors.py
+++ b/tempest/api/database/flavors/test_flavors.py
@@ -20,8 +20,8 @@
 class DatabaseFlavorsTest(base.BaseDatabaseTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(DatabaseFlavorsTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(DatabaseFlavorsTest, cls).resource_setup()
         cls.client = cls.database_flavors_client
 
     @test.attr(type='smoke')
diff --git a/tempest/api/database/flavors/test_flavors_negative.py b/tempest/api/database/flavors/test_flavors_negative.py
index 202dc48..9f14cce 100644
--- a/tempest/api/database/flavors/test_flavors_negative.py
+++ b/tempest/api/database/flavors/test_flavors_negative.py
@@ -21,8 +21,8 @@
 class DatabaseFlavorsNegativeTest(base.BaseDatabaseTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(DatabaseFlavorsNegativeTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(DatabaseFlavorsNegativeTest, cls).resource_setup()
         cls.client = cls.database_flavors_client
 
     @test.attr(type=['negative', 'gate'])
diff --git a/tempest/api/database/versions/test_versions.py b/tempest/api/database/versions/test_versions.py
index 453abe7..80fcecf 100644
--- a/tempest/api/database/versions/test_versions.py
+++ b/tempest/api/database/versions/test_versions.py
@@ -21,8 +21,8 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(DatabaseVersionsTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(DatabaseVersionsTest, cls).resource_setup()
         cls.client = cls.database_versions_client
 
     @test.attr(type='smoke')
diff --git a/tempest/api/identity/admin/test_roles.py b/tempest/api/identity/admin/test_roles.py
index 492d56f..d87d5c1 100644
--- a/tempest/api/identity/admin/test_roles.py
+++ b/tempest/api/identity/admin/test_roles.py
@@ -24,9 +24,8 @@
     _interface = 'json'
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(RolesTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(RolesTestJSON, cls).resource_setup()
         for _ in moves.xrange(5):
             role_name = data_utils.rand_name(name='role-')
             _, role = cls.client.create_role(role_name)
diff --git a/tempest/api/identity/admin/test_tokens.py b/tempest/api/identity/admin/test_tokens.py
index e1db008..2c5fb74 100644
--- a/tempest/api/identity/admin/test_tokens.py
+++ b/tempest/api/identity/admin/test_tokens.py
@@ -35,10 +35,9 @@
                                           tenant['id'], '')
         self.data.users.append(user)
         # then get a token for the user
-        rsp, body = self.token_client.auth(user_name,
-                                           user_password,
-                                           tenant['name'])
-        self.assertEqual(rsp['status'], '200')
+        _, body = self.token_client.auth(user_name,
+                                         user_password,
+                                         tenant['name'])
         self.assertEqual(body['token']['tenant']['name'],
                          tenant['name'])
         # Perform GET Token
@@ -89,15 +88,13 @@
                                      role['id'])
 
         # Get an unscoped token.
-        resp, body = self.token_client.auth(user_name, user_password)
-        self.assertEqual(200, resp.status)
+        _, body = self.token_client.auth(user_name, user_password)
 
         token_id = body['token']['id']
 
         # Use the unscoped token to get a token scoped to tenant1
-        resp, body = self.token_client.auth_token(token_id,
-                                                  tenant=tenant1_name)
-        self.assertEqual(200, resp.status)
+        _, body = self.token_client.auth_token(token_id,
+                                               tenant=tenant1_name)
 
         scoped_token_id = body['token']['id']
 
@@ -105,9 +102,8 @@
         self.client.delete_token(scoped_token_id)
 
         # Use the unscoped token to get a token scoped to tenant2
-        resp, body = self.token_client.auth_token(token_id,
-                                                  tenant=tenant2_name)
-        self.assertEqual(200, resp.status)
+        _, body = self.token_client.auth_token(token_id,
+                                               tenant=tenant2_name)
 
 
 class TokensTestXML(TokensTestJSON):
diff --git a/tempest/api/identity/admin/test_users.py b/tempest/api/identity/admin/test_users.py
index 5838da3..66a1737 100644
--- a/tempest/api/identity/admin/test_users.py
+++ b/tempest/api/identity/admin/test_users.py
@@ -24,8 +24,8 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(UsersTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(UsersTestJSON, cls).resource_setup()
         cls.alt_user = data_utils.rand_name('test_user_')
         cls.alt_password = data_utils.rand_name('pass_')
         cls.alt_email = cls.alt_user + '@testmail.tm'
@@ -97,10 +97,9 @@
         self.token_client.auth(self.data.test_user, self.data.test_password,
                                self.data.test_tenant)
         # Re-auth
-        resp, body = self.token_client.auth(self.data.test_user,
-                                            self.data.test_password,
-                                            self.data.test_tenant)
-        self.assertEqual('200', resp['status'])
+        self.token_client.auth(self.data.test_user,
+                               self.data.test_password,
+                               self.data.test_tenant)
 
     @test.attr(type='gate')
     def test_authentication_request_without_token(self):
@@ -113,10 +112,9 @@
         # Delete the token from database
         self.client.delete_token(token)
         # Re-auth
-        resp, body = self.token_client.auth(self.data.test_user,
-                                            self.data.test_password,
-                                            self.data.test_tenant)
-        self.assertEqual('200', resp['status'])
+        self.token_client.auth(self.data.test_user,
+                               self.data.test_password,
+                               self.data.test_tenant)
         self.client.auth_provider.clear_auth()
 
     @test.attr(type='smoke')
@@ -205,9 +203,8 @@
 
         # Validate the updated password
         # Get a token
-        resp, body = self.token_client.auth(self.data.test_user, new_pass,
-                                            self.data.test_tenant)
-        self.assertEqual('200', resp['status'])
+        _, body = self.token_client.auth(self.data.test_user, new_pass,
+                                         self.data.test_tenant)
         self.assertTrue('id' in body['token'])
 
 
diff --git a/tempest/api/identity/admin/test_users_negative.py b/tempest/api/identity/admin/test_users_negative.py
index a584a7b..bad2b89 100644
--- a/tempest/api/identity/admin/test_users_negative.py
+++ b/tempest/api/identity/admin/test_users_negative.py
@@ -25,8 +25,8 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(UsersNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(UsersNegativeTestJSON, cls).resource_setup()
         cls.alt_user = data_utils.rand_name('test_user_')
         cls.alt_password = data_utils.rand_name('pass_')
         cls.alt_email = cls.alt_user + '@testmail.tm'
diff --git a/tempest/api/identity/admin/v3/test_credentials.py b/tempest/api/identity/admin/v3/test_credentials.py
index d40e0f3..7a0edb0 100644
--- a/tempest/api/identity/admin/v3/test_credentials.py
+++ b/tempest/api/identity/admin/v3/test_credentials.py
@@ -22,9 +22,8 @@
     _interface = 'json'
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(CredentialsTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(CredentialsTestJSON, cls).resource_setup()
         cls.projects = list()
         cls.creds_list = [['project_id', 'user_id', 'id'],
                           ['access', 'secret']]
@@ -43,25 +42,23 @@
             email=u_email, project_id=cls.projects[0])
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.client.delete_user(cls.user_body['id'])
         for p in cls.projects:
             cls.client.delete_project(p)
-        super(CredentialsTestJSON, cls).tearDownClass()
+        super(CredentialsTestJSON, cls).resource_cleanup()
 
     def _delete_credential(self, cred_id):
-        resp, body = self.creds_client.delete_credential(cred_id)
-        self.assertEqual(resp['status'], '204')
+        self.creds_client.delete_credential(cred_id)
 
     @test.attr(type='smoke')
     def test_credentials_create_get_update_delete(self):
         keys = [data_utils.rand_name('Access-'),
                 data_utils.rand_name('Secret-')]
-        resp, cred = self.creds_client.create_credential(
+        _, cred = self.creds_client.create_credential(
             keys[0], keys[1], self.user_body['id'],
             self.projects[0])
         self.addCleanup(self._delete_credential, cred['id'])
-        self.assertEqual(resp['status'], '201')
         for value1 in self.creds_list[0]:
             self.assertIn(value1, cred)
         for value2 in self.creds_list[1]:
@@ -69,18 +66,16 @@
 
         new_keys = [data_utils.rand_name('NewAccess-'),
                     data_utils.rand_name('NewSecret-')]
-        resp, update_body = self.creds_client.update_credential(
+        _, update_body = self.creds_client.update_credential(
             cred['id'], access_key=new_keys[0], secret_key=new_keys[1],
             project_id=self.projects[1])
-        self.assertEqual(resp['status'], '200')
         self.assertEqual(cred['id'], update_body['id'])
         self.assertEqual(self.projects[1], update_body['project_id'])
         self.assertEqual(self.user_body['id'], update_body['user_id'])
         self.assertEqual(update_body['blob']['access'], new_keys[0])
         self.assertEqual(update_body['blob']['secret'], new_keys[1])
 
-        resp, get_body = self.creds_client.get_credential(cred['id'])
-        self.assertEqual(resp['status'], '200')
+        _, get_body = self.creds_client.get_credential(cred['id'])
         for value1 in self.creds_list[0]:
             self.assertEqual(update_body[value1],
                              get_body[value1])
@@ -94,16 +89,14 @@
         fetched_cred_ids = list()
 
         for i in range(2):
-            resp, cred = self.creds_client.create_credential(
+            _, cred = self.creds_client.create_credential(
                 data_utils.rand_name('Access-'),
                 data_utils.rand_name('Secret-'),
                 self.user_body['id'], self.projects[0])
-            self.assertEqual(resp['status'], '201')
             created_cred_ids.append(cred['id'])
             self.addCleanup(self._delete_credential, cred['id'])
 
-        resp, creds = self.creds_client.list_credentials()
-        self.assertEqual(resp['status'], '200')
+        _, creds = self.creds_client.list_credentials()
 
         for i in creds:
             fetched_cred_ids.append(i['id'])
diff --git a/tempest/api/identity/admin/v3/test_endpoints.py b/tempest/api/identity/admin/v3/test_endpoints.py
index 6beb8f2..676f101 100644
--- a/tempest/api/identity/admin/v3/test_endpoints.py
+++ b/tempest/api/identity/admin/v3/test_endpoints.py
@@ -22,9 +22,8 @@
     _interface = 'json'
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(EndPointsTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(EndPointsTestJSON, cls).resource_setup()
         cls.identity_client = cls.client
         cls.client = cls.endpoints_client
         cls.service_ids = list()
@@ -47,19 +46,18 @@
             cls.setup_endpoints.append(endpoint)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         for e in cls.setup_endpoints:
             cls.client.delete_endpoint(e['id'])
         for s in cls.service_ids:
             cls.service_client.delete_service(s)
-        super(EndPointsTestJSON, cls).tearDownClass()
+        super(EndPointsTestJSON, cls).resource_cleanup()
 
     @test.attr(type='gate')
     def test_list_endpoints(self):
         # Get a list of endpoints
-        resp, fetched_endpoints = self.client.list_endpoints()
+        _, fetched_endpoints = self.client.list_endpoints()
         # Asserting LIST endpoints
-        self.assertEqual(resp['status'], '200')
         missing_endpoints =\
             [e for e in self.setup_endpoints if e not in fetched_endpoints]
         self.assertEqual(0, len(missing_endpoints),
@@ -71,11 +69,10 @@
         region = data_utils.rand_name('region')
         url = data_utils.rand_url()
         interface = 'public'
-        resp, endpoint =\
+        _, endpoint =\
             self.client.create_endpoint(self.service_id, interface, url,
                                         region=region, enabled=True)
         # Asserting Create Endpoint response body
-        self.assertEqual(resp['status'], '201')
         self.assertIn('id', endpoint)
         self.assertEqual(region, endpoint['region'])
         self.assertEqual(url, endpoint['url'])
@@ -84,9 +81,7 @@
         fetched_endpoints_id = [e['id'] for e in fetched_endpoints]
         self.assertIn(endpoint['id'], fetched_endpoints_id)
         # Deleting the endpoint created in this method
-        resp, body = self.client.delete_endpoint(endpoint['id'])
-        self.assertEqual(resp['status'], '204')
-        self.assertEqual(body, '')
+        self.client.delete_endpoint(endpoint['id'])
         # Checking whether endpoint is deleted successfully
         resp, fetched_endpoints = self.client.list_endpoints()
         fetched_endpoints_id = [e['id'] for e in fetched_endpoints]
@@ -116,12 +111,11 @@
         region2 = data_utils.rand_name('region')
         url2 = data_utils.rand_url()
         interface2 = 'internal'
-        resp, endpoint = \
+        _, endpoint = \
             self.client.update_endpoint(endpoint_for_update['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(service2['id'], endpoint['service_id'])
         self.assertEqual(interface2, endpoint['interface'])
diff --git a/tempest/api/identity/admin/v3/test_endpoints_negative.py b/tempest/api/identity/admin/v3/test_endpoints_negative.py
index d728b1d..b987d12 100644
--- a/tempest/api/identity/admin/v3/test_endpoints_negative.py
+++ b/tempest/api/identity/admin/v3/test_endpoints_negative.py
@@ -25,8 +25,8 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(EndpointsNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(EndpointsNegativeTestJSON, cls).resource_setup()
         cls.identity_client = cls.client
         cls.client = cls.endpoints_client
         cls.service_ids = list()
@@ -40,10 +40,10 @@
         cls.service_ids.append(cls.service_id)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         for s in cls.service_ids:
             cls.service_client.delete_service(s)
-        super(EndpointsNegativeTestJSON, cls).tearDownClass()
+        super(EndpointsNegativeTestJSON, cls).resource_cleanup()
 
     @test.attr(type=['negative', 'gate'])
     def test_create_with_enabled_False(self):
diff --git a/tempest/api/identity/admin/v3/test_groups.py b/tempest/api/identity/admin/v3/test_groups.py
index 4d2cc46..987a9d5 100644
--- a/tempest/api/identity/admin/v3/test_groups.py
+++ b/tempest/api/identity/admin/v3/test_groups.py
@@ -22,8 +22,8 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(GroupsV3TestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(GroupsV3TestJSON, cls).resource_setup()
 
     @test.attr(type='smoke')
     def test_group_create_update_get(self):
diff --git a/tempest/api/identity/admin/v3/test_list_projects.py b/tempest/api/identity/admin/v3/test_list_projects.py
index a3944e2..be06c7f 100644
--- a/tempest/api/identity/admin/v3/test_list_projects.py
+++ b/tempest/api/identity/admin/v3/test_list_projects.py
@@ -22,8 +22,8 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(ListProjectsTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ListProjectsTestJSON, cls).resource_setup()
         cls.project_ids = list()
         cls.data.setup_test_domain()
         # Create project with domain
diff --git a/tempest/api/identity/admin/v3/test_list_users.py b/tempest/api/identity/admin/v3/test_list_users.py
index 497c5ea..903ad5c 100644
--- a/tempest/api/identity/admin/v3/test_list_users.py
+++ b/tempest/api/identity/admin/v3/test_list_users.py
@@ -32,8 +32,8 @@
                          map(lambda x: x[key], body))
 
     @classmethod
-    def setUpClass(cls):
-        super(UsersV3TestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(UsersV3TestJSON, cls).resource_setup()
         alt_user = data_utils.rand_name('test_user')
         alt_password = data_utils.rand_name('pass')
         cls.alt_email = alt_user + '@testmail.tm'
diff --git a/tempest/api/identity/admin/v3/test_policies.py b/tempest/api/identity/admin/v3/test_policies.py
index 0e79440..65c5230 100644
--- a/tempest/api/identity/admin/v3/test_policies.py
+++ b/tempest/api/identity/admin/v3/test_policies.py
@@ -22,8 +22,7 @@
     _interface = 'json'
 
     def _delete_policy(self, policy_id):
-        resp, _ = self.policy_client.delete_policy(policy_id)
-        self.assertEqual(204, resp.status)
+        self.policy_client.delete_policy(policy_id)
 
     @test.attr(type='smoke')
     def test_list_policies(self):
@@ -39,8 +38,7 @@
             self.addCleanup(self._delete_policy, policy['id'])
             policy_ids.append(policy['id'])
         # List and Verify Policies
-        resp, body = self.policy_client.list_policies()
-        self.assertEqual(resp['status'], '200')
+        _, body = self.policy_client.list_policies()
         for p in body:
             fetched_ids.append(p['id'])
         missing_pols = [p for p in policy_ids if p not in fetched_ids]
@@ -51,7 +49,7 @@
         # Test to update policy
         blob = data_utils.rand_name('BlobName-')
         policy_type = data_utils.rand_name('PolicyType-')
-        resp, policy = self.policy_client.create_policy(blob, policy_type)
+        _, policy = self.policy_client.create_policy(blob, policy_type)
         self.addCleanup(self._delete_policy, policy['id'])
         self.assertIn('id', policy)
         self.assertIn('type', policy)
@@ -59,15 +57,13 @@
         self.assertIsNotNone(policy['id'])
         self.assertEqual(blob, policy['blob'])
         self.assertEqual(policy_type, policy['type'])
-        resp, fetched_policy = self.policy_client.get_policy(policy['id'])
-        self.assertEqual(resp['status'], '200')
         # Update policy
         update_type = data_utils.rand_name('UpdatedPolicyType-')
-        resp, data = self.policy_client.update_policy(
+        _, data = self.policy_client.update_policy(
             policy['id'], type=update_type)
         self.assertIn('type', data)
         # Assertion for updated value with fetched value
-        resp, fetched_policy = self.policy_client.get_policy(policy['id'])
+        _, fetched_policy = self.policy_client.get_policy(policy['id'])
         self.assertIn('id', fetched_policy)
         self.assertIn('blob', fetched_policy)
         self.assertIn('type', fetched_policy)
diff --git a/tempest/api/identity/admin/v3/test_regions.py b/tempest/api/identity/admin/v3/test_regions.py
index c8b034f..c5d5824 100644
--- a/tempest/api/identity/admin/v3/test_regions.py
+++ b/tempest/api/identity/admin/v3/test_regions.py
@@ -23,9 +23,8 @@
     _interface = 'json'
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(RegionsTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(RegionsTestJSON, cls).resource_setup()
         cls.setup_regions = list()
         cls.client = cls.region_client
         for i in range(2):
@@ -34,40 +33,36 @@
             cls.setup_regions.append(region)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         for r in cls.setup_regions:
             cls.client.delete_region(r['id'])
-        super(RegionsTestJSON, cls).tearDownClass()
+        super(RegionsTestJSON, cls).resource_cleanup()
 
     def _delete_region(self, region_id):
-        resp, _ = self.client.delete_region(region_id)
-        self.assertEqual(204, resp.status)
+        self.client.delete_region(region_id)
         self.assertRaises(exceptions.NotFound,
                           self.client.get_region, region_id)
 
     @test.attr(type='gate')
     def test_create_update_get_delete_region(self):
         r_description = data_utils.rand_name('description-')
-        resp, region = self.client.create_region(
+        _, region = self.client.create_region(
             r_description, parent_region_id=self.setup_regions[0]['id'])
-        self.assertEqual(201, resp.status)
         self.addCleanup(self._delete_region, region['id'])
         self.assertEqual(r_description, region['description'])
         self.assertEqual(self.setup_regions[0]['id'],
                          region['parent_region_id'])
         # Update region with new description and parent ID
         r_alt_description = data_utils.rand_name('description-')
-        resp, region = self.client.update_region(
+        _, region = self.client.update_region(
             region['id'],
             description=r_alt_description,
             parent_region_id=self.setup_regions[1]['id'])
-        self.assertEqual(200, resp.status)
         self.assertEqual(r_alt_description, region['description'])
         self.assertEqual(self.setup_regions[1]['id'],
                          region['parent_region_id'])
         # Get the details of region
-        resp, region = self.client.get_region(region['id'])
-        self.assertEqual(200, resp.status)
+        _, region = self.client.get_region(region['id'])
         self.assertEqual(r_alt_description, region['description'])
         self.assertEqual(self.setup_regions[1]['id'],
                          region['parent_region_id'])
@@ -77,19 +72,17 @@
         # Create a region with a specific id
         r_region_id = data_utils.rand_uuid()
         r_description = data_utils.rand_name('description-')
-        resp, region = self.client.create_region(
+        _, region = self.client.create_region(
             r_description, unique_region_id=r_region_id)
         self.addCleanup(self._delete_region, region['id'])
         # Asserting Create Region with specific id response body
-        self.assertEqual(201, resp.status)
         self.assertEqual(r_region_id, region['id'])
         self.assertEqual(r_description, region['description'])
 
     @test.attr(type='gate')
     def test_list_regions(self):
         # Get a list of regions
-        resp, fetched_regions = self.client.list_regions()
-        self.assertEqual(200, resp.status)
+        _, fetched_regions = self.client.list_regions()
         missing_regions =\
             [e for e in self.setup_regions if e not in fetched_regions]
         # Asserting List Regions response
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
index 2e732fe..5e14a04 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -22,9 +22,8 @@
     _interface = 'json'
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(RolesV3TestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(RolesV3TestJSON, cls).resource_setup()
         for _ in range(3):
             role_name = data_utils.rand_name(name='role-')
             _, role = cls.client.create_role(role_name)
@@ -52,7 +51,7 @@
             data_utils.rand_name('Role-'))
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.client.delete_role(cls.role['id'])
         cls.client.delete_group(cls.group_body['id'])
         cls.client.delete_user(cls.user_body['id'])
@@ -61,7 +60,7 @@
         # before deleting,or else it would result in unauthorized error
         cls.client.update_domain(cls.domain['id'], enabled=False)
         cls.client.delete_domain(cls.domain['id'])
-        super(RolesV3TestJSON, cls).tearDownClass()
+        super(RolesV3TestJSON, cls).resource_cleanup()
 
     def _list_assertions(self, body, fetched_role_ids, role_id):
         self.assertEqual(len(body), 1)
@@ -141,11 +140,10 @@
         self.client.add_group_user(self.group_body['id'], self.user_body['id'])
         self.addCleanup(self.client.delete_group_user,
                         self.group_body['id'], self.user_body['id'])
-        resp, body = self.token.auth(self.user_body['id'], self.u_password,
-                                     self.project['name'],
-                                     domain=self.domain['name'])
+        _, body = self.token.auth(self.user_body['id'], self.u_password,
+                                  self.project['name'],
+                                  domain=self.domain['name'])
         roles = body['token']['roles']
-        self.assertEqual(resp['status'], '201')
         self.assertEqual(len(roles), 1)
         self.assertEqual(roles[0]['id'], self.role['id'])
         # Revoke role to group on project
diff --git a/tempest/api/identity/admin/v3/test_services.py b/tempest/api/identity/admin/v3/test_services.py
index f6078da..7e21cc3 100644
--- a/tempest/api/identity/admin/v3/test_services.py
+++ b/tempest/api/identity/admin/v3/test_services.py
@@ -13,41 +13,84 @@
 #    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 exceptions
 from tempest import test
 
 
 class ServicesTestJSON(base.BaseIdentityV3AdminTest):
     _interface = 'json'
 
-    @test.attr(type='gate')
-    def test_update_service(self):
-        # Update description attribute of service
-        name = data_utils.rand_name('service-')
-        serv_type = data_utils.rand_name('type--')
-        desc = data_utils.rand_name('description-')
-        _, 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'])
+    def _del_service(self, service_id):
+        # Used for deleting the services created in this class
+        self.service_client.delete_service(service_id)
+        # Checking whether service is deleted successfully
+        self.assertRaises(exceptions.NotFound, self.service_client.get_service,
+                          service_id)
 
-        s_id = body['id']
-        resp1_desc = body['description']
+    @test.attr(type='smoke')
+    def test_create_update_get_service(self):
+        # Creating a Service
+        name = data_utils.rand_name('service')
+        serv_type = data_utils.rand_name('type')
+        desc = data_utils.rand_name('description')
+        _, create_service = self.service_client.create_service(
+            serv_type, name=name, description=desc)
+        self.addCleanup(self._del_service, create_service['id'])
+        self.assertIsNotNone(create_service['id'])
 
-        s_desc2 = data_utils.rand_name('desc2-')
-        _, body = self.service_client.update_service(
+        # Verifying response body of create service
+        expected_data = {'name': name, 'type': serv_type, 'description': desc}
+        self.assertDictContainsSubset(expected_data, create_service)
+
+        # Update description
+        s_id = create_service['id']
+        resp1_desc = create_service['description']
+        s_desc2 = data_utils.rand_name('desc2')
+        _, update_service = self.service_client.update_service(
             s_id, description=s_desc2)
-        resp2_desc = body['description']
+        resp2_desc = update_service['description']
+
         self.assertNotEqual(resp1_desc, resp2_desc)
 
         # Get service
-        _, body = self.service_client.get_service(s_id)
-        resp3_desc = body['description']
+        _, fetched_service = self.service_client.get_service(s_id)
+        resp3_desc = fetched_service['description']
 
-        self.assertNotEqual(resp1_desc, resp3_desc)
         self.assertEqual(resp2_desc, resp3_desc)
+        self.assertDictContainsSubset(update_service, fetched_service)
+
+    @test.attr(type='smoke')
+    def test_create_service_without_description(self):
+        # Create a service only with name and type
+        name = data_utils.rand_name('service')
+        serv_type = data_utils.rand_name('type')
+        _, service = self.service_client.create_service(
+            serv_type, name=name)
+        self.addCleanup(self.service_client.delete_service, service['id'])
+        self.assertIn('id', service)
+        expected_data = {'name': name, 'type': serv_type}
+        self.assertDictContainsSubset(expected_data, service)
+
+    @test.attr(type='smoke')
+    def test_list_services(self):
+        # Create, List, Verify and Delete Services
+        service_ids = list()
+        for _ in range(3):
+            name = data_utils.rand_name('service')
+            serv_type = data_utils.rand_name('type')
+            _, create_service = self.service_client.create_service(
+                serv_type, name=name)
+            self.addCleanup(self.service_client.delete_service,
+                            create_service['id'])
+            service_ids.append(create_service['id'])
+
+        # List and Verify Services
+        _, services = self.service_client.list_services()
+        fetched_ids = [service['id'] for service in services]
+        found = [s for s in fetched_ids if s in service_ids]
+        self.assertEqual(len(found), len(service_ids))
 
 
 class ServicesTestXML(ServicesTestJSON):
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index bd08614..230e09f 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -35,8 +35,7 @@
             email=u_email)
         self.addCleanup(self.client.delete_user, user['id'])
         # Perform Authentication
-        resp, body = self.token.auth(user['id'], u_password)
-        self.assertEqual(201, resp.status)
+        resp, _ = self.token.auth(user['id'], u_password)
         subject_token = resp['x-subject-token']
         # Perform GET Token
         _, token_details = self.client.get_token(subject_token)
@@ -48,7 +47,6 @@
         self.assertRaises(exceptions.NotFound, self.client.get_token,
                           subject_token)
 
-    @test.skip_because(bug="1351026")
     @test.attr(type='gate')
     def test_rescope_token(self):
         """Rescope a token.
@@ -89,7 +87,6 @@
         # Get an unscoped token.
         resp, token_auth = self.token.auth(user=user['id'],
                                            password=user_password)
-        self.assertEqual(201, resp.status)
 
         token_id = resp['x-subject-token']
         orig_expires_at = token_auth['token']['expires_at']
@@ -114,7 +111,6 @@
                                            tenant=project1_name,
                                            domain='Default')
         token1_id = resp['x-subject-token']
-        self.assertEqual(201, resp.status)
 
         self.assertEqual(orig_expires_at, token_auth['token']['expires_at'],
                          'Expiration time should match original token')
@@ -141,10 +137,9 @@
         self.client.delete_token(token1_id)
 
         # Now get another scoped token using the unscoped token.
-        resp, token_auth = self.token.auth(token=token_id,
-                                           tenant=project2_name,
-                                           domain='Default')
-        self.assertEqual(201, resp.status)
+        _, token_auth = self.token.auth(token=token_id,
+                                        tenant=project2_name,
+                                        domain='Default')
 
         self.assertEqual(project2['id'],
                          token_auth['token']['project']['id'])
diff --git a/tempest/api/identity/admin/v3/test_users.py b/tempest/api/identity/admin/v3/test_users.py
index 3c25819..898bcd0 100644
--- a/tempest/api/identity/admin/v3/test_users.py
+++ b/tempest/api/identity/admin/v3/test_users.py
@@ -77,8 +77,7 @@
         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)
+        resp, _ = self.token.auth(user['id'], new_password)
         subject_token = resp['x-subject-token']
         # Perform GET Token to verify and confirm password is updated
         _, token_details = self.client.get_token(subject_token)
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index 3996cc1..244323e 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -29,8 +29,11 @@
 class BaseIdentityAdminTest(tempest.test.BaseTestCase):
 
     @classmethod
-    def setUpClass(cls):
-        super(BaseIdentityAdminTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(BaseIdentityAdminTest, cls).resource_setup()
+        if getattr(cls, '_interface', None) == 'xml':
+            if not CONF.identity_feature_enabled.xml_api:
+                raise cls.skipException('XML API is not enabled')
         cls.os_adm = clients.AdminManager(interface=cls._interface)
         cls.os = clients.Manager(interface=cls._interface)
 
@@ -72,10 +75,10 @@
 class BaseIdentityV2AdminTest(BaseIdentityAdminTest):
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.identity_feature_enabled.api_v2:
             raise cls.skipException("Identity api v2 is not enabled")
-        super(BaseIdentityV2AdminTest, cls).setUpClass()
+        super(BaseIdentityV2AdminTest, cls).resource_setup()
         cls.client = cls.os_adm.identity_client
         cls.token_client = cls.os_adm.token_client
         if not cls.client.has_admin_extensions():
@@ -84,18 +87,18 @@
         cls.non_admin_client = cls.os.identity_client
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.data.teardown_all()
-        super(BaseIdentityV2AdminTest, cls).tearDownClass()
+        super(BaseIdentityV2AdminTest, cls).resource_cleanup()
 
 
 class BaseIdentityV3AdminTest(BaseIdentityAdminTest):
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.identity_feature_enabled.api_v3:
             raise cls.skipException("Identity api v3 is not enabled")
-        super(BaseIdentityV3AdminTest, cls).setUpClass()
+        super(BaseIdentityV3AdminTest, cls).resource_setup()
         cls.client = cls.os_adm.identity_v3_client
         cls.token = cls.os_adm.token_v3_client
         cls.endpoints_client = cls.os_adm.endpoints_client
@@ -108,9 +111,9 @@
         cls.non_admin_client = cls.os.identity_v3_client
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.data.teardown_all()
-        super(BaseIdentityV3AdminTest, cls).tearDownClass()
+        super(BaseIdentityV3AdminTest, cls).resource_cleanup()
 
 
 class DataGenerator(object):
@@ -202,7 +205,7 @@
         def _try_wrapper(func, item, **kwargs):
             try:
                 if kwargs:
-                    func(item['id'], kwargs)
+                    func(item['id'], **kwargs)
                 else:
                     func(item['id'])
             except exceptions.NotFound:
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index c875b2f..74baba6 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -31,9 +31,9 @@
     """Base test class for Image API tests."""
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.set_network_resources()
-        super(BaseImageTest, cls).setUpClass()
+        super(BaseImageTest, cls).resource_setup()
         cls.created_images = []
         cls._interface = 'json'
         cls.isolated_creds = isolated_creds.IsolatedCreds(
@@ -41,13 +41,10 @@
         if not CONF.service_available.glance:
             skip_msg = ("%s skipped as glance is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
-        if CONF.compute.allow_tenant_isolation:
-            cls.os = clients.Manager(cls.isolated_creds.get_primary_creds())
-        else:
-            cls.os = clients.Manager()
+        cls.os = clients.Manager(cls.isolated_creds.get_primary_creds())
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         for image_id in cls.created_images:
             try:
                 cls.client.delete_image(image_id)
@@ -57,7 +54,7 @@
         for image_id in cls.created_images:
                 cls.client.wait_for_resource_deletion(image_id)
         cls.isolated_creds.clear_isolated_creds()
-        super(BaseImageTest, cls).tearDownClass()
+        super(BaseImageTest, cls).resource_cleanup()
 
     @classmethod
     def create_image(cls, **kwargs):
@@ -79,8 +76,8 @@
 class BaseV1ImageTest(BaseImageTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(BaseV1ImageTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(BaseV1ImageTest, cls).resource_setup()
         cls.client = cls.os.image_client
         if not CONF.image_feature_enabled.api_v1:
             msg = "Glance API v1 not supported"
@@ -89,12 +86,9 @@
 
 class BaseV1ImageMembersTest(BaseV1ImageTest):
     @classmethod
-    def setUpClass(cls):
-        super(BaseV1ImageMembersTest, cls).setUpClass()
-        if CONF.compute.allow_tenant_isolation:
-            cls.os_alt = clients.Manager(cls.isolated_creds.get_alt_creds())
-        else:
-            cls.os_alt = clients.AltManager()
+    def resource_setup(cls):
+        super(BaseV1ImageMembersTest, cls).resource_setup()
+        cls.os_alt = clients.Manager(cls.isolated_creds.get_alt_creds())
 
         cls.alt_img_cli = cls.os_alt.image_client
         cls.alt_tenant_id = cls.alt_img_cli.tenant_id
@@ -113,8 +107,8 @@
 class BaseV2ImageTest(BaseImageTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(BaseV2ImageTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(BaseV2ImageTest, cls).resource_setup()
         cls.client = cls.os.image_client_v2
         if not CONF.image_feature_enabled.api_v2:
             msg = "Glance API v2 not supported"
@@ -124,13 +118,10 @@
 class BaseV2MemberImageTest(BaseV2ImageTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(BaseV2MemberImageTest, cls).setUpClass()
-        if CONF.compute.allow_tenant_isolation:
-            creds = cls.isolated_creds.get_alt_creds()
-            cls.os_alt = clients.Manager(creds)
-        else:
-            cls.os_alt = clients.AltManager()
+    def resource_setup(cls):
+        super(BaseV2MemberImageTest, cls).resource_setup()
+        creds = cls.isolated_creds.get_alt_creds()
+        cls.os_alt = clients.Manager(creds)
         cls.os_img_client = cls.os.image_client_v2
         cls.alt_img_client = cls.os_alt.image_client_v2
         cls.alt_tenant_id = cls.alt_img_client.tenant_id
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index bf55b89..38a623a 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -106,9 +106,8 @@
     """
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(ListImagesTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(ListImagesTest, cls).resource_setup()
         # We add a few images here to test the listing functionality of
         # the images API
         img1 = cls._create_remote_image('one', 'bare', 'raw')
@@ -235,8 +234,7 @@
 
 class ListSnapshotImagesTest(base.BaseV1ImageTest):
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
+    def resource_setup(cls):
         # This test class only uses nova v3 api to create snapshot
         # as the similar test which uses nova v2 api already exists
         # in nova v2 compute images api tests.
@@ -246,7 +244,7 @@
             skip_msg = ("%s skipped as nova v3 api is not available" %
                         cls.__name__)
             raise cls.skipException(skip_msg)
-        super(ListSnapshotImagesTest, cls).setUpClass()
+        super(ListSnapshotImagesTest, cls).resource_setup()
         cls.servers_client = cls.os.servers_v3_client
         cls.servers = []
         # We add a few images here to test the listing functionality of
@@ -265,10 +263,10 @@
         cls.client.wait_for_image_status(image['id'], 'active')
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         for server in getattr(cls, "servers", []):
             cls.servers_client.delete_server(server['id'])
-        super(ListSnapshotImagesTest, cls).tearDownClass()
+        super(ListSnapshotImagesTest, cls).resource_cleanup()
 
     @classmethod
     def _create_snapshot(cls, name, image_id, flavor, **kwargs):
@@ -329,8 +327,8 @@
 
 class UpdateImageMetaTest(base.BaseV1ImageTest):
     @classmethod
-    def setUpClass(cls):
-        super(UpdateImageMetaTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(UpdateImageMetaTest, cls).resource_setup()
         cls.image_id = cls._create_standard_image('1', 'ami', 'ami', 42)
 
     @classmethod
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index a974ebb..7e018e5 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -125,9 +125,8 @@
     """
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(ListImagesTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(ListImagesTest, cls).resource_setup()
         # We add a few images here to test the listing functionality of
         # the images API
         cls._create_standard_image('bare', 'raw')
diff --git a/tempest/api/queuing/__init__.py b/tempest/api/messaging/__init__.py
similarity index 100%
rename from tempest/api/queuing/__init__.py
rename to tempest/api/messaging/__init__.py
diff --git a/tempest/api/queuing/base.py b/tempest/api/messaging/base.py
similarity index 78%
rename from tempest/api/queuing/base.py
rename to tempest/api/messaging/base.py
index 41a02f2..58511a9 100644
--- a/tempest/api/queuing/base.py
+++ b/tempest/api/messaging/base.py
@@ -23,25 +23,25 @@
 LOG = logging.getLogger(__name__)
 
 
-class BaseQueuingTest(test.BaseTestCase):
+class BaseMessagingTest(test.BaseTestCase):
 
     """
-    Base class for the Queuing tests that use the Tempest Zaqar REST client
+    Base class for the Messaging tests that use the Tempest Zaqar REST client
 
     It is assumed that the following option is defined in the
     [service_available] section of etc/tempest.conf
 
-        queuing as True
+        messaging as True
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(BaseQueuingTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(BaseMessagingTest, cls).resource_setup()
         if not CONF.service_available.zaqar:
             raise cls.skipException("Zaqar support is required")
         os = cls.get_client_manager()
-        cls.queuing_cfg = CONF.queuing
-        cls.client = os.queuing_client
+        cls.messaging_cfg = CONF.messaging
+        cls.client = os.messaging_client
 
     @classmethod
     def create_queue(cls, queue_name):
@@ -93,42 +93,42 @@
 
     @classmethod
     def post_messages(cls, queue_name, rbody):
-        '''Wrapper utility that posts messages to a queue.'''
+        """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.'''
+        """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.'''
+        """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.'''
+        """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.'''
+        """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.'''
+        """Wrapper utility that claims messages."""
         resp, body = cls.client.post_claims(
             queue_name, rbody, url_params=False)
 
@@ -136,33 +136,34 @@
 
     @classmethod
     def query_claim(cls, claim_uri):
-        '''Wrapper utility that gets a claim.'''
+        """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.'''
+        """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.'''
+        """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)
+        """Wrapper utility that sets the metadata of a queue."""
+        message_ttl = data_utils.\
+            rand_int_id(start=60, end=CONF.messaging.max_message_ttl)
 
-        key = data_utils.arbitrary_string(size=20, base_text='QueuingKey')
-        value = data_utils.arbitrary_string(size=20, base_text='QueuingValue')
+        key = data_utils.arbitrary_string(size=20, base_text='MessagingKey')
+        value = data_utils.arbitrary_string(size=20,
+                                            base_text='MessagingValue')
         message_body = {key: value}
 
         rbody = ([{'body': message_body, 'ttl': message_ttl}] * repeat)
diff --git a/tempest/api/queuing/test_claims.py b/tempest/api/messaging/test_claims.py
similarity index 87%
rename from tempest/api/queuing/test_claims.py
rename to tempest/api/messaging/test_claims.py
index a306623..1b004dd 100644
--- a/tempest/api/queuing/test_claims.py
+++ b/tempest/api/messaging/test_claims.py
@@ -16,7 +16,7 @@
 import logging
 import urlparse
 
-from tempest.api.queuing import base
+from tempest.api.messaging import base
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import test
@@ -26,12 +26,12 @@
 CONF = config.CONF
 
 
-class TestClaims(base.BaseQueuingTest):
+class TestClaims(base.BaseMessagingTest):
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(TestClaims, cls).setUpClass()
+    def resource_setup(cls):
+        super(TestClaims, cls).resource_setup()
         cls.queue_name = data_utils.rand_name('Queues-Test')
         # Create Queue
         cls.create_queue(cls.queue_name)
@@ -44,9 +44,9 @@
 
         # 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)
+                                           end=CONF.messaging.max_claim_ttl)
+        claim_grace = data_utils.\
+            rand_int_id(start=60, end=CONF.messaging.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)
@@ -90,7 +90,7 @@
 
         # Update Claim
         claim_ttl = data_utils.rand_int_id(start=60,
-                                           end=CONF.queuing.max_claim_ttl)
+                                           end=CONF.messaging.max_claim_ttl)
         update_rbody = {"ttl": claim_ttl}
 
         self.client.update_claim(claim_uri, rbody=update_rbody)
@@ -118,6 +118,6 @@
         self.client.delete_messages(message_uri)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.delete_queue(cls.queue_name)
-        super(TestClaims, cls).tearDownClass()
+        super(TestClaims, cls).resource_cleanup()
diff --git a/tempest/api/queuing/test_messages.py b/tempest/api/messaging/test_messages.py
similarity index 92%
rename from tempest/api/queuing/test_messages.py
rename to tempest/api/messaging/test_messages.py
index 9546c91..3c27ac2 100644
--- a/tempest/api/queuing/test_messages.py
+++ b/tempest/api/messaging/test_messages.py
@@ -15,7 +15,7 @@
 
 import logging
 
-from tempest.api.queuing import base
+from tempest.api.messaging import base
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import test
@@ -25,17 +25,17 @@
 CONF = config.CONF
 
 
-class TestMessages(base.BaseQueuingTest):
+class TestMessages(base.BaseMessagingTest):
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(TestMessages, cls).setUpClass()
+    def resource_setup(cls):
+        super(TestMessages, cls).resource_setup()
         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):
+    def _post_messages(self, repeat=CONF.messaging.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)
@@ -117,6 +117,6 @@
         self.assertEqual('204', resp['status'])
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.delete_queue(cls.queue_name)
-        super(TestMessages, cls).tearDownClass()
+        super(TestMessages, cls).resource_cleanup()
diff --git a/tempest/api/queuing/test_queues.py b/tempest/api/messaging/test_queues.py
similarity index 68%
rename from tempest/api/queuing/test_queues.py
rename to tempest/api/messaging/test_queues.py
index b340b60..accbd17 100644
--- a/tempest/api/queuing/test_queues.py
+++ b/tempest/api/messaging/test_queues.py
@@ -18,34 +18,41 @@
 from six import moves
 from testtools import matchers
 
-from tempest.api.queuing import base
+from tempest.api.messaging import base
 from tempest.common.utils import data_utils
+from tempest import exceptions
 from tempest import test
 
 
 LOG = logging.getLogger(__name__)
 
 
-class TestQueues(base.BaseQueuingTest):
+class TestQueues(base.BaseMessagingTest):
 
     @test.attr(type='smoke')
-    def test_create_queue(self):
-        # Create Queue
+    def test_create_delete_queue(self):
+        # Create & Delete Queue
         queue_name = data_utils.rand_name('test-')
-        resp, body = self.create_queue(queue_name)
+        _, body = self.create_queue(queue_name)
 
         self.addCleanup(self.client.delete_queue, queue_name)
-
-        self.assertEqual('201', resp['status'])
+        # NOTE(gmann): create_queue returns response status code as 201
+        # so specifically checking the expected empty response body as
+        # this is not going to be checked in response_checker().
         self.assertEqual('', body)
 
+        self.delete_queue(queue_name)
+        self.assertRaises(exceptions.NotFound,
+                          self.client.get_queue,
+                          queue_name)
 
-class TestManageQueue(base.BaseQueuingTest):
+
+class TestManageQueue(base.BaseMessagingTest):
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(TestManageQueue, cls).setUpClass()
+    def resource_setup(cls):
+        super(TestManageQueue, cls).resource_setup()
         cls.queues = list()
         for _ in moves.xrange(5):
             queue_name = data_utils.rand_name('Queues-Test')
@@ -54,33 +61,21 @@
             cls.client.create_queue(queue_name)
 
     @test.attr(type='smoke')
-    def test_delete_queue(self):
-        # Delete Queue
-        queue_name = self.queues.pop()
-        resp, body = self.delete_queue(queue_name)
-        self.assertEqual('204', resp['status'])
-        self.assertEqual('', body)
-
-    @test.attr(type='smoke')
     def test_check_queue_existence(self):
         # Checking Queue Existence
         for queue_name in self.queues:
-            resp, body = self.check_queue_exists(queue_name)
-            self.assertEqual('204', resp['status'])
-            self.assertEqual('', body)
+            self.check_queue_exists(queue_name)
 
     @test.attr(type='smoke')
     def test_check_queue_head(self):
         # Checking Queue Existence by calling HEAD
         for queue_name in self.queues:
-            resp, body = self.check_queue_exists_head(queue_name)
-            self.assertEqual('204', resp['status'])
-            self.assertEqual('', body)
+            self.check_queue_exists_head(queue_name)
 
     @test.attr(type='smoke')
     def test_list_queues(self):
         # Listing queues
-        resp, body = self.list_queues()
+        _, body = self.list_queues()
         self.assertEqual(len(body['queues']), len(self.queues))
         for item in body['queues']:
             self.assertIn(item['name'], self.queues)
@@ -91,7 +86,7 @@
         queue_name = self.queues[data_utils.rand_int_id(0,
                                                         len(self.queues) - 1)]
         # Get Queue Stats for a newly created Queue
-        resp, body = self.get_queue_stats(queue_name)
+        _, body = self.get_queue_stats(queue_name)
         msgs = body['messages']
         for element in ('free', 'claimed', 'total'):
             self.assertEqual(0, msgs[element])
@@ -104,8 +99,7 @@
         queue_name = self.queues[data_utils.rand_int_id(0,
                                                         len(self.queues) - 1)]
         # Check the Queue has no metadata
-        resp, body = self.get_queue_metadata(queue_name)
-        self.assertEqual('200', resp['status'])
+        _, body = self.get_queue_metadata(queue_name)
         self.assertThat(body, matchers.HasLength(0))
         # Create metadata
         key3 = [0, 1, 2, 3, 4]
@@ -116,16 +110,14 @@
         req_body = dict()
         req_body[data_utils.rand_name('key1')] = req_body1
         # Set Queue Metadata
-        resp, body = self.set_queue_metadata(queue_name, req_body)
-        self.assertEqual('204', resp['status'])
-        self.assertEqual('', body)
+        self.set_queue_metadata(queue_name, req_body)
+
         # Get Queue Metadata
-        resp, body = self.get_queue_metadata(queue_name)
-        self.assertEqual('200', resp['status'])
+        _, body = self.get_queue_metadata(queue_name)
         self.assertThat(body, matchers.Equals(req_body))
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         for queue_name in cls.queues:
             cls.client.delete_queue(queue_name)
-        super(TestManageQueue, cls).tearDownClass()
+        super(TestManageQueue, cls).resource_cleanup()
diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py
index f8782ad..0d27afa 100644
--- a/tempest/api/network/admin/test_agent_management.py
+++ b/tempest/api/network/admin/test_agent_management.py
@@ -21,8 +21,8 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(AgentManagementTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(AgentManagementTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('agent', 'network'):
             msg = "agent extension not enabled."
             raise cls.skipException(msg)
diff --git a/tempest/api/network/admin/test_dhcp_agent_scheduler.py b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
index c84d1a7..78f211d 100644
--- a/tempest/api/network/admin/test_dhcp_agent_scheduler.py
+++ b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
@@ -20,9 +20,8 @@
     _interface = 'json'
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(DHCPAgentSchedulersTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(DHCPAgentSchedulersTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('dhcp_agent_scheduler', 'network'):
             msg = "dhcp_agent_scheduler extension not enabled."
             raise cls.skipException(msg)
diff --git a/tempest/api/network/admin/test_external_network_extension.py b/tempest/api/network/admin/test_external_network_extension.py
index 710c669..5e6d8f3 100644
--- a/tempest/api/network/admin/test_external_network_extension.py
+++ b/tempest/api/network/admin/test_external_network_extension.py
@@ -18,8 +18,8 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(ExternalNetworksTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ExternalNetworksTestJSON, cls).resource_setup()
         cls.network = cls.create_network()
 
     def _create_network(self, external=True):
@@ -84,6 +84,41 @@
         self.assertEqual(self.network['id'], show_net['id'])
         self.assertFalse(show_net['router:external'])
 
+    def test_delete_external_networks_with_floating_ip(self):
+        """Verifies external network can be deleted while still holding
+        (unassociated) floating IPs
+
+        """
+        # Set cls.client to admin to use base.create_subnet()
+        client = self.admin_client
+        _, body = client.create_network(**{'router:external': True})
+        external_network = body['network']
+        self.addCleanup(self._try_delete_resource,
+                        client.delete_network,
+                        external_network['id'])
+        subnet = self.create_subnet(external_network, client=client)
+        _, body = client.create_floatingip(
+            floating_network_id=external_network['id'])
+        created_floating_ip = body['floatingip']
+        self.addCleanup(self._try_delete_resource,
+                        client.delete_floatingip,
+                        created_floating_ip['id'])
+        _, floatingip_list = client.list_floatingips(
+            network=external_network['id'])
+        self.assertIn(created_floating_ip['id'],
+                      (f['id'] for f in floatingip_list['floatingips']))
+        client.delete_network(external_network['id'])
+        # Verifies floating ip is deleted
+        _, floatingip_list = client.list_floatingips()
+        self.assertNotIn(created_floating_ip['id'],
+                         (f['id'] for f in floatingip_list['floatingips']))
+        # Verifies subnet is deleted
+        _, subnet_list = client.list_subnets()
+        self.assertNotIn(subnet['id'],
+                         (s['id'] for s in subnet_list))
+        # Removes subnet from the cleanup list
+        self.subnets.remove(subnet)
+
 
 class ExternalNetworksTestXML(ExternalNetworksTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/network/admin/test_floating_ips_admin_actions.py b/tempest/api/network/admin/test_floating_ips_admin_actions.py
index 3718cb5..46c5e76 100644
--- a/tempest/api/network/admin/test_floating_ips_admin_actions.py
+++ b/tempest/api/network/admin/test_floating_ips_admin_actions.py
@@ -26,8 +26,8 @@
     force_tenant_isolation = True
 
     @classmethod
-    def setUpClass(cls):
-        super(FloatingIPAdminTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FloatingIPAdminTestJSON, cls).resource_setup()
         cls.ext_net_id = CONF.network.public_network_id
         cls.floating_ip = cls.create_floatingip(cls.ext_net_id)
         cls.alt_manager = clients.Manager(cls.isolated_creds.get_alt_creds())
diff --git a/tempest/api/network/admin/test_l3_agent_scheduler.py b/tempest/api/network/admin/test_l3_agent_scheduler.py
index d7de73b..567af24 100644
--- a/tempest/api/network/admin/test_l3_agent_scheduler.py
+++ b/tempest/api/network/admin/test_l3_agent_scheduler.py
@@ -34,8 +34,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(L3AgentSchedulerTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(L3AgentSchedulerTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('l3_agent_scheduler', 'network'):
             msg = "L3 Agent Scheduler Extension not enabled."
             raise cls.skipException(msg)
diff --git a/tempest/api/network/admin/test_lbaas_agent_scheduler.py b/tempest/api/network/admin/test_lbaas_agent_scheduler.py
index d0c31b3..1476f30 100644
--- a/tempest/api/network/admin/test_lbaas_agent_scheduler.py
+++ b/tempest/api/network/admin/test_lbaas_agent_scheduler.py
@@ -35,9 +35,8 @@
     """
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(LBaaSAgentSchedulerTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(LBaaSAgentSchedulerTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('lbaas_agent_scheduler', 'network'):
             msg = "LBaaS Agent Scheduler Extension not enabled."
             raise cls.skipException(msg)
diff --git a/tempest/api/network/admin/test_load_balancer_admin_actions.py b/tempest/api/network/admin/test_load_balancer_admin_actions.py
index a97d275..6d115e8 100644
--- a/tempest/api/network/admin/test_load_balancer_admin_actions.py
+++ b/tempest/api/network/admin/test_load_balancer_admin_actions.py
@@ -29,9 +29,8 @@
     """
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(LoadBalancerAdminTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(LoadBalancerAdminTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('lbaas', 'network'):
             msg = "lbaas extension not enabled."
             raise cls.skipException(msg)
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index 9ac97f9..72aef36 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -39,8 +39,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(QuotasTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(QuotasTest, cls).resource_setup()
         if not test.is_extension_enabled('quotas', 'network'):
             msg = "quotas extension not enabled."
             raise cls.skipException(msg)
diff --git a/tempest/api/network/base.py b/tempest/api/network/base.py
index 1a23cb6..4b5f107 100644
--- a/tempest/api/network/base.py
+++ b/tempest/api/network/base.py
@@ -56,12 +56,17 @@
     _ip_version = 4
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         # Create no network resources for these test.
         cls.set_network_resources()
-        super(BaseNetworkTest, cls).setUpClass()
+        super(BaseNetworkTest, cls).resource_setup()
         if not CONF.service_available.neutron:
             raise cls.skipException("Neutron support is required")
+        if getattr(cls, '_interface', None) == 'xml':
+            if not CONF.network_feature_enabled.xml_api:
+                raise cls.skipException('XML API is not enabled')
+        if cls._ip_version == 6 and not CONF.network_feature_enabled.ipv6:
+            raise cls.skipException("IPv6 Tests are disabled.")
 
         os = cls.get_client_manager()
 
@@ -83,62 +88,100 @@
         cls.fw_rules = []
         cls.fw_policies = []
         cls.ipsecpolicies = []
+        cls.ethertype = "IPv" + str(cls._ip_version)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         if CONF.service_available.neutron:
             # Clean up ipsec policies
             for ipsecpolicy in cls.ipsecpolicies:
-                cls.client.delete_ipsecpolicy(ipsecpolicy['id'])
+                cls._try_delete_resource(cls.client.delete_ipsecpolicy,
+                                         ipsecpolicy['id'])
             # Clean up firewall policies
             for fw_policy in cls.fw_policies:
-                cls.client.delete_firewall_policy(fw_policy['id'])
+                cls._try_delete_resource(cls.client.delete_firewall_policy,
+                                         fw_policy['id'])
             # Clean up firewall rules
             for fw_rule in cls.fw_rules:
-                cls.client.delete_firewall_rule(fw_rule['id'])
+                cls._try_delete_resource(cls.client.delete_firewall_rule,
+                                         fw_rule['id'])
             # Clean up ike policies
             for ikepolicy in cls.ikepolicies:
-                cls.client.delete_ikepolicy(ikepolicy['id'])
+                cls._try_delete_resource(cls.client.delete_ikepolicy,
+                                         ikepolicy['id'])
             # Clean up vpn services
             for vpnservice in cls.vpnservices:
-                cls.client.delete_vpnservice(vpnservice['id'])
+                cls._try_delete_resource(cls.client.delete_vpnservice,
+                                         vpnservice['id'])
             # Clean up floating IPs
             for floating_ip in cls.floating_ips:
-                cls.client.delete_floatingip(floating_ip['id'])
+                cls._try_delete_resource(cls.client.delete_floatingip,
+                                         floating_ip['id'])
             # Clean up routers
             for router in cls.routers:
-                cls.delete_router(router)
+                cls._try_delete_resource(cls.delete_router,
+                                         router)
 
             # Clean up health monitors
             for health_monitor in cls.health_monitors:
-                cls.client.delete_health_monitor(health_monitor['id'])
+                cls._try_delete_resource(cls.client.delete_health_monitor,
+                                         health_monitor['id'])
             # Clean up members
             for member in cls.members:
-                cls.client.delete_member(member['id'])
+                cls._try_delete_resource(cls.client.delete_member,
+                                         member['id'])
             # Clean up vips
             for vip in cls.vips:
-                cls.client.delete_vip(vip['id'])
+                cls._try_delete_resource(cls.client.delete_vip,
+                                         vip['id'])
             # Clean up pools
             for pool in cls.pools:
-                cls.client.delete_pool(pool['id'])
+                cls._try_delete_resource(cls.client.delete_pool,
+                                         pool['id'])
             # Clean up metering label rules
             for metering_label_rule in cls.metering_label_rules:
-                cls.admin_client.delete_metering_label_rule(
+                cls._try_delete_resource(
+                    cls.admin_client.delete_metering_label_rule,
                     metering_label_rule['id'])
             # Clean up metering labels
             for metering_label in cls.metering_labels:
-                cls.admin_client.delete_metering_label(metering_label['id'])
+                cls._try_delete_resource(
+                    cls.admin_client.delete_metering_label,
+                    metering_label['id'])
             # Clean up ports
             for port in cls.ports:
-                cls.client.delete_port(port['id'])
+                cls._try_delete_resource(cls.client.delete_port,
+                                         port['id'])
             # Clean up subnets
             for subnet in cls.subnets:
-                cls.client.delete_subnet(subnet['id'])
+                cls._try_delete_resource(cls.client.delete_subnet,
+                                         subnet['id'])
             # Clean up networks
             for network in cls.networks:
-                cls.client.delete_network(network['id'])
+                cls._try_delete_resource(cls.client.delete_network,
+                                         network['id'])
             cls.clear_isolated_creds()
-        super(BaseNetworkTest, cls).tearDownClass()
+        super(BaseNetworkTest, cls).resource_cleanup()
+
+    @classmethod
+    def _try_delete_resource(self, delete_callable, *args, **kwargs):
+        """Cleanup resources in case of test-failure
+
+        Some resources are explicitly deleted by the test.
+        If the test failed to delete a resource, this method will execute
+        the appropriate delete methods. Otherwise, the method ignores NotFound
+        exceptions thrown for resources that were correctly deleted by the
+        test.
+
+        :param delete_callable: delete method
+        :param args: arguments for delete method
+        :param kwargs: keyword arguments for delete method
+        """
+        try:
+            delete_callable(*args, **kwargs)
+        # if resource is not found, this means it was deleted in the test
+        except exceptions.NotFound:
+            pass
 
     @classmethod
     def create_network(cls, network_name=None):
@@ -151,33 +194,40 @@
         return network
 
     @classmethod
-    def create_subnet(cls, network, gateway=None, cidr=None, mask_bits=None,
-                      **kwargs):
+    def create_subnet(cls, network, gateway='', cidr=None, mask_bits=None,
+                      ip_version=None, client=None, **kwargs):
         """Wrapper utility that returns a test subnet."""
+
+        # allow tests to use admin client
+        if not client:
+            client = cls.client
+
         # The cidr and mask_bits depend on the ip version.
-        if cls._ip_version == 4:
+        ip_version = ip_version if ip_version is not None else cls._ip_version
+        gateway_not_set = gateway == ''
+        if ip_version == 4:
             cidr = cidr or netaddr.IPNetwork(CONF.network.tenant_network_cidr)
             mask_bits = mask_bits or CONF.network.tenant_network_mask_bits
-        elif cls._ip_version == 6:
+        elif ip_version == 6:
             cidr = (
                 cidr or netaddr.IPNetwork(CONF.network.tenant_network_v6_cidr))
             mask_bits = mask_bits or CONF.network.tenant_network_v6_mask_bits
         # Find a cidr that is not in use yet and create a subnet with it
         for subnet_cidr in cidr.subnet(mask_bits):
-            if not gateway:
-                gateway = str(netaddr.IPAddress(subnet_cidr) + 1)
+            if gateway_not_set:
+                gateway_ip = str(netaddr.IPAddress(subnet_cidr) + 1)
+            else:
+                gateway_ip = gateway
             try:
-                resp, body = cls.client.create_subnet(
+                resp, body = client.create_subnet(
                     network_id=network['id'],
                     cidr=str(subnet_cidr),
-                    ip_version=cls._ip_version,
-                    gateway_ip=gateway,
+                    ip_version=ip_version,
+                    gateway_ip=gateway_ip,
                     **kwargs)
                 break
             except exceptions.BadRequest as e:
                 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
-                # Unset gateway value if there is an overlapping subnet
-                gateway = None
                 if not is_overlapping_cidr:
                     raise
         else:
@@ -265,9 +315,11 @@
         return vip
 
     @classmethod
-    def create_member(cls, protocol_port, pool):
+    def create_member(cls, protocol_port, pool, ip_version=None):
         """Wrapper utility that returns a test member."""
-        resp, body = cls.client.create_member(address="10.0.9.46",
+        ip_version = ip_version if ip_version is not None else cls._ip_version
+        member_address = "fd00::abcd" if ip_version == 6 else "10.0.9.46"
+        resp, body = cls.client.create_member(address=member_address,
                                               protocol_port=protocol_port,
                                               pool_id=pool['id'])
         member = body['member']
@@ -363,21 +415,17 @@
 class BaseAdminNetworkTest(BaseNetworkTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(BaseAdminNetworkTest, cls).setUpClass()
-        admin_username = CONF.compute_admin.username
-        admin_password = CONF.compute_admin.password
-        admin_tenant = CONF.compute_admin.tenant_name
-        if not (admin_username and admin_password and admin_tenant):
+    def resource_setup(cls):
+        super(BaseAdminNetworkTest, cls).resource_setup()
+
+        try:
+            creds = cls.isolated_creds.get_admin_creds()
+            cls.os_adm = clients.Manager(
+                credentials=creds, interface=cls._interface)
+        except NotImplementedError:
             msg = ("Missing Administrative Network API credentials "
                    "in configuration.")
             raise cls.skipException(msg)
-        if (CONF.compute.allow_tenant_isolation or
-            cls.force_tenant_isolation is True):
-            cls.os_adm = clients.Manager(cls.isolated_creds.get_admin_creds(),
-                                         interface=cls._interface)
-        else:
-            cls.os_adm = clients.ComputeAdminManager(interface=cls._interface)
         cls.admin_client = cls.os_adm.network_client
 
     @classmethod
diff --git a/tempest/api/network/base_routers.py b/tempest/api/network/base_routers.py
index f69e6fd..38985a0 100644
--- a/tempest/api/network/base_routers.py
+++ b/tempest/api/network/base_routers.py
@@ -22,8 +22,8 @@
     # require admin credentials by default
 
     @classmethod
-    def setUpClass(cls):
-        super(BaseRouterTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(BaseRouterTest, cls).resource_setup()
 
     def _delete_router(self, router_id):
         self.client.delete_router(router_id)
diff --git a/tempest/api/network/base_security_groups.py b/tempest/api/network/base_security_groups.py
index c2af2f2..622ed01 100644
--- a/tempest/api/network/base_security_groups.py
+++ b/tempest/api/network/base_security_groups.py
@@ -20,8 +20,8 @@
 class BaseSecGroupTest(base.BaseNetworkTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(BaseSecGroupTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(BaseSecGroupTest, cls).resource_setup()
 
     def _create_security_group(self):
         # Create a security group
diff --git a/tempest/api/network/common.py b/tempest/api/network/common.py
deleted file mode 100644
index 5ac8b5a..0000000
--- a/tempest/api/network/common.py
+++ /dev/null
@@ -1,157 +0,0 @@
-# Copyright 2013 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.
-
-import abc
-
-import six
-
-
-class AttributeDict(dict):
-
-    """
-    Provide attribute access (dict.key) to dictionary values.
-    """
-
-    def __getattr__(self, name):
-        """Allow attribute access for all keys in the dict."""
-        if name in self:
-            return self[name]
-        return super(AttributeDict, self).__getattribute__(name)
-
-
-@six.add_metaclass(abc.ABCMeta)
-class DeletableResource(AttributeDict):
-
-    """
-    Support deletion of neutron resources (networks, subnets) via a
-    delete() method, as is supported by keystone and nova resources.
-    """
-
-    def __init__(self, *args, **kwargs):
-        self.client = kwargs.pop('client', None)
-        super(DeletableResource, self).__init__(*args, **kwargs)
-
-    def __str__(self):
-        return '<%s id="%s" name="%s">' % (self.__class__.__name__,
-                                           self.id, self.name)
-
-    @abc.abstractmethod
-    def delete(self):
-        return
-
-    def __hash__(self):
-        return id(self)
-
-
-class DeletableNetwork(DeletableResource):
-
-    def delete(self):
-        self.client.delete_network(self.id)
-
-
-class DeletableSubnet(DeletableResource):
-
-    def __init__(self, *args, **kwargs):
-        super(DeletableSubnet, self).__init__(*args, **kwargs)
-        self._router_ids = set()
-
-    def update(self, *args, **kwargs):
-        body = dict(subnet=dict(*args, **kwargs))
-        result = self.client.update_subnet(subnet=self.id, body=body)
-        super(DeletableSubnet, self).update(**result['subnet'])
-
-    def add_to_router(self, router_id):
-        self._router_ids.add(router_id)
-        body = dict(subnet_id=self.id)
-        self.client.add_interface_router(router_id, body=body)
-
-    def delete(self):
-        for router_id in self._router_ids.copy():
-            body = dict(subnet_id=self.id)
-            self.client.remove_interface_router(router_id, body=body)
-            self._router_ids.remove(router_id)
-        self.client.delete_subnet(self.id)
-
-
-class DeletableRouter(DeletableResource):
-
-    def add_gateway(self, network_id):
-        body = dict(network_id=network_id)
-        self.client.add_gateway_router(self.id, body=body)
-
-    def delete(self):
-        self.client.remove_gateway_router(self.id)
-        self.client.delete_router(self.id)
-
-
-class DeletableFloatingIp(DeletableResource):
-
-    def update(self, *args, **kwargs):
-        result = self.client.update_floatingip(floatingip=self.id,
-                                               body=dict(
-                                                   floatingip=dict(*args,
-                                                                   **kwargs)
-                                               ))
-        super(DeletableFloatingIp, self).update(**result['floatingip'])
-
-    def __repr__(self):
-        return '<%s addr="%s">' % (self.__class__.__name__,
-                                   self.floating_ip_address)
-
-    def __str__(self):
-        return '<"FloatingIP" addr="%s" id="%s">' % (self.floating_ip_address,
-                                                     self.id)
-
-    def delete(self):
-        self.client.delete_floatingip(self.id)
-
-
-class DeletablePort(DeletableResource):
-
-    def delete(self):
-        self.client.delete_port(self.id)
-
-
-class DeletableSecurityGroup(DeletableResource):
-
-    def delete(self):
-        self.client.delete_security_group(self.id)
-
-
-class DeletableSecurityGroupRule(DeletableResource):
-
-    def __repr__(self):
-        return '<%s id="%s">' % (self.__class__.__name__, self.id)
-
-    def delete(self):
-        self.client.delete_security_group_rule(self.id)
-
-
-class DeletablePool(DeletableResource):
-
-    def delete(self):
-        self.client.delete_pool(self.id)
-
-
-class DeletableMember(DeletableResource):
-
-    def delete(self):
-        self.client.delete_member(self.id)
-
-
-class DeletableVip(DeletableResource):
-
-    def delete(self):
-        self.client.delete_vip(self.id)
diff --git a/tempest/api/network/test_allowed_address_pair.py b/tempest/api/network/test_allowed_address_pair.py
index 86acc71..a1166c8 100644
--- a/tempest/api/network/test_allowed_address_pair.py
+++ b/tempest/api/network/test_allowed_address_pair.py
@@ -13,9 +13,14 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import netaddr
+
 from tempest.api.network import base
+from tempest import config
 from tempest import test
 
+CONF = config.CONF
+
 
 class AllowedAddressPairTestJSON(base.BaseNetworkTest):
     _interface = 'json'
@@ -37,9 +42,8 @@
     """
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(AllowedAddressPairTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(AllowedAddressPairTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('allowed-address-pairs', 'network'):
             msg = "Allowed Address Pairs extension not enabled."
             raise cls.skipException(msg)
@@ -69,22 +73,50 @@
         self._confirm_allowed_address_pair(port[0], self.ip_address)
 
     @test.attr(type='smoke')
-    def test_update_port_with_address_pair(self):
+    def _update_port_with_address(self, address, mac_address=None, **kwargs):
         # Create a port without allowed address pair
         _, body = self.client.create_port(network_id=self.network['id'])
         port_id = body['port']['id']
         self.addCleanup(self.client.delete_port, port_id)
-
-        # Confirm  port is created
-        _, body = self.client.show_port(port_id)
+        if mac_address is None:
+            mac_address = self.mac_address
 
         # Update allowed address pair attribute of port
-        allowed_address_pairs = [{'ip_address': self.ip_address,
-                                  'mac_address': self.mac_address}]
+        allowed_address_pairs = [{'ip_address': address,
+                                  'mac_address': mac_address}]
+        if kwargs:
+            allowed_address_pairs.append(kwargs['allowed_address_pairs'])
         _, body = self.client.update_port(
             port_id, allowed_address_pairs=allowed_address_pairs)
-        newport = body['port']
-        self._confirm_allowed_address_pair(newport, self.ip_address)
+        allowed_address_pair = body['port']['allowed_address_pairs']
+        self.assertEqual(allowed_address_pair, allowed_address_pairs)
+
+    @test.attr(type='smoke')
+    def test_update_port_with_address_pair(self):
+        # Update port with allowed address pair
+        self._update_port_with_address(self.ip_address)
+
+    @test.attr(type='smoke')
+    def test_update_port_with_cidr_address_pair(self):
+        # Update allowed address pair with cidr
+        cidr = str(netaddr.IPNetwork(CONF.network.tenant_network_cidr))
+        self._update_port_with_address(cidr)
+
+    @test.attr(type='smoke')
+    def test_update_port_with_multiple_ip_mac_address_pair(self):
+        # Create an ip _address and mac_address through port create
+        _, resp = self.client.create_port(network_id=self.network['id'])
+        newportid = resp['port']['id']
+        self.addCleanup(self.client.delete_port, newportid)
+        ipaddress = resp['port']['fixed_ips'][0]['ip_address']
+        macaddress = resp['port']['mac_address']
+
+        # Update allowed address pair port with multiple ip and  mac
+        allowed_address_pairs = {'ip_address': ipaddress,
+                                 'mac_address': macaddress}
+        self._update_port_with_address(
+            self.ip_address, self.mac_address,
+            allowed_address_pairs=allowed_address_pairs)
 
     def _confirm_allowed_address_pair(self, port, ip):
         msg = 'Port allowed address pairs should not be empty'
@@ -95,5 +127,9 @@
         self.assertEqual(mac_address, self.mac_address)
 
 
+class AllowedAddressPairIpV6TestJSON(AllowedAddressPairTestJSON):
+    _ip_version = 6
+
+
 class AllowedAddressPairTestXML(AllowedAddressPairTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/network/test_extensions.py b/tempest/api/network/test_extensions.py
index c3607c8..715136c 100644
--- a/tempest/api/network/test_extensions.py
+++ b/tempest/api/network/test_extensions.py
@@ -33,8 +33,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(ExtensionsTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ExtensionsTestJSON, cls).resource_setup()
 
     @test.attr(type='smoke')
     def test_list_show_extensions(self):
diff --git a/tempest/api/network/test_extra_dhcp_options.py b/tempest/api/network/test_extra_dhcp_options.py
index 82ebc5a..6d083b3 100644
--- a/tempest/api/network/test_extra_dhcp_options.py
+++ b/tempest/api/network/test_extra_dhcp_options.py
@@ -36,26 +36,30 @@
     """
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(ExtraDHCPOptionsTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ExtraDHCPOptionsTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('extra_dhcp_opt', 'network'):
             msg = "Extra DHCP Options extension not enabled."
             raise cls.skipException(msg)
         cls.network = cls.create_network()
         cls.subnet = cls.create_subnet(cls.network)
         cls.port = cls.create_port(cls.network)
+        cls.ip_tftp = ('123.123.123.123' if cls._ip_version == 4
+                       else '2015::dead')
+        cls.ip_server = ('123.123.123.45' if cls._ip_version == 4
+                         else '2015::badd')
+        cls.extra_dhcp_opts = [
+            {'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'},
+            {'opt_value': cls.ip_tftp, 'opt_name': 'tftp-server'},
+            {'opt_value': cls.ip_server, 'opt_name': 'server-ip-address'}
+        ]
 
     @test.attr(type='smoke')
     def test_create_list_port_with_extra_dhcp_options(self):
         # Create a port with Extra DHCP Options
-        extra_dhcp_opts = [
-            {'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'},
-            {'opt_value': '123.123.123.123', 'opt_name': 'tftp-server'},
-            {'opt_value': '123.123.123.45', 'opt_name': 'server-ip-address'}
-        ]
-        _, body = self.client.create_port(network_id=self.network['id'],
-                                          extra_dhcp_opts=extra_dhcp_opts)
+        _, body = self.client.create_port(
+            network_id=self.network['id'],
+            extra_dhcp_opts=self.extra_dhcp_opts)
         port_id = body['port']['id']
         self.addCleanup(self.client.delete_port, port_id)
 
@@ -64,23 +68,19 @@
         ports = body['ports']
         port = [p for p in ports if p['id'] == port_id]
         self.assertTrue(port)
-        self._confirm_extra_dhcp_options(port[0], extra_dhcp_opts)
+        self._confirm_extra_dhcp_options(port[0], self.extra_dhcp_opts)
 
     @test.attr(type='smoke')
     def test_update_show_port_with_extra_dhcp_options(self):
         # Update port with extra dhcp options
-        extra_dhcp_opts = [
-            {'opt_value': 'pxelinux.0', 'opt_name': 'bootfile-name'},
-            {'opt_value': '123.123.123.123', 'opt_name': 'tftp-server'},
-            {'opt_value': '123.123.123.45', 'opt_name': 'server-ip-address'}
-        ]
         name = data_utils.rand_name('new-port-name')
-        _, body = self.client.update_port(self.port['id'], name=name,
-                                          extra_dhcp_opts=extra_dhcp_opts)
-
+        _, body = self.client.update_port(
+            self.port['id'],
+            name=name,
+            extra_dhcp_opts=self.extra_dhcp_opts)
         # Confirm extra dhcp options were added to the port
         _, body = self.client.show_port(self.port['id'])
-        self._confirm_extra_dhcp_options(body['port'], extra_dhcp_opts)
+        self._confirm_extra_dhcp_options(body['port'], self.extra_dhcp_opts)
 
     def _confirm_extra_dhcp_options(self, port, extra_dhcp_opts):
         retrieved = port['extra_dhcp_opts']
@@ -93,3 +93,7 @@
             else:
                 self.fail('Extra DHCP option not found in port %s' %
                           str(retrieved_option))
+
+
+class ExtraDHCPOptionsIpV6TestJSON(ExtraDHCPOptionsTestJSON):
+    _ip_version = 6
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index 8b42a9e..52672ea 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -46,9 +46,8 @@
     """
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(FloatingIPTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FloatingIPTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('router', 'network'):
             msg = "router extension not enabled."
             raise cls.skipException(msg)
diff --git a/tempest/api/network/test_fwaas_extensions.py b/tempest/api/network/test_fwaas_extensions.py
index 6eec79e..8e2b7f5 100644
--- a/tempest/api/network/test_fwaas_extensions.py
+++ b/tempest/api/network/test_fwaas_extensions.py
@@ -36,6 +36,8 @@
         List firewall policies
         Create firewall policy
         Update firewall policy
+        Insert firewall rule to policy
+        Remove firewall rule from policy
         Delete firewall policy
         Show firewall policy
         List firewall
@@ -46,8 +48,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(FWaaSExtensionTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(FWaaSExtensionTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('fwaas', 'network'):
             msg = "FWaaS Extension not enabled."
             raise cls.skipException(msg)
@@ -62,6 +64,14 @@
         except exceptions.NotFound:
             pass
 
+    def _try_delete_rule(self, rule_id):
+        # delete rule, if it exists
+        try:
+            self.client.delete_firewall_rule(rule_id)
+        # if rule is not found, this means it was deleted in the test
+        except exceptions.NotFound:
+            pass
+
     def _try_delete_firewall(self, fw_id):
         # delete firewall, if it exists
         try:
@@ -72,18 +82,20 @@
 
         self.client.wait_for_resource_deletion('firewall', fw_id)
 
-    def _wait_for_active(self, fw_id):
+    def _wait_until_ready(self, fw_id):
+        target_states = ('ACTIVE', 'CREATED')
+
         def _wait():
             _, firewall = self.client.show_firewall(fw_id)
             firewall = firewall['firewall']
-            return firewall['status'] == 'ACTIVE'
+            return firewall['status'] in target_states
 
         if not test.call_until_true(_wait, CONF.network.build_timeout,
                                     CONF.network.build_interval):
-            m = 'Timed out waiting for firewall %s to become ACTIVE.' % fw_id
+            m = ("Timed out waiting for firewall %s to reach %s state(s)" %
+                 (fw_id, target_states))
             raise exceptions.TimeoutException(m)
 
-    @test.attr(type='smoke')
     def test_list_firewall_rules(self):
         # List firewall rules
         _, fw_rules = self.client.list_firewall_rules()
@@ -101,7 +113,6 @@
                         m['ip_version'],
                         m['enabled']) for m in fw_rules])
 
-    @test.attr(type='smoke')
     def test_create_update_delete_firewall_rule(self):
         # Create firewall rule
         _, body = self.client.create_firewall_rule(
@@ -122,14 +133,12 @@
         self.assertNotIn(fw_rule_id,
                          [m['id'] for m in fw_rules['firewall_rules']])
 
-    @test.attr(type='smoke')
     def test_show_firewall_rule(self):
         # show a created firewall rule
         _, fw_rule = self.client.show_firewall_rule(self.fw_rule['id'])
         for key, value in fw_rule['firewall_rule'].iteritems():
             self.assertEqual(self.fw_rule[key], value)
 
-    @test.attr(type='smoke')
     def test_list_firewall_policies(self):
         _, fw_policies = self.client.list_firewall_policies()
         fw_policies = fw_policies['firewall_policies']
@@ -140,7 +149,6 @@
                         m['name'],
                         m['firewall_rules']) for m in fw_policies])
 
-    @test.attr(type='smoke')
     def test_create_update_delete_firewall_policy(self):
         # Create firewall policy
         _, body = self.client.create_firewall_policy(
@@ -163,7 +171,6 @@
         fw_policies = fw_policies['firewall_policies']
         self.assertNotIn(fw_policy_id, [m['id'] for m in fw_policies])
 
-    @test.attr(type='smoke')
     def test_show_firewall_policy(self):
         # show a created firewall policy
         _, fw_policy = self.client.show_firewall_policy(self.fw_policy['id'])
@@ -171,7 +178,6 @@
         for key, value in fw_policy.iteritems():
             self.assertEqual(self.fw_policy[key], value)
 
-    @test.attr(type='smoke')
     def test_create_show_delete_firewall(self):
         # Create tenant network resources required for an ACTIVE firewall
         network = self.create_network()
@@ -190,7 +196,8 @@
         firewall_id = created_firewall['id']
         self.addCleanup(self._try_delete_firewall, firewall_id)
 
-        self._wait_for_active(firewall_id)
+        # Wait for the firewall resource to become ready
+        self._wait_until_ready(firewall_id)
 
         # show a created firewall
         _, firewall = self.client.show_firewall(firewall_id)
@@ -214,6 +221,40 @@
         # Delete firewall
         self.client.delete_firewall(firewall_id)
 
+    @test.attr(type='smoke')
+    def test_insert_remove_firewall_rule_from_policy(self):
+        # Create firewall rule
+        resp, body = self.client.create_firewall_rule(
+            name=data_utils.rand_name("fw-rule"),
+            action="allow",
+            protocol="tcp")
+        fw_rule_id = body['firewall_rule']['id']
+        self.addCleanup(self._try_delete_rule, fw_rule_id)
+        # Create firewall policy
+        _, body = self.client.create_firewall_policy(
+            name=data_utils.rand_name("fw-policy"))
+        fw_policy_id = body['firewall_policy']['id']
+        self.addCleanup(self._try_delete_policy, fw_policy_id)
+
+        # Insert rule to firewall policy
+        self.client.insert_firewall_rule_in_policy(
+            fw_policy_id, fw_rule_id, '', '')
+
+        # Verify insertion of rule in policy
+        self.assertIn(fw_rule_id, self._get_list_fw_rule_ids(fw_policy_id))
+        # Remove rule from the firewall policy
+        self.client.remove_firewall_rule_from_policy(
+            fw_policy_id, fw_rule_id)
+
+        # Verify removal of rule from firewall policy
+        self.assertNotIn(fw_rule_id, self._get_list_fw_rule_ids(fw_policy_id))
+
+    def _get_list_fw_rule_ids(self, fw_policy_id):
+        _, fw_policy = self.client.show_firewall_policy(
+            fw_policy_id)
+        return [ruleid for ruleid in fw_policy['firewall_policy']
+                ['firewall_rules']]
+
 
 class FWaaSExtensionTestXML(FWaaSExtensionTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/network/test_load_balancer.py b/tempest/api/network/test_load_balancer.py
index e3109ea..8b8e3b1 100644
--- a/tempest/api/network/test_load_balancer.py
+++ b/tempest/api/network/test_load_balancer.py
@@ -38,9 +38,8 @@
     """
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(LoadBalancerTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(LoadBalancerTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('lbaas', 'network'):
             msg = "lbaas extension not enabled."
             raise cls.skipException(msg)
@@ -56,7 +55,9 @@
                                  protocol_port=80,
                                  subnet=cls.subnet,
                                  pool=cls.pool)
-        cls.member = cls.create_member(80, cls.pool)
+        cls.member = cls.create_member(80, cls.pool, cls._ip_version)
+        cls.member_address = ("10.0.9.47" if cls._ip_version == 4
+                              else "2015::beef")
         cls.health_monitor = cls.create_health_monitor(delay=4,
                                                        max_retries=3,
                                                        Type="TCP",
@@ -214,13 +215,14 @@
     def test_list_members_with_filters(self):
         attr_exceptions = ['status', 'status_description']
         self._check_list_with_filter('member', attr_exceptions,
-                                     address="10.0.9.47", protocol_port=80,
+                                     address=self.member_address,
+                                     protocol_port=80,
                                      pool_id=self.pool['id'])
 
     @test.attr(type='smoke')
     def test_create_update_delete_member(self):
         # Creates a member
-        _, body = self.client.create_member(address="10.0.9.47",
+        _, body = self.client.create_member(address=self.member_address,
                                             protocol_port=80,
                                             pool_id=self.pool['id'])
         member = body['member']
@@ -420,5 +422,9 @@
         self.assertEqual(2, member['weight'])
 
 
+class LoadBalancerIpV6TestJSON(LoadBalancerTestJSON):
+    _ip_version = 6
+
+
 class LoadBalancerTestXML(LoadBalancerTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/network/test_metering_extensions.py b/tempest/api/network/test_metering_extensions.py
index 5b8db43..07ebd8c 100644
--- a/tempest/api/network/test_metering_extensions.py
+++ b/tempest/api/network/test_metering_extensions.py
@@ -35,24 +35,20 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(MeteringJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(MeteringJSON, cls).resource_setup()
         if not test.is_extension_enabled('metering', 'network'):
             msg = "metering extension not enabled."
             raise cls.skipException(msg)
         description = "metering label created by tempest"
         name = data_utils.rand_name("metering-label")
-        try:
-            cls.metering_label = cls.create_metering_label(name, description)
-            remote_ip_prefix = "10.0.0.0/24"
-            direction = "ingress"
-            cls.metering_label_rule = cls.create_metering_label_rule(
-                remote_ip_prefix, direction,
-                metering_label_id=cls.metering_label['id'])
-        except Exception:
-            LOG.exception('setUpClass failed')
-            cls.tearDownClass()
-            raise
+        cls.metering_label = cls.create_metering_label(name, description)
+        remote_ip_prefix = ("10.0.0.0/24" if cls._ip_version == 4
+                            else "fd02::/64")
+        direction = "ingress"
+        cls.metering_label_rule = cls.create_metering_label_rule(
+            remote_ip_prefix, direction,
+            metering_label_id=cls.metering_label['id'])
 
     def _delete_metering_label(self, metering_label_id):
         # Deletes a label and verifies if it is deleted or not
@@ -117,8 +113,10 @@
     @test.attr(type='smoke')
     def test_create_delete_metering_label_rule_with_filters(self):
         # Creates a rule
+        remote_ip_prefix = ("10.0.1.0/24" if self._ip_version == 4
+                            else "fd03::/64")
         _, body = (self.admin_client.create_metering_label_rule(
-                   remote_ip_prefix="10.0.1.0/24",
+                   remote_ip_prefix=remote_ip_prefix,
                    direction="ingress",
                    metering_label_id=self.metering_label['id']))
         metering_label_rule = body['metering_label_rule']
@@ -147,5 +145,9 @@
         self.assertFalse(metering_label_rule['excluded'])
 
 
+class MeteringIpV6JSON(MeteringJSON):
+    _ip_version = 6
+
+
 class MeteringXML(MeteringJSON):
     interface = 'xml'
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index f3da614..be23a82 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -12,11 +12,13 @@
 #    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 itertools
 
 import netaddr
 import testtools
 
 from tempest.api.network import base
+from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
@@ -41,6 +43,7 @@
         network update
         subnet update
         delete a network also deletes its subnets
+        list external networks
 
         All subnet tests are run once with ipv4 and once with ipv6.
 
@@ -59,20 +62,100 @@
     """
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(NetworksTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(NetworksTestJSON, cls).resource_setup()
         cls.network = cls.create_network()
         cls.name = cls.network['name']
         cls.subnet = cls.create_subnet(cls.network)
         cls.cidr = cls.subnet['cidr']
+        cls._subnet_data = {6: {'gateway':
+                                str(cls._get_gateway_from_tempest_conf(6)),
+                                'allocation_pools':
+                                cls._get_allocation_pools_from_gateway(6),
+                                'dns_nameservers': ['2001:4860:4860::8844',
+                                                    '2001:4860:4860::8888'],
+                                'host_routes': [{'destination': '2001::/64',
+                                                 'nexthop': '2003::1'}],
+                                'new_host_routes': [{'destination':
+                                                     '2001::/64',
+                                                     'nexthop': '2005::1'}],
+                                'new_dns_nameservers':
+                                ['2001:4860:4860::7744',
+                                 '2001:4860:4860::7888']},
+                            4: {'gateway':
+                                str(cls._get_gateway_from_tempest_conf(4)),
+                                'allocation_pools':
+                                cls._get_allocation_pools_from_gateway(4),
+                                'dns_nameservers': ['8.8.4.4', '8.8.8.8'],
+                                'host_routes': [{'destination': '10.20.0.0/32',
+                                                 'nexthop': '10.100.1.1'}],
+                                'new_host_routes': [{'destination':
+                                                     '10.20.0.0/32',
+                                                     'nexthop':
+                                                     '10.100.1.2'}],
+                                'new_dns_nameservers': ['7.8.8.8', '7.8.4.4']}}
+
+    @classmethod
+    def _get_gateway_from_tempest_conf(cls, ip_version):
+        """Return first subnet gateway for configured CIDR """
+        if ip_version == 4:
+            cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
+            mask_bits = CONF.network.tenant_network_mask_bits
+        elif ip_version == 6:
+            cidr = netaddr.IPNetwork(CONF.network.tenant_network_v6_cidr)
+            mask_bits = CONF.network.tenant_network_v6_mask_bits
+
+        if mask_bits >= cidr.prefixlen:
+            return netaddr.IPAddress(cidr) + 1
+        else:
+            for subnet in cidr.subnet(mask_bits):
+                return netaddr.IPAddress(subnet) + 1
+
+    @classmethod
+    def _get_allocation_pools_from_gateway(cls, ip_version):
+        """Return allocation range for subnet of given gateway"""
+        gateway = cls._get_gateway_from_tempest_conf(ip_version)
+        return [{'start': str(gateway + 2), 'end': str(gateway + 3)}]
+
+    def subnet_dict(self, include_keys):
+        """Return a subnet dict which has include_keys and their corresponding
+           value from self._subnet_data
+        """
+        return dict((key, self._subnet_data[self._ip_version][key])
+                    for key in include_keys)
+
+    def _compare_resource_attrs(self, actual, expected):
+        exclude_keys = set(actual).symmetric_difference(expected)
+        self.assertThat(actual, custom_matchers.MatchesDictExceptForKeys(
+                        expected, exclude_keys))
+
+    def _create_verify_delete_subnet(self, cidr=None, mask_bits=None,
+                                     **kwargs):
+        network = self.create_network()
+        net_id = network['id']
+        gateway = kwargs.pop('gateway', None)
+        subnet = self.create_subnet(network, gateway, cidr, mask_bits,
+                                    **kwargs)
+        compare_args_full = dict(gateway_ip=gateway, cidr=cidr,
+                                 mask_bits=mask_bits, **kwargs)
+        compare_args = dict((k, v) for k, v in compare_args_full.iteritems()
+                            if v is not None)
+
+        if 'dns_nameservers' in set(subnet).intersection(compare_args):
+            self.assertEqual(sorted(compare_args['dns_nameservers']),
+                             sorted(subnet['dns_nameservers']))
+            del subnet['dns_nameservers'], compare_args['dns_nameservers']
+
+        self._compare_resource_attrs(subnet, compare_args)
+        self.client.delete_network(net_id)
+        self.networks.pop()
+        self.subnets.pop()
 
     @test.attr(type='smoke')
     def test_create_update_delete_network_subnet(self):
         # Create a network
         name = data_utils.rand_name('network-')
-        _, body = self.client.create_network(name=name)
-        network = body['network']
+        network = self.create_network(network_name=name)
         net_id = network['id']
         self.assertEqual('ACTIVE', network['status'])
         # Verify network update
@@ -88,11 +171,6 @@
         _, body = self.client.update_subnet(subnet_id, name=new_name)
         updated_subnet = body['subnet']
         self.assertEqual(updated_subnet['name'], new_name)
-        # Delete subnet and network
-        _, body = self.client.delete_subnet(subnet_id)
-        # Remove subnet from cleanup list
-        self.subnets.pop()
-        _, body = self.client.delete_network(net_id)
 
     @test.attr(type='smoke')
     def test_show_network(self):
@@ -204,33 +282,92 @@
         self.subnets.pop()
 
     @test.attr(type='smoke')
-    def test_create_delete_subnet_with_gw(self):
-        gateway = '10.100.0.13'
-        name = data_utils.rand_name('network-')
-        _, body = self.client.create_network(name=name)
-        network = body['network']
-        net_id = network['id']
-        subnet = self.create_subnet(network, gateway)
-        # Verifies Subnet GW in IPv4
-        self.assertEqual(subnet['gateway_ip'], gateway)
-        # Delete network and subnet
-        self.client.delete_network(net_id)
-        self.subnets.pop()
+    def test_create_delete_subnet_without_gateway(self):
+        self._create_verify_delete_subnet()
 
     @test.attr(type='smoke')
-    def test_create_delete_subnet_without_gw(self):
-        net = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
-        gateway_ip = str(netaddr.IPAddress(net.first + 1))
-        name = data_utils.rand_name('network-')
-        _, body = self.client.create_network(name=name)
-        network = body['network']
-        net_id = network['id']
-        subnet = self.create_subnet(network)
-        # Verifies Subnet GW in IPv4
-        self.assertEqual(subnet['gateway_ip'], gateway_ip)
-        # Delete network and subnet
-        self.client.delete_network(net_id)
-        self.subnets.pop()
+    def test_create_delete_subnet_with_gw(self):
+        self._create_verify_delete_subnet(
+            **self.subnet_dict(['gateway']))
+
+    @test.attr(type='smoke')
+    def test_create_delete_subnet_with_allocation_pools(self):
+        self._create_verify_delete_subnet(
+            **self.subnet_dict(['allocation_pools']))
+
+    @test.attr(type='smoke')
+    def test_create_delete_subnet_with_gw_and_allocation_pools(self):
+        self._create_verify_delete_subnet(**self.subnet_dict(
+            ['gateway', 'allocation_pools']))
+
+    @test.attr(type='smoke')
+    def test_create_delete_subnet_with_host_routes_and_dns_nameservers(self):
+        self._create_verify_delete_subnet(
+            **self.subnet_dict(['host_routes', 'dns_nameservers']))
+
+    @test.attr(type='smoke')
+    def test_create_delete_subnet_with_dhcp_enabled(self):
+        self._create_verify_delete_subnet(enable_dhcp=True)
+
+    @test.attr(type='smoke')
+    def test_update_subnet_gw_dns_host_routes_dhcp(self):
+        network = self.create_network()
+
+        subnet = self.create_subnet(
+            network, **self.subnet_dict(['gateway', 'host_routes',
+                                        'dns_nameservers',
+                                         'allocation_pools']))
+        subnet_id = subnet['id']
+        new_gateway = str(netaddr.IPAddress(
+                          self._subnet_data[self._ip_version]['gateway']) + 1)
+        # Verify subnet update
+        new_host_routes = self._subnet_data[self._ip_version][
+            'new_host_routes']
+
+        new_dns_nameservers = self._subnet_data[self._ip_version][
+            'new_dns_nameservers']
+        kwargs = {'host_routes': new_host_routes,
+                  'dns_nameservers': new_dns_nameservers,
+                  'gateway_ip': new_gateway, 'enable_dhcp': True}
+
+        new_name = "New_subnet"
+        _, body = self.client.update_subnet(subnet_id, name=new_name,
+                                            **kwargs)
+        updated_subnet = body['subnet']
+        kwargs['name'] = new_name
+        self.assertEqual(sorted(updated_subnet['dns_nameservers']),
+                         sorted(kwargs['dns_nameservers']))
+        del subnet['dns_nameservers'], kwargs['dns_nameservers']
+
+        self._compare_resource_attrs(updated_subnet, kwargs)
+
+    @test.attr(type='smoke')
+    def test_create_delete_subnet_all_attributes(self):
+        self._create_verify_delete_subnet(
+            enable_dhcp=True,
+            **self.subnet_dict(['gateway', 'host_routes', 'dns_nameservers']))
+
+    @test.attr(type='smoke')
+    def test_external_network_visibility(self):
+        """Verifies user can see external networks but not subnets."""
+        _, body = self.client.list_networks(**{'router:external': True})
+        networks = [network['id'] for network in body['networks']]
+        self.assertNotEmpty(networks, "No external networks found")
+
+        nonexternal = [net for net in body['networks'] if
+                       not net['router:external']]
+        self.assertEmpty(nonexternal, "Found non-external networks"
+                                      " in filtered list (%s)." % nonexternal)
+        self.assertIn(CONF.network.public_network_id, networks)
+
+        subnets_iter = (network['subnets'] for network in body['networks'])
+        # subnets_iter is a list (iterator) of lists. This flattens it to a
+        # list of UUIDs
+        public_subnets_iter = itertools.chain(*subnets_iter)
+        _, body = self.client.list_subnets()
+        subnets = [sub['id'] for sub in body['subnets']
+                   if sub['id'] in public_subnets_iter]
+        self.assertEmpty(subnets, "Public subnets visible")
 
 
 class NetworksTestXML(NetworksTestJSON):
@@ -365,63 +502,81 @@
 class NetworksIpV6TestJSON(NetworksTestJSON):
     _ip_version = 6
 
-    @classmethod
-    def setUpClass(cls):
-        if not CONF.network_feature_enabled.ipv6:
-            skip_msg = "IPv6 Tests are disabled."
-            raise cls.skipException(skip_msg)
-        super(NetworksIpV6TestJSON, cls).setUpClass()
-
     @test.attr(type='smoke')
     def test_create_delete_subnet_with_gw(self):
         net = netaddr.IPNetwork(CONF.network.tenant_network_v6_cidr)
         gateway = str(netaddr.IPAddress(net.first + 2))
         name = data_utils.rand_name('network-')
-        _, body = self.client.create_network(name=name)
-        network = body['network']
-        net_id = network['id']
+        network = self.create_network(network_name=name)
         subnet = self.create_subnet(network, gateway)
         # Verifies Subnet GW in IPv6
         self.assertEqual(subnet['gateway_ip'], gateway)
-        # Delete network and subnet
-        self.client.delete_network(net_id)
-        self.subnets.pop()
 
     @test.attr(type='smoke')
-    def test_create_delete_subnet_without_gw(self):
+    def test_create_delete_subnet_with_default_gw(self):
         net = netaddr.IPNetwork(CONF.network.tenant_network_v6_cidr)
         gateway_ip = str(netaddr.IPAddress(net.first + 1))
         name = data_utils.rand_name('network-')
-        _, body = self.client.create_network(name=name)
-        network = body['network']
-        net_id = network['id']
+        network = self.create_network(network_name=name)
         subnet = self.create_subnet(network)
         # Verifies Subnet GW in IPv6
         self.assertEqual(subnet['gateway_ip'], gateway_ip)
-        # Delete network and subnet
-        _, body = self.client.delete_network(net_id)
-        self.subnets.pop()
+
+    @test.attr(type='smoke')
+    def test_create_list_subnet_with_no_gw64_one_network(self):
+        name = data_utils.rand_name('network-')
+        network = self.create_network(name)
+        ipv6_gateway = self.subnet_dict(['gateway'])['gateway']
+        subnet1 = self.create_subnet(network,
+                                     ip_version=6,
+                                     gateway=ipv6_gateway)
+        self.assertEqual(netaddr.IPNetwork(subnet1['cidr']).version, 6,
+                         'The created subnet is not IPv6')
+        subnet2 = self.create_subnet(network,
+                                     gateway=None,
+                                     ip_version=4)
+        self.assertEqual(netaddr.IPNetwork(subnet2['cidr']).version, 4,
+                         'The created subnet is not IPv4')
+        # Verifies Subnet GW is set in IPv6
+        self.assertEqual(subnet1['gateway_ip'], ipv6_gateway)
+        # Verifies Subnet GW is None in IPv4
+        self.assertEqual(subnet2['gateway_ip'], None)
+        # Verifies all 2 subnets in the same network
+        _, body = self.client.list_subnets()
+        subnets = [sub['id'] for sub in body['subnets']
+                   if sub['network_id'] == network['id']]
+        test_subnet_ids = [sub['id'] for sub in (subnet1, subnet2)]
+        self.assertItemsEqual(subnets,
+                              test_subnet_ids,
+                              'Subnet are not in the same network')
 
     @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-')
-        _, body = self.client.create_network(name=name)
-        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
-        self.client.delete_network(net_id)
-        self.subnets.pop()
+    def test_create_delete_subnet_with_v6_attributes_stateful(self):
+        self._create_verify_delete_subnet(
+            gateway=self._subnet_data[self._ip_version]['gateway'],
+            ipv6_ra_mode='dhcpv6-stateful',
+            ipv6_address_mode='dhcpv6-stateful')
+
+    @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_slaac(self):
+        self._create_verify_delete_subnet(
+            ipv6_ra_mode='slaac',
+            ipv6_address_mode='slaac')
+
+    @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_stateless(self):
+        self._create_verify_delete_subnet(
+            ipv6_ra_mode='dhcpv6-stateless',
+            ipv6_address_mode='dhcpv6-stateless')
 
 
 class NetworksIpV6TestXML(NetworksIpV6TestJSON):
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index f06d17c..7c5bdfe 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -16,6 +16,7 @@
 import socket
 
 from tempest.api.network import base
+from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import test
@@ -37,9 +38,8 @@
     """
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(PortsTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(PortsTestJSON, cls).resource_setup()
         cls.network = cls.create_network()
         cls.port = cls.create_port(cls.network)
 
@@ -72,18 +72,12 @@
         _, body = self.client.show_port(self.port['id'])
         port = body['port']
         self.assertIn('id', port)
-        self.assertEqual(port['id'], self.port['id'])
-        self.assertEqual(self.port['admin_state_up'], port['admin_state_up'])
-        self.assertEqual(self.port['device_id'], port['device_id'])
-        self.assertEqual(self.port['device_owner'], port['device_owner'])
-        self.assertEqual(self.port['mac_address'], port['mac_address'])
-        self.assertEqual(self.port['name'], port['name'])
-        self.assertEqual(self.port['security_groups'],
-                         port['security_groups'])
-        self.assertEqual(self.port['network_id'], port['network_id'])
-        self.assertEqual(self.port['security_groups'],
-                         port['security_groups'])
-        self.assertEqual(port['fixed_ips'], [])
+        # TODO(Santosh)- This is a temporary workaround to compare create_port
+        # and show_port dict elements.Remove this once extra_dhcp_opts issue
+        # gets fixed in neutron.( bug - 1365341.)
+        self.assertThat(self.port,
+                        custom_matchers.MatchesDictExceptForKeys
+                        (port, excluded_keys=['extra_dhcp_opts']))
 
     @test.attr(type='smoke')
     def test_show_port_fields(self):
@@ -157,6 +151,41 @@
         port = self.update_port(port, fixed_ips=fixed_ip_1)
         self.assertEqual(1, len(port['fixed_ips']))
 
+    def _update_port_with_security_groups(self, security_groups_names):
+        post_body = {"network_id": self.network['id']}
+        self.create_subnet(self.network)
+        security_groups_list = list()
+        for name in security_groups_names:
+            _, group_create_body = self.client.create_security_group(
+                name=name)
+            self.addCleanup(self.client.delete_security_group,
+                            group_create_body['security_group']['id'])
+            security_groups_list.append(group_create_body['security_group']
+                                        ['id'])
+        # Create a port
+        _, body = self.client.create_port(**post_body)
+        self.addCleanup(self.client.delete_port, body['port']['id'])
+        port = body['port']
+        # Update the port with security groups
+        update_body = {"security_groups": security_groups_list}
+        _, body = self.client.update_port(
+            port['id'], **update_body)
+        # Verify the security groups updated to port
+        port_show = body['port']
+        for security_group in security_groups_list:
+            self.assertIn(security_group, port_show['security_groups'])
+
+    @test.attr(type='smoke')
+    def test_update_port_with_security_group(self):
+        self._update_port_with_security_groups(
+            [data_utils.rand_name('secgroup')])
+
+    @test.attr(type='smoke')
+    def test_update_port_with_two_security_groups(self):
+        self._update_port_with_security_groups(
+            [data_utils.rand_name('secgroup'),
+             data_utils.rand_name('secgroup')])
+
 
 class PortsTestXML(PortsTestJSON):
     _interface = 'xml'
@@ -166,9 +195,8 @@
     _interface = 'json'
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(PortsAdminExtendedAttrsTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(PortsAdminExtendedAttrsTestJSON, cls).resource_setup()
         cls.identity_client = cls._get_identity_admin_client()
         cls.tenant = cls.identity_client.get_tenant_by_name(
             CONF.identity.tenant_name)
@@ -248,14 +276,6 @@
     _tenant_network_cidr = CONF.network.tenant_network_v6_cidr
     _tenant_network_mask_bits = CONF.network.tenant_network_v6_mask_bits
 
-    @classmethod
-    def setUpClass(cls):
-        super(PortsIpV6TestJSON, cls).setUpClass()
-        if not CONF.network_feature_enabled.ipv6:
-            cls.tearDownClass()
-            skip_msg = "IPv6 Tests are disabled."
-            raise cls.skipException(skip_msg)
-
 
 class PortsIpV6TestXML(PortsIpV6TestJSON):
     _interface = 'xml'
@@ -266,14 +286,6 @@
     _tenant_network_cidr = CONF.network.tenant_network_v6_cidr
     _tenant_network_mask_bits = CONF.network.tenant_network_v6_mask_bits
 
-    @classmethod
-    def setUpClass(cls):
-        if not CONF.network_feature_enabled.ipv6:
-            skip_msg = "IPv6 Tests are disabled."
-            raise cls.skipException(skip_msg)
-        super(PortsAdminExtendedAttrsIpV6TestJSON, cls).setUpClass()
 
-
-class PortsAdminExtendedAttrsIpV6TestXML(
-    PortsAdminExtendedAttrsIpV6TestJSON):
+class PortsAdminExtendedAttrsIpV6TestXML(PortsAdminExtendedAttrsIpV6TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index bcd8113..2b4e60a 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -28,13 +28,16 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(RoutersTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(RoutersTest, cls).resource_setup()
         if not test.is_extension_enabled('router', 'network'):
             msg = "router extension not enabled."
             raise cls.skipException(msg)
         admin_manager = clients.AdminManager()
         cls.identity_admin_client = admin_manager.identity_client
+        cls.tenant_cidr = (CONF.network.tenant_network_cidr
+                           if cls._ip_version == 4 else
+                           CONF.network.tenant_network_v6_cidr)
 
     def _cleanup_router(self, router):
         self.delete_router(router)
@@ -319,7 +322,7 @@
         network02 = self.create_network(
             network_name=data_utils.rand_name('router-network02-'))
         subnet01 = self.create_subnet(network01)
-        sub02_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr).next()
+        sub02_cidr = netaddr.IPNetwork(self.tenant_cidr).next()
         subnet02 = self.create_subnet(network02, cidr=sub02_cidr)
         router = self._create_router(data_utils.rand_name('router-'))
         interface01 = self._add_router_interface_with_subnet_id(router['id'],
@@ -337,3 +340,7 @@
         self.assertEqual(router_id, interface_port['device_id'])
         self.assertEqual(subnet_id,
                          interface_port['fixed_ips'][0]['subnet_id'])
+
+
+class RoutersIpV6Test(RoutersTest):
+    _ip_version = 6
diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py
index feee51b..88aa3c9 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -28,15 +28,17 @@
     _interface = 'json'
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(RoutersNegativeTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(RoutersNegativeTest, cls).resource_setup()
         if not test.is_extension_enabled('router', 'network'):
             msg = "router extension not enabled."
             raise cls.skipException(msg)
         cls.router = cls.create_router(data_utils.rand_name('router-'))
         cls.network = cls.create_network()
         cls.subnet = cls.create_subnet(cls.network)
+        cls.tenant_cidr = (CONF.network.tenant_network_cidr
+                           if cls._ip_version == 4 else
+                           CONF.network.tenant_network_v6_cidr)
 
     @test.attr(type=['negative', 'smoke'])
     def test_router_add_gateway_invalid_network_returns_404(self):
@@ -50,7 +52,7 @@
     def test_router_add_gateway_net_not_external_returns_400(self):
         alt_network = self.create_network(
             network_name=data_utils.rand_name('router-negative-'))
-        sub_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr).next()
+        sub_cidr = netaddr.IPNetwork(self.tenant_cidr).next()
         self.create_subnet(alt_network, cidr=sub_cidr)
         self.assertRaises(exceptions.BadRequest,
                           self.client.update_router,
@@ -80,3 +82,7 @@
         self.assertRaises(exceptions.Conflict,
                           self.client.delete_router,
                           self.router['id'])
+
+
+class RoutersNegativeIpV6Test(RoutersNegativeTest):
+    _ip_version = 6
diff --git a/tempest/api/network/test_security_groups.py b/tempest/api/network/test_security_groups.py
index 855b5fb..40cf04f 100644
--- a/tempest/api/network/test_security_groups.py
+++ b/tempest/api/network/test_security_groups.py
@@ -17,19 +17,57 @@
 
 from tempest.api.network import base_security_groups as base
 from tempest.common.utils import data_utils
+from tempest import config
 from tempest import test
 
+CONF = config.CONF
+
 
 class SecGroupTest(base.BaseSecGroupTest):
     _interface = 'json'
+    _tenant_network_cidr = CONF.network.tenant_network_cidr
 
     @classmethod
-    def setUpClass(cls):
-        super(SecGroupTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(SecGroupTest, cls).resource_setup()
         if not test.is_extension_enabled('security-group', 'network'):
             msg = "security-group extension not enabled."
             raise cls.skipException(msg)
 
+    def _create_verify_security_group_rule(self, sg_id, direction,
+                                           ethertype, protocol,
+                                           port_range_min,
+                                           port_range_max,
+                                           remote_group_id=None,
+                                           remote_ip_prefix=None):
+        # Create Security Group rule with the input params and validate
+        # that SG rule is created with the same parameters.
+        resp, rule_create_body = self.client.create_security_group_rule(
+            security_group_id=sg_id,
+            direction=direction,
+            ethertype=ethertype,
+            protocol=protocol,
+            port_range_min=port_range_min,
+            port_range_max=port_range_max,
+            remote_group_id=remote_group_id,
+            remote_ip_prefix=remote_ip_prefix
+        )
+
+        sec_group_rule = rule_create_body['security_group_rule']
+        self.addCleanup(self._delete_security_group_rule,
+                        sec_group_rule['id'])
+
+        expected = {'direction': direction, 'protocol': protocol,
+                    'ethertype': ethertype, 'port_range_min': port_range_min,
+                    'port_range_max': port_range_max,
+                    'remote_group_id': remote_group_id,
+                    'remote_ip_prefix': remote_ip_prefix}
+        for key, value in six.iteritems(expected):
+            self.assertEqual(value, sec_group_rule[key],
+                             "Field %s of the created security group "
+                             "rule does not match with %s." %
+                             (key, value))
+
     @test.attr(type='smoke')
     def test_list_security_groups(self):
         # Verify the that security group belonging to tenant exist in list
@@ -80,7 +118,8 @@
             _, rule_create_body = self.client.create_security_group_rule(
                 security_group_id=group_create_body['security_group']['id'],
                 protocol=protocol,
-                direction='ingress'
+                direction='ingress',
+                ethertype=self.ethertype
             )
 
             # Show details of the created security rule
@@ -102,29 +141,76 @@
 
     @test.attr(type='smoke')
     def test_create_security_group_rule_with_additional_args(self):
-        # Verify creating security group rule with the following
-        # arguments works: "protocol": "tcp", "port_range_max": 77,
-        # "port_range_min": 77, "direction":"ingress".
-        group_create_body, _ = self._create_security_group()
+        """Verify security group rule with additional arguments works.
 
+        direction:ingress, ethertype:[IPv4/IPv6],
+        protocol:tcp, port_range_min:77, port_range_max:77
+        """
+        group_create_body, _ = self._create_security_group()
+        sg_id = group_create_body['security_group']['id']
         direction = 'ingress'
         protocol = 'tcp'
         port_range_min = 77
         port_range_max = 77
-        _, rule_create_body = self.client.create_security_group_rule(
-            security_group_id=group_create_body['security_group']['id'],
-            direction=direction,
-            protocol=protocol,
-            port_range_min=port_range_min,
-            port_range_max=port_range_max
-        )
+        self._create_verify_security_group_rule(sg_id, direction,
+                                                self.ethertype, protocol,
+                                                port_range_min,
+                                                port_range_max)
 
-        sec_group_rule = rule_create_body['security_group_rule']
+    @test.attr(type='smoke')
+    def test_create_security_group_rule_with_icmp_type_code(self):
+        """Verify security group rule for icmp protocol works.
 
-        self.assertEqual(sec_group_rule['direction'], direction)
-        self.assertEqual(sec_group_rule['protocol'], protocol)
-        self.assertEqual(int(sec_group_rule['port_range_min']), port_range_min)
-        self.assertEqual(int(sec_group_rule['port_range_max']), port_range_max)
+        Specify icmp type (port_range_min) and icmp code
+        (port_range_max) with different values. A seperate testcase
+        is added for icmp protocol as icmp validation would be
+        different from tcp/udp.
+        """
+        group_create_body, _ = self._create_security_group()
+
+        sg_id = group_create_body['security_group']['id']
+        direction = 'ingress'
+        protocol = 'icmp'
+        icmp_type_codes = [(3, 2), (2, 3), (3, 0), (2, None)]
+        for icmp_type, icmp_code in icmp_type_codes:
+            self._create_verify_security_group_rule(sg_id, direction,
+                                                    self.ethertype, protocol,
+                                                    icmp_type, icmp_code)
+
+    @test.attr(type='smoke')
+    def test_create_security_group_rule_with_remote_group_id(self):
+        # Verify creating security group rule with remote_group_id works
+        sg1_body, _ = self._create_security_group()
+        sg2_body, _ = self._create_security_group()
+
+        sg_id = sg1_body['security_group']['id']
+        direction = 'ingress'
+        protocol = 'udp'
+        port_range_min = 50
+        port_range_max = 55
+        remote_id = sg2_body['security_group']['id']
+        self._create_verify_security_group_rule(sg_id, direction,
+                                                self.ethertype, protocol,
+                                                port_range_min,
+                                                port_range_max,
+                                                remote_group_id=remote_id)
+
+    @test.attr(type='smoke')
+    def test_create_security_group_rule_with_remote_ip_prefix(self):
+        # Verify creating security group rule with remote_ip_prefix works
+        sg1_body, _ = self._create_security_group()
+
+        sg_id = sg1_body['security_group']['id']
+        direction = 'ingress'
+        protocol = 'tcp'
+        port_range_min = 76
+        port_range_max = 77
+        ip_prefix = self._tenant_network_cidr
+        self._create_verify_security_group_rule(sg_id, direction,
+                                                self.ethertype, protocol,
+                                                port_range_min,
+                                                port_range_max,
+                                                remote_ip_prefix=ip_prefix)
 
     @test.attr(type='smoke')
     def test_create_security_group_rule_with_protocol_integer_value(self):
@@ -147,3 +233,12 @@
 
 class SecGroupTestXML(SecGroupTest):
     _interface = 'xml'
+
+
+class SecGroupIPv6Test(SecGroupTest):
+    _ip_version = 6
+    _tenant_network_cidr = CONF.network.tenant_network_v6_cidr
+
+
+class SecGroupIPv6TestXML(SecGroupIPv6Test):
+    _interface = 'xml'
diff --git a/tempest/api/network/test_security_groups_negative.py b/tempest/api/network/test_security_groups_negative.py
index 53c9d12..42f7f71 100644
--- a/tempest/api/network/test_security_groups_negative.py
+++ b/tempest/api/network/test_security_groups_negative.py
@@ -16,16 +16,20 @@
 import uuid
 
 from tempest.api.network import base_security_groups as base
+from tempest import config
 from tempest import exceptions
 from tempest import test
 
+CONF = config.CONF
+
 
 class NegativeSecGroupTest(base.BaseSecGroupTest):
     _interface = 'json'
+    _tenant_network_cidr = CONF.network.tenant_network_cidr
 
     @classmethod
-    def setUpClass(cls):
-        super(NegativeSecGroupTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(NegativeSecGroupTest, cls).resource_setup()
         if not test.is_extension_enabled('security-group', 'network'):
             msg = "security-group extension not enabled."
             raise cls.skipException(msg)
@@ -60,23 +64,87 @@
         self.assertRaises(
             exceptions.BadRequest, self.client.create_security_group_rule,
             security_group_id=group_create_body['security_group']['id'],
-            protocol=pname, direction='ingress')
+            protocol=pname, direction='ingress', ethertype=self.ethertype)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_security_group_rule_with_bad_remote_ip_prefix(self):
+        group_create_body, _ = self._create_security_group()
+
+        # Create rule with bad remote_ip_prefix
+        prefix = ['192.168.1./24', '192.168.1.1/33', 'bad_prefix', '256']
+        for remote_ip_prefix in prefix:
+            self.assertRaises(
+                exceptions.BadRequest, self.client.create_security_group_rule,
+                security_group_id=group_create_body['security_group']['id'],
+                protocol='tcp', direction='ingress', ethertype=self.ethertype,
+                remote_ip_prefix=remote_ip_prefix)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_security_group_rule_with_non_existent_remote_groupid(self):
+        group_create_body, _ = self._create_security_group()
+        non_exist_id = str(uuid.uuid4())
+
+        # Create rule with non existent remote_group_id
+        group_ids = ['bad_group_id', non_exist_id]
+        for remote_group_id in group_ids:
+            self.assertRaises(
+                exceptions.NotFound, self.client.create_security_group_rule,
+                security_group_id=group_create_body['security_group']['id'],
+                protocol='tcp', direction='ingress', ethertype=self.ethertype,
+                remote_group_id=remote_group_id)
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_security_group_rule_with_remote_ip_and_group(self):
+        sg1_body, _ = self._create_security_group()
+        sg2_body, _ = self._create_security_group()
+
+        # Create rule specifying both remote_ip_prefix and remote_group_id
+        prefix = self._tenant_network_cidr
+        self.assertRaises(
+            exceptions.BadRequest, self.client.create_security_group_rule,
+            security_group_id=sg1_body['security_group']['id'],
+            protocol='tcp', direction='ingress',
+            ethertype=self.ethertype, remote_ip_prefix=prefix,
+            remote_group_id=sg2_body['security_group']['id'])
+
+    @test.attr(type=['negative', 'gate'])
+    def test_create_security_group_rule_with_bad_ethertype(self):
+        group_create_body, _ = self._create_security_group()
+
+        # Create rule with bad ethertype
+        ethertype = 'bad_ethertype'
+        self.assertRaises(
+            exceptions.BadRequest, self.client.create_security_group_rule,
+            security_group_id=group_create_body['security_group']['id'],
+            protocol='udp', direction='ingress', ethertype=ethertype)
 
     @test.attr(type=['negative', 'gate'])
     def test_create_security_group_rule_with_invalid_ports(self):
         group_create_body, _ = self._create_security_group()
 
-        # Create rule with invalid ports
+        # Create rule for tcp protocol 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'),
+                  (None, 6, 'port_range_min must be <= port_range_max'),
                   (-16, 65536, 'Invalid value for port')]
         for pmin, pmax, msg in states:
             ex = self.assertRaises(
                 exceptions.BadRequest, self.client.create_security_group_rule,
                 security_group_id=group_create_body['security_group']['id'],
                 protocol='tcp', port_range_min=pmin, port_range_max=pmax,
-                direction='ingress')
+                direction='ingress', ethertype=self.ethertype)
+            self.assertIn(msg, str(ex))
+
+        # Create rule for icmp protocol with invalid ports
+        states = [(1, 256, 'Invalid value for ICMP code'),
+                  (300, 1, 'Invalid value for ICMP type')]
+        for pmin, pmax, msg in states:
+            ex = self.assertRaises(
+                exceptions.BadRequest, self.client.create_security_group_rule,
+                security_group_id=group_create_body['security_group']['id'],
+                protocol='icmp', port_range_min=pmin, port_range_max=pmax,
+                direction='ingress', ethertype=self.ethertype)
             self.assertIn(msg, str(ex))
 
     @test.attr(type=['negative', 'smoke'])
@@ -88,14 +156,47 @@
                           name=name)
 
     @test.attr(type=['negative', 'smoke'])
+    def test_create_duplicate_security_group_rule_fails(self):
+        # Create duplicate security group rule, it should fail.
+        body, _ = self._create_security_group()
+
+        min_port = 66
+        max_port = 67
+        # Create a rule with valid params
+        resp, _ = self.client.create_security_group_rule(
+            security_group_id=body['security_group']['id'],
+            direction='ingress',
+            ethertype=self.ethertype,
+            protocol='tcp',
+            port_range_min=min_port,
+            port_range_max=max_port
+        )
+
+        # Try creating the same security group rule, it should fail
+        self.assertRaises(
+            exceptions.Conflict, self.client.create_security_group_rule,
+            security_group_id=body['security_group']['id'],
+            protocol='tcp', direction='ingress', ethertype=self.ethertype,
+            port_range_min=min_port, port_range_max=max_port)
+
+    @test.attr(type=['negative', 'smoke'])
     def test_create_security_group_rule_with_non_existent_security_group(self):
         # Create security group rules with not existing security group.
         non_existent_sg = str(uuid.uuid4())
         self.assertRaises(exceptions.NotFound,
                           self.client.create_security_group_rule,
                           security_group_id=non_existent_sg,
-                          direction='ingress')
+                          direction='ingress', ethertype=self.ethertype)
 
 
 class NegativeSecGroupTestXML(NegativeSecGroupTest):
     _interface = 'xml'
+
+
+class NegativeSecGroupIPv6Test(NegativeSecGroupTest):
+    _ip_version = 6
+    _tenant_network_cidr = CONF.network.tenant_network_v6_cidr
+
+
+class NegativeSecGroupIPv6TestXML(NegativeSecGroupIPv6Test):
+    _interface = 'xml'
diff --git a/tempest/api/network/test_service_type_management.py b/tempest/api/network/test_service_type_management.py
index dbb72fb..302069f 100644
--- a/tempest/api/network/test_service_type_management.py
+++ b/tempest/api/network/test_service_type_management.py
@@ -18,8 +18,8 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(ServiceTypeManagementTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(ServiceTypeManagementTestJSON, cls).resource_setup()
         if not test.is_extension_enabled('service-type', 'network'):
             msg = "Neutron Service Type Management not enabled."
             raise cls.skipException(msg)
diff --git a/tempest/api/network/test_vpnaas_extensions.py b/tempest/api/network/test_vpnaas_extensions.py
index 09e9640..96b9804 100644
--- a/tempest/api/network/test_vpnaas_extensions.py
+++ b/tempest/api/network/test_vpnaas_extensions.py
@@ -34,12 +34,12 @@
     """
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not test.is_extension_enabled('vpnaas', 'network'):
             msg = "vpnaas extension not enabled."
             raise cls.skipException(msg)
-        super(VPNaaSTestJSON, cls).setUpClass()
+        super(VPNaaSTestJSON, cls).resource_setup()
+        cls.ext_net_id = CONF.network.public_network_id
         cls.network = cls.create_network()
         cls.subnet = cls.create_subnet(cls.network)
         cls.router = cls.create_router(
@@ -122,17 +122,21 @@
         tenant_id = self._get_tenant_id()
 
         # Create vpn service for the newly created tenant
+        network2 = self.create_network()
+        subnet2 = self.create_subnet(network2)
+        router2 = self.create_router(data_utils.rand_name('router-'),
+                                     external_network_id=self.ext_net_id)
+        self.create_router_interface(router2['id'], subnet2['id'])
         name = data_utils.rand_name('vpn-service')
         _, body = self.admin_client.create_vpnservice(
-            subnet_id=self.subnet['id'],
-            router_id=self.router['id'],
+            subnet_id=subnet2['id'],
+            router_id=router2['id'],
             name=name,
             admin_state_up=True,
             tenant_id=tenant_id)
         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']]
@@ -168,9 +172,14 @@
     @test.attr(type='smoke')
     def test_create_update_delete_vpn_service(self):
         # Creates a VPN service and sets up deletion
-        name = data_utils.rand_name('vpn-service')
-        _, body = self.client.create_vpnservice(subnet_id=self.subnet['id'],
-                                                router_id=self.router['id'],
+        network1 = self.create_network()
+        subnet1 = self.create_subnet(network1)
+        router1 = self.create_router(data_utils.rand_name('router-'),
+                                     external_network_id=self.ext_net_id)
+        self.create_router_interface(router1['id'], subnet1['id'])
+        name = data_utils.rand_name('vpn-service1')
+        _, body = self.client.create_vpnservice(subnet_id=subnet1['id'],
+                                                router_id=router1['id'],
                                                 name=name,
                                                 admin_state_up=True)
         vpnservice = body['vpnservice']
diff --git a/tempest/api/object_storage/base.py b/tempest/api/object_storage/base.py
index ccc0067..2e39cf9 100644
--- a/tempest/api/object_storage/base.py
+++ b/tempest/api/object_storage/base.py
@@ -28,26 +28,20 @@
 class BaseObjectTest(tempest.test.BaseTestCase):
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.set_network_resources()
-        super(BaseObjectTest, cls).setUpClass()
+        super(BaseObjectTest, cls).resource_setup()
         if not CONF.service_available.swift:
             skip_msg = ("%s skipped as swift is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
         cls.isolated_creds = isolated_creds.IsolatedCreds(
             cls.__name__, network_resources=cls.network_resources)
-        if CONF.compute.allow_tenant_isolation:
-            # Get isolated creds for normal user
-            cls.os = clients.Manager(cls.isolated_creds.get_primary_creds())
-            # Get isolated creds for admin user
-            cls.os_admin = clients.Manager(
-                cls.isolated_creds.get_admin_creds())
-            # Get isolated creds for alt user
-            cls.os_alt = clients.Manager(cls.isolated_creds.get_alt_creds())
-        else:
-            cls.os = clients.Manager()
-            cls.os_admin = clients.AdminManager()
-            cls.os_alt = clients.AltManager()
+        # Get isolated creds for normal user
+        cls.os = clients.Manager(cls.isolated_creds.get_primary_creds())
+        # Get isolated creds for admin user
+        cls.os_admin = clients.Manager(cls.isolated_creds.get_admin_creds())
+        # Get isolated creds for alt user
+        cls.os_alt = clients.Manager(cls.isolated_creds.get_alt_creds())
 
         cls.object_client = cls.os.object_client
         cls.container_client = cls.os.container_client
@@ -69,12 +63,13 @@
         cls.object_client_alt.auth_provider.clear_auth()
         cls.container_client_alt.auth_provider.clear_auth()
 
-        cls.data = base.DataGenerator(cls.identity_admin_client)
+        cls.data = SwiftDataGenerator(cls.identity_admin_client)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
+        cls.data.teardown_all()
         cls.isolated_creds.clear_isolated_creds()
-        super(BaseObjectTest, cls).tearDownClass()
+        super(BaseObjectTest, cls).resource_cleanup()
 
     @classmethod
     def delete_containers(cls, containers, container_client=None,
@@ -116,3 +111,28 @@
         self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders(
                         target, method))
         self.assertThat(resp, custom_matchers.AreAllWellFormatted())
+
+
+class SwiftDataGenerator(base.DataGenerator):
+
+    def setup_test_user(self, reseller=False):
+        super(SwiftDataGenerator, self).setup_test_user()
+        if reseller:
+            role_name = CONF.object_storage.reseller_admin_role
+        else:
+            role_name = CONF.object_storage.operator_role
+        role_id = self._get_role_id(role_name)
+        self._assign_role(role_id)
+
+    def _get_role_id(self, role_name):
+        try:
+            _, roles = self.client.list_roles()
+            return next(r['id'] for r in roles if r['name'] == role_name)
+        except StopIteration:
+            msg = "Role name '%s' is not found" % role_name
+            raise exceptions.NotFound(msg)
+
+    def _assign_role(self, role_id):
+        self.client.assign_user_role(self.tenant['id'],
+                                     self.user['id'],
+                                     role_id)
diff --git a/tempest/api/object_storage/test_account_bulk.py b/tempest/api/object_storage/test_account_bulk.py
index a94c883..31a80cf 100644
--- a/tempest/api/object_storage/test_account_bulk.py
+++ b/tempest/api/object_storage/test_account_bulk.py
@@ -50,21 +50,30 @@
 
         return tarpath.name, container_name, object_name
 
-    @test.attr(type='gate')
-    def test_extract_archive(self):
-        # Test bulk operation of file upload with an archived file
-        filepath, container_name, object_name = self._create_archive()
-
+    def _upload_archive(self, filepath):
+        # upload an archived file
         params = {'extract-archive': 'tar'}
         with open(filepath) as fh:
             mydata = fh.read()
             resp, body = self.account_client.create_account(data=mydata,
                                                             params=params)
+        return resp, body
+
+    def _check_contents_deleted(self, container_name):
+        param = {'format': 'txt'}
+        resp, body = self.account_client.list_account_containers(param)
+        self.assertHeaders(resp, 'Account', 'GET')
+        self.assertNotIn(container_name, body)
+
+    @test.attr(type='gate')
+    @test.requires_ext(extension='bulk', service='object')
+    def test_extract_archive(self):
+        # Test bulk operation of file upload with an archived file
+        filepath, container_name, object_name = self._create_archive()
+        resp, _ = self._upload_archive(filepath)
 
         self.containers.append(container_name)
 
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
-
         # When uploading an archived file with the bulk operation, the response
         # does not contain 'content-length' header. This is the special case,
         # therefore the existence of response headers is checked without
@@ -80,7 +89,6 @@
         param = {'format': 'json'}
         resp, body = self.account_client.list_account_containers(param)
 
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Account', 'GET')
 
         self.assertIn(container_name, [b['name'] for b in body])
@@ -89,29 +97,22 @@
         resp, contents_list = self.container_client.list_container_contents(
             container_name, param)
 
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'GET')
 
         self.assertIn(object_name, [c['name'] for c in contents_list])
 
     @test.attr(type='gate')
+    @test.requires_ext(extension='bulk', service='object')
     def test_bulk_delete(self):
         # Test bulk operation of deleting multiple files
         filepath, container_name, object_name = self._create_archive()
-
-        params = {'extract-archive': 'tar'}
-        with open(filepath) as fh:
-            mydata = fh.read()
-            resp, body = self.account_client.create_account(data=mydata,
-                                                            params=params)
+        self._upload_archive(filepath)
 
         data = '%s/%s\n%s' % (container_name, object_name, container_name)
         params = {'bulk-delete': ''}
         resp, body = self.account_client.delete_account(data=data,
                                                         params=params)
 
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
-
         # When deleting multiple files using the bulk operation, the response
         # does not contain 'content-length' header. This is the special case,
         # therefore the existence of response headers is checked without
@@ -124,11 +125,33 @@
         # Check only the format of common headers with custom matcher
         self.assertThat(resp, custom_matchers.AreAllWellFormatted())
 
-        # Check if a container is deleted
-        param = {'format': 'txt'}
-        resp, body = self.account_client.list_account_containers(param)
+        # Check if uploaded contents are completely deleted
+        self._check_contents_deleted(container_name)
 
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
-        self.assertHeaders(resp, 'Account', 'GET')
+    @test.attr(type='gate')
+    @test.requires_ext(extension='bulk', service='object')
+    def test_bulk_delete_by_POST(self):
+        # Test bulk operation of deleting multiple files
+        filepath, container_name, object_name = self._create_archive()
+        self._upload_archive(filepath)
 
-        self.assertNotIn(container_name, body)
+        data = '%s/%s\n%s' % (container_name, object_name, container_name)
+        params = {'bulk-delete': ''}
+
+        resp, body = self.account_client.create_account_metadata(
+            {}, data=data, params=params)
+
+        # When deleting multiple files using the bulk operation, the response
+        # does not contain 'content-length' header. This is the special case,
+        # therefore the existence of response headers is checked without
+        # custom matcher.
+        self.assertIn('transfer-encoding', resp)
+        self.assertIn('content-type', resp)
+        self.assertIn('x-trans-id', resp)
+        self.assertIn('date', resp)
+
+        # Check only the format of common headers with custom matcher
+        self.assertThat(resp, custom_matchers.AreAllWellFormatted())
+
+        # Check if uploaded contents are completely deleted
+        self._check_contents_deleted(container_name)
diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py
index 19e3068..e75e971 100644
--- a/tempest/api/object_storage/test_account_quotas.py
+++ b/tempest/api/object_storage/test_account_quotas.py
@@ -18,7 +18,6 @@
 from tempest import clients
 from tempest.common.utils import data_utils
 from tempest import config
-from tempest import exceptions
 from tempest import test
 
 CONF = config.CONF
@@ -27,38 +26,15 @@
 class AccountQuotasTest(base.BaseObjectTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(AccountQuotasTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(AccountQuotasTest, cls).resource_setup()
         cls.container_name = data_utils.rand_name(name="TestContainer")
         cls.container_client.create_container(cls.container_name)
 
-        cls.data.setup_test_user()
+        cls.data.setup_test_user(reseller=True)
 
         cls.os_reselleradmin = clients.Manager(cls.data.test_credentials)
 
-        # Retrieve the ResellerAdmin role id
-        reseller_role_id = None
-        try:
-            _, roles = cls.os_admin.identity_client.list_roles()
-            reseller_role_id = next(r['id'] for r in roles if r['name']
-                                    == CONF.object_storage.reseller_admin_role)
-        except StopIteration:
-            msg = "No ResellerAdmin role found"
-            raise exceptions.NotFound(msg)
-
-        # Retrieve the ResellerAdmin user id
-        reseller_user_id = cls.data.test_credentials.user_id
-
-        # Retrieve the ResellerAdmin tenant id
-        reseller_tenant_id = cls.data.test_credentials.tenant_id
-
-        # Assign the newly created user the appropriate ResellerAdmin role
-        cls.os_admin.identity_client.assign_user_role(
-            reseller_tenant_id,
-            reseller_user_id,
-            reseller_role_id)
-
         # Retrieve a ResellerAdmin auth data and use it to set a quota
         # on the client's account
         cls.reselleradmin_auth_data = \
@@ -94,11 +70,10 @@
         super(AccountQuotasTest, self).tearDown()
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         if hasattr(cls, "container_name"):
             cls.delete_containers([cls.container_name])
-        cls.data.teardown_all()
-        super(AccountQuotasTest, cls).tearDownClass()
+        super(AccountQuotasTest, cls).resource_cleanup()
 
     @test.attr(type="smoke")
     @test.requires_ext(extension='account_quotas', service='object')
@@ -108,7 +83,6 @@
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
 
-        self.assertEqual(resp["status"], "201")
         self.assertHeaders(resp, 'Object', 'PUT')
 
     @test.attr(type=["smoke"])
diff --git a/tempest/api/object_storage/test_account_quotas_negative.py b/tempest/api/object_storage/test_account_quotas_negative.py
index 6afd381..6c1fb5a 100644
--- a/tempest/api/object_storage/test_account_quotas_negative.py
+++ b/tempest/api/object_storage/test_account_quotas_negative.py
@@ -27,38 +27,15 @@
 class AccountQuotasNegativeTest(base.BaseObjectTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(AccountQuotasNegativeTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(AccountQuotasNegativeTest, cls).resource_setup()
         cls.container_name = data_utils.rand_name(name="TestContainer")
         cls.container_client.create_container(cls.container_name)
 
-        cls.data.setup_test_user()
+        cls.data.setup_test_user(reseller=True)
 
         cls.os_reselleradmin = clients.Manager(cls.data.test_credentials)
 
-        # Retrieve the ResellerAdmin role id
-        reseller_role_id = None
-        try:
-            _, roles = cls.os_admin.identity_client.list_roles()
-            reseller_role_id = next(r['id'] for r in roles if r['name']
-                                    == CONF.object_storage.reseller_admin_role)
-        except StopIteration:
-            msg = "No ResellerAdmin role found"
-            raise exceptions.NotFound(msg)
-
-        # Retrieve the ResellerAdmin tenant id
-        reseller_user_id = cls.data.test_credentials.user_id
-
-        # Retrieve the ResellerAdmin tenant id
-        reseller_tenant_id = cls.data.test_credentials.tenant_id
-
-        # Assign the newly created user the appropriate ResellerAdmin role
-        cls.os_admin.identity_client.assign_user_role(
-            reseller_tenant_id,
-            reseller_user_id,
-            reseller_role_id)
-
         # Retrieve a ResellerAdmin auth data and use it to set a quota
         # on the client's account
         cls.reselleradmin_auth_data = \
@@ -93,11 +70,10 @@
         super(AccountQuotasNegativeTest, self).tearDown()
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         if hasattr(cls, "container_name"):
             cls.delete_containers([cls.container_name])
-        cls.data.teardown_all()
-        super(AccountQuotasNegativeTest, cls).tearDownClass()
+        super(AccountQuotasNegativeTest, cls).resource_cleanup()
 
     @test.attr(type=["negative", "smoke"])
     @test.requires_ext(extension='account_quotas', service='object')
diff --git a/tempest/api/object_storage/test_account_services.py b/tempest/api/object_storage/test_account_services.py
index d615374..2bc4f59 100644
--- a/tempest/api/object_storage/test_account_services.py
+++ b/tempest/api/object_storage/test_account_services.py
@@ -14,15 +14,14 @@
 #    under the License.
 
 import random
-
 from six import moves
+import testtools
 
 from tempest.api.object_storage import base
 from tempest import clients
 from tempest.common import custom_matchers
 from tempest.common.utils import data_utils
 from tempest import config
-from tempest import exceptions
 from tempest import test
 
 CONF = config.CONF
@@ -33,9 +32,8 @@
     containers = []
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(AccountTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(AccountTest, cls).resource_setup()
         for i in moves.xrange(ord('a'), ord('f') + 1):
             name = data_utils.rand_name(name='%s-' % chr(i))
             cls.container_client.create_container(name)
@@ -43,10 +41,9 @@
         cls.containers_count = len(cls.containers)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.delete_containers(cls.containers)
-        cls.data.teardown_all()
-        super(AccountTest, cls).tearDownClass()
+        super(AccountTest, cls).resource_cleanup()
 
     @test.attr(type='smoke')
     def test_list_containers(self):
@@ -66,39 +63,10 @@
         # the base user of this instance.
         self.data.setup_test_user()
 
-        os_test_user = clients.Manager(
-            self.data.test_credentials)
-
-        # Retrieve the id of an operator role of object storage
-        test_role_id = None
-        swift_role = CONF.object_storage.operator_role
-        try:
-            _, roles = self.os_admin.identity_client.list_roles()
-            test_role_id = next(r['id'] for r in roles if r['name']
-                                == swift_role)
-        except StopIteration:
-            msg = "%s role found" % swift_role
-            raise exceptions.NotFound(msg)
-
-        # Retrieve the test_user id
-        _, users = self.os_admin.identity_client.get_users()
-        test_user_id = next(usr['id'] for usr in users if usr['name']
-                            == self.data.test_user)
-
-        # Retrieve the test_tenant id
-        _, tenants = self.os_admin.identity_client.list_tenants()
-        test_tenant_id = next(tnt['id'] for tnt in tenants if tnt['name']
-                              == self.data.test_tenant)
-
-        # Assign the newly created user the appropriate operator role
-        self.os_admin.identity_client.assign_user_role(
-            test_tenant_id,
-            test_user_id,
-            test_role_id)
+        os_test_user = clients.Manager(self.data.test_credentials)
 
         resp, container_list = \
             os_test_user.account_client.list_account_containers()
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
 
         # When sending a request to an account which has not received a PUT
         # container request, the response does not contain 'accept-ranges'
@@ -124,7 +92,6 @@
         params = {'format': 'json'}
         resp, container_list = self.account_client.list_account_containers(
             params=params)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Account', 'GET')
         self.assertIsNotNone(container_list)
         self.assertTrue([c['name'] for c in container_list])
@@ -137,7 +104,6 @@
         params = {'format': 'xml'}
         resp, container_list = self.account_client.list_account_containers(
             params=params)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Account', 'GET')
         self.assertIsNotNone(container_list)
         self.assertEqual(container_list.tag, 'account')
@@ -148,10 +114,12 @@
         self.assertEqual(container_list.find(".//bytes").tag, 'bytes')
 
     @test.attr(type='smoke')
+    @testtools.skipIf(
+        not CONF.object_storage_feature_enabled.discoverability,
+        'Discoverability function is disabled')
     def test_list_extensions(self):
         resp, extensions = self.account_client.list_extensions()
 
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertThat(resp, custom_matchers.AreAllWellFormatted())
 
     @test.attr(type='smoke')
@@ -210,7 +178,6 @@
                   'end_marker': self.containers[self.containers_count - 1]}
         resp, container_list = self.account_client.list_account_containers(
             params=params)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Account', 'GET')
         self.assertEqual(len(container_list), self.containers_count - 2)
 
@@ -236,7 +203,6 @@
                   'end_marker': self.containers[self.containers_count / 2]}
         resp, container_list = self.account_client.list_account_containers(
             params=params)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Account', 'GET')
         self.assertEqual(len(container_list),
                          min(limit, self.containers_count / 2))
@@ -250,7 +216,6 @@
                   'end_marker': self.containers[self.containers_count - 1]}
         resp, container_list = self.account_client.list_account_containers(
             params=params)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Account', 'GET')
         self.assertEqual(len(container_list),
                          min(limit, self.containers_count - 2))
@@ -265,7 +230,6 @@
         resp, _ = self.account_client.create_account_metadata(metadata)
 
         resp, _ = self.account_client.list_account_metadata()
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Account', 'HEAD')
         self.assertIn('x-account-meta-test-account-meta1', resp)
         self.assertIn('x-account-meta-test-account-meta2', resp)
@@ -275,7 +239,6 @@
     def test_list_no_account_metadata(self):
         # list no account metadata
         resp, _ = self.account_client.list_account_metadata()
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Account', 'HEAD')
         self.assertNotIn('x-account-meta-', str(resp))
 
@@ -284,7 +247,6 @@
         # add metadata to account
         metadata = {'test-account-meta1': 'Meta1'}
         resp, _ = self.account_client.create_account_metadata(metadata)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Account', 'POST')
 
         resp, body = self.account_client.list_account_metadata()
@@ -300,7 +262,6 @@
         metadata = {'test-account-meta1': 'Meta1'}
         self.account_client.create_account_metadata(metadata)
         resp, _ = self.account_client.delete_account_metadata(metadata)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Account', 'POST')
 
         resp, _ = self.account_client.list_account_metadata()
@@ -312,7 +273,6 @@
         # registered at a server
         metadata = {'test-account-meta1': ''}
         resp, _ = self.account_client.create_account_metadata(metadata)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Account', 'POST')
 
         resp, _ = self.account_client.list_account_metadata()
@@ -326,7 +286,6 @@
         self.account_client.create_account_metadata(metadata_1)
         metadata_2 = {'test-account-meta1': ''}
         resp, _ = self.account_client.delete_account_metadata(metadata_2)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Account', 'POST')
 
         resp, _ = self.account_client.list_account_metadata()
@@ -341,7 +300,6 @@
         resp, body = self.account_client.create_and_delete_account_metadata(
             metadata_2,
             metadata_1)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Account', 'POST')
 
         resp, _ = self.account_client.list_account_metadata()
diff --git a/tempest/api/object_storage/test_account_services_negative.py b/tempest/api/object_storage/test_account_services_negative.py
index 490672d..e4c46e2 100644
--- a/tempest/api/object_storage/test_account_services_negative.py
+++ b/tempest/api/object_storage/test_account_services_negative.py
@@ -47,5 +47,3 @@
         self.assertRaises(exceptions.Unauthorized,
                           self.custom_account_client.list_account_containers,
                           params=params)
-        # delete the user which was created
-        self.data.teardown_all()
diff --git a/tempest/api/object_storage/test_container_acl.py b/tempest/api/object_storage/test_container_acl.py
index fc51504..2244900 100644
--- a/tempest/api/object_storage/test_container_acl.py
+++ b/tempest/api/object_storage/test_container_acl.py
@@ -21,17 +21,12 @@
 
 class ObjectTestACLs(base.BaseObjectTest):
     @classmethod
-    def setUpClass(cls):
-        super(ObjectTestACLs, cls).setUpClass()
+    def resource_setup(cls):
+        super(ObjectTestACLs, cls).resource_setup()
         cls.data.setup_test_user()
         test_os = clients.Manager(cls.data.test_credentials)
         cls.test_auth_data = test_os.auth_provider.auth_data
 
-    @classmethod
-    def tearDownClass(cls):
-        cls.data.teardown_all()
-        super(ObjectTestACLs, cls).tearDownClass()
-
     def setUp(self):
         super(ObjectTestACLs, self).setUp()
         self.container_name = data_utils.rand_name(name='TestContainer')
@@ -50,13 +45,11 @@
         resp_meta, body = self.container_client.update_container_metadata(
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
-        self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp_meta, 'Container', 'POST')
         # create object
         object_name = data_utils.rand_name(name='Object')
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, 'data')
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
         # Trying to read the object with rights
         self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -65,7 +58,6 @@
         )
         resp, _ = self.custom_object_client.get_object(
             self.container_name, object_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'GET')
 
     @test.attr(type='smoke')
@@ -77,7 +69,6 @@
         resp_meta, body = self.container_client.update_container_metadata(
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
-        self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp_meta, 'Container', 'POST')
         # Trying to write the object with rights
         self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -88,5 +79,4 @@
         resp, _ = self.custom_object_client.create_object(
             self.container_name,
             object_name, 'data')
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'PUT')
diff --git a/tempest/api/object_storage/test_container_acl_negative.py b/tempest/api/object_storage/test_container_acl_negative.py
index ca53876..fed4549 100644
--- a/tempest/api/object_storage/test_container_acl_negative.py
+++ b/tempest/api/object_storage/test_container_acl_negative.py
@@ -23,17 +23,12 @@
 
 class ObjectACLsNegativeTest(base.BaseObjectTest):
     @classmethod
-    def setUpClass(cls):
-        super(ObjectACLsNegativeTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(ObjectACLsNegativeTest, cls).resource_setup()
         cls.data.setup_test_user()
         test_os = clients.Manager(cls.data.test_credentials)
         cls.test_auth_data = test_os.auth_provider.auth_data
 
-    @classmethod
-    def tearDownClass(cls):
-        cls.data.teardown_all()
-        super(ObjectACLsNegativeTest, cls).tearDownClass()
-
     def setUp(self):
         super(ObjectACLsNegativeTest, self).setUp()
         self.container_name = data_utils.rand_name(name='TestContainer')
@@ -93,7 +88,6 @@
         object_name = data_utils.rand_name(name='Object')
         resp, _ = self.object_client.create_object(
             self.container_name, object_name, 'data')
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
         # trying to get object with non authorized user token
         self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -111,7 +105,6 @@
         object_name = data_utils.rand_name(name='Object')
         resp, _ = self.object_client.create_object(
             self.container_name, object_name, 'data')
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
         # trying to delete object with non-authorized user token
         self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -130,13 +123,11 @@
         resp_meta, body = self.container_client.update_container_metadata(
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
-        self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp_meta, 'Container', 'POST')
         # create object
         object_name = data_utils.rand_name(name='Object')
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, 'data')
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
         # Trying to read the object without rights
         self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -155,7 +146,6 @@
         resp_meta, body = self.container_client.update_container_metadata(
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
-        self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp_meta, 'Container', 'POST')
         # Trying to write the object without rights
         self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -178,7 +168,6 @@
         resp_meta, body = self.container_client.update_container_metadata(
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
-        self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp_meta, 'Container', 'POST')
         # Trying to write the object without write rights
         self.custom_object_client.auth_provider.set_alt_auth_data(
@@ -201,13 +190,11 @@
         resp_meta, body = self.container_client.update_container_metadata(
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
-        self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp_meta, 'Container', 'POST')
         # create object
         object_name = data_utils.rand_name(name='Object')
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, 'data')
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
         # Trying to delete the object without write rights
         self.custom_object_client.auth_provider.set_alt_auth_data(
diff --git a/tempest/api/object_storage/test_container_quotas.py b/tempest/api/object_storage/test_container_quotas.py
index 59b84d9..46944ed 100644
--- a/tempest/api/object_storage/test_container_quotas.py
+++ b/tempest/api/object_storage/test_container_quotas.py
@@ -61,7 +61,6 @@
 
         resp, _ = self.object_client.create_object(
             self.container_name, object_name, data)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'PUT')
 
         nafter = self._get_bytes_used()
diff --git a/tempest/api/object_storage/test_container_services.py b/tempest/api/object_storage/test_container_services.py
index 8689d10..fe06fd0 100644
--- a/tempest/api/object_storage/test_container_services.py
+++ b/tempest/api/object_storage/test_container_services.py
@@ -51,7 +51,6 @@
         container_name = data_utils.rand_name(name='TestContainer')
         resp, body = self.container_client.create_container(container_name)
         self.containers.append(container_name)
-        self.assertIn(resp['status'], ('202', '201'))
         self.assertHeaders(resp, 'Container', 'PUT')
 
     @test.attr(type='smoke')
@@ -62,7 +61,6 @@
         self.containers.append(container_name)
 
         resp, _ = self.container_client.create_container(container_name)
-        self.assertIn(resp['status'], ('202', '201'))
         self.assertHeaders(resp, 'Container', 'PUT')
 
     @test.attr(type='smoke')
@@ -74,7 +72,6 @@
             container_name,
             metadata=metadata)
         self.containers.append(container_name)
-        self.assertIn(resp['status'], ('201', '202'))
         self.assertHeaders(resp, 'Container', 'PUT')
 
         resp, _ = self.container_client.list_container_metadata(
@@ -93,7 +90,6 @@
             container_name,
             metadata=metadata)
         self.containers.append(container_name)
-        self.assertIn(resp['status'], ('201', '202'))
         self.assertHeaders(resp, 'Container', 'PUT')
 
         resp, _ = self.container_client.list_container_metadata(
@@ -116,7 +112,6 @@
         resp, _ = self.container_client.create_container(
             container_name,
             remove_metadata=metadata_2)
-        self.assertIn(resp['status'], ('201', '202'))
         self.assertHeaders(resp, 'Container', 'PUT')
 
         resp, _ = self.container_client.list_container_metadata(
@@ -135,7 +130,6 @@
         resp, _ = self.container_client.create_container(
             container_name,
             remove_metadata=metadata)
-        self.assertIn(resp['status'], ('201', '202'))
         self.assertHeaders(resp, 'Container', 'PUT')
 
         resp, _ = self.container_client.list_container_metadata(
@@ -146,11 +140,9 @@
     def test_delete_container(self):
         # create a container
         container_name = self._create_container()
-        # delete container
+        # delete container, success asserted within
         resp, _ = self.container_client.delete_container(container_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'DELETE')
-
         self.containers.remove(container_name)
 
     @test.attr(type='smoke')
@@ -161,7 +153,6 @@
 
         resp, object_list = self.container_client.list_container_contents(
             container_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEqual(object_name, object_list.strip('\n'))
 
@@ -172,7 +163,6 @@
 
         resp, object_list = self.container_client.list_container_contents(
             container_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEqual('', object_list.strip('\n'))
 
@@ -187,7 +177,6 @@
         resp, object_list = self.container_client.list_container_contents(
             container_name,
             params=params)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEqual(object_name.split('/')[0], object_list.strip('/\n'))
 
@@ -201,7 +190,6 @@
         resp, object_list = self.container_client.list_container_contents(
             container_name,
             params=params)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEqual(object_name, object_list.strip('\n'))
 
@@ -215,7 +203,6 @@
         resp, object_list = self.container_client.list_container_contents(
             container_name,
             params=params)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'GET')
 
         self.assertIsNotNone(object_list)
@@ -235,7 +222,6 @@
         resp, object_list = self.container_client.list_container_contents(
             container_name,
             params=params)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'GET')
 
         self.assertIsNotNone(object_list)
@@ -260,7 +246,6 @@
         resp, object_list = self.container_client.list_container_contents(
             container_name,
             params=params)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEqual(object_name, object_list.strip('\n'))
 
@@ -274,7 +259,6 @@
         resp, object_list = self.container_client.list_container_contents(
             container_name,
             params=params)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEqual(object_name, object_list.strip('\n'))
 
@@ -289,7 +273,6 @@
         resp, object_list = self.container_client.list_container_contents(
             container_name,
             params=params)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEqual(object_name, object_list.strip('\n'))
 
@@ -304,7 +287,6 @@
         resp, object_list = self.container_client.list_container_contents(
             container_name,
             params=params)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'GET')
         self.assertEqual(object_name, object_list.strip('\n'))
 
@@ -320,7 +302,6 @@
 
         resp, _ = self.container_client.list_container_metadata(
             container_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'HEAD')
         self.assertIn('x-container-meta-name', resp)
         self.assertEqual(resp['x-container-meta-name'], metadata['name'])
@@ -332,7 +313,6 @@
 
         resp, _ = self.container_client.list_container_metadata(
             container_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'HEAD')
         self.assertNotIn('x-container-meta-', str(resp))
 
@@ -350,7 +330,6 @@
             container_name,
             metadata=metadata_2,
             remove_metadata=metadata_1)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'POST')
 
         resp, _ = self.container_client.list_container_metadata(
@@ -369,7 +348,6 @@
         resp, _ = self.container_client.update_container_metadata(
             container_name,
             metadata=metadata)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'POST')
 
         resp, _ = self.container_client.list_container_metadata(
@@ -390,7 +368,6 @@
         resp, _ = self.container_client.delete_container_metadata(
             container_name,
             metadata=metadata)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'POST')
 
         resp, _ = self.container_client.list_container_metadata(
@@ -406,7 +383,6 @@
         resp, _ = self.container_client.update_container_metadata(
             container_name,
             metadata=metadata)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'POST')
 
         resp, _ = self.container_client.list_container_metadata(
@@ -426,7 +402,6 @@
         resp, _ = self.container_client.delete_container_metadata(
             container_name,
             metadata=metadata)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'POST')
 
         resp, _ = self.container_client.list_container_metadata(container_name)
diff --git a/tempest/api/object_storage/test_container_staticweb.py b/tempest/api/object_storage/test_container_staticweb.py
index 581c6d9..5c4e0bf 100644
--- a/tempest/api/object_storage/test_container_staticweb.py
+++ b/tempest/api/object_storage/test_container_staticweb.py
@@ -23,9 +23,8 @@
 class StaticWebTest(base.BaseObjectTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(StaticWebTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(StaticWebTest, cls).resource_setup()
         cls.container_name = data_utils.rand_name(name="TestContainer")
 
         # This header should be posted on the container before every test
@@ -45,11 +44,10 @@
             metadata_prefix="X-Container-")
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         if hasattr(cls, "container_name"):
             cls.delete_containers([cls.container_name])
-        cls.data.teardown_all()
-        super(StaticWebTest, cls).tearDownClass()
+        super(StaticWebTest, cls).resource_cleanup()
 
     @test.requires_ext(extension='staticweb', service='object')
     @test.attr('gate')
@@ -69,7 +67,6 @@
         # we should retrieve the self.object_name file
         resp, body = self.custom_account_client.request("GET",
                                                         self.container_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         # This request is equivalent to GET object
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, self.object_data)
@@ -94,7 +91,6 @@
         # we should retrieve a listing of objects
         resp, body = self.custom_account_client.request("GET",
                                                         self.container_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         # The target of the request is not any Swift resource. Therefore, the
         # existence of response header is checked without a custom matcher.
         self.assertIn('content-length', resp)
@@ -133,7 +129,6 @@
         # we should retrieve a listing of objects
         resp, body = self.custom_account_client.request("GET",
                                                         self.container_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertIn(self.object_name, body)
         css = '<link rel="stylesheet" type="text/css" href="listings.css" />'
         self.assertIn(css, body)
diff --git a/tempest/api/object_storage/test_container_sync.py b/tempest/api/object_storage/test_container_sync.py
index 5f46d01..a50e392 100644
--- a/tempest/api/object_storage/test_container_sync.py
+++ b/tempest/api/object_storage/test_container_sync.py
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
 import time
 import urlparse
 
@@ -34,9 +35,8 @@
     clients = {}
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(ContainerSyncTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(ContainerSyncTest, cls).resource_setup()
         cls.containers = []
         cls.objects = []
 
@@ -61,13 +61,16 @@
             cls.containers.append(cont_name)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         for client in cls.clients.values():
             cls.delete_containers(cls.containers, client[0], client[1])
-        super(ContainerSyncTest, cls).tearDownClass()
+        super(ContainerSyncTest, cls).resource_cleanup()
 
     @test.attr(type='slow')
     @test.skip_because(bug='1317133')
+    @testtools.skipIf(
+        not CONF.object_storage_feature_enabled.container_sync,
+        'Old-style container sync function is disabled')
     def test_container_synchronization(self):
         # container to container synchronization
         # to allow/accept sync requests to/from other accounts
@@ -87,12 +90,10 @@
                        (client_base_url, str(cont[1]))}
             resp, body = \
                 cont_client[0].put(str(cont[0]), body=None, headers=headers)
-            self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
             # create object in container
             object_name = data_utils.rand_name(name='TestSyncObject')
             data = object_name[::-1]  # data_utils.arbitrary_string()
             resp, _ = obj_client[0].create_object(cont[0], object_name, data)
-            self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
             self.objects.append(object_name)
 
         # wait until container contents list is not empty
@@ -105,7 +106,6 @@
                     cont_client[client_index].\
                     list_container_contents(self.containers[client_index],
                                             params=params)
-                self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
                 object_lists.append(dict(
                     (obj['name'], obj) for obj in object_list))
             # check that containers are not empty and have equal keys()
@@ -125,5 +125,4 @@
         for obj_client, cont in obj_clients:
             for obj_name in object_lists[0]:
                 resp, object_content = obj_client.get_object(cont, obj_name)
-                self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
                 self.assertEqual(object_content, obj_name[::-1])
diff --git a/tempest/api/object_storage/test_crossdomain.py b/tempest/api/object_storage/test_crossdomain.py
index d1541b9..66e8176 100644
--- a/tempest/api/object_storage/test_crossdomain.py
+++ b/tempest/api/object_storage/test_crossdomain.py
@@ -15,7 +15,6 @@
 # under the License.
 
 from tempest.api.object_storage import base
-from tempest import clients
 from tempest.common import custom_matchers
 from tempest import test
 
@@ -23,13 +22,8 @@
 class CrossdomainTest(base.BaseObjectTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(CrossdomainTest, cls).setUpClass()
-        # creates a test user. The test user will set its base_url to the Swift
-        # endpoint and test the healthcheck feature.
-        cls.data.setup_test_user()
-
-        cls.os_test_user = clients.Manager(cls.data.test_credentials)
+    def resource_setup(cls):
+        super(CrossdomainTest, cls).resource_setup()
 
         cls.xml_start = '<?xml version="1.0"?>\n' \
                         '<!DOCTYPE cross-domain-policy SYSTEM ' \
@@ -38,31 +32,17 @@
 
         cls.xml_end = "</cross-domain-policy>"
 
-    @classmethod
-    def tearDownClass(cls):
-        cls.data.teardown_all()
-        super(CrossdomainTest, cls).tearDownClass()
-
     def setUp(self):
         super(CrossdomainTest, self).setUp()
 
-        client = self.os_test_user.account_client
         # Turning http://.../v1/foobar into http://.../
-        client.skip_path()
-
-    def tearDown(self):
-        # clear the base_url for subsequent requests
-        self.os_test_user.account_client.reset_path()
-
-        super(CrossdomainTest, self).tearDown()
+        self.account_client.skip_path()
 
     @test.attr('gate')
     @test.requires_ext(extension='crossdomain', service='object')
     def test_get_crossdomain_policy(self):
-        resp, body = self.os_test_user.account_client.get("crossdomain.xml",
-                                                          {})
+        resp, body = self.account_client.get("crossdomain.xml", {})
 
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertTrue(body.startswith(self.xml_start) and
                         body.endswith(self.xml_end))
 
diff --git a/tempest/api/object_storage/test_healthcheck.py b/tempest/api/object_storage/test_healthcheck.py
index e27c7ef..53c0347 100644
--- a/tempest/api/object_storage/test_healthcheck.py
+++ b/tempest/api/object_storage/test_healthcheck.py
@@ -23,8 +23,8 @@
 class HealthcheckTest(base.BaseObjectTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(HealthcheckTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(HealthcheckTest, cls).resource_setup()
 
     def setUp(self):
         super(HealthcheckTest, self).setUp()
@@ -36,9 +36,6 @@
 
         resp, _ = self.account_client.get("healthcheck", {})
 
-        # The status is expected to be 200
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
-
         # The target of the request is not any Swift resource. Therefore, the
         # existence of response header is checked without a custom matcher.
         self.assertIn('content-length', resp)
diff --git a/tempest/api/object_storage/test_object_expiry.py b/tempest/api/object_storage/test_object_expiry.py
index 73b4f3b..5fa209d 100644
--- a/tempest/api/object_storage/test_object_expiry.py
+++ b/tempest/api/object_storage/test_object_expiry.py
@@ -23,8 +23,8 @@
 
 class ObjectExpiryTest(base.BaseObjectTest):
     @classmethod
-    def setUpClass(cls):
-        super(ObjectExpiryTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(ObjectExpiryTest, cls).resource_setup()
         cls.container_name = data_utils.rand_name(name='TestContainer')
         cls.container_client.create_container(cls.container_name)
 
@@ -36,9 +36,9 @@
                                                    self.object_name, '')
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.delete_containers([cls.container_name])
-        super(ObjectExpiryTest, cls).tearDownClass()
+        super(ObjectExpiryTest, cls).resource_cleanup()
 
     def _test_object_expiry(self, metadata):
         # update object metadata
@@ -51,7 +51,6 @@
         resp, _ = \
             self.object_client.list_object_metadata(self.container_name,
                                                     self.object_name)
-        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
@@ -60,7 +59,6 @@
 
         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)
 
diff --git a/tempest/api/object_storage/test_object_formpost.py b/tempest/api/object_storage/test_object_formpost.py
index dc5585e..7a9fcf6 100644
--- a/tempest/api/object_storage/test_object_formpost.py
+++ b/tempest/api/object_storage/test_object_formpost.py
@@ -30,9 +30,8 @@
     containers = []
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(ObjectFormPostTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(ObjectFormPostTest, cls).resource_setup()
         cls.container_name = data_utils.rand_name(name='TestContainer')
         cls.object_name = data_utils.rand_name(name='ObjectTemp')
 
@@ -56,11 +55,10 @@
             self.key)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.account_client.delete_account_metadata(metadata=cls.metadata)
         cls.delete_containers(cls.containers)
-        cls.data.teardown_all()
-        super(ObjectFormPostTest, cls).tearDownClass()
+        super(ObjectFormPostTest, cls).resource_cleanup()
 
     def get_multipart_form(self, expires=600):
         path = "%s/%s/%s" % (
@@ -119,12 +117,10 @@
         url = "%s/%s" % (self.container_name, self.object_name)
 
         resp, body = self.object_client.post(url, body, headers=headers)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, "Object", "POST")
 
         # Ensure object is available
         resp, body = self.object_client.get("%s/%s%s" % (
             self.container_name, self.object_name, "testfile"))
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, "Object", "GET")
         self.assertEqual(body, "hello world")
diff --git a/tempest/api/object_storage/test_object_formpost_negative.py b/tempest/api/object_storage/test_object_formpost_negative.py
index 878bf6d..32f5917 100644
--- a/tempest/api/object_storage/test_object_formpost_negative.py
+++ b/tempest/api/object_storage/test_object_formpost_negative.py
@@ -30,9 +30,8 @@
     containers = []
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(ObjectFormPostNegativeTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(ObjectFormPostNegativeTest, cls).resource_setup()
         cls.container_name = data_utils.rand_name(name='TestContainer')
         cls.object_name = data_utils.rand_name(name='ObjectTemp')
 
@@ -56,11 +55,10 @@
             self.key)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.account_client.delete_account_metadata(metadata=cls.metadata)
         cls.delete_containers(cls.containers)
-        cls.data.teardown_all()
-        super(ObjectFormPostNegativeTest, cls).tearDownClass()
+        super(ObjectFormPostNegativeTest, cls).resource_cleanup()
 
     def get_multipart_form(self, expires=600):
         path = "%s/%s/%s" % (
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 8b74b7e..f78220c 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -30,16 +30,16 @@
 
 class ObjectTest(base.BaseObjectTest):
     @classmethod
-    def setUpClass(cls):
-        super(ObjectTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(ObjectTest, cls).resource_setup()
         cls.container_name = data_utils.rand_name(name='TestContainer')
         cls.container_client.create_container(cls.container_name)
         cls.containers = [cls.container_name]
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.delete_containers(cls.containers)
-        super(ObjectTest, cls).tearDownClass()
+        super(ObjectTest, cls).resource_cleanup()
 
     def _create_object(self, metadata=None):
         # setup object
@@ -60,7 +60,6 @@
         for i in six.moves.xrange(segments):
             resp, _ = self.object_client.create_object_segments(
                 self.container_name, object_name, i, data_segments[i])
-            self.assertEqual(resp['status'], '201')
 
         return object_name, data_segments
 
@@ -97,7 +96,6 @@
         data = data_utils.arbitrary_string()
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
 
         # check uploaded content
@@ -117,7 +115,6 @@
             object_name,
             data,
             metadata=metadata)
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
 
         resp, body = self.object_client.get_object(
@@ -144,7 +141,6 @@
             object_name,
             data,
             metadata=metadata)
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
 
         # download compressed object
@@ -168,7 +164,6 @@
             object_name,
             data,
             metadata=metadata)
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
 
         # check uploaded content
@@ -212,7 +207,6 @@
             name=object_name,
             contents=StringIO.StringIO(data),
             chunk_size=512)
-        self.assertEqual(status, 201)
         self.assertHeaders(resp_headers, 'Object', 'PUT')
 
         # check uploaded content
@@ -239,7 +233,6 @@
             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,
@@ -258,7 +251,6 @@
             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,
@@ -278,7 +270,6 @@
             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,
@@ -303,7 +294,6 @@
             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,
@@ -327,7 +317,6 @@
             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,
@@ -345,7 +334,6 @@
         # delete object
         resp, _ = self.object_client.delete_object(self.container_name,
                                                    object_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'DELETE')
 
     @test.attr(type='smoke')
@@ -359,7 +347,6 @@
             object_name,
             metadata,
             metadata_prefix='')
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'POST')
 
         resp, _ = self.object_client.list_object_metadata(
@@ -384,7 +371,6 @@
             object_name,
             update_metadata,
             metadata_prefix='')
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'POST')
 
         resp, _ = self.object_client.list_object_metadata(
@@ -410,7 +396,6 @@
             object_name,
             update_metadata,
             metadata_prefix='')
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'POST')
 
         resp, _ = self.object_client.list_object_metadata(
@@ -439,7 +424,6 @@
             object_name,
             update_metadata,
             metadata_prefix='')
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'POST')
 
         resp, _ = self.object_client.list_object_metadata(
@@ -458,7 +442,6 @@
             object_name,
             update_metadata,
             metadata_prefix='')
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'POST')
 
         resp, _ = self.object_client.list_object_metadata(
@@ -484,7 +467,6 @@
             object_name,
             update_metadata,
             metadata_prefix='')
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'POST')
 
         resp, _ = self.object_client.list_object_metadata(
@@ -506,7 +488,6 @@
         resp, _ = self.object_client.list_object_metadata(
             self.container_name,
             object_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'HEAD')
         self.assertIn('x-object-meta-test-meta', resp)
         self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
@@ -519,7 +500,6 @@
         resp, _ = self.object_client.list_object_metadata(
             self.container_name,
             object_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'HEAD')
         self.assertNotIn('x-object-meta-', str(resp))
 
@@ -542,7 +522,6 @@
         resp, _ = self.object_client.list_object_metadata(
             self.container_name,
             object_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
 
         # Check only the existence of common headers with custom matcher
         self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders(
@@ -573,7 +552,6 @@
         # get object
         resp, body = self.object_client.get_object(self.container_name,
                                                    object_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'GET')
 
         self.assertEqual(body, data)
@@ -592,7 +570,6 @@
             self.container_name,
             object_name,
             metadata=None)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertIn('x-object-meta-test-meta', resp)
         self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
@@ -613,7 +590,6 @@
             self.container_name,
             object_name,
             metadata=metadata)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, data[rand_num - 3: rand_num])
 
@@ -637,7 +613,6 @@
             self.container_name,
             object_name,
             metadata=None)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
 
         # Check only the existence of common headers with custom matcher
         self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders(
@@ -678,7 +653,6 @@
             self.container_name,
             object_name,
             metadata=list_metadata)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, data)
 
@@ -699,7 +673,6 @@
             self.container_name,
             object_name,
             metadata=list_metadata)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, data)
 
@@ -721,7 +694,6 @@
             self.container_name,
             object_name,
             metadata=list_metadata)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, data)
 
@@ -737,7 +709,6 @@
             self.container_name,
             object_name,
             metadata=list_metadata)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, data)
 
@@ -751,7 +722,6 @@
             self.container_name,
             object_name,
             metadata=list_metadata)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, data)
 
@@ -774,7 +744,6 @@
         # copy source object to destination
         resp, _ = self.object_client.copy_object_in_same_container(
             self.container_name, src_object_name, dst_object_name)
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
 
         # check data
@@ -796,7 +765,6 @@
         self.assertNotEqual(resp_tmp['content-type'], metadata['content-type'])
         resp, _ = self.object_client.copy_object_in_same_container(
             self.container_name, object_name, object_name, metadata)
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
 
         # check the content type
@@ -822,7 +790,6 @@
         resp, _ = self.object_client.copy_object_2d_way(self.container_name,
                                                         src_object_name,
                                                         dst_object_name)
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'COPY')
         self.assertEqual(
             resp['x-copied-from'],
@@ -855,14 +822,12 @@
         resp, _ = self.object_client.update_object_metadata(src_container_name,
                                                             object_name,
                                                             orig_metadata)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'POST')
 
         # copy object from source container to destination container
         resp, _ = self.object_client.copy_object_across_containers(
             src_container_name, object_name, dst_container_name,
             object_name)
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
 
         # check if object is present in destination container
@@ -884,7 +849,6 @@
         dst_object_name, resp = self._copy_object_2d(src_object_name,
                                                      metadata)
 
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'COPY')
 
         self.assertNotIn('x-object-meta-src', resp)
@@ -904,7 +868,6 @@
         metadata = {'x-object-meta-test': ''}
         dst_obj_name, resp = self._copy_object_2d(src_obj_name, metadata)
 
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'COPY')
 
         expected = {'x-object-meta-test': '',
@@ -927,7 +890,6 @@
         metadata = {'x-object-meta-test': 'value'}
         dst_obj_name, resp = self._copy_object_2d(src_obj_name, metadata)
 
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'COPY')
 
         expected = {'x-object-meta-test': 'value',
@@ -951,7 +913,6 @@
         for i in six.moves.xrange(segments):
             resp, _ = self.object_client.create_object_segments(
                 self.container_name, object_name, i, data_segments[i])
-            self.assertEqual(resp['status'], '201')
         # creating a manifest file
         metadata = {'X-Object-Manifest': '%s/%s/'
                     % (self.container_name, object_name)}
@@ -1012,7 +973,6 @@
         md5 = hashlib.md5(local_data).hexdigest()
         headers = {'If-None-Match': md5}
         resp, body = self.object_client.get(url, headers=headers)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'GET')
 
 
@@ -1035,7 +995,6 @@
         cont_headers = {'X-Container-Read': '.r:*,.rlistings'}
         resp_meta, body = self.container_client.update_container_metadata(
             self.container_name, metadata=cont_headers, metadata_prefix='')
-        self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp_meta, 'Container', 'POST')
 
         # create object
@@ -1044,13 +1003,11 @@
                                            base_text=object_name)
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
 
         # list container metadata
         resp_meta, _ = self.container_client.list_container_metadata(
             self.container_name)
-        self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp_meta, 'Container', 'HEAD')
 
         self.assertIn('x-container-read', resp_meta)
@@ -1075,7 +1032,6 @@
         resp_meta, body = self.container_client.update_container_metadata(
             self.container_name, metadata=cont_headers,
             metadata_prefix='')
-        self.assertIn(int(resp_meta['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp_meta, 'Container', 'POST')
 
         # create object
@@ -1084,13 +1040,11 @@
                                            base_text=object_name)
         resp, _ = self.object_client.create_object(self.container_name,
                                                    object_name, data)
-        self.assertEqual(resp['status'], '201')
         self.assertHeaders(resp, 'Object', 'PUT')
 
         # list container metadata
         resp, _ = self.container_client.list_container_metadata(
             self.container_name)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Container', 'HEAD')
 
         self.assertIn('x-container-read', resp)
diff --git a/tempest/api/object_storage/test_object_slo.py b/tempest/api/object_storage/test_object_slo.py
index 0443a80..6622349 100644
--- a/tempest/api/object_storage/test_object_slo.py
+++ b/tempest/api/object_storage/test_object_slo.py
@@ -59,23 +59,23 @@
         object_name_base_1 = object_name + '_01'
         object_name_base_2 = object_name + '_02'
         data_size = MIN_SEGMENT_SIZE
-        self.data = data_utils.arbitrary_string(data_size)
+        self.content = data_utils.arbitrary_string(data_size)
         self._create_object(self.container_name,
                             object_name_base_1,
-                            self.data)
+                            self.content)
         self._create_object(self.container_name,
                             object_name_base_2,
-                            self.data)
+                            self.content)
 
         path_object_1 = '/%s/%s' % (self.container_name,
                                     object_name_base_1)
         path_object_2 = '/%s/%s' % (self.container_name,
                                     object_name_base_2)
         data_manifest = [{'path': path_object_1,
-                          'etag': hashlib.md5(self.data).hexdigest(),
+                          'etag': hashlib.md5(self.content).hexdigest(),
                           'size_bytes': data_size},
                          {'path': path_object_2,
-                          'etag': hashlib.md5(self.data).hexdigest(),
+                          'etag': hashlib.md5(self.content).hexdigest(),
                           'size_bytes': data_size}]
 
         return json.dumps(data_manifest)
@@ -120,7 +120,6 @@
                                    manifest,
                                    params)
 
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self._assertHeadersSLO(resp, 'PUT')
 
     @test.attr(type='gate')
@@ -132,7 +131,6 @@
             self.container_name,
             object_name)
 
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self._assertHeadersSLO(resp, 'HEAD')
 
     @test.attr(type='gate')
@@ -144,10 +142,9 @@
             self.container_name,
             object_name)
 
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self._assertHeadersSLO(resp, 'GET')
 
-        sum_data = self.data + self.data
+        sum_data = self.content + self.content
         self.assertEqual(body, sum_data)
 
     @test.attr(type='gate')
@@ -161,8 +158,6 @@
             object_name,
             params=params_del)
 
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
-
         # When deleting SLO using multipart manifest, the response contains
         # not 'content-length' but 'transfer-encoding' header. This is the
         # special case, therefore the existence of response headers is checked
diff --git a/tempest/api/object_storage/test_object_temp_url.py b/tempest/api/object_storage/test_object_temp_url.py
index 264a18a..dd4fd17 100644
--- a/tempest/api/object_storage/test_object_temp_url.py
+++ b/tempest/api/object_storage/test_object_temp_url.py
@@ -30,8 +30,8 @@
 class ObjectTempUrlTest(base.BaseObjectTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(ObjectTempUrlTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(ObjectTempUrlTest, cls).resource_setup()
         # create a container
         cls.container_name = data_utils.rand_name(name='TestContainer')
         cls.container_client.create_container(cls.container_name)
@@ -52,16 +52,14 @@
                                         cls.object_name, cls.content)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         for metadata in cls.metadatas:
             cls.account_client.delete_account_metadata(
                 metadata=metadata)
 
         cls.delete_containers(cls.containers)
 
-        # delete the user setup created
-        cls.data.teardown_all()
-        super(ObjectTempUrlTest, cls).tearDownClass()
+        super(ObjectTempUrlTest, cls).resource_cleanup()
 
     def setUp(self):
         super(ObjectTempUrlTest, self).setUp()
@@ -107,13 +105,11 @@
 
         # trying to get object using temp url within expiry time
         resp, body = self.object_client.get(url)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, self.content)
 
         # Testing a HEAD on this Temp URL
         resp, body = self.object_client.head(url)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'HEAD')
 
     @test.attr(type='gate')
@@ -138,7 +134,6 @@
                                  self.object_name, "GET",
                                  expires, key2)
         resp, body = self.object_client.get(url)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertEqual(body, self.content)
 
     @test.attr(type='gate')
@@ -155,12 +150,10 @@
 
         # trying to put random data in the object using temp url
         resp, body = self.object_client.put(url, new_data, None)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'PUT')
 
         # Testing a HEAD on this Temp URL
         resp, body = self.object_client.head(url)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'HEAD')
 
         # Validate that the content of the object has been modified
@@ -183,7 +176,6 @@
 
         # Testing a HEAD on this Temp URL
         resp, body = self.object_client.head(url)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'HEAD')
 
     @test.attr(type='gate')
@@ -198,7 +190,6 @@
 
         # trying to get object using temp url within expiry time
         resp, body = self.object_client.get(url)
-        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'GET')
         self.assertEqual(body, self.content)
         self.assertEqual(resp['content-disposition'], 'inline')
diff --git a/tempest/api/object_storage/test_object_temp_url_negative.py b/tempest/api/object_storage/test_object_temp_url_negative.py
index 7d26433..b752348 100644
--- a/tempest/api/object_storage/test_object_temp_url_negative.py
+++ b/tempest/api/object_storage/test_object_temp_url_negative.py
@@ -31,9 +31,8 @@
     containers = []
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(ObjectTempUrlNegativeTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(ObjectTempUrlNegativeTest, cls).resource_setup()
 
         cls.container_name = data_utils.rand_name(name='TestContainer')
         cls.container_client.create_container(cls.container_name)
@@ -47,15 +46,13 @@
             cls.account_client.list_account_metadata()
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         resp, _ = cls.account_client.delete_account_metadata(
             metadata=cls.metadata)
 
         cls.delete_containers(cls.containers)
 
-        # delete the user setup created
-        cls.data.teardown_all()
-        super(ObjectTempUrlNegativeTest, cls).tearDownClass()
+        super(ObjectTempUrlNegativeTest, cls).resource_cleanup()
 
     def setUp(self):
         super(ObjectTempUrlNegativeTest, self).setUp()
@@ -69,10 +66,10 @@
 
         # create object
         self.object_name = data_utils.rand_name(name='ObjectTemp')
-        self.data = data_utils.arbitrary_string(size=len(self.object_name),
-                                                base_text=self.object_name)
+        self.content = data_utils.arbitrary_string(size=len(self.object_name),
+                                                   base_text=self.object_name)
         self.object_client.create_object(self.container_name,
-                                         self.object_name, self.data)
+                                         self.object_name, self.content)
 
     def _get_expiry_date(self, expiration_time=1000):
         return int(time.time() + expiration_time)
diff --git a/tempest/api/object_storage/test_object_version.py b/tempest/api/object_storage/test_object_version.py
index 8d2ff9b..da40e5a 100644
--- a/tempest/api/object_storage/test_object_version.py
+++ b/tempest/api/object_storage/test_object_version.py
@@ -13,25 +13,29 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import testtools
+
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
+from tempest import config
 from tempest import test
 
+CONF = config.CONF
+
 
 class ContainerTest(base.BaseObjectTest):
     @classmethod
-    def setUpClass(cls):
-        super(ContainerTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(ContainerTest, cls).resource_setup()
         cls.containers = []
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.delete_containers(cls.containers)
-        super(ContainerTest, cls).tearDownClass()
+        super(ContainerTest, cls).resource_cleanup()
 
     def assertContainer(self, container, count, byte, versioned):
         resp, _ = self.container_client.list_container_metadata(container)
-        self.assertEqual(resp['status'], ('204'))
         self.assertHeaders(resp, 'Container', 'HEAD')
         header_value = resp.get('x-container-object-count', 'Missing Header')
         self.assertEqual(header_value, count)
@@ -41,13 +45,15 @@
         self.assertEqual(header_value, versioned)
 
     @test.attr(type='smoke')
+    @testtools.skipIf(
+        not CONF.object_storage_feature_enabled.object_versioning,
+        'Object-versioning is disabled')
     def test_versioned_container(self):
         # create container
         vers_container_name = data_utils.rand_name(name='TestVersionContainer')
         resp, body = self.container_client.create_container(
             vers_container_name)
         self.containers.append(vers_container_name)
-        self.assertIn(resp['status'], ('202', '201'))
         self.assertHeaders(resp, 'Container', 'PUT')
         self.assertContainer(vers_container_name, '0', '0', 'Missing Header')
 
@@ -58,7 +64,6 @@
             metadata=headers,
             metadata_prefix='')
         self.containers.append(base_container_name)
-        self.assertIn(resp['status'], ('202', '201'))
         self.assertHeaders(resp, 'Container', 'PUT')
         self.assertContainer(base_container_name, '0', '0',
                              vers_container_name)
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
index 0b22de5..5a586fc 100644
--- a/tempest/api/orchestration/base.py
+++ b/tempest/api/orchestration/base.py
@@ -30,8 +30,8 @@
     """Base test case class for all Orchestration API tests."""
 
     @classmethod
-    def setUpClass(cls):
-        super(BaseOrchestrationTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(BaseOrchestrationTest, cls).resource_setup()
         cls.os = clients.Manager()
         if not CONF.service_available.heat:
             raise cls.skipException("Heat support is required")
@@ -146,11 +146,11 @@
             return yaml.safe_load(f)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls._clear_stacks()
         cls._clear_keypairs()
         cls._clear_images()
-        super(BaseOrchestrationTest, cls).tearDownClass()
+        super(BaseOrchestrationTest, cls).resource_cleanup()
 
     @staticmethod
     def stack_output(stack, output_key):
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index ffadb16..f1a4f85 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -30,9 +30,8 @@
 class NeutronResourcesTestJSON(base.BaseOrchestrationTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(NeutronResourcesTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(NeutronResourcesTestJSON, cls).resource_setup()
         if not CONF.orchestration.image_ref:
             raise cls.skipException("No image available to test")
         os = clients.Manager()
diff --git a/tempest/api/orchestration/stacks/test_non_empty_stack.py b/tempest/api/orchestration/stacks/test_non_empty_stack.py
index 72ad5f5..759cbbe 100644
--- a/tempest/api/orchestration/stacks/test_non_empty_stack.py
+++ b/tempest/api/orchestration/stacks/test_non_empty_stack.py
@@ -25,8 +25,8 @@
 class StacksTestJSON(base.BaseOrchestrationTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(StacksTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(StacksTestJSON, cls).resource_setup()
         cls.stack_name = data_utils.rand_name('heat')
         template = cls.read_template('non_empty_stack')
         image_id = (CONF.orchestration.image_ref or
diff --git a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
index 2f58611..1da340c 100644
--- a/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
+++ b/tempest/api/orchestration/stacks/test_nova_keypair_resources.py
@@ -27,8 +27,8 @@
     _type = 'type'
 
     @classmethod
-    def setUpClass(cls):
-        super(NovaKeyPairResourcesYAMLTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(NovaKeyPairResourcesYAMLTest, cls).resource_setup()
         cls.stack_name = data_utils.rand_name('heat')
         template = cls.read_template('nova_keypair', ext=cls._tpl_type)
 
diff --git a/tempest/api/orchestration/stacks/test_stacks.py b/tempest/api/orchestration/stacks/test_stacks.py
index 8023f2c..d7fbd65 100644
--- a/tempest/api/orchestration/stacks/test_stacks.py
+++ b/tempest/api/orchestration/stacks/test_stacks.py
@@ -23,8 +23,8 @@
     empty_template = "HeatTemplateFormatVersion: '2012-12-12'\n"
 
     @classmethod
-    def setUpClass(cls):
-        super(StacksTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(StacksTestJSON, cls).resource_setup()
 
     @test.attr(type='smoke')
     def test_stack_list_responds(self):
diff --git a/tempest/api/orchestration/stacks/test_swift_resources.py b/tempest/api/orchestration/stacks/test_swift_resources.py
index cbe62a1..307468e 100644
--- a/tempest/api/orchestration/stacks/test_swift_resources.py
+++ b/tempest/api/orchestration/stacks/test_swift_resources.py
@@ -26,9 +26,8 @@
 
 class SwiftResourcesTestJSON(base.BaseOrchestrationTest):
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(SwiftResourcesTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(SwiftResourcesTestJSON, cls).resource_setup()
         cls.stack_name = data_utils.rand_name('heat')
         template = cls.read_template('swift_basic')
         os = clients.Manager()
@@ -66,9 +65,9 @@
         params = {'format': 'json'}
         _, container_list = \
             self.account_client.list_account_containers(params=params)
-        self.assertEqual(2, len(container_list))
-        for cont in container_list:
-            self.assertTrue(cont['name'].startswith(self.stack_name))
+        created_containers = [cont for cont in container_list
+                              if cont['name'].startswith(self.stack_name)]
+        self.assertEqual(2, len(created_containers))
 
     @test.services('object_storage')
     def test_acl(self):
diff --git a/tempest/api/orchestration/stacks/test_templates.py b/tempest/api/orchestration/stacks/test_templates.py
index 0d6060d..262c576 100644
--- a/tempest/api/orchestration/stacks/test_templates.py
+++ b/tempest/api/orchestration/stacks/test_templates.py
@@ -26,9 +26,8 @@
 """
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(TemplateYAMLTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(TemplateYAMLTestJSON, cls).resource_setup()
         cls.stack_name = data_utils.rand_name('heat')
         cls.stack_identifier = cls.create_stack(cls.stack_name, cls.template)
         cls.client.wait_for_stack_status(cls.stack_identifier,
diff --git a/tempest/api/orchestration/stacks/test_templates_negative.py b/tempest/api/orchestration/stacks/test_templates_negative.py
index b325104..9082107 100644
--- a/tempest/api/orchestration/stacks/test_templates_negative.py
+++ b/tempest/api/orchestration/stacks/test_templates_negative.py
@@ -30,8 +30,8 @@
     invalid_template_url = 'http://www.example.com/template.yaml'
 
     @classmethod
-    def setUpClass(cls):
-        super(TemplateYAMLNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(TemplateYAMLNegativeTestJSON, cls).resource_setup()
         cls.parameters = {}
 
     @test.attr(type=['gate', 'negative'])
diff --git a/tempest/api/orchestration/stacks/test_update.py b/tempest/api/orchestration/stacks/test_update.py
deleted file mode 100644
index 791a19b..0000000
--- a/tempest/api/orchestration/stacks/test_update.py
+++ /dev/null
@@ -1,83 +0,0 @@
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-import logging
-
-from tempest.api.orchestration import base
-from tempest.common.utils import data_utils
-from tempest import test
-
-
-LOG = logging.getLogger(__name__)
-
-
-class UpdateStackTestJSON(base.BaseOrchestrationTest):
-    _interface = 'json'
-
-    template = '''
-heat_template_version: 2013-05-23
-resources:
-  random1:
-    type: OS::Heat::RandomString
-'''
-    update_template = '''
-heat_template_version: 2013-05-23
-resources:
-  random1:
-    type: OS::Heat::RandomString
-  random2:
-    type: OS::Heat::RandomString
-'''
-
-    def update_stack(self, stack_identifier, template):
-        stack_name = stack_identifier.split('/')[0]
-        self.client.update_stack(
-            stack_identifier=stack_identifier,
-            name=stack_name,
-            template=template)
-        self.client.wait_for_stack_status(stack_identifier, 'UPDATE_COMPLETE')
-
-    @test.attr(type='gate')
-    def test_stack_update_nochange(self):
-        stack_name = data_utils.rand_name('heat')
-        stack_identifier = self.create_stack(stack_name, self.template)
-        self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
-        expected_resources = {'random1': 'OS::Heat::RandomString'}
-        self.assertEqual(expected_resources,
-                         self.list_resources(stack_identifier))
-
-        # Update with no changes, resources should be unchanged
-        self.update_stack(stack_identifier, self.template)
-        self.assertEqual(expected_resources,
-                         self.list_resources(stack_identifier))
-
-    @test.attr(type='gate')
-    @test.skip_because(bug='1308682')
-    def test_stack_update_add_remove(self):
-        stack_name = data_utils.rand_name('heat')
-        stack_identifier = self.create_stack(stack_name, self.template)
-        self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
-        initial_resources = {'random1': 'OS::Heat::RandomString'}
-        self.assertEqual(initial_resources,
-                         self.list_resources(stack_identifier))
-
-        # Add one resource via a stack update
-        self.update_stack(stack_identifier, self.update_template)
-        updated_resources = {'random1': 'OS::Heat::RandomString',
-                             'random2': 'OS::Heat::RandomString'}
-        self.assertEqual(updated_resources,
-                         self.list_resources(stack_identifier))
-
-        # Then remove it by updating with the original template
-        self.update_stack(stack_identifier, self.template)
-        self.assertEqual(initial_resources,
-                         self.list_resources(stack_identifier))
diff --git a/tempest/api/orchestration/stacks/test_volumes.py b/tempest/api/orchestration/stacks/test_volumes.py
index f371370..f47078c 100644
--- a/tempest/api/orchestration/stacks/test_volumes.py
+++ b/tempest/api/orchestration/stacks/test_volumes.py
@@ -26,8 +26,8 @@
 class CinderResourcesTest(base.BaseOrchestrationTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(CinderResourcesTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(CinderResourcesTest, cls).resource_setup()
         if not CONF.service_available.cinder:
             raise cls.skipException('Cinder support is required')
 
diff --git a/tempest/api/telemetry/base.py b/tempest/api/telemetry/base.py
index 8c2f37b..769c201 100644
--- a/tempest/api/telemetry/base.py
+++ b/tempest/api/telemetry/base.py
@@ -26,11 +26,11 @@
     """Base test case class for all Telemetry API tests."""
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.service_available.ceilometer:
             raise cls.skipException("Ceilometer support is required")
         cls.set_network_resources()
-        super(BaseTelemetryTest, cls).setUpClass()
+        super(BaseTelemetryTest, cls).resource_setup()
         os = cls.get_client_manager()
         cls.telemetry_client = os.telemetry_client
         cls.servers_client = os.servers_client
@@ -84,12 +84,12 @@
                 pass
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.cleanup_resources(cls.telemetry_client.delete_alarm, cls.alarm_ids)
         cls.cleanup_resources(cls.servers_client.delete_server, cls.server_ids)
         cls.cleanup_resources(cls.image_client.delete_image, cls.image_ids)
         cls.clear_isolated_creds()
-        super(BaseTelemetryTest, cls).tearDownClass()
+        super(BaseTelemetryTest, cls).resource_cleanup()
 
     def await_samples(self, metric, query):
         """
diff --git a/tempest/api/telemetry/test_telemetry_alarming_api.py b/tempest/api/telemetry/test_telemetry_alarming_api.py
index 95758e8..b45d545 100644
--- a/tempest/api/telemetry/test_telemetry_alarming_api.py
+++ b/tempest/api/telemetry/test_telemetry_alarming_api.py
@@ -20,8 +20,8 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(TelemetryAlarmingAPITestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(TelemetryAlarmingAPITestJSON, cls).resource_setup()
         cls.rule = {'meter_name': 'cpu_util',
                     'comparison_operator': 'gt',
                     'threshold': 80.0,
diff --git a/tempest/api/telemetry/test_telemetry_notification_api.py b/tempest/api/telemetry/test_telemetry_notification_api.py
index 9b15c51..42e2a2d 100644
--- a/tempest/api/telemetry/test_telemetry_notification_api.py
+++ b/tempest/api/telemetry/test_telemetry_notification_api.py
@@ -23,16 +23,15 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if CONF.telemetry.too_slow_to_test:
             raise cls.skipException("Ceilometer feature for fast work mysql "
                                     "is disabled")
-        super(TelemetryNotificationAPITestJSON, cls).setUpClass()
+        super(TelemetryNotificationAPITestJSON, cls).resource_setup()
 
     @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_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index f3b1ad5..9e24993 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -21,20 +21,19 @@
 LOG = logging.getLogger(__name__)
 
 
-class VolumeMultiBackendTest(base.BaseVolumeV1AdminTest):
+class VolumeMultiBackendV2Test(base.BaseVolumeAdminTest):
     _interface = "json"
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(VolumeMultiBackendTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumeMultiBackendV2Test, cls).resource_setup()
         if not CONF.volume_feature_enabled.multi_backend:
             raise cls.skipException("Cinder multi-backend feature disabled")
 
         cls.backend1_name = CONF.volume.backend1_name
         cls.backend2_name = CONF.volume.backend2_name
 
-        cls.volume_client = cls.os_adm.volumes_client
+        cls.name_field = cls.special_fields['name_field']
         cls.volume_type_id_list = []
         cls.volume_id_list_with_prefix = []
         cls.volume_id_list_without_prefix = []
@@ -61,39 +60,41 @@
             extra_specs = {spec_key_with_prefix: backend_name_key}
         else:
             extra_specs = {spec_key_without_prefix: backend_name_key}
-        _, self.type = self.client.create_volume_type(
+        _, self.type = self.volume_types_client.create_volume_type(
             type_name, extra_specs=extra_specs)
         self.volume_type_id_list.append(self.type['id'])
 
-        _, self.volume = self.volume_client.create_volume(
-            size=1, display_name=vol_name, volume_type=type_name)
-        self.volume_client.wait_for_volume_status(
-            self.volume['id'], 'available')
+        params = {self.name_field: vol_name, 'volume_type': type_name}
+
+        _, self.volume = self.admin_volume_client.create_volume(size=1,
+                                                                **params)
         if with_prefix:
             self.volume_id_list_with_prefix.append(self.volume['id'])
         else:
             self.volume_id_list_without_prefix.append(
                 self.volume['id'])
+        self.admin_volume_client.wait_for_volume_status(
+            self.volume['id'], 'available')
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         # volumes deletion
         vid_prefix = getattr(cls, 'volume_id_list_with_prefix', [])
         for volume_id in vid_prefix:
-            cls.volume_client.delete_volume(volume_id)
-            cls.volume_client.wait_for_resource_deletion(volume_id)
+            cls.admin_volume_client.delete_volume(volume_id)
+            cls.admin_volume_client.wait_for_resource_deletion(volume_id)
 
         vid_no_pre = getattr(cls, 'volume_id_list_without_prefix', [])
         for volume_id in vid_no_pre:
-            cls.volume_client.delete_volume(volume_id)
-            cls.volume_client.wait_for_resource_deletion(volume_id)
+            cls.admin_volume_client.delete_volume(volume_id)
+            cls.admin_volume_client.wait_for_resource_deletion(volume_id)
 
         # volume types deletion
         volume_type_id_list = getattr(cls, 'volume_type_id_list', [])
         for volume_type_id in volume_type_id_list:
-            cls.client.delete_volume_type(volume_type_id)
+            cls.volume_types_client.delete_volume_type(volume_type_id)
 
-        super(VolumeMultiBackendTest, cls).tearDownClass()
+        super(VolumeMultiBackendV2Test, cls).resource_cleanup()
 
     @test.attr(type='smoke')
     def test_backend_name_reporting(self):
@@ -130,7 +131,7 @@
         # the multi backend feature has been enabled
         # if multi-backend is enabled: os-vol-attr:host should be like:
         # host@backend_name
-        _, volume = self.volume_client.get_volume(volume_id)
+        _, volume = self.admin_volume_client.get_volume(volume_id)
 
         volume1_host = volume['os-vol-host-attr:host']
         msg = ("multi-backend reporting incorrect values for volume %s" %
@@ -141,12 +142,16 @@
         # this test checks that the two volumes created at setUp don't
         # belong to the same backend (if they are, than the
         # volume backend distinction is not working properly)
-        _, volume = self.volume_client.get_volume(volume1_id)
+        _, volume = self.admin_volume_client.get_volume(volume1_id)
         volume1_host = volume['os-vol-host-attr:host']
 
-        _, volume = self.volume_client.get_volume(volume2_id)
+        _, volume = self.admin_volume_client.get_volume(volume2_id)
         volume2_host = volume['os-vol-host-attr:host']
 
         msg = ("volumes %s and %s were created in the same backend" %
                (volume1_id, volume2_id))
         self.assertNotEqual(volume1_host, volume2_host, msg)
+
+
+class VolumeMultiBackendV1Test(VolumeMultiBackendV2Test):
+    _api_version = 1
diff --git a/tempest/api/volume/admin/test_snapshots_actions.py b/tempest/api/volume/admin/test_snapshots_actions.py
index abbe1e9..02a2526 100644
--- a/tempest/api/volume/admin/test_snapshots_actions.py
+++ b/tempest/api/volume/admin/test_snapshots_actions.py
@@ -18,35 +18,33 @@
 from tempest import test
 
 
-class SnapshotsActionsTest(base.BaseVolumeV1AdminTest):
+class SnapshotsActionsV2Test(base.BaseVolumeAdminTest):
     _interface = "json"
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(SnapshotsActionsTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(SnapshotsActionsV2Test, cls).resource_setup()
         cls.client = cls.snapshots_client
 
-        # Create admin volume client
-        cls.admin_snapshots_client = cls.os_adm.snapshots_client
-
         # Create a test shared volume for tests
         vol_name = data_utils.rand_name(cls.__name__ + '-Volume-')
+        cls.name_field = cls.special_fields['name_field']
+        params = {cls.name_field: vol_name}
         _, cls.volume = \
-            cls.volumes_client.create_volume(size=1, display_name=vol_name)
+            cls.volumes_client.create_volume(size=1, **params)
         cls.volumes_client.wait_for_volume_status(cls.volume['id'],
                                                   'available')
 
         # Create a test shared snapshot for tests
         snap_name = data_utils.rand_name(cls.__name__ + '-Snapshot-')
+        params = {cls.name_field: snap_name}
         _, cls.snapshot = \
-            cls.client.create_snapshot(cls.volume['id'],
-                                       display_name=snap_name)
+            cls.client.create_snapshot(cls.volume['id'], **params)
         cls.client.wait_for_snapshot_status(cls.snapshot['id'],
                                             'available')
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         # Delete the test snapshot
         cls.client.delete_snapshot(cls.snapshot['id'])
         cls.client.wait_for_resource_deletion(cls.snapshot['id'])
@@ -55,7 +53,7 @@
         cls.volumes_client.delete_volume(cls.volume['id'])
         cls.volumes_client.wait_for_resource_deletion(cls.volume['id'])
 
-        super(SnapshotsActionsTest, cls).tearDownClass()
+        super(SnapshotsActionsV2Test, cls).resource_cleanup()
 
     def tearDown(self):
         # Set snapshot's status to available after test
@@ -63,7 +61,7 @@
         snapshot_id = self.snapshot['id']
         self.admin_snapshots_client.reset_snapshot_status(snapshot_id,
                                                           status)
-        super(SnapshotsActionsTest, self).tearDown()
+        super(SnapshotsActionsV2Test, self).tearDown()
 
     def _create_reset_and_force_delete_temp_snapshot(self, status=None):
         # Create snapshot, reset snapshot status,
@@ -128,7 +126,11 @@
         self._create_reset_and_force_delete_temp_snapshot('error_deleting')
 
 
-class SnapshotsActionsTestXML(SnapshotsActionsTest):
+class SnapshotsActionsV1Test(SnapshotsActionsV2Test):
+    _api_version = 1
+
+
+class SnapshotsActionsV1TestXML(SnapshotsActionsV1Test):
     _interface = "xml"
 
     def _get_progress_alias(self):
diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py
index 017363d..c92a60c 100644
--- a/tempest/api/volume/admin/test_volume_hosts.py
+++ b/tempest/api/volume/admin/test_volume_hosts.py
@@ -17,7 +17,7 @@
 from tempest import test
 
 
-class VolumeHostsAdminTestsJSON(base.BaseVolumeV1AdminTest):
+class VolumeHostsAdminV2TestsJSON(base.BaseVolumeAdminTest):
     _interface = "json"
 
     @test.attr(type='gate')
@@ -27,5 +27,9 @@
                         "response of list hosts is: % s" % hosts)
 
 
-class VolumeHostsAdminTestsXML(VolumeHostsAdminTestsJSON):
+class VolumeHostsAdminV1TestsJSON(VolumeHostsAdminV2TestsJSON):
+    _api_version = 1
+
+
+class VolumeHostsAdminV1TestsXML(VolumeHostsAdminV1TestsJSON):
     _interface = 'xml'
diff --git a/tempest/api/volume/admin/test_volume_quotas.py b/tempest/api/volume/admin/test_volume_quotas.py
index fa3b667..6e45b0f 100644
--- a/tempest/api/volume/admin/test_volume_quotas.py
+++ b/tempest/api/volume/admin/test_volume_quotas.py
@@ -27,9 +27,8 @@
     force_tenant_isolation = True
 
     @classmethod
-    def setUpClass(cls):
-        super(VolumeQuotasAdminTestJSON, cls).setUpClass()
-        cls.admin_volume_client = cls.os_adm.volumes_client
+    def resource_setup(cls):
+        super(VolumeQuotasAdminTestJSON, cls).resource_setup()
         cls.demo_tenant_id = cls.isolated_creds.get_primary_creds().tenant_id
 
     @test.attr(type='gate')
@@ -71,7 +70,8 @@
 
     @test.attr(type='gate')
     def test_show_quota_usage(self):
-        _, quota_usage = self.quotas_client.get_quota_usage(self.adm_tenant)
+        _, quota_usage = self.quotas_client.get_quota_usage(
+            self.os_adm.credentials.tenant_id)
         for key in QUOTA_KEYS:
             self.assertIn(key, quota_usage)
             for usage_key in QUOTA_USAGE_KEYS:
diff --git a/tempest/api/volume/admin/test_volume_quotas_negative.py b/tempest/api/volume/admin/test_volume_quotas_negative.py
index 515024f..60a0adb 100644
--- a/tempest/api/volume/admin/test_volume_quotas_negative.py
+++ b/tempest/api/volume/admin/test_volume_quotas_negative.py
@@ -23,9 +23,8 @@
     force_tenant_isolation = True
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(VolumeQuotasNegativeTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumeQuotasNegativeTestJSON, cls).resource_setup()
         demo_user = cls.isolated_creds.get_primary_creds()
         cls.demo_tenant_id = demo_user.tenant_id
         cls.shared_quota_set = {'gigabytes': 3, 'volumes': 1, 'snapshots': 1}
diff --git a/tempest/api/volume/admin/test_volume_services.py b/tempest/api/volume/admin/test_volume_services.py
index 4a68e05..7820148 100644
--- a/tempest/api/volume/admin/test_volume_services.py
+++ b/tempest/api/volume/admin/test_volume_services.py
@@ -25,8 +25,8 @@
     _interface = "json"
 
     @classmethod
-    def setUpClass(cls):
-        super(VolumesServicesTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesServicesTestJSON, cls).resource_setup()
         cls.client = cls.os_adm.volume_services_client
         _, cls.services = cls.client.list_services()
         cls.host_name = cls.services[0]['host']
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 070d38f..a481224 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -21,7 +21,7 @@
 CONF = config.CONF
 
 
-class VolumeTypesTest(base.BaseVolumeV1AdminTest):
+class VolumeTypesV2Test(base.BaseVolumeAdminTest):
     _interface = "json"
 
     def _delete_volume(self, volume_id):
@@ -29,12 +29,12 @@
         self.volumes_client.wait_for_resource_deletion(volume_id)
 
     def _delete_volume_type(self, volume_type_id):
-        self.client.delete_volume_type(volume_type_id)
+        self.volume_types_client.delete_volume_type(volume_type_id)
 
     @test.attr(type='smoke')
     def test_volume_type_list(self):
         # List Volume types.
-        _, body = self.client.list_volume_types()
+        _, body = self.volume_types_client.list_volume_types()
         self.assertIsInstance(body, list)
 
     @test.attr(type='smoke')
@@ -43,32 +43,32 @@
         volume = {}
         vol_name = data_utils.rand_name("volume-")
         vol_type_name = data_utils.rand_name("volume-type-")
+        self.name_field = self.special_fields['name_field']
         proto = CONF.volume.storage_protocol
         vendor = CONF.volume.vendor_name
         extra_specs = {"storage_protocol": proto,
                        "vendor_name": vendor}
         body = {}
-        _, body = self.client.create_volume_type(
+        _, body = self.volume_types_client.create_volume_type(
             vol_type_name,
             extra_specs=extra_specs)
         self.assertIn('id', body)
         self.addCleanup(self._delete_volume_type, body['id'])
         self.assertIn('name', body)
+        params = {self.name_field: vol_name, 'volume_type': vol_type_name}
         _, volume = self.volumes_client.create_volume(
-            size=1, display_name=vol_name,
-            volume_type=vol_type_name)
+            size=1, **params)
         self.assertIn('id', volume)
         self.addCleanup(self._delete_volume, volume['id'])
-        self.assertIn('display_name', volume)
-        self.assertEqual(volume['display_name'], vol_name,
+        self.assertIn(self.name_field, volume)
+        self.assertEqual(volume[self.name_field], vol_name,
                          "The created volume name is not equal "
                          "to the requested name")
         self.assertTrue(volume['id'] is not None,
                         "Field volume id is empty or not found.")
-        self.volumes_client.wait_for_volume_status(volume['id'],
-                                                   'available')
+        self.volumes_client.wait_for_volume_status(volume['id'], 'available')
         _, fetched_volume = self.volumes_client.get_volume(volume['id'])
-        self.assertEqual(vol_name, fetched_volume['display_name'],
+        self.assertEqual(vol_name, fetched_volume[self.name_field],
                          'The fetched Volume is different '
                          'from the created Volume')
         self.assertEqual(volume['id'], fetched_volume['id'],
@@ -87,7 +87,7 @@
         vendor = CONF.volume.vendor_name
         extra_specs = {"storage_protocol": proto,
                        "vendor_name": vendor}
-        _, body = self.client.create_volume_type(
+        _, body = self.volume_types_client.create_volume_type(
             name,
             extra_specs=extra_specs)
         self.assertIn('id', body)
@@ -98,7 +98,8 @@
                          "to the requested name")
         self.assertTrue(body['id'] is not None,
                         "Field volume_type id is empty or not found.")
-        _, fetched_volume_type = self.client.get_volume_type(body['id'])
+        _, fetched_volume_type = self.volume_types_client.get_volume_type(
+            body['id'])
         self.assertEqual(name, fetched_volume_type['name'],
                          'The fetched Volume_type is different '
                          'from the created Volume_type')
@@ -115,11 +116,11 @@
         provider = "LuksEncryptor"
         control_location = "front-end"
         name = data_utils.rand_name("volume-type-")
-        _, body = self.client.create_volume_type(name)
+        _, body = self.volume_types_client.create_volume_type(name)
         self.addCleanup(self._delete_volume_type, body['id'])
 
         # Create encryption type
-        _, encryption_type = self.client.create_encryption_type(
+        _, encryption_type = self.volume_types_client.create_encryption_type(
             body['id'], provider=provider,
             control_location=control_location)
         self.assertIn('volume_type_id', encryption_type)
@@ -131,8 +132,9 @@
                          "equal to the requested control_location")
 
         # Get encryption type
-        _, fetched_encryption_type = self.client.get_encryption_type(
-            encryption_type['volume_type_id'])
+        _, fetched_encryption_type = (
+            self.volume_types_client.get_encryption_type(
+                encryption_type['volume_type_id']))
         self.assertEqual(provider,
                          fetched_encryption_type['provider'],
                          'The fetched encryption_type provider is different '
@@ -143,11 +145,16 @@
                          'different from the created encryption_type')
 
         # Delete encryption type
-        self.client.delete_encryption_type(
+        self.volume_types_client.delete_encryption_type(
             encryption_type['volume_type_id'])
         resource = {"id": encryption_type['volume_type_id'],
                     "type": "encryption-type"}
-        self.client.wait_for_resource_deletion(resource)
-        _, deleted_encryption_type = self.client.get_encryption_type(
-            encryption_type['volume_type_id'])
+        self.volume_types_client.wait_for_resource_deletion(resource)
+        _, deleted_encryption_type = (
+            self.volume_types_client.get_encryption_type(
+                encryption_type['volume_type_id']))
         self.assertEmpty(deleted_encryption_type)
+
+
+class VolumeTypesV1Test(VolumeTypesV2Test):
+    _api_version = 1
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs.py b/tempest/api/volume/admin/test_volume_types_extra_specs.py
index c682866..3b9f6bb 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs.py
@@ -18,29 +18,30 @@
 from tempest import test
 
 
-class VolumeTypesExtraSpecsTest(base.BaseVolumeV1AdminTest):
+class VolumeTypesExtraSpecsV2Test(base.BaseVolumeAdminTest):
     _interface = "json"
 
     @classmethod
-    def setUpClass(cls):
-        super(VolumeTypesExtraSpecsTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumeTypesExtraSpecsV2Test, cls).resource_setup()
         vol_type_name = data_utils.rand_name('Volume-type-')
-        _, cls.volume_type = cls.client.create_volume_type(vol_type_name)
+        _, cls.volume_type = cls.volume_types_client.create_volume_type(
+            vol_type_name)
 
     @classmethod
-    def tearDownClass(cls):
-        cls.client.delete_volume_type(cls.volume_type['id'])
-        super(VolumeTypesExtraSpecsTest, cls).tearDownClass()
+    def resource_cleanup(cls):
+        cls.volume_types_client.delete_volume_type(cls.volume_type['id'])
+        super(VolumeTypesExtraSpecsV2Test, cls).resource_cleanup()
 
     @test.attr(type='smoke')
     def test_volume_type_extra_specs_list(self):
         # List Volume types extra specs.
         extra_specs = {"spec1": "val1"}
-        _, body = self.client.create_volume_type_extra_specs(
+        _, body = self.volume_types_client.create_volume_type_extra_specs(
             self.volume_type['id'], extra_specs)
         self.assertEqual(extra_specs, body,
                          "Volume type extra spec incorrectly created")
-        _, body = self.client.list_volume_types_extra_specs(
+        _, body = self.volume_types_client.list_volume_types_extra_specs(
             self.volume_type['id'])
         self.assertIsInstance(body, dict)
         self.assertIn('spec1', body)
@@ -49,13 +50,13 @@
     def test_volume_type_extra_specs_update(self):
         # Update volume type extra specs
         extra_specs = {"spec2": "val1"}
-        _, body = self.client.create_volume_type_extra_specs(
+        _, body = self.volume_types_client.create_volume_type_extra_specs(
             self.volume_type['id'], extra_specs)
         self.assertEqual(extra_specs, body,
                          "Volume type extra spec incorrectly created")
 
         extra_spec = {"spec2": "val2"}
-        _, body = self.client.update_volume_type_extra_specs(
+        _, body = self.volume_types_client.update_volume_type_extra_specs(
             self.volume_type['id'],
             extra_spec.keys()[0],
             extra_spec)
@@ -67,18 +68,22 @@
     def test_volume_type_extra_spec_create_get_delete(self):
         # Create/Get/Delete volume type extra spec.
         extra_specs = {"spec3": "val1"}
-        _, body = self.client.create_volume_type_extra_specs(
+        _, body = self.volume_types_client.create_volume_type_extra_specs(
             self.volume_type['id'],
             extra_specs)
         self.assertEqual(extra_specs, body,
                          "Volume type extra spec incorrectly created")
 
-        self.client.get_volume_type_extra_specs(
+        self.volume_types_client.get_volume_type_extra_specs(
             self.volume_type['id'],
             extra_specs.keys()[0])
         self.assertEqual(extra_specs, body,
                          "Volume type extra spec incorrectly fetched")
 
-        self.client.delete_volume_type_extra_specs(
+        self.volume_types_client.delete_volume_type_extra_specs(
             self.volume_type['id'],
             extra_specs.keys()[0])
+
+
+class VolumeTypesExtraSpecsV1Test(VolumeTypesExtraSpecsV2Test):
+    _api_version = 1
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 ff4f113..e474aa0 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
@@ -21,113 +21,128 @@
 from tempest import test
 
 
-class ExtraSpecsNegativeTest(base.BaseVolumeV1AdminTest):
+class ExtraSpecsNegativeV2Test(base.BaseVolumeAdminTest):
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
-        super(ExtraSpecsNegativeTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(ExtraSpecsNegativeV2Test, cls).resource_setup()
         vol_type_name = data_utils.rand_name('Volume-type-')
         cls.extra_specs = {"spec1": "val1"}
-        _, cls.volume_type = cls.client.create_volume_type(
+        _, cls.volume_type = cls.volume_types_client.create_volume_type(
             vol_type_name,
             extra_specs=cls.extra_specs)
 
     @classmethod
-    def tearDownClass(cls):
-        cls.client.delete_volume_type(cls.volume_type['id'])
-        super(ExtraSpecsNegativeTest, cls).tearDownClass()
+    def resource_cleanup(cls):
+        cls.volume_types_client.delete_volume_type(cls.volume_type['id'])
+        super(ExtraSpecsNegativeV2Test, cls).resource_cleanup()
 
     @test.attr(type='gate')
     def test_update_no_body(self):
         # Should not update volume type extra specs with no body
         extra_spec = {"spec1": "val2"}
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.update_volume_type_extra_specs,
-                          self.volume_type['id'], extra_spec.keys()[0], None)
+        self.assertRaises(
+            exceptions.BadRequest,
+            self.volume_types_client.update_volume_type_extra_specs,
+            self.volume_type['id'], extra_spec.keys()[0], None)
 
     @test.attr(type='gate')
     def test_update_nonexistent_extra_spec_id(self):
         # Should not update volume type extra specs with nonexistent id.
         extra_spec = {"spec1": "val2"}
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.update_volume_type_extra_specs,
-                          self.volume_type['id'], str(uuid.uuid4()),
-                          extra_spec)
+        self.assertRaises(
+            exceptions.BadRequest,
+            self.volume_types_client.update_volume_type_extra_specs,
+            self.volume_type['id'], str(uuid.uuid4()),
+            extra_spec)
 
     @test.attr(type='gate')
     def test_update_none_extra_spec_id(self):
         # Should not update volume type extra specs with none id.
         extra_spec = {"spec1": "val2"}
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.update_volume_type_extra_specs,
-                          self.volume_type['id'], None, extra_spec)
+        self.assertRaises(
+            exceptions.BadRequest,
+            self.volume_types_client.update_volume_type_extra_specs,
+            self.volume_type['id'], None, extra_spec)
 
     @test.attr(type='gate')
     def test_update_multiple_extra_spec(self):
         # Should not update volume type extra specs with multiple specs as
             # body.
         extra_spec = {"spec1": "val2", 'spec2': 'val1'}
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.update_volume_type_extra_specs,
-                          self.volume_type['id'], extra_spec.keys()[0],
-                          extra_spec)
+        self.assertRaises(
+            exceptions.BadRequest,
+            self.volume_types_client.update_volume_type_extra_specs,
+            self.volume_type['id'], extra_spec.keys()[0],
+            extra_spec)
 
     @test.attr(type='gate')
     def test_create_nonexistent_type_id(self):
         # Should not create volume type extra spec for nonexistent volume
             # type id.
         extra_specs = {"spec2": "val1"}
-        self.assertRaises(exceptions.NotFound,
-                          self.client.create_volume_type_extra_specs,
-                          str(uuid.uuid4()), extra_specs)
+        self.assertRaises(
+            exceptions.NotFound,
+            self.volume_types_client.create_volume_type_extra_specs,
+            str(uuid.uuid4()), extra_specs)
 
     @test.attr(type='gate')
     def test_create_none_body(self):
         # Should not create volume type extra spec for none POST body.
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.create_volume_type_extra_specs,
-                          self.volume_type['id'], None)
+        self.assertRaises(
+            exceptions.BadRequest,
+            self.volume_types_client.create_volume_type_extra_specs,
+            self.volume_type['id'], None)
 
     @test.attr(type='gate')
     def test_create_invalid_body(self):
         # Should not create volume type extra spec for invalid POST body.
-        self.assertRaises(exceptions.BadRequest,
-                          self.client.create_volume_type_extra_specs,
-                          self.volume_type['id'], ['invalid'])
+        self.assertRaises(
+            exceptions.BadRequest,
+            self.volume_types_client.create_volume_type_extra_specs,
+            self.volume_type['id'], ['invalid'])
 
     @test.attr(type='gate')
     def test_delete_nonexistent_volume_type_id(self):
         # Should not delete volume type extra spec for nonexistent
             # type id.
         extra_specs = {"spec1": "val1"}
-        self.assertRaises(exceptions.NotFound,
-                          self.client.delete_volume_type_extra_specs,
-                          str(uuid.uuid4()), extra_specs.keys()[0])
+        self.assertRaises(
+            exceptions.NotFound,
+            self.volume_types_client.delete_volume_type_extra_specs,
+            str(uuid.uuid4()), extra_specs.keys()[0])
 
     @test.attr(type='gate')
     def test_list_nonexistent_volume_type_id(self):
         # Should not list volume type extra spec for nonexistent type id.
-        self.assertRaises(exceptions.NotFound,
-                          self.client.list_volume_types_extra_specs,
-                          str(uuid.uuid4()))
+        self.assertRaises(
+            exceptions.NotFound,
+            self.volume_types_client.list_volume_types_extra_specs,
+            str(uuid.uuid4()))
 
     @test.attr(type='gate')
     def test_get_nonexistent_volume_type_id(self):
         # Should not get volume type extra spec for nonexistent type id.
         extra_specs = {"spec1": "val1"}
-        self.assertRaises(exceptions.NotFound,
-                          self.client.get_volume_type_extra_specs,
-                          str(uuid.uuid4()), extra_specs.keys()[0])
+        self.assertRaises(
+            exceptions.NotFound,
+            self.volume_types_client.get_volume_type_extra_specs,
+            str(uuid.uuid4()), extra_specs.keys()[0])
 
     @test.attr(type='gate')
     def test_get_nonexistent_extra_spec_id(self):
         # Should not get volume type extra spec for nonexistent extra spec
             # id.
-        self.assertRaises(exceptions.NotFound,
-                          self.client.get_volume_type_extra_specs,
-                          self.volume_type['id'], str(uuid.uuid4()))
+        self.assertRaises(
+            exceptions.NotFound,
+            self.volume_types_client.get_volume_type_extra_specs,
+            self.volume_type['id'], str(uuid.uuid4()))
 
 
-class ExtraSpecsNegativeTestXML(ExtraSpecsNegativeTest):
+class ExtraSpecsNegativeV1Test(ExtraSpecsNegativeV2Test):
+    _api_version = 1
+
+
+class ExtraSpecsNegativeV1TestXML(ExtraSpecsNegativeV1Test):
     _interface = 'xml'
diff --git a/tempest/api/volume/admin/test_volume_types_negative.py b/tempest/api/volume/admin/test_volume_types_negative.py
index c18e15d..9c9913f 100644
--- a/tempest/api/volume/admin/test_volume_types_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_negative.py
@@ -20,35 +20,43 @@
 from tempest import test
 
 
-class VolumeTypesNegativeTest(base.BaseVolumeV1AdminTest):
+class VolumeTypesNegativeV2Test(base.BaseVolumeAdminTest):
     _interface = 'json'
 
     @test.attr(type='gate')
     def test_create_with_nonexistent_volume_type(self):
         # Should not be able to create volume with nonexistent volume_type.
+        self.name_field = self.special_fields['name_field']
+        params = {self.name_field: str(uuid.uuid4()),
+                  'volume_type': str(uuid.uuid4())}
         self.assertRaises(exceptions.NotFound,
                           self.volumes_client.create_volume, size=1,
-                          display_name=str(uuid.uuid4()),
-                          volume_type=str(uuid.uuid4()))
+                          **params)
 
     @test.attr(type='gate')
     def test_create_with_empty_name(self):
         # Should not be able to create volume type with an empty name.
         self.assertRaises(exceptions.BadRequest,
-                          self.client.create_volume_type, '')
+                          self.volume_types_client.create_volume_type, '')
 
     @test.attr(type='gate')
     def test_get_nonexistent_type_id(self):
         # Should not be able to get volume type with nonexistent type id.
-        self.assertRaises(exceptions.NotFound, self.client.get_volume_type,
+        self.assertRaises(exceptions.NotFound,
+                          self.volume_types_client.get_volume_type,
                           str(uuid.uuid4()))
 
     @test.attr(type='gate')
     def test_delete_nonexistent_type_id(self):
         # Should not be able to delete volume type with nonexistent type id.
-        self.assertRaises(exceptions.NotFound, self.client.delete_volume_type,
+        self.assertRaises(exceptions.NotFound,
+                          self.volume_types_client.delete_volume_type,
                           str(uuid.uuid4()))
 
 
-class VolumesTypesNegativeTestXML(VolumeTypesNegativeTest):
+class VolumeTypesNegativeV1Test(VolumeTypesNegativeV2Test):
+    _api_version = 1
+
+
+class VolumeTypesNegativeV1TestXML(VolumeTypesNegativeV1Test):
     _interface = 'xml'
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index d6db1df..1c3e04a 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -18,32 +18,30 @@
 from tempest import test
 
 
-class VolumesActionsTest(base.BaseVolumeV1AdminTest):
+class VolumesActionsV2Test(base.BaseVolumeAdminTest):
     _interface = "json"
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(VolumesActionsTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesActionsV2Test, cls).resource_setup()
         cls.client = cls.volumes_client
 
-        # Create admin volume client
-        cls.admin_volume_client = cls.os_adm.volumes_client
-
         # Create a test shared volume for tests
         vol_name = utils.rand_name(cls.__name__ + '-Volume-')
+        cls.name_field = cls.special_fields['name_field']
+        params = {cls.name_field: vol_name}
 
         _, cls.volume = cls.client.create_volume(size=1,
-                                                 display_name=vol_name)
+                                                 **params)
         cls.client.wait_for_volume_status(cls.volume['id'], 'available')
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         # Delete the test volume
         cls.client.delete_volume(cls.volume['id'])
         cls.client.wait_for_resource_deletion(cls.volume['id'])
 
-        super(VolumesActionsTest, cls).tearDownClass()
+        super(VolumesActionsV2Test, cls).resource_cleanup()
 
     def _reset_volume_status(self, volume_id, status):
         # Reset the volume status
@@ -54,13 +52,14 @@
     def tearDown(self):
         # Set volume's status to available after test
         self._reset_volume_status(self.volume['id'], 'available')
-        super(VolumesActionsTest, self).tearDown()
+        super(VolumesActionsV2Test, self).tearDown()
 
     def _create_temp_volume(self):
         # Create a temp volume for force delete tests
         vol_name = utils.rand_name('Volume')
+        params = {self.name_field: vol_name}
         _, temp_volume = self.client.create_volume(size=1,
-                                                   display_name=vol_name)
+                                                   **params)
         self.client.wait_for_volume_status(temp_volume['id'], 'available')
 
         return temp_volume
@@ -96,5 +95,9 @@
         self._create_reset_and_force_delete_temp_volume('error')
 
 
-class VolumesActionsTestXML(VolumesActionsTest):
+class VolumesActionsV1Test(VolumesActionsV2Test):
+    _api_version = 1
+
+
+class VolumesActionsV1TestXML(VolumesActionsV1Test):
     _interface = "xml"
diff --git a/tempest/api/volume/admin/test_volumes_backup.py b/tempest/api/volume/admin/test_volumes_backup.py
index 3699e9c..1357d31 100644
--- a/tempest/api/volume/admin/test_volumes_backup.py
+++ b/tempest/api/volume/admin/test_volumes_backup.py
@@ -23,19 +23,16 @@
 LOG = logging.getLogger(__name__)
 
 
-class VolumesBackupsTest(base.BaseVolumeV1AdminTest):
+class VolumesBackupsV2Test(base.BaseVolumeAdminTest):
     _interface = "json"
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(VolumesBackupsTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesBackupsV2Test, cls).resource_setup()
 
         if not CONF.volume_feature_enabled.backup:
             raise cls.skipException("Cinder backup feature disabled")
 
-        cls.volumes_adm_client = cls.os_adm.volumes_client
-        cls.backups_adm_client = cls.os_adm.backups_client
         cls.volume = cls.create_volume()
 
     @test.attr(type='smoke')
@@ -48,8 +45,8 @@
         self.addCleanup(self.backups_adm_client.delete_backup,
                         backup['id'])
         self.assertEqual(backup_name, backup['name'])
-        self.volumes_adm_client.wait_for_volume_status(self.volume['id'],
-                                                       'available')
+        self.admin_volume_client.wait_for_volume_status(
+            self.volume['id'], 'available')
         self.backups_adm_client.wait_for_backup_status(backup['id'],
                                                        'available')
 
@@ -66,10 +63,14 @@
         _, restore = self.backups_adm_client.restore_backup(backup['id'])
 
         # Delete backup
-        self.addCleanup(self.volumes_adm_client.delete_volume,
+        self.addCleanup(self.admin_volume_client.delete_volume,
                         restore['volume_id'])
         self.assertEqual(backup['id'], restore['backup_id'])
         self.backups_adm_client.wait_for_backup_status(backup['id'],
                                                        'available')
-        self.volumes_adm_client.wait_for_volume_status(restore['volume_id'],
-                                                       'available')
+        self.admin_volume_client.wait_for_volume_status(
+            restore['volume_id'], 'available')
+
+
+class VolumesBackupsV1Test(VolumesBackupsV2Test):
+    _api_version = 1
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index 3cd0827..5d99123 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -32,9 +32,9 @@
     _interface = 'json'
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         cls.set_network_resources()
-        super(BaseVolumeTest, cls).setUpClass()
+        super(BaseVolumeTest, cls).resource_setup()
 
         if not CONF.service_available.cinder:
             skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
@@ -69,6 +69,7 @@
             if not CONF.volume_feature_enabled.api_v2:
                 msg = "Volume API v2 is disabled"
                 raise cls.skipException(msg)
+            cls.snapshots_client = cls.os.snapshots_v2_client
             cls.volumes_client = cls.os.volumes_v2_client
             cls.volumes_extension_client = cls.os.volumes_v2_extension_client
             cls.availability_zone_client = (
@@ -82,11 +83,11 @@
             raise exceptions.InvalidConfiguration(message=msg)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         cls.clear_snapshots()
         cls.clear_volumes()
         cls.clear_isolated_creds()
-        super(BaseVolumeTest, cls).tearDownClass()
+        super(BaseVolumeTest, cls).resource_cleanup()
 
     @classmethod
     def create_volume(cls, size=1, **kwargs):
@@ -148,23 +149,76 @@
     _api_version = 1
 
 
-class BaseVolumeV1AdminTest(BaseVolumeV1Test):
+class BaseVolumeAdminTest(BaseVolumeTest):
     """Base test case class for all Volume Admin API tests."""
     @classmethod
-    def setUpClass(cls):
-        super(BaseVolumeV1AdminTest, cls).setUpClass()
-        cls.adm_user = CONF.identity.admin_username
-        cls.adm_pass = CONF.identity.admin_password
-        cls.adm_tenant = CONF.identity.admin_tenant_name
-        if not all((cls.adm_user, cls.adm_pass, cls.adm_tenant)):
-            msg = ("Missing Volume Admin API credentials "
-                   "in configuration.")
+    def resource_setup(cls):
+        super(BaseVolumeAdminTest, cls).resource_setup()
+
+        try:
+            cls.adm_creds = cls.isolated_creds.get_admin_creds()
+            cls.os_adm = clients.Manager(
+                credentials=cls.adm_creds, interface=cls._interface)
+        except NotImplementedError:
+            msg = "Missing Volume Admin API credentials in configuration."
             raise cls.skipException(msg)
-        if CONF.compute.allow_tenant_isolation:
-            cls.os_adm = clients.Manager(cls.isolated_creds.get_admin_creds(),
-                                         interface=cls._interface)
-        else:
-            cls.os_adm = clients.AdminManager(interface=cls._interface)
-        cls.client = cls.os_adm.volume_types_client
-        cls.hosts_client = cls.os_adm.volume_hosts_client
+
+        cls.qos_specs = []
+
         cls.quotas_client = cls.os_adm.volume_quotas_client
+
+        if cls._api_version == 1:
+            if not CONF.volume_feature_enabled.api_v1:
+                msg = "Volume API v1 is disabled"
+                raise cls.skipException(msg)
+            cls.volume_qos_client = cls.os_adm.volume_qos_client
+            cls.volume_types_client = cls.os_adm.volume_types_client
+            cls.admin_volume_client = cls.os_adm.volumes_client
+            cls.hosts_client = cls.os_adm.volume_hosts_client
+            cls.admin_snapshots_client = cls.os_adm.snapshots_client
+            cls.backups_adm_client = cls.os_adm.backups_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.volume_qos_client = cls.os_adm.volume_qos_v2_client
+            cls.volume_types_client = cls.os_adm.volume_types_v2_client
+            cls.admin_volume_client = cls.os_adm.volumes_v2_client
+            cls.hosts_client = cls.os_adm.volume_hosts_v2_client
+            cls.admin_snapshots_client = cls.os_adm.snapshots_v2_client
+            cls.backups_adm_client = cls.os_adm.backups_v2_client
+
+    @classmethod
+    def resource_cleanup(cls):
+        cls.clear_qos_specs()
+        super(BaseVolumeAdminTest, cls).resource_cleanup()
+
+    @classmethod
+    def create_test_qos_specs(cls, name=None, consumer=None, **kwargs):
+        """create a test Qos-Specs."""
+        name = name or data_utils.rand_name(cls.__name__ + '-QoS')
+        consumer = consumer or 'front-end'
+        _, qos_specs = cls.volume_qos_client.create_qos(name, consumer,
+                                                        **kwargs)
+        cls.qos_specs.append(qos_specs['id'])
+        return qos_specs
+
+    @classmethod
+    def clear_qos_specs(cls):
+        for qos_id in cls.qos_specs:
+            try:
+                cls.volume_qos_client.delete_qos(qos_id)
+            except exceptions.NotFound:
+                # The qos_specs may have already been deleted which is OK.
+                pass
+
+        for qos_id in cls.qos_specs:
+            try:
+                cls.volume_qos_client.wait_for_resource_deletion(qos_id)
+            except exceptions.NotFound:
+                # The qos_specs may have already been deleted which is OK.
+                pass
+
+
+class BaseVolumeV1AdminTest(BaseVolumeAdminTest):
+    _api_version = 1
diff --git a/tempest/api/volume/test_availability_zone.py b/tempest/api/volume/test_availability_zone.py
index c026f71..648bd8b 100644
--- a/tempest/api/volume/test_availability_zone.py
+++ b/tempest/api/volume/test_availability_zone.py
@@ -24,8 +24,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(AvailabilityZoneV2TestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(AvailabilityZoneV2TestJSON, cls).resource_setup()
         cls.client = cls.availability_zone_client
 
     @test.attr(type='gate')
diff --git a/tempest/api/volume/test_qos.py b/tempest/api/volume/test_qos.py
new file mode 100644
index 0000000..a719b79
--- /dev/null
+++ b/tempest/api/volume/test_qos.py
@@ -0,0 +1,175 @@
+# 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.volume import base
+from tempest.common.utils import data_utils as utils
+from tempest import test
+
+
+class QosSpecsV2TestJSON(base.BaseVolumeAdminTest):
+    """Test the Cinder QoS-specs.
+
+    Tests for  create, list, delete, show, associate,
+    disassociate, set/unset key V2 APIs.
+    """
+
+    @classmethod
+    def resource_setup(cls):
+        super(QosSpecsV2TestJSON, cls).resource_setup()
+        # Create admin qos client
+        # Create a test shared qos-specs for tests
+        cls.qos_name = utils.rand_name(cls.__name__ + '-QoS')
+        cls.qos_consumer = 'front-end'
+
+        cls.created_qos = cls.create_test_qos_specs(cls.qos_name,
+                                                    cls.qos_consumer,
+                                                    read_iops_sec='2000')
+
+    def _create_delete_test_qos_with_given_consumer(self, consumer):
+        name = utils.rand_name('qos')
+        qos = {'name': name, 'consumer': consumer}
+        body = self.create_test_qos_specs(name, consumer)
+        for key in ['name', 'consumer']:
+            self.assertEqual(qos[key], body[key])
+
+        self.volume_qos_client.delete_qos(body['id'])
+        self.volume_qos_client.wait_for_resource_deletion(body['id'])
+
+        # validate the deletion
+        _, list_qos = self.volume_qos_client.list_qos()
+        self.assertNotIn(body, list_qos)
+
+    def _create_test_volume_type(self):
+        vol_type_name = utils.rand_name("volume-type")
+        _, vol_type = self.volume_types_client.create_volume_type(
+            vol_type_name)
+        self.addCleanup(self.volume_types_client.delete_volume_type,
+                        vol_type['id'])
+        return vol_type
+
+    def _test_associate_qos(self, vol_type_id):
+        self.volume_qos_client.associate_qos(
+            self.created_qos['id'], vol_type_id)
+
+    def _test_get_association_qos(self):
+        _, body = self.volume_qos_client.get_association_qos(
+            self.created_qos['id'])
+
+        associations = []
+        for association in body:
+            associations.append(association['id'])
+
+        return associations
+
+    def test_create_delete_qos_with_front_end_consumer(self):
+        """Tests the creation and deletion of QoS specs
+
+        With consumer as front end
+        """
+        self._create_delete_test_qos_with_given_consumer('front-end')
+
+    def test_create_delete_qos_with_back_end_consumer(self):
+        """Tests the creation and deletion of QoS specs
+
+        With consumer as back-end
+        """
+        self._create_delete_test_qos_with_given_consumer('back-end')
+
+    @test.attr(type='smoke')
+    def test_create_delete_qos_with_both_consumer(self):
+        """Tests the creation and deletion of QoS specs
+
+        With consumer as both front end and back end
+        """
+        self._create_delete_test_qos_with_given_consumer('both')
+
+    @test.attr(type='smoke')
+    def test_get_qos(self):
+        """Tests the detail of a given qos-specs"""
+        _, body = self.volume_qos_client.get_qos(self.created_qos['id'])
+        self.assertEqual(self.qos_name, body['name'])
+        self.assertEqual(self.qos_consumer, body['consumer'])
+
+    @test.attr(type='smoke')
+    def test_list_qos(self):
+        """Tests the list of all qos-specs"""
+        _, body = self.volume_qos_client.list_qos()
+        self.assertIn(self.created_qos, body)
+
+    @test.attr(type='smoke')
+    def test_set_unset_qos_key(self):
+        """Test the addition of a specs key to qos-specs"""
+        args = {'iops_bytes': '500'}
+        _, body = self.volume_qos_client.set_qos_key(self.created_qos['id'],
+                                                     iops_bytes='500')
+        self.assertEqual(args, body)
+        _, body = self.volume_qos_client.get_qos(self.created_qos['id'])
+        self.assertEqual(args['iops_bytes'], body['specs']['iops_bytes'])
+
+        # test the deletion of a specs key from qos-specs
+        keys = ['iops_bytes']
+        self.volume_qos_client.unset_qos_key(self.created_qos['id'], keys)
+        operation = 'qos-key-unset'
+        self.volume_qos_client.wait_for_qos_operations(self.created_qos['id'],
+                                                       operation, keys)
+        _, body = self.volume_qos_client.get_qos(self.created_qos['id'])
+        self.assertNotIn(keys[0], body['specs'])
+
+    @test.attr(type='smoke')
+    def test_associate_disassociate_qos(self):
+        """Test the following operations :
+
+        1. associate_qos
+        2. get_association_qos
+        3. disassociate_qos
+        4. disassociate_all_qos
+        """
+
+        # create a test volume-type
+        vol_type = []
+        for _ in range(0, 3):
+            vol_type.append(self._create_test_volume_type())
+
+        # associate the qos-specs with volume-types
+        for i in range(0, 3):
+            self._test_associate_qos(vol_type[i]['id'])
+
+        # get the association of the qos-specs
+        associations = self._test_get_association_qos()
+
+        for i in range(0, 3):
+            self.assertIn(vol_type[i]['id'], associations)
+
+        # disassociate a volume-type with qos-specs
+        self.volume_qos_client.disassociate_qos(
+            self.created_qos['id'], vol_type[0]['id'])
+        operation = 'disassociate'
+        self.volume_qos_client.wait_for_qos_operations(self.created_qos['id'],
+                                                       operation,
+                                                       vol_type[0]['id'])
+        associations = self._test_get_association_qos()
+        self.assertNotIn(vol_type[0]['id'], associations)
+
+        # disassociate all volume-types from qos-specs
+        self.volume_qos_client.disassociate_all_qos(
+            self.created_qos['id'])
+        operation = 'disassociate-all'
+        self.volume_qos_client.wait_for_qos_operations(self.created_qos['id'],
+                                                       operation)
+        associations = self._test_get_association_qos()
+        self.assertEmpty(associations)
+
+
+class QosSpecsV1TestJSON(QosSpecsV2TestJSON):
+    _api_version = 1
diff --git a/tempest/api/volume/test_snapshot_metadata.py b/tempest/api/volume/test_snapshot_metadata.py
index 94ba095..777d3de 100644
--- a/tempest/api/volume/test_snapshot_metadata.py
+++ b/tempest/api/volume/test_snapshot_metadata.py
@@ -17,13 +17,11 @@
 from tempest import test
 
 
-class SnapshotMetadataTest(base.BaseVolumeV1Test):
-    _interface = "json"
+class SnapshotV2MetadataTestJSON(base.BaseVolumeTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(SnapshotMetadataTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(SnapshotV2MetadataTestJSON, cls).resource_setup()
         cls.client = cls.snapshots_client
         # Create a volume
         cls.volume = cls.create_volume()
@@ -34,7 +32,7 @@
     def tearDown(self):
         # Update the metadata to {}
         self.client.update_snapshot_metadata(self.snapshot_id, {})
-        super(SnapshotMetadataTest, self).tearDown()
+        super(SnapshotV2MetadataTestJSON, self).tearDown()
 
     @test.attr(type='gate')
     def test_create_get_delete_snapshot_metadata(self):
@@ -100,5 +98,13 @@
         self.assertEqual(expect, body)
 
 
-class SnapshotMetadataTestXML(SnapshotMetadataTest):
+class SnapshotV2MetadataTestXML(SnapshotV2MetadataTestJSON):
+    _interface = "xml"
+
+
+class SnapshotV1MetadataTestJSON(SnapshotV2MetadataTestJSON):
+    _api_version = 1
+
+
+class SnapshotV1MetadataTestXML(SnapshotV1MetadataTestJSON):
     _interface = "xml"
diff --git a/tempest/api/volume/test_volume_metadata.py b/tempest/api/volume/test_volume_metadata.py
index ac760aa..2ec8667 100644
--- a/tempest/api/volume/test_volume_metadata.py
+++ b/tempest/api/volume/test_volume_metadata.py
@@ -22,9 +22,8 @@
 class VolumesV2MetadataTest(base.BaseVolumeTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(VolumesV2MetadataTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesV2MetadataTest, cls).resource_setup()
         # Create a volume
         cls.volume = cls.create_volume()
         cls.volume_id = cls.volume['id']
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index 4a6ba03..fe217c1 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -26,19 +26,20 @@
 class VolumesV2TransfersTest(base.BaseVolumeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(VolumesV2TransfersTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesV2TransfersTest, cls).resource_setup()
 
         # Add another tenant to test volume-transfer
-        if CONF.compute.allow_tenant_isolation:
-            cls.os_alt = clients.Manager(cls.isolated_creds.get_alt_creds(),
-                                         interface=cls._interface)
-            # Add admin tenant to cleanup resources
-            cls.os_adm = clients.Manager(cls.isolated_creds.get_admin_creds(),
-                                         interface=cls._interface)
-        else:
-            cls.os_alt = clients.AltManager()
-            cls.os_adm = clients.ComputeAdminManager(interface=cls._interface)
+        cls.os_alt = clients.Manager(cls.isolated_creds.get_alt_creds(),
+                                     interface=cls._interface)
+        # Add admin tenant to cleanup resources
+        try:
+            creds = cls.isolated_creds.get_admin_creds()
+            cls.os_adm = clients.Manager(
+                credentials=creds, interface=cls._interface)
+        except NotImplementedError:
+            msg = "Missing Volume Admin API credentials in configuration."
+            raise cls.skipException(msg)
 
         cls.client = cls.volumes_client
         cls.alt_client = cls.os_alt.volumes_client
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index c87878d..a9bc70a 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -24,9 +24,8 @@
 class VolumesV2ActionsTest(base.BaseVolumeTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(VolumesV2ActionsTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesV2ActionsTest, cls).resource_setup()
         cls.client = cls.volumes_client
         cls.image_client = cls.os.image_client
 
@@ -45,12 +44,12 @@
         self.image_client.wait_for_resource_deletion(image_id)
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         # Delete the test instance
         cls.servers_client.delete_server(cls.server['id'])
         cls.servers_client.wait_for_server_termination(cls.server['id'])
 
-        super(VolumesV2ActionsTest, cls).tearDownClass()
+        super(VolumesV2ActionsTest, cls).resource_cleanup()
 
     @test.stresstest(class_setup_per='process')
     @test.attr(type='smoke')
diff --git a/tempest/api/volume/test_volumes_extend.py b/tempest/api/volume/test_volumes_extend.py
index c9e80aa..edd497c 100644
--- a/tempest/api/volume/test_volumes_extend.py
+++ b/tempest/api/volume/test_volumes_extend.py
@@ -23,9 +23,8 @@
 class VolumesV2ExtendTest(base.BaseVolumeTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(VolumesV2ExtendTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesV2ExtendTest, cls).resource_setup()
         cls.client = cls.volumes_client
 
     @test.attr(type='gate')
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index a346a17..033beb4 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -26,8 +26,8 @@
 class VolumesV2GetTest(base.BaseVolumeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(VolumesV2GetTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesV2GetTest, cls).resource_setup()
         cls.client = cls.volumes_client
 
         cls.name_field = cls.special_fields['name_field']
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 272a41a..016e9ab 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -55,9 +55,8 @@
                              [str_vol(v) for v in fetched_list]))
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(VolumesV2ListTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesV2ListTestJSON, cls).resource_setup()
         cls.client = cls.volumes_client
         cls.name = cls.VOLUME_FIELDS[1]
 
@@ -72,12 +71,12 @@
             cls.volume_id_list.append(volume['id'])
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         # Delete the created volumes
         for volid in cls.volume_id_list:
             cls.client.delete_volume(volid)
             cls.client.wait_for_resource_deletion(volid)
-        super(VolumesV2ListTestJSON, cls).tearDownClass()
+        super(VolumesV2ListTestJSON, cls).resource_cleanup()
 
     def _list_by_param_value_and_assert(self, params, with_detail=False):
         """
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index 5f0cffa..2b43c63 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -24,9 +24,8 @@
 class VolumesV2NegativeTest(base.BaseVolumeTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(VolumesV2NegativeTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesV2NegativeTest, cls).resource_setup()
         cls.client = cls.volumes_client
 
         cls.name_field = cls.special_fields['name_field']
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 7db1ef1..78df1df 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -20,21 +20,18 @@
 CONF = config.CONF
 
 
-class VolumesSnapshotTest(base.BaseVolumeV1Test):
-    _interface = "json"
+class VolumesV2SnapshotTestJSON(base.BaseVolumeTest):
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(VolumesSnapshotTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesV2SnapshotTestJSON, cls).resource_setup()
         cls.volume_origin = cls.create_volume()
 
         if not CONF.volume_feature_enabled.snapshot:
             raise cls.skipException("Cinder volume snapshots are disabled")
 
-    @classmethod
-    def tearDownClass(cls):
-        super(VolumesSnapshotTest, cls).tearDownClass()
+        cls.name_field = cls.special_fields['name_field']
+        cls.descrip_field = cls.special_fields['descrip_field']
 
     def _detach(self, volume_id):
         """Detach volume."""
@@ -90,8 +87,8 @@
     def test_snapshot_create_get_list_update_delete(self):
         # Create a snapshot
         s_name = data_utils.rand_name('snap')
-        snapshot = self.create_snapshot(self.volume_origin['id'],
-                                        display_name=s_name)
+        params = {self.name_field: s_name}
+        snapshot = self.create_snapshot(self.volume_origin['id'], **params)
 
         # Get the snap and check for some of its details
         _, snap_get = self.snapshots_client.get_snapshot(snapshot['id'])
@@ -100,26 +97,26 @@
                          "Referred volume origin mismatch")
 
         # Compare also with the output from the list action
-        tracking_data = (snapshot['id'], snapshot['display_name'])
+        tracking_data = (snapshot['id'], snapshot[self.name_field])
         _, snaps_list = self.snapshots_client.list_snapshots()
-        snaps_data = [(f['id'], f['display_name']) for f in snaps_list]
+        snaps_data = [(f['id'], f[self.name_field]) for f in snaps_list]
         self.assertIn(tracking_data, snaps_data)
 
         # Updates snapshot with new values
         new_s_name = data_utils.rand_name('new-snap')
         new_desc = 'This is the new description of snapshot.'
+        params = {self.name_field: new_s_name,
+                  self.descrip_field: new_desc}
         _, update_snapshot = \
-            self.snapshots_client.update_snapshot(snapshot['id'],
-                                                  display_name=new_s_name,
-                                                  display_description=new_desc)
+            self.snapshots_client.update_snapshot(snapshot['id'], **params)
         # Assert response body for update_snapshot method
-        self.assertEqual(new_s_name, update_snapshot['display_name'])
-        self.assertEqual(new_desc, update_snapshot['display_description'])
+        self.assertEqual(new_s_name, update_snapshot[self.name_field])
+        self.assertEqual(new_desc, update_snapshot[self.descrip_field])
         # Assert response body for get_snapshot method
         _, updated_snapshot = \
             self.snapshots_client.get_snapshot(snapshot['id'])
-        self.assertEqual(new_s_name, updated_snapshot['display_name'])
-        self.assertEqual(new_desc, updated_snapshot['display_description'])
+        self.assertEqual(new_s_name, updated_snapshot[self.name_field])
+        self.assertEqual(new_desc, updated_snapshot[self.descrip_field])
 
         # Delete the snapshot
         self.snapshots_client.delete_snapshot(snapshot['id'])
@@ -131,11 +128,11 @@
         """list snapshots with params."""
         # Create a snapshot
         display_name = data_utils.rand_name('snap')
-        snapshot = self.create_snapshot(self.volume_origin['id'],
-                                        display_name=display_name)
+        params = {self.name_field: display_name}
+        snapshot = self.create_snapshot(self.volume_origin['id'], **params)
 
         # Verify list snapshots by display_name filter
-        params = {'display_name': snapshot['display_name']}
+        params = {self.name_field: snapshot[self.name_field]}
         self._list_by_param_values_and_assert(params)
 
         # Verify list snapshots by status filter
@@ -144,7 +141,7 @@
 
         # Verify list snapshots by status and display name filter
         params = {'status': 'available',
-                  'display_name': snapshot['display_name']}
+                  self.name_field: snapshot[self.name_field]}
         self._list_by_param_values_and_assert(params)
 
     @test.attr(type='gate')
@@ -152,18 +149,18 @@
         """list snapshot details with params."""
         # Create a snapshot
         display_name = data_utils.rand_name('snap')
-        snapshot = self.create_snapshot(self.volume_origin['id'],
-                                        display_name=display_name)
+        params = {self.name_field: display_name}
+        snapshot = self.create_snapshot(self.volume_origin['id'], **params)
 
         # Verify list snapshot details by display_name filter
-        params = {'display_name': snapshot['display_name']}
+        params = {self.name_field: snapshot[self.name_field]}
         self._list_by_param_values_and_assert(params, with_detail=True)
         # Verify list snapshot details by status filter
         params = {'status': 'available'}
         self._list_by_param_values_and_assert(params, with_detail=True)
         # Verify list snapshot details by status and display name filter
         params = {'status': 'available',
-                  'display_name': snapshot['display_name']}
+                  self.name_field: snapshot[self.name_field]}
         self._list_by_param_values_and_assert(params, with_detail=True)
 
     @test.attr(type='gate')
@@ -181,5 +178,13 @@
         self.clear_snapshots()
 
 
-class VolumesSnapshotTestXML(VolumesSnapshotTest):
+class VolumesV2SnapshotTestXML(VolumesV2SnapshotTestJSON):
+    _interface = "xml"
+
+
+class VolumesV1SnapshotTestJSON(VolumesV2SnapshotTestJSON):
+    _api_version = 1
+
+
+class VolumesV1SnapshotTestXML(VolumesV1SnapshotTestJSON):
     _interface = "xml"
diff --git a/tempest/api/volume/test_volumes_snapshots_negative.py b/tempest/api/volume/test_volumes_snapshots_negative.py
index 61aa307..75a62a8 100644
--- a/tempest/api/volume/test_volumes_snapshots_negative.py
+++ b/tempest/api/volume/test_volumes_snapshots_negative.py
@@ -21,12 +21,11 @@
 CONF = config.CONF
 
 
-class VolumesSnapshotNegativeTest(base.BaseVolumeV1Test):
-    _interface = "json"
+class VolumesV2SnapshotNegativeTestJSON(base.BaseVolumeTest):
 
     @classmethod
-    def setUpClass(cls):
-        super(VolumesSnapshotNegativeTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesV2SnapshotNegativeTestJSON, cls).resource_setup()
 
         if not CONF.volume_feature_enabled.snapshot:
             raise cls.skipException("Cinder volume snapshots are disabled")
@@ -48,5 +47,13 @@
                           None, display_name=s_name)
 
 
-class VolumesSnapshotNegativeTestXML(VolumesSnapshotNegativeTest):
+class VolumesV2SnapshotNegativeTestXML(VolumesV2SnapshotNegativeTestJSON):
+    _interface = "xml"
+
+
+class VolumesV1SnapshotNegativeTestJSON(VolumesV2SnapshotNegativeTestJSON):
+    _api_version = 1
+
+
+class VolumesV1SnapshotNegativeTestXML(VolumesV1SnapshotNegativeTestJSON):
     _interface = "xml"
diff --git a/tempest/api/volume/v2/test_volumes_list.py b/tempest/api/volume/v2/test_volumes_list.py
index 3ae227d..cc56873 100644
--- a/tempest/api/volume/v2/test_volumes_list.py
+++ b/tempest/api/volume/v2/test_volumes_list.py
@@ -31,9 +31,8 @@
     """
 
     @classmethod
-    @test.safe_setup
-    def setUpClass(cls):
-        super(VolumesV2ListTestJSON, cls).setUpClass()
+    def resource_setup(cls):
+        super(VolumesV2ListTestJSON, cls).resource_setup()
         cls.client = cls.volumes_client
 
         # Create 3 test volumes
@@ -47,12 +46,12 @@
             cls.volume_id_list.append(volume['id'])
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         # Delete the created volumes
         for volid in cls.volume_id_list:
             cls.client.delete_volume(volid)
             cls.client.wait_for_resource_deletion(volid)
-        super(VolumesV2ListTestJSON, cls).tearDownClass()
+        super(VolumesV2ListTestJSON, cls).resource_cleanup()
 
     @test.attr(type='gate')
     def test_volume_list_details_with_multiple_params(self):
diff --git a/tempest/api_schema/request/compute/flavors.py b/tempest/api_schema/request/compute/flavors.py
index 8fe9e3a..adaaf27 100644
--- a/tempest/api_schema/request/compute/flavors.py
+++ b/tempest/api_schema/request/compute/flavors.py
@@ -40,14 +40,19 @@
     "json-schema": {
         "type": "object",
         "properties": {
-            "name": {"type": "string"},
-            "ram": {"type": "integer", "minimum": 1},
-            "vcpus": {"type": "integer", "minimum": 1},
-            "disk": {"type": "integer"},
-            "id": {"type": "integer"},
-            "swap": {"type": "integer"},
-            "rxtx_factor": {"type": "integer"},
-            "OS-FLV-EXT-DATA:ephemeral": {"type": "integer"}
+           "flavor": {
+               "type": "object",
+               "properties": {
+                   "name": {"type": "string",
+                            "exclude_tests": ["gen_str_min_length"]},
+                   "ram": {"type": "integer", "minimum": 1},
+                   "vcpus": {"type": "integer", "minimum": 1},
+                   "disk": {"type": "integer"},
+                   "id": {"type": "integer",
+                          "exclude_tests": ["gen_none", "gen_string"]
+                          },
+                   }
+               }
         }
     }
 }
diff --git a/tempest/api_schema/response/compute/availability_zone.py b/tempest/api_schema/response/compute/availability_zone.py
index c1abc64..ab3e2ea 100644
--- a/tempest/api_schema/response/compute/availability_zone.py
+++ b/tempest/api_schema/response/compute/availability_zone.py
@@ -27,7 +27,7 @@
                     'properties': {
                         'available': {'type': 'boolean'},
                         'active': {'type': 'boolean'},
-                        'updated_at': {'type': 'string'}
+                        'updated_at': {'type': ['string', 'null']}
                     },
                     'required': ['available', 'active', 'updated_at']
                 }
diff --git a/tempest/api_schema/response/compute/services.py b/tempest/api_schema/response/compute/services.py
index eaba129..fc42b89 100644
--- a/tempest/api_schema/response/compute/services.py
+++ b/tempest/api_schema/response/compute/services.py
@@ -28,7 +28,7 @@
                         'state': {'type': 'string'},
                         'binary': {'type': 'string'},
                         'status': {'type': 'string'},
-                        'updated_at': {'type': 'string'},
+                        'updated_at': {'type': ['string', 'null']},
                         'disabled_reason': {'type': ['string', 'null']}
                     },
                     'required': ['id', 'zone', 'host', 'state', 'binary',
diff --git a/tempest/api_schema/response/compute/v2/hypervisors.py b/tempest/api_schema/response/compute/v2/hypervisors.py
index 1878881..cbb7698 100644
--- a/tempest/api_schema/response/compute/v2/hypervisors.py
+++ b/tempest/api_schema/response/compute/v2/hypervisors.py
@@ -26,11 +26,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']},
+                'uuid': {'type': 'string'},
                 'name': {'type': 'string'}
             }
         }
diff --git a/tempest/api_schema/response/compute/v2/security_group_default_rule.py b/tempest/api_schema/response/compute/v2/security_group_default_rule.py
new file mode 100644
index 0000000..9246ab8
--- /dev/null
+++ b/tempest/api_schema/response/compute/v2/security_group_default_rule.py
@@ -0,0 +1,61 @@
+# Copyright 2014 NEC Corporation.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+common_security_group_default_rule_info = {
+    'type': 'object',
+    'properties': {
+        'from_port': {'type': 'integer'},
+        'id': {'type': 'integer'},
+        'ip_protocol': {'type': 'string'},
+        'ip_range': {
+            'type': 'object',
+            'properties': {
+                'cidr': {'type': 'string'}
+            },
+            'required': ['cidr'],
+        },
+        'to_port': {'type': 'integer'},
+    },
+    'required': ['from_port', 'id', 'ip_protocol', 'ip_range', 'to_port'],
+}
+
+create_get_security_group_default_rule = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'security_group_default_rule':
+                common_security_group_default_rule_info
+        },
+        'required': ['security_group_default_rule']
+    }
+}
+
+delete_security_group_default_rule = {
+    'status_code': [204]
+}
+
+list_security_group_default_rules = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'security_group_default_rules': {
+                'type': 'array',
+                'items': common_security_group_default_rule_info
+            }
+        },
+        'required': ['security_group_default_rules']
+    }
+}
diff --git a/tempest/api_schema/response/compute/v2/servers.py b/tempest/api_schema/response/compute/v2/servers.py
index 5fc2008..09abaed 100644
--- a/tempest/api_schema/response/compute/v2/servers.py
+++ b/tempest/api_schema/response/compute/v2/servers.py
@@ -117,21 +117,23 @@
     }
 }
 
+common_attach_volume_info = {
+    'type': 'object',
+    'properties': {
+        'id': {'type': 'string'},
+        'device': {'type': 'string'},
+        'volumeId': {'type': 'string'},
+        'serverId': {'type': ['integer', 'string']}
+    },
+    'required': ['id', 'device', 'volumeId', 'serverId']
+}
+
 attach_volume = {
     'status_code': [200],
     'response_body': {
         'type': 'object',
         'properties': {
-            'volumeAttachment': {
-                'type': 'object',
-                'properties': {
-                    'id': {'type': 'string'},
-                    'device': {'type': 'string'},
-                    'volumeId': {'type': 'string'},
-                    'serverId': {'type': ['integer', 'string']}
-                },
-                'required': ['id', 'device', 'volumeId', 'serverId']
-            }
+            'volumeAttachment': common_attach_volume_info
         },
         'required': ['volumeAttachment']
     }
@@ -141,6 +143,27 @@
     'status_code': [202]
 }
 
+get_volume_attachment = copy.deepcopy(attach_volume)
+get_volume_attachment['response_body']['properties'][
+    'volumeAttachment']['properties'].update({'serverId': {'type': 'string'}})
+
+list_volume_attachments = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'volumeAttachments': {
+                'type': 'array',
+                'items': common_attach_volume_info
+            }
+        },
+        'required': ['volumeAttachments']
+    }
+}
+list_volume_attachments['response_body']['properties'][
+    'volumeAttachments']['items']['properties'].update(
+    {'serverId': {'type': 'string'}})
+
 set_get_server_metadata_item = {
     'status_code': [200],
     'response_body': {
diff --git a/tempest/api_schema/response/queuing/__init__.py b/tempest/api_schema/response/messaging/__init__.py
similarity index 100%
rename from tempest/api_schema/response/queuing/__init__.py
rename to tempest/api_schema/response/messaging/__init__.py
diff --git a/tempest/api_schema/response/queuing/v1/__init__.py b/tempest/api_schema/response/messaging/v1/__init__.py
similarity index 100%
rename from tempest/api_schema/response/queuing/v1/__init__.py
rename to tempest/api_schema/response/messaging/v1/__init__.py
diff --git a/tempest/api_schema/response/queuing/v1/queues.py b/tempest/api_schema/response/messaging/v1/queues.py
similarity index 98%
rename from tempest/api_schema/response/queuing/v1/queues.py
rename to tempest/api_schema/response/messaging/v1/queues.py
index f0b2691..09e0147 100644
--- a/tempest/api_schema/response/queuing/v1/queues.py
+++ b/tempest/api_schema/response/messaging/v1/queues.py
@@ -105,7 +105,9 @@
 
 resource_schema = {
     'type': 'array',
-    'items': 'string',
+    'items': {
+        'type': 'string'
+    },
     'minItems': 1
 }
 
diff --git a/tempest/auth.py b/tempest/auth.py
index c84ad6b..b1ead29 100644
--- a/tempest/auth.py
+++ b/tempest/auth.py
@@ -40,11 +40,9 @@
     Provide authentication
     """
 
-    def __init__(self, credentials, client_type='tempest',
-                 interface=None):
+    def __init__(self, credentials, interface=None):
         """
         :param credentials: credentials for authentication
-        :param client_type: 'tempest' or 'official'
         :param interface: 'json' or 'xml'. Applicable for tempest client only
         """
         credentials = self._convert_credentials(credentials)
@@ -52,9 +50,8 @@
             self.credentials = credentials
         else:
             raise TypeError("Invalid credentials")
-        self.client_type = client_type
         self.interface = interface
-        if self.client_type == 'tempest' and self.interface is None:
+        if self.interface is None:
             self.interface = 'json'
         self.cache = None
         self.alt_auth_data = None
@@ -68,11 +65,10 @@
             return credentials
 
     def __str__(self):
-        return "Creds :{creds}, client type: {client_type}, interface: " \
-               "{interface}, cached auth data: {cache}".format(
-                   creds=self.credentials, client_type=self.client_type,
-                   interface=self.interface, cache=self.cache
-               )
+        return "Creds :{creds}, interface: {interface}, " \
+               "cached auth data: {cache}".format(
+                   creds=self.credentials, interface=self.interface,
+                   cache=self.cache)
 
     @abc.abstractmethod
     def _decorate_request(self, filters, method, url, headers=None, body=None,
@@ -208,9 +204,8 @@
 
     token_expiry_threshold = datetime.timedelta(seconds=60)
 
-    def __init__(self, credentials, client_type='tempest', interface=None):
-        super(KeystoneAuthProvider, self).__init__(credentials, client_type,
-                                                   interface)
+    def __init__(self, credentials, interface=None):
+        super(KeystoneAuthProvider, self).__init__(credentials, interface)
         self.auth_client = self._auth_client()
 
     def _decorate_request(self, filters, method, url, headers=None, body=None,
@@ -244,15 +239,12 @@
 
     def _get_auth(self):
         # Bypasses the cache
-        if self.client_type == 'tempest':
-            auth_func = getattr(self.auth_client, 'get_token')
-            auth_params = self._auth_params()
+        auth_func = getattr(self.auth_client, 'get_token')
+        auth_params = self._auth_params()
 
-            # returns token, auth_data
-            token, auth_data = auth_func(**auth_params)
-            return token, auth_data
-        else:
-            raise NotImplementedError
+        # returns token, auth_data
+        token, auth_data = auth_func(**auth_params)
+        return token, auth_data
 
     def get_token(self):
         return self.auth_data[0]
@@ -263,23 +255,17 @@
     EXPIRY_DATE_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
 
     def _auth_client(self):
-        if self.client_type == 'tempest':
-            if self.interface == 'json':
-                return json_id.TokenClientJSON()
-            else:
-                return xml_id.TokenClientXML()
+        if self.interface == 'json':
+            return json_id.TokenClientJSON()
         else:
-            raise NotImplementedError
+            return xml_id.TokenClientXML()
 
     def _auth_params(self):
-        if self.client_type == 'tempest':
-            return dict(
-                user=self.credentials.username,
-                password=self.credentials.password,
-                tenant=self.credentials.tenant_name,
-                auth_data=True)
-        else:
-            raise NotImplementedError
+        return dict(
+            user=self.credentials.username,
+            password=self.credentials.password,
+            tenant=self.credentials.tenant_name,
+            auth_data=True)
 
     def _fill_credentials(self, auth_data_body):
         tenant = auth_data_body['token']['tenant']
@@ -350,24 +336,18 @@
     EXPIRY_DATE_FORMAT = '%Y-%m-%dT%H:%M:%S.%fZ'
 
     def _auth_client(self):
-        if self.client_type == 'tempest':
-            if self.interface == 'json':
-                return json_v3id.V3TokenClientJSON()
-            else:
-                return xml_v3id.V3TokenClientXML()
+        if self.interface == 'json':
+            return json_v3id.V3TokenClientJSON()
         else:
-            raise NotImplementedError
+            return xml_v3id.V3TokenClientXML()
 
     def _auth_params(self):
-        if self.client_type == 'tempest':
-            return dict(
-                user=self.credentials.username,
-                password=self.credentials.password,
-                tenant=self.credentials.tenant_name,
-                domain=self.credentials.user_domain_name,
-                auth_data=True)
-        else:
-            raise NotImplementedError
+        return dict(
+            user=self.credentials.username,
+            password=self.credentials.password,
+            tenant=self.credentials.tenant_name,
+            domain=self.credentials.user_domain_name,
+            auth_data=True)
 
     def _fill_credentials(self, auth_data_body):
         # project or domain, depending on the scope
diff --git a/tempest/cli/__init__.py b/tempest/cli/__init__.py
index c33589a..4782129 100644
--- a/tempest/cli/__init__.py
+++ b/tempest/cli/__init__.py
@@ -14,46 +14,21 @@
 #    under the License.
 
 import functools
-import os
-import shlex
-import subprocess
 
+from tempest_lib.cli import base
+from tempest_lib.cli import output_parser
 import testtools
 
-import tempest.cli.output_parser
+from tempest.common import credentials
 from tempest import config
 from tempest import exceptions
-from tempest.openstack.common import log as logging
 from tempest.openstack.common import versionutils
-import tempest.test
+from tempest import test
 
 
-LOG = logging.getLogger(__name__)
-
 CONF = config.CONF
 
 
-def execute(cmd, action, flags='', params='', fail_ok=False,
-            merge_stderr=False):
-    """Executes specified command for the given action."""
-    cmd = ' '.join([os.path.join(CONF.cli.cli_dir, cmd),
-                    flags, action, params])
-    LOG.info("running: '%s'" % cmd)
-    cmd = shlex.split(cmd.encode('utf-8'))
-    result = ''
-    result_err = ''
-    stdout = subprocess.PIPE
-    stderr = subprocess.STDOUT if merge_stderr else subprocess.PIPE
-    proc = subprocess.Popen(cmd, stdout=stdout, stderr=stderr)
-    result, result_err = proc.communicate()
-    if not fail_ok and proc.returncode != 0:
-        raise exceptions.CommandFailed(proc.returncode,
-                                       cmd,
-                                       result,
-                                       result_err)
-    return result
-
-
 def check_client_version(client, version):
     """Checks if the client's version is compatible with the given version
 
@@ -62,8 +37,8 @@
     @return: True if the client version is compatible with the given version
              parameter, False otherwise.
     """
-    current_version = execute(client, '', params='--version',
-                              merge_stderr=True)
+    current_version = base.execute(client, '', params='--version',
+                                   merge_stderr=True, cli_dir=CONF.cli.cli_dir)
 
     if not current_version.strip():
         raise exceptions.TempestException('"%s --version" output was empty' %
@@ -92,100 +67,52 @@
     return decorator
 
 
-class ClientTestBase(tempest.test.BaseTestCase):
+class ClientTestBase(test.BaseTestCase):
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.cli.enabled:
             msg = "cli testing disabled"
             raise cls.skipException(msg)
-        super(ClientTestBase, cls).setUpClass()
+        super(ClientTestBase, cls).resource_setup()
+        cls.cred_prov = credentials.get_isolated_credentials(cls.__name__)
+        cls.creds = cls.cred_prov.get_admin_creds()
 
-    def __init__(self, *args, **kwargs):
-        self.parser = tempest.cli.output_parser
-        super(ClientTestBase, self).__init__(*args, **kwargs)
+    def _get_clients(self):
+        clients = base.CLIClient(self.creds.username,
+                                 self.creds.password,
+                                 self.creds.tenant_name,
+                                 CONF.identity.uri, CONF.cli.cli_dir)
+        return clients
 
-    def nova(self, action, flags='', params='', admin=True, fail_ok=False):
-        """Executes nova command for the given action."""
-        flags += ' --endpoint-type %s' % CONF.compute.endpoint_type
-        return self.cmd_with_auth(
-            'nova', action, flags, params, admin, fail_ok)
-
-    def nova_manage(self, action, flags='', params='', fail_ok=False,
-                    merge_stderr=False):
-        """Executes nova-manage command for the given action."""
-        return execute(
-            'nova-manage', action, flags, params, fail_ok, merge_stderr)
-
-    def keystone(self, action, flags='', params='', admin=True, fail_ok=False):
-        """Executes keystone command for the given action."""
-        return self.cmd_with_auth(
-            'keystone', action, flags, params, admin, fail_ok)
-
-    def glance(self, action, flags='', params='', admin=True, fail_ok=False):
-        """Executes glance command for the given action."""
-        flags += ' --os-endpoint-type %s' % CONF.image.endpoint_type
-        return self.cmd_with_auth(
-            'glance', action, flags, params, admin, fail_ok)
-
-    def ceilometer(self, action, flags='', params='', admin=True,
-                   fail_ok=False):
-        """Executes ceilometer command for the given action."""
-        flags += ' --os-endpoint-type %s' % CONF.telemetry.endpoint_type
-        return self.cmd_with_auth(
-            'ceilometer', action, flags, params, admin, fail_ok)
-
-    def heat(self, action, flags='', params='', admin=True,
-             fail_ok=False):
-        """Executes heat command for the given action."""
-        flags += ' --os-endpoint-type %s' % CONF.orchestration.endpoint_type
-        return self.cmd_with_auth(
-            'heat', action, flags, params, admin, fail_ok)
-
-    def cinder(self, action, flags='', params='', admin=True, fail_ok=False):
-        """Executes cinder command for the given action."""
-        flags += ' --endpoint-type %s' % CONF.volume.endpoint_type
-        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, 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, merge_stderr)
-
-    def cmd_with_auth(self, cmd, action, flags='', params='',
-                      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 '
-                 '--os-auth-url %s' %
-                 (CONF.identity.admin_username,
-                  CONF.identity.admin_tenant_name,
-                  CONF.identity.admin_password,
-                  CONF.identity.uri))
-        flags = creds + ' ' + flags
-        return execute(cmd, action, flags, params, fail_ok, merge_stderr)
+    # TODO(mtreinish): The following code is basically copied from tempest-lib.
+    # The base cli test class in tempest-lib 0.0.1 doesn't work as a mixin like
+    # is needed here. The code below should be removed when tempest-lib
+    # provides a way to provide this functionality
+    def setUp(self):
+        super(ClientTestBase, self).setUp()
+        self.clients = self._get_clients()
+        self.parser = output_parser
 
     def assertTableStruct(self, items, field_names):
-        """Verify that all items has keys listed in field_names."""
+        """Verify that all items has keys listed in field_names.
+
+        :param items: items to assert are field names in the output table
+        :type items: list
+        :param field_names: field names from the output table of the cmd
+        :type field_names: list
+        """
         for item in items:
             for field in field_names:
                 self.assertIn(field, item)
 
     def assertFirstLineStartsWith(self, lines, beginning):
+        """Verify that the first line starts with a string
+
+        :param lines: strings for each line of output
+        :type lines: list
+        :param beginning: verify this is at the beginning of the first line
+        :type beginning: string
+        """
         self.assertTrue(lines[0].startswith(beginning),
                         msg=('Beginning of first line has invalid content: %s'
                              % lines[:3]))
diff --git a/tempest/cli/output_parser.py b/tempest/cli/output_parser.py
deleted file mode 100644
index 80234a3..0000000
--- a/tempest/cli/output_parser.py
+++ /dev/null
@@ -1,171 +0,0 @@
-# Copyright 2013 OpenStack Foundation
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-"""Collection of utilities for parsing CLI clients output."""
-
-import re
-
-from tempest import exceptions
-from tempest.openstack.common import log as logging
-
-
-LOG = logging.getLogger(__name__)
-
-
-delimiter_line = re.compile('^\+\-[\+\-]+\-\+$')
-
-
-def details_multiple(output_lines, with_label=False):
-    """Return list of dicts with item details from cli output tables.
-
-    If with_label is True, key '__label' is added to each items dict.
-    For more about 'label' see OutputParser.tables().
-    """
-    items = []
-    tables_ = tables(output_lines)
-    for table_ in tables_:
-        if 'Property' not in table_['headers'] \
-           or 'Value' not in table_['headers']:
-            raise exceptions.InvalidStructure()
-        item = {}
-        for value in table_['values']:
-            item[value[0]] = value[1]
-        if with_label:
-            item['__label'] = table_['label']
-        items.append(item)
-    return items
-
-
-def details(output_lines, with_label=False):
-    """Return dict with details of first item (table) found in output."""
-    items = details_multiple(output_lines, with_label)
-    return items[0]
-
-
-def listing(output_lines):
-    """Return list of dicts with basic item info parsed from cli output.
-    """
-
-    items = []
-    table_ = table(output_lines)
-    for row in table_['values']:
-        item = {}
-        for col_idx, col_key in enumerate(table_['headers']):
-            item[col_key] = row[col_idx]
-        items.append(item)
-    return items
-
-
-def tables(output_lines):
-    """Find all ascii-tables in output and parse them.
-
-    Return list of tables parsed from cli output as dicts.
-    (see OutputParser.table())
-
-    And, if found, label key (separated line preceding the table)
-    is added to each tables dict.
-    """
-    tables_ = []
-
-    table_ = []
-    label = None
-
-    start = False
-    header = False
-
-    if not isinstance(output_lines, list):
-        output_lines = output_lines.split('\n')
-
-    for line in output_lines:
-        if delimiter_line.match(line):
-            if not start:
-                start = True
-            elif not header:
-                # we are after head area
-                header = True
-            else:
-                # table ends here
-                start = header = None
-                table_.append(line)
-
-                parsed = table(table_)
-                parsed['label'] = label
-                tables_.append(parsed)
-
-                table_ = []
-                label = None
-                continue
-        if start:
-            table_.append(line)
-        else:
-            if label is None:
-                label = line
-            else:
-                LOG.warn('Invalid line between tables: %s' % line)
-    if len(table_) > 0:
-        LOG.warn('Missing end of table')
-
-    return tables_
-
-
-def table(output_lines):
-    """Parse single table from cli output.
-
-    Return dict with list of column names in 'headers' key and
-    rows in 'values' key.
-    """
-    table_ = {'headers': [], 'values': []}
-    columns = None
-
-    if not isinstance(output_lines, list):
-        output_lines = output_lines.split('\n')
-
-    if not output_lines[-1]:
-        # skip last line if empty (just newline at the end)
-        output_lines = output_lines[:-1]
-
-    for line in output_lines:
-        if delimiter_line.match(line):
-            columns = _table_columns(line)
-            continue
-        if '|' not in line:
-            LOG.warn('skipping invalid table line: %s' % line)
-            continue
-        row = []
-        for col in columns:
-            row.append(line[col[0]:col[1]].strip())
-        if table_['headers']:
-            table_['values'].append(row)
-        else:
-            table_['headers'] = row
-
-    return table_
-
-
-def _table_columns(first_table_row):
-    """Find column ranges in output line.
-
-    Return list of tuples (start,end) for each column
-    detected by plus (+) characters in delimiter line.
-    """
-    positions = []
-    start = 1  # there is '+' at 0
-    while start < len(first_table_row):
-        end = first_table_row.find('+', start)
-        if end == -1:
-            break
-        positions.append((start, end))
-        start = end + 1
-    return positions
diff --git a/tempest/api/queuing/__init__.py b/tempest/cli/simple_read_only/compute/__init__.py
similarity index 100%
copy from tempest/api/queuing/__init__.py
copy to tempest/cli/simple_read_only/compute/__init__.py
diff --git a/tempest/cli/simple_read_only/test_nova.py b/tempest/cli/simple_read_only/compute/test_nova.py
similarity index 94%
rename from tempest/cli/simple_read_only/test_nova.py
rename to tempest/cli/simple_read_only/compute/test_nova.py
index 9bac7a6..4fe4982 100644
--- a/tempest/cli/simple_read_only/test_nova.py
+++ b/tempest/cli/simple_read_only/compute/test_nova.py
@@ -13,11 +13,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest_lib import exceptions
 import testtools
 
 from tempest import cli
 from tempest import config
-from tempest import exceptions
 from tempest.openstack.common import log as logging
 import tempest.test
 
@@ -41,11 +41,16 @@
     """
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.service_available.nova:
             msg = ("%s skipped as Nova is not available" % cls.__name__)
             raise cls.skipException(msg)
-        super(SimpleReadOnlyNovaClientTest, cls).setUpClass()
+        super(SimpleReadOnlyNovaClientTest, cls).resource_setup()
+
+    def nova(self, *args, **kwargs):
+        return self.clients.nova(*args,
+                                 endpoint_type=CONF.compute.endpoint_type,
+                                 **kwargs)
 
     def test_admin_fake_action(self):
         self.assertRaises(exceptions.CommandFailed,
diff --git a/tempest/cli/simple_read_only/test_nova_manage.py b/tempest/cli/simple_read_only/compute/test_nova_manage.py
similarity index 88%
rename from tempest/cli/simple_read_only/test_nova_manage.py
rename to tempest/cli/simple_read_only/compute/test_nova_manage.py
index c27b12e..34ec671 100644
--- a/tempest/cli/simple_read_only/test_nova_manage.py
+++ b/tempest/cli/simple_read_only/compute/test_nova_manage.py
@@ -13,9 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest_lib import exceptions
+
 from tempest import cli
 from tempest import config
-from tempest import exceptions
 from tempest.openstack.common import log as logging
 
 
@@ -36,7 +37,7 @@
     """
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.service_available.nova:
             msg = ("%s skipped as Nova is not available" % cls.__name__)
             raise cls.skipException(msg)
@@ -44,7 +45,10 @@
             msg = ("%s skipped as *-manage commands not available"
                    % cls.__name__)
             raise cls.skipException(msg)
-        super(SimpleReadOnlyNovaManageTest, cls).setUpClass()
+        super(SimpleReadOnlyNovaManageTest, cls).resource_setup()
+
+    def nova_manage(self, *args, **kwargs):
+        return self.clients.nova_manage(*args, **kwargs)
 
     def test_admin_fake_action(self):
         self.assertRaises(exceptions.CommandFailed,
@@ -65,20 +69,17 @@
                          self.nova_manage('', '--version', merge_stderr=True))
 
     def test_debug_flag(self):
-        self.assertNotEqual("", self.nova_manage('flavor list',
+        self.assertNotEqual("", self.nova_manage('service list',
                             '--debug'))
 
     def test_verbose_flag(self):
-        self.assertNotEqual("", self.nova_manage('flavor list',
+        self.assertNotEqual("", self.nova_manage('service list',
                             '--verbose'))
 
     # test actions
     def test_version(self):
         self.assertNotEqual("", self.nova_manage('version'))
 
-    def test_flavor_list(self):
-        self.assertNotEqual("", self.nova_manage('flavor list'))
-
     def test_db_sync(self):
         # make sure command doesn't error out
         self.nova_manage('db sync')
diff --git a/tempest/api/queuing/__init__.py b/tempest/cli/simple_read_only/data_processing/__init__.py
similarity index 100%
copy from tempest/api/queuing/__init__.py
copy to tempest/cli/simple_read_only/data_processing/__init__.py
diff --git a/tempest/cli/simple_read_only/test_sahara.py b/tempest/cli/simple_read_only/data_processing/test_sahara.py
similarity index 94%
rename from tempest/cli/simple_read_only/test_sahara.py
rename to tempest/cli/simple_read_only/data_processing/test_sahara.py
index 2c6e0e2..1f2403c 100644
--- a/tempest/cli/simple_read_only/test_sahara.py
+++ b/tempest/cli/simple_read_only/data_processing/test_sahara.py
@@ -15,9 +15,10 @@
 import logging
 import re
 
+from tempest_lib import exceptions
+
 from tempest import cli
 from tempest import config
-from tempest import exceptions
 from tempest import test
 
 CONF = config.CONF
@@ -34,11 +35,15 @@
     """
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.service_available.sahara:
             msg = "Skipping all Sahara cli tests because it is not available"
             raise cls.skipException(msg)
-        super(SimpleReadOnlySaharaClientTest, cls).setUpClass()
+        super(SimpleReadOnlySaharaClientTest, cls).resource_setup()
+
+    def sahara(self, *args, **kwargs):
+        return self.clients.sahara(
+            *args, endpoint_type=CONF.data_processing.endpoint_type, **kwargs)
 
     @test.attr(type='negative')
     def test_sahara_fake_action(self):
diff --git a/tempest/api/queuing/__init__.py b/tempest/cli/simple_read_only/identity/__init__.py
similarity index 100%
copy from tempest/api/queuing/__init__.py
copy to tempest/cli/simple_read_only/identity/__init__.py
diff --git a/tempest/cli/simple_read_only/test_keystone.py b/tempest/cli/simple_read_only/identity/test_keystone.py
similarity index 97%
rename from tempest/cli/simple_read_only/test_keystone.py
rename to tempest/cli/simple_read_only/identity/test_keystone.py
index 9218fcd..1fc7908 100644
--- a/tempest/cli/simple_read_only/test_keystone.py
+++ b/tempest/cli/simple_read_only/identity/test_keystone.py
@@ -15,9 +15,10 @@
 
 import re
 
+from tempest_lib import exceptions
+
 from tempest import cli
 from tempest import config
-from tempest import exceptions
 from tempest.openstack.common import log as logging
 
 CONF = config.CONF
@@ -34,6 +35,9 @@
     their own. They only verify the structure of output if present.
     """
 
+    def keystone(self, *args, **kwargs):
+        return self.clients.keystone(*args, **kwargs)
+
     def test_admin_fake_action(self):
         self.assertRaises(exceptions.CommandFailed,
                           self.keystone,
diff --git a/tempest/api/queuing/__init__.py b/tempest/cli/simple_read_only/image/__init__.py
similarity index 100%
copy from tempest/api/queuing/__init__.py
copy to tempest/cli/simple_read_only/image/__init__.py
diff --git a/tempest/cli/simple_read_only/test_glance.py b/tempest/cli/simple_read_only/image/test_glance.py
similarity index 90%
rename from tempest/cli/simple_read_only/test_glance.py
rename to tempest/cli/simple_read_only/image/test_glance.py
index 2fd8212..03e00d7 100644
--- a/tempest/cli/simple_read_only/test_glance.py
+++ b/tempest/cli/simple_read_only/image/test_glance.py
@@ -15,9 +15,10 @@
 
 import re
 
+from tempest_lib import exceptions
+
 from tempest import cli
 from tempest import config
-from tempest import exceptions
 from tempest.openstack.common import log as logging
 
 CONF = config.CONF
@@ -34,11 +35,16 @@
     """
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.service_available.glance:
             msg = ("%s skipped as Glance is not available" % cls.__name__)
             raise cls.skipException(msg)
-        super(SimpleReadOnlyGlanceClientTest, cls).setUpClass()
+        super(SimpleReadOnlyGlanceClientTest, cls).resource_setup()
+
+    def glance(self, *args, **kwargs):
+        return self.clients.glance(*args,
+                                   endpoint_type=CONF.image.endpoint_type,
+                                   **kwargs)
 
     def test_glance_fake_action(self):
         self.assertRaises(exceptions.CommandFailed,
diff --git a/tempest/api/queuing/__init__.py b/tempest/cli/simple_read_only/network/__init__.py
similarity index 100%
copy from tempest/api/queuing/__init__.py
copy to tempest/cli/simple_read_only/network/__init__.py
diff --git a/tempest/cli/simple_read_only/test_neutron.py b/tempest/cli/simple_read_only/network/test_neutron.py
similarity index 76%
rename from tempest/cli/simple_read_only/test_neutron.py
rename to tempest/cli/simple_read_only/network/test_neutron.py
index 87f6b67..6090882 100644
--- a/tempest/cli/simple_read_only/test_neutron.py
+++ b/tempest/cli/simple_read_only/network/test_neutron.py
@@ -15,9 +15,10 @@
 
 import re
 
+from tempest_lib import exceptions
+
 from tempest import cli
 from tempest import config
-from tempest import exceptions
 from tempest.openstack.common import log as logging
 from tempest import test
 
@@ -35,11 +36,16 @@
     """
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if (not CONF.service_available.neutron):
             msg = "Skipping all Neutron cli tests because it is not available"
             raise cls.skipException(msg)
-        super(SimpleReadOnlyNeutronClientTest, cls).setUpClass()
+        super(SimpleReadOnlyNeutronClientTest, cls).resource_setup()
+
+    def neutron(self, *args, **kwargs):
+        return self.clients.neutron(*args,
+                                    endpoint_type=CONF.network.endpoint_type,
+                                    **kwargs)
 
     @test.attr(type='smoke')
     def test_neutron_fake_action(self):
@@ -156,6 +162,42 @@
                                              'allocation_pools'])
 
     @test.attr(type='smoke')
+    @test.requires_ext(extension='vpnaas', service='network')
+    def test_neutron_vpn_ikepolicy_list(self):
+        ikepolicy = self.parser.listing(self.neutron('vpn-ikepolicy-list'))
+        self.assertTableStruct(ikepolicy, ['id', 'name',
+                                           'auth_algorithm',
+                                           'encryption_algorithm',
+                                           'ike_version', 'pfs'])
+
+    @test.attr(type='smoke')
+    @test.requires_ext(extension='vpnaas', service='network')
+    def test_neutron_vpn_ipsecpolicy_list(self):
+        ipsecpolicy = self.parser.listing(self.neutron('vpn-ipsecpolicy-list'))
+        self.assertTableStruct(ipsecpolicy, ['id', 'name',
+                                             'auth_algorithm',
+                                             'encryption_algorithm',
+                                             'pfs'])
+
+    @test.attr(type='smoke')
+    @test.requires_ext(extension='vpnaas', service='network')
+    def test_neutron_vpn_service_list(self):
+        vpn_list = self.parser.listing(self.neutron('vpn-service-list'))
+        self.assertTableStruct(vpn_list, ['id', 'name',
+                                          'router_id', 'status'])
+
+    @test.attr(type='smoke')
+    @test.requires_ext(extension='vpnaas', service='network')
+    def test_neutron_ipsec_site_connection_list(self):
+        ipsec_site = self.parser.listing(self.neutron
+                                         ('ipsec-site-connection-list'))
+        self.assertTableStruct(ipsec_site, ['id', 'name',
+                                            'peer_address',
+                                            'peer_cidrs',
+                                            'route_mode',
+                                            'auth_mode', 'status'])
+
+    @test.attr(type='smoke')
     def test_neutron_help(self):
         help_text = self.neutron('help')
         lines = help_text.split('\n')
diff --git a/tempest/api/queuing/__init__.py b/tempest/cli/simple_read_only/object_storage/__init__.py
similarity index 100%
copy from tempest/api/queuing/__init__.py
copy to tempest/cli/simple_read_only/object_storage/__init__.py
diff --git a/tempest/cli/simple_read_only/test_swift.py b/tempest/cli/simple_read_only/object_storage/test_swift.py
similarity index 91%
rename from tempest/cli/simple_read_only/test_swift.py
rename to tempest/cli/simple_read_only/object_storage/test_swift.py
index 069a384..40c4c15 100644
--- a/tempest/cli/simple_read_only/test_swift.py
+++ b/tempest/cli/simple_read_only/object_storage/test_swift.py
@@ -15,9 +15,10 @@
 
 import re
 
+from tempest_lib import exceptions
+
 from tempest import cli
 from tempest import config
-from tempest import exceptions
 
 CONF = config.CONF
 
@@ -31,11 +32,15 @@
     """
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(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()
+        super(SimpleReadOnlySwiftClientTest, cls).resource_setup()
+
+    def swift(self, *args, **kwargs):
+        return self.clients.swift(
+            *args, endpoint_type=CONF.object_storage.endpoint_type, **kwargs)
 
     def test_swift_fake_action(self):
         self.assertRaises(exceptions.CommandFailed,
diff --git a/tempest/services/queuing/json/__init__.py b/tempest/cli/simple_read_only/orchestration/__init__.py
similarity index 100%
copy from tempest/services/queuing/json/__init__.py
copy to tempest/cli/simple_read_only/orchestration/__init__.py
diff --git a/tempest/cli/simple_read_only/test_heat.py b/tempest/cli/simple_read_only/orchestration/test_heat.py
similarity index 83%
rename from tempest/cli/simple_read_only/test_heat.py
rename to tempest/cli/simple_read_only/orchestration/test_heat.py
index 8e413a9..d3a9b01 100644
--- a/tempest/cli/simple_read_only/test_heat.py
+++ b/tempest/cli/simple_read_only/orchestration/test_heat.py
@@ -32,12 +32,19 @@
     """
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if (not CONF.service_available.heat):
             msg = ("Skipping all Heat cli tests because it is "
                    "not available")
             raise cls.skipException(msg)
-        super(SimpleReadOnlyHeatClientTest, cls).setUpClass()
+        super(SimpleReadOnlyHeatClientTest, cls).resource_setup()
+        cls.heat_template_path = os.path.join(os.path.dirname(
+            os.path.dirname(os.path.realpath(__file__))),
+            'heat_templates/heat_minimal.yaml')
+
+    def heat(self, *args, **kwargs):
+        return self.clients.heat(
+            *args, endpoint_type=CONF.orchestration.endpoint_type, **kwargs)
 
     def test_heat_stack_list(self):
         self.heat('stack-list')
@@ -56,7 +63,7 @@
 
     def test_heat_resource_template_fmt_arg_long_json(self):
         ret = self.heat('resource-template --format json OS::Nova::Server')
-        self.assertIn('"Type": "OS::Nova::Server",', ret)
+        self.assertIn('"Type": "OS::Nova::Server"', ret)
         self.assertIsInstance(json.loads(ret), dict)
 
     def test_heat_resource_type_list(self):
@@ -70,17 +77,13 @@
         self.assertIsInstance(json.loads(rsrc_schema), dict)
 
     def test_heat_template_validate_yaml(self):
-        filepath = os.path.join(os.path.dirname(os.path.realpath(__file__)),
-                                'heat_templates/heat_minimal.yaml')
-        ret = self.heat('template-validate -f %s' % filepath)
+        ret = self.heat('template-validate -f %s' % self.heat_template_path)
         # On success template-validate returns a json representation
         # of the template parameters
         self.assertIsInstance(json.loads(ret), dict)
 
     def test_heat_template_validate_hot(self):
-        filepath = os.path.join(os.path.dirname(os.path.realpath(__file__)),
-                                'heat_templates/heat_minimal_hot.yaml')
-        ret = self.heat('template-validate -f %s' % filepath)
+        ret = self.heat('template-validate -f %s' % self.heat_template_path)
         self.assertIsInstance(json.loads(ret), dict)
 
     def test_heat_help(self):
diff --git a/tempest/api/queuing/__init__.py b/tempest/cli/simple_read_only/telemetry/__init__.py
similarity index 100%
copy from tempest/api/queuing/__init__.py
copy to tempest/cli/simple_read_only/telemetry/__init__.py
diff --git a/tempest/cli/simple_read_only/test_ceilometer.py b/tempest/cli/simple_read_only/telemetry/test_ceilometer.py
similarity index 86%
rename from tempest/cli/simple_read_only/test_ceilometer.py
rename to tempest/cli/simple_read_only/telemetry/test_ceilometer.py
index b622dd4..f9bf8b2 100644
--- a/tempest/cli/simple_read_only/test_ceilometer.py
+++ b/tempest/cli/simple_read_only/telemetry/test_ceilometer.py
@@ -32,26 +32,26 @@
     """
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if (not CONF.service_available.ceilometer):
             msg = ("Skipping all Ceilometer cli tests because it is "
                    "not available")
             raise cls.skipException(msg)
-        super(SimpleReadOnlyCeilometerClientTest, cls).setUpClass()
+        super(SimpleReadOnlyCeilometerClientTest, cls).resource_setup()
 
-    @test.services('telemetry')
+    def ceilometer(self, *args, **kwargs):
+        return self.clients.ceilometer(
+            *args, endpoint_type=CONF.telemetry.endpoint_type, **kwargs)
+
     def test_ceilometer_meter_list(self):
         self.ceilometer('meter-list')
 
     @test.attr(type='slow')
-    @test.services('telemetry')
     def test_ceilometer_resource_list(self):
         self.ceilometer('resource-list')
 
-    @test.services('telemetry')
     def test_ceilometermeter_alarm_list(self):
         self.ceilometer('alarm-list')
 
-    @test.services('telemetry')
     def test_ceilometer_version(self):
         self.ceilometer('', flags='--version')
diff --git a/tempest/api/queuing/__init__.py b/tempest/cli/simple_read_only/volume/__init__.py
similarity index 100%
copy from tempest/api/queuing/__init__.py
copy to tempest/cli/simple_read_only/volume/__init__.py
diff --git a/tempest/cli/simple_read_only/test_cinder.py b/tempest/cli/simple_read_only/volume/test_cinder.py
similarity index 88%
rename from tempest/cli/simple_read_only/test_cinder.py
rename to tempest/cli/simple_read_only/volume/test_cinder.py
index 3a9a7a6..c2e0a42 100644
--- a/tempest/cli/simple_read_only/test_cinder.py
+++ b/tempest/cli/simple_read_only/volume/test_cinder.py
@@ -16,11 +16,13 @@
 import logging
 import re
 
+from tempest_lib import exceptions
 import testtools
 
 from tempest import cli
+from tempest import clients
 from tempest import config
-from tempest import exceptions
+
 
 CONF = config.CONF
 LOG = logging.getLogger(__name__)
@@ -35,11 +37,19 @@
     """
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
         if not CONF.service_available.cinder:
             msg = ("%s skipped as Cinder is not available" % cls.__name__)
             raise cls.skipException(msg)
-        super(SimpleReadOnlyCinderClientTest, cls).setUpClass()
+        super(SimpleReadOnlyCinderClientTest, cls).resource_setup()
+        id_cl = clients.AdminManager().identity_client
+        tenant = id_cl.get_tenant_by_name(CONF.identity.admin_tenant_name)
+        cls.admin_tenant_id = tenant['id']
+
+    def cinder(self, *args, **kwargs):
+        return self.clients.cinder(*args,
+                                   endpoint_type=CONF.volume.endpoint_type,
+                                   **kwargs)
 
     def test_cinder_fake_action(self):
         self.assertRaises(exceptions.CommandFailed,
@@ -81,15 +91,13 @@
     def test_cinder_quota_defaults(self):
         """This CLI can accept and string as param."""
         roles = self.parser.listing(self.cinder('quota-defaults',
-                                                params=CONF.identity.
-                                                admin_tenant_name))
+                                                params=self.admin_tenant_id))
         self.assertTableStruct(roles, ['Property', 'Value'])
 
     def test_cinder_quota_show(self):
         """This CLI can accept and string as param."""
         roles = self.parser.listing(self.cinder('quota-show',
-                                                params=CONF.identity.
-                                                admin_tenant_name))
+                                                params=self.admin_tenant_id))
         self.assertTableStruct(roles, ['Property', 'Value'])
 
     def test_cinder_rate_limits(self):
@@ -121,14 +129,17 @@
         self.assertTableStruct(zone_list, ['Name', 'Status'])
 
     def test_cinder_endpoints(self):
-        endpoints = self.parser.listing(self.cinder('endpoints'))
-        self.assertTableStruct(endpoints, ['nova', 'Value'])
+        out = self.cinder('endpoints')
+        tables = self.parser.tables(out)
+        for table in tables:
+            headers = table['headers']
+            self.assertTrue(2 >= len(headers))
+            self.assertEqual('Value', headers[1])
 
     def test_cinder_service_list(self):
         service_list = self.parser.listing(self.cinder('service-list'))
         self.assertTableStruct(service_list, ['Binary', 'Host', 'Zone',
-                                              'Status', 'State', 'Updated_at',
-                                              'Disabled Reason'])
+                                              'Status', 'State', 'Updated_at'])
 
     def test_cinder_transfer_list(self):
         transfer_list = self.parser.listing(self.cinder('transfer-list'))
diff --git a/tempest/clients.py b/tempest/clients.py
index 2b8b6fb..756614d 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -13,9 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import keystoneclient.exceptions
-import keystoneclient.v2_0.client
-
 from tempest import auth
 from tempest.common import rest_client
 from tempest import config
@@ -151,6 +148,8 @@
 from tempest.services.identity.xml.identity_client import TokenClientXML
 from tempest.services.image.v1.json.image_client import ImageClientJSON
 from tempest.services.image.v2.json.image_client import ImageClientV2JSON
+from tempest.services.messaging.json.messaging_client import \
+    MessagingClientJSON
 from tempest.services.network.json.network_client import NetworkClientJSON
 from tempest.services.network.xml.network_client import NetworkClientXML
 from tempest.services.object_storage.account_client import AccountClient
@@ -162,7 +161,6 @@
     ObjectClientCustomizedHeader
 from tempest.services.orchestration.json.orchestration_client import \
     OrchestrationClient
-from tempest.services.queuing.json.queuing_client import QueuingClientJSON
 from tempest.services.telemetry.json.telemetry_client import \
     TelemetryClientJSON
 from tempest.services.telemetry.xml.telemetry_client import \
@@ -180,17 +178,28 @@
 from tempest.services.volume.json.backups_client import BackupsClientJSON
 from tempest.services.volume.json.extensions_client import \
     ExtensionsClientJSON as VolumeExtensionClientJSON
+from tempest.services.volume.json.qos_client import QosSpecsClientJSON
 from tempest.services.volume.json.snapshots_client import SnapshotsClientJSON
 from tempest.services.volume.json.volumes_client import VolumesClientJSON
+from tempest.services.volume.v2.json.admin.volume_hosts_client import \
+    VolumeHostsV2ClientJSON
+from tempest.services.volume.v2.json.admin.volume_types_client import \
+    VolumeTypesV2ClientJSON
 from tempest.services.volume.v2.json.availability_zone_client import \
     VolumeV2AvailabilityZoneClientJSON
+from tempest.services.volume.v2.json.backups_client import BackupsClientV2JSON
 from tempest.services.volume.v2.json.extensions_client import \
     ExtensionsV2ClientJSON as VolumeV2ExtensionClientJSON
+from tempest.services.volume.v2.json.qos_client import QosSpecsV2ClientJSON
+from tempest.services.volume.v2.json.snapshots_client import \
+    SnapshotsV2ClientJSON
 from tempest.services.volume.v2.json.volumes_client import VolumesV2ClientJSON
 from tempest.services.volume.v2.xml.availability_zone_client import \
     VolumeV2AvailabilityZoneClientXML
 from tempest.services.volume.v2.xml.extensions_client import \
     ExtensionsV2ClientXML as VolumeV2ExtensionClientXML
+from tempest.services.volume.v2.xml.snapshots_client import \
+    SnapshotsV2ClientXML
 from tempest.services.volume.v2.xml.volumes_client import VolumesV2ClientXML
 from tempest.services.volume.xml.admin.volume_hosts_client import \
     VolumeHostsClientXML
@@ -221,180 +230,33 @@
     def __init__(self, credentials=None, interface='json', service=None):
         # Set interface and client type first
         self.interface = interface
-        self.client_type = 'tempest'
         # super cares for credentials validation
         super(Manager, self).__init__(credentials=credentials)
 
+        self._set_compute_clients(self.interface)
+        self._set_identity_clients(self.interface)
+        self._set_volume_clients(self.interface)
+
         if self.interface == 'xml':
-            self.certificates_client = CertificatesClientXML(
-                self.auth_provider)
-            self.servers_client = ServersClientXML(self.auth_provider)
-            self.limits_client = LimitsClientXML(self.auth_provider)
-            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(
-                self.auth_provider)
-            self.floating_ips_client = FloatingIPsClientXML(
-                self.auth_provider)
-            self.backups_client = BackupsClientXML(self.auth_provider)
-            self.snapshots_client = SnapshotsClientXML(self.auth_provider)
-            self.volumes_client = VolumesClientXML(self.auth_provider)
-            self.volumes_v2_client = VolumesV2ClientXML(self.auth_provider)
-            self.volume_types_client = VolumeTypesClientXML(
-                self.auth_provider)
-            self.identity_client = IdentityClientXML(self.auth_provider)
-            self.identity_v3_client = IdentityV3ClientXML(
-                self.auth_provider)
-            self.security_groups_client = SecurityGroupsClientXML(
-                self.auth_provider)
-            self.interfaces_client = InterfacesClientXML(self.auth_provider)
-            self.endpoints_client = EndPointClientXML(self.auth_provider)
-            self.fixed_ips_client = FixedIPsClientXML(self.auth_provider)
-            self.availability_zone_client = AvailabilityZoneClientXML(
-                self.auth_provider)
-            self.service_client = ServiceClientXML(self.auth_provider)
-            self.volume_services_client = VolumesServicesClientXML(
-                self.auth_provider)
-            self.aggregates_client = AggregatesClientXML(self.auth_provider)
-            self.services_client = ServicesClientXML(self.auth_provider)
-            self.tenant_usages_client = TenantUsagesClientXML(
-                self.auth_provider)
-            self.policy_client = PolicyClientXML(self.auth_provider)
-            self.region_client = RegionClientXML(self.auth_provider)
-            self.hosts_client = HostsClientXML(self.auth_provider)
-            self.hypervisor_client = HypervisorClientXML(self.auth_provider)
             self.network_client = NetworkClientXML(self.auth_provider)
-            self.credentials_client = CredentialsClientXML(
-                self.auth_provider)
-            self.instance_usages_audit_log_client = \
-                InstanceUsagesAuditLogClientXML(self.auth_provider)
-            self.volume_hosts_client = VolumeHostsClientXML(
-                self.auth_provider)
-            self.volume_quotas_client = VolumeQuotasClientXML(
-                self.auth_provider)
-            self.volumes_extension_client = VolumeExtensionClientXML(
-                self.auth_provider)
-            self.volumes_v2_extension_client = VolumeV2ExtensionClientXML(
-                self.auth_provider)
             if CONF.service_available.ceilometer:
                 self.telemetry_client = TelemetryClientXML(
                     self.auth_provider)
-            self.token_client = TokenClientXML()
-            self.token_v3_client = V3TokenClientXML()
-            self.volume_availability_zone_client = \
-                VolumeAvailabilityZoneClientXML(self.auth_provider)
-            self.volume_v2_availability_zone_client = \
-                VolumeV2AvailabilityZoneClientXML(self.auth_provider)
 
         elif self.interface == 'json':
-            self.certificates_client = CertificatesClientJSON(
-                self.auth_provider)
-            self.certificates_v3_client = CertificatesV3ClientJSON(
-                self.auth_provider)
             self.baremetal_client = BaremetalClientJSON(self.auth_provider)
-            self.servers_client = ServersClientJSON(self.auth_provider)
-            self.servers_v3_client = ServersV3ClientJSON(self.auth_provider)
-            self.limits_client = LimitsClientJSON(self.auth_provider)
-            self.images_client = ImagesClientJSON(self.auth_provider)
-            self.keypairs_v3_client = KeyPairsV3ClientJSON(
-                self.auth_provider)
-            self.keypairs_client = KeyPairsClientJSON(self.auth_provider)
-            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)
-            self.extensions_v3_client = ExtensionsV3ClientJSON(
-                self.auth_provider)
-            self.extensions_client = ExtensionsClientJSON(
-                self.auth_provider)
-            self.volumes_extensions_client = VolumesExtensionsClientJSON(
-                self.auth_provider)
-            self.floating_ips_client = FloatingIPsClientJSON(
-                self.auth_provider)
-            self.backups_client = BackupsClientJSON(self.auth_provider)
-            self.snapshots_client = SnapshotsClientJSON(self.auth_provider)
-            self.volumes_client = VolumesClientJSON(self.auth_provider)
-            self.volumes_v2_client = VolumesV2ClientJSON(self.auth_provider)
-            self.volume_types_client = VolumeTypesClientJSON(
-                self.auth_provider)
-            self.identity_client = IdentityClientJSON(self.auth_provider)
-            self.identity_v3_client = IdentityV3ClientJSON(
-                self.auth_provider)
-            self.security_groups_client = SecurityGroupsClientJSON(
-                self.auth_provider)
-            self.interfaces_v3_client = InterfacesV3ClientJSON(
-                self.auth_provider)
-            self.interfaces_client = InterfacesClientJSON(
-                self.auth_provider)
-            self.endpoints_client = EndPointClientJSON(self.auth_provider)
-            self.fixed_ips_client = FixedIPsClientJSON(self.auth_provider)
-            self.availability_zone_v3_client = AvailabilityZoneV3ClientJSON(
-                self.auth_provider)
-            self.availability_zone_client = AvailabilityZoneClientJSON(
-                self.auth_provider)
-            self.services_v3_client = ServicesV3ClientJSON(
-                self.auth_provider)
-            self.service_client = ServiceClientJSON(self.auth_provider)
-            self.volume_services_client = VolumesServicesClientJSON(
-                self.auth_provider)
-            self.agents_v3_client = AgentsV3ClientJSON(self.auth_provider)
-            self.aggregates_v3_client = AggregatesV3ClientJSON(
-                self.auth_provider)
-            self.aggregates_client = AggregatesClientJSON(
-                self.auth_provider)
-            self.services_client = ServicesClientJSON(self.auth_provider)
-            self.tenant_usages_client = TenantUsagesClientJSON(
-                self.auth_provider)
-            self.version_v3_client = VersionV3ClientJSON(self.auth_provider)
-            self.migrations_v3_client = MigrationsV3ClientJSON(
-                self.auth_provider)
-            self.policy_client = PolicyClientJSON(self.auth_provider)
-            self.region_client = RegionClientJSON(self.auth_provider)
-            self.hosts_client = HostsClientJSON(self.auth_provider)
-            self.hypervisor_v3_client = HypervisorV3ClientJSON(
-                self.auth_provider)
-            self.hypervisor_client = HypervisorClientJSON(
-                self.auth_provider)
             self.network_client = NetworkClientJSON(self.auth_provider)
-            self.credentials_client = CredentialsClientJSON(
-                self.auth_provider)
-            self.instance_usages_audit_log_client = \
-                InstanceUsagesAuditLogClientJSON(self.auth_provider)
-            self.volume_hosts_client = VolumeHostsClientJSON(
-                self.auth_provider)
-            self.volume_quotas_client = VolumeQuotasClientJSON(
-                self.auth_provider)
-            self.volumes_extension_client = VolumeExtensionClientJSON(
-                self.auth_provider)
-            self.volumes_v2_extension_client = VolumeV2ExtensionClientJSON(
-                self.auth_provider)
-            self.hosts_v3_client = HostsV3ClientJSON(self.auth_provider)
             self.database_flavors_client = DatabaseFlavorsClientJSON(
                 self.auth_provider)
             self.database_versions_client = DatabaseVersionsClientJSON(
                 self.auth_provider)
-            self.queuing_client = QueuingClientJSON(self.auth_provider)
+            self.messaging_client = MessagingClientJSON(self.auth_provider)
             if CONF.service_available.ceilometer:
                 self.telemetry_client = TelemetryClientJSON(
                     self.auth_provider)
-            self.token_client = TokenClientJSON()
-            self.token_v3_client = V3TokenClientJSON()
             self.negative_client = rest_client.NegativeRestClient(
                 self.auth_provider)
             self.negative_client.service = service
-            self.volume_availability_zone_client = \
-                VolumeAvailabilityZoneClientJSON(self.auth_provider)
-            self.volume_v2_availability_zone_client = \
-                VolumeV2AvailabilityZoneClientJSON(self.auth_provider)
 
         else:
             msg = "Unsupported interface type `%s'" % interface
@@ -408,7 +270,6 @@
 
         # common clients
         self.account_client = AccountClient(self.auth_provider)
-        self.agents_client = AgentsClientJSON(self.auth_provider)
         if CONF.service_available.glance:
             self.image_client = ImageClientJSON(self.auth_provider)
             self.image_client_v2 = ImageClientV2JSON(self.auth_provider)
@@ -424,24 +285,180 @@
             AccountClientCustomizedHeader(self.auth_provider)
         self.data_processing_client = DataProcessingClient(
             self.auth_provider)
+
+    def _set_compute_clients(self, type):
+        if type == 'json':
+            self._set_compute_json_clients()
+        else:
+            self._set_compute_xml_clients()
+
+        # Common compute clients
+        self.agents_client = AgentsClientJSON(self.auth_provider)
+        self.networks_client = NetworksClientJSON(self.auth_provider)
         self.migrations_client = MigrationsClientJSON(self.auth_provider)
         self.security_group_default_rules_client = (
             SecurityGroupDefaultRulesClientJSON(self.auth_provider))
-        self.networks_client = NetworksClientJSON(self.auth_provider)
 
+    def _set_compute_xml_clients(self):
+        self.certificates_client = CertificatesClientXML(self.auth_provider)
+        self.servers_client = ServersClientXML(self.auth_provider)
+        self.limits_client = LimitsClientXML(self.auth_provider)
+        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(
+            self.auth_provider)
+        self.floating_ips_client = FloatingIPsClientXML(self.auth_provider)
+        self.security_groups_client = SecurityGroupsClientXML(
+            self.auth_provider)
+        self.interfaces_client = InterfacesClientXML(self.auth_provider)
+        self.fixed_ips_client = FixedIPsClientXML(self.auth_provider)
+        self.availability_zone_client = AvailabilityZoneClientXML(
+            self.auth_provider)
+        self.aggregates_client = AggregatesClientXML(self.auth_provider)
+        self.services_client = ServicesClientXML(self.auth_provider)
+        self.tenant_usages_client = TenantUsagesClientXML(self.auth_provider)
+        self.hosts_client = HostsClientXML(self.auth_provider)
+        self.hypervisor_client = HypervisorClientXML(self.auth_provider)
+        self.instance_usages_audit_log_client = \
+            InstanceUsagesAuditLogClientXML(self.auth_provider)
 
-class AltManager(Manager):
+    def _set_compute_json_clients(self):
+        self.certificates_client = CertificatesClientJSON(self.auth_provider)
+        self.certificates_v3_client = CertificatesV3ClientJSON(
+            self.auth_provider)
+        self.servers_client = ServersClientJSON(self.auth_provider)
+        self.servers_v3_client = ServersV3ClientJSON(self.auth_provider)
+        self.limits_client = LimitsClientJSON(self.auth_provider)
+        self.images_client = ImagesClientJSON(self.auth_provider)
+        self.keypairs_client = KeyPairsClientJSON(self.auth_provider)
+        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)
+        self.extensions_client = ExtensionsClientJSON(self.auth_provider)
+        self.extensions_v3_client = ExtensionsV3ClientJSON(self.auth_provider)
+        self.volumes_extensions_client = VolumesExtensionsClientJSON(
+            self.auth_provider)
+        self.floating_ips_client = FloatingIPsClientJSON(self.auth_provider)
+        self.security_groups_client = SecurityGroupsClientJSON(
+            self.auth_provider)
+        self.interfaces_client = InterfacesClientJSON(self.auth_provider)
+        self.interfaces_v3_client = InterfacesV3ClientJSON(self.auth_provider)
+        self.fixed_ips_client = FixedIPsClientJSON(self.auth_provider)
+        self.availability_zone_client = AvailabilityZoneClientJSON(
+            self.auth_provider)
+        self.availability_zone_v3_client = AvailabilityZoneV3ClientJSON(
+            self.auth_provider)
+        self.services_v3_client = ServicesV3ClientJSON(self.auth_provider)
+        self.agents_v3_client = AgentsV3ClientJSON(self.auth_provider)
+        self.aggregates_client = AggregatesClientJSON(self.auth_provider)
+        self.aggregates_v3_client = AggregatesV3ClientJSON(self.auth_provider)
+        self.services_client = ServicesClientJSON(self.auth_provider)
+        self.tenant_usages_client = TenantUsagesClientJSON(self.auth_provider)
+        self.version_v3_client = VersionV3ClientJSON(self.auth_provider)
+        self.migrations_v3_client = MigrationsV3ClientJSON(self.auth_provider)
+        self.hosts_client = HostsClientJSON(self.auth_provider)
+        self.hosts_v3_client = HostsV3ClientJSON(self.auth_provider)
+        self.hypervisor_client = HypervisorClientJSON(self.auth_provider)
+        self.hypervisor_v3_client = HypervisorV3ClientJSON(self.auth_provider)
+        self.instance_usages_audit_log_client = \
+            InstanceUsagesAuditLogClientJSON(self.auth_provider)
 
-    """
-    Manager object that uses the alt_XXX credentials for its
-    managed client objects
-    """
+    def _set_identity_clients(self, type):
+        if type == 'json':
+            self._set_identity_json_clients()
+        else:
+            self._set_identity_xml_clients()
 
-    def __init__(self, interface='json', service=None):
-        super(AltManager, self).__init__(
-            credentials=auth.get_default_credentials('alt_user'),
-            interface=interface,
-            service=service)
+    def _set_identity_xml_clients(self):
+        self.identity_client = IdentityClientXML(self.auth_provider)
+        self.identity_v3_client = IdentityV3ClientXML(self.auth_provider)
+        self.endpoints_client = EndPointClientXML(self.auth_provider)
+        self.service_client = ServiceClientXML(self.auth_provider)
+        self.policy_client = PolicyClientXML(self.auth_provider)
+        self.region_client = RegionClientXML(self.auth_provider)
+        self.token_client = TokenClientXML()
+        if CONF.identity_feature_enabled.api_v3:
+            self.token_v3_client = V3TokenClientXML()
+        self.credentials_client = CredentialsClientXML(self.auth_provider)
+
+    def _set_identity_json_clients(self):
+        self.identity_client = IdentityClientJSON(self.auth_provider)
+        self.identity_v3_client = IdentityV3ClientJSON(self.auth_provider)
+        self.endpoints_client = EndPointClientJSON(self.auth_provider)
+        self.service_client = ServiceClientJSON(self.auth_provider)
+        self.policy_client = PolicyClientJSON(self.auth_provider)
+        self.region_client = RegionClientJSON(self.auth_provider)
+        self.token_client = TokenClientJSON()
+        if CONF.identity_feature_enabled.api_v3:
+            self.token_v3_client = V3TokenClientJSON()
+        self.credentials_client = CredentialsClientJSON(self.auth_provider)
+
+    def _set_volume_clients(self, type):
+        if type == 'json':
+            self._set_volume_json_clients()
+        else:
+            self._set_volume_xml_clients()
+
+        # Common volume clients
+        # NOTE : As XML clients are not implemented for Qos-specs.
+        # So, setting the qos_client here. Once client are implemented,
+        # qos_client would be moved to its respective if/else.
+        # Bug : 1312553
+        self.volume_qos_client = QosSpecsClientJSON(self.auth_provider)
+        self.volume_qos_v2_client = QosSpecsV2ClientJSON(
+            self.auth_provider)
+
+    def _set_volume_xml_clients(self):
+        self.backups_client = BackupsClientXML(self.auth_provider)
+        self.snapshots_client = SnapshotsClientXML(self.auth_provider)
+        self.snapshots_v2_client = SnapshotsV2ClientXML(self.auth_provider)
+        self.volumes_client = VolumesClientXML(self.auth_provider)
+        self.volumes_v2_client = VolumesV2ClientXML(self.auth_provider)
+        self.volume_types_client = VolumeTypesClientXML(self.auth_provider)
+        self.volume_services_client = VolumesServicesClientXML(
+            self.auth_provider)
+        self.volume_hosts_client = VolumeHostsClientXML(self.auth_provider)
+        self.volume_quotas_client = VolumeQuotasClientXML(self.auth_provider)
+        self.volumes_extension_client = VolumeExtensionClientXML(
+            self.auth_provider)
+        self.volumes_v2_extension_client = VolumeV2ExtensionClientXML(
+            self.auth_provider)
+        self.volume_availability_zone_client = \
+            VolumeAvailabilityZoneClientXML(self.auth_provider)
+        self.volume_v2_availability_zone_client = \
+            VolumeV2AvailabilityZoneClientXML(self.auth_provider)
+
+    def _set_volume_json_clients(self):
+        self.backups_client = BackupsClientJSON(self.auth_provider)
+        self.backups_v2_client = BackupsClientV2JSON(self.auth_provider)
+        self.snapshots_client = SnapshotsClientJSON(self.auth_provider)
+        self.snapshots_v2_client = SnapshotsV2ClientJSON(self.auth_provider)
+        self.volumes_client = VolumesClientJSON(self.auth_provider)
+        self.volumes_v2_client = VolumesV2ClientJSON(self.auth_provider)
+        self.volume_types_client = VolumeTypesClientJSON(self.auth_provider)
+        self.volume_services_client = VolumesServicesClientJSON(
+            self.auth_provider)
+        self.volume_hosts_client = VolumeHostsClientJSON(self.auth_provider)
+        self.volume_hosts_v2_client = VolumeHostsV2ClientJSON(
+            self.auth_provider)
+        self.volume_quotas_client = VolumeQuotasClientJSON(self.auth_provider)
+        self.volumes_extension_client = VolumeExtensionClientJSON(
+            self.auth_provider)
+        self.volumes_v2_extension_client = VolumeV2ExtensionClientJSON(
+            self.auth_provider)
+        self.volume_availability_zone_client = \
+            VolumeAvailabilityZoneClientJSON(self.auth_provider)
+        self.volume_v2_availability_zone_client = \
+            VolumeV2AvailabilityZoneClientJSON(self.auth_provider)
+        self.volume_types_v2_client = VolumeTypesV2ClientJSON(
+            self.auth_provider)
 
 
 class AdminManager(Manager):
@@ -471,290 +488,3 @@
             credentials=auth.get_default_credentials('compute_admin'),
             interface=interface,
             service=service)
-
-
-class OfficialClientManager(manager.Manager):
-    """
-    Manager that provides access to the official python clients for
-    calling various OpenStack APIs.
-    """
-
-    NOVACLIENT_VERSION = '2'
-    CINDERCLIENT_VERSION = '1'
-    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
-        # not implemented yet, setting to 'tempest' for now.
-        self.client_type = 'tempest'
-        self.interface = None
-        # super cares for credentials validation
-        super(OfficialClientManager, self).__init__(credentials=credentials)
-        self.baremetal_client = self._get_baremetal_client()
-        self.compute_client = self._get_compute_client(credentials)
-        self.identity_client = self._get_identity_client(credentials)
-        self.image_client = self._get_image_client()
-        self.network_client = self._get_network_client()
-        self.volume_client = self._get_volume_client(credentials)
-        self.object_storage_client = self._get_object_storage_client(
-            credentials)
-        self.orchestration_client = self._get_orchestration_client(
-            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')
-        keystone_admin = self._get_identity_client(admin_credentials)
-
-        username = self.credentials.username
-        tenant_name = self.credentials.tenant_name
-        user_id = keystone_admin.users.find(name=username).id
-        tenant_id = keystone_admin.tenants.find(name=tenant_name).id
-
-        roles = keystone_admin.roles.roles_for_user(
-            user=user_id, tenant=tenant_id)
-
-        return [r.name for r in roles]
-
-    def _get_compute_client(self, credentials):
-        # Novaclient will not execute operations for anyone but the
-        # identified user, so a new client needs to be created for
-        # each user that operations need to be performed for.
-        if not CONF.service_available.nova:
-            return None
-        import novaclient.client
-
-        auth_url = CONF.identity.uri
-        dscv = CONF.identity.disable_ssl_certificate_validation
-        region = CONF.identity.region
-
-        client_args = (credentials.username, credentials.password,
-                       credentials.tenant_name, auth_url)
-
-        # Create our default Nova client to use in testing
-        service_type = CONF.compute.catalog_type
-        endpoint_type = CONF.compute.endpoint_type
-        return novaclient.client.Client(self.NOVACLIENT_VERSION,
-                                        *client_args,
-                                        service_type=service_type,
-                                        endpoint_type=endpoint_type,
-                                        region_name=region,
-                                        no_cache=True,
-                                        insecure=dscv,
-                                        http_log_debug=True)
-
-    def _get_image_client(self):
-        if not CONF.service_available.glance:
-            return None
-        import glanceclient
-        token = self.identity_client.auth_token
-        region = CONF.identity.region
-        endpoint_type = CONF.image.endpoint_type
-        endpoint = self.identity_client.service_catalog.url_for(
-            attr='region', filter_value=region,
-            service_type=CONF.image.catalog_type, endpoint_type=endpoint_type)
-        dscv = CONF.identity.disable_ssl_certificate_validation
-        return glanceclient.Client('1', endpoint=endpoint, token=token,
-                                   insecure=dscv)
-
-    def _get_volume_client(self, credentials):
-        if not CONF.service_available.cinder:
-            return None
-        import cinderclient.client
-        auth_url = CONF.identity.uri
-        region = CONF.identity.region
-        endpoint_type = CONF.volume.endpoint_type
-        dscv = CONF.identity.disable_ssl_certificate_validation
-        return cinderclient.client.Client(self.CINDERCLIENT_VERSION,
-                                          credentials.username,
-                                          credentials.password,
-                                          credentials.tenant_name,
-                                          auth_url,
-                                          region_name=region,
-                                          endpoint_type=endpoint_type,
-                                          insecure=dscv,
-                                          http_log_debug=True)
-
-    def _get_object_storage_client(self, credentials):
-        if not CONF.service_available.swift:
-            return None
-        import swiftclient
-        auth_url = CONF.identity.uri
-        # add current tenant to swift operator role group.
-        admin_credentials = auth.get_default_credentials('identity_admin')
-        keystone_admin = self._get_identity_client(admin_credentials)
-
-        # enable test user to operate swift by adding operator role to him.
-        roles = keystone_admin.roles.list()
-        operator_role = CONF.object_storage.operator_role
-        member_role = [role for role in roles if role.name == operator_role][0]
-        # NOTE(maurosr): This is surrounded in the try-except block cause
-        # neutron tests doesn't have tenant isolation.
-        try:
-            keystone_admin.roles.add_user_role(self.identity_client.user_id,
-                                               member_role.id,
-                                               self.identity_client.tenant_id)
-        except keystoneclient.exceptions.Conflict:
-            pass
-
-        endpoint_type = CONF.object_storage.endpoint_type
-        os_options = {'endpoint_type': endpoint_type}
-        return swiftclient.Connection(auth_url, credentials.username,
-                                      credentials.password,
-                                      tenant_name=credentials.tenant_name,
-                                      auth_version='2',
-                                      os_options=os_options)
-
-    def _get_orchestration_client(self, credentials):
-        if not CONF.service_available.heat:
-            return None
-        import heatclient.client
-
-        keystone = self._get_identity_client(credentials)
-        region = CONF.identity.region
-        endpoint_type = CONF.orchestration.endpoint_type
-        token = keystone.auth_token
-        service_type = CONF.orchestration.catalog_type
-        try:
-            endpoint = 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 heatclient.client.Client(self.HEATCLIENT_VERSION,
-                                            endpoint,
-                                            token=token,
-                                            username=credentials.username,
-                                            password=credentials.password)
-
-    def _get_identity_client(self, credentials):
-        # This identity client is not intended to check the security
-        # of the identity service, so use admin credentials by default.
-
-        auth_url = CONF.identity.uri
-        dscv = CONF.identity.disable_ssl_certificate_validation
-
-        return keystoneclient.v2_0.client.Client(
-            username=credentials.username,
-            password=credentials.password,
-            tenant_name=credentials.tenant_name,
-            auth_url=auth_url,
-            insecure=dscv)
-
-    def _get_baremetal_client(self):
-        # ironic client is currently intended to by used by admin users
-        if not CONF.service_available.ironic:
-            return None
-        import ironicclient.client
-        roles = self._get_roles()
-        if CONF.identity.admin_role not in roles:
-            return None
-
-        auth_url = CONF.identity.uri
-        api_version = self.IRONICCLIENT_VERSION
-        insecure = CONF.identity.disable_ssl_certificate_validation
-        service_type = CONF.baremetal.catalog_type
-        endpoint_type = CONF.baremetal.endpoint_type
-        creds = {
-            'os_username': self.credentials.username,
-            'os_password': self.credentials.password,
-            'os_tenant_name': self.credentials.tenant_name
-        }
-
-        try:
-            return ironicclient.client.get_client(
-                api_version=api_version,
-                os_auth_url=auth_url,
-                insecure=insecure,
-                os_service_type=service_type,
-                os_endpoint_type=endpoint_type,
-                **creds)
-        except keystoneclient.exceptions.EndpointNotFound:
-            return None
-
-    def _get_network_client(self):
-        # The intended configuration is for the network client to have
-        # admin privileges and indicate for whom resources are being
-        # created via a 'tenant_id' parameter.  This will often be
-        # preferable to authenticating as a specific user because
-        # working with certain resources (public routers and networks)
-        # often requires admin privileges anyway.
-        if not CONF.service_available.neutron:
-            return None
-        import neutronclient.v2_0.client
-
-        credentials = auth.get_default_credentials('identity_admin')
-
-        auth_url = CONF.identity.uri
-        dscv = CONF.identity.disable_ssl_certificate_validation
-        endpoint_type = CONF.network.endpoint_type
-
-        return neutronclient.v2_0.client.Client(
-            username=credentials.username,
-            password=credentials.password,
-            tenant_name=credentials.tenant_name,
-            endpoint_type=endpoint_type,
-            auth_url=auth_url,
-            insecure=dscv)
-
-    def _get_data_processing_client(self, credentials):
-        if not CONF.service_available.sahara:
-            # Sahara isn't available
-            return None
-
-        import saharaclient.client
-
-        endpoint_type = CONF.data_processing.endpoint_type
-        catalog_type = CONF.data_processing.catalog_type
-        auth_url = CONF.identity.uri
-
-        client = saharaclient.client.Client(
-            self.SAHARACLIENT_VERSION,
-            credentials.username,
-            credentials.password,
-            project_name=credentials.tenant_name,
-            endpoint_type=endpoint_type,
-            service_type=catalog_type,
-            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/cleanup.py b/tempest/cmd/cleanup.py
new file mode 100755
index 0000000..a305e42
--- /dev/null
+++ b/tempest/cmd/cleanup.py
@@ -0,0 +1,300 @@
+#!/usr/bin/env python
+#
+# Copyright 2014 Dell 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.
+
+"""
+Utility for cleaning up environment after Tempest run
+
+Runtime Arguments
+-----------------
+
+--init-saved-state: Before you can execute cleanup you must initialize
+the saved state by running it with the --init-saved-state flag
+(creating ./saved_state.json), which protects your deployment from
+cleanup deleting objects you want to keep.  Typically you would run
+cleanup with --init-saved-state prior to a tempest run. If this is not
+the case saved_state.json must be edited, removing objects you want
+cleanup to delete.
+
+--dry-run: Creates a report (dry_run.json) of the tenants that will be
+cleaned up (in the "_tenants_to_clean" array), and the global objects
+that will be removed (tenants, users, flavors and images).  Once
+cleanup is executed in normal mode, running it again with --dry-run
+should yield an empty report.
+
+**NOTE**: The _tenants_to_clean array in dry-run.json lists the
+tenants that cleanup will loop through and delete child objects, not
+delete the tenant itself. This may differ from the tenants array as you
+can clean the tempest and alternate tempest tenants but not delete the
+tenants themselves.  This is actually the default behavior.
+
+**Normal mode**: running with no arguments, will query your deployment and
+build a list of objects to delete after filtering out out the objects
+found in saved_state.json and based on the
+--preserve-tempest-conf-objects and
+--delete-tempest-conf-objects flags.
+
+By default the tempest and alternate tempest users and tenants are not
+deleted and the admin user specified in tempest.conf is never deleted.
+
+Please run with --help to see full list of options.
+"""
+import argparse
+import json
+import sys
+
+from tempest import auth
+from tempest import clients
+from tempest.cmd import cleanup_service
+from tempest import config
+from tempest.openstack.common import log as logging
+
+SAVED_STATE_JSON = "saved_state.json"
+DRY_RUN_JSON = "dry_run.json"
+LOG = logging.getLogger(__name__)
+CONF = config.CONF
+
+
+class Cleanup(object):
+
+    def __init__(self):
+        self.admin_mgr = clients.AdminManager()
+        self.dry_run_data = {}
+        self.json_data = {}
+        self._init_options()
+
+        self.admin_id = ""
+        self.admin_role_id = ""
+        self.admin_tenant_id = ""
+        self._init_admin_ids()
+
+        self.admin_role_added = []
+
+        # available services
+        self.tenant_services = cleanup_service.get_tenant_cleanup_services()
+        self.global_services = cleanup_service.get_global_cleanup_services()
+        cleanup_service.init_conf()
+
+    def run(self):
+        opts = self.options
+        if opts.init_saved_state:
+            self._init_state()
+            return
+
+        self._load_json()
+        self._cleanup()
+
+    def _cleanup(self):
+        LOG.debug("Begin cleanup")
+        is_dry_run = self.options.dry_run
+        is_preserve = self.options.preserve_tempest_conf_objects
+        is_save_state = False
+
+        if is_dry_run:
+            self.dry_run_data["_tenants_to_clean"] = {}
+            f = open(DRY_RUN_JSON, 'w+')
+
+        admin_mgr = self.admin_mgr
+        # Always cleanup tempest and alt tempest tenants unless
+        # they are in saved state json. Therefore is_preserve is False
+        kwargs = {'data': self.dry_run_data,
+                  'is_dry_run': is_dry_run,
+                  'saved_state_json': self.json_data,
+                  'is_preserve': False,
+                  'is_save_state': is_save_state}
+        tenant_service = cleanup_service.TenantService(admin_mgr, **kwargs)
+        tenants = tenant_service.list()
+        LOG.debug("Process %s tenants" % len(tenants))
+
+        # Loop through list of tenants and clean them up.
+        for tenant in tenants:
+            self._add_admin(tenant['id'])
+            self._clean_tenant(tenant)
+
+        kwargs = {'data': self.dry_run_data,
+                  'is_dry_run': is_dry_run,
+                  'saved_state_json': self.json_data,
+                  'is_preserve': is_preserve,
+                  'is_save_state': is_save_state}
+        for service in self.global_services:
+            svc = service(admin_mgr, **kwargs)
+            svc.run()
+
+        if is_dry_run:
+            f.write(json.dumps(self.dry_run_data, sort_keys=True,
+                               indent=2, separators=(',', ': ')))
+            f.close()
+
+        self._remove_admin_user_roles()
+
+    def _remove_admin_user_roles(self):
+        tenant_ids = self.admin_role_added
+        LOG.debug("Removing admin user roles where needed for tenants: %s"
+                  % tenant_ids)
+        for tenant_id in tenant_ids:
+            self._remove_admin_role(tenant_id)
+
+    def _clean_tenant(self, tenant):
+        LOG.debug("Cleaning tenant:  %s " % tenant['name'])
+        is_dry_run = self.options.dry_run
+        dry_run_data = self.dry_run_data
+        is_preserve = self.options.preserve_tempest_conf_objects
+        tenant_id = tenant['id']
+        tenant_name = tenant['name']
+        tenant_data = None
+        if is_dry_run:
+            tenant_data = dry_run_data["_tenants_to_clean"][tenant_id] = {}
+            tenant_data['name'] = tenant_name
+
+        kwargs = {"username": CONF.identity.admin_username,
+                  "password": CONF.identity.admin_password,
+                  "tenant_name": tenant['name']}
+        mgr = clients.Manager(credentials=auth.get_credentials(**kwargs))
+        kwargs = {'data': tenant_data,
+                  'is_dry_run': is_dry_run,
+                  'saved_state_json': None,
+                  'is_preserve': is_preserve,
+                  'is_save_state': False,
+                  'tenant_id': tenant_id}
+        for service in self.tenant_services:
+            svc = service(mgr, **kwargs)
+            svc.run()
+
+    def _init_admin_ids(self):
+        id_cl = self.admin_mgr.identity_client
+
+        tenant = id_cl.get_tenant_by_name(CONF.identity.admin_tenant_name)
+        self.admin_tenant_id = tenant['id']
+
+        user = id_cl.get_user_by_username(self.admin_tenant_id,
+                                          CONF.identity.admin_username)
+        self.admin_id = user['id']
+
+        _, roles = id_cl.list_roles()
+        for role in roles:
+            if role['name'] == CONF.identity.admin_role:
+                self.admin_role_id = role['id']
+                break
+
+    def _init_options(self):
+        parser = argparse.ArgumentParser(
+            description='Cleanup after tempest run')
+        parser.add_argument('--init-saved-state', action="store_true",
+                            dest='init_saved_state', default=False,
+                            help="Creates JSON file: " + SAVED_STATE_JSON +
+                            ", representing the current state of your "
+                            "deployment,  specifically objects types "
+                            "Tempest creates and destroys during a run. "
+                            "You must run with this flag prior to "
+                            "executing cleanup.")
+        parser.add_argument('--preserve-tempest-conf-objects',
+                            action="store_true",
+                            dest='preserve_tempest_conf_objects',
+                            default=True, help="Do not delete the "
+                            "tempest and alternate tempest users and "
+                            "tenants, so they may be used for future "
+                            "tempest runs. By default this is argument "
+                            "is true.")
+        parser.add_argument('--delete-tempest-conf-objects',
+                            action="store_false",
+                            dest='preserve_tempest_conf_objects',
+                            default=False,
+                            help="Delete the tempest and "
+                            "alternate tempest users and tenants.")
+        parser.add_argument('--dry-run', action="store_true",
+                            dest='dry_run', default=False,
+                            help="Generate JSON file:" + DRY_RUN_JSON +
+                            ", that reports the objects that would have "
+                            "been deleted had a full cleanup been run.")
+
+        self.options = parser.parse_args()
+
+    def _add_admin(self, tenant_id):
+        id_cl = self.admin_mgr.identity_client
+        needs_role = True
+        _, roles = id_cl.list_user_roles(tenant_id, self.admin_id)
+        for role in roles:
+            if role['id'] == self.admin_role_id:
+                needs_role = False
+                LOG.debug("User already had admin privilege for this tenant")
+        if needs_role:
+            LOG.debug("Adding admin priviledge for : %s" % tenant_id)
+            id_cl.assign_user_role(tenant_id, self.admin_id,
+                                   self.admin_role_id)
+            self.admin_role_added.append(tenant_id)
+
+    def _remove_admin_role(self, tenant_id):
+        LOG.debug("Remove admin user role for tenant: %s" % tenant_id)
+        # Must initialize AdminManager for each user role
+        # Otherwise authentication exception is thrown, weird
+        id_cl = clients.AdminManager().identity_client
+        if (self._tenant_exists(tenant_id)):
+            try:
+                id_cl.remove_user_role(tenant_id, self.admin_id,
+                                       self.admin_role_id)
+            except Exception as ex:
+                LOG.exception("Failed removing role from tenant which still"
+                              "exists, exception: %s" % ex)
+
+    def _tenant_exists(self, tenant_id):
+        id_cl = self.admin_mgr.identity_client
+        try:
+            t = id_cl.get_tenant(tenant_id)
+            LOG.debug("Tenant is: %s" % str(t))
+            return True
+        except Exception as ex:
+            LOG.debug("Tenant no longer exists? %s" % ex)
+            return False
+
+    def _init_state(self):
+        LOG.debug("Initializing saved state.")
+        data = {}
+        admin_mgr = self.admin_mgr
+        kwargs = {'data': data,
+                  'is_dry_run': False,
+                  'saved_state_json': data,
+                  'is_preserve': False,
+                  'is_save_state': True}
+        for service in self.global_services:
+            svc = service(admin_mgr, **kwargs)
+            svc.run()
+
+        f = open(SAVED_STATE_JSON, 'w+')
+        f.write(json.dumps(data,
+                           sort_keys=True, indent=2, separators=(',', ': ')))
+        f.close()
+
+    def _load_json(self):
+        try:
+            json_file = open(SAVED_STATE_JSON)
+            self.json_data = json.load(json_file)
+            json_file.close()
+        except IOError as ex:
+            LOG.exception("Failed loading saved state, please be sure you"
+                          " have first run cleanup with --init-saved-state "
+                          "flag prior to running tempest. Exception: %s" % ex)
+            sys.exit(ex)
+        except Exception as ex:
+            LOG.exception("Exception parsing saved state json : %s" % ex)
+            sys.exit(ex)
+
+
+def main():
+    cleanup = Cleanup()
+    cleanup.run()
+    LOG.info('Cleanup finished!')
+    return 0
+
+if __name__ == "__main__":
+    sys.exit(main())
diff --git a/tempest/cmd/cleanup_service.py b/tempest/cmd/cleanup_service.py
new file mode 100644
index 0000000..8adfbef
--- /dev/null
+++ b/tempest/cmd/cleanup_service.py
@@ -0,0 +1,1060 @@
+# Copyright 2014 Dell 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 import config
+from tempest.openstack.common import log as logging
+from tempest import test
+
+LOG = logging.getLogger(__name__)
+CONF = config.CONF
+
+CONF_USERS = None
+CONF_TENANTS = None
+CONF_PUB_NETWORK = None
+CONF_PRIV_NETWORK_NAME = None
+CONF_PUB_ROUTER = None
+CONF_FLAVORS = None
+CONF_IMAGES = None
+
+IS_CEILOMETER = None
+IS_CINDER = None
+IS_GLANCE = None
+IS_HEAT = None
+IS_NEUTRON = None
+IS_NOVA = None
+
+
+def init_conf():
+    global CONF_USERS
+    global CONF_TENANTS
+    global CONF_PUB_NETWORK
+    global CONF_PRIV_NETWORK_NAME
+    global CONF_PUB_ROUTER
+    global CONF_FLAVORS
+    global CONF_IMAGES
+
+    global IS_CEILOMETER
+    global IS_CINDER
+    global IS_GLANCE
+    global IS_HEAT
+    global IS_NEUTRON
+    global IS_NOVA
+
+    CONF_USERS = [CONF.identity.admin_username, CONF.identity.username,
+                  CONF.identity.alt_username]
+    CONF_TENANTS = [CONF.identity.admin_tenant_name,
+                    CONF.identity.tenant_name,
+                    CONF.identity.alt_tenant_name]
+    CONF_PUB_NETWORK = CONF.network.public_network_id
+    CONF_PRIV_NETWORK_NAME = CONF.compute.fixed_network_name
+    CONF_PUB_ROUTER = CONF.network.public_router_id
+    CONF_FLAVORS = [CONF.compute.flavor_ref, CONF.compute.flavor_ref_alt]
+    CONF_IMAGES = [CONF.compute.image_ref, CONF.compute.image_ref_alt]
+
+    IS_CEILOMETER = CONF.service_available.ceilometer
+    IS_CINDER = CONF.service_available.cinder
+    IS_GLANCE = CONF.service_available.glance
+    IS_HEAT = CONF.service_available.heat
+    IS_NEUTRON = CONF.service_available.neutron
+    IS_NOVA = CONF.service_available.nova
+
+
+class BaseService(object):
+    def __init__(self, kwargs):
+        self.client = None
+        for key, value in kwargs.items():
+            setattr(self, key, value)
+
+    def _filter_by_tenant_id(self, item_list):
+        if (item_list is None
+                or len(item_list) == 0
+                or not hasattr(self, 'tenant_id')
+                or self.tenant_id is None
+                or 'tenant_id' not in item_list[0]):
+            return item_list
+
+        _filtered_list = []
+        for item in item_list:
+            if item['tenant_id'] == self.tenant_id:
+                _filtered_list.append(item)
+        return _filtered_list
+
+    def list(self):
+        pass
+
+    def delete(self):
+        pass
+
+    def dry_run(self):
+        pass
+
+    def save_state(self):
+        pass
+
+    def run(self):
+        if self.is_dry_run:
+            self.dry_run()
+        elif self.is_save_state:
+            self.save_state()
+        else:
+            self.delete()
+
+
+class SnapshotService(BaseService):
+
+    def __init__(self, manager, **kwargs):
+        super(SnapshotService, self).__init__(kwargs)
+        self.client = manager.snapshots_client
+
+    def list(self):
+        client = self.client
+        __, snaps = client.list_snapshots()
+        LOG.debug("List count, %s Snapshots" % len(snaps))
+        return snaps
+
+    def delete(self):
+        snaps = self.list()
+        client = self.client
+        for snap in snaps:
+            try:
+                client.delete_snapshot(snap['id'])
+            except Exception as e:
+                LOG.exception("Delete Snapshot exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        snaps = self.list()
+        self.data['snapshots'] = snaps
+
+
+class ServerService(BaseService):
+    def __init__(self, manager, **kwargs):
+        super(ServerService, self).__init__(kwargs)
+        self.client = manager.servers_client
+
+    def list(self):
+        client = self.client
+        _, servers_body = client.list_servers()
+        servers = servers_body['servers']
+        LOG.debug("List count, %s Servers" % len(servers))
+        return servers
+
+    def delete(self):
+        client = self.client
+        servers = self.list()
+        for server in servers:
+            try:
+                client.delete_server(server['id'])
+            except Exception as e:
+                LOG.exception("Delete Server exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        servers = self.list()
+        self.data['servers'] = servers
+
+
+class ServerGroupService(ServerService):
+
+    def list(self):
+        client = self.client
+        _, sgs = client.list_server_groups()
+        LOG.debug("List count, %s Server Groups" % len(sgs))
+        return sgs
+
+    def delete(self):
+        client = self.client
+        sgs = self.list()
+        for sg in sgs:
+            try:
+                client.delete_server_group(sg['id'])
+            except Exception as e:
+                LOG.exception("Delete Server Group exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        sgs = self.list()
+        self.data['server_groups'] = sgs
+
+
+class StackService(BaseService):
+    def __init__(self, manager, **kwargs):
+        super(StackService, self).__init__(kwargs)
+        self.client = manager.orchestration_client
+
+    def list(self):
+        client = self.client
+        _, stacks = client.list_stacks()
+        LOG.debug("List count, %s Stacks" % len(stacks))
+        return stacks
+
+    def delete(self):
+        client = self.client
+        stacks = self.list()
+        for stack in stacks:
+            try:
+                client.delete_stack(stack['id'])
+            except Exception as e:
+                LOG.exception("Delete Stack exception: %s " % e)
+                pass
+
+    def dry_run(self):
+        stacks = self.list()
+        self.data['stacks'] = stacks
+
+
+class KeyPairService(BaseService):
+    def __init__(self, manager, **kwargs):
+        super(KeyPairService, self).__init__(kwargs)
+        self.client = manager.keypairs_client
+
+    def list(self):
+        client = self.client
+        _, keypairs = client.list_keypairs()
+        LOG.debug("List count, %s Keypairs" % len(keypairs))
+        return keypairs
+
+    def delete(self):
+        client = self.client
+        keypairs = self.list()
+        for k in keypairs:
+            try:
+                name = k['keypair']['name']
+                client.delete_keypair(name)
+            except Exception as e:
+                LOG.exception("Delete Keypairs exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        keypairs = self.list()
+        self.data['keypairs'] = keypairs
+
+
+class SecurityGroupService(BaseService):
+    def __init__(self, manager, **kwargs):
+        super(SecurityGroupService, self).__init__(kwargs)
+        self.client = manager.security_groups_client
+
+    def list(self):
+        client = self.client
+        _, secgrps = client.list_security_groups()
+        secgrp_del = [grp for grp in secgrps if grp['name'] != 'default']
+        LOG.debug("List count, %s Security Groups" % len(secgrp_del))
+        return secgrp_del
+
+    def delete(self):
+        client = self.client
+        secgrp_del = self.list()
+        for g in secgrp_del:
+            try:
+                client.delete_security_group(g['id'])
+            except Exception as e:
+                LOG.exception("Delete Security Groups exception: %s" % e)
+
+    def dry_run(self):
+        secgrp_del = self.list()
+        self.data['security_groups'] = secgrp_del
+
+
+class FloatingIpService(BaseService):
+    def __init__(self, manager, **kwargs):
+        super(FloatingIpService, self).__init__(kwargs)
+        self.client = manager.floating_ips_client
+
+    def list(self):
+        client = self.client
+        _, floating_ips = client.list_floating_ips()
+        LOG.debug("List count, %s Floating IPs" % len(floating_ips))
+        return floating_ips
+
+    def delete(self):
+        client = self.client
+        floating_ips = self.list()
+        for f in floating_ips:
+            try:
+                client.delete_floating_ip(f['id'])
+            except Exception as e:
+                LOG.exception("Delete Floating IPs exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        floating_ips = self.list()
+        self.data['floating_ips'] = floating_ips
+
+
+class VolumeService(BaseService):
+    def __init__(self, manager, **kwargs):
+        super(VolumeService, self).__init__(kwargs)
+        self.client = manager.volumes_client
+
+    def list(self):
+        client = self.client
+        _, vols = client.list_volumes()
+        LOG.debug("List count, %s Volumes" % len(vols))
+        return vols
+
+    def delete(self):
+        client = self.client
+        vols = self.list()
+        for v in vols:
+            try:
+                client.delete_volume(v['id'])
+            except Exception as e:
+                LOG.exception("Delete Volume exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        vols = self.list()
+        self.data['volumes'] = vols
+
+
+# Begin network service classes
+class NetworkService(BaseService):
+    def __init__(self, manager, **kwargs):
+        super(NetworkService, self).__init__(kwargs)
+        self.client = manager.network_client
+
+    def list(self):
+        client = self.client
+        _, networks = client.list_networks()
+        networks = self._filter_by_tenant_id(networks['networks'])
+        # filter out networks declared in tempest.conf
+        if self.is_preserve:
+            networks = [network for network in networks
+                        if (network['name'] != CONF_PRIV_NETWORK_NAME
+                            and network['id'] != CONF_PUB_NETWORK)]
+        LOG.debug("List count, %s Networks" % networks)
+        return networks
+
+    def delete(self):
+        client = self.client
+        networks = self.list()
+        for n in networks:
+            try:
+                client.delete_network(n['id'])
+            except Exception as e:
+                LOG.exception("Delete Network exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        networks = self.list()
+        self.data['networks'] = networks
+
+
+class NetworkIpSecPolicyService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, ipsecpols = client.list_ipsecpolicies()
+        ipsecpols = ipsecpols['ipsecpolicies']
+        ipsecpols = self._filter_by_tenant_id(ipsecpols)
+        LOG.debug("List count, %s IP Security Policies" % len(ipsecpols))
+        return ipsecpols
+
+    def delete(self):
+        client = self.client
+        ipsecpols = self.list()
+        for ipsecpol in ipsecpols:
+            try:
+                client.delete_ipsecpolicy(ipsecpol['id'])
+            except Exception as e:
+                LOG.exception("Delete IP Securty Policy exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        ipsecpols = self.list()
+        self.data['ip_security_policies'] = ipsecpols
+
+
+class NetworkFwPolicyService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, fwpols = client.list_firewall_policies()
+        fwpols = fwpols['firewall_policies']
+        fwpols = self._filter_by_tenant_id(fwpols)
+        LOG.debug("List count, %s Firewall Policies" % len(fwpols))
+        return fwpols
+
+    def delete(self):
+        client = self.client
+        fwpols = self.list()
+        for fwpol in fwpols:
+            try:
+                client.delete_firewall_policy(fwpol['id'])
+            except Exception as e:
+                LOG.exception("Delete Firewall Policy exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        fwpols = self.list()
+        self.data['firewall_policies'] = fwpols
+
+
+class NetworkFwRulesService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, fwrules = client.list_firewall_rules()
+        fwrules = fwrules['firewall_rules']
+        fwrules = self._filter_by_tenant_id(fwrules)
+        LOG.debug("List count, %s Firewall Rules" % len(fwrules))
+        return fwrules
+
+    def delete(self):
+        client = self.client
+        fwrules = self.list()
+        for fwrule in fwrules:
+            try:
+                client.delete_firewall_rule(fwrule['id'])
+            except Exception as e:
+                LOG.exception("Delete Firewall Rule exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        fwrules = self.list()
+        self.data['firewall_rules'] = fwrules
+
+
+class NetworkIkePolicyService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, ikepols = client.list_ikepolicies()
+        ikepols = ikepols['ikepolicies']
+        ikepols = self._filter_by_tenant_id(ikepols)
+        LOG.debug("List count, %s IKE Policies" % len(ikepols))
+        return ikepols
+
+    def delete(self):
+        client = self.client
+        ikepols = self.list()
+        for ikepol in ikepols:
+            try:
+                client.delete_firewall_rule(ikepol['id'])
+            except Exception as e:
+                LOG.exception("Delete IKE Policy exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        ikepols = self.list()
+        self.data['ike_policies'] = ikepols
+
+
+class NetworkVpnServiceService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, vpnsrvs = client.list_vpnservices()
+        vpnsrvs = vpnsrvs['vpnservices']
+        vpnsrvs = self._filter_by_tenant_id(vpnsrvs)
+        LOG.debug("List count, %s VPN Services" % len(vpnsrvs))
+        return vpnsrvs
+
+    def delete(self):
+        client = self.client
+        vpnsrvs = self.list()
+        for vpnsrv in vpnsrvs:
+            try:
+                client.delete_vpnservice(vpnsrv['id'])
+            except Exception as e:
+                LOG.exception("Delete VPN Service exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        vpnsrvs = self.list()
+        self.data['vpn_services'] = vpnsrvs
+
+
+class NetworkFloatingIpService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, flips = client.list_floatingips()
+        flips = flips['floatingips']
+        flips = self._filter_by_tenant_id(flips)
+        LOG.debug("List count, %s Network Floating IPs" % len(flips))
+        return flips
+
+    def delete(self):
+        client = self.client
+        flips = self.list()
+        for flip in flips:
+            try:
+                client.delete_floatingip(flip['id'])
+            except Exception as e:
+                LOG.exception("Delete Network Floating IP exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        flips = self.list()
+        self.data['floating_ips'] = flips
+
+
+class NetworkRouterService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, routers = client.list_routers()
+        routers = routers['routers']
+        routers = self._filter_by_tenant_id(routers)
+        if self.is_preserve:
+            routers = [router for router in routers
+                       if router['id'] != CONF_PUB_ROUTER]
+
+        LOG.debug("List count, %s Routers" % len(routers))
+        return routers
+
+    def delete(self):
+        client = self.client
+        routers = self.list()
+        for router in routers:
+            try:
+                rid = router['id']
+                _, ports = client.list_router_interfaces(rid)
+                ports = ports['ports']
+                for port in ports:
+                    subid = port['fixed_ips'][0]['subnet_id']
+                    client.remove_router_interface_with_subnet_id(rid, subid)
+                    client.delete_router(rid)
+            except Exception as e:
+                LOG.exception("Delete Router exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        routers = self.list()
+        self.data['routers'] = routers
+
+
+class NetworkHealthMonitorService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, hms = client.list_health_monitors()
+        hms = hms['health_monitors']
+        hms = self._filter_by_tenant_id(hms)
+        LOG.debug("List count, %s Health Monitors" % len(hms))
+        return hms
+
+    def delete(self):
+        client = self.client
+        hms = self.list()
+        for hm in hms:
+            try:
+                client.delete_health_monitor(hm['id'])
+            except Exception as e:
+                LOG.exception("Delete Health Monitor exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        hms = self.list()
+        self.data['health_monitors'] = hms
+
+
+class NetworkMemberService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, members = client.list_members()
+        members = members['members']
+        members = self._filter_by_tenant_id(members)
+        LOG.debug("List count, %s Members" % len(members))
+        return members
+
+    def delete(self):
+        client = self.client
+        members = self.list()
+        for member in members:
+            try:
+                client.delete_member(member['id'])
+            except Exception as e:
+                LOG.exception("Delete Member exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        members = self.list()
+        self.data['members'] = members
+
+
+class NetworkVipService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, vips = client.list_vips()
+        vips = vips['vips']
+        vips = self._filter_by_tenant_id(vips)
+        LOG.debug("List count, %s VIPs" % len(vips))
+        return vips
+
+    def delete(self):
+        client = self.client
+        vips = self.list()
+        for vip in vips:
+            try:
+                client.delete_vip(vip['id'])
+            except Exception as e:
+                LOG.exception("Delete VIP exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        vips = self.list()
+        self.data['vips'] = vips
+
+
+class NetworkPoolService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, pools = client.list_pools()
+        pools = pools['pools']
+        pools = self._filter_by_tenant_id(pools)
+        LOG.debug("List count, %s Pools" % len(pools))
+        return pools
+
+    def delete(self):
+        client = self.client
+        pools = self.list()
+        for pool in pools:
+            try:
+                client.delete_pool(pool['id'])
+            except Exception as e:
+                LOG.exception("Delete Pool exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        pools = self.list()
+        self.data['pools'] = pools
+
+
+class NetworMeteringLabelRuleService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, rules = client.list_metering_label_rules()
+        rules = rules['metering_label_rules']
+        rules = self._filter_by_tenant_id(rules)
+        LOG.debug("List count, %s Metering Label Rules" % len(rules))
+        return rules
+
+    def delete(self):
+        client = self.client
+        rules = self.list()
+        for rule in rules:
+            try:
+                client.delete_metering_label_rule(rule['id'])
+            except Exception as e:
+                LOG.exception("Delete Metering Label Rule exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        rules = self.list()
+        self.data['rules'] = rules
+
+
+class NetworMeteringLabelService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, labels = client.list_metering_labels()
+        labels = labels['metering_labels']
+        labels = self._filter_by_tenant_id(labels)
+        LOG.debug("List count, %s Metering Labels" % len(labels))
+        return labels
+
+    def delete(self):
+        client = self.client
+        labels = self.list()
+        for label in labels:
+            try:
+                client.delete_metering_label(label['id'])
+            except Exception as e:
+                LOG.exception("Delete Metering Label exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        labels = self.list()
+        self.data['labels'] = labels
+
+
+class NetworkPortService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, ports = client.list_ports()
+        ports = ports['ports']
+        ports = self._filter_by_tenant_id(ports)
+        LOG.debug("List count, %s Ports" % len(ports))
+        return ports
+
+    def delete(self):
+        client = self.client
+        ports = self.list()
+        for port in ports:
+            try:
+                client.delete_port(port['id'])
+            except Exception as e:
+                LOG.exception("Delete Port exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        ports = self.list()
+        self.data['ports'] = ports
+
+
+class NetworkSubnetService(NetworkService):
+
+    def list(self):
+        client = self.client
+        _, subnets = client.list_subnets()
+        subnets = subnets['subnets']
+        subnets = self._filter_by_tenant_id(subnets)
+        LOG.debug("List count, %s Subnets" % len(subnets))
+        return subnets
+
+    def delete(self):
+        client = self.client
+        subnets = self.list()
+        for subnet in subnets:
+            try:
+                client.delete_subnet(subnet['id'])
+            except Exception as e:
+                LOG.exception("Delete Subnet exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        subnets = self.list()
+        self.data['subnets'] = subnets
+
+
+# Telemetry services
+class TelemetryAlarmService(BaseService):
+    def __init__(self, manager, **kwargs):
+        super(TelemetryAlarmService, self).__init__(kwargs)
+        self.client = manager.telemetry_client
+
+    def list(self):
+        client = self.client
+        _, alarms = client.list_alarms()
+        LOG.debug("List count, %s Alarms" % len(alarms))
+        return alarms
+
+    def delete(self):
+        client = self.client
+        alarms = self.list()
+        for alarm in alarms:
+            try:
+                client.delete_alarm(alarm['id'])
+            except Exception as e:
+                LOG.exception("Delete Alarms exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        alarms = self.list()
+        self.data['alarms'] = alarms
+
+
+# begin global services
+class FlavorService(BaseService):
+    def __init__(self, manager, **kwargs):
+        super(FlavorService, self).__init__(kwargs)
+        self.client = manager.flavors_client
+
+    def list(self):
+        client = self.client
+        _, flavors = client.list_flavors({"is_public": None})
+        if not self.is_save_state:
+            # recreate list removing saved flavors
+            flavors = [flavor for flavor in flavors if flavor['id']
+                       not in self.saved_state_json['flavors'].keys()]
+
+        if self.is_preserve:
+            flavors = [flavor for flavor in flavors
+                       if flavor['id'] not in CONF_FLAVORS]
+        LOG.debug("List count, %s Flavors after reconcile" % len(flavors))
+        return flavors
+
+    def delete(self):
+        client = self.client
+        flavors = self.list()
+        for flavor in flavors:
+            try:
+                client.delete_flavor(flavor['id'])
+            except Exception as e:
+                LOG.exception("Delete Flavor exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        flavors = self.list()
+        self.data['flavors'] = flavors
+
+    def save_state(self):
+        flavors = self.list()
+        flavor_data = self.data['flavors'] = {}
+        for flavor in flavors:
+            flavor_data[flavor['id']] = flavor['name']
+
+
+class ImageService(BaseService):
+    def __init__(self, manager, **kwargs):
+        super(ImageService, self).__init__(kwargs)
+        self.client = manager.images_client
+
+    def list(self):
+        client = self.client
+        _, images = client.list_images({"all_tenants": True})
+        if not self.is_save_state:
+            images = [image for image in images if image['id']
+                      not in self.saved_state_json['images'].keys()]
+        if self.is_preserve:
+            images = [image for image in images
+                      if image['id'] not in CONF_IMAGES]
+        LOG.debug("List count, %s Images after reconcile" % len(images))
+        return images
+
+    def delete(self):
+        client = self.client
+        images = self.list()
+        for image in images:
+            try:
+                client.delete_image(image['id'])
+            except Exception as e:
+                LOG.exception("Delete Image exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        images = self.list()
+        self.data['images'] = images
+
+    def save_state(self):
+        images = self.list()
+        image_data = self.data['images'] = {}
+        for image in images:
+            image_data[image['id']] = image['name']
+
+
+class IdentityService(BaseService):
+    def __init__(self, manager, **kwargs):
+        super(IdentityService, self).__init__(kwargs)
+        self.client = manager.identity_client
+
+
+class UserService(IdentityService):
+
+    def list(self):
+        client = self.client
+        _, users = client.get_users()
+
+        if not self.is_save_state:
+            users = [user for user in users if user['id']
+                     not in self.saved_state_json['users'].keys()]
+
+        if self.is_preserve:
+            users = [user for user in users if user['name']
+                     not in CONF_USERS]
+
+        elif not self.is_save_state:  # Never delete admin user
+            users = [user for user in users if user['name'] !=
+                     CONF.identity.admin_username]
+
+        LOG.debug("List count, %s Users after reconcile" % len(users))
+        return users
+
+    def delete(self):
+        client = self.client
+        users = self.list()
+        for user in users:
+            try:
+                client.delete_user(user['id'])
+            except Exception as e:
+                LOG.exception("Delete User exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        users = self.list()
+        self.data['users'] = users
+
+    def save_state(self):
+        users = self.list()
+        user_data = self.data['users'] = {}
+        for user in users:
+            user_data[user['id']] = user['name']
+
+
+class RoleService(IdentityService):
+
+    def list(self):
+        client = self.client
+        try:
+            _, roles = client.list_roles()
+            # reconcile roles with saved state and never list admin role
+            if not self.is_save_state:
+                roles = [role for role in roles if
+                         (role['id'] not in
+                          self.saved_state_json['roles'].keys()
+                          and role['name'] != CONF.identity.admin_role)]
+                LOG.debug("List count, %s Roles after reconcile" % len(roles))
+            return roles
+        except Exception as ex:
+            LOG.exception("Cannot retrieve Roles, exception: %s" % ex)
+            return []
+
+    def delete(self):
+        client = self.client
+        roles = self.list()
+        for role in roles:
+            try:
+                client.delete_role(role['id'])
+            except Exception as e:
+                LOG.exception("Delete Role exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        roles = self.list()
+        self.data['roles'] = roles
+
+    def save_state(self):
+        roles = self.list()
+        role_data = self.data['roles'] = {}
+        for role in roles:
+            role_data[role['id']] = role['name']
+
+
+class TenantService(IdentityService):
+
+    def list(self):
+        client = self.client
+        _, tenants = client.list_tenants()
+        if not self.is_save_state:
+            tenants = [tenant for tenant in tenants if (tenant['id']
+                       not in self.saved_state_json['tenants'].keys()
+                       and tenant['name'] != CONF.identity.admin_tenant_name)]
+
+        if self.is_preserve:
+            tenants = [tenant for tenant in tenants if tenant['name']
+                       not in CONF_TENANTS]
+
+        LOG.debug("List count, %s Tenants after reconcile" % len(tenants))
+        return tenants
+
+    def delete(self):
+        client = self.client
+        tenants = self.list()
+        for tenant in tenants:
+            try:
+                client.delete_tenant(tenant['id'])
+            except Exception as e:
+                LOG.exception("Delete Tenant exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        tenants = self.list()
+        self.data['tenants'] = tenants
+
+    def save_state(self):
+        tenants = self.list()
+        tenant_data = self.data['tenants'] = {}
+        for tenant in tenants:
+            tenant_data[tenant['id']] = tenant['name']
+
+
+class DomainService(BaseService):
+
+    def __init__(self, manager, **kwargs):
+        super(DomainService, self).__init__(kwargs)
+        self.client = manager.identity_v3_client
+
+    def list(self):
+        client = self.client
+        _, domains = client.list_domains()
+        if not self.is_save_state:
+            domains = [domain for domain in domains if domain['id']
+                       not in self.saved_state_json['domains'].keys()]
+
+        LOG.debug("List count, %s Domains after reconcile" % len(domains))
+        return domains
+
+    def delete(self):
+        client = self.client
+        domains = self.list()
+        for domain in domains:
+            try:
+                client.update_domain(domain['id'], enabled=False)
+                client.delete_domain(domain['id'])
+            except Exception as e:
+                LOG.exception("Delete Domain exception: %s" % e)
+                pass
+
+    def dry_run(self):
+        domains = self.list()
+        self.data['domains'] = domains
+
+    def save_state(self):
+        domains = self.list()
+        domain_data = self.data['domains'] = {}
+        for domain in domains:
+            domain_data[domain['id']] = domain['name']
+
+
+def get_tenant_cleanup_services():
+    tenant_services = []
+
+    if IS_CEILOMETER:
+        tenant_services.append(TelemetryAlarmService)
+    if IS_NOVA:
+        tenant_services.append(ServerService)
+        tenant_services.append(KeyPairService)
+        tenant_services.append(SecurityGroupService)
+        tenant_services.append(ServerGroupService)
+        if not IS_NEUTRON:
+            tenant_services.append(FloatingIpService)
+    if IS_HEAT:
+        tenant_services.append(StackService)
+    if IS_NEUTRON:
+        if test.is_extension_enabled('vpnaas', 'network'):
+            tenant_services.append(NetworkIpSecPolicyService)
+            tenant_services.append(NetworkIkePolicyService)
+            tenant_services.append(NetworkVpnServiceService)
+        if test.is_extension_enabled('fwaas', 'network'):
+            tenant_services.append(NetworkFwPolicyService)
+            tenant_services.append(NetworkFwRulesService)
+        if test.is_extension_enabled('lbaas', 'network'):
+            tenant_services.append(NetworkHealthMonitorService)
+            tenant_services.append(NetworkMemberService)
+            tenant_services.append(NetworkVipService)
+            tenant_services.append(NetworkPoolService)
+        if test.is_extension_enabled('metering', 'network'):
+            tenant_services.append(NetworMeteringLabelRuleService)
+            tenant_services.append(NetworMeteringLabelService)
+        tenant_services.append(NetworkRouterService)
+        tenant_services.append(NetworkFloatingIpService)
+        tenant_services.append(NetworkPortService)
+        tenant_services.append(NetworkSubnetService)
+        tenant_services.append(NetworkService)
+    if IS_CINDER:
+        tenant_services.append(SnapshotService)
+        tenant_services.append(VolumeService)
+    return tenant_services
+
+
+def get_global_cleanup_services():
+    global_services = []
+    if IS_NOVA:
+        global_services.append(FlavorService)
+    if IS_GLANCE:
+        global_services.append(ImageService)
+    global_services.append(UserService)
+    global_services.append(TenantService)
+    global_services.append(DomainService)
+    global_services.append(RoleService)
+    return global_services
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index f37bfdb..6879db9 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -20,30 +20,35 @@
 """
 
 import argparse
+import collections
 import datetime
-import logging
 import os
 import sys
 import unittest
 
+import netaddr
 import yaml
 
 import tempest.auth
 from tempest import config
 from tempest import exceptions
+from tempest.openstack.common import log as logging
 from tempest.openstack.common import timeutils
 from tempest.services.compute.json import flavors_client
+from tempest.services.compute.json import security_groups_client
 from tempest.services.compute.json import servers_client
 from tempest.services.identity.json import identity_client
 from tempest.services.image.v2.json import image_client
+from tempest.services.network.json import network_client
 from tempest.services.object_storage import container_client
 from tempest.services.object_storage import object_client
 from tempest.services.telemetry.json import telemetry_client
 from tempest.services.volume.json import volumes_client
 
+CONF = config.CONF
 OPTS = {}
 USERS = {}
-RES = {}
+RES = collections.defaultdict(list)
 
 LOG = None
 
@@ -68,7 +73,9 @@
         self.images = image_client.ImageClientV2JSON(_auth)
         self.flavors = flavors_client.FlavorsClientJSON(_auth)
         self.telemetry = telemetry_client.TelemetryClientJSON(_auth)
+        self.secgroups = security_groups_client.SecurityGroupsClientJSON(_auth)
         self.volumes = volumes_client.VolumesClientJSON(_auth)
+        self.networks = network_client.NetworkClientJSON(_auth)
 
 
 def load_resources(fname):
@@ -89,6 +96,10 @@
     else:
         LOG.error("%s not found in USERS: %s" % (name, USERS))
 
+
+def resp_ok(response):
+    return 200 >= int(response['status']) < 300
+
 ###################
 #
 # TENANTS
@@ -110,6 +121,13 @@
         else:
             LOG.warn("Tenant '%s' already exists in this environment" % tenant)
 
+
+def destroy_tenants(tenants):
+    admin = keystone_admin()
+    for tenant in tenants:
+        tenant_id = admin.identity.get_tenant_by_name(tenant)['id']
+        r, body = admin.identity.delete_tenant(tenant_id)
+
 ##############
 #
 # USERS
@@ -174,6 +192,15 @@
                 enabled=True)
 
 
+def destroy_users(users):
+    admin = keystone_admin()
+    for user in users:
+        tenant_id = admin.identity.get_tenant_by_name(user['tenant'])['id']
+        user_id = admin.identity.get_user_by_username(tenant_id,
+                                                      user['name'])['id']
+        r, body = admin.identity.delete_user(user_id)
+
+
 def collect_users(users):
     global USERS
     LOG.info("Collecting users")
@@ -195,14 +222,36 @@
     def runTest(self, *args):
         pass
 
+    def _ping_ip(self, ip_addr, count, namespace=None):
+        if namespace is None:
+            ping_cmd = "ping -c1 " + ip_addr
+        else:
+            ping_cmd = "sudo ip netns exec %s ping -c1 %s" % (namespace,
+                                                              ip_addr)
+        for current in range(count):
+            return_code = os.system(ping_cmd)
+            if return_code is 0:
+                break
+        self.assertNotEqual(current, count - 1,
+                            "Server is not pingable at %s" % ip_addr)
+
     def check(self):
         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()
+        self.check_volumes()
         self.check_telemetry()
+        self.check_secgroups()
+
+        # validate neutron is enabled and ironic disabled:
+        # Tenant network isolation is not supported when using ironic.
+        # "admin" has set up a neutron flat network environment within a shared
+        # fixed network for all tenants to use.
+        # In this case, network/subnet/router creation can be skipped and the
+        # server booted the same as nova network.
+        if (CONF.service_available.neutron and
+                not CONF.baremetal.driver_enabled):
+            self.check_networking()
 
     def check_users(self):
         """Check that the users we expect to exist, do.
@@ -249,15 +298,32 @@
                 "Couldn't find expected server %s" % server['name'])
 
             r, found = client.servers.get_server(found['id'])
-            # get the ipv4 address
-            addr = found['addresses']['private'][0]['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))
+            # validate neutron is enabled and ironic disabled:
+            if (CONF.service_available.neutron and
+                    not CONF.baremetal.driver_enabled):
+                for network_name, body in found['addresses'].items():
+                    for addr in body:
+                        ip = addr['addr']
+                        if addr.get('OS-EXT-IPS:type', 'fixed') == 'fixed':
+                            namespace = _get_router_namespace(client,
+                                                              network_name)
+                            self._ping_ip(ip, 60, namespace)
+                        else:
+                            self._ping_ip(ip, 60)
+            else:
+                addr = found['addresses']['private'][0]['addr']
+                self._ping_ip(addr, 60)
+
+    def check_secgroups(self):
+        """Check that the security groups are still existing."""
+        LOG.info("Checking security groups")
+        for secgroup in self.res['secgroups']:
+            client = client_for_user(secgroup['owner'])
+            found = _get_resource_by_name(client.secgroups, 'security_groups',
+                                          secgroup['name'])
+            self.assertIsNotNone(
+                found,
+                "Couldn't find expected secgroup %s" % secgroup['name'])
 
     def check_telemetry(self):
         """Check that ceilometer provides a sane sample.
@@ -268,6 +334,8 @@
         If in check mode confirm that the oldest sample available is from
         before the upgrade.
         """
+        if not self.res.get('telemetry'):
+            return
         LOG.info("checking telemetry")
         for server in self.res['servers']:
             client = client_for_user(server['owner'])
@@ -286,15 +354,15 @@
         LOG.info("checking volumes")
         for volume in self.res['volumes']:
             client = client_for_user(volume['owner'])
-            found = _get_volume_by_name(client, volume['name'])
+            vol_body = _get_volume_by_name(client, volume['name'])
             self.assertIsNotNone(
-                found,
+                vol_body,
                 "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'])
+            attachment = client.volumes.get_attachment_from_volume(vol_body)
+            self.assertEqual(vol_body['id'], attachment['volume_id'])
             self.assertEqual(server_id, attachment['server_id'])
 
     def _confirm_telemetry_sample(self, server, sample):
@@ -317,6 +385,17 @@
                 'timestamp should come before start of second javelin run'
             )
 
+    def check_networking(self):
+        """Check that the networks are still there."""
+        for res_type in ('networks', 'subnets', 'routers'):
+            for res in self.res[res_type]:
+                client = client_for_user(res['owner'])
+                found = _get_resource_by_name(client.networks, res_type,
+                                              res['name'])
+                self.assertIsNotNone(
+                    found,
+                    "Couldn't find expected resource %s" % res['name'])
+
 
 #######################
 #
@@ -343,6 +422,15 @@
             obj['container'], obj['name'],
             _file_contents(obj['file']))
 
+
+def destroy_objects(objects):
+    for obj in objects:
+        client = client_for_user(obj['owner'])
+        r, body = client.objects.delete_object(obj['container'], obj['name'])
+        if not (200 <= int(r['status']) < 299):
+            raise ValueError("unable to destroy object: [%s] %s" % (r, body))
+
+
 #######################
 #
 # IMAGES
@@ -414,6 +502,147 @@
 
 #######################
 #
+# NETWORKS
+#
+#######################
+
+def _get_router_namespace(client, network):
+    network_id = _get_resource_by_name(client.networks,
+                                       'networks', network)['id']
+    resp, n_body = client.networks.list_routers()
+    if not resp_ok(resp):
+        raise ValueError("unable to routers list: [%s] %s" % (resp, n_body))
+    for router in n_body['routers']:
+        router_id = router['id']
+        resp, r_body = client.networks.list_router_interfaces(router_id)
+        if not resp_ok(resp):
+            raise ValueError("unable to router interfaces list: [%s] %s" %
+                             (resp, r_body))
+        for port in r_body['ports']:
+            if port['network_id'] == network_id:
+                return "qrouter-%s" % router_id
+
+
+def _get_resource_by_name(client, resource, name):
+    get_resources = getattr(client, 'list_%s' % resource)
+    if get_resources is None:
+        raise AttributeError("client doesn't have method list_%s" % resource)
+    r, body = get_resources()
+    if not resp_ok(r):
+        raise ValueError("unable to list %s: [%s] %s" % (resource, r, body))
+    if isinstance(body, dict):
+        body = body[resource]
+    for res in body:
+        if name == res['name']:
+            return res
+    raise ValueError('%s not found in %s resources' % (name, resource))
+
+
+def create_networks(networks):
+    LOG.info("Creating networks")
+    for network in networks:
+        client = client_for_user(network['owner'])
+
+        # only create a network if the name isn't here
+        r, body = client.networks.list_networks()
+        if any(item['name'] == network['name'] for item in body['networks']):
+            LOG.warning("Dupplicated network name: %s" % network['name'])
+            continue
+
+        client.networks.create_network(name=network['name'])
+
+
+def destroy_networks(networks):
+    LOG.info("Destroying subnets")
+    for network in networks:
+        client = client_for_user(network['owner'])
+        network_id = _get_resource_by_name(client.networks, 'networks',
+                                           network['name'])['id']
+        client.networks.delete_network(network_id)
+
+
+def create_subnets(subnets):
+    LOG.info("Creating subnets")
+    for subnet in subnets:
+        client = client_for_user(subnet['owner'])
+
+        network = _get_resource_by_name(client.networks, 'networks',
+                                        subnet['network'])
+        ip_version = netaddr.IPNetwork(subnet['range']).version
+        # ensure we don't overlap with another subnet in the network
+        try:
+            client.networks.create_subnet(network_id=network['id'],
+                                          cidr=subnet['range'],
+                                          name=subnet['name'],
+                                          ip_version=ip_version)
+        except exceptions.BadRequest as e:
+            is_overlapping_cidr = 'overlaps with another subnet' in str(e)
+            if not is_overlapping_cidr:
+                raise
+
+
+def destroy_subnets(subnets):
+    LOG.info("Destroying subnets")
+    for subnet in subnets:
+        client = client_for_user(subnet['owner'])
+        subnet_id = _get_resource_by_name(client.networks,
+                                          'subnets', subnet['name'])['id']
+        client.networks.delete_subnet(subnet_id)
+
+
+def create_routers(routers):
+    LOG.info("Creating routers")
+    for router in routers:
+        client = client_for_user(router['owner'])
+
+        # only create a router if the name isn't here
+        r, body = client.networks.list_routers()
+        if any(item['name'] == router['name'] for item in body['routers']):
+            LOG.warning("Dupplicated router name: %s" % router['name'])
+            continue
+
+        client.networks.create_router(router['name'])
+
+
+def destroy_routers(routers):
+    LOG.info("Destroying routers")
+    for router in routers:
+        client = client_for_user(router['owner'])
+        router_id = _get_resource_by_name(client.networks,
+                                          'routers', router['name'])['id']
+        for subnet in router['subnet']:
+            subnet_id = _get_resource_by_name(client.networks,
+                                              'subnets', subnet)['id']
+            client.networks.remove_router_interface_with_subnet_id(router_id,
+                                                                   subnet_id)
+        client.networks.delete_router(router_id)
+
+
+def add_router_interface(routers):
+    for router in routers:
+        client = client_for_user(router['owner'])
+        router_id = _get_resource_by_name(client.networks,
+                                          'routers', router['name'])['id']
+
+        for subnet in router['subnet']:
+            subnet_id = _get_resource_by_name(client.networks,
+                                              'subnets', subnet)['id']
+            # connect routers to their subnets
+            client.networks.add_router_interface_with_subnet_id(router_id,
+                                                                subnet_id)
+        # connect routers to exteral network if set to "gateway"
+        if router['gateway']:
+            if CONF.network.public_network_id:
+                ext_net = CONF.network.public_network_id
+                client.networks._update_router(
+                    router_id, set_enable_snat=True,
+                    external_gateway_info={"network_id": ext_net})
+            else:
+                raise ValueError('public_network_id is not configured.')
+
+
+#######################
+#
 # SERVERS
 #
 #######################
@@ -447,10 +676,21 @@
 
         image_id = _get_image_by_name(client, server['image'])['id']
         flavor_id = _get_flavor_by_name(client, server['flavor'])['id']
-        resp, body = client.servers.create_server(server['name'], image_id,
-                                                  flavor_id)
+        # validate neutron is enabled and ironic disabled
+        kwargs = dict()
+        if (CONF.service_available.neutron and
+                not CONF.baremetal.driver_enabled and server.get('networks')):
+            get_net_id = lambda x: (_get_resource_by_name(
+                client.networks, 'networks', x)['id'])
+            kwargs['networks'] = [{'uuid': get_net_id(network)}
+                                  for network in server['networks']]
+        resp, body = client.servers.create_server(
+            server['name'], image_id, flavor_id, **kwargs)
         server_id = body['id']
         client.servers.wait_for_server_status(server_id, 'ACTIVE')
+        # create to security group(s) after server spawning
+        for secgroup in server['secgroups']:
+            client.servers.add_security_group(server_id, secgroup)
 
 
 def destroy_servers(servers):
@@ -470,6 +710,44 @@
                                                    ignore_error=True)
 
 
+def create_secgroups(secgroups):
+    LOG.info("Creating security groups")
+    for secgroup in secgroups:
+        client = client_for_user(secgroup['owner'])
+
+        # only create a security group if the name isn't here
+        # i.e. a security group may be used by another server
+        # only create a router if the name isn't here
+        r, body = client.secgroups.list_security_groups()
+        if any(item['name'] == secgroup['name'] for item in body):
+            LOG.warning("Security group '%s' already exists" %
+                        secgroup['name'])
+            continue
+
+        resp, body = client.secgroups.create_security_group(
+            secgroup['name'], secgroup['description'])
+        if not resp_ok(resp):
+            raise ValueError("Failed to create security group: [%s] %s" %
+                             (resp, body))
+        secgroup_id = body['id']
+        # for each security group, create the rules
+        for rule in secgroup['rules']:
+            ip_proto, from_port, to_port, cidr = rule.split()
+            client.secgroups.create_security_group_rule(
+                secgroup_id, ip_proto, from_port, to_port, cidr=cidr)
+
+
+def destroy_secgroups(secgroups):
+    LOG.info("Destroying security groups")
+    for secgroup in secgroups:
+        client = client_for_user(secgroup['owner'])
+        sg_id = _get_resource_by_name(client.secgroups,
+                                      'security_groups',
+                                      secgroup['name'])
+        # sg rules are deleted automatically
+        client.secgroups.delete_security_group(sg_id['id'])
+
+
 #######################
 #
 # VOLUMES
@@ -478,30 +756,46 @@
 
 def _get_volume_by_name(client, name):
     r, body = client.volumes.list_volumes()
-    for volume in body['volumes']:
-        if name == volume['name']:
+    for volume in body:
+        if name == volume['display_name']:
             return volume
     return None
 
 
 def create_volumes(volumes):
+    if not volumes:
+        return
+    LOG.info("Creating 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):
+        if _get_volume_by_name(client, volume['name']):
+            LOG.info("volume '%s' already exists" % volume['name'])
             continue
 
-        client.volumes.create_volume(volume['name'], volume['size'])
+        size = volume['gb']
+        v_name = volume['name']
+        resp, body = client.volumes.create_volume(size=size,
+                                                  display_name=v_name)
+        client.volumes.wait_for_volume_status(body['id'], 'available')
+
+
+def destroy_volumes(volumes):
+    for volume in volumes:
+        client = client_for_user(volume['owner'])
+        volume_id = _get_volume_by_name(client, volume['name'])['id']
+        client.volumes.detach_volume(volume_id)
+        client.volumes.delete_volume(volume_id)
 
 
 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)
+        volume_id = _get_volume_by_name(client, volume['name'])['id']
+        device = volume['device']
+        client.volumes.attach_volume(volume_id, server_id, device)
 
 
 #######################
@@ -521,28 +815,34 @@
     # next create resources in a well known order
     create_objects(RES['objects'])
     create_images(RES['images'])
+
+    # validate neutron is enabled and ironic is disabled
+    if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
+        create_networks(RES['networks'])
+        create_subnets(RES['subnets'])
+        create_routers(RES['routers'])
+        add_router_interface(RES['routers'])
+
+    create_secgroups(RES['secgroups'])
     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'])
+    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'])
     destroy_images(RES['images'])
-    # destroy_objects
-
-    # destroy_users
-    # destroy_tenants
-
+    destroy_objects(RES['objects'])
+    destroy_volumes(RES['volumes'])
+    if CONF.service_available.neutron and not CONF.baremetal.driver_enabled:
+        destroy_routers(RES['routers'])
+        destroy_subnets(RES['subnets'])
+        destroy_networks(RES['networks'])
+    destroy_secgroups(RES['secgroups'])
+    destroy_users(RES['users'])
+    destroy_tenants(RES['tenants'])
     LOG.warn("Destroy mode incomplete")
 
 
@@ -592,28 +892,17 @@
         config.CONF.set_config_path(OPTS.config_file)
 
 
-def setup_logging(debug=True):
+def setup_logging():
     global LOG
+    logging.setup(__name__)
     LOG = logging.getLogger(__name__)
-    if debug:
-        LOG.setLevel(logging.DEBUG)
-    else:
-        LOG.setLevel(logging.INFO)
-
-    ch = logging.StreamHandler(sys.stdout)
-    ch.setLevel(logging.DEBUG)
-    formatter = logging.Formatter(
-        datefmt='%Y-%m-%d %H:%M:%S',
-        fmt='%(asctime)s.%(msecs).03d - %(levelname)s - %(message)s')
-    ch.setFormatter(formatter)
-    LOG.addHandler(ch)
 
 
 def main():
     global RES
     get_options()
     setup_logging()
-    RES = load_resources(OPTS.resources)
+    RES.update(load_resources(OPTS.resources))
 
     if OPTS.mode == 'create':
         create_resources()
diff --git a/tempest/cmd/resources.yaml b/tempest/cmd/resources.yaml
index 3450e1f..2d6664c 100644
--- a/tempest/cmd/resources.yaml
+++ b/tempest/cmd/resources.yaml
@@ -17,11 +17,17 @@
     tenant: discuss
 
 secgroups:
-  - angon:
+  - name: angon
     owner: javelin
+    description: angon
     rules:
       - 'icmp -1 -1 0.0.0.0/0'
       - 'tcp 22 22 0.0.0.0/0'
+  - name: baobab
+    owner: javelin
+    description: baobab
+    rules:
+      - 'tcp 80 80 0.0.0.0/0'
 
 # resources that we want to create
 images:
@@ -36,22 +42,55 @@
   - name: assegai
     server: peltast
     owner: javelin
-    size: 1
+    gb: 1
+    device: /dev/vdb
   - name: pifpouf
     server: hoplite
     owner: javelin
-    size: 2
+    gb: 2
+    device: /dev/vdb
+networks:
+  - name: world1
+    owner: javelin
+  - name: world2
+    owner: javelin
+subnets:
+  - name: subnet1
+    range: 10.1.0.0/24
+    network: world1
+    owner: javelin
+  - name: subnet2
+    range: 192.168.1.0/24
+    network: world2
+    owner: javelin
+routers:
+  - name: connector
+    owner: javelin
+    gateway: true
+    subnet:
+      - subnet1
+      - subnet2
 servers:
   - name: peltast
     owner: javelin
     flavor: m1.small
     image: javelin_cirros
+    networks:
+      - world1
+    secgroups:
+      - angon
+      - baobab
   - name: hoplite
     owner: javelin
     flavor: m1.medium
     image: javelin_cirros
+    networks:
+      - world2
+    secgroups:
+      - angon
 objects:
   - container: jc1
     name: javelin1
     owner: javelin
     file: /etc/hosts
+telemetry: true
diff --git a/tempest/cmd/run_stress.py b/tempest/cmd/run_stress.py
index a3f185c..d21a441 100755
--- a/tempest/cmd/run_stress.py
+++ b/tempest/cmd/run_stress.py
@@ -102,9 +102,11 @@
                                       call_inherited=ns.call_inherited)
 
     if ns.serial:
+        # Duration is total time
+        duration = ns.duration / len(tests)
         for test in tests:
             step_result = driver.stress_openstack([test],
-                                                  ns.duration,
+                                                  duration,
                                                   ns.number,
                                                   ns.stop)
             # NOTE(mkoderer): we just save the last result code
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index cd696a9..f426e4d 100755
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -122,6 +122,18 @@
                             not CONF.volume_feature_enabled.api_v2, update)
 
 
+def verify_api_versions(os, service, update):
+    verify = {
+        'cinder': verify_cinder_api_versions,
+        'glance': verify_glance_api_versions,
+        'keystone': verify_keystone_api_versions,
+        'nova': verify_nova_api_versions,
+    }
+    if service not in verify:
+        return
+    verify[service](os, update)
+
+
 def get_extension_client(os, service):
     extensions_client = {
         'nova': os.extensions_client,
@@ -247,7 +259,7 @@
         'data_processing': 'sahara',
         'baremetal': 'ironic',
         'identity': 'keystone',
-        'queuing': 'zaqar',
+        'messaging': 'zaqar',
         'database': 'trove'
     }
     # Get catalog list for endpoints to use for validation
@@ -337,10 +349,13 @@
         elif service not in services:
             continue
         results = verify_extensions(os, service, results)
-    verify_keystone_api_versions(os, update)
-    verify_glance_api_versions(os, update)
-    verify_nova_api_versions(os, update)
-    verify_cinder_api_versions(os, update)
+
+    # Verify API verisons of all services in the keystone catalog and keystone
+    # itself.
+    services.append('keystone')
+    for service in services:
+        verify_api_versions(os, service, update)
+
     display_results(results, update, replace)
     if update:
         conf_file.close()
diff --git a/tempest/common/accounts.py b/tempest/common/accounts.py
index ad88ea2..66285e4 100644
--- a/tempest/common/accounts.py
+++ b/tempest/common/accounts.py
@@ -38,7 +38,12 @@
 
     def __init__(self, name):
         super(Accounts, self).__init__(name)
-        accounts = read_accounts_yaml(CONF.auth.test_accounts_file)
+        if os.path.isfile(CONF.auth.test_accounts_file):
+            accounts = read_accounts_yaml(CONF.auth.test_accounts_file)
+            self.use_default_creds = False
+        else:
+            accounts = {}
+            self.use_default_creds = True
         self.hash_dict = self.get_hash_dict(accounts)
         self.accounts_dir = os.path.join(CONF.lock_path, 'test_accounts')
         self.isolated_creds = {}
@@ -52,8 +57,19 @@
             hash_dict[temp_hash.hexdigest()] = account
         return hash_dict
 
-    def _create_hash_file(self, hash):
-        path = os.path.join(os.path.join(self.accounts_dir, hash))
+    def is_multi_user(self):
+        # Default credentials is not a valid option with locking Account
+        if self.use_default_creds:
+            raise exceptions.InvalidConfiguration(
+                "Account file %s doesn't exist" % CONF.auth.test_accounts_file)
+        else:
+            return len(self.hash_dict) > 1
+
+    def is_multi_tenant(self):
+        return self.is_multi_user()
+
+    def _create_hash_file(self, hash_string):
+        path = os.path.join(os.path.join(self.accounts_dir, hash_string))
         if not os.path.isfile(path):
             open(path, 'w').close()
             return True
@@ -66,20 +82,23 @@
             # Create File from first hash (since none are in use)
             self._create_hash_file(hashes[0])
             return hashes[0]
-        for hash in hashes:
-            res = self._create_hash_file(hash)
+        for _hash in hashes:
+            res = self._create_hash_file(_hash)
             if res:
-                return hash
+                return _hash
         msg = 'Insufficient number of users provided'
         raise exceptions.InvalidConfiguration(msg)
 
     def _get_creds(self):
-        free_hash = self._get_free_hash(self.hashes.keys())
+        if self.use_default_creds:
+            raise exceptions.InvalidConfiguration(
+                "Account file %s doesn't exist" % CONF.auth.test_accounts_file)
+        free_hash = self._get_free_hash(self.hash_dict.keys())
         return self.hash_dict[free_hash]
 
     @lockutils.synchronized('test_accounts_io', external=True)
-    def remove_hash(self, hash):
-        hash_path = os.path.join(self.accounts_dir, hash)
+    def remove_hash(self, hash_string):
+        hash_path = os.path.join(self.accounts_dir, hash_string)
         if not os.path.isfile(hash_path):
             LOG.warning('Expected an account lock file %s to remove, but '
                         'one did not exist')
@@ -89,43 +108,106 @@
                 os.rmdir(self.accounts_dir)
 
     def get_hash(self, creds):
-        for hash in self.hash_dict:
-            # NOTE(mtreinish) Assuming with v3 that username, tenant, password
-            # is unique enough
-            cred_dict = {
-                'username': creds.username,
-                'tenant_name': creds.tenant_name,
-                'password': creds.password
-            }
-            if self.hash_dict[hash] == cred_dict:
-                return hash
+        for _hash in self.hash_dict:
+            # Comparing on the attributes that are expected in the YAML
+            if all([getattr(creds, k) == self.hash_dict[_hash][k] for k in
+                    creds.CONF_ATTRIBUTES]):
+                return _hash
         raise AttributeError('Invalid credentials %s' % creds)
 
     def remove_credentials(self, creds):
-        hash = self.get_hash(creds)
-        self.remove_hash(hash, self.accounts_dir)
+        _hash = self.get_hash(creds)
+        self.remove_hash(_hash)
 
     def get_primary_creds(self):
-        if self.credentials.get('primary'):
-            return self.credentials.get('primary')
+        if self.isolated_creds.get('primary'):
+            return self.isolated_creds.get('primary')
         creds = self._get_creds()
         primary_credential = auth.get_credentials(**creds)
-        self.credentials['primary'] = primary_credential
+        self.isolated_creds['primary'] = primary_credential
         return primary_credential
 
     def get_alt_creds(self):
-        if self.credentials.get('alt'):
-            return self.credentials.get('alt')
+        if self.isolated_creds.get('alt'):
+            return self.isolated_creds.get('alt')
         creds = self._get_creds()
         alt_credential = auth.get_credentials(**creds)
-        self.credentials['alt'] = alt_credential
+        self.isolated_creds['alt'] = alt_credential
         return alt_credential
 
     def clear_isolated_creds(self):
-        for creds in self.credentials.values():
+        for creds in self.isolated_creds.values():
             self.remove_credentials(creds)
 
     def get_admin_creds(self):
         msg = ('If admin credentials are available tenant_isolation should be'
                ' used instead')
         raise NotImplementedError(msg)
+
+
+class NotLockingAccounts(Accounts):
+    """Credentials provider which always returns the first and second
+    configured accounts as primary and alt users.
+    This credential provider can be used in case of serial test execution
+    to preserve the current behaviour of the serial tempest run.
+    """
+
+    def _unique_creds(self, cred_arg=None):
+        """Verify that the configured credentials are valid and distinct """
+        if self.use_default_creds:
+            try:
+                user = self.get_primary_creds()
+                alt_user = self.get_alt_creds()
+                return getattr(user, cred_arg) != getattr(alt_user, cred_arg)
+            except exceptions.InvalidCredentials as ic:
+                msg = "At least one of the configured credentials is " \
+                      "not valid: %s" % ic.message
+                raise exceptions.InvalidConfiguration(msg)
+        else:
+            # TODO(andreaf) Add a uniqueness check here
+            return len(self.hash_dict) > 1
+
+    def is_multi_user(self):
+        return self._unique_creds('username')
+
+    def is_multi_tenant(self):
+        return self._unique_creds('tenant_id')
+
+    def get_creds(self, id):
+        try:
+            # No need to sort the dict as within the same python process
+            # the HASH seed won't change, so subsequent calls to keys()
+            # will return the same result
+            _hash = self.hash_dict.keys()[id]
+        except IndexError:
+            msg = 'Insufficient number of users provided'
+            raise exceptions.InvalidConfiguration(msg)
+        return self.hash_dict[_hash]
+
+    def get_primary_creds(self):
+        if self.isolated_creds.get('primary'):
+            return self.isolated_creds.get('primary')
+        if not self.use_default_creds:
+            creds = self.get_creds(0)
+            primary_credential = auth.get_credentials(**creds)
+        else:
+            primary_credential = auth.get_default_credentials('user')
+        self.isolated_creds['primary'] = primary_credential
+        return primary_credential
+
+    def get_alt_creds(self):
+        if self.isolated_creds.get('alt'):
+            return self.isolated_creds.get('alt')
+        if not self.use_default_creds:
+            creds = self.get_creds(1)
+            alt_credential = auth.get_credentials(**creds)
+        else:
+            alt_credential = auth.get_default_credentials('alt_user')
+        self.isolated_creds['alt'] = alt_credential
+        return alt_credential
+
+    def clear_isolated_creds(self):
+        self.isolated_creds = {}
+
+    def get_admin_creds(self):
+        return auth.get_default_credentials("identity_admin", fill_in=False)
diff --git a/tempest/common/cred_provider.py b/tempest/common/cred_provider.py
index 9808ed1..c5be0c0 100644
--- a/tempest/common/cred_provider.py
+++ b/tempest/common/cred_provider.py
@@ -1,4 +1,5 @@
-# (c) 2014 Deutsche Telekom AG
+# Copyright (c) 2014 Deutsche Telekom AG
+# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
 #    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
@@ -24,8 +25,8 @@
 
 @six.add_metaclass(abc.ABCMeta)
 class CredentialProvider(object):
-    def __init__(self, name, tempest_client=True, interface='json',
-                 password='pass', network_resources=None):
+    def __init__(self, name, interface='json', password='pass',
+                 network_resources=None):
         self.name = name
 
     @abc.abstractmethod
@@ -43,3 +44,11 @@
     @abc.abstractmethod
     def clear_isolated_creds(self):
         return
+
+    @abc.abstractmethod
+    def is_multi_user(self):
+        return
+
+    @abc.abstractmethod
+    def is_multi_tenant(self):
+        return
diff --git a/tempest/common/credentials.py b/tempest/common/credentials.py
new file mode 100644
index 0000000..08b592f
--- /dev/null
+++ b/tempest/common/credentials.py
@@ -0,0 +1,39 @@
+# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
+#    Licensed under the Apache License, Version 2.0 (the "License");
+#    you may not use this file except in compliance with the License.
+#    You may obtain a copy of the License at
+#
+#        http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS,
+#    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#    See the License for the specific language governing permissions and
+#    limitations under the License.
+
+from tempest.common import accounts
+from tempest.common import isolated_creds
+from tempest import config
+
+CONF = config.CONF
+
+
+# Return the right implementation of CredentialProvider based on config
+# Dropping interface and password, as they are never used anyways
+# TODO(andreaf) Drop them from the CredentialsProvider interface completely
+def get_isolated_credentials(name, network_resources=None,
+                             force_tenant_isolation=False):
+    # If a test requires a new account to work, it can have it via forcing
+    # tenant isolation. A new account will be produced only for that test.
+    # In case admin credentials are not available for the account creation,
+    # the test should be skipped else it would fail.
+    if CONF.auth.allow_tenant_isolation or force_tenant_isolation:
+        return isolated_creds.IsolatedCreds(
+            name=name,
+            network_resources=network_resources)
+    else:
+        if CONF.auth.locking_credentials_provider:
+            # Most params are not relevant for pre-created accounts
+            return accounts.Accounts(name=name)
+        else:
+            return accounts.NotLockingAccounts(name=name)
diff --git a/tempest/common/custom_matchers.py b/tempest/common/custom_matchers.py
index 7348a7d..39e3a67 100644
--- a/tempest/common/custom_matchers.py
+++ b/tempest/common/custom_matchers.py
@@ -13,7 +13,6 @@
 #    under the License.
 
 import re
-from unittest import util
 
 from testtools import helpers
 
@@ -204,24 +203,35 @@
         self.intersect = set(self.expected) & set(self.actual)
         self.symmetric_diff = set(self.expected) ^ set(self.actual)
 
+    def _format_dict(self, dict_to_format):
+        # Ensure the error string dict is printed in a set order
+        # NOTE(mtreinish): needed to ensure a deterministic error msg for
+        # testing. Otherwise the error message will be dependent on the
+        # dict ordering.
+        dict_string = "{"
+        for key in sorted(dict_to_format):
+            dict_string += "'%s': %s, " % (key, dict_to_format[key])
+        dict_string = dict_string[:-2] + '}'
+        return dict_string
+
     def describe(self):
         msg = ""
         if self.symmetric_diff:
             only_expected = helpers.dict_subtract(self.expected, self.actual)
             only_actual = helpers.dict_subtract(self.actual, self.expected)
             if only_expected:
-                msg += "Only in expected:\n  %s\n" % \
-                       util.safe_repr(only_expected)
+                msg += "Only in expected:\n  %s\n" % self._format_dict(
+                    only_expected)
             if only_actual:
-                msg += "Only in actual:\n  %s\n" % \
-                       util.safe_repr(only_actual)
+                msg += "Only in actual:\n  %s\n" % self._format_dict(
+                    only_actual)
         diff_set = set(o for o in self.intersect if
                        self.expected[o] != self.actual[o])
         if diff_set:
             msg += "Differences:\n"
-        for o in diff_set:
-            msg += "  %s: expected %s, actual %s\n" % (
-                o, self.expected[o], self.actual[o])
+            for o in diff_set:
+                msg += "  %s: expected %s, actual %s\n" % (
+                    o, self.expected[o], self.actual[o])
         return msg
 
     def get_details(self):
diff --git a/tempest/common/generate_sample_tempest.py b/tempest/common/generate_sample_tempest.py
deleted file mode 100644
index ceb3394..0000000
--- a/tempest/common/generate_sample_tempest.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright 2013 IBM Corp.
-# 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 sys
-
-import tempest.config
-from tempest.openstack.common.config import generator
-
-# NOTE(mtreinish): This hack is needed because of how oslo config is used in
-# tempest. Tempest is run from inside a test runner and so we can't rely on the
-# global CONF object being fully populated when we run a test. (test runners
-# don't init every file for running a test) So to get around that we manually
-# load the config file in tempest for each test class to ensure that every
-# config option is set. However, the tool expects the CONF object to be fully
-# populated when it inits all the files in the project. This just works around
-# the issue by manually loading the config file (which may or may not exist)
-# which will populate all the options before running the generator.
-
-
-if __name__ == "__main__":
-    tempest.config.register_opts()
-    generator.generate(sys.argv[1:])
diff --git a/tempest/common/generator/base_generator.py b/tempest/common/generator/base_generator.py
index 0398af1..3f405b1 100644
--- a/tempest/common/generator/base_generator.py
+++ b/tempest/common/generator/base_generator.py
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import copy
 import functools
 
 import jsonschema
@@ -30,9 +31,11 @@
     return expected_result
 
 
-def generator_type(*args):
+def generator_type(*args, **kwargs):
     def wrapper(func):
         func.types = args
+        for key in kwargs:
+            setattr(func, key, kwargs[key])
         return func
     return wrapper
 
@@ -106,37 +109,74 @@
             jsonschema.Draft4Validator.check_schema(schema['json-schema'])
         jsonschema.validate(schema, self.schema)
 
-    def generate(self, schema):
+    def generate_scenarios(self, schema, path=None):
         """
-        Generate an json dictionary based on a schema.
-        Only one value is mis-generated for each dictionary created.
+        Generates the scenario (all possible test cases) out of the given
+        schema.
 
-        Any generator must return a list of tuples or a single tuple.
-        The values of this tuple are:
-          result[0]: Name of the test
-          result[1]: json schema for the test
-          result[2]: expected result of the test (can be None)
+        :param schema: a dict style schema (see ``BasicGeneratorSet.schema``)
+        :param path: the schema path if the given schema is a subschema
         """
-        LOG.debug("generate_invalid: %s" % schema)
-        schema_type = schema["type"]
-        if isinstance(schema_type, list):
+        schema_type = schema['type']
+        scenarios = []
+
+        if schema_type == 'object':
+            properties = schema["properties"]
+            for attribute, definition in properties.iteritems():
+                current_path = copy.copy(path)
+                if path is not None:
+                    current_path.append(attribute)
+                else:
+                    current_path = [attribute]
+                scenarios.extend(
+                    self.generate_scenarios(definition, current_path))
+        elif isinstance(schema_type, list):
             if "integer" in schema_type:
                 schema_type = "integer"
             else:
                 raise Exception("non-integer list types not supported")
-        result = []
-        if schema_type not in self.types_dict:
-            raise TypeError("generator (%s) doesn't support type: %s"
-                            % (self.__class__.__name__, schema_type))
         for generator in self.types_dict[schema_type]:
-            ret = generator(schema)
-            if ret is not None:
-                if isinstance(ret, list):
-                    result.extend(ret)
-                elif isinstance(ret, tuple):
-                    result.append(ret)
-                else:
-                    raise Exception("generator (%s) returns invalid result: %s"
-                                    % (generator, ret))
-        LOG.debug("result: %s" % result)
-        return result
+            if hasattr(generator, "needed_property"):
+                prop = generator.needed_property
+                if (prop not in schema or
+                    schema[prop] is None or
+                    schema[prop] is False):
+                    continue
+
+            name = generator.__name__
+            if ("exclude_tests" in schema and
+               name in schema["exclude_tests"]):
+                continue
+            if path is not None:
+                name = "%s_%s" % ("_".join(path), name)
+            scenarios.append({
+                "_negtest_name": name,
+                "_negtest_generator": generator,
+                "_negtest_schema": schema,
+                "_negtest_path": path})
+        return scenarios
+
+    def generate_payload(self, test, schema):
+        """
+        Generates one jsonschema out of the given test. It's mandatory to use
+        generate_scenarios before to register all needed variables to the test.
+
+        :param test: A test object (scenario) with all _negtest variables on it
+        :param schema: schema for the test
+        """
+        generator = test._negtest_generator
+        ret = generator(test._negtest_schema)
+        path = copy.copy(test._negtest_path)
+        expected_result = None
+
+        if ret is not None:
+            generator_result = generator(test._negtest_schema)
+            invalid_snippet = generator_result[1]
+            expected_result = generator_result[2]
+            element = path.pop()
+            if len(path) > 0:
+                schema_snip = reduce(dict.get, path, schema)
+                schema_snip[element] = invalid_snippet
+            else:
+                schema[element] = invalid_snippet
+        return expected_result
diff --git a/tempest/common/generator/negative_generator.py b/tempest/common/generator/negative_generator.py
index 4f3d2cd..1d5ed43 100644
--- a/tempest/common/generator/negative_generator.py
+++ b/tempest/common/generator/negative_generator.py
@@ -47,65 +47,32 @@
         if min_length > 0:
             return "x" * (min_length - 1)
 
-    @base.generator_type("string")
+    @base.generator_type("string", needed_property="maxLength")
     @base.simple_generator
     def gen_str_max_length(self, schema):
         max_length = schema.get("maxLength", -1)
-        if max_length > -1:
-            return "x" * (max_length + 1)
+        return "x" * (max_length + 1)
 
-    @base.generator_type("integer")
+    @base.generator_type("integer", needed_property="minimum")
     @base.simple_generator
     def gen_int_min(self, schema):
-        if "minimum" in schema:
-            minimum = schema["minimum"]
-            if "exclusiveMinimum" not in schema:
-                minimum -= 1
-            return minimum
+        minimum = schema["minimum"]
+        if "exclusiveMinimum" not in schema:
+            minimum -= 1
+        return minimum
 
-    @base.generator_type("integer")
+    @base.generator_type("integer", needed_property="maximum")
     @base.simple_generator
     def gen_int_max(self, schema):
-        if "maximum" in schema:
-            maximum = schema["maximum"]
-            if "exclusiveMaximum" not in schema:
-                maximum += 1
-            return maximum
+        maximum = schema["maximum"]
+        if "exclusiveMaximum" not in schema:
+            maximum += 1
+        return maximum
 
-    @base.generator_type("object")
-    def gen_obj_remove_attr(self, schema):
-        invalids = []
-        valid_schema = valid.ValidTestGenerator().generate_valid(schema)
-        required = schema.get("required", [])
-        for r in required:
-            new_valid = copy.deepcopy(valid_schema)
-            del new_valid[r]
-            invalids.append(("gen_obj_remove_attr", new_valid, None))
-        return invalids
-
-    @base.generator_type("object")
+    @base.generator_type("object", needed_property="additionalProperties")
     @base.simple_generator
     def gen_obj_add_attr(self, schema):
         valid_schema = valid.ValidTestGenerator().generate_valid(schema)
-        if not schema.get("additionalProperties", True):
-            new_valid = copy.deepcopy(valid_schema)
-            new_valid["$$$$$$$$$$"] = "xxx"
-            return new_valid
-
-    @base.generator_type("object")
-    def gen_inv_prop_obj(self, schema):
-        LOG.debug("generate_invalid_object: %s" % schema)
-        valid_schema = valid.ValidTestGenerator().generate_valid(schema)
-        invalids = []
-        properties = schema["properties"]
-
-        for k, v in properties.iteritems():
-            for invalid in self.generate(v):
-                LOG.debug(v)
-                new_valid = copy.deepcopy(valid_schema)
-                new_valid[k] = invalid[1]
-                name = "prop_%s_%s" % (k, invalid[0])
-                invalids.append((name, new_valid, invalid[2]))
-
-        LOG.debug("generate_invalid_object return: %s" % invalids)
-        return invalids
+        new_valid = copy.deepcopy(valid_schema)
+        new_valid["$$$$$$$$$$"] = "xxx"
+        return new_valid
diff --git a/tempest/common/generator/valid_generator.py b/tempest/common/generator/valid_generator.py
index 0d7b398..7b80afc 100644
--- a/tempest/common/generator/valid_generator.py
+++ b/tempest/common/generator/valid_generator.py
@@ -54,5 +54,28 @@
             obj[k] = self.generate_valid(v)
         return obj
 
+    def generate(self, schema):
+        schema_type = schema["type"]
+        if isinstance(schema_type, list):
+            if "integer" in schema_type:
+                schema_type = "integer"
+            else:
+                raise Exception("non-integer list types not supported")
+        result = []
+        if schema_type not in self.types_dict:
+            raise TypeError("generator (%s) doesn't support type: %s"
+                            % (self.__class__.__name__, schema_type))
+        for generator in self.types_dict[schema_type]:
+            ret = generator(schema)
+            if ret is not None:
+                if isinstance(ret, list):
+                    result.extend(ret)
+                elif isinstance(ret, tuple):
+                    result.append(ret)
+                else:
+                    raise Exception("generator (%s) returns invalid result: %s"
+                                    % (generator, ret))
+        return result
+
     def generate_valid(self, schema):
         return self.generate(schema)[0][1]
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index dca1f86..228e47c 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -13,7 +13,6 @@
 #    under the License.
 
 import netaddr
-from neutronclient.common import exceptions as n_exc
 
 from tempest import auth
 from tempest import clients
@@ -29,15 +28,14 @@
 
 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)
+    def __init__(self, name, interface='json', password='pass',
+                 network_resources=None):
+        super(IsolatedCreds, self).__init__(name, interface, password,
+                                            network_resources)
         self.network_resources = network_resources
         self.isolated_creds = {}
         self.isolated_net_resources = {}
         self.ports = []
-        self.tempest_client = tempest_client
         self.interface = interface
         self.password = password
         self.identity_admin_client, self.network_admin_client = (
@@ -50,94 +48,50 @@
             identity
             network
         """
-        if self.tempest_client:
-            os = clients.AdminManager(interface=self.interface)
-        else:
-            os = clients.OfficialClientManager(
-                auth.get_default_credentials('identity_admin')
-            )
+        os = clients.AdminManager(interface=self.interface)
         return os.identity_client, os.network_client
 
     def _create_tenant(self, name, description):
-        if self.tempest_client:
-            _, tenant = self.identity_admin_client.create_tenant(
-                name=name, description=description)
-        else:
-            tenant = self.identity_admin_client.tenants.create(
-                name,
-                description=description)
+        _, tenant = self.identity_admin_client.create_tenant(
+            name=name, description=description)
         return tenant
 
     def _get_tenant_by_name(self, name):
-        if self.tempest_client:
-            _, tenant = self.identity_admin_client.get_tenant_by_name(name)
-        else:
-            tenants = self.identity_admin_client.tenants.list()
-            for ten in tenants:
-                if ten['name'] == name:
-                    tenant = ten
-                    break
-            else:
-                raise exceptions.NotFound('No such tenant')
+        _, tenant = self.identity_admin_client.get_tenant_by_name(name)
         return tenant
 
     def _create_user(self, username, password, tenant, email):
-        if self.tempest_client:
-            _, user = self.identity_admin_client.create_user(username,
-                                                             password,
-                                                             tenant['id'],
-                                                             email)
-        else:
-            user = self.identity_admin_client.users.create(username, password,
-                                                           email,
-                                                           tenant_id=tenant.id)
+        _, user = self.identity_admin_client.create_user(
+            username, password, tenant['id'], email)
         return user
 
     def _get_user(self, tenant, username):
-        if self.tempest_client:
-            _, user = self.identity_admin_client.get_user_by_username(
-                tenant['id'],
-                username)
-        else:
-            user = self.identity_admin_client.users.get(username)
+        _, user = self.identity_admin_client.get_user_by_username(
+            tenant['id'], username)
         return user
 
     def _list_roles(self):
-        if self.tempest_client:
-            _, roles = self.identity_admin_client.list_roles()
-        else:
-            roles = self.identity_admin_client.roles.list()
+        _, roles = self.identity_admin_client.list_roles()
         return roles
 
     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)
+            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['id'],
-                                                        user['id'], role['id'])
-        else:
-            self.identity_admin_client.roles.add_user_role(user.id, role.id,
-                                                           tenant.id)
+        self.identity_admin_client.assign_user_role(tenant['id'], user['id'],
+                                                    role['id'])
 
     def _delete_user(self, user):
-        if self.tempest_client:
-            self.identity_admin_client.delete_user(user)
-        else:
-            self.identity_admin_client.users.delete(user)
+        self.identity_admin_client.delete_user(user)
 
     def _delete_tenant(self, tenant):
-        if self.tempest_client:
-            self.identity_admin_client.delete_tenant(tenant)
-        else:
-            self.identity_admin_client.tenants.delete(tenant)
+        if CONF.service_available.neutron:
+            self._cleanup_default_secgroup(tenant)
+        self.identity_admin_client.delete_tenant(tenant)
 
     def _create_creds(self, suffix="", admin=False):
         """Create random credentials under the following schema.
@@ -173,15 +127,9 @@
         return self._get_credentials(user, tenant)
 
     def _get_credentials(self, user, tenant):
-        if self.tempest_client:
-            user_get = user.get
-            tenant_get = tenant.get
-        else:
-            user_get = user.__dict__.get
-            tenant_get = tenant.__dict__.get
         return auth.get_credentials(
-            username=user_get('name'), user_id=user_get('id'),
-            tenant_name=tenant_get('name'), tenant_id=tenant_get('id'),
+            username=user['name'], user_id=user['id'],
+            tenant_name=tenant['name'], tenant_id=tenant['id'],
             password=self.password)
 
     def _create_network_resources(self, tenant_id):
@@ -226,45 +174,32 @@
         return network, subnet, router
 
     def _create_network(self, name, tenant_id):
-        if self.tempest_client:
-            resp, resp_body = self.network_admin_client.create_network(
-                name=name, tenant_id=tenant_id)
-        else:
-            body = {'network': {'tenant_id': tenant_id, 'name': name}}
-            resp_body = self.network_admin_client.create_network(body)
+        _, resp_body = self.network_admin_client.create_network(
+            name=name, tenant_id=tenant_id)
         return resp_body['network']
 
     def _create_subnet(self, subnet_name, tenant_id, network_id):
-        if not self.tempest_client:
-            body = {'subnet': {'name': subnet_name, 'tenant_id': tenant_id,
-                               'network_id': network_id, 'ip_version': 4}}
-            if self.network_resources:
-                body['enable_dhcp'] = self.network_resources['dhcp']
         base_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
         mask_bits = CONF.network.tenant_network_mask_bits
         for subnet_cidr in base_cidr.subnet(mask_bits):
             try:
-                if self.tempest_client:
-                    if self.network_resources:
-                        resp, resp_body = self.network_admin_client.\
-                            create_subnet(
-                                network_id=network_id, cidr=str(subnet_cidr),
-                                name=subnet_name,
-                                tenant_id=tenant_id,
-                                enable_dhcp=self.network_resources['dhcp'],
-                                ip_version=4)
-                    else:
-                        resp, resp_body = self.network_admin_client.\
-                            create_subnet(network_id=network_id,
-                                          cidr=str(subnet_cidr),
-                                          name=subnet_name,
-                                          tenant_id=tenant_id,
-                                          ip_version=4)
+                if self.network_resources:
+                    _, resp_body = self.network_admin_client.\
+                        create_subnet(
+                            network_id=network_id, cidr=str(subnet_cidr),
+                            name=subnet_name,
+                            tenant_id=tenant_id,
+                            enable_dhcp=self.network_resources['dhcp'],
+                            ip_version=4)
                 else:
-                    body['subnet']['cidr'] = str(subnet_cidr)
-                    resp_body = self.network_admin_client.create_subnet(body)
+                    _, resp_body = self.network_admin_client.\
+                        create_subnet(network_id=network_id,
+                                      cidr=str(subnet_cidr),
+                                      name=subnet_name,
+                                      tenant_id=tenant_id,
+                                      ip_version=4)
                 break
-            except (n_exc.BadRequest, exceptions.BadRequest) as e:
+            except exceptions.BadRequest as e:
                 if 'overlaps with another subnet' not in str(e):
                     raise
         else:
@@ -276,25 +211,15 @@
     def _create_router(self, router_name, tenant_id):
         external_net_id = dict(
             network_id=CONF.network.public_network_id)
-        if self.tempest_client:
-            resp, resp_body = self.network_admin_client.create_router(
-                router_name,
-                external_gateway_info=external_net_id,
-                tenant_id=tenant_id)
-        else:
-            body = {'router': {'name': router_name, 'tenant_id': tenant_id,
-                               'external_gateway_info': external_net_id,
-                               'admin_state_up': True}}
-            resp_body = self.network_admin_client.create_router(body)
+        _, resp_body = self.network_admin_client.create_router(
+            router_name,
+            external_gateway_info=external_net_id,
+            tenant_id=tenant_id)
         return resp_body['router']
 
     def _add_router_interface(self, router_id, subnet_id):
-        if self.tempest_client:
-            self.network_admin_client.add_router_interface_with_subnet_id(
-                router_id, subnet_id)
-        else:
-            body = {'subnet_id': subnet_id}
-            self.network_admin_client.add_interface_router(router_id, body)
+        self.network_admin_client.add_router_interface_with_subnet_id(
+            router_id, subnet_id)
 
     def get_primary_network(self):
         return self.isolated_net_resources.get('primary')[0]
@@ -376,6 +301,18 @@
             LOG.warn('network with name: %s not found for delete' %
                      network_name)
 
+    def _cleanup_default_secgroup(self, tenant):
+        net_client = self.network_admin_client
+        _, resp_body = net_client.list_security_groups(tenant_id=tenant,
+                                                       name="default")
+        secgroups_to_delete = resp_body['security_groups']
+        for secgroup in secgroups_to_delete:
+            try:
+                net_client.delete_security_group(secgroup['id'])
+            except exceptions.NotFound:
+                LOG.warn('Security group %s, id %s not found for clean-up' %
+                         (secgroup['name'], secgroup['id']))
+
     def _clear_isolated_net_resources(self):
         net_client = self.network_admin_client
         for cred in self.isolated_net_resources:
@@ -386,12 +323,8 @@
             if (not self.network_resources or
                 self.network_resources.get('router')):
                 try:
-                    if self.tempest_client:
-                        net_client.remove_router_interface_with_subnet_id(
-                            router['id'], subnet['id'])
-                    else:
-                        body = {'subnet_id': subnet['id']}
-                        net_client.remove_interface_router(router['id'], body)
+                    net_client.remove_router_interface_with_subnet_id(
+                        router['id'], subnet['id'])
                 except exceptions.NotFound:
                     LOG.warn('router with name: %s not found for delete' %
                              router['name'])
@@ -418,3 +351,9 @@
             except exceptions.NotFound:
                 LOG.warn("tenant with name: %s not found for delete" %
                          creds.tenant_name)
+
+    def is_multi_user(self):
+        return True
+
+    def is_multi_tenant(self):
+        return True
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 132d0a6..6f2e1bd 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -16,12 +16,13 @@
 
 import collections
 import json
+import logging as real_logging
 import re
-import string
 import time
 
 import jsonschema
 from lxml import etree
+import six
 
 from tempest.common import http
 from tempest.common.utils import misc as misc_utils
@@ -36,8 +37,21 @@
 MAX_RECURSION_DEPTH = 2
 TOKEN_CHARS_RE = re.compile('^[-A-Za-z0-9+/=]*$')
 
-# All the successful HTTP status codes from RFC 2616
-HTTP_SUCCESS = (200, 201, 202, 203, 204, 205, 206)
+# All the successful HTTP status codes from RFC 7231 & 4918
+HTTP_SUCCESS = (200, 201, 202, 203, 204, 205, 206, 207)
+
+
+# convert a structure into a string safely
+def safe_body(body, maxlen=4096):
+    try:
+        text = six.text_type(body)
+    except UnicodeDecodeError:
+        # if this isn't actually text, return marker that
+        return "<BinaryData: removed>"
+    if len(text) > maxlen:
+        return text[:maxlen]
+    else:
+        return text
 
 
 class RestClient(object):
@@ -195,8 +209,9 @@
     @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)
+                      "codes which explicitly defined in the RFC 7231 & 4918."
+                      "{0} is not a defined Success Code!"
+                      ).format(expected_code)
         if isinstance(expected_code, list):
             for code in expected_code:
                 assert code in HTTP_SUCCESS, assert_msg
@@ -258,6 +273,31 @@
             self.LOG.debug('Starting Request (%s): %s %s' %
                            (caller_name, method, req_url))
 
+    def _log_request_full(self, method, req_url, resp,
+                          secs="", req_headers=None,
+                          req_body=None, resp_body=None,
+                          caller_name=None, extra=None):
+        if 'X-Auth-Token' in req_headers:
+            req_headers['X-Auth-Token'] = '<omitted>'
+        log_fmt = """Request (%s): %s %s %s%s
+    Request - Headers: %s
+        Body: %s
+    Response - Headers: %s
+        Body: %s"""
+
+        self.LOG.debug(
+            log_fmt % (
+                caller_name,
+                resp['status'],
+                method,
+                req_url,
+                secs,
+                str(req_headers),
+                safe_body(req_body),
+                str(resp),
+                safe_body(resp_body)),
+            extra=extra)
+
     def _log_request(self, method, req_url, resp,
                      secs="", req_headers=None,
                      req_body=None, resp_body=None):
@@ -272,42 +312,21 @@
         caller_name = misc_utils.find_test_caller()
         if secs:
             secs = " %.3fs" % secs
-        self.LOG.info(
-            'Request (%s): %s %s %s%s' % (
-                caller_name,
-                resp['status'],
-                method,
-                req_url,
-                secs),
-            extra=extra)
-
-        # We intentionally duplicate the info content because in a parallel
-        # world this is important to match
-        trace_regex = CONF.debug.trace_requests
-        if trace_regex and re.search(trace_regex, caller_name):
-            if 'X-Auth-Token' in req_headers:
-                req_headers['X-Auth-Token'] = '<omitted>'
-            log_fmt = """Request (%s): %s %s %s%s
-    Request - Headers: %s
-        Body: %s
-    Response - Headers: %s
-        Body: %s"""
-
-            self.LOG.debug(
-                log_fmt % (
+        if not self.LOG.isEnabledFor(real_logging.DEBUG):
+            self.LOG.info(
+                'Request (%s): %s %s %s%s' % (
                     caller_name,
                     resp['status'],
                     method,
                     req_url,
-                    secs,
-                    str(req_headers),
-                    filter(lambda x: x in string.printable,
-                           str(req_body)[:2048]),
-                    str(resp),
-                    filter(lambda x: x in string.printable,
-                           str(resp_body)[:2048])),
+                    secs),
                 extra=extra)
 
+        # Also look everything at DEBUG if you want to filter this
+        # out, don't run at debug.
+        self._log_request_full(method, req_url, resp, secs, req_headers,
+                               req_body, resp_body, caller_name, extra)
+
     def _parse_resp(self, body):
         if self._get_type() is "json":
             body = json.loads(body)
@@ -552,7 +571,14 @@
             if self.is_resource_deleted(id):
                 return
             if int(time.time()) - start_time >= self.build_timeout:
-                raise exceptions.TimeoutException
+                message = ('Failed to delete %(resource_type)s %(id)s within '
+                           'the required time (%(timeout)s s).' %
+                           {'resource_type': self.resource_type, 'id': id,
+                            'timeout': self.build_timeout})
+                caller = misc_utils.find_test_caller()
+                if caller:
+                    message = '(%s) %s' % (caller, message)
+                raise exceptions.TimeoutException(message)
             time.sleep(self.build_interval)
 
     def is_resource_deleted(self, id):
@@ -563,6 +589,11 @@
                    % self.__class__.__name__)
         raise NotImplementedError(message)
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'resource'
+
     @classmethod
     def validate_response(cls, schema, resp, body):
         # Only check the response if the status code is a success code
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 89904b2..6a238d0 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -91,7 +91,7 @@
         return self.exec_command(cmd)
 
     def get_mac_address(self):
-        cmd = "/sbin/ifconfig | awk '/HWaddr/ {print $5}'"
+        cmd = "/bin/ip addr | awk '/ether/ {print $2}'"
         return self.exec_command(cmd)
 
     def get_ip_list(self):
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index c4f1214..52568cb 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -131,3 +131,31 @@
             if caller:
                 message = '(%s) %s' % (caller, message)
             raise exceptions.TimeoutException(message)
+
+
+def wait_for_bm_node_status(client, node_id, attr, status):
+    """Waits for a baremetal node attribute to reach given status.
+
+    The client should have a show_node(node_uuid) method to get the node.
+    """
+    _, node = client.show_node(node_id)
+    start = int(time.time())
+
+    while node[attr] != status:
+        time.sleep(client.build_interval)
+        _, node = client.show_node(node_id)
+        if node[attr] == status:
+            return
+
+        if int(time.time()) - start >= client.build_timeout:
+            message = ('Node %(node_id)s failed to reach %(attr)s=%(status)s '
+                       'within the required time (%(timeout)s s).' %
+                       {'node_id': node_id,
+                        'attr': attr,
+                        'status': status,
+                        'timeout': client.build_timeout})
+            message += ' Current state of %s: %s.' % (attr, node[attr])
+            caller = misc_utils.find_test_caller()
+            if caller:
+                message = '(%s) %s' % (caller, message)
+            raise exceptions.TimeoutException(message)
diff --git a/tempest/config.py b/tempest/config.py
index 93d4874..616a476 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -20,6 +20,7 @@
 
 from oslo.config import cfg
 
+from tempest.openstack.common import lockutils
 from tempest.openstack.common import log as logging
 
 
@@ -38,9 +39,28 @@
                default='etc/accounts.yaml',
                help="Path to the yaml file that contains the list of "
                     "credentials to use for running tests"),
+    cfg.BoolOpt('allow_tenant_isolation',
+                default=False,
+                help="Allows test cases to create/destroy tenants and "
+                     "users. This option requires that OpenStack Identity "
+                     "API admin credentials are known. If false, isolated "
+                     "test cases and parallel execution, can still be "
+                     "achieved configuring a list of test accounts",
+                deprecated_opts=[cfg.DeprecatedOpt('allow_tenant_isolation',
+                                                   group='compute'),
+                                 cfg.DeprecatedOpt('allow_tenant_isolation',
+                                                   group='orchestration')]),
+    cfg.BoolOpt('locking_credentials_provider',
+                default=False,
+                help="If set to True it enables the Accounts provider, "
+                     "which locks credentials to allow for parallel execution "
+                     "with pre-provisioned accounts. It can only be used to "
+                     "run tests that ensure credentials cleanup happens. "
+                     "It requires at least `2 * CONC` distinct accounts "
+                     "configured in `test_accounts_file`, with CONC == the "
+                     "number of concurrent test processes."),
 ]
 
-
 identity_group = cfg.OptGroup(name='identity',
                               title="Keystone Configuration Options")
 
@@ -123,18 +143,15 @@
     cfg.BoolOpt('api_v3',
                 default=True,
                 help='Is the v3 identity API enabled'),
+    cfg.BoolOpt('xml_api',
+                default=False,
+                help='If false, skip all identity api tests with xml'),
 ]
 
 compute_group = cfg.OptGroup(name='compute',
                              title='Compute Service Options')
 
 ComputeGroup = [
-    cfg.BoolOpt('allow_tenant_isolation',
-                default=False,
-                help="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 admin credentials are known."),
     cfg.StrOpt('image_ref',
                help="Valid primary image reference to be used in tests. "
                     "This is a required option"),
@@ -205,10 +222,12 @@
                     "channel."),
     cfg.StrOpt('fixed_network_name',
                default='private',
-               help="Visible fixed network name "),
+               help="Name of the fixed network that is visible to all test "
+                    "tenants."),
     cfg.StrOpt('network_for_ssh',
                default='public',
-               help="Network used for SSH connections."),
+               help="Network used for SSH connections. Ignored if "
+                    "use_floatingip_for_ssh=true or run_ssh=false."),
     cfg.IntOpt('ip_version_for_ssh',
                default=4,
                help="IP version used for SSH connections."),
@@ -249,7 +268,9 @@
     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.')
+                    'test the floating IP bulk feature for CRUD operation. '
+                    'This block must not overlap an existing floating IP '
+                    'pool.')
 ]
 
 compute_features_group = cfg.OptGroup(name='compute-feature-enabled',
@@ -298,7 +319,7 @@
                 default=True,
                 help="Does the test environment support suspend/resume?"),
     cfg.BoolOpt('live_migration',
-                default=False,
+                default=True,
                 help="Does the test environment support live migration "
                      "available?"),
     cfg.BoolOpt('block_migration_for_live_migration',
@@ -419,10 +440,10 @@
                default=28,
                help="The mask bits for tenant ipv4 subnets"),
     cfg.StrOpt('tenant_network_v6_cidr',
-               default="2003::/64",
+               default="2003::/48",
                help="The cidr block to allocate tenant ipv6 subnets from"),
     cfg.IntOpt('tenant_network_v6_mask_bits',
-               default=96,
+               default=64,
                help="The mask bits for tenant ipv6 subnets"),
     cfg.BoolOpt('tenant_networks_reachable',
                 default=False,
@@ -435,7 +456,9 @@
     cfg.StrOpt('public_router_id',
                default="",
                help="Id of the public router that provides external "
-                    "connectivity"),
+                    "connectivity. This should only be used when Neutron's "
+                    "'allow_overlapping_ips' is set to 'False' in "
+                    "neutron.conf. usually not needed past 'Grizzly' release"),
     cfg.IntOpt('build_timeout',
                default=300,
                help="Timeout in seconds to wait for network operation to "
@@ -467,16 +490,19 @@
                 help="Allow the execution of IPv6 subnet tests that use "
                      "the extended IPv6 attributes ipv6_ra_mode "
                      "and ipv6_address_mode"
-                )
+                ),
+    cfg.BoolOpt('xml_api',
+                default=False,
+                help='If false, skip all network api tests with xml')
 ]
 
-queuing_group = cfg.OptGroup(name='queuing',
-                             title='Queuing Service')
+messaging_group = cfg.OptGroup(name='messaging',
+                               title='Messaging Service')
 
-QueuingGroup = [
+MessagingGroup = [
     cfg.StrOpt('catalog_type',
-               default='queuing',
-               help='Catalog type of the Queuing service.'),
+               default='messaging',
+               help='Catalog type of the Messaging service.'),
     cfg.IntOpt('max_queues_per_page',
                default=20,
                help='The maximum number of queue records per page when '
@@ -514,7 +540,7 @@
                help='Time in seconds between volume availability checks.'),
     cfg.IntOpt('build_timeout',
                default=300,
-               help='Timeout in seconds to wait for a volume to become'
+               help='Timeout in seconds to wait for a volume to become '
                     'available.'),
     cfg.StrOpt('catalog_type',
                default='volume',
@@ -622,6 +648,15 @@
                 help="A list of the enabled optional discoverable apis. "
                      "A single entry, all, indicates that all of these "
                      "features are expected to be enabled"),
+    cfg.BoolOpt('container_sync',
+                default=True,
+                help="Execute (old style) container-sync tests"),
+    cfg.BoolOpt('object_versioning',
+                default=True,
+                help="Execute object-versioning tests"),
+    cfg.BoolOpt('discoverability',
+                default=True,
+                help="Execute discoverability tests"),
 ]
 
 database_group = cfg.OptGroup(name='database',
@@ -657,12 +692,6 @@
                choices=['public', 'admin', 'internal',
                         'publicURL', 'adminURL', 'internalURL'],
                help="The endpoint type to use for the orchestration service."),
-    cfg.BoolOpt('allow_tenant_isolation',
-                default=False,
-                help="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 admin credentials are known."),
     cfg.IntOpt('build_interval',
                default=1,
                help="Time in seconds between build status checks."),
@@ -950,7 +979,14 @@
 
 
 baremetal_group = cfg.OptGroup(name='baremetal',
-                               title='Baremetal provisioning service options')
+                               title='Baremetal provisioning service options',
+                               help='When enabling baremetal tests, Nova '
+                                    'must be configured to use the Ironic '
+                                    'driver. The following paremeters for the '
+                                    '[compute] section must be disabled: '
+                                    'console_output, interface_attach, '
+                                    'live_migration, pause, rescue, resize '
+                                    'shelve, snapshot, and suspend')
 
 BaremetalGroup = [
     cfg.StrOpt('catalog_type',
@@ -1011,44 +1047,60 @@
                help="Test generator class for all negative tests"),
 ]
 
+_opts = [
+    (auth_group, AuthGroup),
+    (compute_group, ComputeGroup),
+    (compute_features_group, ComputeFeaturesGroup),
+    (identity_group, IdentityGroup),
+    (identity_feature_group, IdentityFeatureGroup),
+    (image_group, ImageGroup),
+    (image_feature_group, ImageFeaturesGroup),
+    (network_group, NetworkGroup),
+    (network_feature_group, NetworkFeaturesGroup),
+    (messaging_group, MessagingGroup),
+    (volume_group, VolumeGroup),
+    (volume_feature_group, VolumeFeaturesGroup),
+    (object_storage_group, ObjectStoreGroup),
+    (object_storage_feature_group, ObjectStoreFeaturesGroup),
+    (database_group, DatabaseGroup),
+    (orchestration_group, OrchestrationGroup),
+    (telemetry_group, TelemetryGroup),
+    (dashboard_group, DashboardGroup),
+    (data_processing_group, DataProcessingGroup),
+    (boto_group, BotoGroup),
+    (compute_admin_group, ComputeAdminGroup),
+    (stress_group, StressGroup),
+    (scenario_group, ScenarioGroup),
+    (service_available_group, ServiceAvailableGroup),
+    (debug_group, DebugGroup),
+    (baremetal_group, BaremetalGroup),
+    (input_scenario_group, InputScenarioGroup),
+    (cli_group, CLIGroup),
+    (negative_group, NegativeGroup)
+]
+
 
 def register_opts():
-    register_opt_group(cfg.CONF, auth_group, AuthGroup)
-    register_opt_group(cfg.CONF, compute_group, ComputeGroup)
-    register_opt_group(cfg.CONF, compute_features_group,
-                       ComputeFeaturesGroup)
-    register_opt_group(cfg.CONF, identity_group, IdentityGroup)
-    register_opt_group(cfg.CONF, identity_feature_group,
-                       IdentityFeatureGroup)
-    register_opt_group(cfg.CONF, image_group, ImageGroup)
-    register_opt_group(cfg.CONF, image_feature_group, ImageFeaturesGroup)
-    register_opt_group(cfg.CONF, network_group, NetworkGroup)
-    register_opt_group(cfg.CONF, network_feature_group,
-                       NetworkFeaturesGroup)
-    register_opt_group(cfg.CONF, queuing_group, QueuingGroup)
-    register_opt_group(cfg.CONF, volume_group, VolumeGroup)
-    register_opt_group(cfg.CONF, volume_feature_group,
-                       VolumeFeaturesGroup)
-    register_opt_group(cfg.CONF, object_storage_group, ObjectStoreGroup)
-    register_opt_group(cfg.CONF, object_storage_feature_group,
-                       ObjectStoreFeaturesGroup)
-    register_opt_group(cfg.CONF, database_group, DatabaseGroup)
-    register_opt_group(cfg.CONF, orchestration_group, OrchestrationGroup)
-    register_opt_group(cfg.CONF, telemetry_group, TelemetryGroup)
-    register_opt_group(cfg.CONF, dashboard_group, DashboardGroup)
-    register_opt_group(cfg.CONF, data_processing_group,
-                       DataProcessingGroup)
-    register_opt_group(cfg.CONF, boto_group, BotoGroup)
-    register_opt_group(cfg.CONF, compute_admin_group, ComputeAdminGroup)
-    register_opt_group(cfg.CONF, stress_group, StressGroup)
-    register_opt_group(cfg.CONF, scenario_group, ScenarioGroup)
-    register_opt_group(cfg.CONF, service_available_group,
-                       ServiceAvailableGroup)
-    register_opt_group(cfg.CONF, debug_group, DebugGroup)
-    register_opt_group(cfg.CONF, baremetal_group, BaremetalGroup)
-    register_opt_group(cfg.CONF, input_scenario_group, InputScenarioGroup)
-    register_opt_group(cfg.CONF, cli_group, CLIGroup)
-    register_opt_group(cfg.CONF, negative_group, NegativeGroup)
+    for g, o in _opts:
+        register_opt_group(cfg.CONF, g, o)
+
+
+def list_opts():
+    """Return a list of oslo.config options available.
+
+    The purpose of this is to allow tools like the Oslo sample config file
+    generator to discover the options exposed to users.
+    """
+    optlist = [(g.name, o) for g, o in _opts]
+
+    # NOTE(jgrimm): Can be removed once oslo-incubator/oslo changes happen.
+    optlist.append((None, lockutils.util_opts))
+    optlist.append((None, logging.common_cli_opts))
+    optlist.append((None, logging.logging_cli_opts))
+    optlist.append((None, logging.generic_log_opts))
+    optlist.append((None, logging.log_opts))
+
+    return optlist
 
 
 # this should never be called outside of this class
@@ -1082,7 +1134,7 @@
             'object-storage-feature-enabled']
         self.database = cfg.CONF.database
         self.orchestration = cfg.CONF.orchestration
-        self.queuing = cfg.CONF.queuing
+        self.messaging = cfg.CONF.messaging
         self.telemetry = cfg.CONF.telemetry
         self.dashboard = cfg.CONF.dashboard
         self.data_processing = cfg.CONF.data_processing
@@ -1132,8 +1184,10 @@
         # to remove an issue with the config file up to date checker.
         if parse_conf:
             config_files.append(path)
-
-        cfg.CONF([], project='tempest', default_config_files=config_files)
+        if os.path.isfile(path):
+            cfg.CONF([], project='tempest', default_config_files=config_files)
+        else:
+            cfg.CONF([], project='tempest')
         logging.setup('tempest')
         LOG = logging.getLogger('tempest')
         LOG.info("Using tempest config file %s" % path)
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index abc60cb..6014cff 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -24,7 +24,7 @@
 
 PYTHON_CLIENT_RE = re.compile('import (%s)client' % '|'.join(PYTHON_CLIENTS))
 TEST_DEFINITION = re.compile(r'^\s*def test.*')
-SETUPCLASS_DEFINITION = re.compile(r'^\s*def setUpClass')
+SETUP_TEARDOWN_CLASS_DEFINITION = re.compile(r'^\s+def (setUp|tearDown)Class')
 SCENARIO_DECORATOR = re.compile(r'\s*@.*services\((.*)\)')
 VI_HEADER_RE = re.compile(r"^#\s+vim?:.+")
 mutable_default_args = re.compile(r"^\s*def .+\((.+=\{\}|.+=\[\])")
@@ -58,15 +58,15 @@
                         "T104: Scenario tests require a service decorator")
 
 
-def no_setupclass_for_unit_tests(physical_line, filename):
+def no_setup_teardown_class_for_tests(physical_line, filename):
 
     if pep8.noqa(physical_line):
         return
 
-    if 'tempest/tests' in filename:
-        if SETUPCLASS_DEFINITION.match(physical_line):
+    if 'tempest/test.py' not in filename:
+        if SETUP_TEARDOWN_CLASS_DEFINITION.match(physical_line):
             return (physical_line.find('def'),
-                    "T105: setUpClass can not be used with unit tests")
+                    "T105: (setUp|tearDown)Class can not be used in tests")
 
 
 def no_vi_headers(physical_line, line_number, lines):
@@ -106,20 +106,6 @@
                             "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 no_mutable_default_args(logical_line):
     """Check that mutable object isn't used as default argument
 
@@ -133,8 +119,7 @@
 def factory(register):
     register(import_no_clients_in_api)
     register(scenario_tests_need_service_tags)
-    register(no_setupclass_for_unit_tests)
+    register(no_setup_teardown_class_for_tests)
     register(no_vi_headers)
     register(service_tags_not_in_module_path)
-    register(no_official_client_manager_in_api_tests)
     register(no_mutable_default_args)
diff --git a/tempest/manager.py b/tempest/manager.py
index fb2842f..538b619 100644
--- a/tempest/manager.py
+++ b/tempest/manager.py
@@ -51,18 +51,17 @@
         self.client_attr_names = []
 
     @classmethod
-    def get_auth_provider_class(cls, auth_version):
-        if auth_version == 'v2':
-            return auth.KeystoneV2AuthProvider
-        else:
+    def get_auth_provider_class(cls, credentials):
+        if isinstance(credentials, auth.KeystoneV3Credentials):
             return auth.KeystoneV3AuthProvider
+        else:
+            return auth.KeystoneV2AuthProvider
 
     def get_auth_provider(self, credentials):
         if credentials is None:
             raise exceptions.InvalidCredentials(
                 'Credentials must be specified')
-        auth_provider_class = self.get_auth_provider_class(self.auth_version)
+        auth_provider_class = self.get_auth_provider_class(credentials)
         return auth_provider_class(
-            client_type=getattr(self, 'client_type', None),
             interface=getattr(self, 'interface', None),
             credentials=credentials)
diff --git a/tempest/openstack/common/__init__.py b/tempest/openstack/common/__init__.py
index d1223ea..e69de29 100644
--- a/tempest/openstack/common/__init__.py
+++ b/tempest/openstack/common/__init__.py
@@ -1,17 +0,0 @@
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-import six
-
-
-six.add_move(six.MovedModule('mox', 'mox', 'mox3.mox'))
diff --git a/tempest/openstack/common/_i18n.py b/tempest/openstack/common/_i18n.py
new file mode 100644
index 0000000..fdc8327
--- /dev/null
+++ b/tempest/openstack/common/_i18n.py
@@ -0,0 +1,45 @@
+#    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.
+
+"""oslo.i18n integration module.
+
+See http://docs.openstack.org/developer/oslo.i18n/usage.html
+
+"""
+
+try:
+    import oslo.i18n
+
+    # NOTE(dhellmann): This reference to o-s-l-o will be replaced by the
+    # application name when this module is synced into the separate
+    # repository. It is OK to have more than one translation function
+    # using the same domain, since there will still only be one message
+    # catalog.
+    _translators = oslo.i18n.TranslatorFactory(domain='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
+except ImportError:
+    # NOTE(dims): Support for cases where a project wants to use
+    # code from tempest-incubator, but is not ready to be internationalized
+    # (like tempest)
+    _ = _LI = _LW = _LE = _LC = lambda x: x
diff --git a/tempest/openstack/common/config/__init__.py b/tempest/openstack/common/config/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/openstack/common/config/__init__.py
+++ /dev/null
diff --git a/tempest/openstack/common/config/generator.py b/tempest/openstack/common/config/generator.py
deleted file mode 100644
index 664200e..0000000
--- a/tempest/openstack/common/config/generator.py
+++ /dev/null
@@ -1,313 +0,0 @@
-# Copyright 2012 SINA Corporation
-# Copyright 2014 Cisco Systems, Inc.
-# 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.
-#
-
-"""Extracts OpenStack config option info from module(s)."""
-
-from __future__ import print_function
-
-import argparse
-import imp
-import os
-import re
-import socket
-import sys
-import textwrap
-
-from oslo.config import cfg
-import six
-import stevedore.named
-
-from tempest.openstack.common import gettextutils
-from tempest.openstack.common import importutils
-
-gettextutils.install('tempest')
-
-STROPT = "StrOpt"
-BOOLOPT = "BoolOpt"
-INTOPT = "IntOpt"
-FLOATOPT = "FloatOpt"
-LISTOPT = "ListOpt"
-DICTOPT = "DictOpt"
-MULTISTROPT = "MultiStrOpt"
-
-OPT_TYPES = {
-    STROPT: 'string value',
-    BOOLOPT: 'boolean value',
-    INTOPT: 'integer value',
-    FLOATOPT: 'floating point value',
-    LISTOPT: 'list value',
-    DICTOPT: 'dict value',
-    MULTISTROPT: 'multi valued',
-}
-
-OPTION_REGEX = re.compile(r"(%s)" % "|".join([STROPT, BOOLOPT, INTOPT,
-                                              FLOATOPT, LISTOPT, DICTOPT,
-                                              MULTISTROPT]))
-
-PY_EXT = ".py"
-BASEDIR = os.path.abspath(os.path.join(os.path.dirname(__file__),
-                                       "../../../../"))
-WORDWRAP_WIDTH = 60
-
-
-def raise_extension_exception(extmanager, ep, err):
-    raise
-
-
-def generate(argv):
-    parser = argparse.ArgumentParser(
-        description='generate sample configuration file',
-    )
-    parser.add_argument('-m', dest='modules', action='append')
-    parser.add_argument('-l', dest='libraries', action='append')
-    parser.add_argument('srcfiles', nargs='*')
-    parsed_args = parser.parse_args(argv)
-
-    mods_by_pkg = dict()
-    for filepath in parsed_args.srcfiles:
-        pkg_name = filepath.split(os.sep)[1]
-        mod_str = '.'.join(['.'.join(filepath.split(os.sep)[:-1]),
-                            os.path.basename(filepath).split('.')[0]])
-        mods_by_pkg.setdefault(pkg_name, list()).append(mod_str)
-    # NOTE(lzyeval): place top level modules before packages
-    pkg_names = sorted(pkg for pkg in mods_by_pkg if pkg.endswith(PY_EXT))
-    ext_names = sorted(pkg for pkg in mods_by_pkg if pkg not in pkg_names)
-    pkg_names.extend(ext_names)
-
-    # opts_by_group is a mapping of group name to an options list
-    # The options list is a list of (module, options) tuples
-    opts_by_group = {'DEFAULT': []}
-
-    if parsed_args.modules:
-        for module_name in parsed_args.modules:
-            module = _import_module(module_name)
-            if module:
-                for group, opts in _list_opts(module):
-                    opts_by_group.setdefault(group, []).append((module_name,
-                                                                opts))
-
-    # Look for entry points defined in libraries (or applications) for
-    # option discovery, and include their return values in the output.
-    #
-    # Each entry point should be a function returning an iterable
-    # of pairs with the group name (or None for the default group)
-    # and the list of Opt instances for that group.
-    if parsed_args.libraries:
-        loader = stevedore.named.NamedExtensionManager(
-            'oslo.config.opts',
-            names=list(set(parsed_args.libraries)),
-            invoke_on_load=False,
-            on_load_failure_callback=raise_extension_exception
-        )
-        for ext in loader:
-            for group, opts in ext.plugin():
-                opt_list = opts_by_group.setdefault(group or 'DEFAULT', [])
-                opt_list.append((ext.name, opts))
-
-    for pkg_name in pkg_names:
-        mods = mods_by_pkg.get(pkg_name)
-        mods.sort()
-        for mod_str in mods:
-            if mod_str.endswith('.__init__'):
-                mod_str = mod_str[:mod_str.rfind(".")]
-
-            mod_obj = _import_module(mod_str)
-            if not mod_obj:
-                raise RuntimeError("Unable to import module %s" % mod_str)
-
-            for group, opts in _list_opts(mod_obj):
-                opts_by_group.setdefault(group, []).append((mod_str, opts))
-
-    print_group_opts('DEFAULT', opts_by_group.pop('DEFAULT', []))
-    for group in sorted(opts_by_group.keys()):
-        print_group_opts(group, opts_by_group[group])
-
-
-def _import_module(mod_str):
-    try:
-        if mod_str.startswith('bin.'):
-            imp.load_source(mod_str[4:], os.path.join('bin', mod_str[4:]))
-            return sys.modules[mod_str[4:]]
-        else:
-            return importutils.import_module(mod_str)
-    except Exception as e:
-        sys.stderr.write("Error importing module %s: %s\n" % (mod_str, str(e)))
-        return None
-
-
-def _is_in_group(opt, 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.
-        if not(value['opt'] != opt):
-            return True
-    return False
-
-
-def _guess_groups(opt):
-    # is it in the DEFAULT group?
-    if _is_in_group(opt, cfg.CONF):
-        return 'DEFAULT'
-
-    # what other groups is it in?
-    for value in cfg.CONF.values():
-        if isinstance(value, cfg.CONF.GroupAttr):
-            if _is_in_group(opt, value._group):
-                return value._group.name
-
-    raise RuntimeError(
-        "Unable to find group for option %s, "
-        "maybe it's defined twice in the same group?"
-        % opt.name
-    )
-
-
-def _list_opts(obj):
-    def is_opt(o):
-        return (isinstance(o, cfg.Opt) and
-                not isinstance(o, cfg.SubCommandOpt))
-
-    opts = list()
-    for attr_str in dir(obj):
-        attr_obj = getattr(obj, attr_str)
-        if is_opt(attr_obj):
-            opts.append(attr_obj)
-        elif (isinstance(attr_obj, list) and
-              all(map(lambda x: is_opt(x), attr_obj))):
-            opts.extend(attr_obj)
-
-    ret = {}
-    for opt in opts:
-        ret.setdefault(_guess_groups(opt), []).append(opt)
-    return ret.items()
-
-
-def print_group_opts(group, opts_by_module):
-    print("[%s]" % group)
-    print('')
-    for mod, opts in opts_by_module:
-        print('#')
-        print('# Options defined in %s' % mod)
-        print('#')
-        print('')
-        for opt in opts:
-            _print_opt(opt)
-        print('')
-
-
-def _get_my_ip():
-    try:
-        csock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
-        csock.connect(('8.8.8.8', 80))
-        (addr, port) = csock.getsockname()
-        csock.close()
-        return addr
-    except socket.error:
-        return None
-
-
-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
-        # part.
-        value = os.path.normpath("/usr/" + value[len(sys.prefix):])
-    elif value.startswith(BASEDIR):
-        return value.replace(BASEDIR, '/usr/lib/python/site-packages')
-    elif BASEDIR in value:
-        return value.replace(BASEDIR, '')
-    elif value == _get_my_ip():
-        return '10.0.0.1'
-    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
-
-
-def _print_opt(opt):
-    opt_name, opt_default, opt_help = opt.dest, opt.default, opt.help
-    if not opt_help:
-        sys.stderr.write('WARNING: "%s" is missing help string.\n' % opt_name)
-        opt_help = ""
-    try:
-        opt_type = OPTION_REGEX.search(str(type(opt))).group(0)
-    except (ValueError, AttributeError) as err:
-        sys.stderr.write("%s\n" % str(err))
-        sys.exit(1)
-    opt_help = u'%s (%s)' % (opt_help,
-                             OPT_TYPES[opt_type])
-    print('#', "\n# ".join(textwrap.wrap(opt_help, WORDWRAP_WIDTH)))
-    if opt.deprecated_opts:
-        for deprecated_opt in opt.deprecated_opts:
-            if deprecated_opt.name:
-                deprecated_group = (deprecated_opt.group if
-                                    deprecated_opt.group else "DEFAULT")
-                print('# Deprecated group/name - [%s]/%s' %
-                      (deprecated_group,
-                       deprecated_opt.name))
-    try:
-        if opt_default is None:
-            print('#%s=<None>' % opt_name)
-        elif opt_type == STROPT:
-            assert(isinstance(opt_default, six.string_types))
-            print('#%s=%s' % (opt_name, _sanitize_default(opt_name,
-                                                          opt_default)))
-        elif opt_type == BOOLOPT:
-            assert(isinstance(opt_default, bool))
-            print('#%s=%s' % (opt_name, str(opt_default).lower()))
-        elif opt_type == INTOPT:
-            assert(isinstance(opt_default, int) and
-                   not isinstance(opt_default, bool))
-            print('#%s=%s' % (opt_name, opt_default))
-        elif opt_type == FLOATOPT:
-            assert(isinstance(opt_default, float))
-            print('#%s=%s' % (opt_name, opt_default))
-        elif opt_type == LISTOPT:
-            assert(isinstance(opt_default, list))
-            print('#%s=%s' % (opt_name, ','.join(opt_default)))
-        elif opt_type == DICTOPT:
-            assert(isinstance(opt_default, dict))
-            opt_default_strlist = [str(key) + ':' + str(value)
-                                   for (key, value) in opt_default.items()]
-            print('#%s=%s' % (opt_name, ','.join(opt_default_strlist)))
-        elif opt_type == MULTISTROPT:
-            assert(isinstance(opt_default, list))
-            if not opt_default:
-                opt_default = ['']
-            for default in opt_default:
-                print('#%s=%s' % (opt_name, default))
-        print('')
-    except Exception:
-        sys.stderr.write('Error in option "%s"\n' % opt_name)
-        sys.exit(1)
-
-
-def main():
-    generate(sys.argv[1:])
-
-if __name__ == '__main__':
-    main()
diff --git a/tempest/openstack/common/log.py b/tempest/openstack/common/log.py
index 44102c0..26cd6ad 100644
--- a/tempest/openstack/common/log.py
+++ b/tempest/openstack/common/log.py
@@ -33,20 +33,20 @@
 import logging.config
 import logging.handlers
 import os
+import socket
 import sys
 import traceback
 
 from oslo.config import cfg
+from oslo.serialization import jsonutils
+from oslo.utils import importutils
 import six
 from six import moves
 
-from tempest.openstack.common.gettextutils import _
-from tempest.openstack.common import importutils
-from tempest.openstack.common import jsonutils
+_PY26 = sys.version_info[0:2] == (2, 6)
+
+from tempest.openstack.common._i18n import _
 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"
@@ -124,7 +124,9 @@
                       'qpid=WARN', 'sqlalchemy=WARN', 'suds=INFO',
                       'oslo.messaging=INFO', 'iso8601=WARN',
                       'requests.packages.urllib3.connectionpool=WARN',
-                      'urllib3.connectionpool=WARN']
+                      'urllib3.connectionpool=WARN', 'websocket=WARN',
+                      "keystonemiddleware=WARN", "routes.middleware=WARN",
+                      "stevedore=WARN"]
 
 log_opts = [
     cfg.StrOpt('logging_context_format_string',
@@ -227,6 +229,15 @@
     def audit(self, msg, *args, **kwargs):
         self.log(logging.AUDIT, msg, *args, **kwargs)
 
+    def isEnabledFor(self, level):
+        if _PY26:
+            # This method was added in python 2.7 (and it does the exact
+            # same logic, so we need to do the exact same logic so that
+            # python 2.6 has this capability as well).
+            return self.logger.isEnabledFor(level)
+        else:
+            return super(BaseLoggerAdapter, self).isEnabledFor(level)
+
 
 class LazyAdapter(BaseLoggerAdapter):
     def __init__(self, name='unknown', version='unknown'):
@@ -289,11 +300,10 @@
         self.warn(stdmsg, *args, **kwargs)
 
     def process(self, msg, kwargs):
-        # NOTE(mrodden): catch any Message/other object and
-        #                coerce to unicode before they can get
-        #                to the python logging and possibly
-        #                cause string encoding trouble
-        if not isinstance(msg, six.string_types):
+        # NOTE(jecarey): If msg is not unicode, coerce it into unicode
+        #                before it can get to the python logging and
+        #                possibly cause string encoding trouble
+        if not isinstance(msg, six.text_type):
             msg = six.text_type(msg)
 
         if 'extra' not in kwargs:
@@ -410,18 +420,20 @@
     sys.excepthook = _create_logging_excepthook(product_name)
 
 
-def set_defaults(logging_context_format_string,
+def set_defaults(logging_context_format_string=None,
                  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(
+    if default_log_levels is not None:
+        cfg.set_defaults(
             log_opts,
-            logging_context_format_string=logging_context_format_string,
             default_log_levels=default_log_levels)
+    if logging_context_format_string is not None:
+        cfg.set_defaults(
+            log_opts,
+            logging_context_format_string=logging_context_format_string)
 
 
 def _find_facility_from_conf():
@@ -470,18 +482,6 @@
     for handler in log_root.handlers:
         log_root.removeHandler(handler)
 
-    if CONF.use_syslog:
-        facility = _find_facility_from_conf()
-        # 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()
     if logpath:
         filelog = logging.handlers.WatchedFileHandler(logpath)
@@ -540,6 +540,20 @@
         else:
             logger.setLevel(level_name)
 
+    if CONF.use_syslog:
+        try:
+            facility = _find_facility_from_conf()
+            # TODO(bogdando) use the format provided by RFCSysLogHandler
+            #   after existing syslog format deprecation in J
+            if CONF.use_syslog_rfc_format:
+                syslog = RFCSysLogHandler(facility=facility)
+            else:
+                syslog = logging.handlers.SysLogHandler(facility=facility)
+            log_root.addHandler(syslog)
+        except socket.error:
+            log_root.error('Unable to add syslog handler. Verify that syslog '
+                           'is running.')
+
 
 _loggers = {}
 
@@ -609,6 +623,12 @@
     def format(self, record):
         """Uses contextstring if request_id is set, otherwise default."""
 
+        # NOTE(jecarey): If msg is not unicode, coerce it into unicode
+        #                before it can get to the python logging and
+        #                possibly cause string encoding trouble
+        if not isinstance(record.msg, six.text_type):
+            record.msg = six.text_type(record.msg)
+
         # store project info
         record.project = self.project
         record.version = self.version
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index f7db79d..ea4365e 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -16,29 +16,20 @@
 
 import logging
 import os
-import re
 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
-from novaclient import exceptions as nova_exceptions
 import six
 
-from tempest.api.network import common as net_common
 from tempest import auth
 from tempest import clients
+from tempest.common import credentials
 from tempest.common import debug
-from tempest.common import isolated_creds
 from tempest.common.utils import data_utils
 from tempest.common.utils.linux import remote_client
 from tempest import config
 from tempest import exceptions
 from tempest.openstack.common import log
-from tempest.openstack.common import timeutils
 from tempest.services.network import resources as net_resources
 import tempest.test
 
@@ -55,28 +46,21 @@
 
 
 class ScenarioTest(tempest.test.BaseTestCase):
-    """Replaces the OfficialClientTest base class.
-
-    Uses tempest own clients as opposed to OfficialClients.
-
-    Common differences:
-    - replace resource.attribute with resource['attribute']
-    - replace resouce.delete with delete_callable(resource['id'])
-    - replace local waiters with common / rest_client waiters
-    """
+    """Base class for scenario tests. Uses tempest own clients. """
 
     @classmethod
-    def setUpClass(cls):
-        super(ScenarioTest, cls).setUpClass()
-        # Using tempest client for isolated credentials as well
-        cls.isolated_creds = isolated_creds.IsolatedCreds(
-            cls.__name__, tempest_client=True,
-            network_resources=cls.network_resources)
+    def resource_setup(cls):
+        super(ScenarioTest, cls).resource_setup()
+        # TODO(andreaf) Some of the code from this resource_setup could be
+        # moved into `BaseTestCase`
+        cls.isolated_creds = credentials.get_isolated_credentials(
+            cls.__name__, network_resources=cls.network_resources)
         cls.manager = clients.Manager(
             credentials=cls.credentials()
         )
         cls.admin_manager = clients.Manager(cls.admin_credentials())
         # Clients (in alphabetical order)
+        cls.flavors_client = cls.manager.flavors_client
         cls.floating_ips_client = cls.manager.floating_ips_client
         # Glance image client v1
         cls.image_client = cls.manager.image_client
@@ -92,24 +76,23 @@
         cls.interface_client = cls.manager.interfaces_client
         # Neutron network client
         cls.network_client = cls.manager.network_client
-
-    @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
+        # Heat client
+        cls.orchestration_client = cls.manager.orchestration_client
 
     @classmethod
     def credentials(cls):
-        return cls._get_credentials(cls.isolated_creds.get_primary_creds,
-                                    'user')
+        return cls.isolated_creds.get_primary_creds()
+
+    @classmethod
+    def alt_credentials(cls):
+        return cls.isolated_creds.get_alt_creds()
 
     @classmethod
     def admin_credentials(cls):
-        return cls._get_credentials(cls.isolated_creds.get_admin_creds,
-                                    'identity_admin')
+        try:
+            return cls.isolated_creds.get_admin_creds()
+        except NotImplementedError:
+            raise cls.skipException('Admin Credentials are not available')
 
     # ## Methods to handle sync and async deletes
 
@@ -143,7 +126,7 @@
     def addCleanup_with_wait(self, waiter_callable, thing_id, thing_id_param,
                              cleanup_callable, cleanup_args=None,
                              cleanup_kwargs=None, ignore_error=True):
-        """Adds wait for ansyc resource deletion at the end of cleanups
+        """Adds wait for async resource deletion at the end of cleanups
 
         @param waiter_callable: callable to wait for the resource to delete
         @param thing_id: the id of the resource to be cleaned-up
@@ -181,11 +164,13 @@
     # The create_[resource] functions only return body and discard the
     # resp part which is not used in scenario tests
 
-    def create_keypair(self):
+    def create_keypair(self, client=None):
+        if not client:
+            client = self.keypairs_client
         name = data_utils.rand_name(self.__class__.__name__)
         # We don't need to create a keypair by pubkey in scenario
-        resp, body = self.keypairs_client.create_keypair(name)
-        self.addCleanup(self.keypairs_client.delete_keypair, name)
+        resp, body = client.create_keypair(name)
+        self.addCleanup(client.delete_keypair, name)
         return body
 
     def create_server(self, name=None, image=None, flavor=None,
@@ -208,26 +193,6 @@
         if create_kwargs is None:
             create_kwargs = {}
 
-        fixed_network_name = CONF.compute.fixed_network_name
-        if 'nics' not in create_kwargs and fixed_network_name:
-            _, networks = self.networks_client.list_networks()
-            # If several networks found, set the NetID on which to connect the
-            # server to avoid the following error "Multiple possible networks
-            # found, use a Network ID to be more specific."
-            # See Tempest #1250866
-            if len(networks) > 1:
-                for network in networks:
-                    if network['label'] == fixed_network_name:
-                        create_kwargs['nics'] = [{'net-id': network['id']}]
-                        break
-                # If we didn't find the network we were looking for :
-                else:
-                    msg = ("The network on which the NIC of the server must "
-                           "be connected can not be found : "
-                           "fixed_network_name=%s. Starting instance without "
-                           "specifying a network.") % fixed_network_name
-                    LOG.info(msg)
-
         LOG.debug("Creating a server (name: %s, image: %s, flavor: %s)",
                   name, image, flavor)
         _, server = self.servers_client.create_server(name, image, flavor,
@@ -257,14 +222,18 @@
         _, volume = self.volumes_client.create_volume(
             size=size, display_name=name, snapshot_id=snapshot_id,
             imageRef=imageRef, volume_type=volume_type)
+
         if wait_on_delete:
             self.addCleanup(self.volumes_client.wait_for_resource_deletion,
                             volume['id'])
-        self.addCleanup_with_wait(
-            waiter_callable=self.volumes_client.wait_for_resource_deletion,
-            thing_id=volume['id'], thing_id_param='id',
-            cleanup_callable=self.delete_wrapper,
-            cleanup_args=[self.volumes_client.delete_volume, volume['id']])
+            self.addCleanup(self.delete_wrapper,
+                            self.volumes_client.delete_volume, volume['id'])
+        else:
+            self.addCleanup_with_wait(
+                waiter_callable=self.volumes_client.wait_for_resource_deletion,
+                thing_id=volume['id'], thing_id_param='id',
+                cleanup_callable=self.delete_wrapper,
+                cleanup_args=[self.volumes_client.delete_volume, volume['id']])
 
         self.assertEqual(name, volume['display_name'])
         self.volumes_client.wait_for_volume_status(volume['id'], 'available')
@@ -332,8 +301,9 @@
         if isinstance(server_or_ip, six.string_types):
             ip = server_or_ip
         else:
-            network_name_for_ssh = CONF.compute.network_for_ssh
-            ip = server_or_ip.networks[network_name_for_ssh][0]
+            addr = server_or_ip['addresses'][CONF.compute.network_for_ssh][0]
+            ip = addr['addr']
+
         if username is None:
             username = CONF.scenario.ssh_user
         if private_key is None:
@@ -398,13 +368,23 @@
         LOG.debug("image:%s" % self.image)
 
     def _log_console_output(self, servers=None):
+        if not CONF.compute_feature_enabled.console_output:
+            LOG.debug('Console output not supported, cannot log')
+            return
         if not servers:
             _, servers = self.servers_client.list_servers()
             servers = servers['servers']
         for server in servers:
-            LOG.debug('Console output for %s', server['id'])
-            LOG.debug(self.servers_client.get_console_output(server['id'],
-                                                             length=None))
+            console_output = self.servers_client.get_console_output(
+                server['id'], length=None)
+            LOG.debug('Console output for %s\nhead=%s\nbody=\n%s',
+                      server['id'], console_output[0], console_output[1])
+
+    def _log_net_info(self, exc):
+        # network debug is called as part of ssh init
+        if not isinstance(exc, exceptions.SSHTimeout):
+            LOG.debug('Network information on a devstack host')
+            debug.log_net_debug()
 
     def create_server_snapshot(self, server, name=None):
         # Glance client
@@ -429,10 +409,55 @@
                   image_name, server['name'])
         return snapshot_image
 
+    def nova_volume_attach(self):
+        # TODO(andreaf) Device should be here CONF.compute.volume_device_name
+        _, volume = self.servers_client.attach_volume(
+            self.server['id'], self.volume['id'], '/dev/vdb')
+        self.assertEqual(self.volume['id'], volume['id'])
+        self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
+        # Refresh the volume after the attachment
+        _, self.volume = self.volumes_client.get_volume(volume['id'])
 
-# TODO(yfried): change this class name to NetworkScenarioTest once client
-# migration is complete
-class NeutronScenarioTest(ScenarioTest):
+    def nova_volume_detach(self):
+        self.servers_client.detach_volume(self.server['id'], self.volume['id'])
+        self.volumes_client.wait_for_volume_status(self.volume['id'],
+                                                   'available')
+
+        _, volume = self.volumes_client.get_volume(self.volume['id'])
+        self.assertEqual('available', volume['status'])
+
+    def rebuild_server(self, server_id, image=None,
+                       preserve_ephemeral=False, wait=True,
+                       rebuild_kwargs=None):
+        if image is None:
+            image = CONF.compute.image_ref
+
+        rebuild_kwargs = rebuild_kwargs or {}
+
+        LOG.debug("Rebuilding server (id: %s, image: %s, preserve eph: %s)",
+                  server_id, image, preserve_ephemeral)
+        self.servers_client.rebuild(server_id=server_id, image_ref=image,
+                                    preserve_ephemeral=preserve_ephemeral,
+                                    **rebuild_kwargs)
+        if wait:
+            self.servers_client.wait_for_server_status(server_id, 'ACTIVE')
+
+    def ping_ip_address(self, ip_address, should_succeed=True,
+                        ping_timeout=None):
+        timeout = ping_timeout or CONF.compute.ping_timeout
+        cmd = ['ping', '-c1', '-w1', ip_address]
+
+        def ping():
+            proc = subprocess.Popen(cmd,
+                                    stdout=subprocess.PIPE,
+                                    stderr=subprocess.PIPE)
+            proc.communicate()
+            return (proc.returncode == 0) == should_succeed
+
+        return tempest.test.call_until_true(ping, timeout, 1)
+
+
+class NetworkScenarioTest(ScenarioTest):
     """Base class for network scenario tests.
     This class provide helpers for network scenario tests, using the neutron
     API. Helpers from ancestor which use the nova network API are overridden
@@ -445,30 +470,24 @@
 
     @classmethod
     def check_preconditions(cls):
-        if CONF.service_available.neutron:
-            cls.enabled = True
-            # verify that neutron_available is telling the truth
-            try:
-                cls.network_client.list_networks()
-            except exc.EndpointNotFound:
-                cls.enabled = False
-                raise
-        else:
-            cls.enabled = False
-            msg = 'Neutron not available'
-            raise cls.skipException(msg)
+        if not CONF.service_available.neutron:
+            raise cls.skipException('Neutron not available')
 
     @classmethod
-    def setUpClass(cls):
-        super(NeutronScenarioTest, cls).setUpClass()
-        cls.tenant_id = cls.manager.identity_client.tenant_id
+    def resource_setup(cls):
         cls.check_preconditions()
+        super(NetworkScenarioTest, cls).resource_setup()
+        cls.tenant_id = cls.manager.identity_client.tenant_id
 
-    def _create_network(self, tenant_id, namestart='network-smoke-'):
+    def _create_network(self, client=None, tenant_id=None,
+                        namestart='network-smoke-'):
+        if not client:
+            client = self.network_client
+        if not tenant_id:
+            tenant_id = client.rest_client.tenant_id
         name = data_utils.rand_name(namestart)
-        _, result = self.network_client.create_network(name=name,
-                                                       tenant_id=tenant_id)
-        network = net_resources.DeletableNetwork(client=self.network_client,
+        _, result = client.create_network(name=name, tenant_id=tenant_id)
+        network = net_resources.DeletableNetwork(client=client,
                                                  **result['network'])
         self.assertEqual(network.name, name)
         self.addCleanup(self.delete_wrapper, network.delete)
@@ -498,11 +517,14 @@
             return resource_list[resource_type]
         return temp
 
-    def _create_subnet(self, network, namestart='subnet-smoke-', **kwargs):
+    def _create_subnet(self, network, client=None, namestart='subnet-smoke',
+                       **kwargs):
         """
         Create a subnet for the given network within the cidr block
         configured for tenant networks.
         """
+        if not client:
+            client = self.network_client
 
         def cidr_in_use(cidr, tenant_id):
             """
@@ -531,27 +553,29 @@
                 **kwargs
             )
             try:
-                _, result = self.network_client.create_subnet(**subnet)
+                _, result = client.create_subnet(**subnet)
                 break
-            except exc.NeutronClientException as e:
+            except exceptions.Conflict as e:
                 is_overlapping_cidr = 'overlaps with another subnet' in str(e)
                 if not is_overlapping_cidr:
                     raise
         self.assertIsNotNone(result, 'Unable to allocate tenant network')
-        subnet = net_resources.DeletableSubnet(client=self.network_client,
+        subnet = net_resources.DeletableSubnet(client=client,
                                                **result['subnet'])
         self.assertEqual(subnet.cidr, str_cidr)
         self.addCleanup(self.delete_wrapper, subnet.delete)
         return subnet
 
-    def _create_port(self, network, namestart='port-quotatest'):
+    def _create_port(self, network, client=None, namestart='port-quotatest'):
+        if not client:
+            client = self.network_client
         name = data_utils.rand_name(namestart)
-        _, result = self.network_client.create_port(
+        _, result = client.create_port(
             name=name,
             network_id=network.id,
             tenant_id=network.tenant_id)
         self.assertIsNotNone(result, 'Unable to allocate port')
-        port = net_resources.DeletablePort(client=self.network_client,
+        port = net_resources.DeletablePort(client=client,
                                            **result['port'])
         self.addCleanup(self.delete_wrapper, port.delete)
         return port
@@ -563,16 +587,23 @@
                          "Unable to determine which port to target.")
         return ports[0]['id']
 
-    def _create_floating_ip(self, thing, external_network_id, port_id=None):
+    def _get_network_by_name(self, network_name):
+        net = self._list_networks(name=network_name)
+        return net_resources.AttributeDict(net[0])
+
+    def _create_floating_ip(self, thing, external_network_id, port_id=None,
+                            client=None):
+        if not client:
+            client = self.network_client
         if not port_id:
             port_id = self._get_server_port_id(thing)
-        _, result = self.network_client.create_floatingip(
+        _, result = client.create_floatingip(
             floating_network_id=external_network_id,
             port_id=port_id,
             tenant_id=thing['tenant_id']
         )
         floating_ip = net_resources.DeletableFloatingIp(
-            client=self.network_client,
+            client=client,
             **result['floatingip'])
         self.addCleanup(self.delete_wrapper, floating_ip.delete)
         return floating_ip
@@ -591,18 +622,28 @@
         self.assertIsNone(floating_ip.port_id)
         return floating_ip
 
-    def _ping_ip_address(self, ip_address, should_succeed=True):
-        cmd = ['ping', '-c1', '-w1', ip_address]
+    def check_floating_ip_status(self, floating_ip, status):
+        """Verifies floatingip reaches the given status
 
-        def ping():
-            proc = subprocess.Popen(cmd,
-                                    stdout=subprocess.PIPE,
-                                    stderr=subprocess.PIPE)
-            proc.wait()
-            return (proc.returncode == 0) == should_succeed
+        :param floating_ip: net_resources.DeletableFloatingIp floating IP to
+        to check status
+        :param status: target status
+        :raises: AssertionError if status doesn't match
+        """
+        def refresh():
+            floating_ip.refresh()
+            return status == floating_ip.status
 
-        return tempest.test.call_until_true(
-            ping, CONF.compute.ping_timeout, 1)
+        tempest.test.call_until_true(refresh,
+                                     CONF.network.build_timeout,
+                                     CONF.network.build_interval)
+        self.assertEqual(status, floating_ip.status,
+                         message="FloatingIP: {fp} is at status: {cst}. "
+                                 "failed  to reach status: {st}"
+                         .format(fp=floating_ip, cst=floating_ip.status,
+                                 st=status))
+        LOG.info("FloatingIP: {fp} is at status: {st}"
+                 .format(fp=floating_ip, st=status))
 
     def _check_vm_connectivity(self, ip_address,
                                username=None,
@@ -623,8 +664,8 @@
             msg = "Timed out waiting for %s to become reachable" % ip_address
         else:
             msg = "ip address %s is reachable" % ip_address
-        self.assertTrue(self._ping_ip_address(ip_address,
-                                              should_succeed=should_connect),
+        self.assertTrue(self.ping_ip_address(ip_address,
+                                             should_succeed=should_connect),
                         msg=msg)
         if should_connect:
             # no need to check ssh for negative connectivity
@@ -648,9 +689,7 @@
                 ex_msg += ": " + msg
             LOG.exception(ex_msg)
             self._log_console_output(servers)
-            # network debug is called as part of ssh init
-            if not isinstance(e, exceptions.SSHTimeout):
-                debug.log_net_debug()
+            self._log_net_info(e)
             raise
 
     def _check_tenant_network_connectivity(self, server,
@@ -674,9 +713,7 @@
         except Exception as e:
             LOG.exception('Tenant network connectivity check failed')
             self._log_console_output(servers_for_debug)
-            # network debug is called as part of ssh init
-            if not isinstance(e, exceptions.SSHTimeout):
-                debug.log_net_debug()
+            self._log_net_info(e)
             raise
 
     def _check_remote_connectivity(self, source, dest, should_succeed=True):
@@ -702,10 +739,12 @@
                                             CONF.compute.ping_timeout,
                                             1)
 
-    def _create_security_group(self, tenant_id, client=None,
+    def _create_security_group(self, client=None, tenant_id=None,
                                namestart='secgroup-smoke'):
         if client is None:
             client = self.network_client
+        if tenant_id is None:
+            tenant_id = client.rest_client.tenant_id
         secgroup = self._create_empty_security_group(namestart=namestart,
                                                      client=client,
                                                      tenant_id=tenant_id)
@@ -717,7 +756,7 @@
             self.assertEqual(secgroup.id, rule.security_group_id)
         return secgroup
 
-    def _create_empty_security_group(self, tenant_id, client=None,
+    def _create_empty_security_group(self, client=None, tenant_id=None,
                                      namestart='secgroup-smoke'):
         """Create a security group without rules.
 
@@ -730,6 +769,8 @@
         """
         if client is None:
             client = self.network_client
+        if not tenant_id:
+            tenant_id = client.rest_client.tenant_id
         sg_name = data_utils.rand_name(namestart)
         sg_desc = sg_name + " description"
         sg_dict = dict(name=sg_name,
@@ -746,26 +787,25 @@
         self.addCleanup(self.delete_wrapper, secgroup.delete)
         return secgroup
 
-    def _default_security_group(self, tenant_id, client=None):
+    def _default_security_group(self, client=None, tenant_id=None):
         """Get default secgroup for given tenant_id.
 
         :returns: DeletableSecurityGroup -- default secgroup for given tenant
         """
         if client is None:
             client = self.network_client
+        if not tenant_id:
+            tenant_id = client.rest_client.tenant_id
         sgs = [
             sg for sg in client.list_security_groups().values()[0]
             if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
         ]
         msg = "No default security group for tenant %s." % (tenant_id)
         self.assertTrue(len(sgs) > 0, msg)
-        if len(sgs) > 1:
-            msg = "Found %d default security groups" % len(sgs)
-            raise exc.NeutronClientNoUniqueMatch(msg=msg)
         return net_resources.DeletableSecurityGroup(client=client,
                                                     **sgs[0])
 
-    def _create_security_group_rule(self, client=None, secgroup=None,
+    def _create_security_group_rule(self, secgroup=None, client=None,
                                     tenant_id=None, **kwargs):
         """Create a rule from a dictionary of rule parameters.
 
@@ -773,8 +813,6 @@
         default secgroup in tenant_id.
 
         :param secgroup: type DeletableSecurityGroup.
-        :param secgroup_id: search for secgroup by id
-            default -- choose default secgroup for given tenant_id
         :param tenant_id: if secgroup not passed -- the tenant in which to
             search for default secgroup
         :param kwargs: a dictionary containing rule parameters:
@@ -788,8 +826,11 @@
         """
         if client is None:
             client = self.network_client
+        if not tenant_id:
+            tenant_id = client.rest_client.tenant_id
         if secgroup is None:
-            secgroup = self._default_security_group(tenant_id)
+            secgroup = self._default_security_group(client=client,
+                                                    tenant_id=tenant_id)
 
         ruleset = dict(security_group_id=secgroup.id,
                        tenant_id=secgroup.tenant_id)
@@ -845,13 +886,48 @@
 
         return rules
 
+    def _create_pool(self, lb_method, protocol, subnet_id):
+        """Wrapper utility that returns a test pool."""
+        client = self.network_client
+        name = data_utils.rand_name('pool')
+        _, resp_pool = client.create_pool(protocol=protocol, name=name,
+                                          subnet_id=subnet_id,
+                                          lb_method=lb_method)
+        pool = net_resources.DeletablePool(client=client, **resp_pool['pool'])
+        self.assertEqual(pool['name'], name)
+        self.addCleanup(self.delete_wrapper, pool.delete)
+        return pool
+
+    def _create_member(self, address, protocol_port, pool_id):
+        """Wrapper utility that returns a test member."""
+        client = self.network_client
+        _, resp_member = client.create_member(protocol_port=protocol_port,
+                                              pool_id=pool_id,
+                                              address=address)
+        member = net_resources.DeletableMember(client=client,
+                                               **resp_member['member'])
+        self.addCleanup(self.delete_wrapper, member.delete)
+        return member
+
+    def _create_vip(self, protocol, protocol_port, subnet_id, pool_id):
+        """Wrapper utility that returns a test vip."""
+        client = self.network_client
+        name = data_utils.rand_name('vip')
+        _, resp_vip = client.create_vip(protocol=protocol, name=name,
+                                        subnet_id=subnet_id, pool_id=pool_id,
+                                        protocol_port=protocol_port)
+        vip = net_resources.DeletableVip(client=client, **resp_vip['vip'])
+        self.assertEqual(vip['name'], name)
+        self.addCleanup(self.delete_wrapper, vip.delete)
+        return vip
+
     def _ssh_to_server(self, server, private_key):
         ssh_login = CONF.compute.image_ssh_user
         return self.get_remote_client(server,
                                       username=ssh_login,
                                       private_key=private_key)
 
-    def _get_router(self, tenant_id):
+    def _get_router(self, client=None, tenant_id=None):
         """Retrieve a router for the given tenant id.
 
         If a public router has been configured, it will be returned.
@@ -860,554 +936,65 @@
         network has, a tenant router will be created and returned that
         routes traffic to the public network.
         """
+        if not client:
+            client = self.network_client
+        if not tenant_id:
+            tenant_id = client.rest_client.tenant_id
         router_id = CONF.network.public_router_id
         network_id = CONF.network.public_network_id
         if router_id:
-            result = self.network_client.show_router(router_id)
-            return net_resources.AttributeDict(**result['router'])
+            resp, body = client.show_router(router_id)
+            return net_resources.AttributeDict(**body['router'])
         elif network_id:
-            router = self._create_router(tenant_id)
+            router = self._create_router(client, tenant_id)
             router.set_gateway(network_id)
             return router
         else:
             raise Exception("Neither of 'public_router_id' or "
                             "'public_network_id' has been defined.")
 
-    def _create_router(self, tenant_id, namestart='router-smoke-'):
+    def _create_router(self, client=None, tenant_id=None,
+                       namestart='router-smoke'):
+        if not client:
+            client = self.network_client
+        if not tenant_id:
+            tenant_id = client.rest_client.tenant_id
         name = data_utils.rand_name(namestart)
-        _, result = self.network_client.create_router(name=name,
-                                                      admin_state_up=True,
-                                                      tenant_id=tenant_id, )
-        router = net_resources.DeletableRouter(client=self.network_client,
+        _, result = client.create_router(name=name,
+                                         admin_state_up=True,
+                                         tenant_id=tenant_id)
+        router = net_resources.DeletableRouter(client=client,
                                                **result['router'])
         self.assertEqual(router.name, name)
         self.addCleanup(self.delete_wrapper, router.delete)
         return router
 
-    def _create_networks(self, tenant_id=None):
+    def create_networks(self, client=None, tenant_id=None):
         """Create a network with a subnet connected to a router.
 
+        The baremetal driver is a special case since all nodes are
+        on the same shared network.
+
         :returns: network, subnet, router
         """
-        if tenant_id is None:
-            tenant_id = self.tenant_id
-        network = self._create_network(tenant_id)
-        router = self._get_router(tenant_id)
-        subnet = self._create_subnet(network)
-        subnet.add_to_router(router.id)
+        if CONF.baremetal.driver_enabled:
+            # NOTE(Shrews): This exception is for environments where tenant
+            # credential isolation is available, but network separation is
+            # not (the current baremetal case). Likely can be removed when
+            # test account mgmt is reworked:
+            # https://blueprints.launchpad.net/tempest/+spec/test-accounts
+            network = self._get_network_by_name(
+                CONF.compute.fixed_network_name)
+            router = None
+            subnet = None
+        else:
+            network = self._create_network(client=client, tenant_id=tenant_id)
+            router = self._get_router(client=client, tenant_id=tenant_id)
+            subnet = self._create_subnet(network=network, client=client)
+            subnet.add_to_router(router.id)
         return network, subnet, router
 
 
-class OfficialClientTest(tempest.test.BaseTestCase):
-    """
-    Official Client test base class for scenario testing.
-
-    Official Client tests are tests that have the following characteristics:
-
-     * Test basic operations of an API, typically in an order that
-       a regular user would perform those operations
-     * Test only the correct inputs and action paths -- no fuzz or
-       random input data is sent, only valid inputs.
-     * Use only the default client tool for calling an API
-    """
-
-    @classmethod
-    def setUpClass(cls):
-        super(OfficialClientTest, cls).setUpClass()
-        cls.isolated_creds = isolated_creds.IsolatedCreds(
-            cls.__name__, tempest_client=False,
-            network_resources=cls.network_resources)
-
-        cls.manager = clients.OfficialClientManager(
-            credentials=cls.credentials())
-        cls.compute_client = cls.manager.compute_client
-        cls.image_client = cls.manager.image_client
-        cls.baremetal_client = cls.manager.baremetal_client
-        cls.identity_client = cls.manager.identity_client
-        cls.network_client = cls.manager.network_client
-        cls.volume_client = cls.manager.volume_client
-        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.ceilometer_client = cls.manager.ceilometer_client
-
-    @classmethod
-    def tearDownClass(cls):
-        cls.isolated_creds.clear_isolated_creds()
-        super(OfficialClientTest, cls).tearDownClass()
-
-    @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')
-
-    @classmethod
-    def alt_credentials(cls):
-        return cls._get_credentials(cls.isolated_creds.get_alt_creds,
-                                    'alt_user')
-
-    @classmethod
-    def admin_credentials(cls):
-        return cls._get_credentials(cls.isolated_creds.get_admin_creds,
-                                    'identity_admin')
-
-    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.
-
-        # 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:
-            thing.delete()
-        except Exception as e:
-            # If the resource is already missing, mission accomplished.
-            if not self.not_found_exception(e):
-                raise
-
-    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)
-
-    def addCleanup_with_wait(self, things, thing_id,
-                             error_status='ERROR',
-                             exc_type=nova_exceptions.NotFound,
-                             cleanup_callable=None, cleanup_args=None,
-                             cleanup_kwargs=None):
-        """Adds wait for ansyc resource deletion at the end of cleanups
-
-        @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_args is None:
-            cleanup_args = []
-        if cleanup_kwargs is None:
-            cleanup_kwargs = {}
-        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',
-                       not_found_exception=nova_exceptions.NotFound):
-        """
-        Given a thing and an expected status, do a loop, sleeping
-        for a configurable amount of time, checking for the
-        expected status to show. At any time, if the returned
-        status of the thing is ERROR, fail out.
-        """
-        self._status_timeout(things, thing_id,
-                             expected_status=expected_status,
-                             error_status=error_status,
-                             not_found_exception=not_found_exception)
-
-    def delete_timeout(self, things, thing_id,
-                       error_status='ERROR',
-                       not_found_exception=nova_exceptions.NotFound):
-        """
-        Given a thing, do a loop, sleeping
-        for a configurable amount of time, checking for the
-        deleted status to show. At any time, if the returned
-        status of the thing is ERROR, fail out.
-        """
-        self._status_timeout(things,
-                             thing_id,
-                             allow_notfound=True,
-                             error_status=error_status,
-                             not_found_exception=not_found_exception)
-
-    def _status_timeout(self,
-                        things,
-                        thing_id,
-                        expected_status=None,
-                        allow_notfound=False,
-                        error_status='ERROR',
-                        not_found_exception=nova_exceptions.NotFound):
-
-        log_status = expected_status if expected_status else ''
-        if allow_notfound:
-            log_status += ' or NotFound' if log_status != '' else 'NotFound'
-
-        def check_status():
-            # python-novaclient has resources available to its client
-            # that all implement a get() method taking an identifier
-            # for the singular resource to retrieve.
-            try:
-                thing = things.get(thing_id)
-            except not_found_exception:
-                if allow_notfound:
-                    return True
-                raise
-            except Exception as e:
-                if allow_notfound and self.not_found_exception(e):
-                    return True
-                raise
-
-            new_status = thing.status
-
-            # Some components are reporting error status in lower case
-            # so case sensitive comparisons can really mess things
-            # up.
-            if new_status.lower() == error_status.lower():
-                message = ("%s failed to get to expected status (%s). "
-                           "In %s state.") % (thing, expected_status,
-                                              new_status)
-                raise exceptions.BuildErrorException(message,
-                                                     server_id=thing_id)
-            elif new_status == expected_status and expected_status is not None:
-                return True  # All good.
-            LOG.debug("Waiting for %s to get to %s status. "
-                      "Currently in %s status",
-                      thing, log_status, new_status)
-        if not tempest.test.call_until_true(
-            check_status,
-            CONF.compute.build_timeout,
-            CONF.compute.build_interval):
-            message = ("Timed out waiting for thing %s "
-                       "to become %s") % (thing_id, log_status)
-            raise exceptions.TimeoutException(message)
-
-    def _create_loginable_secgroup_rule_nova(self, client=None,
-                                             secgroup_id=None):
-        if client is None:
-            client = self.compute_client
-        if secgroup_id is None:
-            sgs = client.security_groups.list()
-            for sg in sgs:
-                if sg.name == 'default':
-                    secgroup_id = sg.id
-
-        # These rules are intended to permit inbound ssh and icmp
-        # traffic from all sources, so no group_id is provided.
-        # Setting a group_id would only permit traffic from ports
-        # belonging to the same security group.
-        rulesets = [
-            {
-                # ssh
-                'ip_protocol': 'tcp',
-                'from_port': 22,
-                'to_port': 22,
-                'cidr': '0.0.0.0/0',
-            },
-            {
-                # ssh -6
-                'ip_protocol': 'tcp',
-                'from_port': 22,
-                'to_port': 22,
-                'cidr': '::/0',
-            },
-            {
-                # ping
-                'ip_protocol': 'icmp',
-                'from_port': -1,
-                'to_port': -1,
-                'cidr': '0.0.0.0/0',
-            },
-            {
-                # ping6
-                'ip_protocol': 'icmp',
-                'from_port': -1,
-                'to_port': -1,
-                'cidr': '::/0',
-            }
-        ]
-        rules = list()
-        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 rebuild_server(self, server, client=None, image=None,
-                       preserve_ephemeral=False, wait=True,
-                       rebuild_kwargs=None):
-        if client is None:
-            client = self.compute_client
-        if image is None:
-            image = CONF.compute.image_ref
-        rebuild_kwargs = rebuild_kwargs or {}
-
-        LOG.debug("Rebuilding server (name: %s, image: %s, preserve eph: %s)",
-                  server.name, image, preserve_ephemeral)
-        server.rebuild(image, preserve_ephemeral=preserve_ephemeral,
-                       **rebuild_kwargs)
-        if wait:
-            self.status_timeout(client.servers, server.id, 'ACTIVE')
-
-    def create_server(self, client=None, name=None, image=None, flavor=None,
-                      wait_on_boot=True, wait_on_delete=True,
-                      create_kwargs=None):
-        """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:
-            name = data_utils.rand_name('scenario-server-')
-        if image is None:
-            image = CONF.compute.image_ref
-        if flavor is None:
-            flavor = CONF.compute.flavor_ref
-        if create_kwargs is None:
-            create_kwargs = {}
-
-        fixed_network_name = CONF.compute.fixed_network_name
-        if 'nics' not in create_kwargs and fixed_network_name:
-            networks = client.networks.list()
-            # If several networks found, set the NetID on which to connect the
-            # server to avoid the following error "Multiple possible networks
-            # found, use a Network ID to be more specific."
-            # See Tempest #1250866
-            if len(networks) > 1:
-                for network in networks:
-                    if network.label == fixed_network_name:
-                        create_kwargs['nics'] = [{'net-id': network.id}]
-                        break
-                # If we didn't find the network we were looking for :
-                else:
-                    msg = ("The network on which the NIC of the server must "
-                           "be connected can not be found : "
-                           "fixed_network_name=%s. Starting instance without "
-                           "specifying a network.") % fixed_network_name
-                    LOG.info(msg)
-
-        LOG.debug("Creating a server (name: %s, image: %s, flavor: %s)",
-                  name, image, flavor)
-        server = client.servers.create(name, image, flavor, **create_kwargs)
-        self.assertEqual(server.name, name)
-        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)
-        LOG.debug("Created server: %s", server)
-        return server
-
-    def create_volume(self, client=None, size=1, name=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:
-            name = data_utils.rand_name('scenario-volume-')
-        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,
-                                       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)
-        return volume
-
-    def create_server_snapshot(self, server, compute_client=None,
-                               image_client=None, name=None):
-        if compute_client is None:
-            compute_client = self.compute_client
-        if image_client is None:
-            image_client = self.image_client
-        if name is None:
-            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_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)
-        LOG.debug("Created snapshot image %s for server %s",
-                  snapshot_image.name, server.name)
-        return snapshot_image
-
-    def create_keypair(self, client=None, name=None):
-        if client is None:
-            client = self.compute_client
-        if name is None:
-            name = data_utils.rand_name('scenario-keypair-')
-        keypair = client.keypairs.create(name)
-        self.assertEqual(keypair.name, name)
-        self.addCleanup(self.delete_wrapper, keypair)
-        return keypair
-
-    def get_remote_client(self, server_or_ip, username=None, private_key=None):
-        if isinstance(server_or_ip, six.string_types):
-            ip = server_or_ip
-        else:
-            network_name_for_ssh = CONF.compute.network_for_ssh
-            ip = server_or_ip.networks[network_name_for_ssh][0]
-        if username is None:
-            username = CONF.scenario.ssh_user
-        if private_key is None:
-            private_key = self.keypair.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 CONF.compute_feature_enabled.console_output:
-            LOG.debug('Console output not supported, cannot log')
-            return
-        if not servers:
-            servers = self.compute_client.servers.list()
-        for server in servers:
-            LOG.debug('Console output for %s', server.id)
-            LOG.debug(server.get_console_output())
-
-    def wait_for_volume_status(self, status):
-        volume_id = self.volume.id
-        self.status_timeout(
-            self.volume_client.volumes, volume_id, status)
-
-    def _image_create(self, name, fmt, path, properties=None):
-        if properties is None:
-            properties = {}
-        name = data_utils.rand_name('%s-' % name)
-        image_file = open(path, 'rb')
-        self.addCleanup(image_file.close)
-        params = {
-            'name': name,
-            'container_format': fmt,
-            'disk_format': fmt,
-            'is_public': 'False',
-        }
-        params.update(properties)
-        image = self.image_client.images.create(**params)
-        self.addCleanup(self.image_client.images.delete, image)
-        self.assertEqual("queued", image.status)
-        image.update(data=image_file)
-        return image.id
-
-    def glance_image_create(self):
-        img_path = CONF.scenario.img_dir + "/" + CONF.scenario.img_file
-        aki_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.aki_img_file
-        ari_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ari_img_file
-        ami_img_path = CONF.scenario.img_dir + "/" + CONF.scenario.ami_img_file
-        img_container_format = CONF.scenario.img_container_format
-        img_disk_format = CONF.scenario.img_disk_format
-        LOG.debug("paths: img: %s, container_fomat: %s, disk_format: %s, "
-                  "ami: %s, ari: %s, aki: %s" %
-                  (img_path, img_container_format, img_disk_format,
-                   ami_img_path, ari_img_path, aki_img_path))
-        try:
-            self.image = self._image_create('scenario-img',
-                                            img_container_format,
-                                            img_path,
-                                            properties={'disk_format':
-                                                        img_disk_format})
-        except IOError:
-            LOG.debug("A qcow2 image was not found. Try to get a uec image.")
-            kernel = self._image_create('scenario-aki', 'aki', aki_img_path)
-            ramdisk = self._image_create('scenario-ari', 'ari', ari_img_path)
-            properties = {
-                'properties': {'kernel_id': kernel, 'ramdisk_id': ramdisk}
-            }
-            self.image = self._image_create('scenario-ami', 'ami',
-                                            path=ami_img_path,
-                                            properties=properties)
-        LOG.debug("image:%s" % self.image)
-
-
 # power/provision states as of icehouse
 class BaremetalPowerStates(object):
     """Possible power states of an Ironic node."""
@@ -1432,23 +1019,23 @@
     ERROR = 'error'
 
 
-class BaremetalScenarioTest(OfficialClientTest):
+class BaremetalScenarioTest(ScenarioTest):
     @classmethod
-    def setUpClass(cls):
-        super(BaremetalScenarioTest, cls).setUpClass()
-
+    def resource_setup(cls):
         if (not CONF.service_available.ironic or
            not CONF.baremetal.driver_enabled):
             msg = 'Ironic not available or Ironic compute driver not enabled'
             raise cls.skipException(msg)
+        super(BaremetalScenarioTest, cls).resource_setup()
 
         # use an admin client manager for baremetal client
-        admin_creds = cls.admin_credentials()
-        manager = clients.OfficialClientManager(credentials=admin_creds)
+        manager = clients.Manager(
+            credentials=cls.admin_credentials()
+        )
         cls.baremetal_client = manager.baremetal_client
 
         # allow any issues obtaining the node list to raise early
-        cls.baremetal_client.node.list()
+        cls.baremetal_client.list_nodes()
 
     def _node_state_timeout(self, node_id, state_attr,
                             target_states, timeout=10, interval=1):
@@ -1457,7 +1044,7 @@
 
         def check_state():
             node = self.get_node(node_id=node_id)
-            if getattr(node, state_attr) in target_states:
+            if node.get(state_attr) in target_states:
                 return True
             return False
 
@@ -1479,13 +1066,12 @@
 
     def wait_node(self, instance_id):
         """Waits for a node to be associated with instance_id."""
-        from ironicclient import exc as ironic_exceptions
 
         def _get_node():
             node = None
             try:
                 node = self.get_node(instance_id=instance_id)
-            except ironic_exceptions.HTTPNotFound:
+            except exceptions.NotFound:
                 pass
             return node is not None
 
@@ -1497,14 +1083,20 @@
 
     def get_node(self, node_id=None, instance_id=None):
         if node_id:
-            return self.baremetal_client.node.get(node_id)
+            _, body = self.baremetal_client.show_node(node_id)
+            return body
         elif instance_id:
-            return self.baremetal_client.node.get_by_instance_uuid(instance_id)
+            _, body = self.baremetal_client.show_node_by_instance_uuid(
+                instance_id)
+            if body['nodes']:
+                return body['nodes'][0]
 
-    def get_ports(self, node_id):
+    def get_ports(self, node_uuid):
         ports = []
-        for port in self.baremetal_client.node.list_ports(node_id):
-            ports.append(self.baremetal_client.port.get(port.uuid))
+        _, body = self.baremetal_client.list_node_ports(node_uuid)
+        for port in body['ports']:
+            _, p = self.baremetal_client.show_port(port['uuid'])
+            ports.append(p)
         return ports
 
     def add_keypair(self):
@@ -1519,59 +1111,50 @@
 
     def boot_instance(self):
         create_kwargs = {
-            'key_name': self.keypair.id
+            'key_name': self.keypair['name']
         }
         self.instance = self.create_server(
             wait_on_boot=False, create_kwargs=create_kwargs)
 
-        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'])
 
-        self.wait_node(self.instance.id)
-        self.node = self.get_node(instance_id=self.instance.id)
-
-        self.wait_power_state(self.node.uuid, BaremetalPowerStates.POWER_ON)
+        self.wait_power_state(self.node['uuid'], BaremetalPowerStates.POWER_ON)
 
         self.wait_provisioning_state(
-            self.node.uuid,
+            self.node['uuid'],
             [BaremetalProvisionStates.DEPLOYWAIT,
              BaremetalProvisionStates.ACTIVE],
             timeout=15)
 
-        self.wait_provisioning_state(self.node.uuid,
+        self.wait_provisioning_state(self.node['uuid'],
                                      BaremetalProvisionStates.ACTIVE,
                                      timeout=CONF.baremetal.active_timeout)
 
-        self.status_timeout(
-            self.compute_client.servers, self.instance.id, 'ACTIVE')
-
-        self.node = self.get_node(instance_id=self.instance.id)
-        self.instance = self.compute_client.servers.get(self.instance.id)
+        self.servers_client.wait_for_server_status(self.instance['id'],
+                                                   'ACTIVE')
+        self.node = self.get_node(instance_id=self.instance['id'])
+        _, self.instance = self.servers_client.get_server(self.instance['id'])
 
     def terminate_instance(self):
-        self.instance.delete()
-        self.wait_power_state(self.node.uuid, BaremetalPowerStates.POWER_OFF)
+        self.servers_client.delete_server(self.instance['id'])
+        self.wait_power_state(self.node['uuid'],
+                              BaremetalPowerStates.POWER_OFF)
         self.wait_provisioning_state(
-            self.node.uuid,
+            self.node['uuid'],
             BaremetalProvisionStates.NOSTATE,
             timeout=CONF.baremetal.unprovision_timeout)
 
 
-class EncryptionScenarioTest(OfficialClientTest):
+class EncryptionScenarioTest(ScenarioTest):
     """
     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 resource_setup(cls):
+        super(EncryptionScenarioTest, cls).resource_setup()
+        cls.admin_volume_types_client = cls.admin_manager.volume_types_client
 
     def _wait_for_volume_status(self, status):
         self.status_timeout(
@@ -1579,611 +1162,47 @@
 
     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 = {'key_name': self.keypair['name']}
+        self.server = self.create_server(image=self.image,
                                          create_kwargs=create_kwargs)
 
     def create_volume_type(self, client=None, name=None):
         if not client:
-            client = self.admin_volume_client
+            client = self.admin_volume_types_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
+        _, body = client.create_volume_type(
+            randomized_name)
+        self.assertIn('id', body)
+        self.addCleanup(client.delete_volume_type, body['id'])
+        return body
 
     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
+            client = self.admin_volume_types_client
         if not type_id:
             volume_type = self.create_volume_type()
-            type_id = volume_type.id
+            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})
+        client.create_encryption_type(
+            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
-    """
-
-    @classmethod
-    def check_preconditions(cls):
-        if (CONF.service_available.neutron):
-            cls.enabled = True
-            # verify that neutron_available is telling the truth
-            try:
-                cls.network_client.list_networks()
-            except exc.EndpointNotFound:
-                cls.enabled = False
-                raise
-        else:
-            cls.enabled = False
-            msg = 'Neutron not available'
-            raise cls.skipException(msg)
-
-    @classmethod
-    def setUpClass(cls):
-        super(NetworkScenarioTest, cls).setUpClass()
-        cls.tenant_id = cls.manager.identity_client.tenant_id
-
-    def _create_network(self, tenant_id, namestart='network-smoke-'):
-        name = data_utils.rand_name(namestart)
-        body = dict(
-            network=dict(
-                name=name,
-                tenant_id=tenant_id,
-            ),
-        )
-        result = self.network_client.create_network(body=body)
-        network = net_common.DeletableNetwork(client=self.network_client,
-                                              **result['network'])
-        self.assertEqual(network.name, name)
-        self.addCleanup(self.delete_wrapper, network)
-        return network
-
-    def _list_networks(self, **kwargs):
-        nets = self.network_client.list_networks(**kwargs)
-        return nets['networks']
-
-    def _list_subnets(self, **kwargs):
-        subnets = self.network_client.list_subnets(**kwargs)
-        return subnets['subnets']
-
-    def _list_routers(self, **kwargs):
-        routers = self.network_client.list_routers(**kwargs)
-        return routers['routers']
-
-    def _list_ports(self, **kwargs):
-        ports = self.network_client.list_ports(**kwargs)
-        return ports['ports']
-
-    def _get_tenant_own_network_num(self, tenant_id):
-        nets = self._list_networks(tenant_id=tenant_id)
-        return len(nets)
-
-    def _get_tenant_own_subnet_num(self, tenant_id):
-        subnets = self._list_subnets(tenant_id=tenant_id)
-        return len(subnets)
-
-    def _get_tenant_own_port_num(self, tenant_id):
-        ports = self._list_ports(tenant_id=tenant_id)
-        return len(ports)
-
-    def _create_subnet(self, network, namestart='subnet-smoke-', **kwargs):
-        """
-        Create a subnet for the given network within the cidr block
-        configured for tenant networks.
-        """
-
-        def cidr_in_use(cidr, tenant_id):
-            """
-            :return True if subnet with cidr already exist in tenant
-                False else
-            """
-            cidr_in_use = self._list_subnets(tenant_id=tenant_id, cidr=cidr)
-            return len(cidr_in_use) != 0
-
-        tenant_cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
-        result = None
-        # Repeatedly attempt subnet creation with sequential cidr
-        # blocks until an unallocated block is found.
-        for subnet_cidr in tenant_cidr.subnet(
-            CONF.network.tenant_network_mask_bits):
-            str_cidr = str(subnet_cidr)
-            if cidr_in_use(str_cidr, tenant_id=network.tenant_id):
-                continue
-
-            body = dict(
-                subnet=dict(
-                    name=data_utils.rand_name(namestart),
-                    ip_version=4,
-                    network_id=network.id,
-                    tenant_id=network.tenant_id,
-                    cidr=str_cidr,
-                ),
-            )
-            body['subnet'].update(kwargs)
-            try:
-                result = self.network_client.create_subnet(body=body)
-                break
-            except exc.NeutronClientException as e:
-                is_overlapping_cidr = 'overlaps with another subnet' in str(e)
-                if not is_overlapping_cidr:
-                    raise
-        self.assertIsNotNone(result, 'Unable to allocate tenant network')
-        subnet = net_common.DeletableSubnet(client=self.network_client,
-                                            **result['subnet'])
-        self.assertEqual(subnet.cidr, str_cidr)
-        self.addCleanup(self.delete_wrapper, subnet)
-        return subnet
-
-    def _create_port(self, network, namestart='port-quotatest-'):
-        name = data_utils.rand_name(namestart)
-        body = dict(
-            port=dict(name=name,
-                      network_id=network.id,
-                      tenant_id=network.tenant_id))
-        result = self.network_client.create_port(body=body)
-        self.assertIsNotNone(result, 'Unable to allocate port')
-        port = net_common.DeletablePort(client=self.network_client,
-                                        **result['port'])
-        self.addCleanup(self.delete_wrapper, port)
-        return port
-
-    def _get_server_port_id(self, server, ip_addr=None):
-        ports = self._list_ports(device_id=server.id, fixed_ip=ip_addr)
-        self.assertEqual(len(ports), 1,
-                         "Unable to determine which port to target.")
-        return ports[0]['id']
-
-    def _create_floating_ip(self, thing, external_network_id, port_id=None):
-        if not port_id:
-            port_id = self._get_server_port_id(thing)
-        body = dict(
-            floatingip=dict(
-                floating_network_id=external_network_id,
-                port_id=port_id,
-                tenant_id=thing.tenant_id,
-            )
-        )
-        result = self.network_client.create_floatingip(body=body)
-        floating_ip = net_common.DeletableFloatingIp(
-            client=self.network_client,
-            **result['floatingip'])
-        self.addCleanup(self.delete_wrapper, floating_ip)
-        return floating_ip
-
-    def _associate_floating_ip(self, floating_ip, server):
-        port_id = self._get_server_port_id(server)
-        floating_ip.update(port_id=port_id)
-        self.assertEqual(port_id, floating_ip.port_id)
-        return floating_ip
-
-    def _disassociate_floating_ip(self, floating_ip):
-        """
-        :param floating_ip: type DeletableFloatingIp
-        """
-        floating_ip.update(port_id=None)
-        self.assertIsNone(floating_ip.port_id)
-        return floating_ip
-
-    def _ping_ip_address(self, ip_address, should_succeed=True):
-        cmd = ['ping', '-c1', '-w1', ip_address]
-
-        def ping():
-            proc = subprocess.Popen(cmd,
-                                    stdout=subprocess.PIPE,
-                                    stderr=subprocess.PIPE)
-            proc.wait()
-            return (proc.returncode == 0) == should_succeed
-
-        return tempest.test.call_until_true(
-            ping, CONF.compute.ping_timeout, 1)
-
-    def _create_pool(self, lb_method, protocol, subnet_id):
-        """Wrapper utility that returns a test pool."""
-        name = data_utils.rand_name('pool-')
-        body = {
-            "pool": {
-                "protocol": protocol,
-                "name": name,
-                "subnet_id": subnet_id,
-                "lb_method": lb_method
-            }
-        }
-        resp = self.network_client.create_pool(body=body)
-        pool = net_common.DeletablePool(client=self.network_client,
-                                        **resp['pool'])
-        self.assertEqual(pool['name'], name)
-        self.addCleanup(self.delete_wrapper, pool)
-        return pool
-
-    def _create_member(self, address, protocol_port, pool_id):
-        """Wrapper utility that returns a test member."""
-        body = {
-            "member": {
-                "protocol_port": protocol_port,
-                "pool_id": pool_id,
-                "address": address
-            }
-        }
-        resp = self.network_client.create_member(body)
-        member = net_common.DeletableMember(client=self.network_client,
-                                            **resp['member'])
-        self.addCleanup(self.delete_wrapper, member)
-        return member
-
-    def _create_vip(self, protocol, protocol_port, subnet_id, pool_id):
-        """Wrapper utility that returns a test vip."""
-        name = data_utils.rand_name('vip-')
-        body = {
-            "vip": {
-                "protocol": protocol,
-                "name": name,
-                "subnet_id": subnet_id,
-                "pool_id": pool_id,
-                "protocol_port": protocol_port
-            }
-        }
-        resp = self.network_client.create_vip(body)
-        vip = net_common.DeletableVip(client=self.network_client,
-                                      **resp['vip'])
-        self.assertEqual(vip['name'], name)
-        self.addCleanup(self.delete_wrapper, vip)
-        return vip
-
-    def _check_vm_connectivity(self, ip_address,
-                               username=None,
-                               private_key=None,
-                               should_connect=True):
-        """
-        :param ip_address: server to test against
-        :param username: server's ssh username
-        :param private_key: server's ssh private key to be used
-        :param should_connect: True/False indicates positive/negative test
-            positive - attempt ping and ssh
-            negative - attempt ping and fail if succeed
-
-        :raises: AssertError if the result of the connectivity check does
-            not match the value of the should_connect param
-        """
-        if should_connect:
-            msg = "Timed out waiting for %s to become reachable" % ip_address
-        else:
-            msg = "ip address %s is reachable" % ip_address
-        self.assertTrue(self._ping_ip_address(ip_address,
-                                              should_succeed=should_connect),
-                        msg=msg)
-        if should_connect:
-            # no need to check ssh for negative connectivity
-            self.get_remote_client(ip_address, username, private_key)
-
-    def _check_public_network_connectivity(self, ip_address, username,
-                                           private_key, should_connect=True,
-                                           msg=None, servers=None):
-        # The target login is assumed to have been configured for
-        # key-based authentication by cloud-init.
-        LOG.debug('checking network connections to IP %s with user: %s' %
-                  (ip_address, username))
-        try:
-            self._check_vm_connectivity(ip_address,
-                                        username,
-                                        private_key,
-                                        should_connect=should_connect)
-        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)
-            # 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,
-                                           username,
-                                           private_key,
-                                           should_connect=True,
-                                           servers_for_debug=None):
-        if not CONF.network.tenant_networks_reachable:
-            msg = 'Tenant networks not configured to be reachable.'
-            LOG.info(msg)
-            return
-        # The target login is assumed to have been configured for
-        # key-based authentication by cloud-init.
-        try:
-            for net_name, ip_addresses in server.networks.iteritems():
-                for ip_address in ip_addresses:
-                    self._check_vm_connectivity(ip_address,
-                                                username,
-                                                private_key,
-                                                should_connect=should_connect)
-        except Exception as e:
-            LOG.exception('Tenant network connectivity check failed')
-            self._log_console_output(servers_for_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):
-        """
-        check ping server via source ssh connection
-
-        :param source: RemoteClient: an ssh connection from which to ping
-        :param dest: and IP to ping against
-        :param should_succeed: boolean should ping succeed or not
-        :returns: boolean -- should_succeed == ping
-        :returns: ping is false if ping failed
-        """
-        def ping_remote():
-            try:
-                source.ping_host(dest)
-            except exceptions.SSHExecCommandFailed:
-                LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
-                         % (dest, source.ssh_client.host))
-                return not should_succeed
-            return should_succeed
-
-        return tempest.test.call_until_true(ping_remote,
-                                            CONF.compute.ping_timeout,
-                                            1)
-
-    def _create_security_group_neutron(self, tenant_id, client=None,
-                                       namestart='secgroup-smoke-'):
-        if client is None:
-            client = self.network_client
-        secgroup = self._create_empty_security_group(namestart=namestart,
-                                                     client=client,
-                                                     tenant_id=tenant_id)
-
-        # Add rules to the security group
-        rules = self._create_loginable_secgroup_rule_neutron(secgroup=secgroup)
-        for rule in rules:
-            self.assertEqual(tenant_id, rule.tenant_id)
-            self.assertEqual(secgroup.id, rule.security_group_id)
-        return secgroup
-
-    def _create_empty_security_group(self, tenant_id, client=None,
-                                     namestart='secgroup-smoke-'):
-        """Create a security group without rules.
-
-        Default rules will be created:
-         - IPv4 egress to any
-         - IPv6 egress to any
-
-        :param tenant_id: secgroup will be created in this tenant
-        :returns: DeletableSecurityGroup -- containing the secgroup created
-        """
-        if client is None:
-            client = self.network_client
-        sg_name = data_utils.rand_name(namestart)
-        sg_desc = sg_name + " description"
-        sg_dict = dict(name=sg_name,
-                       description=sg_desc)
-        sg_dict['tenant_id'] = tenant_id
-        body = dict(security_group=sg_dict)
-        result = client.create_security_group(body=body)
-        secgroup = net_common.DeletableSecurityGroup(
-            client=client,
-            **result['security_group']
-        )
-        self.assertEqual(secgroup.name, sg_name)
-        self.assertEqual(tenant_id, secgroup.tenant_id)
-        self.assertEqual(secgroup.description, sg_desc)
-        self.addCleanup(self.delete_wrapper, secgroup)
-        return secgroup
-
-    def _default_security_group(self, tenant_id, client=None):
-        """Get default secgroup for given tenant_id.
-
-        :returns: DeletableSecurityGroup -- default secgroup for given tenant
-        """
-        if client is None:
-            client = self.network_client
-        sgs = [
-            sg for sg in client.list_security_groups().values()[0]
-            if sg['tenant_id'] == tenant_id and sg['name'] == 'default'
-        ]
-        msg = "No default security group for tenant %s." % (tenant_id)
-        self.assertTrue(len(sgs) > 0, msg)
-        if len(sgs) > 1:
-            msg = "Found %d default security groups" % len(sgs)
-            raise exc.NeutronClientNoUniqueMatch(msg=msg)
-        return net_common.DeletableSecurityGroup(client=client,
-                                                 **sgs[0])
-
-    def _create_security_group_rule(self, client=None, secgroup=None,
-                                    tenant_id=None, **kwargs):
-        """Create a rule from a dictionary of rule parameters.
-
-        Create a rule in a secgroup. if secgroup not defined will search for
-        default secgroup in tenant_id.
-
-        :param secgroup: type DeletableSecurityGroup.
-        :param secgroup_id: search for secgroup by id
-            default -- choose default secgroup for given tenant_id
-        :param tenant_id: if secgroup not passed -- the tenant in which to
-            search for default secgroup
-        :param kwargs: a dictionary containing rule parameters:
-            for example, to allow incoming ssh:
-            rule = {
-                    direction: 'ingress'
-                    protocol:'tcp',
-                    port_range_min: 22,
-                    port_range_max: 22
-                    }
-        """
-        if client is None:
-            client = self.network_client
-        if secgroup is None:
-            secgroup = self._default_security_group(tenant_id)
-
-        ruleset = dict(security_group_id=secgroup.id,
-                       tenant_id=secgroup.tenant_id,
-                       )
-        ruleset.update(kwargs)
-
-        body = dict(security_group_rule=dict(ruleset))
-        sg_rule = client.create_security_group_rule(body=body)
-        sg_rule = net_common.DeletableSecurityGroupRule(
-            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)
-
-        return sg_rule
-
-    def _create_loginable_secgroup_rule_neutron(self, client=None,
-                                                secgroup=None):
-        """These rules are intended to permit inbound ssh and icmp
-        traffic from all sources, so no group_id is provided.
-        Setting a group_id would only permit traffic from ports
-        belonging to the same security group.
-        """
-
-        if client is None:
-            client = self.network_client
-        rules = []
-        rulesets = [
-            dict(
-                # ssh
-                protocol='tcp',
-                port_range_min=22,
-                port_range_max=22,
-            ),
-            dict(
-                # ping
-                protocol='icmp',
-            )
-        ]
-        for ruleset in rulesets:
-            for r_direction in ['ingress', 'egress']:
-                ruleset['direction'] = r_direction
-                try:
-                    sg_rule = self._create_security_group_rule(
-                        client=client, secgroup=secgroup, **ruleset)
-                except exc.NeutronClientException as ex:
-                    # if rule already exist - skip rule and continue
-                    if not (ex.status_code is 409 and 'Security group rule'
-                            ' already exists' in ex.message):
-                        raise ex
-                else:
-                    self.assertEqual(r_direction, sg_rule.direction)
-                    rules.append(sg_rule)
-
-        return rules
-
-    def _ssh_to_server(self, server, private_key):
-        ssh_login = CONF.compute.image_ssh_user
-        return self.get_remote_client(server,
-                                      username=ssh_login,
-                                      private_key=private_key)
-
-    def _show_quota_network(self, tenant_id):
-        quota = self.network_client.show_quota(tenant_id)
-        return quota['quota']['network']
-
-    def _show_quota_subnet(self, tenant_id):
-        quota = self.network_client.show_quota(tenant_id)
-        return quota['quota']['subnet']
-
-    def _show_quota_port(self, tenant_id):
-        quota = self.network_client.show_quota(tenant_id)
-        return quota['quota']['port']
-
-    def _get_router(self, tenant_id):
-        """Retrieve a router for the given tenant id.
-
-        If a public router has been configured, it will be returned.
-
-        If a public router has not been configured, but a public
-        network has, a tenant router will be created and returned that
-        routes traffic to the public network.
-        """
-        router_id = CONF.network.public_router_id
-        network_id = CONF.network.public_network_id
-        if router_id:
-            result = self.network_client.show_router(router_id)
-            return net_common.AttributeDict(**result['router'])
-        elif network_id:
-            router = self._create_router(tenant_id)
-            router.add_gateway(network_id)
-            return router
-        else:
-            raise Exception("Neither of 'public_router_id' or "
-                            "'public_network_id' has been defined.")
-
-    def _create_router(self, tenant_id, namestart='router-smoke-'):
-        name = data_utils.rand_name(namestart)
-        body = dict(
-            router=dict(
-                name=name,
-                admin_state_up=True,
-                tenant_id=tenant_id,
-            ),
-        )
-        result = self.network_client.create_router(body=body)
-        router = net_common.DeletableRouter(client=self.network_client,
-                                            **result['router'])
-        self.assertEqual(router.name, name)
-        self.addCleanup(self.delete_wrapper, router)
-        return router
-
-    def _create_networks(self, tenant_id=None):
-        """Create a network with a subnet connected to a router.
-
-        :returns: network, subnet, router
-        """
-        if tenant_id is None:
-            tenant_id = self.tenant_id
-        network = self._create_network(tenant_id)
-        router = self._get_router(tenant_id)
-        subnet = self._create_subnet(network)
-        subnet.add_to_router(router.id)
-        return network, subnet, router
-
-
-class OrchestrationScenarioTest(OfficialClientTest):
+class OrchestrationScenarioTest(ScenarioTest):
     """
     Base class for orchestration scenario tests
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(OrchestrationScenarioTest, cls).setUpClass()
+    def resource_setup(cls):
         if not CONF.service_available.heat:
             raise cls.skipException("Heat support is required")
+        super(OrchestrationScenarioTest, cls).resource_setup()
 
     @classmethod
     def credentials(cls):
@@ -2204,106 +1223,17 @@
 
     @classmethod
     def _get_default_network(cls):
-        networks = cls.network_client.list_networks()
-        for net in networks['networks']:
-            if net['name'] == CONF.compute.fixed_network_name:
+        _, networks = cls.networks_client.list_networks()
+        for net in networks:
+            if net['label'] == CONF.compute.fixed_network_name:
                 return net
 
     @staticmethod
     def _stack_output(stack, output_key):
         """Return a stack output value for a given key."""
-        return next((o['output_value'] for o in stack.outputs
+        return next((o['output_value'] for o in stack['outputs']
                     if o['output_key'] == output_key), None)
 
-    def _ping_ip_address(self, ip_address, should_succeed=True):
-        cmd = ['ping', '-c1', '-w1', ip_address]
-
-        def ping():
-            proc = subprocess.Popen(cmd,
-                                    stdout=subprocess.PIPE,
-                                    stderr=subprocess.PIPE)
-            proc.wait()
-            return (proc.returncode == 0) == should_succeed
-
-        return tempest.test.call_until_true(
-            ping, CONF.orchestration.build_timeout, 1)
-
-    def _wait_for_resource_status(self, stack_identifier, resource_name,
-                                  status, failure_pattern='^.*_FAILED$'):
-        """Waits for a Resource to reach a given status."""
-        fail_regexp = re.compile(failure_pattern)
-        build_timeout = CONF.orchestration.build_timeout
-        build_interval = CONF.orchestration.build_interval
-
-        start = timeutils.utcnow()
-        while timeutils.delta_seconds(start,
-                                      timeutils.utcnow()) < build_timeout:
-            try:
-                res = self.client.resources.get(
-                    stack_identifier, resource_name)
-            except heat_exceptions.HTTPNotFound:
-                # ignore this, as the resource may not have
-                # been created yet
-                pass
-            else:
-                if res.resource_status == status:
-                    return
-                if fail_regexp.search(res.resource_status):
-                    raise exceptions.StackResourceBuildErrorException(
-                        resource_name=res.resource_name,
-                        stack_identifier=stack_identifier,
-                        resource_status=res.resource_status,
-                        resource_status_reason=res.resource_status_reason)
-            time.sleep(build_interval)
-
-        message = ('Resource %s failed to reach %s status within '
-                   'the required time (%s s).' %
-                   (res.resource_name, status, build_timeout))
-        raise exceptions.TimeoutException(message)
-
-    def _wait_for_stack_status(self, stack_identifier, status,
-                               failure_pattern='^.*_FAILED$'):
-        """
-        Waits for a Stack to reach a given status.
-
-        Note this compares the full $action_$status, e.g
-        CREATE_COMPLETE, not just COMPLETE which is exposed
-        via the status property of Stack in heatclient
-        """
-        fail_regexp = re.compile(failure_pattern)
-        build_timeout = CONF.orchestration.build_timeout
-        build_interval = CONF.orchestration.build_interval
-
-        start = timeutils.utcnow()
-        while timeutils.delta_seconds(start,
-                                      timeutils.utcnow()) < build_timeout:
-            try:
-                stack = self.client.stacks.get(stack_identifier)
-            except heat_exceptions.HTTPNotFound:
-                # ignore this, as the stackource may not have
-                # been created yet
-                pass
-            else:
-                if stack.stack_status == status:
-                    return
-                if fail_regexp.search(stack.stack_status):
-                    raise exceptions.StackBuildErrorException(
-                        stack_identifier=stack_identifier,
-                        stack_status=stack.stack_status,
-                        stack_status_reason=stack.stack_status_reason)
-            time.sleep(build_interval)
-
-        message = ('Stack %s failed to reach %s status within '
-                   'the required time (%s s).' %
-                   (stack.stack_name, status, build_timeout))
-        raise exceptions.TimeoutException(message)
-
-    def _stack_delete(self, stack_identifier):
-        try:
-            self.client.stacks.delete(stack_identifier)
-        except heat_exceptions.HTTPNotFound:
-            pass
-
 
 class SwiftScenarioTest(ScenarioTest):
     """
@@ -2314,50 +1244,57 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        cls.set_network_resources()
-        super(SwiftScenarioTest, cls).setUpClass()
+    def resource_setup(cls):
         if not CONF.service_available.swift:
             skip_msg = ("%s skipped as swift is not available" %
                         cls.__name__)
             raise cls.skipException(skip_msg)
+        cls.set_network_resources()
+        super(SwiftScenarioTest, cls).resource_setup()
         # Clients for Swift
         cls.account_client = cls.manager.account_client
         cls.container_client = cls.manager.container_client
         cls.object_client = cls.manager.object_client
 
-    def _get_swift_stat(self):
+    def get_swift_stat(self):
         """get swift status for our user account."""
         self.account_client.list_account_containers()
         LOG.debug('Swift status information obtained successfully')
 
-    def _create_container(self, container_name=None):
+    def create_container(self, container_name=None):
         name = container_name or data_utils.rand_name(
             'swift-scenario-container')
         self.container_client.create_container(name)
         # look for the container to assure it is created
-        self._list_and_check_container_objects(name)
+        self.list_and_check_container_objects(name)
         LOG.debug('Container %s created' % (name))
+        self.addCleanup(self.delete_wrapper,
+                        self.container_client.delete_container,
+                        name)
         return name
 
-    def _delete_container(self, container_name):
+    def delete_container(self, container_name):
         self.container_client.delete_container(container_name)
         LOG.debug('Container %s deleted' % (container_name))
 
-    def _upload_object_to_container(self, container_name, obj_name=None):
+    def upload_object_to_container(self, container_name, obj_name=None):
         obj_name = obj_name or data_utils.rand_name('swift-scenario-object')
         obj_data = data_utils.arbitrary_string()
         self.object_client.create_object(container_name, obj_name, obj_data)
+        self.addCleanup(self.delete_wrapper,
+                        self.object_client.delete_object,
+                        container_name,
+                        obj_name)
         return obj_name, obj_data
 
-    def _delete_object(self, container_name, filename):
+    def delete_object(self, container_name, filename):
         self.object_client.delete_object(container_name, filename)
-        self._list_and_check_container_objects(container_name,
-                                               not_present_obj=[filename])
+        self.list_and_check_container_objects(container_name,
+                                              not_present_obj=[filename])
 
-    def _list_and_check_container_objects(self, container_name,
-                                          present_obj=None,
-                                          not_present_obj=None):
+    def list_and_check_container_objects(self, container_name,
+                                         present_obj=None,
+                                         not_present_obj=None):
         """
         List objects for a given container and assert which are present and
         which are not.
@@ -2375,7 +1312,7 @@
             for obj in not_present_obj:
                 self.assertNotIn(obj, object_list)
 
-    def _change_container_acl(self, container_name, acl):
+    def change_container_acl(self, container_name, acl):
         metadata_param = {'metadata_prefix': 'x-container-',
                           'metadata': {'read': acl}}
         self.container_client.update_container_metadata(container_name,
@@ -2383,6 +1320,6 @@
         resp, _ = self.container_client.list_container_metadata(container_name)
         self.assertEqual(resp['x-container-read'], acl)
 
-    def _download_and_verify(self, container_name, obj_name, expected_data):
+    def download_and_verify(self, container_name, obj_name, expected_data):
         _, obj = self.object_client.get_object(container_name, obj_name)
         self.assertEqual(obj, expected_data)
diff --git a/tempest/scenario/orchestration/test_autoscaling.py b/tempest/scenario/orchestration/test_autoscaling.py
deleted file mode 100644
index 8894106..0000000
--- a/tempest/scenario/orchestration/test_autoscaling.py
+++ /dev/null
@@ -1,125 +0,0 @@
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-import time
-
-import heatclient.exc as heat_exceptions
-
-from tempest import config
-from tempest.scenario import manager
-from tempest import test
-
-CONF = config.CONF
-
-
-class AutoScalingTest(manager.OrchestrationScenarioTest):
-
-    def setUp(self):
-        super(AutoScalingTest, self).setUp()
-        if not CONF.orchestration.image_ref:
-            raise self.skipException("No image available to test")
-        self.client = self.orchestration_client
-
-    def assign_keypair(self):
-        self.stack_name = self._stack_rand_name()
-        if CONF.orchestration.keypair_name:
-            self.keypair_name = CONF.orchestration.keypair_name
-        else:
-            self.keypair = self.create_keypair()
-            self.keypair_name = self.keypair.id
-
-    def launch_stack(self):
-        net = self._get_default_network()
-        self.parameters = {
-            'KeyName': self.keypair_name,
-            'InstanceType': CONF.orchestration.instance_type,
-            'ImageId': CONF.orchestration.image_ref,
-            'StackStart': str(time.time()),
-            'Subnet': net['subnets'][0]
-        }
-
-        # create the stack
-        self.template = self._load_template(__file__, 'test_autoscaling.yaml')
-        self.client.stacks.create(
-            stack_name=self.stack_name,
-            template=self.template,
-            parameters=self.parameters)
-
-        self.stack = self.client.stacks.get(self.stack_name)
-        self.stack_identifier = '%s/%s' % (self.stack_name, self.stack.id)
-
-        # 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.addCleanup(self.client.stacks.delete, self.stack)
-
-    @test.skip_because(bug="1257575")
-    @test.attr(type='slow')
-    @test.services('orchestration', 'compute')
-    def test_scale_up_then_down(self):
-
-        self.assign_keypair()
-        self.launch_stack()
-
-        sid = self.stack_identifier
-        timeout = CONF.orchestration.build_timeout
-        interval = 10
-
-        self.assertEqual('CREATE', self.stack.action)
-        # wait for create to complete.
-        self.status_timeout(self.client.stacks, sid, 'COMPLETE',
-                            error_status='FAILED')
-
-        self.stack.get()
-        self.assertEqual('CREATE_COMPLETE', self.stack.stack_status)
-
-        # the resource SmokeServerGroup is implemented as a nested
-        # stack, so servers can be counted by counting the resources
-        # inside that nested stack
-        resource = self.client.resources.get(sid, 'SmokeServerGroup')
-        nested_stack_id = resource.physical_resource_id
-
-        def server_count():
-            # the number of servers is the number of resources
-            # in the nested stack
-            self.server_count = len(
-                self.client.resources.list(nested_stack_id))
-            return self.server_count
-
-        def assertScale(from_servers, to_servers):
-            test.call_until_true(lambda: server_count() == to_servers,
-                                 timeout, interval)
-            self.assertEqual(to_servers, self.server_count,
-                             'Failed scaling from %d to %d servers. '
-                             'Current server count: %s' % (
-                                 from_servers, to_servers,
-                                 self.server_count))
-
-        # he marched them up to the top of the hill
-        assertScale(1, 2)
-        assertScale(2, 3)
-
-        # and he marched them down again
-        assertScale(3, 2)
-        assertScale(2, 1)
-
-        # delete stack on completion
-        self.stack.delete()
-        self.status_timeout(self.client.stacks, sid, 'COMPLETE',
-                            error_status='FAILED',
-                            not_found_exception=heat_exceptions.NotFound)
-
-        try:
-            self.stack.get()
-            self.assertEqual('DELETE_COMPLETE', self.stack.stack_status)
-        except heat_exceptions.NotFound:
-            pass
diff --git a/tempest/scenario/orchestration/test_autoscaling.yaml b/tempest/scenario/orchestration/test_autoscaling.yaml
deleted file mode 100644
index 4651284..0000000
--- a/tempest/scenario/orchestration/test_autoscaling.yaml
+++ /dev/null
@@ -1,185 +0,0 @@
-HeatTemplateFormatVersion: '2012-12-12'
-Description: |
-  Template which tests autoscaling and load balancing
-Parameters:
-  KeyName:
-    Type: String
-  InstanceType:
-    Type: String
-  ImageId:
-    Type: String
-  Subnet:
-    Type: String
-  StackStart:
-    Description: Epoch seconds when the stack was launched
-    Type: Number
-  ConsumeStartSeconds:
-    Description: Seconds after invocation when memory should be consumed
-    Type: Number
-    Default: '60'
-  ConsumeStopSeconds:
-    Description: Seconds after StackStart when memory should be released
-    Type: Number
-    Default: '420'
-  ScaleUpThreshold:
-    Description: Memory percentage threshold to scale up on
-    Type: String
-    Default: '70'
-  ScaleDownThreshold:
-    Description: Memory percentage threshold to scale down on
-    Type: String
-    Default: '60'
-  ConsumeMemoryLimit:
-    Description: Memory percentage threshold to consume
-    Type: Number
-    Default: '71'
-Resources:
-  SmokeServerGroup:
-    Type: AWS::AutoScaling::AutoScalingGroup
-    Properties:
-      AvailabilityZones: {'Fn::GetAZs': ''}
-      LaunchConfigurationName: {Ref: LaunchConfig}
-      MinSize: '1'
-      MaxSize: '3'
-      VPCZoneIdentifier: [{Ref: Subnet}]
-  SmokeServerScaleUpPolicy:
-    Type: AWS::AutoScaling::ScalingPolicy
-    Properties:
-      AdjustmentType: ChangeInCapacity
-      AutoScalingGroupName: {Ref: SmokeServerGroup}
-      Cooldown: '60'
-      ScalingAdjustment: '1'
-  SmokeServerScaleDownPolicy:
-    Type: AWS::AutoScaling::ScalingPolicy
-    Properties:
-      AdjustmentType: ChangeInCapacity
-      AutoScalingGroupName: {Ref: SmokeServerGroup}
-      Cooldown: '60'
-      ScalingAdjustment: '-1'
-  MEMAlarmHigh:
-    Type: AWS::CloudWatch::Alarm
-    Properties:
-      AlarmDescription: Scale-up if MEM > ScaleUpThreshold% for 10 seconds
-      MetricName: MemoryUtilization
-      Namespace: system/linux
-      Statistic: Average
-      Period: '10'
-      EvaluationPeriods: '1'
-      Threshold: {Ref: ScaleUpThreshold}
-      AlarmActions: [{Ref: SmokeServerScaleUpPolicy}]
-      Dimensions:
-      - Name: AutoScalingGroupName
-        Value: {Ref: SmokeServerGroup}
-      ComparisonOperator: GreaterThanThreshold
-  MEMAlarmLow:
-    Type: AWS::CloudWatch::Alarm
-    Properties:
-      AlarmDescription: Scale-down if MEM < ScaleDownThreshold% for 10 seconds
-      MetricName: MemoryUtilization
-      Namespace: system/linux
-      Statistic: Average
-      Period: '10'
-      EvaluationPeriods: '1'
-      Threshold: {Ref: ScaleDownThreshold}
-      AlarmActions: [{Ref: SmokeServerScaleDownPolicy}]
-      Dimensions:
-      - Name: AutoScalingGroupName
-        Value: {Ref: SmokeServerGroup}
-      ComparisonOperator: LessThanThreshold
-  CfnUser:
-    Type: AWS::IAM::User
-  SmokeKeys:
-    Type: AWS::IAM::AccessKey
-    Properties:
-      UserName: {Ref: CfnUser}
-  SmokeSecurityGroup:
-    Type: AWS::EC2::SecurityGroup
-    Properties:
-      GroupDescription: Standard firewall rules
-      SecurityGroupIngress:
-      - {IpProtocol: tcp, FromPort: '22', ToPort: '22', CidrIp: 0.0.0.0/0}
-      - {IpProtocol: tcp, FromPort: '80', ToPort: '80', CidrIp: 0.0.0.0/0}
-  LaunchConfig:
-    Type: AWS::AutoScaling::LaunchConfiguration
-    Metadata:
-      AWS::CloudFormation::Init:
-        config:
-          files:
-            /etc/cfn/cfn-credentials:
-              content:
-                Fn::Replace:
-                - $AWSAccessKeyId: {Ref: SmokeKeys}
-                  $AWSSecretKey: {'Fn::GetAtt': [SmokeKeys, SecretAccessKey]}
-                - |
-                  AWSAccessKeyId=$AWSAccessKeyId
-                  AWSSecretKey=$AWSSecretKey
-              mode: '000400'
-              owner: root
-              group: root
-            /root/watch_loop:
-              content:
-                Fn::Replace:
-                - _hi_: {Ref: MEMAlarmHigh}
-                  _lo_: {Ref: MEMAlarmLow}
-                - |
-                  #!/bin/bash
-                  while :
-                  do
-                    /opt/aws/bin/cfn-push-stats --watch _hi_ --mem-util
-                    /opt/aws/bin/cfn-push-stats --watch _lo_ --mem-util
-                    sleep 4
-                  done
-              mode: '000700'
-              owner: root
-              group: root
-            /root/consume_memory:
-              content:
-                Fn::Replace:
-                - StackStart: {Ref: StackStart}
-                  ConsumeStopSeconds: {Ref: ConsumeStopSeconds}
-                  ConsumeStartSeconds: {Ref: ConsumeStartSeconds}
-                  ConsumeMemoryLimit: {Ref: ConsumeMemoryLimit}
-                - |
-                  #!/usr/bin/env python
-                  import psutil
-                  import time
-                  import datetime
-                  import sys
-                  a = []
-                  sleep_until_consume = ConsumeStartSeconds
-                  stack_start = StackStart
-                  consume_stop_time = stack_start + ConsumeStopSeconds
-                  memory_limit = ConsumeMemoryLimit
-                  if sleep_until_consume > 0:
-                      sys.stdout.flush()
-                      time.sleep(sleep_until_consume)
-                  while psutil.virtual_memory().percent < memory_limit:
-                      sys.stdout.flush()
-                      a.append(' ' * 10**5)
-                      time.sleep(0.1)
-                  sleep_until_exit = consume_stop_time - time.time()
-                  if sleep_until_exit > 0:
-                      time.sleep(sleep_until_exit)
-              mode: '000700'
-              owner: root
-              group: root
-    Properties:
-      ImageId: {Ref: ImageId}
-      InstanceType: {Ref: InstanceType}
-      KeyName: {Ref: KeyName}
-      SecurityGroups: [{Ref: SmokeSecurityGroup}]
-      UserData:
-        Fn::Base64:
-          Fn::Replace:
-          - ConsumeStopSeconds: {Ref: ConsumeStopSeconds}
-            ConsumeStartSeconds: {Ref: ConsumeStartSeconds}
-            ConsumeMemoryLimit: {Ref: ConsumeMemoryLimit}
-          - |
-            #!/bin/bash -v
-            /opt/aws/bin/cfn-init
-            # report on memory consumption every 4 seconds
-            /root/watch_loop &
-            # wait ConsumeStartSeconds then ramp up memory consumption
-            # until it is over ConsumeMemoryLimit%
-            # then exits ConsumeStopSeconds seconds after stack launch
-            /root/consume_memory > /root/consume_memory.log &
diff --git a/tempest/scenario/orchestration/test_server_cfn_init.py b/tempest/scenario/orchestration/test_server_cfn_init.py
index 36e6126..ddfabe4 100644
--- a/tempest/scenario/orchestration/test_server_cfn_init.py
+++ b/tempest/scenario/orchestration/test_server_cfn_init.py
@@ -38,7 +38,7 @@
             self.keypair_name = CONF.orchestration.keypair_name
         else:
             self.keypair = self.create_keypair()
-            self.keypair_name = self.keypair.id
+            self.keypair_name = self.keypair['name']
 
     def launch_stack(self):
         net = self._get_default_network()
@@ -52,40 +52,46 @@
 
         # create the stack
         self.template = self._load_template(__file__, self.template_name)
-        self.client.stacks.create(
-            stack_name=self.stack_name,
+        _, stack = self.client.create_stack(
+            name=self.stack_name,
             template=self.template,
             parameters=self.parameters)
+        stack = stack['stack']
 
-        self.stack = self.client.stacks.get(self.stack_name)
-        self.stack_identifier = '%s/%s' % (self.stack_name, self.stack.id)
-        self.addCleanup(self._stack_delete, self.stack_identifier)
+        _, self.stack = self.client.get_stack(stack['id'])
+        self.stack_identifier = '%s/%s' % (self.stack_name, self.stack['id'])
+        self.addCleanup(self.delete_wrapper,
+                        self.orchestration_client.delete_stack,
+                        self.stack_identifier)
 
     def check_stack(self):
         sid = self.stack_identifier
-        self._wait_for_resource_status(
+        self.client.wait_for_resource_status(
             sid, 'WaitHandle', 'CREATE_COMPLETE')
-        self._wait_for_resource_status(
+        self.client.wait_for_resource_status(
             sid, 'SmokeSecurityGroup', 'CREATE_COMPLETE')
-        self._wait_for_resource_status(
+        self.client.wait_for_resource_status(
             sid, 'SmokeKeys', 'CREATE_COMPLETE')
-        self._wait_for_resource_status(
+        self.client.wait_for_resource_status(
             sid, 'CfnUser', 'CREATE_COMPLETE')
-        self._wait_for_resource_status(
+        self.client.wait_for_resource_status(
             sid, 'SmokeServer', 'CREATE_COMPLETE')
 
-        server_resource = self.client.resources.get(sid, 'SmokeServer')
-        server_id = server_resource.physical_resource_id
-        server = self.compute_client.servers.get(server_id)
-        server_ip = server.networks[CONF.compute.network_for_ssh][0]
+        _, server_resource = self.client.get_resource(sid, 'SmokeServer')
+        server_id = server_resource['physical_resource_id']
+        _, server = self.servers_client.get_server(server_id)
+        server_ip =\
+            server['addresses'][CONF.compute.network_for_ssh][0]['addr']
 
-        if not self._ping_ip_address(server_ip):
+        if not self.ping_ip_address(
+            server_ip, ping_timeout=CONF.orchestration.build_timeout):
             self._log_console_output(servers=[server])
             self.fail(
-                "Timed out waiting for %s to become reachable" % server_ip)
+                "(CfnInitScenarioTest:test_server_cfn_init) Timed out waiting "
+                "for %s to become reachable" % server_ip)
 
         try:
-            self._wait_for_resource_status(
+            self.client.wait_for_resource_status(
                 sid, 'WaitCondition', 'CREATE_COMPLETE')
         except (exceptions.StackResourceBuildErrorException,
                 exceptions.TimeoutException) as e:
@@ -96,9 +102,9 @@
             # logs to be compared
             self._log_console_output(servers=[server])
 
-        self._wait_for_stack_status(sid, 'CREATE_COMPLETE')
+        self.client.wait_for_stack_status(sid, 'CREATE_COMPLETE')
 
-        stack = self.client.stacks.get(sid)
+        _, stack = self.client.get_stack(sid)
 
         # This is an assert of great significance, as it means the following
         # has happened:
@@ -123,6 +129,7 @@
                 raise e
 
     @test.attr(type='slow')
+    @test.skip_because(bug='1374175')
     @test.services('orchestration', 'compute')
     def test_server_cfn_init(self):
         self.assign_keypair()
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index 3ad5c69..75769ce 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -33,8 +33,8 @@
     Deletes aggregate
     """
     @classmethod
-    def setUpClass(cls):
-        super(TestAggregatesBasicOps, cls).setUpClass()
+    def resource_setup(cls):
+        super(TestAggregatesBasicOps, cls).resource_setup()
         cls.aggregates_client = cls.manager.aggregates_client
         cls.hosts_client = cls.manager.hosts_client
 
diff --git a/tempest/scenario/test_baremetal_basic_ops.py b/tempest/scenario/test_baremetal_basic_ops.py
index 9ad6bc4..ea10140 100644
--- a/tempest/scenario/test_baremetal_basic_ops.py
+++ b/tempest/scenario/test_baremetal_basic_ops.py
@@ -41,26 +41,23 @@
           expected state transitions
     """
     def rebuild_instance(self, preserve_ephemeral=False):
-        self.rebuild_server(self.instance,
+        self.rebuild_server(server_id=self.instance['id'],
                             preserve_ephemeral=preserve_ephemeral,
                             wait=False)
 
-        node = self.get_node(instance_id=self.instance.id)
-        self.instance = self.compute_client.servers.get(self.instance.id)
-
-        self.addCleanup_with_wait(self.compute_client.servers,
-                                  self.instance.id,
-                                  cleanup_callable=self.delete_wrapper,
-                                  cleanup_args=[self.instance])
+        node = self.get_node(instance_id=self.instance['id'])
 
         # We should remain on the same node
-        self.assertEqual(self.node.uuid, node.uuid)
+        self.assertEqual(self.node['uuid'], node['uuid'])
         self.node = node
 
-        self.status_timeout(self.compute_client.servers, self.instance.id,
-                            'REBUILD')
-        self.status_timeout(self.compute_client.servers, self.instance.id,
-                            'ACTIVE')
+        self.servers_client.wait_for_server_status(
+            server_id=self.instance['id'],
+            status='REBUILD',
+            ready_wait=False)
+        self.servers_client.wait_for_server_status(
+            server_id=self.instance['id'],
+            status='ACTIVE')
 
     def create_remote_file(self, client, filename):
         """Create a file on the remote client connection.
@@ -99,23 +96,26 @@
 
     def get_flavor_ephemeral_size(self):
         """Returns size of the ephemeral partition in GiB."""
-        f_id = self.instance.flavor['id']
-        ephemeral = self.compute_client.flavors.get(f_id).ephemeral
-        if ephemeral != 'N/A':
-            return int(ephemeral)
-        return None
+        f_id = self.instance['flavor']['id']
+        _, flavor = self.flavors_client.get_flavor_details(f_id)
+        ephemeral = flavor.get('OS-FLV-EXT-DATA:ephemeral')
+        if not ephemeral or ephemeral == 'N/A':
+            return None
+        return int(ephemeral)
 
     def add_floating_ip(self):
-        floating_ip = self.compute_client.floating_ips.create()
-        self.instance.add_floating_ip(floating_ip)
-        return floating_ip.ip
+        _, floating_ip = self.floating_ips_client.create_floating_ip()
+        self.floating_ips_client.associate_floating_ip_to_server(
+            floating_ip['ip'], self.instance['id'])
+        return floating_ip['ip']
 
     def validate_ports(self):
-        for port in self.get_ports(self.node.uuid):
-            n_port_id = port.extra['vif_port_id']
-            n_port = self.network_client.show_port(n_port_id)['port']
-            self.assertEqual(n_port['device_id'], self.instance.id)
-            self.assertEqual(n_port['mac_address'], port.address)
+        for port in self.get_ports(self.node['uuid']):
+            n_port_id = port['extra']['vif_port_id']
+            _, body = self.network_client.show_port(n_port_id)
+            n_port = body['port']
+            self.assertEqual(n_port['device_id'], self.instance['id'])
+            self.assertEqual(n_port['mac_address'], port['address'])
 
     @test.services('baremetal', 'compute', 'image', 'network')
     def test_baremetal_server_ops(self):
@@ -132,19 +132,23 @@
         # We expect the ephemeral partition to be mounted on /mnt and to have
         # the same size as our flavor definition.
         eph_size = self.get_flavor_ephemeral_size()
-        self.assertIsNotNone(eph_size)
-        self.verify_partition(vm_client, 'ephemeral0', '/mnt', eph_size)
+        if eph_size > 0:
+            preserve_ephemeral = True
 
-        # Create the test file
-        self.create_remote_file(vm_client, test_filename)
+            self.verify_partition(vm_client, 'ephemeral0', '/mnt', eph_size)
+            # Create the test file
+            self.create_remote_file(vm_client, test_filename)
+        else:
+            preserve_ephemeral = False
 
-        # Rebuild and preserve the ephemeral partition
-        self.rebuild_instance(True)
+        # Rebuild and preserve the ephemeral partition if it exists
+        self.rebuild_instance(preserve_ephemeral)
         self.verify_connectivity()
 
         # Check that we maintained our data
-        vm_client = self.get_remote_client(self.instance)
-        self.verify_partition(vm_client, 'ephemeral0', '/mnt', eph_size)
-        vm_client.exec_command('ls ' + test_filename)
+        if eph_size > 0:
+            vm_client = self.get_remote_client(self.instance)
+            self.verify_partition(vm_client, 'ephemeral0', '/mnt', eph_size)
+            vm_client.exec_command('ls ' + test_filename)
 
         self.terminate_instance()
diff --git a/tempest/scenario/test_dashboard_basic_ops.py b/tempest/scenario/test_dashboard_basic_ops.py
index 4fcc70a..875a1d9 100644
--- a/tempest/scenario/test_dashboard_basic_ops.py
+++ b/tempest/scenario/test_dashboard_basic_ops.py
@@ -34,12 +34,11 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        cls.set_network_resources()
-        super(TestDashboardBasicOps, cls).setUpClass()
-
+    def resource_setup(cls):
         if not CONF.service_available.horizon:
             raise cls.skipException("Horizon support is required")
+        cls.set_network_resources()
+        super(TestDashboardBasicOps, cls).resource_setup()
 
     def check_login_page(self):
         response = urllib2.urlopen(CONF.dashboard.dashboard_url)
diff --git a/tempest/scenario/test_encrypted_cinder_volumes.py b/tempest/scenario/test_encrypted_cinder_volumes.py
index 366cd93..ac2ef8a 100644
--- a/tempest/scenario/test_encrypted_cinder_volumes.py
+++ b/tempest/scenario/test_encrypted_cinder_volumes.py
@@ -37,12 +37,12 @@
 
     def create_encrypted_volume(self, encryption_provider):
         volume_type = self.create_volume_type(name='luks')
-        self.create_encryption_type(type_id=volume_type.id,
+        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)
+        self.volume = self.create_volume(volume_type=volume_type['name'])
 
     def attach_detach_volume(self):
         self.nova_volume_attach()
diff --git a/tempest/scenario/test_large_ops.py b/tempest/scenario/test_large_ops.py
index 15cf13b..91b95a8 100644
--- a/tempest/scenario/test_large_ops.py
+++ b/tempest/scenario/test_large_ops.py
@@ -25,7 +25,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class TestLargeOpsScenario(manager.NetworkScenarioTest):
+class TestLargeOpsScenario(manager.ScenarioTest):
 
     """
     Test large operations.
@@ -38,40 +38,48 @@
     """
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(cls):
+        if CONF.scenario.large_ops_number < 1:
+            raise cls.skipException("large_ops_number not set to multiple "
+                                    "instances")
         cls.set_network_resources()
-        super(TestLargeOpsScenario, cls).setUpClass()
+        super(TestLargeOpsScenario, cls).resource_setup()
 
     def _wait_for_server_status(self, status):
         for server in self.servers:
-            self.status_timeout(
-                self.compute_client.servers, server.id, status)
+            # Make sure nova list keeps working throughout the build process
+            self.servers_client.list_servers()
+            self.servers_client.wait_for_server_status(server['id'], status)
 
     def nova_boot(self):
         name = data_utils.rand_name('scenario-server-')
-        client = self.compute_client
         flavor_id = CONF.compute.flavor_ref
-        secgroup = self._create_security_group_nova()
-        self.servers = client.servers.create(
-            name=name, image=self.image,
-            flavor=flavor_id,
+        secgroup = self._create_security_group()
+        self.servers_client.create_server(
+            name,
+            self.image,
+            flavor_id,
             min_count=CONF.scenario.large_ops_number,
-            security_groups=[secgroup.name])
+            security_groups=[secgroup])
         # needed because of bug 1199788
-        self.servers = [x for x in client.servers.list() if name in x.name]
+        params = {'name': name}
+        _, server_list = self.servers_client.list_servers(params)
+        self.servers = server_list['servers']
         for server in self.servers:
             # after deleting all servers - wait for all servers to clear
             # before cleanup continues
-            self.addCleanup(self.delete_timeout,
-                            self.compute_client.servers,
-                            server.id)
+            self.addCleanup(self.servers_client.wait_for_server_termination,
+                            server['id'])
         for server in self.servers:
-            self.addCleanup_with_wait(self.compute_client.servers, server.id)
+            self.addCleanup_with_wait(
+                waiter_callable=(self.servers_client.
+                                 wait_for_server_termination),
+                thing_id=server['id'], thing_id_param='server_id',
+                cleanup_callable=self.delete_wrapper,
+                cleanup_args=[self.servers_client.delete_server, server['id']])
         self._wait_for_server_status('ACTIVE')
 
     def _large_ops_scenario(self):
-        if CONF.scenario.large_ops_number < 1:
-            return
         self.glance_image_create()
         self.nova_boot()
 
diff --git a/tempest/scenario/test_load_balancer_basic.py b/tempest/scenario/test_load_balancer_basic.py
index 8191984..9e404c8 100644
--- a/tempest/scenario/test_load_balancer_basic.py
+++ b/tempest/scenario/test_load_balancer_basic.py
@@ -18,11 +18,11 @@
 import time
 import urllib2
 
-from tempest.api.network import common as net_common
 from tempest.common import commands
 from tempest import config
 from tempest import exceptions
 from tempest.scenario import manager
+from tempest.services.network import resources as net_resources
 from tempest import test
 
 config = config.CONF
@@ -38,9 +38,8 @@
     2. SSH to the instance and start two servers
     3. Create a load balancer with two members and with ROUND_ROBIN algorithm
        associate the VIP with a floating ip
-    4. Send 10 requests to the floating ip and check that they are shared
-       between the two servers and that both of them get equal portions
-    of the requests
+    4. Send NUM requests to the floating ip and check that they are shared
+       between the two servers.
     """
 
     @classmethod
@@ -58,8 +57,8 @@
             raise cls.skipException(msg)
 
     @classmethod
-    def setUpClass(cls):
-        super(TestLoadBalancerBasic, cls).setUpClass()
+    def resource_setup(cls):
+        super(TestLoadBalancerBasic, cls).resource_setup()
         cls.check_preconditions()
         cls.servers_keypairs = {}
         cls.members = []
@@ -67,15 +66,45 @@
         cls.server_ips = {}
         cls.port1 = 80
         cls.port2 = 88
+        cls.num = 50
 
     def setUp(self):
         super(TestLoadBalancerBasic, self).setUp()
         self.server_ips = {}
         self.server_fixed_ips = {}
-        self._create_security_group()
+        self._create_security_group_for_test()
+        self._set_net_and_subnet()
 
-    def _create_security_group(self):
-        self.security_group = self._create_security_group_neutron(
+    def _set_net_and_subnet(self):
+        """
+        Query and set appropriate network and subnet attributes to be used
+        for the test.  Existing tenant networks are used if they are found.
+        The configured private network and associated subnet is used as a
+        fallback in absence of tenant networking.
+        """
+        try:
+            tenant_net = self._list_networks(tenant_id=self.tenant_id)[0]
+        except IndexError:
+            tenant_net = None
+
+        if tenant_net:
+            tenant_subnet = self._list_subnets(tenant_id=self.tenant_id)[0]
+            self.subnet = net_resources.DeletableSubnet(
+                client=self.network_client,
+                **tenant_subnet)
+            self.network = tenant_net
+        else:
+            self.network = self._get_network_by_name(
+                config.compute.fixed_network_name)
+            # TODO(adam_g): We are assuming that the first subnet associated
+            # with the fixed network is the one we want.  In the future, we
+            # should instead pull a subnet id from config, which is set by
+            # devstack/admin/etc.
+            subnet = self._list_subnets(network_id=self.network['id'])[0]
+            self.subnet = net_resources.AttributeDict(subnet)
+
+    def _create_security_group_for_test(self):
+        self.security_group = self._create_security_group(
             tenant_id=self.tenant_id)
         self._create_security_group_rules_for_port(self.port1)
         self._create_security_group_rules_for_port(self.port2)
@@ -88,35 +117,35 @@
             'port_range_max': port,
         }
         self._create_security_group_rule(
-            client=self.network_client,
             secgroup=self.security_group,
             tenant_id=self.tenant_id,
             **rule)
 
     def _create_server(self, name):
-        keypair = self.create_keypair(name='keypair-%s' % name)
-        security_groups = [self.security_group.name]
-        net = self._list_networks(tenant_id=self.tenant_id)[0]
+        keypair = self.create_keypair()
+        security_groups = [self.security_group]
         create_kwargs = {
             'nics': [
-                {'net-id': net['id']},
+                {'net-id': self.network['id']},
             ],
-            'key_name': keypair.name,
+            'key_name': keypair['name'],
             'security_groups': security_groups,
         }
-        server = self.create_server(name=name,
-                                    create_kwargs=create_kwargs)
-        self.servers_keypairs[server.id] = keypair
+        net_name = self.network['name']
+        server = self.create_server(name=name, create_kwargs=create_kwargs)
+        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.floating_ips[floating_ip] = server
-            self.server_ips[server.id] = floating_ip.floating_ip_address
+            self.server_ips[server['id']] = floating_ip.floating_ip_address
         else:
-            self.server_ips[server.id] = server.networks[net['name']][0]
-        self.server_fixed_ips[server.id] = server.networks[net['name']][0]
+            self.server_ips[server['id']] =\
+                server['addresses'][net_name][0]['addr']
+        self.server_fixed_ips[server['id']] =\
+            server['addresses'][net_name][0]['addr']
         self.assertTrue(self.servers_keypairs)
         return server
 
@@ -132,10 +161,9 @@
         1. SSH to the instance
         2. Start two http backends listening on ports 80 and 88 respectively
         """
-
         for server_id, ip in self.server_ips.iteritems():
-            private_key = self.servers_keypairs[server_id].private_key
-            server_name = self.compute_client.servers.get(server_id).name
+            private_key = self.servers_keypairs[server_id]['private_key']
+            server_name = self.servers_client.get_server(server_id)[1]['name']
             username = config.scenario.ssh_user
             ssh_client = self.get_remote_client(
                 server_or_ip=ip,
@@ -196,10 +224,6 @@
 
     def _create_pool(self):
         """Create a pool with ROUND_ROBIN algorithm."""
-        # get tenant subnet and verify there's only one
-        subnet = self._list_subnets(tenant_id=self.tenant_id)[0]
-        self.subnet = net_common.DeletableSubnet(client=self.network_client,
-                                                 **subnet)
         self.pool = super(TestLoadBalancerBasic, self)._create_pool(
             lb_method='ROUND_ROBIN',
             protocol='HTTP',
@@ -245,11 +269,7 @@
                                     protocol_port=80,
                                     subnet_id=self.subnet.id,
                                     pool_id=self.pool.id)
-        self.status_timeout(NeutronRetriever(self.network_client,
-                                             self.network_client.vip_path,
-                                             net_common.DeletableVip),
-                            self.vip.id,
-                            expected_status='ACTIVE')
+        self.vip.wait_for_status('ACTIVE')
         if (config.network.public_network_id and not
                 config.network.tenant_networks_reachable):
             self._assign_floating_ip_to_vip(self.vip)
@@ -262,60 +282,30 @@
         # 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)
+        self.network_client.update_port(
+            self.vip.port_id, security_groups=[self.security_group.id])
 
     def _check_load_balancing(self):
         """
-        1. Send 10 requests on the floating ip associated with the VIP
-        2. Check that the requests are shared between
-           the two servers and that both of them get equal portions
-           of the requests
+        1. Send NUM requests on the floating ip associated with the VIP
+        2. Check that the requests are shared between the two servers
         """
 
         self._check_connection(self.vip_ip)
-        self._send_requests(self.vip_ip, set(["server1", "server2"]))
+        self._send_requests(self.vip_ip, ["server1", "server2"])
 
-    def _send_requests(self, vip_ip, expected, num_req=10):
-        count = 0
-        while count < num_req:
-            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))
+    def _send_requests(self, vip_ip, servers):
+        counters = dict.fromkeys(servers, 0)
+        for i in range(self.num):
+            server = urllib2.urlopen("http://{0}/".format(vip_ip)).read()
+            counters[server] += 1
+        # Assert that each member of the pool gets balanced at least once
+        for member, counter in counters.iteritems():
+            self.assertGreater(counter, 0, 'Member %s never balanced' % member)
 
-    @test.attr(type='smoke')
     @test.services('compute', 'network')
     def test_load_balancer_basic(self):
         self._create_server('server1')
         self._start_servers()
         self._create_load_balancer()
         self._check_load_balancing()
-
-
-class NeutronRetriever(object):
-    """
-    Helper class to make possible handling neutron objects returned by GET
-    requests as attribute dicts.
-
-    Whet get() method is called, the returned dictionary is wrapped into
-    a corresponding DeletableResource class which provides attribute access
-    to dictionary values.
-
-    Usage:
-        This retriever is used to allow using status_timeout from
-        tempest.manager with Neutron objects.
-    """
-
-    def __init__(self, network_client, path, resource):
-        self.network_client = network_client
-        self.path = path
-        self.resource = resource
-
-    def get(self, thing_id):
-        obj = self.network_client.get(self.path % thing_id)
-        return self.resource(client=self.network_client, **obj.values()[0])
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 8a8e387..ead021e 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -16,6 +16,7 @@
 from tempest.common import custom_matchers
 from tempest.common import debug
 from tempest import config
+from tempest import exceptions
 from tempest.openstack.common import log as logging
 from tempest.scenario import manager
 from tempest import test
@@ -77,9 +78,8 @@
 
     def nova_volume_attach(self):
         volume_device_path = '/dev/' + CONF.compute.volume_device_name
-        _, volume_attachment = self.servers_client.attach_volume(
+        _, volume = self.servers_client.attach_volume(
             self.server['id'], self.volume['id'], volume_device_path)
-        volume = volume_attachment['volumeAttachment']
         self.assertEqual(self.volume['id'], volume['id'])
         self.volumes_client.wait_for_volume_status(volume['id'], 'in-use')
         # Refresh the volume after the attachment
@@ -130,6 +130,17 @@
         self.addCleanup(self.servers_client.remove_security_group,
                         self.server['id'], secgroup['name'])
 
+        def wait_for_secgroup_add():
+            _, body = self.servers_client.get_server(self.server['id'])
+            return {'name': secgroup['name']} in body['security_groups']
+
+        if not test.call_until_true(wait_for_secgroup_add,
+                                    CONF.compute.build_timeout,
+                                    CONF.compute.build_interval):
+            msg = ('Timed out waiting for adding security group %s to server '
+                   '%s' % (secgroup['id'], self.server['id']))
+            raise exceptions.TimeoutException(msg)
+
     @test.services('compute', 'volume', 'image', 'network')
     def test_minimum_basic_scenario(self):
         self.glance_image_create()
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index 431de9a..0c48334 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -40,9 +40,8 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(TestNetworkAdvancedServerOps, cls).setUpClass()
-        cls.check_preconditions()
+    def check_preconditions(cls):
+        super(TestNetworkAdvancedServerOps, cls).check_preconditions()
         if not (CONF.network.tenant_networks_reachable
                 or CONF.network.public_network_id):
             msg = ('Either tenant_networks_reachable must be "true", or '
@@ -50,88 +49,99 @@
             cls.enabled = False
             raise cls.skipException(msg)
 
-    def setUp(self):
-        super(TestNetworkAdvancedServerOps, self).setUp()
-        key_name = data_utils.rand_name('keypair-smoke-')
-        self.keypair = self.create_keypair(name=key_name)
-        security_group =\
-            self._create_security_group_neutron(tenant_id=self.tenant_id)
-        network = self._create_network(self.tenant_id)
-        router = self._get_router(self.tenant_id)
-        subnet = self._create_subnet(network)
-        subnet.add_to_router(router.id)
+    @classmethod
+    def resource_setup(cls):
+        # Create no network resources for these tests.
+        cls.set_network_resources()
+        super(TestNetworkAdvancedServerOps, cls).resource_setup()
+
+    def _setup_network_and_servers(self):
+        self.keypair = self.create_keypair()
+        security_group = self._create_security_group()
+        network, subnet, router = self.create_networks()
         public_network_id = CONF.network.public_network_id
         create_kwargs = {
-            'nics': [
-                {'net-id': network.id},
+            'networks': [
+                {'uuid': network.id},
             ],
-            'key_name': self.keypair.name,
-            'security_groups': [security_group.name],
+            'key_name': self.keypair['name'],
+            'security_groups': [security_group],
         }
-        server_name = data_utils.rand_name('server-smoke-%d-')
+        server_name = data_utils.rand_name('server-smoke')
         self.server = self.create_server(name=server_name,
                                          create_kwargs=create_kwargs)
         self.floating_ip = self._create_floating_ip(self.server,
                                                     public_network_id)
+        # Verify that we can indeed connect to the server before we mess with
+        # it's state
+        self._wait_server_status_and_check_network_connectivity()
 
     def _check_network_connectivity(self, should_connect=True):
         username = CONF.compute.image_ssh_user
-        private_key = self.keypair.private_key
+        private_key = self.keypair['private_key']
         self._check_tenant_network_connectivity(
-            self.server, username, private_key, should_connect=should_connect,
+            self.server, username, private_key,
+            should_connect=should_connect,
             servers_for_debug=[self.server])
         floating_ip = self.floating_ip.floating_ip_address
         self._check_public_network_connectivity(floating_ip, username,
                                                 private_key, should_connect,
                                                 servers=[self.server])
+        self.check_floating_ip_status(self.floating_ip, 'ACTIVE')
 
     def _wait_server_status_and_check_network_connectivity(self):
-        self.status_timeout(self.compute_client.servers, self.server.id,
-                            'ACTIVE')
+        self.servers_client.wait_for_server_status(self.server['id'], 'ACTIVE')
         self._check_network_connectivity()
 
+    @test.skip_because(bug="1323658")
     @test.services('compute', 'network')
     def test_server_connectivity_stop_start(self):
-        self.server.stop()
-        self.status_timeout(self.compute_client.servers, self.server.id,
-                            'SHUTOFF')
+        self._setup_network_and_servers()
+        self.servers_client.stop(self.server['id'])
+        self.servers_client.wait_for_server_status(self.server['id'],
+                                                   'SHUTOFF')
         self._check_network_connectivity(should_connect=False)
-        self.server.start()
+        self.servers_client.start(self.server['id'])
         self._wait_server_status_and_check_network_connectivity()
 
     @test.services('compute', 'network')
     def test_server_connectivity_reboot(self):
-        self.server.reboot()
+        self._setup_network_and_servers()
+        self.servers_client.reboot(self.server['id'], reboot_type='SOFT')
         self._wait_server_status_and_check_network_connectivity()
 
     @test.services('compute', 'network')
     def test_server_connectivity_rebuild(self):
+        self._setup_network_and_servers()
         image_ref_alt = CONF.compute.image_ref_alt
-        self.server.rebuild(image_ref_alt)
+        self.servers_client.rebuild(self.server['id'],
+                                    image_ref=image_ref_alt)
         self._wait_server_status_and_check_network_connectivity()
 
     @testtools.skipUnless(CONF.compute_feature_enabled.pause,
                           'Pause is not available.')
     @test.services('compute', 'network')
     def test_server_connectivity_pause_unpause(self):
-        self.server.pause()
-        self.status_timeout(self.compute_client.servers, self.server.id,
-                            'PAUSED')
+        self._setup_network_and_servers()
+        self.servers_client.pause_server(self.server['id'])
+        self.servers_client.wait_for_server_status(self.server['id'], 'PAUSED')
         self._check_network_connectivity(should_connect=False)
-        self.server.unpause()
+        self.servers_client.unpause_server(self.server['id'])
         self._wait_server_status_and_check_network_connectivity()
 
     @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
                           'Suspend is not available.')
     @test.services('compute', 'network')
     def test_server_connectivity_suspend_resume(self):
-        self.server.suspend()
-        self.status_timeout(self.compute_client.servers, self.server.id,
-                            'SUSPENDED')
+        self._setup_network_and_servers()
+        self.servers_client.suspend_server(self.server['id'])
+        self.servers_client.wait_for_server_status(self.server['id'],
+                                                   'SUSPENDED')
         self._check_network_connectivity(should_connect=False)
-        self.server.resume()
+        self.servers_client.resume_server(self.server['id'])
         self._wait_server_status_and_check_network_connectivity()
 
+    @test.skip_because(bug="1323658")
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize is not available.')
     @test.services('compute', 'network')
@@ -140,9 +150,9 @@
         if resize_flavor == CONF.compute.flavor_ref:
             msg = "Skipping test - flavor_ref and flavor_ref_alt are identical"
             raise self.skipException(msg)
-        resize_flavor = CONF.compute.flavor_ref_alt
-        self.server.resize(resize_flavor)
-        self.status_timeout(self.compute_client.servers, self.server.id,
-                            'VERIFY_RESIZE')
-        self.server.confirm_resize()
+        self._setup_network_and_servers()
+        self.servers_client.resize(self.server['id'], flavor_ref=resize_flavor)
+        self.servers_client.wait_for_server_status(self.server['id'],
+                                                   'VERIFY_RESIZE')
+        self.servers_client.confirm_resize(self.server['id'])
         self._wait_server_status_and_check_network_connectivity()
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 81cfd91..e3f87e9 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -34,7 +34,7 @@
                                            ['floating_ip', 'server'])
 
 
-class TestNetworkBasicOps(manager.NeutronScenarioTest):
+class TestNetworkBasicOps(manager.NetworkScenarioTest):
 
     """
     This smoke test suite assumes that Nova has been configured to
@@ -88,23 +88,26 @@
             raise cls.skipException(msg)
 
     @classmethod
-    def setUpClass(cls):
-        # Create no network resources for these tests.
-        cls.set_network_resources()
-        super(TestNetworkBasicOps, cls).setUpClass()
+    def resource_setup(cls):
         for ext in ['router', 'security-group']:
             if not test.is_extension_enabled(ext, 'network'):
                 msg = "%s extension not enabled." % ext
                 raise cls.skipException(msg)
+        # Create no network resources for these tests.
+        cls.set_network_resources()
+        super(TestNetworkBasicOps, cls).resource_setup()
 
     def setUp(self):
         super(TestNetworkBasicOps, self).setUp()
-        self.security_group = \
-            self._create_security_group(tenant_id=self.tenant_id)
-        self.network, self.subnet, self.router = self._create_networks()
-        self.check_networks()
         self.keypairs = {}
         self.servers = []
+
+    def _setup_network_and_servers(self):
+        self.security_group = \
+            self._create_security_group(tenant_id=self.tenant_id)
+        self.network, self.subnet, self.router = self.create_networks()
+        self.check_networks()
+
         name = data_utils.rand_name('server-smoke')
         server = self._create_server(name, self.network)
         self._check_tenant_network_connectivity()
@@ -123,27 +126,29 @@
         self.assertIn(self.network.name, seen_names)
         self.assertIn(self.network.id, seen_ids)
 
-        seen_subnets = self._list_subnets()
-        seen_net_ids = [n['network_id'] for n in seen_subnets]
-        seen_subnet_ids = [n['id'] for n in seen_subnets]
-        self.assertIn(self.network.id, seen_net_ids)
-        self.assertIn(self.subnet.id, seen_subnet_ids)
+        if self.subnet:
+            seen_subnets = self._list_subnets()
+            seen_net_ids = [n['network_id'] for n in seen_subnets]
+            seen_subnet_ids = [n['id'] for n in seen_subnets]
+            self.assertIn(self.network.id, seen_net_ids)
+            self.assertIn(self.subnet.id, seen_subnet_ids)
 
-        seen_routers = self._list_routers()
-        seen_router_ids = [n['id'] for n in seen_routers]
-        seen_router_names = [n['name'] for n in seen_routers]
-        self.assertIn(self.router.name,
-                      seen_router_names)
-        self.assertIn(self.router.id,
-                      seen_router_ids)
+        if self.router:
+            seen_routers = self._list_routers()
+            seen_router_ids = [n['id'] for n in seen_routers]
+            seen_router_names = [n['name'] for n in seen_routers]
+            self.assertIn(self.router.name,
+                          seen_router_names)
+            self.assertIn(self.router.id,
+                          seen_router_ids)
 
     def _create_server(self, name, network):
         keypair = self.create_keypair()
         self.keypairs[keypair['name']] = keypair
         security_groups = [self.security_group]
         create_kwargs = {
-            'nics': [
-                {'net-id': network.id},
+            'networks': [
+                {'uuid': network.id},
             ],
             'key_name': keypair['name'],
             'security_groups': security_groups,
@@ -171,16 +176,28 @@
 
     def _check_public_network_connectivity(self, should_connect=True,
                                            msg=None):
+        """Verifies connectivty to a VM via public network and floating IP,
+        and verifies floating IP has resource status is correct.
+
+        :param should_connect: bool. determines if connectivity check is
+        negative or positive.
+        :param msg: Failure message to add to Error message. Should describe
+        the place in the test scenario where the method was called,
+        to indicate the context of the failure
+        """
         ssh_login = CONF.compute.image_ssh_user
         floating_ip, server = self.floating_ip_tuple
         ip_address = floating_ip.floating_ip_address
         private_key = None
+        floatingip_status = 'DOWN'
         if should_connect:
             private_key = self._get_server_key(server)
+            floatingip_status = 'ACTIVE'
         # call the common method in the parent class
         super(TestNetworkBasicOps, self)._check_public_network_connectivity(
             ip_address, ssh_login, private_key, should_connect, msg,
             self.servers)
+        self.check_floating_ip_status(floating_ip, floatingip_status)
 
     def _disassociate_floating_ips(self):
         floating_ip, server = self.floating_ip_tuple
@@ -198,7 +215,7 @@
             floating_ip, server)
 
     def _create_new_network(self):
-        self.new_net = self._create_network(self.tenant_id)
+        self.new_net = self._create_network(tenant_id=self.tenant_id)
         self.new_subnet = self._create_subnet(
             network=self.new_net,
             gateway_ip=None)
@@ -345,8 +362,11 @@
         VMs are created with unique keypair so connectivity also asserts that
         floating IP is associated with the new VM instead of the old one
 
+        Verifies that floating IP status is updated correctly after each change
+
 
         """
+        self._setup_network_and_servers()
         self._check_public_network_connectivity(should_connect=True)
         self._check_network_internal_connectivity(network=self.network)
         self._check_network_external_connectivity()
@@ -372,7 +392,7 @@
         4. check VM can ping new network dhcp port
 
         """
-
+        self._setup_network_and_servers()
         self._check_public_network_connectivity(should_connect=True)
         self._create_new_network()
         self._hotplug_server()
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index ecb802f..6ea3253 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -99,7 +99,7 @@
         """
 
         def __init__(self, credentials):
-            self.manager = clients.OfficialClientManager(credentials)
+            self.manager = clients.Manager(credentials)
             # Credentials from manager are filled with both names and IDs
             self.creds = self.manager.credentials
             self.network = None
@@ -113,18 +113,13 @@
             self.subnet = subnet
             self.router = router
 
-        def _get_tenant_credentials(self):
-            # FIXME(andreaf) Unused method
-            return self.creds
-
     @classmethod
     def check_preconditions(cls):
-        super(TestSecurityGroupsBasicOps, cls).check_preconditions()
-        if (cls.alt_creds is None) or \
-                (cls.tenant_id is cls.alt_creds.tenant_id):
-            msg = 'No alt_tenant defined'
+        if CONF.baremetal.driver_enabled:
+            msg = ('Not currently supported by baremetal.')
             cls.enabled = False
             raise cls.skipException(msg)
+        super(TestSecurityGroupsBasicOps, cls).check_preconditions()
         if not (CONF.network.tenant_networks_reachable or
                 CONF.network.public_network_id):
             msg = ('Either tenant_networks_reachable must be "true", or '
@@ -133,17 +128,19 @@
             raise cls.skipException(msg)
 
     @classmethod
-    def setUpClass(cls):
+    def resource_setup(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)
-        # Credentials from the manager are filled with both IDs and Names
-        cls.alt_creds = cls.alt_manager.credentials
-        cls.check_preconditions()
+        super(TestSecurityGroupsBasicOps, cls).resource_setup()
         # TODO(mnewby) Consider looking up entities as needed instead
         # of storing them as collections on the class.
+
+        # get credentials for secondary tenant
+        cls.alt_creds = cls.isolated_creds.get_alt_creds()
+        cls.alt_manager = clients.Manager(cls.alt_creds)
+        # Credentials from the manager are filled with both IDs and Names
+        cls.alt_creds = cls.alt_manager.credentials
+
         cls.floating_ips = {}
         cls.tenants = {}
         creds = cls.credentials()
@@ -162,21 +159,22 @@
         self._verify_network_details(self.primary_tenant)
         self._verify_mac_addr(self.primary_tenant)
 
-    def _create_tenant_keypairs(self, tenant_id):
-        keypair = self.create_keypair(
-            name=data_utils.rand_name('keypair-smoke-'))
-        self.tenants[tenant_id].keypair = keypair
+    def _create_tenant_keypairs(self, tenant):
+        keypair = self.create_keypair(tenant.manager.keypairs_client)
+        tenant.keypair = keypair
 
     def _create_tenant_security_groups(self, tenant):
         access_sg = self._create_empty_security_group(
             namestart='secgroup_access-',
-            tenant_id=tenant.creds.tenant_id
+            tenant_id=tenant.creds.tenant_id,
+            client=tenant.manager.network_client
         )
 
         # 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
+            tenant_id=tenant.creds.tenant_id,
+            client=tenant.manager.network_client
         )
         tenant.security_groups.update(access=access_sg, default=def_sg)
         ssh_rule = dict(
@@ -185,7 +183,9 @@
             port_range_max=22,
             direction='ingress',
         )
-        self._create_security_group_rule(secgroup=access_sg, **ssh_rule)
+        self._create_security_group_rule(secgroup=access_sg,
+                                         client=tenant.manager.network_client,
+                                         **ssh_rule)
 
     def _verify_network_details(self, tenant):
         # Checks that we see the newly created network/subnet/router via
@@ -212,7 +212,7 @@
 
         myport = (tenant.router.id, tenant.subnet.id)
         router_ports = [(i['device_id'], i['fixed_ips'][0]['subnet_id']) for i
-                        in self.network_client.list_ports()['ports']
+                        in self._list_ports()
                         if self._is_router_port(i)]
 
         self.assertIn(myport, router_ports)
@@ -229,16 +229,19 @@
         """
         self._set_compute_context(tenant)
         if security_groups is None:
-            security_groups = [tenant.security_groups['default'].name]
+            security_groups = [tenant.security_groups['default']]
         create_kwargs = {
-            'nics': [
-                {'net-id': tenant.network.id},
+            'networks': [
+                {'uuid': tenant.network.id},
             ],
-            'key_name': tenant.keypair.name,
+            'key_name': tenant.keypair['name'],
             'security_groups': security_groups,
             'tenant_id': tenant.creds.tenant_id
         }
         server = self.create_server(name=name, create_kwargs=create_kwargs)
+        self.assertEqual(
+            sorted([s['name'] for s in security_groups]),
+            sorted([s['name'] for s in server['security_groups']]))
         return server
 
     def _create_tenant_servers(self, tenant, num=1):
@@ -257,27 +260,30 @@
         in order to access tenant internal network
         workaround ip namespace
         """
-        secgroups = [sg.name for sg in tenant.security_groups.values()]
+        secgroups = tenant.security_groups.values()
         name = 'server-{tenant}-access_point-'.format(
             tenant=tenant.creds.tenant_name)
         name = data_utils.rand_name(name)
         server = self._create_server(name, tenant,
                                      security_groups=secgroups)
         tenant.access_point = server
-        self._assign_floating_ips(server)
+        self._assign_floating_ips(tenant, server)
 
-    def _assign_floating_ips(self, server):
+    def _assign_floating_ips(self, tenant, server):
         public_network_id = CONF.network.public_network_id
-        floating_ip = self._create_floating_ip(server, public_network_id)
-        self.floating_ips.setdefault(server, floating_ip)
+        floating_ip = self._create_floating_ip(
+            server, public_network_id,
+            client=tenant.manager.network_client)
+        self.floating_ips.setdefault(server['id'], floating_ip)
 
     def _create_tenant_network(self, tenant):
-        network, subnet, router = self._create_networks(tenant.creds.tenant_id)
+        network, subnet, router = self.create_networks(
+            client=tenant.manager.network_client)
         tenant.set_network(network, subnet, router)
 
     def _set_compute_context(self, tenant):
-        self.compute_client = tenant.manager.compute_client
-        return self.compute_client
+        self.servers_client = tenant.manager.servers_client
+        return self.servers_client
 
     def _deploy_tenant(self, tenant_or_id):
         """
@@ -290,12 +296,10 @@
         """
         if not isinstance(tenant_or_id, self.TenantProperties):
             tenant = self.tenants[tenant_or_id]
-            tenant_id = tenant_or_id
         else:
             tenant = tenant_or_id
-            tenant_id = tenant.creds.tenant_id
         self._set_compute_context(tenant)
-        self._create_tenant_keypairs(tenant_id)
+        self._create_tenant_keypairs(tenant)
         self._create_tenant_network(tenant)
         self._create_tenant_security_groups(tenant)
         self._set_access_point(tenant)
@@ -305,12 +309,12 @@
         returns the ip (floating/internal) of a server
         """
         if floating:
-            server_ip = self.floating_ips[server].floating_ip_address
+            server_ip = self.floating_ips[server['id']].floating_ip_address
         else:
             server_ip = None
-            network_name = self.tenants[server.tenant_id].network.name
-            if network_name in server.networks:
-                server_ip = server.networks[network_name][0]
+            network_name = self.tenants[server['tenant_id']].network.name
+            if network_name in server['addresses']:
+                server_ip = server['addresses'][network_name][0]['addr']
         return server_ip
 
     def _connect_to_access_point(self, tenant):
@@ -318,8 +322,8 @@
         create ssh connection to tenant access point
         """
         access_point_ssh = \
-            self.floating_ips[tenant.access_point].floating_ip_address
-        private_key = tenant.keypair.private_key
+            self.floating_ips[tenant.access_point['id']].floating_ip_address
+        private_key = tenant.keypair['private_key']
         access_point_ssh = self._ssh_to_server(access_point_ssh,
                                                private_key=private_key)
         return access_point_ssh
@@ -383,6 +387,7 @@
         )
         self._create_security_group_rule(
             secgroup=dest_tenant.security_groups['default'],
+            client=dest_tenant.manager.network_client,
             **ruleset
         )
         access_point_ssh = self._connect_to_access_point(source_tenant)
@@ -396,6 +401,7 @@
         # allow reverse traffic and check
         self._create_security_group_rule(
             secgroup=source_tenant.security_groups['default'],
+            client=source_tenant.manager.network_client,
             **ruleset
         )
 
@@ -414,8 +420,7 @@
         mac_addr = mac_addr.strip().lower()
         # Get the fixed_ips and mac_address fields of all ports. Select
         # only those two columns to reduce the size of the response.
-        port_list = self.network_client.list_ports(
-            fields=['fixed_ips', 'mac_address'])['ports']
+        port_list = self._list_ports(fields=['fixed_ips', 'mac_address'])
         port_detail_list = [
             (port['fixed_ips'][0]['subnet_id'],
              port['fixed_ips'][0]['ip_address'],
@@ -429,6 +434,8 @@
     @test.attr(type='smoke')
     @test.services('compute', 'network')
     def test_cross_tenant_traffic(self):
+        if not self.isolated_creds.is_multi_tenant():
+            raise self.skipException("No secondary tenant defined")
         try:
             # deploy new tenant
             self._deploy_tenant(self.alt_tenant)
diff --git a/tempest/scenario/test_server_advanced_ops.py b/tempest/scenario/test_server_advanced_ops.py
index 463f5aa..d10fcce 100644
--- a/tempest/scenario/test_server_advanced_ops.py
+++ b/tempest/scenario/test_server_advanced_ops.py
@@ -35,13 +35,12 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        cls.set_network_resources()
-        super(TestServerAdvancedOps, cls).setUpClass()
-
+    def resource_setup(cls):
         if CONF.compute.flavor_ref_alt == CONF.compute.flavor_ref:
             msg = "Skipping test - flavor_ref and flavor_ref_alt are identical"
             raise cls.skipException(msg)
+        cls.set_network_resources()
+        super(TestServerAdvancedOps, cls).resource_setup()
 
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize is not available.')
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index b38b1a3..eb636f7 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -35,8 +35,7 @@
      * Create a security group to control network access in instance
      * Add simple permissive rules to the security group
      * Launch an instance
-     * Pause/unpause the instance
-     * Suspend/resume the instance
+     * Perform ssh to instance
      * Terminate the instance
     """
 
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 4783273..e30c824 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -15,7 +15,6 @@
 
 import time
 
-from cinderclient import exceptions as cinder_exceptions
 import testtools
 
 from tempest.common.utils import data_utils
@@ -30,7 +29,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class TestStampPattern(manager.OfficialClientTest):
+class TestStampPattern(manager.ScenarioTest):
     """
     This test is for snapshotting an instance/volume and attaching the volume
     created from snapshot to the instance booted from snapshot.
@@ -52,20 +51,19 @@
     """
 
     @classmethod
-    def setUpClass(cls):
-        super(TestStampPattern, cls).setUpClass()
-
+    def resource_setup(cls):
         if not CONF.volume_feature_enabled.snapshot:
             raise cls.skipException("Cinder volume snapshots are disabled")
+        super(TestStampPattern, cls).resource_setup()
 
     def _wait_for_volume_snapshot_status(self, volume_snapshot, status):
-        self.status_timeout(self.volume_client.volume_snapshots,
-                            volume_snapshot.id, status)
+        self.snapshots_client.wait_for_snapshot_status(volume_snapshot['id'],
+                                                       status)
 
     def _boot_image(self, image_id):
-        security_groups = [self.security_group.name]
+        security_groups = [self.security_group]
         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)
@@ -74,53 +72,53 @@
         self.keypair = self.create_keypair()
 
     def _create_floating_ip(self):
-        floating_ip = self.compute_client.floating_ips.create()
-        self.addCleanup(self.delete_wrapper, floating_ip)
+        _, floating_ip = self.floating_ips_client.create_floating_ip()
+        self.addCleanup(self.delete_wrapper,
+                        self.floating_ips_client.delete_floating_ip,
+                        floating_ip['id'])
         return floating_ip
 
     def _add_floating_ip(self, server, floating_ip):
-        server.add_floating_ip(floating_ip)
+        self.floating_ips_client.associate_floating_ip_to_server(
+            floating_ip['ip'], server['id'])
 
     def _ssh_to_server(self, server_or_ip):
         return self.get_remote_client(server_or_ip)
 
     def _create_volume_snapshot(self, volume):
         snapshot_name = data_utils.rand_name('scenario-snapshot-')
-        volume_snapshots = self.volume_client.volume_snapshots
-        snapshot = volume_snapshots.create(
-            volume.id, display_name=snapshot_name)
+        _, snapshot = self.snapshots_client.create_snapshot(
+            volume['id'], display_name=snapshot_name)
 
         def cleaner():
-            volume_snapshots.delete(snapshot)
+            self.snapshots_client.delete_snapshot(snapshot['id'])
             try:
-                while volume_snapshots.get(snapshot.id):
+                while self.snapshots_client.get_snapshot(snapshot['id']):
                     time.sleep(1)
-            except cinder_exceptions.NotFound:
+            except exceptions.NotFound:
                 pass
         self.addCleanup(cleaner)
         self._wait_for_volume_status(volume, 'available')
-        self._wait_for_volume_snapshot_status(snapshot, 'available')
-        self.assertEqual(snapshot_name, snapshot.display_name)
+        self.snapshots_client.wait_for_snapshot_status(snapshot['id'],
+                                                       'available')
+        self.assertEqual(snapshot_name, snapshot['display_name'])
         return snapshot
 
     def _wait_for_volume_status(self, volume, status):
-        self.status_timeout(
-            self.volume_client.volumes, volume.id, status)
+        self.volumes_client.wait_for_volume_status(volume['id'], status)
 
     def _create_volume(self, snapshot_id=None):
         return self.create_volume(snapshot_id=snapshot_id)
 
     def _attach_volume(self, server, volume):
-        attach_volume_client = self.compute_client.volumes.create_server_volume
-        attached_volume = attach_volume_client(server.id,
-                                               volume.id,
-                                               '/dev/vdb')
-        self.assertEqual(volume.id, attached_volume.id)
+        # TODO(andreaf) we should use device from config instead if vdb
+        _, attached_volume = self.servers_client.attach_volume(
+            server['id'], volume['id'], device='/dev/vdb')
+        self.assertEqual(volume['id'], attached_volume['id'])
         self._wait_for_volume_status(attached_volume, 'in-use')
 
     def _detach_volume(self, server, volume):
-        detach_volume_client = self.compute_client.volumes.delete_server_volume
-        detach_volume_client(server.id, volume.id)
+        self.servers_client.detach_volume(server['id'], volume['id'])
         self._wait_for_volume_status(volume, 'available')
 
     def _wait_for_volume_available_on_the_system(self, server_or_ip):
@@ -157,7 +155,7 @@
     def test_stamp_pattern(self):
         # prepare for booting a instance
         self._add_keypair()
-        self.security_group = self._create_security_group_nova()
+        self.security_group = self._create_security_group()
 
         # boot an instance and create a timestamp file in it
         volume = self._create_volume()
@@ -167,7 +165,7 @@
         if CONF.compute.use_floatingip_for_ssh:
             floating_ip_for_server = self._create_floating_ip()
             self._add_floating_ip(server, floating_ip_for_server)
-            ip_for_server = floating_ip_for_server.ip
+            ip_for_server = floating_ip_for_server['ip']
         else:
             ip_for_server = server
 
@@ -184,17 +182,17 @@
 
         # create second volume from the snapshot(volume2)
         volume_from_snapshot = self._create_volume(
-            snapshot_id=volume_snapshot.id)
+            snapshot_id=volume_snapshot['id'])
 
         # boot second instance from the snapshot(instance2)
-        server_from_snapshot = self._boot_image(snapshot_image.id)
+        server_from_snapshot = self._boot_image(snapshot_image['id'])
 
         # create and add floating IP to server_from_snapshot
         if CONF.compute.use_floatingip_for_ssh:
             floating_ip_for_snapshot = self._create_floating_ip()
             self._add_floating_ip(server_from_snapshot,
                                   floating_ip_for_snapshot)
-            ip_for_snapshot = floating_ip_for_snapshot.ip
+            ip_for_snapshot = floating_ip_for_snapshot['ip']
         else:
             ip_for_snapshot = server_from_snapshot
 
diff --git a/tempest/scenario/test_swift_basic_ops.py b/tempest/scenario/test_swift_basic_ops.py
index ad74ec4..fcb9505 100644
--- a/tempest/scenario/test_swift_basic_ops.py
+++ b/tempest/scenario/test_swift_basic_ops.py
@@ -41,13 +41,16 @@
 
     @test.services('object_storage')
     def test_swift_basic_ops(self):
-        self._get_swift_stat()
-        container_name = self._create_container()
-        obj_name, obj_data = self._upload_object_to_container(container_name)
-        self._list_and_check_container_objects(container_name, [obj_name])
-        self._download_and_verify(container_name, obj_name, obj_data)
-        self._delete_object(container_name, obj_name)
-        self._delete_container(container_name)
+        self.get_swift_stat()
+        container_name = self.create_container()
+        obj_name, obj_data = self.upload_object_to_container(container_name)
+        self.list_and_check_container_objects(container_name,
+                                              present_obj=[obj_name])
+        self.download_and_verify(container_name, obj_name, obj_data)
+        self.delete_object(container_name, obj_name)
+        self.list_and_check_container_objects(container_name,
+                                              not_present_obj=[obj_name])
+        self.delete_container(container_name)
 
     @test.services('object_storage')
     def test_swift_acl_anonymous_download(self):
@@ -58,15 +61,13 @@
         4. Check if the object can be download by anonymous user
         5. Delete the object and container
         """
-        container_name = self._create_container()
-        obj_name, _ = self._upload_object_to_container(container_name)
+        container_name = self.create_container()
+        obj_name, _ = self.upload_object_to_container(container_name)
         obj_url = '%s/%s/%s' % (self.object_client.base_url,
                                 container_name, obj_name)
         http_client = http.ClosingHttp()
         resp, _ = http_client.request(obj_url, 'GET')
         self.assertEqual(resp.status, 401)
-        self._change_container_acl(container_name, '.r:*')
+        self.change_container_acl(container_name, '.r:*')
         resp, _ = http_client.request(obj_url, 'GET')
         self.assertEqual(resp.status, 200)
-        self._delete_object(container_name, obj_name)
-        self._delete_container(container_name)
diff --git a/tempest/scenario/test_swift_telemetry_middleware.py b/tempest/scenario/test_swift_telemetry_middleware.py
new file mode 100644
index 0000000..e8eb45c
--- /dev/null
+++ b/tempest/scenario/test_swift_telemetry_middleware.py
@@ -0,0 +1,103 @@
+#
+# Copyright 2014 Red Hat
+#
+# Author: Chris Dent <chdent@redhat.com>
+# 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 import config
+from tempest.openstack.common import log as logging
+from tempest.scenario import manager
+from tempest import test
+
+CONF = config.CONF
+
+LOG = logging.getLogger(__name__)
+
+# Loop for up to 120 seconds waiting on notifications
+# NOTE(chdent): The choice of 120 seconds is fairly
+# arbitrary: Long enough to give the notifications the
+# chance to travel across a highly latent bus but not
+# so long as to allow excessive latency to never be visible.
+# TODO(chdent): Ideally this value would come from configuration.
+NOTIFICATIONS_WAIT = 120
+NOTIFICATIONS_SLEEP = 1
+
+
+class TestSwiftTelemetry(manager.SwiftScenarioTest):
+    """
+    Test that swift uses the ceilometer middleware.
+     * create container.
+     * upload a file to the created container.
+     * retrieve the file from the created container.
+     * wait for notifications from ceilometer.
+    """
+
+    @classmethod
+    def resource_setup(cls):
+        if not CONF.service_available.ceilometer:
+            skip_msg = ("%s skipped as ceilometer is not available" %
+                        cls.__name__)
+            raise cls.skipException(skip_msg)
+        elif CONF.telemetry.too_slow_to_test:
+            skip_msg = "Ceilometer feature for fast work mysql is disabled"
+            raise cls.skipException(skip_msg)
+        super(TestSwiftTelemetry, cls).resource_setup()
+        cls.telemetry_client = cls.manager.telemetry_client
+
+    def _confirm_notifications(self, container_name, obj_name):
+        """
+        Loop seeking for appropriate notifications about the containers
+        and objects sent to swift.
+        """
+
+        def _check_samples():
+            """
+            Return True only if we have notifications about some
+            containers and some objects and the notifications are about
+            the expected containers and objects.
+            Otherwise returning False will case _check_samples to be
+            called again.
+            """
+            _, results = self.telemetry_client.list_samples(
+                'storage.api.request')
+            LOG.debug('got samples %s', results)
+
+            # Extract container info from samples.
+            containers = [sample['resource_metadata']['container']
+                          for sample in results
+                          if sample['resource_metadata']['container']
+                          != 'None']
+            # Extract object info from samples.
+            objects = [sample['resource_metadata']['object']
+                       for sample in results
+                       if sample['resource_metadata']['object'] != 'None']
+
+            return (containers
+                    and objects
+                    and container_name in containers
+                    and obj_name in objects)
+
+        self.assertTrue(test.call_until_true(_check_samples,
+                                             NOTIFICATIONS_WAIT,
+                                             NOTIFICATIONS_SLEEP),
+                        'Correct notifications were not received after '
+                        '%s seconds.' % NOTIFICATIONS_WAIT)
+
+    @test.services('object_storage', 'telemetry')
+    def test_swift_middleware_notifies(self):
+        container_name = self.create_container()
+        obj_name, _ = self.upload_object_to_container(container_name)
+        self._confirm_notifications(container_name, obj_name)
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index c32923a..62876c4 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -36,11 +36,10 @@
      * Check written content in the instance booted from snapshot
     """
     @classmethod
-    def setUpClass(cls):
-        super(TestVolumeBootPattern, cls).setUpClass()
-
+    def resource_setup(cls):
         if not CONF.volume_feature_enabled.snapshot:
             raise cls.skipException("Cinder volume snapshots are disabled")
+        super(TestVolumeBootPattern, cls).resource_setup()
 
     def _create_volume_from_image(self):
         img_uuid = CONF.compute.image_ref
@@ -117,7 +116,7 @@
                 private_key=keypair['private_key'])
         except Exception:
             LOG.exception('ssh to server failed')
-            self._log_console_output(self)
+            self._log_console_output(servers=[server])
             raise
 
     def _get_content(self, ssh_client):
diff --git a/tempest/scenario/utils.py b/tempest/scenario/utils.py
index e2adb34..e6624a3 100644
--- a/tempest/scenario/utils.py
+++ b/tempest/scenario/utils.py
@@ -25,6 +25,7 @@
 from tempest import clients
 from tempest.common.utils import misc
 from tempest import config
+from tempest import exceptions
 
 CONF = config.CONF
 
@@ -40,33 +41,33 @@
         self.non_ssh_image_pattern = \
             CONF.input_scenario.non_ssh_image_regex
         # Setup clients
-        ocm = clients.OfficialClientManager(
-            auth.get_default_credentials('user'))
-        self.client = ocm.compute_client
+        os = clients.Manager()
+        self.images_client = os.images_client
+        self.flavors_client = os.flavors_client
 
     def ssh_user(self, image_id):
-        _image = self.client.images.get(image_id)
+        _, _image = self.images_client.get_image(image_id)
         for regex, user in self.ssh_users:
             # First match wins
-            if re.match(regex, _image.name) is not None:
+            if re.match(regex, _image['name']) is not None:
                 return user
         else:
             return self.default_ssh_user
 
     def _is_sshable_image(self, image):
         return not re.search(pattern=self.non_ssh_image_pattern,
-                             string=str(image.name))
+                             string=str(image['name']))
 
     def is_sshable_image(self, image_id):
-        _image = self.client.images.get(image_id)
+        _, _image = self.images_client.get_image(image_id)
         return self._is_sshable_image(_image)
 
     def _is_flavor_enough(self, flavor, image):
-        return image.minDisk <= flavor.disk
+        return image['minDisk'] <= flavor['disk']
 
     def is_flavor_enough(self, flavor_id, image_id):
-        _image = self.client.images.get(image_id)
-        _flavor = self.client.flavors.get(flavor_id)
+        _, _image = self.images_client.get_image(image_id)
+        _, _flavor = self.flavors_client.get_flavor_details(flavor_id)
         return self._is_flavor_enough(_flavor, _image)
 
 
@@ -81,7 +82,7 @@
     load_tests = testscenarios.load_tests_apply_scenarios
 
 
-    class TestInputScenario(manager.OfficialClientTest):
+    class TestInputScenario(manager.ScenarioTest):
 
         scenario_utils = utils.InputScenarioUtils()
         scenario_flavor = scenario_utils.scenario_flavors
@@ -91,17 +92,18 @@
 
         def test_create_server_metadata(self):
             name = rand_name('instance')
-            _ = self.compute_client.servers.create(name=name,
-                                                   flavor=self.flavor_ref,
-                                                   image=self.image_ref)
+            self.servers_client.create_server(name=name,
+                                              flavor_ref=self.flavor_ref,
+                                              image_ref=self.image_ref)
     """
     validchars = "-_.{ascii}{digit}".format(ascii=string.ascii_letters,
                                             digit=string.digits)
 
     def __init__(self):
-        ocm = clients.OfficialClientManager(
+        os = clients.Manager(
             auth.get_default_credentials('user', fill_in=False))
-        self.client = ocm.compute_client
+        self.images_client = os.images_client
+        self.flavors_client = os.flavors_client
         self.image_pattern = CONF.input_scenario.image_regex
         self.flavor_pattern = CONF.input_scenario.flavor_regex
 
@@ -118,10 +120,11 @@
         if not CONF.service_available.glance:
             return []
         if not hasattr(self, '_scenario_images'):
-            images = self.client.images.list(detailed=False)
+            _, images = self.images_client.list_images()
             self._scenario_images = [
-                (self._normalize_name(i.name), dict(image_ref=i.id))
-                for i in images if re.search(self.image_pattern, str(i.name))
+                (self._normalize_name(i['name']), dict(image_ref=i['id']))
+                for i in images if re.search(self.image_pattern,
+                                             str(i['name']))
             ]
         return self._scenario_images
 
@@ -131,10 +134,11 @@
         :return: a scenario with name and uuid of flavors
         """
         if not hasattr(self, '_scenario_flavors'):
-            flavors = self.client.flavors.list(detailed=False)
+            _, flavors = self.flavors_client.list_flavors()
             self._scenario_flavors = [
-                (self._normalize_name(f.name), dict(flavor_ref=f.id))
-                for f in flavors if re.search(self.flavor_pattern, str(f.name))
+                (self._normalize_name(f['name']), dict(flavor_ref=f['id']))
+                for f in flavors if re.search(self.flavor_pattern,
+                                              str(f['name']))
             ]
         return self._scenario_flavors
 
@@ -148,9 +152,12 @@
         loader, standard_tests, pattern = args
     else:
         standard_tests, module, loader = args
-    scenario_utils = InputScenarioUtils()
-    scenario_flavor = scenario_utils.scenario_flavors
-    scenario_image = scenario_utils.scenario_images
+    try:
+        scenario_utils = InputScenarioUtils()
+        scenario_flavor = scenario_utils.scenario_flavors
+        scenario_image = scenario_utils.scenario_images
+    except exceptions.InvalidConfiguration:
+        return standard_tests
     for test in testtools.iterate_tests(standard_tests):
         setattr(test, 'scenarios', testscenarios.multiply_scenarios(
             scenario_image,
diff --git a/tempest/services/baremetal/base.py b/tempest/services/baremetal/base.py
index 0b97f74..4933300 100644
--- a/tempest/services/baremetal/base.py
+++ b/tempest/services/baremetal/base.py
@@ -95,9 +95,13 @@
                     for ch in get_change(value, path + '%s/' % name):
                         yield ch
                 else:
-                    yield {'path': path + name,
-                           'value': value,
-                           'op': 'replace'}
+                    if value is None:
+                        yield {'path': path + name,
+                               'op': 'remove'}
+                    else:
+                        yield {'path': path + name,
+                               'value': value,
+                               'op': 'replace'}
 
         patch = [ch for ch in get_change(kw)
                  if ch['path'].lstrip('/') in allowed_attributes]
diff --git a/tempest/services/baremetal/v1/base_v1.py b/tempest/services/baremetal/v1/base_v1.py
index 07eee8a..9359808 100644
--- a/tempest/services/baremetal/v1/base_v1.py
+++ b/tempest/services/baremetal/v1/base_v1.py
@@ -27,9 +27,9 @@
         self.uri_prefix = 'v%s' % self.version
 
     @base.handle_errors
-    def list_nodes(self):
+    def list_nodes(self, **kwargs):
         """List all existing nodes."""
-        return self._list_request('nodes')
+        return self._list_request('nodes', **kwargs)
 
     @base.handle_errors
     def list_chassis(self):
@@ -37,11 +37,21 @@
         return self._list_request('chassis')
 
     @base.handle_errors
+    def list_chassis_nodes(self, chassis_uuid):
+        """List all nodes associated with a chassis."""
+        return self._list_request('/chassis/%s/nodes' % chassis_uuid)
+
+    @base.handle_errors
     def list_ports(self, **kwargs):
         """List all existing ports."""
         return self._list_request('ports', **kwargs)
 
     @base.handle_errors
+    def list_node_ports(self, uuid):
+        """List all ports associated with the node."""
+        return self._list_request('/nodes/%s/ports' % uuid)
+
+    @base.handle_errors
     def list_nodestates(self, uuid):
         """List all existing states."""
         return self._list_request('/nodes/%s/states' % uuid)
@@ -68,6 +78,21 @@
         return self._show_request('nodes', uuid)
 
     @base.handle_errors
+    def show_node_by_instance_uuid(self, instance_uuid):
+        """
+        Gets a node associated with given instance uuid.
+
+        :param uuid: Unique identifier of the node in UUID format.
+        :return: Serialized node as a dictionary.
+
+        """
+        uri = '/nodes/detail?instance_uuid=%s' % instance_uuid
+
+        return self._show_request('nodes',
+                                  uuid=None,
+                                  uri=uri)
+
+    @base.handle_errors
     def show_chassis(self, uuid):
         """
         Gets a specific chassis.
@@ -203,7 +228,8 @@
                            'properties/cpu_num',
                            'properties/storage',
                            'properties/memory',
-                           'driver')
+                           'driver',
+                           'instance_uuid')
 
         patch = self._make_patch(node_attributes, **kwargs)
 
@@ -308,3 +334,33 @@
         resp, body = self._list_request(path)
         self.expected_success(200, resp.status)
         return body
+
+    @base.handle_errors
+    def get_console(self, node_uuid):
+        """
+        Get connection information about the console.
+
+        :param node_uuid: Unique identifier of the node in UUID format.
+
+        """
+
+        resp, body = self._show_request('nodes/states/console', node_uuid)
+        self.expected_success(200, resp.status)
+        return resp, body
+
+    @base.handle_errors
+    def set_console_mode(self, node_uuid, enabled):
+        """
+        Start and stop the node console.
+
+        :param node_uuid: Unique identifier of the node in UUID format.
+        :param enabled: Boolean value; whether to enable or disable the
+                        console.
+
+        """
+
+        enabled = {'enabled': enabled}
+        resp, body = self._put_request('nodes/%s/states/console' % node_uuid,
+                                       enabled)
+        self.expected_success(202, resp.status)
+        return resp, body
diff --git a/tempest/services/compute/json/aggregates_client.py b/tempest/services/compute/json/aggregates_client.py
index 1cb010d..09927d3 100644
--- a/tempest/services/compute/json/aggregates_client.py
+++ b/tempest/services/compute/json/aggregates_client.py
@@ -79,6 +79,11 @@
             return True
         return False
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'aggregate'
+
     def add_host(self, aggregate_id, host):
         """Adds a host to the given aggregate."""
         post_body = {
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index 5452f3a..8faf8a7 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -99,6 +99,11 @@
                 return False
         return True
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'flavor'
+
     def set_flavor_extra_spec(self, flavor_id, specs):
         """Sets extra Specs to the mentioned flavor."""
         post_body = json.dumps({'extra_specs': specs})
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index 8b020d0..0ed1720 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -102,6 +102,11 @@
             return True
         return False
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'floating_ip'
+
     def list_floating_ip_pools(self, params=None):
         """Returns a list of all floating IP Pools."""
         url = 'os-floating-ip-pools'
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index 9877391..079a91e 100644
--- a/tempest/services/compute/json/images_client.py
+++ b/tempest/services/compute/json/images_client.py
@@ -76,7 +76,7 @@
     def get_image(self, image_id):
         """Returns the details of a single image."""
         resp, body = self.get("images/%s" % str(image_id))
-        self.expected_success(200, resp)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         self.validate_response(schema.get_image, resp, body)
         return resp, body['image']
@@ -143,3 +143,8 @@
         except exceptions.NotFound:
             return True
         return False
+
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'image'
diff --git a/tempest/services/compute/json/security_group_default_rules_client.py b/tempest/services/compute/json/security_group_default_rules_client.py
index 6d29837..7743f9c 100644
--- a/tempest/services/compute/json/security_group_default_rules_client.py
+++ b/tempest/services/compute/json/security_group_default_rules_client.py
@@ -15,6 +15,8 @@
 
 import json
 
+from tempest.api_schema.response.compute.v2 import \
+    security_group_default_rule as schema
 from tempest.common import rest_client
 from tempest import config
 
@@ -46,8 +48,9 @@
         post_body = json.dumps({'security_group_default_rule': post_body})
         url = 'os-security-group-default-rules'
         resp, body = self.post(url, post_body)
-        self.expected_success(200, resp.status)
         body = json.loads(body)
+        self.validate_response(schema.create_get_security_group_default_rule,
+                               resp, body)
         return resp, body['security_group_default_rule']
 
     def delete_security_group_default_rule(self,
@@ -55,20 +58,23 @@
         """Deletes the provided Security Group default rule."""
         resp, body = self.delete('os-security-group-default-rules/%s' % str(
             security_group_default_rule_id))
-        self.expected_success(204, resp.status)
+        self.validate_response(schema.delete_security_group_default_rule,
+                               resp, body)
         return resp, body
 
     def list_security_group_default_rules(self):
         """List all Security Group default rules."""
         resp, body = self.get('os-security-group-default-rules')
-        self.expected_success(200, resp.status)
         body = json.loads(body)
+        self.validate_response(schema.list_security_group_default_rules,
+                               resp, body)
         return resp, body['security_group_default_rules']
 
     def get_security_group_default_rule(self, security_group_default_rule_id):
         """Return the details of provided Security Group default rule."""
         resp, body = self.get('os-security-group-default-rules/%s' % str(
             security_group_default_rule_id))
-        self.expected_success(200, resp.status)
         body = json.loads(body)
+        self.validate_response(schema.create_get_security_group_default_rule,
+                               resp, body)
         return resp, body['security_group_default_rule']
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index 29859a9..733a50b 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -143,3 +143,8 @@
         except exceptions.NotFound:
             return True
         return False
+
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'security_group'
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 88b68d3..4268b1a 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -175,11 +175,12 @@
         return resp, body
 
     def wait_for_server_status(self, server_id, status, extra_timeout=0,
-                               raise_on_error=True):
+                               raise_on_error=True, ready_wait=True):
         """Waits for a server to reach a given status."""
         return waiters.wait_for_server_status(self, server_id, status,
                                               extra_timeout=extra_timeout,
-                                              raise_on_error=raise_on_error)
+                                              raise_on_error=raise_on_error,
+                                              ready_wait=ready_wait)
 
     def wait_for_server_termination(self, server_id, ignore_error=False):
         """Waits for server to reach termination."""
@@ -368,7 +369,7 @@
                                post_body)
         body = json.loads(body)
         self.validate_response(schema.attach_volume, resp, body)
-        return resp, body
+        return resp, body['volumeAttachment']
 
     def detach_volume(self, server_id, volume_id):
         """Detaches a volume from a server instance."""
@@ -377,6 +378,22 @@
         self.validate_response(schema.detach_volume, resp, body)
         return resp, body
 
+    def get_volume_attachment(self, server_id, attach_id):
+        """Return details about the given volume attachment."""
+        resp, body = self.get('servers/%s/os-volume_attachments/%s' % (
+            str(server_id), attach_id))
+        body = json.loads(body)
+        self.validate_response(schema.get_volume_attachment, resp, body)
+        return resp, body['volumeAttachment']
+
+    def list_volume_attachments(self, server_id):
+        """Returns the list of volume attachments for a given instance."""
+        resp, body = self.get('servers/%s/os-volume_attachments' % (
+            str(server_id)))
+        body = json.loads(body)
+        self.validate_response(schema.list_volume_attachments, resp, body)
+        return resp, body['volumeAttachments']
+
     def add_security_group(self, server_id, name):
         """Adds a security group to the server."""
         return self.action(server_id, 'addSecurityGroup', None, name=name)
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index 673e365..309dc5b 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -116,3 +116,8 @@
         except exceptions.NotFound:
             return True
         return False
+
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'volume'
diff --git a/tempest/services/compute/v3/json/aggregates_client.py b/tempest/services/compute/v3/json/aggregates_client.py
index 960fe05..e11ed45 100644
--- a/tempest/services/compute/v3/json/aggregates_client.py
+++ b/tempest/services/compute/v3/json/aggregates_client.py
@@ -79,6 +79,11 @@
             return True
         return False
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'aggregate'
+
     def add_host(self, aggregate_id, host):
         """Adds a host to the given aggregate."""
         post_body = {
diff --git a/tempest/services/compute/v3/json/flavors_client.py b/tempest/services/compute/v3/json/flavors_client.py
index d1eee5b..fdca6b3 100644
--- a/tempest/services/compute/v3/json/flavors_client.py
+++ b/tempest/services/compute/v3/json/flavors_client.py
@@ -99,6 +99,11 @@
                 return False
         return True
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'flavor'
+
     def set_flavor_extra_spec(self, flavor_id, specs):
         """Sets extra Specs to the mentioned flavor."""
         post_body = json.dumps({'extra_specs': specs})
diff --git a/tempest/services/compute/xml/aggregates_client.py b/tempest/services/compute/xml/aggregates_client.py
index 9c2d4aa..47cde65 100644
--- a/tempest/services/compute/xml/aggregates_client.py
+++ b/tempest/services/compute/xml/aggregates_client.py
@@ -94,6 +94,11 @@
             return True
         return False
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'aggregate'
+
     def add_host(self, aggregate_id, host):
         """Adds a host to the given aggregate."""
         post_body = xml_utils.Element("add_host", host=host)
diff --git a/tempest/services/compute/xml/flavors_client.py b/tempest/services/compute/xml/flavors_client.py
index 68ef323..63d1a4d 100644
--- a/tempest/services/compute/xml/flavors_client.py
+++ b/tempest/services/compute/xml/flavors_client.py
@@ -136,6 +136,11 @@
                 return False
         return True
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'flavor'
+
     def set_flavor_extra_spec(self, flavor_id, specs):
         """Sets extra Specs to the mentioned flavor."""
         extra_specs = xml_utils.Element("extra_specs")
diff --git a/tempest/services/compute/xml/floating_ips_client.py b/tempest/services/compute/xml/floating_ips_client.py
index 730e870..84f06ab 100644
--- a/tempest/services/compute/xml/floating_ips_client.py
+++ b/tempest/services/compute/xml/floating_ips_client.py
@@ -108,6 +108,11 @@
             return True
         return False
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'floating_ip'
+
     def list_floating_ip_pools(self, params=None):
         """Returns a list of all floating IP Pools."""
         url = 'os-floating-ip-pools'
diff --git a/tempest/services/compute/xml/images_client.py b/tempest/services/compute/xml/images_client.py
index 6b15404..ce37b07 100644
--- a/tempest/services/compute/xml/images_client.py
+++ b/tempest/services/compute/xml/images_client.py
@@ -127,7 +127,7 @@
     def get_image(self, image_id):
         """Returns the details of a single image."""
         resp, body = self.get("images/%s" % str(image_id))
-        self.expected_success(200, resp)
+        self.expected_success(200, resp.status)
         body = self._parse_image(etree.fromstring(body))
         return resp, body
 
@@ -204,3 +204,8 @@
         except exceptions.NotFound:
             return True
         return False
+
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'image'
diff --git a/tempest/services/compute/xml/security_groups_client.py b/tempest/services/compute/xml/security_groups_client.py
index 56ac7ba..e529623 100644
--- a/tempest/services/compute/xml/security_groups_client.py
+++ b/tempest/services/compute/xml/security_groups_client.py
@@ -159,3 +159,8 @@
         except exceptions.NotFound:
             return True
         return False
+
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'security_group'
diff --git a/tempest/services/compute/xml/servers_client.py b/tempest/services/compute/xml/servers_client.py
index 156d889..06f1b83 100644
--- a/tempest/services/compute/xml/servers_client.py
+++ b/tempest/services/compute/xml/servers_client.py
@@ -349,8 +349,11 @@
             networks = xml_utils.Element("networks")
             server.append(networks)
             for network in kwargs['networks']:
-                s = xml_utils.Element("network", uuid=network['uuid'],
-                                      fixed_ip=network['fixed_ip'])
+                if 'fixed_ip' in network:
+                    s = xml_utils.Element("network", uuid=network['uuid'],
+                                          fixed_ip=network['fixed_ip'])
+                else:
+                    s = xml_utils.Element("network", uuid=network['uuid'])
                 networks.append(s)
 
         if 'meta' in kwargs:
diff --git a/tempest/services/compute/xml/volumes_extensions_client.py b/tempest/services/compute/xml/volumes_extensions_client.py
index e9c5035..da1764a 100644
--- a/tempest/services/compute/xml/volumes_extensions_client.py
+++ b/tempest/services/compute/xml/volumes_extensions_client.py
@@ -141,3 +141,8 @@
         except exceptions.NotFound:
             return True
         return False
+
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'volume'
diff --git a/tempest/services/identity/json/identity_client.py b/tempest/services/identity/json/identity_client.py
index ac65f81..e76c1bd 100644
--- a/tempest/services/identity/json/identity_client.py
+++ b/tempest/services/identity/json/identity_client.py
@@ -309,6 +309,7 @@
 
         body = json.dumps(creds)
         resp, body = self.post(self.auth_url, body=body)
+        self.expected_success(200, resp.status)
 
         return resp, body['access']
 
@@ -326,6 +327,7 @@
 
         body = json.dumps(creds)
         resp, body = self.post(self.auth_url, body=body)
+        self.expected_success(200, resp.status)
 
         return resp, body['access']
 
diff --git a/tempest/services/identity/v3/json/credentials_client.py b/tempest/services/identity/v3/json/credentials_client.py
index f795c7b..d424f4c 100644
--- a/tempest/services/identity/v3/json/credentials_client.py
+++ b/tempest/services/identity/v3/json/credentials_client.py
@@ -41,13 +41,14 @@
         }
         post_body = json.dumps({'credential': post_body})
         resp, body = self.post('credentials', post_body)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         body['credential']['blob'] = json.loads(body['credential']['blob'])
         return resp, body['credential']
 
     def update_credential(self, credential_id, **kwargs):
         """Updates a credential."""
-        resp, body = self.get_credential(credential_id)
+        _, body = self.get_credential(credential_id)
         cred_type = kwargs.get('type', body['type'])
         access_key = kwargs.get('access_key', body['blob']['access'])
         secret_key = kwargs.get('secret_key', body['blob']['secret'])
@@ -63,6 +64,7 @@
         }
         post_body = json.dumps({'credential': post_body})
         resp, body = self.patch('credentials/%s' % credential_id, post_body)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         body['credential']['blob'] = json.loads(body['credential']['blob'])
         return resp, body['credential']
@@ -70,6 +72,7 @@
     def get_credential(self, credential_id):
         """To GET Details of a credential."""
         resp, body = self.get('credentials/%s' % credential_id)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         body['credential']['blob'] = json.loads(body['credential']['blob'])
         return resp, body['credential']
@@ -77,10 +80,12 @@
     def list_credentials(self):
         """Lists out all the available credentials."""
         resp, body = self.get('credentials')
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['credentials']
 
     def delete_credential(self, credential_id):
         """Deletes a credential."""
         resp, body = self.delete('credentials/%s' % credential_id)
+        self.expected_success(204, resp.status)
         return resp, body
diff --git a/tempest/services/identity/v3/json/endpoints_client.py b/tempest/services/identity/v3/json/endpoints_client.py
index f7a894b..c3fedb2 100644
--- a/tempest/services/identity/v3/json/endpoints_client.py
+++ b/tempest/services/identity/v3/json/endpoints_client.py
@@ -32,6 +32,7 @@
     def list_endpoints(self):
         """GET endpoints."""
         resp, body = self.get('endpoints')
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['endpoints']
 
@@ -56,6 +57,7 @@
         }
         post_body = json.dumps({'endpoint': post_body})
         resp, body = self.post('endpoints', post_body)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return resp, body['endpoint']
 
@@ -82,10 +84,12 @@
             post_body['enabled'] = enabled
         post_body = json.dumps({'endpoint': post_body})
         resp, body = self.patch('endpoints/%s' % endpoint_id, post_body)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['endpoint']
 
     def delete_endpoint(self, endpoint_id):
         """Delete endpoint."""
         resp_header, resp_body = self.delete('endpoints/%s' % endpoint_id)
+        self.expected_success(204, resp_header.status)
         return resp_header, resp_body
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index 0522f37..5ad416c 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -31,14 +31,11 @@
         self.endpoint_url = 'adminURL'
         self.api_version = "v3"
 
-    def create_user(self, user_name, **kwargs):
+    def create_user(self, user_name, password=None, project_id=None,
+                    email=None, domain_id='default', **kwargs):
         """Creates a user."""
-        password = kwargs.get('password', None)
-        email = kwargs.get('email', None)
         en = kwargs.get('enabled', True)
-        project_id = kwargs.get('project_id', None)
         description = kwargs.get('description', None)
-        domain_id = kwargs.get('domain_id', 'default')
         post_body = {
             'project_id': project_id,
             'description': description,
@@ -588,6 +585,7 @@
 
         body = json.dumps(creds)
         resp, body = self.post(self.auth_url, body=body)
+        self.expected_success(201, resp.status)
         return resp, body
 
     def request(self, method, url, extra_headers=False, headers=None,
diff --git a/tempest/services/identity/v3/json/policy_client.py b/tempest/services/identity/v3/json/policy_client.py
index 3c90fa1..e093260 100644
--- a/tempest/services/identity/v3/json/policy_client.py
+++ b/tempest/services/identity/v3/json/policy_client.py
@@ -37,12 +37,14 @@
         }
         post_body = json.dumps({'policy': post_body})
         resp, body = self.post('policies', post_body)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return resp, body['policy']
 
     def list_policies(self):
         """Lists the policies."""
         resp, body = self.get('policies')
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['policies']
 
@@ -50,12 +52,12 @@
         """Lists out the given policy."""
         url = 'policies/%s' % policy_id
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['policy']
 
     def update_policy(self, policy_id, **kwargs):
         """Updates a policy."""
-        resp, body = self.get_policy(policy_id)
         type = kwargs.get('type')
         post_body = {
             'type': type
@@ -63,10 +65,13 @@
         post_body = json.dumps({'policy': post_body})
         url = 'policies/%s' % policy_id
         resp, body = self.patch(url, post_body)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['policy']
 
     def delete_policy(self, policy_id):
         """Deletes the policy."""
         url = "policies/%s" % policy_id
-        return self.delete(url)
+        resp, body = self.delete(url)
+        self.expected_success(204, 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 c078765..becea6b 100644
--- a/tempest/services/identity/v3/json/region_client.py
+++ b/tempest/services/identity/v3/json/region_client.py
@@ -43,6 +43,7 @@
                 'regions/%s' % kwargs.get('unique_region_id'), req_body)
         else:
             resp, body = self.post('regions', req_body)
+        self.expected_success(201, resp.status)
         body = json.loads(body)
         return resp, body['region']
 
@@ -55,6 +56,7 @@
             post_body['parent_region_id'] = kwargs.get('parent_region_id')
         post_body = json.dumps({'region': post_body})
         resp, body = self.patch('regions/%s' % region_id, post_body)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['region']
 
@@ -62,6 +64,7 @@
         """Get region."""
         url = 'regions/%s' % region_id
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body['region']
 
@@ -71,10 +74,12 @@
         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['regions']
 
     def delete_region(self, region_id):
         """Delete region."""
         resp, body = self.delete('regions/%s' % region_id)
+        self.expected_success(204, resp.status)
         return resp, body
diff --git a/tempest/services/identity/v3/json/service_client.py b/tempest/services/identity/v3/json/service_client.py
index 82e8aad..8e89957 100644
--- a/tempest/services/identity/v3/json/service_client.py
+++ b/tempest/services/identity/v3/json/service_client.py
@@ -57,10 +57,10 @@
     def create_service(self, serv_type, name=None, description=None,
                        enabled=True):
         body_dict = {
-            "name": name,
+            'name': name,
             'type': serv_type,
             'enabled': enabled,
-            "description": description,
+            'description': description,
         }
         body = json.dumps({'service': body_dict})
         resp, body = self.post("services", body)
@@ -73,3 +73,9 @@
         resp, body = self.delete(url)
         self.expected_success(204, resp.status)
         return resp, body
+
+    def list_services(self):
+        resp, body = self.get('services')
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return resp, body['services']
diff --git a/tempest/services/identity/v3/xml/credentials_client.py b/tempest/services/identity/v3/xml/credentials_client.py
index 3c44188..37513d0 100644
--- a/tempest/services/identity/v3/xml/credentials_client.py
+++ b/tempest/services/identity/v3/xml/credentials_client.py
@@ -60,13 +60,14 @@
                                     type=cred_type, user_id=user_id)
         credential.append(blob)
         resp, body = self.post('credentials', str(common.Document(credential)))
+        self.expected_success(201, resp.status)
         body = self._parse_body(etree.fromstring(body))
         body['blob'] = json.loads(body['blob'])
         return resp, body
 
     def update_credential(self, credential_id, **kwargs):
         """Updates a credential."""
-        resp, body = self.get_credential(credential_id)
+        _, body = self.get_credential(credential_id)
         cred_type = kwargs.get('type', body['type'])
         access_key = kwargs.get('access_key', body['blob']['access'])
         secret_key = kwargs.get('secret_key', body['blob']['secret'])
@@ -83,6 +84,7 @@
         credential.append(blob)
         resp, body = self.patch('credentials/%s' % credential_id,
                                 str(common.Document(credential)))
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         body['blob'] = json.loads(body['blob'])
         return resp, body
@@ -90,6 +92,7 @@
     def get_credential(self, credential_id):
         """To GET Details of a credential."""
         resp, body = self.get('credentials/%s' % credential_id)
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         body['blob'] = json.loads(body['blob'])
         return resp, body
@@ -97,10 +100,12 @@
     def list_credentials(self):
         """Lists out all the available credentials."""
         resp, body = self.get('credentials')
+        self.expected_success(200, resp.status)
         body = self._parse_creds(etree.fromstring(body))
         return resp, body
 
     def delete_credential(self, credential_id):
         """Deletes a credential."""
         resp, body = self.delete('credentials/%s' % credential_id)
+        self.expected_success(204, resp.status)
         return resp, body
diff --git a/tempest/services/identity/v3/xml/endpoints_client.py b/tempest/services/identity/v3/xml/endpoints_client.py
index 6490e34..892fb58 100644
--- a/tempest/services/identity/v3/xml/endpoints_client.py
+++ b/tempest/services/identity/v3/xml/endpoints_client.py
@@ -65,6 +65,7 @@
     def list_endpoints(self):
         """Get the list of endpoints."""
         resp, body = self.get("endpoints")
+        self.expected_success(200, resp.status)
         body = self._parse_array(etree.fromstring(body))
         return resp, body
 
@@ -90,6 +91,7 @@
                                          enabled=enabled)
         resp, body = self.post('endpoints',
                                str(common.Document(create_endpoint)))
+        self.expected_success(201, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
@@ -120,10 +122,12 @@
             endpoint.add_attr("enabled", str(enabled).lower())
 
         resp, body = self.patch('endpoints/%s' % str(endpoint_id), str(doc))
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def delete_endpoint(self, endpoint_id):
         """Delete endpoint."""
         resp_header, resp_body = self.delete('endpoints/%s' % endpoint_id)
+        self.expected_success(204, resp_header.status)
         return resp_header, resp_body
diff --git a/tempest/services/identity/v3/xml/identity_client.py b/tempest/services/identity/v3/xml/identity_client.py
index 5b761b3..fdc0a0a 100644
--- a/tempest/services/identity/v3/xml/identity_client.py
+++ b/tempest/services/identity/v3/xml/identity_client.py
@@ -95,14 +95,11 @@
         _json = common.xml_to_json(body)
         return _json
 
-    def create_user(self, user_name, **kwargs):
+    def create_user(self, user_name, password=None, project_id=None,
+                    email=None, domain_id='default', **kwargs):
         """Creates a user."""
-        password = kwargs.get('password', None)
-        email = kwargs.get('email', None)
         en = kwargs.get('enabled', 'true')
-        project_id = kwargs.get('project_id', None)
         description = kwargs.get('description', None)
-        domain_id = kwargs.get('domain_id', 'default')
         post_body = common.Element("user",
                                    xmlns=XMLNS,
                                    name=user_name,
@@ -590,6 +587,7 @@
             auth.append(scope)
 
         resp, body = self.post(self.auth_url, body=str(common.Document(auth)))
+        self.expected_success(201, resp.status)
         return resp, body
 
     def request(self, method, url, extra_headers=False, headers=None,
diff --git a/tempest/services/identity/v3/xml/policy_client.py b/tempest/services/identity/v3/xml/policy_client.py
index 73d831b..41bbfe5 100644
--- a/tempest/services/identity/v3/xml/policy_client.py
+++ b/tempest/services/identity/v3/xml/policy_client.py
@@ -67,12 +67,14 @@
         create_policy = common.Element("policy", xmlns=XMLNS,
                                        blob=blob, type=type)
         resp, body = self.post('policies', str(common.Document(create_policy)))
+        self.expected_success(201, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def list_policies(self):
         """Lists the policies."""
         resp, body = self.get('policies')
+        self.expected_success(200, resp.status)
         body = self._parse_array(etree.fromstring(body))
         return resp, body
 
@@ -80,20 +82,23 @@
         """Lists out the given policy."""
         url = 'policies/%s' % policy_id
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def update_policy(self, policy_id, **kwargs):
         """Updates a policy."""
-        resp, body = self.get_policy(policy_id)
         type = kwargs.get('type')
         update_policy = common.Element("policy", xmlns=XMLNS, type=type)
         url = 'policies/%s' % policy_id
         resp, body = self.patch(url, str(common.Document(update_policy)))
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
     def delete_policy(self, policy_id):
         """Deletes the policy."""
         url = "policies/%s" % policy_id
-        return self.delete(url)
+        resp, body = self.delete(url)
+        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 f854138..7669678 100644
--- a/tempest/services/identity/v3/xml/region_client.py
+++ b/tempest/services/identity/v3/xml/region_client.py
@@ -79,6 +79,7 @@
         else:
             resp, body = self.post('regions',
                                    str(common.Document(create_region)))
+        self.expected_success(201, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
@@ -95,6 +96,7 @@
 
         resp, body = self.patch('regions/%s' % str(region_id),
                                 str(common.Document(update_region)))
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
@@ -102,6 +104,7 @@
         """Get Region."""
         url = 'regions/%s' % region_id
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
@@ -111,10 +114,12 @@
         if params:
             url += '?%s' % urllib.urlencode(params)
         resp, body = self.get(url)
+        self.expected_success(200, resp.status)
         body = self._parse_array(etree.fromstring(body))
         return resp, body
 
     def delete_region(self, region_id):
         """Delete region."""
         resp, body = self.delete('regions/%s' % region_id)
+        self.expected_success(204, resp.status)
         return resp, body
diff --git a/tempest/services/identity/v3/xml/service_client.py b/tempest/services/identity/v3/xml/service_client.py
index 3beeb89..14adfac 100644
--- a/tempest/services/identity/v3/xml/service_client.py
+++ b/tempest/services/identity/v3/xml/service_client.py
@@ -37,6 +37,14 @@
         data = common.xml_to_json(body)
         return data
 
+    def _parse_array(self, node):
+        array = []
+        for child in node.getchildren():
+            tag_list = child.tag.split('}', 1)
+            if tag_list[1] == "service":
+                array.append(common.xml_to_json(child))
+        return array
+
     def update_service(self, service_id, **kwargs):
         """Updates a service_id."""
         resp, body = self.get_service(service_id)
@@ -79,3 +87,9 @@
         resp, body = self.delete(url)
         self.expected_success(204, resp.status)
         return resp, body
+
+    def list_services(self):
+        resp, body = self.get('services')
+        self.expected_success(200, resp.status)
+        body = self._parse_array(etree.fromstring(body))
+        return resp, body
diff --git a/tempest/services/identity/xml/identity_client.py b/tempest/services/identity/xml/identity_client.py
index 4ada46c..eaf9390 100644
--- a/tempest/services/identity/xml/identity_client.py
+++ b/tempest/services/identity/xml/identity_client.py
@@ -157,6 +157,7 @@
         auth = xml.Element('auth', **auth_kwargs)
         auth.append(passwordCreds)
         resp, body = self.post(self.auth_url, body=str(xml.Document(auth)))
+        self.expected_success(200, resp.status)
         return resp, body['access']
 
     def auth_token(self, token_id, tenant=None):
@@ -167,4 +168,5 @@
         auth = xml.Element('auth', **auth_kwargs)
         auth.append(tokenCreds)
         resp, body = self.post(self.auth_url, body=str(xml.Document(auth)))
+        self.expected_success(200, resp.status)
         return resp, body['access']
diff --git a/tempest/services/image/v1/json/image_client.py b/tempest/services/image/v1/json/image_client.py
index bc5e04a..d0d32e5 100644
--- a/tempest/services/image/v1/json/image_client.py
+++ b/tempest/services/image/v1/json/image_client.py
@@ -240,6 +240,11 @@
             return True
         return False
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'image_meta'
+
     def get_image_membership(self, image_id):
         url = 'v1/images/%s/members' % image_id
         resp, body = self.get(url)
diff --git a/tempest/services/image/v2/json/image_client.py b/tempest/services/image/v2/json/image_client.py
index c420df9..4865073 100644
--- a/tempest/services/image/v2/json/image_client.py
+++ b/tempest/services/image/v2/json/image_client.py
@@ -117,6 +117,11 @@
             return True
         return False
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'image'
+
     def store_image(self, image_id, data):
         url = 'v2/images/%s/file' % image_id
         headers = {'Content-Type': 'application/octet-stream'}
diff --git a/tempest/services/queuing/__init__.py b/tempest/services/messaging/__init__.py
similarity index 100%
rename from tempest/services/queuing/__init__.py
rename to tempest/services/messaging/__init__.py
diff --git a/tempest/services/queuing/json/__init__.py b/tempest/services/messaging/json/__init__.py
similarity index 100%
rename from tempest/services/queuing/json/__init__.py
rename to tempest/services/messaging/json/__init__.py
diff --git a/tempest/services/queuing/json/queuing_client.py b/tempest/services/messaging/json/messaging_client.py
similarity index 86%
rename from tempest/services/queuing/json/queuing_client.py
rename to tempest/services/messaging/json/messaging_client.py
index 14960ad..2794ea9 100644
--- a/tempest/services/queuing/json/queuing_client.py
+++ b/tempest/services/messaging/json/messaging_client.py
@@ -16,7 +16,7 @@
 import json
 import urllib
 
-from tempest.api_schema.response.queuing.v1 import queues as queues_schema
+from tempest.api_schema.response.messaging.v1 import queues as queues_schema
 from tempest.common import rest_client
 from tempest.common.utils import data_utils
 from tempest import config
@@ -25,11 +25,11 @@
 CONF = config.CONF
 
 
-class QueuingClientJSON(rest_client.RestClient):
+class MessagingClientJSON(rest_client.RestClient):
 
     def __init__(self, auth_provider):
-        super(QueuingClientJSON, self).__init__(auth_provider)
-        self.service = CONF.queuing.catalog_type
+        super(MessagingClientJSON, self).__init__(auth_provider)
+        self.service = CONF.messaging.catalog_type
         self.version = '1'
         self.uri_prefix = 'v{0}'.format(self.version)
 
@@ -48,22 +48,26 @@
     def create_queue(self, queue_name):
         uri = '{0}/queues/{1}'.format(self.uri_prefix, queue_name)
         resp, body = self.put(uri, body=None)
+        self.expected_success(201, resp.status)
         return resp, body
 
     def get_queue(self, queue_name):
         uri = '{0}/queues/{1}'.format(self.uri_prefix, queue_name)
         resp, body = self.get(uri)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def head_queue(self, queue_name):
         uri = '{0}/queues/{1}'.format(self.uri_prefix, queue_name)
         resp, body = self.head(uri)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def delete_queue(self, queue_name):
         uri = '{0}/queues/{1}'.format(self.uri_prefix, queue_name)
-        resp = self.delete(uri)
-        return resp
+        resp, body = self.delete(uri)
+        self.expected_success(204, resp.status)
+        return resp, body
 
     def get_queue_stats(self, queue_name):
         uri = '{0}/queues/{1}/stats'.format(self.uri_prefix, queue_name)
@@ -75,12 +79,14 @@
     def get_queue_metadata(self, queue_name):
         uri = '{0}/queues/{1}/metadata'.format(self.uri_prefix, queue_name)
         resp, body = self.get(uri)
+        self.expected_success(200, resp.status)
         body = json.loads(body)
         return resp, body
 
     def set_queue_metadata(self, queue_name, rbody):
         uri = '{0}/queues/{1}/metadata'.format(self.uri_prefix, queue_name)
         resp, body = self.put(uri, body=json.dumps(rbody))
+        self.expected_success(204, resp.status)
         return resp, body
 
     def post_messages(self, queue_name, rbody):
@@ -90,6 +96,7 @@
                                headers=self.headers)
 
         body = json.loads(body)
+        self.validate_response(queues_schema.post_messages, resp, body)
         return resp, body
 
     def list_messages(self, queue_name):
@@ -126,7 +133,7 @@
 
     def delete_messages(self, message_uri):
         resp, body = self.delete(message_uri)
-        assert(resp['status'] == '204')
+        self.expected_success(204, resp.status)
         return resp, body
 
     def post_claims(self, queue_name, rbody, url_params=False):
@@ -152,10 +159,10 @@
 
     def update_claim(self, claim_uri, rbody):
         resp, body = self.patch(claim_uri, body=json.dumps(rbody))
-        assert(resp['status'] == '204')
+        self.expected_success(204, resp.status)
         return resp, body
 
     def release_claim(self, claim_uri):
         resp, body = self.delete(claim_uri)
-        assert(resp['status'] == '204')
+        self.expected_success(204, resp.status)
         return resp, body
diff --git a/tempest/services/network/json/network_client.py b/tempest/services/network/json/network_client.py
index 16a4f5c..46475f0 100644
--- a/tempest/services/network/json/network_client.py
+++ b/tempest/services/network/json/network_client.py
@@ -85,8 +85,14 @@
         update_body['admin_state_up'] = kwargs.get(
             'admin_state_up', body['router']['admin_state_up'])
         cur_gw_info = body['router']['external_gateway_info']
-        if cur_gw_info and not set_enable_snat:
-            cur_gw_info.pop('enable_snat', None)
+        if cur_gw_info:
+            # TODO(kevinbenton): setting the external gateway info is not
+            # allowed for a regular tenant. If the ability to update is also
+            # merged, a test case for this will need to be added similar to
+            # the SNAT case.
+            cur_gw_info.pop('external_fixed_ips', None)
+            if not set_enable_snat:
+                cur_gw_info.pop('enable_snat', None)
         update_body['external_gateway_info'] = kwargs.get(
             'external_gateway_info', body['router']['external_gateway_info'])
         update_body = dict(router=update_body)
@@ -320,3 +326,30 @@
         self.rest_client.expected_success(201, resp.status)
         body = json.loads(body)
         return resp, body
+
+    def insert_firewall_rule_in_policy(self, firewall_policy_id,
+                                       firewall_rule_id, insert_after="",
+                                       insert_before=""):
+        uri = '%s/fw/firewall_policies/%s/insert_rule' % (self.uri_prefix,
+                                                          firewall_policy_id)
+        body = {
+            "firewall_rule_id": firewall_rule_id,
+            "insert_after": insert_after,
+            "insert_before": insert_before
+        }
+        body = json.dumps(body)
+        resp, body = self.put(uri, body)
+        self.rest_client.expected_success(200, resp.status)
+        body = json.loads(body)
+        return resp, body
+
+    def remove_firewall_rule_from_policy(self, firewall_policy_id,
+                                         firewall_rule_id):
+        uri = '%s/fw/firewall_policies/%s/remove_rule' % (self.uri_prefix,
+                                                          firewall_policy_id)
+        update_body = {"firewall_rule_id": firewall_rule_id}
+        update_body = json.dumps(update_body)
+        resp, body = self.put(uri, update_body)
+        self.rest_client.expected_success(200, resp.status)
+        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 94ba5aa..5ad5f37 100644
--- a/tempest/services/network/network_client_base.py
+++ b/tempest/services/network/network_client_base.py
@@ -13,6 +13,7 @@
 import time
 import urllib
 
+from tempest.common.utils import misc
 from tempest import config
 from tempest import exceptions
 
@@ -227,3 +228,39 @@
         except exceptions.NotFound:
             return True
         return False
+
+    def wait_for_resource_status(self, fetch, status, interval=None,
+                                 timeout=None):
+        """
+        @summary: Waits for a network resource to reach a status
+        @param fetch: the callable to be used to query the resource status
+        @type fecth: callable that takes no parameters and returns the resource
+        @param status: the status that the resource has to reach
+        @type status: String
+        @param interval: the number of seconds to wait between each status
+          query
+        @type interval: Integer
+        @param timeout: the maximum number of seconds to wait for the resource
+          to reach the desired status
+        @type timeout: Integer
+        """
+        if not interval:
+            interval = self.build_interval
+        if not timeout:
+            timeout = self.build_timeout
+        start_time = time.time()
+
+        while time.time() - start_time <= timeout:
+            resource = fetch()
+            if resource['status'] == status:
+                return
+            time.sleep(interval)
+
+        # At this point, the wait has timed out
+        message = 'Resource %s' % (str(resource))
+        message += ' failed to reach status %s' % status
+        message += ' within the required time %s' % timeout
+        caller = misc.find_test_caller()
+        if caller:
+            message = '(%s) %s' % (caller, message)
+        raise exceptions.TimeoutException(message)
diff --git a/tempest/services/network/resources.py b/tempest/services/network/resources.py
index b2feb87..a84b4d5 100644
--- a/tempest/services/network/resources.py
+++ b/tempest/services/network/resources.py
@@ -51,9 +51,23 @@
     def delete(self):
         return
 
+    @abc.abstractmethod
+    def refresh(self):
+        return
+
     def __hash__(self):
         return hash(self.id)
 
+    def wait_for_status(self, status):
+        if not hasattr(self, 'status'):
+            return
+
+        def helper_get():
+            self.refresh()
+            return self
+
+        return self.client.wait_for_resource_status(helper_get, status)
+
 
 class DeletableNetwork(DeletableResource):
 
@@ -106,6 +120,12 @@
 
 class DeletableFloatingIp(DeletableResource):
 
+    def refresh(self, *args, **kwargs):
+        _, result = self.client.show_floatingip(self.id,
+                                                *args,
+                                                **kwargs)
+        super(DeletableFloatingIp, self).update(**result['floatingip'])
+
     def update(self, *args, **kwargs):
         _, result = self.client.update_floatingip(self.id,
                                                   *args,
@@ -161,3 +181,7 @@
 
     def delete(self):
         self.client.delete_vip(self.id)
+
+    def refresh(self):
+        _, result = self.client.show_vip(self.id)
+        super(DeletableVip, self).update(**result['vip'])
\ No newline at end of file
diff --git a/tempest/services/network/xml/network_client.py b/tempest/services/network/xml/network_client.py
index 17b1f8e..4a8dddc 100644
--- a/tempest/services/network/xml/network_client.py
+++ b/tempest/services/network/xml/network_client.py
@@ -25,7 +25,8 @@
     # list of plurals used for xml serialization
     PLURALS = ['dns_nameservers', 'host_routes', 'allocation_pools',
                'fixed_ips', 'extensions', 'extra_dhcp_opts', 'pools',
-               'health_monitors', 'vips', 'members', 'allowed_address_pairs']
+               'health_monitors', 'vips', 'members', 'allowed_address_pairs',
+               'firewall_rules', 'security_groups']
 
     def get_rest_client(self, auth_provider):
         rc = rest_client.RestClient(auth_provider)
@@ -281,6 +282,27 @@
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
+    def insert_firewall_rule_in_policy(self, firewall_policy_id,
+                                       firewall_rule_id, insert_after="",
+                                       insert_before=""):
+        uri = '%s/fw/firewall_policies/%s/insert_rule' % (self.uri_prefix,
+                                                          firewall_policy_id)
+        rule = common.Element("firewall_rule_id", firewall_rule_id)
+        resp, body = self.put(uri, str(common.Document(rule)))
+        self.rest_client.expected_success(200, resp.status)
+        body = _root_tag_fetcher_and_xml_to_json_parse(body)
+        return resp, body
+
+    def remove_firewall_rule_from_policy(self, firewall_policy_id,
+                                         firewall_rule_id):
+        uri = '%s/fw/firewall_policies/%s/remove_rule' % (self.uri_prefix,
+                                                          firewall_policy_id)
+        rule = common.Element("firewall_rule_id", firewall_rule_id)
+        resp, body = self.put(uri, str(common.Document(rule)))
+        self.rest_client.expected_success(200, resp.status)
+        body = _root_tag_fetcher_and_xml_to_json_parse(body)
+        return resp, body
+
 
 def _root_tag_fetcher_and_xml_to_json_parse(xml_returned_body):
     body = ET.fromstring(xml_returned_body)
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index eca57c0..4417e3b 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -52,17 +52,17 @@
             headers[remove_metadata_prefix + key] = remove_metadata[key]
 
         resp, body = self.put(url, data, headers)
+        self.expected_success(200, resp.status)
         return resp, body
 
     def delete_account(self, data=None, params=None):
         """Delete an account."""
         url = ''
         if params:
-            if 'bulk-delete' in params:
-                url += 'bulk-delete&'
             url = '?%s%s' % (url, urllib.urlencode(params))
 
         resp, body = self.delete(url, headers={}, body=data)
+        self.expected_success(200, resp.status)
         return resp, body
 
     def list_account_metadata(self):
@@ -71,16 +71,24 @@
         Returns all account metadata headers
         """
         resp, body = self.head('')
+        self.expected_success(204, resp.status)
         return resp, body
 
     def create_account_metadata(self, metadata,
-                                metadata_prefix='X-Account-Meta-'):
+                                metadata_prefix='X-Account-Meta-',
+                                data=None, params=None):
         """Creates an account metadata entry."""
         headers = {}
-        for key in metadata:
-            headers[metadata_prefix + key] = metadata[key]
+        if metadata:
+            for key in metadata:
+                headers[metadata_prefix + key] = metadata[key]
 
-        resp, body = self.post('', headers=headers, body=None)
+        url = ''
+        if params:
+            url = '?%s%s' % (url, urllib.urlencode(params))
+
+        resp, body = self.post(url, headers=headers, body=data)
+        self.expected_success([200, 204], resp.status)
         return resp, body
 
     def delete_account_metadata(self, metadata,
@@ -93,6 +101,7 @@
         for item in metadata:
             headers[metadata_prefix + item] = metadata[item]
         resp, body = self.post('', headers=headers, body=None)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def create_and_delete_account_metadata(
@@ -111,6 +120,7 @@
             headers[delete_metadata_prefix + key] = delete_metadata[key]
 
         resp, body = self.post('', headers=headers, body=None)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def list_account_containers(self, params=None):
@@ -143,6 +153,7 @@
             body = etree.fromstring(body)
         else:
             body = body.strip().splitlines()
+        self.expected_success([200, 204], resp.status)
         return resp, body
 
     def list_extensions(self):
@@ -152,6 +163,7 @@
         finally:
             self.reset_path()
         body = json.loads(body)
+        self.expected_success(200, resp.status)
         return resp, body
 
 
@@ -218,7 +230,7 @@
 
         url = '?format=%s' % self.format
         if params:
-            url += '&%s' + urllib.urlencode(params)
+            url += '&%s' % urllib.urlencode(params)
 
         headers = {}
         if metadata:
@@ -226,4 +238,5 @@
                 headers[str(key)] = metadata[key]
 
         resp, body = self.get(url, headers=headers)
+        self.expected_success(200, resp.status)
         return resp, body
diff --git a/tempest/services/object_storage/container_client.py b/tempest/services/object_storage/container_client.py
index ffc1326..182c4d0 100644
--- a/tempest/services/object_storage/container_client.py
+++ b/tempest/services/object_storage/container_client.py
@@ -53,12 +53,14 @@
                 headers[remove_metadata_prefix + key] = remove_metadata[key]
 
         resp, body = self.put(url, body=None, headers=headers)
+        self.expected_success([201, 202], resp.status)
         return resp, body
 
     def delete_container(self, container_name):
         """Deletes the container (if it's empty)."""
         url = str(container_name)
         resp, body = self.delete(url)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def update_container_metadata(
@@ -79,6 +81,7 @@
                 headers[remove_metadata_prefix + key] = remove_metadata[key]
 
         resp, body = self.post(url, body=None, headers=headers)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def delete_container_metadata(self, container_name, metadata,
@@ -92,6 +95,7 @@
                 headers[metadata_prefix + item] = metadata[item]
 
         resp, body = self.post(url, body=None, headers=headers)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def list_container_metadata(self, container_name):
@@ -100,6 +104,7 @@
         """
         url = str(container_name)
         resp, body = self.head(url)
+        self.expected_success(204, resp.status)
         return resp, body
 
     def list_all_container_objects(self, container, params=None):
@@ -121,6 +126,7 @@
         resp, objlist = self.list_container_contents(
             container,
             params={'limit': limit, 'format': 'json'})
+        self.expected_success(200, resp.status)
         return objlist
         """tmp = []
         for obj in objlist:
@@ -186,4 +192,5 @@
             body = json.loads(body)
         elif params and params.get('format') == 'xml':
             body = etree.fromstring(body)
+        self.expected_success([200, 204], resp.status)
         return resp, body
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index b2f8205..2231407 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -46,11 +46,14 @@
             url += '?%s' % urllib.urlencode(params)
 
         resp, body = self.put(url, data, headers)
+        self.expected_success(201, resp.status)
         return resp, body
 
     def update_object(self, container, object_name, data):
         """Upload data to replace current storage object."""
-        return self.create_object(container, object_name, data)
+        resp, body = self.create_object(container, object_name, data)
+        self.expected_success(201, resp.status)
+        return resp, body
 
     def delete_object(self, container, object_name, params=None):
         """Delete storage object."""
@@ -58,6 +61,7 @@
         if params:
             url += '?%s' % urllib.urlencode(params)
         resp, body = self.delete(url, headers={})
+        self.expected_success([200, 204], resp.status)
         return resp, body
 
     def update_object_metadata(self, container, object_name, metadata,
@@ -70,6 +74,7 @@
 
         url = "%s/%s" % (str(container), str(object_name))
         resp, body = self.post(url, None, headers=headers)
+        self.expected_success(202, resp.status)
         return resp, body
 
     def list_object_metadata(self, container, object_name):
@@ -77,6 +82,7 @@
 
         url = "%s/%s" % (str(container), str(object_name))
         resp, body = self.head(url)
+        self.expected_success(200, resp.status)
         return resp, body
 
     def get_object(self, container, object_name, metadata=None):
@@ -89,6 +95,7 @@
 
         url = "{0}/{1}".format(container, object_name)
         resp, body = self.get(url, headers=headers)
+        self.expected_success([200, 206], resp.status)
         return resp, body
 
     def copy_object_in_same_container(self, container, src_object_name,
@@ -105,6 +112,7 @@
                 headers[str(key)] = metadata[key]
 
         resp, body = self.put(url, None, headers=headers)
+        self.expected_success(201, resp.status)
         return resp, body
 
     def copy_object_across_containers(self, src_container, src_object_name,
@@ -122,6 +130,7 @@
                 headers[str(key)] = metadata[key]
 
         resp, body = self.put(url, None, headers=headers)
+        self.expected_success(201, resp.status)
         return resp, body
 
     def copy_object_2d_way(self, container, src_object_name, dest_object_name,
@@ -137,12 +146,14 @@
                 headers[str(key)] = metadata[key]
 
         resp, body = self.copy(url, headers=headers)
+        self.expected_success(201, resp.status)
         return resp, body
 
     def create_object_segments(self, container, object_name, segment, data):
         """Creates object segments."""
         url = "{0}/{1}/{2}".format(container, object_name, segment)
         resp, body = self.put(url, data)
+        self.expected_success(201, resp.status)
         return resp, body
 
     def put_object_with_chunk(self, container, name, contents, chunk_size):
@@ -167,7 +178,7 @@
             resp_headers[header.lower()] = value
 
         self._error_checker('PUT', None, headers, contents, resp, body)
-
+        self.expected_success(201, resp.status)
         return resp.status, resp.reason, resp_headers
 
 
@@ -220,6 +231,7 @@
 
         url = "{0}/{1}".format(container, object_name)
         resp, body = self.get(url, headers=headers)
+        self.expected_success(200, resp.status)
         return resp, body
 
     def create_object(self, container, object_name, data, metadata=None):
@@ -234,6 +246,7 @@
             headers['content-length'] = '0'
         url = "%s/%s" % (str(container), str(object_name))
         resp, body = self.put(url, data, headers=headers)
+        self.expected_success(201, resp.status)
         return resp, body
 
     def delete_object(self, container, object_name, metadata=None):
@@ -246,6 +259,7 @@
 
         url = "%s/%s" % (str(container), str(object_name))
         resp, body = self.delete(url, headers=headers)
+        self.expected_success(200, resp.status)
         return resp, body
 
     def create_object_continue(self, container, object_name,
diff --git a/tempest/services/orchestration/json/orchestration_client.py b/tempest/services/orchestration/json/orchestration_client.py
index d3867cd..15306a0 100644
--- a/tempest/services/orchestration/json/orchestration_client.py
+++ b/tempest/services/orchestration/json/orchestration_client.py
@@ -62,6 +62,7 @@
         uri = 'stacks'
         resp, body = self.post(uri, headers=headers, body=body)
         self.expected_success(201, resp.status)
+        body = json.loads(body)
         return resp, body
 
     def update_stack(self, stack_identifier, name, disable_rollback=True,
diff --git a/tempest/services/volume/json/admin/volume_hosts_client.py b/tempest/services/volume/json/admin/volume_hosts_client.py
index b3a22b5..10cb0be 100644
--- a/tempest/services/volume/json/admin/volume_hosts_client.py
+++ b/tempest/services/volume/json/admin/volume_hosts_client.py
@@ -22,13 +22,13 @@
 CONF = config.CONF
 
 
-class VolumeHostsClientJSON(rest_client.RestClient):
+class BaseVolumeHostsClientJSON(rest_client.RestClient):
     """
     Client class to send CRUD Volume Hosts API requests to a Cinder endpoint
     """
 
     def __init__(self, auth_provider):
-        super(VolumeHostsClientJSON, self).__init__(auth_provider)
+        super(BaseVolumeHostsClientJSON, self).__init__(auth_provider)
 
         self.service = CONF.volume.catalog_type
         self.build_interval = CONF.volume.build_interval
@@ -45,3 +45,9 @@
         body = json.loads(body)
         self.expected_success(200, resp.status)
         return resp, body['hosts']
+
+
+class VolumeHostsClientJSON(BaseVolumeHostsClientJSON):
+    """
+    Client class to send CRUD Volume Host API V1 requests to a Cinder endpoint
+    """
diff --git a/tempest/services/volume/json/admin/volume_types_client.py b/tempest/services/volume/json/admin/volume_types_client.py
index 44ef9fe..eedf880 100644
--- a/tempest/services/volume/json/admin/volume_types_client.py
+++ b/tempest/services/volume/json/admin/volume_types_client.py
@@ -23,13 +23,13 @@
 CONF = config.CONF
 
 
-class VolumeTypesClientJSON(rest_client.RestClient):
+class BaseVolumeTypesClientJSON(rest_client.RestClient):
     """
     Client class to send CRUD Volume Types API requests to a Cinder endpoint
     """
 
     def __init__(self, auth_provider):
-        super(VolumeTypesClientJSON, self).__init__(auth_provider)
+        super(BaseVolumeTypesClientJSON, self).__init__(auth_provider)
 
         self.service = CONF.volume.catalog_type
         self.build_interval = CONF.volume.build_interval
@@ -55,6 +55,11 @@
             return True
         return False
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'volume-type/encryption-type'
+
     def list_volume_types(self, params=None):
         """List all the volume_types created."""
         url = 'types'
@@ -188,3 +193,7 @@
         resp, body = self.delete(
             "/types/%s/encryption/provider" % str(vol_type_id))
         self.expected_success(202, resp.status)
+
+
+class VolumeTypesClientJSON(BaseVolumeTypesClientJSON):
+    """Volume V1 Volume Types client"""
diff --git a/tempest/services/volume/json/backups_client.py b/tempest/services/volume/json/backups_client.py
index 63fc646..da47639 100644
--- a/tempest/services/volume/json/backups_client.py
+++ b/tempest/services/volume/json/backups_client.py
@@ -23,13 +23,13 @@
 CONF = config.CONF
 
 
-class BackupsClientJSON(rest_client.RestClient):
+class BaseBackupsClientJSON(rest_client.RestClient):
     """
     Client class to send CRUD Volume backup API requests to a Cinder endpoint
     """
 
     def __init__(self, auth_provider):
-        super(BackupsClientJSON, self).__init__(auth_provider)
+        super(BaseBackupsClientJSON, self).__init__(auth_provider)
         self.service = CONF.volume.catalog_type
         self.build_interval = CONF.volume.build_interval
         self.build_timeout = CONF.volume.build_timeout
@@ -99,3 +99,7 @@
                            'the required time (%s s).' %
                            (backup_id, status, self.build_timeout))
                 raise exceptions.TimeoutException(message)
+
+
+class BackupsClientJSON(BaseBackupsClientJSON):
+    """Volume V1 Backups client"""
diff --git a/tempest/services/volume/json/qos_client.py b/tempest/services/volume/json/qos_client.py
new file mode 100644
index 0000000..b647bc7
--- /dev/null
+++ b/tempest/services/volume/json/qos_client.py
@@ -0,0 +1,166 @@
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import json
+import time
+
+from tempest.common import rest_client
+from tempest import config
+from tempest import exceptions
+
+CONF = config.CONF
+
+
+class BaseQosSpecsClientJSON(rest_client.RestClient):
+    """Client class to send CRUD QoS API requests"""
+
+    def __init__(self, auth_provider):
+        super(BaseQosSpecsClientJSON, self).__init__(auth_provider)
+        self.service = CONF.volume.catalog_type
+        self.build_interval = CONF.volume.build_interval
+        self.build_timeout = CONF.volume.build_timeout
+
+    def is_resource_deleted(self, qos_id):
+        try:
+            self.get_qos(qos_id)
+        except exceptions.NotFound:
+            return True
+        return False
+
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'qos'
+
+    def wait_for_qos_operations(self, qos_id, operation, args=None):
+        """Waits for a qos operations to be completed.
+
+        NOTE : operation value is required for  wait_for_qos_operations()
+        operation = 'qos-key' / 'disassociate' / 'disassociate-all'
+        args = keys[] when operation = 'qos-key'
+        args = volume-type-id disassociated when operation = 'disassociate'
+        args = None when operation = 'disassociate-all'
+        """
+        start_time = int(time.time())
+        while True:
+            if operation == 'qos-key-unset':
+                resp, body = self.get_qos(qos_id)
+                self.expected_success(200, resp.status)
+                if not any(key in body['specs'] for key in args):
+                    return
+            elif operation == 'disassociate':
+                resp, body = self.get_association_qos(qos_id)
+                self.expected_success(200, resp.status)
+                if not any(args in body[i]['id'] for i in range(0, len(body))):
+                    return
+            elif operation == 'disassociate-all':
+                resp, body = self.get_association_qos(qos_id)
+                self.expected_success(200, resp.status)
+                if not body:
+                    return
+            else:
+                msg = (" operation value is either not defined or incorrect.")
+                raise exceptions.UnprocessableEntity(msg)
+
+            if int(time.time()) - start_time >= self.build_timeout:
+                raise exceptions.TimeoutException
+            time.sleep(self.build_interval)
+
+    def create_qos(self, name, consumer, **kwargs):
+        """Create a QoS Specification.
+
+        name : name of the QoS specifications
+        consumer : conumer of Qos ( front-end / back-end / both )
+        """
+        post_body = {'name': name, 'consumer': consumer}
+        post_body.update(kwargs)
+        post_body = json.dumps({'qos_specs': post_body})
+        resp, body = self.post('qos-specs', post_body)
+        self.expected_success(200, resp.status)
+        body = json.loads(body)
+        return resp, body['qos_specs']
+
+    def delete_qos(self, qos_id, force=False):
+        """Delete the specified QoS specification."""
+        resp, body = self.delete(
+            "qos-specs/%s?force=%s" % (str(qos_id), force))
+        self.expected_success(202, resp.status)
+
+    def list_qos(self):
+        """List all the QoS specifications created."""
+        url = 'qos-specs'
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return resp, body['qos_specs']
+
+    def get_qos(self, qos_id):
+        """Get the specified QoS specification."""
+        url = "qos-specs/%s" % str(qos_id)
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return resp, body['qos_specs']
+
+    def set_qos_key(self, qos_id, **kwargs):
+        """Set the specified keys/values of QoS specification.
+
+        kwargs : it is the dictionary of the key=value pairs to set
+        """
+        put_body = json.dumps({"qos_specs": kwargs})
+        resp, body = self.put('qos-specs/%s' % qos_id, put_body)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return resp, body['qos_specs']
+
+    def unset_qos_key(self, qos_id, keys):
+        """Unset the specified keys of QoS specification.
+
+        keys : it is the array of the keys to unset
+        """
+        put_body = json.dumps({'keys': keys})
+        resp, _ = self.put('qos-specs/%s/delete_keys' % qos_id, put_body)
+        self.expected_success(202, resp.status)
+
+    def associate_qos(self, qos_id, vol_type_id):
+        """Associate the specified QoS with specified volume-type."""
+        url = "qos-specs/%s/associate" % str(qos_id)
+        url += "?vol_type_id=%s" % vol_type_id
+        resp, _ = self.get(url)
+        self.expected_success(202, resp.status)
+
+    def get_association_qos(self, qos_id):
+        """Get the association of the specified QoS specification."""
+        url = "qos-specs/%s/associations" % str(qos_id)
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return resp, body['qos_associations']
+
+    def disassociate_qos(self, qos_id, vol_type_id):
+        """Disassociate the specified QoS with specified volume-type."""
+        url = "qos-specs/%s/disassociate" % str(qos_id)
+        url += "?vol_type_id=%s" % vol_type_id
+        resp, _ = self.get(url)
+        self.expected_success(202, resp.status)
+
+    def disassociate_all_qos(self, qos_id):
+        """Disassociate the specified QoS with all associations."""
+        url = "qos-specs/%s/disassociate_all" % str(qos_id)
+        resp, _ = self.get(url)
+        self.expected_success(202, resp.status)
+
+
+class QosSpecsClientJSON(BaseQosSpecsClientJSON):
+    """Volume V1 QoS client."""
diff --git a/tempest/services/volume/json/snapshots_client.py b/tempest/services/volume/json/snapshots_client.py
index f50ba2f..e9d5b83 100644
--- a/tempest/services/volume/json/snapshots_client.py
+++ b/tempest/services/volume/json/snapshots_client.py
@@ -24,15 +24,16 @@
 LOG = logging.getLogger(__name__)
 
 
-class SnapshotsClientJSON(rest_client.RestClient):
-    """Client class to send CRUD Volume API requests."""
+class BaseSnapshotsClientJSON(rest_client.RestClient):
+    """Base Client class to send CRUD Volume API requests."""
 
     def __init__(self, auth_provider):
-        super(SnapshotsClientJSON, self).__init__(auth_provider)
+        super(BaseSnapshotsClientJSON, self).__init__(auth_provider)
 
         self.service = CONF.volume.catalog_type
         self.build_interval = CONF.volume.build_interval
         self.build_timeout = CONF.volume.build_timeout
+        self.create_resp = 200
 
     def list_snapshots(self, params=None):
         """List all the snapshot."""
@@ -77,7 +78,7 @@
         post_body = json.dumps({'snapshot': post_body})
         resp, body = self.post('snapshots', post_body)
         body = json.loads(body)
-        self.expected_success(200, resp.status)
+        self.expected_success(self.create_resp, resp.status)
         return resp, body['snapshot']
 
     def update_snapshot(self, snapshot_id, **kwargs):
@@ -137,6 +138,11 @@
             return True
         return False
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'volume-snapshot'
+
     def reset_snapshot_status(self, snapshot_id, status):
         """Reset the specified snapshot's status."""
         post_body = json.dumps({'os-reset_status': {"status": status}})
@@ -203,3 +209,7 @@
         resp, body = self.post('snapshots/%s/action' % snapshot_id, post_body)
         self.expected_success(202, resp.status)
         return resp, body
+
+
+class SnapshotsClientJSON(BaseSnapshotsClientJSON):
+    """Client class to send CRUD Volume V1 API requests."""
diff --git a/tempest/services/volume/json/volumes_client.py b/tempest/services/volume/json/volumes_client.py
index c3a9269..cf2837b 100644
--- a/tempest/services/volume/json/volumes_client.py
+++ b/tempest/services/volume/json/volumes_client.py
@@ -187,6 +187,11 @@
             return True
         return False
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'volume'
+
     def extend_volume(self, volume_id, extend_size):
         """Extend a volume."""
         post_body = {
diff --git a/tempest/services/queuing/json/__init__.py b/tempest/services/volume/v2/json/admin/__init__.py
similarity index 100%
copy from tempest/services/queuing/json/__init__.py
copy to tempest/services/volume/v2/json/admin/__init__.py
diff --git a/tempest/services/volume/v2/json/admin/volume_hosts_client.py b/tempest/services/volume/v2/json/admin/volume_hosts_client.py
new file mode 100644
index 0000000..d631570
--- /dev/null
+++ b/tempest/services/volume/v2/json/admin/volume_hosts_client.py
@@ -0,0 +1,28 @@
+# 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.
+
+
+from tempest.services.volume.json.admin import volume_hosts_client
+
+
+class VolumeHostsV2ClientJSON(volume_hosts_client.BaseVolumeHostsClientJSON):
+    """
+    Client class to send CRUD Volume V2 API requests to a Cinder endpoint
+    """
+
+    def __init__(self, auth_provider):
+        super(VolumeHostsV2ClientJSON, self).__init__(auth_provider)
+
+        self.api_version = "v2"
diff --git a/tempest/services/volume/v2/json/admin/volume_types_client.py b/tempest/services/volume/v2/json/admin/volume_types_client.py
new file mode 100644
index 0000000..76fa45d
--- /dev/null
+++ b/tempest/services/volume/v2/json/admin/volume_types_client.py
@@ -0,0 +1,28 @@
+# 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.
+
+
+from tempest.services.volume.json.admin import volume_types_client
+
+
+class VolumeTypesV2ClientJSON(volume_types_client.BaseVolumeTypesClientJSON):
+    """
+    Client class to send CRUD Volume V2 API requests to a Cinder endpoint
+    """
+
+    def __init__(self, auth_provider):
+        super(VolumeTypesV2ClientJSON, self).__init__(auth_provider)
+
+        self.api_version = "v2"
diff --git a/tempest/services/volume/v2/json/backups_client.py b/tempest/services/volume/v2/json/backups_client.py
new file mode 100644
index 0000000..9698075
--- /dev/null
+++ b/tempest/services/volume/v2/json/backups_client.py
@@ -0,0 +1,26 @@
+# 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.
+
+from tempest.services.volume.json import backups_client
+
+
+class BackupsClientV2JSON(backups_client.BaseBackupsClientJSON):
+    """
+    Client class to send CRUD Volume V2 API requests to a Cinder endpoint
+    """
+
+    def __init__(self, auth_provider):
+        super(BackupsClientV2JSON, self).__init__(auth_provider)
+        self.api_version = "v2"
diff --git a/tempest/services/volume/v2/json/qos_client.py b/tempest/services/volume/v2/json/qos_client.py
new file mode 100644
index 0000000..a734df8
--- /dev/null
+++ b/tempest/services/volume/v2/json/qos_client.py
@@ -0,0 +1,23 @@
+# 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.services.volume.json import qos_client
+
+
+class QosSpecsV2ClientJSON(qos_client.BaseQosSpecsClientJSON):
+
+    def __init__(self, auth_provider):
+        super(QosSpecsV2ClientJSON, self).__init__(auth_provider)
+
+        self.api_version = "v2"
diff --git a/tempest/services/volume/v2/json/snapshots_client.py b/tempest/services/volume/v2/json/snapshots_client.py
new file mode 100644
index 0000000..553176b
--- /dev/null
+++ b/tempest/services/volume/v2/json/snapshots_client.py
@@ -0,0 +1,23 @@
+#    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.services.volume.json import snapshots_client
+
+
+class SnapshotsV2ClientJSON(snapshots_client.BaseSnapshotsClientJSON):
+    """Client class to send CRUD Volume V2 API requests."""
+
+    def __init__(self, auth_provider):
+        super(SnapshotsV2ClientJSON, self).__init__(auth_provider)
+
+        self.api_version = "v2"
+        self.create_resp = 202
diff --git a/tempest/services/volume/v2/xml/snapshots_client.py b/tempest/services/volume/v2/xml/snapshots_client.py
new file mode 100644
index 0000000..b29d86c
--- /dev/null
+++ b/tempest/services/volume/v2/xml/snapshots_client.py
@@ -0,0 +1,23 @@
+#    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.services.volume.xml import snapshots_client
+
+
+class SnapshotsV2ClientXML(snapshots_client.BaseSnapshotsClientXML):
+    """Client class to send CRUD Volume V2 API requests."""
+
+    def __init__(self, auth_provider):
+        super(SnapshotsV2ClientXML, self).__init__(auth_provider)
+
+        self.api_version = "v2"
+        self.create_resp = 202
diff --git a/tempest/services/volume/xml/admin/volume_hosts_client.py b/tempest/services/volume/xml/admin/volume_hosts_client.py
index 98a7c58..583b2c5 100644
--- a/tempest/services/volume/xml/admin/volume_hosts_client.py
+++ b/tempest/services/volume/xml/admin/volume_hosts_client.py
@@ -24,14 +24,14 @@
 CONF = config.CONF
 
 
-class VolumeHostsClientXML(rest_client.RestClient):
+class BaseVolumeHostsClientXML(rest_client.RestClient):
     """
     Client class to send CRUD Volume Hosts API requests to a Cinder endpoint
     """
     TYPE = "xml"
 
     def __init__(self, auth_provider):
-        super(VolumeHostsClientXML, self).__init__(auth_provider)
+        super(BaseVolumeHostsClientXML, self).__init__(auth_provider)
         self.service = CONF.volume.catalog_type
         self.build_interval = CONF.compute.build_interval
         self.build_timeout = CONF.compute.build_timeout
@@ -72,3 +72,9 @@
         self.expected_success(200, resp.status)
         body = self._parse_array(etree.fromstring(body))
         return resp, body
+
+
+class VolumeHostsClientXML(BaseVolumeHostsClientXML):
+    """
+    Client class to send CRUD Volume Host API V1 requests to a Cinder endpoint
+    """
diff --git a/tempest/services/volume/xml/admin/volume_types_client.py b/tempest/services/volume/xml/admin/volume_types_client.py
index 679d097..03d39a8 100644
--- a/tempest/services/volume/xml/admin/volume_types_client.py
+++ b/tempest/services/volume/xml/admin/volume_types_client.py
@@ -25,14 +25,14 @@
 CONF = config.CONF
 
 
-class VolumeTypesClientXML(rest_client.RestClient):
+class BaseVolumeTypesClientXML(rest_client.RestClient):
     """
     Client class to send CRUD Volume Types API requests to a Cinder endpoint
     """
     TYPE = "xml"
 
     def __init__(self, auth_provider):
-        super(VolumeTypesClientXML, self).__init__(auth_provider)
+        super(BaseVolumeTypesClientXML, self).__init__(auth_provider)
         self.service = CONF.volume.catalog_type
         self.build_interval = CONF.compute.build_interval
         self.build_timeout = CONF.compute.build_timeout
@@ -205,3 +205,14 @@
         except exceptions.NotFound:
             return True
         return False
+
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'volume-type'
+
+
+class VolumeTypesClientXML(BaseVolumeTypesClientXML):
+    """
+    Client class to send CRUD Volume Type API V1 requests to a Cinder endpoint
+    """
diff --git a/tempest/services/volume/xml/snapshots_client.py b/tempest/services/volume/xml/snapshots_client.py
index 7636707..fb591b1 100644
--- a/tempest/services/volume/xml/snapshots_client.py
+++ b/tempest/services/volume/xml/snapshots_client.py
@@ -26,16 +26,17 @@
 LOG = logging.getLogger(__name__)
 
 
-class SnapshotsClientXML(rest_client.RestClient):
-    """Client class to send CRUD Volume API requests."""
+class BaseSnapshotsClientXML(rest_client.RestClient):
+    """Base Client class to send CRUD Volume API requests."""
     TYPE = "xml"
 
     def __init__(self, auth_provider):
-        super(SnapshotsClientXML, self).__init__(auth_provider)
+        super(BaseSnapshotsClientXML, self).__init__(auth_provider)
 
         self.service = CONF.volume.catalog_type
         self.build_interval = CONF.volume.build_interval
         self.build_timeout = CONF.volume.build_timeout
+        self.create_resp = 200
 
     def list_snapshots(self, params=None):
         """List all snapshot."""
@@ -90,7 +91,7 @@
         resp, body = self.post('snapshots',
                                str(common.Document(snapshot)))
         body = common.xml_to_json(etree.fromstring(body))
-        self.expected_success(200, resp.status)
+        self.expected_success(self.create_resp, resp.status)
         return resp, body
 
     def update_snapshot(self, snapshot_id, **kwargs):
@@ -152,6 +153,11 @@
             return True
         return False
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'volume-snapshot'
+
     def reset_snapshot_status(self, snapshot_id, status):
         """Reset the specified snapshot's status."""
         post_body = common.Element("os-reset_status", status=status)
@@ -243,3 +249,7 @@
             body = common.xml_to_json(etree.fromstring(body))
         self.expected_success(202, resp.status)
         return resp, body
+
+
+class SnapshotsClientXML(BaseSnapshotsClientXML):
+    """Client class to send CRUD Volume V1 API requests."""
diff --git a/tempest/services/volume/xml/volumes_client.py b/tempest/services/volume/xml/volumes_client.py
index a8c1ae5..0fe7e0d 100644
--- a/tempest/services/volume/xml/volumes_client.py
+++ b/tempest/services/volume/xml/volumes_client.py
@@ -226,6 +226,11 @@
             return True
         return False
 
+    @property
+    def resource_type(self):
+        """Returns the primary type of resource this client works with."""
+        return 'volume'
+
     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",
diff --git a/tempest/stress/actions/server_create_destroy.py b/tempest/stress/actions/server_create_destroy.py
index 4a9f0d5..34e299d 100644
--- a/tempest/stress/actions/server_create_destroy.py
+++ b/tempest/stress/actions/server_create_destroy.py
@@ -28,15 +28,13 @@
     def run(self):
         name = data_utils.rand_name("instance")
         self.logger.info("creating %s" % name)
-        resp, server = self.manager.servers_client.create_server(
+        _, server = self.manager.servers_client.create_server(
             name, self.image, self.flavor)
         server_id = server['id']
-        assert(resp.status == 202)
         self.manager.servers_client.wait_for_server_status(server_id,
                                                            'ACTIVE')
         self.logger.info("created %s" % server_id)
         self.logger.info("deleting %s" % name)
-        resp, _ = self.manager.servers_client.delete_server(server_id)
-        assert(resp.status == 204)
+        self.manager.servers_client.delete_server(server_id)
         self.manager.servers_client.wait_for_server_termination(server_id)
         self.logger.info("deleted %s" % server_id)
diff --git a/tempest/stress/actions/ssh_floating.py b/tempest/stress/actions/ssh_floating.py
index 478cd07..5bc8cac 100644
--- a/tempest/stress/actions/ssh_floating.py
+++ b/tempest/stress/actions/ssh_floating.py
@@ -30,7 +30,7 @@
         proc = subprocess.Popen(cmd,
                                 stdout=subprocess.PIPE,
                                 stderr=subprocess.PIPE)
-        proc.wait()
+        proc.communicate()
         success = proc.returncode == 0
         return success
 
@@ -74,19 +74,17 @@
         self.logger.info("creating %s" % name)
         vm_args = self.vm_extra_args.copy()
         vm_args['security_groups'] = [self.sec_grp]
-        resp, server = servers_client.create_server(name, self.image,
-                                                    self.flavor,
-                                                    **vm_args)
+        _, server = servers_client.create_server(name, self.image,
+                                                 self.flavor,
+                                                 **vm_args)
         self.server_id = server['id']
-        assert(resp.status == 202)
         if self.wait_after_vm_create:
             self.manager.servers_client.wait_for_server_status(self.server_id,
                                                                'ACTIVE')
 
     def _destroy_vm(self):
         self.logger.info("deleting %s" % self.server_id)
-        resp, _ = self.manager.servers_client.delete_server(self.server_id)
-        assert(resp.status == 204)  # It cannot be 204 if I had to wait..
+        self.manager.servers_client.delete_server(self.server_id)
         self.manager.servers_client.wait_for_server_termination(self.server_id)
         self.logger.info("deleted %s" % self.server_id)
 
diff --git a/tempest/stress/actions/volume_attach_delete.py b/tempest/stress/actions/volume_attach_delete.py
index e0238d3..9c4070f 100644
--- a/tempest/stress/actions/volume_attach_delete.py
+++ b/tempest/stress/actions/volume_attach_delete.py
@@ -28,10 +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(
+        _, 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')
         self.logger.info("created volume: %s" % volume['id'])
@@ -39,20 +38,18 @@
         # Step 2: create vm instance
         vm_name = data_utils.rand_name("instance")
         self.logger.info("creating vm: %s" % vm_name)
-        resp, server = self.manager.servers_client.create_server(
+        _, server = self.manager.servers_client.create_server(
             vm_name, self.image, self.flavor)
         server_id = server['id']
-        assert(resp.status == 202)
         self.manager.servers_client.wait_for_server_status(server_id, 'ACTIVE')
         self.logger.info("created vm %s" % server_id)
 
         # Step 3: attach volume to vm
         self.logger.info("attach volume (%s) to vm %s" %
                          (volume['id'], server_id))
-        resp, body = self.manager.servers_client.attach_volume(server_id,
-                                                               volume['id'],
-                                                               '/dev/vdc')
-        assert(resp.status == 200)
+        self.manager.servers_client.attach_volume(server_id,
+                                                  volume['id'],
+                                                  '/dev/vdc')
         self.manager.volumes_client.wait_for_volume_status(volume['id'],
                                                            'in-use')
         self.logger.info("volume (%s) attached to vm %s" %
@@ -60,14 +57,12 @@
 
         # Step 4: delete vm
         self.logger.info("deleting vm: %s" % vm_name)
-        resp, _ = self.manager.servers_client.delete_server(server_id)
-        assert(resp.status == 204)
+        self.manager.servers_client.delete_server(server_id)
         self.manager.servers_client.wait_for_server_termination(server_id)
         self.logger.info("deleted vm: %s" % server_id)
 
         # Step 5: delete volume
         self.logger.info("deleting volume: %s" % volume['id'])
-        resp, _ = self.manager.volumes_client.delete_volume(volume['id'])
-        assert(resp.status == 202)
+        self.manager.volumes_client.delete_volume(volume['id'])
         self.manager.volumes_client.wait_for_resource_deletion(volume['id'])
         self.logger.info("deleted volume: %s" % volume['id'])
diff --git a/tempest/stress/actions/volume_attach_verify.py b/tempest/stress/actions/volume_attach_verify.py
index 0d3cb23..a13d890 100644
--- a/tempest/stress/actions/volume_attach_verify.py
+++ b/tempest/stress/actions/volume_attach_verify.py
@@ -24,12 +24,10 @@
 
     def _create_keypair(self):
         keyname = data_utils.rand_name("key")
-        resp, self.key = self.manager.keypairs_client.create_keypair(keyname)
-        assert(resp.status == 200)
+        _, self.key = self.manager.keypairs_client.create_keypair(keyname)
 
     def _delete_keypair(self):
-        resp, _ = self.manager.keypairs_client.delete_keypair(self.key['name'])
-        assert(resp.status == 202)
+        self.manager.keypairs_client.delete_keypair(self.key['name'])
 
     def _create_vm(self):
         self.name = name = data_utils.rand_name("instance")
@@ -38,18 +36,16 @@
         vm_args = self.vm_extra_args.copy()
         vm_args['security_groups'] = [self.sec_grp]
         vm_args['key_name'] = self.key['name']
-        resp, server = servers_client.create_server(name, self.image,
-                                                    self.flavor,
-                                                    **vm_args)
+        _, server = servers_client.create_server(name, self.image,
+                                                 self.flavor,
+                                                 **vm_args)
         self.server_id = server['id']
-        assert(resp.status == 202)
         self.manager.servers_client.wait_for_server_status(self.server_id,
                                                            'ACTIVE')
 
     def _destroy_vm(self):
         self.logger.info("deleting server: %s" % self.server_id)
-        resp, _ = self.manager.servers_client.delete_server(self.server_id)
-        assert(resp.status == 204)  # It cannot be 204 if I had to wait..
+        self.manager.servers_client.delete_server(self.server_id)
         self.manager.servers_client.wait_for_server_termination(self.server_id)
         self.logger.info("deleted server: %s" % self.server_id)
 
@@ -81,10 +77,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(
+        _, 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')
         self.logger.info("created volume: %s" % self.volume['id'])
@@ -92,8 +87,7 @@
     def _delete_volume(self):
         self.logger.info("deleting volume: %s" % self.volume['id'])
         volumes_client = self.manager.volumes_client
-        resp, _ = volumes_client.delete_volume(self.volume['id'])
-        assert(resp.status == 202)
+        volumes_client.delete_volume(self.volume['id'])
         volumes_client.wait_for_resource_deletion(self.volume['id'])
         self.logger.info("deleted volume: %s" % self.volume['id'])
 
@@ -193,10 +187,9 @@
         servers_client = self.manager.servers_client
         self.logger.info("attach volume (%s) to vm %s" %
                          (self.volume['id'], self.server_id))
-        resp, body = servers_client.attach_volume(self.server_id,
-                                                  self.volume['id'],
-                                                  self.part_name)
-        assert(resp.status == 200)
+        servers_client.attach_volume(self.server_id,
+                                     self.volume['id'],
+                                     self.part_name)
         self.manager.volumes_client.wait_for_volume_status(self.volume['id'],
                                                            'in-use')
         if self.enable_ssh_verify:
@@ -204,9 +197,8 @@
                              % self.server_id)
             self.part_wait(self.attach_match_count)
 
-        resp, body = servers_client.detach_volume(self.server_id,
-                                                  self.volume['id'])
-        assert(resp.status == 202)
+        servers_client.detach_volume(self.server_id,
+                                     self.volume['id'])
         self.manager.volumes_client.wait_for_volume_status(self.volume['id'],
                                                            'available')
         if self.enable_ssh_verify:
diff --git a/tempest/stress/actions/volume_create_delete.py b/tempest/stress/actions/volume_create_delete.py
index 4e75be0..b1c5bb7 100644
--- a/tempest/stress/actions/volume_create_delete.py
+++ b/tempest/stress/actions/volume_create_delete.py
@@ -20,14 +20,12 @@
         name = data_utils.rand_name("volume")
         self.logger.info("creating %s" % name)
         volumes_client = self.manager.volumes_client
-        resp, volume = volumes_client.create_volume(size=1,
-                                                    display_name=name)
-        assert(resp.status == 200)
+        _, volume = volumes_client.create_volume(size=1,
+                                                 display_name=name)
         vol_id = volume['id']
         volumes_client.wait_for_volume_status(vol_id, 'available')
         self.logger.info("created %s" % volume['id'])
         self.logger.info("deleting %s" % name)
-        resp, _ = volumes_client.delete_volume(vol_id)
-        assert(resp.status == 202)
+        volumes_client.delete_volume(vol_id)
         volumes_client.wait_for_resource_deletion(vol_id)
         self.logger.info("deleted %s" % vol_id)
diff --git a/tempest/test.py b/tempest/test.py
index f34933e..14cf3bb 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -24,13 +24,12 @@
 import uuid
 
 import fixtures
-import testresources
 import testscenarios
 import testtools
 
 from tempest import clients
+from tempest.common import credentials
 import tempest.common.generator.valid_generator as valid
-from tempest.common import isolated_creds
 from tempest import config
 from tempest import exceptions
 from tempest.openstack.common import importutils
@@ -66,35 +65,7 @@
     return decorator
 
 
-def safe_setup(f):
-    """A decorator used to wrap the setUpClass for cleaning up resources
-       when setUpClass failed.
-    """
-    @functools.wraps(f)
-    def decorator(cls):
-            try:
-                f(cls)
-            except Exception as se:
-                etype, value, trace = sys.exc_info()
-                LOG.exception("setUpClass failed: %s" % se)
-                try:
-                    cls.tearDownClass()
-                except Exception as te:
-                    LOG.exception("tearDownClass failed: %s" % te)
-                try:
-                    raise etype(value), None, trace
-                finally:
-                    del trace  # for avoiding circular refs
-
-    return decorator
-
-
-def services(*args, **kwargs):
-    """A decorator used to set an attr for each service used in a test case
-
-    This decorator applies a testtools attr for each service that gets
-    exercised by a test case.
-    """
+def get_service_list():
     service_list = {
         'compute': CONF.service_available.nova,
         'image': CONF.service_available.glance,
@@ -110,16 +81,29 @@
         'telemetry': CONF.service_available.ceilometer,
         'data_processing': CONF.service_available.sahara
     }
+    return service_list
 
+
+def services(*args, **kwargs):
+    """A decorator used to set an attr for each service used in a test case
+
+    This decorator applies a testtools attr for each service that gets
+    exercised by a test case.
+    """
     def decorator(f):
+        services = ['compute', 'image', 'baremetal', 'volume', 'orchestration',
+                    'network', 'identity', 'object_storage', 'dashboard',
+                    'telemetry', 'data_processing']
         for service in args:
-            if service not in service_list:
-                raise exceptions.InvalidServiceTag('%s is not a valid service'
-                                                   % service)
+            if service not in services:
+                raise exceptions.InvalidServiceTag('%s is not a valid '
+                                                   'service' % service)
         attr(type=list(args))(f)
 
         @functools.wraps(f)
         def wrapper(self, *func_args, **func_kwargs):
+            service_list = get_service_list()
+
             for service in args:
                 if not service_list[service]:
                     msg = 'Skipped because the %s service is not available' % (
@@ -237,23 +221,9 @@
 
 atexit.register(validate_tearDownClass)
 
-if sys.version_info >= (2, 7):
-    class BaseDeps(testtools.TestCase,
-                   testtools.testcase.WithAttributes,
-                   testresources.ResourcedTestCase):
-        pass
-else:
-    # Define asserts for py26
-    import unittest2
 
-    class BaseDeps(testtools.TestCase,
-                   testtools.testcase.WithAttributes,
-                   testresources.ResourcedTestCase,
-                   unittest2.TestCase):
-        pass
-
-
-class BaseTestCase(BaseDeps):
+class BaseTestCase(testtools.testcase.WithAttributes,
+                   testtools.TestCase):
 
     setUpClassCalled = False
     _service = None
@@ -268,15 +238,58 @@
 
     @classmethod
     def setUpClass(cls):
+        # It should never be overridden by descendants
         if hasattr(super(BaseTestCase, cls), 'setUpClass'):
             super(BaseTestCase, cls).setUpClass()
         cls.setUpClassCalled = True
+        # No test resource is allocated until here
+        try:
+            # TODO(andreaf) Split-up resource_setup in stages:
+            # skip checks, pre-hook, credentials, clients, resources, post-hook
+            cls.resource_setup()
+        except Exception:
+            etype, value, trace = sys.exc_info()
+            LOG.info("%s in resource setup. Invoking tearDownClass." % etype)
+            # Catch any exception in tearDown so we can re-raise the original
+            # exception at the end
+            try:
+                cls.tearDownClass()
+            except Exception as te:
+                tetype, _, _ = sys.exc_info()
+                # TODO(gmann): Till we split-up resource_setup &
+                # resource_cleanup in more structural way, log
+                # AttributeError as info instead of exception.
+                if tetype is AttributeError:
+                    LOG.info("tearDownClass failed: %s" % te)
+                else:
+                    LOG.exception("tearDownClass failed: %s" % te)
+            try:
+                raise etype(value), None, trace
+            finally:
+                del trace  # for avoiding circular refs
 
     @classmethod
     def tearDownClass(cls):
         at_exit_set.discard(cls)
+        # It should never be overridden by descendants
         if hasattr(super(BaseTestCase, cls), 'tearDownClass'):
             super(BaseTestCase, cls).tearDownClass()
+        try:
+            cls.resource_cleanup()
+        finally:
+            cls.clear_isolated_creds()
+
+    @classmethod
+    def resource_setup(cls):
+        """Class level setup steps for test cases.
+        Recommended order: skip checks, credentials, clients, resources.
+        """
+        pass
+
+    @classmethod
+    def resource_cleanup(cls):
+        """Class level resource cleanup for test cases. """
+        pass
 
     def setUp(self):
         super(BaseTestCase, self).setUp()
@@ -312,31 +325,22 @@
         """
         Returns an OpenStack client manager
         """
-        cls.isolated_creds = isolated_creds.IsolatedCreds(
-            cls.__name__, network_resources=cls.network_resources)
-
         force_tenant_isolation = getattr(cls, 'force_tenant_isolation', None)
-        if CONF.compute.allow_tenant_isolation or force_tenant_isolation:
-            creds = cls.isolated_creds.get_primary_creds()
-            if getattr(cls, '_interface', None):
-                os = clients.Manager(credentials=creds,
-                                     interface=cls._interface,
-                                     service=cls._service)
-            elif interface:
-                os = clients.Manager(credentials=creds,
-                                     interface=interface,
-                                     service=cls._service)
-            else:
-                os = clients.Manager(credentials=creds,
-                                     service=cls._service)
-        else:
-            if getattr(cls, '_interface', None):
-                os = clients.Manager(interface=cls._interface,
-                                     service=cls._service)
-            elif interface:
-                os = clients.Manager(interface=interface, service=cls._service)
-            else:
-                os = clients.Manager(service=cls._service)
+
+        if (not hasattr(cls, 'isolated_creds') or
+            not cls.isolated_creds.name == cls.__name__):
+            cls.isolated_creds = credentials.get_isolated_credentials(
+                name=cls.__name__, network_resources=cls.network_resources,
+                force_tenant_isolation=force_tenant_isolation,
+            )
+
+        creds = cls.isolated_creds.get_primary_creds()
+        params = dict(credentials=creds, service=cls._service)
+        if getattr(cls, '_interface', None):
+            interface = cls._interface
+        if interface:
+            params['interface'] = interface
+        os = clients.Manager(**params)
         return os
 
     @classmethod
@@ -344,7 +348,7 @@
         """
         Clears isolated creds if set
         """
-        if getattr(cls, 'isolated_creds'):
+        if hasattr(cls, 'isolated_creds'):
             cls.isolated_creds.clear_isolated_creds()
 
     @classmethod
@@ -460,13 +464,9 @@
                                              "expected_result": expected_result
                                              }))
         if schema is not None:
-            for name, schema, expected_result in generator.generate(schema):
-                if (expected_result is None and
-                    "default_result_code" in description):
-                    expected_result = description["default_result_code"]
-                scenario_list.append((name,
-                                      {"schema": schema,
-                                       "expected_result": expected_result}))
+            for scenario in generator.generate_scenarios(schema):
+                scenario_list.append((scenario['_negtest_name'],
+                                      scenario))
         LOG.debug(scenario_list)
         return scenario_list
 
@@ -496,8 +496,14 @@
         """
         LOG.info("Executing %s" % description["name"])
         LOG.debug(description)
+        generator = importutils.import_class(
+            CONF.negative.test_generator)()
+        schema = description.get("json-schema", None)
         method = description["http-method"]
         url = description["url"]
+        expected_result = None
+        if "default_result_code" in description:
+            expected_result = description["default_result_code"]
 
         resources = [self.get_resource(r) for
                      r in description.get("resources", [])]
@@ -507,13 +513,19 @@
             # entry (see get_resource).
             # We just send a valid json-schema with it
             valid_schema = None
-            schema = description.get("json-schema", None)
             if schema:
                 valid_schema = \
                     valid.ValidTestGenerator().generate_valid(schema)
             new_url, body = self._http_arguments(valid_schema, url, method)
-        elif hasattr(self, "schema"):
-            new_url, body = self._http_arguments(self.schema, url, method)
+        elif hasattr(self, "_negtest_name"):
+            schema_under_test = \
+                valid.ValidTestGenerator().generate_valid(schema)
+            local_expected_result = \
+                generator.generate_payload(self, schema_under_test)
+            if local_expected_result is not None:
+                expected_result = local_expected_result
+            new_url, body = \
+                self._http_arguments(schema_under_test, url, method)
         else:
             raise Exception("testscenarios are not active. Please make sure "
                             "that your test runner supports the load_tests "
@@ -525,7 +537,7 @@
             client = self.client
         resp, resp_body = client.send_request(method, new_url,
                                               resources, body=body)
-        self._check_negative_response(resp.status, resp_body)
+        self._check_negative_response(expected_result, resp.status, resp_body)
 
     def _http_arguments(self, json_dict, url, method):
         LOG.debug("dict: %s url: %s method: %s" % (json_dict, url, method))
@@ -536,8 +548,7 @@
         else:
             return url, json.dumps(json_dict)
 
-    def _check_negative_response(self, result, body):
-        expected_result = getattr(self, "expected_result", None)
+    def _check_negative_response(self, expected_result, result, body):
         self.assertTrue(result >= 400 and result < 500 and result != 413,
                         "Expected client error, got %s:%s" %
                         (result, body))
diff --git a/tempest/tests/cli/test_cli.py b/tempest/tests/cli/test_cli.py
index 1fd5ccb..8f18dfc 100644
--- a/tempest/tests/cli/test_cli.py
+++ b/tempest/tests/cli/test_cli.py
@@ -13,17 +13,25 @@
 #    under the License.
 
 import mock
+from tempest_lib.cli import base as cli_base
 import testtools
 
 from tempest import cli
+from tempest import config
 from tempest import exceptions
 from tempest.tests import base
+from tempest.tests import fake_config
 
 
 class TestMinClientVersion(base.TestCase):
     """Tests for the min_client_version decorator.
     """
 
+    def setUp(self):
+        super(TestMinClientVersion, self).setUp()
+        self.useFixture(fake_config.ConfigFixture())
+        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
+
     def _test_min_version(self, required, installed, expect_skip):
 
         @cli.min_client_version(client='nova', version=required)
@@ -33,7 +41,7 @@
                 # expected so we need to fail.
                 self.fail('Should not have gotten past the decorator.')
 
-        with mock.patch.object(cli, 'execute',
+        with mock.patch.object(cli_base, 'execute',
                                return_value=installed) as mock_cmd:
             if expect_skip:
                 self.assertRaises(testtools.TestCase.skipException, fake,
@@ -41,6 +49,7 @@
             else:
                 fake(self, expect_skip)
             mock_cmd.assert_called_once_with('nova', '', params='--version',
+                                             cli_dir='/usr/local/bin',
                                              merge_stderr=True)
 
     def test_min_client_version(self):
@@ -52,7 +61,7 @@
         for case in cases:
             self._test_min_version(*case)
 
-    @mock.patch.object(cli, 'execute', return_value=' ')
+    @mock.patch.object(cli_base, 'execute', return_value=' ')
     def test_check_client_version_empty_output(self, mock_execute):
         # Tests that an exception is raised if the command output is empty.
         self.assertRaises(exceptions.TempestException,
diff --git a/tempest/tests/cli/test_command_failed.py b/tempest/tests/cli/test_command_failed.py
deleted file mode 100644
index 36a4fc8..0000000
--- a/tempest/tests/cli/test_command_failed.py
+++ /dev/null
@@ -1,30 +0,0 @@
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest import exceptions
-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 exceptions.CommandFailed(returncode, cmd, stdout, stderr)
-        except exceptions.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/cli/test_output_parser.py b/tempest/tests/cli/test_output_parser.py
deleted file mode 100644
index 7ad270c..0000000
--- a/tempest/tests/cli/test_output_parser.py
+++ /dev/null
@@ -1,177 +0,0 @@
-# Copyright 2014 NEC Corporation.
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-
-from tempest.cli import output_parser
-from tempest import exceptions
-from tempest.tests import base
-
-
-class TestOutputParser(base.TestCase):
-    OUTPUT_LINES = """
-+----+------+---------+
-| ID | Name | Status  |
-+----+------+---------+
-| 11 | foo  | BUILD   |
-| 21 | bar  | ERROR   |
-| 31 | bee  | None    |
-+----+------+---------+
-"""
-    OUTPUT_LINES2 = """
-+----+-------+---------+
-| ID | Name2 | Status2 |
-+----+-------+---------+
-| 41 | aaa   | SSSSS   |
-| 51 | bbb   | TTTTT   |
-| 61 | ccc   | AAAAA   |
-+----+-------+---------+
-"""
-
-    EXPECTED_TABLE = {'headers': ['ID', 'Name', 'Status'],
-                      'values': [['11', 'foo', 'BUILD'],
-                                 ['21', 'bar', 'ERROR'],
-                                 ['31', 'bee', 'None']]}
-    EXPECTED_TABLE2 = {'headers': ['ID', 'Name2', 'Status2'],
-                       'values': [['41', 'aaa', 'SSSSS'],
-                                  ['51', 'bbb', 'TTTTT'],
-                                  ['61', 'ccc', 'AAAAA']]}
-
-    def test_table_with_normal_values(self):
-        actual = output_parser.table(self.OUTPUT_LINES)
-        self.assertIsInstance(actual, dict)
-        self.assertEqual(self.EXPECTED_TABLE, actual)
-
-    def test_table_with_list(self):
-        output_lines = self.OUTPUT_LINES.split('\n')
-        actual = output_parser.table(output_lines)
-        self.assertIsInstance(actual, dict)
-        self.assertEqual(self.EXPECTED_TABLE, actual)
-
-    def test_table_with_invalid_line(self):
-        output_lines = self.OUTPUT_LINES + "aaaa"
-        actual = output_parser.table(output_lines)
-        self.assertIsInstance(actual, dict)
-        self.assertEqual(self.EXPECTED_TABLE, actual)
-
-    def test_tables_with_normal_values(self):
-        output_lines = 'test' + self.OUTPUT_LINES +\
-                       'test2' + self.OUTPUT_LINES2
-        expected = [{'headers': self.EXPECTED_TABLE['headers'],
-                     'label': 'test',
-                     'values': self.EXPECTED_TABLE['values']},
-                    {'headers': self.EXPECTED_TABLE2['headers'],
-                     'label': 'test2',
-                     'values': self.EXPECTED_TABLE2['values']}]
-        actual = output_parser.tables(output_lines)
-        self.assertIsInstance(actual, list)
-        self.assertEqual(expected, actual)
-
-    def test_tables_with_invalid_values(self):
-        output_lines = 'test' + self.OUTPUT_LINES +\
-                       'test2' + self.OUTPUT_LINES2 + '\n'
-        expected = [{'headers': self.EXPECTED_TABLE['headers'],
-                     'label': 'test',
-                     'values': self.EXPECTED_TABLE['values']},
-                    {'headers': self.EXPECTED_TABLE2['headers'],
-                     'label': 'test2',
-                     'values': self.EXPECTED_TABLE2['values']}]
-        actual = output_parser.tables(output_lines)
-        self.assertIsInstance(actual, list)
-        self.assertEqual(expected, actual)
-
-    def test_tables_with_invalid_line(self):
-        output_lines = 'test' + self.OUTPUT_LINES +\
-                       'test2' + self.OUTPUT_LINES2 +\
-                       '+----+-------+---------+'
-        expected = [{'headers': self.EXPECTED_TABLE['headers'],
-                     'label': 'test',
-                     'values': self.EXPECTED_TABLE['values']},
-                    {'headers': self.EXPECTED_TABLE2['headers'],
-                     'label': 'test2',
-                     'values': self.EXPECTED_TABLE2['values']}]
-
-        actual = output_parser.tables(output_lines)
-        self.assertIsInstance(actual, list)
-        self.assertEqual(expected, actual)
-
-    LISTING_OUTPUT = """
-+----+
-| ID |
-+----+
-| 11 |
-| 21 |
-| 31 |
-+----+
-"""
-
-    def test_listing(self):
-        expected = [{'ID': '11'}, {'ID': '21'}, {'ID': '31'}]
-        actual = output_parser.listing(self.LISTING_OUTPUT)
-        self.assertIsInstance(actual, list)
-        self.assertEqual(expected, actual)
-
-    def test_details_multiple_with_invalid_line(self):
-        self.assertRaises(exceptions.InvalidStructure,
-                          output_parser.details_multiple,
-                          self.OUTPUT_LINES)
-
-    DETAILS_LINES1 = """First Table
-+----------+--------+
-| Property | Value  |
-+----------+--------+
-| foo      | BUILD  |
-| bar      | ERROR  |
-| bee      | None   |
-+----------+--------+
-"""
-    DETAILS_LINES2 = """Second Table
-+----------+--------+
-| Property | Value  |
-+----------+--------+
-| aaa      | VVVVV  |
-| bbb      | WWWWW  |
-| ccc      | XXXXX  |
-+----------+--------+
-"""
-
-    def test_details_with_normal_line_label_false(self):
-        expected = {'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'}
-        actual = output_parser.details(self.DETAILS_LINES1)
-        self.assertEqual(expected, actual)
-
-    def test_details_with_normal_line_label_true(self):
-        expected = {'__label': 'First Table',
-                    'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'}
-        actual = output_parser.details(self.DETAILS_LINES1, with_label=True)
-        self.assertEqual(expected, actual)
-
-    def test_details_multiple_with_normal_line_label_false(self):
-        expected = [{'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'},
-                    {'aaa': 'VVVVV', 'bbb': 'WWWWW', 'ccc': 'XXXXX'}]
-        actual = output_parser.details_multiple(self.DETAILS_LINES1 +
-                                                self.DETAILS_LINES2)
-        self.assertIsInstance(actual, list)
-        self.assertEqual(expected, actual)
-
-    def test_details_multiple_with_normal_line_label_true(self):
-        expected = [{'__label': 'First Table',
-                     'foo': 'BUILD', 'bar': 'ERROR', 'bee': 'None'},
-                    {'__label': 'Second Table',
-                     'aaa': 'VVVVV', 'bbb': 'WWWWW', 'ccc': 'XXXXX'}]
-        actual = output_parser.details_multiple(self.DETAILS_LINES1 +
-                                                self.DETAILS_LINES2,
-                                                with_label=True)
-        self.assertIsInstance(actual, list)
-        self.assertEqual(expected, actual)
diff --git a/tempest/tests/cmd/test_verify_tempest_config.py b/tempest/tests/cmd/test_verify_tempest_config.py
index d0140dd..6679c79 100644
--- a/tempest/tests/cmd/test_verify_tempest_config.py
+++ b/tempest/tests/cmd/test_verify_tempest_config.py
@@ -86,6 +86,24 @@
         self.assertIn('v2.0', versions)
         self.assertIn('v3.0', versions)
 
+    def test_verify_api_versions(self):
+        api_services = ['cinder', 'glance', 'keystone', 'nova']
+        fake_os = mock.MagicMock()
+        for svc in api_services:
+            m = 'verify_%s_api_versions' % svc
+            with mock.patch.object(verify_tempest_config, m) as verify_mock:
+                verify_tempest_config.verify_api_versions(fake_os, svc, True)
+                verify_mock.assert_called_once_with(fake_os, True)
+
+    def test_verify_api_versions_not_implemented(self):
+        api_services = ['cinder', 'glance', 'keystone', 'nova']
+        fake_os = mock.MagicMock()
+        for svc in api_services:
+            m = 'verify_%s_api_versions' % svc
+            with mock.patch.object(verify_tempest_config, m) as verify_mock:
+                verify_tempest_config.verify_api_versions(fake_os, 'foo', True)
+                self.assertFalse(verify_mock.called)
+
     def test_verify_keystone_api_versions_no_v3(self):
         self.useFixture(mockpatch.PatchObject(
             verify_tempest_config, '_get_unversioned_endpoint',
@@ -238,8 +256,8 @@
                                                           'neutron', {})
         self.assertIn('neutron', results)
         self.assertIn('extensions', results['neutron'])
-        self.assertEqual(['fake1', 'fake2', 'not_fake'],
-                         results['neutron']['extensions'])
+        self.assertEqual(sorted(['fake1', 'fake2', 'not_fake']),
+                         sorted(results['neutron']['extensions']))
 
     def test_verify_extensions_cinder(self):
         def fake_list_extensions():
@@ -277,8 +295,8 @@
                                                           'cinder', {})
         self.assertIn('cinder', results)
         self.assertIn('extensions', results['cinder'])
-        self.assertEqual(['fake1', 'fake2', 'not_fake'],
-                         results['cinder']['extensions'])
+        self.assertEqual(sorted(['fake1', 'fake2', 'not_fake']),
+                         sorted(results['cinder']['extensions']))
 
     def test_verify_extensions_nova(self):
         def fake_list_extensions():
@@ -316,8 +334,8 @@
                                                           'nova', {})
         self.assertIn('nova', results)
         self.assertIn('extensions', results['nova'])
-        self.assertEqual(['fake1', 'fake2', 'not_fake'],
-                         results['nova']['extensions'])
+        self.assertEqual(sorted(['fake1', 'fake2', 'not_fake']),
+                         sorted(results['nova']['extensions']))
 
     def test_verify_extensions_nova_v3(self):
         def fake_list_extensions():
@@ -355,8 +373,8 @@
                                                           'nova_v3', {})
         self.assertIn('nova_v3', results)
         self.assertIn('extensions', results['nova_v3'])
-        self.assertEqual(['fake1', 'fake2', 'not_fake'],
-                         results['nova_v3']['extensions'])
+        self.assertEqual(sorted(['fake1', 'fake2', 'not_fake']),
+                         sorted(results['nova_v3']['extensions']))
 
     def test_verify_extensions_swift(self):
         def fake_list_extensions():
@@ -395,5 +413,5 @@
                                                           'swift', {})
         self.assertIn('swift', results)
         self.assertIn('extensions', results['swift'])
-        self.assertEqual(['not_fake', 'fake1', 'fake2'],
-                         results['swift']['extensions'])
+        self.assertEqual(sorted(['not_fake', 'fake1', 'fake2']),
+                         sorted(results['swift']['extensions']))
diff --git a/tempest/tests/common/test_accounts.py b/tempest/tests/common/test_accounts.py
index c24bfb6..cf7ce65 100644
--- a/tempest/tests/common/test_accounts.py
+++ b/tempest/tests/common/test_accounts.py
@@ -57,6 +57,7 @@
             'tempest.common.accounts.read_accounts_yaml',
             return_value=self.test_accounts))
         cfg.CONF.set_default('test_accounts_file', '', group='auth')
+        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
 
     def _get_hash_list(self, accounts_list):
         hash_list = []
@@ -185,3 +186,49 @@
                                  hash_list[2])
         remove_mock.mock.assert_called_once_with(hash_path)
         rmdir_mock.mock.assert_not_called()
+
+    def test_is_multi_user(self):
+        test_accounts_class = accounts.Accounts('test_name')
+        self.assertTrue(test_accounts_class.is_multi_user())
+
+    def test_is_not_multi_user(self):
+        self.test_accounts = [self.test_accounts[0]]
+        self.useFixture(mockpatch.Patch(
+            'tempest.common.accounts.read_accounts_yaml',
+            return_value=self.test_accounts))
+        test_accounts_class = accounts.Accounts('test_name')
+        self.assertFalse(test_accounts_class.is_multi_user())
+
+
+class TestNotLockingAccount(base.TestCase):
+
+    def setUp(self):
+        super(TestNotLockingAccount, self).setUp()
+        self.useFixture(fake_config.ConfigFixture())
+        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
+        self.temp_dir = tempfile.mkdtemp()
+        cfg.CONF.set_default('lock_path', self.temp_dir)
+        self.addCleanup(os.rmdir, self.temp_dir)
+        self.test_accounts = [
+            {'username': 'test_user1', 'tenant_name': 'test_tenant1',
+             'password': 'p'},
+            {'username': 'test_user2', 'tenant_name': 'test_tenant2',
+             'password': 'p'},
+            {'username': 'test_user3', 'tenant_name': 'test_tenant3',
+             'password': 'p'},
+        ]
+        self.useFixture(mockpatch.Patch(
+            'tempest.common.accounts.read_accounts_yaml',
+            return_value=self.test_accounts))
+        cfg.CONF.set_default('test_accounts_file', '', group='auth')
+        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+
+    def test_get_creds(self):
+        test_accounts_class = accounts.NotLockingAccounts('test_name')
+        for i in xrange(len(self.test_accounts)):
+            creds = test_accounts_class.get_creds(i)
+            msg = "Empty credentials returned for ID %s" % str(i)
+            self.assertIsNotNone(creds, msg)
+        self.assertRaises(exceptions.InvalidConfiguration,
+                          test_accounts_class.get_creds,
+                          id=len(self.test_accounts))
diff --git a/tempest/tests/common/utils/linux/test_remote_client.py b/tempest/tests/common/utils/linux/test_remote_client.py
index 0db4cfa..e8650c5 100644
--- a/tempest/tests/common/utils/linux/test_remote_client.py
+++ b/tempest/tests/common/utils/linux/test_remote_client.py
@@ -117,7 +117,7 @@
 
         self.assertEqual(self.conn.get_mac_address(), macs)
         self._assert_exec_called_with(
-            "/sbin/ifconfig | awk '/HWaddr/ {print $5}'")
+            "/bin/ip addr | awk '/ether/ {print $2}'")
 
     def test_get_ip_list(self):
         ips = """1: lo: <LOOPBACK,UP,LOWER_UP> mtu 16436 qdisc noqueue
diff --git a/tempest/tests/common/utils/test_misc.py b/tempest/tests/common/utils/test_misc.py
index aee9805..554027f 100644
--- a/tempest/tests/common/utils/test_misc.py
+++ b/tempest/tests/common/utils/test_misc.py
@@ -82,7 +82,7 @@
         self.assertEqual(':tearDown', tearDown())
 
     def test_find_test_caller_teardown_class(self):
-        def tearDownClass(cls):
+        def tearDownClass(cls):  # noqa
             return misc.find_test_caller()
         self.assertEqual('TestMisc:tearDownClass',
                          tearDownClass(self.__class__))
diff --git a/tempest/tests/negative/test_negative_auto_test.py b/tempest/tests/negative/test_negative_auto_test.py
index dddd083..fb1da43 100644
--- a/tempest/tests/negative/test_negative_auto_test.py
+++ b/tempest/tests/negative/test_negative_auto_test.py
@@ -43,9 +43,9 @@
     def _check_prop_entries(self, result, entry):
         entries = [a for a in result if entry in a[0]]
         self.assertIsNotNone(entries)
-        self.assertIs(len(entries), 2)
+        self.assertGreater(len(entries), 1)
         for entry in entries:
-            self.assertIsNotNone(entry[1]['schema'])
+            self.assertIsNotNone(entry[1]['_negtest_name'])
 
     def _check_resource_entries(self, result, entry):
         entries = [a for a in result if entry in a[0]]
@@ -57,12 +57,11 @@
     def test_generate_scenario(self):
         scenarios = test.NegativeAutoTest.\
             generate_scenario(self.fake_input_desc)
-
         self.assertIsInstance(scenarios, list)
         for scenario in scenarios:
             self.assertIsInstance(scenario, tuple)
             self.assertIsInstance(scenario[0], str)
             self.assertIsInstance(scenario[1], dict)
-        self._check_prop_entries(scenarios, "prop_minRam")
-        self._check_prop_entries(scenarios, "prop_minDisk")
+        self._check_prop_entries(scenarios, "minRam")
+        self._check_prop_entries(scenarios, "minDisk")
         self._check_resource_entries(scenarios, "inv_res")
diff --git a/tempest/tests/negative/test_negative_generators.py b/tempest/tests/negative/test_negative_generators.py
index a7af619..2fa6933 100644
--- a/tempest/tests/negative/test_negative_generators.py
+++ b/tempest/tests/negative/test_negative_generators.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import copy
+
 import jsonschema
 import mock
 
@@ -86,15 +88,6 @@
 class BaseNegativeGenerator(object):
     types = ['string', 'integer', 'object']
 
-    fake_input_str = {"type": "string",
-                      "minLength": 2,
-                      "maxLength": 8,
-                      'results': {'gen_int': 404}}
-
-    fake_input_int = {"type": "integer",
-                      "maximum": 255,
-                      "minimum": 1}
-
     fake_input_obj = {"type": "object",
                       "properties": {"minRam": {"type": "integer"},
                                      "diskName": {"type": "string"},
@@ -106,31 +99,21 @@
         "type": "not_defined"
     }
 
-    def _validate_result(self, data):
-        self.assertTrue(isinstance(data, list))
-        for t in data:
-            self.assertIsInstance(t, tuple)
-            self.assertEqual(3, len(t))
-            self.assertIsInstance(t[0], str)
+    class fake_test_class(object):
+        def __init__(self, scenario):
+            for k, v in scenario.iteritems():
+                setattr(self, k, v)
 
-    def test_generate_string(self):
-        result = self.generator.generate(self.fake_input_str)
-        self._validate_result(result)
-
-    def test_generate_integer(self):
-        result = self.generator.generate(self.fake_input_int)
-        self._validate_result(result)
-
-    def test_generate_obj(self):
-        result = self.generator.generate(self.fake_input_obj)
-        self._validate_result(result)
+    def _validate_result(self, valid_schema, invalid_schema):
+        for k, v in valid_schema.iteritems():
+            self.assertTrue(k in invalid_schema)
 
     def test_generator_mandatory_functions(self):
         for data_type in self.types:
             self.assertIn(data_type, self.generator.types_dict)
 
     def test_generate_with_unknown_type(self):
-        self.assertRaises(TypeError, self.generator.generate,
+        self.assertRaises(TypeError, self.generator.generate_payload,
                           self.unknown_type_schema)
 
 
@@ -151,3 +134,16 @@
     def setUp(self):
         super(TestNegativeNegativeGenerator, self).setUp()
         self.generator = negative_generator.NegativeTestGenerator()
+
+    def test_generate_obj(self):
+        schema = self.fake_input_obj
+        scenarios = self.generator.generate_scenarios(schema)
+        for scenario in scenarios:
+            test = self.fake_test_class(scenario)
+            valid_schema = \
+                valid_generator.ValidTestGenerator().generate_valid(schema)
+            schema_under_test = copy.copy(valid_schema)
+            expected_result = \
+                self.generator.generate_payload(test, schema_under_test)
+            self.assertEqual(expected_result, None)
+            self._validate_result(valid_schema, schema_under_test)
diff --git a/tempest/tests/stress/test_stress.py b/tempest/tests/stress/test_stress.py
index 3dc2199..9c3533d 100644
--- a/tempest/tests/stress/test_stress.py
+++ b/tempest/tests/stress/test_stress.py
@@ -16,7 +16,8 @@
 import shlex
 import subprocess
 
-import tempest.cli as cli
+from tempest_lib import exceptions
+
 from tempest.openstack.common import log as logging
 from tempest.tests import base
 
@@ -43,9 +44,9 @@
             result, result_err = proc.communicate()
             if proc.returncode != 0:
                 LOG.debug('error of %s:\n%s' % (cmd_str, result_err))
-                raise cli.CommandFailed(proc.returncode,
-                                        cmd,
-                                        result)
+                raise exceptions.CommandFailed(proc.returncode,
+                                               cmd,
+                                               result)
         finally:
             LOG.debug('output of %s:\n%s' % (cmd_str, result))
         return proc.returncode
diff --git a/tempest/tests/test_credentials.py b/tempest/tests/test_credentials.py
index 9da5f92..ea576c4 100644
--- a/tempest/tests/test_credentials.py
+++ b/tempest/tests/test_credentials.py
@@ -128,12 +128,22 @@
         creds = self._get_credentials()
         self.assertTrue(creds.is_valid())
 
-    def test_is_not_valid(self):
+    def _test_is_not_valid(self, ignore_key):
         creds = self._get_credentials()
         for attr in self.attributes.keys():
+            if attr == ignore_key:
+                continue
+            temp_attr = getattr(creds, attr)
             delattr(creds, attr)
             self.assertFalse(creds.is_valid(),
                              "Credentials should be invalid without %s" % attr)
+            setattr(creds, attr, temp_attr)
+
+    def test_is_not_valid(self):
+        # NOTE(mtreinish): A KeystoneV2 credential object is valid without
+        # a tenant_name. So skip that check. See tempest.auth for the valid
+        # credential requirements
+        self._test_is_not_valid('tenant_name')
 
     def test_default(self):
         self.useFixture(fixtures.LockFixture('auth_version'))
@@ -205,6 +215,12 @@
                     config_value = 'fake_' + attr
                 self.assertEqual(getattr(creds, attr), config_value)
 
+    def test_is_not_valid(self):
+        # NOTE(mtreinish) For a Keystone V3 credential object a project name
+        # is not required to be valid, so we skip that check. See tempest.auth
+        # for the valid credential requirements
+        self._test_is_not_valid('project_name')
+
     def test_synced_attributes(self):
         attributes = self.attributes
         # Create V3 credentials with tenant instead of project, and user_domain
diff --git a/tempest/tests/test_decorators.py b/tempest/tests/test_decorators.py
index 12104ec..32cefd0 100644
--- a/tempest/tests/test_decorators.py
+++ b/tempest/tests/test_decorators.py
@@ -97,6 +97,28 @@
                           self._test_services_helper, 'compute',
                           'volume')
 
+    def test_services_list(self):
+        service_list = test.get_service_list()
+        for service in service_list:
+            try:
+                self._test_services_helper(service)
+            except exceptions.InvalidServiceTag:
+                self.fail('%s is not listed in the valid service tag list'
+                          % service)
+            except KeyError:
+                # NOTE(mtreinish): This condition is to test for a entry in
+                # the outer decorator list but not in the service_list dict.
+                # However, because we're looping over the service_list dict
+                # it's unlikely we'll trigger this. So manual review is still
+                # need for the list in the outer decorator.
+                self.fail('%s is in the list of valid service tags but there '
+                          'is no corresponding entry in the dict returned from'
+                          ' get_service_list()' % service)
+            except testtools.TestCase.skipException:
+                # Test didn't raise an exception because of an incorrect list
+                # entry so move onto the next entry
+                continue
+
 
 class TestStressDecorator(BaseDecoratorsTest):
     def _test_stresstest_helper(self, expected_frequency='process',
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index 9c13013..6857461 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -47,13 +47,27 @@
     just assertTrue if the check is expected to fail and assertFalse if it
     should pass.
     """
-    def test_no_setupclass_for_unit_tests(self):
-        self.assertTrue(checks.no_setupclass_for_unit_tests(
+    def test_no_setup_teardown_class_for_tests(self):
+        self.assertTrue(checks.no_setup_teardown_class_for_tests(
             "  def setUpClass(cls):", './tempest/tests/fake_test.py'))
-        self.assertIsNone(checks.no_setupclass_for_unit_tests(
+        self.assertIsNone(checks.no_setup_teardown_class_for_tests(
             "  def setUpClass(cls): # noqa", './tempest/tests/fake_test.py'))
-        self.assertFalse(checks.no_setupclass_for_unit_tests(
+        self.assertTrue(checks.no_setup_teardown_class_for_tests(
             "  def setUpClass(cls):", './tempest/api/fake_test.py'))
+        self.assertTrue(checks.no_setup_teardown_class_for_tests(
+            "  def setUpClass(cls):", './tempest/scenario/fake_test.py'))
+        self.assertFalse(checks.no_setup_teardown_class_for_tests(
+            "  def setUpClass(cls):", './tempest/test.py'))
+        self.assertTrue(checks.no_setup_teardown_class_for_tests(
+            "  def tearDownClass(cls):", './tempest/tests/fake_test.py'))
+        self.assertIsNone(checks.no_setup_teardown_class_for_tests(
+            "  def tearDownClass(cls): # noqa", './tempest/tests/fake_test.py'))
+        self.assertTrue(checks.no_setup_teardown_class_for_tests(
+            "  def tearDownClass(cls):", './tempest/api/fake_test.py'))
+        self.assertTrue(checks.no_setup_teardown_class_for_tests(
+            "  def tearDownClass(cls):", './tempest/scenario/fake_test.py'))
+        self.assertFalse(checks.no_setup_teardown_class_for_tests(
+            "  def tearDownClass(cls):", './tempest/test.py'))
 
     def test_import_no_clients_in_api(self):
         for client in checks.PYTHON_CLIENTS:
@@ -100,14 +114,6 @@
         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"))
-
     def test_no_mutable_default_args(self):
         self.assertEqual(1, len(list(checks.no_mutable_default_args(
             " def function1(para={}):"))))
diff --git a/tempest/tests/test_list_tests.py b/tempest/tests/test_list_tests.py
index 157fc5f..efdb413 100644
--- a/tempest/tests/test_list_tests.py
+++ b/tempest/tests/test_list_tests.py
@@ -12,6 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import os
 import re
 import subprocess
 
@@ -20,16 +21,23 @@
 
 class TestTestList(base.TestCase):
 
-    def test_no_import_errors(self):
+    def test_testr_list_tests_no_errors(self):
+        # Remove unit test discover path from env to test tempest tests
+        test_env = os.environ.copy()
+        test_env.pop('OS_TEST_PATH')
         import_failures = []
-        p = subprocess.Popen(['testr', 'list-tests'], stdout=subprocess.PIPE)
-        ids = p.stdout.read()
+        p = subprocess.Popen(['testr', 'list-tests'], stdout=subprocess.PIPE,
+                             env=test_env)
+        ids, err = p.communicate()
+        self.assertEqual(0, p.returncode,
+                         "test discovery failed, one or more files cause an "
+                         "error on import")
         ids = ids.split('\n')
         for test_id in ids:
             if re.match('(\w+\.){3}\w+', test_id):
                 if not test_id.startswith('tempest.'):
-                    fail_id = test_id.split('unittest.loader.ModuleImport'
-                                            'Failure.')[1]
+                    parts = test_id.partition('tempest')
+                    fail_id = parts[1] + parts[2]
                     import_failures.append(fail_id)
         error_message = ("The following tests have import failures and aren't"
                          " being run with test filters %s" % import_failures)
diff --git a/tempest/tests/test_tenant_isolation.py b/tempest/tests/test_tenant_isolation.py
index eddbb1d..27c45c2 100644
--- a/tempest/tests/test_tenant_isolation.py
+++ b/tempest/tests/test_tenant_isolation.py
@@ -12,12 +12,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import keystoneclient.v2_0.client as keystoneclient
 import mock
-import neutronclient.v2_0.client as neutronclient
 from oslo.config import cfg
 
-from tempest import clients
 from tempest.common import http
 from tempest.common import isolated_creds
 from tempest import config
@@ -52,24 +49,6 @@
         self.assertTrue(isinstance(iso_creds.network_admin_client,
                                    json_network_client.NetworkClientJSON))
 
-    def test_official_client(self):
-        self.useFixture(mockpatch.PatchObject(keystoneclient.Client,
-                                              'authenticate'))
-        self.useFixture(mockpatch.PatchObject(clients.OfficialClientManager,
-                                              '_get_image_client'))
-        self.useFixture(mockpatch.PatchObject(clients.OfficialClientManager,
-                                              '_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,
-                                   keystoneclient.Client))
-        self.assertTrue(isinstance(iso_creds.network_admin_client,
-                                   neutronclient.Client))
-
     def test_tempest_client_xml(self):
         iso_creds = isolated_creds.IsolatedCreds('test class', interface='xml')
         self.assertEqual(iso_creds.interface, 'xml')
@@ -272,6 +251,13 @@
 
     @mock.patch('tempest.common.rest_client.RestClient')
     def test_network_cleanup(self, MockRestClient):
+        def side_effect(**args):
+            return ({'status': 200},
+                    {"security_groups": [{"tenant_id": args['tenant_id'],
+                                          "name": args['name'],
+                                          "description": args['name'],
+                                          "security_group_rules": [],
+                                          "id": "sg-%s" % args['tenant_id']}]})
         iso_creds = isolated_creds.IsolatedCreds('test class',
                                                  password='fake_password')
         # Create primary tenant and network
@@ -341,7 +327,23 @@
                                            return_value=return_values)
 
         port_list_mock.start()
+        secgroup_list_mock = mock.patch.object(iso_creds.network_admin_client,
+                                               'list_security_groups',
+                                               side_effect=side_effect)
+        secgroup_list_mock.start()
+
+        return_values = (fake_http.fake_httplib({}, status=204), {})
+        remove_secgroup_mock = self.patch(
+            'tempest.services.network.network_client_base.'
+            'NetworkClientBase.delete', return_value=return_values)
         iso_creds.clear_isolated_creds()
+        # Verify default security group delete
+        calls = remove_secgroup_mock.mock_calls
+        self.assertEqual(len(calls), 3)
+        args = map(lambda x: x[1][0], calls)
+        self.assertIn('v2.0/security-groups/sg-1234', args)
+        self.assertIn('v2.0/security-groups/sg-12345', args)
+        self.assertIn('v2.0/security-groups/sg-123456', args)
         # Verify remove router interface calls
         calls = remove_router_interface_mock.mock_calls
         self.assertEqual(len(calls), 3)
diff --git a/tempest/tests/test_wrappers.py b/tempest/tests/test_wrappers.py
index bba4012..ae7860d 100644
--- a/tempest/tests/test_wrappers.py
+++ b/tempest/tests/test_wrappers.py
@@ -34,7 +34,6 @@
         # Setup Test files
         self.testr_conf_file = os.path.join(self.directory, '.testr.conf')
         self.setup_cfg_file = os.path.join(self.directory, 'setup.cfg')
-        self.subunit_trace = os.path.join(self.directory, 'subunit-trace.py')
         self.passing_file = os.path.join(self.test_dir, 'test_passing.py')
         self.failing_file = os.path.join(self.test_dir, 'test_failing.py')
         self.init_file = os.path.join(self.test_dir, '__init__.py')
@@ -45,7 +44,6 @@
         shutil.copy('setup.py', self.setup_py)
         shutil.copy('tempest/tests/files/setup.cfg', self.setup_cfg_file)
         shutil.copy('tempest/tests/files/__init__.py', self.init_file)
-        shutil.copy('tools/subunit-trace.py', self.subunit_trace)
         # copy over the pretty_tox scripts
         shutil.copy('tools/pretty_tox.sh',
                     os.path.join(self.directory, 'pretty_tox.sh'))
@@ -62,21 +60,18 @@
         p = subprocess.Popen(
             "bash %s" % cmd, shell=True,
             stdout=subprocess.PIPE, stderr=subprocess.PIPE)
-        # wait in the general case is dangerous, however the amount of
-        # data coming back on those pipes is small enough it shouldn't be
-        # a problem.
-        p.wait()
+        out, err = p.communicate()
 
         self.assertEqual(
             p.returncode, expected,
-            "Stdout: %s; Stderr: %s" % (p.stdout, p.stderr))
+            "Stdout: %s; Stderr: %s" % (out, err))
 
     def test_pretty_tox(self):
         # Git init is required for the pbr testr command. pbr requires a git
         # version or an sdist to work. so make the test directory a git repo
         # too.
         subprocess.call(['git', 'init'], stderr=DEVNULL)
-        self.assertRunExit('pretty_tox.sh tests.passing', 0)
+        self.assertRunExit('pretty_tox.sh passing', 0)
 
     def test_pretty_tox_fails(self):
         # Git init is required for the pbr testr command. pbr requires a git
@@ -86,7 +81,7 @@
         self.assertRunExit('pretty_tox.sh', 1)
 
     def test_pretty_tox_serial(self):
-        self.assertRunExit('pretty_tox_serial.sh tests.passing', 0)
+        self.assertRunExit('pretty_tox_serial.sh passing', 0)
 
     def test_pretty_tox_serial_fails(self):
         self.assertRunExit('pretty_tox_serial.sh', 1)
diff --git a/tempest/thirdparty/boto/test.py b/tempest/thirdparty/boto/test.py
index 4bf71f3..62073bd 100644
--- a/tempest/thirdparty/boto/test.py
+++ b/tempest/thirdparty/boto/test.py
@@ -108,8 +108,8 @@
     CODE_RE = '.*'  # regexp makes sense in group match
 
     def match(self, exc):
-        """:returns: Retruns with an error string if not matches,
-               returns with None when matches.
+        """:returns: Returns with an error string if it does not match,
+               returns with None when it matches.
         """
         if not isinstance(exc, exception.BotoServerError):
             return "%r not an BotoServerError instance" % exc
@@ -195,8 +195,8 @@
     """Recommended to use as base class for boto related test."""
 
     @classmethod
-    def setUpClass(cls):
-        super(BotoTestCase, cls).setUpClass()
+    def resource_setup(cls):
+        super(BotoTestCase, cls).resource_setup()
         cls.conclusion = decision_maker()
         cls.os = cls.get_client_manager()
         # The trash contains cleanup functions and paramaters in tuples
@@ -245,7 +245,7 @@
             raise self.failureException, "BotoServerError not raised"
 
     @classmethod
-    def tearDownClass(cls):
+    def resource_cleanup(cls):
         """Calls the callables added by addResourceCleanUp,
         when you overwrite this function don't forget to call this too.
         """
@@ -264,7 +264,7 @@
             finally:
                 del cls._resource_trash_bin[key]
         cls.clear_isolated_creds()
-        super(BotoTestCase, cls).tearDownClass()
+        super(BotoTestCase, cls).resource_cleanup()
         # NOTE(afazekas): let the super called even on exceptions
         # The real exceptions already logged, if the super throws another,
         # does not causes hidden issues
@@ -485,7 +485,7 @@
 
     @classmethod
     def destroy_volume_wait(cls, volume):
-        """Delete volume, tryies to detach first.
+        """Delete volume, tries to detach first.
            Use just for teardown!
         """
         exc_num = 0
@@ -498,7 +498,10 @@
         def _volume_state():
             volume.update(validate=True)
             try:
-                if volume.status != "available":
+                # NOTE(gmann): Make sure volume is attached.
+                # Checking status as 'not "available"' is not enough to make
+                # sure volume is attached as it can be in "error" state
+                if volume.status == "in-use":
                     volume.detach(force=True)
             except BaseException:
                 LOG.exception("Failed to detach volume %s" % volume)
@@ -518,7 +521,7 @@
 
     @classmethod
     def destroy_snapshot_wait(cls, snapshot):
-        """delete snaphot, wait until not exists."""
+        """delete snapshot, wait until it ceases to exist."""
         snapshot.delete()
 
         def _update():
diff --git a/tempest/thirdparty/boto/test_ec2_instance_run.py b/tempest/thirdparty/boto/test_ec2_instance_run.py
index 2c68d6b..00b17d9 100644
--- a/tempest/thirdparty/boto/test_ec2_instance_run.py
+++ b/tempest/thirdparty/boto/test_ec2_instance_run.py
@@ -13,8 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from boto import exception
-
 from tempest.common.utils import data_utils
 from tempest.common.utils.linux import remote_client
 from tempest import config
@@ -32,8 +30,8 @@
 class InstanceRunTest(boto_test.BotoTestCase):
 
     @classmethod
-    def setUpClass(cls):
-        super(InstanceRunTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(InstanceRunTest, cls).resource_setup()
         if not cls.conclusion['A_I_IMAGES_READY']:
             raise cls.skipException("".join(("EC2 ", cls.__name__,
                                     ": requires ami/aki/ari manifest")))
@@ -82,6 +80,13 @@
                 raise exceptions.EC2RegisterImageException(
                     image_id=image["image_id"])
 
+    def _terminate_reservation(self, reservation, rcuk):
+        for instance in reservation.instances:
+            instance.terminate()
+        for instance in reservation.instances:
+            self.assertInstanceStateWait(instance, '_GONE')
+        self.cancelResourceCleanUp(rcuk)
+
     def test_run_idempotent_instances(self):
         # EC2 run instances idempotently
 
@@ -96,11 +101,6 @@
                                            reservation)
             return (reservation, rcuk)
 
-        def _terminate_reservation(reservation, rcuk):
-            for instance in reservation.instances:
-                instance.terminate()
-            self.cancelResourceCleanUp(rcuk)
-
         reservation_1, rcuk_1 = _run_instance('token_1')
         reservation_2, rcuk_2 = _run_instance('token_2')
         reservation_1a, rcuk_1a = _run_instance('token_1')
@@ -116,8 +116,8 @@
         # handled by rcuk1
         self.cancelResourceCleanUp(rcuk_1a)
 
-        _terminate_reservation(reservation_1, rcuk_1)
-        _terminate_reservation(reservation_2, rcuk_2)
+        self._terminate_reservation(reservation_1, rcuk_1)
+        self._terminate_reservation(reservation_2, rcuk_2)
 
     def test_run_stop_terminate_instance(self):
         # EC2 run, stop and terminate instance
@@ -139,9 +139,7 @@
             if instance.state != "stopped":
                 self.assertInstanceStateWait(instance, "stopped")
 
-        for instance in reservation.instances:
-            instance.terminate()
-        self.cancelResourceCleanUp(rcuk)
+        self._terminate_reservation(reservation, rcuk)
 
     def test_run_stop_terminate_instance_with_tags(self):
         # EC2 run, stop and terminate instance with tags
@@ -188,9 +186,7 @@
             if instance.state != "stopped":
                 self.assertInstanceStateWait(instance, "stopped")
 
-        for instance in reservation.instances:
-            instance.terminate()
-        self.cancelResourceCleanUp(rcuk)
+        self._terminate_reservation(reservation, rcuk)
 
     def test_run_terminate_instance(self):
         # EC2 run, terminate immediately
@@ -202,18 +198,7 @@
 
         for instance in reservation.instances:
             instance.terminate()
-        try:
-            instance.update(validate=True)
-        except ValueError:
-            pass
-        except exception.EC2ResponseError as exc:
-            if self.ec2_error_code.\
-                client.InvalidInstanceID.NotFound.match(exc) is None:
-                pass
-            else:
-                raise
-        else:
-            self.assertNotEqual(instance.state, "running")
+        self.assertInstanceStateWait(instance, '_GONE')
 
     def test_compute_with_volumes(self):
         # EC2 1. integration test (not strict)
@@ -321,8 +306,7 @@
 
         volume.detach()
 
-        self.assertVolumeStatusWait(_volume_state, "available")
-        wait.re_search_wait(_volume_state, "available")
+        self.assertVolumeStatusWait(volume, "available")
 
         wait.state_wait(_part_state, 'DECREASE')
 
diff --git a/tempest/thirdparty/boto/test_ec2_keys.py b/tempest/thirdparty/boto/test_ec2_keys.py
index 698e3e1..c3e1e2a 100644
--- a/tempest/thirdparty/boto/test_ec2_keys.py
+++ b/tempest/thirdparty/boto/test_ec2_keys.py
@@ -26,8 +26,8 @@
 class EC2KeysTest(boto_test.BotoTestCase):
 
     @classmethod
-    def setUpClass(cls):
-        super(EC2KeysTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(EC2KeysTest, cls).resource_setup()
         cls.client = cls.os.ec2api_client
         cls.ec = cls.ec2_error_code
 
diff --git a/tempest/thirdparty/boto/test_ec2_network.py b/tempest/thirdparty/boto/test_ec2_network.py
index 792dde3..132a5a8 100644
--- a/tempest/thirdparty/boto/test_ec2_network.py
+++ b/tempest/thirdparty/boto/test_ec2_network.py
@@ -13,30 +13,30 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest import test
 from tempest.thirdparty.boto import test as boto_test
 
 
 class EC2NetworkTest(boto_test.BotoTestCase):
 
     @classmethod
-    def setUpClass(cls):
-        super(EC2NetworkTest, cls).setUpClass()
-        cls.client = cls.os.ec2api_client
+    def resource_setup(cls):
+        super(EC2NetworkTest, cls).resource_setup()
+        cls.ec2_client = cls.os.ec2api_client
 
     # Note(afazekas): these tests for things duable without an instance
-    @test.skip_because(bug="1080406")
     def test_disassociate_not_associated_floating_ip(self):
         # EC2 disassociate not associated floating ip
         ec2_codes = self.ec2_error_code
-        address = self.client.allocate_address()
+        address = self.ec2_client.allocate_address()
         public_ip = address.public_ip
-        rcuk = self.addResourceCleanUp(self.client.release_address, public_ip)
-        addresses_get = self.client.get_all_addresses(addresses=(public_ip,))
+        rcuk = self.addResourceCleanUp(self.ec2_client.release_address,
+                                       public_ip)
+        addresses_get = self.ec2_client.get_all_addresses(
+            addresses=(public_ip,))
         self.assertEqual(len(addresses_get), 1)
         self.assertEqual(addresses_get[0].public_ip, public_ip)
         self.assertBotoError(ec2_codes.client.InvalidAssociationID.NotFound,
                              address.disassociate)
-        self.client.release_address(public_ip)
-        self.cancelResourceCleanUp(rcuk)
+        self.ec2_client.release_address(public_ip)
         self.assertAddressReleasedWait(address)
+        self.cancelResourceCleanUp(rcuk)
diff --git a/tempest/thirdparty/boto/test_ec2_security_groups.py b/tempest/thirdparty/boto/test_ec2_security_groups.py
index 7d9bdab..fb3d32b 100644
--- a/tempest/thirdparty/boto/test_ec2_security_groups.py
+++ b/tempest/thirdparty/boto/test_ec2_security_groups.py
@@ -20,8 +20,8 @@
 class EC2SecurityGroupTest(boto_test.BotoTestCase):
 
     @classmethod
-    def setUpClass(cls):
-        super(EC2SecurityGroupTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(EC2SecurityGroupTest, cls).resource_setup()
         cls.client = cls.os.ec2api_client
 
     def test_create_authorize_security_group(self):
diff --git a/tempest/thirdparty/boto/test_ec2_volumes.py b/tempest/thirdparty/boto/test_ec2_volumes.py
index b50c6b0..9cee8a4 100644
--- a/tempest/thirdparty/boto/test_ec2_volumes.py
+++ b/tempest/thirdparty/boto/test_ec2_volumes.py
@@ -29,8 +29,8 @@
 class EC2VolumesTest(boto_test.BotoTestCase):
 
     @classmethod
-    def setUpClass(cls):
-        super(EC2VolumesTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(EC2VolumesTest, cls).resource_setup()
 
         if not CONF.service_available.cinder:
             skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
diff --git a/tempest/thirdparty/boto/test_s3_buckets.py b/tempest/thirdparty/boto/test_s3_buckets.py
index 3a8dc89..342fc0e 100644
--- a/tempest/thirdparty/boto/test_s3_buckets.py
+++ b/tempest/thirdparty/boto/test_s3_buckets.py
@@ -14,18 +14,16 @@
 #    under the License.
 
 from tempest.common.utils import data_utils
-from tempest import test
 from tempest.thirdparty.boto import test as boto_test
 
 
 class S3BucketsTest(boto_test.BotoTestCase):
 
     @classmethod
-    def setUpClass(cls):
-        super(S3BucketsTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(S3BucketsTest, cls).resource_setup()
         cls.client = cls.os.s3_client
 
-    @test.skip_because(bug="1076965")
     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 389e25c..f5dec95 100644
--- a/tempest/thirdparty/boto/test_s3_ec2_images.py
+++ b/tempest/thirdparty/boto/test_s3_ec2_images.py
@@ -26,8 +26,8 @@
 class S3ImagesTest(boto_test.BotoTestCase):
 
     @classmethod
-    def setUpClass(cls):
-        super(S3ImagesTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(S3ImagesTest, cls).resource_setup()
         if not cls.conclusion['A_I_IMAGES_READY']:
             raise cls.skipException("".join(("EC2 ", cls.__name__,
                                     ": requires ami/aki/ari manifest")))
diff --git a/tempest/thirdparty/boto/test_s3_objects.py b/tempest/thirdparty/boto/test_s3_objects.py
index db3c1cf..43774c2 100644
--- a/tempest/thirdparty/boto/test_s3_objects.py
+++ b/tempest/thirdparty/boto/test_s3_objects.py
@@ -24,8 +24,8 @@
 class S3BucketsTest(boto_test.BotoTestCase):
 
     @classmethod
-    def setUpClass(cls):
-        super(S3BucketsTest, cls).setUpClass()
+    def resource_setup(cls):
+        super(S3BucketsTest, cls).resource_setup()
         cls.client = cls.os.s3_client
 
     def test_create_get_delete_object(self):
diff --git a/test-requirements.txt b/test-requirements.txt
index cd8154b..6eefeee 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,10 +1,13 @@
+# The order of packages is significant, because pip processes them in the order
+# of appearance. Changing the order has an impact on the overall integration
+# process, which may cause wedges in the gate later.
 hacking>=0.9.2,<0.10
 # needed for doc build
-sphinx>=1.1.2,!=1.2.0,<1.3
+sphinx>=1.1.2,!=1.2.0,!=1.3b1,<1.3
 python-subunit>=0.0.18
-oslosphinx
+oslosphinx>=2.2.0  # Apache-2.0
 mox>=0.5.3
 mock>=1.0
 coverage>=3.6
-oslotest
-stevedore>=0.14
+oslotest>=1.2.0  # Apache-2.0
+stevedore>=1.1.0  # Apache-2.0
diff --git a/tools/check_logs.py b/tools/check_logs.py
index 917aaaf..c8d3a1a 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -31,7 +31,7 @@
 is_grenade = os.environ.get('DEVSTACK_GATE_GRENADE') is not None
 dump_all_errors = True
 
-# As logs are made clean, add to this set
+# As logs are made clean, remove from this set
 allowed_dirty = set([
     'c-api',
     'ceilometer-acentral',
@@ -80,7 +80,6 @@
 
 def scan_content(name, content, regexp, whitelist):
     had_errors = False
-    print_log_name = True
     for line in content:
         if not line.startswith("Stderr:") and regexp.match(line):
             whitelisted = False
@@ -91,13 +90,8 @@
                     whitelisted = True
                     break
             if not whitelisted or dump_all_errors:
-                if print_log_name:
-                    print("\nLog File Has Errors: %s" % name)
-                    print_log_name = False
                 if not whitelisted:
                     had_errors = True
-                    print("*** Not Whitelisted ***"),
-                print(line.rstrip())
     return had_errors
 
 
@@ -151,17 +145,21 @@
             whitelists = loaded
     logs_with_errors = process_files(files_to_process, urls_to_process,
                                      whitelists)
-    if logs_with_errors:
-        print("Logs have errors")
-    if is_grenade:
-        print("Currently not failing grenade runs with errors")
-        return 0
+
     failed = False
-    for log in logs_with_errors:
-        if log not in allowed_dirty:
-            print("Log: %s not allowed to have ERRORS or TRACES" % log)
-            failed = True
+    if logs_with_errors:
+        log_files = set(logs_with_errors)
+        for log in log_files:
+            msg = '%s log file has errors' % log
+            if log not in allowed_dirty:
+                msg += ' and is not allowed to have them'
+                failed = True
+            print(msg)
+        print("\nPlease check the respective log files to see the errors")
     if failed:
+        if is_grenade:
+            print("Currently not failing grenade runs with errors")
+            return 0
         return 1
     print("ok")
     return 0
diff --git a/tools/config/check_uptodate.sh b/tools/config/check_uptodate.sh
index 0f0d77e..7b08695 100755
--- a/tools/config/check_uptodate.sh
+++ b/tools/config/check_uptodate.sh
@@ -15,7 +15,7 @@
 TEMPDIR=`mktemp -d /tmp/${PROJECT_NAME}.XXXXXX`
 trap "rm -rf $TEMPDIR" EXIT
 
-tools/config/generate_sample.sh -b ./ -p ${PROJECT_NAME} -o ${TEMPDIR}
+oslo-config-generator --config-file tools/config/config-generator.tempest.conf --output-file ${TEMPDIR}/${CFGFILE_NAME}
 if [ $? != 0 ]
 then
     exit 1
@@ -24,6 +24,6 @@
 if ! diff -u ${TEMPDIR}/${CFGFILE_NAME} ${CFGFILE}
 then
    echo "${0##*/}: ${PROJECT_NAME}.conf.sample is not up to date."
-   echo "${0##*/}: Please run ${0%%${0##*/}}generate_sample.sh."
+   echo "${0##*/}: Please run tox -egenconfig."
    exit 1
 fi
diff --git a/tools/config/config-generator.tempest.conf b/tools/config/config-generator.tempest.conf
new file mode 100644
index 0000000..e5a02f8
--- /dev/null
+++ b/tools/config/config-generator.tempest.conf
@@ -0,0 +1,3 @@
+[DEFAULT]
+output_file = etc/tempest.conf.sample
+namespace = tempest.config
diff --git a/tools/config/generate_sample.sh b/tools/config/generate_sample.sh
deleted file mode 100755
index d22b2f0..0000000
--- a/tools/config/generate_sample.sh
+++ /dev/null
@@ -1,138 +0,0 @@
-#!/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
-}
-
-PARSED_OPTIONS=$(getopt -n "${0##*/}" -o hb:p:m:l:o: \
-                 --long help,base-dir:,package-name:,output-dir:,module:,library: -- "$@")
-
-if [ $? != 0 ] ; then print_hint ; exit 1 ; fi
-
-eval set -- "$PARSED_OPTIONS"
-
-while true; do
-    case "$1" in
-        -h|--help)
-            echo "${0##*/} [options]"
-            echo ""
-            echo "options:"
-            echo "-h, --help                show brief help"
-            echo "-b, --base-dir=DIR        project base directory"
-            echo "-p, --package-name=NAME   project package name"
-            echo "-o, --output-dir=DIR      file output directory"
-            echo "-m, --module=MOD          extra python module to interrogate for options"
-            echo "-l, --library=LIB         extra library that registers options for discovery"
-            exit 0
-            ;;
-        -b|--base-dir)
-            shift
-            BASEDIR=`echo $1 | sed -e 's/\/*$//g'`
-            shift
-            ;;
-        -p|--package-name)
-            shift
-            PACKAGENAME=`echo $1`
-            shift
-            ;;
-        -o|--output-dir)
-            shift
-            OUTPUTDIR=`echo $1 | sed -e 's/\/*$//g'`
-            shift
-            ;;
-        -m|--module)
-            shift
-            MODULES="$MODULES -m $1"
-            shift
-            ;;
-        -l|--library)
-            shift
-            LIBRARIES="$LIBRARIES -l $1"
-            shift
-            ;;
-        --)
-            break
-            ;;
-    esac
-done
-
-BASEDIR=${BASEDIR:-`pwd`}
-if ! [ -d $BASEDIR ]
-then
-    echo "${0##*/}: missing project base directory" >&2 ; print_hint ; exit 1
-elif [[ $BASEDIR != /* ]]
-then
-    BASEDIR=$(cd "$BASEDIR" && pwd)
-fi
-
-PACKAGENAME=${PACKAGENAME:-$(python setup.py --name)}
-TARGETDIR=$BASEDIR/$PACKAGENAME
-if ! [ -d $TARGETDIR ]
-then
-    echo "${0##*/}: invalid project package name" >&2 ; print_hint ; exit 1
-fi
-
-OUTPUTDIR=${OUTPUTDIR:-$BASEDIR/etc}
-# NOTE(bnemec): Some projects put their sample config in etc/,
-#               some in etc/$PACKAGENAME/
-if [ -d $OUTPUTDIR/$PACKAGENAME ]
-then
-    OUTPUTDIR=$OUTPUTDIR/$PACKAGENAME
-elif ! [ -d $OUTPUTDIR ]
-then
-    echo "${0##*/}: cannot access \`$OUTPUTDIR': No such file or directory" >&2
-    exit 1
-fi
-
-BASEDIRESC=`echo $BASEDIR | sed -e 's/\//\\\\\//g'`
-find $TARGETDIR -type f -name "*.pyc" -delete
-FILES=$(find $TARGETDIR -type f -name "*.py" ! -path "*/tests/*" \
-        -exec grep -l "Opt(" {} + | sed -e "s/^$BASEDIRESC\///g" | sort -u)
-
-RC_FILE="`dirname $0`/oslo.config.generator.rc"
-if test -r "$RC_FILE"
-then
-    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
-
-for lib in ${TEMPEST_CONFIG_GENERATOR_EXTRA_LIBRARIES}; do
-    LIBRARIES="$LIBRARIES -l $lib"
-done
-
-export EVENTLET_NO_GREENDNS=yes
-
-OS_VARS=$(set | sed -n '/^OS_/s/=[^=]*$//gp' | xargs)
-[ "$OS_VARS" ] && eval "unset \$OS_VARS"
-DEFAULT_MODULEPATH=tempest.openstack.common.config.generator
-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)
-for CONCAT_FILE in $CONCAT_FILES; do
-    cat $CONCAT_FILE >> $OUTPUTFILE
-done
diff --git a/tools/config/oslo.config.generator.rc b/tools/config/oslo.config.generator.rc
deleted file mode 100644
index 303e156..0000000
--- a/tools/config/oslo.config.generator.rc
+++ /dev/null
@@ -1 +0,0 @@
-MODULEPATH=tempest.common.generate_sample_tempest
diff --git a/tools/pretty_tox.sh b/tools/pretty_tox.sh
index 0a04ce6..ff554c5 100755
--- a/tools/pretty_tox.sh
+++ b/tools/pretty_tox.sh
@@ -3,4 +3,4 @@
 set -o pipefail
 
 TESTRARGS=$1
-python setup.py testr --slowest --testr-args="--subunit $TESTRARGS" | $(dirname $0)/subunit-trace.py --no-failure-debug -f
+python setup.py testr --slowest --testr-args="--subunit $TESTRARGS" | subunit-trace --no-failure-debug -f
diff --git a/tools/pretty_tox_serial.sh b/tools/pretty_tox_serial.sh
index db70890..e0fca0f 100755
--- a/tools/pretty_tox_serial.sh
+++ b/tools/pretty_tox_serial.sh
@@ -7,7 +7,7 @@
 if [ ! -d .testrepository ]; then
     testr init
 fi
-testr run --subunit $TESTRARGS | $(dirname $0)/subunit-trace.py -f -n
+testr run --subunit $TESTRARGS | subunit-trace -f -n
 retval=$?
 testr slowest
 
diff --git a/tools/subunit-trace.py b/tools/subunit-trace.py
deleted file mode 100755
index 8ad59bb..0000000
--- a/tools/subunit-trace.py
+++ /dev/null
@@ -1,295 +0,0 @@
-#!/usr/bin/env python
-
-# Copyright 2014 Hewlett-Packard Development Company, L.P.
-# Copyright 2014 Samsung Electronics
-# 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.
-
-"""Trace a subunit stream in reasonable detail and high accuracy."""
-
-import argparse
-import functools
-import re
-import sys
-
-import mimeparse
-import subunit
-import testtools
-
-DAY_SECONDS = 60 * 60 * 24
-FAILS = []
-RESULTS = {}
-
-
-class Starts(testtools.StreamResult):
-
-    def __init__(self, output):
-        super(Starts, self).__init__()
-        self._output = output
-
-    def startTestRun(self):
-        self._neednewline = False
-        self._emitted = set()
-
-    def status(self, test_id=None, test_status=None, test_tags=None,
-               runnable=True, file_name=None, file_bytes=None, eof=False,
-               mime_type=None, route_code=None, timestamp=None):
-        super(Starts, self).status(
-            test_id, test_status,
-            test_tags=test_tags, runnable=runnable, file_name=file_name,
-            file_bytes=file_bytes, eof=eof, mime_type=mime_type,
-            route_code=route_code, timestamp=timestamp)
-        if not test_id:
-            if not file_bytes:
-                return
-            if not mime_type or mime_type == 'test/plain;charset=utf8':
-                mime_type = 'text/plain; charset=utf-8'
-            primary, sub, parameters = mimeparse.parse_mime_type(mime_type)
-            content_type = testtools.content_type.ContentType(
-                primary, sub, parameters)
-            content = testtools.content.Content(
-                content_type, lambda: [file_bytes])
-            text = content.as_text()
-            if text and text[-1] not in '\r\n':
-                self._neednewline = True
-            self._output.write(text)
-        elif test_status == 'inprogress' and test_id not in self._emitted:
-            if self._neednewline:
-                self._neednewline = False
-                self._output.write('\n')
-            worker = ''
-            for tag in test_tags or ():
-                if tag.startswith('worker-'):
-                    worker = '(' + tag[7:] + ') '
-            if timestamp:
-                timestr = timestamp.isoformat()
-            else:
-                timestr = ''
-                self._output.write('%s: %s%s [start]\n' %
-                                   (timestr, worker, test_id))
-            self._emitted.add(test_id)
-
-
-def cleanup_test_name(name, strip_tags=True, strip_scenarios=False):
-    """Clean up the test name for display.
-
-    By default we strip out the tags in the test because they don't help us
-    in identifying the test that is run to it's result.
-
-    Make it possible to strip out the testscenarios information (not to
-    be confused with tempest scenarios) however that's often needed to
-    indentify generated negative tests.
-    """
-    if strip_tags:
-        tags_start = name.find('[')
-        tags_end = name.find(']')
-        if tags_start > 0 and tags_end > tags_start:
-            newname = name[:tags_start]
-            newname += name[tags_end + 1:]
-            name = newname
-
-    if strip_scenarios:
-        tags_start = name.find('(')
-        tags_end = name.find(')')
-        if tags_start > 0 and tags_end > tags_start:
-            newname = name[:tags_start]
-            newname += name[tags_end + 1:]
-            name = newname
-
-    return name
-
-
-def get_duration(timestamps):
-    start, end = timestamps
-    if not start or not end:
-        duration = ''
-    else:
-        delta = end - start
-        duration = '%d.%06ds' % (
-            delta.days * DAY_SECONDS + delta.seconds, delta.microseconds)
-    return duration
-
-
-def find_worker(test):
-    for tag in test['tags']:
-        if tag.startswith('worker-'):
-            return int(tag[7:])
-    return 'NaN'
-
-
-# Print out stdout/stderr if it exists, always
-def print_attachments(stream, test, all_channels=False):
-    """Print out subunit attachments.
-
-    Print out subunit attachments that contain content. This
-    runs in 2 modes, one for successes where we print out just stdout
-    and stderr, and an override that dumps all the attachments.
-    """
-    channels = ('stdout', 'stderr')
-    for name, detail in test['details'].items():
-        # NOTE(sdague): the subunit names are a little crazy, and actually
-        # are in the form pythonlogging:'' (with the colon and quotes)
-        name = name.split(':')[0]
-        if detail.content_type.type == 'test':
-            detail.content_type.type = 'text'
-        if (all_channels or name in channels) and detail.as_text():
-            title = "Captured %s:" % name
-            stream.write("\n%s\n%s\n" % (title, ('~' * len(title))))
-            # indent attachment lines 4 spaces to make them visually
-            # offset
-            for line in detail.as_text().split('\n'):
-                stream.write("    %s\n" % line)
-
-
-def show_outcome(stream, test, print_failures=False):
-    global RESULTS
-    status = test['status']
-    # TODO(sdague): ask lifeless why on this?
-    if status == 'exists':
-        return
-
-    worker = find_worker(test)
-    name = cleanup_test_name(test['id'])
-    duration = get_duration(test['timestamps'])
-
-    if worker not in RESULTS:
-        RESULTS[worker] = []
-    RESULTS[worker].append(test)
-
-    # don't count the end of the return code as a fail
-    if name == 'process-returncode':
-        return
-
-    if status == 'success':
-        stream.write('{%s} %s [%s] ... ok\n' % (
-            worker, name, duration))
-        print_attachments(stream, test)
-    elif status == 'fail':
-        FAILS.append(test)
-        stream.write('{%s} %s [%s] ... FAILED\n' % (
-            worker, name, duration))
-        if not print_failures:
-            print_attachments(stream, test, all_channels=True)
-    elif status == 'skip':
-        stream.write('{%s} %s ... SKIPPED: %s\n' % (
-            worker, name, test['details']['reason'].as_text()))
-    else:
-        stream.write('{%s} %s [%s] ... %s\n' % (
-            worker, name, duration, test['status']))
-        if not print_failures:
-            print_attachments(stream, test, all_channels=True)
-
-    stream.flush()
-
-
-def print_fails(stream):
-    """Print summary failure report.
-
-    Currently unused, however there remains debate on inline vs. at end
-    reporting, so leave the utility function for later use.
-    """
-    if not FAILS:
-        return
-    stream.write("\n==============================\n")
-    stream.write("Failed %s tests - output below:" % len(FAILS))
-    stream.write("\n==============================\n")
-    for f in FAILS:
-        stream.write("\n%s\n" % f['id'])
-        stream.write("%s\n" % ('-' * len(f['id'])))
-        print_attachments(stream, f, all_channels=True)
-    stream.write('\n')
-
-
-def count_tests(key, value):
-    count = 0
-    for k, v in RESULTS.items():
-        for item in v:
-            if key in item:
-                if re.search(value, item[key]):
-                    count += 1
-    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)
-    delta = tests[-1]['timestamps'][1] - tests[0]['timestamps'][0]
-    return num_tests, delta
-
-
-def print_summary(stream):
-    stream.write("\n======\nTotals\n======\n")
-    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'))
-
-    # we could have no results, especially as we filter out the process-codes
-    if RESULTS:
-        stream.write("\n==============\nWorker Balance\n==============\n")
-
-        for w in range(max(RESULTS.keys()) + 1):
-            if w not in RESULTS:
-                stream.write(
-                    " - WARNING: missing Worker %s! "
-                    "Race in testr accounting.\n" % w)
-            else:
-                num, time = worker_stats(w)
-                stream.write(" - Worker %s (%s tests) => %ss\n" %
-                             (w, num, time))
-
-
-def parse_args():
-    parser = argparse.ArgumentParser()
-    parser.add_argument('--no-failure-debug', '-n', action='store_true',
-                        dest='print_failures', help='Disable printing failure '
-                        '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')
-    return parser.parse_args()
-
-
-def main():
-    args = parse_args()
-    stream = subunit.ByteStreamToStreamResult(
-        sys.stdin, non_subunit_name='stdout')
-    starts = Starts(sys.stdout)
-    outcomes = testtools.StreamToDict(
-        functools.partial(show_outcome, sys.stdout,
-                          print_failures=args.print_failures))
-    summary = testtools.StreamSummary()
-    result = testtools.CopyStreamResult([starts, outcomes, summary])
-    result.startTestRun()
-    try:
-        stream.run(result)
-    finally:
-        result.stopTestRun()
-    if args.post_fails:
-        print_fails(sys.stdout)
-    print_summary(sys.stdout)
-    return (0 if summary.wasSuccessful() else 1)
-
-
-if __name__ == '__main__':
-    sys.exit(main())
diff --git a/tox.ini b/tox.ini
index a071d4b..f75e868 100644
--- a/tox.ini
+++ b/tox.ini
@@ -3,75 +3,83 @@
 minversion = 1.6
 skipsdist = True
 
-[testenv]
+[tempestenv]
+sitepackages = True
 setenv = VIRTUAL_ENV={envdir}
          OS_TEST_PATH=./tempest/test_discover
-         PYTHONHASHSEED=0
+deps = -r{toxinidir}/requirements.txt
+
+[testenv]
+setenv = VIRTUAL_ENV={envdir}
+         OS_TEST_PATH=./tempest/tests
 usedevelop = True
 install_command = pip install -U {opts} {packages}
+whitelist_externals = *
+deps = -r{toxinidir}/requirements.txt
+       -r{toxinidir}/test-requirements.txt
+commands = bash tools/pretty_tox.sh '{posargs}'
 
-[testenv:py26]
-setenv = OS_TEST_PATH=./tempest/tests
-         PYTHONHASHSEED=0
-commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
-
-[testenv:py33]
-setenv = OS_TEST_PATH=./tempest/tests
-         PYTHONHASHSEED=0
-commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
-
-[testenv:py27]
-setenv = OS_TEST_PATH=./tempest/tests
-         PYTHONHASHSEED=0
-commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
+[testenv:genconfig]
+commands = oslo-config-generator --config-file tools/config/config-generator.tempest.conf
 
 [testenv:cover]
 setenv = OS_TEST_PATH=./tempest/tests
-         PYTHONHASHSEED=0
 commands = python setup.py testr --coverage --testr-arg='tempest\.tests {posargs}'
 
 [testenv:all]
-sitepackages = True
+sitepackages = {[tempestenv]sitepackages}
+# 'all' includes slow tests
+setenv = {[tempestenv]setenv}
+         OS_TEST_TIMEOUT=1200
+deps = {[tempestenv]deps}
 commands =
   bash tools/pretty_tox.sh '{posargs}'
 
 [testenv:full]
-sitepackages = True
+sitepackages = {[tempestenv]sitepackages}
+setenv = {[tempestenv]setenv}
+deps = {[tempestenv]deps}
 # The regex below is used to select which tests to run and exclude the slow tag:
 # See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
 commands =
   bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
 
 [testenv:full-serial]
+sitepackages = {[tempestenv]sitepackages}
+setenv = {[tempestenv]setenv}
+deps = {[tempestenv]deps}
 # The regex below is used to select which tests to run and exclude the slow tag:
 # See the testrepostiory bug: https://bugs.launchpad.net/testrepository/+bug/1208610
 commands =
   bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
 
-[testenv:testr-full]
-sitepackages = True
-commands =
-  bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])(^tempest\.(api|scenario|thirdparty|cli)) {posargs}'
-
 [testenv:heat-slow]
-sitepackages = True
-setenv = OS_TEST_TIMEOUT=1200
+sitepackages = {[tempestenv]sitepackages}
+setenv = {[tempestenv]setenv}
+         OS_TEST_TIMEOUT=1200
+deps = {[tempestenv]deps}
 # The regex below is used to select heat api/scenario tests tagged as slow.
 commands =
   bash tools/pretty_tox.sh '(?=.*\[.*\bslow\b.*\])(^tempest\.(api|scenario)\.orchestration) {posargs}'
 
 [testenv:large-ops]
-sitepackages = True
+sitepackages = {[tempestenv]sitepackages}
+setenv = {[tempestenv]setenv}
+deps = {[tempestenv]deps}
 commands =
   python setup.py testr --slowest --testr-args='tempest.scenario.test_large_ops {posargs}'
 
 [testenv:smoke]
-sitepackages = True
+sitepackages = {[tempestenv]sitepackages}
+setenv = {[tempestenv]setenv}
+deps = {[tempestenv]deps}
 commands =
    bash tools/pretty_tox.sh '(?!.*\[.*\bslow\b.*\])((smoke)|(^tempest\.scenario)) {posargs}'
 
 [testenv:smoke-serial]
-sitepackages = True
+sitepackages = {[tempestenv]sitepackages}
+setenv = {[tempestenv]setenv}
+deps = {[tempestenv]deps}
 # This is still serial because neutron doesn't work with parallel. See:
 # https://bugs.launchpad.net/tempest/+bug/1216076 so the neutron smoke
 # job would fail if we moved it to parallel.
@@ -79,28 +87,23 @@
    bash tools/pretty_tox_serial.sh '(?!.*\[.*\bslow\b.*\])((smoke)|(^tempest\.scenario)) {posargs}'
 
 [testenv:stress]
-sitepackages = True
+sitepackages = {[tempestenv]sitepackages}
+setenv = {[tempestenv]setenv}
+deps = {[tempestenv]deps}
 commands =
-    run-tempest-stress -a -d 3600 -S
+    run-tempest-stress {posargs}
 
 [testenv:venv]
 commands = {posargs}
-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]
 commands =
    flake8 {posargs}
    {toxinidir}/tools/config/check_uptodate.sh
 
-deps = -r{toxinidir}/requirements.txt
-       -r{toxinidir}/test-requirements.txt
-
 [hacking]
 local-check-factory = tempest.hacking.checks.factory
 import_exceptions = tempest.services