Merge "Stop leaking identity resources in teardown_all()"
diff --git a/etc/accounts.yaml.sample b/etc/accounts.yaml.sample
new file mode 100644
index 0000000..d191769
--- /dev/null
+++ b/etc/accounts.yaml.sample
@@ -0,0 +1,7 @@
+- username: 'user_1'
+  tenant_name: 'test_tenant_1'
+  password: 'test_password'
+
+- username: 'user_2'
+  tenant_name: 'test_tenant_2'
+  password: 'test_password'
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index f80fc1b..e60b731 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -105,6 +105,17 @@
 #syslog_log_facility=LOG_USER
 
 
+[auth]
+
+#
+# Options defined in tempest.config
+#
+
+# Path to the yaml file that contains the list of credentials
+# to use for running tests (string value)
+#test_accounts_file=etc/accounts.yaml
+
+
 [baremetal]
 
 #
@@ -386,6 +397,9 @@
 # If false, skip all nova v3 tests. (boolean value)
 #api_v3=false
 
+# If false skip all v2 api tests with xml (boolean value)
+#xml_api_v2=true
+
 # If false, skip disk config tests (boolean value)
 #disk_config=true
 
@@ -411,6 +425,10 @@
 # Does the test environment support pausing? (boolean value)
 #pause=true
 
+# Does the test environment support shelving/unshelving?
+# (boolean value)
+#shelve=true
+
 # Does the test environment support suspend/resume? (boolean
 # value)
 #suspend=true
@@ -448,6 +466,10 @@
 # value)
 #enable_instance_password=true
 
+# Does the test environment support dynamic network interface
+# attachment? (boolean value)
+#interface_attach=true
+
 
 [dashboard]
 
diff --git a/tempest/api/baremetal/README.rst b/tempest/api/baremetal/README.rst
new file mode 100644
index 0000000..759c937
--- /dev/null
+++ b/tempest/api/baremetal/README.rst
@@ -0,0 +1,25 @@
+Tempest Field Guide to Baremetal API tests
+==========================================
+
+
+What are these tests?
+---------------------
+
+These tests stress the OpenStack baremetal provisioning API provided by
+Ironic.
+
+
+Why are these tests in tempest?
+------------------------------
+
+The purpose of these tests is to exercise the various APIs provided by Ironic
+for managing baremetal nodes.
+
+
+Scope of these tests
+--------------------
+
+The baremetal API test perform basic CRUD operations on the Ironic node
+inventory.  They do not actually perform hardware provisioning. It is important
+to note that all Ironic API actions are admin operations meant to be used
+either by cloud operators or other OpenStack services (i.e., Nova).
diff --git a/tempest/api_schema/compute/__init__.py b/tempest/api/baremetal/admin/__init__.py
similarity index 100%
copy from tempest/api_schema/compute/__init__.py
copy to tempest/api/baremetal/admin/__init__.py
diff --git a/tempest/api/baremetal/base.py b/tempest/api/baremetal/admin/base.py
similarity index 100%
rename from tempest/api/baremetal/base.py
rename to tempest/api/baremetal/admin/base.py
diff --git a/tempest/api/baremetal/test_api_discovery.py b/tempest/api/baremetal/admin/test_api_discovery.py
similarity index 97%
rename from tempest/api/baremetal/test_api_discovery.py
rename to tempest/api/baremetal/admin/test_api_discovery.py
index bee10b9..7368b3e 100644
--- a/tempest/api/baremetal/test_api_discovery.py
+++ b/tempest/api/baremetal/admin/test_api_discovery.py
@@ -10,7 +10,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api.baremetal import base
+from tempest.api.baremetal.admin import base
 from tempest import test
 
 
diff --git a/tempest/api/baremetal/test_chassis.py b/tempest/api/baremetal/admin/test_chassis.py
similarity index 98%
rename from tempest/api/baremetal/test_chassis.py
rename to tempest/api/baremetal/admin/test_chassis.py
index 4ab86c2..c306c34 100644
--- a/tempest/api/baremetal/test_chassis.py
+++ b/tempest/api/baremetal/admin/test_chassis.py
@@ -11,7 +11,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api.baremetal import base
+from tempest.api.baremetal.admin import base
 from tempest.common.utils import data_utils
 from tempest import exceptions as exc
 from tempest import test
diff --git a/tempest/api/baremetal/test_drivers.py b/tempest/api/baremetal/admin/test_drivers.py
similarity index 96%
rename from tempest/api/baremetal/test_drivers.py
rename to tempest/api/baremetal/admin/test_drivers.py
index 852b6ab..649886b 100644
--- a/tempest/api/baremetal/test_drivers.py
+++ b/tempest/api/baremetal/admin/test_drivers.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api.baremetal import base
+from tempest.api.baremetal.admin import base
 from tempest import config
 from tempest import test
 
diff --git a/tempest/api/baremetal/test_nodes.py b/tempest/api/baremetal/admin/test_nodes.py
similarity index 98%
rename from tempest/api/baremetal/test_nodes.py
rename to tempest/api/baremetal/admin/test_nodes.py
index 1572840..fc67854 100644
--- a/tempest/api/baremetal/test_nodes.py
+++ b/tempest/api/baremetal/admin/test_nodes.py
@@ -12,7 +12,7 @@
 
 import six
 
-from tempest.api.baremetal import base
+from tempest.api.baremetal.admin import base
 from tempest import exceptions as exc
 from tempest import test
 
diff --git a/tempest/api/baremetal/test_nodestates.py b/tempest/api/baremetal/admin/test_nodestates.py
similarity index 97%
rename from tempest/api/baremetal/test_nodestates.py
rename to tempest/api/baremetal/admin/test_nodestates.py
index 3044bc6..f24f490 100644
--- a/tempest/api/baremetal/test_nodestates.py
+++ b/tempest/api/baremetal/admin/test_nodestates.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api.baremetal import base
+from tempest.api.baremetal.admin import base
 from tempest import exceptions
 from tempest.openstack.common import timeutils
 from tempest import test
diff --git a/tempest/api/baremetal/test_ports.py b/tempest/api/baremetal/admin/test_ports.py
similarity index 99%
rename from tempest/api/baremetal/test_ports.py
rename to tempest/api/baremetal/admin/test_ports.py
index 4ac7e29..d4adba9 100644
--- a/tempest/api/baremetal/test_ports.py
+++ b/tempest/api/baremetal/admin/test_ports.py
@@ -10,7 +10,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api.baremetal import base
+from tempest.api.baremetal.admin import base
 from tempest.common.utils import data_utils
 from tempest import exceptions as exc
 from tempest import test
diff --git a/tempest/api/baremetal/test_ports_negative.py b/tempest/api/baremetal/admin/test_ports_negative.py
similarity index 99%
rename from tempest/api/baremetal/test_ports_negative.py
rename to tempest/api/baremetal/admin/test_ports_negative.py
index 3e77a5f..7646677 100644
--- a/tempest/api/baremetal/test_ports_negative.py
+++ b/tempest/api/baremetal/admin/test_ports_negative.py
@@ -10,7 +10,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api.baremetal import base
+from tempest.api.baremetal.admin import base
 from tempest.common.utils import data_utils
 from tempest import exceptions as exc
 from tempest import test
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index a3295eb..343a39a 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -37,6 +37,9 @@
     def setUpClass(cls):
         cls.set_network_resources()
         super(BaseComputeTest, cls).setUpClass()
+        if getattr(cls, '_interface', None) == 'xml' and cls._api_version == 2:
+            if not CONF.compute_feature_enabled.xml_api_v2:
+                raise cls.skipException('XML API is not enabled')
 
         # TODO(andreaf) WE should care also for the alt_manager here
         # but only once client lazy load in the manager is done
diff --git a/tempest/api/compute/limits/test_absolute_limits_negative.py b/tempest/api/compute/limits/test_absolute_limits_negative.py
index f88699b..b2e2981 100644
--- a/tempest/api/compute/limits/test_absolute_limits_negative.py
+++ b/tempest/api/compute/limits/test_absolute_limits_negative.py
@@ -39,7 +39,9 @@
         for xx in range(max_meta_data):
             meta_data[str(xx)] = str(xx)
 
-        self.assertRaises(exceptions.OverLimit,
+        # A 403 Forbidden or 413 Overlimit (old behaviour) exception
+        # will be raised when out of quota
+        self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
                           self.server_client.create_server,
                           name='test', meta=meta_data,
                           flavor_ref=self.flavor_ref,
diff --git a/tempest/api/compute/servers/test_attach_interfaces.py b/tempest/api/compute/servers/test_attach_interfaces.py
index 067d721..d1192c0 100644
--- a/tempest/api/compute/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/servers/test_attach_interfaces.py
@@ -29,6 +29,8 @@
     def setUpClass(cls):
         if not CONF.service_available.neutron:
             raise cls.skipException("Neutron is required")
+        if not CONF.compute_feature_enabled.interface_attach:
+            raise cls.skipException("Interface attachment is not available.")
         # This test class requires network and subnet
         cls.set_network_resources(network=True, subnet=True)
         super(AttachInterfacesTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/servers/test_delete_server.py b/tempest/api/compute/servers/test_delete_server.py
index 9e34922..9c8271f 100644
--- a/tempest/api/compute/servers/test_delete_server.py
+++ b/tempest/api/compute/servers/test_delete_server.py
@@ -70,6 +70,8 @@
         self.assertEqual('204', resp['status'])
         self.client.wait_for_server_termination(server['id'])
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+                          'Shelve is not available.')
     @test.attr(type='gate')
     def test_delete_server_while_in_shelved_state(self):
         # Delete a server while it's VM state is Shelved
diff --git a/tempest/api/compute/servers/test_server_actions.py b/tempest/api/compute/servers/test_server_actions.py
index 71fcbff..ee525e7 100644
--- a/tempest/api/compute/servers/test_server_actions.py
+++ b/tempest/api/compute/servers/test_server_actions.py
@@ -403,6 +403,8 @@
         self.assertEqual(202, resp.status)
         self.client.wait_for_server_status(self.server_id, 'ACTIVE')
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+                          'Shelve is not available.')
     @test.attr(type='gate')
     def test_shelve_unshelve_server(self):
         resp, server = self.client.shelve_server(self.server_id)
diff --git a/tempest/api/compute/servers/test_server_personality.py b/tempest/api/compute/servers/test_server_personality.py
index b7e4e38..6cc463d 100644
--- a/tempest/api/compute/servers/test_server_personality.py
+++ b/tempest/api/compute/servers/test_server_personality.py
@@ -40,8 +40,10 @@
             path = 'etc/test' + str(i) + '.txt'
             personality.append({'path': path,
                                 'contents': base64.b64encode(file_contents)})
-        self.assertRaises(exceptions.OverLimit, self.create_test_server,
-                          personality=personality)
+        # A 403 Forbidden or 413 Overlimit (old behaviour) exception
+        # will be raised when out of quota
+        self.assertRaises((exceptions.Unauthorized, exceptions.OverLimit),
+                          self.create_test_server, personality=personality)
 
     @test.attr(type='gate')
     def test_can_create_server_with_max_number_personality_files(self):
diff --git a/tempest/api/compute/servers/test_server_rescue_negative.py b/tempest/api/compute/servers/test_server_rescue_negative.py
index b35e55c..4582a46 100644
--- a/tempest/api/compute/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/servers/test_server_rescue_negative.py
@@ -34,7 +34,7 @@
 
         cls.set_network_resources(network=True, subnet=True, router=True)
         super(ServerRescueNegativeTestJSON, cls).setUpClass()
-        cls.device = 'vdf'
+        cls.device = CONF.compute.volume_device_name
 
         # Create a volume and wait for it to become ready for attach
         resp, cls.volume = cls.volumes_extensions_client.create_volume(
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index d3297ce..792b523 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -425,6 +425,8 @@
                           self.client.restore_soft_deleted_server,
                           self.server_id)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+                          'Shelve is not available.')
     @test.attr(type=['negative', 'gate'])
     def test_shelve_non_existent_server(self):
         # shelve a non existent server
@@ -432,6 +434,8 @@
         self.assertRaises(exceptions.NotFound, self.client.shelve_server,
                           nonexistent_server)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+                          'Shelve is not available.')
     @test.attr(type=['negative', 'gate'])
     def test_shelve_shelved_server(self):
         # shelve a shelved server.
@@ -460,6 +464,8 @@
 
         self.client.unshelve_server(self.server_id)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+                          'Shelve is not available.')
     @test.attr(type=['negative', 'gate'])
     def test_unshelve_non_existent_server(self):
         # unshelve a non existent server
@@ -467,6 +473,8 @@
         self.assertRaises(exceptions.NotFound, self.client.unshelve_server,
                           nonexistent_server)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+                          'Shelve is not available.')
     @test.attr(type=['negative', 'gate'])
     def test_unshelve_server_invalid_state(self):
         # unshelve an active server.
diff --git a/tempest/api/compute/v3/admin/test_flavors_access.py b/tempest/api/compute/v3/admin/test_flavors_access.py
index c641bf6..09b6ebd 100644
--- a/tempest/api/compute/v3/admin/test_flavors_access.py
+++ b/tempest/api/compute/v3/admin/test_flavors_access.py
@@ -38,7 +38,6 @@
         cls.vcpus = 1
         cls.disk = 10
 
-    @test.skip_because(bug='1265416')
     @test.attr(type='gate')
     def test_flavor_access_list_with_private_flavor(self):
         # Test to list flavor access successfully by querying private flavor
@@ -58,7 +57,6 @@
         self.assertEqual(str(new_flavor_id), str(first_flavor['flavor_id']))
         self.assertEqual(self.adm_tenant_id, first_flavor['tenant_id'])
 
-    @test.skip_because(bug='1265416')
     @test.attr(type='gate')
     def test_flavor_access_add_remove(self):
         # Test to add and remove flavor access to a given tenant.
diff --git a/tempest/api/compute/v3/admin/test_flavors_access_negative.py b/tempest/api/compute/v3/admin/test_flavors_access_negative.py
index 02ecb24..0fdfabd 100644
--- a/tempest/api/compute/v3/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_access_negative.py
@@ -55,7 +55,6 @@
                           self.client.list_flavor_access,
                           new_flavor_id)
 
-    @test.skip_because(bug='1265416')
     @test.attr(type=['negative', 'gate'])
     def test_flavor_non_admin_add(self):
         # Test to add flavor access as a user without admin privileges.
@@ -72,7 +71,6 @@
                           new_flavor['id'],
                           self.tenant_id)
 
-    @test.skip_because(bug='1265416')
     @test.attr(type=['negative', 'gate'])
     def test_flavor_non_admin_remove(self):
         # Test to remove flavor access as a user without admin privileges.
@@ -93,7 +91,6 @@
                           new_flavor['id'],
                           self.tenant_id)
 
-    @test.skip_because(bug='1265416')
     @test.attr(type=['negative', 'gate'])
     def test_add_flavor_access_duplicate(self):
         # Create a new flavor.
@@ -118,7 +115,6 @@
                           new_flavor['id'],
                           self.tenant_id)
 
-    @test.skip_because(bug='1265416')
     @test.attr(type=['negative', 'gate'])
     def test_remove_flavor_access_not_found(self):
         # Create a new flavor.
diff --git a/tempest/api/compute/v3/admin/test_servers.py b/tempest/api/compute/v3/admin/test_servers.py
index 366cfc6..d99c329 100644
--- a/tempest/api/compute/v3/admin/test_servers.py
+++ b/tempest/api/compute/v3/admin/test_servers.py
@@ -51,7 +51,6 @@
         self.assertEqual('200', resp['status'])
         self.assertEqual([], servers)
 
-    @test.skip_because(bug='1265416')
     @test.attr(type='gate')
     def test_list_servers_by_admin_with_all_tenants(self):
         # Listing servers by admin user with all tenants parameter
diff --git a/tempest/api/compute/v3/servers/test_attach_interfaces.py b/tempest/api/compute/v3/servers/test_attach_interfaces.py
index 43440c1..c2cf7e0 100644
--- a/tempest/api/compute/v3/servers/test_attach_interfaces.py
+++ b/tempest/api/compute/v3/servers/test_attach_interfaces.py
@@ -29,6 +29,8 @@
     def setUpClass(cls):
         if not CONF.service_available.neutron:
             raise cls.skipException("Neutron is required")
+        if not CONF.compute_feature_enabled.interface_attach:
+            raise cls.skipException("Interface attachment is not available.")
         # This test class requires network and subnet
         cls.set_network_resources(network=True, subnet=True)
         super(AttachInterfacesV3Test, cls).setUpClass()
diff --git a/tempest/api/compute/v3/servers/test_delete_server.py b/tempest/api/compute/v3/servers/test_delete_server.py
index add69ab..e2b47ee 100644
--- a/tempest/api/compute/v3/servers/test_delete_server.py
+++ b/tempest/api/compute/v3/servers/test_delete_server.py
@@ -68,6 +68,8 @@
         self.assertEqual('204', resp['status'])
         self.client.wait_for_server_termination(server['id'])
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+                          'Shelve is not available.')
     @test.attr(type='gate')
     def test_delete_server_while_in_shelved_state(self):
         # Delete a server while it's VM state is Shelved
diff --git a/tempest/api/compute/v3/servers/test_server_actions.py b/tempest/api/compute/v3/servers/test_server_actions.py
index 3ee8050..4404043 100644
--- a/tempest/api/compute/v3/servers/test_server_actions.py
+++ b/tempest/api/compute/v3/servers/test_server_actions.py
@@ -394,6 +394,8 @@
         self.assertEqual(202, resp.status)
         self.client.wait_for_server_status(self.server_id, 'ACTIVE')
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+                          'Shelve is not available.')
     @test.attr(type='gate')
     def test_shelve_unshelve_server(self):
         resp, server = self.client.shelve_server(self.server_id)
diff --git a/tempest/api/compute/v3/servers/test_server_rescue_negative.py b/tempest/api/compute/v3/servers/test_server_rescue_negative.py
index 5eb6c9a..6d192a3 100644
--- a/tempest/api/compute/v3/servers/test_server_rescue_negative.py
+++ b/tempest/api/compute/v3/servers/test_server_rescue_negative.py
@@ -33,7 +33,7 @@
             raise cls.skipException(msg)
 
         super(ServerRescueNegativeV3Test, cls).setUpClass()
-        cls.device = 'vdf'
+        cls.device = CONF.compute.volume_device_name
 
         # Create a volume and wait for it to become ready for attach
         resp, cls.volume = cls.volumes_client.create_volume(
@@ -56,7 +56,8 @@
 
     @classmethod
     def tearDownClass(cls):
-        cls.delete_volume(cls.volume['id'])
+        if hasattr(cls, 'volume'):
+            cls.delete_volume(cls.volume['id'])
         super(ServerRescueNegativeV3Test, cls).tearDownClass()
 
     def _detach(self, server_id, volume_id):
diff --git a/tempest/api/compute/v3/servers/test_servers_negative.py b/tempest/api/compute/v3/servers/test_servers_negative.py
index 90deaa9..f8ff7c8 100644
--- a/tempest/api/compute/v3/servers/test_servers_negative.py
+++ b/tempest/api/compute/v3/servers/test_servers_negative.py
@@ -397,6 +397,8 @@
                           self.client.restore_soft_deleted_server,
                           self.server_id)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+                          'Shelve is not available.')
     @test.attr(type=['negative', 'gate'])
     def test_shelve_non_existent_server(self):
         # shelve a non existent server
@@ -404,6 +406,8 @@
         self.assertRaises(exceptions.NotFound, self.client.shelve_server,
                           nonexistent_server)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+                          'Shelve is not available.')
     @test.attr(type=['negative', 'gate'])
     def test_shelve_shelved_server(self):
         # shelve a shelved server.
@@ -431,6 +435,8 @@
 
         self.client.unshelve_server(self.server_id)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+                          'Shelve is not available.')
     @test.attr(type=['negative', 'gate'])
     def test_unshelve_non_existent_server(self):
         # unshelve a non existent server
@@ -438,6 +444,8 @@
         self.assertRaises(exceptions.NotFound, self.client.unshelve_server,
                           nonexistent_server)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.shelve,
+                          'Shelve is not available.')
     @test.attr(type=['negative', 'gate'])
     def test_unshelve_server_invalid_state(self):
         # unshelve an active server.
diff --git a/tempest/api/data_processing/base.py b/tempest/api/data_processing/base.py
index cfb5a3d..65085b9 100644
--- a/tempest/api/data_processing/base.py
+++ b/tempest/api/data_processing/base.py
@@ -40,6 +40,7 @@
         cls._data_sources = []
         cls._job_binary_internals = []
         cls._job_binaries = []
+        cls._jobs = []
 
     @classmethod
     def tearDownClass(cls):
@@ -47,12 +48,13 @@
                               cls.client.delete_cluster_template)
         cls.cleanup_resources(getattr(cls, '_node_group_templates', []),
                               cls.client.delete_node_group_template)
-        cls.cleanup_resources(getattr(cls, '_data_sources', []),
-                              cls.client.delete_data_source)
-        cls.cleanup_resources(getattr(cls, '_job_binary_internals', []),
-                              cls.client.delete_job_binary_internal)
+        cls.cleanup_resources(getattr(cls, '_jobs', []), cls.client.delete_job)
         cls.cleanup_resources(getattr(cls, '_job_binaries', []),
                               cls.client.delete_job_binary)
+        cls.cleanup_resources(getattr(cls, '_job_binary_internals', []),
+                              cls.client.delete_job_binary_internal)
+        cls.cleanup_resources(getattr(cls, '_data_sources', []),
+                              cls.client.delete_data_source)
         cls.clear_isolated_creds()
         super(BaseDataProcessingTest, cls).tearDownClass()
 
@@ -132,6 +134,7 @@
 
         return resp_body
 
+    @classmethod
     def create_job_binary(cls, name, url, extra=None, **kwargs):
         """Creates watched job binary with specified params.
 
@@ -144,3 +147,18 @@
         cls._job_binaries.append(resp_body['id'])
 
         return resp_body
+
+    @classmethod
+    def create_job(cls, name, job_type, mains, libs=None, **kwargs):
+        """Creates watched job with specified params.
+
+        It supports passing additional params using kwargs and returns created
+        object. All resources created in this method will be automatically
+        removed in tearDownClass method.
+        """
+        _, resp_body = cls.client.create_job(name,
+                                             job_type, mains, libs, **kwargs)
+        # store id of created job
+        cls._jobs.append(resp_body['id'])
+
+        return resp_body
diff --git a/tempest/api/data_processing/test_jobs.py b/tempest/api/data_processing/test_jobs.py
new file mode 100644
index 0000000..8591dbd
--- /dev/null
+++ b/tempest/api/data_processing/test_jobs.py
@@ -0,0 +1,90 @@
+# Copyright (c) 2014 Mirantis Inc.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.data_processing import base as dp_base
+from tempest.common.utils import data_utils
+from tempest import test
+
+
+class JobTest(dp_base.BaseDataProcessingTest):
+    """Link to the API documentation is http://docs.openstack.org/developer/
+    sahara/restapi/rest_api_v1.1_EDP.html#jobs
+    """
+    @classmethod
+    @test.safe_setup
+    def setUpClass(cls):
+        super(JobTest, cls).setUpClass()
+        # create job binary
+        job_binary = {
+            'name': data_utils.rand_name('sahara-job-binary'),
+            'url': 'swift://sahara-container.sahara/example.jar',
+            'description': 'Test job binary',
+            'extra': {
+                'user': cls.os.credentials.username,
+                'password': cls.os.credentials.password
+            }
+        }
+        resp_body = cls.create_job_binary(**job_binary)
+        job_binary_id = resp_body['id']
+
+        cls.job = {
+            'job_type': 'Pig',
+            'mains': [job_binary_id]
+        }
+
+    def _create_job(self, job_name=None):
+        """Creates Job with optional name specified.
+
+        It creates job and ensures job name. Returns id and name of created
+        job.
+        """
+        if not job_name:
+            # generate random name if it's not specified
+            job_name = data_utils.rand_name('sahara-job')
+
+        # create job
+        resp_body = self.create_job(job_name, **self.job)
+
+        # ensure that job created successfully
+        self.assertEqual(job_name, resp_body['name'])
+
+        return resp_body['id'], job_name
+
+    @test.attr(type='smoke')
+    def test_job_create(self):
+        self._create_job()
+
+    @test.attr(type='smoke')
+    def test_job_list(self):
+        job_info = self._create_job()
+
+        # check for job in list
+        _, jobs = self.client.list_jobs()
+        jobs_info = [(job['id'], job['name']) for job in jobs]
+        self.assertIn(job_info, jobs_info)
+
+    @test.attr(type='smoke')
+    def test_job_get(self):
+        job_id, job_name = self._create_job()
+
+        # check job fetch by id
+        _, job = self.client.get_job(job_id)
+        self.assertEqual(job_name, job['name'])
+
+    @test.attr(type='smoke')
+    def test_job_delete(self):
+        job_id, _ = self._create_job()
+
+        # delete the job by id
+        self.client.delete_job(job_id)
diff --git a/tempest/api/identity/admin/test_roles.py b/tempest/api/identity/admin/test_roles.py
index 7a6d07f..492d56f 100644
--- a/tempest/api/identity/admin/test_roles.py
+++ b/tempest/api/identity/admin/test_roles.py
@@ -49,7 +49,7 @@
 
     @test.attr(type='gate')
     def test_list_roles(self):
-        # Return a list of all roles
+        """Return a list of all roles."""
         _, body = self.client.list_roles()
         found = [role for role in body if role in self.data.roles]
         self.assertTrue(any(found))
@@ -57,7 +57,7 @@
 
     @test.attr(type='gate')
     def test_role_create_delete(self):
-        # Role should be created, verified, and deleted
+        """Role should be created, verified, and deleted."""
         role_name = data_utils.rand_name(name='role-test-')
         _, body = self.client.create_role(role_name)
         self.assertEqual(role_name, body['name'])
@@ -74,7 +74,7 @@
 
     @test.attr(type='gate')
     def test_get_role_by_id(self):
-        # Get a role by its id
+        """Get a role by its id."""
         self.data.setup_test_role()
         role_id = self.data.role['id']
         role_name = self.data.role['name']
@@ -84,7 +84,7 @@
 
     @test.attr(type='gate')
     def test_assign_user_role(self):
-        # Assign a role to a user on a tenant
+        """Assign a role to a user on a tenant."""
         (user, tenant, role) = self._get_role_params()
         self.client.assign_user_role(tenant['id'], user['id'], role['id'])
         _, roles = self.client.list_user_roles(tenant['id'], user['id'])
@@ -92,7 +92,7 @@
 
     @test.attr(type='gate')
     def test_remove_user_role(self):
-        # Remove a role assigned to a user on a tenant
+        """Remove a role assigned to a user on a tenant."""
         (user, tenant, role) = self._get_role_params()
         _, user_role = self.client.assign_user_role(tenant['id'],
                                                     user['id'], role['id'])
@@ -101,7 +101,7 @@
 
     @test.attr(type='gate')
     def test_list_user_roles(self):
-        # List roles assigned to a user on tenant
+        """List roles assigned to a user on tenant."""
         (user, tenant, role) = self._get_role_params()
         self.client.assign_user_role(tenant['id'], user['id'], role['id'])
         _, roles = self.client.list_user_roles(tenant['id'], user['id'])
diff --git a/tempest/api/network/test_routers.py b/tempest/api/network/test_routers.py
index d38633f..dca4c17 100644
--- a/tempest/api/network/test_routers.py
+++ b/tempest/api/network/test_routers.py
@@ -110,6 +110,36 @@
                         create_body['router']['id'])
         self.assertEqual(tenant_id, create_body['router']['tenant_id'])
 
+    @test.requires_ext(extension='ext-gw-mode', service='network')
+    @test.attr(type='smoke')
+    def test_create_router_with_default_snat_value(self):
+        # Create a router with default snat rule
+        name = data_utils.rand_name('router')
+        router = self._create_router(name,
+                 external_network_id=CONF.network.public_network_id)
+        self._verify_router_gateway(router['id'],
+              {'network_id': CONF.network.public_network_id,
+              'enable_snat': True})
+
+    @test.requires_ext(extension='ext-gw-mode', service='network')
+    @test.attr(type='smoke')
+    def test_create_router_with_snat_explicit(self):
+        name = data_utils.rand_name('snat-router')
+        # Create a router enabling snat attributes
+        enable_snat_states = [False, True]
+        for enable_snat in enable_snat_states:
+            external_gateway_info = {
+                'network_id': CONF.network.public_network_id,
+                'enable_snat': enable_snat}
+            resp, create_body = self.admin_client.create_router(
+                name, external_gateway_info=external_gateway_info)
+            self.assertEqual('201', resp['status'])
+            self.addCleanup(self.admin_client.delete_router,
+                    create_body['router']['id'])
+            # Verify snat attributes after router creation
+            self._verify_router_gateway(create_body['router']['id'],
+                    exp_ext_gw_info=external_gateway_info)
+
     @test.attr(type='smoke')
     def test_add_remove_router_interface_with_subnet_id(self):
         network = self.create_network()
@@ -151,7 +181,7 @@
                          router['id'])
 
     def _verify_router_gateway(self, router_id, exp_ext_gw_info=None):
-        resp, show_body = self.client.show_router(router_id)
+        resp, show_body = self.admin_client.show_router(router_id)
         self.assertEqual('200', resp['status'])
         actual_ext_gw_info = show_body['router']['external_gateway_info']
         if exp_ext_gw_info is None:
diff --git a/tempest/api/telemetry/test_telemetry_notification_api.py b/tempest/api/telemetry/test_telemetry_notification_api.py
index 2a170c7..9b15c51 100644
--- a/tempest/api/telemetry/test_telemetry_notification_api.py
+++ b/tempest/api/telemetry/test_telemetry_notification_api.py
@@ -47,6 +47,7 @@
     @test.services("image")
     @testtools.skipIf(not CONF.image_feature_enabled.api_v1,
                       "Glance api v1 is disabled")
+    @test.skip_because(bug='1351627')
     def test_check_glance_v1_notifications(self):
         _, body = self.create_image(self.image_client)
         self.image_client.update_image(body['id'], data='data')
@@ -62,6 +63,7 @@
     @test.services("image")
     @testtools.skipIf(not CONF.image_feature_enabled.api_v2,
                       "Glance api v2 is disabled")
+    @test.skip_because(bug='1351627')
     def test_check_glance_v2_notifications(self):
         _, body = self.create_image(self.image_client_v2)
 
diff --git a/tempest/api_schema/compute/__init__.py b/tempest/api_schema/response/__init__.py
similarity index 100%
copy from tempest/api_schema/compute/__init__.py
copy to tempest/api_schema/response/__init__.py
diff --git a/tempest/api_schema/compute/__init__.py b/tempest/api_schema/response/compute/__init__.py
similarity index 100%
rename from tempest/api_schema/compute/__init__.py
rename to tempest/api_schema/response/compute/__init__.py
diff --git a/tempest/api_schema/compute/agents.py b/tempest/api_schema/response/compute/agents.py
similarity index 100%
rename from tempest/api_schema/compute/agents.py
rename to tempest/api_schema/response/compute/agents.py
diff --git a/tempest/api_schema/compute/aggregates.py b/tempest/api_schema/response/compute/aggregates.py
similarity index 100%
rename from tempest/api_schema/compute/aggregates.py
rename to tempest/api_schema/response/compute/aggregates.py
diff --git a/tempest/api_schema/compute/availability_zone.py b/tempest/api_schema/response/compute/availability_zone.py
similarity index 100%
rename from tempest/api_schema/compute/availability_zone.py
rename to tempest/api_schema/response/compute/availability_zone.py
diff --git a/tempest/api_schema/compute/certificates.py b/tempest/api_schema/response/compute/certificates.py
similarity index 100%
rename from tempest/api_schema/compute/certificates.py
rename to tempest/api_schema/response/compute/certificates.py
diff --git a/tempest/api_schema/compute/flavors.py b/tempest/api_schema/response/compute/flavors.py
similarity index 96%
rename from tempest/api_schema/compute/flavors.py
rename to tempest/api_schema/response/compute/flavors.py
index aa019e4..44020d2 100644
--- a/tempest/api_schema/compute/flavors.py
+++ b/tempest/api_schema/response/compute/flavors.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api_schema.compute import parameter_types
+from tempest.api_schema.response.compute import parameter_types
 
 list_flavors = {
     'status_code': [200],
diff --git a/tempest/api_schema/compute/flavors_access.py b/tempest/api_schema/response/compute/flavors_access.py
similarity index 100%
rename from tempest/api_schema/compute/flavors_access.py
rename to tempest/api_schema/response/compute/flavors_access.py
diff --git a/tempest/api_schema/compute/flavors_extra_specs.py b/tempest/api_schema/response/compute/flavors_extra_specs.py
similarity index 100%
rename from tempest/api_schema/compute/flavors_extra_specs.py
rename to tempest/api_schema/response/compute/flavors_extra_specs.py
diff --git a/tempest/api_schema/compute/hosts.py b/tempest/api_schema/response/compute/hosts.py
similarity index 100%
rename from tempest/api_schema/compute/hosts.py
rename to tempest/api_schema/response/compute/hosts.py
diff --git a/tempest/api_schema/compute/hypervisors.py b/tempest/api_schema/response/compute/hypervisors.py
similarity index 100%
rename from tempest/api_schema/compute/hypervisors.py
rename to tempest/api_schema/response/compute/hypervisors.py
diff --git a/tempest/api_schema/compute/interfaces.py b/tempest/api_schema/response/compute/interfaces.py
similarity index 95%
rename from tempest/api_schema/compute/interfaces.py
rename to tempest/api_schema/response/compute/interfaces.py
index 79a8f42..fd53eb3 100644
--- a/tempest/api_schema/compute/interfaces.py
+++ b/tempest/api_schema/response/compute/interfaces.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api_schema.compute import parameter_types
+from tempest.api_schema.response.compute import parameter_types
 
 delete_interface = {
     'status_code': [202]
diff --git a/tempest/api_schema/compute/keypairs.py b/tempest/api_schema/response/compute/keypairs.py
similarity index 100%
rename from tempest/api_schema/compute/keypairs.py
rename to tempest/api_schema/response/compute/keypairs.py
diff --git a/tempest/api_schema/compute/migrations.py b/tempest/api_schema/response/compute/migrations.py
similarity index 100%
rename from tempest/api_schema/compute/migrations.py
rename to tempest/api_schema/response/compute/migrations.py
diff --git a/tempest/api_schema/compute/parameter_types.py b/tempest/api_schema/response/compute/parameter_types.py
similarity index 100%
rename from tempest/api_schema/compute/parameter_types.py
rename to tempest/api_schema/response/compute/parameter_types.py
diff --git a/tempest/api_schema/compute/quotas.py b/tempest/api_schema/response/compute/quotas.py
similarity index 100%
rename from tempest/api_schema/compute/quotas.py
rename to tempest/api_schema/response/compute/quotas.py
diff --git a/tempest/api_schema/compute/servers.py b/tempest/api_schema/response/compute/servers.py
similarity index 98%
rename from tempest/api_schema/compute/servers.py
rename to tempest/api_schema/response/compute/servers.py
index a16e425..d6c2ddb 100644
--- a/tempest/api_schema/compute/servers.py
+++ b/tempest/api_schema/response/compute/servers.py
@@ -14,7 +14,7 @@
 
 import copy
 
-from tempest.api_schema.compute import parameter_types
+from tempest.api_schema.response.compute import parameter_types
 
 get_password = {
     'status_code': [200],
diff --git a/tempest/api_schema/compute/services.py b/tempest/api_schema/response/compute/services.py
similarity index 100%
rename from tempest/api_schema/compute/services.py
rename to tempest/api_schema/response/compute/services.py
diff --git a/tempest/api_schema/compute/v2/__init__.py b/tempest/api_schema/response/compute/v2/__init__.py
similarity index 100%
rename from tempest/api_schema/compute/v2/__init__.py
rename to tempest/api_schema/response/compute/v2/__init__.py
diff --git a/tempest/api_schema/compute/v2/agents.py b/tempest/api_schema/response/compute/v2/agents.py
similarity index 93%
rename from tempest/api_schema/compute/v2/agents.py
rename to tempest/api_schema/response/compute/v2/agents.py
index 30f999f..d827377 100644
--- a/tempest/api_schema/compute/v2/agents.py
+++ b/tempest/api_schema/response/compute/v2/agents.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api_schema.compute import agents
+from tempest.api_schema.response.compute import agents
 
 create_agent = {
     'status_code': [200],
diff --git a/tempest/api_schema/compute/v2/aggregates.py b/tempest/api_schema/response/compute/v2/aggregates.py
similarity index 93%
rename from tempest/api_schema/compute/v2/aggregates.py
rename to tempest/api_schema/response/compute/v2/aggregates.py
index bc36044..d87e4de 100644
--- a/tempest/api_schema/compute/v2/aggregates.py
+++ b/tempest/api_schema/response/compute/v2/aggregates.py
@@ -14,7 +14,7 @@
 
 import copy
 
-from tempest.api_schema.compute import aggregates
+from tempest.api_schema.response.compute import aggregates
 
 delete_aggregate = {
     'status_code': [200]
diff --git a/tempest/api_schema/compute/v2/availability_zone.py b/tempest/api_schema/response/compute/v2/availability_zone.py
similarity index 95%
rename from tempest/api_schema/compute/v2/availability_zone.py
rename to tempest/api_schema/response/compute/v2/availability_zone.py
index d3d2787..e261d3d 100644
--- a/tempest/api_schema/compute/v2/availability_zone.py
+++ b/tempest/api_schema/response/compute/v2/availability_zone.py
@@ -14,7 +14,7 @@
 
 import copy
 
-from tempest.api_schema.compute import availability_zone as common
+from tempest.api_schema.response.compute import availability_zone as common
 
 
 base = {
diff --git a/tempest/api_schema/compute/v2/certificates.py b/tempest/api_schema/response/compute/v2/certificates.py
similarity index 91%
rename from tempest/api_schema/compute/v2/certificates.py
rename to tempest/api_schema/response/compute/v2/certificates.py
index 1eb38ce..bda6075 100644
--- a/tempest/api_schema/compute/v2/certificates.py
+++ b/tempest/api_schema/response/compute/v2/certificates.py
@@ -14,6 +14,6 @@
 
 import copy
 
-from tempest.api_schema.compute import certificates
+from tempest.api_schema.response.compute import certificates
 
 create_certificate = copy.deepcopy(certificates._common_schema)
diff --git a/tempest/api_schema/compute/v2/extensions.py b/tempest/api_schema/response/compute/v2/extensions.py
similarity index 100%
rename from tempest/api_schema/compute/v2/extensions.py
rename to tempest/api_schema/response/compute/v2/extensions.py
diff --git a/tempest/api_schema/compute/v2/fixed_ips.py b/tempest/api_schema/response/compute/v2/fixed_ips.py
similarity index 100%
rename from tempest/api_schema/compute/v2/fixed_ips.py
rename to tempest/api_schema/response/compute/v2/fixed_ips.py
diff --git a/tempest/api_schema/compute/v2/flavors.py b/tempest/api_schema/response/compute/v2/flavors.py
similarity index 92%
rename from tempest/api_schema/compute/v2/flavors.py
rename to tempest/api_schema/response/compute/v2/flavors.py
index bee6ecb..811ea84 100644
--- a/tempest/api_schema/compute/v2/flavors.py
+++ b/tempest/api_schema/response/compute/v2/flavors.py
@@ -14,11 +14,11 @@
 
 import copy
 
-from tempest.api_schema.compute import flavors
+from tempest.api_schema.response.compute import flavors
 
 list_flavors_details = copy.deepcopy(flavors.common_flavor_list_details)
 
-# 'swap' attributes comes as integre value but if it is empty it comes as "".
+# 'swap' attributes comes as integer value but if it is empty it comes as "".
 # So defining type of as string and integer.
 list_flavors_details['response_body']['properties']['flavors']['items'][
     'properties']['swap'] = {'type': ['string', 'integer']}
@@ -38,7 +38,7 @@
 
 create_get_flavor_details = copy.deepcopy(flavors.common_flavor_details)
 
-# 'swap' attributes comes as integre value but if it is empty it comes as "".
+# 'swap' attributes comes as integer value but if it is empty it comes as "".
 # So defining type of as string and integer.
 create_get_flavor_details['response_body']['properties']['flavor'][
     'properties']['swap'] = {'type': ['string', 'integer']}
diff --git a/tempest/api_schema/compute/v2/floating_ips.py b/tempest/api_schema/response/compute/v2/floating_ips.py
similarity index 100%
rename from tempest/api_schema/compute/v2/floating_ips.py
rename to tempest/api_schema/response/compute/v2/floating_ips.py
diff --git a/tempest/api_schema/compute/v2/hosts.py b/tempest/api_schema/response/compute/v2/hosts.py
similarity index 95%
rename from tempest/api_schema/compute/v2/hosts.py
rename to tempest/api_schema/response/compute/v2/hosts.py
index 86efadf..0944792 100644
--- a/tempest/api_schema/compute/v2/hosts.py
+++ b/tempest/api_schema/response/compute/v2/hosts.py
@@ -14,7 +14,7 @@
 
 import copy
 
-from tempest.api_schema.compute import hosts
+from tempest.api_schema.response.compute import hosts
 
 
 startup_host = {
diff --git a/tempest/api_schema/compute/v2/hypervisors.py b/tempest/api_schema/response/compute/v2/hypervisors.py
similarity index 95%
rename from tempest/api_schema/compute/v2/hypervisors.py
rename to tempest/api_schema/response/compute/v2/hypervisors.py
index 6bb43a7..7ad81c0 100644
--- a/tempest/api_schema/compute/v2/hypervisors.py
+++ b/tempest/api_schema/response/compute/v2/hypervisors.py
@@ -13,7 +13,7 @@
 #    under the License.
 
 import copy
-from tempest.api_schema.compute import hypervisors
+from tempest.api_schema.response.compute import hypervisors
 
 hypervisors_servers = copy.deepcopy(hypervisors.common_hypervisors_detail)
 
diff --git a/tempest/api_schema/compute/v2/images.py b/tempest/api_schema/response/compute/v2/images.py
similarity index 97%
rename from tempest/api_schema/compute/v2/images.py
rename to tempest/api_schema/response/compute/v2/images.py
index 90737a2..923c744 100644
--- a/tempest/api_schema/compute/v2/images.py
+++ b/tempest/api_schema/response/compute/v2/images.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api_schema.compute import parameter_types
+from tempest.api_schema.response.compute import parameter_types
 
 common_image_schema = {
     'type': 'object',
diff --git a/tempest/api_schema/compute/v2/instance_usage_audit_logs.py b/tempest/api_schema/response/compute/v2/instance_usage_audit_logs.py
similarity index 100%
rename from tempest/api_schema/compute/v2/instance_usage_audit_logs.py
rename to tempest/api_schema/response/compute/v2/instance_usage_audit_logs.py
diff --git a/tempest/api_schema/compute/v2/interfaces.py b/tempest/api_schema/response/compute/v2/interfaces.py
similarity index 92%
rename from tempest/api_schema/compute/v2/interfaces.py
rename to tempest/api_schema/response/compute/v2/interfaces.py
index 7fca791..64d161d 100644
--- a/tempest/api_schema/compute/v2/interfaces.py
+++ b/tempest/api_schema/response/compute/v2/interfaces.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api_schema.compute import interfaces as common_schema
+from tempest.api_schema.response.compute import interfaces as common_schema
 
 list_interfaces = {
     'status_code': [200],
diff --git a/tempest/api_schema/compute/v2/keypairs.py b/tempest/api_schema/response/compute/v2/keypairs.py
similarity index 96%
rename from tempest/api_schema/compute/v2/keypairs.py
rename to tempest/api_schema/response/compute/v2/keypairs.py
index 32d8cca..ec26fa0 100644
--- a/tempest/api_schema/compute/v2/keypairs.py
+++ b/tempest/api_schema/response/compute/v2/keypairs.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api_schema.compute import keypairs
+from tempest.api_schema.response.compute import keypairs
 
 get_keypair = {
     'status_code': [200],
diff --git a/tempest/api_schema/compute/v2/limits.py b/tempest/api_schema/response/compute/v2/limits.py
similarity index 100%
rename from tempest/api_schema/compute/v2/limits.py
rename to tempest/api_schema/response/compute/v2/limits.py
diff --git a/tempest/api_schema/compute/v2/quota_classes.py b/tempest/api_schema/response/compute/v2/quota_classes.py
similarity index 95%
rename from tempest/api_schema/compute/v2/quota_classes.py
rename to tempest/api_schema/response/compute/v2/quota_classes.py
index 3464fb4..5474a89 100644
--- a/tempest/api_schema/compute/v2/quota_classes.py
+++ b/tempest/api_schema/response/compute/v2/quota_classes.py
@@ -15,7 +15,7 @@
 
 import copy
 
-from tempest.api_schema.compute.v2 import quotas
+from tempest.api_schema.response.compute.v2 import quotas
 
 # NOTE(mriedem): os-quota-class-sets responses are the same as os-quota-sets
 # except for the key in the response body is quota_class_set instead of
diff --git a/tempest/api_schema/compute/v2/quotas.py b/tempest/api_schema/response/compute/v2/quotas.py
similarity index 97%
rename from tempest/api_schema/compute/v2/quotas.py
rename to tempest/api_schema/response/compute/v2/quotas.py
index 31c0458..630b227 100644
--- a/tempest/api_schema/compute/v2/quotas.py
+++ b/tempest/api_schema/response/compute/v2/quotas.py
@@ -14,7 +14,7 @@
 
 import copy
 
-from tempest.api_schema.compute import quotas
+from tempest.api_schema.response.compute import quotas
 
 quota_set = copy.deepcopy(quotas.common_quota_set)
 quota_set['response_body']['properties']['quota_set']['properties'][
diff --git a/tempest/api_schema/compute/v2/security_groups.py b/tempest/api_schema/response/compute/v2/security_groups.py
similarity index 100%
rename from tempest/api_schema/compute/v2/security_groups.py
rename to tempest/api_schema/response/compute/v2/security_groups.py
diff --git a/tempest/api_schema/compute/v2/servers.py b/tempest/api_schema/response/compute/v2/servers.py
similarity index 98%
rename from tempest/api_schema/compute/v2/servers.py
rename to tempest/api_schema/response/compute/v2/servers.py
index 4abadf4..5fc2008 100644
--- a/tempest/api_schema/compute/v2/servers.py
+++ b/tempest/api_schema/response/compute/v2/servers.py
@@ -14,8 +14,8 @@
 
 import copy
 
-from tempest.api_schema.compute import parameter_types
-from tempest.api_schema.compute import servers
+from tempest.api_schema.response.compute import parameter_types
+from tempest.api_schema.response.compute import servers
 
 create_server = {
     'status_code': [202],
diff --git a/tempest/api_schema/compute/v2/tenant_usages.py b/tempest/api_schema/response/compute/v2/tenant_usages.py
similarity index 100%
rename from tempest/api_schema/compute/v2/tenant_usages.py
rename to tempest/api_schema/response/compute/v2/tenant_usages.py
diff --git a/tempest/api_schema/compute/v2/volumes.py b/tempest/api_schema/response/compute/v2/volumes.py
similarity index 100%
rename from tempest/api_schema/compute/v2/volumes.py
rename to tempest/api_schema/response/compute/v2/volumes.py
diff --git a/tempest/api_schema/compute/v3/__init__.py b/tempest/api_schema/response/compute/v3/__init__.py
similarity index 100%
rename from tempest/api_schema/compute/v3/__init__.py
rename to tempest/api_schema/response/compute/v3/__init__.py
diff --git a/tempest/api_schema/compute/v3/agents.py b/tempest/api_schema/response/compute/v3/agents.py
similarity index 93%
rename from tempest/api_schema/compute/v3/agents.py
rename to tempest/api_schema/response/compute/v3/agents.py
index 597a089..9ef05df 100644
--- a/tempest/api_schema/compute/v3/agents.py
+++ b/tempest/api_schema/response/compute/v3/agents.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api_schema.compute import agents
+from tempest.api_schema.response.compute import agents
 
 create_agent = {
     'status_code': [201],
diff --git a/tempest/api_schema/compute/v3/aggregates.py b/tempest/api_schema/response/compute/v3/aggregates.py
similarity index 94%
rename from tempest/api_schema/compute/v3/aggregates.py
rename to tempest/api_schema/response/compute/v3/aggregates.py
index 0272641..e3bae13 100644
--- a/tempest/api_schema/compute/v3/aggregates.py
+++ b/tempest/api_schema/response/compute/v3/aggregates.py
@@ -14,7 +14,7 @@
 
 import copy
 
-from tempest.api_schema.compute import aggregates
+from tempest.api_schema.response.compute import aggregates
 
 delete_aggregate = {
     'status_code': [204]
diff --git a/tempest/api_schema/compute/v3/availability_zone.py b/tempest/api_schema/response/compute/v3/availability_zone.py
similarity index 95%
rename from tempest/api_schema/compute/v3/availability_zone.py
rename to tempest/api_schema/response/compute/v3/availability_zone.py
index 5f36c33..dbb1d41 100644
--- a/tempest/api_schema/compute/v3/availability_zone.py
+++ b/tempest/api_schema/response/compute/v3/availability_zone.py
@@ -14,7 +14,7 @@
 
 import copy
 
-from tempest.api_schema.compute import availability_zone as common
+from tempest.api_schema.response.compute import availability_zone as common
 
 
 base = {
diff --git a/tempest/api_schema/compute/v3/certificates.py b/tempest/api_schema/response/compute/v3/certificates.py
similarity index 92%
rename from tempest/api_schema/compute/v3/certificates.py
rename to tempest/api_schema/response/compute/v3/certificates.py
index 0723a16..c768391 100644
--- a/tempest/api_schema/compute/v3/certificates.py
+++ b/tempest/api_schema/response/compute/v3/certificates.py
@@ -14,7 +14,7 @@
 
 import copy
 
-from tempest.api_schema.compute import certificates
+from tempest.api_schema.response.compute import certificates
 
 create_certificate = copy.deepcopy(certificates._common_schema)
 create_certificate['status_code'] = [201]
diff --git a/tempest/api_schema/compute/v3/extensions.py b/tempest/api_schema/response/compute/v3/extensions.py
similarity index 100%
rename from tempest/api_schema/compute/v3/extensions.py
rename to tempest/api_schema/response/compute/v3/extensions.py
diff --git a/tempest/api_schema/compute/v3/flavors.py b/tempest/api_schema/response/compute/v3/flavors.py
similarity index 95%
rename from tempest/api_schema/compute/v3/flavors.py
rename to tempest/api_schema/response/compute/v3/flavors.py
index 52010f5..d6c2c85 100644
--- a/tempest/api_schema/compute/v3/flavors.py
+++ b/tempest/api_schema/response/compute/v3/flavors.py
@@ -14,8 +14,8 @@
 
 import copy
 
-from tempest.api_schema.compute import flavors
-from tempest.api_schema.compute import flavors_extra_specs
+from tempest.api_schema.response.compute import flavors
+from tempest.api_schema.response.compute import flavors_extra_specs
 
 list_flavors_details = copy.deepcopy(flavors.common_flavor_list_details)
 
diff --git a/tempest/api_schema/compute/v3/hosts.py b/tempest/api_schema/response/compute/v3/hosts.py
similarity index 96%
rename from tempest/api_schema/compute/v3/hosts.py
rename to tempest/api_schema/response/compute/v3/hosts.py
index eb689d1..f356371 100644
--- a/tempest/api_schema/compute/v3/hosts.py
+++ b/tempest/api_schema/response/compute/v3/hosts.py
@@ -14,7 +14,7 @@
 
 import copy
 
-from tempest.api_schema.compute import hosts
+from tempest.api_schema.response.compute import hosts
 
 startup_host = {
     'status_code': [200],
diff --git a/tempest/api_schema/compute/v3/hypervisors.py b/tempest/api_schema/response/compute/v3/hypervisors.py
similarity index 96%
rename from tempest/api_schema/compute/v3/hypervisors.py
rename to tempest/api_schema/response/compute/v3/hypervisors.py
index aa31827..9a9a9f7 100644
--- a/tempest/api_schema/compute/v3/hypervisors.py
+++ b/tempest/api_schema/response/compute/v3/hypervisors.py
@@ -13,7 +13,7 @@
 #    under the License.
 
 import copy
-from tempest.api_schema.compute import hypervisors
+from tempest.api_schema.response.compute import hypervisors
 
 list_hypervisors_detail = copy.deepcopy(
     hypervisors.common_list_hypervisors_detail)
diff --git a/tempest/api_schema/compute/v3/interfaces.py b/tempest/api_schema/response/compute/v3/interfaces.py
similarity index 92%
rename from tempest/api_schema/compute/v3/interfaces.py
rename to tempest/api_schema/response/compute/v3/interfaces.py
index 5e1cee2..7f716ee 100644
--- a/tempest/api_schema/compute/v3/interfaces.py
+++ b/tempest/api_schema/response/compute/v3/interfaces.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api_schema.compute import interfaces as common_schema
+from tempest.api_schema.response.compute import interfaces as common_schema
 
 list_interfaces = {
     'status_code': [200],
diff --git a/tempest/api_schema/compute/v3/keypairs.py b/tempest/api_schema/response/compute/v3/keypairs.py
similarity index 95%
rename from tempest/api_schema/compute/v3/keypairs.py
rename to tempest/api_schema/response/compute/v3/keypairs.py
index de5f4ba..ea15405 100644
--- a/tempest/api_schema/compute/v3/keypairs.py
+++ b/tempest/api_schema/response/compute/v3/keypairs.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api_schema.compute import keypairs
+from tempest.api_schema.response.compute import keypairs
 
 get_keypair = {
     'status_code': [200],
diff --git a/tempest/api_schema/compute/v3/quotas.py b/tempest/api_schema/response/compute/v3/quotas.py
similarity index 97%
rename from tempest/api_schema/compute/v3/quotas.py
rename to tempest/api_schema/response/compute/v3/quotas.py
index a3212ed..85ed3b3 100644
--- a/tempest/api_schema/compute/v3/quotas.py
+++ b/tempest/api_schema/response/compute/v3/quotas.py
@@ -14,7 +14,7 @@
 
 import copy
 
-from tempest.api_schema.compute import quotas
+from tempest.api_schema.response.compute import quotas
 
 quota_set = copy.deepcopy(quotas.common_quota_set)
 quota_set['response_body']['properties']['quota_set']['properties'][
diff --git a/tempest/api_schema/compute/v3/servers.py b/tempest/api_schema/response/compute/v3/servers.py
similarity index 98%
rename from tempest/api_schema/compute/v3/servers.py
rename to tempest/api_schema/response/compute/v3/servers.py
index a84ac3c..230de5f 100644
--- a/tempest/api_schema/compute/v3/servers.py
+++ b/tempest/api_schema/response/compute/v3/servers.py
@@ -14,8 +14,8 @@
 
 import copy
 
-from tempest.api_schema.compute import parameter_types
-from tempest.api_schema.compute import servers
+from tempest.api_schema.response.compute import parameter_types
+from tempest.api_schema.response.compute import servers
 
 create_server = {
     'status_code': [202],
diff --git a/tempest/api_schema/compute/version.py b/tempest/api_schema/response/compute/version.py
similarity index 100%
rename from tempest/api_schema/compute/version.py
rename to tempest/api_schema/response/compute/version.py
diff --git a/tempest/api_schema/queuing/__init__.py b/tempest/api_schema/response/queuing/__init__.py
similarity index 100%
rename from tempest/api_schema/queuing/__init__.py
rename to tempest/api_schema/response/queuing/__init__.py
diff --git a/tempest/api_schema/queuing/v1/__init__.py b/tempest/api_schema/response/queuing/v1/__init__.py
similarity index 100%
rename from tempest/api_schema/queuing/v1/__init__.py
rename to tempest/api_schema/response/queuing/v1/__init__.py
diff --git a/tempest/api_schema/queuing/v1/queues.py b/tempest/api_schema/response/queuing/v1/queues.py
similarity index 100%
rename from tempest/api_schema/queuing/v1/queues.py
rename to tempest/api_schema/response/queuing/v1/queues.py
diff --git a/tempest/cli/__init__.py b/tempest/cli/__init__.py
index 02f8c05..c33589a 100644
--- a/tempest/cli/__init__.py
+++ b/tempest/cli/__init__.py
@@ -13,14 +13,18 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import functools
 import os
 import shlex
 import subprocess
 
+import testtools
+
 import tempest.cli.output_parser
 from tempest import config
 from tempest import exceptions
 from tempest.openstack.common import log as logging
+from tempest.openstack.common import versionutils
 import tempest.test
 
 
@@ -29,6 +33,65 @@
 CONF = config.CONF
 
 
+def execute(cmd, action, flags='', params='', fail_ok=False,
+            merge_stderr=False):
+    """Executes specified command for the given action."""
+    cmd = ' '.join([os.path.join(CONF.cli.cli_dir, cmd),
+                    flags, action, params])
+    LOG.info("running: '%s'" % cmd)
+    cmd = shlex.split(cmd.encode('utf-8'))
+    result = ''
+    result_err = ''
+    stdout = subprocess.PIPE
+    stderr = subprocess.STDOUT if merge_stderr else subprocess.PIPE
+    proc = subprocess.Popen(cmd, stdout=stdout, stderr=stderr)
+    result, result_err = proc.communicate()
+    if not fail_ok and proc.returncode != 0:
+        raise exceptions.CommandFailed(proc.returncode,
+                                       cmd,
+                                       result,
+                                       result_err)
+    return result
+
+
+def check_client_version(client, version):
+    """Checks if the client's version is compatible with the given version
+
+    @param client: The client to check.
+    @param version: The version to compare against.
+    @return: True if the client version is compatible with the given version
+             parameter, False otherwise.
+    """
+    current_version = execute(client, '', params='--version',
+                              merge_stderr=True)
+
+    if not current_version.strip():
+        raise exceptions.TempestException('"%s --version" output was empty' %
+                                          client)
+
+    return versionutils.is_compatible(version, current_version,
+                                      same_major=False)
+
+
+def min_client_version(*args, **kwargs):
+    """A decorator to skip tests if the client used isn't of the right version.
+
+    @param client: The client command to run. For python-novaclient, this is
+                   'nova', for python-cinderclient this is 'cinder', etc.
+    @param version: The minimum version required to run the CLI test.
+    """
+    def decorator(func):
+        @functools.wraps(func)
+        def wrapper(*func_args, **func_kwargs):
+            if not check_client_version(kwargs['client'], kwargs['version']):
+                msg = "requires %s client version >= %s" % (kwargs['client'],
+                                                            kwargs['version'])
+                raise testtools.TestCase.skipException(msg)
+            return func(*func_args, **func_kwargs)
+        return wrapper
+    return decorator
+
+
 class ClientTestBase(tempest.test.BaseTestCase):
     @classmethod
     def setUpClass(cls):
@@ -50,7 +113,7 @@
     def nova_manage(self, action, flags='', params='', fail_ok=False,
                     merge_stderr=False):
         """Executes nova-manage command for the given action."""
-        return self.cmd(
+        return execute(
             'nova-manage', action, flags, params, fail_ok, merge_stderr)
 
     def keystone(self, action, flags='', params='', admin=True, fail_ok=False):
@@ -114,28 +177,7 @@
                   CONF.identity.admin_password,
                   CONF.identity.uri))
         flags = creds + ' ' + flags
-        return self.cmd(cmd, action, flags, params, fail_ok, merge_stderr)
-
-    def cmd(self, cmd, action, flags='', params='', fail_ok=False,
-            merge_stderr=False):
-        """Executes specified command for the given action."""
-        cmd = ' '.join([os.path.join(CONF.cli.cli_dir, cmd),
-                        flags, action, params])
-        LOG.info("running: '%s'" % cmd)
-        cmd = shlex.split(cmd.encode('utf-8'))
-        result = ''
-        result_err = ''
-        stdout = subprocess.PIPE
-        stderr = subprocess.STDOUT if merge_stderr else subprocess.PIPE
-        proc = subprocess.Popen(
-            cmd, stdout=stdout, stderr=stderr)
-        result, result_err = proc.communicate()
-        if not fail_ok and proc.returncode != 0:
-            raise exceptions.CommandFailed(proc.returncode,
-                                           cmd,
-                                           result,
-                                           result_err)
-        return result
+        return execute(cmd, action, flags, params, fail_ok, merge_stderr)
 
     def assertTableStruct(self, items, field_names):
         """Verify that all items has keys listed in field_names."""
diff --git a/tempest/cli/simple_read_only/test_glance.py b/tempest/cli/simple_read_only/test_glance.py
index 90cdc55..2fd8212 100644
--- a/tempest/cli/simple_read_only/test_glance.py
+++ b/tempest/cli/simple_read_only/test_glance.py
@@ -77,7 +77,7 @@
         wanted_commands = set(('image-create', 'image-delete', 'help',
                                'image-download', 'image-show', 'image-update',
                                'member-create', 'member-delete',
-                               'member-list'))
+                               'member-list', 'image-list'))
         self.assertFalse(wanted_commands - commands)
 
     # Optional arguments:
diff --git a/tempest/cli/simple_read_only/test_heat.py b/tempest/cli/simple_read_only/test_heat.py
index 7a952fc..bd79fa6 100644
--- a/tempest/cli/simple_read_only/test_heat.py
+++ b/tempest/cli/simple_read_only/test_heat.py
@@ -85,6 +85,7 @@
     def test_heat_help(self):
         self.heat('help')
 
+    @tempest.cli.min_client_version(client='heat', version='0.2.7')
     def test_heat_bash_completion(self):
         self.heat('bash-completion')
 
diff --git a/tempest/cli/simple_read_only/test_neutron.py b/tempest/cli/simple_read_only/test_neutron.py
index 87f6b67..f8a330c 100644
--- a/tempest/cli/simple_read_only/test_neutron.py
+++ b/tempest/cli/simple_read_only/test_neutron.py
@@ -173,6 +173,17 @@
                                'router-show', 'agent-update', 'help'))
         self.assertFalse(wanted_commands - commands)
 
+    @test.attr(type='smoke')
+    @test.requires_ext(extension='l3_agent_scheduler', service='network')
+    def test_neutron_l3_agent_list_hosting_router(self):
+        router_list = self.parser.listing(self.neutron('router-list'))
+        for router in router_list:
+            l3_list = self.parser.listing(self.neutron
+                                          ('l3-agent-list-hosting-router',
+                                           params=router['id']))
+            self.assertTableStruct(l3_list, ['id', 'host',
+                                             'admin_state_up', 'alive'])
+
     # Optional arguments:
 
     @test.attr(type='smoke')
diff --git a/tempest/cli/simple_read_only/test_nova.py b/tempest/cli/simple_read_only/test_nova.py
index 7085cc9..9bac7a6 100644
--- a/tempest/cli/simple_read_only/test_nova.py
+++ b/tempest/cli/simple_read_only/test_nova.py
@@ -144,6 +144,7 @@
     def test_admin_secgroup_list_rules(self):
         self.nova('secgroup-list-rules')
 
+    @tempest.cli.min_client_version(client='nova', version='2.18')
     def test_admin_server_group_list(self):
         self.nova('server-group-list')
 
diff --git a/tempest/cmd/javelin.py b/tempest/cmd/javelin.py
index 67b92b0..3616a82 100755
--- a/tempest/cmd/javelin.py
+++ b/tempest/cmd/javelin.py
@@ -309,6 +309,14 @@
     return name, fname
 
 
+def _get_image_by_name(client, name):
+    r, body = client.images.image_list()
+    for image in body:
+        if name == image['name']:
+            return image
+    return None
+
+
 def create_images(images):
     if not images:
         return
@@ -317,9 +325,7 @@
         client = client_for_user(image['owner'])
 
         # only upload a new image if the name isn't there
-        r, body = client.images.image_list()
-        names = [x['name'] for x in body]
-        if image['name'] in names:
+        if _get_image_by_name(client, image['name']):
             LOG.info("Image '%s' already exists" % image['name'])
             continue
 
@@ -345,6 +351,20 @@
         client.images.store_image(image_id, open(fname, 'r'))
 
 
+def destroy_images(images):
+    if not images:
+        return
+    LOG.info("Destroying images")
+    for image in images:
+        client = client_for_user(image['owner'])
+
+        response = _get_image_by_name(client, image['name'])
+        if not response:
+            LOG.info("Image '%s' does not exists" % image['name'])
+            continue
+        client.images.delete_image(response['id'])
+
+
 #######################
 #
 # SERVERS
@@ -359,14 +379,6 @@
     return None
 
 
-def _get_image_by_name(client, name):
-    r, body = client.images.image_list()
-    for image in body:
-        if name == image['name']:
-            return image
-    return None
-
-
 def _get_flavor_by_name(client, name):
     r, body = client.flavors.list_flavors()
     for flavor in body:
@@ -478,13 +490,14 @@
     # destroy_volumes
 
     destroy_servers(RES['servers'])
-    LOG.warn("Destroy mode incomplete")
-    # destroy_images
+    destroy_images(RES['images'])
     # destroy_objects
 
     # destroy_users
     # destroy_tenants
 
+    LOG.warn("Destroy mode incomplete")
+
 
 def get_options():
     global OPTS
diff --git a/tempest/common/accounts.py b/tempest/common/accounts.py
new file mode 100644
index 0000000..80f5f91
--- /dev/null
+++ b/tempest/common/accounts.py
@@ -0,0 +1,130 @@
+# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import hashlib
+import os
+import yaml
+
+from tempest import auth
+from tempest.common import cred_provider
+from tempest import config
+from tempest import exceptions
+from tempest.openstack.common import lockutils
+from tempest.openstack.common import log as logging
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+def read_accounts_yaml(path):
+    yaml_file = open(path, 'r')
+    accounts = yaml.load(yaml_file)
+    return accounts
+
+
+class Accounts(cred_provider.CredentialProvider):
+
+    def __init__(self, name):
+        super(Accounts, self).__init__(name)
+        accounts = read_accounts_yaml(CONF.auth.test_accounts_file)
+        self.hash_dict = self.get_hash_dict(accounts)
+        self.accounts_dir = os.path.join(CONF.lock_path, 'test_accounts')
+        self.isolated_creds = {}
+
+    @classmethod
+    def get_hash_dict(cls, accounts):
+        hash_dict = {}
+        for account in accounts:
+            temp_hash = hashlib.md5()
+            temp_hash.update(str(account))
+            hash_dict[temp_hash.hexdigest()] = account
+        return hash_dict
+
+    def _create_hash_file(self, hash):
+        path = os.path.join(os.path.join(self.accounts_dir, hash))
+        if not os.path.isfile(path):
+            open(path, 'w').close()
+            return True
+        return False
+
+    @lockutils.synchronized('test_accounts_io', external=True)
+    def _get_free_hash(self, hashes):
+        if not os.path.isdir(self.accounts_dir):
+            os.mkdir(self.accounts_dir)
+            # Create File from first hash (since none are in use)
+            self._create_hash_file(hashes[0])
+            return hashes[0]
+        for hash in hashes:
+            res = self._create_hash_file(hash)
+            if res:
+                return hash
+        msg = 'Insufficient number of users provided'
+        raise exceptions.InvalidConfiguration(msg)
+
+    def _get_creds(self):
+        free_hash = self._get_free_hash(self.hashes.keys())
+        return self.hash_dict[free_hash]
+
+    @lockutils.synchronized('test_accounts_io', external=True)
+    def remove_hash(self, hash):
+        hash_path = os.path.join(self.accounts_dir, hash)
+        if not os.path.isfile(hash_path):
+            LOG.warning('Expected an account lock file %s to remove, but '
+                        'one did not exist')
+        else:
+            os.remove(hash_path)
+            if not os.listdir(self.accounts_dir):
+                os.rmdir(self.accounts_dir)
+
+    def get_hash(self, creds):
+        for hash in self.hash_dict:
+            # NOTE(mtreinish) Assuming with v3 that username, tenant, password
+            # is unique enough
+            cred_dict = {
+                'username': creds.username,
+                'tenant_name': creds.tenant_name,
+                'password': creds.password
+            }
+            if self.hash_dict[hash] == cred_dict:
+                return hash
+        raise AttributeError('Invalid credentials %s' % creds)
+
+    def remove_credentials(self, creds):
+        hash = self.get_hash(creds)
+        self.remove_hash(hash, self.accounts_dir)
+
+    def get_primary_creds(self):
+        if self.credentials.get('primary'):
+            return self.credentials.get('primary')
+        creds = self._get_creds()
+        primary_credential = auth.get_credentials(**creds)
+        self.credentials['primary'] = primary_credential
+        return primary_credential
+
+    def get_alt_creds(self):
+        if self.credentials.get('alt'):
+            return self.credentials.get('alt')
+        creds = self._get_creds()
+        alt_credential = auth.get_credentials(**creds)
+        self.credentials['alt'] = alt_credential
+        return alt_credential
+
+    def clear_isolated_creds(self):
+        for creds in self.credentials.values():
+            self.remove_credentials(creds)
+
+    def get_admin_creds(self):
+        msg = ('If admin credentials are available tenant_isolation should be'
+               ' used instead')
+        raise NotImplementedError(msg)
diff --git a/tempest/common/isolated_creds.py b/tempest/common/isolated_creds.py
index 98b0116..f711f2f 100644
--- a/tempest/common/isolated_creds.py
+++ b/tempest/common/isolated_creds.py
@@ -330,7 +330,8 @@
             # Maintained until tests are ported
             LOG.info("Acquired isolated creds:\n credentials: %s"
                      % credentials)
-            if CONF.service_available.neutron:
+            if (CONF.service_available.neutron and
+                not CONF.baremetal.driver_enabled):
                 network, subnet, router = self._create_network_resources(
                     credentials.tenant_id)
                 self.isolated_net_resources[credential_type] = (
@@ -372,31 +373,6 @@
             LOG.warn('network with name: %s not found for delete' %
                      network_name)
 
-    def _cleanup_ports(self, network_id):
-        # TODO(mlavalle) This method will be removed once patch
-        # https://review.openstack.org/#/c/46563/ merges in Neutron
-        if not self.ports:
-            if self.tempest_client:
-                resp, resp_body = self.network_admin_client.list_ports()
-            else:
-                resp_body = self.network_admin_client.list_ports()
-            self.ports = resp_body['ports']
-        ports_to_delete = [
-            port
-            for port in self.ports
-            if (port['network_id'] == network_id and
-                port['device_owner'] != 'network:router_interface' and
-                port['device_owner'] != 'network:dhcp')
-        ]
-        for port in ports_to_delete:
-            try:
-                LOG.info('Cleaning up port id %s, name %s' %
-                         (port['id'], port['name']))
-                self.network_admin_client.delete_port(port['id'])
-            except exceptions.NotFound:
-                LOG.warn('Port id: %s, name %s not found for clean-up' %
-                         (port['id'], port['name']))
-
     def _clear_isolated_net_resources(self):
         net_client = self.network_admin_client
         for cred in self.isolated_net_resources:
@@ -418,11 +394,6 @@
                              router['name'])
                 self._clear_isolated_router(router['id'], router['name'])
             if (not self.network_resources or
-                self.network_resources.get('network')):
-                # TODO(mlavalle) This method call will be removed once patch
-                # https://review.openstack.org/#/c/46563/ merges in Neutron
-                self._cleanup_ports(network['id'])
-            if (not self.network_resources or
                 self.network_resources.get('subnet')):
                 self._clear_isolated_subnet(subnet['id'], subnet['name'])
             if (not self.network_resources or
diff --git a/tempest/config.py b/tempest/config.py
index 01bc243..39c2be1 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -29,6 +29,18 @@
         conf.register_opt(opt, group=opt_group.name)
 
 
+auth_group = cfg.OptGroup(name='auth',
+                          title="Options for authentication and credentials")
+
+
+AuthGroup = [
+    cfg.StrOpt('test_accounts_file',
+               default='etc/accounts.yaml',
+               help="Path to the yaml file that contains the list of "
+                    "credentials to use for running tests"),
+]
+
+
 identity_group = cfg.OptGroup(name='identity',
                               title="Keystone Configuration Options")
 
@@ -261,6 +273,9 @@
     cfg.BoolOpt('api_v3',
                 default=False,
                 help="If false, skip all nova v3 tests."),
+    cfg.BoolOpt('xml_api_v2',
+                default=True,
+                help="If false skip all v2 api tests with xml"),
     cfg.BoolOpt('disk_config',
                 default=True,
                 help="If false, skip disk config tests"),
@@ -286,6 +301,9 @@
     cfg.BoolOpt('pause',
                 default=True,
                 help="Does the test environment support pausing?"),
+    cfg.BoolOpt('shelve',
+                default=True,
+                help="Does the test environment support shelving/unshelving?"),
     cfg.BoolOpt('suspend',
                 default=True,
                 help="Does the test environment support suspend/resume?"),
@@ -321,7 +339,11 @@
                 default=True,
                 help='Enables returning of the instance password by the '
                      'relevant server API calls such as create, rebuild '
-                     'or rescue.')
+                     'or rescue.'),
+    cfg.BoolOpt('interface_attach',
+                default=True,
+                help='Does the test environment support dynamic network '
+                     'interface attachment?')
 ]
 
 
@@ -1005,6 +1027,7 @@
 
 
 def register_opts():
+    register_opt_group(cfg.CONF, auth_group, AuthGroup)
     register_opt_group(cfg.CONF, compute_group, ComputeGroup)
     register_opt_group(cfg.CONF, compute_features_group,
                        ComputeFeaturesGroup)
@@ -1053,6 +1076,7 @@
     DEFAULT_CONFIG_FILE = "tempest.conf"
 
     def _set_attrs(self):
+        self.auth = cfg.CONF.auth
         self.compute = cfg.CONF.compute
         self.compute_feature_enabled = cfg.CONF['compute-feature-enabled']
         self.identity = cfg.CONF.identity
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 3cfc698..606208e 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -1085,7 +1085,8 @@
             try:
                 source.ping_host(dest)
             except exceptions.SSHExecCommandFailed:
-                LOG.exception('Failed to ping host via ssh connection')
+                LOG.warn('Failed to ping IP: %s via a ssh connection from: %s.'
+                         % (dest, source.ssh_client.host))
                 return not should_succeed
             return should_succeed
 
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index 7dc817d..8c7af3d 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -14,8 +14,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 import collections
-
 import re
+import testtools
 
 from tempest.api.network import common as net_common
 from tempest.common import debug
@@ -347,6 +347,8 @@
                                                 msg="after re-associate "
                                                     "floating ip")
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
+                          'NIC hotplug not available')
     @test.attr(type='smoke')
     @test.services('compute', 'network')
     def test_hotplug_nic(self):
diff --git a/tempest/services/compute/json/agents_client.py b/tempest/services/compute/json/agents_client.py
index 4f6602f..5b76a56 100644
--- a/tempest/services/compute/json/agents_client.py
+++ b/tempest/services/compute/json/agents_client.py
@@ -15,8 +15,8 @@
 import json
 import urllib
 
-from tempest.api_schema.compute import agents as common_schema
-from tempest.api_schema.compute.v2 import agents as schema
+from tempest.api_schema.response.compute import agents as common_schema
+from tempest.api_schema.response.compute.v2 import agents as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/json/aggregates_client.py b/tempest/services/compute/json/aggregates_client.py
index 71d6f63..1cb010d 100644
--- a/tempest/services/compute/json/aggregates_client.py
+++ b/tempest/services/compute/json/aggregates_client.py
@@ -15,8 +15,8 @@
 
 import json
 
-from tempest.api_schema.compute import aggregates as schema
-from tempest.api_schema.compute.v2 import aggregates as v2_schema
+from tempest.api_schema.response.compute import aggregates as schema
+from tempest.api_schema.response.compute.v2 import aggregates as v2_schema
 from tempest.common import rest_client
 from tempest import config
 from tempest import exceptions
diff --git a/tempest/services/compute/json/availability_zone_client.py b/tempest/services/compute/json/availability_zone_client.py
index 1c067e8..00f8330 100644
--- a/tempest/services/compute/json/availability_zone_client.py
+++ b/tempest/services/compute/json/availability_zone_client.py
@@ -15,7 +15,7 @@
 
 import json
 
-from tempest.api_schema.compute.v2 import availability_zone as schema
+from tempest.api_schema.response.compute.v2 import availability_zone as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/json/certificates_client.py b/tempest/services/compute/json/certificates_client.py
index 1d04628..356ded2 100644
--- a/tempest/services/compute/json/certificates_client.py
+++ b/tempest/services/compute/json/certificates_client.py
@@ -15,8 +15,8 @@
 
 import json
 
-from tempest.api_schema.compute import certificates as schema
-from tempest.api_schema.compute.v2 import certificates as v2schema
+from tempest.api_schema.response.compute import certificates as schema
+from tempest.api_schema.response.compute.v2 import certificates as v2schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/json/extensions_client.py b/tempest/services/compute/json/extensions_client.py
index ed2b14d..41d1c4e 100644
--- a/tempest/services/compute/json/extensions_client.py
+++ b/tempest/services/compute/json/extensions_client.py
@@ -15,7 +15,7 @@
 
 import json
 
-from tempest.api_schema.compute.v2 import extensions as schema
+from tempest.api_schema.response.compute.v2 import extensions as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/json/fixed_ips_client.py b/tempest/services/compute/json/fixed_ips_client.py
index f2d5cbe..5903334 100644
--- a/tempest/services/compute/json/fixed_ips_client.py
+++ b/tempest/services/compute/json/fixed_ips_client.py
@@ -15,7 +15,7 @@
 
 import json
 
-from tempest.api_schema.compute.v2 import fixed_ips as schema
+from tempest.api_schema.response.compute.v2 import fixed_ips as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index 89cbe1d..5452f3a 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -16,11 +16,11 @@
 import json
 import urllib
 
-from tempest.api_schema.compute import flavors as common_schema
-from tempest.api_schema.compute import flavors_access as schema_access
-from tempest.api_schema.compute import flavors_extra_specs \
+from tempest.api_schema.response.compute import flavors as common_schema
+from tempest.api_schema.response.compute import flavors_access as schema_access
+from tempest.api_schema.response.compute import flavors_extra_specs \
     as schema_extra_specs
-from tempest.api_schema.compute.v2 import flavors as v2schema
+from tempest.api_schema.response.compute.v2 import flavors as v2schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index cd195f4..8b020d0 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -16,7 +16,7 @@
 import json
 import urllib
 
-from tempest.api_schema.compute.v2 import floating_ips as schema
+from tempest.api_schema.response.compute.v2 import floating_ips as schema
 from tempest.common import rest_client
 from tempest import config
 from tempest import exceptions
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index 342f946..8644173 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -15,8 +15,8 @@
 import json
 import urllib
 
-from tempest.api_schema.compute import hosts as schema
-from tempest.api_schema.compute.v2 import hosts as v2_schema
+from tempest.api_schema.response.compute import hosts as schema
+from tempest.api_schema.response.compute.v2 import hosts as v2_schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/json/hypervisor_client.py b/tempest/services/compute/json/hypervisor_client.py
index 30228b3..8eacf61 100644
--- a/tempest/services/compute/json/hypervisor_client.py
+++ b/tempest/services/compute/json/hypervisor_client.py
@@ -15,8 +15,8 @@
 
 import json
 
-from tempest.api_schema.compute import hypervisors as common_schema
-from tempest.api_schema.compute.v2 import hypervisors as v2schema
+from tempest.api_schema.response.compute import hypervisors as common_schema
+from tempest.api_schema.response.compute.v2 import hypervisors as v2schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/json/images_client.py b/tempest/services/compute/json/images_client.py
index af7752a..9877391 100644
--- a/tempest/services/compute/json/images_client.py
+++ b/tempest/services/compute/json/images_client.py
@@ -16,7 +16,7 @@
 import json
 import urllib
 
-from tempest.api_schema.compute.v2 import images as schema
+from tempest.api_schema.response.compute.v2 import images as schema
 from tempest.common import rest_client
 from tempest.common import waiters
 from tempest import config
diff --git a/tempest/services/compute/json/instance_usage_audit_log_client.py b/tempest/services/compute/json/instance_usage_audit_log_client.py
index 4700ca7..4b0362b 100644
--- a/tempest/services/compute/json/instance_usage_audit_log_client.py
+++ b/tempest/services/compute/json/instance_usage_audit_log_client.py
@@ -15,7 +15,7 @@
 
 import json
 
-from tempest.api_schema.compute.v2 import instance_usage_audit_logs \
+from tempest.api_schema.response.compute.v2 import instance_usage_audit_logs \
     as schema
 from tempest.common import rest_client
 from tempest import config
diff --git a/tempest/services/compute/json/interfaces_client.py b/tempest/services/compute/json/interfaces_client.py
index cdac8b7..83c253a 100644
--- a/tempest/services/compute/json/interfaces_client.py
+++ b/tempest/services/compute/json/interfaces_client.py
@@ -16,9 +16,9 @@
 import json
 import time
 
-from tempest.api_schema.compute import interfaces as common_schema
-from tempest.api_schema.compute import servers as servers_schema
-from tempest.api_schema.compute.v2 import interfaces as schema
+from tempest.api_schema.response.compute import interfaces as common_schema
+from tempest.api_schema.response.compute import servers as servers_schema
+from tempest.api_schema.response.compute.v2 import interfaces as schema
 from tempest.common import rest_client
 from tempest import config
 from tempest import exceptions
diff --git a/tempest/services/compute/json/keypairs_client.py b/tempest/services/compute/json/keypairs_client.py
index be93789..31c42a5 100644
--- a/tempest/services/compute/json/keypairs_client.py
+++ b/tempest/services/compute/json/keypairs_client.py
@@ -15,8 +15,8 @@
 
 import json
 
-from tempest.api_schema.compute import keypairs as common_schema
-from tempest.api_schema.compute.v2 import keypairs as schema
+from tempest.api_schema.response.compute import keypairs as common_schema
+from tempest.api_schema.response.compute.v2 import keypairs as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/json/limits_client.py b/tempest/services/compute/json/limits_client.py
index e503bef..81c602b 100644
--- a/tempest/services/compute/json/limits_client.py
+++ b/tempest/services/compute/json/limits_client.py
@@ -15,7 +15,7 @@
 
 import json
 
-from tempest.api_schema.compute.v2 import limits as schema
+from tempest.api_schema.response.compute.v2 import limits as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/json/migrations_client.py b/tempest/services/compute/json/migrations_client.py
index beef5d2..f4abbb2 100644
--- a/tempest/services/compute/json/migrations_client.py
+++ b/tempest/services/compute/json/migrations_client.py
@@ -15,7 +15,7 @@
 import json
 import urllib
 
-from tempest.api_schema.compute import migrations as schema
+from tempest.api_schema.response.compute import migrations as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index 14b7100..b691529 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -15,8 +15,9 @@
 
 import json
 
-from tempest.api_schema.compute.v2 import quota_classes as classes_schema
-from tempest.api_schema.compute.v2 import quotas as schema
+from tempest.api_schema.response.compute.v2\
+    import quota_classes as classes_schema
+from tempest.api_schema.response.compute.v2 import quotas as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/json/security_groups_client.py b/tempest/services/compute/json/security_groups_client.py
index a86f3df..29859a9 100644
--- a/tempest/services/compute/json/security_groups_client.py
+++ b/tempest/services/compute/json/security_groups_client.py
@@ -16,7 +16,7 @@
 import json
 import urllib
 
-from tempest.api_schema.compute.v2 import security_groups as schema
+from tempest.api_schema.response.compute.v2 import security_groups as schema
 from tempest.common import rest_client
 from tempest import config
 from tempest import exceptions
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index a4e3641..f44be29 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -18,8 +18,8 @@
 import time
 import urllib
 
-from tempest.api_schema.compute import servers as common_schema
-from tempest.api_schema.compute.v2 import servers as schema
+from tempest.api_schema.response.compute import servers as common_schema
+from tempest.api_schema.response.compute.v2 import servers as schema
 from tempest.common import rest_client
 from tempest.common import waiters
 from tempest import config
diff --git a/tempest/services/compute/json/services_client.py b/tempest/services/compute/json/services_client.py
index d58ca6f..e56263c 100644
--- a/tempest/services/compute/json/services_client.py
+++ b/tempest/services/compute/json/services_client.py
@@ -17,7 +17,7 @@
 import json
 import urllib
 
-from tempest.api_schema.compute import services as schema
+from tempest.api_schema.response.compute import services as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/json/tenant_usages_client.py b/tempest/services/compute/json/tenant_usages_client.py
index f8adae7..a0b9b4a 100644
--- a/tempest/services/compute/json/tenant_usages_client.py
+++ b/tempest/services/compute/json/tenant_usages_client.py
@@ -16,7 +16,7 @@
 import json
 import urllib
 
-from tempest.api_schema.compute.v2 import tenant_usages as schema
+from tempest.api_schema.response.compute.v2 import tenant_usages as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/json/volumes_extensions_client.py b/tempest/services/compute/json/volumes_extensions_client.py
index d1014af..673e365 100644
--- a/tempest/services/compute/json/volumes_extensions_client.py
+++ b/tempest/services/compute/json/volumes_extensions_client.py
@@ -17,7 +17,7 @@
 import time
 import urllib
 
-from tempest.api_schema.compute.v2 import volumes as schema
+from tempest.api_schema.response.compute.v2 import volumes as schema
 from tempest.common import rest_client
 from tempest import config
 from tempest import exceptions
diff --git a/tempest/services/compute/v3/json/agents_client.py b/tempest/services/compute/v3/json/agents_client.py
index 31314b7..ffca142 100644
--- a/tempest/services/compute/v3/json/agents_client.py
+++ b/tempest/services/compute/v3/json/agents_client.py
@@ -15,8 +15,8 @@
 import json
 import urllib
 
-from tempest.api_schema.compute import agents as common_schema
-from tempest.api_schema.compute.v3 import agents as schema
+from tempest.api_schema.response.compute import agents as common_schema
+from tempest.api_schema.response.compute.v3 import agents as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/v3/json/aggregates_client.py b/tempest/services/compute/v3/json/aggregates_client.py
index d9b7930..960fe05 100644
--- a/tempest/services/compute/v3/json/aggregates_client.py
+++ b/tempest/services/compute/v3/json/aggregates_client.py
@@ -15,8 +15,8 @@
 
 import json
 
-from tempest.api_schema.compute import aggregates as schema
-from tempest.api_schema.compute.v3 import aggregates as v3_schema
+from tempest.api_schema.response.compute import aggregates as schema
+from tempest.api_schema.response.compute.v3 import aggregates as v3_schema
 from tempest.common import rest_client
 from tempest import config
 from tempest import exceptions
diff --git a/tempest/services/compute/v3/json/availability_zone_client.py b/tempest/services/compute/v3/json/availability_zone_client.py
index bf74e68..0da78da 100644
--- a/tempest/services/compute/v3/json/availability_zone_client.py
+++ b/tempest/services/compute/v3/json/availability_zone_client.py
@@ -15,7 +15,7 @@
 
 import json
 
-from tempest.api_schema.compute.v3 import availability_zone as schema
+from tempest.api_schema.response.compute.v3 import availability_zone as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/v3/json/certificates_client.py b/tempest/services/compute/v3/json/certificates_client.py
index be9b3c3..42e9d5a 100644
--- a/tempest/services/compute/v3/json/certificates_client.py
+++ b/tempest/services/compute/v3/json/certificates_client.py
@@ -15,8 +15,8 @@
 
 import json
 
-from tempest.api_schema.compute import certificates as schema
-from tempest.api_schema.compute.v3 import certificates as v3schema
+from tempest.api_schema.response.compute import certificates as schema
+from tempest.api_schema.response.compute.v3 import certificates as v3schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/v3/json/extensions_client.py b/tempest/services/compute/v3/json/extensions_client.py
index 13292db..f172efd 100644
--- a/tempest/services/compute/v3/json/extensions_client.py
+++ b/tempest/services/compute/v3/json/extensions_client.py
@@ -15,7 +15,7 @@
 
 import json
 
-from tempest.api_schema.compute.v3 import extensions as schema
+from tempest.api_schema.response.compute.v3 import extensions as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/v3/json/flavors_client.py b/tempest/services/compute/v3/json/flavors_client.py
index 5afab5a..d1eee5b 100644
--- a/tempest/services/compute/v3/json/flavors_client.py
+++ b/tempest/services/compute/v3/json/flavors_client.py
@@ -16,11 +16,11 @@
 import json
 import urllib
 
-from tempest.api_schema.compute import flavors as common_schema
-from tempest.api_schema.compute import flavors_access as schema_access
-from tempest.api_schema.compute import flavors_extra_specs \
+from tempest.api_schema.response.compute import flavors as common_schema
+from tempest.api_schema.response.compute import flavors_access as schema_access
+from tempest.api_schema.response.compute import flavors_extra_specs \
     as schema_extra_specs
-from tempest.api_schema.compute.v3 import flavors as v3schema
+from tempest.api_schema.response.compute.v3 import flavors as v3schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/v3/json/hosts_client.py b/tempest/services/compute/v3/json/hosts_client.py
index d2eb43d..476afad 100644
--- a/tempest/services/compute/v3/json/hosts_client.py
+++ b/tempest/services/compute/v3/json/hosts_client.py
@@ -15,8 +15,8 @@
 import json
 import urllib
 
-from tempest.api_schema.compute import hosts as schema
-from tempest.api_schema.compute.v3 import hosts as v3_schema
+from tempest.api_schema.response.compute import hosts as schema
+from tempest.api_schema.response.compute.v3 import hosts as v3_schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/v3/json/hypervisor_client.py b/tempest/services/compute/v3/json/hypervisor_client.py
index 51468c9..507157a 100644
--- a/tempest/services/compute/v3/json/hypervisor_client.py
+++ b/tempest/services/compute/v3/json/hypervisor_client.py
@@ -15,8 +15,8 @@
 
 import json
 
-from tempest.api_schema.compute import hypervisors as common_schema
-from tempest.api_schema.compute.v3 import hypervisors as v3schema
+from tempest.api_schema.response.compute import hypervisors as common_schema
+from tempest.api_schema.response.compute.v3 import hypervisors as v3schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/v3/json/interfaces_client.py b/tempest/services/compute/v3/json/interfaces_client.py
index e66ccaa..e99c124 100644
--- a/tempest/services/compute/v3/json/interfaces_client.py
+++ b/tempest/services/compute/v3/json/interfaces_client.py
@@ -16,9 +16,9 @@
 import json
 import time
 
-from tempest.api_schema.compute import interfaces as common_schema
-from tempest.api_schema.compute import servers as servers_schema
-from tempest.api_schema.compute.v3 import interfaces as schema
+from tempest.api_schema.response.compute import interfaces as common_schema
+from tempest.api_schema.response.compute import servers as servers_schema
+from tempest.api_schema.response.compute.v3 import interfaces as schema
 from tempest.common import rest_client
 from tempest import config
 from tempest import exceptions
diff --git a/tempest/services/compute/v3/json/keypairs_client.py b/tempest/services/compute/v3/json/keypairs_client.py
index f090d7d..a290acb 100644
--- a/tempest/services/compute/v3/json/keypairs_client.py
+++ b/tempest/services/compute/v3/json/keypairs_client.py
@@ -15,8 +15,8 @@
 
 import json
 
-from tempest.api_schema.compute import keypairs as common_schema
-from tempest.api_schema.compute.v3 import keypairs as schema
+from tempest.api_schema.response.compute import keypairs as common_schema
+from tempest.api_schema.response.compute.v3 import keypairs as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/v3/json/migration_client.py b/tempest/services/compute/v3/json/migration_client.py
index c821567..bf1ae85 100644
--- a/tempest/services/compute/v3/json/migration_client.py
+++ b/tempest/services/compute/v3/json/migration_client.py
@@ -15,7 +15,7 @@
 import json
 import urllib
 
-from tempest.api_schema.compute import migrations as schema
+from tempest.api_schema.response.compute import migrations as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/v3/json/quotas_client.py b/tempest/services/compute/v3/json/quotas_client.py
index 37a8906..f9aa9e9 100644
--- a/tempest/services/compute/v3/json/quotas_client.py
+++ b/tempest/services/compute/v3/json/quotas_client.py
@@ -15,7 +15,7 @@
 
 import json
 
-from tempest.api_schema.compute.v3 import quotas as schema
+from tempest.api_schema.response.compute.v3 import quotas as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/v3/json/servers_client.py b/tempest/services/compute/v3/json/servers_client.py
index c3fd355..89e282d 100644
--- a/tempest/services/compute/v3/json/servers_client.py
+++ b/tempest/services/compute/v3/json/servers_client.py
@@ -19,8 +19,8 @@
 import time
 import urllib
 
-from tempest.api_schema.compute import servers as common_schema
-from tempest.api_schema.compute.v3 import servers as schema
+from tempest.api_schema.response.compute import servers as common_schema
+from tempest.api_schema.response.compute.v3 import servers as schema
 from tempest.common import rest_client
 from tempest.common import waiters
 from tempest import config
diff --git a/tempest/services/compute/v3/json/services_client.py b/tempest/services/compute/v3/json/services_client.py
index 96ff580..0645287 100644
--- a/tempest/services/compute/v3/json/services_client.py
+++ b/tempest/services/compute/v3/json/services_client.py
@@ -17,7 +17,7 @@
 import json
 import urllib
 
-from tempest.api_schema.compute import services as schema
+from tempest.api_schema.response.compute import services as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/compute/v3/json/version_client.py b/tempest/services/compute/v3/json/version_client.py
index 568678d..bc4f58c 100644
--- a/tempest/services/compute/v3/json/version_client.py
+++ b/tempest/services/compute/v3/json/version_client.py
@@ -15,7 +15,7 @@
 
 import json
 
-from tempest.api_schema.compute import version as schema
+from tempest.api_schema.response.compute import version as schema
 from tempest.common import rest_client
 from tempest import config
 
diff --git a/tempest/services/data_processing/v1_1/client.py b/tempest/services/data_processing/v1_1/client.py
index 1fe0cf1..7acbae7 100644
--- a/tempest/services/data_processing/v1_1/client.py
+++ b/tempest/services/data_processing/v1_1/client.py
@@ -258,3 +258,38 @@
 
         uri = 'job-binaries/%s/data' % job_binary_id
         return self._request_and_check_resp(self.get, uri, 200)
+
+    def list_jobs(self):
+        """List all jobs for a user."""
+
+        uri = 'jobs'
+        return self._request_check_and_parse_resp(self.get, uri, 200, 'jobs')
+
+    def get_job(self, job_id):
+        """Returns the details of a single job."""
+
+        uri = 'jobs/%s' % job_id
+        return self._request_check_and_parse_resp(self.get, uri, 200, 'job')
+
+    def create_job(self, name, job_type, mains, libs=None, **kwargs):
+        """Creates job with specified params.
+
+        It supports passing additional params using kwargs and returns created
+        object.
+        """
+        uri = 'jobs'
+        body = kwargs.copy()
+        body.update({
+            'name': name,
+            'type': job_type,
+            'mains': mains,
+            'libs': libs or list(),
+        })
+        return self._request_check_and_parse_resp(self.post, uri, 202,
+                                                  'job', body=json.dumps(body))
+
+    def delete_job(self, job_id):
+        """Deletes the specified job by id."""
+
+        uri = 'jobs/%s' % job_id
+        return self._request_and_check_resp(self.delete, uri, 204)
diff --git a/tempest/services/queuing/json/queuing_client.py b/tempest/services/queuing/json/queuing_client.py
index 031c9c6..14960ad 100644
--- a/tempest/services/queuing/json/queuing_client.py
+++ b/tempest/services/queuing/json/queuing_client.py
@@ -16,7 +16,7 @@
 import json
 import urllib
 
-from tempest.api_schema.queuing.v1 import queues as queues_schema
+from tempest.api_schema.response.queuing.v1 import queues as queues_schema
 from tempest.common import rest_client
 from tempest.common.utils import data_utils
 from tempest import config
diff --git a/tempest/test.py b/tempest/test.py
index 5b7330b..95ae23f 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -623,7 +623,6 @@
     while now < timeout:
         if func():
             return True
-        LOG.debug("Sleeping for %d seconds", sleep_for)
         time.sleep(sleep_for)
         now = time.time()
     return False
diff --git a/tempest/tests/cli/test_cli.py b/tempest/tests/cli/test_cli.py
new file mode 100644
index 0000000..1fd5ccb
--- /dev/null
+++ b/tempest/tests/cli/test_cli.py
@@ -0,0 +1,59 @@
+# Copyright 2014 IBM Corp.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import mock
+import testtools
+
+from tempest import cli
+from tempest import exceptions
+from tempest.tests import base
+
+
+class TestMinClientVersion(base.TestCase):
+    """Tests for the min_client_version decorator.
+    """
+
+    def _test_min_version(self, required, installed, expect_skip):
+
+        @cli.min_client_version(client='nova', version=required)
+        def fake(self, expect_skip):
+            if expect_skip:
+                # If we got here, the decorator didn't raise a skipException as
+                # expected so we need to fail.
+                self.fail('Should not have gotten past the decorator.')
+
+        with mock.patch.object(cli, 'execute',
+                               return_value=installed) as mock_cmd:
+            if expect_skip:
+                self.assertRaises(testtools.TestCase.skipException, fake,
+                                  self, expect_skip)
+            else:
+                fake(self, expect_skip)
+            mock_cmd.assert_called_once_with('nova', '', params='--version',
+                                             merge_stderr=True)
+
+    def test_min_client_version(self):
+        # required, installed, expect_skip
+        cases = (('2.17.0', '2.17.0', False),
+                 ('2.17.0', '2.18.0', False),
+                 ('2.18.0', '2.17.0', True))
+
+        for case in cases:
+            self._test_min_version(*case)
+
+    @mock.patch.object(cli, 'execute', return_value=' ')
+    def test_check_client_version_empty_output(self, mock_execute):
+        # Tests that an exception is raised if the command output is empty.
+        self.assertRaises(exceptions.TempestException,
+                          cli.check_client_version, 'nova', '2.18.0')
diff --git a/tempest/tests/common/test_accounts.py b/tempest/tests/common/test_accounts.py
new file mode 100644
index 0000000..c24bfb6
--- /dev/null
+++ b/tempest/tests/common/test_accounts.py
@@ -0,0 +1,187 @@
+# Copyright 2014 Hewlett-Packard Development Company, L.P.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import hashlib
+import os
+import tempfile
+
+import mock
+from oslo.config import cfg
+from oslotest import mockpatch
+
+from tempest import auth
+from tempest.common import accounts
+from tempest.common import http
+from tempest import config
+from tempest import exceptions
+from tempest.tests import base
+from tempest.tests import fake_config
+from tempest.tests import fake_identity
+
+
+class TestAccount(base.TestCase):
+
+    def setUp(self):
+        super(TestAccount, self).setUp()
+        self.useFixture(fake_config.ConfigFixture())
+        self.stubs.Set(config, 'TempestConfigPrivate', fake_config.FakePrivate)
+        self.temp_dir = tempfile.mkdtemp()
+        cfg.CONF.set_default('lock_path', self.temp_dir)
+        self.addCleanup(os.rmdir, self.temp_dir)
+        self.test_accounts = [
+            {'username': 'test_user1', 'tenant_name': 'test_tenant1',
+             'password': 'p'},
+            {'username': 'test_user2', 'tenant_name': 'test_tenant2',
+             'password': 'p'},
+            {'username': 'test_user3', 'tenant_name': 'test_tenant3',
+             'password': 'p'},
+            {'username': 'test_user4', 'tenant_name': 'test_tenant4',
+             'password': 'p'},
+            {'username': 'test_user5', 'tenant_name': 'test_tenant5',
+             'password': 'p'},
+            {'username': 'test_user6', 'tenant_name': 'test_tenant6',
+             'password': 'p'},
+        ]
+        self.useFixture(mockpatch.Patch(
+            'tempest.common.accounts.read_accounts_yaml',
+            return_value=self.test_accounts))
+        cfg.CONF.set_default('test_accounts_file', '', group='auth')
+
+    def _get_hash_list(self, accounts_list):
+        hash_list = []
+        for account in accounts_list:
+            hash = hashlib.md5()
+            hash.update(str(account))
+            hash_list.append(hash.hexdigest())
+        return hash_list
+
+    def test_get_hash(self):
+        self.stubs.Set(http.ClosingHttp, 'request',
+                       fake_identity._fake_v2_response)
+        test_account_class = accounts.Accounts('test_name')
+        hash_list = self._get_hash_list(self.test_accounts)
+        test_cred_dict = self.test_accounts[3]
+        test_creds = auth.get_credentials(**test_cred_dict)
+        results = test_account_class.get_hash(test_creds)
+        self.assertEqual(hash_list[3], results)
+
+    def test_get_hash_dict(self):
+        test_account_class = accounts.Accounts('test_name')
+        hash_dict = test_account_class.get_hash_dict(self.test_accounts)
+        hash_list = self._get_hash_list(self.test_accounts)
+        for hash in hash_list:
+            self.assertIn(hash, hash_dict.keys())
+            self.assertIn(hash_dict[hash], self.test_accounts)
+
+    def test_create_hash_file_previous_file(self):
+        # Emulate the lock existing on the filesystem
+        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+        with mock.patch('__builtin__.open', mock.mock_open(), create=True):
+            test_account_class = accounts.Accounts('test_name')
+            res = test_account_class._create_hash_file('12345')
+        self.assertFalse(res, "_create_hash_file should return False if the "
+                         "pseudo-lock file already exists")
+
+    def test_create_hash_file_no_previous_file(self):
+        # Emulate the lock not existing on the filesystem
+        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=False))
+        with mock.patch('__builtin__.open', mock.mock_open(), create=True):
+            test_account_class = accounts.Accounts('test_name')
+            res = test_account_class._create_hash_file('12345')
+        self.assertTrue(res, "_create_hash_file should return True if the "
+                        "pseudo-lock doesn't already exist")
+
+    @mock.patch('tempest.openstack.common.lockutils.lock')
+    def test_get_free_hash_no_previous_accounts(self, lock_mock):
+        # Emulate no pre-existing lock
+        self.useFixture(mockpatch.Patch('os.path.isdir', return_value=False))
+        hash_list = self._get_hash_list(self.test_accounts)
+        mkdir_mock = self.useFixture(mockpatch.Patch('os.mkdir'))
+        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=False))
+        test_account_class = accounts.Accounts('test_name')
+        with mock.patch('__builtin__.open', mock.mock_open(),
+                        create=True) as open_mock:
+            test_account_class._get_free_hash(hash_list)
+            lock_path = os.path.join(accounts.CONF.lock_path, 'test_accounts',
+                                     hash_list[0])
+            open_mock.assert_called_once_with(lock_path, 'w')
+        mkdir_path = os.path.join(accounts.CONF.lock_path, 'test_accounts')
+        mkdir_mock.mock.assert_called_once_with(mkdir_path)
+
+    @mock.patch('tempest.openstack.common.lockutils.lock')
+    def test_get_free_hash_no_free_accounts(self, lock_mock):
+        hash_list = self._get_hash_list(self.test_accounts)
+        # Emulate pre-existing lock dir
+        self.useFixture(mockpatch.Patch('os.path.isdir', return_value=True))
+        # Emulate all lcoks in list are in use
+        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+        test_account_class = accounts.Accounts('test_name')
+        self.assertRaises(exceptions.InvalidConfiguration,
+                          test_account_class._get_free_hash, hash_list)
+
+    @mock.patch('tempest.openstack.common.lockutils.lock')
+    def test_get_free_hash_some_in_use_accounts(self, lock_mock):
+        # Emulate no pre-existing lock
+        self.useFixture(mockpatch.Patch('os.path.isdir', return_value=True))
+        hash_list = self._get_hash_list(self.test_accounts)
+        test_account_class = accounts.Accounts('test_name')
+
+        def _fake_is_file(path):
+            # Fake isfile() to return that the path exists unless a specific
+            # hash is in the path
+            if hash_list[3] in path:
+                return False
+            return True
+
+        self.stubs.Set(os.path, 'isfile', _fake_is_file)
+        with mock.patch('__builtin__.open', mock.mock_open(),
+                        create=True) as open_mock:
+            test_account_class._get_free_hash(hash_list)
+            lock_path = os.path.join(accounts.CONF.lock_path, 'test_accounts',
+                                     hash_list[3])
+            open_mock.assert_called_once_with(lock_path, 'w')
+
+    @mock.patch('tempest.openstack.common.lockutils.lock')
+    def test_remove_hash_last_account(self, lock_mock):
+        hash_list = self._get_hash_list(self.test_accounts)
+        # Pretend the pseudo-lock is there
+        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+        # Pretend the lock dir is empty
+        self.useFixture(mockpatch.Patch('os.listdir', return_value=[]))
+        test_account_class = accounts.Accounts('test_name')
+        remove_mock = self.useFixture(mockpatch.Patch('os.remove'))
+        rmdir_mock = self.useFixture(mockpatch.Patch('os.rmdir'))
+        test_account_class.remove_hash(hash_list[2])
+        hash_path = os.path.join(accounts.CONF.lock_path, 'test_accounts',
+                                 hash_list[2])
+        lock_path = os.path.join(accounts.CONF.lock_path, 'test_accounts')
+        remove_mock.mock.assert_called_once_with(hash_path)
+        rmdir_mock.mock.assert_called_once_with(lock_path)
+
+    @mock.patch('tempest.openstack.common.lockutils.lock')
+    def test_remove_hash_not_last_account(self, lock_mock):
+        hash_list = self._get_hash_list(self.test_accounts)
+        # Pretend the pseudo-lock is there
+        self.useFixture(mockpatch.Patch('os.path.isfile', return_value=True))
+        # Pretend the lock dir is empty
+        self.useFixture(mockpatch.Patch('os.listdir', return_value=[
+            hash_list[1], hash_list[4]]))
+        test_account_class = accounts.Accounts('test_name')
+        remove_mock = self.useFixture(mockpatch.Patch('os.remove'))
+        rmdir_mock = self.useFixture(mockpatch.Patch('os.rmdir'))
+        test_account_class.remove_hash(hash_list[2])
+        hash_path = os.path.join(accounts.CONF.lock_path, 'test_accounts',
+                                 hash_list[2])
+        remove_mock.mock.assert_called_once_with(hash_path)
+        rmdir_mock.mock.assert_not_called()
diff --git a/tempest/tests/fake_config.py b/tempest/tests/fake_config.py
index 536cbcf..9e56916 100644
--- a/tempest/tests/fake_config.py
+++ b/tempest/tests/fake_config.py
@@ -61,3 +61,4 @@
     def __init__(self, parse_conf=True, config_path=None):
         cfg.CONF([], default_config_files=[])
         self._set_attrs()
+        self.lock_path = cfg.CONF.lock_path
diff --git a/tox.ini b/tox.ini
index 4f2465a..9c32121 100644
--- a/tox.ini
+++ b/tox.ini
@@ -6,23 +6,28 @@
 [testenv]
 setenv = VIRTUAL_ENV={envdir}
          OS_TEST_PATH=./tempest/test_discover
+         PYTHONHASHSEED=0
 usedevelop = True
 install_command = pip install -U {opts} {packages}
 
 [testenv:py26]
 setenv = OS_TEST_PATH=./tempest/tests
+         PYTHONHASHSEED=0
 commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
 
 [testenv:py33]
 setenv = OS_TEST_PATH=./tempest/tests
+         PYTHONHASHSEED=0
 commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
 
 [testenv:py27]
 setenv = OS_TEST_PATH=./tempest/tests
+         PYTHONHASHSEED=0
 commands = python setup.py test --slowest --testr-arg='tempest\.tests {posargs}'
 
 [testenv:cover]
 setenv = OS_TEST_PATH=./tempest/tests
+         PYTHONHASHSEED=0
 commands = python setup.py testr --coverage --testr-arg='tempest\.tests {posargs}'
 
 [testenv:all]