Merge "Cinder volume type access tests"
diff --git a/HACKING.rst b/HACKING.rst
index 480650c..432db7d 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -160,11 +160,17 @@
 
 Negative Tests
 --------------
-TODO: Write the guideline related to negative tests.
+Error handling is an important aspect of API design and usage. Negative
+tests are a way to ensure that an application can gracefully handle
+invalid or unexpected input. However, as a black box integration test
+suite, Tempest is not suitable for handling all negative test cases, as
+the wide variety and complexity of negative tests can lead to long test
+runs and knowledge of internal implementation details. The bulk of
+negative testing should be handled with project function tests. The
+exception to this rule is API tests used for interoperability testing.
 
 Test skips because of Known Bugs
 --------------------------------
-
 If a test is broken because of a bug it is appropriate to skip the test until
 bug has been fixed. You should use the skip_because decorator so that
 Tempest's skip tracking tool can watch the bug status.
diff --git a/REVIEWING.rst b/REVIEWING.rst
index bd6018d..676a217 100644
--- a/REVIEWING.rst
+++ b/REVIEWING.rst
@@ -72,6 +72,19 @@
 scenario tests this is up to the reviewers discretion whether a docstring is
 required or not.
 
+Release Notes
+-------------
+Release notes are how we indicate to users and other consumers of Tempest what
+has changed in a given release. Since Tempest 10.0.0 we've been using `reno`_
+to manage and build the release notes. There are certain types of changes that
+require release notes and we should not approve them without including a release
+note. These include but aren't limited to, any addition, deprecation or removal
+from the lib interface, any change to configuration options (including
+deprecation), CLI additions or deprecations, major feature additions, and
+anything backwards incompatible or would require a user to take note or do
+something extra.
+
+.. _reno: http://docs.openstack.org/developer/reno/
 
 When to approve
 ---------------
diff --git a/doc/source/conf.py b/doc/source/conf.py
index c2df0b6..eef3620 100644
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -34,7 +34,7 @@
               'oslo_config.sphinxconfiggen',
              ]
 
-config_generator_config_file = '../../etc/config-generator.tempest.conf'
+config_generator_config_file = '../../tempest/cmd/config-generator.tempest.conf'
 sample_config_basename = '_static/tempest'
 
 todo_include_todos = True
diff --git a/doc/source/index.rst b/doc/source/index.rst
index c73fac3..60ff46b 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -14,6 +14,7 @@
    plugin-registry
    library
    microversion_testing
+   test-removal
 
 ------------
 Field Guides
@@ -51,6 +52,7 @@
    account_generator
    cleanup
    javelin
+   subunit_describe_calls
    workspace
    run
 
diff --git a/doc/source/subunit_describe_calls.rst b/doc/source/subunit_describe_calls.rst
new file mode 100644
index 0000000..2bda50c
--- /dev/null
+++ b/doc/source/subunit_describe_calls.rst
@@ -0,0 +1,5 @@
+------------------------------
+Subunit Describe Calls Utility
+------------------------------
+
+.. automodule:: tempest.cmd.subunit_describe_calls
diff --git a/doc/source/test-removal.rst b/doc/source/test-removal.rst
new file mode 100644
index 0000000..6570bb7
--- /dev/null
+++ b/doc/source/test-removal.rst
@@ -0,0 +1,168 @@
+Tempest Test Removal Procedure
+==============================
+
+Historically tempest was the only way of doing functional testing and
+integration testing in OpenStack. This was mostly only an artifact of tempest
+being the only proven pattern for doing this, not an artifact of a design
+decision. However, moving forward as functional testing is being spun up in
+each individual project we really only want tempest to be the integration test
+suite it was intended to be; testing the high level interactions between
+projects through REST API requests. In this model there are probably existing
+tests that aren't the best fit living in tempest. However, since tempest is
+largely still the only gating test suite in this space we can't carelessly rip
+out everything from the tree. This document outlines the procedure which was
+developed to ensure we minimize the risk for removing something of value from
+the tempest tree.
+
+This procedure might seem overly conservative and slow paced, but this is by
+design to try and ensure we don't remove something that is actually providing
+value. Having potential duplication between testing is not a big deal
+especially compared to the alternative of removing something which is actually
+providing value and is actively catching bugs, or blocking incorrect patches
+from landing.
+
+Proposing a test removal
+------------------------
+
+3 prong rule for removal
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+In the proposal etherpad we'll be looking for answers to 3 questions
+
+ #. The tests proposed for removal must have equiv. coverage in a different
+    project's test suite (whether this is another gating test project, or an in
+    tree funcitonal test suite) For API tests preferably the other project will
+    have a similar source of friction in place to prevent breaking api changes
+    so that we don't regress and let breaking api changes slip through the
+    gate.
+ #. The test proposed for removal has a failure rate <  0.50% in the gate over
+    the past release (the value and interval will likely be adjusted in the
+    future)
+ #. There must not be an external user/consumer of tempest that depends on the
+    test proposed for removal
+
+The answers to 1 and 2 are easy to verify. For 1 just provide a link to the new
+test location. If you are linking to the tempest removal patch please also put
+a Depends-On in the commit message for the commit which moved the test into
+another repo.
+
+For prong 2 you can use OpenStack-Health:
+
+Using OpenStack-Health
+""""""""""""""""""""""
+
+Go to: http://status.openstack.org/openstack-health and then navigate to a per
+test page for six months. You'll end up with a page that will graph the success
+and failure rates on the bottom graph. For example, something like `this URL`_.
+
+.. _this URL: http://status.openstack.org/openstack-health/#/test/tempest.scenario.test_volume_boot_pattern.TestVolumeBootPatternV2.test_volume_boot_pattern?groupKey=project&resolutionKey=day&duration=P6M
+
+The Old Way using subunit2sql directly
+""""""""""""""""""""""""""""""""""""""
+
+SELECT * from tests where test_id like "%test_id%";
+(where $test_id is the full test_id, but truncated to the class because of
+setupclass or teardownclass failures)
+
+You can access the infra mysql subunit2sql db w/ read-only permissions with:
+
+ * hostname: logstash.openstack.org
+ * username: query
+ * password: query
+ * db_name: subunit2sql
+
+For example if you were trying to remove the test with the id:
+tempest.api.compute.admin.test_flavors_negative.FlavorsAdminNegativeTestJSON.test_get_flavor_details_for_deleted_flavor
+you would run the following:
+
+ #. run: "mysql -u query -p -h logstash.openstack.org subunit2sql" to connect
+    to the subunit2sql db
+ #. run the query: MySQL [subunit2sql]> select * from tests where test_id like
+    "tempest.api.compute.admin.test_flavors_negative.FlavorsAdminNegativeTestJSON%";
+    which will return a table of all the tests in the class (but it will also
+    catch failures in setupClass and tearDownClass)
+ #. paste the output table with numbers and the mysql command you ran to
+    generate it into the etherpad.
+
+Eventually a cli interface will be created to make that a bit more friendly.
+Also a dashboard is in the works so we don't need to manually run the command.
+
+The intent of the 2nd prong is to verify that moving the test into a project
+specific testing is preventing bugs (assuming the tempest tests were catching
+issues) from bubbling up a layer into tempest jobs. If we're seeing failure
+rates above a certain threshold in the gate checks that means the functional
+testing isn't really being effective in catching that bug (and therefore
+blocking it from landing) and having the testing run in tempest still has
+value.
+
+However for the 3rd prong verification is a bit more subjective. The original
+intent of this prong was mostly for refstack/defcore and also for things that
+running on the stable branches. We don't want to remove any tests if that
+would break our api consistency checking between releases, or something that
+defcore/refstack is depending on being in tempest. It's worth pointing out
+that if a test is used in defcore as part of interop testing then it will
+probably have continuing value being in tempest as part of the
+integration/integrated tests in general. This is one area where some overlap
+is expected between testing in projects and tempest, which is not a bad thing.
+
+Discussing the 3rd prong
+""""""""""""""""""""""""
+
+There are 2 approaches to addressing the 3rd prong. Either it can be raised
+during a qa meeting during the tempest discussion. Please put it on the agenda
+well ahead of the scheduled meeting. Since the meeting time will be well known
+ahead of time anyone who depends on the tests will have ample time beforehand
+to outline any concerns on the before the meeting. To give ample time for
+people to respond to removal proposals please add things to the agend by the
+Monday before the meeting.
+
+The other option is to raise the removal on the openstack-dev mailing list.
+(for example see: http://lists.openstack.org/pipermail/openstack-dev/2016-February/086218.html )
+This will raise the issue to the wider community and attract at least the same
+(most likely more) attention than discussing it during the irc meeting. The
+only downside is that it might take more time to get a response, given the
+nature of ML.
+
+Exceptions to this procedure
+----------------------------
+
+For the most part all tempest test removals have to go through this procedure
+there are a couple of exceptions though:
+
+ #. The class of testing has been decided to be outside the scope of tempest.
+ #. A revert for a patch which added a broken test, or testing which didn't
+    actually run in the gate (basically any revert for something which
+    shouldn't have been added)
+
+For the first exception type the only types of testing in tree which have been
+declared out of scope at this point are:
+
+ * The CLI tests (which should be completely removed at this point)
+ * Neutron Adv. Services testing (which should be completely removed at this
+   point)
+ * XML API Tests (which should be completely removed at this point)
+ * EC2 API/boto tests (which should be completely removed at this point)
+
+For tests that fit into this category the only criteria for removal is that
+there is equivalent testing elsewhere.
+
+Tempest Scope
+^^^^^^^^^^^^^
+
+Also starting in the liberty cycle tempest has defined a set of projects which
+are defined as in scope for direct testing in tempest. As of today that list
+is:
+
+ * Keystone
+ * Nova
+ * Glance
+ * Cinder
+ * Neutron
+ * Swift
+
+anything that lives in tempest which doesn't test one of these projects can be
+removed assuming there is equivalent testing elsewhere. Preferably using the
+`tempest plugin mechanism`_
+to mantain continuity after migrating the tests out of tempest
+
+.. _tempest plugin mechanism: http://docs.openstack.org/developer/tempest/plugin.html
diff --git a/releasenotes/notes/.placeholder b/releasenotes/notes/.placeholder
deleted file mode 100644
index e69de29..0000000
--- a/releasenotes/notes/.placeholder
+++ /dev/null
diff --git a/releasenotes/notes/add_subunit_describe_calls-5498a37e6cd66c4b.yaml b/releasenotes/notes/add_subunit_describe_calls-5498a37e6cd66c4b.yaml
new file mode 100644
index 0000000..b457ddd
--- /dev/null
+++ b/releasenotes/notes/add_subunit_describe_calls-5498a37e6cd66c4b.yaml
@@ -0,0 +1,4 @@
+---
+features:
+  - Adds subunit-describe-calls. A parser for subunit streams to determine what
+    REST API calls are made inside of a test and in what order they are called.
diff --git a/releasenotes/notes/image-clients-as-library-86d17caa26ce3961.yaml b/releasenotes/notes/image-clients-as-library-86d17caa26ce3961.yaml
index 90a5056..1fa4ddd 100644
--- a/releasenotes/notes/image-clients-as-library-86d17caa26ce3961.yaml
+++ b/releasenotes/notes/image-clients-as-library-86d17caa26ce3961.yaml
@@ -7,6 +7,7 @@
     without any maintenance changes.
 
       * image_members_client(v1)
+      * images_client(v1)
       * image_members_client(v2)
       * images_client(v2)
       * namespaces_client(v2)
diff --git a/releasenotes/notes/remove-input-scenarios-functionality-01308e6d4307f580.yaml b/releasenotes/notes/remove-input-scenarios-functionality-01308e6d4307f580.yaml
new file mode 100644
index 0000000..4ee883f
--- /dev/null
+++ b/releasenotes/notes/remove-input-scenarios-functionality-01308e6d4307f580.yaml
@@ -0,0 +1,11 @@
+---
+upgrade:
+  - The input scenarios functionality no longer exists in tempest. This caused
+    a large number of issues for limited benefit and was only used by a single
+    test, test_server_basic_ops. If you were using this functionality you'll
+    now have to do it manually with a script and/or tempest workspaces
+deprecations:
+  - All the options in the input-scenario group are now deprecated. These were
+    only used in tree by the now removed input scenarios functionality in
+    test_server_basic_ops. They were only deprecated because there could be
+    external consumers via plugins. They will be removed during the Ocata cycle.
diff --git a/releasenotes/notes/remove-trove-tests-666522e9113549f9.yaml b/releasenotes/notes/remove-trove-tests-666522e9113549f9.yaml
new file mode 100644
index 0000000..1157a4f
--- /dev/null
+++ b/releasenotes/notes/remove-trove-tests-666522e9113549f9.yaml
@@ -0,0 +1,4 @@
+---
+upgrade:
+  - All tests for the Trove project have been removed from tempest. They now
+    live as a tempest plugin in the the trove project.
diff --git a/releasenotes/notes/tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml b/releasenotes/notes/tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml
new file mode 100644
index 0000000..eeda921
--- /dev/null
+++ b/releasenotes/notes/tempest-init-global-config-dir-location-changes-12260255871d3a2b.yaml
@@ -0,0 +1,12 @@
+---
+upgrade:
+  - The location on disk that the *tempest init* command looks for has changed.
+    Previously it would attempt to use python packaging's data files to guess
+    where setuptools/distutils were installing data files, which was incredibly
+    unreliable and depended on how you installed tempest and which versions of
+    setuptools, distutils, and python you had installed. Instead, now it will
+    use either /etc/tempest, $XDG_CONFIG_PATH/.config/tempest, or
+    ~/.tempest/etc (attempted in that order). If none of these exist it will
+    create an empty ~/.tempest/etc directory. If you were relying on the
+    previous behavior and none of these directories were being used you will
+    need to move the files to live in one of these directories.
diff --git a/setup.cfg b/setup.cfg
index 66a8743..2a3000d 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -34,6 +34,7 @@
     tempest = tempest.cmd.main:main
     skip-tracker = tempest.lib.cmd.skip_tracker:main
     check-uuid = tempest.lib.cmd.check_uuid:run
+    subunit-describe-calls = tempest.cmd.subunit_describe_calls:entry_point
 tempest.cm =
     account-generator = tempest.cmd.account_generator:TempestAccountGenerator
     init = tempest.cmd.init:TempestInit
diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py
index 427a748..6f80730 100644
--- a/tempest/api/compute/images/test_image_metadata.py
+++ b/tempest/api/compute/images/test_image_metadata.py
@@ -16,6 +16,7 @@
 import six
 
 from tempest.api.compute import base
+from tempest.common import image as common_image
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
@@ -55,15 +56,18 @@
         super(ImagesMetadataTestJSON, cls).resource_setup()
         cls.image_id = None
 
-        name = data_utils.rand_name('image')
+        params = {
+            'name': data_utils.rand_name('image'),
+            'container_format': 'bare',
+            'disk_format': 'raw'
+        }
         if CONF.image_feature_enabled.api_v1:
-            kwargs = dict(is_public=False)
+            params.update({'is_public': False})
+            params = {'headers': common_image.image_meta_to_headers(**params)}
         else:
-            kwargs = dict(visibility='private')
-        body = cls.glance_client.create_image(name=name,
-                                              container_format='bare',
-                                              disk_format='raw',
-                                              **kwargs)
+            params.update({'visibility': 'private'})
+
+        body = cls.glance_client.create_image(**params)
         body = body['image'] if 'image' in body else body
         cls.image_id = body['id']
         cls.images.append(cls.image_id)
diff --git a/tempest/api/compute/images/test_list_image_filters.py b/tempest/api/compute/images/test_list_image_filters.py
index e74ca67..9017461 100644
--- a/tempest/api/compute/images/test_list_image_filters.py
+++ b/tempest/api/compute/images/test_list_image_filters.py
@@ -19,6 +19,7 @@
 import testtools
 
 from tempest.api.compute import base
+from tempest.common import image as common_image
 from tempest.common.utils import data_utils
 from tempest.common import waiters
 from tempest import config
@@ -58,15 +59,19 @@
         super(ListImageFiltersTestJSON, cls).resource_setup()
 
         def _create_image():
-            name = data_utils.rand_name('image')
+            params = {
+                'name': data_utils.rand_name('image'),
+                'container_format': 'bare',
+                'disk_format': 'raw'
+            }
             if CONF.image_feature_enabled.api_v1:
-                kwargs = dict(is_public=False)
+                params.update({'is_public': False})
+                params = {'headers':
+                          common_image.image_meta_to_headers(**params)}
             else:
-                kwargs = dict(visibility='private')
-            body = cls.glance_client.create_image(name=name,
-                                                  container_format='bare',
-                                                  disk_format='raw',
-                                                  **kwargs)
+                params.update({'visibility': 'private'})
+
+            body = cls.glance_client.create_image(**params)
             body = body['image'] if 'image' in body else body
             image_id = body['id']
             cls.images.append(image_id)
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 3a4428a..0d06119 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -375,17 +375,19 @@
             'backup_type': "daily",
             'instance_uuid': self.server_id,
         }
+        params = {
+            'status': 'active',
+            'sort_key': 'created_at',
+            'sort_dir': 'asc'
+        }
         if CONF.image_feature_enabled.api_v1:
-            params = dict(
-                properties=properties, status='active',
-                sort_key='created_at', sort_dir='asc',)
+            for key, value in properties.items():
+                params['property-%s' % key] = value
             image_list = glance_client.list_images(
                 detail=True,
                 **params)['images']
         else:
             # Additional properties are flattened in glance v2.
-            params = dict(
-                status='active', sort_key='created_at', sort_dir='asc')
             params.update(properties)
             image_list = glance_client.list_images(params)['images']
 
diff --git a/tempest/api/compute/servers/test_server_rescue.py b/tempest/api/compute/servers/test_server_rescue.py
index 32faf7d..9834d02 100644
--- a/tempest/api/compute/servers/test_server_rescue.py
+++ b/tempest/api/compute/servers/test_server_rescue.py
@@ -61,9 +61,6 @@
         waiters.wait_for_server_status(cls.servers_client, cls.server_id,
                                        'ACTIVE')
 
-    def setUp(self):
-        super(ServerRescueTestJSON, self).setUp()
-
     @classmethod
     def resource_cleanup(cls):
         # Deleting the floating IP which is created in this method
@@ -72,9 +69,6 @@
             cls.sg_id)
         super(ServerRescueTestJSON, cls).resource_cleanup()
 
-    def tearDown(self):
-        super(ServerRescueTestJSON, self).tearDown()
-
     def _unrescue(self, server_id):
         self.servers_client.unrescue_server(server_id)
         waiters.wait_for_server_status(self.servers_client, server_id,
diff --git a/tempest/api/data_processing/test_node_group_templates.py b/tempest/api/data_processing/test_node_group_templates.py
index 388bb58..c2dae85 100644
--- a/tempest/api/data_processing/test_node_group_templates.py
+++ b/tempest/api/data_processing/test_node_group_templates.py
@@ -25,10 +25,6 @@
         if cls.default_plugin is None:
             raise cls.skipException("No Sahara plugins configured")
 
-    @classmethod
-    def resource_setup(cls):
-        super(NodeGroupTemplateTest, cls).resource_setup()
-
     def _create_node_group_template(self, template_name=None):
         """Creates Node Group Template with optional name specified.
 
diff --git a/tempest/api/database/__init__.py b/tempest/api/database/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api/database/__init__.py
+++ /dev/null
diff --git a/tempest/api/database/base.py b/tempest/api/database/base.py
deleted file mode 100644
index 01e05db..0000000
--- a/tempest/api/database/base.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# 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 import config
-import tempest.test
-
-CONF = config.CONF
-
-
-class BaseDatabaseTest(tempest.test.BaseTestCase):
-    """Base test case class for all Database API tests."""
-
-    credentials = ['primary']
-
-    @classmethod
-    def skip_checks(cls):
-        super(BaseDatabaseTest, cls).skip_checks()
-        if not CONF.service_available.trove:
-            skip_msg = ("%s skipped as trove is not available" % cls.__name__)
-            raise cls.skipException(skip_msg)
-
-    @classmethod
-    def setup_clients(cls):
-        super(BaseDatabaseTest, cls).setup_clients()
-        cls.database_flavors_client = cls.os.database_flavors_client
-        cls.os_flavors_client = cls.os.flavors_client
-        cls.database_limits_client = cls.os.database_limits_client
-        cls.database_versions_client = cls.os.database_versions_client
-
-    @classmethod
-    def resource_setup(cls):
-        super(BaseDatabaseTest, cls).resource_setup()
-
-        cls.catalog_type = CONF.database.catalog_type
-        cls.db_flavor_ref = CONF.database.db_flavor_ref
-        cls.db_current_version = CONF.database.db_current_version
diff --git a/tempest/api/database/flavors/__init__.py b/tempest/api/database/flavors/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api/database/flavors/__init__.py
+++ /dev/null
diff --git a/tempest/api/database/flavors/test_flavors.py b/tempest/api/database/flavors/test_flavors.py
deleted file mode 100644
index bb7a0a4..0000000
--- a/tempest/api/database/flavors/test_flavors.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# 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.api.database import base
-from tempest.lib import decorators
-from tempest import test
-
-
-class DatabaseFlavorsTest(base.BaseDatabaseTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(DatabaseFlavorsTest, cls).setup_clients()
-        cls.client = cls.database_flavors_client
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('c94b825e-0132-4686-8049-8a4a2bc09525')
-    @decorators.skip_because(bug='1567134')
-    def test_get_db_flavor(self):
-        # The expected flavor details should be returned
-        flavor = (self.client.show_db_flavor(self.db_flavor_ref)
-                  ['flavor'])
-        self.assertEqual(self.db_flavor_ref, str(flavor['id']))
-        self.assertIn('ram', flavor)
-        self.assertIn('links', flavor)
-        self.assertIn('name', flavor)
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('685025d6-0cec-4673-8a8d-995cb8e0d3bb')
-    @decorators.skip_because(bug='1567134')
-    def test_list_db_flavors(self):
-        flavor = (self.client.show_db_flavor(self.db_flavor_ref)
-                  ['flavor'])
-        # List of all flavors should contain the expected flavor
-        flavors = self.client.list_db_flavors()['flavors']
-        self.assertIn(flavor, flavors)
-
-    def _check_values(self, names, db_flavor, os_flavor, in_db=True):
-        for name in names:
-            self.assertIn(name, os_flavor)
-            if in_db:
-                self.assertIn(name, db_flavor)
-                self.assertEqual(str(db_flavor[name]), str(os_flavor[name]),
-                                 "DB flavor differs from OS on '%s' value"
-                                 % name)
-            else:
-                self.assertNotIn(name, db_flavor)
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('afb2667f-4ec2-4925-bcb7-313fdcffb80d')
-    @test.services('compute')
-    @decorators.skip_because(bug='1567134')
-    def test_compare_db_flavors_with_os(self):
-        db_flavors = self.client.list_db_flavors()['flavors']
-        os_flavors = (self.os_flavors_client.list_flavors(detail=True)
-                      ['flavors'])
-        self.assertEqual(len(os_flavors), len(db_flavors),
-                         "OS flavors %s do not match DB flavors %s" %
-                         (os_flavors, db_flavors))
-        for os_flavor in os_flavors:
-            db_flavor =\
-                self.client.show_db_flavor(os_flavor['id'])['flavor']
-            self._check_values(['id', 'name', 'ram'], db_flavor, os_flavor)
-            self._check_values(['disk', 'vcpus', 'swap'], db_flavor, os_flavor,
-                               in_db=False)
diff --git a/tempest/api/database/flavors/test_flavors_negative.py b/tempest/api/database/flavors/test_flavors_negative.py
deleted file mode 100644
index cd2981b..0000000
--- a/tempest/api/database/flavors/test_flavors_negative.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# 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.api.database import base
-from tempest.lib import exceptions as lib_exc
-from tempest import test
-
-
-class DatabaseFlavorsNegativeTest(base.BaseDatabaseTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(DatabaseFlavorsNegativeTest, cls).setup_clients()
-        cls.client = cls.database_flavors_client
-
-    @test.attr(type=['negative'])
-    @test.idempotent_id('f8e7b721-373f-4a64-8e9c-5327e975af3e')
-    def test_get_non_existent_db_flavor(self):
-        # flavor details are not returned for non-existent flavors
-        self.assertRaises(lib_exc.NotFound,
-                          self.client.show_db_flavor, -1)
diff --git a/tempest/api/database/limits/__init__.py b/tempest/api/database/limits/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api/database/limits/__init__.py
+++ /dev/null
diff --git a/tempest/api/database/limits/test_limits.py b/tempest/api/database/limits/test_limits.py
deleted file mode 100644
index ee51b1d..0000000
--- a/tempest/api/database/limits/test_limits.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# 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.api.database import base
-from tempest import test
-
-
-class DatabaseLimitsTest(base.BaseDatabaseTest):
-
-    @classmethod
-    def resource_setup(cls):
-        super(DatabaseLimitsTest, cls).resource_setup()
-        cls.client = cls.database_limits_client
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('73024538-f316-4829-b3e9-b459290e137a')
-    def test_absolute_limits(self):
-        # Test to verify if all absolute limit parameters are
-        # present when verb is ABSOLUTE
-        limits = self.client.list_db_limits()['limits']
-        expected_abs_limits = ['max_backups', 'max_volumes',
-                               'max_instances', 'verb']
-        absolute_limit = [l for l in limits
-                          if l['verb'] == 'ABSOLUTE']
-        self.assertEqual(1, len(absolute_limit), "One ABSOLUTE limit "
-                         "verb is allowed. Fetched %s"
-                         % len(absolute_limit))
-        actual_abs_limits = absolute_limit[0].keys()
-        missing_abs_limit = set(expected_abs_limits) - set(actual_abs_limits)
-        self.assertEmpty(missing_abs_limit,
-                         "Failed to find the following absolute limit(s)"
-                         " in a fetched list: %s" %
-                         ', '.join(str(a) for a in missing_abs_limit))
diff --git a/tempest/api/database/versions/__init__.py b/tempest/api/database/versions/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/api/database/versions/__init__.py
+++ /dev/null
diff --git a/tempest/api/database/versions/test_versions.py b/tempest/api/database/versions/test_versions.py
deleted file mode 100644
index ae568b1..0000000
--- a/tempest/api/database/versions/test_versions.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# 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.api.database import base
-from tempest import test
-
-
-class DatabaseVersionsTest(base.BaseDatabaseTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(DatabaseVersionsTest, cls).setup_clients()
-        cls.client = cls.database_versions_client
-
-    @test.attr(type='smoke')
-    @test.idempotent_id('6952cd77-90cd-4dca-bb60-8e2c797940cf')
-    def test_list_db_versions(self):
-        versions = self.client.list_db_versions()['versions']
-        self.assertTrue(len(versions) > 0, "No database versions found")
-        # List of all versions should contain the current version, and there
-        # should only be one 'current' version
-        current_versions = list()
-        for version in versions:
-            if 'CURRENT' == version['status']:
-                current_versions.append(version['id'])
-        self.assertEqual(1, len(current_versions))
-        self.assertIn(self.db_current_version, current_versions)
diff --git a/tempest/api/identity/admin/v3/test_tokens.py b/tempest/api/identity/admin/v3/test_tokens.py
index 6f12939..89cfd5b 100644
--- a/tempest/api/identity/admin/v3/test_tokens.py
+++ b/tempest/api/identity/admin/v3/test_tokens.py
@@ -13,6 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import six
+
 from tempest.api.identity import base
 from tempest.common.utils import data_utils
 from tempest.lib import exceptions as lib_exc
@@ -97,8 +99,8 @@
         orig_expires_at = token_auth['token']['expires_at']
         orig_user = token_auth['token']['user']
 
-        self.assertIsInstance(token_auth['token']['expires_at'], unicode)
-        self.assertIsInstance(token_auth['token']['issued_at'], unicode)
+        self.assertIsInstance(token_auth['token']['expires_at'], six.text_type)
+        self.assertIsInstance(token_auth['token']['issued_at'], six.text_type)
         self.assertEqual(['password'], token_auth['token']['methods'])
         self.assertEqual(user['id'], token_auth['token']['user']['id'])
         self.assertEqual(user['name'], token_auth['token']['user']['name'])
@@ -118,7 +120,7 @@
 
         self.assertEqual(orig_expires_at, token_auth['token']['expires_at'],
                          'Expiration time should match original token')
-        self.assertIsInstance(token_auth['token']['issued_at'], unicode)
+        self.assertIsInstance(token_auth['token']['issued_at'], six.text_type)
         self.assertEqual(set(['password', 'token']),
                          set(token_auth['token']['methods']))
         self.assertEqual(orig_user, token_auth['token']['user'],
diff --git a/tempest/api/identity/base.py b/tempest/api/identity/base.py
index bc1b158..7a1e3a5 100644
--- a/tempest/api/identity/base.py
+++ b/tempest/api/identity/base.py
@@ -29,7 +29,7 @@
     @classmethod
     def disable_user(cls, user_name):
         user = cls.get_user_by_name(user_name)
-        cls.users_client.enable_disable_user(user['id'], enabled=False)
+        cls.users_client.update_user_enabled(user['id'], enabled=False)
 
     @classmethod
     def disable_tenant(cls, tenant_name):
@@ -81,14 +81,6 @@
         cls.non_admin_tenants_client = cls.os.tenants_public_client
         cls.non_admin_users_client = cls.os.users_public_client
 
-    @classmethod
-    def resource_setup(cls):
-        super(BaseIdentityV2Test, cls).resource_setup()
-
-    @classmethod
-    def resource_cleanup(cls):
-        super(BaseIdentityV2Test, cls).resource_cleanup()
-
 
 class BaseIdentityV2AdminTest(BaseIdentityV2Test):
 
@@ -137,10 +129,6 @@
         cls.non_admin_token = cls.os.token_v3_client
         cls.non_admin_projects_client = cls.os.projects_client
 
-    @classmethod
-    def resource_cleanup(cls):
-        super(BaseIdentityV3Test, cls).resource_cleanup()
-
 
 class BaseIdentityV3AdminTest(BaseIdentityV3Test):
 
@@ -227,27 +215,24 @@
             name=data_utils.rand_name('test_role'))['role']
         self.roles.append(self.role)
 
-    @staticmethod
-    def _try_wrapper(func, item, **kwargs):
-        try:
-            test_utils.call_and_ignore_notfound_exc(func, item['id'], **kwargs)
-        except Exception:
-            LOG.exception("Unexpected exception occurred in %s deletion. "
-                          "But ignored here." % item['id'])
-
     def teardown_all(self):
         for user in self.users:
-            self._try_wrapper(self.users_client.delete_user, user)
+            test_utils.call_and_ignore_notfound_exc(
+                self.users_client.delete_user, user)
         for tenant in self.tenants:
-            self._try_wrapper(self.projects_client.delete_tenant, tenant)
-        for project in self.projects:
-            self._try_wrapper(self.projects_client.delete_project, project)
+            test_utils.call_and_ignore_notfound_exc(
+                self.projects_client.delete_tenant, tenant)
+        for project in reversed(self.projects):
+            test_utils.call_and_ignore_notfound_exc(
+                self.projects_client.delete_project, project)
         for role in self.roles:
-            self._try_wrapper(self.roles_client.delete_role, role)
+            test_utils.call_and_ignore_notfound_exc(
+                self.roles_client.delete_role, role)
         for domain in self.domains:
-            self._try_wrapper(self.domains_client.update_domain, domain,
-                              enabled=False)
-            self._try_wrapper(self.domains_client.delete_domain, domain)
+            test_utils.call_and_ignore_notfound_exc(
+                self.domains_client.update_domain, domain, enabled=False)
+            test_utils.call_and_ignore_notfound_exc(
+                self.domains_client.delete_domain, domain)
 
 
 class DataGeneratorV2(BaseDataGenerator):
diff --git a/tempest/api/identity/v2/test_ec2_credentials.py b/tempest/api/identity/v2/test_ec2_credentials.py
index 5902196..3c379f0 100644
--- a/tempest/api/identity/v2/test_ec2_credentials.py
+++ b/tempest/api/identity/v2/test_ec2_credentials.py
@@ -33,14 +33,14 @@
         cls.creds = cls.os.credentials
 
     @test.idempotent_id('b580fab9-7ae9-46e8-8138-417260cb6f9f')
-    def test_create_ec2_credentials(self):
-        """Create user ec2 credentials."""
-        resp = self.non_admin_users_client.create_user_ec2_credentials(
+    def test_create_ec2_credential(self):
+        """Create user ec2 credential."""
+        resp = self.non_admin_users_client.create_user_ec2_credential(
             self.creds.user_id,
             tenant_id=self.creds.tenant_id)["credential"]
         access = resp['access']
         self.addCleanup(
-            self.non_admin_users_client.delete_user_ec2_credentials,
+            self.non_admin_users_client.delete_user_ec2_credential,
             self.creds.user_id, access)
         self.assertNotEmpty(resp['access'])
         self.assertNotEmpty(resp['secret'])
@@ -53,21 +53,21 @@
         created_creds = []
         fetched_creds = []
         # create first ec2 credentials
-        creds1 = self.non_admin_users_client.create_user_ec2_credentials(
+        creds1 = self.non_admin_users_client.create_user_ec2_credential(
             self.creds.user_id,
             tenant_id=self.creds.tenant_id)["credential"]
         created_creds.append(creds1['access'])
         # create second ec2 credentials
-        creds2 = self.non_admin_users_client.create_user_ec2_credentials(
+        creds2 = self.non_admin_users_client.create_user_ec2_credential(
             self.creds.user_id,
             tenant_id=self.creds.tenant_id)["credential"]
         created_creds.append(creds2['access'])
         # add credentials to be cleaned up
         self.addCleanup(
-            self.non_admin_users_client.delete_user_ec2_credentials,
+            self.non_admin_users_client.delete_user_ec2_credential,
             self.creds.user_id, creds1['access'])
         self.addCleanup(
-            self.non_admin_users_client.delete_user_ec2_credentials,
+            self.non_admin_users_client.delete_user_ec2_credential,
             self.creds.user_id, creds2['access'])
         # get the list of user ec2 credentials
         resp = self.non_admin_users_client.list_user_ec2_credentials(
@@ -81,32 +81,32 @@
                          ', '.join(cred for cred in missing))
 
     @test.idempotent_id('cb284075-b613-440d-83ca-fe0b33b3c2b8')
-    def test_show_ec2_credentials(self):
-        """Get the definite user ec2 credentials."""
-        resp = self.non_admin_users_client.create_user_ec2_credentials(
+    def test_show_ec2_credential(self):
+        """Get the definite user ec2 credential."""
+        resp = self.non_admin_users_client.create_user_ec2_credential(
             self.creds.user_id,
             tenant_id=self.creds.tenant_id)["credential"]
         self.addCleanup(
-            self.non_admin_users_client.delete_user_ec2_credentials,
+            self.non_admin_users_client.delete_user_ec2_credential,
             self.creds.user_id, resp['access'])
 
-        ec2_creds = self.non_admin_users_client.show_user_ec2_credentials(
+        ec2_creds = self.non_admin_users_client.show_user_ec2_credential(
             self.creds.user_id, resp['access']
         )["credential"]
         for key in ['access', 'secret', 'user_id', 'tenant_id']:
             self.assertEqual(ec2_creds[key], resp[key])
 
     @test.idempotent_id('6aba0d4c-b76b-4e46-aa42-add79bc1551d')
-    def test_delete_ec2_credentials(self):
-        """Delete user ec2 credentials."""
-        resp = self.non_admin_users_client.create_user_ec2_credentials(
+    def test_delete_ec2_credential(self):
+        """Delete user ec2 credential."""
+        resp = self.non_admin_users_client.create_user_ec2_credential(
             self.creds.user_id,
             tenant_id=self.creds.tenant_id)["credential"]
         access = resp['access']
-        self.non_admin_users_client.delete_user_ec2_credentials(
+        self.non_admin_users_client.delete_user_ec2_credential(
             self.creds.user_id, access)
         self.assertRaises(
             lib_exc.NotFound,
-            self.non_admin_users_client.show_user_ec2_credentials,
+            self.non_admin_users_client.show_user_ec2_credential,
             self.creds.user_id,
             access)
diff --git a/tempest/api/image/base.py b/tempest/api/image/base.py
index 3fefc81..6fd6ea6 100644
--- a/tempest/api/image/base.py
+++ b/tempest/api/image/base.py
@@ -14,6 +14,7 @@
 
 from six import moves
 
+from tempest.common import image as common_image
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest.lib.common.utils import test_utils
@@ -55,14 +56,20 @@
         super(BaseImageTest, cls).resource_cleanup()
 
     @classmethod
-    def create_image(cls, **kwargs):
+    def create_image(cls, data=None, **kwargs):
         """Wrapper that returns a test image."""
 
         if 'name' not in kwargs:
             name = data_utils.rand_name(cls.__name__ + "-instance")
             kwargs['name'] = name
 
-        image = cls.client.create_image(**kwargs)
+        params = cls._get_create_params(**kwargs)
+        if data:
+            # NOTE: On glance v1 API, the data should be passed on
+            # a header. Then here handles the data separately.
+            params['data'] = data
+
+        image = cls.client.create_image(**params)
         # Image objects returned by the v1 client have the image
         # data inside a dict that is keyed against 'image'.
         if 'image' in image:
@@ -70,6 +77,10 @@
         cls.created_images.append(image['id'])
         return image
 
+    @classmethod
+    def _get_create_params(cls, **kwargs):
+        return kwargs
+
 
 class BaseV1ImageTest(BaseImageTest):
 
@@ -85,6 +96,10 @@
         super(BaseV1ImageTest, cls).setup_clients()
         cls.client = cls.os.image_client
 
+    @classmethod
+    def _get_create_params(cls, **kwargs):
+        return {'headers': common_image.image_meta_to_headers(**kwargs)}
+
 
 class BaseV1ImageMembersTest(BaseV1ImageTest):
 
diff --git a/tempest/api/image/v1/test_images.py b/tempest/api/image/v1/test_images.py
index 59ac646..def7750 100644
--- a/tempest/api/image/v1/test_images.py
+++ b/tempest/api/image/v1/test_images.py
@@ -320,8 +320,10 @@
         metadata = common_image.get_image_meta_from_headers(resp)
         self.assertEqual(metadata['properties'], {'key1': 'value1'})
         metadata['properties'].update(req_metadata)
-        metadata = self.client.update_image(
-            self.image_id, properties=metadata['properties'])['image']
+        headers = common_image.image_meta_to_headers(
+            properties=metadata['properties'])
+        metadata = self.client.update_image(self.image_id,
+                                            headers=headers)['image']
 
         resp = self.client.check_image(self.image_id)
         resp_metadata = common_image.get_image_meta_from_headers(resp)
diff --git a/tempest/api/image/v1/test_images_negative.py b/tempest/api/image/v1/test_images_negative.py
index babee74..9e67c25 100644
--- a/tempest/api/image/v1/test_images_negative.py
+++ b/tempest/api/image/v1/test_images_negative.py
@@ -27,17 +27,17 @@
     def test_register_with_invalid_container_format(self):
         # Negative tests for invalid data supplied to POST /images
         self.assertRaises(lib_exc.BadRequest, self.client.create_image,
-                          name='test',
-                          container_format='wrong',
-                          disk_format='vhd',)
+                          headers={'x-image-meta-name': 'test',
+                                   'x-image-meta-container_format': 'wrong',
+                                   'x-image-meta-disk_format': 'vhd'})
 
     @test.attr(type=['negative'])
     @test.idempotent_id('993face5-921d-4e84-aabf-c1bba4234a67')
     def test_register_with_invalid_disk_format(self):
         self.assertRaises(lib_exc.BadRequest, self.client.create_image,
-                          name='test',
-                          container_format='bare',
-                          disk_format='wrong',)
+                          headers={'x-image-meta-name': 'test',
+                                   'x-image-meta-container_format': 'bare',
+                                   'x-image-meta-disk_format': 'wrong'})
 
     @test.attr(type=['negative'])
     @test.idempotent_id('bb016f15-0820-4f27-a92d-09b2f67d2488')
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index 1d96439..bf80ff5 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -565,9 +565,9 @@
         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')
+        six.assertCountEqual(self, subnets,
+                             test_subnet_ids,
+                             'Subnet are not in the same network')
 
 
 class NetworksIpV6TestAttrs(NetworksIpV6Test):
diff --git a/tempest/api/orchestration/stacks/test_stacks.py b/tempest/api/orchestration/stacks/test_stacks.py
index 28463ab..f13a2d9 100644
--- a/tempest/api/orchestration/stacks/test_stacks.py
+++ b/tempest/api/orchestration/stacks/test_stacks.py
@@ -18,10 +18,6 @@
 class StacksTestJSON(base.BaseOrchestrationTest):
     empty_template = "HeatTemplateFormatVersion: '2012-12-12'\n"
 
-    @classmethod
-    def resource_setup(cls):
-        super(StacksTestJSON, cls).resource_setup()
-
     @test.attr(type='smoke')
     @test.idempotent_id('d35d628c-07f6-4674-85a1-74db9919e986')
     def test_stack_list_responds(self):
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 6ebe4dc..9e49b94 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs.py
@@ -47,20 +47,19 @@
             self.volume_type['id'], extra_specs)['extra_specs']
         self.assertEqual(extra_specs, body,
                          "Volume type extra spec incorrectly created")
-
-        extra_spec = {"spec2": "val2"}
+        spec_key = "spec2"
+        extra_spec = {spec_key: "val2"}
         body = self.admin_volume_types_client.update_volume_type_extra_specs(
-            self.volume_type['id'],
-            extra_spec.keys()[0],
-            extra_spec)
-        self.assertIn('spec2', body)
-        self.assertEqual(extra_spec['spec2'], body['spec2'],
+            self.volume_type['id'], spec_key, extra_spec)
+        self.assertIn(spec_key, body)
+        self.assertEqual(extra_spec[spec_key], body[spec_key],
                          "Volume type extra spec incorrectly updated")
 
     @test.idempotent_id('d4772798-601f-408a-b2a5-29e8a59d1220')
     def test_volume_type_extra_spec_create_get_delete(self):
         # Create/Get/Delete volume type extra spec.
-        extra_specs = {"spec3": "val1"}
+        spec_key = "spec3"
+        extra_specs = {spec_key: "val1"}
         body = self.admin_volume_types_client.create_volume_type_extra_specs(
             self.volume_type['id'],
             extra_specs)['extra_specs']
@@ -69,13 +68,11 @@
 
         self.admin_volume_types_client.show_volume_type_extra_specs(
             self.volume_type['id'],
-            extra_specs.keys()[0])
+            spec_key)
         self.assertEqual(extra_specs, body,
                          "Volume type extra spec incorrectly fetched")
-
         self.admin_volume_types_client.delete_volume_type_extra_specs(
-            self.volume_type['id'],
-            extra_specs.keys()[0])
+            self.volume_type['id'], spec_key)
 
 
 class VolumeTypesExtraSpecsV1Test(VolumeTypesExtraSpecsV2Test):
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 d929b43..2193aa6 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
@@ -32,11 +32,10 @@
     @test.idempotent_id('08961d20-5cbb-4910-ac0f-89ad6dbb2da1')
     def test_update_no_body(self):
         # Should not update volume type extra specs with no body
-        extra_spec = {"spec1": "val2"}
         self.assertRaises(
             lib_exc.BadRequest,
             self.admin_volume_types_client.update_volume_type_extra_specs,
-            self.volume_type['id'], extra_spec.keys()[0], None)
+            self.volume_type['id'], "spec1", None)
 
     @test.idempotent_id('25e5a0ee-89b3-4c53-8310-236f76c75365')
     def test_update_nonexistent_extra_spec_id(self):
@@ -65,7 +64,7 @@
         self.assertRaises(
             lib_exc.BadRequest,
             self.admin_volume_types_client.update_volume_type_extra_specs,
-            self.volume_type['id'], extra_spec.keys()[0],
+            self.volume_type['id'], list(extra_spec)[0],
             extra_spec)
 
     @test.idempotent_id('49d5472c-a53d-4eab-a4d3-450c4db1c545')
@@ -97,12 +96,11 @@
     @test.idempotent_id('031cda8b-7d23-4246-8bf6-bbe73fd67074')
     def test_delete_nonexistent_volume_type_id(self):
         # Should not delete volume type extra spec for nonexistent
-            # type id.
-        extra_specs = {"spec1": "val1"}
+        # type id.
         self.assertRaises(
             lib_exc.NotFound,
             self.admin_volume_types_client.delete_volume_type_extra_specs,
-            data_utils.rand_uuid(), extra_specs.keys()[0])
+            data_utils.rand_uuid(), "spec1")
 
     @test.idempotent_id('dee5cf0c-cdd6-4353-b70c-e847050d71fb')
     def test_list_nonexistent_volume_type_id(self):
@@ -115,11 +113,10 @@
     @test.idempotent_id('9f402cbd-1838-4eb4-9554-126a6b1908c9')
     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(
             lib_exc.NotFound,
             self.admin_volume_types_client.show_volume_type_extra_specs,
-            data_utils.rand_uuid(), extra_specs.keys()[0])
+            data_utils.rand_uuid(), "spec1")
 
     @test.idempotent_id('c881797d-12ff-4f1a-b09d-9f6212159753')
     def test_get_nonexistent_extra_spec_id(self):
diff --git a/tempest/api/volume/admin/test_volumes_list.py b/tempest/api/volume/admin/test_volumes_list.py
new file mode 100644
index 0000000..64041b8
--- /dev/null
+++ b/tempest/api/volume/admin/test_volumes_list.py
@@ -0,0 +1,59 @@
+# Copyright 2016 Red Hat, 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.
+
+import operator
+
+from tempest.api.volume import base
+from tempest.common import waiters
+from tempest import test
+
+
+class VolumesListAdminV2TestJSON(base.BaseVolumeAdminTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(VolumesListAdminV2TestJSON, cls).resource_setup()
+        # Create 3 test volumes
+        cls.volume_list = []
+        for i in range(3):
+            volume = cls.create_volume()
+            # Fetch volume details
+            volume_details = cls.volumes_client.show_volume(
+                volume['id'])['volume']
+            cls.volume_list.append(volume_details)
+
+    @test.idempotent_id('5866286f-3290-4cfd-a414-088aa6cdc469')
+    def test_volume_list_param_tenant(self):
+        # Test to list volumes from single tenant
+        # Create a volume in admin tenant
+        adm_vol = self.admin_volume_client.create_volume()['volume']
+        waiters.wait_for_volume_status(self.admin_volume_client,
+                                       adm_vol['id'], 'available')
+        self.addCleanup(self.admin_volume_client.delete_volume, adm_vol['id'])
+        params = {'all_tenants': 1,
+                  'project_id': self.volumes_client.tenant_id}
+        # Getting volume list from primary tenant using admin credentials
+        fetched_list = self.admin_volume_client.list_volumes(
+            detail=True, params=params)['volumes']
+        # Verifying fetched volume ids list is related to primary tenant
+        fetched_list_ids = map(operator.itemgetter('id'), fetched_list)
+        expected_list_ids = map(operator.itemgetter('id'), self.volume_list)
+        self.assertEqual(sorted(expected_list_ids), sorted(fetched_list_ids))
+        # Verifying tenant id of volumes fetched list is related to
+        # primary tenant
+        fetched_tenant_id = map(operator.itemgetter(
+            'os-vol-tenant-attr:tenant_id'), fetched_list)
+        expected_tenant_id = [self.volumes_client.tenant_id] * 3
+        self.assertEqual(expected_tenant_id, fetched_tenant_id)
diff --git a/tempest/api/volume/v2/test_image_metadata.py b/tempest/api/volume/v2/test_image_metadata.py
new file mode 100644
index 0000000..1e7bb30
--- /dev/null
+++ b/tempest/api/volume/v2/test_image_metadata.py
@@ -0,0 +1,64 @@
+# Copyright 2016 Red Hat, 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.
+
+from testtools import matchers
+
+from tempest.api.volume import base
+from tempest import config
+from tempest import test
+
+CONF = config.CONF
+
+
+class VolumesV2ImageMetadata(base.BaseVolumeTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(VolumesV2ImageMetadata, cls).resource_setup()
+        # Create a volume from image ID
+        cls.volume = cls.create_volume(imageRef=CONF.compute.image_ref)
+
+    @test.idempotent_id('03efff0b-5c75-4822-8f10-8789ac15b13e')
+    @test.services('image')
+    def test_update_image_metadata(self):
+        # Update image metadata
+        image_metadata = {'image_id': '5137a025-3c5f-43c1-bc64-5f41270040a5',
+                          'image_name': 'image',
+                          'kernel_id': '6ff710d2-942b-4d6b-9168-8c9cc2404ab1',
+                          'ramdisk_id': 'somedisk'}
+        self.volumes_client.update_volume_image_metadata(self.volume['id'],
+                                                         **image_metadata)
+
+        # Fetch image metadata from the volume
+        volume_image_metadata = self.volumes_client.show_volume(
+            self.volume['id'])['volume']['volume_image_metadata']
+
+        # Verify image metadata was updated
+        self.assertThat(volume_image_metadata.items(),
+                        matchers.ContainsAll(image_metadata.items()))
+
+        # Delete one item from image metadata of the volume
+        self.volumes_client.delete_volume_image_metadata(self.volume['id'],
+                                                         'ramdisk_id')
+        del image_metadata['ramdisk_id']
+
+        # Fetch the new image metadata from the volume
+        volume_image_metadata = self.volumes_client.show_volume(
+            self.volume['id'])['volume']['volume_image_metadata']
+
+        # Verify image metadata was updated after item deletion
+        self.assertThat(volume_image_metadata.items(),
+                        matchers.ContainsAll(image_metadata.items()))
+        self.assertNotIn('ramdisk_id', volume_image_metadata)
diff --git a/tempest/clients.py b/tempest/clients.py
index 8c1b279..3a1a3c0 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -21,98 +21,15 @@
 from tempest import config
 from tempest import exceptions
 from tempest.lib.services import compute
-from tempest.lib.services.identity.v2.endpoints_client import EndpointsClient
-from tempest.lib.services.identity.v2.token_client import TokenClient
-from tempest.lib.services.identity.v3.token_client import V3TokenClient
-from tempest.lib.services.image.v1.image_members_client import \
-    ImageMembersClient
-from tempest.lib.services.image.v2.image_members_client import \
-    ImageMembersClient as ImageMembersClientV2
-from tempest.lib.services.image.v2.images_client import \
-    ImagesClient as ImagesV2Client
-from tempest.lib.services.image.v2.namespaces_client import NamespacesClient
-from tempest.lib.services.image.v2.resource_types_client import \
-    ResourceTypesClient
-from tempest.lib.services.image.v2.schemas_client import SchemasClient
+from tempest.lib.services import image
 from tempest.lib.services import network
 from tempest import manager
-from tempest.services.baremetal.v1.json.baremetal_client import \
-    BaremetalClient
-from tempest.services.data_processing.v1_1.data_processing_client import \
-    DataProcessingClient
-from tempest.services.database.json.flavors_client import \
-    DatabaseFlavorsClient
-from tempest.services.database.json.limits_client import \
-    DatabaseLimitsClient
-from tempest.services.database.json.versions_client import \
-    DatabaseVersionsClient
-from tempest.services.identity.v2.json.identity_client import IdentityClient
-from tempest.services.identity.v2.json.roles_client import RolesClient
-from tempest.services.identity.v2.json.services_client import \
-    ServicesClient as IdentityServicesClient
-from tempest.services.identity.v2.json.tenants_client import TenantsClient
-from tempest.services.identity.v2.json.users_client import UsersClient
-from tempest.services.identity.v3.json.credentials_client import \
-    CredentialsClient
-from tempest.services.identity.v3.json.domains_client import DomainsClient
-from tempest.services.identity.v3.json.endpoints_client import \
-    EndPointsClient as EndPointsV3Client
-from tempest.services.identity.v3.json.groups_client import GroupsClient
-from tempest.services.identity.v3.json.identity_client import \
-    IdentityClient as IdentityV3Client
-from tempest.services.identity.v3.json.policies_client import PoliciesClient
-from tempest.services.identity.v3.json.projects_client import ProjectsClient
-from tempest.services.identity.v3.json.regions_client import RegionsClient
-from tempest.services.identity.v3.json.roles_client import \
-    RolesClient as RolesV3Client
-from tempest.services.identity.v3.json.services_client import \
-    ServicesClient as IdentityServicesV3Client
-from tempest.services.identity.v3.json.trusts_client import TrustsClient
-from tempest.services.identity.v3.json.users_clients import \
-    UsersClient as UsersV3Client
-from tempest.services.image.v1.json.images_client import ImagesClient
-from tempest.services.object_storage.account_client import AccountClient
-from tempest.services.object_storage.container_client import ContainerClient
-from tempest.services.object_storage.object_client import ObjectClient
-from tempest.services.orchestration.json.orchestration_client import \
-    OrchestrationClient
-from tempest.services.volume.v1.json.admin.hosts_client import \
-    HostsClient as VolumeHostsClient
-from tempest.services.volume.v1.json.admin.quotas_client import \
-    QuotasClient as VolumeQuotasClient
-from tempest.services.volume.v1.json.admin.services_client import \
-    ServicesClient as VolumeServicesClient
-from tempest.services.volume.v1.json.admin.types_client import \
-    TypesClient as VolumeTypesClient
-from tempest.services.volume.v1.json.availability_zone_client import \
-    AvailabilityZoneClient as VolumeAvailabilityZoneClient
-from tempest.services.volume.v1.json.backups_client import BackupsClient
-from tempest.services.volume.v1.json.extensions_client import \
-    ExtensionsClient as VolumeExtensionsClient
-from tempest.services.volume.v1.json.qos_client import QosSpecsClient
-from tempest.services.volume.v1.json.snapshots_client import SnapshotsClient
-from tempest.services.volume.v1.json.volumes_client import VolumesClient
-from tempest.services.volume.v2.json.admin.hosts_client import \
-    HostsClient as VolumeHostsV2Client
-from tempest.services.volume.v2.json.admin.quotas_client import \
-    QuotasClient as VolumeQuotasV2Client
-from tempest.services.volume.v2.json.admin.services_client import \
-    ServicesClient as VolumeServicesV2Client
-from tempest.services.volume.v2.json.admin.types_client import \
-    TypesClient as VolumeTypesV2Client
-from tempest.services.volume.v2.json.availability_zone_client import \
-    AvailabilityZoneClient as VolumeAvailabilityZoneV2Client
-from tempest.services.volume.v2.json.backups_client import \
-    BackupsClient as BackupsV2Client
-from tempest.services.volume.v2.json.extensions_client import \
-    ExtensionsClient as VolumeExtensionsV2Client
-from tempest.services.volume.v2.json.qos_client import \
-    QosSpecsClient as QosSpecsV2Client
-from tempest.services.volume.v2.json.snapshots_client import \
-    SnapshotsClient as SnapshotsV2Client
-from tempest.services.volume.v2.json.volumes_client import \
-    VolumesClient as VolumesV2Client
-from tempest.services.volume.v3.json.messages_client import MessagesClient
+from tempest.services import baremetal
+from tempest.services import data_processing
+from tempest.services import identity
+from tempest.services import object_storage
+from tempest.services import orchestration
+from tempest.services import volume
 
 CONF = config.CONF
 LOG = logging.getLogger(__name__)
@@ -146,20 +63,19 @@
         """
         super(Manager, self).__init__(credentials=credentials, scope=scope)
         self._set_compute_clients()
-        self._set_database_clients()
         self._set_identity_clients()
         self._set_volume_clients()
         self._set_object_storage_clients()
         self._set_image_clients()
         self._set_network_clients()
 
-        self.baremetal_client = BaremetalClient(
+        self.baremetal_client = baremetal.BaremetalClient(
             self.auth_provider,
             CONF.baremetal.catalog_type,
             CONF.identity.region,
             endpoint_type=CONF.baremetal.endpoint_type,
             **self.default_params_with_timeout_values)
-        self.orchestration_client = OrchestrationClient(
+        self.orchestration_client = orchestration.OrchestrationClient(
             self.auth_provider,
             CONF.orchestration.catalog_type,
             CONF.orchestration.region or CONF.identity.region,
@@ -167,7 +83,7 @@
             build_interval=CONF.orchestration.build_interval,
             build_timeout=CONF.orchestration.build_timeout,
             **self.default_params)
-        self.data_processing_client = DataProcessingClient(
+        self.data_processing_client = data_processing.DataProcessingClient(
             self.auth_provider,
             CONF.data_processing.catalog_type,
             CONF.identity.region,
@@ -225,19 +141,19 @@
         params.update(self.default_params)
 
         if CONF.service_available.glance:
-            self.image_client = ImagesClient(
+            self.image_client = image.v1.ImagesClient(
                 self.auth_provider, **params)
-            self.image_member_client = ImageMembersClient(
+            self.image_member_client = image.v1.ImageMembersClient(
                 self.auth_provider, **params)
-            self.image_client_v2 = ImagesV2Client(
+            self.image_client_v2 = image.v2.ImagesClient(
                 self.auth_provider, **params)
-            self.image_member_client_v2 = ImageMembersClientV2(
+            self.image_member_client_v2 = image.v2.ImageMembersClient(
                 self.auth_provider, **params)
-            self.namespaces_client = NamespacesClient(
+            self.namespaces_client = image.v2.NamespacesClient(
                 self.auth_provider, **params)
-            self.resource_types_client = ResourceTypesClient(
+            self.resource_types_client = image.v2.ResourceTypesClient(
                 self.auth_provider, **params)
-            self.schemas_client = SchemasClient(
+            self.schemas_client = image.v2.SchemasClient(
                 self.auth_provider, **params)
 
     def _set_compute_clients(self):
@@ -325,23 +241,6 @@
         self.snapshots_extensions_client = compute.SnapshotsClient(
             self.auth_provider, **params_volume)
 
-    def _set_database_clients(self):
-        self.database_flavors_client = DatabaseFlavorsClient(
-            self.auth_provider,
-            CONF.database.catalog_type,
-            CONF.identity.region,
-            **self.default_params_with_timeout_values)
-        self.database_limits_client = DatabaseLimitsClient(
-            self.auth_provider,
-            CONF.database.catalog_type,
-            CONF.identity.region,
-            **self.default_params_with_timeout_values)
-        self.database_versions_client = DatabaseVersionsClient(
-            self.auth_provider,
-            CONF.database.catalog_type,
-            CONF.identity.region,
-            **self.default_params_with_timeout_values)
-
     def _set_identity_clients(self):
         params = {
             'service': CONF.identity.catalog_type,
@@ -352,62 +251,71 @@
         # Clients below use the admin endpoint type of Keystone API v2
         params_v2_admin = params.copy()
         params_v2_admin['endpoint_type'] = CONF.identity.v2_admin_endpoint_type
-        self.endpoints_client = EndpointsClient(self.auth_provider,
-                                                **params_v2_admin)
-        self.identity_client = IdentityClient(self.auth_provider,
-                                              **params_v2_admin)
-        self.tenants_client = TenantsClient(self.auth_provider,
-                                            **params_v2_admin)
-        self.roles_client = RolesClient(self.auth_provider, **params_v2_admin)
-        self.users_client = UsersClient(self.auth_provider, **params_v2_admin)
-        self.identity_services_client = IdentityServicesClient(
+        self.endpoints_client = identity.v2.EndpointsClient(self.auth_provider,
+                                                            **params_v2_admin)
+        self.identity_client = identity.v2.IdentityClient(self.auth_provider,
+                                                          **params_v2_admin)
+        self.tenants_client = identity.v2.TenantsClient(self.auth_provider,
+                                                        **params_v2_admin)
+        self.roles_client = identity.v2.RolesClient(self.auth_provider,
+                                                    **params_v2_admin)
+        self.users_client = identity.v2.UsersClient(self.auth_provider,
+                                                    **params_v2_admin)
+        self.identity_services_client = identity.v2.ServicesClient(
             self.auth_provider, **params_v2_admin)
 
         # Clients below use the public endpoint type of Keystone API v2
         params_v2_public = params.copy()
         params_v2_public['endpoint_type'] = (
             CONF.identity.v2_public_endpoint_type)
-        self.identity_public_client = IdentityClient(self.auth_provider,
-                                                     **params_v2_public)
-        self.tenants_public_client = TenantsClient(self.auth_provider,
-                                                   **params_v2_public)
-        self.users_public_client = UsersClient(self.auth_provider,
-                                               **params_v2_public)
+        self.identity_public_client = identity.v2.IdentityClient(
+            self.auth_provider, **params_v2_public)
+        self.tenants_public_client = identity.v2.TenantsClient(
+            self.auth_provider, **params_v2_public)
+        self.users_public_client = identity.v2.UsersClient(
+            self.auth_provider, **params_v2_public)
 
         # Clients below use the endpoint type of Keystone API v3
         params_v3 = params.copy()
         params_v3['endpoint_type'] = CONF.identity.v3_endpoint_type
-        self.domains_client = DomainsClient(self.auth_provider,
-                                            **params_v3)
-        self.identity_v3_client = IdentityV3Client(self.auth_provider,
-                                                   **params_v3)
-        self.trusts_client = TrustsClient(self.auth_provider, **params_v3)
-        self.users_v3_client = UsersV3Client(self.auth_provider, **params_v3)
-        self.endpoints_v3_client = EndPointsV3Client(self.auth_provider,
-                                                     **params_v3)
-        self.roles_v3_client = RolesV3Client(self.auth_provider, **params_v3)
-        self.identity_services_v3_client = IdentityServicesV3Client(
+        self.domains_client = identity.v3.DomainsClient(self.auth_provider,
+                                                        **params_v3)
+        self.identity_v3_client = identity.v3.IdentityClient(
             self.auth_provider, **params_v3)
-        self.policies_client = PoliciesClient(self.auth_provider, **params_v3)
-        self.projects_client = ProjectsClient(self.auth_provider, **params_v3)
-        self.regions_client = RegionsClient(self.auth_provider, **params_v3)
-        self.credentials_client = CredentialsClient(self.auth_provider,
-                                                    **params_v3)
-        self.groups_client = GroupsClient(self.auth_provider, **params_v3)
+        self.trusts_client = identity.v3.TrustsClient(self.auth_provider,
+                                                      **params_v3)
+        self.users_v3_client = identity.v3.UsersClient(self.auth_provider,
+                                                       **params_v3)
+        self.endpoints_v3_client = identity.v3.EndPointsClient(
+            self.auth_provider, **params_v3)
+        self.roles_v3_client = identity.v3.RolesClient(self.auth_provider,
+                                                       **params_v3)
+        self.identity_services_v3_client = identity.v3.ServicesClient(
+            self.auth_provider, **params_v3)
+        self.policies_client = identity.v3.PoliciesClient(self.auth_provider,
+                                                          **params_v3)
+        self.projects_client = identity.v3.ProjectsClient(self.auth_provider,
+                                                          **params_v3)
+        self.regions_client = identity.v3.RegionsClient(self.auth_provider,
+                                                        **params_v3)
+        self.credentials_client = identity.v3.CredentialsClient(
+            self.auth_provider, **params_v3)
+        self.groups_client = identity.v3.GroupsClient(self.auth_provider,
+                                                      **params_v3)
 
         # Token clients do not use the catalog. They only need default_params.
         # They read auth_url, so they should only be set if the corresponding
         # API version is marked as enabled
         if CONF.identity_feature_enabled.api_v2:
             if CONF.identity.uri:
-                self.token_client = TokenClient(
+                self.token_client = identity.v2.TokenClient(
                     CONF.identity.uri, **self.default_params)
             else:
                 msg = 'Identity v2 API enabled, but no identity.uri set'
                 raise exceptions.InvalidConfiguration(msg)
         if CONF.identity_feature_enabled.api_v3:
             if CONF.identity.uri_v3:
-                self.token_v3_client = V3TokenClient(
+                self.token_v3_client = identity.v3.V3TokenClient(
                     CONF.identity.uri_v3, **self.default_params)
             else:
                 msg = 'Identity v3 API enabled, but no identity.uri_v3 set'
@@ -423,49 +331,50 @@
         }
         params.update(self.default_params)
 
-        self.volume_qos_client = QosSpecsClient(self.auth_provider,
-                                                **params)
-        self.volume_qos_v2_client = QosSpecsV2Client(
+        self.volume_qos_client = volume.v1.QosSpecsClient(self.auth_provider,
+                                                          **params)
+        self.volume_qos_v2_client = volume.v2.QosSpecsClient(
             self.auth_provider, **params)
-        self.volume_services_client = VolumeServicesClient(
+        self.volume_services_client = volume.v1.ServicesClient(
             self.auth_provider, **params)
-        self.volume_services_v2_client = VolumeServicesV2Client(
+        self.volume_services_v2_client = volume.v2.ServicesClient(
             self.auth_provider, **params)
-        self.backups_client = BackupsClient(self.auth_provider, **params)
-        self.backups_v2_client = BackupsV2Client(self.auth_provider,
-                                                 **params)
-        self.snapshots_client = SnapshotsClient(self.auth_provider,
-                                                **params)
-        self.snapshots_v2_client = SnapshotsV2Client(self.auth_provider,
-                                                     **params)
-        self.volumes_client = VolumesClient(
+        self.backups_client = volume.v1.BackupsClient(self.auth_provider,
+                                                      **params)
+        self.backups_v2_client = volume.v2.BackupsClient(self.auth_provider,
+                                                         **params)
+        self.snapshots_client = volume.v1.SnapshotsClient(self.auth_provider,
+                                                          **params)
+        self.snapshots_v2_client = volume.v2.SnapshotsClient(
+            self.auth_provider, **params)
+        self.volumes_client = volume.v1.VolumesClient(
             self.auth_provider, default_volume_size=CONF.volume.volume_size,
             **params)
-        self.volumes_v2_client = VolumesV2Client(
+        self.volumes_v2_client = volume.v2.VolumesClient(
             self.auth_provider, default_volume_size=CONF.volume.volume_size,
             **params)
-        self.volume_messages_client = MessagesClient(self.auth_provider,
-                                                     **params)
-        self.volume_types_client = VolumeTypesClient(self.auth_provider,
-                                                     **params)
-        self.volume_types_v2_client = VolumeTypesV2Client(
+        self.volume_messages_client = volume.v3.MessagesClient(
             self.auth_provider, **params)
-        self.volume_hosts_client = VolumeHostsClient(self.auth_provider,
-                                                     **params)
-        self.volume_hosts_v2_client = VolumeHostsV2Client(
-            self.auth_provider, **params)
-        self.volume_quotas_client = VolumeQuotasClient(self.auth_provider,
-                                                       **params)
-        self.volume_quotas_v2_client = VolumeQuotasV2Client(self.auth_provider,
+        self.volume_types_client = volume.v1.TypesClient(self.auth_provider,
+                                                         **params)
+        self.volume_types_v2_client = volume.v2.TypesClient(self.auth_provider,
                                                             **params)
-        self.volumes_extension_client = VolumeExtensionsClient(
+        self.volume_hosts_client = volume.v1.HostsClient(self.auth_provider,
+                                                         **params)
+        self.volume_hosts_v2_client = volume.v2.HostsClient(self.auth_provider,
+                                                            **params)
+        self.volume_quotas_client = volume.v1.QuotasClient(self.auth_provider,
+                                                           **params)
+        self.volume_quotas_v2_client = volume.v2.QuotasClient(
             self.auth_provider, **params)
-        self.volumes_v2_extension_client = VolumeExtensionsV2Client(
+        self.volumes_extension_client = volume.v1.ExtensionsClient(
+            self.auth_provider, **params)
+        self.volumes_v2_extension_client = volume.v2.ExtensionsClient(
             self.auth_provider, **params)
         self.volume_availability_zone_client = \
-            VolumeAvailabilityZoneClient(self.auth_provider, **params)
+            volume.v1.AvailabilityZoneClient(self.auth_provider, **params)
         self.volume_v2_availability_zone_client = \
-            VolumeAvailabilityZoneV2Client(self.auth_provider, **params)
+            volume.v2.AvailabilityZoneClient(self.auth_provider, **params)
 
     def _set_object_storage_clients(self):
         params = {
@@ -475,6 +384,9 @@
         }
         params.update(self.default_params_with_timeout_values)
 
-        self.account_client = AccountClient(self.auth_provider, **params)
-        self.container_client = ContainerClient(self.auth_provider, **params)
-        self.object_client = ObjectClient(self.auth_provider, **params)
+        self.account_client = object_storage.AccountClient(self.auth_provider,
+                                                           **params)
+        self.container_client = object_storage.ContainerClient(
+            self.auth_provider, **params)
+        self.object_client = object_storage.ObjectClient(self.auth_provider,
+                                                         **params)
diff --git a/tempest/cmd/cleanup.py b/tempest/cmd/cleanup.py
index 289650f..80de6f5 100644
--- a/tempest/cmd/cleanup.py
+++ b/tempest/cmd/cleanup.py
@@ -71,9 +71,6 @@
 
 class TempestCleanup(command.Command):
 
-    def __init__(self, app, cmd):
-        super(TempestCleanup, self).__init__(app, cmd)
-
     def take_action(self, parsed_args):
         try:
             self.init(parsed_args)
diff --git a/etc/config-generator.tempest.conf b/tempest/cmd/config-generator.tempest.conf
similarity index 100%
rename from etc/config-generator.tempest.conf
rename to tempest/cmd/config-generator.tempest.conf
diff --git a/tempest/cmd/init.py b/tempest/cmd/init.py
index 77d62d3..e3788ab 100644
--- a/tempest/cmd/init.py
+++ b/tempest/cmd/init.py
@@ -18,6 +18,7 @@
 import sys
 
 from cliff import command
+from oslo_config import generator
 from oslo_log import log as logging
 from six import moves
 
@@ -39,45 +40,28 @@
 def get_tempest_default_config_dir():
     """Get default config directory of tempest
 
-    Returns the correct default config dir to support both cases of
-    tempest being or not installed in a virtualenv.
-    Cases considered:
-    - no virtual env, python2: real_prefix and base_prefix not set
-    - no virtual env, python3: real_prefix not set, base_prefix set and
-      identical to prefix
-    - virtualenv, python2: real_prefix and prefix are set and different
-    - virtualenv, python3: real_prefix not set, base_prefix and prefix are
-      set and identical
-    - pyvenv, any python version: real_prefix not set, base_prefix and prefix
-      are set and different
+    There are 3 dirs that get tried in priority order. First is /etc/tempest,
+    if that doesn't exist it looks for a tempest dir in the XDG_CONFIG_HOME
+    dir (defaulting to ~/.config/tempest) and last it tries for a
+    ~/.tempest/etc directory. If none of these exist a ~/.tempest/etc
+    directory will be created.
 
     :return: default config dir
     """
-    real_prefix = getattr(sys, 'real_prefix', None)
-    base_prefix = getattr(sys, 'base_prefix', None)
-    prefix = sys.prefix
     global_conf_dir = '/etc/tempest'
-    if (real_prefix is None and
-            (base_prefix is None or base_prefix == prefix) and
-            os.path.isdir(global_conf_dir)):
-        # Probably not running in a virtual environment.
-        # NOTE(andreaf) we cannot distinguish this case from the case of
-        # a virtual environment created with virtualenv, and running python3.
-        # Also if it appears we are not in virtual env and fail to find
-        # global config: '/etc/tempest', fall back to
-        # '[sys.prefix]/etc/tempest'
+    xdg_config = os.environ.get('XDG_CONFIG_HOME',
+                                os.path.expanduser('~/.config'))
+    user_xdg_global_path = os.path.join(xdg_config, 'tempest')
+    user_global_path = os.path.join(os.path.expanduser('~'), '.tempest/etc')
+    if os.path.isdir(global_conf_dir):
         return global_conf_dir
+    elif os.path.isdir(user_xdg_global_path):
+        return user_xdg_global_path
+    elif os.path.isdir(user_global_path):
+        return user_global_path
     else:
-        conf_dir = os.path.join(prefix, 'etc/tempest')
-        if os.path.isdir(conf_dir):
-            return conf_dir
-        else:
-            # NOTE: The prefix is gotten from the path which pyconfig.h is
-            # installed under. Some envs contain it under /usr/include, not
-            # /user/local/include. Then prefix becomes /usr on such envs.
-            # However, etc/tempest is installed under /usr/local and the bove
-            # path logic mismatches. This is a workaround for such envs.
-            return os.path.join(prefix, 'local/etc/tempest')
+        os.makedirs(user_global_path)
+        return user_global_path
 
 
 class TempestInit(command.Command):
@@ -125,19 +109,20 @@
         else:
             LOG.warning("Global config dir %s can't be found" % config_dir)
 
-    def generate_sample_config(self, local_dir, config_dir):
-        if os.path.isdir(config_dir):
-            conf_generator = os.path.join(config_dir,
-                                          'config-generator.tempest.conf')
-
-            subprocess.call(['oslo-config-generator', '--config-file',
-                             conf_generator],
-                            cwd=local_dir)
+    def generate_sample_config(self, local_dir):
+        conf_generator = os.path.join(os.path.dirname(__file__),
+                                      'config-generator.tempest.conf')
+        output_file = os.path.join(local_dir, 'etc/tempest.conf.sample')
+        if os.path.isfile(conf_generator):
+            generator.main(['--config-file', conf_generator, '--output-file',
+                            output_file])
         else:
             LOG.warning("Skipping sample config generation because global "
-                        "config dir %s can't be found" % config_dir)
+                        "config file %s can't be found" % conf_generator)
 
     def create_working_dir(self, local_dir, config_dir):
+        # make sure we are working with abspath however tempest init is called
+        local_dir = os.path.abspath(local_dir)
         # Create local dir if missing
         if not os.path.isdir(local_dir):
             LOG.debug('Creating local working dir: %s' % local_dir)
@@ -162,7 +147,7 @@
         # Create and copy local etc dir
         self.copy_config(etc_dir, config_dir)
         # Generate the sample config file
-        self.generate_sample_config(local_dir, config_dir)
+        self.generate_sample_config(local_dir)
         # Update local confs to reflect local paths
         self.update_local_conf(config_path, lock_dir, log_dir)
         # Generate a testr conf file
diff --git a/tempest/cmd/run.py b/tempest/cmd/run.py
index e78f6b0..26bd418 100644
--- a/tempest/cmd/run.py
+++ b/tempest/cmd/run.py
@@ -70,6 +70,7 @@
 
     def take_action(self, parsed_args):
         self._set_env()
+        returncode = 0
         # Local execution mode
         if os.path.isfile('.testr.conf'):
             # If you're running in local execution mode and there is not a
@@ -77,8 +78,8 @@
             if not os.path.isdir('.testrepository'):
                 returncode = run_argv(['testr', 'init'], sys.stdin, sys.stdout,
                                       sys.stderr)
-            if returncode:
-                sys.exit(returncode)
+                if returncode:
+                    sys.exit(returncode)
         else:
             print("No .testr.conf file was found for local execution")
             sys.exit(2)
diff --git a/tempest/cmd/subunit_describe_calls.py b/tempest/cmd/subunit_describe_calls.py
new file mode 100644
index 0000000..c990add
--- /dev/null
+++ b/tempest/cmd/subunit_describe_calls.py
@@ -0,0 +1,259 @@
+# Copyright 2016 Rackspace
+#
+# 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.
+
+"""
+subunit-describe-calls is a parser for subunit streams to determine what REST
+API calls are made inside of a test and in what order they are called.
+
+Runtime Arguments
+-----------------
+
+**--subunit, -s**: (Required) The path to the subunit file being parsed
+
+**--non-subunit-name, -n**: (Optional) The file_name that the logs are being
+stored in
+
+**--output-file, -o**: (Required) The path where the JSON output will be
+written to
+
+**--ports, -p**: (Optional) The path to a JSON file describing the ports being
+used by different services
+
+Usage
+-----
+
+subunit-describe-calls will take in a file path via the --subunit parameter
+which contains either a subunit v1 or v2 stream. This is then parsed checking
+for details contained in the file_bytes of the --non-subunit-name parameter
+(the default is pythonlogging which is what Tempest uses to store logs). By
+default the OpenStack Kilo release port defaults (http://bit.ly/22jpF5P)
+are used unless a file is provided via the --ports option. The resulting output
+is dumped in JSON output to the path provided in the --output-file option.
+
+Ports file JSON structure
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+  {
+      "<port number>": "<name of service>",
+      ...
+  }
+
+
+Output file JSON structure
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+  {
+      "full_test_name[with_id_and_tags]": [
+          {
+              "name": "The ClassName.MethodName that made the call",
+              "verb": "HTTP Verb",
+              "service": "Name of the service",
+              "url": "A shortened version of the URL called",
+              "status_code": "The status code of the response"
+          }
+      ]
+  }
+"""
+import argparse
+import collections
+import io
+import json
+import os
+import re
+
+import subunit
+import testtools
+
+
+class UrlParser(testtools.TestResult):
+    uuid_re = re.compile(r'(^|[^0-9a-f])[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-'
+                         '[0-9a-f]{4}-[0-9a-f]{12}([^0-9a-f]|$)')
+    id_re = re.compile(r'(^|[^0-9a-z])[0-9a-z]{8}[0-9a-z]{4}[0-9a-z]{4}'
+                       '[0-9a-z]{4}[0-9a-z]{12}([^0-9a-z]|$)')
+    ip_re = re.compile(r'(^|[^0-9])[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]'
+                       '{1,3}([^0-9]|$)')
+    url_re = re.compile(r'.*INFO.*Request \((?P<name>.*)\): (?P<code>[\d]{3}) '
+                        '(?P<verb>\w*) (?P<url>.*) .*')
+    port_re = re.compile(r'.*:(?P<port>\d+).*')
+    path_re = re.compile(r'http[s]?://[^/]*/(?P<path>.*)')
+
+    # Based on mitaka defaults:
+    # http://docs.openstack.org/mitaka/config-reference/
+    # firewalls-default-ports.html
+    services = {
+        "8776": "Block Storage",
+        "8774": "Nova",
+        "8773": "Nova-API", "8775": "Nova-API",
+        "8386": "Sahara",
+        "35357": "Keystone", "5000": "Keystone",
+        "9292": "Glance", "9191": "Glance",
+        "9696": "Neutron",
+        "6000": "Swift", "6001": "Swift", "6002": "Swift",
+        "8004": "Heat", "8000": "Heat", "8003": "Heat",
+        "8777": "Ceilometer",
+        "80": "Horizon",
+        "8080": "Swift",
+        "443": "SSL",
+        "873": "rsync",
+        "3260": "iSCSI",
+        "3306": "MySQL",
+        "5672": "AMQP"}
+
+    def __init__(self, services=None):
+        super(UrlParser, self).__init__()
+        self.test_logs = {}
+        self.services = services or self.services
+
+    def addSuccess(self, test, details=None):
+        output = test.shortDescription() or test.id()
+        calls = self.parse_details(details)
+        self.test_logs.update({output: calls})
+
+    def addSkip(self, test, err, details=None):
+        output = test.shortDescription() or test.id()
+        calls = self.parse_details(details)
+        self.test_logs.update({output: calls})
+
+    def addError(self, test, err, details=None):
+        output = test.shortDescription() or test.id()
+        calls = self.parse_details(details)
+        self.test_logs.update({output: calls})
+
+    def addFailure(self, test, err, details=None):
+        output = test.shortDescription() or test.id()
+        calls = self.parse_details(details)
+        self.test_logs.update({output: calls})
+
+    def stopTestRun(self):
+        super(UrlParser, self).stopTestRun()
+
+    def startTestRun(self):
+        super(UrlParser, self).startTestRun()
+
+    def parse_details(self, details):
+        if details is None:
+            return
+
+        calls = []
+        for _, detail in details.items():
+            for line in detail.as_text().split("\n"):
+                match = self.url_re.match(line)
+                if match is not None:
+                    calls.append({
+                        "name": match.group("name"),
+                        "verb": match.group("verb"),
+                        "status_code": match.group("code"),
+                        "service": self.get_service(match.group("url")),
+                        "url": self.url_path(match.group("url"))})
+
+        return calls
+
+    def get_service(self, url):
+        match = self.port_re.match(url)
+        if match is not None:
+            return self.services.get(match.group("port"), "Unknown")
+        return "Unknown"
+
+    def url_path(self, url):
+        match = self.path_re.match(url)
+        if match is not None:
+            path = match.group("path")
+            path = self.uuid_re.sub(r'\1<uuid>\2', path)
+            path = self.ip_re.sub(r'\1<ip>\2', path)
+            path = self.id_re.sub(r'\1<id>\2', path)
+            return path
+        return url
+
+
+class FileAccumulator(testtools.StreamResult):
+
+    def __init__(self, non_subunit_name='pythonlogging'):
+        super(FileAccumulator, self).__init__()
+        self.route_codes = collections.defaultdict(io.BytesIO)
+        self.non_subunit_name = non_subunit_name
+
+    def status(self, **kwargs):
+        if kwargs.get('file_name') != self.non_subunit_name:
+            return
+        file_bytes = kwargs.get('file_bytes')
+        if not file_bytes:
+            return
+        route_code = kwargs.get('route_code')
+        stream = self.route_codes[route_code]
+        stream.write(file_bytes)
+
+
+class ArgumentParser(argparse.ArgumentParser):
+    def __init__(self):
+        desc = "Outputs all HTTP calls a given test made that were logged."
+        super(ArgumentParser, self).__init__(description=desc)
+
+        self.prog = "Argument Parser"
+
+        self.add_argument(
+            "-s", "--subunit", metavar="<subunit file>", required=True,
+            default=None, help="The path to the subunit output file.")
+
+        self.add_argument(
+            "-n", "--non-subunit-name", metavar="<non subunit name>",
+            default="pythonlogging",
+            help="The name used in subunit to describe the file contents.")
+
+        self.add_argument(
+            "-o", "--output-file", metavar="<output file>", default=None,
+            help="The output file name for the json.", required=True)
+
+        self.add_argument(
+            "-p", "--ports", metavar="<ports file>", default=None,
+            help="A JSON file describing the ports for each service.")
+
+
+def parse(subunit_file, non_subunit_name, ports):
+    if ports is not None and os.path.exists(ports):
+        ports = json.loads(open(ports).read())
+
+    url_parser = UrlParser(ports)
+    stream = open(subunit_file, 'rb')
+    suite = subunit.ByteStreamToStreamResult(
+        stream, non_subunit_name=non_subunit_name)
+    result = testtools.StreamToExtendedDecorator(url_parser)
+    accumulator = FileAccumulator(non_subunit_name)
+    result = testtools.StreamResultRouter(result)
+    result.add_rule(accumulator, 'test_id', test_id=None)
+    result.startTestRun()
+    suite.run(result)
+
+    for bytes_io in accumulator.route_codes.values():  # v1 processing
+        bytes_io.seek(0)
+        suite = subunit.ProtocolTestCase(bytes_io)
+        suite.run(url_parser)
+    result.stopTestRun()
+
+    return url_parser
+
+
+def output(url_parser, output_file):
+    with open(output_file, "w") as outfile:
+        outfile.write(json.dumps(url_parser.test_logs))
+
+
+def entry_point():
+    cl_args = ArgumentParser().parse_args()
+    parser = parse(cl_args.subunit, cl_args.non_subunit_name, cl_args.ports)
+    output(parser, cl_args.output_file)
+
+
+if __name__ == "__main__":
+    entry_point()
diff --git a/tempest/cmd/verify_tempest_config.py b/tempest/cmd/verify_tempest_config.py
index 4b12ecb..77b88f9 100644
--- a/tempest/cmd/verify_tempest_config.py
+++ b/tempest/cmd/verify_tempest_config.py
@@ -285,7 +285,6 @@
         'data_processing': 'sahara',
         'baremetal': 'ironic',
         'identity': 'keystone',
-        'database': 'trove'
     }
     # Get catalog list for endpoints to use for validation
     _token, auth_data = os.auth_provider.get_auth()
diff --git a/tempest/common/dynamic_creds.py b/tempest/common/dynamic_creds.py
index b0c01f5..c9b9db1 100644
--- a/tempest/common/dynamic_creds.py
+++ b/tempest/common/dynamic_creds.py
@@ -159,7 +159,10 @@
         # it must beassigned a role on the project. So we need to ensure that
         # our newly created user has a role on the newly created project.
         if self.identity_version == 'v3' and not role_assigned:
-            self.creds_client.create_user_role('Member')
+            try:
+                self.creds_client.create_user_role('Member')
+            except lib_exc.Conflict:
+                LOG.warning('Member role already exists, ignoring conflict.')
             self.creds_client.assign_user_role(user, project, 'Member')
 
         creds = self.creds_client.get_credentials(user, project, user_password)
diff --git a/tempest/common/image.py b/tempest/common/image.py
index 42ce5ac..72e3a72 100644
--- a/tempest/common/image.py
+++ b/tempest/common/image.py
@@ -13,6 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import copy
+
+import six
+
 
 def get_image_meta_from_headers(resp):
     meta = {'properties': {}}
@@ -36,3 +40,23 @@
             except ValueError:
                 pass
     return meta
+
+
+def image_meta_to_headers(**metadata):
+    headers = {}
+    fields_copy = copy.deepcopy(metadata)
+
+    copy_from = fields_copy.pop('copy_from', None)
+    if copy_from is not None:
+        headers['x-glance-api-copy-from'] = copy_from
+
+    for key, value in six.iteritems(fields_copy.pop('properties', {})):
+        headers['x-image-meta-property-%s' % key] = str(value)
+
+    for key, value in six.iteritems(fields_copy.pop('api', {})):
+        headers['x-glance-api-property-%s' % key] = str(value)
+
+    for key, value in six.iteritems(fields_copy):
+        headers['x-image-meta-%s' % key] = str(value)
+
+    return headers
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index d8dad69..e083167 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -20,7 +20,7 @@
 from tempest import exceptions
 from tempest.lib.common.utils import misc as misc_utils
 from tempest.lib import exceptions as lib_exc
-from tempest.services.image.v1.json import images_client as images_v1_client
+from tempest.lib.services.image.v1 import images_client as images_v1_client
 
 CONF = config.CONF
 LOG = logging.getLogger(__name__)
diff --git a/tempest/config.py b/tempest/config.py
index a9cf537..eb5e23a 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -811,21 +811,6 @@
                 help="Execute discoverability tests"),
 ]
 
-database_group = cfg.OptGroup(name='database',
-                              title='Database Service Options')
-
-DatabaseGroup = [
-    cfg.StrOpt('catalog_type',
-               default='database',
-               help="Catalog type of the Database service."),
-    cfg.StrOpt('db_flavor_ref',
-               default="1",
-               help="Valid primary flavor to use in database tests."),
-    cfg.StrOpt('db_current_version',
-               default="v1.0",
-               help="Current database version to use in database tests."),
-]
-
 orchestration_group = cfg.OptGroup(name='orchestration',
                                    title='Orchestration Service Options')
 
@@ -1002,9 +987,6 @@
     cfg.BoolOpt('ironic',
                 default=False,
                 help="Whether or not Ironic is expected to be available"),
-    cfg.BoolOpt('trove',
-                default=False,
-                help="Whether or not Trove is expected to be available"),
 ]
 
 debug_group = cfg.OptGroup(name="debug",
@@ -1035,23 +1017,28 @@
 
 input_scenario_group = cfg.OptGroup(name="input-scenario",
                                     title="Filters and values for"
-                                          " input scenarios")
+                                          " input scenarios[DEPRECATED]")
+
 
 InputScenarioGroup = [
     cfg.StrOpt('image_regex',
                default='^cirros-0.3.1-x86_64-uec$',
-               help="Matching images become parameters for scenario tests"),
+               help="Matching images become parameters for scenario tests",
+               deprecated_for_removal=True),
     cfg.StrOpt('flavor_regex',
                default='^m1.nano$',
-               help="Matching flavors become parameters for scenario tests"),
+               help="Matching flavors become parameters for scenario tests",
+               deprecated_for_removal=True),
     cfg.StrOpt('non_ssh_image_regex',
                default='^.*[Ww]in.*$',
                help="SSH verification in tests is skipped"
-                    "for matching images"),
+                    "for matching images",
+               deprecated_for_removal=True),
     cfg.StrOpt('ssh_user_regex',
                default="[[\"^.*[Cc]irros.*$\", \"cirros\"]]",
                help="List of user mapped to regex "
-                    "to matching image names."),
+                    "to matching image names.",
+               deprecated_for_removal=True),
 ]
 
 
@@ -1136,7 +1123,6 @@
     (volume_feature_group, VolumeFeaturesGroup),
     (object_storage_group, ObjectStoreGroup),
     (object_storage_feature_group, ObjectStoreFeaturesGroup),
-    (database_group, DatabaseGroup),
     (orchestration_group, OrchestrationGroup),
     (data_processing_group, DataProcessingGroup),
     (data_processing_feature_group, DataProcessingFeaturesGroup),
@@ -1203,7 +1189,6 @@
         self.object_storage = _CONF['object-storage']
         self.object_storage_feature_enabled = _CONF[
             'object-storage-feature-enabled']
-        self.database = _CONF.database
         self.orchestration = _CONF.orchestration
         self.data_processing = _CONF['data-processing']
         self.data_processing_feature_enabled = _CONF[
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 09106d1..e2d6585 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -19,7 +19,7 @@
 
 
 PYTHON_CLIENTS = ['cinder', 'glance', 'keystone', 'nova', 'swift', 'neutron',
-                  'trove', 'ironic', 'savanna', 'heat', 'sahara']
+                  'ironic', 'savanna', 'heat', 'sahara']
 
 PYTHON_CLIENT_RE = re.compile('import (%s)client' % '|'.join(PYTHON_CLIENTS))
 TEST_DEFINITION = re.compile(r'^\s*def test.*')
diff --git a/tempest/lib/common/utils/data_utils.py b/tempest/lib/common/utils/data_utils.py
index f9f0c83..7fcec8c 100644
--- a/tempest/lib/common/utils/data_utils.py
+++ b/tempest/lib/common/utils/data_utils.py
@@ -154,7 +154,7 @@
     This generates a string with an arbitrary number of characters, generated
     by looping the base_text string. If the size is smaller than the size of
     base_text, returning string is shrinked to the size.
-    :param int size: a returning charactors size
+    :param int size: a returning characters size
     :param str base_text: a string you want to repeat
     :return: size string
     :rtype: string
diff --git a/tempest/lib/services/compute/aggregates_client.py b/tempest/lib/services/compute/aggregates_client.py
index 168126c..ae747d8 100644
--- a/tempest/lib/services/compute/aggregates_client.py
+++ b/tempest/lib/services/compute/aggregates_client.py
@@ -108,7 +108,11 @@
         return rest_client.ResponseBody(resp, body)
 
     def set_metadata(self, aggregate_id, **kwargs):
-        """Replace the aggregate's existing metadata with new metadata."""
+        """Replace the aggregate's existing metadata with new metadata.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-compute-v2.1.html#addAggregateMetadata
+        """
         post_body = json.dumps({'set_metadata': kwargs})
         resp, body = self.post('os-aggregates/%s/action' % aggregate_id,
                                post_body)
diff --git a/tempest/lib/services/compute/base_compute_client.py b/tempest/lib/services/compute/base_compute_client.py
index 433c94c..a706a79 100644
--- a/tempest/lib/services/compute/base_compute_client.py
+++ b/tempest/lib/services/compute/base_compute_client.py
@@ -36,11 +36,6 @@
 
     api_microversion_header_name = 'X-OpenStack-Nova-API-Version'
 
-    def __init__(self, auth_provider, service, region,
-                 **kwargs):
-        super(BaseComputeClient, self).__init__(
-            auth_provider, service, region, **kwargs)
-
     def get_headers(self):
         headers = super(BaseComputeClient, self).get_headers()
         if COMPUTE_MICROVERSION:
diff --git a/tempest/lib/services/compute/flavors_client.py b/tempest/lib/services/compute/flavors_client.py
index e377c84..0d80a82 100644
--- a/tempest/lib/services/compute/flavors_client.py
+++ b/tempest/lib/services/compute/flavors_client.py
@@ -52,7 +52,7 @@
         """Create a new flavor or instance type.
 
         Available params: see http://developer.openstack.org/
-                              api-ref-compute-v2.1.html#create-flavors
+                              api-ref-compute-v2.1.html#createFlavor
         """
         if kwargs.get('ephemeral'):
             kwargs['OS-FLV-EXT-DATA:ephemeral'] = kwargs.pop('ephemeral')
diff --git a/tempest/lib/services/image/__init__.py b/tempest/lib/services/image/__init__.py
index e69de29..4b01663 100644
--- a/tempest/lib/services/image/__init__.py
+++ b/tempest/lib/services/image/__init__.py
@@ -0,0 +1,18 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise 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.lib.services.image import v1
+from tempest.lib.services.image import v2
+
+__all__ = ['v1', 'v2']
diff --git a/tempest/lib/services/image/v1/__init__.py b/tempest/lib/services/image/v1/__init__.py
index e69de29..9bd8262 100644
--- a/tempest/lib/services/image/v1/__init__.py
+++ b/tempest/lib/services/image/v1/__init__.py
@@ -0,0 +1,19 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise 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.lib.services.image.v1.image_members_client import \
+    ImageMembersClient
+from tempest.lib.services.image.v1.images_client import ImagesClient
+
+__all__ = ['ImageMembersClient', 'ImagesClient']
diff --git a/tempest/services/image/v1/json/images_client.py b/tempest/lib/services/image/v1/images_client.py
similarity index 82%
rename from tempest/services/image/v1/json/images_client.py
rename to tempest/lib/services/image/v1/images_client.py
index 5680668..0db98f8 100644
--- a/tempest/services/image/v1/json/images_client.py
+++ b/tempest/lib/services/image/v1/images_client.py
@@ -13,11 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import copy
 import functools
 
 from oslo_serialization import jsonutils as json
-import six
 from six.moves.urllib import parse as urllib
 
 from tempest.lib.common import rest_client
@@ -29,20 +27,6 @@
 class ImagesClient(rest_client.RestClient):
     api_version = "v1"
 
-    def _image_meta_to_headers(self, fields):
-        headers = {}
-        fields_copy = copy.deepcopy(fields)
-        copy_from = fields_copy.pop('copy_from', None)
-        if copy_from is not None:
-            headers['x-glance-api-copy-from'] = copy_from
-        for key, value in six.iteritems(fields_copy.pop('properties', {})):
-            headers['x-image-meta-property-%s' % key] = str(value)
-        for key, value in six.iteritems(fields_copy.pop('api', {})):
-            headers['x-glance-api-property-%s' % key] = str(value)
-        for key, value in six.iteritems(fields_copy):
-            headers['x-image-meta-%s' % key] = str(value)
-        return headers
-
     def _create_with_data(self, headers, data):
         # We are going to do chunked transfert, so split the input data
         # info fixed-sized chunks.
@@ -74,14 +58,14 @@
             self._http = self._get_http()
         return self._http
 
-    def create_image(self, data=None, **kwargs):
+    def create_image(self, data=None, headers=None):
         """Create an image.
 
         Available params: http://developer.openstack.org/
                           api-ref-image-v1.html#createImage-v1
         """
-        headers = {}
-        headers.update(self._image_meta_to_headers(kwargs))
+        if headers is None:
+            headers = {}
 
         if data is not None:
             return self._create_with_data(headers, data)
@@ -91,14 +75,14 @@
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
-    def update_image(self, image_id, data=None, **kwargs):
+    def update_image(self, image_id, data=None, headers=None):
         """Update an image.
 
         Available params: http://developer.openstack.org/
                           api-ref-image-v1.html#updateImage-v1
         """
-        headers = {}
-        headers.update(self._image_meta_to_headers(kwargs))
+        if headers is None:
+            headers = {}
 
         if data is not None:
             return self._update_with_data(image_id, headers, data)
@@ -130,10 +114,6 @@
         if detail:
             url += '/detail'
 
-        properties = kwargs.pop('properties', {})
-        for key, value in six.iteritems(properties):
-            kwargs['property-%s' % key] = value
-
         if kwargs.get('changes_since'):
             kwargs['changes-since'] = kwargs.pop('changes_since')
 
diff --git a/tempest/lib/services/image/v2/__init__.py b/tempest/lib/services/image/v2/__init__.py
index e69de29..32bad8b 100644
--- a/tempest/lib/services/image/v2/__init__.py
+++ b/tempest/lib/services/image/v2/__init__.py
@@ -0,0 +1,24 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise 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.lib.services.image.v2.image_members_client import \
+    ImageMembersClient
+from tempest.lib.services.image.v2.images_client import ImagesClient
+from tempest.lib.services.image.v2.namespaces_client import NamespacesClient
+from tempest.lib.services.image.v2.resource_types_client import \
+    ResourceTypesClient
+from tempest.lib.services.image.v2.schemas_client import SchemasClient
+
+__all__ = ['ImageMembersClient', 'ImagesClient', 'NamespacesClient',
+           'ResourceTypesClient', 'SchemasClient']
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index dd6e0e5..f889c44 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -79,8 +79,6 @@
         cls.security_groups_client = cls.manager.security_groups_client
         cls.security_group_rules_client = (
             cls.manager.security_group_rules_client)
-        # Heat client
-        cls.orchestration_client = cls.manager.orchestration_client
 
         if CONF.volume_feature_enabled.api_v1:
             cls.volumes_client = cls.manager.volumes_client
@@ -388,6 +386,7 @@
         if CONF.image_feature_enabled.api_v1:
             params['is_public'] = 'False'
             params['properties'] = properties
+            params = {'headers': common_image.image_meta_to_headers(**params)}
         else:
             params['visibility'] = 'private'
             # Additional properties are flattened out in the v2 API.
@@ -1037,7 +1036,7 @@
         if not tenant_id:
             tenant_id = client.tenant_id
         sgs = [
-            sg for sg in client.list_security_groups().values()[0]
+            sg for sg in list(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)
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index a9f2dff..80728dc 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -20,15 +20,12 @@
 from tempest import config
 from tempest import exceptions
 from tempest.scenario import manager
-from tempest.scenario import utils as test_utils
 from tempest import test
 
 CONF = config.CONF
 
 LOG = logging.getLogger(__name__)
 
-load_tests = test_utils.load_tests_input_scenario_utils
-
 
 class TestServerBasicOps(manager.ScenarioTest):
 
@@ -47,27 +44,10 @@
 
     def setUp(self):
         super(TestServerBasicOps, self).setUp()
-        # Setup image and flavor the test instance
-        # Support both configured and injected values
-        if not hasattr(self, 'image_ref'):
-            self.image_ref = CONF.compute.image_ref
-        if not hasattr(self, 'flavor_ref'):
-            self.flavor_ref = CONF.compute.flavor_ref
-        self.image_utils = test_utils.ImageUtils(self.manager)
-        if not self.image_utils.is_flavor_enough(self.flavor_ref,
-                                                 self.image_ref):
-            raise self.skipException(
-                '{image} does not fit in {flavor}'.format(
-                    image=self.image_ref, flavor=self.flavor_ref
-                )
-            )
-        self.run_ssh = CONF.validation.run_validation and \
-            self.image_utils.is_sshable_image(self.image_ref)
-        self.ssh_user = self.image_utils.ssh_user(self.image_ref)
-        LOG.debug('Starting test for i:{image}, f:{flavor}. '
-                  'Run ssh: {ssh}, user: {ssh_user}'.format(
-                      image=self.image_ref, flavor=self.flavor_ref,
-                      ssh=self.run_ssh, ssh_user=self.ssh_user))
+        self.image_ref = CONF.compute.image_ref
+        self.flavor_ref = CONF.compute.flavor_ref
+        self.run_ssh = CONF.validation.run_validation
+        self.ssh_user = CONF.validation.image_ssh_user
 
     def verify_ssh(self, keypair):
         if self.run_ssh:
@@ -76,7 +56,7 @@
             # Check ssh
             self.ssh_client = self.get_remote_client(
                 ip_address=self.fip,
-                username=self.image_utils.ssh_user(self.image_ref),
+                username=self.ssh_user,
                 private_key=keypair['private_key'])
 
     def verify_metadata(self):
diff --git a/tempest/scenario/utils.py b/tempest/scenario/utils.py
deleted file mode 100644
index c7ba659..0000000
--- a/tempest/scenario/utils.py
+++ /dev/null
@@ -1,185 +0,0 @@
-# Copyright 2013 Hewlett-Packard, Ltd.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-
-import re
-import string
-import unicodedata
-
-from oslo_serialization import jsonutils as json
-import testscenarios
-import testtools
-
-from tempest import clients
-from tempest.common import credentials_factory as credentials
-from tempest import config
-from tempest.lib.common.utils import misc
-from tempest.lib import exceptions as exc_lib
-
-CONF = config.CONF
-
-
-class ImageUtils(object):
-
-    default_ssh_user = 'root'
-
-    def __init__(self, os):
-        # Load configuration items
-        self.ssh_users = json.loads(CONF.input_scenario.ssh_user_regex)
-        self.non_ssh_image_pattern = \
-            CONF.input_scenario.non_ssh_image_regex
-        # Setup clients
-        self.compute_images_client = os.compute_images_client
-        self.flavors_client = os.flavors_client
-
-    def ssh_user(self, image_id):
-        _image = self.compute_images_client.show_image(image_id)['image']
-        for regex, user in self.ssh_users:
-            # First match wins
-            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']))
-
-    def is_sshable_image(self, image_id):
-        _image = self.compute_images_client.show_image(image_id)['image']
-        return self._is_sshable_image(_image)
-
-    def _is_flavor_enough(self, flavor, image):
-        return image['minDisk'] <= flavor['disk']
-
-    def is_flavor_enough(self, flavor_id, image_id):
-        _image = self.compute_images_client.show_image(image_id)['image']
-        _flavor = self.flavors_client.show_flavor(flavor_id)['flavor']
-        return self._is_flavor_enough(_flavor, _image)
-
-
-@misc.singleton
-class InputScenarioUtils(object):
-
-    """Example usage:
-
-    import testscenarios
-    (...)
-    load_tests = testscenarios.load_tests_apply_scenarios
-
-
-    class TestInputScenario(manager.ScenarioTest):
-
-        scenario_utils = utils.InputScenarioUtils()
-        scenario_flavor = scenario_utils.scenario_flavors
-        scenario_image = scenario_utils.scenario_images
-        scenarios = testscenarios.multiply_scenarios(scenario_image,
-                                                     scenario_flavor)
-
-        def test_create_server_metadata(self):
-            name = rand_name('instance')
-            self.servers_client.create_server(name=name,
-                                              flavorRef=self.flavor_ref,
-                                              imageRef=self.image_ref)
-    """
-    validchars = "-_.{ascii}{digit}".format(ascii=string.ascii_letters,
-                                            digit=string.digits)
-
-    def __init__(self):
-        network_resources = {
-            'network': False,
-            'router': False,
-            'subnet': False,
-            'dhcp': False,
-        }
-        self.cred_provider = credentials.get_credentials_provider(
-            name='InputScenarioUtils',
-            identity_version=CONF.identity.auth_version,
-            network_resources=network_resources)
-        os = clients.Manager(
-            self.cred_provider.get_primary_creds().credentials)
-        self.compute_images_client = os.compute_images_client
-        self.flavors_client = os.flavors_client
-        self.image_pattern = CONF.input_scenario.image_regex
-        self.flavor_pattern = CONF.input_scenario.flavor_regex
-
-    def _normalize_name(self, name):
-        nname = unicodedata.normalize('NFKD', name).encode('ASCII', 'ignore')
-        nname = ''.join(c for c in nname if c in self.validchars)
-        return nname
-
-    def clear_creds(self):
-        self.cred_provider.clear_creds()
-
-    @property
-    def scenario_images(self):
-        """:return: a scenario with name and uuid of images"""
-        if not CONF.service_available.glance:
-            return []
-        if not hasattr(self, '_scenario_images'):
-            try:
-                images = self.compute_images_client.list_images()['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']))
-                ]
-            except Exception:
-                self._scenario_images = []
-        return self._scenario_images
-
-    @property
-    def scenario_flavors(self):
-        """:return: a scenario with name and uuid of flavors"""
-        if not hasattr(self, '_scenario_flavors'):
-            try:
-                flavors = self.flavors_client.list_flavors()['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']))
-                ]
-            except Exception:
-                self._scenario_flavors = []
-        return self._scenario_flavors
-
-
-def load_tests_input_scenario_utils(*args):
-    """Wrapper for testscenarios to set the scenarios
-
-    The purpose is to avoid running a getattr on the CONF object at import.
-    """
-
-    if getattr(args[0], 'suiteClass', None) is not None:
-        loader, standard_tests, pattern = args
-    else:
-        standard_tests, module, loader = args
-    output = None
-    scenario_utils = None
-    try:
-        scenario_utils = InputScenarioUtils()
-        scenario_flavor = scenario_utils.scenario_flavors
-        scenario_image = scenario_utils.scenario_images
-    except (exc_lib.InvalidCredentials, TypeError):
-        output = standard_tests
-    finally:
-        if scenario_utils:
-            scenario_utils.clear_creds()
-    if output is not None:
-        return output
-    for test in testtools.iterate_tests(standard_tests):
-        setattr(test, 'scenarios', testscenarios.multiply_scenarios(
-            scenario_image,
-            scenario_flavor))
-    return testscenarios.load_tests_apply_scenarios(*args)
diff --git a/tempest/services/baremetal/__init__.py b/tempest/services/baremetal/__init__.py
index e69de29..390f40a 100644
--- a/tempest/services/baremetal/__init__.py
+++ b/tempest/services/baremetal/__init__.py
@@ -0,0 +1,18 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise 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.services.baremetal.v1.json.baremetal_client import \
+    BaremetalClient
+
+__all__ = ['BaremetalClient']
diff --git a/tempest/services/data_processing/__init__.py b/tempest/services/data_processing/__init__.py
index e69de29..c49bc5c 100644
--- a/tempest/services/data_processing/__init__.py
+++ b/tempest/services/data_processing/__init__.py
@@ -0,0 +1,18 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise 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.services.data_processing.v1_1.data_processing_client import \
+    DataProcessingClient
+
+__all__ = ['DataProcessingClient']
diff --git a/tempest/services/database/__init__.py b/tempest/services/database/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/database/__init__.py
+++ /dev/null
diff --git a/tempest/services/database/json/__init__.py b/tempest/services/database/json/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/database/json/__init__.py
+++ /dev/null
diff --git a/tempest/services/database/json/flavors_client.py b/tempest/services/database/json/flavors_client.py
deleted file mode 100644
index bd8ffb0..0000000
--- a/tempest/services/database/json/flavors_client.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# 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 oslo_serialization import jsonutils as json
-from six.moves import urllib
-
-from tempest.lib.common import rest_client
-
-
-class DatabaseFlavorsClient(rest_client.RestClient):
-
-    def list_db_flavors(self, params=None):
-        url = 'flavors'
-        if params:
-            url += '?%s' % urllib.parse.urlencode(params)
-
-        resp, body = self.get(url)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return rest_client.ResponseBody(resp, body)
-
-    def show_db_flavor(self, db_flavor_id):
-        resp, body = self.get("flavors/%s" % db_flavor_id)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/database/json/limits_client.py b/tempest/services/database/json/limits_client.py
deleted file mode 100644
index a1c58c2..0000000
--- a/tempest/services/database/json/limits_client.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# 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 oslo_serialization import jsonutils as json
-from six.moves.urllib import parse as urllib
-
-from tempest.lib.common import rest_client
-
-
-class DatabaseLimitsClient(rest_client.RestClient):
-
-    def list_db_limits(self, params=None):
-        """List all limits."""
-        url = 'limits'
-        if params:
-            url += '?%s' % urllib.urlencode(params)
-        resp, body = self.get(url)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/database/json/versions_client.py b/tempest/services/database/json/versions_client.py
deleted file mode 100644
index 2f28203..0000000
--- a/tempest/services/database/json/versions_client.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# 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 oslo_serialization import jsonutils as json
-from six.moves.urllib import parse as urllib
-
-from tempest.lib.common import rest_client
-
-
-class DatabaseVersionsClient(rest_client.RestClient):
-
-    def __init__(self, auth_provider, service, region, **kwargs):
-        super(DatabaseVersionsClient, self).__init__(
-            auth_provider, service, region, **kwargs)
-        self.skip_path()
-
-    def list_db_versions(self, params=None):
-        """List all versions."""
-        url = ''
-        if params:
-            url += '?%s' % urllib.urlencode(params)
-
-        resp, body = self.get(url)
-        self.expected_success(200, resp.status)
-        body = json.loads(body)
-        return rest_client.ResponseBody(resp, body)
diff --git a/tempest/services/identity/__init__.py b/tempest/services/identity/__init__.py
index e69de29..0e24926 100644
--- a/tempest/services/identity/__init__.py
+++ b/tempest/services/identity/__init__.py
@@ -0,0 +1,18 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise 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.services.identity import v2
+from tempest.services.identity import v3
+
+__all__ = ['v2', 'v3']
diff --git a/tempest/services/identity/v2/__init__.py b/tempest/services/identity/v2/__init__.py
index e69de29..6f4ebcf 100644
--- a/tempest/services/identity/v2/__init__.py
+++ b/tempest/services/identity/v2/__init__.py
@@ -0,0 +1,24 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise 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.lib.services.identity.v2.endpoints_client import EndpointsClient
+from tempest.lib.services.identity.v2.token_client import TokenClient
+from tempest.services.identity.v2.json.identity_client import IdentityClient
+from tempest.services.identity.v2.json.roles_client import RolesClient
+from tempest.services.identity.v2.json.services_client import ServicesClient
+from tempest.services.identity.v2.json.tenants_client import TenantsClient
+from tempest.services.identity.v2.json.users_client import UsersClient
+
+__all__ = ['EndpointsClient', 'TokenClient', 'IdentityClient', 'RolesClient',
+           'ServicesClient', 'TenantsClient', 'UsersClient']
diff --git a/tempest/services/identity/v2/json/users_client.py b/tempest/services/identity/v2/json/users_client.py
index 1048840..4ea17f9 100644
--- a/tempest/services/identity/v2/json/users_client.py
+++ b/tempest/services/identity/v2/json/users_client.py
@@ -78,7 +78,7 @@
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
-    def enable_disable_user(self, user_id, **kwargs):
+    def update_user_enabled(self, user_id, **kwargs):
         """Enables or disables a user.
 
         Available params: see http://developer.openstack.org/
@@ -121,7 +121,7 @@
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
-    def create_user_ec2_credentials(self, user_id, **kwargs):
+    def create_user_ec2_credential(self, user_id, **kwargs):
         # TODO(piyush): Current api-site doesn't contain this API description.
         # After fixing the api-site, we need to fix here also for putting the
         # link to api-site.
@@ -132,7 +132,7 @@
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
-    def delete_user_ec2_credentials(self, user_id, access):
+    def delete_user_ec2_credential(self, user_id, access):
         resp, body = self.delete('/users/%s/credentials/OS-EC2/%s' %
                                  (user_id, access))
         self.expected_success(204, resp.status)
@@ -144,7 +144,7 @@
         body = json.loads(body)
         return rest_client.ResponseBody(resp, body)
 
-    def show_user_ec2_credentials(self, user_id, access):
+    def show_user_ec2_credential(self, user_id, access):
         resp, body = self.get('/users/%s/credentials/OS-EC2/%s' %
                               (user_id, access))
         self.expected_success(200, resp.status)
diff --git a/tempest/services/identity/v3/__init__.py b/tempest/services/identity/v3/__init__.py
index e69de29..144c5a9 100644
--- a/tempest/services/identity/v3/__init__.py
+++ b/tempest/services/identity/v3/__init__.py
@@ -0,0 +1,33 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise 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.lib.services.identity.v3.token_client import V3TokenClient
+from tempest.services.identity.v3.json.credentials_client import \
+    CredentialsClient
+from tempest.services.identity.v3.json.domains_client import DomainsClient
+from tempest.services.identity.v3.json.endpoints_client import EndPointsClient
+from tempest.services.identity.v3.json.groups_client import GroupsClient
+from tempest.services.identity.v3.json.identity_client import IdentityClient
+from tempest.services.identity.v3.json.policies_client import PoliciesClient
+from tempest.services.identity.v3.json.projects_client import ProjectsClient
+from tempest.services.identity.v3.json.regions_client import RegionsClient
+from tempest.services.identity.v3.json.roles_client import RolesClient
+from tempest.services.identity.v3.json.services_client import ServicesClient
+from tempest.services.identity.v3.json.trusts_client import TrustsClient
+from tempest.services.identity.v3.json.users_clients import UsersClient
+
+__all__ = ['V3TokenClient', 'CredentialsClient', 'DomainsClient',
+           'EndPointsClient', 'GroupsClient', 'IdentityClient',
+           'PoliciesClient', 'ProjectsClient', 'RegionsClient', 'RolesClient',
+           'ServicesClient', 'TrustsClient', 'UsersClient', ]
diff --git a/tempest/services/image/__init__.py b/tempest/services/image/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/image/__init__.py
+++ /dev/null
diff --git a/tempest/services/image/v1/__init__.py b/tempest/services/image/v1/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/image/v1/__init__.py
+++ /dev/null
diff --git a/tempest/services/image/v1/json/__init__.py b/tempest/services/image/v1/json/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/tempest/services/image/v1/json/__init__.py
+++ /dev/null
diff --git a/tempest/services/object_storage/__init__.py b/tempest/services/object_storage/__init__.py
index e69de29..96fe4a3 100644
--- a/tempest/services/object_storage/__init__.py
+++ b/tempest/services/object_storage/__init__.py
@@ -0,0 +1,19 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise 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.services.object_storage.account_client import AccountClient
+from tempest.services.object_storage.container_client import ContainerClient
+from tempest.services.object_storage.object_client import ObjectClient
+
+__all__ = ['AccountClient', 'ContainerClient', 'ObjectClient']
diff --git a/tempest/services/orchestration/__init__.py b/tempest/services/orchestration/__init__.py
index e69de29..5a1ffcc 100644
--- a/tempest/services/orchestration/__init__.py
+++ b/tempest/services/orchestration/__init__.py
@@ -0,0 +1,18 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise 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.services.orchestration.json.orchestration_client import \
+    OrchestrationClient
+
+__all__ = ['OrchestrationClient']
diff --git a/tempest/services/volume/__init__.py b/tempest/services/volume/__init__.py
index e69de29..4d29cdd 100644
--- a/tempest/services/volume/__init__.py
+++ b/tempest/services/volume/__init__.py
@@ -0,0 +1,19 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise 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.services.volume import v1
+from tempest.services.volume import v2
+from tempest.services.volume import v3
+
+__all__ = ['v1', 'v2', 'v3']
diff --git a/tempest/services/volume/base/base_backups_client.py b/tempest/services/volume/base/base_backups_client.py
index 780da7b..3842d66 100644
--- a/tempest/services/volume/base/base_backups_client.py
+++ b/tempest/services/volume/base/base_backups_client.py
@@ -26,7 +26,11 @@
     """Client class to send CRUD Volume backup API requests"""
 
     def create_backup(self, **kwargs):
-        """Creates a backup of volume."""
+        """Creates a backup of volume.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-blockstorage-v2.html#createBackup
+        """
         post_body = json.dumps({'backup': kwargs})
         resp, body = self.post('backups', post_body)
         body = json.loads(body)
@@ -34,7 +38,11 @@
         return rest_client.ResponseBody(resp, body)
 
     def restore_backup(self, backup_id, **kwargs):
-        """Restore volume from backup."""
+        """Restore volume from backup.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-blockstorage-v2.html#restoreBackup
+        """
         post_body = json.dumps({'restore': kwargs})
         resp, body = self.post('backups/%s/restore' % (backup_id), post_body)
         body = json.loads(body)
diff --git a/tempest/services/volume/base/base_snapshots_client.py b/tempest/services/volume/base/base_snapshots_client.py
index 68503dd..da7bb01 100644
--- a/tempest/services/volume/base/base_snapshots_client.py
+++ b/tempest/services/volume/base/base_snapshots_client.py
@@ -60,7 +60,11 @@
         return rest_client.ResponseBody(resp, body)
 
     def update_snapshot(self, snapshot_id, **kwargs):
-        """Updates a snapshot."""
+        """Updates a snapshot.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-blockstorage-v2.html#updateSnapshot
+        """
         put_body = json.dumps({'snapshot': kwargs})
         resp, body = self.put('snapshots/%s' % snapshot_id, put_body)
         body = json.loads(body)
@@ -123,11 +127,11 @@
         return rest_client.ResponseBody(resp, body)
 
     def update_snapshot_metadata(self, snapshot_id, **kwargs):
-        """Update metadata for the snapshot."""
-        # TODO(piyush): Current api-site doesn't contain this API description.
-        # After fixing the api-site, we need to fix here also for putting the
-        # link to api-site.
-        # LP: https://bugs.launchpad.net/openstack-api-site/+bug/1529063
+        """Update metadata for the snapshot.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-blockstorage-v2.html#updateSnapshotMetadata
+        """
         put_body = json.dumps(kwargs)
         url = "snapshots/%s/metadata" % str(snapshot_id)
         resp, body = self.put(url, put_body)
diff --git a/tempest/services/volume/base/base_volumes_client.py b/tempest/services/volume/base/base_volumes_client.py
old mode 100644
new mode 100755
index 6237745..d694c53
--- a/tempest/services/volume/base/base_volumes_client.py
+++ b/tempest/services/volume/base/base_volumes_client.py
@@ -96,7 +96,11 @@
         return rest_client.ResponseBody(resp, body)
 
     def update_volume(self, volume_id, **kwargs):
-        """Updates the Specified Volume."""
+        """Updates the Specified Volume.
+
+        Available params: see http://developer.openstack.org/
+                                api-ref-blockstorage-v2.html#updateVolume
+        """
         put_body = json.dumps({'volume': kwargs})
         resp, body = self.put('volumes/%s' % volume_id, put_body)
         body = json.loads(body)
@@ -119,7 +123,11 @@
         return rest_client.ResponseBody(resp, body)
 
     def attach_volume(self, volume_id, **kwargs):
-        """Attaches a volume to a given instance on a given mountpoint."""
+        """Attaches a volume to a given instance on a given mountpoint.
+
+        Available params: see http://developer.openstack.org/
+                                api-ref-blockstorage-v2.html#attachVolume
+        """
         post_body = json.dumps({'os-attach': kwargs})
         url = 'volumes/%s/action' % (volume_id)
         resp, body = self.post(url, post_body)
@@ -171,7 +179,11 @@
         return 'volume'
 
     def extend_volume(self, volume_id, **kwargs):
-        """Extend a volume."""
+        """Extend a volume.
+
+        Available params: see http://developer.openstack.org/
+                                api-ref-blockstorage-v2.html#extendVolume
+        """
         post_body = json.dumps({'os-extend': kwargs})
         url = 'volumes/%s/action' % (volume_id)
         resp, body = self.post(url, post_body)
@@ -179,7 +191,11 @@
         return rest_client.ResponseBody(resp, body)
 
     def reset_volume_status(self, volume_id, **kwargs):
-        """Reset the Specified Volume's Status."""
+        """Reset the Specified Volume's Status.
+
+        Available params: see http://developer.openstack.org/
+                                api-ref-blockstorage-v2.html#resetVolume
+        """
         post_body = json.dumps({'os-reset_status': kwargs})
         resp, body = self.post('volumes/%s/action' % volume_id, post_body)
         self.expected_success(202, resp.status)
@@ -202,7 +218,11 @@
         return rest_client.ResponseBody(resp, body)
 
     def create_volume_transfer(self, **kwargs):
-        """Create a volume transfer."""
+        """Create a volume transfer.
+
+        Available params: see http://developer.openstack.org/
+                                api-ref-blockstorage-v2.html#createVolumeTransfer
+        """
         post_body = json.dumps({'transfer': kwargs})
         resp, body = self.post('os-volume-transfer', post_body)
         body = json.loads(body)
@@ -218,7 +238,11 @@
         return rest_client.ResponseBody(resp, body)
 
     def list_volume_transfers(self, **params):
-        """List all the volume transfers created."""
+        """List all the volume transfers created.
+
+        Available params: see http://developer.openstack.org/
+                                api-ref-blockstorage-v2.html#listVolumeTransfer
+        """
         url = 'os-volume-transfer'
         if params:
             url += '?%s' % urllib.urlencode(params)
@@ -234,7 +258,11 @@
         return rest_client.ResponseBody(resp, body)
 
     def accept_volume_transfer(self, transfer_id, **kwargs):
-        """Accept a volume transfer."""
+        """Accept a volume transfer.
+
+        Available params: see http://developer.openstack.org/
+                                api-ref-blockstorage-v2.html#acceptVolumeTransfer
+        """
         url = 'os-volume-transfer/%s/accept' % transfer_id
         post_body = json.dumps({'accept': kwargs})
         resp, body = self.post(url, post_body)
@@ -299,6 +327,28 @@
         self.expected_success(200, resp.status)
         return rest_client.ResponseBody(resp, body)
 
+    def update_volume_image_metadata(self, volume_id, **kwargs):
+        """Update image metadata for the volume.
+
+        Available params: see http://developer.openstack.org/
+                              api-ref-blockstorage-v2.html
+                              #setVolumeimagemetadata
+        """
+        post_body = json.dumps({'os-set_image_metadata': {'metadata': kwargs}})
+        url = "volumes/%s/action" % (volume_id)
+        resp, body = self.post(url, post_body)
+        body = json.loads(body)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
+    def delete_volume_image_metadata(self, volume_id, key_name):
+        """Delete image metadata item for the volume."""
+        post_body = json.dumps({'os-unset_image_metadata': {'key': key_name}})
+        url = "volumes/%s/action" % (volume_id)
+        resp, body = self.post(url, post_body)
+        self.expected_success(200, resp.status)
+        return rest_client.ResponseBody(resp, body)
+
     def retype_volume(self, volume_id, **kwargs):
         """Updates volume with new volume type."""
         post_body = json.dumps({'os-retype': kwargs})
diff --git a/tempest/services/volume/v1/__init__.py b/tempest/services/volume/v1/__init__.py
index e69de29..6bdb8c4 100644
--- a/tempest/services/volume/v1/__init__.py
+++ b/tempest/services/volume/v1/__init__.py
@@ -0,0 +1,30 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise 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.services.volume.v1.json.admin.hosts_client import HostsClient
+from tempest.services.volume.v1.json.admin.quotas_client import QuotasClient
+from tempest.services.volume.v1.json.admin.services_client import \
+    ServicesClient
+from tempest.services.volume.v1.json.admin.types_client import TypesClient
+from tempest.services.volume.v1.json.availability_zone_client import \
+    AvailabilityZoneClient
+from tempest.services.volume.v1.json.backups_client import BackupsClient
+from tempest.services.volume.v1.json.extensions_client import ExtensionsClient
+from tempest.services.volume.v1.json.qos_client import QosSpecsClient
+from tempest.services.volume.v1.json.snapshots_client import SnapshotsClient
+from tempest.services.volume.v1.json.volumes_client import VolumesClient
+
+__all__ = ['HostsClient', 'QuotasClient', 'ServicesClient', 'TypesClient',
+           'AvailabilityZoneClient', 'BackupsClient', 'ExtensionsClient',
+           'QosSpecsClient', 'SnapshotsClient', 'VolumesClient']
diff --git a/tempest/services/volume/v2/__init__.py b/tempest/services/volume/v2/__init__.py
index e69de29..c75b0e5 100644
--- a/tempest/services/volume/v2/__init__.py
+++ b/tempest/services/volume/v2/__init__.py
@@ -0,0 +1,30 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise 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.services.volume.v2.json.admin.hosts_client import HostsClient
+from tempest.services.volume.v2.json.admin.quotas_client import QuotasClient
+from tempest.services.volume.v2.json.admin.services_client import \
+    ServicesClient
+from tempest.services.volume.v2.json.admin.types_client import TypesClient
+from tempest.services.volume.v2.json.availability_zone_client import \
+    AvailabilityZoneClient
+from tempest.services.volume.v2.json.backups_client import BackupsClient
+from tempest.services.volume.v2.json.extensions_client import ExtensionsClient
+from tempest.services.volume.v2.json.qos_client import QosSpecsClient
+from tempest.services.volume.v2.json.snapshots_client import SnapshotsClient
+from tempest.services.volume.v2.json.volumes_client import VolumesClient
+
+__all__ = ['HostsClient', 'QuotasClient', 'ServicesClient', 'TypesClient',
+           'AvailabilityZoneClient', 'BackupsClient', 'ExtensionsClient',
+           'QosSpecsClient', 'SnapshotsClient', 'VolumesClient']
diff --git a/tempest/services/volume/v3/__init__.py b/tempest/services/volume/v3/__init__.py
index e69de29..d50098c 100644
--- a/tempest/services/volume/v3/__init__.py
+++ b/tempest/services/volume/v3/__init__.py
@@ -0,0 +1,17 @@
+# Copyright (c) 2016 Hewlett-Packard Enterprise 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.services.volume.v3.json.messages_client import MessagesClient
+
+__all__ = ['MessagesClient']
diff --git a/tempest/test.py b/tempest/test.py
index 4e06db8..97ab25c 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -72,14 +72,9 @@
         'image': CONF.service_available.glance,
         'baremetal': CONF.service_available.ironic,
         'volume': CONF.service_available.cinder,
-        'orchestration': CONF.service_available.heat,
-        # NOTE(mtreinish) nova-network will provide networking functionality
-        # if neutron isn't available, so always set to True.
         'network': True,
         'identity': True,
         'object_storage': CONF.service_available.swift,
-        'data_processing': CONF.service_available.sahara,
-        'database': CONF.service_available.trove
     }
     return service_list
 
@@ -91,9 +86,8 @@
     exercised by a test case.
     """
     def decorator(f):
-        services = ['compute', 'image', 'baremetal', 'volume', 'orchestration',
-                    'network', 'identity', 'object_storage', 'data_processing',
-                    'database']
+        services = ['compute', 'image', 'baremetal', 'volume',
+                    'network', 'identity', 'object_storage']
         for service in args:
             if service not in services:
                 raise exceptions.InvalidServiceTag('%s is not a valid '
diff --git a/tempest/tests/cmd/sample_streams/calls.subunit b/tempest/tests/cmd/sample_streams/calls.subunit
new file mode 100644
index 0000000..d5b4790
--- /dev/null
+++ b/tempest/tests/cmd/sample_streams/calls.subunit
Binary files differ
diff --git a/tempest/tests/cmd/test_run.py b/tempest/tests/cmd/test_run.py
index 9aa06e5..dcffd21 100644
--- a/tempest/tests/cmd/test_run.py
+++ b/tempest/tests/cmd/test_run.py
@@ -102,6 +102,14 @@
         subprocess.call(['git', 'init'], stderr=DEVNULL)
         self.assertRunExit(['tempest', 'run', '--regex', 'passing'], 0)
 
+    def test_tempest_run_passes_with_testrepository(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)
+        subprocess.call(['testr', 'init'])
+        self.assertRunExit(['tempest', 'run', '--regex', 'passing'], 0)
+
     def test_tempest_run_fails(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
diff --git a/tempest/tests/cmd/test_subunit_describe_calls.py b/tempest/tests/cmd/test_subunit_describe_calls.py
new file mode 100644
index 0000000..43b417a
--- /dev/null
+++ b/tempest/tests/cmd/test_subunit_describe_calls.py
@@ -0,0 +1,83 @@
+# Copyright 2016 Rackspace
+#
+# 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 os
+import subprocess
+import tempfile
+
+from tempest.cmd import subunit_describe_calls
+from tempest.tests import base
+
+
+class TestSubunitDescribeCalls(base.TestCase):
+    def test_return_code(self):
+        subunit_file = os.path.join(
+            os.path.dirname(os.path.abspath(__file__)),
+            'sample_streams/calls.subunit')
+        p = subprocess.Popen([
+            'subunit-describe-calls', '-s', subunit_file,
+            '-o', tempfile.mkstemp()[1]], stdin=subprocess.PIPE)
+        p.communicate()
+        self.assertEqual(0, p.returncode)
+
+    def test_parse(self):
+        subunit_file = os.path.join(
+            os.path.dirname(os.path.abspath(__file__)),
+            'sample_streams/calls.subunit')
+        parser = subunit_describe_calls.parse(
+            subunit_file, "pythonlogging", None)
+        expected_result = {
+            'bar': [{'name': 'AgentsAdminTestJSON:setUp',
+                     'service': 'Nova',
+                     'status_code': '200',
+                     'url': 'v2.1/<id>/os-agents',
+                     'verb': 'POST'},
+                    {'name': 'AgentsAdminTestJSON:test_create_agent',
+                     'service': 'Nova',
+                     'status_code': '200',
+                     'url': 'v2.1/<id>/os-agents',
+                     'verb': 'POST'},
+                    {'name': 'AgentsAdminTestJSON:tearDown',
+                     'service': 'Nova',
+                     'status_code': '200',
+                     'url': 'v2.1/<id>/os-agents/1',
+                     'verb': 'DELETE'},
+                    {'name': 'AgentsAdminTestJSON:_run_cleanups',
+                     'service': 'Nova',
+                     'status_code': '200',
+                     'url': 'v2.1/<id>/os-agents/2',
+                     'verb': 'DELETE'}],
+            'foo': [{'name': 'AgentsAdminTestJSON:setUp',
+                     'service': 'Nova',
+                     'status_code': '200',
+                     'url': 'v2.1/<id>/os-agents',
+                     'verb': 'POST'},
+                    {'name': 'AgentsAdminTestJSON:test_delete_agent',
+                     'service': 'Nova',
+                     'status_code': '200',
+                     'url': 'v2.1/<id>/os-agents/3',
+                     'verb': 'DELETE'},
+                    {'name': 'AgentsAdminTestJSON:test_delete_agent',
+                     'service': 'Nova',
+                     'status_code': '200',
+                     'url': 'v2.1/<id>/os-agents',
+                     'verb': 'GET'},
+                    {'name': 'AgentsAdminTestJSON:tearDown',
+                     'service': 'Nova',
+                     'status_code': '404',
+                     'url': 'v2.1/<id>/os-agents/3',
+                     'verb': 'DELETE'}]}
+        self.assertEqual(expected_result, parser.test_logs)
diff --git a/tempest/tests/cmd/test_tempest_init.py b/tempest/tests/cmd/test_tempest_init.py
index 685a0b3..031bf4d 100644
--- a/tempest/tests/cmd/test_tempest_init.py
+++ b/tempest/tests/cmd/test_tempest_init.py
@@ -13,7 +13,6 @@
 # under the License.
 
 import os
-import shutil
 
 import fixtures
 
@@ -43,15 +42,12 @@
         local_dir = self.useFixture(fixtures.TempDir())
         etc_dir_path = os.path.join(local_dir.path, 'etc/')
         os.mkdir(etc_dir_path)
-        tmp_dir = self.useFixture(fixtures.TempDir())
-        config_dir = os.path.join(tmp_dir.path, 'config/')
-        shutil.copytree('etc/', config_dir)
         init_cmd = init.TempestInit(None, None)
         local_sample_conf_file = os.path.join(etc_dir_path,
                                               'tempest.conf.sample')
         # Verify no sample config file exist
         self.assertFalse(os.path.isfile(local_sample_conf_file))
-        init_cmd.generate_sample_config(local_dir.path, config_dir)
+        init_cmd.generate_sample_config(local_dir.path)
 
         # Verify sample config file exist with some content
         self.assertTrue(os.path.isfile(local_sample_conf_file))
diff --git a/tempest/tests/common/test_dynamic_creds.py b/tempest/tests/common/test_dynamic_creds.py
index e97f65f..7a8637f 100644
--- a/tempest/tests/common/test_dynamic_creds.py
+++ b/tempest/tests/common/test_dynamic_creds.py
@@ -21,6 +21,7 @@
 from tempest import config
 from tempest import exceptions
 from tempest.lib.common import rest_client
+from tempest.lib import exceptions as lib_exc
 from tempest.lib.services.identity.v2 import token_client as v2_token_client
 from tempest.lib.services.identity.v3 import token_client as v3_token_client
 from tempest.lib.services.network import routers_client
@@ -635,3 +636,15 @@
             return_value=(rest_client.ResponseBody
                           (200, {'project': {'id': id, 'name': name}}))))
         return project_fix
+
+    @mock.patch('tempest.lib.common.rest_client.RestClient')
+    def test_member_role_creation_with_duplicate(self, rest_client_mock):
+        creds = dynamic_creds.DynamicCredentialProvider(**self.fixed_params)
+        creds.creds_client = mock.MagicMock()
+        creds.creds_client.create_user_role.side_effect = lib_exc.Conflict
+        with mock.patch('tempest.common.dynamic_creds.LOG') as log_mock:
+            creds._create_creds()
+            log_mock.warning.assert_called_once_with(
+                "Member role already exists, ignoring conflict.")
+        creds.creds_client.assign_user_role.assert_called_once_with(
+            mock.ANY, mock.ANY, 'Member')
diff --git a/tempest/tests/common/test_image.py b/tempest/tests/common/test_image.py
index fdd0ae8..34772a2 100644
--- a/tempest/tests/common/test_image.py
+++ b/tempest/tests/common/test_image.py
@@ -38,3 +38,22 @@
             'name': 'New Http Image'
         }
         self.assertEqual(expected, observed)
+
+    def test_image_meta_to_headers(self):
+        observed = image.image_meta_to_headers(
+            name='test',
+            container_format='wrong',
+            disk_format='vhd',
+            copy_from='http://localhost/images/10',
+            properties={'foo': 'bar'},
+            api={'abc': 'def'})
+
+        expected = {
+            'x-image-meta-name': 'test',
+            'x-image-meta-container_format': 'wrong',
+            'x-image-meta-disk_format': 'vhd',
+            'x-glance-api-copy-from': 'http://localhost/images/10',
+            'x-image-meta-property-foo': 'bar',
+            'x-glance-api-property-abc': 'def'
+        }
+        self.assertEqual(expected, observed)
diff --git a/tempest/tests/lib/services/identity/v3/test_token_client.py b/tempest/tests/lib/services/identity/v3/test_token_client.py
index e9ef740..9f4b4cc 100644
--- a/tempest/tests/lib/services/identity/v3/test_token_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_token_client.py
@@ -25,9 +25,6 @@
 
 class TestTokenClientV3(base.TestCase):
 
-    def setUp(self):
-        super(TestTokenClientV3, self).setUp()
-
     def test_init_without_authurl(self):
         self.assertRaises(exceptions.IdentityError,
                           token_client.V3TokenClient, None)
diff --git a/test-requirements.txt b/test-requirements.txt
index 763f0ba..a5b0d29 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,7 +1,7 @@
 # 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.11,>=0.10.0
+hacking<0.12,>=0.11.0 # Apache-2.0
 # needed for doc build
 sphinx!=1.2.0,!=1.3b1,<1.3,>=1.1.2 # BSD
 python-subunit>=0.0.18 # Apache-2.0/BSD
diff --git a/tox.ini b/tox.ini
index 44162fd..cff222d 100644
--- a/tox.ini
+++ b/tox.ini
@@ -28,7 +28,7 @@
     bash tools/pretty_tox.sh '{posargs}'
 
 [testenv:genconfig]
-commands = oslo-config-generator --config-file etc/config-generator.tempest.conf
+commands = oslo-config-generator --config-file tempest/cmd/config-generator.tempest.conf
 
 [testenv:cover]
 setenv = OS_TEST_PATH=./tempest/tests