Merge "Sahara: minor changes for API tests"
diff --git a/etc/tempest.conf.sample b/etc/tempest.conf.sample
index 2ed2582..858fce9 100644
--- a/etc/tempest.conf.sample
+++ b/etc/tempest.conf.sample
@@ -109,6 +109,9 @@
 # value)
 #driver_enabled=false
 
+# Driver name which Ironic uses (string value)
+#driver=fake
+
 # The endpoint type to use for the baremetal provisioning
 # service (string value)
 #endpoint_type=publicURL
diff --git a/tempest/api/baremetal/test_drivers.py b/tempest/api/baremetal/test_drivers.py
index 445ca60..5e1e310 100644
--- a/tempest/api/baremetal/test_drivers.py
+++ b/tempest/api/baremetal/test_drivers.py
@@ -13,14 +13,23 @@
 #    under the License.
 
 from tempest.api.baremetal import base
+from tempest import config
 from tempest import test
 
+CONF = config.CONF
+
 
 class TestDrivers(base.BaseBaremetalTest):
     """Tests for drivers."""
+    @classmethod
+    @test.safe_setup
+    def setUpClass(cls):
+        super(TestDrivers, cls).setUpClass()
+        cls.driver_name = CONF.baremetal.driver
 
     @test.attr(type="smoke")
     def test_list_drivers(self):
         resp, drivers = self.client.list_drivers()
         self.assertEqual('200', resp['status'])
-        self.assertIn('fake', [d['name'] for d in drivers['drivers']])
+        self.assertIn(self.driver_name,
+                      [d['name'] for d in drivers['drivers']])
diff --git a/tempest/api/compute/admin/test_quotas.py b/tempest/api/compute/admin/test_quotas.py
index 348666d..9263396 100644
--- a/tempest/api/compute/admin/test_quotas.py
+++ b/tempest/api/compute/admin/test_quotas.py
@@ -13,14 +13,26 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import six
+from testtools import matchers
+
 from tempest.api.compute import base
+from tempest.common import tempest_fixtures as fixtures
 from tempest.common.utils import data_utils
+from tempest.openstack.common import log as logging
 from tempest import test
 
+LOG = logging.getLogger(__name__)
+
 
 class QuotasAdminTestJSON(base.BaseV2ComputeAdminTest):
     force_tenant_isolation = True
 
+    def setUp(self):
+        # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
+        self.useFixture(fixtures.LockFixture('compute_quotas'))
+        super(QuotasAdminTestJSON, self).setUp()
+
     @classmethod
     def setUpClass(cls):
         super(QuotasAdminTestJSON, cls).setUpClass()
@@ -134,3 +146,49 @@
 
 class QuotasAdminTestXML(QuotasAdminTestJSON):
     _interface = 'xml'
+
+
+class QuotaClassesAdminTestJSON(base.BaseV2ComputeAdminTest):
+    """Tests the os-quota-class-sets API to update default quotas.
+    """
+
+    def setUp(self):
+        # All test cases in this class need to externally lock on doing
+        # anything with default quota values.
+        self.useFixture(fixtures.LockFixture('compute_quotas'))
+        super(QuotaClassesAdminTestJSON, self).setUp()
+
+    @classmethod
+    def setUpClass(cls):
+        super(QuotaClassesAdminTestJSON, cls).setUpClass()
+        cls.adm_client = cls.os_adm.quota_classes_client
+
+    def _restore_default_quotas(self, original_defaults):
+        LOG.debug("restoring quota class defaults")
+        resp, body = self.adm_client.update_quota_class_set(
+            'default', **original_defaults)
+        self.assertEqual(200, resp.status)
+
+    @test.attr(type='gate')
+    def test_update_default_quotas(self):
+        LOG.debug("get the current 'default' quota class values")
+        resp, body = self.adm_client.get_quota_class_set('default')
+        self.assertEqual(200, resp.status)
+        self.assertIn('id', body)
+        self.assertEqual('default', body.pop('id'))
+        # restore the defaults when the test is done
+        self.addCleanup(self._restore_default_quotas, body.copy())
+        # increment all of the values for updating the default quota class
+        for quota, default in six.iteritems(body):
+            body[quota] = default + 1
+        LOG.debug("update limits for the default quota class set")
+        resp, update_body = self.adm_client.update_quota_class_set('default',
+                                                                   **body)
+        self.assertEqual(200, resp.status)
+        LOG.debug("assert that the response has all of the changed values")
+        self.assertThat(update_body.items(),
+                        matchers.ContainsAll(body.items()))
+
+
+class QuotaClassesAdminTestXML(QuotaClassesAdminTestJSON):
+    _interface = 'xml'
diff --git a/tempest/api/compute/admin/test_servers_negative.py b/tempest/api/compute/admin/test_servers_negative.py
index 15025ba..cccaf13 100644
--- a/tempest/api/compute/admin/test_servers_negative.py
+++ b/tempest/api/compute/admin/test_servers_negative.py
@@ -55,6 +55,8 @@
         return flavor_id
 
     @test.skip_because(bug="1298131")
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_server_using_overlimit_ram(self):
         flavor_name = data_utils.rand_name("flavor-")
@@ -74,6 +76,8 @@
                           flavor_ref['id'])
 
     @test.skip_because(bug="1298131")
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_server_using_overlimit_vcpus(self):
         flavor_name = data_utils.rand_name("flavor-")
diff --git a/tempest/api/compute/base.py b/tempest/api/compute/base.py
index a1aaa95..caf4174 100644
--- a/tempest/api/compute/base.py
+++ b/tempest/api/compute/base.py
@@ -67,6 +67,8 @@
             cls.keypairs_client = cls.os.keypairs_client
             cls.security_groups_client = cls.os.security_groups_client
             cls.quotas_client = cls.os.quotas_client
+            # NOTE(mriedem): os-quota-class-sets is v2 API only
+            cls.quota_classes_client = cls.os.quota_classes_client
             cls.limits_client = cls.os.limits_client
             cls.volumes_extensions_client = cls.os.volumes_extensions_client
             cls.volumes_client = cls.os.volumes_client
diff --git a/tempest/api/compute/flavors/test_flavors.py b/tempest/api/compute/flavors/test_flavors.py
index 0e6b9d6..c1c2d05 100644
--- a/tempest/api/compute/flavors/test_flavors.py
+++ b/tempest/api/compute/flavors/test_flavors.py
@@ -89,44 +89,40 @@
     @test.attr(type='gate')
     def test_list_flavors_detailed_filter_by_min_disk(self):
         # The detailed list of flavors should be filtered by disk space
-        resp, flavors = self.client.list_flavors_with_detail()
-        flavors = sorted(flavors, key=lambda k: k['disk'])
-        flavor_id = flavors[0]['id']
+        resp, flavor = self.client.get_flavor_details(self.flavor_ref)
+        flavor_id = flavor['id']
 
-        params = {self._min_disk: flavors[0]['disk'] + 1}
+        params = {self._min_disk: flavor['disk'] + 1}
         resp, flavors = self.client.list_flavors_with_detail(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
     @test.attr(type='gate')
     def test_list_flavors_detailed_filter_by_min_ram(self):
         # The detailed list of flavors should be filtered by RAM
-        resp, flavors = self.client.list_flavors_with_detail()
-        flavors = sorted(flavors, key=lambda k: k['ram'])
-        flavor_id = flavors[0]['id']
+        resp, flavor = self.client.get_flavor_details(self.flavor_ref)
+        flavor_id = flavor['id']
 
-        params = {self._min_ram: flavors[0]['ram'] + 1}
+        params = {self._min_ram: flavor['ram'] + 1}
         resp, flavors = self.client.list_flavors_with_detail(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
     @test.attr(type='gate')
     def test_list_flavors_filter_by_min_disk(self):
         # The list of flavors should be filtered by disk space
-        resp, flavors = self.client.list_flavors_with_detail()
-        flavors = sorted(flavors, key=lambda k: k['disk'])
-        flavor_id = flavors[0]['id']
+        resp, flavor = self.client.get_flavor_details(self.flavor_ref)
+        flavor_id = flavor['id']
 
-        params = {self._min_disk: flavors[0]['disk'] + 1}
+        params = {self._min_disk: flavor['disk'] + 1}
         resp, flavors = self.client.list_flavors(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
     @test.attr(type='gate')
     def test_list_flavors_filter_by_min_ram(self):
         # The list of flavors should be filtered by RAM
-        resp, flavors = self.client.list_flavors_with_detail()
-        flavors = sorted(flavors, key=lambda k: k['ram'])
-        flavor_id = flavors[0]['id']
+        resp, flavor = self.client.get_flavor_details(self.flavor_ref)
+        flavor_id = flavor['id']
 
-        params = {self._min_ram: flavors[0]['ram'] + 1}
+        params = {self._min_ram: flavor['ram'] + 1}
         resp, flavors = self.client.list_flavors(params)
         self.assertFalse(any([i for i in flavors if i['id'] == flavor_id]))
 
diff --git a/tempest/api/compute/servers/test_servers_negative.py b/tempest/api/compute/servers/test_servers_negative.py
index 6343ead..d3297ce 100644
--- a/tempest/api/compute/servers/test_servers_negative.py
+++ b/tempest/api/compute/servers/test_servers_negative.py
@@ -106,6 +106,8 @@
         self.assertRaises(exceptions.BadRequest,
                           self.create_test_server, accessIPv6=IPv6)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_nonexistent_server(self):
         # Resize a non-existent server
@@ -114,6 +116,8 @@
                           self.client.resize,
                           nonexistent_server, self.flavor_ref)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_server_with_non_existent_flavor(self):
         # Resize a server with non-existent flavor
@@ -121,6 +125,8 @@
         self.assertRaises(exceptions.BadRequest, self.client.resize,
                           self.server_id, flavor_ref=nonexistent_flavor)
 
+    @testtools.skipUnless(CONF.compute_feature_enabled.resize,
+                          'Resize not available.')
     @test.attr(type=['negative', 'gate'])
     def test_resize_server_with_null_flavor(self):
         # Resize a server with null flavor
diff --git a/tempest/api/compute/test_quotas.py b/tempest/api/compute/test_quotas.py
index dc85e76..eeff3ce 100644
--- a/tempest/api/compute/test_quotas.py
+++ b/tempest/api/compute/test_quotas.py
@@ -14,11 +14,17 @@
 #    under the License.
 
 from tempest.api.compute import base
+from tempest.common import tempest_fixtures as fixtures
 from tempest import test
 
 
 class QuotasTestJSON(base.BaseV2ComputeTest):
 
+    def setUp(self):
+        # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
+        self.useFixture(fixtures.LockFixture('compute_quotas'))
+        super(QuotasTestJSON, self).setUp()
+
     @classmethod
     def setUpClass(cls):
         super(QuotasTestJSON, cls).setUpClass()
diff --git a/tempest/api/compute/v3/admin/test_flavors.py b/tempest/api/compute/v3/admin/test_flavors.py
index 8a4e3cf..09d76b8 100644
--- a/tempest/api/compute/v3/admin/test_flavors.py
+++ b/tempest/api/compute/v3/admin/test_flavors.py
@@ -294,7 +294,7 @@
         flavor_name = data_utils.rand_name(self.flavor_name_prefix)
         new_flavor_id = data_utils.rand_int_id(start=1000)
 
-        ram = " 1024 "
+        ram = "1024"
         resp, flavor = self.client.create_flavor(flavor_name,
                                                  ram, self.vcpus,
                                                  self.disk,
diff --git a/tempest/api/compute/v3/admin/test_flavors_negative.py b/tempest/api/compute/v3/admin/test_flavors_negative.py
index 3f8a2da..6d3308e 100644
--- a/tempest/api/compute/v3/admin/test_flavors_negative.py
+++ b/tempest/api/compute/v3/admin/test_flavors_negative.py
@@ -57,7 +57,7 @@
         resp, flavor = self.client.create_flavor(flavor_name,
                                                  self.ram,
                                                  self.vcpus, self.disk,
-                                                 '',
+                                                 None,
                                                  ephemeral=self.ephemeral,
                                                  swap=self.swap,
                                                  rxtx=self.rxtx)
diff --git a/tempest/api/compute/v3/servers/test_instance_actions.py b/tempest/api/compute/v3/servers/test_instance_actions.py
index 399541b..4c2dcbe 100644
--- a/tempest/api/compute/v3/servers/test_instance_actions.py
+++ b/tempest/api/compute/v3/servers/test_instance_actions.py
@@ -27,7 +27,6 @@
         cls.resp = resp
         cls.server_id = server['id']
 
-    @test.skip_because(bug="1206032")
     @test.attr(type='gate')
     def test_list_server_actions(self):
         # List actions of the provided server
@@ -40,12 +39,10 @@
         self.assertTrue(any([i for i in body if i['action'] == 'create']))
         self.assertTrue(any([i for i in body if i['action'] == 'reboot']))
 
-    @test.skip_because(bug="1206032")
     @test.attr(type='gate')
-    @test.skip_because(bug="1281915")
     def test_get_server_action(self):
         # Get the action details of the provided server
-        request_id = self.resp['x-compute-request-id']
+        request_id = self.resp['x-openstack-request-id']
         resp, body = self.client.get_server_action(self.server_id,
                                                    request_id)
         self.assertEqual(200, resp.status)
diff --git a/tempest/api/compute/v3/test_quotas.py b/tempest/api/compute/v3/test_quotas.py
index 62a7556..ecf70cf 100644
--- a/tempest/api/compute/v3/test_quotas.py
+++ b/tempest/api/compute/v3/test_quotas.py
@@ -14,11 +14,17 @@
 #    under the License.
 
 from tempest.api.compute import base
+from tempest.common import tempest_fixtures as fixtures
 from tempest import test
 
 
 class QuotasV3Test(base.BaseV3ComputeTest):
 
+    def setUp(self):
+        # NOTE(mriedem): Avoid conflicts with os-quota-class-sets tests.
+        self.useFixture(fixtures.LockFixture('compute_quotas'))
+        super(QuotasV3Test, self).setUp()
+
     @classmethod
     def setUpClass(cls):
         super(QuotasV3Test, cls).setUpClass()
diff --git a/tempest/api/network/admin/test_quotas.py b/tempest/api/network/admin/test_quotas.py
index a307986..d1a8faf 100644
--- a/tempest/api/network/admin/test_quotas.py
+++ b/tempest/api/network/admin/test_quotas.py
@@ -85,3 +85,50 @@
         self.assertEqual('200', resp['status'])
         for q in non_default_quotas['quotas']:
             self.assertNotEqual(tenant_id, q['tenant_id'])
+
+    @test.requires_ext(extension='lbaas', service='network')
+    @test.attr(type='gate')
+    def test_lbaas_quotas(self):
+        # Add a tenant to conduct the test
+        test_tenant = data_utils.rand_name('test_tenant_')
+        test_description = data_utils.rand_name('desc_')
+        _, tenant = self.identity_admin_client.create_tenant(
+            name=test_tenant,
+            description=test_description)
+        tenant_id = tenant['id']
+        self.addCleanup(self.identity_admin_client.delete_tenant, tenant_id)
+        # Change lbaas quotas for tenant
+        new_quotas = {'vip': 1, 'pool': 2,
+                      'member': 3, 'health_monitor': 4}
+
+        resp, quota_set = self.admin_client.update_quotas(tenant_id,
+                                                          **new_quotas)
+        self.assertEqual('200', resp['status'])
+        self.addCleanup(self.admin_client.reset_quotas, tenant_id)
+        self.assertEqual(1, quota_set['vip'])
+        self.assertEqual(2, quota_set['pool'])
+        self.assertEqual(3, quota_set['member'])
+        self.assertEqual(4, quota_set['health_monitor'])
+        # Confirm our tenant is listed among tenants with non default quotas
+        resp, non_default_quotas = self.admin_client.list_quotas()
+        self.assertEqual('200', resp['status'])
+        found = False
+        for qs in non_default_quotas['quotas']:
+            if qs['tenant_id'] == tenant_id:
+                found = True
+        self.assertTrue(found)
+        # Confirm from APi quotas were changed as requested for tenant
+        resp, quota_set = self.admin_client.show_quotas(tenant_id)
+        quota_set = quota_set['quota']
+        self.assertEqual('200', resp['status'])
+        self.assertEqual(1, quota_set['vip'])
+        self.assertEqual(2, quota_set['pool'])
+        self.assertEqual(3, quota_set['member'])
+        self.assertEqual(4, quota_set['health_monitor'])
+        # Reset quotas to default and confirm
+        resp, body = self.admin_client.reset_quotas(tenant_id)
+        self.assertEqual('204', resp['status'])
+        resp, non_default_quotas = self.admin_client.list_quotas()
+        self.assertEqual('200', resp['status'])
+        for q in non_default_quotas['quotas']:
+            self.assertNotEqual(tenant_id, q['tenant_id'])
diff --git a/tempest/api/network/test_allowed_address_pair.py b/tempest/api/network/test_allowed_address_pair.py
index e0e26da..c897716 100644
--- a/tempest/api/network/test_allowed_address_pair.py
+++ b/tempest/api/network/test_allowed_address_pair.py
@@ -70,6 +70,27 @@
         self.assertTrue(port, msg)
         self._confirm_allowed_address_pair(port[0], self.ip_address)
 
+    @test.attr(type='smoke')
+    def test_update_port_with_address_pair(self):
+        # Create a port without allowed address pair
+        resp, body = self.client.create_port(network_id=self.network['id'])
+        self.assertEqual('201', resp['status'])
+        port_id = body['port']['id']
+        self.addCleanup(self.client.delete_port, port_id)
+
+        # Confirm  port is created
+        resp, body = self.client.show_port(port_id)
+        self.assertEqual('200', resp['status'])
+
+        # Update allowed address pair attribute of port
+        allowed_address_pairs = [{'ip_address': self.ip_address,
+                                  'mac_address': self.mac_address}]
+        resp, body = self.client.update_port(port_id,
+                          allowed_address_pairs=allowed_address_pairs)
+        self.assertEqual('200', resp['status'])
+        newport = body['port']
+        self._confirm_allowed_address_pair(newport, self.ip_address)
+
     def _confirm_allowed_address_pair(self, port, ip):
         msg = 'Port allowed address pairs should not be empty'
         self.assertTrue(port['allowed_address_pairs'], msg)
diff --git a/tempest/api/network/test_vpnaas_extensions.py b/tempest/api/network/test_vpnaas_extensions.py
index d1fe15c..0cc3f19 100644
--- a/tempest/api/network/test_vpnaas_extensions.py
+++ b/tempest/api/network/test_vpnaas_extensions.py
@@ -22,19 +22,15 @@
 CONF = config.CONF
 
 
-class VPNaaSTestJSON(base.BaseNetworkTest):
+class VPNaaSTestJSON(base.BaseAdminNetworkTest):
     _interface = 'json'
 
     """
     Tests the following operations in the Neutron API using the REST client for
     Neutron:
-
-        List VPN Services
-        Show VPN Services
-        Create VPN Services
-        Update VPN Services
-        Delete VPN Services
+        List, Show, Create, Delete, and Update VPN Service
         List, Show, Create, Delete, and Update IKE policy
+        List, Show, Create, Delete, and Update IPSec policy
     """
 
     @classmethod
@@ -47,11 +43,12 @@
         cls.network = cls.create_network()
         cls.subnet = cls.create_subnet(cls.network)
         cls.router = cls.create_router(
-            data_utils.rand_name("router-"),
+            data_utils.rand_name("router"),
             external_network_id=CONF.network.public_network_id)
         cls.create_router_interface(cls.router['id'], cls.subnet['id'])
         cls.vpnservice = cls.create_vpnservice(cls.subnet['id'],
                                                cls.router['id'])
+
         cls.ikepolicy = cls.create_ikepolicy(
             data_utils.rand_name("ike-policy-"))
         cls.ipsecpolicy = cls.create_ipsecpolicy(
@@ -87,6 +84,85 @@
             self.assertIn(key, actual)
             self.assertEqual(value, actual[key])
 
+    def _delete_vpn_service(self, vpn_service_id):
+        resp, _ = self.client.delete_vpnservice(vpn_service_id)
+        self.assertEqual('204', resp['status'])
+        # Asserting if vpn service is found in the list after deletion
+        _, body = self.client.list_vpnservices()
+        vpn_services = [vs['id'] for vs in body['vpnservices']]
+        self.assertNotIn(vpn_service_id, vpn_services)
+
+    def _get_tenant_id(self):
+        """
+        Returns the tenant_id of the client current user
+        """
+        # TODO(jroovers) This is a temporary workaround to get the tenant_id
+        # of the the current client. Replace this once tenant_isolation for
+        # neutron is fixed.
+        _, body = self.client.show_network(self.network['id'])
+        return body['network']['tenant_id']
+
+    @test.attr(type='smoke')
+    def test_admin_create_ipsec_policy_for_tenant(self):
+        tenant_id = self._get_tenant_id()
+        # Create IPSec policy for the newly created tenant
+        name = data_utils.rand_name('ipsec-policy')
+        resp, body = (self.admin_client.
+                      create_ipsecpolicy(name=name, tenant_id=tenant_id))
+        self.assertEqual('201', resp['status'])
+        ipsecpolicy = body['ipsecpolicy']
+        self.assertIsNotNone(ipsecpolicy['id'])
+        self.addCleanup(self.admin_client.delete_ipsecpolicy,
+                        ipsecpolicy['id'])
+
+        # Assert that created ipsec policy is found in API list call
+        _, body = self.client.list_ipsecpolicies()
+        ipsecpolicies = [policy['id'] for policy in body['ipsecpolicies']]
+        self.assertIn(ipsecpolicy['id'], ipsecpolicies)
+
+    @test.attr(type='smoke')
+    def test_admin_create_vpn_service_for_tenant(self):
+        tenant_id = self._get_tenant_id()
+
+        # Create vpn service for the newly created tenant
+        name = data_utils.rand_name('vpn-service')
+        resp, body = self.admin_client.create_vpnservice(
+            subnet_id=self.subnet['id'],
+            router_id=self.router['id'],
+            name=name,
+            admin_state_up=True,
+            tenant_id=tenant_id)
+        self.assertEqual('201', resp['status'])
+        vpnservice = body['vpnservice']
+        self.assertIsNotNone(vpnservice['id'])
+        self.addCleanup(self.admin_client.delete_vpnservice, vpnservice['id'])
+
+        # Assert that created vpnservice is found in API list call
+        _, body = self.client.list_vpnservices()
+        vpn_services = [vs['id'] for vs in body['vpnservices']]
+        self.assertIn(vpnservice['id'], vpn_services)
+
+    @test.attr(type='smoke')
+    def test_admin_create_ike_policy_for_tenant(self):
+        tenant_id = self._get_tenant_id()
+
+        # Create IKE policy for the newly created tenant
+        name = data_utils.rand_name('ike-policy')
+        resp, body = (self.admin_client.
+                      create_ikepolicy(name=name, ike_version="v1",
+                                       encryption_algorithm="aes-128",
+                                       auth_algorithm="sha1",
+                                       tenant_id=tenant_id))
+        self.assertEqual('201', resp['status'])
+        ikepolicy = body['ikepolicy']
+        self.assertIsNotNone(ikepolicy['id'])
+        self.addCleanup(self.admin_client.delete_ikepolicy, ikepolicy['id'])
+
+        # Assert that created ike policy is found in API list call
+        _, body = self.client.list_ikepolicies()
+        ikepolicies = [ikp['id'] for ikp in body['ikepolicies']]
+        self.assertIn(ikepolicy['id'], ikepolicies)
+
     @test.attr(type='smoke')
     def test_list_vpn_services(self):
         # Verify the VPN service exists in the list of all VPN services
@@ -97,14 +173,15 @@
 
     @test.attr(type='smoke')
     def test_create_update_delete_vpn_service(self):
-        # Creates a VPN service
-        name = data_utils.rand_name('vpn-service-')
+        # Creates a VPN service and sets up deletion
+        name = data_utils.rand_name('vpn-service')
         resp, body = self.client.create_vpnservice(subnet_id=self.subnet['id'],
                                                    router_id=self.router['id'],
                                                    name=name,
                                                    admin_state_up=True)
         self.assertEqual('201', resp['status'])
         vpnservice = body['vpnservice']
+        self.addCleanup(self._delete_vpn_service, vpnservice['id'])
         # Assert if created vpnservices are not found in vpnservices list
         resp, body = self.client.list_vpnservices()
         vpn_services = [vs['id'] for vs in body['vpnservices']]
@@ -116,14 +193,6 @@
         # But precondition is that current state of vpnservice
         # should be "ACTIVE" not "PENDING*"
 
-        # Verification of vpn service delete
-        resp, body = self.client.delete_vpnservice(vpnservice['id'])
-        self.assertEqual('204', resp['status'])
-        # Asserting if vpn service is found in the list after deletion
-        resp, body = self.client.list_vpnservices()
-        vpn_services = [vs['id'] for vs in body['vpnservices']]
-        self.assertNotIn(vpnservice['id'], vpn_services)
-
     @test.attr(type='smoke')
     def test_show_vpn_service(self):
         # Verifies the details of a vpn service
@@ -137,6 +206,9 @@
         self.assertEqual(self.vpnservice['router_id'], vpnservice['router_id'])
         self.assertEqual(self.vpnservice['subnet_id'], vpnservice['subnet_id'])
         self.assertEqual(self.vpnservice['tenant_id'], vpnservice['tenant_id'])
+        valid_status = ["ACTIVE", "DOWN", "BUILD", "ERROR", "PENDING_CREATE",
+                        "PENDING_UPDATE", "PENDING_DELETE"]
+        self.assertIn(vpnservice['status'], valid_status)
 
     @test.attr(type='smoke')
     def test_list_ike_policies(self):
@@ -149,7 +221,7 @@
     @test.attr(type='smoke')
     def test_create_update_delete_ike_policy(self):
         # Creates a IKE policy
-        name = data_utils.rand_name('ike-policy-')
+        name = data_utils.rand_name('ike-policy')
         resp, body = (self.client.create_ikepolicy(
                       name=name,
                       ike_version="v1",
@@ -157,19 +229,31 @@
                       auth_algorithm="sha1"))
         self.assertEqual('201', resp['status'])
         ikepolicy = body['ikepolicy']
+        self.assertIsNotNone(ikepolicy['id'])
         self.addCleanup(self._delete_ike_policy, ikepolicy['id'])
-        # Verification of ike policy update
-        description = "Updated ike policy"
-        new_ike = {'description': description, 'pfs': 'group5',
-                   'name': data_utils.rand_name("New-IKE-")}
-        resp, body = self.client.update_ikepolicy(ikepolicy['id'],
-                                                  **new_ike)
+
+        # Update IKE Policy
+        new_ike = {'name': data_utils.rand_name("New-IKE"),
+                   'description': "Updated ike policy",
+                   'encryption_algorithm': "aes-256",
+                   'ike_version': "v2",
+                   'pfs': "group14",
+                   'lifetime': {'units': "seconds", 'value': 2000}}
+        resp, _ = self.client.update_ikepolicy(ikepolicy['id'], **new_ike)
         self.assertEqual('200', resp['status'])
-        updated_ike_policy = body['ikepolicy']
-        self.assertEqual(updated_ike_policy['description'], description)
+        # Confirm that update was successful by verifying using 'show'
+        _, body = self.client.show_ikepolicy(ikepolicy['id'])
+        ike_policy = body['ikepolicy']
+        for key, value in new_ike.iteritems():
+            self.assertIn(key, ike_policy)
+            self.assertEqual(value, ike_policy[key])
+
         # Verification of ike policy delete
-        resp, body = self.client.delete_ikepolicy(ikepolicy['id'])
+        resp, _ = self.client.delete_ikepolicy(ikepolicy['id'])
         self.assertEqual('204', resp['status'])
+        _, body = self.client.list_ikepolicies()
+        ikepolicies = [ikp['id'] for ikp in body['ikepolicies']]
+        self.assertNotIn(ike_policy['id'], ikepolicies)
 
     @test.attr(type='smoke')
     def test_show_ike_policy(self):
diff --git a/tempest/api_schema/compute/agents.py b/tempest/api_schema/compute/agents.py
index b9ad240..e5f3a8d 100644
--- a/tempest/api_schema/compute/agents.py
+++ b/tempest/api_schema/compute/agents.py
@@ -22,7 +22,7 @@
                 'items': {
                     'type': 'object',
                     'properties': {
-                        'agent_id': {'type': ['integer', 'string']},
+                        'agent_id': {'type': 'integer'},
                         'hypervisor': {'type': 'string'},
                         'os': {'type': 'string'},
                         'architecture': {'type': 'string'},
diff --git a/tempest/api_schema/compute/keypairs.py b/tempest/api_schema/compute/keypairs.py
index b8f905f..2ae410c 100644
--- a/tempest/api_schema/compute/keypairs.py
+++ b/tempest/api_schema/compute/keypairs.py
@@ -49,10 +49,7 @@
                 'fingerprint': {'type': 'string'},
                 'name': {'type': 'string'},
                 'public_key': {'type': 'string'},
-                # NOTE: Now the type of 'user_id' is integer, but here
-                # allows 'string' also because we will be able to change
-                # it to 'uuid' in the future.
-                'user_id': {'type': ['integer', 'string']},
+                'user_id': {'type': 'string'},
                 'private_key': {'type': 'string'}
             },
             # When create keypair API is being called with 'Public key'
diff --git a/tempest/api_schema/compute/migrations.py b/tempest/api_schema/compute/migrations.py
index 6723869..6549272 100644
--- a/tempest/api_schema/compute/migrations.py
+++ b/tempest/api_schema/compute/migrations.py
@@ -22,10 +22,7 @@
                 'items': {
                     'type': 'object',
                     'properties': {
-                        # NOTE: Now the type of 'id' is integer, but here
-                        # allows 'string' also because we will be able to
-                        # change it to 'uuid' in the future.
-                        'id': {'type': ['integer', 'string']},
+                        'id': {'type': 'integer'},
                         'status': {'type': 'string'},
                         'instance_uuid': {'type': 'string'},
                         'source_node': {'type': 'string'},
@@ -33,12 +30,8 @@
                         'dest_node': {'type': 'string'},
                         'dest_compute': {'type': 'string'},
                         'dest_host': {'type': 'string'},
-                        'old_instance_type_id': {
-                            'type': ['integer', 'string']
-                        },
-                        'new_instance_type_id': {
-                            'type': ['integer', 'string']
-                        },
+                        'old_instance_type_id': {'type': 'integer'},
+                        'new_instance_type_id': {'type': 'integer'},
                         'created_at': {'type': 'string'},
                         'updated_at': {'type': ['string', 'null']}
                     },
diff --git a/tempest/api_schema/compute/servers.py b/tempest/api_schema/compute/servers.py
index 14e9ce9..ad0aa29 100644
--- a/tempest/api_schema/compute/servers.py
+++ b/tempest/api_schema/compute/servers.py
@@ -48,7 +48,7 @@
     }
 }
 
-base_update_server = {
+base_update_get_server = {
     'status_code': [200],
     'response_body': {
         'type': 'object',
@@ -56,13 +56,13 @@
             'server': {
                 'type': 'object',
                 'properties': {
-                    'id': {'type': ['integer', 'string']},
+                    'id': {'type': 'string'},
                     'name': {'type': 'string'},
                     'status': {'type': 'string'},
                     'image': {
                         'type': 'object',
                         'properties': {
-                            'id': {'type': ['integer', 'string']},
+                            'id': {'type': 'string'},
                             'links': parameter_types.links
                         },
                         'required': ['id', 'links']
@@ -70,7 +70,7 @@
                     'flavor': {
                         'type': 'object',
                         'properties': {
-                            'id': {'type': ['integer', 'string']},
+                            'id': {'type': 'string'},
                             'links': parameter_types.links
                         },
                         'required': ['id', 'links']
diff --git a/tempest/api_schema/compute/services.py b/tempest/api_schema/compute/services.py
index 4c58013..eaba129 100644
--- a/tempest/api_schema/compute/services.py
+++ b/tempest/api_schema/compute/services.py
@@ -22,10 +22,7 @@
                 'items': {
                     'type': 'object',
                     'properties': {
-                        # NOTE: Now the type of 'id' is integer, but here
-                        # allows 'string' also because we will be able to
-                        # change it to 'uuid' in the future.
-                        'id': {'type': ['integer', 'string']},
+                        'id': {'type': 'integer'},
                         'zone': {'type': 'string'},
                         'host': {'type': 'string'},
                         'state': {'type': 'string'},
diff --git a/tempest/api_schema/compute/v2/floating_ips.py b/tempest/api_schema/compute/v2/floating_ips.py
index 03e6aef..fb3667b 100644
--- a/tempest/api_schema/compute/v2/floating_ips.py
+++ b/tempest/api_schema/compute/v2/floating_ips.py
@@ -27,7 +27,7 @@
                         # able to change it to 'uuid' in the future.
                         'id': {'type': ['integer', 'string']},
                         'pool': {'type': ['string', 'null']},
-                        'instance_id': {'type': ['integer', 'string', 'null']},
+                        'instance_id': {'type': ['string', 'null']},
                         'ip': {
                             'type': 'string',
                             'format': 'ip-address'
@@ -58,7 +58,7 @@
                     # 'uuid' in the future.
                     'id': {'type': ['integer', 'string']},
                     'pool': {'type': ['string', 'null']},
-                    'instance_id': {'type': ['integer', 'string', 'null']},
+                    'instance_id': {'type': ['string', 'null']},
                     'ip': {
                         'type': 'string',
                         'format': 'ip-address'
@@ -117,3 +117,14 @@
         'required': ['floating_ips_bulk_create']
     }
 }
+
+delete_floating_ips_bulk = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'floating_ips_bulk_delete': {'type': 'string'}
+        },
+        'required': ['floating_ips_bulk_delete']
+    }
+}
diff --git a/tempest/api_schema/compute/v2/images.py b/tempest/api_schema/compute/v2/images.py
index d121060..90737a2 100644
--- a/tempest/api_schema/compute/v2/images.py
+++ b/tempest/api_schema/compute/v2/images.py
@@ -30,10 +30,7 @@
         'server': {
             'type': 'object',
             'properties': {
-                # NOTE: Now the type of 'id' is integer, but here
-                # allows 'string' also because we will be able to
-                # change it to 'uuid' in the future.
-                'id': {'type': ['integer', 'string']},
+                'id': {'type': 'string'},
                 'links': parameter_types.links
             },
             'required': ['id', 'links']
diff --git a/tempest/api_schema/compute/v2/keypairs.py b/tempest/api_schema/compute/v2/keypairs.py
index 9a025c3..32d8cca 100644
--- a/tempest/api_schema/compute/v2/keypairs.py
+++ b/tempest/api_schema/compute/v2/keypairs.py
@@ -25,10 +25,7 @@
                     'public_key': {'type': 'string'},
                     'name': {'type': 'string'},
                     'fingerprint': {'type': 'string'},
-                    # NOTE: Now the type of 'user_id' is integer, but here
-                    # allows 'string' also because we will be able to change
-                    # it to 'uuid' in the future.
-                    'user_id': {'type': ['integer', 'string']},
+                    'user_id': {'type': 'string'},
                     'deleted': {'type': 'boolean'},
                     'created_at': {'type': 'string'},
                     'updated_at': {'type': ['string', 'null']},
diff --git a/tempest/api_schema/compute/v2/quota_classes.py b/tempest/api_schema/compute/v2/quota_classes.py
new file mode 100644
index 0000000..3464fb4
--- /dev/null
+++ b/tempest/api_schema/compute/v2/quota_classes.py
@@ -0,0 +1,31 @@
+# Copyright 2014 IBM Corporation.
+# All rights reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import copy
+
+from tempest.api_schema.compute.v2 import quotas
+
+# NOTE(mriedem): os-quota-class-sets responses are the same as os-quota-sets
+# except for the key in the response body is quota_class_set instead of
+# quota_set, so update this copy of the schema from os-quota-sets.
+quota_set = copy.deepcopy(quotas.quota_set)
+quota_set['response_body']['properties']['quota_class_set'] = (
+    quota_set['response_body']['properties'].pop('quota_set'))
+quota_set['response_body']['required'] = ['quota_class_set']
+
+quota_set_update = copy.deepcopy(quotas.quota_set_update)
+quota_set_update['response_body']['properties']['quota_class_set'] = (
+    quota_set_update['response_body']['properties'].pop('quota_set'))
+quota_set_update['response_body']['required'] = ['quota_class_set']
diff --git a/tempest/api_schema/compute/v2/servers.py b/tempest/api_schema/compute/v2/servers.py
index fe53abd..dc4054c 100644
--- a/tempest/api_schema/compute/v2/servers.py
+++ b/tempest/api_schema/compute/v2/servers.py
@@ -25,10 +25,7 @@
             'server': {
                 'type': 'object',
                 'properties': {
-                    # NOTE: Now the type of 'id' is uuid, but here allows
-                    # 'integer' also because old OpenStack uses 'integer'
-                    # as a server id.
-                    'id': {'type': ['integer', 'string']},
+                    'id': {'type': 'string'},
                     'security_groups': {'type': 'array'},
                     'links': parameter_types.links,
                     'adminPass': {'type': 'string'},
@@ -46,7 +43,7 @@
     }
 }
 
-update_server = copy.deepcopy(servers.base_update_server)
+update_server = copy.deepcopy(servers.base_update_get_server)
 update_server['response_body']['properties']['server']['properties'].update({
     'hostId': {'type': 'string'},
     'OS-DCF:diskConfig': {'type': 'string'},
@@ -60,6 +57,39 @@
     'hostId'
 )
 
+get_server = copy.deepcopy(servers.base_update_get_server)
+get_server['response_body']['properties']['server']['properties'].update({
+    'key_name': {'type': ['string', 'null']},
+    'hostId': {'type': 'string'},
+
+    # NOTE: Non-admin users also can see "OS-SRV-USG" and "OS-EXT-AZ"
+    # attributes.
+    'OS-SRV-USG:launched_at': {'type': ['string', 'null']},
+    'OS-SRV-USG:terminated_at': {'type': ['string', 'null']},
+    'OS-EXT-AZ:availability_zone': {'type': 'string'},
+
+    # NOTE: Admin users only can see "OS-EXT-STS" and "OS-EXT-SRV-ATTR"
+    # attributes.
+    'OS-EXT-STS:task_state': {'type': ['string', 'null']},
+    'OS-EXT-STS:vm_state': {'type': 'string'},
+    'OS-EXT-STS:power_state': {'type': 'integer'},
+    'OS-EXT-SRV-ATTR:host': {'type': ['string', 'null']},
+    'OS-EXT-SRV-ATTR:instance_name': {'type': 'string'},
+    'OS-EXT-SRV-ATTR:hypervisor_hostname': {'type': ['string', 'null']},
+    'os-extended-volumes:volumes_attached': {'type': 'array'},
+    'OS-DCF:diskConfig': {'type': 'string'},
+    'accessIPv4': parameter_types.access_ip_v4,
+    'accessIPv6': parameter_types.access_ip_v6,
+    'config_drive': {'type': 'string'}
+})
+get_server['response_body']['properties']['server']['required'].append(
+    # NOTE: OS-SRV-USG, OS-EXT-AZ, OS-EXT-STS, OS-EXT-SRV-ATTR,
+    # os-extended-volumes, OS-DCF and accessIPv4/v6 are API
+    # extension, and some environments return a response without
+    # these attributes. So they are not 'required'.
+    'hostId'
+)
+
 list_virtual_interfaces = {
     'status_code': [200],
     'response_body': {
@@ -178,6 +208,20 @@
     'status_code': [204]
 }
 
+list_server_groups = {
+    'status_code': [200],
+    'response_body': {
+        'type': 'object',
+        'properties': {
+            'server_groups': {
+                'type': 'array',
+                'items': common_server_group
+            }
+        },
+        'required': ['server_groups']
+    }
+}
+
 instance_actions_object = copy.deepcopy(servers.common_instance_actions)
 instance_actions_object[
     'properties'].update({'instance_uuid': {'type': 'string'}})
diff --git a/tempest/api_schema/compute/v2/volumes.py b/tempest/api_schema/compute/v2/volumes.py
index 84a659c..1af951f 100644
--- a/tempest/api_schema/compute/v2/volumes.py
+++ b/tempest/api_schema/compute/v2/volumes.py
@@ -38,7 +38,7 @@
                                 'id': {'type': 'string'},
                                 'device': {'type': 'string'},
                                 'volumeId': {'type': 'string'},
-                                'serverId': {'type': ['integer', 'string']}
+                                'serverId': {'type': 'string'}
                             }
                             # NOTE- If volume is not attached to any server
                             # then, 'attachments' attributes comes as array
@@ -86,7 +86,7 @@
                                     'id': {'type': 'string'},
                                     'device': {'type': 'string'},
                                     'volumeId': {'type': 'string'},
-                                    'serverId': {'type': ['integer', 'string']}
+                                    'serverId': {'type': 'string'}
                                 }
                                 # NOTE- If volume is not attached to any server
                                 # then, 'attachments' attributes comes as array
diff --git a/tempest/api_schema/compute/v3/servers.py b/tempest/api_schema/compute/v3/servers.py
index 4fb2d87..3b50516 100644
--- a/tempest/api_schema/compute/v3/servers.py
+++ b/tempest/api_schema/compute/v3/servers.py
@@ -25,10 +25,7 @@
             'server': {
                 'type': 'object',
                 'properties': {
-                    # NOTE: Now the type of 'id' is uuid, but here allows
-                    # 'integer' also because old OpenStack uses 'integer'
-                    # as a server id.
-                    'id': {'type': ['integer', 'string']},
+                    'id': {'type': 'string'},
                     'os-security-groups:security_groups': {'type': 'array'},
                     'links': parameter_types.links,
                     'admin_password': {'type': 'string'},
@@ -57,7 +54,7 @@
         ['type', 'mac_addr']
     )
 
-update_server = copy.deepcopy(servers.base_update_server)
+update_server = copy.deepcopy(servers.base_update_get_server)
 update_server['response_body']['properties']['server']['properties'].update({
     'addresses': addresses_v3,
     'host_id': {'type': 'string'},
@@ -71,6 +68,43 @@
     'host_id'
 )
 
+get_server = copy.deepcopy(servers.base_update_get_server)
+get_server['response_body']['properties']['server']['properties'].update({
+    'key_name': {'type': ['string', 'null']},
+    'host_id': {'type': 'string'},
+
+    # NOTE: Non-admin users also can see "os-server-usage" and
+    # "os-extended-availability-zone" attributes.
+    'os-server-usage:launched_at': {'type': ['string', 'null']},
+    'os-server-usage:terminated_at': {'type': ['string', 'null']},
+    'os-extended-availability-zone:availability_zone': {'type': 'string'},
+
+    # NOTE: Admin users only can see "os-extended-status" and
+    # "os-extended-server-attributes" attributes.
+    'os-extended-status:task_state': {'type': ['string', 'null']},
+    'os-extended-status:vm_state': {'type': 'string'},
+    'os-extended-status:power_state': {'type': 'integer'},
+    'os-extended-status:locked_by': {'type': ['string', 'null']},
+    'os-extended-server-attributes:host': {'type': ['string', 'null']},
+    'os-extended-server-attributes:instance_name': {'type': 'string'},
+    'os-extended-server-attributes:hypervisor_hostname': {
+        'type': ['string', 'null']
+    },
+    'os-extended-volumes:volumes_attached': {'type': 'array'},
+    'os-pci:pci_devices': {'type': 'array'},
+    'os-access-ips:access_ip_v4': parameter_types.access_ip_v4,
+    'os-access-ips:access_ip_v6': parameter_types.access_ip_v6,
+    'os-config-drive:config_drive': {'type': 'string'}
+})
+get_server['response_body']['properties']['server']['required'].append(
+    # NOTE: os-server-usage, os-extended-availability-zone,
+    # os-extended-status, os-extended-server-attributes,
+    # os-extended-volumes, os-pci, os-access-ips and
+    # os-config-driveare API extension, and some environments
+    # return a response without these attributes. So they are not 'required'.
+    'host_id'
+)
+
 attach_detach_volume = {
     'status_code': [202]
 }
diff --git a/tempest/cli/simple_read_only/test_cinder.py b/tempest/cli/simple_read_only/test_cinder.py
index e9a0cee..946b89e 100644
--- a/tempest/cli/simple_read_only/test_cinder.py
+++ b/tempest/cli/simple_read_only/test_cinder.py
@@ -50,13 +50,20 @@
         self.assertTableStruct(roles, ['Name', 'Value'])
 
     def test_cinder_backup_list(self):
-        self.cinder('backup-list')
+        backup_list = self.parser.listing(self.cinder('backup-list'))
+        self.assertTableStruct(backup_list, ['ID', 'Volume ID', 'Status',
+                                             'Name', 'Size', 'Object Count',
+                                             'Container'])
 
     def test_cinder_extra_specs_list(self):
-        self.cinder('extra-specs-list')
+        extra_specs_list = self.parser.listing(self.cinder('extra-specs-list'))
+        self.assertTableStruct(extra_specs_list, ['ID', 'Name', 'extra_specs'])
 
     def test_cinder_volumes_list(self):
-        self.cinder('list')
+        list = self.parser.listing(self.cinder('list'))
+        self.assertTableStruct(list, ['ID', 'Status', 'Name', 'Size',
+                                      'Volume Type', 'Bootable',
+                                      'Attached to'])
         self.cinder('list', params='--all-tenants 1')
         self.cinder('list', params='--all-tenants 0')
         self.assertRaises(subprocess.CalledProcessError,
@@ -85,44 +92,59 @@
         self.assertTableStruct(roles, ['Property', 'Value'])
 
     def test_cinder_rate_limits(self):
-        self.cinder('rate-limits')
+        rate_limits = self.parser.listing(self.cinder('rate-limits'))
+        self.assertTableStruct(rate_limits, ['Verb', 'URI', 'Value', 'Remain',
+                                             'Unit', 'Next_Available'])
 
     @testtools.skipUnless(CONF.volume_feature_enabled.snapshot,
                           'Volume snapshot not available.')
     def test_cinder_snapshot_list(self):
-        self.cinder('snapshot-list')
+        snapshot_list = self.parser.listing(self.cinder('snapshot-list'))
+        self.assertTableStruct(snapshot_list, ['ID', 'Volume ID', 'Status',
+                                               'Name', 'Size'])
 
     def test_cinder_type_list(self):
-        self.cinder('type-list')
+        type_list = self.parser.listing(self.cinder('type-list'))
+        self.assertTableStruct(type_list, ['ID', 'Name'])
 
     def test_cinder_list_extensions(self):
-        self.cinder('list-extensions')
         roles = self.parser.listing(self.cinder('list-extensions'))
         self.assertTableStruct(roles, ['Name', 'Summary', 'Alias', 'Updated'])
 
     def test_cinder_credentials(self):
-        self.cinder('credentials')
+        credentials = self.parser.listing(self.cinder('credentials'))
+        self.assertTableStruct(credentials, ['User Credentials', 'Value'])
 
     def test_cinder_availability_zone_list(self):
-        self.cinder('availability-zone-list')
+        zone_list = self.parser.listing(self.cinder('availability-zone-list'))
+        self.assertTableStruct(zone_list, ['Name', 'Status'])
 
     def test_cinder_endpoints(self):
-        self.cinder('endpoints')
+        endpoints = self.parser.listing(self.cinder('endpoints'))
+        self.assertTableStruct(endpoints, ['nova', 'Value'])
 
     def test_cinder_service_list(self):
-        self.cinder('service-list')
+        service_list = self.parser.listing(self.cinder('service-list'))
+        self.assertTableStruct(service_list, ['Binary', 'Host', 'Zone',
+                                              'Status', 'State', 'Updated_at',
+                                              'Disabled Reason'])
 
     def test_cinder_transfer_list(self):
-        self.cinder('transfer-list')
+        transfer_list = self.parser.listing(self.cinder('transfer-list'))
+        self.assertTableStruct(transfer_list, ['ID', 'Volume ID', 'Name'])
 
     def test_cinder_bash_completion(self):
         self.cinder('bash-completion')
 
     def test_cinder_qos_list(self):
-        self.cinder('qos-list')
+        qos_list = self.parser.listing(self.cinder('qos-list'))
+        self.assertTableStruct(qos_list, ['ID', 'Name', 'Consumer', 'specs'])
 
     def test_cinder_encryption_type_list(self):
-        self.cinder('encryption-type-list')
+        encrypt_list = self.parser.listing(self.cinder('encryption-type-list'))
+        self.assertTableStruct(encrypt_list, ['Volume Type ID', 'Provider',
+                                              'Cipher', 'Key Size',
+                                              'Control Location'])
 
     def test_admin_help(self):
         help_text = self.cinder('help')
diff --git a/tempest/cli/simple_read_only/test_neutron.py b/tempest/cli/simple_read_only/test_neutron.py
index c1d58b5..49d079e 100644
--- a/tempest/cli/simple_read_only/test_neutron.py
+++ b/tempest/cli/simple_read_only/test_neutron.py
@@ -49,7 +49,8 @@
 
     @test.attr(type='smoke')
     def test_neutron_net_list(self):
-        self.neutron('net-list')
+        net_list = self.parser.listing(self.neutron('net-list'))
+        self.assertTableStruct(net_list, ['id', 'name', 'subnets'])
 
     @test.attr(type='smoke')
     def test_neutron_ext_list(self):
@@ -111,11 +112,14 @@
     @test.attr(type='smoke')
     @test.requires_ext(extension='external-net', service='network')
     def test_neutron_net_external_list(self):
-        self.neutron('net-external-list')
+        net_ext_list = self.parser.listing(self.neutron('net-external-list'))
+        self.assertTableStruct(net_ext_list, ['id', 'name', 'subnets'])
 
     @test.attr(type='smoke')
     def test_neutron_port_list(self):
-        self.neutron('port-list')
+        port_list = self.parser.listing(self.neutron('port-list'))
+        self.assertTableStruct(port_list, ['id', 'name', 'mac_address',
+                                           'fixed_ips'])
 
     @test.attr(type='smoke')
     @test.requires_ext(extension='quotas', service='network')
@@ -125,7 +129,9 @@
     @test.attr(type='smoke')
     @test.requires_ext(extension='router', service='network')
     def test_neutron_router_list(self):
-        self.neutron('router-list')
+        router_list = self.parser.listing(self.neutron('router-list'))
+        self.assertTableStruct(router_list, ['id', 'name',
+                                             'external_gateway_info'])
 
     @test.attr(type='smoke')
     @test.requires_ext(extension='security-group', service='network')
@@ -136,11 +142,18 @@
     @test.attr(type='smoke')
     @test.requires_ext(extension='security-group', service='network')
     def test_neutron_security_group_rule_list(self):
-        self.neutron('security-group-rule-list')
+        security_grp = self.parser.listing(self.neutron
+                                           ('security-group-rule-list'))
+        self.assertTableStruct(security_grp, ['id', 'security_group',
+                                              'direction', 'protocol',
+                                              'remote_ip_prefix',
+                                              'remote_group'])
 
     @test.attr(type='smoke')
     def test_neutron_subnet_list(self):
-        self.neutron('subnet-list')
+        subnet_list = self.parser.listing(self.neutron('subnet-list'))
+        self.assertTableStruct(subnet_list, ['id', 'name', 'cidr',
+                                             'allocation_pools'])
 
     @test.attr(type='smoke')
     def test_neutron_help(self):
diff --git a/tempest/clients.py b/tempest/clients.py
index 4050a20..4e2205e 100644
--- a/tempest/clients.py
+++ b/tempest/clients.py
@@ -50,6 +50,7 @@
 from tempest.services.compute.json.limits_client import LimitsClientJSON
 from tempest.services.compute.json.migrations_client import \
     MigrationsClientJSON
+from tempest.services.compute.json.quotas_client import QuotaClassesClientJSON
 from tempest.services.compute.json.quotas_client import QuotasClientJSON
 from tempest.services.compute.json.security_groups_client import \
     SecurityGroupsClientJSON
@@ -105,6 +106,7 @@
     InterfacesClientXML
 from tempest.services.compute.xml.keypairs_client import KeyPairsClientXML
 from tempest.services.compute.xml.limits_client import LimitsClientXML
+from tempest.services.compute.xml.quotas_client import QuotaClassesClientXML
 from tempest.services.compute.xml.quotas_client import QuotasClientXML
 from tempest.services.compute.xml.security_groups_client \
     import SecurityGroupsClientXML
@@ -220,6 +222,8 @@
             self.images_client = ImagesClientXML(self.auth_provider)
             self.keypairs_client = KeyPairsClientXML(self.auth_provider)
             self.quotas_client = QuotasClientXML(self.auth_provider)
+            self.quota_classes_client = QuotaClassesClientXML(
+                self.auth_provider)
             self.flavors_client = FlavorsClientXML(self.auth_provider)
             self.extensions_client = ExtensionsClientXML(self.auth_provider)
             self.volumes_extensions_client = VolumesExtensionsClientXML(
@@ -288,6 +292,8 @@
             self.keypairs_v3_client = KeyPairsV3ClientJSON(
                 self.auth_provider)
             self.quotas_client = QuotasClientJSON(self.auth_provider)
+            self.quota_classes_client = QuotaClassesClientJSON(
+                self.auth_provider)
             self.quotas_v3_client = QuotasV3ClientJSON(self.auth_provider)
             self.flavors_client = FlavorsClientJSON(self.auth_provider)
             self.flavors_v3_client = FlavorsV3ClientJSON(self.auth_provider)
diff --git a/tempest/common/commands.py b/tempest/common/commands.py
index 6720847..2ab008d 100644
--- a/tempest/common/commands.py
+++ b/tempest/common/commands.py
@@ -50,7 +50,7 @@
 
 
 def iptables_raw(table):
-    return sudo_cmd_call("iptables -v -S -t " + table)
+    return sudo_cmd_call("iptables --line-numbers -L -nv -t " + table)
 
 
 def ip_ns_list():
diff --git a/tempest/config.py b/tempest/config.py
index 6475844..0796d98 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -942,6 +942,9 @@
     cfg.BoolOpt('driver_enabled',
                 default=False,
                 help="Whether the Ironic nova-compute driver is enabled"),
+    cfg.StrOpt('driver',
+               default='fake',
+               help="Driver name which Ironic uses"),
     cfg.StrOpt('endpoint_type',
                default='publicURL',
                choices=['public', 'admin', 'internal',
diff --git a/tempest/hacking/checks.py b/tempest/hacking/checks.py
index 4e35aaa..93329bc 100644
--- a/tempest/hacking/checks.py
+++ b/tempest/hacking/checks.py
@@ -105,9 +105,24 @@
                             "T107: service tag should not be in path")
 
 
+def no_official_client_manager_in_api_tests(physical_line, filename):
+    """Check that the OfficialClientManager isn't used in the api tests
+
+    The api tests should not use the official clients.
+
+    T108: Can not use OfficialClientManager in the API tests
+    """
+    if 'tempest/api' in filename:
+        if 'OfficialClientManager' in physical_line:
+            return (physical_line.find('OfficialClientManager'),
+                    'T108: OfficialClientManager can not be used in the api '
+                    'tests')
+
+
 def factory(register):
     register(import_no_clients_in_api)
     register(scenario_tests_need_service_tags)
     register(no_setupclass_for_unit_tests)
     register(no_vi_headers)
     register(service_tags_not_in_module_path)
+    register(no_official_client_manager_in_api_tests)
diff --git a/tempest/scenario/manager.py b/tempest/scenario/manager.py
index 07d8828..ca79325 100644
--- a/tempest/scenario/manager.py
+++ b/tempest/scenario/manager.py
@@ -21,6 +21,8 @@
 import subprocess
 import time
 
+from cinderclient import exceptions as cinder_exceptions
+import glanceclient
 from heatclient import exc as heat_exceptions
 import netaddr
 from neutronclient.common import exceptions as exc
@@ -83,8 +85,6 @@
         cls.orchestration_client = cls.manager.orchestration_client
         cls.data_processing_client = cls.manager.data_processing_client
         cls.ceilometer_client = cls.manager.ceilometer_client
-        cls.resource_keys = {}
-        cls.os_resources = []
 
     @classmethod
     def _get_credentials(cls, get_creds, ctype):
@@ -109,72 +109,85 @@
         return cls._get_credentials(cls.isolated_creds.get_admin_creds,
                                     'identity_admin')
 
-    @staticmethod
-    def cleanup_resource(resource, test_name):
+    def setUp(self):
+        super(OfficialClientTest, self).setUp()
+        self.cleanup_waits = []
+        # NOTE(mtreinish) This is safe to do in setUp instead of setUp class
+        # because scenario tests in the same test class should not share
+        # resources. If resources were shared between test cases then it
+        # should be a single scenario test instead of multiples.
 
-        LOG.debug("Deleting %r from shared resources of %s" %
-                  (resource, test_name))
+        # NOTE(yfried): this list is cleaned at the end of test_methods and
+        # not at the end of the class
+        self.addCleanup(self._wait_for_cleanups)
+
+    @staticmethod
+    def not_found_exception(exception):
+        """
+        @return: True if exception is of NotFound type
+        """
+        NOT_FOUND_LIST = ['NotFound', 'HTTPNotFound']
+        return (exception.__class__.__name__ in NOT_FOUND_LIST
+                or
+                hasattr(exception, 'status_code') and
+                exception.status_code == 404)
+
+    def delete_wrapper(self, thing):
+        """Ignores NotFound exceptions for delete operations.
+
+        @param thing: object with delete() method.
+            OpenStack resources are assumed to have a delete() method which
+            destroys the resource
+        """
+
         try:
-            # OpenStack resources are assumed to have a delete()
-            # method which destroys the resource...
-            resource.delete()
+            thing.delete()
         except Exception as e:
             # If the resource is already missing, mission accomplished.
-            # - Status code tolerated as a workaround for bug 1247568
-            # - HTTPNotFound tolerated as this is currently raised when
-            # attempting to delete an already-deleted heat stack.
-            if (e.__class__.__name__ in ('NotFound', 'HTTPNotFound') or
-                    (hasattr(e, 'status_code') and e.status_code == 404)):
-                return
-            raise
-
-        def is_deletion_complete():
-            # Deletion testing is only required for objects whose
-            # existence cannot be checked via retrieval.
-            if isinstance(resource, dict):
-                return True
-            try:
-                resource.get()
-            except Exception as e:
-                # Clients are expected to return an exception
-                # called 'NotFound' if retrieval fails.
-                if e.__class__.__name__ == 'NotFound':
-                    return True
+            if not self.not_found_exception(e):
                 raise
-            return False
 
-        # Block until resource deletion has completed or timed-out
-        tempest.test.call_until_true(is_deletion_complete, 10, 1)
+    def _wait_for_cleanups(self):
+        """To handle async delete actions, a list of waits is added
+        which will be iterated over as the last step of clearing the
+        cleanup queue. That way all the delete calls are made up front
+        and the tests won't succeed unless the deletes are eventually
+        successful. This is the same basic approach used in the api tests to
+        limit cleanup execution time except here it is multi-resource,
+        because of the nature of the scenario tests.
+        """
+        for wait in self.cleanup_waits:
+            self.delete_timeout(**wait)
 
-    @classmethod
-    def tearDownClass(cls):
-        # NOTE(jaypipes): Because scenario tests are typically run in a
-        # specific order, and because test methods in scenario tests
-        # generally create resources in a particular order, we destroy
-        # resources in the reverse order in which resources are added to
-        # the scenario test class object
-        while cls.os_resources:
-            thing = cls.os_resources.pop()
-            cls.cleanup_resource(thing, cls.__name__)
-        cls.isolated_creds.clear_isolated_creds()
-        super(OfficialClientTest, cls).tearDownClass()
+    def addCleanup_with_wait(self, things, thing_id,
+                             error_status='ERROR',
+                             exc_type=nova_exceptions.NotFound,
+                             cleanup_callable=None, cleanup_args=[],
+                             cleanup_kwargs={}):
+        """Adds wait for ansyc resource deletion at the end of cleanups
 
-    @classmethod
-    def set_resource(cls, key, thing):
-        LOG.debug("Adding %r to shared resources of %s" %
-                  (thing, cls.__name__))
-        cls.resource_keys[key] = thing
-        cls.os_resources.append(thing)
-
-    @classmethod
-    def get_resource(cls, key):
-        return cls.resource_keys[key]
-
-    @classmethod
-    def remove_resource(cls, key):
-        thing = cls.resource_keys[key]
-        cls.os_resources.remove(thing)
-        del cls.resource_keys[key]
+        @param things: type of the resource to delete
+        @param thing_id:
+        @param error_status: see manager.delete_timeout()
+        @param exc_type: see manager.delete_timeout()
+        @param cleanup_callable: method to load pass to self.addCleanup with
+            the following *cleanup_args, **cleanup_kwargs.
+            usually a delete method. if not used, will try to use:
+            things.delete(thing_id)
+        """
+        if cleanup_callable is None:
+            LOG.debug("no delete method passed. using {rclass}.delete({id}) as"
+                      " default".format(rclass=things, id=thing_id))
+            self.addCleanup(things.delete, thing_id)
+        else:
+            self.addCleanup(cleanup_callable, *cleanup_args, **cleanup_kwargs)
+        wait_dict = {
+            'things': things,
+            'thing_id': thing_id,
+            'error_status': error_status,
+            'not_found_exception': exc_type,
+        }
+        self.cleanup_waits.append(wait_dict)
 
     def status_timeout(self, things, thing_id, expected_status,
                        error_status='ERROR',
@@ -226,8 +239,11 @@
             except not_found_exception:
                 if allow_notfound:
                     return True
-                else:
-                    raise
+                raise
+            except Exception as e:
+                if allow_notfound and self.not_found_exception(e):
+                    return True
+                raise
 
             new_status = thing.status
 
@@ -287,6 +303,7 @@
         for ruleset in rulesets:
             sg_rule = client.security_group_rules.create(secgroup_id,
                                                          **ruleset)
+            self.addCleanup(self.delete_wrapper, sg_rule)
             rules.append(sg_rule)
         return rules
 
@@ -300,7 +317,7 @@
         secgroup = client.security_groups.create(sg_name, sg_desc)
         self.assertEqual(secgroup.name, sg_name)
         self.assertEqual(secgroup.description, sg_desc)
-        self.set_resource(sg_name, secgroup)
+        self.addCleanup(self.delete_wrapper, secgroup)
 
         # Add rules to the security group
         self._create_loginable_secgroup_rule_nova(client, secgroup.id)
@@ -308,7 +325,17 @@
         return secgroup
 
     def create_server(self, client=None, name=None, image=None, flavor=None,
-                      wait=True, create_kwargs={}):
+                      wait_on_boot=True, wait_on_delete=True,
+                      create_kwargs={}):
+        """Creates VM instance.
+
+        @param client: compute client to create the instance
+        @param image: image from which to create the instance
+        @param wait_on_boot: wait for status ACTIVE before continue
+        @param wait_on_delete: force synchronous delete on cleanup
+        @param create_kwargs: additional details for instance creation
+        @return: client.server object
+        """
         if client is None:
             client = self.compute_client
         if name is None:
@@ -342,19 +369,25 @@
                   name, image, flavor)
         server = client.servers.create(name, image, flavor, **create_kwargs)
         self.assertEqual(server.name, name)
-        self.set_resource(name, server)
-        if wait:
+        if wait_on_delete:
+            self.addCleanup(self.delete_timeout,
+                            self.compute_client.servers,
+                            server.id)
+        self.addCleanup_with_wait(self.compute_client.servers, server.id,
+                                  cleanup_callable=self.delete_wrapper,
+                                  cleanup_args=[server])
+        if wait_on_boot:
             self.status_timeout(client.servers, server.id, 'ACTIVE')
         # The instance retrieved on creation is missing network
         # details, necessitating retrieval after it becomes active to
         # ensure correct details.
         server = client.servers.get(server.id)
-        self.set_resource(name, server)
         LOG.debug("Created server: %s", server)
         return server
 
     def create_volume(self, client=None, size=1, name=None,
-                      snapshot_id=None, imageRef=None):
+                      snapshot_id=None, imageRef=None, volume_type=None,
+                      wait_on_delete=True):
         if client is None:
             client = self.volume_client
         if name is None:
@@ -362,8 +395,14 @@
         LOG.debug("Creating a volume (size: %s, name: %s)", size, name)
         volume = client.volumes.create(size=size, display_name=name,
                                        snapshot_id=snapshot_id,
-                                       imageRef=imageRef)
-        self.set_resource(name, volume)
+                                       imageRef=imageRef,
+                                       volume_type=volume_type)
+        if wait_on_delete:
+            self.addCleanup(self.delete_timeout,
+                            self.volume_client.volumes,
+                            volume.id)
+        self.addCleanup_with_wait(self.volume_client.volumes, volume.id,
+                                  exc_type=cinder_exceptions.NotFound)
         self.assertEqual(name, volume.display_name)
         self.status_timeout(client.volumes, volume.id, 'available')
         LOG.debug("Created volume: %s", volume)
@@ -379,7 +418,8 @@
             name = data_utils.rand_name('scenario-snapshot-')
         LOG.debug("Creating a snapshot image for server: %s", server.name)
         image_id = compute_client.servers.create_image(server, name)
-        self.addCleanup(image_client.images.delete, image_id)
+        self.addCleanup_with_wait(self.image_client.images, image_id,
+                                  exc_type=glanceclient.exc.HTTPNotFound)
         self.status_timeout(image_client.images, image_id, 'active')
         snapshot_image = image_client.images.get(image_id)
         self.assertEqual(name, snapshot_image.name)
@@ -394,7 +434,7 @@
             name = data_utils.rand_name('scenario-keypair-')
         keypair = client.keypairs.create(name)
         self.assertEqual(keypair.name, name)
-        self.set_resource(name, keypair)
+        self.addCleanup(self.delete_wrapper, keypair)
         return keypair
 
     def get_remote_client(self, server_or_ip, username=None, private_key=None):
@@ -588,9 +628,12 @@
             'key_name': self.keypair.id
         }
         self.instance = self.create_server(
-            wait=False, create_kwargs=create_kwargs)
+            wait_on_boot=False, create_kwargs=create_kwargs)
 
-        self.set_resource('instance', self.instance)
+        self.addCleanup_with_wait(self.compute_client.servers,
+                                  self.instance.id,
+                                  cleanup_callable=self.delete_wrapper,
+                                  cleanup_args=[self.instance])
 
         self.wait_node(self.instance.id)
         self.node = self.get_node(instance_id=self.instance.id)
@@ -615,7 +658,6 @@
 
     def terminate_instance(self):
         self.instance.delete()
-        self.remove_resource('instance')
         self.wait_power_state(self.node.uuid, BaremetalPowerStates.POWER_OFF)
         self.wait_provisioning_state(
             self.node.uuid,
@@ -623,6 +665,75 @@
             timeout=CONF.baremetal.unprovision_timeout)
 
 
+class EncryptionScenarioTest(OfficialClientTest):
+    """
+    Base class for encryption scenario tests
+    """
+
+    @classmethod
+    def setUpClass(cls):
+        super(EncryptionScenarioTest, cls).setUpClass()
+
+        # use admin credentials to create encrypted volume types
+        admin_creds = cls.admin_credentials()
+        manager = clients.OfficialClientManager(credentials=admin_creds)
+        cls.admin_volume_client = manager.volume_client
+
+    def _wait_for_volume_status(self, status):
+        self.status_timeout(
+            self.volume_client.volumes, self.volume.id, status)
+
+    def nova_boot(self):
+        self.keypair = self.create_keypair()
+        create_kwargs = {'key_name': self.keypair.name}
+        self.server = self.create_server(self.compute_client,
+                                         image=self.image,
+                                         create_kwargs=create_kwargs)
+
+    def create_volume_type(self, client=None, name=None):
+        if not client:
+            client = self.admin_volume_client
+        if not name:
+            name = 'generic'
+        randomized_name = data_utils.rand_name('scenario-type-' + name + '-')
+        LOG.debug("Creating a volume type: %s", randomized_name)
+        volume_type = client.volume_types.create(randomized_name)
+        self.addCleanup(client.volume_types.delete, volume_type.id)
+        return volume_type
+
+    def create_encryption_type(self, client=None, type_id=None, provider=None,
+                               key_size=None, cipher=None,
+                               control_location=None):
+        if not client:
+            client = self.admin_volume_client
+        if not type_id:
+            volume_type = self.create_volume_type()
+            type_id = volume_type.id
+        LOG.debug("Creating an encryption type for volume type: %s", type_id)
+        client.volume_encryption_types.create(type_id,
+                                              {'provider': provider,
+                                               'key_size': key_size,
+                                               'cipher': cipher,
+                                               'control_location':
+                                               control_location})
+
+    def nova_volume_attach(self):
+        attach_volume_client = self.compute_client.volumes.create_server_volume
+        volume = attach_volume_client(self.server.id,
+                                      self.volume.id,
+                                      '/dev/vdb')
+        self.assertEqual(self.volume.id, volume.id)
+        self._wait_for_volume_status('in-use')
+
+    def nova_volume_detach(self):
+        detach_volume_client = self.compute_client.volumes.delete_server_volume
+        detach_volume_client(self.server.id, self.volume.id)
+        self._wait_for_volume_status('available')
+
+        volume = self.volume_client.volumes.get(self.volume.id)
+        self.assertEqual('available', volume.status)
+
+
 class NetworkScenarioTest(OfficialClientTest):
     """
     Base class for network scenario tests
@@ -660,7 +771,7 @@
         network = net_common.DeletableNetwork(client=self.network_client,
                                               **result['network'])
         self.assertEqual(network.name, name)
-        self.set_resource(name, network)
+        self.addCleanup(self.delete_wrapper, network)
         return network
 
     def _list_networks(self, **kwargs):
@@ -736,7 +847,7 @@
         subnet = net_common.DeletableSubnet(client=self.network_client,
                                             **result['subnet'])
         self.assertEqual(subnet.cidr, str_cidr)
-        self.set_resource(data_utils.rand_name(namestart), subnet)
+        self.addCleanup(self.delete_wrapper, subnet)
         return subnet
 
     def _create_port(self, network, namestart='port-quotatest-'):
@@ -749,7 +860,7 @@
         self.assertIsNotNone(result, 'Unable to allocate port')
         port = net_common.DeletablePort(client=self.network_client,
                                         **result['port'])
-        self.set_resource(name, port)
+        self.addCleanup(self.delete_wrapper, port)
         return port
 
     def _get_server_port_id(self, server, ip_addr=None):
@@ -772,7 +883,7 @@
         floating_ip = net_common.DeletableFloatingIp(
             client=self.network_client,
             **result['floatingip'])
-        self.set_resource(data_utils.rand_name('floatingip-'), floating_ip)
+        self.addCleanup(self.delete_wrapper, floating_ip)
         return floating_ip
 
     def _associate_floating_ip(self, floating_ip, server):
@@ -817,7 +928,7 @@
         pool = net_common.DeletablePool(client=self.network_client,
                                         **resp['pool'])
         self.assertEqual(pool['name'], name)
-        self.set_resource(name, pool)
+        self.addCleanup(self.delete_wrapper, pool)
         return pool
 
     def _create_member(self, address, protocol_port, pool_id):
@@ -832,7 +943,7 @@
         resp = self.network_client.create_member(body)
         member = net_common.DeletableMember(client=self.network_client,
                                             **resp['member'])
-        self.set_resource(data_utils.rand_name('member-'), member)
+        self.addCleanup(self.delete_wrapper, member)
         return member
 
     def _create_vip(self, protocol, protocol_port, subnet_id, pool_id):
@@ -851,7 +962,7 @@
         vip = net_common.DeletableVip(client=self.network_client,
                                       **resp['vip'])
         self.assertEqual(vip['name'], name)
-        self.set_resource(name, vip)
+        self.addCleanup(self.delete_wrapper, vip)
         return vip
 
     def _check_vm_connectivity(self, ip_address,
@@ -993,7 +1104,7 @@
         self.assertEqual(secgroup.name, sg_name)
         self.assertEqual(tenant_id, secgroup.tenant_id)
         self.assertEqual(secgroup.description, sg_desc)
-        self.set_resource(sg_name, secgroup)
+        self.addCleanup(self.delete_wrapper, secgroup)
         return secgroup
 
     def _default_security_group(self, tenant_id, client=None):
@@ -1052,6 +1163,7 @@
             client=client,
             **sg_rule['security_group_rule']
         )
+        self.addCleanup(self.delete_wrapper, sg_rule)
         self.assertEqual(secgroup.tenant_id, sg_rule.tenant_id)
         self.assertEqual(secgroup.id, sg_rule.security_group_id)
 
@@ -1150,7 +1262,7 @@
         router = net_common.DeletableRouter(client=self.network_client,
                                             **result['router'])
         self.assertEqual(router.name, name)
-        self.set_resource(name, router)
+        self.addCleanup(self.delete_wrapper, router)
         return router
 
     def _create_networks(self, tenant_id=None):
diff --git a/tempest/scenario/orchestration/test_autoscaling.py b/tempest/scenario/orchestration/test_autoscaling.py
index 82ba3c5..aa7b6f8 100644
--- a/tempest/scenario/orchestration/test_autoscaling.py
+++ b/tempest/scenario/orchestration/test_autoscaling.py
@@ -59,7 +59,7 @@
         # if a keypair was set, do not delete the stack on exit to allow
         # for manual post-mortums
         if not CONF.orchestration.keypair_name:
-            self.set_resource('stack', self.stack)
+            self.addCleanup(self.client.stacks.delete, self.stack)
 
     @test.skip_because(bug="1257575")
     @test.attr(type='slow')
diff --git a/tempest/scenario/test_aggregates_basic_ops.py b/tempest/scenario/test_aggregates_basic_ops.py
index 6817c48..0059619 100644
--- a/tempest/scenario/test_aggregates_basic_ops.py
+++ b/tempest/scenario/test_aggregates_basic_ops.py
@@ -42,13 +42,12 @@
         availability_zone = kwargs['availability_zone']
         self.assertEqual(aggregate.name, aggregate_name)
         self.assertEqual(aggregate.availability_zone, availability_zone)
-        self.set_resource(aggregate.id, aggregate)
+        self.addCleanup(self._delete_aggregate, aggregate)
         LOG.debug("Aggregate %s created." % (aggregate.name))
         return aggregate
 
     def _delete_aggregate(self, aggregate):
         self.compute_client.aggregates.delete(aggregate.id)
-        self.remove_resource(aggregate.id)
         LOG.debug("Aggregate %s deleted. " % (aggregate.name))
 
     def _get_host_name(self):
@@ -60,6 +59,7 @@
     def _add_host(self, aggregate_name, host):
         aggregate = self.compute_client.aggregates.add_host(aggregate_name,
                                                             host)
+        self.addCleanup(self._remove_host, aggregate, host)
         self.assertIn(host, aggregate.hosts)
         LOG.debug("Host %s added to Aggregate %s." % (host, aggregate.name))
 
@@ -128,6 +128,3 @@
         metadata.update(additional_metadata)
         self._check_aggregate_details(aggregate, aggregate.name, az, [host],
                                       metadata)
-
-        self._remove_host(aggregate, host)
-        self._delete_aggregate(aggregate)
diff --git a/tempest/scenario/test_encrypted_cinder_volumes.py b/tempest/scenario/test_encrypted_cinder_volumes.py
new file mode 100644
index 0000000..366cd93
--- /dev/null
+++ b/tempest/scenario/test_encrypted_cinder_volumes.py
@@ -0,0 +1,63 @@
+# Copyright (c) 2014 The Johns Hopkins University/Applied Physics Laboratory
+# 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.scenario import manager
+from tempest import test
+
+
+class TestEncryptedCinderVolumes(manager.EncryptionScenarioTest):
+
+    """
+    This test is for verifying the functionality of encrypted cinder volumes.
+
+    For both LUKS and cryptsetup encryption types, this test performs
+    the following:
+        * Creates an image in Glance
+        * Boots an instance from the image
+        * Creates an encryption type (as admin)
+        * Creates a volume of that encryption type (as a regular user)
+        * Attaches and detaches the encrypted volume to the instance
+    """
+
+    def launch_instance(self):
+        self.glance_image_create()
+        self.nova_boot()
+
+    def create_encrypted_volume(self, encryption_provider):
+        volume_type = self.create_volume_type(name='luks')
+        self.create_encryption_type(type_id=volume_type.id,
+                                    provider=encryption_provider,
+                                    key_size=512,
+                                    cipher='aes-xts-plain64',
+                                    control_location='front-end')
+        self.volume = self.create_volume(volume_type=volume_type.name)
+
+    def attach_detach_volume(self):
+        self.nova_volume_attach()
+        self.nova_volume_detach()
+
+    @test.services('compute', 'volume', 'image')
+    def test_encrypted_cinder_volumes_luks(self):
+        self.launch_instance()
+        self.create_encrypted_volume('nova.volume.encryptors.'
+                                     'luks.LuksEncryptor')
+        self.attach_detach_volume()
+
+    @test.services('compute', 'volume', 'image')
+    def test_encrypted_cinder_volumes_cryptsetup(self):
+        self.launch_instance()
+        self.create_encrypted_volume('nova.volume.encryptors.'
+                                     'cryptsetup.CryptsetupEncryptor')
+        self.attach_detach_volume()
\ No newline at end of file
diff --git a/tempest/scenario/test_large_ops.py b/tempest/scenario/test_large_ops.py
index ed5743c..15cf13b 100644
--- a/tempest/scenario/test_large_ops.py
+++ b/tempest/scenario/test_large_ops.py
@@ -60,7 +60,13 @@
         # needed because of bug 1199788
         self.servers = [x for x in client.servers.list() if name in x.name]
         for server in self.servers:
-            self.set_resource(server.name, server)
+            # after deleting all servers - wait for all servers to clear
+            # before cleanup continues
+            self.addCleanup(self.delete_timeout,
+                            self.compute_client.servers,
+                            server.id)
+        for server in self.servers:
+            self.addCleanup_with_wait(self.compute_client.servers, server.id)
         self._wait_for_server_status('ACTIVE')
 
     def _large_ops_scenario(self):
diff --git a/tempest/scenario/test_load_balancer_basic.py b/tempest/scenario/test_load_balancer_basic.py
index 826da48..800b3b0 100644
--- a/tempest/scenario/test_load_balancer_basic.py
+++ b/tempest/scenario/test_load_balancer_basic.py
@@ -74,15 +74,11 @@
         self.server_fixed_ips = {}
         self._create_security_group()
 
-    def cleanup_wrapper(self, resource):
-        self.cleanup_resource(resource, self.__class__.__name__)
-
     def _create_security_group(self):
         self.security_group = self._create_security_group_neutron(
             tenant_id=self.tenant_id)
         self._create_security_group_rules_for_port(self.port1)
         self._create_security_group_rules_for_port(self.port2)
-        self.addCleanup(self.cleanup_wrapper, self.security_group)
 
     def _create_security_group_rules_for_port(self, port):
         rule = {
@@ -99,7 +95,6 @@
 
     def _create_server(self, name):
         keypair = self.create_keypair(name='keypair-%s' % name)
-        self.addCleanup(self.cleanup_wrapper, keypair)
         security_groups = [self.security_group.name]
         net = self._list_networks(tenant_id=self.tenant_id)[0]
         create_kwargs = {
@@ -111,14 +106,12 @@
         }
         server = self.create_server(name=name,
                                     create_kwargs=create_kwargs)
-        self.addCleanup(self.cleanup_wrapper, server)
         self.servers_keypairs[server.id] = keypair
         if (config.network.public_network_id and not
                 config.network.tenant_networks_reachable):
             public_network_id = config.network.public_network_id
             floating_ip = self._create_floating_ip(
                 server, public_network_id)
-            self.addCleanup(self.cleanup_wrapper, floating_ip)
             self.floating_ips[floating_ip] = server
             self.server_ips[server.id] = floating_ip.floating_ip_address
         else:
@@ -211,7 +204,6 @@
             lb_method='ROUND_ROBIN',
             protocol='HTTP',
             subnet_id=self.subnet.id)
-        self.addCleanup(self.cleanup_wrapper, self.pool)
         self.assertTrue(self.pool)
 
     def _create_members(self):
@@ -227,17 +219,14 @@
                 member1 = self._create_member(address=ip,
                                               protocol_port=self.port1,
                                               pool_id=self.pool.id)
-                self.addCleanup(self.cleanup_wrapper, member1)
                 member2 = self._create_member(address=ip,
                                               protocol_port=self.port2,
                                               pool_id=self.pool.id)
-                self.addCleanup(self.cleanup_wrapper, member2)
                 self.members.extend([member1, member2])
             else:
                 member = self._create_member(address=ip,
                                              protocol_port=self.port1,
                                              pool_id=self.pool.id)
-                self.addCleanup(self.cleanup_wrapper, member)
                 self.members.append(member)
         self.assertTrue(self.members)
 
@@ -246,7 +235,6 @@
         port_id = vip.port_id
         floating_ip = self._create_floating_ip(vip, public_network_id,
                                                port_id=port_id)
-        self.addCleanup(self.cleanup_wrapper, floating_ip)
         self.floating_ips.setdefault(vip.id, [])
         self.floating_ips[vip.id].append(floating_ip)
 
@@ -257,7 +245,6 @@
                                     protocol_port=80,
                                     subnet_id=self.subnet.id,
                                     pool_id=self.pool.id)
-        self.addCleanup(self.cleanup_wrapper, self.vip)
         self.status_timeout(NeutronRetriever(self.network_client,
                                              self.network_client.vip_path,
                                              net_common.DeletableVip),
@@ -271,6 +258,13 @@
         else:
             self.vip_ip = self.vip.address
 
+        # Currently the ovs-agent is not enforcing security groups on the
+        # vip port - see https://bugs.launchpad.net/neutron/+bug/1163569
+        # However the linuxbridge-agent does, and it is necessary to add a
+        # security group with a rule that allows tcp port 80 to the vip port.
+        body = {'port': {'security_groups': [self.security_group.id]}}
+        self.network_client.update_port(self.vip.port_id, body)
+
     def _check_load_balancing(self):
         """
         1. Send 10 requests on the floating ip associated with the VIP
diff --git a/tempest/scenario/test_minimum_basic.py b/tempest/scenario/test_minimum_basic.py
index 0406217..29fdc74 100644
--- a/tempest/scenario/test_minimum_basic.py
+++ b/tempest/scenario/test_minimum_basic.py
@@ -85,7 +85,7 @@
 
     def nova_floating_ip_create(self):
         self.floating_ip = self.compute_client.floating_ips.create()
-        self.addCleanup(self.floating_ip.delete)
+        self.addCleanup(self.delete_wrapper, self.floating_ip)
 
     def nova_floating_ip_add(self):
         self.server.add_floating_ip(self.floating_ip)
diff --git a/tempest/scenario/test_network_advanced_server_ops.py b/tempest/scenario/test_network_advanced_server_ops.py
index f1cd320..431de9a 100644
--- a/tempest/scenario/test_network_advanced_server_ops.py
+++ b/tempest/scenario/test_network_advanced_server_ops.py
@@ -50,23 +50,15 @@
             cls.enabled = False
             raise cls.skipException(msg)
 
-    def cleanup_wrapper(self, resource):
-        self.cleanup_resource(resource, self.__class__.__name__)
-
     def setUp(self):
         super(TestNetworkAdvancedServerOps, self).setUp()
         key_name = data_utils.rand_name('keypair-smoke-')
         self.keypair = self.create_keypair(name=key_name)
-        self.addCleanup(self.cleanup_wrapper, self.keypair)
         security_group =\
             self._create_security_group_neutron(tenant_id=self.tenant_id)
-        self.addCleanup(self.cleanup_wrapper, security_group)
         network = self._create_network(self.tenant_id)
-        self.addCleanup(self.cleanup_wrapper, network)
         router = self._get_router(self.tenant_id)
-        self.addCleanup(self.cleanup_wrapper, router)
         subnet = self._create_subnet(network)
-        self.addCleanup(self.cleanup_wrapper, subnet)
         subnet.add_to_router(router.id)
         public_network_id = CONF.network.public_network_id
         create_kwargs = {
@@ -79,10 +71,8 @@
         server_name = data_utils.rand_name('server-smoke-%d-')
         self.server = self.create_server(name=server_name,
                                          create_kwargs=create_kwargs)
-        self.addCleanup(self.cleanup_wrapper, self.server)
         self.floating_ip = self._create_floating_ip(self.server,
                                                     public_network_id)
-        self.addCleanup(self.cleanup_wrapper, self.floating_ip)
 
     def _check_network_connectivity(self, should_connect=True):
         username = CONF.compute.image_ssh_user
diff --git a/tempest/scenario/test_network_basic_ops.py b/tempest/scenario/test_network_basic_ops.py
index c84d4b9..7dc817d 100644
--- a/tempest/scenario/test_network_basic_ops.py
+++ b/tempest/scenario/test_network_basic_ops.py
@@ -96,17 +96,11 @@
                 raise cls.skipException(msg)
         cls.check_preconditions()
 
-    def cleanup_wrapper(self, resource):
-        self.cleanup_resource(resource, self.__class__.__name__)
-
     def setUp(self):
         super(TestNetworkBasicOps, self).setUp()
         self.security_group = \
             self._create_security_group_neutron(tenant_id=self.tenant_id)
-        self.addCleanup(self.cleanup_wrapper, self.security_group)
         self.network, self.subnet, self.router = self._create_networks()
-        for r in [self.network, self.router, self.subnet]:
-            self.addCleanup(self.cleanup_wrapper, r)
         self.check_networks()
         self.servers = {}
         name = data_utils.rand_name('server-smoke')
@@ -144,7 +138,6 @@
 
     def _create_server(self, name, network):
         keypair = self.create_keypair(name='keypair-%s' % name)
-        self.addCleanup(self.cleanup_wrapper, keypair)
         security_groups = [self.security_group.name]
         create_kwargs = {
             'nics': [
@@ -154,7 +147,6 @@
             'security_groups': security_groups,
         }
         server = self.create_server(name=name, create_kwargs=create_kwargs)
-        self.addCleanup(self.cleanup_wrapper, server)
         return dict(server=server, keypair=keypair)
 
     def _check_tenant_network_connectivity(self):
@@ -171,7 +163,6 @@
         for server in self.servers.keys():
             floating_ip = self._create_floating_ip(server, public_network_id)
             self.floating_ip_tuple = Floating_IP_tuple(floating_ip, server)
-            self.addCleanup(self.cleanup_wrapper, floating_ip)
 
     def _check_public_network_connectivity(self, should_connect=True,
                                            msg=None):
@@ -204,11 +195,9 @@
 
     def _create_new_network(self):
         self.new_net = self._create_network(self.tenant_id)
-        self.addCleanup(self.cleanup_wrapper, self.new_net)
         self.new_subnet = self._create_subnet(
             network=self.new_net,
             gateway_ip=None)
-        self.addCleanup(self.cleanup_wrapper, self.new_subnet)
 
     def _hotplug_server(self):
         old_floating_ip, server = self.floating_ip_tuple
@@ -226,7 +215,10 @@
                                                      port_id=None,
                                                      fixed_ip=None)
         # move server to the head of the cleanup list
-        self.addCleanup(self.cleanup_wrapper, server)
+        self.addCleanup(self.delete_timeout,
+                        self.compute_client.servers,
+                        server.id)
+        self.addCleanup(self.delete_wrapper, server)
 
         def check_ports():
             port_list = [port for port in
diff --git a/tempest/scenario/test_security_groups_basic_ops.py b/tempest/scenario/test_security_groups_basic_ops.py
index dd89dc0..8058b3d 100644
--- a/tempest/scenario/test_security_groups_basic_ops.py
+++ b/tempest/scenario/test_security_groups_basic_ops.py
@@ -165,7 +165,6 @@
     def _create_tenant_keypairs(self, tenant_id):
         keypair = self.create_keypair(
             name=data_utils.rand_name('keypair-smoke-'))
-        self.addCleanup(self.cleanup_wrapper, keypair)
         self.tenants[tenant_id].keypair = keypair
 
     def _create_tenant_security_groups(self, tenant):
@@ -173,14 +172,12 @@
             namestart='secgroup_access-',
             tenant_id=tenant.creds.tenant_id
         )
-        self.addCleanup(self.cleanup_wrapper, access_sg)
 
         # don't use default secgroup since it allows in-tenant traffic
         def_sg = self._create_empty_security_group(
             namestart='secgroup_general-',
             tenant_id=tenant.creds.tenant_id
         )
-        self.addCleanup(self.cleanup_wrapper, def_sg)
         tenant.security_groups.update(access=access_sg, default=def_sg)
         ssh_rule = dict(
             protocol='tcp',
@@ -188,9 +185,7 @@
             port_range_max=22,
             direction='ingress',
         )
-        rule = self._create_security_group_rule(secgroup=access_sg,
-                                                **ssh_rule)
-        self.addCleanup(self.cleanup_wrapper, rule)
+        self._create_security_group_rule(secgroup=access_sg, **ssh_rule)
 
     def _verify_network_details(self, tenant):
         # Checks that we see the newly created network/subnet/router via
@@ -238,7 +233,6 @@
             'tenant_id': tenant.creds.tenant_id
         }
         server = self.create_server(name=name, create_kwargs=create_kwargs)
-        self.addCleanup(self.cleanup_wrapper, server)
         return server
 
     def _create_tenant_servers(self, tenant, num=1):
@@ -269,13 +263,10 @@
     def _assign_floating_ips(self, server):
         public_network_id = CONF.network.public_network_id
         floating_ip = self._create_floating_ip(server, public_network_id)
-        self.addCleanup(self.cleanup_wrapper, floating_ip)
         self.floating_ips.setdefault(server, floating_ip)
 
     def _create_tenant_network(self, tenant):
         network, subnet, router = self._create_networks(tenant.creds.tenant_id)
-        for r in [network, router, subnet]:
-            self.addCleanup(self.cleanup_wrapper, r)
         tenant.set_network(network, subnet, router)
 
     def _set_compute_context(self, tenant):
@@ -355,11 +346,10 @@
             remote_group_id=tenant.security_groups['default'].id,
             direction='ingress'
         )
-        rule = self._create_security_group_rule(
+        self._create_security_group_rule(
             secgroup=tenant.security_groups['default'],
             **ruleset
         )
-        self.addCleanup(self.cleanup_wrapper, rule)
         access_point_ssh = self._connect_to_access_point(tenant)
         for server in tenant.servers:
             self._check_connectivity(access_point=access_point_ssh,
@@ -385,11 +375,10 @@
             protocol='icmp',
             direction='ingress'
         )
-        rule_s2d = self._create_security_group_rule(
+        self._create_security_group_rule(
             secgroup=dest_tenant.security_groups['default'],
             **ruleset
         )
-        self.addCleanup(self.cleanup_wrapper, rule_s2d)
         access_point_ssh = self._connect_to_access_point(source_tenant)
         ip = self._get_server_ip(dest_tenant.access_point,
                                  floating=self.floating_ip_access)
@@ -399,11 +388,10 @@
         self._test_cross_tenant_block(dest_tenant, source_tenant)
 
         # allow reverse traffic and check
-        rule_d2s = self._create_security_group_rule(
+        self._create_security_group_rule(
             secgroup=source_tenant.security_groups['default'],
             **ruleset
         )
-        self.addCleanup(self.cleanup_wrapper, rule_d2s)
 
         access_point_ssh_2 = self._connect_to_access_point(dest_tenant)
         ip = self._get_server_ip(source_tenant.access_point,
diff --git a/tempest/scenario/test_server_basic_ops.py b/tempest/scenario/test_server_basic_ops.py
index 54f1d9e..38686d9 100644
--- a/tempest/scenario/test_server_basic_ops.py
+++ b/tempest/scenario/test_server_basic_ops.py
@@ -74,23 +74,17 @@
             'key_name': self.keypair.id,
             'security_groups': security_groups
         }
-        instance = self.create_server(image=self.image_ref,
-                                      flavor=self.flavor_ref,
-                                      create_kwargs=create_kwargs)
-        self.set_resource('instance', instance)
-
-    def terminate_instance(self):
-        instance = self.get_resource('instance')
-        instance.delete()
-        self.remove_resource('instance')
+        self.instance = self.create_server(image=self.image_ref,
+                                           flavor=self.flavor_ref,
+                                           create_kwargs=create_kwargs)
 
     def verify_ssh(self):
         if self.run_ssh:
             # Obtain a floating IP
             floating_ip = self.compute_client.floating_ips.create()
+            self.addCleanup(self.delete_wrapper, floating_ip)
             # Attach a floating IP
-            instance = self.get_resource('instance')
-            instance.add_floating_ip(floating_ip)
+            self.instance.add_floating_ip(floating_ip)
             # Check ssh
             try:
                 self.get_remote_client(
@@ -108,4 +102,4 @@
         self.security_group = self._create_security_group_nova()
         self.boot_instance()
         self.verify_ssh()
-        self.terminate_instance()
+        self.instance.delete()
diff --git a/tempest/scenario/test_snapshot_pattern.py b/tempest/scenario/test_snapshot_pattern.py
index d41490a..7dd662d 100644
--- a/tempest/scenario/test_snapshot_pattern.py
+++ b/tempest/scenario/test_snapshot_pattern.py
@@ -65,7 +65,7 @@
 
     def _create_floating_ip(self):
         floating_ip = self.compute_client.floating_ips.create()
-        self.addCleanup(floating_ip.delete)
+        self.addCleanup(self.delete_wrapper, floating_ip)
         return floating_ip
 
     def _set_floating_ip_to_server(self, server, floating_ip):
diff --git a/tempest/scenario/test_stamp_pattern.py b/tempest/scenario/test_stamp_pattern.py
index 20561ae..be27024 100644
--- a/tempest/scenario/test_stamp_pattern.py
+++ b/tempest/scenario/test_stamp_pattern.py
@@ -74,7 +74,7 @@
 
     def _create_floating_ip(self):
         floating_ip = self.compute_client.floating_ips.create()
-        self.addCleanup(floating_ip.delete)
+        self.addCleanup(self.delete_wrapper, floating_ip)
         return floating_ip
 
     def _add_floating_ip(self, server, floating_ip):
diff --git a/tempest/scenario/test_volume_boot_pattern.py b/tempest/scenario/test_volume_boot_pattern.py
index 4905dbf..bf5d1f6 100644
--- a/tempest/scenario/test_volume_boot_pattern.py
+++ b/tempest/scenario/test_volume_boot_pattern.py
@@ -10,6 +10,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from cinderclient import exceptions as cinder_exc
+
 from tempest.common.utils import data_utils
 from tempest import config
 from tempest.openstack.common import log
@@ -69,7 +71,8 @@
         snap = volume_snapshots.create(volume_id=vol_id,
                                        force=True,
                                        display_name=snap_name)
-        self.set_resource(snap.id, snap)
+        self.addCleanup_with_wait(self.volume_client.volume_snapshots, snap.id,
+                                  exc_type=cinder_exc.NotFound)
         self.status_timeout(volume_snapshots,
                             snap.id,
                             'available')
@@ -100,8 +103,7 @@
     def _ssh_to_server(self, server, keypair):
         if CONF.compute.use_floatingip_for_ssh:
             floating_ip = self.compute_client.floating_ips.create()
-            fip_name = data_utils.rand_name('scenario-fip')
-            self.set_resource(fip_name, floating_ip)
+            self.addCleanup(self.delete_wrapper, floating_ip)
             server.add_floating_ip(floating_ip)
             ip = floating_ip.ip
         else:
diff --git a/tempest/services/botoclients.py b/tempest/services/botoclients.py
index 7616a99..7af904b 100644
--- a/tempest/services/botoclients.py
+++ b/tempest/services/botoclients.py
@@ -37,13 +37,16 @@
                  *args, **kwargs):
         # FIXME(andreaf) replace credentials and auth_url with auth_provider
 
+        insecure_ssl = CONF.identity.disable_ssl_certificate_validation
+
         self.connection_timeout = str(CONF.boto.http_socket_timeout)
         self.num_retries = str(CONF.boto.num_retries)
         self.build_timeout = CONF.boto.build_timeout
         self.ks_cred = {"username": username,
                         "password": password,
                         "auth_url": auth_url,
-                        "tenant_name": tenant_name}
+                        "tenant_name": tenant_name,
+                        "insecure": insecure_ssl}
 
     def _keystone_aws_get(self):
         # FIXME(andreaf) Move EC2 credentials to AuthProvider
@@ -90,7 +93,10 @@
         self._config_boto_timeout(self.connection_timeout, self.num_retries)
         if not all((self.connection_data["aws_access_key_id"],
                    self.connection_data["aws_secret_access_key"])):
-            if all(self.ks_cred.itervalues()):
+            if all([self.ks_cred.get('auth_url'),
+                    self.ks_cred.get('username'),
+                    self.ks_cred.get('tenant_name'),
+                    self.ks_cred.get('password')]):
                 ec2_cred = self._keystone_aws_get()
                 self.connection_data["aws_access_key_id"] = \
                     ec2_cred.access
@@ -109,6 +115,7 @@
 
     def __init__(self, *args, **kwargs):
         super(APIClientEC2, self).__init__(*args, **kwargs)
+        insecure_ssl = CONF.identity.disable_ssl_certificate_validation
         aws_access = CONF.boto.aws_access
         aws_secret = CONF.boto.aws_secret
         purl = urlparse.urlparse(CONF.boto.ec2_url)
@@ -129,6 +136,7 @@
         self.connection_data = {"aws_access_key_id": aws_access,
                                 "aws_secret_access_key": aws_secret,
                                 "is_secure": purl.scheme == "https",
+                                "validate_certs": not insecure_ssl,
                                 "region": region,
                                 "host": purl.hostname,
                                 "port": port,
@@ -187,6 +195,7 @@
 
     def __init__(self, *args, **kwargs):
         super(ObjectClientS3, self).__init__(*args, **kwargs)
+        insecure_ssl = CONF.identity.disable_ssl_certificate_validation
         aws_access = CONF.boto.aws_access
         aws_secret = CONF.boto.aws_secret
         purl = urlparse.urlparse(CONF.boto.s3_url)
@@ -201,6 +210,7 @@
         self.connection_data = {"aws_access_key_id": aws_access,
                                 "aws_secret_access_key": aws_secret,
                                 "is_secure": purl.scheme == "https",
+                                "validate_certs": not insecure_ssl,
                                 "host": purl.hostname,
                                 "port": port,
                                 "calling_format": boto.s3.connection.
diff --git a/tempest/services/compute/json/floating_ips_client.py b/tempest/services/compute/json/floating_ips_client.py
index 92b4ddf..0028eea 100644
--- a/tempest/services/compute/json/floating_ips_client.py
+++ b/tempest/services/compute/json/floating_ips_client.py
@@ -137,4 +137,5 @@
         post_body = json.dumps({'ip_range': ip_range})
         resp, body = self.put('os-floating-ips-bulk/delete', post_body)
         body = json.loads(body)
+        self.validate_response(schema.delete_floating_ips_bulk, resp, body)
         return resp, body['floating_ips_bulk_delete']
diff --git a/tempest/services/compute/json/quotas_client.py b/tempest/services/compute/json/quotas_client.py
index 7e828d8..14b7100 100644
--- a/tempest/services/compute/json/quotas_client.py
+++ b/tempest/services/compute/json/quotas_client.py
@@ -15,6 +15,7 @@
 
 import json
 
+from tempest.api_schema.compute.v2 import quota_classes as classes_schema
 from tempest.api_schema.compute.v2 import quotas as schema
 from tempest.common import rest_client
 from tempest import config
@@ -118,3 +119,32 @@
         resp, body = self.delete('os-quota-sets/%s' % str(tenant_id))
         self.validate_response(schema.delete_quota, resp, body)
         return resp, body
+
+
+class QuotaClassesClientJSON(rest_client.RestClient):
+
+    def __init__(self, auth_provider):
+        super(QuotaClassesClientJSON, self).__init__(auth_provider)
+        self.service = CONF.compute.catalog_type
+
+    def get_quota_class_set(self, quota_class_id):
+        """List the quota class set for a quota class."""
+
+        url = 'os-quota-class-sets/%s' % str(quota_class_id)
+        resp, body = self.get(url)
+        body = json.loads(body)
+        self.validate_response(classes_schema.quota_set, resp, body)
+        return resp, body['quota_class_set']
+
+    def update_quota_class_set(self, quota_class_id, **kwargs):
+        """
+        Updates the quota class's limits for one or more resources.
+        """
+        post_body = json.dumps({'quota_class_set': kwargs})
+
+        resp, body = self.put('os-quota-class-sets/%s' % str(quota_class_id),
+                              post_body)
+
+        body = json.loads(body)
+        self.validate_response(classes_schema.quota_set_update, resp, body)
+        return resp, body['quota_class_set']
diff --git a/tempest/services/compute/json/servers_client.py b/tempest/services/compute/json/servers_client.py
index e1661c0..69d2f35 100644
--- a/tempest/services/compute/json/servers_client.py
+++ b/tempest/services/compute/json/servers_client.py
@@ -134,6 +134,7 @@
         """Returns the details of an existing server."""
         resp, body = self.get("servers/%s" % str(server_id))
         body = json.loads(body)
+        self.validate_response(schema.get_server, resp, body)
         return resp, body['server']
 
     def delete_server(self, server_id):
@@ -524,6 +525,7 @@
         """List the server-groups."""
         resp, body = self.get("os-server-groups")
         body = json.loads(body)
+        self.validate_response(schema.list_server_groups, resp, body)
         return resp, body['server_groups']
 
     def get_server_group(self, server_group_id):
diff --git a/tempest/services/compute/v3/json/servers_client.py b/tempest/services/compute/v3/json/servers_client.py
index 11258a6..d933998 100644
--- a/tempest/services/compute/v3/json/servers_client.py
+++ b/tempest/services/compute/v3/json/servers_client.py
@@ -136,6 +136,7 @@
         """Returns the details of an existing server."""
         resp, body = self.get("servers/%s" % str(server_id))
         body = json.loads(body)
+        self.validate_response(schema.get_server, resp, body)
         return resp, body['server']
 
     def delete_server(self, server_id):
diff --git a/tempest/services/compute/xml/quotas_client.py b/tempest/services/compute/xml/quotas_client.py
index 5502fcc..7f87248 100644
--- a/tempest/services/compute/xml/quotas_client.py
+++ b/tempest/services/compute/xml/quotas_client.py
@@ -22,6 +22,19 @@
 CONF = config.CONF
 
 
+def format_quota(q):
+    quota = {}
+    for k, v in q.items():
+        try:
+            v = int(v)
+        except ValueError:
+            pass
+
+        quota[k] = v
+
+    return quota
+
+
 class QuotasClientXML(rest_client.RestClient):
     TYPE = "xml"
 
@@ -29,18 +42,6 @@
         super(QuotasClientXML, self).__init__(auth_provider)
         self.service = CONF.compute.catalog_type
 
-    def _format_quota(self, q):
-        quota = {}
-        for k, v in q.items():
-            try:
-                v = int(v)
-            except ValueError:
-                pass
-
-            quota[k] = v
-
-        return quota
-
     def get_quota_set(self, tenant_id, user_id=None):
         """List the quota set for a tenant."""
 
@@ -49,7 +50,7 @@
             url += '?user_id=%s' % str(user_id)
         resp, body = self.get(url)
         body = xml_utils.xml_to_json(etree.fromstring(body))
-        body = self._format_quota(body)
+        body = format_quota(body)
         return resp, body
 
     def get_default_quota_set(self, tenant_id):
@@ -58,7 +59,7 @@
         url = 'os-quota-sets/%s/defaults' % str(tenant_id)
         resp, body = self.get(url)
         body = xml_utils.xml_to_json(etree.fromstring(body))
-        body = self._format_quota(body)
+        body = format_quota(body)
         return resp, body
 
     def update_quota_set(self, tenant_id, user_id=None,
@@ -124,9 +125,41 @@
                                   str(xml_utils.Document(post_body)))
 
         body = xml_utils.xml_to_json(etree.fromstring(body))
-        body = self._format_quota(body)
+        body = format_quota(body)
         return resp, body
 
     def delete_quota_set(self, tenant_id):
         """Delete the tenant's quota set."""
         return self.delete('os-quota-sets/%s' % str(tenant_id))
+
+
+class QuotaClassesClientXML(rest_client.RestClient):
+    TYPE = "xml"
+
+    def __init__(self, auth_provider):
+        super(QuotaClassesClientXML, self).__init__(auth_provider)
+        self.service = CONF.compute.catalog_type
+
+    def get_quota_class_set(self, quota_class_id):
+        """List the quota class set for a quota class."""
+
+        url = 'os-quota-class-sets/%s' % str(quota_class_id)
+        resp, body = self.get(url)
+        body = xml_utils.xml_to_json(etree.fromstring(body))
+        body = format_quota(body)
+        return resp, body
+
+    def update_quota_class_set(self, quota_class_id, **kwargs):
+        """
+        Updates the quota class's limits for one or more resources.
+        """
+        post_body = xml_utils.Element("quota_class_set",
+                                      xmlns=xml_utils.XMLNS_11,
+                                      **kwargs)
+
+        resp, body = self.put('os-quota-class-sets/%s' % str(quota_class_id),
+                              str(xml_utils.Document(post_body)))
+
+        body = xml_utils.xml_to_json(etree.fromstring(body))
+        body = format_quota(body)
+        return resp, body
diff --git a/tempest/services/network/network_client_base.py b/tempest/services/network/network_client_base.py
index 81792c4..4ee8302 100644
--- a/tempest/services/network/network_client_base.py
+++ b/tempest/services/network/network_client_base.py
@@ -28,6 +28,7 @@
     'vips': 'lb',
     'health_monitors': 'lb',
     'members': 'lb',
+    'ipsecpolicies': 'vpn',
     'vpnservices': 'vpn',
     'ikepolicies': 'vpn',
     'ipsecpolicies': 'vpn',
@@ -47,6 +48,7 @@
 resource_plural_map = {
     'security_groups': 'security_groups',
     'security_group_rules': 'security_group_rules',
+    'ipsecpolicy': 'ipsecpolicies',
     'ikepolicy': 'ikepolicies',
     'ipsecpolicy': 'ipsecpolicies',
     'quotas': 'quotas',
diff --git a/tempest/tests/test_commands.py b/tempest/tests/test_commands.py
index bdb9269..1e2925b 100644
--- a/tempest/tests/test_commands.py
+++ b/tempest/tests/test_commands.py
@@ -47,7 +47,8 @@
     @mock.patch('subprocess.Popen')
     def test_iptables_raw(self, mock):
         table = 'filter'
-        expected = ['/usr/bin/sudo', '-n', 'iptables', '-v', '-S', '-t',
+        expected = ['/usr/bin/sudo', '-n', 'iptables', '--line-numbers',
+                    '-L', '-nv', '-t',
                     '%s' % table]
         commands.iptables_raw(table)
         mock.assert_called_once_with(expected, **self.subprocess_args)
diff --git a/tempest/tests/test_hacking.py b/tempest/tests/test_hacking.py
index 91c3274..52fdf7e 100644
--- a/tempest/tests/test_hacking.py
+++ b/tempest/tests/test_hacking.py
@@ -99,3 +99,11 @@
             './tempest/scenario/compute/fake_test.py'))
         self.assertFalse(checks.service_tags_not_in_module_path(
             "@test.services('compute')", './tempest/api/image/fake_test.py'))
+
+    def test_no_official_client_manager_in_api_tests(self):
+        self.assertTrue(checks.no_official_client_manager_in_api_tests(
+            "cls.official_client = clients.OfficialClientManager(credentials)",
+            "tempest/api/compute/base.py"))
+        self.assertFalse(checks.no_official_client_manager_in_api_tests(
+            "cls.official_client = clients.OfficialClientManager(credentials)",
+            "tempest/scenario/fake_test.py"))
diff --git a/tempest/tests/test_ssh.py b/tempest/tests/test_ssh.py
index bf1f553..27cd6b5 100644
--- a/tempest/tests/test_ssh.py
+++ b/tempest/tests/test_ssh.py
@@ -36,13 +36,13 @@
             rsa_mock.assert_called_once_with(mock.sentinel.csio)
             cs_mock.assert_called_once_with('mykey')
             rsa_mock.reset_mock()
-            cs_mock.rest_mock()
+            cs_mock.reset_mock()
             pkey = mock.sentinel.pkey
             # Shouldn't call out to load a file from RSAKey, since
             # a sentinel isn't a basestring...
             ssh.Client('localhost', 'root', pkey=pkey)
-            rsa_mock.assert_not_called()
-            cs_mock.assert_not_called()
+            self.assertEqual(0, rsa_mock.call_count)
+            self.assertEqual(0, cs_mock.call_count)
 
     def _set_ssh_connection_mocks(self):
         client_mock = mock.MagicMock()
@@ -75,7 +75,7 @@
             password=None
         )]
         self.assertEqual(expected_connect, client_mock.connect.mock_calls)
-        s_mock.assert_not_called()
+        self.assertEqual(0, s_mock.call_count)
 
     def test_get_ssh_connection_two_attemps(self):
         c_mock, aa_mock, client_mock = self._set_ssh_connection_mocks()