Merge "Auto-generate sample config file"
diff --git a/patrole_tempest_plugin/policy_authority.py b/patrole_tempest_plugin/policy_authority.py
index d2d07c0..0a1aa13 100644
--- a/patrole_tempest_plugin/policy_authority.py
+++ b/patrole_tempest_plugin/policy_authority.py
@@ -225,7 +225,7 @@
 
         try:
             policy_data = json.dumps(policy_data)
-        except ValueError:
+        except (TypeError, ValueError):
             error_message = 'Policy file for {0} service is invalid.'.format(
                 service)
             raise rbac_exceptions.RbacParsingException(error_message)
diff --git a/patrole_tempest_plugin/tests/api/compute/rbac_base.py b/patrole_tempest_plugin/tests/api/compute/rbac_base.py
index bab193e..6246446 100644
--- a/patrole_tempest_plugin/tests/api/compute/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/compute/rbac_base.py
@@ -39,25 +39,6 @@
         cls.tenant_usages_client = cls.os_primary.tenant_usages_client
 
     @classmethod
-    def resource_setup(cls):
-        super(BaseV2ComputeRbacTest, cls).resource_setup()
-        cls.flavors = []
-
-    @classmethod
-    def resource_cleanup(cls):
-        cls.clear_flavors()
-        super(BaseV2ComputeRbacTest, cls).resource_cleanup()
-
-    @classmethod
-    def clear_flavors(cls):
-        for flavor in cls.flavors:
-            test_utils.call_and_ignore_notfound_exc(
-                cls.flavors_client.delete_flavor, flavor['id'])
-        for flavor in cls.flavors:
-            test_utils.call_and_ignore_notfound_exc(
-                cls.flavors_client.wait_for_resource_deletion, flavor['id'])
-
-    @classmethod
     def create_flavor(cls, **kwargs):
         flavor_kwargs = {
             "name": data_utils.rand_name(cls.__name__ + '-flavor'),
@@ -69,5 +50,9 @@
         if kwargs:
             flavor_kwargs.update(kwargs)
         flavor = cls.flavors_client.create_flavor(**flavor_kwargs)['flavor']
-        cls.flavors.append(flavor)
+        cls.addClassResourceCleanup(
+            cls.flavors_client.wait_for_resource_deletion, flavor['id'])
+        cls.addClassResourceCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            cls.flavors_client.delete_flavor, flavor['id'])
         return flavor
diff --git a/patrole_tempest_plugin/tests/api/compute/test_agents_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_agents_rbac.py
index 4712ed0..cbe8d01 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_agents_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_agents_rbac.py
@@ -13,10 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -27,7 +27,7 @@
     @classmethod
     def skip_checks(cls):
         super(AgentsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-agents', 'compute'):
+        if not utils.is_extension_enabled('os-agents', 'compute'):
             raise cls.skipException(
                 '%s skipped as os-agents not enabled' % cls.__name__)
 
diff --git a/patrole_tempest_plugin/tests/api/compute/test_aggregates_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_aggregates_rbac.py
index eec4030..261fded 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_aggregates_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_aggregates_rbac.py
@@ -13,10 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -27,7 +27,7 @@
     @classmethod
     def skip_checks(cls):
         super(AggregatesRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-aggregates', 'compute'):
+        if not utils.is_extension_enabled('os-aggregates', 'compute'):
             msg = "%s skipped as os-aggregates not enabled." % cls.__name__
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/compute/test_availability_zone_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_availability_zone_rbac.py
index 2ce9176..2a8a6ae 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_availability_zone_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_availability_zone_rbac.py
@@ -11,8 +11,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -23,7 +23,7 @@
     @classmethod
     def skip_checks(cls):
         super(NovaAvailabilityZoneRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-availability-zone', 'compute'):
+        if not utils.is_extension_enabled('os-availability-zone', 'compute'):
             msg = ("%s skipped as os-availability-zone not "
                    "enabled." % cls.__name__)
             raise cls.skipException(msg)
diff --git a/patrole_tempest_plugin/tests/api/compute/test_flavor_extra_specs_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_flavor_extra_specs_rbac.py
index 031d8ad..2d60e09 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_flavor_extra_specs_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_flavor_extra_specs_rbac.py
@@ -13,10 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -27,7 +27,7 @@
     @classmethod
     def skip_checks(cls):
         super(FlavorExtraSpecsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-flavor-extra-specs', 'compute'):
+        if not utils.is_extension_enabled('os-flavor-extra-specs', 'compute'):
             msg = "os-flavor-extra-specs extension not enabled."
             raise cls.skipException(msg)
 
@@ -36,12 +36,6 @@
         super(FlavorExtraSpecsRbacTest, cls).resource_setup()
         cls.flavor = cls.create_flavor()
 
-    @classmethod
-    def resource_cleanup(cls):
-        cls.flavors_client.delete_flavor(cls.flavor['id'])
-        cls.flavors_client.wait_for_resource_deletion(cls.flavor['id'])
-        super(FlavorExtraSpecsRbacTest, cls).resource_cleanup()
-
     def _set_flavor_extra_spec(self):
         rand_key = data_utils.rand_name(self.__class__.__name__ + '-key')
         rand_val = data_utils.rand_name(self.__class__.__name__ + '-val')
diff --git a/patrole_tempest_plugin/tests/api/compute/test_flavor_manage_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_flavor_manage_rbac.py
index 519a55a..afe5013 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_flavor_manage_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_flavor_manage_rbac.py
@@ -13,8 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -29,7 +29,7 @@
     @classmethod
     def skip_checks(cls):
         super(FlavorManageRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
+        if not utils.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
             msg = "OS-FLV-EXT-DATA extension not enabled."
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/compute/test_flavor_rxtx_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_flavor_rxtx_rbac.py
index 7340689..b530cbf 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_flavor_rxtx_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_flavor_rxtx_rbac.py
@@ -13,16 +13,15 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from oslo_config import cfg
-
+from tempest.common import utils
+from tempest import config
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_exceptions
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
 
-CONF = cfg.CONF
+CONF = config.CONF
 
 
 class FlavorRxtxRbacTest(rbac_base.BaseV2ComputeRbacTest):
@@ -30,7 +29,7 @@
     @classmethod
     def skip_checks(cls):
         super(FlavorRxtxRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-flavor-rxtx', 'compute'):
+        if not utils.is_extension_enabled('os-flavor-rxtx', 'compute'):
             msg = "os-flavor-rxtx extension not enabled."
             raise cls.skipException(msg)
 
@@ -40,7 +39,6 @@
         rule="os_compute_api:os-flavor-rxtx")
     def test_list_flavors_details_rxtx(self):
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
-        # Enforces os_compute_api:os-flavor-rxtx
         result = self.flavors_client.list_flavors(detail=True)['flavors']
         if 'rxtx_factor' not in result[0]:
             raise rbac_exceptions.RbacMalformedResponse(
@@ -52,9 +50,8 @@
         rule="os_compute_api:os-flavor-rxtx")
     def test_get_flavor_rxtx(self):
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
-        # Enforces os_compute_api:os-flavor-rxtx
-        result =\
-            self.flavors_client.show_flavor(CONF.compute.flavor_ref)['flavor']
+        result = self.flavors_client.show_flavor(
+            CONF.compute.flavor_ref)['flavor']
         if 'rxtx_factor' not in result:
             raise rbac_exceptions.RbacMalformedResponse(
                 attribute='rxtx_factor')
diff --git a/patrole_tempest_plugin/tests/api/compute/test_floating_ip_pools_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_floating_ip_pools_rbac.py
index 7b35525..15891d7 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_floating_ip_pools_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_floating_ip_pools_rbac.py
@@ -13,9 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest import config
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -38,10 +38,12 @@
     @classmethod
     def skip_checks(cls):
         super(FloatingIpPoolsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-floating-ip-pools', 'compute'):
+        if not utils.is_extension_enabled('os-floating-ip-pools', 'compute'):
             msg = "%s skipped as os-floating-ip-pools extension not enabled." \
                   % cls.__name__
             raise cls.skipException(msg)
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
 
     @decorators.idempotent_id('c1a17153-b25d-4444-a721-5897d7737482')
     @rbac_rule_validation.action(
diff --git a/patrole_tempest_plugin/tests/api/compute/test_floating_ips_bulk_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_floating_ips_bulk_rbac.py
index cceccd4..e149bf2 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_floating_ips_bulk_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_floating_ips_bulk_rbac.py
@@ -13,9 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest import config
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -38,10 +38,12 @@
     @classmethod
     def skip_checks(cls):
         super(FloatingIpsBulkRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-floating-ips-bulk', 'compute'):
+        if not utils.is_extension_enabled('os-floating-ips-bulk', 'compute'):
             msg = "%s skipped as os-floating-ips-bulk extension not enabled." \
                   % cls.__name__
             raise cls.skipException(msg)
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
 
     @decorators.idempotent_id('3b5c8a02-005d-4256-8a95-6fa2f389c6cf')
     @rbac_rule_validation.action(
diff --git a/patrole_tempest_plugin/tests/api/compute/test_floating_ips_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_floating_ips_rbac.py
index 764d165..8ab5a51 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_floating_ips_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_floating_ips_rbac.py
@@ -13,9 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest import config
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -33,10 +34,12 @@
     @classmethod
     def skip_checks(cls):
         super(FloatingIpsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-floating-ips', 'compute'):
+        if not utils.is_extension_enabled('os-floating-ips', 'compute'):
             msg = "%s skipped as os-floating-ips extension not enabled." \
                   % cls.__name__
             raise cls.skipException(msg)
+        if not CONF.network_feature_enabled.floating_ips:
+            raise cls.skipException("Floating ips are not available")
 
     @decorators.idempotent_id('ac1b3053-f755-4cda-85a0-30e88b88d7ba')
     @rbac_rule_validation.action(
@@ -45,3 +48,39 @@
     def test_list_floating_ips(self):
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.floating_ips_client.list_floating_ips()['floating_ips']
+
+    @decorators.idempotent_id('bebe52b3-5269-4e72-80c8-5a4a39c3bfa6')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-floating-ips")
+    def test_show_floating_ip(self):
+        body = self.floating_ips_client.create_floating_ip(
+            pool=CONF.network.floating_network_name)['floating_ip']
+        self.addCleanup(
+            self.floating_ips_client.delete_floating_ip, body['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.floating_ips_client.show_floating_ip(body['id'])['floating_ip']
+
+    @decorators.idempotent_id('2bfb8745-c329-4ee9-95f6-c165a1989dbf')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-floating-ips")
+    def test_create_floating_ips(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        body = self.floating_ips_client.create_floating_ip(
+            pool=CONF.network.floating_network_name)['floating_ip']
+        self.addCleanup(
+            self.floating_ips_client.delete_floating_ip, body['id'])
+
+    @decorators.idempotent_id('d3028373-5027-4e7a-b761-01c515403ecb')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-floating-ips")
+    def test_delete_floating_ip(self):
+        body = self.floating_ips_client.create_floating_ip(
+            pool=CONF.network.floating_network_name)['floating_ip']
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.floating_ips_client.delete_floating_ip, body['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.floating_ips_client.delete_floating_ip(body['id'])
diff --git a/patrole_tempest_plugin/tests/api/compute/test_hosts_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_hosts_rbac.py
index 2a6b171..f10744c 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_hosts_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_hosts_rbac.py
@@ -13,8 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -25,7 +25,7 @@
     @classmethod
     def skip_checks(cls):
         super(HostsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-hosts', 'compute'):
+        if not utils.is_extension_enabled('os-hosts', 'compute'):
             msg = "%s skipped as os-hosts not enabled." % cls.__name__
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/compute/test_hypervisor_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_hypervisor_rbac.py
index e687fb4..c07ab24 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_hypervisor_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_hypervisor_rbac.py
@@ -13,8 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -25,7 +25,7 @@
     @classmethod
     def skip_checks(cls):
         super(HypervisorRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-hypervisors', 'compute'):
+        if not utils.is_extension_enabled('os-hypervisors', 'compute'):
             msg = "%s skipped as os-hypervisors extension not enabled." \
                   % cls.__name__
             raise cls.skipException(msg)
diff --git a/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py
index cdabf6f..e315623 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py
@@ -63,11 +63,11 @@
         super(ImagesRbacTest, cls).resource_setup()
         cls.image = cls.glance_image_client.create_image(
             name=data_utils.rand_name(cls.__name__ + '-image'))
-
-    @classmethod
-    def resource_cleanup(cls):
-        cls.glance_image_client.delete_image(cls.image['id'])
-        super(ImagesRbacTest, cls).resource_cleanup()
+        cls.addClassResourceCleanup(
+            cls.glance_image_client.wait_for_resource_deletion,
+            cls.image['id'])
+        cls.addClassResourceCleanup(
+            cls.glance_image_client.delete_image, cls.image['id'])
 
     @decorators.idempotent_id('b861f302-b72b-4055-81db-c62ff30b136d')
     @rbac_rule_validation.action(
diff --git a/patrole_tempest_plugin/tests/api/compute/test_instance_usages_audit_log_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_instance_usages_audit_log_rbac.py
index 90a9e10..5fc4c3b 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_instance_usages_audit_log_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_instance_usages_audit_log_rbac.py
@@ -17,8 +17,8 @@
 
 from six.moves.urllib import parse as urllib
 
+from tempest.common import utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -29,8 +29,8 @@
     @classmethod
     def skip_checks(cls):
         super(InstanceUsagesAuditLogRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-instance-usage-audit-log',
-                                         'compute'):
+        if not utils.is_extension_enabled('os-instance-usage-audit-log',
+                                          'compute'):
             msg = "os-instance-usage-audit-log extension not enabled."
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/compute/test_limits_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_limits_rbac.py
index 2f19d13..ad2c5ba 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_limits_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_limits_rbac.py
@@ -11,8 +11,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -23,7 +23,7 @@
     @classmethod
     def skip_checks(cls):
         super(LimitsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-limits', 'compute'):
+        if not utils.is_extension_enabled('os-limits', 'compute'):
             msg = "%s skipped as os-limits not enabled." % cls.__name__
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/compute/test_migrations_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_migrations_rbac.py
index dc2bdf6..1bf46a1 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_migrations_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_migrations_rbac.py
@@ -13,8 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -25,7 +25,7 @@
     @classmethod
     def skip_checks(cls):
         super(MigrationsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-migrations', 'compute'):
+        if not utils.is_extension_enabled('os-migrations', 'compute'):
             msg = "%s skipped as os-migrations not enabled." % cls.__name__
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/compute/test_quota_class_sets_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_quota_class_sets_rbac.py
index a7d8997..162c003 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_quota_class_sets_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_quota_class_sets_rbac.py
@@ -14,9 +14,9 @@
 #    under the License.
 
 from tempest.common import tempest_fixtures as fixtures
+from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -33,7 +33,7 @@
     @classmethod
     def skip_checks(cls):
         super(QuotaClassesRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-quota-class-sets', 'compute'):
+        if not utils.is_extension_enabled('os-quota-class-sets', 'compute'):
             msg = "%s skipped as os-quota-class-sets extension not enabled."\
                   % cls.__name__
             raise cls.skipException(msg)
@@ -51,12 +51,8 @@
         project_name = data_utils.rand_name(cls.__name__ + '-Project')
         cls.project_id = cls.identity_projects_client.create_project(
             project_name)['project']['id']
-
-    @classmethod
-    def resource_cleanup(cls):
-        cls.identity_projects_client.delete_project(
-            cls.project_id)
-        super(QuotaClassesRbacTest, cls).resource_cleanup()
+        cls.addClassResourceCleanup(
+            cls.identity_projects_client.delete_project, cls.project_id)
 
     @decorators.idempotent_id('c10198ed-9df2-440e-a49b-367dadc6de94')
     @rbac_rule_validation.action(
diff --git a/patrole_tempest_plugin/tests/api/compute/test_quota_sets_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_quota_sets_rbac.py
index a4527c3..6052150 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_quota_sets_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_quota_sets_rbac.py
@@ -13,10 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -32,7 +32,7 @@
     @classmethod
     def skip_checks(cls):
         super(QuotaSetsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-quota-sets', 'compute'):
+        if not utils.is_extension_enabled('os-quota-sets', 'compute'):
             msg = "%s skipped as os-quota-sets extension not enabled."\
                   % cls.__name__
             raise cls.skipException(msg)
diff --git a/patrole_tempest_plugin/tests/api/compute/test_security_groups_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_security_groups_rbac.py
index 36d8c2c..43d48c9 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_security_groups_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_security_groups_rbac.py
@@ -33,12 +33,12 @@
         super(SecurtiyGroupsRbacTest, cls).skip_checks()
         # All the tests below require the network service.
         # NOTE(gmann) Currently 'network' service is always True in
-        # test.get_service_list() So below check is not much of use.
+        # utils.get_service_list() So below check is not much of use.
         # Commenting the below check as Tempest is moving the get_service_list
         # from test.py to utils.
         # If we want to check 'network' service availability, then
         # get_service_list can be used from new location.
-        # if not test.get_service_list()['network']:
+        # if not utils.get_service_list()['network']:
         #    raise cls.skipException(
         #        'Skipped because the network service is not available')
 
@@ -103,12 +103,12 @@
         super(SecurityGroupsRbacMaxV235Test, cls).skip_checks()
         # All the tests below require the network service.
         # NOTE(gmann) Currently 'network' service is always True in
-        # test.get_service_list() So below check is not much of use.
+        # utils.get_service_list() So below check is not much of use.
         # Commenting the below check as Tempest is moving the get_service_list
         # from test.py to utils.
         # If we want to check 'network' service availability, then
         # get_service_list can be used from new location.
-        # if not test.get_service_list()['network']:
+        # if not utils.get_service_list()['network']:
         #    raise cls.skipException(
         #        'Skipped because the network service is not available')
 
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py
index aeefebf..f28bf3c 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py
@@ -13,22 +13,22 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from oslo_log import log
 import testtools
 
+from tempest.common import utils
 from tempest.common import waiters
 from tempest import config
+from tempest.lib.common import api_version_utils
 from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
-from tempest import test
 
 from patrole_tempest_plugin import rbac_exceptions
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
 
 CONF = config.CONF
-LOG = log.getLogger(__name__)
 
 
 class ServerActionsRbacTest(rbac_base.BaseV2ComputeRbacTest):
@@ -38,27 +38,11 @@
     @classmethod
     def resource_setup(cls):
         super(ServerActionsRbacTest, cls).resource_setup()
-        # Create test server
         cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id']
         cls.flavor_ref = CONF.compute.flavor_ref
         cls.flavor_ref_alt = CONF.compute.flavor_ref_alt
         cls.image_ref = CONF.compute.image_ref
 
-        # Create a volume
-        volume_name = data_utils.rand_name(cls.__name__ + '-volume')
-        name_field = 'name'
-        if not CONF.volume_feature_enabled.api_v2:
-            name_field = 'display_name'
-
-        params = {name_field: volume_name,
-                  'imageRef': CONF.compute.image_ref,
-                  'size': CONF.volume.volume_size}
-        volume = cls.volumes_client.create_volume(**params)['volume']
-        waiters.wait_for_volume_resource_status(cls.volumes_client,
-                                                volume['id'], 'available')
-        cls.volumes.append(volume)
-        cls.volume_id = volume['id']
-
     def setUp(self):
         super(ServerActionsRbacTest, self).setUp()
         try:
@@ -70,81 +54,20 @@
             server = self.create_test_server(wait_until='ACTIVE')
             self.__class__.server_id = server['id']
         except Exception:
-            # Rebuilding the server in case something happened during a test
-            self.__class__.server_id = self.rebuild_server(self.server_id)
+            # Recreating the server in case something happened during a test
+            self.__class__.server_id = self.recreate_server(self.server_id)
 
-    @classmethod
-    def resource_cleanup(cls):
-        # If a test case creates an image from a server that is created with
-        # a volume, a volume snapshot will automatically be created by default.
-        # We need to delete the volume snapshot.
-        try:
-            body = cls.snapshots_extensions_client.list_snapshots()
-            volume_snapshots = body['snapshots']
-        except Exception:
-            LOG.info("Cannot retrieve snapshots for cleanup.")
-        else:
-            for snapshot in volume_snapshots:
-                if snapshot['volumeId'] == cls.volume_id:
-                    # Wait for snapshot status to become 'available' before
-                    # deletion
-                    waiters.wait_for_volume_resource_status(
-                        cls.snapshots_extensions_client, snapshot['id'],
-                        'available')
-                    cls.snapshots_extensions_client.delete_snapshot(
-                        snapshot['id'])
-
-            for snapshot in volume_snapshots:
-                if snapshot['volumeId'] == cls.volume_id:
-                    cls.snapshots_extensions_client.wait_for_resource_deletion(
-                        snapshot['id'])
-
-        super(ServerActionsRbacTest, cls).resource_cleanup()
-
-    def _create_test_server_with_volume(self, volume_id):
-        # Create a server with the volume created earlier
-        server_name = data_utils.rand_name(self.__class__.__name__ + "-server")
-        bd_map_v2 = [{'uuid': volume_id,
-                      'source_type': 'volume',
-                      'destination_type': 'volume',
-                      'boot_index': 0,
-                      'delete_on_termination': True}]
-        device_mapping = {'block_device_mapping_v2': bd_map_v2}
-
-        # Since the server is booted from volume, the imageRef does not need
-        # to be specified.
-        server = self.servers_client.create_server(
-            name=server_name, imageRef='',
-            flavorRef=CONF.compute.flavor_ref,
-            **device_mapping)['server']
-
-        waiters.wait_for_server_status(
-            self.os_admin.servers_client, server['id'], 'ACTIVE')
-
-        self.servers.append(server)
-        return server
-
-    def _test_start_server(self):
-        self.servers_client.start_server(self.server_id)
-        waiters.wait_for_server_status(
-            self.os_admin.servers_client, self.server_id, 'ACTIVE')
-
-    def _test_stop_server(self):
+    def _stop_server(self):
         self.servers_client.stop_server(self.server_id)
         waiters.wait_for_server_status(
             self.os_admin.servers_client, self.server_id, 'SHUTOFF')
 
-    def _test_resize_server(self, flavor):
+    def _resize_server(self, flavor):
         self.servers_client.resize_server(self.server_id, flavor)
         waiters.wait_for_server_status(
             self.os_admin.servers_client, self.server_id, 'VERIFY_RESIZE')
 
-    def _test_revert_resize_server(self):
-        self.servers_client.revert_resize_server(self.server_id)
-        waiters.wait_for_server_status(
-            self.os_admin.servers_client, self.server_id, 'ACTIVE')
-
-    def _test_confirm_resize_server(self):
+    def _confirm_resize_server(self):
         self.servers_client.confirm_resize_server(self.server_id)
         waiters.wait_for_server_status(
             self.os_admin.servers_client, self.server_id, 'ACTIVE')
@@ -155,7 +78,7 @@
     @decorators.idempotent_id('ab4a17d2-166f-4a6d-9944-f17baa576cf2')
     def test_stop_server(self):
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
-        self._test_stop_server()
+        self._stop_server()
 
     @decorators.attr(type='slow')
     @rbac_rule_validation.action(
@@ -163,9 +86,12 @@
         rule="os_compute_api:servers:start")
     @decorators.idempotent_id('8876bfa9-4d10-406e-a335-a57e451abb12')
     def test_start_server(self):
-        self._test_stop_server()
+        self._stop_server()
+
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
-        self._test_start_server()
+        self.servers_client.start_server(self.server_id)
+        waiters.wait_for_server_status(
+            self.os_admin.servers_client, self.server_id, 'ACTIVE')
 
     @decorators.attr(type='slow')
     @rbac_rule_validation.action(
@@ -176,7 +102,7 @@
                           'Resize is not available.')
     def test_resize_server(self):
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
-        self._test_resize_server(self.flavor_ref_alt)
+        self._resize_server(self.flavor_ref_alt)
 
     @decorators.attr(type='slow')
     @rbac_rule_validation.action(
@@ -186,9 +112,12 @@
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize is not available.')
     def test_revert_resize_server(self):
-        self._test_resize_server(self.flavor_ref_alt)
+        self._resize_server(self.flavor_ref_alt)
+
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
-        self._test_revert_resize_server()
+        self.servers_client.revert_resize_server(self.server_id)
+        waiters.wait_for_server_status(
+            self.os_admin.servers_client, self.server_id, 'ACTIVE')
 
     @decorators.attr(type='slow')
     @rbac_rule_validation.action(
@@ -198,13 +127,12 @@
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize is not available.')
     def test_confirm_resize_server(self):
-        self._test_resize_server(self.flavor_ref_alt)
+        self._resize_server(self.flavor_ref_alt)
+        self.addCleanup(self._confirm_resize_server)
+        self.addCleanup(self._resize_server, self.flavor_ref)
+
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
-        self.addCleanup(
-            lambda: (self._test_resize_server(self.flavor_ref),
-                     self._test_confirm_resize_server())
-        )
-        self._test_confirm_resize_server()
+        self._confirm_resize_server()
 
     @rbac_rule_validation.action(
         service="nova",
@@ -266,7 +194,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.servers_client.show_server(self.server_id)
 
-    @test.services('image')
+    @utils.services('image')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:servers:create_image")
@@ -275,21 +203,69 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
 
         # This function will also call show image
-        self.create_image_from_server(self.server_id,
-                                      wait_until='ACTIVE')
+        self.create_image_from_server(self.server_id, wait_until='ACTIVE')
 
-    @test.services('image', 'volume')
+    @utils.services('image', 'volume')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:servers:create_image:allow_volume_backed")
     @decorators.idempotent_id('8b869f73-49b3-4cc4-a0ce-ef64f8e1d6f9')
-    def test_create_image_volume_backed(self):
-        server = self._create_test_server_with_volume(self.volume_id)
+    def test_create_image_from_volume_backed_server(self):
+        # volume_backed=True creates a volume and create server will be
+        # requested with 'block_device_mapping_v2' with necessary values for
+        # this test.
+        server = self.create_test_server(volume_backed=True,
+                                         wait_until='ACTIVE')
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
 
-        # This function will also call show image
-        self.create_image_from_server(server['id'],
-                                      wait_until='ACTIVE')
+        # This function will also call show image.
+        image = self.create_image_from_server(server['id'],
+                                              wait_until='ACTIVE',
+                                              wait_for_server=False)
+        self.addCleanup(self.compute_images_client.wait_for_resource_deletion,
+                        image['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.compute_images_client.delete_image, image['id'])
+
+    @decorators.idempotent_id('9fdd4630-731c-4f7c-bce5-69fa3792c52a')
+    @testtools.skipUnless(CONF.compute_feature_enabled.snapshot,
+                          'Snapshotting not available, backup not possible.')
+    @utils.services('image')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-create-backup")
+    def test_create_backup(self):
+        # Prioritize glance v2 over v1 for deleting/waiting for image status.
+        if CONF.image_feature_enabled.api_v2:
+            glance_admin_client = self.os_admin.image_client_v2
+        elif CONF.image_feature_enabled.api_v1:
+            glance_admin_client = self.os_admin.image_client
+        else:
+            raise lib_exc.InvalidConfiguration(
+                'Either api_v1 or api_v2 must be True in '
+                '[image-feature-enabled].')
+
+        backup_name = data_utils.rand_name(self.__class__.__name__ + '-Backup')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        resp = self.servers_client.create_backup(
+            self.server_id, backup_type='daily', rotation=1,
+            name=backup_name).response
+
+        # Prior to microversion 2.45, image ID must be parsed from location
+        # header. With microversion 2.45+, image_id is returned.
+        if api_version_utils.compare_version_header_to_response(
+                "OpenStack-API-Version", "2.45", resp, "lt"):
+            image_id = resp['image_id']
+        else:
+            image_id = data_utils.parse_image_id(resp['location'])
+
+        # Use admin credentials to wait since waiting involves show, which is
+        # a different policy.
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        glance_admin_client.delete_image, image_id)
+        waiters.wait_for_image_status(glance_admin_client, image_id, 'active')
 
 
 class ServerActionsV214RbacTest(rbac_base.BaseV2ComputeRbacTest):
@@ -308,8 +284,11 @@
     @decorators.idempotent_id('78ecef3c-faff-412a-83be-47651963eb21')
     def test_evacuate_server(self):
         fake_host_name = data_utils.rand_name(
-            self.__class__.__name__ + '-FakeHost')
+            self.__class__.__name__ + '-fake-host')
 
+        # NOTE(felipemonteiro): Because evacuating a server is a risky action
+        # to test in the gates, a 404 is coerced using a fake host. However,
+        # the policy check is done before the 404 is thrown.
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.assertRaisesRegex(lib_exc.NotFound,
                                "Compute host %s not found." % fake_host_name,
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_groups_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_groups_rbac.py
index f9b065c..be24569 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_server_groups_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_groups_rbac.py
@@ -13,8 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -25,7 +25,7 @@
     @classmethod
     def skip_checks(cls):
         super(ServerGroupsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-server-groups', 'compute'):
+        if not utils.is_extension_enabled('os-server-groups', 'compute'):
             msg = "%s skipped as os-server-groups not enabled." % cls.__name__
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py
index 654d3f1..f15dd78 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py
@@ -15,13 +15,13 @@
 
 import testtools
 
+from tempest.common import utils
 from tempest.common import waiters
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions as lib_exc
-from tempest import test
 
 from patrole_tempest_plugin import rbac_exceptions
 from patrole_tempest_plugin import rbac_rule_validation
@@ -76,7 +76,7 @@
         return self.create_test_server(
             wait_until='ACTIVE', adminPass=self.password)
 
-    @test.requires_ext(extension='os-admin-actions', service='compute')
+    @utils.requires_ext(extension='os-admin-actions', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-admin-actions:reset_state")
@@ -88,7 +88,7 @@
         self.addCleanup(self.servers_client.reset_state, self.server['id'],
                         state='active')
 
-    @test.requires_ext(extension='os-admin-actions', service='compute')
+    @utils.requires_ext(extension='os-admin-actions', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-admin-actions:inject_network_info")
@@ -98,7 +98,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.servers_client.inject_network_info(self.server['id'])
 
-    @test.requires_ext(extension='os-admin-actions', service='compute')
+    @utils.requires_ext(extension='os-admin-actions', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-admin-actions:reset_network")
@@ -127,7 +127,7 @@
         waiters.wait_for_server_status(
             self.os_admin.servers_client, self.server['id'], 'ACTIVE')
 
-    @test.requires_ext(extension='os-config-drive', service='compute')
+    @utils.requires_ext(extension='os-config-drive', service='compute')
     @decorators.idempotent_id('2c82e819-382d-4d6f-87f0-a45954cbbc64')
     @rbac_rule_validation.action(
         service="nova",
@@ -142,7 +142,7 @@
             raise rbac_exceptions.RbacMalformedResponse(
                 attribute=expected_attr)
 
-    @test.requires_ext(extension='os-config-drive', service='compute')
+    @utils.requires_ext(extension='os-config-drive', service='compute')
     @decorators.idempotent_id('55c62ef7-b72b-4970-acc6-05b0a4316e5d')
     @rbac_rule_validation.action(
         service="nova",
@@ -157,7 +157,7 @@
             raise rbac_exceptions.RbacMalformedResponse(
                 attribute=expected_attr)
 
-    @test.requires_ext(extension='os-deferred-delete', service='compute')
+    @utils.requires_ext(extension='os-deferred-delete', service='compute')
     @decorators.idempotent_id('189bfed4-1e6d-475c-bb8c-d57e60895391')
     @rbac_rule_validation.action(
         service="nova",
@@ -169,7 +169,7 @@
         self.servers_client.force_delete_server(self.server['id'])
 
     @decorators.idempotent_id('d873740a-7b10-40a9-943d-7cc18115370e')
-    @test.requires_ext(extension='OS-EXT-AZ', service='compute')
+    @utils.requires_ext(extension='OS-EXT-AZ', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-extended-availability-zone")
@@ -185,7 +185,7 @@
                 attribute=expected_attr)
 
     @decorators.idempotent_id('727e5360-770a-4b9c-8015-513a40216635')
-    @test.requires_ext(extension='OS-EXT-AZ', service='compute')
+    @utils.requires_ext(extension='OS-EXT-AZ', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-extended-availability-zone")
@@ -199,8 +199,52 @@
             raise rbac_exceptions.RbacMalformedResponse(
                 attribute=expected_attr)
 
+    @decorators.idempotent_id('4aa5d93e-4887-468a-8eb4-b6eca0ca6437')
+    @utils.requires_ext(extension='OS-EXT-SRV-ATTR', service='compute')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-extended-server-attributes")
+    def test_list_servers_extended_server_attributes(self):
+        """Test list servers with details, with extended server attributes in
+        response body.
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        body = self.servers_client.list_servers(detail=True)['servers']
+
+        # NOTE(felipemonteiro): The attributes included below should be
+        # returned by all microversions. We don't include tests for other
+        # microversions since Tempest schema validation takes care of that in
+        # `show_server` call above. (Attributes there are *optional*.)
+        for attr in ('host', 'instance_name'):
+            whole_attr = 'OS-EXT-SRV-ATTR:%s' % attr
+            if whole_attr not in body[0]:
+                raise rbac_exceptions.RbacMalformedResponse(
+                    attribute=whole_attr)
+
+    @decorators.idempotent_id('2ed7aee2-94b2-4a9f-ae63-a51b7f94fe30')
+    @utils.requires_ext(extension='OS-EXT-SRV-ATTR', service='compute')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-extended-server-attributes")
+    def test_show_server_extended_server_attributes(self):
+        """Test show server with extended server attributes in response
+        body.
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        body = self.servers_client.show_server(self.server['id'])['server']
+
+        # NOTE(felipemonteiro): The attributes included below should be
+        # returned by all microversions. We don't include tests for other
+        # microversions since Tempest schema validation takes care of that in
+        # `show_server` call above. (Attributes there are *optional*.)
+        for attr in ('host', 'instance_name'):
+            whole_attr = 'OS-EXT-SRV-ATTR:%s' % attr
+            if whole_attr not in body:
+                raise rbac_exceptions.RbacMalformedResponse(
+                    attribute=whole_attr)
+
     @decorators.idempotent_id('82053c27-3134-4003-9b55-bc9fafdb0e3b')
-    @test.requires_ext(extension='OS-EXT-STS', service='compute')
+    @utils.requires_ext(extension='OS-EXT-STS', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-extended-status")
@@ -217,7 +261,7 @@
                     attribute=attr)
 
     @decorators.idempotent_id('7d2620a5-eea1-4a8b-96ea-86ad77a73fc8')
-    @test.requires_ext(extension='OS-EXT-STS', service='compute')
+    @utils.requires_ext(extension='OS-EXT-STS', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-extended-status")
@@ -234,7 +278,7 @@
                     attribute=attr)
 
     @decorators.idempotent_id('21e39cbe-6c32-48fc-80dd-3e1fece6053f')
-    @test.requires_ext(extension='os-extended-volumes', service='compute')
+    @utils.requires_ext(extension='os-extended-volumes', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-extended-volumes")
@@ -251,7 +295,7 @@
                 attribute=expected_attr)
 
     @decorators.idempotent_id('7f163708-0d25-4138-8512-dfdd72a92989')
-    @test.requires_ext(extension='os-extended-volumes', service='compute')
+    @utils.requires_ext(extension='os-extended-volumes', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-extended-volumes")
@@ -267,7 +311,7 @@
             raise rbac_exceptions.RbacMalformedResponse(
                 attribute=expected_attr)
 
-    @test.requires_ext(extension='os-instance-actions', service='compute')
+    @utils.requires_ext(extension='os-instance-actions', service='compute')
     @decorators.idempotent_id('9d1b131d-407e-4fa3-8eef-eb2c4526f1da')
     @rbac_rule_validation.action(
         service="nova",
@@ -277,7 +321,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.servers_client.list_instance_actions(self.server['id'])
 
-    @test.requires_ext(extension='os-instance-actions', service='compute')
+    @utils.requires_ext(extension='os-instance-actions', service='compute')
     @decorators.idempotent_id('eb04c439-4215-4029-9ccb-5b3c041bfc25')
     @rbac_rule_validation.action(
         service="nova",
@@ -365,7 +409,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.servers_client.unlock_server(self.server['id'])
 
-    @test.requires_ext(extension='os-rescue', service='compute')
+    @utils.requires_ext(extension='os-rescue', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-rescue")
@@ -375,7 +419,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.servers_client.rescue_server(self.server['id'])
 
-    @test.requires_ext(extension='os-server-diagnostics', service='compute')
+    @utils.requires_ext(extension='os-server-diagnostics', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-server-diagnostics")
@@ -385,7 +429,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.servers_client.show_server_diagnostics(self.server['id'])
 
-    @test.requires_ext(extension='os-server-password', service='compute')
+    @utils.requires_ext(extension='os-server-password', service='compute')
     @decorators.idempotent_id('aaf43f78-c178-4581-ac18-14afd3f1f6ba')
     @rbac_rule_validation.action(
         service="nova",
@@ -395,7 +439,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.servers_client.delete_password(self.server['id'])
 
-    @test.requires_ext(extension='os-server-password', service='compute')
+    @utils.requires_ext(extension='os-server-password', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-server-password")
@@ -405,7 +449,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.servers_client.show_password(self.server['id'])
 
-    @test.requires_ext(extension='OS-SRV-USG', service='compute')
+    @utils.requires_ext(extension='OS-SRV-USG', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-server-usage")
@@ -419,7 +463,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.servers_client.show_server(self.server['id'])
 
-    @test.requires_ext(extension='os-simple-tenant-usage', service='compute')
+    @utils.requires_ext(extension='os-simple-tenant-usage', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-simple-tenant-usage:list")
@@ -429,7 +473,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.tenant_usages_client.list_tenant_usages()
 
-    @test.requires_ext(extension='os-simple-tenant-usage', service='compute')
+    @utils.requires_ext(extension='os-simple-tenant-usage', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-simple-tenant-usage:show")
@@ -516,7 +560,7 @@
 
     @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
                           "Interface attachment is not available.")
-    @test.requires_ext(extension='os-attach-interfaces', service='compute')
+    @utils.requires_ext(extension='os-attach-interfaces', service='compute')
     @decorators.idempotent_id('ddf53cb6-4a0a-4e5a-91e3-6c32aaa3b9b6')
     @rbac_rule_validation.action(
         service="nova",
@@ -527,9 +571,23 @@
         self.interfaces_client.list_interfaces(
             self.server['id'])['interfaceAttachments']
 
+    @decorators.idempotent_id('1b9cf7db-dc50-48a2-8eb9-8c25af5e934a')
     @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
                           "Interface attachment is not available.")
-    @test.requires_ext(extension='os-attach-interfaces', service='compute')
+    @utils.requires_ext(extension='os-attach-interfaces', service='compute')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-attach-interfaces")
+    def test_show_interface(self):
+        """Test show interfaces, part of os-attach-interfaces."""
+        interface = self._attach_interface_to_server()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.interfaces_client.show_interface(
+            self.server['id'], interface['port_id'])['interfaceAttachment']
+
+    @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
+                          "Interface attachment is not available.")
+    @utils.requires_ext(extension='os-attach-interfaces', service='compute')
     @decorators.idempotent_id('d2d3a24d-4738-4bce-a287-36d664746cde')
     @rbac_rule_validation.action(
         service="nova",
@@ -541,7 +599,7 @@
 
     @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
                           "Interface attachment is not available.")
-    @test.requires_ext(extension='os-attach-interfaces', service='compute')
+    @utils.requires_ext(extension='os-attach-interfaces', service='compute')
     @decorators.idempotent_id('55b05692-ed44-4608-a84c-cd4219c82799')
     @rbac_rule_validation.action(
         service="nova",
@@ -555,7 +613,7 @@
                                                 interface['port_id'])
 
     @decorators.idempotent_id('6886d360-0d86-4760-b1a3-882d81fbebcc')
-    @test.requires_ext(extension='os-ips', service='compute')
+    @utils.requires_ext(extension='os-ips', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:ips:index")
@@ -565,7 +623,7 @@
         self.servers_client.list_addresses(self.server['id'])['addresses']
 
     @decorators.idempotent_id('fa43e7e5-0db9-48eb-9c6b-c11eb766b8e4')
-    @test.requires_ext(extension='os-ips', service='compute')
+    @utils.requires_ext(extension='os-ips', service='compute')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:ips:show")
@@ -581,7 +639,7 @@
 
     @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
                           "Interface attachment is not available.")
-    @test.requires_ext(extension='os-multinic', service='compute')
+    @utils.requires_ext(extension='os-multinic', service='compute')
     @rbac_rule_validation.action(
         service="nova", rule="os_compute_api:os-multinic")
     @decorators.idempotent_id('bd3e2c74-130a-40f0-8085-124d93fe67da')
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py
index 35ca437..0fe92a9 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py
@@ -15,12 +15,13 @@
 
 from oslo_log import log
 
+from tempest.common import utils
 from tempest.common import waiters
 from tempest import config
 from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 from tempest.lib import exceptions
-from tempest import test
 
 from patrole_tempest_plugin import rbac_exceptions
 from patrole_tempest_plugin import rbac_rule_validation
@@ -75,7 +76,7 @@
         self.create_test_server(wait_until='ACTIVE',
                                 availability_zone=availability_zone)
 
-    @test.services('volume')
+    @utils.services('volume')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:servers:create:attach_volume")
@@ -98,10 +99,18 @@
 
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         # Use image_id='' to avoid using the default image in tempest.conf.
-        self.create_test_server(name=server_name, image_id='',
-                                **device_mapping)
+        server = self.create_test_server(name=server_name, image_id='',
+                                         **device_mapping)
+        # Delete the server and wait for the volume to become available to
+        # avoid clean up errors.
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        waiters.wait_for_volume_resource_status,
+                        self.volumes_client, volume_id, 'available')
+        self.addCleanup(waiters.wait_for_server_termination,
+                        self.servers_client, server['id'])
+        self.addCleanup(self.delete_server, server['id'])
 
-    @test.services('network')
+    @utils.services('network')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:servers:create:attach_network")
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_tags_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_tags_rbac.py
index d3576d6..0f49095 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_server_tags_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_tags_rbac.py
@@ -13,9 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -29,7 +29,7 @@
     @classmethod
     def skip_checks(cls):
         super(ServerTagsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-server-tags', 'compute'):
+        if not utils.is_extension_enabled('os-server-tags', 'compute'):
             msg = "os-server-tags extension is not enabled."
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/compute/test_services_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_services_rbac.py
index 94d094c..316da00 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_services_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_services_rbac.py
@@ -13,8 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -25,7 +25,7 @@
     @classmethod
     def skip_checks(cls):
         super(ServicesRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-services', 'compute'):
+        if not utils.is_extension_enabled('os-services', 'compute'):
             raise cls.skipException(
                 '%s skipped as os-services not enabled' % cls.__name__)
 
diff --git a/patrole_tempest_plugin/tests/api/compute/test_tenant_networks_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_tenant_networks_rbac.py
index 9313943..830e19a 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_tenant_networks_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_tenant_networks_rbac.py
@@ -15,8 +15,8 @@
 
 from oslo_config import cfg
 
+from tempest.common import utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -40,7 +40,7 @@
     @classmethod
     def skip_checks(cls):
         super(TenantNetworksRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-tenant-networks', 'compute'):
+        if not utils.is_extension_enabled('os-tenant-networks', 'compute'):
             msg = "os-tenant-networks extension not enabled."
             raise cls.skipException(msg)
         if not CONF.service_available.neutron:
diff --git a/patrole_tempest_plugin/tests/api/identity/rbac_base.py b/patrole_tempest_plugin/tests/api/identity/rbac_base.py
index 51daf96..a99365d 100644
--- a/patrole_tempest_plugin/tests/api/identity/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/identity/rbac_base.py
@@ -26,49 +26,21 @@
 LOG = logging.getLogger(__name__)
 
 
-class BaseIdentityV2RbacTest(base.BaseIdentityV2Test):
+class BaseIdentityRbacTest(base.BaseIdentityTest):
 
     @classmethod
     def skip_checks(cls):
-        super(BaseIdentityV2RbacTest, cls).skip_checks()
+        super(BaseIdentityRbacTest, cls).skip_checks()
         if not CONF.patrole.enable_rbac:
             raise cls.skipException(
                 "%s skipped as RBAC testing not enabled" % cls.__name__)
 
     @classmethod
     def setup_clients(cls):
-        super(BaseIdentityV2RbacTest, cls).setup_clients()
+        super(BaseIdentityRbacTest, cls).setup_clients()
         cls.rbac_utils = rbac_utils.RbacUtils(cls)
 
     @classmethod
-    def resource_setup(cls):
-        super(BaseIdentityV2RbacTest, cls).resource_setup()
-        cls.endpoints = []
-        cls.roles = []
-        cls.services = []
-        cls.users = []
-
-    @classmethod
-    def resource_cleanup(cls):
-        for endpoint in cls.endpoints:
-            test_utils.call_and_ignore_notfound_exc(
-                cls.endpoints_client.delete_endpoint, endpoint['id'])
-
-        for role in cls.roles:
-            test_utils.call_and_ignore_notfound_exc(
-                cls.roles_client.delete_role, role['id'])
-
-        for service in cls.services:
-            test_utils.call_and_ignore_notfound_exc(
-                cls.services_client.delete_service, service['id'])
-
-        for user in cls.users:
-            test_utils.call_and_ignore_notfound_exc(
-                cls.users_client.delete_user, user['id'])
-
-        super(BaseIdentityV2RbacTest, cls).resource_cleanup()
-
-    @classmethod
     def setup_test_endpoint(cls, service=None):
         """Creates a service and an endpoint for test."""
         interface = 'public'
@@ -87,13 +59,11 @@
             params['publicurl'] = url
         elif cls.identity_version == 'v3':
             params['url'] = url
-        else:
-            LOG.debug("Keystone version is invalid."
-                      " Please enter a valid version number.")
-            raise KeyError
 
         endpoint = cls.endpoints_client.create_endpoint(**params)['endpoint']
-        cls.endpoints.append(endpoint)
+        cls.addClassResourceCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            cls.endpoints_client.delete_endpoint, endpoint['id'])
 
         return endpoint
 
@@ -102,7 +72,9 @@
         """Set up a test role."""
         name = data_utils.rand_name(cls.__name__ + '-test_role')
         role = cls.roles_client.create_role(name=name)['role']
-        cls.roles.append(role)
+        cls.addClassResourceCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            cls.roles_client.delete_role, role['id'])
 
         return role
 
@@ -122,12 +94,10 @@
             service = service['OS-KSADM:service']
         elif cls.identity_version == 'v3':
             service = service['service']
-        else:
-            LOG.debug("Keystone version is invalid."
-                      " Please enter a valid version number.")
-            raise KeyError
 
-        cls.services.append(service)
+        cls.addClassResourceCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            cls.services_client.delete_service, service['id'])
 
         return service
 
@@ -142,12 +112,14 @@
             email=email,
             password=password,
             **kwargs)['user']
-        cls.users.append(user)
+        cls.addClassResourceCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            cls.users_client.delete_user, user['id'])
 
         return user
 
 
-class BaseIdentityV2AdminRbacTest(BaseIdentityV2RbacTest):
+class BaseIdentityV2AdminRbacTest(BaseIdentityRbacTest):
     """Base test class for the Identity v2 admin API.
 
     Keystone's v2 API is split into two APIs: an admin and non-admin API. RBAC
@@ -156,6 +128,8 @@
     request object has ``context_is_admin``. For more details, see the
     implementation of ``assert_admin`` in ``keystone.common.wsgi``.
     """
+    identity_version = 'v2'
+    credentials = ['primary']
 
     @classmethod
     def skip_checks(cls):
@@ -213,9 +187,10 @@
         return token_id
 
 
-class BaseIdentityV3RbacTest(BaseIdentityV2RbacTest):
+class BaseIdentityV3RbacTest(BaseIdentityRbacTest):
 
     identity_version = 'v3'
+    credentials = ['primary']
 
     @classmethod
     def setup_clients(cls):
diff --git a/patrole_tempest_plugin/tests/api/image/test_image_namespace_tags_rbac.py b/patrole_tempest_plugin/tests/api/image/test_image_namespace_tags_rbac.py
index 8e2bc49..ecf2ec2 100644
--- a/patrole_tempest_plugin/tests/api/image/test_image_namespace_tags_rbac.py
+++ b/patrole_tempest_plugin/tests/api/image/test_image_namespace_tags_rbac.py
@@ -39,11 +39,9 @@
         cls.namespace = cls.namespaces_client.create_namespace(
             namespace=data_utils.rand_name(
                 cls.__name__ + '-namespace'))['namespace']
-
-    @classmethod
-    def resource_cleanup(cls):
-        cls.namespaces_client.delete_namespace(cls.namespace)
-        super(NamespaceTagsRbacTest, cls).resource_cleanup()
+        cls.addClassResourceCleanup(
+            cls.namespaces_client.delete_namespace,
+            cls.namespace)
 
     def _create_namespace_tag(self, multiple=False):
         tag_count = 2 if multiple else 1
diff --git a/patrole_tempest_plugin/tests/api/image/test_image_resource_types_rbac.py b/patrole_tempest_plugin/tests/api/image/test_image_resource_types_rbac.py
index 456e10b..701e345 100644
--- a/patrole_tempest_plugin/tests/api/image/test_image_resource_types_rbac.py
+++ b/patrole_tempest_plugin/tests/api/image/test_image_resource_types_rbac.py
@@ -31,13 +31,9 @@
         cls.namespaces_client.create_namespace(
             namespace=cls.namespace_name,
             protected=False)
-
-    @classmethod
-    def resource_cleanup(cls):
-        test_utils.call_and_ignore_notfound_exc(
-            cls.namespaces_client.delete_namespace,
-            cls.namespace_name)
-        super(ImageResourceTypesRbacTest, cls).resource_cleanup()
+        cls.addClassResourceCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            cls.namespaces_client.delete_namespace, cls.namespace_name)
 
     @rbac_rule_validation.action(service="glance",
                                  rule="list_metadef_resource_types")
diff --git a/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py b/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py
index 506dd5b..fb747d6 100644
--- a/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py
@@ -13,9 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.network import rbac_base as base
@@ -26,7 +26,7 @@
     @classmethod
     def skip_checks(cls):
         super(AgentsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('agent', 'network'):
+        if not utils.is_extension_enabled('agent', 'network'):
             msg = "agent extension not enabled."
             raise cls.skipException(msg)
 
@@ -70,7 +70,7 @@
     @classmethod
     def skip_checks(cls):
         super(L3AgentSchedulerRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('l3_agent_scheduler', 'network'):
+        if not utils.is_extension_enabled('l3_agent_scheduler', 'network'):
             msg = "l3_agent_scheduler extension not enabled."
             raise cls.skipException(msg)
 
@@ -149,7 +149,7 @@
     @classmethod
     def skip_checks(cls):
         super(DHCPAgentSchedulersRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('dhcp_agent_scheduler', 'network'):
+        if not utils.is_extension_enabled('dhcp_agent_scheduler', 'network'):
             msg = "dhcp_agent_scheduler extension not enabled."
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/network/test_floating_ips_rbac.py b/patrole_tempest_plugin/tests/api/network/test_floating_ips_rbac.py
index 67b32a2..dc674d1 100644
--- a/patrole_tempest_plugin/tests/api/network/test_floating_ips_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_floating_ips_rbac.py
@@ -30,10 +30,15 @@
     @classmethod
     def resource_setup(cls):
         super(FloatingIpsRbacTest, cls).resource_setup()
-
-        # Create an external network for floating ip creation
+        # Create an external network for floating ip creation.
         cls.fip_extnet = cls.create_network(**{'router:external': True})
+        # Update router:external attribute to False for proper subnet resource
+        # cleanup by base class.
         cls.fip_extnet_id = cls.fip_extnet['id']
+        cls.addClassResourceCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            cls.networks_client.update_network, cls.fip_extnet_id,
+            **{'router:external': False})
 
         # Create a subnet for the external network
         cls.cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
@@ -41,14 +46,6 @@
                           cidr=cls.cidr,
                           mask_bits=24)
 
-    @classmethod
-    def resource_cleanup(cls):
-        # Update router:external attribute to False for proper subnet resource
-        # cleanup by base class
-        cls.networks_client.update_network(cls.fip_extnet_id,
-                                           **{'router:external': False})
-        super(FloatingIpsRbacTest, cls).resource_cleanup()
-
     def _create_floatingip(self, floating_ip_address=None):
         if floating_ip_address is not None:
             body = self.floating_ips_client.create_floatingip(
diff --git a/patrole_tempest_plugin/tests/api/network/test_metering_label_rules_rbac.py b/patrole_tempest_plugin/tests/api/network/test_metering_label_rules_rbac.py
index 3c74c07..5ffc966 100644
--- a/patrole_tempest_plugin/tests/api/network/test_metering_label_rules_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_metering_label_rules_rbac.py
@@ -13,11 +13,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.network import rbac_base as base
@@ -30,7 +30,7 @@
     @classmethod
     def skip_checks(cls):
         super(MeteringLabelRulesRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('metering', 'network'):
+        if not utils.is_extension_enabled('metering', 'network'):
             msg = "metering extension not enabled."
             raise cls.skipException(msg)
 
@@ -44,15 +44,11 @@
     @classmethod
     def resource_setup(cls):
         super(MeteringLabelRulesRbacTest, cls).resource_setup()
-
         body = cls.metering_labels_client.create_metering_label(
             name=data_utils.rand_name(cls.__name__))
         cls.label = body['metering_label']
-
-    @classmethod
-    def resource_cleanup(cls):
-        cls.metering_labels_client.delete_metering_label(cls.label['id'])
-        super(MeteringLabelRulesRbacTest, cls).resource_cleanup()
+        cls.addClassResourceCleanup(
+            cls.metering_labels_client.delete_metering_label, cls.label['id'])
 
     def _create_metering_label_rule(self, label):
         body = self.metering_label_rules_client.create_metering_label_rule(
diff --git a/patrole_tempest_plugin/tests/api/network/test_metering_labels_rbac.py b/patrole_tempest_plugin/tests/api/network/test_metering_labels_rbac.py
index 89c6870..64df7c5 100644
--- a/patrole_tempest_plugin/tests/api/network/test_metering_labels_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_metering_labels_rbac.py
@@ -13,10 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.network import rbac_base as base
@@ -27,7 +27,7 @@
     @classmethod
     def skip_checks(cls):
         super(MeteringLabelsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('metering', 'network'):
+        if not utils.is_extension_enabled('metering', 'network'):
             msg = "metering extension not enabled."
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/network/test_networks_multiprovider_rbac.py b/patrole_tempest_plugin/tests/api/network/test_networks_multiprovider_rbac.py
index 9d2b67a..7c7395b 100644
--- a/patrole_tempest_plugin/tests/api/network/test_networks_multiprovider_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_networks_multiprovider_rbac.py
@@ -14,10 +14,10 @@
 #    under the License.
 
 from oslo_log import log
+from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_exceptions
 from patrole_tempest_plugin import rbac_rule_validation
@@ -31,7 +31,7 @@
     @classmethod
     def skip_checks(cls):
         super(NetworksMultiProviderRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('multi-provider', 'network'):
+        if not utils.is_extension_enabled('multi-provider', 'network'):
             msg = "multi-provider extension not enabled."
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py b/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py
index 148804e..e0cf098 100644
--- a/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py
@@ -15,10 +15,10 @@
 
 import netaddr
 
+from tempest.common import utils
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_exceptions
 from patrole_tempest_plugin import rbac_rule_validation
@@ -110,7 +110,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_network(shared=True)
 
-    @test.requires_ext(extension='external-net', service='network')
+    @utils.requires_ext(extension='external-net', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="create_network:router:external")
     @decorators.idempotent_id('51adf2a7-739c-41e0-8857-3b4c460cbd24')
@@ -123,7 +123,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_network(router_external=True)
 
-    @test.requires_ext(extension='provider', service='network')
+    @utils.requires_ext(extension='provider', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="create_network:provider:network_type")
     @decorators.idempotent_id('3c42f7b8-b80c-44ef-8fa4-69ec4b1836bc')
@@ -136,7 +136,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_network(provider_network_type='vxlan')
 
-    @test.requires_ext(extension='provider', service='network')
+    @utils.requires_ext(extension='provider', service='network')
     @rbac_rule_validation.action(
         service="neutron",
         rule="create_network:provider:segmentation_id")
@@ -179,7 +179,7 @@
         self._update_network(shared_network=True)
         self.addCleanup(self._update_network, shared_network=False)
 
-    @test.requires_ext(extension='external-net', service='network')
+    @utils.requires_ext(extension='external-net', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="update_network:router:external")
     @decorators.idempotent_id('34884c22-499b-4960-97f1-e2ed8522a9c9')
@@ -205,7 +205,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.networks_client.show_network(self.network['id'])
 
-    @test.requires_ext(extension='external-net', service='network')
+    @utils.requires_ext(extension='external-net', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="get_network:router:external")
     @decorators.idempotent_id('529e4814-22e9-413f-af48-8fefcd637344')
@@ -221,7 +221,7 @@
         self.networks_client.show_network(self.network['id'],
                                           **kwargs)
 
-    @test.requires_ext(extension='provider', service='network')
+    @utils.requires_ext(extension='provider', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="get_network:provider:network_type")
     @decorators.idempotent_id('6521dd60-0950-458b-8491-09d3c84ac0f4')
@@ -240,7 +240,7 @@
         if len(retrieved_network) == 0:
             raise rbac_exceptions.RbacMalformedResponse(True)
 
-    @test.requires_ext(extension='provider', service='network')
+    @utils.requires_ext(extension='provider', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="get_network:provider:physical_network")
     @decorators.idempotent_id('c049f11a-240c-4a85-ad43-a4d3fd0a5e39')
@@ -259,7 +259,7 @@
         if len(retrieved_network) == 0:
             raise rbac_exceptions.RbacMalformedResponse(empty=True)
 
-    @test.requires_ext(extension='provider', service='network')
+    @utils.requires_ext(extension='provider', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="get_network:provider:segmentation_id")
     @decorators.idempotent_id('38d9f085-6365-4f81-bac9-c53c294d727e')
@@ -351,7 +351,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.subnets_client.delete_subnet(subnet['id'])
 
-    @test.requires_ext(extension='dhcp_agent_scheduler', service='network')
+    @utils.requires_ext(extension='dhcp_agent_scheduler', service='network')
     @decorators.idempotent_id('b524f19f-fbb4-4d11-a85d-03bfae17bf0e')
     @rbac_rule_validation.action(service="neutron",
                                  rule="get_dhcp-agents")
diff --git a/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py b/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py
index 888f879..2fb26f8 100644
--- a/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py
@@ -16,11 +16,11 @@
 
 import netaddr
 
+from tempest.common import utils
 from tempest.common.utils import net_utils
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_exceptions
 from patrole_tempest_plugin import rbac_rule_validation
@@ -79,7 +79,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.create_port(self.network, port_security_enabled=True)
 
-    @test.requires_ext(extension='binding', service='network')
+    @utils.requires_ext(extension='binding', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="create_port:binding:host_id")
     @decorators.idempotent_id('a54bd6b8-a7eb-4101-bfe8-093930b0d660')
@@ -91,7 +91,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.create_port(**post_body)
 
-    @test.requires_ext(extension='binding', service='network')
+    @utils.requires_ext(extension='binding', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="create_port:binding:profile")
     @decorators.idempotent_id('98fa38ab-c2ed-46a0-99f0-59f18cbd257a')
@@ -154,7 +154,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.ports_client.show_port(self.port['id'])
 
-    @test.requires_ext(extension='binding', service='network')
+    @utils.requires_ext(extension='binding', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="get_port:binding:vif_type")
     @decorators.idempotent_id('125aff0b-8fed-4f8e-8410-338616594b06')
@@ -173,7 +173,7 @@
             raise rbac_exceptions.RbacMalformedResponse(
                 attribute='binding:vif_type')
 
-    @test.requires_ext(extension='binding', service='network')
+    @utils.requires_ext(extension='binding', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="get_port:binding:vif_details")
     @decorators.idempotent_id('e42bfd77-fcce-45ee-9728-3424300f0d6f')
@@ -192,7 +192,7 @@
             raise rbac_exceptions.RbacMalformedResponse(
                 attribute='binding:vif_details')
 
-    @test.requires_ext(extension='binding', service='network')
+    @utils.requires_ext(extension='binding', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="get_port:binding:host_id")
     @decorators.idempotent_id('8e61bcdc-6f81-443c-833e-44410266551e')
@@ -213,7 +213,7 @@
             raise rbac_exceptions.RbacMalformedResponse(
                 attribute='binding:host_id')
 
-    @test.requires_ext(extension='binding', service='network')
+    @utils.requires_ext(extension='binding', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="get_port:binding:profile")
     @decorators.idempotent_id('d497cea9-c4ad-42e0-acc9-8d257d6b01fc')
@@ -290,7 +290,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.ports_client.update_port(self.port['id'], security_groups=[])
 
-    @test.requires_ext(extension='binding', service='network')
+    @utils.requires_ext(extension='binding', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="update_port:binding:host_id")
     @decorators.idempotent_id('24206a72-0d90-4712-918c-5c9a1ebef64d')
@@ -306,7 +306,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.ports_client.update_port(**updated_body)
 
-    @test.requires_ext(extension='binding', service='network')
+    @utils.requires_ext(extension='binding', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="update_port:binding:profile")
     @decorators.idempotent_id('990ea8d1-9257-4f71-a3bf-d6d0914625c5')
diff --git a/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py b/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py
index 45a5cda..c3ed9e1 100644
--- a/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py
@@ -15,11 +15,11 @@
 
 import netaddr
 
+from tempest.common import utils
 from tempest.common.utils import net_utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_exceptions
 from patrole_tempest_plugin import rbac_rule_validation
@@ -30,7 +30,7 @@
     @classmethod
     def skip_checks(cls):
         super(RouterRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('router', 'network'):
+        if not utils.is_extension_enabled('router', 'network'):
             msg = "router extension not enabled."
             raise cls.skipException(msg)
 
@@ -69,7 +69,7 @@
                         router['router']['id'])
 
     @decorators.idempotent_id('6139eb97-95c0-40d8-a109-99de11ab2e5e')
-    @test.requires_ext(extension='l3-ha', service='network')
+    @utils.requires_ext(extension='l3-ha', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="create_router:ha")
     def test_create_high_availability_router(self):
@@ -83,7 +83,7 @@
                         router['router']['id'])
 
     @decorators.idempotent_id('c6254ca6-2728-412d-803d-d4aa3935e56d')
-    @test.requires_ext(extension='dvr', service='network')
+    @utils.requires_ext(extension='dvr', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="create_router:distributed")
     def test_create_distributed_router(self):
@@ -96,7 +96,7 @@
         self.addCleanup(self.routers_client.delete_router,
                         router['router']['id'])
 
-    @test.requires_ext(extension='ext-gw-mode', service='network')
+    @utils.requires_ext(extension='ext-gw-mode', service='network')
     @rbac_rule_validation.action(
         service="neutron",
         rule="create_router:external_gateway_info:enable_snat")
@@ -156,7 +156,7 @@
         self.routers_client.show_router(self.router['id'], fields=['id'])
 
     @decorators.idempotent_id('3ed26ea2-b419-410c-b4b5-576c1edafa06')
-    @test.requires_ext(extension='dvr', service='network')
+    @utils.requires_ext(extension='dvr', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="get_router:distributed")
     def test_show_distributed_router(self):
@@ -221,7 +221,7 @@
             self.router['id'],
             external_gateway_info=None)
 
-    @test.requires_ext(extension='ext-gw-mode', service='network')
+    @utils.requires_ext(extension='ext-gw-mode', service='network')
     @rbac_rule_validation.action(
         service="neutron",
         rule="update_router:external_gateway_info:enable_snat")
@@ -268,7 +268,7 @@
             external_gateway_info=None)
 
     @decorators.idempotent_id('ddc20731-dea1-4321-9abf-8772bf0b5977')
-    @test.requires_ext(extension='l3-ha', service='network')
+    @utils.requires_ext(extension='l3-ha', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="update_router:ha")
     def test_update_high_availability_router(self):
@@ -282,7 +282,7 @@
                         ha=False)
 
     @decorators.idempotent_id('e1932c19-8f73-41cd-b5d2-84c7ae5d530c')
-    @test.requires_ext(extension='dvr', service='network')
+    @utils.requires_ext(extension='dvr', service='network')
     @rbac_rule_validation.action(service="neutron",
                                  rule="update_router:distributed")
     def test_update_distributed_router(self):
diff --git a/patrole_tempest_plugin/tests/api/network/test_security_groups_rbac.py b/patrole_tempest_plugin/tests/api/network/test_security_groups_rbac.py
index 2672b57..3ed23fd 100644
--- a/patrole_tempest_plugin/tests/api/network/test_security_groups_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_security_groups_rbac.py
@@ -13,10 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.network import rbac_base as base
@@ -27,7 +27,7 @@
     @classmethod
     def skip_checks(cls):
         super(SecGroupRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('security-group', 'network'):
+        if not utils.is_extension_enabled('security-group', 'network'):
             msg = "security-group extension not enabled."
             raise cls.skipException(msg)
 
@@ -37,14 +37,9 @@
         secgroup_name = data_utils.rand_name(cls.__name__ + '-secgroup')
         cls.secgroup = cls.security_groups_client.create_security_group(
             name=secgroup_name)['security_group']
-
-    @classmethod
-    def resource_cleanup(cls):
-        # Clean up security group
-        test_utils.call_and_ignore_notfound_exc(
+        cls.addClassResourceCleanup(
             cls.security_groups_client.delete_security_group,
             cls.secgroup['id'])
-        super(SecGroupRbacTest, cls).resource_cleanup()
 
     def _create_security_group(self):
         # Create a security group
diff --git a/patrole_tempest_plugin/tests/api/network/test_subnetpools_rbac.py b/patrole_tempest_plugin/tests/api/network/test_subnetpools_rbac.py
index 44f6be4..9231c15 100644
--- a/patrole_tempest_plugin/tests/api/network/test_subnetpools_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_subnetpools_rbac.py
@@ -13,11 +13,11 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.network import rbac_base as base
@@ -30,7 +30,7 @@
     @classmethod
     def skip_checks(cls):
         super(SubnetPoolsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('subnet_allocation', 'network'):
+        if not utils.is_extension_enabled('subnet_allocation', 'network'):
             msg = "subnet_allocation extension not enabled."
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py b/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py
index 68f5156..23f11cf 100644
--- a/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py
@@ -13,9 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.network import rbac_base as base
@@ -26,7 +26,7 @@
     @classmethod
     def skip_checks(cls):
         super(SubnetsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('subnet_allocation', 'network'):
+        if not utils.is_extension_enabled('subnet_allocation', 'network'):
             msg = "subnet_allocation extension not enabled."
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/volume/rbac_base.py b/patrole_tempest_plugin/tests/api/volume/rbac_base.py
index 6db364e..f4531df 100644
--- a/patrole_tempest_plugin/tests/api/volume/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/volume/rbac_base.py
@@ -41,24 +41,17 @@
         cls.group_types_client = cls.os_primary.group_types_v3_client
 
     @classmethod
-    def resource_setup(cls):
-        super(BaseVolumeRbacTest, cls).resource_setup()
-        cls.volume_types = []
-
-    @classmethod
-    def resource_cleanup(cls):
-        super(BaseVolumeRbacTest, cls).resource_cleanup()
-        # Allow volumes to be cleared first, so only clear volume types
-        # after super's resource_cleanup.
-        cls.clear_volume_types()
-
-    @classmethod
     def create_volume_type(cls, name=None, **kwargs):
         """Create a test volume-type"""
         name = name or data_utils.rand_name(cls.__name__ + '-volume-type')
         volume_type = cls.volume_types_client.create_volume_type(
             name=name, **kwargs)['volume_type']
-        cls.volume_types.append(volume_type)
+        cls.addClassResourceCleanup(
+            cls.volume_types_client.wait_for_resource_deletion,
+            volume_type['id'])
+        cls.addClassResourceCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            cls.volume_types_client.delete_volume_type, volume_type['id'])
         return volume_type
 
     def create_group_type(self, name=None, ignore_notfound=False, **kwargs):
@@ -77,14 +70,3 @@
                             group_type['id'])
 
         return group_type
-
-    @classmethod
-    def clear_volume_types(cls):
-        for vol_type in cls.volume_types:
-            test_utils.call_and_ignore_notfound_exc(
-                cls.volume_types_client.delete_volume_type, vol_type['id'])
-
-        for vol_type in cls.volume_types:
-            test_utils.call_and_ignore_notfound_exc(
-                cls.volume_types_client.wait_for_resource_deletion,
-                vol_type['id'])
diff --git a/patrole_tempest_plugin/tests/api/volume/test_capabilities_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_capabilities_rbac.py
index 45b1660..74ffe60 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_capabilities_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_capabilities_rbac.py
@@ -13,8 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.volume import rbac_base
@@ -25,7 +25,7 @@
     @classmethod
     def skip_checks(cls):
         super(CapabilitiesRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('capabilities', 'volume'):
+        if not utils.is_extension_enabled('capabilities', 'volume'):
             msg = "%s skipped as capabilities not enabled." % cls.__name__
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/volume/test_encryption_types_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_encryption_types_rbac.py
index f11ef03..2cae0bd 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_encryption_types_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_encryption_types_rbac.py
@@ -12,8 +12,9 @@
 #    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.common import utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.volume import rbac_base
@@ -24,7 +25,7 @@
     @classmethod
     def skip_checks(cls):
         super(EncryptionTypesRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('encryption', 'volume'):
+        if not utils.is_extension_enabled('encryption', 'volume'):
             msg = "%s skipped as encryption not enabled." % cls.__name__
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/volume/test_quota_classes_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_quota_classes_rbac.py
index 1518ef4..d016498 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_quota_classes_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_quota_classes_rbac.py
@@ -13,9 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.volume import rbac_base
@@ -26,7 +26,7 @@
     @classmethod
     def skip_checks(cls):
         super(QuotaClassesRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-quota-class-sets', 'volume'):
+        if not utils.is_extension_enabled('os-quota-class-sets', 'volume'):
             msg = ("%s skipped as os-quota-class-sets not enabled."
                    % cls.__name__)
             raise cls.skipException(msg)
diff --git a/patrole_tempest_plugin/tests/api/volume/test_scheduler_stats_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_scheduler_stats_rbac.py
index dd423d1..25562e8 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_scheduler_stats_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_scheduler_stats_rbac.py
@@ -13,8 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.volume import rbac_base
@@ -25,7 +25,7 @@
     @classmethod
     def skip_checks(cls):
         super(SchedulerStatsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('scheduler-stats', 'volume'):
+        if not utils.is_extension_enabled('scheduler-stats', 'volume'):
             msg = "%s skipped as scheduler-stats not enabled." % cls.__name__
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_actions_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_actions_rbac.py
index 209821e..466fb0c 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volume_actions_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_actions_rbac.py
@@ -14,12 +14,12 @@
 #    under the License.
 
 from tempest.common import compute
+from tempest.common import utils
 from tempest.common import waiters
 from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.volume import rbac_base
@@ -68,7 +68,7 @@
         waiters.wait_for_volume_resource_status(
             self.admin_volumes_client, volume_id, 'available')
 
-    @test.services('compute')
+    @utils.services('compute')
     @rbac_rule_validation.action(service="cinder", rule="volume:attach")
     @decorators.idempotent_id('f97b10e4-2eed-4f8b-8632-71c02cb9fe42')
     def test_attach_volume_to_instance(self):
@@ -76,7 +76,7 @@
         self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._attach_volume(server)
 
-    @test.services('compute')
+    @utils.services('compute')
     @decorators.attr(type='slow')
     @rbac_rule_validation.action(service="cinder", rule="volume:detach")
     @decorators.idempotent_id('5a042f6a-688b-42e6-a02e-fe5c47b89b07')
@@ -88,7 +88,7 @@
         self._detach_volume()
 
     @decorators.attr(type=["slow"])
-    @test.services('image')
+    @utils.services('image')
     @rbac_rule_validation.action(
         service="cinder",
         rule="volume_extension:volume_actions:upload_image")
@@ -189,7 +189,7 @@
         self.volumes_client.wait_for_resource_deletion(volume['id'])
 
     @decorators.idempotent_id('48bd302b-950a-4830-840c-3158246ecdcc')
-    @test.services('compute')
+    @utils.services('compute')
     @rbac_rule_validation.action(
         service="cinder",
         rule="volume_extension:volume_admin_actions:force_detach")
@@ -229,7 +229,7 @@
         cls.admin_volumes_client = cls.os_admin.volumes_client_latest
 
     @decorators.attr(type=["slow"])
-    @test.services('image')
+    @utils.services('image')
     @rbac_rule_validation.action(
         service="cinder",
         rule="volume_extension:volume_actions:upload_public")
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_services_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_services_rbac.py
index ac6d2ce..63978aa 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volume_services_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_services_rbac.py
@@ -13,8 +13,8 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.volume import rbac_base
@@ -29,7 +29,7 @@
     @classmethod
     def skip_checks(cls):
         super(VolumeServicesRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-services', 'volume'):
+        if not utils.is_extension_enabled('os-services', 'volume'):
             msg = "%s skipped as os-services not enabled." % cls.__name__
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_types_access_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_types_access_rbac.py
index af9994c..773df2b 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volume_types_access_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_types_access_rbac.py
@@ -13,9 +13,9 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.volume import rbac_base
@@ -27,7 +27,7 @@
     @classmethod
     def skip_checks(cls):
         super(VolumeTypesAccessRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-volume-type-access', 'volume'):
+        if not utils.is_extension_enabled('os-volume-type-access', 'volume'):
             msg = "os-volume-type-access extension not enabled."
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_types_extra_specs_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_types_extra_specs_rbac.py
index 210901c..aa02316 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volume_types_extra_specs_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_types_extra_specs_rbac.py
@@ -13,10 +13,10 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import utils
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest import test
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.volume import rbac_base
@@ -28,7 +28,7 @@
     @classmethod
     def skip_checks(cls):
         super(VolumeTypesExtraSpecsRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-types-extra-specs', 'volume'):
+        if not utils.is_extension_enabled('os-types-extra-specs', 'volume'):
             msg = "os-types-extra-specs extension not enabled."
             raise cls.skipException(msg)
 
diff --git a/patrole_tempest_plugin/tests/unit/fixtures.py b/patrole_tempest_plugin/tests/unit/fixtures.py
index ce13029..52c2598 100644
--- a/patrole_tempest_plugin/tests/unit/fixtures.py
+++ b/patrole_tempest_plugin/tests/unit/fixtures.py
@@ -18,10 +18,12 @@
 
 import fixtures
 import mock
+import time
 
 from tempest import clients
 from tempest.common import credentials_factory as credentials
 from tempest import config
+from tempest import test
 
 from patrole_tempest_plugin import rbac_utils
 
@@ -73,13 +75,19 @@
             'os_primary.credentials.project_id': self.PROJECT_ID,
             'get_identity_version.return_value': 'v3'
         }
-        self.mock_test_obj = mock.Mock(__name__='foo', **test_obj_kwargs)
+        self.mock_test_obj = mock.Mock(
+            __name__='patrole_unit_test', spec=test.BaseTestCase,
+            os_primary=mock.Mock(), **test_obj_kwargs)
 
-        # Mock out functionality that can't be used by unit tests.
-        self.mock_time = mock.patch.object(rbac_utils, 'time').start()
-        mock.patch.object(
-            credentials, 'get_configured_admin_credentials').start()
-        mock_admin_mgr = mock.patch.object(clients, 'Manager').start()
+        # Mock out functionality that can't be used by unit tests. Mocking out
+        # time.sleep is a test optimization.
+        self.mock_time = mock.patch.object(
+            rbac_utils, 'time', __name__='mock_time', spec=time).start()
+        mock.patch.object(credentials, 'get_configured_admin_credentials',
+                          spec=object).start()
+        mock_admin_mgr = mock.patch.object(
+            clients, 'Manager', spec=clients.Manager,
+            roles_v3_client=mock.Mock(), roles_client=mock.Mock()).start()
         self.roles_v3_client = mock_admin_mgr.return_value.roles_v3_client
 
         self.set_roles(['admin', 'member'], [])
diff --git a/patrole_tempest_plugin/tests/unit/test_hacking.py b/patrole_tempest_plugin/tests/unit/test_hacking.py
index 021602b..6096c24 100644
--- a/patrole_tempest_plugin/tests/unit/test_hacking.py
+++ b/patrole_tempest_plugin/tests/unit/test_hacking.py
@@ -70,10 +70,10 @@
 
     def test_service_tags_not_in_module_path(self):
         self.assertTrue(checks.service_tags_not_in_module_path(
-            "@test.services('volume')",
+            "@utils.services('volume')",
             "./patrole_tempest_plugin/tests/api/volume/fake_test_rbac.py"))
         self.assertFalse(checks.service_tags_not_in_module_path(
-            "@test.services('image')",
+            "@utils.services('image')",
             "./patrole_tempest_plugin/tests/api/volume/fake_test_rbac.py"))
 
     def test_no_hyphen_at_end_of_rand_name(self):
@@ -138,7 +138,7 @@
         other_decorators = [
             "@decorators.idempotent_id(123)",
             "@decorators.attr(type=['slow'])",
-            "@test.requires_ext(extension='ext', service='svc')"
+            "@utils.requires_ext(extension='ext', service='svc')"
         ]
 
         if with_other_decorators:
diff --git a/patrole_tempest_plugin/tests/unit/test_policy_authority.py b/patrole_tempest_plugin/tests/unit/test_policy_authority.py
index 2a8da9d..db651fc 100644
--- a/patrole_tempest_plugin/tests/unit/test_policy_authority.py
+++ b/patrole_tempest_plugin/tests/unit/test_policy_authority.py
@@ -499,7 +499,8 @@
 
     def _test_validate_service(self, v2_services, v3_services,
                                expected_failure=False, expected_services=None):
-        with mock.patch.object(policy_authority, 'clients') as m_creds:
+        with mock.patch.object(
+            policy_authority, 'clients', autospec=True) as m_creds:
             m_creds.Manager().identity_services_client.list_services.\
                 return_value = v2_services
             m_creds.Manager().identity_services_v3_client.list_services.\
diff --git a/patrole_tempest_plugin/tests/unit/test_rbac_rule_validation.py b/patrole_tempest_plugin/tests/unit/test_rbac_rule_validation.py
index afadb43..3065cfe 100644
--- a/patrole_tempest_plugin/tests/unit/test_rbac_rule_validation.py
+++ b/patrole_tempest_plugin/tests/unit/test_rbac_rule_validation.py
@@ -42,9 +42,9 @@
 
         self.useFixture(
             fixtures.ConfPatcher(rbac_test_role='Member', group='patrole'))
-
-        # Mock the RBAC log so that it is not written to for any unit tests.
-        mock.patch.object(rbac_rv.RBACLOG, 'info').start()
+        # Disable patrole log for unit tests.
+        self.useFixture(
+            fixtures.ConfPatcher(enable_reporting=False, group='patrole_log'))
 
     @mock.patch.object(rbac_rv, 'LOG', autospec=True)
     @mock.patch.object(rbac_rv, 'policy_authority', autospec=True)
diff --git a/releasenotes/notes/extended-server-attributes-36623af87e714369.yaml b/releasenotes/notes/extended-server-attributes-36623af87e714369.yaml
new file mode 100644
index 0000000..a7ccd8e
--- /dev/null
+++ b/releasenotes/notes/extended-server-attributes-36623af87e714369.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Add complete RBAC test coverage for the compute APIs that enforce:
+    "os_compute_api:os-extended-server-attributes".
diff --git a/releasenotes/notes/os-create-backup-test-cd8037ea130c3d8d.yaml b/releasenotes/notes/os-create-backup-test-cd8037ea130c3d8d.yaml
new file mode 100644
index 0000000..625f4ff
--- /dev/null
+++ b/releasenotes/notes/os-create-backup-test-cd8037ea130c3d8d.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Add RBAC test for creating a server backup, providing coverage for the
+    policy action: "os_compute_api:os-create-backup".
diff --git a/requirements.txt b/requirements.txt
index abccb62..0e46596 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,7 @@
 # The order of packages is significant, because pip processes them in the order
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
-hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
+hacking>=1.0.0 # Apache-2.0
 pbr!=2.1.0,>=2.0.0 # Apache-2.0
 oslo.log>=3.30.0 # Apache-2.0
 oslo.config>=4.6.0 # Apache-2.0
diff --git a/test-requirements.txt b/test-requirements.txt
index dc2fec9..1953685 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,7 +1,7 @@
 # The order of packages is significant, because pip processes them in the order
 # of appearance. Changing the order has an impact on the overall integration
 # process, which may cause wedges in the gate later.
-hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
+hacking>=1.0.0 # Apache-2.0
 
 sphinx>=1.6.2 # BSD
 openstackdocstheme>=1.17.0 # Apache-2.0
diff --git a/tox.ini b/tox.ini
index 3f2cfcd..e95cadf 100644
--- a/tox.ini
+++ b/tox.ini
@@ -59,7 +59,13 @@
 commands = oslo-config-generator --config-file etc/config-generator.patrole.conf
 
 [flake8]
-enable-extensions = H106,H203,H904
+# [H106] Don’t put vim configuration in source files.
+# [H203] Use assertIs(Not)None to check for None.
+# [H204] Use assert(Not)Equal to check for equality.
+# [H205] Use assert(Greater|Less)(Equal) for comparison.
+# [H210] Require ‘autospec’, ‘spec’, or ‘spec_set’ in mock.patch/mock.patch.object calls
+# [H904] Delay string interpolations at logging calls.
+enable-extensions = H106,H203,H204,H205,H210,H904
 show-source = True
 # E123, E125 skipped as they are invalid PEP-8.
 #