Merge "Refactor network client: add create_ and update_ methods"
diff --git a/.testr.conf b/.testr.conf
index c25ebec..abaf14a 100644
--- a/.testr.conf
+++ b/.testr.conf
@@ -2,8 +2,7 @@
 test_command=OS_STDOUT_CAPTURE=${OS_STDOUT_CAPTURE:-1} \
              OS_STDERR_CAPTURE=${OS_STDERR_CAPTURE:-1} \
              OS_TEST_TIMEOUT=${OS_TEST_TIMEOUT:-500} \
-             OS_TEST_PATH=${OS_TEST_PATH:-./tempest} \
-             ${PYTHON:-python} -m subunit.run discover -t ./ $OS_TEST_PATH $LISTOPT $IDOPTION
+             ${PYTHON:-python} -m subunit.run discover -t ./ ${OS_TEST_PATH:-./tempest/test_discover} $LISTOPT $IDOPTION
 test_id_option=--load-list $IDFILE
 test_list_option=--list
 group_regex=([^\.]*\.)*
diff --git a/README.rst b/README.rst
index 96f6e4c..4098e32 100644
--- a/README.rst
+++ b/README.rst
@@ -67,7 +67,7 @@
 
 To run one single test  ::
 
-    $> testr run --parallel tempest.api.compute.servers.test_server_actions.ServerActionsTestJSON.test_rebuild_nonexistent_server
+    $> testr run --parallel tempest.api.compute.servers.test_servers_negative.ServersNegativeTestJSON.test_reboot_non_existent_server
 
 Alternatively, you can use the run_tests.sh script which will create a venv
 and run the tests or use tox to do the same.
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 607ba8b..e7145e7 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -234,6 +234,9 @@
 # indicates every extension is enabled (list value)
 #api_extensions=all
 
+# Is the v1 volume API enabled (boolean value)
+#api_v1=true
+
 
 [image-feature-enabled]
 
diff --git a/tempest/api/compute/admin/test_hosts_negative.py b/tempest/api/compute/admin/test_hosts_negative.py
index 6b24e72..dbf7967 100644
--- a/tempest/api/compute/admin/test_hosts_negative.py
+++ b/tempest/api/compute/admin/test_hosts_negative.py
@@ -17,7 +17,7 @@
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
 from tempest import exceptions
-from tempest.test import attr
+from tempest import test
 
 
 class HostsAdminNegativeTestJSON(base.BaseV2ComputeAdminTest):
@@ -41,18 +41,18 @@
         hostname = hosts[0]['host_name']
         return hostname
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_list_hosts_with_non_admin_user(self):
         self.assertRaises(exceptions.Unauthorized,
                           self.non_admin_client.list_hosts)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_show_host_detail_with_nonexistent_hostname(self):
         nonexitent_hostname = data_utils.rand_name('rand_hostname')
         self.assertRaises(exceptions.NotFound,
                           self.client.show_host_detail, nonexitent_hostname)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_show_host_detail_with_non_admin_user(self):
         hostname = self._get_host_name()
 
@@ -60,7 +60,7 @@
                           self.non_admin_client.show_host_detail,
                           hostname)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_update_host_with_non_admin_user(self):
         hostname = self._get_host_name()
 
@@ -68,7 +68,8 @@
                           self.non_admin_client.update_host,
                           hostname)
 
-    @attr(type=['negative', 'gate'])
+    @test.skip_because(bug="1261964", interface="xml")
+    @test.attr(type=['negative', 'gate'])
     def test_update_host_with_extra_param(self):
         # only 'status' and 'maintenance_mode' are the valid params.
         hostname = self._get_host_name()
@@ -80,7 +81,7 @@
                           maintenance_mode='enable',
                           param='XXX')
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_update_host_with_invalid_status(self):
         # 'status' can only be 'enable' or 'disable'
         hostname = self._get_host_name()
@@ -91,7 +92,7 @@
                           status='invalid',
                           maintenance_mode='enable')
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_update_host_with_invalid_maintenance_mode(self):
         # 'maintenance_mode' can only be 'enable' or 'disable'
         hostname = self._get_host_name()
@@ -102,7 +103,7 @@
                           status='enable',
                           maintenance_mode='invalid')
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_update_host_without_param(self):
         # 'status' or 'maintenance_mode' needed for host update
         hostname = self._get_host_name()
@@ -111,7 +112,7 @@
                           self.client.update_host,
                           hostname)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_update_nonexistent_host(self):
         nonexitent_hostname = data_utils.rand_name('rand_hostname')
 
@@ -121,7 +122,7 @@
                           status='enable',
                           maintenance_mode='enable')
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_startup_nonexistent_host(self):
         nonexitent_hostname = data_utils.rand_name('rand_hostname')
 
@@ -129,7 +130,7 @@
                           self.client.startup_host,
                           nonexitent_hostname)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_startup_host_with_non_admin_user(self):
         hostname = self._get_host_name()
 
@@ -137,7 +138,7 @@
                           self.non_admin_client.startup_host,
                           hostname)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_shutdown_nonexistent_host(self):
         nonexitent_hostname = data_utils.rand_name('rand_hostname')
 
@@ -145,7 +146,7 @@
                           self.client.shutdown_host,
                           nonexitent_hostname)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_shutdown_host_with_non_admin_user(self):
         hostname = self._get_host_name()
 
@@ -153,7 +154,7 @@
                           self.non_admin_client.shutdown_host,
                           hostname)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_reboot_nonexistent_host(self):
         nonexitent_hostname = data_utils.rand_name('rand_hostname')
 
@@ -161,7 +162,7 @@
                           self.client.reboot_host,
                           nonexitent_hostname)
 
-    @attr(type=['negative', 'gate'])
+    @test.attr(type=['negative', 'gate'])
     def test_reboot_host_with_non_admin_user(self):
         hostname = self._get_host_name()
 
diff --git a/tempest/api/compute/admin/test_hypervisor.py b/tempest/api/compute/admin/test_hypervisor.py
index ef4f51f..bd431d4 100644
--- a/tempest/api/compute/admin/test_hypervisor.py
+++ b/tempest/api/compute/admin/test_hypervisor.py
@@ -38,24 +38,27 @@
         self.assertEqual(200, resp.status)
         return hypers
 
+    def assertHypervisors(self, hypers):
+        self.assertTrue(len(hypers) > 0, "No hypervisors found: %s" % hypers)
+
     @attr(type='gate')
     def test_get_hypervisor_list(self):
         # List of hypervisor and available hypervisors hostname
         hypers = self._list_hypervisors()
-        self.assertTrue(len(hypers) > 0)
+        self.assertHypervisors(hypers)
 
     @attr(type='gate')
     def test_get_hypervisor_list_details(self):
         # Display the details of the all hypervisor
         resp, hypers = self.client.get_hypervisor_list_details()
         self.assertEqual(200, resp.status)
-        self.assertTrue(len(hypers) > 0)
+        self.assertHypervisors(hypers)
 
     @attr(type='gate')
     def test_get_hypervisor_show_details(self):
         # Display the details of the specified hypervisor
         hypers = self._list_hypervisors()
-        self.assertTrue(len(hypers) > 0)
+        self.assertHypervisors(hypers)
 
         resp, details = (self.client.
                          get_hypervisor_show_details(hypers[0]['id']))
@@ -68,7 +71,7 @@
     def test_get_hypervisor_show_servers(self):
         # Show instances about the specific hypervisors
         hypers = self._list_hypervisors()
-        self.assertTrue(len(hypers) > 0)
+        self.assertHypervisors(hypers)
 
         hostname = hypers[0]['hypervisor_hostname']
         resp, hypervisors = self.client.get_hypervisor_servers(hostname)
@@ -87,18 +90,29 @@
         # Verify that GET shows the specified hypervisor uptime
         hypers = self._list_hypervisors()
 
-        resp, uptime = self.client.get_hypervisor_uptime(hypers[0]['id'])
-        self.assertEqual(200, resp.status)
-        self.assertTrue(len(uptime) > 0)
+        has_valid_uptime = False
+        for hyper in hypers:
+            # because hypervisors might be disabled, this loops looking
+            # for any good hit.
+            try:
+                resp, uptime = self.client.get_hypervisor_uptime(hyper['id'])
+                if (resp.status == 200) and (len(uptime) > 0):
+                    has_valid_uptime = True
+                    break
+            except Exception:
+                pass
+        self.assertTrue(
+            has_valid_uptime,
+            "None of the hypervisors had a valid uptime: %s" % hypers)
 
     @attr(type='gate')
     def test_search_hypervisor(self):
         hypers = self._list_hypervisors()
-        self.assertTrue(len(hypers) > 0)
+        self.assertHypervisors(hypers)
         resp, hypers = self.client.search_hypervisor(
             hypers[0]['hypervisor_hostname'])
         self.assertEqual(200, resp.status)
-        self.assertTrue(len(hypers) > 0)
+        self.assertHypervisors(hypers)
 
 
 class HypervisorAdminTestXML(HypervisorAdminTestJSON):
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index 9cb425a..73d274c 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -260,6 +260,7 @@
 
         cls.servers_client = cls.os.servers_v3_client
         cls.images_client = cls.os.image_client
+        cls.flavors_client = cls.os.flavors_v3_client
         cls.services_client = cls.os.services_v3_client
         cls.extensions_client = cls.os.extensions_v3_client
         cls.availability_zone_client = cls.os.availability_zone_v3_client
@@ -268,6 +269,7 @@
         cls.tenant_usages_client = cls.os.tenant_usages_v3_client
         cls.volumes_client = cls.os.volumes_client
         cls.certificates_client = cls.os.certificates_v3_client
+        cls.keypairs_client = cls.os.keypairs_v3_client
 
     @classmethod
     def create_image_from_server(cls, server_id, **kwargs):
@@ -332,3 +334,4 @@
             cls.os_adm.availability_zone_v3_client
         cls.hypervisor_admin_client = cls.os_adm.hypervisor_v3_client
         cls.tenant_usages_admin_client = cls.os_adm.tenant_usages_v3_client
+        cls.flavors_admin_client = cls.os_adm.flavors_v3_client
diff --git a/tempest/api/compute/images/test_image_metadata.py b/tempest/api/compute/images/test_image_metadata.py
index 618abe2..76e0cae 100644
--- a/tempest/api/compute/images/test_image_metadata.py
+++ b/tempest/api/compute/images/test_image_metadata.py
@@ -17,7 +17,6 @@
 
 from tempest.api.compute import base
 from tempest.common.utils import data_utils
-from tempest import exceptions
 from tempest.test import attr
 
 
@@ -110,49 +109,6 @@
         expected = {'key2': 'value2'}
         self.assertEqual(expected, resp_metadata)
 
-    @attr(type=['negative', 'gate'])
-    def test_list_nonexistant_image_metadata(self):
-        # Negative test: List on nonexistant image
-        # metadata should not happen
-        self.assertRaises(exceptions.NotFound, self.client.list_image_metadata,
-                          999)
-
-    @attr(type=['negative', 'gate'])
-    def test_update_nonexistant_image_metadata(self):
-        # Negative test:An update should not happen for a non-existent image
-        meta = {'key1': 'alt1', 'key2': 'alt2'}
-        self.assertRaises(exceptions.NotFound,
-                          self.client.update_image_metadata, 999, meta)
-
-    @attr(type=['negative', 'gate'])
-    def test_get_nonexistant_image_metadata_item(self):
-        # Negative test: Get on non-existent image should not happen
-        self.assertRaises(exceptions.NotFound,
-                          self.client.get_image_metadata_item, 999, 'key2')
-
-    @attr(type=['negative', 'gate'])
-    def test_set_nonexistant_image_metadata(self):
-        # Negative test: Metadata should not be set to a non-existent image
-        meta = {'key1': 'alt1', 'key2': 'alt2'}
-        self.assertRaises(exceptions.NotFound, self.client.set_image_metadata,
-                          999, meta)
-
-    @attr(type=['negative', 'gate'])
-    def test_set_nonexistant_image_metadata_item(self):
-        # Negative test: Metadata item should not be set to a
-        # nonexistant image
-        meta = {'key1': 'alt'}
-        self.assertRaises(exceptions.NotFound,
-                          self.client.set_image_metadata_item, 999, 'key1',
-                          meta)
-
-    @attr(type=['negative', 'gate'])
-    def test_delete_nonexistant_image_metadata_item(self):
-        # Negative test: Shouldn't be able to delete metadata
-        # item from non-existent image
-        self.assertRaises(exceptions.NotFound,
-                          self.client.delete_image_metadata_item, 999, 'key1')
-
 
 class ImagesMetadataTestXML(ImagesMetadataTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/images/test_image_metadata_negative.py b/tempest/api/compute/images/test_image_metadata_negative.py
new file mode 100644
index 0000000..1767e5d
--- /dev/null
+++ b/tempest/api/compute/images/test_image_metadata_negative.py
@@ -0,0 +1,81 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.api.compute import base
+from tempest.common.utils import data_utils
+from tempest import exceptions
+from tempest.test import attr
+
+
+class ImagesMetadataTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(ImagesMetadataTestJSON, cls).setUpClass()
+        cls.client = cls.images_client
+
+    @attr(type=['negative', 'gate'])
+    def test_list_nonexistent_image_metadata(self):
+        # Negative test: List on nonexistent image
+        # metadata should not happen
+        self.assertRaises(exceptions.NotFound, self.client.list_image_metadata,
+                          data_utils.rand_uuid())
+
+    @attr(type=['negative', 'gate'])
+    def test_update_nonexistent_image_metadata(self):
+        # Negative test:An update should not happen for a non-existent image
+        meta = {'key1': 'alt1', 'key2': 'alt2'}
+        self.assertRaises(exceptions.NotFound,
+                          self.client.update_image_metadata,
+                          data_utils.rand_uuid(), meta)
+
+    @attr(type=['negative', 'gate'])
+    def test_get_nonexistent_image_metadata_item(self):
+        # Negative test: Get on non-existent image should not happen
+        self.assertRaises(exceptions.NotFound,
+                          self.client.get_image_metadata_item,
+                          data_utils.rand_uuid(), 'key2')
+
+    @attr(type=['negative', 'gate'])
+    def test_set_nonexistent_image_metadata(self):
+        # Negative test: Metadata should not be set to a non-existent image
+        meta = {'key1': 'alt1', 'key2': 'alt2'}
+        self.assertRaises(exceptions.NotFound, self.client.set_image_metadata,
+                          data_utils.rand_uuid(), meta)
+
+    @attr(type=['negative', 'gate'])
+    def test_set_nonexistent_image_metadata_item(self):
+        # Negative test: Metadata item should not be set to a
+        # nonexistent image
+        meta = {'key1': 'alt'}
+        self.assertRaises(exceptions.NotFound,
+                          self.client.set_image_metadata_item,
+                          data_utils.rand_uuid(), 'key1',
+                          meta)
+
+    @attr(type=['negative', 'gate'])
+    def test_delete_nonexistent_image_metadata_item(self):
+        # Negative test: Shouldn't be able to delete metadata
+        # item from non-existent image
+        self.assertRaises(exceptions.NotFound,
+                          self.client.delete_image_metadata_item,
+                          data_utils.rand_uuid(), 'key1')
+
+
+class ImagesMetadataTestXML(ImagesMetadataTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_virtual_interfaces.py b/tempest/api/compute/servers/test_virtual_interfaces.py
index 164c6df..968ae47 100644
--- a/tempest/api/compute/servers/test_virtual_interfaces.py
+++ b/tempest/api/compute/servers/test_virtual_interfaces.py
@@ -18,11 +18,8 @@
 import netaddr
 
 from tempest.api.compute import base
-from tempest.common.utils import data_utils
 from tempest import config
-from tempest import exceptions
-from tempest.test import attr
-from tempest.test import skip_because
+from tempest import test
 
 
 class VirtualInterfacesTestJSON(base.BaseV2ComputeTest):
@@ -37,9 +34,9 @@
         resp, server = cls.create_test_server(wait_until='ACTIVE')
         cls.server_id = server['id']
 
-    @skip_because(bug="1183436",
-                  condition=CONF.service_available.neutron)
-    @attr(type='gate')
+    @test.skip_because(bug="1183436",
+                       condition=CONF.service_available.neutron)
+    @test.attr(type='gate')
     def test_list_virtual_interfaces(self):
         # Positive test:Should be able to GET the virtual interfaces list
         # for a given server_id
@@ -54,15 +51,6 @@
             self.assertTrue(netaddr.valid_mac(mac_address),
                             "Invalid mac address detected.")
 
-    @attr(type=['negative', 'gate'])
-    def test_list_virtual_interfaces_invalid_server_id(self):
-        # Negative test: Should not be able to GET virtual interfaces
-        # for an invalid server_id
-        invalid_server_id = data_utils.rand_name('!@#$%^&*()')
-        self.assertRaises(exceptions.NotFound,
-                          self.client.list_virtual_interfaces,
-                          invalid_server_id)
-
 
 class VirtualInterfacesTestXML(VirtualInterfacesTestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/servers/test_virtual_interfaces_negative.py b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
new file mode 100644
index 0000000..a2a6c11
--- /dev/null
+++ b/tempest/api/compute/servers/test_virtual_interfaces_negative.py
@@ -0,0 +1,44 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2013 OpenStack Foundation
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import uuid
+
+from tempest.api.compute import base
+from tempest import exceptions
+from tempest import test
+
+
+class VirtualInterfacesNegativeTestJSON(base.BaseV2ComputeTest):
+    _interface = 'json'
+
+    @classmethod
+    def setUpClass(cls):
+        super(VirtualInterfacesNegativeTestJSON, cls).setUpClass()
+        cls.client = cls.servers_client
+
+    @test.attr(type=['negative', 'gate'])
+    def test_list_virtual_interfaces_invalid_server_id(self):
+        # Negative test: Should not be able to GET virtual interfaces
+        # for an invalid server_id
+        invalid_server_id = str(uuid.uuid4())
+        self.assertRaises(exceptions.NotFound,
+                          self.client.list_virtual_interfaces,
+                          invalid_server_id)
+
+
+class VirtualInterfacesNegativeTestXML(VirtualInterfacesNegativeTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_flavors_access.py b/tempest/api/compute/v3/admin/test_flavors_access.py
index 048312b..86194af 100644
--- a/tempest/api/compute/v3/admin/test_flavors_access.py
+++ b/tempest/api/compute/v3/admin/test_flavors_access.py
@@ -20,7 +20,7 @@
 from tempest import test
 
 
-class FlavorsAccessTestJSON(base.BaseV2ComputeAdminTest):
+class FlavorsAccessV3TestJSON(base.BaseV3ComputeAdminTest):
 
     """
     Tests Flavor Access API extension.
@@ -31,19 +31,15 @@
 
     @classmethod
     def setUpClass(cls):
-        super(FlavorsAccessTestJSON, cls).setUpClass()
-        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
-            msg = "FlavorExtraData extension not enabled."
-            raise cls.skipException(msg)
+        super(FlavorsAccessV3TestJSON, cls).setUpClass()
 
-        cls.client = cls.os_adm.flavors_client
+        cls.client = cls.flavors_admin_client
         admin_client = cls._get_identity_admin_client()
         cls.tenant = admin_client.get_tenant_by_name(cls.flavors_client.
                                                      tenant_name)
         cls.tenant_id = cls.tenant['id']
-        cls.adm_tenant = admin_client.get_tenant_by_name(cls.os_adm.
-                                                         flavors_client.
-                                                         tenant_name)
+        cls.adm_tenant = admin_client.get_tenant_by_name(
+            cls.flavors_admin_client.tenant_name)
         cls.adm_tenant_id = cls.adm_tenant['id']
         cls.flavor_name_prefix = 'test_flavor_access_'
         cls.ram = 512
@@ -61,7 +57,7 @@
                                                      new_flavor_id,
                                                      is_public='False')
         self.addCleanup(self.client.delete_flavor, new_flavor['id'])
-        self.assertEqual(resp.status, 200)
+        self.assertEqual(resp.status, 201)
         resp, flavor_access = self.client.list_flavor_access(new_flavor_id)
         self.assertEqual(resp.status, 200)
         self.assertEqual(len(flavor_access), 1, str(flavor_access))
@@ -107,5 +103,5 @@
         self.assertNotIn(new_flavor['id'], map(lambda x: x['id'], flavors))
 
 
-class FlavorsAdminTestXML(FlavorsAccessTestJSON):
+class FlavorsAdminV3TestXML(FlavorsAccessV3TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_flavors_access_negative.py b/tempest/api/compute/v3/admin/test_flavors_access_negative.py
index 976124e..df6557e 100644
--- a/tempest/api/compute/v3/admin/test_flavors_access_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_access_negative.py
@@ -23,7 +23,7 @@
 from tempest import test
 
 
-class FlavorsAccessNegativeTestJSON(base.BaseV2ComputeAdminTest):
+class FlavorsAccessNegativeV3TestJSON(base.BaseV3ComputeAdminTest):
 
     """
     Tests Flavor Access API extension.
@@ -34,19 +34,15 @@
 
     @classmethod
     def setUpClass(cls):
-        super(FlavorsAccessNegativeTestJSON, cls).setUpClass()
-        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
-            msg = "FlavorExtraData extension not enabled."
-            raise cls.skipException(msg)
+        super(FlavorsAccessNegativeV3TestJSON, cls).setUpClass()
 
-        cls.client = cls.os_adm.flavors_client
+        cls.client = cls.flavors_admin_client
         admin_client = cls._get_identity_admin_client()
         cls.tenant = admin_client.get_tenant_by_name(cls.flavors_client.
                                                      tenant_name)
         cls.tenant_id = cls.tenant['id']
-        cls.adm_tenant = admin_client.get_tenant_by_name(cls.os_adm.
-                                                         flavors_client.
-                                                         tenant_name)
+        cls.adm_tenant = admin_client.get_tenant_by_name(
+            cls.flavors_admin_client.tenant_name)
         cls.adm_tenant_id = cls.adm_tenant['id']
         cls.flavor_name_prefix = 'test_flavor_access_'
         cls.ram = 512
@@ -64,7 +60,7 @@
                                                      new_flavor_id,
                                                      is_public='True')
         self.addCleanup(self.client.delete_flavor, new_flavor['id'])
-        self.assertEqual(resp.status, 200)
+        self.assertEqual(resp.status, 201)
         self.assertRaises(exceptions.NotFound,
                           self.client.list_flavor_access,
                           new_flavor_id)
@@ -148,5 +144,5 @@
                           str(uuid.uuid4()))
 
 
-class FlavorsAdminNegativeTestXML(FlavorsAccessNegativeTestJSON):
+class FlavorsAdminNegativeV3TestXML(FlavorsAccessNegativeV3TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_flavors_extra_specs.py b/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
index 875f742..d745829 100644
--- a/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
+++ b/tempest/api/compute/v3/admin/test_flavors_extra_specs.py
@@ -20,7 +20,7 @@
 from tempest import test
 
 
-class FlavorsExtraSpecsTestJSON(base.BaseV2ComputeAdminTest):
+class FlavorsExtraSpecsV3TestJSON(base.BaseV3ComputeAdminTest):
 
     """
     Tests Flavor Extra Spec API extension.
@@ -32,12 +32,9 @@
 
     @classmethod
     def setUpClass(cls):
-        super(FlavorsExtraSpecsTestJSON, cls).setUpClass()
-        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
-            msg = "FlavorExtraData extension not enabled."
-            raise cls.skipException(msg)
+        super(FlavorsExtraSpecsV3TestJSON, cls).setUpClass()
 
-        cls.client = cls.os_adm.flavors_client
+        cls.client = cls.flavors_admin_client
         flavor_name = data_utils.rand_name('test_flavor')
         ram = 512
         vcpus = 1
@@ -58,7 +55,7 @@
     def tearDownClass(cls):
         resp, body = cls.client.delete_flavor(cls.flavor['id'])
         cls.client.wait_for_resource_deletion(cls.flavor['id'])
-        super(FlavorsExtraSpecsTestJSON, cls).tearDownClass()
+        super(FlavorsExtraSpecsV3TestJSON, cls).tearDownClass()
 
     @test.attr(type='gate')
     def test_flavor_set_get_update_show_unset_keys(self):
@@ -69,7 +66,7 @@
         # SET extra specs to the flavor created in setUp
         set_resp, set_body = \
             self.client.set_flavor_extra_spec(self.flavor['id'], specs)
-        self.assertEqual(set_resp.status, 200)
+        self.assertEqual(set_resp.status, 201)
         self.assertEqual(set_body, specs)
         # GET extra specs and verify
         get_resp, get_body = \
@@ -95,10 +92,10 @@
         # UNSET extra specs that were set in this test
         unset_resp, _ = \
             self.client.unset_flavor_extra_spec(self.flavor['id'], "key1")
-        self.assertEqual(unset_resp.status, 200)
+        self.assertEqual(unset_resp.status, 204)
         unset_resp, _ = \
             self.client.unset_flavor_extra_spec(self.flavor['id'], "key2")
-        self.assertEqual(unset_resp.status, 200)
+        self.assertEqual(unset_resp.status, 204)
 
     @test.attr(type='gate')
     def test_flavor_non_admin_get_all_keys(self):
@@ -117,7 +114,7 @@
         specs = {"key1": "value1", "key2": "value2"}
         resp, body = self.client.set_flavor_extra_spec(
             self.flavor['id'], specs)
-        self.assertEqual(resp.status, 200)
+        self.assertEqual(resp.status, 201)
         self.assertEqual(body['key1'], 'value1')
         self.assertIn('key2', body)
         resp, body = self.flavors_client.get_flavor_extra_spec_with_key(
@@ -127,5 +124,5 @@
         self.assertNotIn('key2', body)
 
 
-class FlavorsExtraSpecsTestXML(FlavorsExtraSpecsTestJSON):
+class FlavorsExtraSpecsV3TestXML(FlavorsExtraSpecsV3TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py b/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
index fb09a63..1d5e447 100644
--- a/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_extra_specs_negative.py
@@ -22,7 +22,7 @@
 from tempest import test
 
 
-class FlavorsExtraSpecsNegativeTestJSON(base.BaseV2ComputeAdminTest):
+class FlavorsExtraSpecsNegativeV3TestJSON(base.BaseV3ComputeAdminTest):
 
     """
     Negative Tests Flavor Extra Spec API extension.
@@ -33,12 +33,9 @@
 
     @classmethod
     def setUpClass(cls):
-        super(FlavorsExtraSpecsNegativeTestJSON, cls).setUpClass()
-        if not test.is_extension_enabled('FlavorExtraData', 'compute'):
-            msg = "FlavorExtraData extension not enabled."
-            raise cls.skipException(msg)
+        super(FlavorsExtraSpecsNegativeV3TestJSON, cls).setUpClass()
 
-        cls.client = cls.os_adm.flavors_client
+        cls.client = cls.flavors_admin_client
         flavor_name = data_utils.rand_name('test_flavor')
         ram = 512
         vcpus = 1
@@ -59,7 +56,7 @@
     def tearDownClass(cls):
         resp, body = cls.client.delete_flavor(cls.flavor['id'])
         cls.client.wait_for_resource_deletion(cls.flavor['id'])
-        super(FlavorsExtraSpecsNegativeTestJSON, cls).tearDownClass()
+        super(FlavorsExtraSpecsNegativeV3TestJSON, cls).tearDownClass()
 
     @test.attr(type=['negative', 'gate'])
     def test_flavor_non_admin_set_keys(self):
@@ -76,7 +73,7 @@
         specs = {"key1": "value1", "key2": "value2"}
         resp, body = self.client.set_flavor_extra_spec(
             self.flavor['id'], specs)
-        self.assertEqual(resp.status, 200)
+        self.assertEqual(resp.status, 201)
         self.assertEqual(body['key1'], 'value1')
         self.assertRaises(exceptions.Unauthorized,
                           self.flavors_client.
@@ -131,5 +128,5 @@
                           key2="value")
 
 
-class FlavorsExtraSpecsNegativeTestXML(FlavorsExtraSpecsNegativeTestJSON):
+class FlavorsExtraSpecsNegativeV3TestXML(FlavorsExtraSpecsNegativeV3TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/v3/keypairs/test_keypairs.py b/tempest/api/compute/v3/keypairs/test_keypairs.py
index b36595c..029633f 100644
--- a/tempest/api/compute/v3/keypairs/test_keypairs.py
+++ b/tempest/api/compute/v3/keypairs/test_keypairs.py
@@ -20,17 +20,17 @@
 from tempest import test
 
 
-class KeyPairsTestJSON(base.BaseV2ComputeTest):
+class KeyPairsV3TestJSON(base.BaseV3ComputeTest):
     _interface = 'json'
 
     @classmethod
     def setUpClass(cls):
-        super(KeyPairsTestJSON, cls).setUpClass()
+        super(KeyPairsV3TestJSON, cls).setUpClass()
         cls.client = cls.keypairs_client
 
     def _delete_keypair(self, keypair_name):
         resp, _ = self.client.delete_keypair(keypair_name)
-        self.assertEqual(202, resp.status)
+        self.assertEqual(204, resp.status)
 
     def _create_keypair(self, keypair_name, pub_key=None):
         resp, body = self.client.create_keypair(keypair_name, pub_key)
@@ -49,7 +49,7 @@
             # as the keypair dicts from list API doesn't have them.
             keypair.pop('private_key')
             keypair.pop('user_id')
-            self.assertEqual(200, resp.status)
+            self.assertEqual(201, resp.status)
             key_list.append(keypair)
         # Fetch all keypairs and verify the list
         # has all created keypairs
@@ -72,7 +72,7 @@
         # Keypair should be created, verified and deleted
         k_name = data_utils.rand_name('keypair-')
         resp, keypair = self._create_keypair(k_name)
-        self.assertEqual(200, resp.status)
+        self.assertEqual(201, resp.status)
         private_key = keypair['private_key']
         key_name = keypair['name']
         self.assertEqual(key_name, k_name,
@@ -111,7 +111,7 @@
                    "XcPojYN56tI0OlrGqojbediJYD0rUsJu4weZpbn8vilb3JuDY+jws"
                    "snSA8wzBx3A/8y9Pp1B nova@ubuntu")
         resp, keypair = self._create_keypair(k_name, pub_key)
-        self.assertEqual(200, resp.status)
+        self.assertEqual(201, resp.status)
         self.assertFalse('private_key' in keypair,
                          "Field private_key is not empty!")
         key_name = keypair['name']
@@ -120,5 +120,5 @@
                          "to the requested name!")
 
 
-class KeyPairsTestXML(KeyPairsTestJSON):
+class KeyPairsV3TestXML(KeyPairsV3TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/v3/keypairs/test_keypairs_negative.py b/tempest/api/compute/v3/keypairs/test_keypairs_negative.py
index 621487c..edc0c26 100644
--- a/tempest/api/compute/v3/keypairs/test_keypairs_negative.py
+++ b/tempest/api/compute/v3/keypairs/test_keypairs_negative.py
@@ -22,12 +22,12 @@
 from tempest import test
 
 
-class KeyPairsNegativeTestJSON(base.BaseV2ComputeTest):
+class KeyPairsNegativeV3TestJSON(base.BaseV3ComputeTest):
     _interface = 'json'
 
     @classmethod
     def setUpClass(cls):
-        super(KeyPairsNegativeTestJSON, cls).setUpClass()
+        super(KeyPairsNegativeV3TestJSON, cls).setUpClass()
         cls.client = cls.keypairs_client
 
     def _create_keypair(self, keypair_name, pub_key=None):
@@ -70,12 +70,11 @@
         # Keypairs with duplicate names should not be created
         k_name = data_utils.rand_name('keypair-')
         resp, _ = self.client.create_keypair(k_name)
-        self.assertEqual(200, resp.status)
+        self.addCleanup(self.client.delete_keypair, k_name)
+        self.assertEqual(201, resp.status)
         # Now try the same keyname to create another key
         self.assertRaises(exceptions.Conflict, self._create_keypair,
                           k_name)
-        resp, _ = self.client.delete_keypair(k_name)
-        self.assertEqual(202, resp.status)
 
     @test.attr(type=['negative', 'gate'])
     def test_create_keypair_with_empty_name_string(self):
@@ -98,5 +97,5 @@
                           k_name)
 
 
-class KeyPairsNegativeTestXML(KeyPairsNegativeTestJSON):
+class KeyPairsNegativeV3TestXML(KeyPairsNegativeV3TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/compute/v3/servers/test_server_actions.py b/tempest/api/compute/v3/servers/test_server_actions.py
index 8cd6c11..602bd5b 100644
--- a/tempest/api/compute/v3/servers/test_server_actions.py
+++ b/tempest/api/compute/v3/servers/test_server_actions.py
@@ -123,6 +123,7 @@
                                                    metadata=meta,
                                                    personality=personality,
                                                    admin_password=password)
+        self.addCleanup(self.client.rebuild, self.server_id, self.image_ref)
 
         # Verify the properties in the initial response are correct
         self.assertEqual(self.server_id, rebuilt_server['id'])
@@ -142,6 +143,35 @@
             linux_client = RemoteClient(server, self.ssh_user, password)
             linux_client.validate_authentication()
 
+    @attr(type='gate')
+    def test_rebuild_server_in_stop_state(self):
+        # The server in stop state  should be rebuilt using the provided
+        # image and remain in SHUTOFF state
+        resp, server = self.client.get_server(self.server_id)
+        old_image = server['image']['id']
+        new_image = self.image_ref_alt \
+            if old_image == self.image_ref else self.image_ref
+        resp, server = self.client.stop(self.server_id)
+        self.assertEqual(202, resp.status)
+        self.client.wait_for_server_status(self.server_id, 'SHUTOFF')
+        self.addCleanup(self.client.start, self.server_id)
+        resp, rebuilt_server = self.client.rebuild(self.server_id, new_image)
+        self.addCleanup(self.client.wait_for_server_status, self.server_id,
+                        'SHUTOFF')
+        self.addCleanup(self.client.rebuild, self.server_id, old_image)
+
+        # Verify the properties in the initial response are correct
+        self.assertEqual(self.server_id, rebuilt_server['id'])
+        rebuilt_image_id = rebuilt_server['image']['id']
+        self.assertEqual(new_image, rebuilt_image_id)
+        self.assertEqual(self.flavor_ref, rebuilt_server['flavor']['id'])
+
+        # Verify the server properties after the rebuild completes
+        self.client.wait_for_server_status(rebuilt_server['id'], 'SHUTOFF')
+        resp, server = self.client.get_server(rebuilt_server['id'])
+        rebuilt_image_id = server['image']['id']
+        self.assertEqual(new_image, rebuilt_image_id)
+
     def _detect_server_image_flavor(self, server_id):
         # Detects the current server image flavor ref.
         resp, server = self.client.get_server(self.server_id)
@@ -199,32 +229,115 @@
                 raise exceptions.TimeoutException(message)
 
     @attr(type='gate')
+    def test_create_backup(self):
+        # Positive test:create backup successfully and rotate backups correctly
+        # create the first and the second backup
+        backup1 = data_utils.rand_name('backup')
+        resp, _ = self.servers_client.create_backup(self.server_id,
+                                                    'daily',
+                                                    2,
+                                                    backup1)
+        oldest_backup_exist = True
+
+        # the oldest one should be deleted automatically in this test
+        def _clean_oldest_backup(oldest_backup):
+            if oldest_backup_exist:
+                self.images_client.delete_image(oldest_backup)
+
+        image1_id = data_utils.parse_image_id(resp['location'])
+        self.addCleanup(_clean_oldest_backup, image1_id)
+        self.assertEqual(202, resp.status)
+        self.images_client.wait_for_image_status(image1_id, 'active')
+
+        backup2 = data_utils.rand_name('backup')
+        self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
+        resp, _ = self.servers_client.create_backup(self.server_id,
+                                                    'daily',
+                                                    2,
+                                                    backup2)
+        image2_id = data_utils.parse_image_id(resp['location'])
+        self.addCleanup(self.images_client.delete_image, image2_id)
+        self.assertEqual(202, resp.status)
+        self.images_client.wait_for_image_status(image2_id, 'active')
+
+        # verify they have been created
+        properties = {
+            'image_type': 'backup',
+            'backup_type': "daily",
+            'instance_uuid': self.server_id,
+        }
+        resp, image_list = self.images_client.image_list_detail(
+            properties,
+            sort_key='created_at',
+            sort_dir='asc')
+        self.assertEqual(200, resp.status)
+        self.assertEqual(2, len(image_list))
+        self.assertEqual((backup1, backup2),
+                         (image_list[0]['name'], image_list[1]['name']))
+
+        # create the third one, due to the rotation is 2,
+        # the first one will be deleted
+        backup3 = data_utils.rand_name('backup')
+        self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
+        resp, _ = self.servers_client.create_backup(self.server_id,
+                                                    'daily',
+                                                    2,
+                                                    backup3)
+        image3_id = data_utils.parse_image_id(resp['location'])
+        self.addCleanup(self.images_client.delete_image, image3_id)
+        self.assertEqual(202, resp.status)
+        # the first back up should be deleted
+        self.images_client.wait_for_resource_deletion(image1_id)
+        oldest_backup_exist = False
+        resp, image_list = self.images_client.image_list_detail(
+            properties,
+            sort_key='created_at',
+            sort_dir='asc')
+        self.assertEqual(200, resp.status)
+        self.assertEqual(2, len(image_list))
+        self.assertEqual((backup2, backup3),
+                         (image_list[0]['name'], image_list[1]['name']))
+
+    def _get_output(self):
+        resp, output = self.servers_client.get_console_output(
+            self.server_id, 10)
+        self.assertEqual(200, resp.status)
+        self.assertTrue(output, "Console output was empty.")
+        lines = len(output.split('\n'))
+        self.assertEqual(lines, 10)
+
+    @attr(type='gate')
     def test_get_console_output(self):
         # Positive test:Should be able to GET the console output
         # for a given server_id and number of lines
-        def get_output():
-            resp, output = self.servers_client.get_console_output(
-                self.server_id, 10)
-            self.assertEqual(200, resp.status)
-            self.assertTrue(output, "Console output was empty.")
-            lines = len(output.split('\n'))
-            self.assertEqual(lines, 10)
-        self.wait_for(get_output)
 
-    @skip_because(bug="1014683")
+        # This reboot is necessary for outputting some console log after
+        # creating a instance backup. If a instance backup, the console
+        # log file is truncated and we cannot get any console log through
+        # "console-log" API.
+        # The detail is https://bugs.launchpad.net/nova/+bug/1251920
+        resp, body = self.servers_client.reboot(self.server_id, 'HARD')
+        self.assertEqual(202, resp.status)
+        self.servers_client.wait_for_server_status(self.server_id, 'ACTIVE')
+
+        self.wait_for(self._get_output)
+
     @attr(type='gate')
-    def test_get_console_output_server_id_in_reboot_status(self):
+    def test_get_console_output_server_id_in_shutoff_status(self):
         # Positive test:Should be able to GET the console output
-        # for a given server_id in reboot status
-        resp, output = self.servers_client.reboot(self.server_id, 'SOFT')
-        self.servers_client.wait_for_server_status(self.server_id,
-                                                   'REBOOT')
-        resp, output = self.servers_client.get_console_output(self.server_id,
-                                                              10)
-        self.assertEqual(200, resp.status)
-        self.assertIsNotNone(output)
-        lines = len(output.split('\n'))
-        self.assertEqual(lines, 10)
+        # for a given server_id in SHUTOFF status
+
+        # NOTE: SHUTOFF is irregular status. To avoid test instability,
+        #       one server is created only for this test without using
+        #       the server that was created in setupClass.
+        resp, server = self.create_test_server(wait_until='ACTIVE')
+        temp_server_id = server['id']
+
+        resp, server = self.servers_client.stop(temp_server_id)
+        self.assertEqual(202, resp.status)
+        self.servers_client.wait_for_server_status(temp_server_id, 'SHUTOFF')
+
+        self.wait_for(self._get_output)
 
     @attr(type='gate')
     def test_pause_unpause_server(self):
@@ -245,6 +358,30 @@
         self.client.wait_for_server_status(self.server_id, 'ACTIVE')
 
     @attr(type='gate')
+    def test_shelve_unshelve_server(self):
+        resp, server = self.client.shelve_server(self.server_id)
+        self.assertEqual(202, resp.status)
+
+        offload_time = self.config.compute.shelved_offload_time
+        if offload_time >= 0:
+            self.client.wait_for_server_status(self.server_id,
+                                               'SHELVED_OFFLOADED',
+                                               extra_timeout=offload_time)
+        else:
+            self.client.wait_for_server_status(self.server_id,
+                                               'SHELVED')
+
+        resp, server = self.client.get_server(self.server_id)
+        image_name = server['name'] + '-shelved'
+        resp, images = self.images_client.image_list(name=image_name)
+        self.assertEqual(1, len(images))
+        self.assertEqual(image_name, images[0]['name'])
+
+        resp, server = self.client.unshelve_server(self.server_id)
+        self.assertEqual(202, resp.status)
+        self.client.wait_for_server_status(self.server_id, 'ACTIVE')
+
+    @attr(type='gate')
     def test_stop_start_server(self):
         resp, server = self.servers_client.stop(self.server_id)
         self.assertEqual(202, resp.status)
diff --git a/tempest/api/compute/v3/servers/test_servers_negative.py b/tempest/api/compute/v3/servers/test_servers_negative.py
index 6532032..85fe47c 100644
--- a/tempest/api/compute/v3/servers/test_servers_negative.py
+++ b/tempest/api/compute/v3/servers/test_servers_negative.py
@@ -25,11 +25,11 @@
 from tempest import test
 
 
-class ServersNegativeTestJSON(base.BaseV2ComputeTest):
+class ServersNegativeV3TestJSON(base.BaseV3ComputeTest):
     _interface = 'json'
 
     def setUp(self):
-        super(ServersNegativeTestJSON, self).setUp()
+        super(ServersNegativeV3TestJSON, self).setUp()
         try:
             self.client.wait_for_server_status(self.server_id, 'ACTIVE')
         except Exception:
@@ -37,10 +37,10 @@
 
     @classmethod
     def setUpClass(cls):
-        super(ServersNegativeTestJSON, cls).setUpClass()
+        super(ServersNegativeV3TestJSON, cls).setUpClass()
         cls.client = cls.servers_client
         cls.alt_os = clients.AltManager()
-        cls.alt_client = cls.alt_os.servers_client
+        cls.alt_client = cls.alt_os.servers_v3_client
         resp, server = cls.create_test_server(wait_until='ACTIVE')
         cls.server_id = server['id']
 
@@ -53,18 +53,6 @@
                           name='')
 
     @test.attr(type=['negative', 'gate'])
-    def test_personality_file_contents_not_encoded(self):
-        # Use an unencoded file when creating a server with personality
-
-        file_contents = 'This is a test file.'
-        person = [{'path': '/etc/testfile.txt',
-                   'contents': file_contents}]
-
-        self.assertRaises(exceptions.BadRequest,
-                          self.create_test_server,
-                          personality=person)
-
-    @test.attr(type=['negative', 'gate'])
     def test_create_with_invalid_image(self):
         # Create a server with an unknown image
 
@@ -86,7 +74,7 @@
 
         IPv4 = '1.1.1.1.1.1'
         self.assertRaises(exceptions.BadRequest,
-                          self.create_test_server, accessIPv4=IPv4)
+                          self.create_test_server, access_ip_v4=IPv4)
 
     @test.attr(type=['negative', 'gate'])
     def test_invalid_ip_v6_address(self):
@@ -95,7 +83,7 @@
         IPv6 = 'notvalid'
 
         self.assertRaises(exceptions.BadRequest,
-                          self.create_test_server, accessIPv6=IPv6)
+                          self.create_test_server, access_ip_v6=IPv6)
 
     @test.attr(type=['negative', 'gate'])
     def test_resize_nonexistent_server(self):
@@ -186,12 +174,12 @@
                           self.create_test_server,
                           name=server_name)
 
+    @test.skip_because(bug="1208743")
     @test.attr(type=['negative', 'gate'])
     def test_create_with_invalid_network_uuid(self):
         # Pass invalid network uuid while creating a server
 
         networks = [{'fixed_ip': '10.0.1.1', 'uuid': 'a-b-c-d-e-f-g-h-i-j'}]
-
         self.assertRaises(exceptions.BadRequest,
                           self.create_test_server,
                           networks=networks)
@@ -421,8 +409,7 @@
 
         resp, server = self.client.get_server(self.server_id)
         image_name = server['name'] + '-shelved'
-        params = {'name': image_name}
-        resp, images = self.images_client.list_images(params)
+        resp, images = self.images_client.image_list(name=image_name)
         self.assertEqual(1, len(images))
         self.assertEqual(image_name, images[0]['name'])
 
@@ -445,5 +432,5 @@
                           self.server_id)
 
 
-class ServersNegativeTestXML(ServersNegativeTestJSON):
+class ServersNegativeV3TestXML(ServersNegativeV3TestJSON):
     _interface = 'xml'
diff --git a/tempest/api/volume/admin/test_multi_backend.py b/tempest/api/volume/admin/test_multi_backend.py
index 03e8469..c563259 100644
--- a/tempest/api/volume/admin/test_multi_backend.py
+++ b/tempest/api/volume/admin/test_multi_backend.py
@@ -22,7 +22,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class VolumeMultiBackendTest(base.BaseVolumeAdminTest):
+class VolumeMultiBackendTest(base.BaseVolumeV1AdminTest):
     _interface = "json"
 
     @classmethod
diff --git a/tempest/api/volume/admin/test_snapshots_actions.py b/tempest/api/volume/admin/test_snapshots_actions.py
index 5e838e5..03fbd33 100644
--- a/tempest/api/volume/admin/test_snapshots_actions.py
+++ b/tempest/api/volume/admin/test_snapshots_actions.py
@@ -15,12 +15,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api.volume.base import BaseVolumeAdminTest
+from tempest.api.volume import base
 from tempest.common.utils import data_utils
 from tempest.test import attr
 
 
-class SnapshotsActionsTest(BaseVolumeAdminTest):
+class SnapshotsActionsTest(base.BaseVolumeV1AdminTest):
     _interface = "json"
 
     @classmethod
diff --git a/tempest/api/volume/admin/test_volume_hosts.py b/tempest/api/volume/admin/test_volume_hosts.py
index e7d8c02..4f40d4a 100644
--- a/tempest/api/volume/admin/test_volume_hosts.py
+++ b/tempest/api/volume/admin/test_volume_hosts.py
@@ -19,7 +19,7 @@
 from tempest.test import attr
 
 
-class VolumeHostsAdminTestsJSON(base.BaseVolumeAdminTest):
+class VolumeHostsAdminTestsJSON(base.BaseVolumeV1AdminTest):
     _interface = "json"
 
     @attr(type='gate')
diff --git a/tempest/api/volume/admin/test_volume_types.py b/tempest/api/volume/admin/test_volume_types.py
index 5218f83..3a92e8d 100644
--- a/tempest/api/volume/admin/test_volume_types.py
+++ b/tempest/api/volume/admin/test_volume_types.py
@@ -15,13 +15,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api.volume.base import BaseVolumeTest
+from tempest.api.volume import base
 from tempest.common.utils import data_utils
 from tempest.services.volume.json.admin import volume_types_client
 from tempest.test import attr
 
 
-class VolumeTypesTest(BaseVolumeTest):
+class VolumeTypesTest(base.BaseVolumeV1Test):
     _interface = "json"
 
     @classmethod
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs.py b/tempest/api/volume/admin/test_volume_types_extra_specs.py
index dbb75af..f0fba07 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs.py
@@ -20,7 +20,7 @@
 from tempest.test import attr
 
 
-class VolumeTypesExtraSpecsTest(base.BaseVolumeAdminTest):
+class VolumeTypesExtraSpecsTest(base.BaseVolumeV1AdminTest):
     _interface = "json"
 
     @classmethod
diff --git a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
index 8b5dce2..cf992f2 100644
--- a/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_extra_specs_negative.py
@@ -23,7 +23,7 @@
 from tempest.test import attr
 
 
-class ExtraSpecsNegativeTest(base.BaseVolumeAdminTest):
+class ExtraSpecsNegativeTest(base.BaseVolumeV1AdminTest):
     _interface = 'json'
 
     @classmethod
diff --git a/tempest/api/volume/admin/test_volume_types_negative.py b/tempest/api/volume/admin/test_volume_types_negative.py
index 44725df..3832048 100644
--- a/tempest/api/volume/admin/test_volume_types_negative.py
+++ b/tempest/api/volume/admin/test_volume_types_negative.py
@@ -22,7 +22,7 @@
 from tempest.test import attr
 
 
-class VolumeTypesNegativeTest(base.BaseVolumeAdminTest):
+class VolumeTypesNegativeTest(base.BaseVolumeV1AdminTest):
     _interface = 'json'
 
     @attr(type='gate')
diff --git a/tempest/api/volume/admin/test_volumes_actions.py b/tempest/api/volume/admin/test_volumes_actions.py
index cb9ff11..941dc7e 100644
--- a/tempest/api/volume/admin/test_volumes_actions.py
+++ b/tempest/api/volume/admin/test_volumes_actions.py
@@ -15,12 +15,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api.volume.base import BaseVolumeAdminTest
+from tempest.api.volume import base
 from tempest.common.utils import data_utils as utils
 from tempest.test import attr
 
 
-class VolumesActionsTest(BaseVolumeAdminTest):
+class VolumesActionsTest(base.BaseVolumeV1AdminTest):
     _interface = "json"
 
     @classmethod
diff --git a/tempest/api/volume/base.py b/tempest/api/volume/base.py
index ba99309..d63fd8b 100644
--- a/tempest/api/volume/base.py
+++ b/tempest/api/volume/base.py
@@ -36,13 +36,12 @@
             skip_msg = ("%s skipped as Cinder is not available" % cls.__name__)
             raise cls.skipException(skip_msg)
 
-        os = cls.get_client_manager()
+        cls.os = cls.get_client_manager()
 
-        cls.os = os
-        cls.volumes_client = os.volumes_client
-        cls.snapshots_client = os.snapshots_client
-        cls.servers_client = os.servers_client
-        cls.volumes_extension_client = os.volumes_extension_client
+        cls.volumes_client = cls.os.volumes_client
+        cls.snapshots_client = cls.os.snapshots_client
+        cls.servers_client = cls.os.servers_client
+        cls.volumes_extension_client = cls.os.volumes_extension_client
         cls.image_ref = cls.config.compute.image_ref
         cls.flavor_ref = cls.config.compute.flavor_ref
         cls.build_interval = cls.config.volume.build_interval
@@ -50,12 +49,6 @@
         cls.snapshots = []
         cls.volumes = []
 
-        cls.volumes_client.keystone_auth(cls.os.username,
-                                         cls.os.password,
-                                         cls.os.auth_url,
-                                         cls.volumes_client.service,
-                                         cls.os.tenant_name)
-
     @classmethod
     def tearDownClass(cls):
         cls.clear_snapshots()
@@ -130,11 +123,26 @@
             time.sleep(self.build_interval)
 
 
-class BaseVolumeAdminTest(BaseVolumeTest):
+class BaseVolumeV1Test(BaseVolumeTest):
+    @classmethod
+    def setUpClass(cls):
+        if not cls.config.volume_feature_enabled.api_v1:
+            msg = "Volume API v1 not supported"
+            raise cls.skipException(msg)
+        super(BaseVolumeV1Test, cls).setUpClass()
+        cls.volumes_client = cls.os.volumes_client
+        cls.volumes_client.keystone_auth(cls.os.username,
+                                         cls.os.password,
+                                         cls.os.auth_url,
+                                         cls.volumes_client.service,
+                                         cls.os.tenant_name)
+
+
+class BaseVolumeV1AdminTest(BaseVolumeV1Test):
     """Base test case class for all Volume Admin API tests."""
     @classmethod
     def setUpClass(cls):
-        super(BaseVolumeAdminTest, cls).setUpClass()
+        super(BaseVolumeV1AdminTest, cls).setUpClass()
         cls.adm_user = cls.config.identity.admin_username
         cls.adm_pass = cls.config.identity.admin_password
         cls.adm_tenant = cls.config.identity.admin_tenant_name
diff --git a/tempest/api/volume/test_volume_transfers.py b/tempest/api/volume/test_volume_transfers.py
index dacebf1..71e9f85 100644
--- a/tempest/api/volume/test_volume_transfers.py
+++ b/tempest/api/volume/test_volume_transfers.py
@@ -15,13 +15,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api.volume.base import BaseVolumeTest
+from tempest.api.volume import base
 from tempest import clients
 from tempest.common.utils.data_utils import rand_name
 from tempest.test import attr
 
 
-class VolumesTransfersTest(BaseVolumeTest):
+class VolumesTransfersTest(base.BaseVolumeV1Test):
     _interface = "json"
 
     @classmethod
diff --git a/tempest/api/volume/test_volumes_actions.py b/tempest/api/volume/test_volumes_actions.py
index 8581d16..61f1bda 100644
--- a/tempest/api/volume/test_volumes_actions.py
+++ b/tempest/api/volume/test_volumes_actions.py
@@ -15,14 +15,14 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest.api.volume.base import BaseVolumeTest
+from tempest.api.volume import base
 from tempest.common.utils import data_utils
 from tempest.test import attr
 from tempest.test import services
 from tempest.test import stresstest
 
 
-class VolumesActionsTest(BaseVolumeTest):
+class VolumesActionsTest(base.BaseVolumeV1Test):
     _interface = "json"
 
     @classmethod
diff --git a/tempest/api/volume/test_volumes_get.py b/tempest/api/volume/test_volumes_get.py
index 14120fe..6d1c25a 100644
--- a/tempest/api/volume/test_volumes_get.py
+++ b/tempest/api/volume/test_volumes_get.py
@@ -21,7 +21,7 @@
 from tempest.test import services
 
 
-class VolumesGetTest(base.BaseVolumeTest):
+class VolumesGetTest(base.BaseVolumeV1Test):
     _interface = "json"
 
     @classmethod
diff --git a/tempest/api/volume/test_volumes_list.py b/tempest/api/volume/test_volumes_list.py
index 3c66eb8..c624a3a 100644
--- a/tempest/api/volume/test_volumes_list.py
+++ b/tempest/api/volume/test_volumes_list.py
@@ -27,7 +27,7 @@
 VOLUME_FIELDS = ('id', 'display_name')
 
 
-class VolumesListTest(base.BaseVolumeTest):
+class VolumesListTest(base.BaseVolumeV1Test):
 
     """
     This test creates a number of 1G volumes. To run successfully,
diff --git a/tempest/api/volume/test_volumes_negative.py b/tempest/api/volume/test_volumes_negative.py
index 928bd49..869aedb 100644
--- a/tempest/api/volume/test_volumes_negative.py
+++ b/tempest/api/volume/test_volumes_negative.py
@@ -23,7 +23,7 @@
 from tempest.test import attr
 
 
-class VolumesNegativeTest(base.BaseVolumeTest):
+class VolumesNegativeTest(base.BaseVolumeV1Test):
     _interface = 'json'
 
     @classmethod
diff --git a/tempest/api/volume/test_volumes_snapshots.py b/tempest/api/volume/test_volumes_snapshots.py
index 6c45c3d..4e57007 100644
--- a/tempest/api/volume/test_volumes_snapshots.py
+++ b/tempest/api/volume/test_volumes_snapshots.py
@@ -20,7 +20,7 @@
 LOG = logging.getLogger(__name__)
 
 
-class VolumesSnapshotTest(base.BaseVolumeTest):
+class VolumesSnapshotTest(base.BaseVolumeV1Test):
     _interface = "json"
 
     @classmethod
diff --git a/tempest/api/volume/test_volumes_snapshots_negative.py b/tempest/api/volume/test_volumes_snapshots_negative.py
index 04a4774..0e4f5dc 100644
--- a/tempest/api/volume/test_volumes_snapshots_negative.py
+++ b/tempest/api/volume/test_volumes_snapshots_negative.py
@@ -20,7 +20,7 @@
 from tempest.test import attr
 
 
-class VolumesSnapshotNegativeTest(base.BaseVolumeTest):
+class VolumesSnapshotNegativeTest(base.BaseVolumeV1Test):
     _interface = "json"
 
     @attr(type=['negative', 'gate'])
diff --git a/tempest/clients.py b/tempest/clients.py
index 3333b9b..1f2e1de 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -56,10 +56,13 @@
     CertificatesV3ClientJSON
 from tempest.services.compute.v3.json.extensions_client import \
     ExtensionsV3ClientJSON
+from tempest.services.compute.v3.json.flavors_client import FlavorsV3ClientJSON
 from tempest.services.compute.v3.json.hypervisor_client import \
     HypervisorV3ClientJSON
 from tempest.services.compute.v3.json.interfaces_client import \
     InterfacesV3ClientJSON
+from tempest.services.compute.v3.json.keypairs_client import \
+    KeyPairsV3ClientJSON
 from tempest.services.compute.v3.json.servers_client import \
     ServersV3ClientJSON
 from tempest.services.compute.v3.json.services_client import \
@@ -72,10 +75,12 @@
     CertificatesV3ClientXML
 from tempest.services.compute.v3.xml.extensions_client import \
     ExtensionsV3ClientXML
+from tempest.services.compute.v3.xml.flavors_client import FlavorsV3ClientXML
 from tempest.services.compute.v3.xml.hypervisor_client import \
     HypervisorV3ClientXML
 from tempest.services.compute.v3.xml.interfaces_client import \
     InterfacesV3ClientXML
+from tempest.services.compute.v3.xml.keypairs_client import KeyPairsV3ClientXML
 from tempest.services.compute.v3.xml.servers_client import ServersV3ClientXML
 from tempest.services.compute.v3.xml.services_client import \
     ServicesV3ClientXML
@@ -91,6 +96,7 @@
 from tempest.services.compute.xml.flavors_client import FlavorsClientXML
 from tempest.services.compute.xml.floating_ips_client import \
     FloatingIPsClientXML
+from tempest.services.compute.xml.hosts_client import HostsClientXML
 from tempest.services.compute.xml.hypervisor_client import HypervisorClientXML
 from tempest.services.compute.xml.images_client import ImagesClientXML
 from tempest.services.compute.xml.instance_usage_audit_log_client import \
@@ -220,9 +226,11 @@
             self.servers_v3_client = ServersV3ClientXML(*client_args)
             self.limits_client = LimitsClientXML(*client_args)
             self.images_client = ImagesClientXML(*client_args)
+            self.keypairs_v3_client = KeyPairsV3ClientXML(*client_args)
             self.keypairs_client = KeyPairsClientXML(*client_args)
             self.quotas_client = QuotasClientXML(*client_args)
             self.flavors_client = FlavorsClientXML(*client_args)
+            self.flavors_v3_client = FlavorsV3ClientXML(*client_args)
             self.extensions_v3_client = ExtensionsV3ClientXML(*client_args)
             self.extensions_client = ExtensionsClientXML(*client_args)
             self.volumes_extensions_client = VolumesExtensionsClientXML(
@@ -252,6 +260,7 @@
                 *client_args)
             self.tenant_usages_client = TenantUsagesClientXML(*client_args)
             self.policy_client = PolicyClientXML(*client_args)
+            self.hosts_client = HostsClientXML(*client_args)
             self.hypervisor_v3_client = HypervisorV3ClientXML(*client_args)
             self.hypervisor_client = HypervisorClientXML(*client_args)
             self.token_v3_client = V3TokenClientXML(*client_args)
@@ -275,9 +284,11 @@
             self.servers_v3_client = ServersV3ClientJSON(*client_args)
             self.limits_client = LimitsClientJSON(*client_args)
             self.images_client = ImagesClientJSON(*client_args)
+            self.keypairs_v3_client = KeyPairsV3ClientJSON(*client_args)
             self.keypairs_client = KeyPairsClientJSON(*client_args)
             self.quotas_client = QuotasClientJSON(*client_args)
             self.flavors_client = FlavorsClientJSON(*client_args)
+            self.flavors_v3_client = FlavorsV3ClientJSON(*client_args)
             self.extensions_v3_client = ExtensionsV3ClientJSON(*client_args)
             self.extensions_client = ExtensionsClientJSON(*client_args)
             self.volumes_extensions_client = VolumesExtensionsClientJSON(
@@ -307,6 +318,7 @@
                 *client_args)
             self.tenant_usages_client = TenantUsagesClientJSON(*client_args)
             self.policy_client = PolicyClientJSON(*client_args)
+            self.hosts_client = HostsClientJSON(*client_args)
             self.hypervisor_v3_client = HypervisorV3ClientJSON(*client_args)
             self.hypervisor_client = HypervisorClientJSON(*client_args)
             self.token_v3_client = V3TokenClientJSON(*client_args)
@@ -326,7 +338,6 @@
             raise exceptions.InvalidConfiguration(msg)
 
         # common clients
-        self.hosts_client = HostsClientJSON(*client_args)
         self.account_client = AccountClient(*client_args)
         if CONF.service_available.glance:
             self.image_client = ImageClientJSON(*client_args)
diff --git a/tempest/common/waiters.py b/tempest/common/waiters.py
index aedba15..ce620a8 100644
--- a/tempest/common/waiters.py
+++ b/tempest/common/waiters.py
@@ -29,7 +29,10 @@
     """Waits for a server to reach a given status."""
 
     def _get_task_state(body):
-        task_state = body.get('OS-EXT-STS:task_state', None)
+        if client.service == CONF.compute.catalog_v3_type:
+            task_state = body.get("os-extended-status:task_state", None)
+        else:
+            task_state = body.get('OS-EXT-STS:task_state', None)
         return task_state
 
     # NOTE(afazekas): UNKNOWN status possible on ERROR
diff --git a/tempest/config.py b/tempest/config.py
index 1247a8d..bf45b4b 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -377,6 +377,9 @@
                 default=['all'],
                 help='A list of enabled extensions with a special entry all '
                      'which indicates every extension is enabled'),
+    cfg.BoolOpt('api_v1',
+                default=True,
+                help="Is the v1 volume API enabled"),
 ]
 
 
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index d3d34d0..409fcc2 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -985,7 +985,7 @@
         username = cls.config.identity.admin_username
         password = cls.config.identity.admin_password
         tenant_name = cls.config.identity.tenant_name
-        return username, tenant_name, password
+        return username, password, tenant_name
 
     def _load_template(self, base_file, file_name):
         filepath = os.path.join(os.path.dirname(os.path.realpath(base_file)),
diff --git a/tempest/services/compute/v3/json/flavors_client.py b/tempest/services/compute/v3/json/flavors_client.py
index 00d6f8a..e99ac91 100644
--- a/tempest/services/compute/v3/json/flavors_client.py
+++ b/tempest/services/compute/v3/json/flavors_client.py
@@ -21,12 +21,12 @@
 from tempest.common.rest_client import RestClient
 
 
-class FlavorsClientJSON(RestClient):
+class FlavorsV3ClientJSON(RestClient):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(FlavorsClientJSON, self).__init__(config, username, password,
-                                                auth_url, tenant_name)
-        self.service = self.config.compute.catalog_type
+        super(FlavorsV3ClientJSON, self).__init__(config, username, password,
+                                                  auth_url, tenant_name)
+        self.service = self.config.compute.catalog_v3_type
 
     def list_flavors(self, params=None):
         url = 'flavors'
@@ -67,7 +67,7 @@
         if kwargs.get('rxtx'):
             post_body['rxtx_factor'] = kwargs.get('rxtx')
         if kwargs.get('is_public'):
-            post_body['os-flavor-access:is_public'] = kwargs.get('is_public')
+            post_body['flavor-access:is_public'] = kwargs.get('is_public')
         post_body = json.dumps({'flavor': post_body})
         resp, body = self.post('flavors', post_body, self.headers)
 
@@ -91,27 +91,27 @@
     def set_flavor_extra_spec(self, flavor_id, specs):
         """Sets extra Specs to the mentioned flavor."""
         post_body = json.dumps({'extra_specs': specs})
-        resp, body = self.post('flavors/%s/os-extra_specs' % flavor_id,
+        resp, body = self.post('flavors/%s/flavor-extra-specs' % flavor_id,
                                post_body, self.headers)
         body = json.loads(body)
         return resp, body['extra_specs']
 
     def get_flavor_extra_spec(self, flavor_id):
         """Gets extra Specs details of the mentioned flavor."""
-        resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id)
+        resp, body = self.get('flavors/%s/flavor-extra-specs' % flavor_id)
         body = json.loads(body)
         return resp, body['extra_specs']
 
     def get_flavor_extra_spec_with_key(self, flavor_id, key):
         """Gets extra Specs key-value of the mentioned flavor and key."""
-        resp, body = self.get('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
-                              key))
+        resp, body = self.get('flavors/%s/flavor-extra-specs/%s' %
+                              (str(flavor_id), key))
         body = json.loads(body)
         return resp, body
 
     def update_flavor_extra_spec(self, flavor_id, key, **kwargs):
         """Update specified extra Specs of the mentioned flavor and key."""
-        resp, body = self.put('flavors/%s/os-extra_specs/%s' %
+        resp, body = self.put('flavors/%s/flavor-extra-specs/%s' %
                               (flavor_id, key),
                               json.dumps(kwargs), self.headers)
         body = json.loads(body)
@@ -119,12 +119,12 @@
 
     def unset_flavor_extra_spec(self, flavor_id, key):
         """Unsets extra Specs from the mentioned flavor."""
-        return self.delete('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
-                           key))
+        return self.delete('flavors/%s/flavor-extra-specs/%s' %
+                           (str(flavor_id), key))
 
     def list_flavor_access(self, flavor_id):
         """Gets flavor access information given the flavor id."""
-        resp, body = self.get('flavors/%s/os-flavor-access' % flavor_id,
+        resp, body = self.get('flavors/%s/flavor-access' % flavor_id,
                               self.headers)
         body = json.loads(body)
         return resp, body['flavor_access']
@@ -132,8 +132,8 @@
     def add_flavor_access(self, flavor_id, tenant_id):
         """Add flavor access for the specified tenant."""
         post_body = {
-            'addTenantAccess': {
-                'tenant': tenant_id
+            'add_tenant_access': {
+                'tenant_id': tenant_id
             }
         }
         post_body = json.dumps(post_body)
@@ -145,8 +145,8 @@
     def remove_flavor_access(self, flavor_id, tenant_id):
         """Remove flavor access from the specified tenant."""
         post_body = {
-            'removeTenantAccess': {
-                'tenant': tenant_id
+            'remove_tenant_access': {
+                'tenant_id': tenant_id
             }
         }
         post_body = json.dumps(post_body)
diff --git a/tempest/services/compute/v3/json/keypairs_client.py b/tempest/services/compute/v3/json/keypairs_client.py
index 5e1900c..500aa0e 100644
--- a/tempest/services/compute/v3/json/keypairs_client.py
+++ b/tempest/services/compute/v3/json/keypairs_client.py
@@ -20,15 +20,15 @@
 from tempest.common.rest_client import RestClient
 
 
-class KeyPairsClientJSON(RestClient):
+class KeyPairsV3ClientJSON(RestClient):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(KeyPairsClientJSON, self).__init__(config, username, password,
-                                                 auth_url, tenant_name)
-        self.service = self.config.compute.catalog_type
+        super(KeyPairsV3ClientJSON, self).__init__(config, username, password,
+                                                   auth_url, tenant_name)
+        self.service = self.config.compute.catalog_v3_type
 
     def list_keypairs(self):
-        resp, body = self.get("os-keypairs")
+        resp, body = self.get("keypairs")
         body = json.loads(body)
         # Each returned keypair is embedded within an unnecessary 'keypair'
         # element which is a deviation from other resources like floating-ips,
@@ -38,7 +38,7 @@
         return resp, body['keypairs']
 
     def get_keypair(self, key_name):
-        resp, body = self.get("os-keypairs/%s" % str(key_name))
+        resp, body = self.get("keypairs/%s" % str(key_name))
         body = json.loads(body)
         return resp, body['keypair']
 
@@ -47,10 +47,10 @@
         if pub_key:
             post_body['keypair']['public_key'] = pub_key
         post_body = json.dumps(post_body)
-        resp, body = self.post("os-keypairs",
+        resp, body = self.post("keypairs",
                                headers=self.headers, body=post_body)
         body = json.loads(body)
         return resp, body['keypair']
 
     def delete_keypair(self, key_name):
-        return self.delete("os-keypairs/%s" % str(key_name))
+        return self.delete("keypairs/%s" % str(key_name))
diff --git a/tempest/services/compute/v3/json/servers_client.py b/tempest/services/compute/v3/json/servers_client.py
index a7fcc6d..a486801 100644
--- a/tempest/services/compute/v3/json/servers_client.py
+++ b/tempest/services/compute/v3/json/servers_client.py
@@ -64,12 +64,14 @@
             'flavor_ref': flavor_ref
         }
 
-        for option in ['personality', 'admin_password', 'key_name',
-                       'security_groups', 'networks',
+        for option in ['personality', 'admin_password', 'key_name', 'networks',
+                       ('os-security-groups:security_groups',
+                        'security_groups'),
                        ('os-user-data:user_data', 'user_data'),
                        ('os-availability-zone:availability_zone',
                         'availability_zone'),
-                       'access_ip_v4', 'access_ip_v6',
+                       ('os-access-ips:access_ip_v4', 'access_ip_v4'),
+                       ('os-access-ips:access_ip_v6', 'access_ip_v6'),
                        ('os-multiple-create:min_count', 'min_count'),
                        ('os-multiple-create:max_count', 'max_count'),
                        ('metadata', 'meta'),
@@ -205,6 +207,13 @@
             body = json.loads(body)[response_key]
         return resp, body
 
+    def create_backup(self, server_id, backup_type, rotation, name):
+        """Backup a server instance."""
+        return self.action(server_id, "create_backup", None,
+                           backup_type=backup_type,
+                           rotation=rotation,
+                           name=name)
+
     def change_password(self, server_id, admin_password):
         """Changes the root password for the server."""
         return self.action(server_id, 'change_password', None,
@@ -356,6 +365,14 @@
         """Resets the state of a server to active/error."""
         return self.action(server_id, 'reset_state', None, state=state)
 
+    def shelve_server(self, server_id, **kwargs):
+        """Shelves the provided server."""
+        return self.action(server_id, 'shelve', None, **kwargs)
+
+    def unshelve_server(self, server_id, **kwargs):
+        """Un-shelves the provided server."""
+        return self.action(server_id, 'unshelve', None, **kwargs)
+
     def get_console_output(self, server_id, length):
         return self.action(server_id, 'get_console_output', 'output',
                            length=length)
@@ -388,3 +405,11 @@
                               (str(server_id), str(request_id)))
         body = json.loads(body)
         return resp, body['instance_action']
+
+    def force_delete_server(self, server_id, **kwargs):
+        """Force delete a server."""
+        return self.action(server_id, 'force_delete', None, **kwargs)
+
+    def restore_soft_deleted_server(self, server_id, **kwargs):
+        """Restore a soft-deleted server."""
+        return self.action(server_id, 'restore', None, **kwargs)
diff --git a/tempest/services/compute/v3/xml/flavors_client.py b/tempest/services/compute/v3/xml/flavors_client.py
index a1c74d9..04c21b4 100644
--- a/tempest/services/compute/v3/xml/flavors_client.py
+++ b/tempest/services/compute/v3/xml/flavors_client.py
@@ -24,21 +24,18 @@
 from tempest.services.compute.xml.common import Element
 from tempest.services.compute.xml.common import Text
 from tempest.services.compute.xml.common import xml_to_json
-from tempest.services.compute.xml.common import XMLNS_11
+from tempest.services.compute.xml.common import XMLNS_V3
 
-
-XMLNS_OS_FLV_EXT_DATA = \
-    "http://docs.openstack.org/compute/ext/flavor_extra_data/api/v1.1"
 XMLNS_OS_FLV_ACCESS = \
-    "http://docs.openstack.org/compute/ext/flavor_access/api/v2"
+    "http://docs.openstack.org/compute/core/flavor-access/api/v3"
 
 
-class FlavorsClientXML(RestClientXML):
+class FlavorsV3ClientXML(RestClientXML):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(FlavorsClientXML, self).__init__(config, username, password,
-                                               auth_url, tenant_name)
-        self.service = self.config.compute.catalog_type
+        super(FlavorsV3ClientXML, self).__init__(config, username, password,
+                                                 auth_url, tenant_name)
+        self.service = self.config.compute.catalog_v3_type
 
     def _format_flavor(self, f):
         flavor = {'links': []}
@@ -51,15 +48,12 @@
                 flavor['links'].append(v)
                 continue
 
-            if k == '{%s}ephemeral' % XMLNS_OS_FLV_EXT_DATA:
-                k = 'OS-FLV-EXT-DATA:ephemeral'
-
             if k == '{%s}is_public' % XMLNS_OS_FLV_ACCESS:
-                k = 'os-flavor-access:is_public'
+                k = 'flavor-access:is_public'
                 v = True if v == 'True' else False
 
             if k == 'extra_specs':
-                k = 'OS-FLV-WITH-EXT-SPECS:extra_specs'
+                k = 'flavor-extra-specs:extra_specs'
                 flavor[k] = dict(v)
                 continue
 
@@ -103,7 +97,7 @@
     def create_flavor(self, name, ram, vcpus, disk, flavor_id, **kwargs):
         """Creates a new flavor or instance type."""
         flavor = Element("flavor",
-                         xmlns=XMLNS_11,
+                         xmlns=XMLNS_V3,
                          ram=ram,
                          vcpus=vcpus,
                          disk=disk,
@@ -114,13 +108,11 @@
         if kwargs.get('swap'):
             flavor.add_attr('swap', kwargs.get('swap'))
         if kwargs.get('ephemeral'):
-            flavor.add_attr('OS-FLV-EXT-DATA:ephemeral',
-                            kwargs.get('ephemeral'))
+            flavor.add_attr('ephemeral', kwargs.get('ephemeral'))
         if kwargs.get('is_public'):
-            flavor.add_attr('os-flavor-access:is_public',
+            flavor.add_attr('flavor-access:is_public',
                             kwargs.get('is_public'))
-        flavor.add_attr('xmlns:OS-FLV-EXT-DATA', XMLNS_OS_FLV_EXT_DATA)
-        flavor.add_attr('xmlns:os-flavor-access', XMLNS_OS_FLV_ACCESS)
+        flavor.add_attr('xmlns:flavor-access', XMLNS_OS_FLV_ACCESS)
         resp, body = self.post('flavors', str(Document(flavor)), self.headers)
         body = xml_to_json(etree.fromstring(body))
         flavor = self._format_flavor(body)
@@ -145,21 +137,21 @@
         extra_specs = Element("extra_specs")
         for key in specs.keys():
             extra_specs.add_attr(key, specs[key])
-        resp, body = self.post('flavors/%s/os-extra_specs' % flavor_id,
+        resp, body = self.post('flavors/%s/flavor-extra-specs' % flavor_id,
                                str(Document(extra_specs)), self.headers)
         body = xml_to_json(etree.fromstring(body))
         return resp, body
 
     def get_flavor_extra_spec(self, flavor_id):
         """Gets extra Specs of the mentioned flavor."""
-        resp, body = self.get('flavors/%s/os-extra_specs' % flavor_id,
+        resp, body = self.get('flavors/%s/flavor-extra-specs' % flavor_id,
                               self.headers)
         body = xml_to_json(etree.fromstring(body))
         return resp, body
 
     def get_flavor_extra_spec_with_key(self, flavor_id, key):
         """Gets extra Specs key-value of the mentioned flavor and key."""
-        resp, xml_body = self.get('flavors/%s/os-extra_specs/%s' %
+        resp, xml_body = self.get('flavors/%s/flavor-extra-specs/%s' %
                                   (str(flavor_id), key), self.headers)
         body = {}
         element = etree.fromstring(xml_body)
@@ -176,7 +168,7 @@
             value = Text(v)
             element.append(value)
 
-        resp, body = self.put('flavors/%s/os-extra_specs/%s' %
+        resp, body = self.put('flavors/%s/flavor-extra-specs/%s' %
                               (flavor_id, key),
                               str(doc), self.headers)
         body = xml_to_json(etree.fromstring(body))
@@ -184,15 +176,15 @@
 
     def unset_flavor_extra_spec(self, flavor_id, key):
         """Unsets an extra spec based on the mentioned flavor and key."""
-        return self.delete('flavors/%s/os-extra_specs/%s' % (str(flavor_id),
-                           key))
+        return self.delete('flavors/%s/flavor-extra-specs/%s' %
+                           (str(flavor_id), key))
 
     def _parse_array_access(self, node):
         return [xml_to_json(x) for x in node]
 
     def list_flavor_access(self, flavor_id):
         """Gets flavor access information given the flavor id."""
-        resp, body = self.get('flavors/%s/os-flavor-access' % str(flavor_id),
+        resp, body = self.get('flavors/%s/flavor-access' % str(flavor_id),
                               self.headers)
         body = self._parse_array(etree.fromstring(body))
         return resp, body
@@ -200,9 +192,9 @@
     def add_flavor_access(self, flavor_id, tenant_id):
         """Add flavor access for the specified tenant."""
         doc = Document()
-        server = Element("addTenantAccess")
+        server = Element("add_tenant_access")
         doc.append(server)
-        server.add_attr("tenant", tenant_id)
+        server.add_attr("tenant_id", tenant_id)
         resp, body = self.post('flavors/%s/action' % str(flavor_id),
                                str(doc), self.headers)
         body = self._parse_array_access(etree.fromstring(body))
@@ -211,9 +203,9 @@
     def remove_flavor_access(self, flavor_id, tenant_id):
         """Remove flavor access from the specified tenant."""
         doc = Document()
-        server = Element("removeTenantAccess")
+        server = Element("remove_tenant_access")
         doc.append(server)
-        server.add_attr("tenant", tenant_id)
+        server.add_attr("tenant_id", tenant_id)
         resp, body = self.post('flavors/%s/action' % str(flavor_id),
                                str(doc), self.headers)
         body = self._parse_array_access(etree.fromstring(body))
diff --git a/tempest/services/compute/v3/xml/keypairs_client.py b/tempest/services/compute/v3/xml/keypairs_client.py
index 0157245..d87daff 100644
--- a/tempest/services/compute/v3/xml/keypairs_client.py
+++ b/tempest/services/compute/v3/xml/keypairs_client.py
@@ -24,21 +24,21 @@
 from tempest.services.compute.xml.common import xml_to_json
 
 
-class KeyPairsClientXML(RestClientXML):
+class KeyPairsV3ClientXML(RestClientXML):
 
     def __init__(self, config, username, password, auth_url, tenant_name=None):
-        super(KeyPairsClientXML, self).__init__(config, username, password,
-                                                auth_url, tenant_name)
-        self.service = self.config.compute.catalog_type
+        super(KeyPairsV3ClientXML, self).__init__(config, username, password,
+                                                  auth_url, tenant_name)
+        self.service = self.config.compute.catalog_v3_type
 
     def list_keypairs(self):
-        resp, body = self.get("os-keypairs", self.headers)
+        resp, body = self.get("keypairs", self.headers)
         node = etree.fromstring(body)
         body = [{'keypair': xml_to_json(x)} for x in node.getchildren()]
         return resp, body
 
     def get_keypair(self, key_name):
-        resp, body = self.get("os-keypairs/%s" % str(key_name), self.headers)
+        resp, body = self.get("keypairs/%s" % str(key_name), self.headers)
         body = xml_to_json(etree.fromstring(body))
         return resp, body
 
@@ -60,10 +60,10 @@
 
         doc.append(keypair_element)
 
-        resp, body = self.post("os-keypairs",
+        resp, body = self.post("keypairs",
                                headers=self.headers, body=str(doc))
         body = xml_to_json(etree.fromstring(body))
         return resp, body
 
     def delete_keypair(self, key_name):
-        return self.delete("os-keypairs/%s" % str(key_name))
+        return self.delete("keypairs/%s" % str(key_name))
diff --git a/tempest/services/compute/v3/xml/servers_client.py b/tempest/services/compute/v3/xml/servers_client.py
index 7af4161..c3381a3 100644
--- a/tempest/services/compute/v3/xml/servers_client.py
+++ b/tempest/services/compute/v3/xml/servers_client.py
@@ -214,6 +214,14 @@
         """Resets the state of a server to active/error."""
         return self.action(server_id, 'reset_state', None, state=state)
 
+    def shelve_server(self, server_id, **kwargs):
+        """Shelves the provided server."""
+        return self.action(server_id, 'shelve', None, **kwargs)
+
+    def unshelve_server(self, server_id, **kwargs):
+        """Un-shelves the provided server."""
+        return self.action(server_id, 'unshelve', None, **kwargs)
+
     def delete_server(self, server_id):
         """Deletes the given server."""
         return self.delete("servers/%s" % str(server_id))
@@ -299,7 +307,17 @@
                          flavor_ref=flavor_ref,
                          image_ref=image_ref,
                          name=name)
-        attrs = ["admin_password", "access_ip_v4", "access_ip_v6", "key_name",
+        attrs = ["admin_password", "key_name",
+                 ('os-access-ips:access_ip_v4',
+                  'access_ip_v4',
+                  'xmlns:os-access-ips',
+                  "http://docs.openstack.org/compute/ext/"
+                  "os-access-ips/api/v3"),
+                 ('os-access-ips:access_ip_v6',
+                  'access_ip_v6',
+                  'xmlns:os-access-ips',
+                  "http://docs.openstack.org/compute/ext/"
+                  "os-access-ips/api/v3"),
                  ("os-user-data:user_data",
                   'user_data',
                   'xmlns:os-user-data',
@@ -346,7 +364,10 @@
                     server.add_attr(post_param, value)
 
         if 'security_groups' in kwargs:
-            secgroups = Element("security_groups")
+            server.add_attr("xmlns:os-security-groups",
+                            "http://docs.openstack.org/compute/ext/"
+                            "securitygroups/api/v3")
+            secgroups = Element("os-security-groups:security_groups")
             server.append(secgroups)
             for secgroup in kwargs['security_groups']:
                 s = Element("security_group", name=secgroup['name'])
@@ -441,6 +462,13 @@
             body = xml_to_json(etree.fromstring(body))
         return resp, body
 
+    def create_backup(self, server_id, backup_type, rotation, name):
+        """Backup a server instance."""
+        return self.action(server_id, "create_backup", None,
+                           backup_type=backup_type,
+                           rotation=rotation,
+                           name=name)
+
     def change_password(self, server_id, password):
         return self.action(server_id, "change_password", None,
                            admin_password=password)
@@ -621,3 +649,11 @@
                               (server_id, request_id), self.headers)
         body = xml_to_json(etree.fromstring(body))
         return resp, body
+
+    def force_delete_server(self, server_id, **kwargs):
+        """Force delete a server."""
+        return self.action(server_id, 'force_delete', None, **kwargs)
+
+    def restore_soft_deleted_server(self, server_id, **kwargs):
+        """Restore a soft-deleted server."""
+        return self.action(server_id, 'restore', None, **kwargs)
diff --git a/tempest/services/compute/xml/hosts_client.py b/tempest/services/compute/xml/hosts_client.py
index f7d7b0a..519798e 100644
--- a/tempest/services/compute/xml/hosts_client.py
+++ b/tempest/services/compute/xml/hosts_client.py
@@ -47,18 +47,16 @@
 
         resp, body = self.get("os-hosts/%s" % str(hostname), self.headers)
         node = etree.fromstring(body)
-        body = [xml_to_json(x) for x in node.getchildren()]
+        body = [xml_to_json(node)]
         return resp, body
 
-    def update_host(self, hostname, status=None, maintenance_mode=None,
-                    **kwargs):
+    def update_host(self, hostname, **kwargs):
         """Update a host."""
 
-        request_body = Element(status=status,
-                               maintenance_mode=maintenance_mode)
+        request_body = Element("updates")
         if kwargs:
-            for k, v in kwargs.iteritem():
-                request_body.add_attr(k, v)
+            for k, v in kwargs.iteritems():
+                request_body.append(Element(k, v))
         resp, body = self.put("os-hosts/%s" % str(hostname),
                               str(Document(request_body)),
                               self.headers)
diff --git a/tempest/test.py b/tempest/test.py
index 56c0554..342846f 100644
--- a/tempest/test.py
+++ b/tempest/test.py
@@ -112,15 +112,24 @@
 
     @param bug: bug number causing the test to skip
     @param condition: optional condition to be True for the skip to have place
+    @param interface: skip the test if it is the same as self._interface
     """
     def decorator(f):
         @functools.wraps(f)
-        def wrapper(*func_args, **func_kwargs):
-            if "bug" in kwargs:
-                if "condition" not in kwargs or kwargs["condition"] is True:
-                    msg = "Skipped until Bug: %s is resolved." % kwargs["bug"]
-                    raise testtools.TestCase.skipException(msg)
-            return f(*func_args, **func_kwargs)
+        def wrapper(self, *func_args, **func_kwargs):
+            skip = False
+            if "condition" in kwargs:
+                if kwargs["condition"] is True:
+                    skip = True
+            elif "interface" in kwargs:
+                if kwargs["interface"] == self._interface:
+                    skip = True
+            else:
+                skip = True
+            if "bug" in kwargs and skip is True:
+                msg = "Skipped until Bug: %s is resolved." % kwargs["bug"]
+                raise testtools.TestCase.skipException(msg)
+            return f(self, *func_args, **func_kwargs)
         return wrapper
     return decorator