Merge "Add unit tests for all generators"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index a184c76..70c791b 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -752,7 +752,7 @@
 
 # Timeout in seconds to wait for a stack to build. (integer
 # value)
-#build_timeout=600
+#build_timeout=1200
 
 # Instance type for tests. Needs to be big enough for a full
 # OS plus the test workload (string value)
diff --git a/requirements.txt b/requirements.txt
index a9e7aeb..e97eece 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,4 @@
-pbr>=0.6,<1.0
+pbr>=0.6,!=0.7,<1.0
 anyjson>=0.3.3
 httplib2>=0.7.5
 jsonschema>=2.0.0,<3.0.0
@@ -17,7 +17,7 @@
 python-saharaclient>=0.6.0
 python-swiftclient>=1.6
 testresources>=0.2.4
-keyring>=1.6.1,<2.0,>=2.1
+keyring>=2.1
 testrepository>=0.0.18
 oslo.config>=1.2.0
 six>=1.5.2
diff --git a/tempest/api/baremetal/test_nodestates.py b/tempest/api/baremetal/test_nodestates.py
new file mode 100644
index 0000000..c658d7f
--- /dev/null
+++ b/tempest/api/baremetal/test_nodestates.py
@@ -0,0 +1,33 @@
+# Copyright 2014 NEC Corporation.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.baremetal import base
+from tempest import test
+
+
+class TestNodeStates(base.BaseBaremetalTest):
+    """Tests for baremetal NodeStates."""
+
+    @classmethod
+    def setUpClass(self):
+        super(TestNodeStates, self).setUpClass()
+        chassis = self.create_chassis()['chassis']
+        self.node = self.create_node(chassis['uuid'])['node']
+
+    @test.attr(type='smoke')
+    def test_list_nodestates(self):
+        resp, nodestates = self.client.list_nodestates(self.node['uuid'])
+        self.assertEqual('200', resp['status'])
+        for key in nodestates:
+            self.assertEqual(nodestates[key], self.node[key])
diff --git a/tempest/api/compute/admin/test_agents.py b/tempest/api/compute/admin/test_agents.py
new file mode 100644
index 0000000..4808601
--- /dev/null
+++ b/tempest/api/compute/admin/test_agents.py
@@ -0,0 +1,123 @@
+# Copyright 2014 NEC Corporation.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.openstack.common import log
+from tempest import test
+
+LOG = log.getLogger(__name__)
+
+
+class AgentsAdminTestJSON(base.BaseV2ComputeAdminTest):
+    """
+    Tests Agents API
+    """
+
+    @classmethod
+    def setUpClass(cls):
+        super(AgentsAdminTestJSON, cls).setUpClass()
+        cls.client = cls.os_adm.agents_client
+
+    def setUp(self):
+        super(AgentsAdminTestJSON, self).setUp()
+        params = self._param_helper(
+            hypervisor='common', os='linux', architecture='x86_64',
+            version='7.0', url='xxx://xxxx/xxx/xxx',
+            md5hash='add6bb58e139be103324d04d82d8f545')
+        resp, body = self.client.create_agent(**params)
+        self.assertEqual(200, resp.status)
+        self.agent_id = body['agent_id']
+
+    def tearDown(self):
+        try:
+            self.client.delete_agent(self.agent_id)
+        except exceptions.NotFound:
+            pass
+        except Exception:
+            LOG.exception('Exception raised deleting agent %s', self.agent_id)
+        super(AgentsAdminTestJSON, self).tearDown()
+
+    def _param_helper(self, **kwargs):
+        rand_key = 'architecture'
+        if rand_key in kwargs:
+            # NOTE: The rand_name is for avoiding agent conflicts.
+            # If you try to create an agent with the same hypervisor,
+            # os and architecture as an exising agent, Nova will return
+            # an HTTPConflict or HTTPServerError.
+            kwargs[rand_key] = data_utils.rand_name(kwargs[rand_key])
+        return kwargs
+
+    @test.attr(type='gate')
+    def test_create_agent(self):
+        # Create an agent.
+        params = self._param_helper(
+            hypervisor='kvm', os='win', architecture='x86',
+            version='7.0', url='xxx://xxxx/xxx/xxx',
+            md5hash='add6bb58e139be103324d04d82d8f545')
+        resp, body = self.client.create_agent(**params)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_agent, body['agent_id'])
+        for expected_item, value in params.items():
+            self.assertEqual(value, body[expected_item])
+
+    @test.attr(type='gate')
+    def test_update_agent(self):
+        # Update an agent.
+        params = self._param_helper(
+            version='8.0', url='xxx://xxxx/xxx/xxx2',
+            md5hash='add6bb58e139be103324d04d82d8f547')
+        resp, body = self.client.update_agent(self.agent_id, **params)
+        self.assertEqual(200, resp.status)
+        for expected_item, value in params.items():
+            self.assertEqual(value, body[expected_item])
+
+    @test.attr(type='gate')
+    def test_delete_agent(self):
+        # Delete an agent.
+        resp, _ = self.client.delete_agent(self.agent_id)
+        self.assertEqual(200, resp.status)
+
+        # Verify the list doesn't contain the deleted agent.
+        resp, agents = self.client.list_agents()
+        self.assertEqual(200, resp.status)
+        self.assertNotIn(self.agent_id, map(lambda x: x['agent_id'], agents))
+
+    @test.attr(type='gate')
+    def test_list_agents(self):
+        # List all agents.
+        resp, agents = self.client.list_agents()
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(agents) > 0, 'Cannot get any agents.(%s)' % agents)
+        self.assertIn(self.agent_id, map(lambda x: x['agent_id'], agents))
+
+    @test.attr(type='gate')
+    def test_list_agents_with_filter(self):
+        # List the agent builds by the filter.
+        params = self._param_helper(
+            hypervisor='xen', os='linux', architecture='x86',
+            version='7.0', url='xxx://xxxx/xxx/xxx1',
+            md5hash='add6bb58e139be103324d04d82d8f546')
+        resp, agent_xen = self.client.create_agent(**params)
+        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_agent, agent_xen['agent_id'])
+
+        agent_id_xen = agent_xen['agent_id']
+        params_filter = {'hypervisor': agent_xen['hypervisor']}
+        resp, agents = self.client.list_agents(params_filter)
+        self.assertEqual(200, resp.status)
+        self.assertTrue(len(agents) > 0, 'Cannot get any agents.(%s)' % agents)
+        self.assertIn(agent_id_xen, map(lambda x: x['agent_id'], agents))
+        self.assertNotIn(self.agent_id, map(lambda x: x['agent_id'], agents))
diff --git a/tempest/api/compute/admin/test_aggregates.py b/tempest/api/compute/admin/test_aggregates.py
index fb249e5..c2376c9 100644
--- a/tempest/api/compute/admin/test_aggregates.py
+++ b/tempest/api/compute/admin/test_aggregates.py
@@ -16,6 +16,7 @@
 from tempest.api.compute import base
 from tempest.common import tempest_fixtures as fixtures
 from tempest.common.utils import data_utils
+from tempest import exceptions
 from tempest import test
 
 
@@ -39,11 +40,20 @@
                     filter(lambda y: y['service'] == 'compute', hosts_all))
         cls.host = hosts[0]
 
+    def _try_delete_aggregate(self, aggregate_id):
+        # delete aggregate, if it exists
+        try:
+            self.client.delete_aggregate(aggregate_id)
+        # if aggregate not found, it depict it was deleted in the test
+        except exceptions.NotFound:
+            pass
+
     @test.attr(type='gate')
     def test_aggregate_create_delete(self):
         # Create and delete an aggregate.
         aggregate_name = data_utils.rand_name(self.aggregate_name_prefix)
         resp, aggregate = self.client.create_aggregate(name=aggregate_name)
+        self.addCleanup(self._try_delete_aggregate, aggregate['id'])
         self.assertEqual(200, resp.status)
         self.assertEqual(aggregate_name, aggregate['name'])
         self.assertIsNone(aggregate['availability_zone'])
@@ -59,6 +69,7 @@
         az_name = data_utils.rand_name(self.az_name_prefix)
         resp, aggregate = self.client.create_aggregate(
             name=aggregate_name, availability_zone=az_name)
+        self.addCleanup(self._try_delete_aggregate, aggregate['id'])
         self.assertEqual(200, resp.status)
         self.assertEqual(aggregate_name, aggregate['name'])
         self.assertEqual(az_name, aggregate['availability_zone'])
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index 09c7274..32e0478 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -76,21 +76,38 @@
     # TODO(afazekas): merge these test cases
     @test.attr(type='gate')
     def test_get_updated_quotas(self):
-        # Verify that GET shows the updated quota set
+        # Verify that GET shows the updated quota set of tenant
         tenant_name = data_utils.rand_name('cpu_quota_tenant_')
         tenant_desc = tenant_name + '-desc'
         identity_client = self.os_adm.identity_client
         _, tenant = identity_client.create_tenant(name=tenant_name,
                                                   description=tenant_desc)
         tenant_id = tenant['id']
-        self.addCleanup(identity_client.delete_tenant,
-                        tenant_id)
+        self.addCleanup(identity_client.delete_tenant, tenant_id)
 
-        self.adm_client.update_quota_set(tenant_id,
-                                         ram='5120')
+        self.adm_client.update_quota_set(tenant_id, ram='5120')
         resp, quota_set = self.adm_client.get_quota_set(tenant_id)
         self.assertEqual(200, resp.status)
-        self.assertEqual(quota_set['ram'], 5120)
+        self.assertEqual(5120, quota_set['ram'])
+
+        # Verify that GET shows the updated quota set of user
+        user_name = data_utils.rand_name('cpu_quota_user_')
+        password = data_utils.rand_name('password-')
+        email = user_name + '@testmail.tm'
+        _, user = identity_client.create_user(name=user_name,
+                                              password=password,
+                                              tenant_id=tenant_id,
+                                              email=email)
+        user_id = user['id']
+        self.addCleanup(identity_client.delete_user, user_id)
+
+        self.adm_client.update_quota_set(tenant_id,
+                                         user_id=user_id,
+                                         ram='2048')
+        resp, quota_set = self.adm_client.get_quota_set(tenant_id,
+                                                        user_id=user_id)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(2048, quota_set['ram'])
 
     @test.attr(type='gate')
     def test_delete_quota(self):
diff --git a/tempest/api/compute/admin/test_servers.py b/tempest/api/compute/admin/test_servers.py
index 1f2ddf4..49af645 100644
--- a/tempest/api/compute/admin/test_servers.py
+++ b/tempest/api/compute/admin/test_servers.py
@@ -14,7 +14,6 @@
 
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
-from tempest import exceptions
 from tempest import test
 
 
@@ -44,16 +43,6 @@
                                               wait_until='ACTIVE')
         cls.s2_id = server['id']
 
-    def _get_unused_flavor_id(self):
-        flavor_id = data_utils.rand_int_id(start=1000)
-        while True:
-            try:
-                resp, body = self.flavors_client.get_flavor_details(flavor_id)
-            except exceptions.NotFound:
-                break
-            flavor_id = data_utils.rand_int_id(start=1000)
-        return flavor_id
-
     @test.attr(type='gate')
     def test_list_servers_by_admin(self):
         # Listing servers by admin user returns empty list by default
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 7631ea5..d1bda83 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -227,6 +227,7 @@
         cls.interfaces_client = cls.os.interfaces_client
         cls.fixed_ips_client = cls.os.fixed_ips_client
         cls.availability_zone_client = cls.os.availability_zone_client
+        cls.agents_client = cls.os.agents_client
         cls.aggregates_client = cls.os.aggregates_client
         cls.services_client = cls.os.services_client
         cls.instance_usages_audit_log_client = \
diff --git a/tempest/api/compute/floating_ips/test_floating_ips_actions.py b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
index abd8a4c..b3789f8 100644
--- a/tempest/api/compute/floating_ips/test_floating_ips_actions.py
+++ b/tempest/api/compute/floating_ips/test_floating_ips_actions.py
@@ -45,6 +45,14 @@
             resp, body = cls.client.delete_floating_ip(cls.floating_ip_id)
         super(FloatingIPsTestJSON, cls).tearDownClass()
 
+    def _try_delete_floating_ip(self, floating_ip_id):
+        # delete floating ip, if it exists
+        try:
+            self.client.delete_floating_ip(floating_ip_id)
+        # if not found, it depicts it was deleted in the test
+        except exceptions.NotFound:
+            pass
+
     @test.attr(type='gate')
     def test_allocate_floating_ip(self):
         # Positive test:Allocation of a new floating IP to a project
@@ -66,6 +74,7 @@
         # should be successful
         # Creating the floating IP that is to be deleted in this method
         resp, floating_ip_body = self.client.create_floating_ip()
+        self.addCleanup(self._try_delete_floating_ip, floating_ip_body['id'])
         # Storing the details of floating IP before deleting it
         cli_resp = self.client.get_floating_ip_details(floating_ip_body['id'])
         resp, floating_ip_details = cli_resp
diff --git a/tempest/api/compute/servers/test_list_server_filters.py b/tempest/api/compute/servers/test_list_server_filters.py
index f0913f1..f66020c 100644
--- a/tempest/api/compute/servers/test_list_server_filters.py
+++ b/tempest/api/compute/servers/test_list_server_filters.py
@@ -28,6 +28,7 @@
     @classmethod
     @test.safe_setup
     def setUpClass(cls):
+        cls.set_network_resources(network=True, subnet=True, dhcp=True)
         super(ListServerFiltersTestJSON, cls).setUpClass()
         cls.client = cls.servers_client
 
@@ -69,8 +70,12 @@
         resp, cls.s3 = cls.create_test_server(name=cls.s3_name,
                                               flavor=cls.flavor_ref_alt,
                                               wait_until='ACTIVE')
-
-        cls.fixed_network_name = CONF.compute.fixed_network_name
+        if (CONF.service_available.neutron and
+                CONF.compute.allow_tenant_isolation):
+            network = cls.isolated_creds.get_primary_network()
+            cls.fixed_network_name = network['name']
+        else:
+            cls.fixed_network_name = CONF.compute.fixed_network_name
 
     @utils.skip_unless_attr('multiple_images', 'Only one image found')
     @test.attr(type='gate')
@@ -226,7 +231,6 @@
         self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
         self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
 
-    @test.skip_because(bug="1170718")
     @test.attr(type='gate')
     def test_list_servers_filtered_by_ip(self):
         # Filter servers by ip
diff --git a/tempest/api/compute/test_authorization.py b/tempest/api/compute/test_authorization.py
index 7f909d7..c87f24e 100644
--- a/tempest/api/compute/test_authorization.py
+++ b/tempest/api/compute/test_authorization.py
@@ -60,7 +60,7 @@
         resp, cls.server = cls.client.get_server(server['id'])
 
         name = data_utils.rand_name('image')
-        resp, body = cls.client.create_image(server['id'], name)
+        resp, body = cls.images_client.create_image(server['id'], name)
         image_id = data_utils.parse_image_id(resp['location'])
         cls.images_client.wait_for_image_status(image_id, 'ACTIVE')
         resp, cls.image = cls.images_client.get_image(image_id)
diff --git a/tempest/api/compute/v3/admin/test_quotas.py b/tempest/api/compute/v3/admin/test_quotas.py
index 917c115..b70e254 100644
--- a/tempest/api/compute/v3/admin/test_quotas.py
+++ b/tempest/api/compute/v3/admin/test_quotas.py
@@ -94,21 +94,38 @@
     # TODO(afazekas): merge these test cases
     @test.attr(type='gate')
     def test_get_updated_quotas(self):
-        # Verify that GET shows the updated quota set
+        # Verify that GET shows the updated quota set of tenant
         tenant_name = data_utils.rand_name('cpu_quota_tenant_')
         tenant_desc = tenant_name + '-desc'
         identity_client = self.os_adm.identity_client
         _, tenant = identity_client.create_tenant(name=tenant_name,
                                                   description=tenant_desc)
         tenant_id = tenant['id']
-        self.addCleanup(identity_client.delete_tenant,
-                        tenant_id)
+        self.addCleanup(identity_client.delete_tenant, tenant_id)
 
-        self.adm_client.update_quota_set(tenant_id,
-                                         ram='5120')
+        self.adm_client.update_quota_set(tenant_id, ram='5120')
         resp, quota_set = self.adm_client.get_quota_set(tenant_id)
         self.assertEqual(200, resp.status)
-        self.assertEqual(quota_set['ram'], 5120)
+        self.assertEqual(5120, quota_set['ram'])
+
+        # Verify that GET shows the updated quota set of user
+        user_name = data_utils.rand_name('cpu_quota_user_')
+        password = data_utils.rand_name('password-')
+        email = user_name + '@testmail.tm'
+        _, user = identity_client.create_user(name=user_name,
+                                              password=password,
+                                              tenant_id=tenant_id,
+                                              email=email)
+        user_id = user['id']
+        self.addCleanup(identity_client.delete_user, user_id)
+
+        self.adm_client.update_quota_set(tenant_id,
+                                         user_id=user_id,
+                                         ram='2048')
+        resp, quota_set = self.adm_client.get_quota_set(tenant_id,
+                                                        user_id=user_id)
+        self.assertEqual(200, resp.status)
+        self.assertEqual(2048, quota_set['ram'])
 
     @test.attr(type='gate')
     def test_delete_quota(self):
diff --git a/tempest/api/compute/v3/admin/test_servers.py b/tempest/api/compute/v3/admin/test_servers.py
index 579a535..366cfc6 100644
--- a/tempest/api/compute/v3/admin/test_servers.py
+++ b/tempest/api/compute/v3/admin/test_servers.py
@@ -14,7 +14,6 @@
 
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
-from tempest import exceptions
 from tempest import test
 
 
@@ -44,16 +43,6 @@
                                               wait_until='ACTIVE')
         cls.s2_id = server['id']
 
-    def _get_unused_flavor_id(self):
-        flavor_id = data_utils.rand_int_id(start=1000)
-        while True:
-            try:
-                resp, body = self.flavors_client.get_flavor_details(flavor_id)
-            except exceptions.NotFound:
-                break
-            flavor_id = data_utils.rand_int_id(start=1000)
-        return flavor_id
-
     @test.attr(type='gate')
     def test_list_servers_by_admin(self):
         # Listing servers by admin user returns empty list by default
diff --git a/tempest/api/compute/v3/servers/test_instance_actions.py b/tempest/api/compute/v3/servers/test_instance_actions.py
index 7d25100..399541b 100644
--- a/tempest/api/compute/v3/servers/test_instance_actions.py
+++ b/tempest/api/compute/v3/servers/test_instance_actions.py
@@ -27,25 +27,27 @@
         cls.resp = resp
         cls.server_id = server['id']
 
+    @test.skip_because(bug="1206032")
     @test.attr(type='gate')
-    def test_list_instance_actions(self):
+    def test_list_server_actions(self):
         # List actions of the provided server
         resp, body = self.client.reboot(self.server_id, 'HARD')
         self.client.wait_for_server_status(self.server_id, 'ACTIVE')
 
-        resp, body = self.client.list_instance_actions(self.server_id)
+        resp, body = self.client.list_server_actions(self.server_id)
         self.assertEqual(200, resp.status)
         self.assertTrue(len(body) == 2, str(body))
         self.assertTrue(any([i for i in body if i['action'] == 'create']))
         self.assertTrue(any([i for i in body if i['action'] == 'reboot']))
 
+    @test.skip_because(bug="1206032")
     @test.attr(type='gate')
     @test.skip_because(bug="1281915")
-    def test_get_instance_action(self):
+    def test_get_server_action(self):
         # Get the action details of the provided server
         request_id = self.resp['x-compute-request-id']
-        resp, body = self.client.get_instance_action(self.server_id,
-                                                     request_id)
+        resp, body = self.client.get_server_action(self.server_id,
+                                                   request_id)
         self.assertEqual(200, resp.status)
-        self.assertEqual(self.server_id, body['instance_uuid'])
+        self.assertEqual(self.server_id, body['server_uuid'])
         self.assertEqual('create', body['action'])
diff --git a/tempest/api/compute/v3/servers/test_instance_actions_negative.py b/tempest/api/compute/v3/servers/test_instance_actions_negative.py
index b0a7050..0b2c6f9 100644
--- a/tempest/api/compute/v3/servers/test_instance_actions_negative.py
+++ b/tempest/api/compute/v3/servers/test_instance_actions_negative.py
@@ -29,15 +29,15 @@
         cls.server_id = server['id']
 
     @test.attr(type=['negative', 'gate'])
-    def test_list_instance_actions_invalid_server(self):
+    def test_list_server_actions_invalid_server(self):
         # List actions of the invalid server id
         invalid_server_id = data_utils.rand_uuid()
         self.assertRaises(exceptions.NotFound,
-                          self.client.list_instance_actions, invalid_server_id)
+                          self.client.list_server_actions, invalid_server_id)
 
     @test.attr(type=['negative', 'gate'])
-    def test_get_instance_action_invalid_request(self):
+    def test_get_server_action_invalid_request(self):
         # Get the action details of the provided server with invalid request
         invalid_request_id = 'req-' + data_utils.rand_uuid()
-        self.assertRaises(exceptions.NotFound, self.client.get_instance_action,
+        self.assertRaises(exceptions.NotFound, self.client.get_server_action,
                           self.server_id, invalid_request_id)
diff --git a/tempest/api/compute/v3/servers/test_list_server_filters.py b/tempest/api/compute/v3/servers/test_list_server_filters.py
index 2cb176c..778b033 100644
--- a/tempest/api/compute/v3/servers/test_list_server_filters.py
+++ b/tempest/api/compute/v3/servers/test_list_server_filters.py
@@ -28,6 +28,7 @@
     @classmethod
     @test.safe_setup
     def setUpClass(cls):
+        cls.set_network_resources(network=True, subnet=True, dhcp=True)
         super(ListServerFiltersV3Test, cls).setUpClass()
         cls.client = cls.servers_client
 
@@ -70,7 +71,12 @@
                                               flavor=cls.flavor_ref_alt,
                                               wait_until='ACTIVE')
 
-        cls.fixed_network_name = CONF.compute.fixed_network_name
+        if (CONF.service_available.neutron and
+                CONF.compute.allow_tenant_isolation):
+            network = cls.isolated_creds.get_primary_network()
+            cls.fixed_network_name = network['name']
+        else:
+            cls.fixed_network_name = CONF.compute.fixed_network_name
 
     @utils.skip_unless_attr('multiple_images', 'Only one image found')
     @test.attr(type='gate')
@@ -226,7 +232,6 @@
         self.assertNotIn(self.s2_name, map(lambda x: x['name'], servers))
         self.assertNotIn(self.s3_name, map(lambda x: x['name'], servers))
 
-    @test.skip_because(bug="1170718")
     @test.attr(type='gate')
     def test_list_servers_filtered_by_ip(self):
         # Filter servers by ip
diff --git a/tempest/api/identity/admin/v3/test_roles.py b/tempest/api/identity/admin/v3/test_roles.py
index 24c7b83..90dccca 100644
--- a/tempest/api/identity/admin/v3/test_roles.py
+++ b/tempest/api/identity/admin/v3/test_roles.py
@@ -73,7 +73,7 @@
         self.assertIn(role_id, fetched_role_ids)
 
     @test.attr(type='smoke')
-    def test_role_create_update_get(self):
+    def test_role_create_update_get_list(self):
         r_name = data_utils.rand_name('Role-')
         resp, role = self.client.create_role(r_name)
         self.addCleanup(self.client.delete_role, role['id'])
@@ -94,6 +94,10 @@
         self.assertEqual(new_name, new_role['name'])
         self.assertEqual(updated_role['id'], new_role['id'])
 
+        resp, roles = self.client.list_roles()
+        self.assertEqual(resp['status'], '200')
+        self.assertIn(role['id'], [r['id'] for r in roles])
+
     @test.attr(type='smoke')
     def test_grant_list_revoke_role_to_user_on_project(self):
         resp, _ = self.client.assign_user_role_on_project(
diff --git a/tempest/api/network/admin/test_agent_management.py b/tempest/api/network/admin/test_agent_management.py
index 342bc6a..b848994 100644
--- a/tempest/api/network/admin/test_agent_management.py
+++ b/tempest/api/network/admin/test_agent_management.py
@@ -37,8 +37,10 @@
         agents = body['agents']
         # Hearthbeats must be excluded from comparison
         self.agent.pop('heartbeat_timestamp', None)
+        self.agent.pop('configurations', None)
         for agent in agents:
             agent.pop('heartbeat_timestamp', None)
+            agent.pop('configurations', None)
         self.assertIn(self.agent, agents)
 
     @test.attr(type=['smoke'])
diff --git a/tempest/api/network/admin/test_dhcp_agent_scheduler.py b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
index 13ae1c0..25e1cc0 100644
--- a/tempest/api/network/admin/test_dhcp_agent_scheduler.py
+++ b/tempest/api/network/admin/test_dhcp_agent_scheduler.py
@@ -20,6 +20,7 @@
     _interface = 'json'
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(DHCPAgentSchedulersTestJSON, cls).setUpClass()
         if not test.is_extension_enabled('dhcp_agent_scheduler', 'network'):
diff --git a/tempest/api/network/admin/test_lbaas_agent_scheduler.py b/tempest/api/network/admin/test_lbaas_agent_scheduler.py
index a5ba90f..675c62d 100644
--- a/tempest/api/network/admin/test_lbaas_agent_scheduler.py
+++ b/tempest/api/network/admin/test_lbaas_agent_scheduler.py
@@ -35,6 +35,7 @@
     """
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(LBaaSAgentSchedulerTestJSON, cls).setUpClass()
         if not test.is_extension_enabled('lbaas_agent_scheduler', 'network'):
diff --git a/tempest/api/network/admin/test_load_balancer_admin_actions.py b/tempest/api/network/admin/test_load_balancer_admin_actions.py
index 34a8e32..6bcc118 100644
--- a/tempest/api/network/admin/test_load_balancer_admin_actions.py
+++ b/tempest/api/network/admin/test_load_balancer_admin_actions.py
@@ -29,6 +29,7 @@
     """
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(LoadBalancerAdminTestJSON, cls).setUpClass()
         if not test.is_extension_enabled('lbaas', 'network'):
@@ -89,6 +90,18 @@
         show_health_monitor = body['health_monitor']
         self.assertEqual(health_monitor['id'], show_health_monitor['id'])
 
+    @test.attr(type='smoke')
+    def test_create_pool_from_admin_user_other_tenant(self):
+        resp, body = self.admin_client.create_pool(
+            name=data_utils.rand_name('pool-'), lb_method="ROUND_ROBIN",
+            protocol="HTTP", subnet_id=self.subnet['id'],
+            tenant_id=self.tenant_id)
+        self.assertEqual('201', resp['status'])
+        pool = body['pool']
+        self.addCleanup(self.admin_client.delete_pool, pool['id'])
+        self.assertIsNotNone(pool['id'])
+        self.assertEqual(self.tenant_id, pool['tenant_id'])
+
 
 class LoadBalancerAdminTestXML(LoadBalancerAdminTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/network/test_extra_dhcp_options.py b/tempest/api/network/test_extra_dhcp_options.py
index ed86d75..371c651 100644
--- a/tempest/api/network/test_extra_dhcp_options.py
+++ b/tempest/api/network/test_extra_dhcp_options.py
@@ -36,6 +36,7 @@
     """
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(ExtraDHCPOptionsTestJSON, cls).setUpClass()
         if not test.is_extension_enabled('extra_dhcp_opt', 'network'):
diff --git a/tempest/api/network/test_floating_ips.py b/tempest/api/network/test_floating_ips.py
index 06871ad..7191940 100644
--- a/tempest/api/network/test_floating_ips.py
+++ b/tempest/api/network/test_floating_ips.py
@@ -44,6 +44,7 @@
     """
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(FloatingIPTestJSON, cls).setUpClass()
         if not test.is_extension_enabled('router', 'network'):
diff --git a/tempest/api/network/test_load_balancer.py b/tempest/api/network/test_load_balancer.py
index 792d61d..3ab015e 100644
--- a/tempest/api/network/test_load_balancer.py
+++ b/tempest/api/network/test_load_balancer.py
@@ -38,6 +38,7 @@
     """
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(LoadBalancerTestJSON, cls).setUpClass()
         if not test.is_extension_enabled('lbaas', 'network'):
@@ -156,10 +157,14 @@
         # Verification of pool update
         new_name = "New_pool"
         resp, body = self.client.update_pool(pool['id'],
-                                             name=new_name)
+                                             name=new_name,
+                                             description="new_description",
+                                             lb_method='LEAST_CONNECTIONS')
         self.assertEqual('200', resp['status'])
         updated_pool = body['pool']
-        self.assertEqual(updated_pool['name'], new_name)
+        self.assertEqual(new_name, updated_pool['name'])
+        self.assertEqual('new_description', updated_pool['description'])
+        self.assertEqual('LEAST_CONNECTIONS', updated_pool['lb_method'])
         # Verification of pool delete
         resp, body = self.client.delete_pool(pool['id'])
         self.assertEqual('204', resp['status'])
@@ -377,6 +382,58 @@
         self.assertIn("active_connections", stats)
         self.assertIn("bytes_out", stats)
 
+    @test.attr(type='smoke')
+    def test_update_list_of_health_monitors_associated_with_pool(self):
+        resp, _ = (self.client.associate_health_monitor_with_pool
+                   (self.health_monitor['id'], self.pool['id']))
+        self.assertEqual('201', resp['status'])
+        resp, _ = self.client.update_health_monitor(
+            self.health_monitor['id'], admin_state_up=False)
+        self.assertEqual('200', resp['status'])
+        resp, body = self.client.show_pool(self.pool['id'])
+        self.assertEqual('200', resp['status'])
+        health_monitors = body['pool']['health_monitors']
+        for health_monitor_id in health_monitors:
+            resp, body = self.client.show_health_monitor(health_monitor_id)
+            self.assertEqual('200', resp['status'])
+            self.assertFalse(body['health_monitor']['admin_state_up'])
+        resp, _ = (self.client.disassociate_health_monitor_with_pool
+                   (self.health_monitor['id'], self.pool['id']))
+        self.assertEqual('204', resp['status'])
+
+    @test.attr(type='smoke')
+    def test_update_admin_state_up_of_pool(self):
+        resp, _ = self.client.update_pool(self.pool['id'],
+                                          admin_state_up=False)
+        self.assertEqual('200', resp['status'])
+        resp, body = self.client.show_pool(self.pool['id'])
+        self.assertEqual('200', resp['status'])
+        pool = body['pool']
+        self.assertFalse(pool['admin_state_up'])
+
+    @test.attr(type='smoke')
+    def test_show_vip_associated_with_pool(self):
+        resp, body = self.client.show_pool(self.pool['id'])
+        self.assertEqual('200', resp['status'])
+        pool = body['pool']
+        resp, body = self.client.show_vip(pool['vip_id'])
+        self.assertEqual('200', resp['status'])
+        vip = body['vip']
+        self.assertEqual(self.vip['name'], vip['name'])
+        self.assertEqual(self.vip['id'], vip['id'])
+
+    @test.attr(type='smoke')
+    def test_show_members_associated_with_pool(self):
+        resp, body = self.client.show_pool(self.pool['id'])
+        self.assertEqual('200', resp['status'])
+        members = body['pool']['members']
+        for member_id in members:
+            resp, body = self.client.show_member(member_id)
+            self.assertEqual('200', resp['status'])
+            self.assertIsNotNone(body['member']['status'])
+            self.assertEqual(member_id, body['member']['id'])
+            self.assertIsNotNone(body['member']['admin_state_up'])
+
 
 class LoadBalancerTestXML(LoadBalancerTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/network/test_networks.py b/tempest/api/network/test_networks.py
index b9041ee..0175de7 100644
--- a/tempest/api/network/test_networks.py
+++ b/tempest/api/network/test_networks.py
@@ -19,7 +19,7 @@
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
-from tempest.test import attr
+from tempest import test
 
 CONF = config.CONF
 
@@ -64,6 +64,7 @@
     """
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(NetworksTestJSON, cls).setUpClass()
         cls.network = cls.create_network()
@@ -71,7 +72,7 @@
         cls.subnet = cls.create_subnet(cls.network)
         cls.cidr = cls.subnet['cidr']
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_create_update_delete_network_subnet(self):
         # Create a network
         name = data_utils.rand_name('network-')
@@ -102,7 +103,7 @@
         resp, body = self.client.delete_network(net_id)
         self.assertEqual('204', resp['status'])
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_show_network(self):
         # Verify the details of a network
         resp, body = self.client.show_network(self.network['id'])
@@ -111,7 +112,7 @@
         for key in ['id', 'name']:
             self.assertEqual(network[key], self.network[key])
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_show_network_fields(self):
         # Verify specific fields of a network
         field_list = [('fields', 'id'), ('fields', 'name'), ]
@@ -123,7 +124,7 @@
         for label, field_name in field_list:
             self.assertEqual(network[field_name], self.network[field_name])
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_list_networks(self):
         # Verify the network exists in the list of all networks
         resp, body = self.client.list_networks()
@@ -132,7 +133,7 @@
                     if network['id'] == self.network['id']]
         self.assertNotEmpty(networks, "Created network not found in the list")
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_list_networks_fields(self):
         # Verify specific fields of the networks
         resp, body = self.client.list_networks(fields='id')
@@ -143,7 +144,7 @@
             self.assertEqual(len(network), 1)
             self.assertIn('id', network)
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_show_subnet(self):
         # Verify the details of a subnet
         resp, body = self.client.show_subnet(self.subnet['id'])
@@ -154,7 +155,7 @@
             self.assertIn(key, subnet)
             self.assertEqual(subnet[key], self.subnet[key])
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_show_subnet_fields(self):
         # Verify specific fields of a subnet
         field_list = [('fields', 'id'), ('fields', 'cidr'), ]
@@ -166,7 +167,7 @@
         for label, field_name in field_list:
             self.assertEqual(subnet[field_name], self.subnet[field_name])
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_list_subnets(self):
         # Verify the subnet exists in the list of all subnets
         resp, body = self.client.list_subnets()
@@ -175,7 +176,7 @@
                    if subnet['id'] == self.subnet['id']]
         self.assertNotEmpty(subnets, "Created subnet not found in the list")
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_list_subnets_fields(self):
         # Verify specific fields of subnets
         resp, body = self.client.list_subnets(fields='id')
@@ -194,7 +195,7 @@
         except exceptions.NotFound:
             pass
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_delete_network_with_subnet(self):
         # Creates a network
         name = data_utils.rand_name('network-')
@@ -221,7 +222,7 @@
         # it from the list.
         self.subnets.pop()
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_create_port_with_no_ip(self):
         # For this test create a new network - do not use any previously
         # created networks.
@@ -275,6 +276,7 @@
     """
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(BulkNetworkOpsTestJSON, cls).setUpClass()
         cls.network1 = cls.create_network()
@@ -310,7 +312,7 @@
         for n in created_ports:
             self.assertNotIn(n['id'], ports_list)
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_bulk_create_delete_network(self):
         # Creates 2 networks in one request
         network_names = [data_utils.rand_name('network-'),
@@ -326,7 +328,7 @@
             self.assertIsNotNone(n['id'])
             self.assertIn(n['id'], networks_list)
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_bulk_create_delete_subnet(self):
         # Creates 2 subnets in one request
         cidr = netaddr.IPNetwork(CONF.network.tenant_network_cidr)
@@ -358,7 +360,7 @@
             self.assertIsNotNone(n['id'])
             self.assertIn(n['id'], subnets_list)
 
-    @attr(type='smoke')
+    @test.attr(type='smoke')
     def test_bulk_create_delete_port(self):
         # Creates 2 ports in one request
         networks = [self.network1['id'], self.network2['id']]
diff --git a/tempest/api/network/test_ports.py b/tempest/api/network/test_ports.py
index fbb25a8..bda5b2b 100644
--- a/tempest/api/network/test_ports.py
+++ b/tempest/api/network/test_ports.py
@@ -27,6 +27,7 @@
     _interface = 'json'
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(PortsTestJSON, cls).setUpClass()
         cls.network = cls.create_network()
@@ -143,6 +144,7 @@
     _interface = 'json'
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(PortsAdminExtendedAttrsTestJSON, cls).setUpClass()
         cls.identity_client = cls._get_identity_admin_client()
@@ -180,15 +182,31 @@
 
     @test.attr(type='smoke')
     def test_list_ports_binding_ext_attr(self):
-        resp, body = self.admin_client.list_ports(
-            **{'tenant_id': self.tenant['id']})
+        # Create a new port
+        post_body = {"network_id": self.network['id']}
+        resp, body = self.admin_client.create_port(**post_body)
+        self.assertEqual('201', resp['status'])
+        port = body['port']
+        self.addCleanup(self.admin_client.delete_port, port['id'])
+
+        # Update the port's binding attributes so that is now 'bound'
+        # to a host
+        update_body = {"binding:host_id": self.host_id}
+        resp, _ = self.admin_client.update_port(port['id'], **update_body)
+        self.assertEqual('200', resp['status'])
+
+        # List all ports, ensure new port is part of list and its binding
+        # attributes are set and accurate
+        resp, body = self.admin_client.list_ports()
         self.assertEqual('200', resp['status'])
         ports_list = body['ports']
-        for port in ports_list:
-            vif_type = port['binding:vif_type']
-            self.assertIsNotNone(vif_type)
-            vif_details = port['binding:vif_details']['port_filter']
-            self.assertIsNotNone(vif_details)
+        pids_list = [p['id'] for p in ports_list]
+        self.assertIn(port['id'], pids_list)
+        listed_port = [p for p in ports_list if p['id'] == port['id']]
+        self.assertEqual(1, len(listed_port),
+                         'Multiple ports listed with id %s in ports listing: '
+                         '%s' % (port['id'], ports_list))
+        self.assertEqual(self.host_id, listed_port[0]['binding:host_id'])
 
     @test.attr(type='smoke')
     def test_show_port_binding_ext_attr(self):
diff --git a/tempest/api/network/test_routers_negative.py b/tempest/api/network/test_routers_negative.py
index e6ad4de..91ab9d6 100644
--- a/tempest/api/network/test_routers_negative.py
+++ b/tempest/api/network/test_routers_negative.py
@@ -23,6 +23,7 @@
     _interface = 'json'
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         super(RoutersNegativeTest, cls).setUpClass()
         if not test.is_extension_enabled('router', 'network'):
diff --git a/tempest/api/network/test_vpnaas_extensions.py b/tempest/api/network/test_vpnaas_extensions.py
index 78bc80a..7edaaf8 100644
--- a/tempest/api/network/test_vpnaas_extensions.py
+++ b/tempest/api/network/test_vpnaas_extensions.py
@@ -21,7 +21,7 @@
 CONF = config.CONF
 
 
-class VPNaaSJSON(base.BaseNetworkTest):
+class VPNaaSTestJSON(base.BaseNetworkTest):
     _interface = 'json'
 
     """
@@ -37,11 +37,12 @@
     """
 
     @classmethod
+    @test.safe_setup
     def setUpClass(cls):
         if not test.is_extension_enabled('vpnaas', 'network'):
             msg = "vpnaas extension not enabled."
             raise cls.skipException(msg)
-        super(VPNaaSJSON, cls).setUpClass()
+        super(VPNaaSTestJSON, cls).setUpClass()
         cls.network = cls.create_network()
         cls.subnet = cls.create_subnet(cls.network)
         cls.router = cls.create_router(
@@ -175,3 +176,7 @@
                          ikepolicy['phase1_negotiation_mode'])
         self.assertEqual(self.ikepolicy['ike_version'],
                          ikepolicy['ike_version'])
+
+
+class VPNaaSTestXML(VPNaaSTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/object_storage/test_account_quotas.py b/tempest/api/object_storage/test_account_quotas.py
index a3098a5..d919245 100644
--- a/tempest/api/object_storage/test_account_quotas.py
+++ b/tempest/api/object_storage/test_account_quotas.py
@@ -82,7 +82,8 @@
         # Set a quota of 20 bytes on the user's account before each test
         headers = {"X-Account-Meta-Quota-Bytes": "20"}
 
-        self.os.custom_account_client.request("POST", "", headers, "")
+        self.os.custom_account_client.request("POST", url="", headers=headers,
+                                              body="")
 
     def tearDown(self):
         # Set the reselleradmin auth in headers for next custom_account_client
@@ -94,7 +95,8 @@
         # remove the quota from the container
         headers = {"X-Remove-Account-Meta-Quota-Bytes": "x"}
 
-        self.os.custom_account_client.request("POST", "", headers, "")
+        self.os.custom_account_client.request("POST", url="", headers=headers,
+                                              body="")
         super(AccountQuotasTest, self).tearDown()
 
     @classmethod
@@ -135,8 +137,9 @@
             )
             headers = {"X-Account-Meta-Quota-Bytes": quota}
 
-            resp, _ = self.os.custom_account_client.request("POST", "",
-                                                            headers, "")
+            resp, _ = self.os.custom_account_client.request("POST", url="",
+                                                            headers=headers,
+                                                            body="")
 
             self.assertEqual(resp["status"], "204")
             self.assertHeaders(resp, 'Account', 'POST')
diff --git a/tempest/api/object_storage/test_account_quotas_negative.py b/tempest/api/object_storage/test_account_quotas_negative.py
index 7648ea1..29afebc 100644
--- a/tempest/api/object_storage/test_account_quotas_negative.py
+++ b/tempest/api/object_storage/test_account_quotas_negative.py
@@ -81,7 +81,8 @@
         # Set a quota of 20 bytes on the user's account before each test
         headers = {"X-Account-Meta-Quota-Bytes": "20"}
 
-        self.os.custom_account_client.request("POST", "", headers, "")
+        self.os.custom_account_client.request("POST", url="", headers=headers,
+                                              body="")
 
     def tearDown(self):
         # Set the reselleradmin auth in headers for next custom_account_client
@@ -93,7 +94,8 @@
         # remove the quota from the container
         headers = {"X-Remove-Account-Meta-Quota-Bytes": "x"}
 
-        self.os.custom_account_client.request("POST", "", headers, "")
+        self.os.custom_account_client.request("POST", url="", headers=headers,
+                                              body="")
         super(AccountQuotasNegativeTest, self).tearDown()
 
     @classmethod
diff --git a/tempest/api/object_storage/test_object_formpost.py b/tempest/api/object_storage/test_object_formpost.py
index e0d15ac..81db252 100644
--- a/tempest/api/object_storage/test_object_formpost.py
+++ b/tempest/api/object_storage/test_object_formpost.py
@@ -39,6 +39,18 @@
         cls.metadata = {'Temp-URL-Key': cls.key}
         cls.account_client.create_account_metadata(metadata=cls.metadata)
 
+    def setUp(self):
+        super(ObjectFormPostTest, self).setUp()
+
+        # make sure the metadata has been set
+        account_client_metadata, _ = \
+            self.account_client.list_account_metadata()
+        self.assertIn('x-account-meta-temp-url-key',
+                      account_client_metadata)
+        self.assertEqual(
+            account_client_metadata['x-account-meta-temp-url-key'],
+            self.key)
+
     @classmethod
     def tearDownClass(cls):
         cls.account_client.delete_account_metadata(metadata=cls.metadata)
@@ -100,13 +112,9 @@
         headers = {'Content-Type': content_type,
                    'Content-Length': str(len(body))}
 
-        url = "%s/%s/%s" % (self.container_client.base_url,
-                            self.container_name,
-                            self.object_name)
+        url = "%s/%s" % (self.container_name, self.object_name)
 
-        # Use a raw request, otherwise authentication headers are used
-        resp, body = self.object_client.http_obj.request(url, "POST",
-                                                         body, headers=headers)
+        resp, body = self.object_client.post(url, body, headers=headers)
         self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, "Object", "POST")
 
diff --git a/tempest/api/object_storage/test_object_formpost_negative.py b/tempest/api/object_storage/test_object_formpost_negative.py
index a52c248..fe0c994 100644
--- a/tempest/api/object_storage/test_object_formpost_negative.py
+++ b/tempest/api/object_storage/test_object_formpost_negative.py
@@ -20,6 +20,7 @@
 
 from tempest.api.object_storage import base
 from tempest.common.utils import data_utils
+from tempest import exceptions
 from tempest import test
 
 
@@ -38,6 +39,18 @@
         cls.metadata = {'Temp-URL-Key': cls.key}
         cls.account_client.create_account_metadata(metadata=cls.metadata)
 
+    def setUp(self):
+        super(ObjectFormPostNegativeTest, self).setUp()
+
+        # make sure the metadata has been set
+        account_client_metadata, _ = \
+            self.account_client.list_account_metadata()
+        self.assertIn('x-account-meta-temp-url-key',
+                      account_client_metadata)
+        self.assertEqual(
+            account_client_metadata['x-account-meta-temp-url-key'],
+            self.key)
+
     @classmethod
     def tearDownClass(cls):
         cls.account_client.delete_account_metadata(metadata=cls.metadata)
@@ -100,12 +113,25 @@
         headers = {'Content-Type': content_type,
                    'Content-Length': str(len(body))}
 
-        url = "%s/%s/%s" % (self.container_client.base_url,
-                            self.container_name,
-                            self.object_name)
+        url = "%s/%s" % (self.container_name, self.object_name)
+        exc = self.assertRaises(
+            exceptions.Unauthorized,
+            self.object_client.post,
+            url, body, headers=headers)
+        self.assertIn('FormPost: Form Expired', str(exc))
 
-        # Use a raw request, otherwise authentication headers are used
-        resp, body = self.object_client.http_obj.request(url, "POST",
-                                                         body, headers=headers)
-        self.assertEqual(int(resp['status']), 401)
-        self.assertIn('FormPost: Form Expired', body)
+    @test.requires_ext(extension='formpost', service='object')
+    @test.attr(type='gate')
+    def test_post_object_using_form_invalid_signature(self):
+        self.key = "Wrong"
+        body, content_type = self.get_multipart_form()
+
+        headers = {'Content-Type': content_type,
+                   'Content-Length': str(len(body))}
+
+        url = "%s/%s" % (self.container_name, self.object_name)
+        exc = self.assertRaises(
+            exceptions.Unauthorized,
+            self.object_client.post,
+            url, body, headers=headers)
+        self.assertIn('FormPost: Invalid Signature', str(exc))
diff --git a/tempest/api/object_storage/test_object_services.py b/tempest/api/object_storage/test_object_services.py
index 91df292..b057698 100644
--- a/tempest/api/object_storage/test_object_services.py
+++ b/tempest/api/object_storage/test_object_services.py
@@ -14,6 +14,7 @@
 #    under the License.
 
 import hashlib
+import re
 from six import moves
 
 from tempest.api.object_storage import base
@@ -35,6 +36,29 @@
         cls.delete_containers(cls.containers)
         super(ObjectTest, cls).tearDownClass()
 
+    def _create_object(self, metadata=None):
+        # setup object
+        object_name = data_utils.rand_name(name='TestObject')
+        data = data_utils.arbitrary_string()
+        self.object_client.create_object(self.container_name,
+                                         object_name, data, metadata=metadata)
+
+        return object_name, data
+
+    def _upload_segments(self):
+        # create object
+        object_name = data_utils.rand_name(name='LObject')
+        data = data_utils.arbitrary_string()
+        segments = 10
+        data_segments = [data + str(i) for i in moves.xrange(segments)]
+        # uploading segments
+        for i in moves.xrange(segments):
+            resp, _ = self.object_client.create_object_segments(
+                self.container_name, object_name, i, data_segments[i])
+            self.assertEqual(resp['status'], '201')
+
+        return object_name, data_segments
+
     @test.attr(type='smoke')
     def test_create_object(self):
         # create object
@@ -64,32 +88,220 @@
         self.assertHeaders(resp, 'Object', 'DELETE')
 
     @test.attr(type='smoke')
-    def test_object_metadata(self):
-        # add metadata to storage object, test if metadata is retrievable
+    def test_update_object_metadata(self):
+        # update object metadata
+        object_name, data = self._create_object()
 
-        # create Object
-        object_name = data_utils.rand_name(name='TestObject')
-        data = data_utils.arbitrary_string()
-        resp, _ = self.object_client.create_object(self.container_name,
-                                                   object_name, data)
-        # set object metadata
-        meta_key = data_utils.rand_name(name='test-')
-        meta_value = data_utils.rand_name(name='MetaValue-')
-        orig_metadata = {meta_key: meta_value}
+        metadata = {'X-Object-Meta-test-meta': 'Meta'}
         resp, _ = self.object_client.update_object_metadata(
-            self.container_name, object_name, orig_metadata)
+            self.container_name,
+            object_name,
+            metadata,
+            metadata_prefix='')
         self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'POST')
 
+        resp, _ = self.object_client.list_object_metadata(
+            self.container_name,
+            object_name)
+        self.assertIn('x-object-meta-test-meta', resp)
+        self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
+
+    def test_update_object_metadata_with_remove_metadata(self):
+        # update object metadata with remove metadata
+        object_name = data_utils.rand_name(name='TestObject')
+        data = data_utils.arbitrary_string()
+        create_metadata = {'X-Object-Meta-test-meta1': 'Meta1'}
+        self.object_client.create_object(self.container_name,
+                                         object_name,
+                                         data,
+                                         metadata=create_metadata)
+
+        update_metadata = {'X-Remove-Object-Meta-test-meta1': 'Meta1'}
+        resp, _ = self.object_client.update_object_metadata(
+            self.container_name,
+            object_name,
+            update_metadata,
+            metadata_prefix='')
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'POST')
+
+        resp, _ = self.object_client.list_object_metadata(
+            self.container_name,
+            object_name)
+        self.assertNotIn('x-object-meta-test-meta1', resp)
+
+    @test.attr(type='smoke')
+    def test_update_object_metadata_with_create_and_remove_metadata(self):
+        # creation and deletion of metadata with one request
+        object_name = data_utils.rand_name(name='TestObject')
+        data = data_utils.arbitrary_string()
+        create_metadata = {'X-Object-Meta-test-meta1': 'Meta1'}
+        self.object_client.create_object(self.container_name,
+                                         object_name,
+                                         data,
+                                         metadata=create_metadata)
+
+        update_metadata = {'X-Object-Meta-test-meta2': 'Meta2',
+                           'X-Remove-Object-Meta-test-meta1': 'Meta1'}
+        resp, _ = self.object_client.update_object_metadata(
+            self.container_name,
+            object_name,
+            update_metadata,
+            metadata_prefix='')
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'POST')
+
+        resp, _ = self.object_client.list_object_metadata(
+            self.container_name,
+            object_name)
+        self.assertNotIn('x-object-meta-test-meta1', resp)
+        self.assertIn('x-object-meta-test-meta2', resp)
+        self.assertEqual(resp['x-object-meta-test-meta2'], 'Meta2')
+
+    @test.attr(type='smoke')
+    def test_update_object_metadata_with_x_object_manifest(self):
+        # update object metadata with x_object_manifest
+
+        # uploading segments
+        object_name, data_segments = self._upload_segments()
+        # creating a manifest file
+        data_empty = ''
+        self.object_client.create_object(self.container_name,
+                                         object_name,
+                                         data_empty,
+                                         metadata=None)
+        object_prefix = '%s/%s' % (self.container_name, object_name)
+        update_metadata = {'X-Object-Manifest': object_prefix}
+        resp, _ = self.object_client.update_object_metadata(
+            self.container_name,
+            object_name,
+            update_metadata,
+            metadata_prefix='')
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'POST')
+
+        resp, _ = self.object_client.list_object_metadata(
+            self.container_name,
+            object_name)
+        self.assertIn('x-object-manifest', resp)
+        self.assertNotEqual(len(resp['x-object-manifest']), 0)
+
+    def test_update_object_metadata_with_x_object_metakey(self):
+        # update object metadata with a blenk value of metadata
+        object_name, data = self._create_object()
+
+        update_metadata = {'X-Object-Meta-test-meta': ''}
+        resp, _ = self.object_client.update_object_metadata(
+            self.container_name,
+            object_name,
+            update_metadata,
+            metadata_prefix='')
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'POST')
+
+        resp, _ = self.object_client.list_object_metadata(
+            self.container_name,
+            object_name)
+        self.assertIn('x-object-meta-test-meta', resp)
+        self.assertEqual(resp['x-object-meta-test-meta'], '')
+
+    @test.attr(type='smoke')
+    def test_update_object_metadata_with_x_remove_object_metakey(self):
+        # update object metadata with a blank value of remove metadata
+        object_name = data_utils.rand_name(name='TestObject')
+        data = data_utils.arbitrary_string()
+        create_metadata = {'X-Object-Meta-test-meta': 'Meta'}
+        self.object_client.create_object(self.container_name,
+                                         object_name,
+                                         data,
+                                         metadata=create_metadata)
+
+        update_metadata = {'X-Remove-Object-Meta-test-meta': ''}
+        resp, _ = self.object_client.update_object_metadata(
+            self.container_name,
+            object_name,
+            update_metadata,
+            metadata_prefix='')
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'POST')
+
+        resp, _ = self.object_client.list_object_metadata(
+            self.container_name,
+            object_name)
+        self.assertNotIn('x-object-meta-test-meta', resp)
+
+    @test.attr(type='smoke')
+    def test_list_object_metadata(self):
         # get object metadata
-        resp, resp_metadata = self.object_client.list_object_metadata(
-            self.container_name, object_name)
+        object_name = data_utils.rand_name(name='TestObject')
+        data = data_utils.arbitrary_string()
+        metadata = {'X-Object-Meta-test-meta': 'Meta'}
+        self.object_client.create_object(self.container_name,
+                                         object_name,
+                                         data,
+                                         metadata=metadata)
+
+        resp, _ = self.object_client.list_object_metadata(
+            self.container_name,
+            object_name)
         self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
         self.assertHeaders(resp, 'Object', 'HEAD')
+        self.assertIn('x-object-meta-test-meta', resp)
+        self.assertEqual(resp['x-object-meta-test-meta'], 'Meta')
 
-        actual_meta_key = 'x-object-meta-' + meta_key
-        self.assertIn(actual_meta_key, resp)
-        self.assertEqual(resp[actual_meta_key], meta_value)
+    @test.attr(type='smoke')
+    def test_list_no_object_metadata(self):
+        # get empty list of object metadata
+        object_name, data = self._create_object()
+
+        resp, _ = self.object_client.list_object_metadata(
+            self.container_name,
+            object_name)
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+        self.assertHeaders(resp, 'Object', 'HEAD')
+        self.assertNotIn('x-object-meta-', str(resp))
+
+    @test.attr(type='smoke')
+    def test_list_object_metadata_with_x_object_manifest(self):
+        # get object metadata with x_object_manifest
+
+        # uploading segments
+        object_name, data_segments = self._upload_segments()
+        # creating a manifest file
+        object_prefix = '%s/%s' % (self.container_name, object_name)
+        metadata = {'X-Object-Manifest': object_prefix}
+        data_empty = ''
+        resp, _ = self.object_client.create_object(
+            self.container_name,
+            object_name,
+            data_empty,
+            metadata=metadata)
+
+        resp, _ = self.object_client.list_object_metadata(
+            self.container_name,
+            object_name)
+        self.assertIn(int(resp['status']), test.HTTP_SUCCESS)
+
+        # Check only the existence of common headers with custom matcher
+        self.assertThat(resp, custom_matchers.ExistsAllResponseHeaders(
+                        'Object', 'HEAD'))
+        self.assertIn('x-object-manifest', resp)
+
+        # Etag value of a large object is enclosed in double-quotations.
+        # This is a special case, therefore the formats of response headers
+        # are checked without a custom matcher.
+        self.assertTrue(resp['etag'].startswith('\"'))
+        self.assertTrue(resp['etag'].endswith('\"'))
+        self.assertTrue(resp['etag'].strip('\"').isalnum())
+        self.assertTrue(re.match("^\d+\.?\d*\Z", resp['x-timestamp']))
+        self.assertNotEqual(len(resp['content-type']), 0)
+        self.assertTrue(re.match("^tx[0-9a-f]*-[0-9a-f]*$",
+                                 resp['x-trans-id']))
+        self.assertNotEqual(len(resp['date']), 0)
+        self.assertEqual(resp['accept-ranges'], 'bytes')
+        self.assertEqual(resp['x-object-manifest'],
+                         '%s/%s' % (self.container_name, object_name))
 
     @test.attr(type='smoke')
     def test_get_object(self):
diff --git a/tempest/api/orchestration/base.py b/tempest/api/orchestration/base.py
index 1832259..7656ff3 100644
--- a/tempest/api/orchestration/base.py
+++ b/tempest/api/orchestration/base.py
@@ -120,3 +120,20 @@
         """Return a stack output value for a given key."""
         return next((o['output_value'] for o in stack['outputs']
                     if o['output_key'] == output_key), None)
+
+    def assert_fields_in_dict(self, obj, *fields):
+        for field in fields:
+            self.assertIn(field, obj)
+
+    def list_resources(self, stack_identifier):
+        """Get a dict mapping of resource names to types."""
+        resp, resources = self.client.list_resources(stack_identifier)
+        self.assertEqual('200', resp['status'])
+        self.assertIsInstance(resources, list)
+        for res in resources:
+            self.assert_fields_in_dict(res, 'logical_resource_id',
+                                       'resource_type', 'resource_status',
+                                       'updated_time')
+
+        return dict((r['resource_name'], r['resource_type'])
+                    for r in resources)
diff --git a/tempest/api/orchestration/stacks/templates/cfn_init_signal.yaml b/tempest/api/orchestration/stacks/templates/cfn_init_signal.yaml
index 23ad06f..fa5345e 100644
--- a/tempest/api/orchestration/stacks/templates/cfn_init_signal.yaml
+++ b/tempest/api/orchestration/stacks/templates/cfn_init_signal.yaml
@@ -11,6 +11,8 @@
     Type: String
   network:
     Type: String
+  timeout:
+    Type: Number
 Resources:
   CfnUser:
     Type: AWS::IAM::User
@@ -68,7 +70,7 @@
     DependsOn: SmokeServer
     Properties:
       Handle: {Ref: WaitHandle}
-      Timeout: '600'
+      Timeout: {Ref: timeout}
 Outputs:
   WaitConditionStatus:
     Description: Contents of /tmp/smoke-status on SmokeServer
diff --git a/tempest/api/orchestration/stacks/templates/neutron_basic.yaml b/tempest/api/orchestration/stacks/templates/neutron_basic.yaml
index 9d90e31..275d040 100644
--- a/tempest/api/orchestration/stacks/templates/neutron_basic.yaml
+++ b/tempest/api/orchestration/stacks/templates/neutron_basic.yaml
@@ -12,6 +12,8 @@
     type: string
   ExternalNetworkId:
     type: string
+  timeout:
+    type: number
 resources:
   Network:
     type: OS::Neutron::Net
@@ -41,15 +43,16 @@
       router_id: {get_param: ExternalRouterId}
       subnet_id: {get_resource: Subnet}
   Server:
-    type: AWS::EC2::Instance
+    type: OS::Nova::Server
     metadata:
       Name: SmokeServerNeutron
     properties:
-      ImageId: {get_param: ImageId}
-      InstanceType: {get_param: InstanceType}
-      KeyName: {get_param: KeyName}
-      SubnetId: {get_resource: Subnet}
-      UserData:
+      image: {get_param: ImageId}
+      flavor: {get_param: InstanceType}
+      key_name: {get_param: KeyName}
+      networks:
+      - network: {get_resource: Network}
+      user_data:
         str_replace:
           template: |
             #!/bin/bash -v
@@ -65,4 +68,4 @@
     depends_on: Server
     properties:
       Handle: {get_resource: WaitHandleNeutron}
-      Timeout: '600'
+      Timeout: {get_param: timeout}
diff --git a/tempest/api/orchestration/stacks/test_neutron_resources.py b/tempest/api/orchestration/stacks/test_neutron_resources.py
index 83470be..b96f6ce 100644
--- a/tempest/api/orchestration/stacks/test_neutron_resources.py
+++ b/tempest/api/orchestration/stacks/test_neutron_resources.py
@@ -53,7 +53,8 @@
                 'InstanceType': CONF.orchestration.instance_type,
                 'ImageId': CONF.orchestration.image_ref,
                 'ExternalRouterId': cls.external_router_id,
-                'ExternalNetworkId': cls.external_network_id
+                'ExternalNetworkId': cls.external_network_id,
+                'timeout': CONF.orchestration.build_timeout
             })
         cls.stack_id = cls.stack_identifier.split('/')[1]
         try:
@@ -90,7 +91,7 @@
         resources = [('Network', 'OS::Neutron::Net'),
                      ('Subnet', 'OS::Neutron::Subnet'),
                      ('RouterInterface', 'OS::Neutron::RouterInterface'),
-                     ('Server', 'AWS::EC2::Instance')]
+                     ('Server', 'OS::Nova::Server')]
         for resource_name, resource_type in resources:
             resource = self.test_resources.get(resource_name, None)
             self.assertIsInstance(resource, dict)
diff --git a/tempest/api/orchestration/stacks/test_non_empty_stack.py b/tempest/api/orchestration/stacks/test_non_empty_stack.py
index 4b1b5ef..9ef95a1 100644
--- a/tempest/api/orchestration/stacks/test_non_empty_stack.py
+++ b/tempest/api/orchestration/stacks/test_non_empty_stack.py
@@ -40,16 +40,18 @@
         cls.resource_type = 'AWS::AutoScaling::LaunchConfiguration'
         cls.client.wait_for_stack_status(cls.stack_id, 'CREATE_COMPLETE')
 
-    def assert_fields_in_dict(self, obj, *fields):
-        for field in fields:
-            self.assertIn(field, obj)
+    def _list_stacks(self, expected_num=None, **filter_kwargs):
+        resp, stacks = self.client.list_stacks(params=filter_kwargs)
+        self.assertEqual('200', resp['status'])
+        self.assertIsInstance(stacks, list)
+        if expected_num is not None:
+            self.assertEqual(expected_num, len(stacks))
+        return stacks
 
     @attr(type='gate')
     def test_stack_list(self):
         """Created stack should be in the list of existing stacks."""
-        resp, stacks = self.client.list_stacks()
-        self.assertEqual('200', resp['status'])
-        self.assertIsInstance(stacks, list)
+        stacks = self._list_stacks()
         stacks_names = map(lambda stack: stack['stack_name'], stacks)
         self.assertIn(self.stack_name, stacks_names)
 
@@ -89,20 +91,8 @@
     def test_list_resources(self):
         """Getting list of created resources for the stack should be possible.
         """
-        resp, resources = self.client.list_resources(self.stack_identifier)
-        self.assertEqual('200', resp['status'])
-        self.assertIsInstance(resources, list)
-        for res in resources:
-            self.assert_fields_in_dict(res, 'logical_resource_id',
-                                       'resource_type', 'resource_status',
-                                       'updated_time')
-
-        resources_names = map(lambda resource: resource['logical_resource_id'],
-                              resources)
-        self.assertIn(self.resource_name, resources_names)
-        resources_types = map(lambda resource: resource['resource_type'],
-                              resources)
-        self.assertIn(self.resource_type, resources_types)
+        resources = self.list_resources(self.stack_identifier)
+        self.assertEqual({self.resource_name: self.resource_type}, resources)
 
     @attr(type='gate')
     def test_show_resource(self):
diff --git a/tempest/api/orchestration/stacks/test_server_cfn_init.py b/tempest/api/orchestration/stacks/test_server_cfn_init.py
index 5f65193..cb5d941 100644
--- a/tempest/api/orchestration/stacks/test_server_cfn_init.py
+++ b/tempest/api/orchestration/stacks/test_server_cfn_init.py
@@ -50,7 +50,8 @@
                 'key_name': keypair_name,
                 'flavor': CONF.orchestration.instance_type,
                 'image': CONF.orchestration.image_ref,
-                'network': cls._get_default_network()['id']
+                'network': cls._get_default_network()['id'],
+                'timeout': CONF.orchestration.build_timeout
             })
 
     @test.attr(type='slow')
@@ -93,7 +94,8 @@
         try:
             self.client.wait_for_resource_status(
                 sid, 'WaitCondition', 'CREATE_COMPLETE')
-        except exceptions.TimeoutException as e:
+        except (exceptions.StackResourceBuildErrorException,
+                exceptions.TimeoutException) as e:
             # attempt to log the server console to help with debugging
             # the cause of the server not signalling the waitcondition
             # to heat.
diff --git a/tempest/api/orchestration/stacks/test_update.py b/tempest/api/orchestration/stacks/test_update.py
new file mode 100644
index 0000000..a9a43b6
--- /dev/null
+++ b/tempest/api/orchestration/stacks/test_update.py
@@ -0,0 +1,84 @@
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import logging
+
+from tempest.api.orchestration import base
+from tempest.common.utils import data_utils
+from tempest import test
+
+
+LOG = logging.getLogger(__name__)
+
+
+class UpdateStackTestJSON(base.BaseOrchestrationTest):
+    _interface = 'json'
+
+    template = '''
+heat_template_version: 2013-05-23
+resources:
+  random1:
+    type: OS::Heat::RandomString
+'''
+    update_template = '''
+heat_template_version: 2013-05-23
+resources:
+  random1:
+    type: OS::Heat::RandomString
+  random2:
+    type: OS::Heat::RandomString
+'''
+
+    def update_stack(self, stack_identifier, template):
+        stack_name = stack_identifier.split('/')[0]
+        resp = self.client.update_stack(
+            stack_identifier=stack_identifier,
+            name=stack_name,
+            template=template)
+        self.assertEqual('202', resp[0]['status'])
+        self.client.wait_for_stack_status(stack_identifier, 'UPDATE_COMPLETE')
+
+    @test.attr(type='gate')
+    def test_stack_update_nochange(self):
+        stack_name = data_utils.rand_name('heat')
+        stack_identifier = self.create_stack(stack_name, self.template)
+        self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
+        expected_resources = {'random1': 'OS::Heat::RandomString'}
+        self.assertEqual(expected_resources,
+                         self.list_resources(stack_identifier))
+
+        # Update with no changes, resources should be unchanged
+        self.update_stack(stack_identifier, self.template)
+        self.assertEqual(expected_resources,
+                         self.list_resources(stack_identifier))
+
+    @test.attr(type='gate')
+    @test.skip_because(bug='1308682')
+    def test_stack_update_add_remove(self):
+        stack_name = data_utils.rand_name('heat')
+        stack_identifier = self.create_stack(stack_name, self.template)
+        self.client.wait_for_stack_status(stack_identifier, 'CREATE_COMPLETE')
+        initial_resources = {'random1': 'OS::Heat::RandomString'}
+        self.assertEqual(initial_resources,
+                         self.list_resources(stack_identifier))
+
+        # Add one resource via a stack update
+        self.update_stack(stack_identifier, self.update_template)
+        updated_resources = {'random1': 'OS::Heat::RandomString',
+                             'random2': 'OS::Heat::RandomString'}
+        self.assertEqual(updated_resources,
+                         self.list_resources(stack_identifier))
+
+        # Then remove it by updating with the original template
+        self.update_stack(stack_identifier, self.template)
+        self.assertEqual(initial_resources,
+                         self.list_resources(stack_identifier))
diff --git a/tempest/api_schema/compute/flavors_access.py b/tempest/api_schema/compute/flavors_access.py
index 152e24c..cd31b0a 100644
--- a/tempest/api_schema/compute/flavors_access.py
+++ b/tempest/api_schema/compute/flavors_access.py
@@ -12,7 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-list_flavor_access = {
+add_remove_list_flavor_access = {
     'status_code': [200],
     'response_body': {
         'type': 'object',
diff --git a/tempest/api_schema/compute/parameter_types.py b/tempest/api_schema/compute/parameter_types.py
index 67c0c9b..95d5b92 100644
--- a/tempest/api_schema/compute/parameter_types.py
+++ b/tempest/api_schema/compute/parameter_types.py
@@ -26,3 +26,8 @@
         'required': ['href', 'rel']
     }
 }
+
+mac_address = {
+    'type': 'string',
+    'pattern': '(?:[a-f0-9]{2}:){5}[a-f0-9]{2}'
+}
diff --git a/tempest/api_schema/compute/servers.py b/tempest/api_schema/compute/servers.py
index 0071845..5eb5ecb 100644
--- a/tempest/api_schema/compute/servers.py
+++ b/tempest/api_schema/compute/servers.py
@@ -22,3 +22,24 @@
         'required': ['password']
     }
 }
+
+get_vnc_console = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'console': {
+                'type': 'object',
+                'properties': {
+                    'type': {'type': 'string'},
+                    'url': {
+                        'type': 'string',
+                        'format': 'uri'
+                    }
+                },
+                'required': ['type', 'url']
+            }
+        },
+        'required': ['console']
+    }
+}
diff --git a/tempest/api_schema/compute/v2/agents.py b/tempest/api_schema/compute/v2/agents.py
new file mode 100644
index 0000000..837731f
--- /dev/null
+++ b/tempest/api_schema/compute/v2/agents.py
@@ -0,0 +1,17 @@
+# Copyright 2014 NEC Corporation.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+delete_agent = {
+    'status_code': [200]
+}
diff --git a/tempest/api_schema/compute/v2/hosts.py b/tempest/api_schema/compute/v2/hosts.py
index add5bb5..cd6bd7b 100644
--- a/tempest/api_schema/compute/v2/hosts.py
+++ b/tempest/api_schema/compute/v2/hosts.py
@@ -12,6 +12,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import copy
+
 body = {
     'type': 'object',
     'properties': {
@@ -25,3 +27,17 @@
     'status_code': [200],
     'response_body': body
 }
+
+# The 'power_action' attribute of 'shutdown_host' API is 'shutdown'
+shutdown_host = copy.deepcopy(startup_host)
+
+shutdown_host['response_body']['properties']['power_action'] = {
+    'enum': ['shutdown']
+}
+
+# The 'power_action' attribute of 'reboot_host' API is 'reboot'
+reboot_host = copy.deepcopy(startup_host)
+
+reboot_host['response_body']['properties']['power_action'] = {
+    'enum': ['reboot']
+}
diff --git a/tempest/api_schema/compute/v2/instance_usage_audit_logs.py b/tempest/api_schema/compute/v2/instance_usage_audit_logs.py
index c1509b4..658f574 100644
--- a/tempest/api_schema/compute/v2/instance_usage_audit_logs.py
+++ b/tempest/api_schema/compute/v2/instance_usage_audit_logs.py
@@ -46,3 +46,14 @@
         'required': ['instance_usage_audit_log']
     }
 }
+
+list_instance_usage_audit_log = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'instance_usage_audit_logs': common_instance_usage_audit_log
+        },
+        'required': ['instance_usage_audit_logs']
+    }
+}
diff --git a/tempest/api_schema/compute/v2/servers.py b/tempest/api_schema/compute/v2/servers.py
index 4e0cec0..81d2ef7 100644
--- a/tempest/api_schema/compute/v2/servers.py
+++ b/tempest/api_schema/compute/v2/servers.py
@@ -42,3 +42,27 @@
         'required': ['server']
     }
 }
+
+list_virtual_interfaces = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'virtual_interfaces': {
+                'type': 'array',
+                'items': {
+                    'type': 'object',
+                    'properties': {
+                        'id': {'type': 'string'},
+                        'mac_address': parameter_types.mac_address,
+                        'OS-EXT-VIF-NET:net_id': {'type': 'string'}
+                    },
+                    # 'OS-EXT-VIF-NET:net_id' is API extension So it is
+                    # not defined as 'required'
+                    'required': ['id', 'mac_address']
+                }
+            }
+        },
+        'required': ['virtual_interfaces']
+    }
+}
diff --git a/tempest/api_schema/compute/v3/agents.py b/tempest/api_schema/compute/v3/agents.py
new file mode 100644
index 0000000..63d1c46
--- /dev/null
+++ b/tempest/api_schema/compute/v3/agents.py
@@ -0,0 +1,17 @@
+# Copyright 2014 NEC Corporation.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+delete_agent = {
+    'status_code': [204]
+}
diff --git a/tempest/api_schema/compute/v3/hosts.py b/tempest/api_schema/compute/v3/hosts.py
index 9731d4b..2cf8f9b 100644
--- a/tempest/api_schema/compute/v3/hosts.py
+++ b/tempest/api_schema/compute/v3/hosts.py
@@ -12,6 +12,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import copy
 from tempest.api_schema.compute.v2 import hosts
 
 startup_host = {
@@ -24,3 +25,17 @@
         'required': ['host']
     }
 }
+
+# The 'power_action' attribute of 'shutdown_host' API is 'shutdown'
+shutdown_host = copy.deepcopy(startup_host)
+
+shutdown_host['response_body']['properties']['power_action'] = {
+    'enum': ['shutdown']
+}
+
+# The 'power_action' attribute of 'reboot_host' API is 'reboot'
+reboot_host = copy.deepcopy(startup_host)
+
+reboot_host['response_body']['properties']['power_action'] = {
+    'enum': ['reboot']
+}
diff --git a/tempest/cli/simple_read_only/test_sahara.py b/tempest/cli/simple_read_only/test_sahara.py
index 5af8dae..36cc324 100644
--- a/tempest/cli/simple_read_only/test_sahara.py
+++ b/tempest/cli/simple_read_only/test_sahara.py
@@ -93,3 +93,48 @@
             'status',
             'node_count'
         ])
+
+    def test_sahara_data_source_list(self):
+        result = self.sahara('data-source-list')
+        data_sources = self.parser.listing(result)
+        self.assertTableStruct(data_sources, [
+            'name',
+            'id',
+            'type',
+            'description'
+        ])
+
+    def test_sahara_job_binary_data_list(self):
+        result = self.sahara('job-binary-data-list')
+        job_binary_data_list = self.parser.listing(result)
+        self.assertTableStruct(job_binary_data_list, [
+            'id',
+            'name'
+        ])
+
+    def test_sahara_job_binary_list(self):
+        result = self.sahara('job-binary-list')
+        job_binaries = self.parser.listing(result)
+        self.assertTableStruct(job_binaries, [
+            'id',
+            'name',
+            'description'
+        ])
+
+    def test_sahara_job_template_list(self):
+        result = self.sahara('job-template-list')
+        job_templates = self.parser.listing(result)
+        self.assertTableStruct(job_templates, [
+            'id',
+            'name',
+            'description'
+        ])
+
+    def test_sahara_job_list(self):
+        result = self.sahara('job-list')
+        jobs = self.parser.listing(result)
+        self.assertTableStruct(jobs, [
+            'id',
+            'cluster_id',
+            'status'
+        ])
diff --git a/tempest/clients.py b/tempest/clients.py
index 444b4d9..0ebbd7c 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -13,16 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-# Default client libs
-import cinderclient.client
-import glanceclient
-import heatclient.client
-import ironicclient.client
 import keystoneclient.exceptions
 import keystoneclient.v2_0.client
-import neutronclient.v2_0.client
-import novaclient.client
-import swiftclient
 
 from tempest.common.rest_client import NegativeRestClient
 from tempest import config
@@ -31,6 +23,8 @@
 from tempest.openstack.common import log as logging
 from tempest.services.baremetal.v1.client_json import BaremetalClientJSON
 from tempest.services import botoclients
+from tempest.services.compute.json.agents_client import \
+    AgentsClientJSON
 from tempest.services.compute.json.aggregates_client import \
     AggregatesClientJSON
 from tempest.services.compute.json.availability_zone_client import \
@@ -373,6 +367,7 @@
 
         # common clients
         self.account_client = AccountClient(self.auth_provider)
+        self.agents_client = AgentsClientJSON(self.auth_provider)
         if CONF.service_available.glance:
             self.image_client = ImageClientJSON(self.auth_provider)
             self.image_client_v2 = ImageClientV2JSON(self.auth_provider)
@@ -465,6 +460,7 @@
     CINDERCLIENT_VERSION = '1'
     HEATCLIENT_VERSION = '1'
     IRONICCLIENT_VERSION = '1'
+    SAHARACLIENT_VERSION = '1.1'
 
     def __init__(self, username, password, tenant_name):
         # FIXME(andreaf) Auth provider for client_type 'official' is
@@ -494,6 +490,10 @@
             username,
             password,
             tenant_name)
+        self.data_processing_client = self._get_data_processing_client(
+            username,
+            password,
+            tenant_name)
 
     def _get_roles(self):
         keystone_admin = self._get_identity_client(
@@ -515,6 +515,9 @@
         # Novaclient will not execute operations for anyone but the
         # identified user, so a new client needs to be created for
         # each user that operations need to be performed for.
+        if not CONF.service_available.nova:
+            return None
+        import novaclient.client
         self._validate_credentials(username, password, tenant_name)
 
         auth_url = CONF.identity.uri
@@ -536,6 +539,9 @@
                                         http_log_debug=True)
 
     def _get_image_client(self):
+        if not CONF.service_available.glance:
+            return None
+        import glanceclient
         token = self.identity_client.auth_token
         region = CONF.identity.region
         endpoint_type = CONF.image.endpoint_type
@@ -547,9 +553,13 @@
                                    insecure=dscv)
 
     def _get_volume_client(self, username, password, tenant_name):
+        if not CONF.service_available.cinder:
+            return None
+        import cinderclient.client
         auth_url = CONF.identity.uri
         region = CONF.identity.region
         endpoint_type = CONF.volume.endpoint_type
+        dscv = CONF.identity.disable_ssl_certificate_validation
         return cinderclient.client.Client(self.CINDERCLIENT_VERSION,
                                           username,
                                           password,
@@ -557,9 +567,13 @@
                                           auth_url,
                                           region_name=region,
                                           endpoint_type=endpoint_type,
+                                          insecure=dscv,
                                           http_log_debug=True)
 
     def _get_object_storage_client(self, username, password, tenant_name):
+        if not CONF.service_available.swift:
+            return None
+        import swiftclient
         auth_url = CONF.identity.uri
         # add current tenant to swift operator role group.
         keystone_admin = self._get_identity_client(
@@ -589,6 +603,9 @@
 
     def _get_orchestration_client(self, username=None, password=None,
                                   tenant_name=None):
+        if not CONF.service_available.heat:
+            return None
+        import heatclient.client
         if not username:
             username = CONF.identity.admin_username
         if not password:
@@ -634,6 +651,9 @@
 
     def _get_baremetal_client(self):
         # ironic client is currently intended to by used by admin users
+        if not CONF.service_available.ironic:
+            return None
+        import ironicclient.client
         roles = self._get_roles()
         if CONF.identity.admin_role not in roles:
             return None
@@ -667,6 +687,9 @@
         # preferable to authenticating as a specific user because
         # working with certain resources (public routers and networks)
         # often requires admin privileges anyway.
+        if not CONF.service_available.neutron:
+            return None
+        import neutronclient.v2_0.client
         username = CONF.identity.admin_username
         password = CONF.identity.admin_password
         tenant_name = CONF.identity.admin_tenant_name
@@ -683,3 +706,25 @@
                                                 endpoint_type=endpoint_type,
                                                 auth_url=auth_url,
                                                 insecure=dscv)
+
+    def _get_data_processing_client(self, username, password, tenant_name):
+        if not CONF.service_available.sahara:
+            # Sahara isn't available
+            return None
+
+        import saharaclient.client
+
+        self._validate_credentials(username, password, tenant_name)
+
+        endpoint_type = CONF.data_processing.endpoint_type
+        catalog_type = CONF.data_processing.catalog_type
+        auth_url = CONF.identity.uri
+
+        client = saharaclient.client.Client(self.SAHARACLIENT_VERSION,
+                                            username, password,
+                                            project_name=tenant_name,
+                                            endpoint_type=endpoint_type,
+                                            service_type=catalog_type,
+                                            auth_url=auth_url)
+
+        return client
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 830968e..8c07d4f 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -197,26 +197,26 @@
                 details = pattern.format(read_code, expected_code)
                 raise exceptions.InvalidHttpSuccessCode(details)
 
-    def post(self, url, body, headers=None):
-        return self.request('POST', url, headers, body)
+    def post(self, url, body, headers=None, extra_headers=False):
+        return self.request('POST', url, extra_headers, headers, body)
 
-    def get(self, url, headers=None):
-        return self.request('GET', url, headers)
+    def get(self, url, headers=None, extra_headers=False):
+        return self.request('GET', url, extra_headers, headers)
 
-    def delete(self, url, headers=None, body=None):
-        return self.request('DELETE', url, headers, body)
+    def delete(self, url, headers=None, body=None, extra_headers=False):
+        return self.request('DELETE', url, extra_headers, headers, body)
 
-    def patch(self, url, body, headers=None):
-        return self.request('PATCH', url, headers, body)
+    def patch(self, url, body, headers=None, extra_headers=False):
+        return self.request('PATCH', url, extra_headers, headers, body)
 
-    def put(self, url, body, headers=None):
-        return self.request('PUT', url, headers, body)
+    def put(self, url, body, headers=None, extra_headers=False):
+        return self.request('PUT', url, extra_headers, headers, body)
 
-    def head(self, url, headers=None):
-        return self.request('HEAD', url, headers)
+    def head(self, url, headers=None, extra_headers=False):
+        return self.request('HEAD', url, extra_headers, headers)
 
-    def copy(self, url, headers=None):
-        return self.request('COPY', url, headers)
+    def copy(self, url, headers=None, extra_headers=False):
+        return self.request('COPY', url, extra_headers, headers)
 
     def get_versions(self):
         resp, body = self.get('')
@@ -418,13 +418,22 @@
 
         return resp, resp_body
 
-    def request(self, method, url, headers=None, body=None):
+    def request(self, method, url, extra_headers=False, headers=None,
+                body=None):
+        # if extra_headers is True
+        # default headers would be added to headers
         retry = 0
 
         if headers is None:
             # NOTE(vponomaryov): if some client do not need headers,
             # it should explicitly pass empty dict
             headers = self.get_headers()
+        elif extra_headers:
+            try:
+                headers = headers.copy()
+                headers.update(self.get_headers())
+            except (ValueError, TypeError):
+                headers = self.get_headers()
 
         resp, resp_body = self._request(method, url,
                                         headers=headers, body=body)
@@ -481,7 +490,7 @@
             raise exceptions.InvalidContentType(str(resp.status))
 
         if resp.status == 401 or resp.status == 403:
-            raise exceptions.Unauthorized()
+            raise exceptions.Unauthorized(resp_body)
 
         if resp.status == 404:
             raise exceptions.NotFound(resp_body)
diff --git a/tempest/common/utils/linux/remote_client.py b/tempest/common/utils/linux/remote_client.py
index 00e5e0d..95b6833 100644
--- a/tempest/common/utils/linux/remote_client.py
+++ b/tempest/common/utils/linux/remote_client.py
@@ -112,3 +112,8 @@
     def turn_nic_on(self, nic):
         cmd = "sudo /bin/ip link set {nic} up".format(nic=nic)
         return self.exec_command(cmd)
+
+    def get_pids(self, pr_name):
+        # Get pid(s) of a process/program
+        cmd = "ps -ef | grep %s | grep -v 'grep' | awk {'print $1'}" % pr_name
+        return self.exec_command(cmd).split('\n')
diff --git a/tempest/config.py b/tempest/config.py
index c0ab323..b9fe572 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -559,7 +559,7 @@
                default=1,
                help="Time in seconds between build status checks."),
     cfg.IntOpt('build_timeout',
-               default=600,
+               default=1200,
                help="Timeout in seconds to wait for a stack to build."),
     cfg.StrOpt('instance_type',
                default='m1.micro',
diff --git a/tempest/exceptions.py b/tempest/exceptions.py
new file mode 100644
index 0000000..857e1e8
--- /dev/null
+++ b/tempest/exceptions.py
@@ -0,0 +1,209 @@
+# Copyright 2012 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import testtools
+
+
+class TempestException(Exception):
+    """
+    Base Tempest Exception
+
+    To correctly use this class, inherit from it and define
+    a 'message' property. That message will get printf'd
+    with the keyword arguments provided to the constructor.
+    """
+    message = "An unknown exception occurred"
+
+    def __init__(self, *args, **kwargs):
+        super(TempestException, self).__init__()
+        try:
+            self._error_string = self.message % kwargs
+        except Exception:
+            # at least get the core message out if something happened
+            self._error_string = self.message
+        if len(args) > 0:
+            # If there is a non-kwarg parameter, assume it's the error
+            # message or reason description and tack it on to the end
+            # of the exception message
+            # Convert all arguments into their string representations...
+            args = ["%s" % arg for arg in args]
+            self._error_string = (self._error_string +
+                                  "\nDetails: %s" % '\n'.join(args))
+
+    def __str__(self):
+        return self._error_string
+
+
+class RestClientException(TempestException,
+                          testtools.TestCase.failureException):
+    pass
+
+
+class RFCViolation(RestClientException):
+    message = "RFC Violation"
+
+
+class InvalidConfiguration(TempestException):
+    message = "Invalid Configuration"
+
+
+class InvalidCredentials(TempestException):
+    message = "Invalid Credentials"
+
+
+class InvalidHttpSuccessCode(RestClientException):
+    message = "The success code is different than the expected one"
+
+
+class NotFound(RestClientException):
+    message = "Object not found"
+
+
+class Unauthorized(RestClientException):
+    message = 'Unauthorized'
+
+
+class InvalidServiceTag(RestClientException):
+    message = "Invalid service tag"
+
+
+class TimeoutException(TempestException):
+    message = "Request timed out"
+
+
+class BuildErrorException(TempestException):
+    message = "Server %(server_id)s failed to build and is in ERROR status"
+
+
+class ImageKilledException(TempestException):
+    message = "Image %(image_id)s 'killed' while waiting for '%(status)s'"
+
+
+class AddImageException(TempestException):
+    message = "Image %(image_id)s failed to become ACTIVE in the allotted time"
+
+
+class EC2RegisterImageException(TempestException):
+    message = ("Image %(image_id)s failed to become 'available' "
+               "in the allotted time")
+
+
+class VolumeBuildErrorException(TempestException):
+    message = "Volume %(volume_id)s failed to build and is in ERROR status"
+
+
+class SnapshotBuildErrorException(TempestException):
+    message = "Snapshot %(snapshot_id)s failed to build and is in ERROR status"
+
+
+class VolumeBackupException(TempestException):
+    message = "Volume backup %(backup_id)s failed and is in ERROR status"
+
+
+class StackBuildErrorException(TempestException):
+    message = ("Stack %(stack_identifier)s is in %(stack_status)s status "
+               "due to '%(stack_status_reason)s'")
+
+
+class StackResourceBuildErrorException(TempestException):
+    message = ("Resource %(resource_name) in stack %(stack_identifier)s is "
+               "in %(resource_status)s status due to "
+               "'%(resource_status_reason)s'")
+
+
+class BadRequest(RestClientException):
+    message = "Bad request"
+
+
+class UnprocessableEntity(RestClientException):
+    message = "Unprocessable entity"
+
+
+class AuthenticationFailure(RestClientException):
+    message = ("Authentication with user %(user)s and password "
+               "%(password)s failed auth using tenant %(tenant)s.")
+
+
+class EndpointNotFound(TempestException):
+    message = "Endpoint not found"
+
+
+class RateLimitExceeded(TempestException):
+    message = "Rate limit exceeded"
+
+
+class OverLimit(TempestException):
+    message = "Quota exceeded"
+
+
+class ServerFault(TempestException):
+    message = "Got server fault"
+
+
+class ImageFault(TempestException):
+    message = "Got image fault"
+
+
+class IdentityError(TempestException):
+    message = "Got identity error"
+
+
+class Conflict(RestClientException):
+    message = "An object with that identifier already exists"
+
+
+class SSHTimeout(TempestException):
+    message = ("Connection to the %(host)s via SSH timed out.\n"
+               "User: %(user)s, Password: %(password)s")
+
+
+class SSHExecCommandFailed(TempestException):
+    """Raised when remotely executed command returns nonzero status."""
+    message = ("Command '%(command)s', exit status: %(exit_status)d, "
+               "Error:\n%(strerror)s")
+
+
+class ServerUnreachable(TempestException):
+    message = "The server is not reachable via the configured network"
+
+
+class TearDownException(TempestException):
+    message = "%(num)d cleanUp operation failed"
+
+
+class ResponseWithNonEmptyBody(RFCViolation):
+    message = ("RFC Violation! Response with %(status)d HTTP Status Code "
+               "MUST NOT have a body")
+
+
+class ResponseWithEntity(RFCViolation):
+    message = ("RFC Violation! Response with 205 HTTP Status Code "
+               "MUST NOT have an entity")
+
+
+class InvalidHTTPResponseBody(RestClientException):
+    message = "HTTP response body is invalid json or xml"
+
+
+class InvalidContentType(RestClientException):
+    message = "Invalid content type provided"
+
+
+class UnexpectedResponseCode(RestClientException):
+    message = "Unexpected response code received"
+
+
+class InvalidStructure(TempestException):
+    message = "Invalid structure of table with details"
diff --git a/tempest/exceptions/README.rst b/tempest/exceptions/README.rst
deleted file mode 100644
index dbe42b2..0000000
--- a/tempest/exceptions/README.rst
+++ /dev/null
@@ -1,27 +0,0 @@
-Tempest Field Guide to Exceptions
-=================================
-
-
-What are these exceptions?
---------------------------
-
-These exceptions are used by Tempest for covering OpenStack specific exceptional
-cases.
-
-How to add new exceptions?
---------------------------
-
-Each exception-template for inheritance purposes should be added into 'base'
-submodule.
-All other exceptions can be added in two ways:
-- in main module
-- in submodule
-But only in one of the ways. Need to make sure, that new exception is not
-present already.
-
-How to use exceptions?
-----------------------
-
-Any exceptions from this module or its submodules should be used in appropriate
-places to handle exceptional cases.
-Classes from 'base' module should be used only for inheritance.
diff --git a/tempest/exceptions/__init__.py b/tempest/exceptions/__init__.py
deleted file mode 100644
index d313def..0000000
--- a/tempest/exceptions/__init__.py
+++ /dev/null
@@ -1,164 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest.exceptions import base
-
-
-class InvalidConfiguration(base.TempestException):
-    message = "Invalid Configuration"
-
-
-class InvalidCredentials(base.TempestException):
-    message = "Invalid Credentials"
-
-
-class InvalidHttpSuccessCode(base.RestClientException):
-    message = "The success code is different than the expected one"
-
-
-class NotFound(base.RestClientException):
-    message = "Object not found"
-
-
-class Unauthorized(base.RestClientException):
-    message = 'Unauthorized'
-
-
-class InvalidServiceTag(base.RestClientException):
-    message = "Invalid service tag"
-
-
-class TimeoutException(base.TempestException):
-    message = "Request timed out"
-
-
-class BuildErrorException(base.TempestException):
-    message = "Server %(server_id)s failed to build and is in ERROR status"
-
-
-class ImageKilledException(base.TempestException):
-    message = "Image %(image_id)s 'killed' while waiting for '%(status)s'"
-
-
-class AddImageException(base.TempestException):
-    message = "Image %(image_id)s failed to become ACTIVE in the allotted time"
-
-
-class EC2RegisterImageException(base.TempestException):
-    message = ("Image %(image_id)s failed to become 'available' "
-               "in the allotted time")
-
-
-class VolumeBuildErrorException(base.TempestException):
-    message = "Volume %(volume_id)s failed to build and is in ERROR status"
-
-
-class SnapshotBuildErrorException(base.TempestException):
-    message = "Snapshot %(snapshot_id)s failed to build and is in ERROR status"
-
-
-class VolumeBackupException(base.TempestException):
-    message = "Volume backup %(backup_id)s failed and is in ERROR status"
-
-
-class StackBuildErrorException(base.TempestException):
-    message = ("Stack %(stack_identifier)s is in %(stack_status)s status "
-               "due to '%(stack_status_reason)s'")
-
-
-class BadRequest(base.RestClientException):
-    message = "Bad request"
-
-
-class UnprocessableEntity(base.RestClientException):
-    message = "Unprocessable entity"
-
-
-class AuthenticationFailure(base.RestClientException):
-    message = ("Authentication with user %(user)s and password "
-               "%(password)s failed auth using tenant %(tenant)s.")
-
-
-class EndpointNotFound(base.TempestException):
-    message = "Endpoint not found"
-
-
-class RateLimitExceeded(base.TempestException):
-    message = "Rate limit exceeded"
-
-
-class OverLimit(base.TempestException):
-    message = "Quota exceeded"
-
-
-class ServerFault(base.TempestException):
-    message = "Got server fault"
-
-
-class ImageFault(base.TempestException):
-    message = "Got image fault"
-
-
-class IdentityError(base.TempestException):
-    message = "Got identity error"
-
-
-class Conflict(base.RestClientException):
-    message = "An object with that identifier already exists"
-
-
-class SSHTimeout(base.TempestException):
-    message = ("Connection to the %(host)s via SSH timed out.\n"
-               "User: %(user)s, Password: %(password)s")
-
-
-class SSHExecCommandFailed(base.TempestException):
-    """Raised when remotely executed command returns nonzero status."""
-    message = ("Command '%(command)s', exit status: %(exit_status)d, "
-               "Error:\n%(strerror)s")
-
-
-class ServerUnreachable(base.TempestException):
-    message = "The server is not reachable via the configured network"
-
-
-class TearDownException(base.TempestException):
-    message = "%(num)d cleanUp operation failed"
-
-
-class ResponseWithNonEmptyBody(base.RFCViolation):
-    message = ("RFC Violation! Response with %(status)d HTTP Status Code "
-               "MUST NOT have a body")
-
-
-class ResponseWithEntity(base.RFCViolation):
-    message = ("RFC Violation! Response with 205 HTTP Status Code "
-               "MUST NOT have an entity")
-
-
-class InvalidHTTPResponseBody(base.RestClientException):
-    message = "HTTP response body is invalid json or xml"
-
-
-class InvalidContentType(base.RestClientException):
-    message = "Invalid content type provided"
-
-
-class UnexpectedResponseCode(base.RestClientException):
-    message = "Unexpected response code received"
-
-
-class InvalidStructure(base.TempestException):
-    message = "Invalid structure of table with details"
diff --git a/tempest/exceptions/base.py b/tempest/exceptions/base.py
deleted file mode 100644
index b8e470e..0000000
--- a/tempest/exceptions/base.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright 2012 OpenStack Foundation
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-import testtools
-
-
-class TempestException(Exception):
-    """
-    Base Tempest Exception
-
-    To correctly use this class, inherit from it and define
-    a 'message' property. That message will get printf'd
-    with the keyword arguments provided to the constructor.
-    """
-    message = "An unknown exception occurred"
-
-    def __init__(self, *args, **kwargs):
-        super(TempestException, self).__init__()
-        try:
-            self._error_string = self.message % kwargs
-        except Exception:
-            # at least get the core message out if something happened
-            self._error_string = self.message
-        if len(args) > 0:
-            # If there is a non-kwarg parameter, assume it's the error
-            # message or reason description and tack it on to the end
-            # of the exception message
-            # Convert all arguments into their string representations...
-            args = ["%s" % arg for arg in args]
-            self._error_string = (self._error_string +
-                                  "\nDetails: %s" % '\n'.join(args))
-
-    def __str__(self):
-        return self._error_string
-
-
-class RestClientException(TempestException,
-                          testtools.TestCase.failureException):
-    pass
-
-
-class RFCViolation(RestClientException):
-    message = "RFC Violation"
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 234faad..270851d 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -47,7 +47,7 @@
     T104: Scenario tests require a services decorator
     """
 
-    if 'tempest/scenario' in filename:
+    if 'tempest/scenario/test_' in filename:
         if TEST_DEFINITION.match(physical_line):
             if not SCENARIO_DECORATOR.match(previous_logical):
                 return (physical_line.find('def'),
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index d7be534..1e7ddb1 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -19,7 +19,6 @@
 import six
 import subprocess
 
-from ironicclient import exc as ironic_exceptions
 import netaddr
 from neutronclient.common import exceptions as exc
 from novaclient import exceptions as nova_exceptions
@@ -78,6 +77,7 @@
         cls.volume_client = cls.manager.volume_client
         cls.object_storage_client = cls.manager.object_storage_client
         cls.orchestration_client = cls.manager.orchestration_client
+        cls.data_processing_client = cls.manager.data_processing_client
         cls.resource_keys = {}
         cls.os_resources = []
 
@@ -489,6 +489,8 @@
 
     def wait_node(self, instance_id):
         """Waits for a node to be associated with instance_id."""
+        from ironicclient import exc as ironic_exceptions
+
         def _get_node():
             node = None
             try:
diff --git a/tempest/scenario/test_load_balancer_basic.py b/tempest/scenario/test_load_balancer_basic.py
index 1092b94..5f71461 100644
--- a/tempest/scenario/test_load_balancer_basic.py
+++ b/tempest/scenario/test_load_balancer_basic.py
@@ -17,7 +17,6 @@
 import urllib
 
 from tempest.api.network import common as net_common
-from tempest.common.utils import data_utils
 from tempest import config
 from tempest import exceptions
 from tempest.scenario import manager
@@ -59,20 +58,27 @@
     def setUpClass(cls):
         super(TestLoadBalancerBasic, cls).setUpClass()
         cls.check_preconditions()
-        cls.security_groups = {}
         cls.servers_keypairs = {}
         cls.members = []
         cls.floating_ips = {}
-        cls.server_ip = None
-        cls.vip_ip = None
+        cls.server_ips = {}
         cls.port1 = 80
         cls.port2 = 88
 
-    def _create_security_groups(self):
-        self.security_groups[self.tenant_id] =\
-            self._create_security_group_neutron(tenant_id=self.tenant_id)
+    def setUp(self):
+        super(TestLoadBalancerBasic, self).setUp()
+        self.server_ips = {}
+        self._create_security_group()
+
+    def cleanup_wrapper(self, resource):
+        self.cleanup_resource(resource, self.__class__.__name__)
+
+    def _create_security_group(self):
+        self.security_group = self._create_security_group_neutron(
+            tenant_id=self.tenant_id)
         self._create_security_group_rules_for_port(self.port1)
         self._create_security_group_rules_for_port(self.port2)
+        self.addCleanup(self.cleanup_wrapper, self.security_group)
 
     def _create_security_group_rules_for_port(self, port):
         rule = {
@@ -83,15 +89,14 @@
         }
         self._create_security_group_rule(
             client=self.network_client,
-            secgroup=self.security_groups[self.tenant_id],
+            secgroup=self.security_group,
             tenant_id=self.tenant_id,
             **rule)
 
-    def _create_server(self):
-        tenant_id = self.tenant_id
-        name = data_utils.rand_name("smoke_server-")
+    def _create_server(self, name):
         keypair = self.create_keypair(name='keypair-%s' % name)
-        security_groups = [self.security_groups[tenant_id].name]
+        self.addCleanup(self.cleanup_wrapper, keypair)
+        security_groups = [self.security_group.name]
         net = self._list_networks(tenant_id=self.tenant_id)[0]
         create_kwargs = {
             'nics': [
@@ -102,51 +107,106 @@
         }
         server = self.create_server(name=name,
                                     create_kwargs=create_kwargs)
-        self.servers_keypairs[server] = keypair
+        self.addCleanup(self.cleanup_wrapper, server)
+        self.servers_keypairs[server.id] = keypair
         if (config.network.public_network_id and not
                 config.network.tenant_networks_reachable):
             public_network_id = config.network.public_network_id
             floating_ip = self._create_floating_ip(
                 server, public_network_id)
+            self.addCleanup(self.cleanup_wrapper, floating_ip)
             self.floating_ips[floating_ip] = server
-            self.server_ip = floating_ip.floating_ip_address
+            self.server_ips[server.id] = floating_ip.floating_ip_address
         else:
-            self.server_ip = server.networks[net['name']][0]
+            self.server_ips[server.id] = server.networks[net.name][0]
         self.assertTrue(self.servers_keypairs)
         return server
 
-    def _start_servers(self, server):
+    def _create_servers(self):
+        for count in range(2):
+            self._create_server(name=("server%s" % (count + 1)))
+        self.assertEqual(len(self.servers_keypairs), 2)
+
+    def _start_servers(self):
         """
+        Start two backends
+
         1. SSH to the instance
         2. Start two http backends listening on ports 80 and 88 respectively
+        In case there are two instances, each backend is created on a separate
+        instance.
+
+        The backends are the inetd services. To start them we need to edit
+        /etc/inetd.conf in the following way:
+        www stream tcp nowait root /bin/sh sh /home/cirros/script_name
+
+        Where /home/cirros/script_name is a path to a script which
+        echoes the responses:
+        echo -e 'HTTP/1.0 200 OK\r\n\r\nserver_name
+
+        If we want the server to listen on port 88, then we use
+        "kerberos" instead of "www".
         """
 
-        private_key = self.servers_keypairs[server].private_key
-        ssh_client = self.get_remote_client(
-            server_or_ip=self.server_ip,
-            private_key=private_key).ssh_client
-        start_server = "while true; do echo -e 'HTTP/1.0 200 OK\r\n\r\n" \
-                       "%(server)s' | sudo nc -l -p %(port)s ; done &"
-        cmd = start_server % {'server': 'server1',
-                              'port': self.port1}
-        ssh_client.exec_command(cmd)
-        cmd = start_server % {'server': 'server2',
-                              'port': self.port2}
-        ssh_client.exec_command(cmd)
+        for server_id, ip in self.server_ips.iteritems():
+            private_key = self.servers_keypairs[server_id].private_key
+            server_name = self.compute_client.servers.get(server_id).name
+            ssh_client = self.get_remote_client(
+                server_or_ip=ip,
+                private_key=private_key)
+            ssh_client.validate_authentication()
+            # Create service for inetd
+            create_script = """sudo sh -c "echo -e \\"echo -e 'HTTP/1.0 """ \
+                            """200 OK\\\\\\r\\\\\\n\\\\\\r\\\\\\n""" \
+                            """%(server)s'\\" >>/home/cirros/%(script)s\""""
 
-    def _check_connection(self, check_ip):
-        def try_connect(ip):
+            cmd = create_script % {
+                'server': server_name,
+                'script': 'script1'}
+            ssh_client.exec_command(cmd)
+            # Configure inetd
+            configure_inetd = """sudo sh -c "echo -e \\"%(service)s """ \
+                              """stream tcp nowait root /bin/sh sh """ \
+                              """/home/cirros/%(script)s\\" >> """ \
+                              """/etc/inetd.conf\""""
+            # "www" stands for port 80
+            cmd = configure_inetd % {'service': 'www',
+                                     'script': 'script1'}
+            ssh_client.exec_command(cmd)
+
+            if len(self.server_ips) == 1:
+                cmd = create_script % {'server': 'server2',
+                                       'script': 'script2'}
+                ssh_client.exec_command(cmd)
+                # "kerberos" stands for port 88
+                cmd = configure_inetd % {'service': 'kerberos',
+                                         'script': 'script2'}
+                ssh_client.exec_command(cmd)
+
+            # Get PIDs of inetd
+            pids = ssh_client.get_pids('inetd')
+            if pids != ['']:
+                # If there are any inetd processes, reload them
+                kill_cmd = "sudo kill -HUP %s" % ' '.join(pids)
+                ssh_client.exec_command(kill_cmd)
+            else:
+                # In other case start inetd
+                start_inetd = "sudo /usr/sbin/inetd /etc/inetd.conf"
+                ssh_client.exec_command(start_inetd)
+
+    def _check_connection(self, check_ip, port=80):
+        def try_connect(ip, port):
             try:
-                urllib.urlopen("http://{0}/".format(ip))
-                return True
+                resp = urllib.urlopen("http://{0}:{1}/".format(ip, port))
+                if resp.getcode() == 200:
+                    return True
+                return False
             except IOError:
                 return False
         timeout = config.compute.ping_timeout
-        timer = 0
-        while not try_connect(check_ip):
-            time.sleep(1)
-            timer += 1
-            if timer >= timeout:
+        start = time.time()
+        while not try_connect(check_ip, port):
+            if (time.time() - start) > timeout:
                 message = "Timed out trying to connect to %s" % check_ip
                 raise exceptions.TimeoutException(message)
 
@@ -157,30 +217,37 @@
         self.subnet = net_common.DeletableSubnet(client=self.network_client,
                                                  **subnet)
         self.pool = super(TestLoadBalancerBasic, self)._create_pool(
-            'ROUND_ROBIN',
-            'HTTP',
-            self.subnet.id)
+            lb_method='ROUND_ROBIN',
+            protocol='HTTP',
+            subnet_id=self.subnet.id)
+        self.addCleanup(self.cleanup_wrapper, self.pool)
         self.assertTrue(self.pool)
 
-    def _create_members(self, server_ids):
+    def _create_members(self):
         """
         Create two members.
 
         In case there is only one server, create both members with the same ip
         but with different ports to listen on.
         """
-        servers = self.compute_client.servers.list()
-        for server in servers:
-            if server.id in server_ids:
-                ip = self.server_ip
-                pool_id = self.pool.id
-                if len(set(server_ids)) == 1 or len(servers) == 1:
-                    member1 = self._create_member(ip, self.port1, pool_id)
-                    member2 = self._create_member(ip, self.port2, pool_id)
-                    self.members.extend([member1, member2])
-                else:
-                    member = self._create_member(ip, self.port1, pool_id)
-                    self.members.append(member)
+
+        for server_id, ip in self.server_ips.iteritems():
+            if len(self.server_ips) == 1:
+                member1 = self._create_member(address=ip,
+                                              protocol_port=self.port1,
+                                              pool_id=self.pool.id)
+                self.addCleanup(self.cleanup_wrapper, member1)
+                member2 = self._create_member(address=ip,
+                                              protocol_port=self.port2,
+                                              pool_id=self.pool.id)
+                self.addCleanup(self.cleanup_wrapper, member2)
+                self.members.extend([member1, member2])
+            else:
+                member = self._create_member(address=ip,
+                                             protocol_port=self.port1,
+                                             pool_id=self.pool.id)
+                self.addCleanup(self.cleanup_wrapper, member)
+                self.members.append(member)
         self.assertTrue(self.members)
 
     def _assign_floating_ip_to_vip(self, vip):
@@ -188,22 +255,23 @@
         port_id = vip.port_id
         floating_ip = self._create_floating_ip(vip, public_network_id,
                                                port_id=port_id)
+        self.addCleanup(self.cleanup_wrapper, floating_ip)
         self.floating_ips.setdefault(vip.id, [])
         self.floating_ips[vip.id].append(floating_ip)
 
     def _create_load_balancer(self):
         self._create_pool()
-        self._create_members([self.servers_keypairs.keys()[0].id])
-        subnet_id = self.subnet.id
-        pool_id = self.pool.id
-        self.vip = super(TestLoadBalancerBasic, self)._create_vip('HTTP', 80,
-                                                                  subnet_id,
-                                                                  pool_id)
-        self._status_timeout(NeutronRetriever(self.network_client,
-                                              self.network_client.vip_path,
-                                              net_common.DeletableVip),
-                             self.vip.id,
-                             expected_status='ACTIVE')
+        self._create_members()
+        self.vip = self._create_vip(protocol='HTTP',
+                                    protocol_port=80,
+                                    subnet_id=self.subnet.id,
+                                    pool_id=self.pool.id)
+        self.addCleanup(self.cleanup_wrapper, self.vip)
+        self.status_timeout(NeutronRetriever(self.network_client,
+                                             self.network_client.vip_path,
+                                             net_common.DeletableVip),
+                            self.vip.id,
+                            expected_status='ACTIVE')
         if (config.network.public_network_id and not
                 config.network.tenant_networks_reachable):
             self._assign_floating_ip_to_vip(self.vip)
@@ -214,33 +282,49 @@
 
     def _check_load_balancing(self):
         """
-        1. Send 10 requests on the floating ip associated with the VIP
+        1. Send 100 requests on the floating ip associated with the VIP
         2. Check that the requests are shared between
            the two servers and that both of them get equal portions
            of the requests
         """
 
         self._check_connection(self.vip_ip)
+        resp = self._send_requests(self.vip_ip)
+        self.assertEqual(set(["server1\n", "server2\n"]), set(resp))
+        self.assertEqual(50, resp.count("server1\n"))
+        self.assertEqual(50, resp.count("server2\n"))
+
+    def _send_requests(self, vip_ip):
         resp = []
-        for count in range(10):
+        for count in range(100):
             resp.append(
                 urllib.urlopen(
-                    "http://{0}/".format(self.vip_ip)).read())
-        self.assertEqual(set(["server1\n", "server2\n"]), set(resp))
-        self.assertEqual(5, resp.count("server1\n"))
-        self.assertEqual(5, resp.count("server2\n"))
+                    "http://{0}/".format(vip_ip)).read())
+        return resp
 
     @test.attr(type='smoke')
     @test.services('compute', 'network')
     def test_load_balancer_basic(self):
-        self._create_security_groups()
-        server = self._create_server()
-        self._start_servers(server)
+        self._create_server('server1')
+        self._start_servers()
         self._create_load_balancer()
         self._check_load_balancing()
 
 
 class NeutronRetriever(object):
+    """
+    Helper class to make possible handling neutron objects returned by GET
+    requests as attribute dicts.
+
+    Whet get() method is called, the returned dictionary is wrapped into
+    a corresponding DeletableResource class which provides attribute access
+    to dictionary values.
+
+    Usage:
+        This retriever is used to allow using status_timeout from
+        tempest.manager with Neutron objects.
+    """
+
     def __init__(self, network_client, path, resource):
         self.network_client = network_client
         self.path = path
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 285c030..13e00a5 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -14,19 +14,17 @@
 #    under the License.
 
 from tempest.common.utils import data_utils
-from tempest.common.utils import test_utils
 from tempest import config
 from tempest.openstack.common import log as logging
 from tempest.scenario import manager
+from tempest.scenario import utils as test_utils
 from tempest import test
 
-import testscenarios
-
 CONF = config.CONF
 
 LOG = logging.getLogger(__name__)
 
-load_tests = testscenarios.load_tests_apply_scenarios
+load_tests = test_utils.load_tests_input_scenario_utils
 
 
 class TestServerBasicOps(manager.OfficialClientTest):
@@ -43,13 +41,6 @@
      * Terminate the instance
     """
 
-    scenario_utils = test_utils.InputScenarioUtils()
-    scenario_flavor = scenario_utils.scenario_flavors
-    scenario_image = scenario_utils.scenario_images
-
-    scenarios = testscenarios.multiply_scenarios(scenario_image,
-                                                 scenario_flavor)
-
     def setUp(self):
         super(TestServerBasicOps, self).setUp()
         # Setup image and flavor the test instance
@@ -113,10 +104,11 @@
             instance.add_floating_ip(floating_ip)
             # Check ssh
             try:
-                self.get_remote_client(
+                linux_client = self.get_remote_client(
                     server_or_ip=floating_ip.ip,
                     username=self.image_utils.ssh_user(self.image_ref),
-                    private_key=self.keypair.private)
+                    private_key=self.keypair.private_key)
+                linux_client.validate_authentication()
             except Exception:
                 LOG.exception('ssh to server failed')
                 self._log_console_output()
diff --git a/tempest/common/utils/test_utils.py b/tempest/scenario/utils.py
similarity index 85%
rename from tempest/common/utils/test_utils.py
rename to tempest/scenario/utils.py
index cc0d831..4c7b6d7 100644
--- a/tempest/common/utils/test_utils.py
+++ b/tempest/scenario/utils.py
@@ -12,15 +12,19 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest import clients
-from tempest.common.utils import misc
-from tempest import config
 
 import json
 import re
 import string
 import unicodedata
 
+import testscenarios
+import testtools
+
+from tempest import clients
+from tempest.common.utils import misc
+from tempest import config
+
 CONF = config.CONF
 
 
@@ -79,7 +83,7 @@
 
     class TestInputScenario(manager.OfficialClientTest):
 
-        scenario_utils = test_utils.InputScenarioUtils()
+        scenario_utils = utils.InputScenarioUtils()
         scenario_flavor = scenario_utils.scenario_flavors
         scenario_image = scenario_utils.scenario_images
         scenarios = testscenarios.multiply_scenarios(scenario_image,
@@ -134,3 +138,22 @@
                 for f in flavors if re.search(self.flavor_pattern, str(f.name))
             ]
         return self._scenario_flavors
+
+
+def load_tests_input_scenario_utils(*args):
+    """
+    Wrapper for testscenarios to set the scenarios to avoid running a getattr
+    on the CONF object at import.
+    """
+    if getattr(args[0], 'suiteClass', None) is not None:
+        loader, standard_tests, pattern = args
+    else:
+        standard_tests, module, loader = args
+    scenario_utils = InputScenarioUtils()
+    scenario_flavor = scenario_utils.scenario_flavors
+    scenario_image = scenario_utils.scenario_images
+    for test in testtools.iterate_tests(standard_tests):
+        setattr(test, 'scenarios', testscenarios.multiply_scenarios(
+            scenario_image,
+            scenario_flavor))
+    return testscenarios.load_tests_apply_scenarios(*args)
diff --git a/tempest/services/baremetal/v1/base_v1.py b/tempest/services/baremetal/v1/base_v1.py
index 2145c88..296a199 100644
--- a/tempest/services/baremetal/v1/base_v1.py
+++ b/tempest/services/baremetal/v1/base_v1.py
@@ -42,6 +42,11 @@
         return self._list_request('ports', **kwargs)
 
     @base.handle_errors
+    def list_nodestates(self, uuid):
+        """List all existing states."""
+        return self._list_request('/nodes/%s/states' % uuid)
+
+    @base.handle_errors
     def list_ports_detail(self):
         """Details list all existing ports."""
         return self._list_request('/ports/detail')
diff --git a/tempest/services/compute/json/agents_client.py b/tempest/services/compute/json/agents_client.py
new file mode 100644
index 0000000..19821e7
--- /dev/null
+++ b/tempest/services/compute/json/agents_client.py
@@ -0,0 +1,58 @@
+# Copyright 2014 NEC Corporation.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import json
+import urllib
+
+from tempest.api_schema.compute.v2 import agents as schema
+from tempest.common import rest_client
+from tempest import config
+
+CONF = config.CONF
+
+
+class AgentsClientJSON(rest_client.RestClient):
+    """
+    Tests Agents API
+    """
+
+    def __init__(self, auth_provider):
+        super(AgentsClientJSON, self).__init__(auth_provider)
+        self.service = CONF.compute.catalog_type
+
+    def list_agents(self, params=None):
+        """List all agent builds."""
+        url = 'os-agents'
+        if params:
+            url += '?%s' % urllib.urlencode(params)
+        resp, body = self.get(url)
+        return resp, json.loads(body).get('agents')
+
+    def create_agent(self, **kwargs):
+        """Create an agent build."""
+        post_body = json.dumps({'agent': kwargs})
+        resp, body = self.post('os-agents', post_body)
+        return resp, self._parse_resp(body)
+
+    def delete_agent(self, agent_id):
+        """Delete an existing agent build."""
+        resp, body = self.delete("os-agents/%s" % str(agent_id))
+        self.validate_response(schema.delete_agent, resp, body)
+        return resp, body
+
+    def update_agent(self, agent_id, **kwargs):
+        """Update an agent build."""
+        put_body = json.dumps({'para': kwargs})
+        resp, body = self.put('os-agents/%s' % str(agent_id), put_body)
+        return resp, self._parse_resp(body)
diff --git a/tempest/services/compute/json/flavors_client.py b/tempest/services/compute/json/flavors_client.py
index 637a33f..0206b82 100644
--- a/tempest/services/compute/json/flavors_client.py
+++ b/tempest/services/compute/json/flavors_client.py
@@ -130,7 +130,8 @@
         """Gets flavor access information given the flavor id."""
         resp, body = self.get('flavors/%s/os-flavor-access' % flavor_id)
         body = json.loads(body)
-        self.validate_response(schema_access.list_flavor_access, resp, body)
+        self.validate_response(schema_access.add_remove_list_flavor_access,
+                               resp, body)
         return resp, body['flavor_access']
 
     def add_flavor_access(self, flavor_id, tenant_id):
@@ -143,6 +144,8 @@
         post_body = json.dumps(post_body)
         resp, body = self.post('flavors/%s/action' % flavor_id, post_body)
         body = json.loads(body)
+        self.validate_response(schema_access.add_remove_list_flavor_access,
+                               resp, body)
         return resp, body['flavor_access']
 
     def remove_flavor_access(self, flavor_id, tenant_id):
@@ -155,4 +158,6 @@
         post_body = json.dumps(post_body)
         resp, body = self.post('flavors/%s/action' % flavor_id, post_body)
         body = json.loads(body)
+        self.validate_response(schema_access.add_remove_list_flavor_access,
+                               resp, body)
         return resp, body['flavor_access']
diff --git a/tempest/services/compute/json/hosts_client.py b/tempest/services/compute/json/hosts_client.py
index a000e56..e148572 100644
--- a/tempest/services/compute/json/hosts_client.py
+++ b/tempest/services/compute/json/hosts_client.py
@@ -76,6 +76,7 @@
 
         resp, body = self.get("os-hosts/%s/shutdown" % str(hostname))
         body = json.loads(body)
+        self.validate_response(v2_schema.shutdown_host, resp, body)
         return resp, body['host']
 
     def reboot_host(self, hostname):
@@ -83,4 +84,5 @@
 
         resp, body = self.get("os-hosts/%s/reboot" % str(hostname))
         body = json.loads(body)
+        self.validate_response(v2_schema.reboot_host, resp, body)
         return resp, body['host']
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 4088be9..4700ca7 100644
--- a/tempest/services/compute/json/instance_usage_audit_log_client.py
+++ b/tempest/services/compute/json/instance_usage_audit_log_client.py
@@ -34,6 +34,8 @@
         url = 'os-instance_usage_audit_log'
         resp, body = self.get(url)
         body = json.loads(body)
+        self.validate_response(schema.list_instance_usage_audit_log,
+                               resp, body)
         return resp, body["instance_usage_audit_logs"]
 
     def get_instance_usage_audit_log(self, time_before):
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index ee2c43f..9bddf2c 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -48,8 +48,8 @@
         self.validate_response(schema.quota_set, resp, body)
         return resp, body['quota_set']
 
-    def update_quota_set(self, tenant_id, force=None,
-                         injected_file_content_bytes=None,
+    def update_quota_set(self, tenant_id, user_id=None,
+                         force=None, injected_file_content_bytes=None,
                          metadata_items=None, ram=None, floating_ips=None,
                          fixed_ips=None, key_pairs=None, instances=None,
                          security_group_rules=None, injected_files=None,
@@ -101,7 +101,13 @@
             post_body['security_groups'] = security_groups
 
         post_body = json.dumps({'quota_set': post_body})
-        resp, body = self.put('os-quota-sets/%s' % str(tenant_id), post_body)
+
+        if user_id:
+            resp, body = self.put('os-quota-sets/%s?user_id=%s' %
+                                  (str(tenant_id), str(user_id)), post_body)
+        else:
+            resp, body = self.put('os-quota-sets/%s' % str(tenant_id),
+                                  post_body)
 
         body = json.loads(body)
         return resp, body['quota_set']
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index 2d23b03..cf1dad9 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -198,12 +198,21 @@
         body = json.loads(body)
         return resp, body
 
-    def action(self, server_id, action_name, response_key, **kwargs):
+    def action(self, server_id, action_name, response_key,
+               schema=None, **kwargs):
         post_body = json.dumps({action_name: kwargs})
         resp, body = self.post('servers/%s/action' % str(server_id),
                                post_body)
         if response_key is not None:
-            body = json.loads(body)[response_key]
+            body = json.loads(body)
+            # Check for Schema as 'None' because if we donot have any server
+            # action schema implemented yet then they can pass 'None' to skip
+            # the validation.Once all server action has their schema
+            # implemented then, this check can be removed if every actions are
+            # supposed to validate their response.
+            if schema is not None:
+                self.validate_response(schema, resp, body)
+            body = body[response_key]
         return resp, body
 
     def create_backup(self, server_id, backup_type, rotation, name):
@@ -262,10 +271,6 @@
         """Reverts a server back to its original flavor."""
         return self.action(server_id, 'revertResize', None, **kwargs)
 
-    def create_image(self, server_id, name):
-        """Creates an image of the given server."""
-        return self.action(server_id, 'createImage', None, name=name)
-
     def list_server_metadata(self, server_id):
         resp, body = self.get("servers/%s/metadata" % str(server_id))
         body = json.loads(body)
@@ -405,7 +410,9 @@
         """
         resp, body = self.get('/'.join(['servers', server_id,
                               'os-virtual-interfaces']))
-        return resp, json.loads(body)
+        body = json.loads(body)
+        self.validate_response(schema.list_virtual_interfaces, resp, body)
+        return resp, body
 
     def rescue_server(self, server_id, **kwargs):
         """Rescue the provided server."""
@@ -453,4 +460,5 @@
     def get_vnc_console(self, server_id, console_type):
         """Get URL of VNC console."""
         return self.action(server_id, "os-getVNCConsole",
-                           "console", type=console_type)
+                           "console", common_schema.get_vnc_console,
+                           type=console_type)
diff --git a/tempest/services/compute/v3/json/agents_client.py b/tempest/services/compute/v3/json/agents_client.py
index 6893af2..e1c286c 100644
--- a/tempest/services/compute/v3/json/agents_client.py
+++ b/tempest/services/compute/v3/json/agents_client.py
@@ -15,6 +15,7 @@
 import json
 import urllib
 
+from tempest.api_schema.compute.v3 import agents as schema
 from tempest.common import rest_client
 from tempest import config
 
@@ -43,7 +44,9 @@
 
     def delete_agent(self, agent_id):
         """Delete an existing agent build."""
-        return self.delete('os-agents/%s' % str(agent_id))
+        resp, body = self.delete("os-agents/%s" % str(agent_id))
+        self.validate_response(schema.delete_agent, resp, body)
+        return resp, body
 
     def update_agent(self, agent_id, **kwargs):
         """Update an agent build."""
diff --git a/tempest/services/compute/v3/json/flavors_client.py b/tempest/services/compute/v3/json/flavors_client.py
index 6983d54..189fe3f 100644
--- a/tempest/services/compute/v3/json/flavors_client.py
+++ b/tempest/services/compute/v3/json/flavors_client.py
@@ -130,7 +130,8 @@
         """Gets flavor access information given the flavor id."""
         resp, body = self.get('flavors/%s/flavor-access' % flavor_id)
         body = json.loads(body)
-        self.validate_response(schema_access.list_flavor_access, resp, body)
+        self.validate_response(schema_access.add_remove_list_flavor_access,
+                               resp, body)
         return resp, body['flavor_access']
 
     def add_flavor_access(self, flavor_id, tenant_id):
@@ -143,6 +144,8 @@
         post_body = json.dumps(post_body)
         resp, body = self.post('flavors/%s/action' % flavor_id, post_body)
         body = json.loads(body)
+        self.validate_response(schema_access.add_remove_list_flavor_access,
+                               resp, body)
         return resp, body['flavor_access']
 
     def remove_flavor_access(self, flavor_id, tenant_id):
@@ -155,4 +158,6 @@
         post_body = json.dumps(post_body)
         resp, body = self.post('flavors/%s/action' % flavor_id, post_body)
         body = json.loads(body)
+        self.validate_response(schema_access.add_remove_list_flavor_access,
+                               resp, body)
         return resp, body['flavor_access']
diff --git a/tempest/services/compute/v3/json/hosts_client.py b/tempest/services/compute/v3/json/hosts_client.py
index 558d4f7..24d43d0 100644
--- a/tempest/services/compute/v3/json/hosts_client.py
+++ b/tempest/services/compute/v3/json/hosts_client.py
@@ -76,6 +76,7 @@
 
         resp, body = self.get("os-hosts/%s/shutdown" % str(hostname))
         body = json.loads(body)
+        self.validate_response(v3_schema.shutdown_host, resp, body)
         return resp, body['host']
 
     def reboot_host(self, hostname):
@@ -83,4 +84,5 @@
 
         resp, body = self.get("os-hosts/%s/reboot" % str(hostname))
         body = json.loads(body)
+        self.validate_response(v3_schema.reboot_host, resp, body)
         return resp, body['host']
diff --git a/tempest/services/compute/v3/json/quotas_client.py b/tempest/services/compute/v3/json/quotas_client.py
index 783e3a7..37a8906 100644
--- a/tempest/services/compute/v3/json/quotas_client.py
+++ b/tempest/services/compute/v3/json/quotas_client.py
@@ -57,7 +57,7 @@
         self.validate_response(schema.quota_set, resp, body)
         return resp, body['quota_set']
 
-    def update_quota_set(self, tenant_id, force=None,
+    def update_quota_set(self, tenant_id, user_id=None, force=None,
                          metadata_items=None, ram=None, floating_ips=None,
                          fixed_ips=None, key_pairs=None, instances=None,
                          security_group_rules=None, cores=None,
@@ -98,7 +98,13 @@
             post_body['security_groups'] = security_groups
 
         post_body = json.dumps({'quota_set': post_body})
-        resp, body = self.put('os-quota-sets/%s' % str(tenant_id), post_body)
+
+        if user_id:
+            resp, body = self.put('os-quota-sets/%s?user_id=%s' %
+                                  (str(tenant_id), str(user_id)), post_body)
+        else:
+            resp, body = self.put('os-quota-sets/%s' % str(tenant_id),
+                                  post_body)
 
         body = json.loads(body)
         self.validate_response(schema.quota_set, resp, body)
diff --git a/tempest/services/compute/v3/json/servers_client.py b/tempest/services/compute/v3/json/servers_client.py
index 6a0d9b2..caeb315 100644
--- a/tempest/services/compute/v3/json/servers_client.py
+++ b/tempest/services/compute/v3/json/servers_client.py
@@ -410,19 +410,19 @@
                               str(server_id))
         return resp, json.loads(body)
 
-    def list_instance_actions(self, server_id):
+    def list_server_actions(self, server_id):
         """List the provided server action."""
-        resp, body = self.get("servers/%s/os-instance-actions" %
+        resp, body = self.get("servers/%s/os-server-actions" %
                               str(server_id))
         body = json.loads(body)
-        return resp, body['instance_actions']
+        return resp, body['server_actions']
 
-    def get_instance_action(self, server_id, request_id):
+    def get_server_action(self, server_id, request_id):
         """Returns the action details of the provided server."""
-        resp, body = self.get("servers/%s/os-instance-actions/%s" %
+        resp, body = self.get("servers/%s/os-server-actions/%s" %
                               (str(server_id), str(request_id)))
         body = json.loads(body)
-        return resp, body['instance_action']
+        return resp, body['server_action']
 
     def force_delete_server(self, server_id, **kwargs):
         """Force delete a server."""
@@ -442,6 +442,7 @@
         resp, body = self.post('servers/%s/action' % str(server_id),
                                post_body)
         body = json.loads(body)
+        self.validate_response(common_schema.get_vnc_console, resp, body)
         return resp, body['console']
 
     def reset_network(self, server_id, **kwargs):
diff --git a/tempest/services/compute/xml/aggregates_client.py b/tempest/services/compute/xml/aggregates_client.py
index b5f7678..9c2d4aa 100644
--- a/tempest/services/compute/xml/aggregates_client.py
+++ b/tempest/services/compute/xml/aggregates_client.py
@@ -61,9 +61,11 @@
 
     def create_aggregate(self, name, availability_zone=None):
         """Creates a new aggregate."""
-        post_body = xml_utils.Element("aggregate",
-                                      name=name,
-                                      availability_zone=availability_zone)
+        if availability_zone is not None:
+            post_body = xml_utils.Element("aggregate", name=name,
+                                          availability_zone=availability_zone)
+        else:
+            post_body = xml_utils.Element("aggregate", name=name)
         resp, body = self.post('os-aggregates',
                                str(xml_utils.Document(post_body)))
         aggregate = self._format_aggregate(etree.fromstring(body))
@@ -71,9 +73,11 @@
 
     def update_aggregate(self, aggregate_id, name, availability_zone=None):
         """Update a aggregate."""
-        put_body = xml_utils.Element("aggregate",
-                                     name=name,
-                                     availability_zone=availability_zone)
+        if availability_zone is not None:
+            put_body = xml_utils.Element("aggregate", name=name,
+                                         availability_zone=availability_zone)
+        else:
+            put_body = xml_utils.Element("aggregate", name=name)
         resp, body = self.put('os-aggregates/%s' % str(aggregate_id),
                               str(xml_utils.Document(put_body)))
         aggregate = self._format_aggregate(etree.fromstring(body))
diff --git a/tempest/services/compute/xml/quotas_client.py b/tempest/services/compute/xml/quotas_client.py
index 8a521ab..5502fcc 100644
--- a/tempest/services/compute/xml/quotas_client.py
+++ b/tempest/services/compute/xml/quotas_client.py
@@ -61,8 +61,8 @@
         body = self._format_quota(body)
         return resp, body
 
-    def update_quota_set(self, tenant_id, force=None,
-                         injected_file_content_bytes=None,
+    def update_quota_set(self, tenant_id, user_id=None,
+                         force=None, injected_file_content_bytes=None,
                          metadata_items=None, ram=None, floating_ips=None,
                          fixed_ips=None, key_pairs=None, instances=None,
                          security_group_rules=None, injected_files=None,
@@ -115,8 +115,14 @@
         if security_groups is not None:
             post_body.add_attr('security_groups', security_groups)
 
-        resp, body = self.put('os-quota-sets/%s' % str(tenant_id),
-                              str(xml_utils.Document(post_body)))
+        if user_id:
+            resp, body = self.put('os-quota-sets/%s?user_id=%s' %
+                                  (str(tenant_id), str(user_id)),
+                                  str(xml_utils.Document(post_body)))
+        else:
+            resp, body = self.put('os-quota-sets/%s' % str(tenant_id),
+                                  str(xml_utils.Document(post_body)))
+
         body = xml_utils.xml_to_json(etree.fromstring(body))
         body = self._format_quota(body)
         return resp, body
diff --git a/tempest/services/identity/json/identity_client.py b/tempest/services/identity/json/identity_client.py
index fe176bf..55239f7 100644
--- a/tempest/services/identity/json/identity_client.py
+++ b/tempest/services/identity/json/identity_client.py
@@ -275,13 +275,20 @@
 
         return resp, body['access']
 
-    def request(self, method, url, headers=None, body=None):
+    def request(self, method, url, extra_headers=False, headers=None,
+                body=None):
         """A simple HTTP request interface."""
         if headers is None:
             # Always accept 'json', for TokenClientXML too.
             # Because XML response is not easily
             # converted to the corresponding JSON one
             headers = self.get_headers(accept_type="json")
+        elif extra_headers:
+            try:
+                headers.update(self.get_headers(accept_type="json"))
+            except (ValueError, TypeError):
+                headers = self.get_headers(accept_type="json")
+
         resp, resp_body = self.http_obj.request(url, method,
                                                 headers=headers, body=body)
         self._log_request(method, url, resp)
diff --git a/tempest/services/identity/v3/json/identity_client.py b/tempest/services/identity/v3/json/identity_client.py
index 4b530f1..6829333 100644
--- a/tempest/services/identity/v3/json/identity_client.py
+++ b/tempest/services/identity/v3/json/identity_client.py
@@ -163,6 +163,12 @@
         body = json.loads(body)
         return resp, body['role']
 
+    def list_roles(self):
+        """Get the list of Roles."""
+        resp, body = self.get("roles")
+        body = json.loads(body)
+        return resp, body['roles']
+
     def update_role(self, name, role_id):
         """Create a Role."""
         post_body = {
@@ -515,13 +521,20 @@
         resp, body = self.post(self.auth_url, body=body)
         return resp, body
 
-    def request(self, method, url, headers=None, body=None):
+    def request(self, method, url, extra_headers=False, headers=None,
+                body=None):
         """A simple HTTP request interface."""
         if headers is None:
             # Always accept 'json', for xml token client too.
             # Because XML response is not easily
             # converted to the corresponding JSON one
             headers = self.get_headers(accept_type="json")
+        elif extra_headers:
+            try:
+                headers.update(self.get_headers(accept_type="json"))
+            except (ValueError, TypeError):
+                headers = self.get_headers(accept_type="json")
+
         resp, resp_body = self.http_obj.request(url, method,
                                                 headers=headers, body=body)
         self._log_request(method, url, resp)
diff --git a/tempest/services/identity/v3/xml/endpoints_client.py b/tempest/services/identity/v3/xml/endpoints_client.py
index 93dc3dc..6490e34 100644
--- a/tempest/services/identity/v3/xml/endpoints_client.py
+++ b/tempest/services/identity/v3/xml/endpoints_client.py
@@ -46,12 +46,19 @@
         json = common.xml_to_json(body)
         return json
 
-    def request(self, method, url, headers=None, body=None, wait=None):
+    def request(self, method, url, extra_headers=False, headers=None,
+                body=None, wait=None):
         """Overriding the existing HTTP request in super class RestClient."""
+        if extra_headers:
+            try:
+                headers.update(self.get_headers())
+            except (ValueError, TypeError):
+                headers = self.get_headers()
         dscv = CONF.identity.disable_ssl_certificate_validation
         self.http_obj = http.ClosingHttp(
             disable_ssl_certificate_validation=dscv)
         return super(EndPointClientXML, self).request(method, url,
+                                                      extra_headers,
                                                       headers=headers,
                                                       body=body)
 
diff --git a/tempest/services/identity/v3/xml/identity_client.py b/tempest/services/identity/v3/xml/identity_client.py
index c49f361..35295d7 100644
--- a/tempest/services/identity/v3/xml/identity_client.py
+++ b/tempest/services/identity/v3/xml/identity_client.py
@@ -217,6 +217,12 @@
         body = self._parse_body(etree.fromstring(body))
         return resp, body
 
+    def list_roles(self):
+        """Get the list of Roles."""
+        resp, body = self.get("roles")
+        body = self._parse_roles(etree.fromstring(body))
+        return resp, body
+
     def update_role(self, name, role_id):
         """Updates a Role."""
         post_body = common.Element("role",
@@ -516,13 +522,19 @@
         resp, body = self.post(self.auth_url, body=str(common.Document(auth)))
         return resp, body
 
-    def request(self, method, url, headers=None, body=None):
+    def request(self, method, url, extra_headers=False, headers=None,
+                body=None):
         """A simple HTTP request interface."""
         if headers is None:
             # Always accept 'json', for xml token client too.
             # Because XML response is not easily
             # converted to the corresponding JSON one
             headers = self.get_headers(accept_type="json")
+        elif extra_headers:
+            try:
+                headers.update(self.get_headers(accept_type="json"))
+            except (ValueError, TypeError):
+                headers = self.get_headers(accept_type="json")
         resp, resp_body = self.http_obj.request(url, method,
                                                 headers=headers, body=body)
         self._log_request(method, url, resp)
diff --git a/tempest/services/identity/v3/xml/policy_client.py b/tempest/services/identity/v3/xml/policy_client.py
index e903089..73d831b 100644
--- a/tempest/services/identity/v3/xml/policy_client.py
+++ b/tempest/services/identity/v3/xml/policy_client.py
@@ -46,12 +46,19 @@
         json = common.xml_to_json(body)
         return json
 
-    def request(self, method, url, headers=None, body=None, wait=None):
+    def request(self, method, url, extra_headers=False, headers=None,
+                body=None, wait=None):
         """Overriding the existing HTTP request in super class RestClient."""
+        if extra_headers:
+            try:
+                headers.update(self.get_headers())
+            except (ValueError, TypeError):
+                headers = self.get_headers()
         dscv = CONF.identity.disable_ssl_certificate_validation
         self.http_obj = http.ClosingHttp(
             disable_ssl_certificate_validation=dscv)
         return super(PolicyClientXML, self).request(method, url,
+                                                    extra_headers,
                                                     headers=headers,
                                                     body=body)
 
diff --git a/tempest/services/network/xml/network_client.py b/tempest/services/network/xml/network_client.py
index 0945b09..50a1954 100644
--- a/tempest/services/network/xml/network_client.py
+++ b/tempest/services/network/xml/network_client.py
@@ -24,7 +24,7 @@
     # list of plurals used for xml serialization
     PLURALS = ['dns_nameservers', 'host_routes', 'allocation_pools',
                'fixed_ips', 'extensions', 'extra_dhcp_opts', 'pools',
-               'health_monitors', 'vips']
+               'health_monitors', 'vips', 'members']
 
     def get_rest_client(self, auth_provider):
         rc = rest_client.RestClient(auth_provider)
@@ -257,6 +257,38 @@
         body = _root_tag_fetcher_and_xml_to_json_parse(body)
         return resp, body
 
+    def create_vpnservice(self, subnet_id, router_id, **kwargs):
+        uri = '%s/vpn/vpnservices' % (self.uri_prefix)
+        vpnservice = common.Element("vpnservice")
+        p1 = common.Element("subnet_id", subnet_id)
+        p2 = common.Element("router_id", router_id)
+        vpnservice.append(p1)
+        vpnservice.append(p2)
+        common.deep_dict_to_xml(vpnservice, kwargs)
+        resp, body = self.post(uri, str(common.Document(vpnservice)))
+        body = _root_tag_fetcher_and_xml_to_json_parse(body)
+        return resp, body
+
+    def create_ikepolicy(self, name, **kwargs):
+        uri = '%s/vpn/ikepolicies' % (self.uri_prefix)
+        ikepolicy = common.Element("ikepolicy")
+        p1 = common.Element("name", name)
+        ikepolicy.append(p1)
+        common.deep_dict_to_xml(ikepolicy, kwargs)
+        resp, body = self.post(uri, str(common.Document(ikepolicy)))
+        body = _root_tag_fetcher_and_xml_to_json_parse(body)
+        return resp, body
+
+    def create_ipsecpolicy(self, name, **kwargs):
+        uri = '%s/vpn/ipsecpolicies' % (self.uri_prefix)
+        ipsecpolicy = common.Element("ipsecpolicy")
+        p1 = common.Element("name", name)
+        ipsecpolicy.append(p1)
+        common.deep_dict_to_xml(ipsecpolicy, kwargs)
+        resp, body = self.post(uri, str(common.Document(ipsecpolicy)))
+        body = _root_tag_fetcher_and_xml_to_json_parse(body)
+        return resp, body
+
 
 def _root_tag_fetcher_and_xml_to_json_parse(xml_returned_body):
     body = ET.fromstring(xml_returned_body)
diff --git a/tempest/services/object_storage/account_client.py b/tempest/services/object_storage/account_client.py
index 6e7910e..a0506f2 100644
--- a/tempest/services/object_storage/account_client.py
+++ b/tempest/services/object_storage/account_client.py
@@ -162,11 +162,17 @@
         self.service = CONF.object_storage.catalog_type
         self.format = 'json'
 
-    def request(self, method, url, headers=None, body=None):
+    def request(self, method, url, extra_headers=False, headers=None,
+                body=None):
         """A simple HTTP request interface."""
         self.http_obj = http.ClosingHttp()
         if headers is None:
             headers = {}
+        elif extra_headers:
+            try:
+                headers.update(self.get_headers())
+            except (ValueError, TypeError):
+                headers = {}
 
         # Authorize the request
         req_url, req_headers, req_body = self.auth_provider.auth_request(
diff --git a/tempest/services/object_storage/object_client.py b/tempest/services/object_storage/object_client.py
index 49f7f49..53a3325 100644
--- a/tempest/services/object_storage/object_client.py
+++ b/tempest/services/object_storage/object_client.py
@@ -29,12 +29,16 @@
 
         self.service = CONF.object_storage.catalog_type
 
-    def create_object(self, container, object_name, data, params=None):
+    def create_object(self, container, object_name, data,
+                      params=None, metadata=None):
         """Create storage object."""
 
         headers = self.get_headers()
         if not data:
             headers['content-length'] = '0'
+        if metadata:
+            for key in metadata:
+                headers[str(key)] = metadata[key]
         url = "%s/%s" % (str(container), str(object_name))
         if params:
             url += '?%s' % urllib.urlencode(params)
@@ -146,13 +150,19 @@
         self.service = CONF.object_storage.catalog_type
         self.format = 'json'
 
-    def request(self, method, url, headers=None, body=None):
+    def request(self, method, url, extra_headers=False, headers=None,
+                body=None):
         """A simple HTTP request interface."""
         dscv = CONF.identity.disable_ssl_certificate_validation
         self.http_obj = http.ClosingHttp(
             disable_ssl_certificate_validation=dscv)
         if headers is None:
             headers = {}
+        elif extra_headers:
+            try:
+                headers.update(self.get_headers())
+            except (ValueError, TypeError):
+                headers = {}
 
         # Authorize the request
         req_url, req_headers, req_body = self.auth_provider.auth_request(
diff --git a/tempest/services/orchestration/json/orchestration_client.py b/tempest/services/orchestration/json/orchestration_client.py
index 113003c..2311bdd 100644
--- a/tempest/services/orchestration/json/orchestration_client.py
+++ b/tempest/services/orchestration/json/orchestration_client.py
@@ -154,7 +154,8 @@
                 if resource_status == status:
                     return
                 if fail_regexp.search(resource_status):
-                    raise exceptions.StackBuildErrorException(
+                    raise exceptions.StackResourceBuildErrorException(
+                        resource_name=resource_name,
                         stack_identifier=stack_identifier,
                         resource_status=resource_status,
                         resource_status_reason=body['resource_status_reason'])
diff --git a/tempest/tests/test_commands.py b/tempest/tests/test_commands.py
new file mode 100644
index 0000000..bdb9269
--- /dev/null
+++ b/tempest/tests/test_commands.py
@@ -0,0 +1,87 @@
+# Copyright 2014 NEC Corporation.  All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import mock
+import subprocess
+
+from tempest.common import commands
+from tempest.tests import base
+
+
+class TestCommands(base.TestCase):
+
+    def setUp(self):
+        super(TestCommands, self).setUp()
+        self.subprocess_args = {'stdout': subprocess.PIPE,
+                                'stderr': subprocess.STDOUT}
+
+    @mock.patch('subprocess.Popen')
+    def test_ip_addr_raw(self, mock):
+        expected = ['/usr/bin/sudo', '-n', 'ip', 'a']
+        commands.ip_addr_raw()
+        mock.assert_called_once_with(expected, **self.subprocess_args)
+
+    @mock.patch('subprocess.Popen')
+    def test_ip_route_raw(self, mock):
+        expected = ['/usr/bin/sudo', '-n', 'ip', 'r']
+        commands.ip_route_raw()
+        mock.assert_called_once_with(expected, **self.subprocess_args)
+
+    @mock.patch('subprocess.Popen')
+    def test_ip_ns_raw(self, mock):
+        expected = ['/usr/bin/sudo', '-n', 'ip', 'netns', 'list']
+        commands.ip_ns_raw()
+        mock.assert_called_once_with(expected, **self.subprocess_args)
+
+    @mock.patch('subprocess.Popen')
+    def test_iptables_raw(self, mock):
+        table = 'filter'
+        expected = ['/usr/bin/sudo', '-n', 'iptables', '-v', '-S', '-t',
+                    '%s' % table]
+        commands.iptables_raw(table)
+        mock.assert_called_once_with(expected, **self.subprocess_args)
+
+    @mock.patch('subprocess.Popen')
+    def test_ip_ns_list(self, mock):
+        expected = ['/usr/bin/sudo', '-n', 'ip', 'netns', 'list']
+        commands.ip_ns_list()
+        mock.assert_called_once_with(expected, **self.subprocess_args)
+
+    @mock.patch('subprocess.Popen')
+    def test_ip_ns_addr(self, mock):
+        ns_list = commands.ip_ns_list()
+        for ns in ns_list:
+            expected = ['/usr/bin/sudo', '-n', 'ip', 'netns', 'exec', ns,
+                        'ip', 'a']
+            commands.ip_ns_addr(ns)
+            mock.assert_called_once_with(expected, **self.subprocess_args)
+
+    @mock.patch('subprocess.Popen')
+    def test_ip_ns_route(self, mock):
+        ns_list = commands.ip_ns_list()
+        for ns in ns_list:
+            expected = ['/usr/bin/sudo', '-n', 'ip', 'netns', 'exec', ns,
+                        'ip', 'r']
+            commands.ip_ns_route(ns)
+            mock.assert_called_once_with(expected, **self.subprocess_args)
+
+    @mock.patch('subprocess.Popen')
+    def test_iptables_ns(self, mock):
+        table = 'filter'
+        ns_list = commands.ip_ns_list()
+        for ns in ns_list:
+            expected = ['/usr/bin/sudo', '-n', 'ip', 'netns', 'exec', ns,
+                        'iptables', '-v', '-S', '-t', table]
+            commands.iptables_ns(ns, table)
+            mock.assert_called_once_with(expected, **self.subprocess_args)
diff --git a/tempest/tests/test_rest_client.py b/tempest/tests/test_rest_client.py
index cfbb37d..64ad3bc 100644
--- a/tempest/tests/test_rest_client.py
+++ b/tempest/tests/test_rest_client.py
@@ -139,6 +139,102 @@
         self._verify_headers(resp)
 
 
+class TestRestClientUpdateHeaders(BaseRestClientTestClass):
+    def setUp(self):
+        self.fake_http = fake_http.fake_httplib2()
+        super(TestRestClientUpdateHeaders, self).setUp()
+        self.useFixture(mockpatch.PatchObject(self.rest_client,
+                                              '_error_checker'))
+        self.headers = {'X-Configuration-Session': 'session_id'}
+
+    def test_post_update_headers(self):
+        __, return_dict = self.rest_client.post(self.url, {},
+                                                extra_headers=True,
+                                                headers=self.headers)
+
+        self.assertDictContainsSubset(
+            {'X-Configuration-Session': 'session_id',
+             'Content-Type': 'application/json',
+             'Accept': 'application/json'},
+            return_dict['headers']
+        )
+
+    def test_get_update_headers(self):
+        __, return_dict = self.rest_client.get(self.url,
+                                               extra_headers=True,
+                                               headers=self.headers)
+
+        self.assertDictContainsSubset(
+            {'X-Configuration-Session': 'session_id',
+             'Content-Type': 'application/json',
+             'Accept': 'application/json'},
+            return_dict['headers']
+        )
+
+    def test_delete_update_headers(self):
+        __, return_dict = self.rest_client.delete(self.url,
+                                                  extra_headers=True,
+                                                  headers=self.headers)
+
+        self.assertDictContainsSubset(
+            {'X-Configuration-Session': 'session_id',
+             'Content-Type': 'application/json',
+             'Accept': 'application/json'},
+            return_dict['headers']
+        )
+
+    def test_patch_update_headers(self):
+        __, return_dict = self.rest_client.patch(self.url, {},
+                                                 extra_headers=True,
+                                                 headers=self.headers)
+
+        self.assertDictContainsSubset(
+            {'X-Configuration-Session': 'session_id',
+             'Content-Type': 'application/json',
+             'Accept': 'application/json'},
+            return_dict['headers']
+        )
+
+    def test_put_update_headers(self):
+        __, return_dict = self.rest_client.put(self.url, {},
+                                               extra_headers=True,
+                                               headers=self.headers)
+
+        self.assertDictContainsSubset(
+            {'X-Configuration-Session': 'session_id',
+             'Content-Type': 'application/json',
+             'Accept': 'application/json'},
+            return_dict['headers']
+        )
+
+    def test_head_update_headers(self):
+        self.useFixture(mockpatch.PatchObject(self.rest_client,
+                                              'response_checker'))
+
+        __, return_dict = self.rest_client.head(self.url,
+                                                extra_headers=True,
+                                                headers=self.headers)
+
+        self.assertDictContainsSubset(
+            {'X-Configuration-Session': 'session_id',
+             'Content-Type': 'application/json',
+             'Accept': 'application/json'},
+            return_dict['headers']
+        )
+
+    def test_copy_update_headers(self):
+        __, return_dict = self.rest_client.copy(self.url,
+                                                extra_headers=True,
+                                                headers=self.headers)
+
+        self.assertDictContainsSubset(
+            {'X-Configuration-Session': 'session_id',
+             'Content-Type': 'application/json',
+             'Accept': 'application/json'},
+            return_dict['headers']
+        )
+
+
 class TestRestClientHeadersXML(TestRestClientHeadersJSON):
     TYPE = "xml"
 
diff --git a/tools/check_logs.py b/tools/check_logs.py
index b5b1780..bc4eaca 100755
--- a/tools/check_logs.py
+++ b/tools/check_logs.py
@@ -46,7 +46,6 @@
     'n-api',
     'n-cpu',
     'n-net',
-    'n-sch',
     'q-agt',
     'q-dhcp',
     'q-lbaas',
diff --git a/tools/verify_tempest_config.py b/tools/verify_tempest_config.py
index aa92c0b..30785c4 100755
--- a/tools/verify_tempest_config.py
+++ b/tools/verify_tempest_config.py
@@ -16,6 +16,7 @@
 
 import json
 import sys
+import urlparse
 
 import httplib2
 
@@ -39,19 +40,37 @@
             not CONF.image_feature_enabled.api_v2))
 
 
-def verify_nova_api_versions(os):
-    # Check nova api versions - only get base URL without PATH
-    os.servers_client.skip_path = True
-    # The nova base endpoint url includes the version but to get the versions
-    # list the unversioned endpoint is needed
-    v2_endpoint = os.servers_client.base_url
-    v2_endpoint_parts = v2_endpoint.split('/')
-    endpoint = v2_endpoint_parts[0] + '//' + v2_endpoint_parts[2]
+def _get_api_versions(os, service):
+    client_dict = {
+        'nova': os.servers_client,
+        'keystone': os.identity_client,
+    }
+    client_dict[service].skip_path()
+    endpoint_parts = urlparse.urlparse(client_dict[service])
+    endpoint = endpoint_parts.scheme + '//' + endpoint_parts.netloc
     __, body = RAW_HTTP.request(endpoint, 'GET')
+    client_dict[service].reset_path()
     body = json.loads(body)
-    # Restore full base_url
-    os.servers_client.skip_path = False
-    versions = map(lambda x: x['id'], body['versions'])
+    if service == 'keystone':
+        versions = map(lambda x: x['id'], body['versions']['values'])
+    else:
+        versions = map(lambda x: x['id'], body['versions'])
+    return versions
+
+
+def verify_keystone_api_versions(os):
+    # Check keystone api versions
+    versions = _get_api_versions(os, 'keystone')
+    if CONF.identity_feature_enabled.api_v2 != ('v2.0' in versions):
+        print('Config option identity api_v2 should be change to %s' % (
+            not CONF.identity_feature_enabled.api_v2))
+    if CONF.identity_feature_enabled.api_v3 != ('v3.0' in versions):
+        print('Config option identity api_v3 should be change to %s' % (
+            not CONF.identity_feature_enabled.api_v3))
+
+
+def verify_nova_api_versions(os):
+    versions = _get_api_versions(os, 'nova')
     if CONF.compute_feature_enabled.api_v3 != ('v3.0' in versions):
         print('Config option compute api_v3 should be change to: %s' % (
               not CONF.compute_feature_enabled.api_v3))
@@ -197,6 +216,7 @@
         elif service not in services:
             continue
         results = verify_extensions(os, service, results)
+    verify_keystone_api_versions(os)
     verify_glance_api_versions(os)
     verify_nova_api_versions(os)
     display_results(results)