Merge "Fix the example of testr testing"
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/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..e0a5376 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -268,6 +268,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):
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/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/clients.py b/tempest/clients.py
index 3333b9b..a38f915 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -60,6 +60,8 @@
     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 \
@@ -76,6 +78,7 @@
     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 +94,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,6 +224,7 @@
             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)
@@ -252,6 +257,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,6 +281,7 @@
             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)
@@ -307,6 +314,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 +334,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/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/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/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