Merge "Doc warnings as errors"
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index 595730a..243a9c0 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -1,14 +1,14 @@
 If you would like to contribute to the development of OpenStack, you must
 follow the steps in this page:
 
-   http://docs.openstack.org/infra/manual/developers.html
+   https://docs.openstack.org/infra/manual/developers.html
 
 If you already have a good understanding of how the system works and your
 OpenStack accounts are set up, you can skip to the development workflow
 section of this documentation to learn how changes to OpenStack should be
 submitted for review via the Gerrit tool:
 
-   http://docs.openstack.org/infra/manual/developers.html#development-workflow
+   https://docs.openstack.org/infra/manual/developers.html#development-workflow
 
 Pull requests submitted through GitHub will be ignored.
 
diff --git a/HACKING.rst b/HACKING.rst
index 722759f..5281b53 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -1,4 +1,64 @@
-patrole Style Commandments
-===============================================
+Patrole Style Commandments
+==========================
 
-Read the OpenStack Style Commandments http://docs.openstack.org/developer/hacking/
+- Step 1: Read the OpenStack Style Commandments: `<https://docs.openstack.org/developer/hacking/>`__
+- Step 2: Review Tempest's Style Commandments: `<https://docs.openstack.org/developer/tempest/HACKING.html>`__
+- Step 3: Read on
+
+Patrole Specific Commandments
+------------------------------
+
+Patrole borrows the following commandments from Tempest; refer to
+`Tempest's Commandments <https://docs.openstack.org/developer/tempest/HACKING.html>`__
+for more information:
+
+.. note::
+
+    The original Tempest Commandments do not include Patrole-specific paths.
+    Patrole-specific paths replace the Tempest-specific paths within Patrole's
+    hacking checks.
+..
+
+- [T102] Cannot import OpenStack python clients in patrole_tempest_plugin/tests/api
+- [T105] Tests cannot use setUpClass/tearDownClass
+- [T106] vim configuration should not be kept in source files.
+- [T107] Check that a service tag isn't in the module path
+- [T108] Check no hyphen at the end of rand_name() argument
+- [T109] Cannot use testtools.skip decorator; instead use
+         decorators.skip_because from tempest.lib
+- [T113] Check that tests use data_utils.rand_uuid() instead of uuid.uuid4()
+- [N322] Method's default argument shouldn't be mutable
+
+The following are Patrole's specific Commandments:
+
+- [P100] The ``rbac_rule_validation.action`` decorator must be applied to
+         an RBAC test (the check fails if the decorator is not one of the
+         two decorators directly above the function declaration)
+- [P101] RBAC test filenames must end with "_rbac.py"; for example,
+         test_servers_rbac.py, not test_servers.py
+- [P102] RBAC test class names must end in 'RbacTest'
+- [P103] ``self.client`` must not be used as a client alias; this allows for
+         code that is more maintainable and easier to read
+
+Role Switching
+--------------
+
+Correct role switching is vital to correct RBAC testing within Patrole. If a
+test does not call ``rbac_utils.switch_role`` with ``toggle_rbac_role=True``
+within the RBAC test, then the test is *not* a valid RBAC test: The API
+endpoint under test will be performed with admin credentials, which is always
+wrong unless ``CONF.rbac_test_role`` is admin.
+
+.. note::
+
+    Switching back to the admin role for setup and clean up is automatically
+    performed. Toggling ``switch_role`` with ``toggle_rbac_role=False`` within
+    the context of a test should *never* be performed and doing so will likely
+    result in an error being thrown.
+..
+
+Patrole does not have a hacking check for role switching, but does use a
+built-in mechanism for verifying that role switching is being correctly
+executed across tests. If a test does not call ``switch_role`` with
+``toggle_rbac_role=True``, then an ``RbacResourceSetupFailed`` exception
+will be raised.
diff --git a/README.rst b/README.rst
index d9a6507..f5b4c00 100644
--- a/README.rst
+++ b/README.rst
@@ -1,32 +1,178 @@
-=======
-patrole
-=======
+========================
+Team and repository tags
+========================
 
-Patrole is a tool for verifying that Role-Based Access Control is being enforced.
+.. image:: http://governance.openstack.org/badges/patrole.svg
+    :target: http://governance.openstack.org/reference/tags/index.html
 
-Patrole allows users to run API tests using specified RBAC roles.  This allows
+..
+
+=========================================
+Patrole - RBAC Integration Tempest Plugin
+=========================================
+
+Patrole is a tool for verifying that Role-Based Access Control is being
+correctly enforced.
+
+Patrole allows users to run API tests using specified RBAC roles. This allows
 deployments to verify that only intended roles have access to those APIs.
 This is critical to ensure security, especially in large deployments with
 custom roles.
 
 * Free software: Apache license
-* Documentation: http://docs.openstack.org/developer/patrole
-* Source: http://git.openstack.org/cgit/openstack/patrole
-* Bugs: http://bugs.launchpad.net/patrole
+* Documentation: https://docs.openstack.org/developer/patrole
+* Source: https://git.openstack.org/cgit/openstack/patrole
+* Bugs: https://bugs.launchpad.net/patrole
 
 Features
---------
-
-Patrole offers RBAC testing for various OpenStack RBAC policies.  It includes
+========
+Patrole offers RBAC testing for various OpenStack RBAC policies. It includes
 a decorator that wraps around tests which verifies that when the test calls the
-corresponding api endpoint, access is only granted for correct roles.
+corresponding API endpoint, access is only granted for correct roles.
 
+Currently, Patrole supports policies contained in code and in policy.json files.
+If both exist, the policy actions in the policy.json are prioritized.
+
+Stable Interface
+----------------
+Patrole offers a stable interface that is guaranteed to be backwards compatible and
+can be directly consumed by other projects. Currently, rbac_exceptions.py and
+rbac_policy_parser.py are guaranteed to be stable.
+
+Release Versioning
+------------------
+`Patrole Release Notes <https://docs.openstack.org/releasenotes/patrole/>`_ show
+what changes have been released.
+
+.. _test-flows:
+
+Test Flows
+----------
 There are several possible test flows.
 
-If the rbac_test_role is allowed to access the endpoint
- - The test passes if no 403 forbidden or RbacActionFailed exception is raised.
+If the ``rbac_test_role`` is allowed to access the endpoint:
 
-If the rbac_test_role is not allowed to access the endpoint
- - If the endpoint returns a 403 forbidden exception the test will pass
- - If the endpoint returns something other than a 403 forbidden to indicate
-   that the role is not allowed, the test will raise an RbacActionFailed exception.
+* The test passes if no 403 ``Forbidden`` or ``RbacActionFailed`` exception is raised.
+
+If the ``rbac_test_role`` is not allowed to access the endpoint:
+
+* If the endpoint returns a 403 `Forbidden` exception the test will pass.
+* If the endpoint returns successfully, then the test will fail with an
+  ``RbacOverPermission`` exception.
+* If the endpoint returns something other than a 403 ``Forbidden`` to indicate
+  that the role is not allowed, the test will raise an ``RbacActionFailed`` exception.
+
+.. note::
+
+    Certain services like Neutron *intentionally* raise a 404 instead of a 403
+    for security concerns. Patrole accomodates this behavior by anticipating
+    a 404 instead of a 403, using the ``expected_exception`` argument. For more
+    information about Neutron's policy enforcement, see:
+    `<https://docs.openstack.org/developer/neutron/devref/policy.html#request-authorization>`__.
+
+How It Works
+============
+Patrole leverages oslo_policy (OpenStack's policy enforcement engine) to
+determine whether a given role is allowed to perform a policy action given a
+specific rule and OpenStack service. This is done before test execution inside
+the ``rbac_rule_validation.action`` decorator. Then, inside the test, the API
+that does policy enforcement for the same rule is called. The outcome is
+compared against the result from oslo_policy and a pass or fail is determined
+as outlined above: `Test Flows`_.
+
+.. note::
+
+    Currently, Patrole does not support checking multiple rules against a single
+    API call. Even though some APIs enforce multiple rules (some indirectly),
+    it is increasingly difficult to maintain the tests if multiple policy
+    actions are expected to be called.
+
+Test Execution Workflow
+-----------------------
+The workflow is as follows:
+
+#. Each test uses the ``rbac_rule_validation.action`` decorator, like below: ::
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:stop")
+    @decorators.idempotent_id('ab4a17d2-166f-4a6d-9944-f17baa576cf2')
+    def test_stop_server(self):
+        # Set the primary credential's role to "rbac_test_role".
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        # Call the API that enforces the policy action specified by "rule".
+        self._test_stop_server()
+
+   The ``service`` attribute accepts an OpenStack service and the ``rule`` attribute
+   accepts a valid OpenStack policy action, like "os_compute_api:servers:stop".
+
+#. The ``rbac_rule_validation.action`` decorator passes these attributes,
+   along with user_id and project_id information derived from the primary
+   Tempest credential (``self.os.credentials.user_id`` and ``self.os.credentials.project_id``),
+   to the ``rbac_policy_parser``.
+
+#. The logic in ``rbac_policy_parser`` then passes all this information along
+   and the role in ``CONF.rbac.rbac_test_role`` to oslo_policy to determine whether
+   the ``rbac_test_role`` is authorized to perform the policy action for the given
+   service.
+
+#. After all of the logic above has executed inside the rbac decorator, the
+   test is executed. The test then sets up test-level resources, if necessary,
+   with **admin** credentials implicitly. This is accomplished through
+   ``rbac_utils.switch_role(toggle_rbac_role=False)``, which is done as part of
+   client setup (inside the call to ``rbac_utils.RbacUtils``): ::
+
+    @classmethod
+    def setup_clients(cls):
+        super(BaseV2ComputeRbacTest, cls).setup_clients()
+        cls.auth_provider = cls.os_primary.auth_provider
+        cls.rbac_utils = rbac_utils.RbacUtils(cls)
+        ...
+
+   This code has *already* executed when the test class is instantiated, because
+   it is located in the base rbac test class. Whenever ``cls.rbac_utils.switch_role``
+   is called, one of two behaviors are possible:
+
+    #. The primary credential's role is changed to admin if ``toggle_rbac_role=False``
+    #. The primary credential's role is changed to ``rbac_test_role`` if
+       ``toggle_rbac_role=True``
+
+   Thus, at the *beginning* of every test and during ``resource_setup`` and
+   ``resource_cleanup``, the primary credential has the admin role.
+
+#. After preliminary test-level setup is performed, like creating a server, a
+   second call to ``self.rbac_utils.switch_role`` is done: ::
+
+    self.rbac_utils.switch_role(cls, toggle_rbac_role=True)
+
+   Now the primary credential has the role specified by ``rbac_test_role``.
+
+#. The API endpoint in which policy enforcement of "os_compute_api:servers:stop"
+   is performed can now be called.
+
+   .. note:
+
+        To determine whether a policy action is enforced, refer to the relevant
+        controller code to make sure that the policy action is indeed enforced.
+
+#. Now that a call is made to "stop_server" with the primary credentials having
+   the role specified by ``rbac_test_role``, either the nova contoller will allow
+   or disallow the action to be performed. Since the "stop_server" policy action in
+   nova is defined as "base.RULE_ADMIN_OR_OWNER", the API will most likely
+   return a successful status code. For more information about this policy action,
+   see `<https://github.com/openstack/nova/blob/master/nova/policies/servers.py>`__.
+
+#. As mentioned above, the result from the API call and the result from oslo_policy
+   are compared for consistency.
+
+#. Finally, after the test has executed, but before ``tearDown`` or ``resource_cleanup``
+   is called, ``self.rbac_utils.switch_role(cls, toggle_rbac_role=False)`` is
+   called, so that the primary credential yet again has admin permissions for
+   test clean up. This call is always performed in the "finally" block inside
+   the ``rbac_rule_validation`` decorator.
+
+.. warning::
+
+    Failure to call ``self.rbac_utils.switch_role(cls, toggle_rbac_role=True)``
+    inside a test with the ``rbac_rule_validation`` decorator applied results
+    in a ``RbacResourceSetupFailed`` being raised, causing the test to fail.
diff --git a/contrib/post_test_hook.sh b/contrib/post_test_hook.sh
deleted file mode 100644
index 3961474..0000000
--- a/contrib/post_test_hook.sh
+++ /dev/null
@@ -1,64 +0,0 @@
-#!/bin/bash -xe
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-# This script is executed inside post_test_hook function in devstack gate.
-# First argument ($1) expects 'rbac-role' as value for setting appropriate
-# tempest rbac option 'rbac_test_role'.
-
-# Install pip manually.
-PATROLE_DIR=$BASE/new/patrole
-sudo pip install -e $PATROLE_DIR
-
-# Allow tempest.conf to be modified by Jenkins.
-sudo chown -R jenkins:stack $BASE/new/tempest
-sudo chown -R jenkins:stack $BASE/data/tempest
-
-TEMPEST_CONFIG=$BASE/new/tempest/etc/tempest.conf
-TEMPEST_COMMAND="sudo -H -u tempest tox"
-# TODO(felipemonteiro): This regex does a negative lookahead to exclude slow
-# tests that contain the @test.attr(type='slow') decorator above them. Slower
-# tests will execute those tests in a separate gate, which will require
-# future modification of this script.
-DEVSTACK_GATE_TEMPEST_REGEX="(?!.*\[.*\bslow\b.*\])(^patrole_tempest_plugin\.tests\.api)"
-
-# Import devstack function 'iniset'.
-source $BASE/new/devstack/functions
-
-# First argument is expected to contain value equal either to 'admin' or
-# 'member' (both lower-case).
-RBAC_ROLE=$1
-
-if [[ "$RBAC_ROLE" == "member" ]]; then
-    RBAC_ROLE="Member"
-fi
-
-# Set rbac_flag=True under [rbac] section in tempest.conf
-iniset $TEMPEST_CONFIG rbac rbac_flag True
-# Set rbac_test_role=$RBAC_ROLE under [rbac] section in tempest.conf
-iniset $TEMPEST_CONFIG rbac rbac_test_role $RBAC_ROLE
-# Set additional, necessary CONF values
-iniset $TEMPEST_CONFIG auth use_dynamic_credentials True
-iniset $TEMPEST_CONFIG auth tempest_roles Member
-
-# Give permissions back to Tempest.
-sudo chown -R tempest:stack $BASE/new/tempest
-sudo chown -R tempest:stack $BASE/data/tempest
-
-set -o errexit
-
-# cd into Tempest directory before executing tox.
-cd $BASE/new/tempest
-
-$TEMPEST_COMMAND -eall-plugin -- $DEVSTACK_GATE_TEMPEST_REGEX --concurrency=$TEMPEST_CONCURRENCY
-sudo -H -u tempest .tox/all-plugin/bin/tempest list-plugins
diff --git a/contrib/pre_test_hook.sh b/contrib/pre_test_hook.sh
deleted file mode 100755
index ffa4c20..0000000
--- a/contrib/pre_test_hook.sh
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/bin/bash -xe
-#
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
-# not use this file except in compliance with the License. You may obtain
-# a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-# This script is executed inside pre_test_hook function in devstack gate.
-# Installs patrole tempest plugin manually.
-
-PATROLE_DIR=$BASE/new/patrole
-sudo pip install -e $PATROLE_DIR
diff --git a/devstack/plugin.sh b/devstack/plugin.sh
new file mode 100644
index 0000000..1066136
--- /dev/null
+++ b/devstack/plugin.sh
@@ -0,0 +1,35 @@
+#!/usr/bin/env bash
+# Plugin file for Patrole Tempest plugin
+# --------------------------------------
+
+# Dependencies:
+# ``functions`` file
+# ``DEST`` must be defined
+
+# Save trace setting
+XTRACE=$(set +o | grep xtrace)
+set -o xtrace
+
+function install_patrole_tempest_plugin() {
+    if is_service_enabled tempest; then
+        setup_package $PATROLE_DIR -e
+
+        if [[ "$RBAC_TEST_ROLE" == "member" ]]; then
+            RBAC_TEST_ROLE="Member"
+        fi
+
+        iniset $TEMPEST_CONFIG rbac enable_rbac True
+        iniset $TEMPEST_CONFIG rbac rbac_test_role $RBAC_TEST_ROLE
+        iniset $TEMPEST_CONFIG rbac strict_policy_check False
+    fi
+}
+
+if is_service_enabled tempest; then
+    if [[ "$1" == "stack" && "$2" == "test-config" ]]; then
+        echo_summary "Installing Patrole Tempest plugin"
+        install_patrole_tempest_plugin
+    fi
+fi
+
+# Restore xtrace
+$XTRACE
diff --git a/devstack/settings b/devstack/settings
new file mode 100644
index 0000000..670e878
--- /dev/null
+++ b/devstack/settings
@@ -0,0 +1,8 @@
+# Settings needed for the Patrole Tempest plugin
+# ----------------------------------------------
+
+PATROLE_DIR=$DEST/patrole
+TEMPEST_DIR=$DEST/tempest
+TEMPEST_CONFIG_DIR=${TEMPEST_CONFIG_DIR:-$TEMPEST_DIR/etc}
+TEMPEST_CONFIG=$TEMPEST_CONFIG_DIR/tempest.conf
+RBAC_TEST_ROLE=${RBAC_TEST_ROLE:-admin}
diff --git a/doc/source/conf.py b/doc/source/conf.py
index 33c2cc3..ddb1d45 100755
--- a/doc/source/conf.py
+++ b/doc/source/conf.py
@@ -23,7 +23,7 @@
 extensions = [
     'sphinx.ext.autodoc',
     #'sphinx.ext.intersphinx',
-    'oslosphinx'
+    'openstackdocstheme'
 ]
 
 # autodoc generation is a bit aggressive and a nuisance when doing heavy
@@ -55,8 +55,16 @@
 # The theme to use for HTML and HTML Help pages.  Major themes that come with
 # Sphinx are currently 'default' and 'sphinxdoc'.
 # html_theme_path = ["."]
-# html_theme = '_theme'
 # html_static_path = ['static']
+html_theme = 'openstackdocs'
+
+# openstackdocstheme options
+repository_name = 'openstack/patrole'
+bug_project = 'patrole'
+bug_tag = ''
+
+# Must set this variable to include year, month, day, hours, and minutes.
+html_last_updated_fmt = '%Y-%m-%d %H:%M'
 
 # Output file base name for HTML help builder.
 htmlhelp_basename = '%sdoc' % project
diff --git a/doc/source/index.rst b/doc/source/index.rst
index fbe592c..35e8439 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -3,7 +3,7 @@
    You can adapt this file completely to your liking, but it should at least
    contain the root `toctree` directive.
 
-Welcome to patrole's documentation!
+Patrole - an OpenStack Tempest Plugin for RBAC Testing
 ========================================================
 
 Contents:
@@ -22,4 +22,3 @@
 * :ref:`genindex`
 * :ref:`modindex`
 * :ref:`search`
-
diff --git a/doc/source/installation.rst b/doc/source/installation.rst
index 00cc57b..31f94f4 100644
--- a/doc/source/installation.rst
+++ b/doc/source/installation.rst
@@ -3,24 +3,36 @@
 ============
 
 Installation Information
-########################
+========================
 
 At the command line::
 
-    $ pip install patrole
+    $ git clone http://git.openstack.org/openstack/patrole
+    $ sudo pip install patrole
 
 Or, if you have virtualenvwrapper installed::
 
     $ mkvirtualenv patrole
-    $ pip install patrole
+    $ sudo pip install patrole
 
 Or to install from the source::
 
     $ navigate to patrole directory
-    $ pip install -e .
+    $ sudo pip install -e .
+
+DevStack Installation
+=====================
+
+Patrole can be installed like any other DevStack plugin by including the
+``install_plugin`` directive inside local.conf::
+
+    [[local|localrc]]
+    ...
+
+    enable_plugin patrole git://git.openstack.org/openstack/patrole
 
 Configuration Information
-#########################
+=========================
 
 tempest.conf
 ++++++++++++
@@ -28,29 +40,35 @@
 To run the RBAC tempest api test, you have to make the following changes to
 the tempest.conf file.
 
-#. [auth] section updates ::
+#. ``auth`` section updates ::
 
-       # Set tempest role to admin so all APIs are accessible
-       tempest_roles = admin
+    # Allows test cases to create/destroy projects and users. This option
+    # requires that OpenStack Identity API admin credentials are known. If
+    # false, isolated test cases and parallel execution, can still be
+    # achieved configuring a list of test accounts (boolean value)
+    use_dynamic_credentials = True
 
-       # Allows test cases to create/destroy tenants and users. This
-       # option enables isolated test cases and better parallel
-       # execution, but also requires that OpenStack Identity API
-       # admin credentials are known. (boolean value)
-       allow_tenant_isolation = True
+#. ``rbac`` section updates ::
 
-       # Allows test cases to create/destroy projects and users. This option
-       # requires that OpenStack Identity API admin credentials are known. If
-       # false, isolated test cases and parallel execution, can still be
-       # achieved configuring a list of test accounts (boolean value)
-       use_dynamic_credentials = False
+    # The role that you want the RBAC tests to use for RBAC testing
+    # This needs to be edited to run the test as a different role.
+    rbac_test_role = _member_
 
-#. [rbac] section updates ::
+    # Enables RBAC Tempest tests if set to True. Otherwise, they are
+    # skipped.
+    enable_rbac = True
 
-       # The role that you want the RBAC tests to use for RBAC testing
-       # This needs to be edited to run the test as a different role. 
-       rbac_test_role = _member_
+    # If set to true, tests throw a RbacParsingException for policies
+    # not found in the policy.json. Otherwise, they throw a
+    # skipException.
+    strict_policy_check = False
 
-       # Enables RBAC Tempest tests if set to True. Otherwise, they are
-       # skipped.
-       rbac_flag = True
+    # The following config options set the location of the service's
+    # policy file. For services that have their policy in code (e.g.,
+    # Nova), this would be the location of a custom policy.json, if
+    # one exists.
+    cinder_policy_file = /etc/cinder/policy.json
+    glance_policy_file = /etc/glance/policy.json
+    keystone_policy_file = /etc/keystone/policy.json
+    neutron_policy_file = /etc/neutron/policy.json
+    nova_policy_file = /etc/nova/policy.json
diff --git a/doc/source/usage.rst b/doc/source/usage.rst
index 5d6c0b9..d2570bc 100644
--- a/doc/source/usage.rst
+++ b/doc/source/usage.rst
@@ -1,10 +1,61 @@
+..
+
 ========
 Usage
 ========
 
-To use run patrole tests in Tempest::
+RBAC (API) Tests
+================
 
-    If patrole is installed correctly tests are run like any others.
+If Patrole is installed correctly, then the RBAC tests can be executed
+from inside the tempest root directory as follows::
 
-    To change the role that the patrole tests are being run as edit rbac_role
-    in the rbac section of tempest.conf.
+    $ tox -eall-plugin -- patrole_tempest_plugin.tests.api
+
+To execute patrole tests for a specific module, run::
+
+    $ tox -eall-plugin -- patrole_tempest_plugin.tests.api.compute
+
+.. note::
+
+    It is possible to run Patrole via ``tox -eall`` in order to run Patrole
+    isolated from other plugins. This can be accomplished by including the
+    installation of services that currently use policy in code -- for example,
+    Nova and Keystone. For example::
+
+        $ tox -evenv-tempest -- pip install /opt/stack/patrole /opt/stack/keystone /opt/stack/nova
+        $ tox -eall -- patrole_tempest_plugin.tests.api
+..
+
+To change the role that the patrole tests are being run as, edit
+``rbac_test_role`` in the ``rbac`` section of tempest.conf: ::
+
+    [rbac]
+    rbac_test_role = Member
+    ...
+
+.. note::
+
+    The ``rbac_test_role`` is service-specific. Member, for example,
+    is an arbitrary role, but by convention is used to designate the default
+    non-admin role in the system. Most patrole tests should be run with
+    **admin** and **Member** roles. However, some services, like Heat, take
+    advantage of a role called **heat_stack_user**, as it appears frequently
+    in Heat's policy.json.
+
+For more information about the Member role,
+please see: `<https://ask.openstack.org/en/question/4759/member-vs-_member_/>`__.
+
+Unit Tests
+==========
+
+Patrole includes unit tests for its RBAC framework. They can be run by
+executing::
+
+    $ tox -e py27
+
+or::
+
+    $ tox -e py35
+
+against the Python 3.5 interpreter.
diff --git a/patrole_tempest_plugin/README.rst b/patrole_tempest_plugin/README.rst
index b016b88..d678422 100644
--- a/patrole_tempest_plugin/README.rst
+++ b/patrole_tempest_plugin/README.rst
@@ -1,6 +1,5 @@
-===============================================
-Tempest Integration of patrole
-===============================================
+==============================
+Tempest Integration of Patrole
+==============================
 
-This directory contains Tempest tests to cover the patrole project.
-
+This directory contains Tempest tests to cover the Patrole project.
diff --git a/patrole_tempest_plugin/config.py b/patrole_tempest_plugin/config.py
index 1edf877..a6f30e7 100644
--- a/patrole_tempest_plugin/config.py
+++ b/patrole_tempest_plugin/config.py
@@ -21,9 +21,110 @@
 RbacGroup = [
     cfg.StrOpt('rbac_test_role',
                default='admin',
-               help="The current RBAC role against which to run"
-                    " Patrole tests."),
-    cfg.BoolOpt('rbac_flag',
+               help="""The current RBAC role against which to run Patrole
+tests."""),
+    cfg.BoolOpt('enable_rbac',
                 default=True,
-                help="Enables RBAC tests.")
+                help="Enables RBAC tests."),
+    cfg.BoolOpt('strict_policy_check',
+                default=False,
+                help="""If true, throws RbacParsingException for policies which
+don't exist or are not included in the service's policy file. If false, throws
+skipException."""),
+    # TODO(rb560u): There needs to be support for reading these JSON files from
+    # other hosts. It may be possible to leverage the v3 identity policy API.
+    cfg.ListOpt('custom_policy_files',
+                default=['/etc/%s/policy.json'],
+                help="""List of the paths to search for policy files. Each
+policy path assumes that the service name is included in the path once. Also
+assumes Patrole is on the same host as the policy files. The paths should be
+ordered by precedence, with high-priority paths before low-priority paths. The
+first path that is found to contain the service's policy file will be used.
+"""),
+    cfg.StrOpt('cinder_policy_file',
+               default='/etc/cinder/policy.json',
+               help="""Location of the Cinder policy file. Assumed to be on
+the same host as Patrole.""",
+               deprecated_for_removal=True,
+               deprecated_reason="It is better to use `custom_policy_files` "
+                                 "which supports any OpenStack service."),
+    cfg.StrOpt('glance_policy_file',
+               default='/etc/glance/policy.json',
+               help="""Location of the Glance policy file. Assumed to be on
+the same host as Patrole.""",
+               deprecated_for_removal=True,
+               deprecated_reason="It is better to use `custom_policy_files` "
+                                 "which supports any OpenStack service."),
+    cfg.StrOpt('keystone_policy_file',
+               default='/etc/keystone/policy.json',
+               help="""Location of the custom Keystone policy file. Assumed to
+be on the same host as Patrole.""",
+               deprecated_for_removal=True,
+               deprecated_reason="It is better to use `custom_policy_files` "
+                                 "which supports any OpenStack service."),
+    cfg.StrOpt('neutron_policy_file',
+               default='/etc/neutron/policy.json',
+               help="""Location of the Neutron policy file. Assumed to be on
+the same host as Patrole.""",
+               deprecated_for_removal=True,
+               deprecated_reason="It is better to use `custom_policy_files` "
+                                 "which supports any OpenStack service."),
+    cfg.StrOpt('nova_policy_file',
+               default='/etc/nova/policy.json',
+               help="""Location of the custom Nova policy file. Assumed to be
+on the same host as Patrole.""",
+               deprecated_for_removal=True,
+               deprecated_reason="It is better to use `custom_policy_files` "
+                                 "which supports any OpenStack service."),
+    cfg.BoolOpt('test_custom_requirements',
+                default=False,
+                help="""
+This option determines whether Patrole should run against a
+`custom_requirements_file` which defines RBAC requirements. The
+purpose of setting this flag to True is to verify that RBAC policy
+is in accordance to requirements. The idea is that the
+`custom_requirements_file` perfectly defines what the RBAC requirements are.
+
+Here are the possible outcomes when running the Patrole tests against
+a `custom_requirements_file`:
+
+YAML definition: allowed
+test run: allowed
+test result: pass
+
+YAML definition: allowed
+test run: not allowed
+test result: fail (under-permission)
+
+YAML definition: not allowed
+test run: allowed
+test result: fail (over-permission)
+"""),
+    cfg.StrOpt('custom_requirements_file',
+               help="""
+File path of the yaml file that defines your RBAC requirements. This
+file must be located on the same host that Patrole runs on. The yaml
+file should be written as follows:
+
+```
+<service>:
+  <api_action>:
+    - <allowed_role>
+    - <allowed_role>
+    - <allowed_role>
+  <api_action>:
+    - <allowed_role>
+    - <allowed_role>
+<service>
+  <api_action>:
+    - <allowed_role>
+```
+Where:
+service = the service that is being tested (cinder, nova, etc)
+api_action = the policy action that is being tested. Examples:
+             - volume:create
+             - os_compute_api:servers:start
+             - add_image
+allowed_role = the Keystone role that is allowed to perform the API
+""")
 ]
diff --git a/patrole_tempest_plugin/tests/api/image/v1/__init__.py b/patrole_tempest_plugin/hacking/__init__.py
similarity index 100%
rename from patrole_tempest_plugin/tests/api/image/v1/__init__.py
rename to patrole_tempest_plugin/hacking/__init__.py
diff --git a/patrole_tempest_plugin/hacking/checks.py b/patrole_tempest_plugin/hacking/checks.py
new file mode 100644
index 0000000..a3ef01f
--- /dev/null
+++ b/patrole_tempest_plugin/hacking/checks.py
@@ -0,0 +1,226 @@
+# Copyright 2013 IBM Corp.
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#   Licensed under the Apache License, Version 2.0 (the "License"); you may
+#   not use this file except in compliance with the License. You may obtain
+#   a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+#   Unless required by applicable law or agreed to in writing, software
+#   distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#   WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#   License for the specific language governing permissions and limitations
+#   under the License.
+
+import os
+import re
+
+import pep8
+
+
+PYTHON_CLIENTS = ['cinder', 'glance', 'keystone', 'nova', 'swift', 'neutron',
+                  'ironic', 'heat', 'sahara']
+
+PYTHON_CLIENT_RE = re.compile('import (%s)client' % '|'.join(PYTHON_CLIENTS))
+TEST_DEFINITION = re.compile(r'^\s*def test.*')
+SETUP_TEARDOWN_CLASS_DEFINITION = re.compile(r'^\s+def (setUp|tearDown)Class')
+SCENARIO_DECORATOR = re.compile(r'\s*@.*services\((.*)\)')
+VI_HEADER_RE = re.compile(r"^#\s+vim?:.+")
+RAND_NAME_HYPHEN_RE = re.compile(r".*rand_name\(.+[\-\_][\"\']\)")
+MUTABLE_DEFAULT_ARGS = re.compile(r"^\s*def .+\((.+=\{\}|.+=\[\])")
+TESTTOOLS_SKIP_DECORATOR = re.compile(r'\s*@testtools\.skip\((.*)\)')
+TEST_METHOD = re.compile(r"^    def test_.+")
+CLASS = re.compile(r"^class .+")
+RBAC_CLASS_NAME_RE = re.compile(r'class .+RbacTest')
+RULE_VALIDATION_DECORATOR = re.compile(
+    r'\s*@.*rbac_rule_validation.action\((.*)\)')
+IDEMPOTENT_ID_DECORATOR = re.compile(r'\s*@decorators\.idempotent_id\((.*)\)')
+
+previous_decorator = None
+
+
+def import_no_clients_in_api_tests(physical_line, filename):
+    """Check for client imports from patrole_tempest_plugin/tests/api
+
+    T102: Cannot import OpenStack python clients
+    """
+    if "patrole_tempest_plugin/tests/api" in filename:
+        res = PYTHON_CLIENT_RE.match(physical_line)
+        if res:
+            return (physical_line.find(res.group(1)),
+                    ("T102: python clients import not allowed "
+                     "in patrole_tempest_plugin/tests/api/* or "
+                     "patrole_tempest_plugin/tests/scenario/* tests"))
+
+
+def no_setup_teardown_class_for_tests(physical_line, filename):
+    """Check that tests do not use setUpClass/tearDownClass
+
+    T105: Tests cannot use setUpClass/tearDownClass
+    """
+    if pep8.noqa(physical_line):
+        return
+
+    if SETUP_TEARDOWN_CLASS_DEFINITION.match(physical_line):
+        return (physical_line.find('def'),
+                "T105: (setUp|tearDown)Class can not be used in tests")
+
+
+def no_vi_headers(physical_line, line_number, lines):
+    """Check for vi editor configuration in source files.
+
+    By default vi modelines can only appear in the first or
+    last 5 lines of a source file.
+
+    T106
+    """
+    # NOTE(gilliard): line_number is 1-indexed
+    if line_number <= 5 or line_number > len(lines) - 5:
+        if VI_HEADER_RE.match(physical_line):
+            return 0, "T106: Don't put vi configuration in source files"
+
+
+def service_tags_not_in_module_path(physical_line, filename):
+    """Check that a service tag isn't in the module path
+
+    A service tag should only be added if the service name isn't already in
+    the module path.
+
+    T107
+    """
+    matches = SCENARIO_DECORATOR.match(physical_line)
+    if matches:
+        services = matches.group(1).split(',')
+        for service in services:
+            service_name = service.strip().strip("'")
+            modulepath = os.path.split(filename)[0]
+            if service_name in modulepath:
+                return (physical_line.find(service_name),
+                        "T107: service tag should not be in path")
+
+
+def no_hyphen_at_end_of_rand_name(logical_line, filename):
+    """Check no hyphen at the end of rand_name() argument
+
+    T108
+    """
+    msg = "T108: hyphen should not be specified at the end of rand_name()"
+    if RAND_NAME_HYPHEN_RE.match(logical_line):
+        return 0, msg
+
+
+def no_mutable_default_args(logical_line):
+    """Check that mutable object isn't used as default argument
+
+    N322: Method's default argument shouldn't be mutable
+    """
+    msg = "N322: Method's default argument shouldn't be mutable!"
+    if MUTABLE_DEFAULT_ARGS.match(logical_line):
+        yield (0, msg)
+
+
+def no_testtools_skip_decorator(logical_line):
+    """Check that methods do not have the testtools.skip decorator
+
+    T109
+    """
+    if TESTTOOLS_SKIP_DECORATOR.match(logical_line):
+        yield (0, "T109: Cannot use testtools.skip decorator; instead use "
+               "decorators.skip_because from tempest.lib")
+
+
+def use_rand_uuid_instead_of_uuid4(logical_line, filename):
+    """Check that tests use data_utils.rand_uuid() instead of uuid.uuid4()
+
+    T113
+    """
+    if 'uuid.uuid4()' not in logical_line:
+        return
+
+    msg = ("T113: Tests should use data_utils.rand_uuid()/rand_uuid_hex() "
+           "instead of uuid.uuid4()/uuid.uuid4().hex")
+    yield (0, msg)
+
+
+def no_rbac_rule_validation_decorator(physical_line, filename,
+                                      previous_logical):
+    """Check that each test has the ``rbac_rule_validation.action`` decorator.
+
+    Checks whether the test function has "@rbac_rule_validation.action"
+    above it; otherwise checks that it has "@decorators.idempotent_id" above
+    it and "@rbac_rule_validation.action" above that.
+
+    Assumes that ``rbac_rule_validation.action`` decorator is either the first
+    or second decorator above the test function; otherwise this check fails.
+
+    P100
+    """
+    global previous_decorator
+
+    if "patrole_tempest_plugin/tests/api" in filename:
+
+        if IDEMPOTENT_ID_DECORATOR.match(physical_line):
+            previous_decorator = previous_logical
+            return
+
+        if TEST_METHOD.match(physical_line):
+            if not RULE_VALIDATION_DECORATOR.match(previous_logical) and \
+                not RULE_VALIDATION_DECORATOR.match(previous_decorator):
+                    return (0, "Must use rbac_rule_validation.action "
+                               "decorator for API and scenario tests")
+
+
+def no_rbac_suffix_in_test_filename(physical_line, filename, previous_logical):
+    """Check that RBAC filenames end with "_rbac" suffix.
+
+    P101
+    """
+    if "patrole_tempest_plugin/tests/api" in filename:
+
+        if filename.endswith('rbac_base.py'):
+            return
+
+        if not filename.endswith('_rbac.py'):
+            return 0, "RBAC test filenames must end in _rbac suffix"
+
+
+def no_rbac_test_suffix_in_test_class_name(physical_line, filename,
+                                           previous_logical):
+    """Check that RBAC class names end with "RbacTest"
+
+    P102
+    """
+    if "patrole_tempest_plugin/tests/api" in filename:
+
+        if filename.endswith('rbac_base.py'):
+            return
+
+        if CLASS.match(physical_line):
+            if not RBAC_CLASS_NAME_RE.match(physical_line):
+                return 0, "RBAC test class names must end in 'RbacTest'"
+
+
+def no_client_alias_in_test_cases(filename, logical_line):
+    """Check that test cases don't use "self.client" to define a client.
+
+    P103
+    """
+    if "patrole_tempest_plugin/tests/api" in filename:
+        if "self.client" in logical_line or "cls.client" in logical_line:
+            return 0, "Do not use 'self.client' as a service client alias"
+
+
+def factory(register):
+    register(import_no_clients_in_api_tests)
+    register(no_setup_teardown_class_for_tests)
+    register(no_vi_headers)
+    register(no_hyphen_at_end_of_rand_name)
+    register(no_mutable_default_args)
+    register(no_testtools_skip_decorator)
+    register(use_rand_uuid_instead_of_uuid4)
+    register(service_tags_not_in_module_path)
+    register(no_rbac_rule_validation_decorator)
+    register(no_rbac_suffix_in_test_filename)
+    register(no_rbac_test_suffix_in_test_class_name)
diff --git a/patrole_tempest_plugin/plugin.py b/patrole_tempest_plugin/plugin.py
index 3abf4aa..28ce12c 100644
--- a/patrole_tempest_plugin/plugin.py
+++ b/patrole_tempest_plugin/plugin.py
@@ -25,7 +25,7 @@
     def load_tests(self):
         base_path = os.path.split(os.path.dirname(
             os.path.abspath(__file__)))[0]
-        test_dir = "patrole_tempest_plugin/tests"
+        test_dir = "patrole_tempest_plugin/tests/api"
         full_test_dir = os.path.join(base_path, test_dir)
         return full_test_dir, base_path
 
@@ -36,4 +36,4 @@
             project_config.RbacGroup)
 
     def get_opt_lists(self):
-        return []
+        return [(project_config.rbac_group.name, project_config.RbacGroup)]
diff --git a/patrole_tempest_plugin/rbac_auth.py b/patrole_tempest_plugin/rbac_auth.py
deleted file mode 100644
index e4e35b1..0000000
--- a/patrole_tempest_plugin/rbac_auth.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from oslo_log import log as logging
-
-from patrole_tempest_plugin import rbac_policy_parser
-
-LOG = logging.getLogger(__name__)
-
-
-class RbacAuthority(object):
-    def __init__(self, tenant_id, user_id, service=None):
-        self.converter = rbac_policy_parser.RbacPolicyParser(
-            tenant_id, user_id, service)
-
-    def get_permission(self, rule_name, role):
-        try:
-            is_allowed = self.converter.allowed(rule_name, role)
-            if is_allowed:
-                LOG.debug("[API]: %s, [Role]: %s is allowed!", rule_name, role)
-            else:
-                LOG.debug("[API]: %s, [Role]: %s is NOT allowed!",
-                          rule_name, role)
-            return is_allowed
-        except KeyError:
-            LOG.debug("[API]: %s, [Role]: %s is NOT allowed!",
-                      rule_name, role)
-            return False
-        return False
diff --git a/patrole_tempest_plugin/rbac_exceptions.py b/patrole_tempest_plugin/rbac_exceptions.py
index c6165ff..aa3135e 100644
--- a/patrole_tempest_plugin/rbac_exceptions.py
+++ b/patrole_tempest_plugin/rbac_exceptions.py
@@ -26,3 +26,15 @@
 
 class RbacOverPermission (exceptions.TempestException):
     message = "Action performed that should not be permitted"
+
+
+class RbacInvalidService (exceptions.TempestException):
+    message = "Attempted to test an invalid service"
+
+
+class RbacParsingException (exceptions.TempestException):
+    message = "Attempted to test an invalid policy file or action"
+
+
+class RbacInvalidErrorCode (exceptions.TempestException):
+    message = "Unsupported error code passed in test"
diff --git a/patrole_tempest_plugin/rbac_policy_parser.py b/patrole_tempest_plugin/rbac_policy_parser.py
index 045a9f8..41871cf 100644
--- a/patrole_tempest_plugin/rbac_policy_parser.py
+++ b/patrole_tempest_plugin/rbac_policy_parser.py
@@ -14,18 +14,24 @@
 #    under the License.
 
 import copy
+import json
 import os
 
+from oslo_config import cfg
 from oslo_log import log as logging
-from oslo_policy import generator
 from oslo_policy import policy
+import stevedore
+
+from tempest.common import credentials_factory as credentials
 
 from patrole_tempest_plugin import rbac_exceptions
+from patrole_tempest_plugin.rbac_utils import RbacAuthority
 
+CONF = cfg.CONF
 LOG = logging.getLogger(__name__)
 
 
-class RbacPolicyParser(object):
+class RbacPolicyParser(RbacAuthority):
     """A class for parsing policy rules into lists of allowed roles.
 
     RBAC testing requires that each rule in a policy file be broken up into
@@ -35,7 +41,7 @@
     each role, whether a given rule is allowed using oslo policy.
     """
 
-    def __init__(self, tenant_id, user_id, service=None, path=None):
+    def __init__(self, project_id, user_id, service, extra_target_data=None):
         """Initialization of Rbac Policy Parser.
 
         Parses a policy file to create a dictionary, mapping policy actions to
@@ -52,39 +58,63 @@
         the custom policy file over the default policy implementation is
         prioritized.
 
-        :param tenant_id: type uuid
-        :param user_id: type uuid
-        :param service: type string
-        :param path: type string
+        :param uuid project_id: project_id of object performing API call
+        :param uuid user_id: user_id of object performing API call
+        :param string service: service of the policy file
+        :param dict extra_target_data: dictionary containing additional object
+            data needed by oslo.policy to validate generic checks
         """
-        service = service.lower().strip()
-        if path is None:
-            self.path = os.path.join('/etc', service, 'policy.json')
+
+        if extra_target_data is None:
+            extra_target_data = {}
+
+        self.validate_service(service)
+
+        # Prioritize dynamically searching for policy files over relying on
+        # deprecated service-specific policy file locations.
+        if CONF.rbac.custom_policy_files:
+            self.discover_policy_files()
+            self.path = self.policy_files.get(service)
         else:
-            self.path = path
+            self.path = getattr(CONF.rbac, '%s_policy_file' % str(service),
+                                None)
 
-        policy_data = "{}"
-
-        # First check whether policy file exists.
-        if os.path.isfile(self.path):
-            policy_data = open(self.path, 'r').read()
-        # Otherwise use oslo_policy to fetch the rules for provided service.
-        else:
-            policy_generator = generator._get_policies_dict([service])
-            if policy_generator and service in policy_generator:
-                policy_data = "{\n"
-                for r in policy_generator[service]:
-                    policy_data = policy_data + r.__str__() + ",\n"
-                policy_data = policy_data[:-2] + "\n}"
-            # Otherwise raise an exception.
-            else:
-                raise rbac_exceptions.RbacResourceSetupFailed(
-                    'Policy file for service: {0}, {1} not found.'
-                    .format(service, self.path))
-
-        self.rules = policy.Rules.load(policy_data, "default")
-        self.tenant_id = tenant_id
+        self.rules = policy.Rules.load(self._get_policy_data(service),
+                                       'default')
+        self.project_id = project_id
         self.user_id = user_id
+        self.extra_target_data = extra_target_data
+
+    @classmethod
+    def validate_service(cls, service):
+        """Validate whether the service passed to ``__init__`` exists."""
+        service = service.lower().strip() if service else None
+
+        # Cache the list of available services in memory to avoid needlessly
+        # doing an API call every time.
+        if not hasattr(cls, 'available_services'):
+            admin_mgr = credentials.AdminManager()
+            services = admin_mgr.identity_services_v3_client.\
+                list_services()['services']
+            cls.available_services = [s['name'] for s in services]
+
+        if not service or service not in cls.available_services:
+            LOG.debug("%s is NOT a valid service.", service)
+            raise rbac_exceptions.RbacInvalidService(
+                "%s is NOT a valid service." % service)
+
+    @classmethod
+    def discover_policy_files(cls):
+        # Dynamically discover the policy file for each service in
+        # ``cls.available_services``. Pick the first ``candidate_path`` found
+        # out of the potential paths in ``CONF.rbac.custom_policy_files``.
+        if not hasattr(cls, 'policy_files'):
+            cls.policy_files = {}
+            for service in cls.available_services:
+                for candidate_path in CONF.rbac.custom_policy_files:
+                    if os.path.isfile(candidate_path % service):
+                        cls.policy_files.setdefault(service,
+                                                    candidate_path % service)
 
     def allowed(self, rule_name, role):
         is_admin_context = self._is_admin_context(role)
@@ -92,9 +122,72 @@
             access=self._get_access_token(role),
             apply_rule=rule_name,
             is_admin=is_admin_context)
-
         return is_allowed
 
+    def _get_policy_data(self, service):
+        file_policy_data = {}
+        mgr_policy_data = {}
+        policy_data = {}
+
+        # Check whether policy file exists and attempt to read it.
+        if self.path and os.path.isfile(self.path):
+            try:
+                with open(self.path, 'r') as policy_file:
+                    file_policy_data = policy_file.read()
+                file_policy_data = json.loads(file_policy_data)
+            except (IOError, ValueError) as e:
+                msg = "Failed to read policy file for service. "
+                if isinstance(e, IOError):
+                    msg += "Please check that policy path exists."
+                else:
+                    msg += "JSON may be improperly formatted."
+                LOG.debug(msg)
+                file_policy_data = {}
+
+        # Check whether policy actions are defined in code. Nova and Keystone,
+        # for example, define their default policy actions in code.
+        mgr = stevedore.named.NamedExtensionManager(
+            'oslo.policy.policies',
+            names=[service],
+            on_load_failure_callback=None,
+            invoke_on_load=True,
+            warn_on_missing_entrypoint=False)
+
+        if mgr:
+            policy_generator = {policy.name: policy.obj for policy in mgr}
+            if policy_generator and service in policy_generator:
+                for rule in policy_generator[service]:
+                    mgr_policy_data[rule.name] = str(rule.check)
+
+        # If data from both file and code exist, combine both together.
+        if file_policy_data and mgr_policy_data:
+            # Add the policy actions from code first.
+            for action, rule in mgr_policy_data.items():
+                policy_data[action] = rule
+            # Overwrite with any custom policy actions defined in policy.json.
+            for action, rule in file_policy_data.items():
+                policy_data[action] = rule
+        elif file_policy_data:
+            policy_data = file_policy_data
+        elif mgr_policy_data:
+            policy_data = mgr_policy_data
+        else:
+            error_message = (
+                'Policy file for {0} service neither found in code nor at {1}.'
+                .format(service, [loc % service for loc in
+                                  CONF.rbac.custom_policy_files])
+            )
+            raise rbac_exceptions.RbacParsingException(error_message)
+
+        try:
+            policy_data = json.dumps(policy_data)
+        except ValueError:
+            error_message = 'Policy file for {0} service is invalid.'.format(
+                service)
+            raise rbac_exceptions.RbacParsingException(error_message)
+
+        return policy_data
+
     def _is_admin_context(self, role):
         """Checks whether a role has admin context.
 
@@ -106,7 +199,7 @@
             return self._allowed(
                 access=self._get_access_token(role),
                 apply_rule='context_is_admin')
-        return role == 'admin'
+        return role == CONF.identity.admin_role
 
     def _get_access_token(self, role):
         access_token = {
@@ -116,8 +209,8 @@
                         "name": role
                     }
                 ],
-                "project_id": self.tenant_id,
-                "tenant_id": self.tenant_id,
+                "project_id": self.project_id,
+                "tenant_id": self.project_id,
                 "user_id": self.user_id
             }
         }
@@ -151,17 +244,18 @@
                   "tenant_id": access_data['project_id'],
                   "network:tenant_id": access_data['project_id'],
                   "user_id": access_data['user_id']}
+        if self.extra_target_data:
+            target.update(self.extra_target_data)
 
         result = self._try_rule(apply_rule, target, access_data, o)
         return result
 
     def _try_rule(self, apply_rule, target, access_data, o):
-        try:
+        if apply_rule not in self.rules:
+            message = "Policy action: {0} not found in policy file: {1}."\
+                      .format(apply_rule, self.path)
+            LOG.debug(message)
+            raise rbac_exceptions.RbacParsingException(message)
+        else:
             rule = self.rules[apply_rule]
             return rule(target, access_data, o)
-        except KeyError as e:
-            LOG.debug("{0} not found in policy file.".format(apply_rule))
-            return False
-        except Exception as e:
-            LOG.debug("Exception: {0} for rule: {1}.".format(e, apply_rule))
-            return False
diff --git a/patrole_tempest_plugin/rbac_rule_validation.py b/patrole_tempest_plugin/rbac_rule_validation.py
index 36784b7..c088ce7 100644
--- a/patrole_tempest_plugin/rbac_rule_validation.py
+++ b/patrole_tempest_plugin/rbac_rule_validation.py
@@ -14,55 +14,240 @@
 #    under the License.
 
 import logging
+import sys
+import testtools
+
+import six
 
 from tempest import config
 from tempest.lib import exceptions
+from tempest import test
 
-from patrole_tempest_plugin import rbac_auth
 from patrole_tempest_plugin import rbac_exceptions
+from patrole_tempest_plugin import rbac_policy_parser
+from patrole_tempest_plugin import requirements_authority
 
 CONF = config.CONF
 LOG = logging.getLogger(__name__)
 
+_SUPPORTED_ERROR_CODES = [403, 404]
 
-def action(service, rule):
+
+def action(service, rule='', admin_only=False, expected_error_code=403,
+           extra_target_data=None):
+    """A decorator which does a policy check and matches it against test run.
+
+    A decorator which allows for positive and negative RBAC testing. Given
+    an OpenStack service and a policy action enforced by that service, an
+    oslo.policy lookup is performed by calling `authority.get_permission`.
+    Alternatively, the RBAC tests can run against a YAML file that defines
+    policy requirements.
+
+    The following cases are possible:
+
+    * If `allowed` is True and the test passes, this is a success.
+    * If `allowed` is True and the test fails, this is a failure.
+    * If `allowed` is False and the test passes, this is a failure.
+    * If `allowed` is False and the test fails, this is a success.
+
+    :param service: A OpenStack service: for example, "nova" or "neutron".
+    :param rule: A policy action defined in a policy.json file (or in code).
+    :param admin_only: Skips over oslo.policy check because the policy action
+        defined by `rule` is not enforced by the service's  policy enforcement
+        logic. For example, Keystone v2 performs an admin check for most of its
+        endpoints. If True, `rule` is effectively ignored.
+    :param expected_error_code: Overrides default value of 403 (Forbidden)
+        with endpoint-specific error code. Currently only supports 403 and 404.
+        Support for 404 is needed because some services, like Neutron,
+        intentionally throw a 404 for security reasons.
+
+    :raises NotFound: if `service` is invalid or
+                      if Tempest credentials cannot be found.
+    :raises Forbidden: for bullet (2) above.
+    :raises RbacOverPermission: for bullet (3) above.
+    """
+
+    if extra_target_data is None:
+        extra_target_data = {}
+
     def decorator(func):
+        role = CONF.rbac.rbac_test_role
+
         def wrapper(*args, **kwargs):
-            try:
-                tenant_id = args[0].auth_provider.credentials.tenant_id
-                user_id = args[0].auth_provider.credentials.user_id
-            except (IndexError, AttributeError) as e:
-                msg = ("{0}: tenant_id/user_id not found in "
-                       "cls.auth_provider.credentials".format(e))
-                LOG.error(msg)
-                raise rbac_exceptions.RbacResourceSetupFailed(msg)
-            authority = rbac_auth.RbacAuthority(tenant_id, user_id, service)
-            allowed = authority.get_permission(rule, CONF.rbac.rbac_test_role)
+            if args and isinstance(args[0], test.BaseTestCase):
+                test_obj = args[0]
+            else:
+                raise rbac_exceptions.RbacResourceSetupFailed(
+                    '`rbac_rule_validation` decorator can only be applied to '
+                    'an instance of `tempest.test.BaseTestCase`.')
+
+            if admin_only:
+                LOG.info("As admin_only is True, only admin role should be "
+                         "allowed to perform the API. Skipping oslo.policy "
+                         "check for policy action {0}.".format(rule))
+                allowed = test_obj.rbac_utils.is_admin
+            else:
+                allowed = _is_authorized(test_obj, service, rule,
+                                         extra_target_data)
+
+            expected_exception, irregular_msg = _get_exception_type(
+                expected_error_code)
 
             try:
-                func(*args)
-            except exceptions.Forbidden as e:
+                func(*args, **kwargs)
+            except rbac_exceptions.RbacInvalidService as e:
+                msg = ("%s is not a valid service." % service)
+                LOG.error(msg)
+                raise exceptions.NotFound(
+                    "%s RbacInvalidService was: %s" % (msg, e))
+            except (expected_exception, rbac_exceptions.RbacActionFailed) as e:
+                if irregular_msg:
+                    LOG.warning(irregular_msg.format(rule, service))
                 if allowed:
                     msg = ("Role %s was not allowed to perform %s." %
-                           (CONF.rbac.rbac_test_role, rule))
+                           (role, rule))
                     LOG.error(msg)
                     raise exceptions.Forbidden(
-                        "%s exception was: %s" %
-                        (msg, e))
-            except rbac_exceptions.RbacActionFailed as e:
-                if allowed:
-                    msg = ("Role %s was not allowed to perform %s." %
-                           (CONF.rbac.rbac_test_role, rule))
-                    LOG.error(msg)
-                    raise exceptions.Forbidden(
-                        "%s RbacActionFailed was: %s" %
-                        (msg, e))
+                        "%s Exception was: %s" % (msg, e))
+            except Exception as e:
+                exc_info = sys.exc_info()
+                error_details = exc_info[1].__str__()
+                msg = ("%s An unexpected exception has occurred: Expected "
+                       "exception was %s, which was not thrown."
+                       % (error_details, expected_exception.__name__))
+                LOG.error(msg)
+                six.reraise(exc_info[0], exc_info[0](msg), exc_info[2])
             else:
                 if not allowed:
-                    LOG.error("Role %s was allowed to perform %s" %
-                              (CONF.rbac.rbac_test_role, rule))
+                    LOG.error("Role %s was allowed to perform %s",
+                              role, rule)
                     raise rbac_exceptions.RbacOverPermission(
                         "OverPermission: Role %s was allowed to perform %s" %
-                        (CONF.rbac.rbac_test_role, rule))
-        return wrapper
+                        (role, rule))
+            finally:
+                test_obj.rbac_utils.switch_role(test_obj,
+                                                toggle_rbac_role=False)
+
+        _wrapper = testtools.testcase.attr(role)(wrapper)
+        return _wrapper
     return decorator
+
+
+def _is_authorized(test_obj, service, rule_name, extra_target_data):
+    """Validates whether current RBAC role has permission to do policy action.
+
+    :param test_obj: type BaseTestCase (tempest base test class)
+    :param service: the OpenStack service that enforces ``rule_name``
+    :param rule_name: the name of the policy action
+    :param extra_target_data: dictionary with unresolved string literals that
+        reference nested BaseTestCase attributes
+    :returns: True if the current RBAC role can perform the policy action else
+        False
+    :raises RbacParsingException: if ``CONF.rbac.strict_policy_check`` is
+        enabled and the ``rule_name`` does not exist in the system
+    :raises skipException: if ``CONF.rbac.strict_policy_check`` is
+        disabled and the ``rule_name`` does not exist in the system
+    """
+    try:
+        project_id = test_obj.auth_provider.credentials.project_id
+        user_id = test_obj.auth_provider.credentials.user_id
+    except AttributeError as e:
+        msg = ("{0}: project_id/user_id not found in "
+               "cls.auth_provider.credentials".format(e))
+        LOG.error(msg)
+        raise rbac_exceptions.RbacResourceSetupFailed(msg)
+
+    try:
+        role = CONF.rbac.rbac_test_role
+        # Test RBAC against custom requirements. Otherwise use oslo.policy
+        if CONF.rbac.test_custom_requirements:
+            authority = requirements_authority.RequirementsAuthority(
+                CONF.rbac.custom_requirements_file, service)
+        else:
+            formatted_target_data = _format_extra_target_data(
+                test_obj, extra_target_data)
+            authority = rbac_policy_parser.RbacPolicyParser(
+                project_id, user_id, service,
+                extra_target_data=formatted_target_data)
+        is_allowed = authority.allowed(rule_name, role)
+
+        if is_allowed:
+            LOG.debug("[Action]: %s, [Role]: %s is allowed!", rule_name,
+                      role)
+        else:
+            LOG.debug("[Action]: %s, [Role]: %s is NOT allowed!",
+                      rule_name, role)
+        return is_allowed
+    except rbac_exceptions.RbacParsingException as e:
+        if CONF.rbac.strict_policy_check:
+            raise e
+        else:
+            raise testtools.TestCase.skipException(str(e))
+    return False
+
+
+def _get_exception_type(expected_error_code=403):
+    """Dynamically calculate the expected exception to be caught.
+
+    Dynamically calculate the expected exception to be caught by the test case.
+    Only `Forbidden` and `NotFound` exceptions are permitted. `NotFound` is
+    supported because Neutron, for security reasons, masks `Forbidden`
+    exceptions as `NotFound` exceptions.
+
+    :param expected_error_code: the integer representation of the expected
+        exception to be caught. Must be contained in `_SUPPORTED_ERROR_CODES`.
+    :returns: tuple of the exception type corresponding to
+        `expected_error_code` and a message explaining that a non-Forbidden
+        exception was expected, if applicable.
+    """
+    expected_exception = None
+    irregular_msg = None
+
+    if not isinstance(expected_error_code, six.integer_types) \
+        or expected_error_code not in _SUPPORTED_ERROR_CODES:
+        msg = ("Please pass an expected error code. Currently "
+               "supported codes: {0}".format(_SUPPORTED_ERROR_CODES))
+        LOG.error(msg)
+        raise rbac_exceptions.RbacInvalidErrorCode(msg)
+
+    if expected_error_code == 403:
+        expected_exception = exceptions.Forbidden
+    elif expected_error_code == 404:
+        expected_exception = exceptions.NotFound
+        irregular_msg = ("NotFound exception was caught for policy action "
+                         "{0}. The service {1} throws a 404 instead of a 403, "
+                         "which is irregular.")
+
+    return expected_exception, irregular_msg
+
+
+def _format_extra_target_data(test_obj, extra_target_data):
+    """Formats the "extra_target_data" dictionary with correct test data.
+
+    Before being formatted, "extra_target_data" is a dictionary that maps a
+    policy string like "trust.trustor_user_id" to a nested list of BaseTestCase
+    attributes. For example, the attribute list in:
+
+        "trust.trustor_user_id": "os.auth_provider.credentials.user_id"
+
+    is parsed by iteratively calling `getattr` until the value of "user_id"
+    is resolved. The resulting dictionary returns:
+
+        "trust.trustor_user_id": "the user_id of the `primary` credential"
+
+    :param test_obj: type BaseTestCase (tempest base test class)
+    :param extra_target_data: dictionary with unresolved string literals that
+        reference nested BaseTestCase attributes
+    :returns: dictionary containing additional object data needed by
+        oslo.policy to validate generic checks
+    """
+    attr_value = test_obj
+    formatted_target_data = {}
+
+    for user_attribute, attr_string in extra_target_data.items():
+        attrs = attr_string.split('.')
+        for attr in attrs:
+            attr_value = getattr(attr_value, attr)
+        formatted_target_data[user_attribute] = attr_value
+
+    return formatted_target_data
diff --git a/patrole_tempest_plugin/rbac_utils.py b/patrole_tempest_plugin/rbac_utils.py
index ae018de..00bfd24 100644
--- a/patrole_tempest_plugin/rbac_utils.py
+++ b/patrole_tempest_plugin/rbac_utils.py
@@ -13,14 +13,16 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import abc
 import six
+import sys
 import time
 
-from tempest.common import credentials_factory
-from tempest import config
-from tempest.test import BaseTestCase
-
 from oslo_log import log as logging
+import oslo_utils.uuidutils as uuid_utils
+
+from tempest.common import credentials_factory as credentials
+from tempest import config
 
 from patrole_tempest_plugin import rbac_exceptions
 
@@ -28,77 +30,155 @@
 LOG = logging.getLogger(__name__)
 
 
-class Singleton(type):
-    _instances = {}
-
-    def __call__(cls, *args, **kwargs):
-        if cls not in cls._instances:
-            cls._instances[cls] = super(Singleton, cls).__call__(*args,
-                                                                 **kwargs)
-        return cls._instances[cls]
-
-
-@six.add_metaclass(Singleton)
 class RbacUtils(object):
 
-    def __init__(cls):
-        creds_provider = credentials_factory.get_credentials_provider(
-            name=__name__,
-            force_tenant_isolation=True,
-            identity_version=BaseTestCase.get_identity_version())
+    def __init__(self, test_obj):
+        self.switch_role(test_obj, toggle_rbac_role=False)
 
-        cls.creds_client = creds_provider.creds_client
-        cls.available_roles = cls.creds_client.roles_client.list_roles()
-        cls.admin_role_id = cls.rbac_role_id = None
-        for item in cls.available_roles['roles']:
-            if item['name'] == CONF.rbac.rbac_test_role:
-                cls.rbac_role_id = item['id']
-            if item['name'] == 'admin':
-                cls.admin_role_id = item['id']
+    # References the last value of `toggle_rbac_role` that was passed to
+    # `switch_role`. Used for ensuring that `switch_role` is correctly used
+    # in a test file, so that false positives are prevented. The key used
+    # to index into the dictionary is the module path plus class name, which is
+    # unique.
+    switch_role_history = {}
+    admin_role_id = None
+    rbac_role_id = None
 
-    def switch_role(cls, test_obj, switchToRbacRole=None):
-        LOG.debug('Switching role to: %s', switchToRbacRole)
-        # Check if admin and rbac roles exist.
-        if not cls.admin_role_id or not cls.rbac_role_id:
-            msg = ("Defined 'rbac_role' or 'admin' role does not exist"
-                   " in the system.")
+    def switch_role(self, test_obj, toggle_rbac_role=False):
+        self.user_id = test_obj.auth_provider.credentials.user_id
+        self.project_id = test_obj.auth_provider.credentials.tenant_id
+        self.token = test_obj.auth_provider.get_token()
+        self.identity_version = test_obj.get_identity_version()
+
+        if not credentials.is_admin_available(
+                identity_version=self.identity_version):
+            msg = "Missing Identity Admin API credentials in configuration."
             raise rbac_exceptions.RbacResourceSetupFailed(msg)
 
-        if not isinstance(switchToRbacRole, bool):
-            msg = ("Wrong value for parameter 'switchToRbacRole' is passed."
-                   " It should be either 'True' or 'False'.")
-            raise rbac_exceptions.RbacResourceSetupFailed(msg)
+        self.roles_client = test_obj.os_admin.roles_v3_client
+
+        LOG.debug('Switching role to: %s', toggle_rbac_role)
 
         try:
-            user_id = test_obj.auth_provider.credentials.user_id
-            project_id = test_obj.auth_provider.credentials.tenant_id
+            if not self.admin_role_id or not self.rbac_role_id:
+                self._get_roles()
 
-            cls._clear_user_roles(user_id, project_id)
+            self._validate_switch_role(test_obj, toggle_rbac_role)
 
-            if switchToRbacRole:
-                cls.creds_client.roles_client.create_user_role_on_project(
-                    project_id, user_id, cls.rbac_role_id)
+            if toggle_rbac_role:
+                self._add_role_to_user(self.rbac_role_id)
             else:
-                cls.creds_client.roles_client.create_user_role_on_project(
-                    project_id, user_id, cls.admin_role_id)
-
+                self._add_role_to_user(self.admin_role_id)
         except Exception as exp:
             LOG.error(exp)
             raise
-
         finally:
+            # NOTE(felipemonteiro): These two comments below are copied from
+            # tempest.api.identity.v2/v3.test_users.
+            #
+            # Reset auth again to verify the password restore does work.
+            # Clear auth restores the original credentials and deletes
+            # cached auth data.
             test_obj.auth_provider.clear_auth()
-            # Sleep to avoid 401 errors caused by rounding in timing of fernet
-            # token creation.
-            time.sleep(1)
+            # Fernet tokens are not subsecond aware and Keystone should only be
+            # precise to the second. Sleep to ensure we are passing the second
+            # boundary before attempting to authenticate. If token is of type
+            # uuid, then do not sleep.
+            if not uuid_utils.is_uuid_like(self.token):
+                time.sleep(1)
             test_obj.auth_provider.set_auth()
 
-    def _clear_user_roles(cls, user_id, tenant_id):
-        roles = cls.creds_client.roles_client.list_user_roles_on_project(
-            tenant_id, user_id)['roles']
+    def _add_role_to_user(self, role_id):
+        role_already_present = self._clear_user_roles(role_id)
+        if role_already_present:
+            return
+
+        self.roles_client.create_user_role_on_project(
+            self.project_id, self.user_id, role_id)
+
+    def _clear_user_roles(self, role_id):
+        roles = self.roles_client.list_user_roles_on_project(
+            self.project_id, self.user_id)['roles']
+
+        # If the user already has the role that is required, return early.
+        role_ids = [role['id'] for role in roles]
+        if role_ids == [role_id]:
+            return True
 
         for role in roles:
-            cls.creds_client.roles_client.delete_role_from_user_on_project(
-                tenant_id, user_id, role['id'])
+            self.roles_client.delete_role_from_user_on_project(
+                self.project_id, self.user_id, role['id'])
 
-rbac_utils = RbacUtils
+        return False
+
+    def _validate_switch_role(self, test_obj, toggle_rbac_role):
+        """Validates that the rbac role passed to `switch_role` is legal.
+
+        Throws an error for the following improper usages of `switch_role`:
+            * `switch_role` is not called with a boolean value
+            * `switch_role` is never called in a test file, except in tearDown
+            * `switch_role` is called with the same boolean value twice
+        """
+        if not isinstance(toggle_rbac_role, bool):
+            raise rbac_exceptions.RbacResourceSetupFailed(
+                'toggle_rbac_role must be a boolean value.')
+
+        # The unique key is the combination of module path plus class name.
+        class_name = test_obj.__name__ if isinstance(test_obj, type) else \
+            test_obj.__class__.__name__
+        module_name = test_obj.__module__
+        key = '%s.%s' % (module_name, class_name)
+
+        self.switch_role_history.setdefault(key, None)
+
+        if self.switch_role_history[key] == toggle_rbac_role:
+            # If an exception was thrown, like a skipException or otherwise,
+            # then this is a legitimate reason why `switch_role` was not
+            # called, so only raise an exception if no current exception is
+            # being handled.
+            if sys.exc_info()[0] is None:
+                self.switch_role_history[key] = False
+                error_message = '`toggle_rbac_role` must not be called with '\
+                    'the same bool value twice. Make sure that you included '\
+                    'a rbac_utils.switch_role method call inside the test.'
+                LOG.error(error_message)
+                raise rbac_exceptions.RbacResourceSetupFailed(error_message)
+        else:
+            self.switch_role_history[key] = toggle_rbac_role
+
+    def _get_roles(self):
+        available_roles = self.roles_client.list_roles()
+        admin_role_id = rbac_role_id = None
+
+        for role in available_roles['roles']:
+            if role['name'] == CONF.rbac.rbac_test_role:
+                rbac_role_id = role['id']
+            if role['name'] == CONF.identity.admin_role:
+                admin_role_id = role['id']
+
+        if not admin_role_id or not rbac_role_id:
+            msg = "Role with name 'admin' does not exist in the system."\
+                if not admin_role_id else "Role defined by rbac_test_role "\
+                "does not exist in the system."
+            raise rbac_exceptions.RbacResourceSetupFailed(msg)
+
+        self.admin_role_id = admin_role_id
+        self.rbac_role_id = rbac_role_id
+
+    @property
+    def is_admin(self):
+        """Verifies whether the current test role equals the admin role.
+
+        :returns: True if ``rbac_test_role`` is the admin role.
+        """
+        return CONF.rbac.rbac_test_role == CONF.identity.admin_role
+
+
+@six.add_metaclass(abc.ABCMeta)
+class RbacAuthority(object):
+    # TODO(rb560u): Add documentation explaining what this class is for
+
+    @abc.abstractmethod
+    def allowed(self, rule_name, role):
+        """Determine whether the role should be able to perform the API"""
+        return
diff --git a/patrole_tempest_plugin/requirements_authority.py b/patrole_tempest_plugin/requirements_authority.py
new file mode 100644
index 0000000..2db12db
--- /dev/null
+++ b/patrole_tempest_plugin/requirements_authority.py
@@ -0,0 +1,72 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+import yaml
+
+from oslo_log import log as logging
+
+from tempest.lib import exceptions
+
+from patrole_tempest_plugin.rbac_utils import RbacAuthority
+
+LOG = logging.getLogger(__name__)
+
+
+class RequirementsParser(object):
+    _inner = None
+
+    class Inner(object):
+        _rbac_map = None
+
+        def __init__(self, filepath):
+            with open(filepath) as f:
+                RequirementsParser.Inner._rbac_map = \
+                    list(yaml.safe_load_all(f))
+
+    def __init__(self, filepath):
+        if RequirementsParser._inner is None:
+            RequirementsParser._inner = RequirementsParser.Inner(filepath)
+
+    @staticmethod
+    def parse(component):
+        try:
+            for section in RequirementsParser.Inner._rbac_map:
+                if component in section:
+                    return section[component]
+        except yaml.parser.ParserError:
+            LOG.error("Error while parsing the requirements YAML file. Did "
+                      "you pass a valid component name from the test case?")
+        return None
+
+
+class RequirementsAuthority(RbacAuthority):
+    def __init__(self, filepath=None, component=None):
+        if filepath is not None and component is not None:
+            self.roles_dict = RequirementsParser(filepath).parse(component)
+        else:
+            self.roles_dict = None
+
+    def allowed(self, rule_name, role):
+        if self.roles_dict is None:
+            raise exceptions.InvalidConfiguration(
+                "Roles dictionary parsed from requirements YAML file is "
+                "empty. Ensure the requirements YAML file is correctly "
+                "formatted.")
+        try:
+            _api = self.roles_dict[rule_name]
+            return role in _api
+        except KeyError:
+            raise KeyError("'%s' API is not defined in the requirements YAML "
+                           "file" % rule_name)
+        return False
diff --git a/patrole_tempest_plugin/tests/api/compute/admin/__init__.py b/patrole_tempest_plugin/tests/api/compute/admin/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/patrole_tempest_plugin/tests/api/compute/admin/__init__.py
+++ /dev/null
diff --git a/patrole_tempest_plugin/tests/api/compute/admin/test_admin_password_rbac.py b/patrole_tempest_plugin/tests/api/compute/admin/test_admin_password_rbac.py
deleted file mode 100644
index c1c92d9..0000000
--- a/patrole_tempest_plugin/tests/api/compute/admin/test_admin_password_rbac.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-import testtools
-
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.compute import rbac_base
-
-
-CONF = config.CONF
-
-
-class PasswordAdminRbacTest(rbac_base.BaseV2ComputeAdminRbacTest):
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(PasswordAdminRbacTest, self).tearDown()
-
-    @classmethod
-    def setup_clients(cls):
-        super(PasswordAdminRbacTest, cls).setup_clients()
-        cls.client = cls.servers_client
-
-    @classmethod
-    def skip_checks(cls):
-        super(PasswordAdminRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
-
-    @classmethod
-    def resource_setup(cls):
-        super(PasswordAdminRbacTest, cls).resource_setup()
-        cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id']
-
-    @testtools.skipUnless(CONF.compute_feature_enabled.change_password,
-                          'Change password not available.')
-    @rbac_rule_validation.action(
-        service="nova", rule="os_compute_api:os-admin-password")
-    @decorators.idempotent_id('908a7d59-3a66-441c-94cf-38e57ed14956')
-    def test_change_server_password(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.change_password(
-            self.server_id,
-            adminPass=data_utils.rand_password())
diff --git a/patrole_tempest_plugin/tests/api/compute/admin/test_admin_server_actions_rbac.py b/patrole_tempest_plugin/tests/api/compute/admin/test_admin_server_actions_rbac.py
deleted file mode 100644
index b2bc2b6..0000000
--- a/patrole_tempest_plugin/tests/api/compute/admin/test_admin_server_actions_rbac.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest import config
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.compute import rbac_base
-
-
-CONF = config.CONF
-
-
-class ServersAdminRbacTest(rbac_base.BaseV2ComputeAdminRbacTest):
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ServersAdminRbacTest, self).tearDown()
-
-    @classmethod
-    def setup_clients(cls):
-        super(ServersAdminRbacTest, cls).setup_clients()
-        cls.client = cls.servers_client
-
-    @classmethod
-    def skip_checks(cls):
-        super(ServersAdminRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
-
-    @classmethod
-    def resource_setup(cls):
-        super(ServersAdminRbacTest, cls).resource_setup()
-        cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id']
-
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-admin-actions:reset_state")
-    @decorators.idempotent_id('ae84dd0b-f364-462e-b565-3457f9c019ef')
-    def test_reset_server_state(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.reset_state(self.server_id, state='error')
-        self.addCleanup(self.client.reset_state,
-                        self.server_id,
-                        state='active')
-
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-admin-actions:inject_network_info")
-    @decorators.idempotent_id('ce48c340-51c1-4cff-9b6e-0cc5ef008630')
-    def test_inject_network_info(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.inject_network_info(self.server_id)
-
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-admin-actions:reset_network")
-    @decorators.idempotent_id('2911a242-15c4-4fcb-80d5-80a8930661b0')
-    def test_reset_network(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.reset_network(self.server_id)
diff --git a/patrole_tempest_plugin/tests/api/compute/rbac_base.py b/patrole_tempest_plugin/tests/api/compute/rbac_base.py
index 4243bdd..0a3a1f5 100644
--- a/patrole_tempest_plugin/tests/api/compute/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/compute/rbac_base.py
@@ -11,13 +11,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.api.compute import base as compute_base
+from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib.common.utils import test_utils
 
-from tempest.api.compute import base as compute_base
-from tempest import config
-
-from patrole_tempest_plugin.rbac_utils import rbac_utils
+from patrole_tempest_plugin import rbac_utils
 
 CONF = config.CONF
 
@@ -29,45 +28,28 @@
     @classmethod
     def skip_checks(cls):
         super(BaseV2ComputeRbacTest, cls).skip_checks()
-        if not CONF.rbac.rbac_flag:
+        if not CONF.rbac.enable_rbac:
             raise cls.skipException(
                 '%s skipped as RBAC flag not enabled' % cls.__name__)
 
     @classmethod
     def setup_clients(cls):
         super(BaseV2ComputeRbacTest, cls).setup_clients()
-        cls.admin_client = cls.os_admin.agents_client
-        cls.auth_provider = cls.os.auth_provider
-        cls.rbac_utils = rbac_utils()
+        cls.auth_provider = cls.os_primary.auth_provider
+        cls.rbac_utils = rbac_utils.RbacUtils(cls)
 
-
-class BaseV2ComputeAdminRbacTest(compute_base.BaseV2ComputeAdminTest):
-
-    credentials = ['admin', 'primary']
-
-    @classmethod
-    def skip_checks(cls):
-        super(BaseV2ComputeAdminRbacTest, cls).skip_checks()
-        if not CONF.rbac.rbac_flag:
-            raise cls.skipException(
-                '%s skipped as RBAC flag not enabled' % cls.__name__)
-
-    @classmethod
-    def setup_clients(cls):
-        super(BaseV2ComputeAdminRbacTest, cls).setup_clients()
-        cls.admin_client = cls.os_admin.agents_client
-        cls.auth_provider = cls.os.auth_provider
-        cls.rbac_utils = rbac_utils()
+        cls.hosts_client = cls.os_primary.hosts_client
+        cls.tenant_usages_client = cls.os_primary.tenant_usages_client
 
     @classmethod
     def resource_setup(cls):
-        super(BaseV2ComputeAdminRbacTest, cls).resource_setup()
+        super(BaseV2ComputeRbacTest, cls).resource_setup()
         cls.flavors = []
 
     @classmethod
     def resource_cleanup(cls):
         cls.clear_flavors()
-        super(BaseV2ComputeAdminRbacTest, cls).resource_cleanup()
+        super(BaseV2ComputeRbacTest, cls).resource_cleanup()
 
     @classmethod
     def clear_flavors(cls):
@@ -78,7 +60,7 @@
     @classmethod
     def _create_flavor(cls, **kwargs):
         flavor_kwargs = {
-            "name": data_utils.rand_name('flavor'),
+            "name": data_utils.rand_name(cls.__name__ + '-flavor'),
             "ram": data_utils.rand_int_id(1, 10),
             "vcpus": data_utils.rand_int_id(1, 10),
             "disk": data_utils.rand_int_id(1, 10),
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 dbb285f..f355358 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_agents_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_agents_rbac.py
@@ -13,31 +13,38 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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
 
-CONF = config.CONF
-
 
 class AgentsRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(AgentsRbacTest, self).tearDown()
-
     @classmethod
     def skip_checks(cls):
         super(AgentsRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
+        if not test.is_extension_enabled('os-agents', 'compute'):
             raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
+                '%s skipped as os-agents not enabled' % cls.__name__)
 
     @rbac_rule_validation.action(
         service="nova", rule="os_compute_api:os-agents")
     @decorators.idempotent_id('d1bc6d97-07f5-4f45-ac29-1c619a6a7e27')
     def test_list_agents_rbac(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.agents_client.list_agents()
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-agents")
+    @decorators.idempotent_id('77d6cae4-1ced-47f7-af2e-3d6a45958fd6')
+    def test_create_agent(self):
+        params = {'hypervisor': 'kvm', 'os': 'win', 'architecture': 'x86',
+                  'version': '7.0', 'url': 'xxx://xxxx/xxx/xxx',
+                  'md5hash': 'add6bb58e139be103324d04d82d8f545'}
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        body = self.agents_client.create_agent(**params)['agent']
+        self.addCleanup(self.agents_client.delete_agent,
+                        body['agent_id'])
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 f7a8b7a..eec4030 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_aggregates_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_aggregates_rbac.py
@@ -13,37 +13,31 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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.compute import rbac_base
 
-CONF = config.CONF
-
 
 class AggregatesRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(AggregatesRbacTest, self).tearDown()
-
     @classmethod
     def skip_checks(cls):
         super(AggregatesRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
+        if not test.is_extension_enabled('os-aggregates', 'compute'):
+            msg = "%s skipped as os-aggregates not enabled." % cls.__name__
+            raise cls.skipException(msg)
 
     @classmethod
     def setup_clients(cls):
         super(AggregatesRbacTest, cls).setup_clients()
-        cls.hosts_client = cls.os.hosts_client
+        cls.hosts_client = cls.os_primary.hosts_client
 
     def _create_aggregate(self):
-        agg_name = data_utils.rand_name('aggregate')
+        agg_name = data_utils.rand_name(self.__class__.__name__ + '-aggregate')
         aggregate = self.aggregates_client.create_aggregate(name=agg_name)
         aggregate_id = aggregate['aggregate']['id']
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
@@ -64,7 +58,7 @@
         service="nova", rule="os_compute_api:os-aggregates:create")
     @decorators.idempotent_id('ba754393-896e-434a-9704-452ff4a84f3f')
     def test_create_aggregate_rbac(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_aggregate()
 
     @rbac_rule_validation.action(
@@ -72,14 +66,14 @@
     @decorators.idempotent_id('8fb0b749-b120-4727-b3fb-bcfa3fa6f55b')
     def test_show_aggregate_rbac(self):
         aggregate_id = self._create_aggregate()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.aggregates_client.show_aggregate(aggregate_id)
 
     @rbac_rule_validation.action(
         service="nova", rule="os_compute_api:os-aggregates:index")
     @decorators.idempotent_id('146284da-5dd6-4c97-b598-42b480f014c6')
     def test_list_aggregate_rbac(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.aggregates_client.list_aggregates()['aggregates']
 
     @rbac_rule_validation.action(
@@ -87,8 +81,8 @@
     @decorators.idempotent_id('c94e0d69-99b6-477e-b301-2cd0e9d0ad81')
     def test_update_aggregate_rbac(self):
         aggregate_id = self._create_aggregate()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        new_name = data_utils.rand_name('aggregate')
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        new_name = data_utils.rand_name(self.__class__.__name__ + '-aggregate')
         self.aggregates_client.update_aggregate(aggregate_id, name=new_name)
 
     @rbac_rule_validation.action(
@@ -96,7 +90,7 @@
     @decorators.idempotent_id('5a50c5a6-0f12-4405-a1ce-2288ae895ea6')
     def test_delete_aggregate_rbac(self):
         aggregate_id = self._create_aggregate()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.aggregates_client.delete_aggregate(aggregate_id)
 
     @rbac_rule_validation.action(
@@ -104,7 +98,7 @@
     @decorators.idempotent_id('97e6e9df-5291-4faa-8147-755b2d1f1ce2')
     def test_add_host_to_aggregate_rbac(self):
         aggregate_id = self._create_aggregate()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._add_host_to_aggregate(aggregate_id)
 
     @rbac_rule_validation.action(
@@ -113,7 +107,7 @@
     def test_remove_host_from_aggregate_rbac(self):
         aggregate_id = self._create_aggregate()
         host_name = self._add_host_to_aggregate(aggregate_id)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.aggregates_client.remove_host(aggregate_id, host=host_name)
 
     @rbac_rule_validation.action(
@@ -121,9 +115,9 @@
     @decorators.idempotent_id('ed6f3849-065c-4ae9-a81e-6ad7ed0d3d9d')
     def test_set_metadata_on_aggregate_rbac(self):
         aggregate_id = self._create_aggregate()
-        rand_key = data_utils.rand_name('key')
-        rand_val = data_utils.rand_name('val')
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        rand_key = data_utils.rand_name(self.__class__.__name__ + '-key')
+        rand_val = data_utils.rand_name(self.__class__.__name__ + '-val')
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.aggregates_client.set_metadata(
             aggregate_id,
             metadata={rand_key: rand_val})
diff --git a/patrole_tempest_plugin/tests/api/compute/test_assisted_volume_snapshot_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_assisted_volume_snapshot_rbac.py
deleted file mode 100644
index 724d07b..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_assisted_volume_snapshot_rbac.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.compute import rbac_base
-
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-
-
-class AssistedVolumeSnapshotRbacTest(rbac_base.BaseV2ComputeRbacTest):
-    """Assisted volume snapshot tests.
-
-    Test class for create and delete
-    """
-
-    @classmethod
-    def setup_clients(cls):
-        """Setup clients."""
-        super(AssistedVolumeSnapshotRbacTest, cls).setup_clients()
-        cls.client = cls.servers_client
-
-    def tearDown(self):
-        """Cleanup and reset RBAC role."""
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(AssistedVolumeSnapshotRbacTest, self).tearDown()
-
-    def _create_and_attach(self):
-        self.server = self.create_test_server(wait_until='ACTIVE')
-        self.volume = self.create_volume()
-        self.attachment = self.attach_volume(
-            self.server, self.volume)
-
-    @decorators.skip_because(bug="1668407")
-    @decorators.idempotent_id('74f64957-912d-4537-983b-cea4a31c5c9f')
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-assisted-volume-snapshots:create")
-    def test_assisted_volume_snapshot_create(self):
-        """Create Role Test.
-
-        RBAC test for assisted volume snapshot role-create
-        """
-        self._create_and_attach()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.assisted_volume_snapshot_client.\
-            create_volume_attachments(self.volume['id'],
-                                      data_utils.rand_uuid())
-
-    @decorators.skip_because(bug="1668407")
-    @decorators.idempotent_id('01323040-c5df-4e15-8b1a-3df98fa7d998')
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-assisted-volume-snapshots:delete")
-    def test_assisted_volume_snapshot_delete(self):
-        """Delete Role Test.
-
-        RBAC test for assisted volume snapshot role-delete
-        """
-        self._create_and_attach()
-        snapshot_id = data_utils.rand_uuid()
-        self.assisted_volume_snapshot_client.\
-            create_volume_attachments(self.volume['id'], snapshot_id)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.assisted_volume_snapshot_client.\
-            delete_volume_attachments(snapshot_id, self.volume['id'])
diff --git a/patrole_tempest_plugin/tests/api/compute/test_attach_interfaces_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_attach_interfaces_rbac.py
deleted file mode 100644
index 84215c3..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_attach_interfaces_rbac.py
+++ /dev/null
@@ -1,97 +0,0 @@
-#    Copyright 2017 AT&T Corporation.
-#    All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest.common import waiters
-from tempest import config
-from tempest.lib.common.utils import test_utils
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.compute import rbac_base
-
-CONF = config.CONF
-
-
-class AttachInterfacesRbacTest(rbac_base.BaseV2ComputeRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(AttachInterfacesRbacTest, cls).setup_clients()
-        cls.client = cls.interfaces_client
-
-    @classmethod
-    def skip_checks(cls):
-        super(AttachInterfacesRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
-        if not CONF.compute_feature_enabled.interface_attach:
-            raise cls.skipException(
-                "%s skipped as interface attachment is not available"
-                % cls.__name__)
-        if not CONF.service_available.neutron:
-            raise cls.skipException(
-                '%s skipped as Neutron is required' % cls.__name__)
-
-    @classmethod
-    def setup_credentials(cls):
-        cls.prepare_instance_network()
-        super(AttachInterfacesRbacTest, cls).setup_credentials()
-
-    @classmethod
-    def resource_setup(cls):
-        super(AttachInterfacesRbacTest, cls).resource_setup()
-        cls.server = cls.create_test_server(wait_until='ACTIVE')
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(AttachInterfacesRbacTest, self).tearDown()
-
-    def _attach_interface_to_server(self):
-        interface = self.client.create_interface(
-            self.server['id'])['interfaceAttachment']
-        waiters.wait_for_interface_status(
-            self.interfaces_client, self.server['id'], interface['port_id'],
-            'ACTIVE')
-        self.addCleanup(
-            test_utils.call_and_ignore_notfound_exc,
-            self.client.delete_interface, self.server['id'],
-            interface['port_id'])
-        return interface
-
-    @decorators.idempotent_id('ddf53cb6-4a0a-4e5a-91e3-6c32aaa3b9b6')
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-attach-interfaces")
-    def test_list_interfaces(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_interfaces(self.server['id'])['interfaceAttachments']
-
-    @decorators.idempotent_id('d2d3a24d-4738-4bce-a287-36d664746cde')
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-attach-interfaces:create")
-    def test_create_interface(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._attach_interface_to_server()
-
-    @decorators.idempotent_id('55b05692-ed44-4608-a84c-cd4219c82799')
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-attach-interfaces:delete")
-    def test_delete_interface(self):
-        interface = self._attach_interface_to_server()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.delete_interface(self.server['id'], interface['port_id'])
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 cb46951..2ce9176 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,38 +11,33 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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
 
-CONF = config.CONF
-
 
 class NovaAvailabilityZoneRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(NovaAvailabilityZoneRbacTest, self).tearDown()
-
     @classmethod
     def skip_checks(cls):
         super(NovaAvailabilityZoneRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
+        if not test.is_extension_enabled('os-availability-zone', 'compute'):
+            msg = ("%s skipped as os-availability-zone not "
+                   "enabled." % cls.__name__)
+            raise cls.skipException(msg)
 
     @rbac_rule_validation.action(service="nova", rule="os_compute_api:"
                                  "os-availability-zone:list")
     @decorators.idempotent_id('cd34e7ea-d26e-4fa3-a8d0-f8883726ce3d')
     def test_get_availability_zone_list_rbac(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.os.availability_zone_client.list_availability_zones()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.availability_zone_client.list_availability_zones()
 
     @rbac_rule_validation.action(service="nova", rule="os_compute_api:"
                                  "os-availability-zone:detail")
     @decorators.idempotent_id('2f61c191-6ece-4f21-b487-39d749e3d38e')
     def test_get_availability_zone_list_detail_rbac(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.os.availability_zone_client.list_availability_zones(detail=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.availability_zone_client.list_availability_zones(detail=True)
diff --git a/patrole_tempest_plugin/tests/api/compute/test_config_drive_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_config_drive_rbac.py
index 5e993dc..794e0d2 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_config_drive_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_config_drive_rbac.py
@@ -35,16 +35,12 @@
                   % cls.__name__
             raise cls.skipException(msg)
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ConfigDriveRbacTest, self).tearDown()
-
     @decorators.idempotent_id('55c62ef7-b72b-4970-acc6-05b0a4316e5d')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-config-drive")
     def test_create_test_server_with_config_drive(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         # NOTE(felipemonteiro): This policy action is always enforced,
         # regardless whether the config_drive flag is set to true or false.
         # However, it has been explicitly set to true below, in case that this
diff --git a/patrole_tempest_plugin/tests/api/compute/test_deferred_delete_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_deferred_delete_rbac.py
deleted file mode 100644
index 618a41c..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_deferred_delete_rbac.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#    Copyright 2017 AT&T Corporation.
-#    All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest import test
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.compute import rbac_base
-
-
-class DeferredDeleteRbacTest(rbac_base.BaseV2ComputeRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(DeferredDeleteRbacTest, cls).setup_clients()
-        cls.client = cls.servers_client
-
-    @classmethod
-    def skip_checks(cls):
-        super(DeferredDeleteRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-deferred-delete', 'compute'):
-            msg = "%s skipped as os-deferred-delete extension not enabled." \
-                  % cls.__name__
-            raise cls.skipException(msg)
-
-    @classmethod
-    def resource_setup(cls):
-        super(DeferredDeleteRbacTest, cls).resource_setup()
-        cls.server = cls.create_test_server(wait_until='ACTIVE')
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(DeferredDeleteRbacTest, self).tearDown()
-
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-deferred-delete")
-    def test_force_delete_server(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # Force-deleting a server enforces os-deferred-delete according to the
-        # following API: https://github.com/openstack/nova/blob/master/nova/api
-        # /openstack/compute/deferred_delete.py
-        self.client.force_delete_server(self.server['id'])
diff --git a/patrole_tempest_plugin/tests/api/compute/test_flavor_access_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_flavor_access_rbac.py
index 62e8d14..b771d32 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_flavor_access_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_flavor_access_rbac.py
@@ -13,68 +13,55 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from oslo_log import log
+from oslo_config import cfg
 
-from tempest import config
 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
 from patrole_tempest_plugin.tests.api.compute import rbac_base
 
-CONF = config.CONF
-LOG = log.getLogger(__name__)
+CONF = cfg.CONF
 
 
-class FlavorAccessAdminRbacTest(rbac_base.BaseV2ComputeAdminRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(FlavorAccessAdminRbacTest, cls).setup_clients()
-        cls.client = cls.flavors_client
+class FlavorAccessRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
     @classmethod
     def skip_checks(cls):
-        super(FlavorAccessAdminRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
+        super(FlavorAccessRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'):
+            msg = "%s skipped as OS-FLV-EXT-DATA extension not enabled."\
+                  % cls.__name__
+            raise cls.skipException(msg)
 
     @classmethod
     def resource_setup(cls):
-        super(FlavorAccessAdminRbacTest, cls).resource_setup()
+        super(FlavorAccessRbacTest, cls).resource_setup()
         cls.flavor_id = cls._create_flavor(is_public=False)['id']
+        cls.public_flavor_id = CONF.compute.flavor_ref
         cls.tenant_id = cls.auth_provider.credentials.tenant_id
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(FlavorAccessAdminRbacTest, self).tearDown()
-
     @decorators.idempotent_id('a2bd3740-765d-4c95-ac98-9e027378c75e')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-flavor-access")
-    def test_list_flavor_access(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.client.list_flavor_access(self.flavor_id)
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+    def test_show_flavor(self):
+        # NOTE(felipemonteiro): show_flavor enforces the specified policy
+        # action, but only works if a public flavor is passed.
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.flavors_client.show_flavor(self.public_flavor_id)['flavor']
 
     @decorators.idempotent_id('39cb5c8f-9990-436f-9282-fc76a41d9bac')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-flavor-access:add_tenant_access")
     def test_add_flavor_access(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.add_flavor_access(
-            flavor_id=self.flavor_id, tenant_id=self.tenant_id)
-        self.addCleanup(self.client.remove_flavor_access,
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.flavors_client.add_flavor_access(
+            flavor_id=self.flavor_id, tenant_id=self.tenant_id)[
+            'flavor_access']
+        self.addCleanup(self.flavors_client.remove_flavor_access,
                         flavor_id=self.flavor_id, tenant_id=self.tenant_id)
 
     @decorators.idempotent_id('61b8621f-52e4-473a-8d07-e228af8853d1')
@@ -82,11 +69,11 @@
         service="nova",
         rule="os_compute_api:os-flavor-access:remove_tenant_access")
     def test_remove_flavor_access(self):
-        self.client.add_flavor_access(
+        self.flavors_client.add_flavor_access(
             flavor_id=self.flavor_id, tenant_id=self.tenant_id)
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.client.remove_flavor_access,
+                        self.flavors_client.remove_flavor_access,
                         flavor_id=self.flavor_id, tenant_id=self.tenant_id)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.remove_flavor_access(
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.flavors_client.remove_flavor_access(
             flavor_id=self.flavor_id, tenant_id=self.tenant_id)
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 505cfa9..e59fd78 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
@@ -22,44 +22,35 @@
 from patrole_tempest_plugin.tests.api.compute import rbac_base
 
 
-class FlavorExtraSpecsAdminRbacTest(rbac_base.BaseV2ComputeAdminRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(FlavorExtraSpecsAdminRbacTest, cls).setup_clients()
-        cls.client = cls.flavors_client
+class FlavorExtraSpecsRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
     @classmethod
     def skip_checks(cls):
-        super(FlavorExtraSpecsAdminRbacTest, cls).skip_checks()
+        super(FlavorExtraSpecsRbacTest, cls).skip_checks()
         if not test.is_extension_enabled('os-flavor-extra-specs', 'compute'):
             msg = "os-flavor-extra-specs extension not enabled."
             raise cls.skipException(msg)
 
     @classmethod
     def resource_setup(cls):
-        super(FlavorExtraSpecsAdminRbacTest, cls).resource_setup()
+        super(FlavorExtraSpecsRbacTest, cls).resource_setup()
         cls.flavor = cls._create_flavor()
 
     @classmethod
     def resource_cleanup(cls):
-        cls.client.delete_flavor(cls.flavor['id'])
-        cls.client.wait_for_resource_deletion(cls.flavor['id'])
-        super(FlavorExtraSpecsAdminRbacTest, cls).resource_cleanup()
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(FlavorExtraSpecsAdminRbacTest, self).tearDown()
+        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('key')
-        rand_val = data_utils.rand_name('val')
+        rand_key = data_utils.rand_name(self.__class__.__name__ + '-key')
+        rand_val = data_utils.rand_name(self.__class__.__name__ + '-val')
         specs = {rand_key: rand_val}
-        self.client.set_flavor_extra_spec(self.flavor['id'],
-                                          **specs)['extra_specs']
+        self.flavors_client.set_flavor_extra_spec(self.flavor['id'],
+                                                  **specs)['extra_specs']
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.client.unset_flavor_extra_spec, self.flavor['id'],
-                        rand_key)
+                        self.flavors_client.unset_flavor_extra_spec,
+                        self.flavor['id'], rand_key)
         return rand_key
 
     @decorators.idempotent_id('daee891d-dfe9-4501-a39c-29f2371bec3c')
@@ -68,15 +59,15 @@
         rule="os_compute_api:os-flavor-extra-specs:show")
     def test_show_flavor_extra_spec(self):
         key = self._set_flavor_extra_spec()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_flavor_extra_spec(self.flavor['id'], key)[key]
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.flavors_client.show_flavor_extra_spec(self.flavor['id'], key)[key]
 
     @decorators.idempotent_id('fcffeca2-ed04-4e85-bf93-02fb5643f22b')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-flavor-extra-specs:create")
     def test_set_flavor_extra_spec(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._set_flavor_extra_spec()
 
     @decorators.idempotent_id('42b85279-6bfa-4f58-b7a2-258c284f03c5')
@@ -85,10 +76,10 @@
         rule="os_compute_api:os-flavor-extra-specs:update")
     def test_update_flavor_extra_spec(self):
         key = self._set_flavor_extra_spec()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        update_val = data_utils.rand_name('val')
-        self.client.update_flavor_extra_spec(self.flavor['id'], key,
-                                             **{key: update_val})[key]
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        update_val = data_utils.rand_name(self.__class__.__name__ + '-val')
+        self.flavors_client.update_flavor_extra_spec(
+            self.flavor['id'], key, **{key: update_val})[key]
 
     @decorators.idempotent_id('4b0e5471-e010-4c09-8965-80898e6760a3')
     @rbac_rule_validation.action(
@@ -96,8 +87,8 @@
         rule="os_compute_api:os-flavor-extra-specs:delete")
     def test_unset_flavor_extra_spec(self):
         key = self._set_flavor_extra_spec()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.unset_flavor_extra_spec(self.flavor['id'], key)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.flavors_client.unset_flavor_extra_spec(self.flavor['id'], key)
 
     @decorators.idempotent_id('02c3831a-3ce9-476e-a722-d805ac2da621')
     @rbac_rule_validation.action(
@@ -105,5 +96,6 @@
         rule="os_compute_api:os-flavor-extra-specs:index")
     def test_list_flavor_extra_specs(self):
         self._set_flavor_extra_spec()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_flavor_extra_specs(self.flavor['id'])['extra_specs']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.flavors_client.list_flavor_extra_specs(
+            self.flavor['id'])['extra_specs']
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
new file mode 100644
index 0000000..33b1564
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_flavor_rxtx_rbac.py
@@ -0,0 +1,39 @@
+#    Copyright 2017 AT&T Corporation.
+#    All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.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
+
+
+class FlavorRxtxRbacTest(rbac_base.BaseV2ComputeRbacTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(FlavorRxtxRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('os-flavor-rxtx', 'compute'):
+            msg = "os-flavor-rxtx extension not enabled."
+            raise cls.skipException(msg)
+
+    @decorators.idempotent_id('0278677c-6e69-4293-a387-b485781e61a1')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-flavor-rxtx")
+    def test_create_flavor_rxtx(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        # Enforces os_compute_api:os-flavor-rxtx.
+        self.flavors_client.list_flavors(detail=True)['flavors']
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 602dc5a..7b35525 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
@@ -25,15 +25,15 @@
 
 class FloatingIpPoolsRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
-    # Tests will fail with a 404 starting from microversion 2.36, according to:
-    # https://developer.openstack.org/api-ref/
-    # compute/?expanded=list-floating-ip-pools-detail
+    # Tests will fail with a 404 starting from microversion 2.36:
+    # See the following link for details:
+    # https://developer.openstack.org/api-ref/compute/#floating-ip-pools-os-floating-ip-pools-deprecated
     max_microversion = '2.35'
 
     @classmethod
     def setup_clients(cls):
         super(FloatingIpPoolsRbacTest, cls).setup_clients()
-        cls.client = cls.os.floating_ip_pools_client
+        cls.fip_pools_client = cls.os_primary.floating_ip_pools_client
 
     @classmethod
     def skip_checks(cls):
@@ -43,14 +43,10 @@
                   % cls.__name__
             raise cls.skipException(msg)
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(FloatingIpPoolsRbacTest, self).tearDown()
-
     @decorators.idempotent_id('c1a17153-b25d-4444-a721-5897d7737482')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-floating-ip-pools")
     def test_list_floating_ip_pools(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_floating_ip_pools()['floating_ip_pools']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.fip_pools_client.list_floating_ip_pools()['floating_ip_pools']
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 e4d1963..cceccd4 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
@@ -25,15 +25,15 @@
 
 class FloatingIpsBulkRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
-    # Tests will fail with a 404 starting from microversion 2.36, according to:
-    # https://developer.openstack.org/api-ref/
-    # compute/?expanded=list-floating-ips-detail
+    # Tests will fail with a 404 starting from microversion 2.36:
+    # See the following link for details:
+    # https://developer.openstack.org/api-ref/compute/#floating-ips-bulk-os-floating-ips-bulk-deprecated
     max_microversion = '2.35'
 
     @classmethod
     def setup_clients(cls):
         super(FloatingIpsBulkRbacTest, cls).setup_clients()
-        cls.client = cls.os.floating_ips_bulk_client
+        cls.fip_bulk_client = cls.os_primary.floating_ips_bulk_client
 
     @classmethod
     def skip_checks(cls):
@@ -43,14 +43,10 @@
                   % cls.__name__
             raise cls.skipException(msg)
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(FloatingIpsBulkRbacTest, self).tearDown()
-
     @decorators.idempotent_id('3b5c8a02-005d-4256-8a95-6fa2f389c6cf')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-floating-ips-bulk")
     def test_list_floating_ips_bulk(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_floating_ips_bulk()['floating_ip_info']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.fip_bulk_client.list_floating_ips_bulk()['floating_ip_info']
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 6738539..764d165 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
@@ -25,17 +25,12 @@
 
 class FloatingIpsRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
-    # Tests will fail with a 404 starting from microversion 2.36, according to:
-    # https://developer.openstack.org/api-ref/
-    # compute/?expanded=list-floating-ip-addresses-detail
+    # Tests will fail with a 404 starting from microversion 2.36:
+    # See the following link for details:
+    # https://developer.openstack.org/api-ref/compute/#floating-ips-os-floating-ips-deprecated
     max_microversion = '2.35'
 
     @classmethod
-    def setup_clients(cls):
-        super(FloatingIpsRbacTest, cls).setup_clients()
-        cls.client = cls.floating_ips_client
-
-    @classmethod
     def skip_checks(cls):
         super(FloatingIpsRbacTest, cls).skip_checks()
         if not test.is_extension_enabled('os-floating-ips', 'compute'):
@@ -43,14 +38,10 @@
                   % cls.__name__
             raise cls.skipException(msg)
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(FloatingIpsRbacTest, self).tearDown()
-
     @decorators.idempotent_id('ac1b3053-f755-4cda-85a0-30e88b88d7ba')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-floating-ips")
     def test_list_floating_ips(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_floating_ips()['floating_ips']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.floating_ips_client.list_floating_ips()['floating_ips']
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 1fca217..2a6b171 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_hosts_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_hosts_rbac.py
@@ -13,37 +13,26 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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
 
-CONF = config.CONF
 
-
-class HostsAdminRbacTest(rbac_base.BaseV2ComputeAdminRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(HostsAdminRbacTest, cls).setup_clients()
-        cls.client = cls.os.hosts_client
+class HostsRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
     @classmethod
     def skip_checks(cls):
-        super(HostsAdminRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(HostsAdminRbacTest, self).tearDown()
+        super(HostsRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('os-hosts', 'compute'):
+            msg = "%s skipped as os-hosts not enabled." % cls.__name__
+            raise cls.skipException(msg)
 
     @decorators.idempotent_id('035b7935-2fae-4218-8d37-27fa83097494')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-hosts")
     def test_list_hosts(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_hosts()['hosts']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.hosts_client.list_hosts()['hosts']
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 a572cda..e687fb4 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_hypervisor_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_hypervisor_rbac.py
@@ -20,29 +20,79 @@
 from patrole_tempest_plugin.tests.api.compute import rbac_base
 
 
-class HypervisorAdminRbacTest(rbac_base.BaseV2ComputeAdminRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(HypervisorAdminRbacTest, cls).setup_clients()
-        cls.client = cls.hypervisor_client
+class HypervisorRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
     @classmethod
     def skip_checks(cls):
-        super(HypervisorAdminRbacTest, cls).skip_checks()
+        super(HypervisorRbacTest, cls).skip_checks()
         if not test.is_extension_enabled('os-hypervisors', 'compute'):
             msg = "%s skipped as os-hypervisors extension not enabled." \
                   % cls.__name__
             raise cls.skipException(msg)
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(HypervisorAdminRbacTest, self).tearDown()
+    @classmethod
+    def resource_setup(cls):
+        super(HypervisorRbacTest, cls).resource_setup()
+        cls.hypervisor =\
+            cls.hypervisor_client.list_hypervisors()['hypervisors'][0]
 
     @decorators.idempotent_id('17bbeb9a-e73e-445f-a771-c794448ef562')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-hypervisors")
     def test_list_hypervisors(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_hypervisors()['hypervisors']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.hypervisor_client.list_hypervisors()['hypervisors']
+
+    @decorators.idempotent_id('36b95c7d-1085-487a-a674-b7c1ca35f520')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-hypervisors")
+    def test_list_hypervisors_with_details(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.hypervisor_client.list_hypervisors(detail=True)['hypervisors']
+
+    @decorators.idempotent_id('8a7f6f9e-34a6-4480-8875-bba566c3a581')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-hypervisors")
+    def test_show_hypervisor(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.hypervisor_client.show_hypervisor(
+            self.hypervisor['id'])['hypervisor']
+
+    @decorators.idempotent_id('b86f03cf-2e79-4d88-9eea-62f761591413')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-hypervisors")
+    def test_list_servers_on_hypervisor(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.hypervisor_client.list_servers_on_hypervisor(
+            self.hypervisor['hypervisor_hostname'])['hypervisors']
+
+    @decorators.idempotent_id('ca0e465c-6365-4a7f-ae58-6f8ddbca06c2')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-hypervisors")
+    def test_show_hypervisor_statistics(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.hypervisor_client.\
+            show_hypervisor_statistics()['hypervisor_statistics']
+
+    @decorators.idempotent_id('109b37c5-91ba-4da5-b2a2-d7618d84406d')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-hypervisors")
+    def test_show_hypervisor_uptime(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.hypervisor_client.show_hypervisor_uptime(
+            self.hypervisor['id'])['hypervisor']
+
+    @decorators.idempotent_id('3dbc71c1-8f04-4674-a67c-dcb2fd99b1b4')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-hypervisors")
+    def test_search_hypervisor(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.hypervisor_client.search_hypervisor(
+            self.hypervisor['hypervisor_hostname'])['hypervisors']
diff --git a/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py
new file mode 100644
index 0000000..cdabf6f
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py
@@ -0,0 +1,210 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest 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 patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.compute import rbac_base
+
+CONF = config.CONF
+
+
+class ImagesRbacTest(rbac_base.BaseV2ComputeRbacTest):
+    """RBAC tests for the Nova images client.
+
+    These APIs are proxy calls to the Image service. Consequently, no nova
+    policy actions are enforced; instead, only glance policy actions are
+    enforced. As such, these tests check that only glance policy actions are
+    executed.
+    """
+
+    # These tests will fail with a 404 starting from microversion 2.36.
+    # See the following link for details:
+    # https://developer.openstack.org/api-ref/compute/#images-deprecated
+    max_microversion = '2.35'
+
+    @classmethod
+    def skip_checks(cls):
+        super(ImagesRbacTest, cls).skip_checks()
+        if not CONF.service_available.glance:
+            skip_msg = ("%s skipped as glance is not available" % cls.__name__)
+            raise cls.skipException(skip_msg)
+
+    @classmethod
+    def setup_clients(cls):
+        super(ImagesRbacTest, cls).setup_clients()
+        if CONF.image_feature_enabled.api_v1:
+            cls.glance_image_client = cls.os_primary.image_client
+        elif CONF.image_feature_enabled.api_v2:
+            cls.glance_image_client = cls.os_primary.image_client_v2
+        else:
+            raise lib_exc.InvalidConfiguration(
+                'Either api_v1 or api_v2 must be True in '
+                '[image-feature-enabled].')
+
+    @classmethod
+    def resource_setup(cls):
+        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()
+
+    @decorators.idempotent_id('b861f302-b72b-4055-81db-c62ff30b136d')
+    @rbac_rule_validation.action(
+        service="glance",
+        rule="get_images")
+    def test_list_images(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.compute_images_client.list_images()
+
+    @decorators.idempotent_id('4365ae0f-15ee-4b54-a527-1679faaed140')
+    @rbac_rule_validation.action(
+        service="glance",
+        rule="get_images")
+    def test_list_images_with_details(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.compute_images_client.list_images(detail=True)
+
+    @decorators.idempotent_id('886dfcae-51bf-4610-9e52-82d7189524c2')
+    @rbac_rule_validation.action(
+        service="glance",
+        rule="get_image")
+    def test_show_image_details(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.compute_images_client.show_image(self.image['id'])
+
+    @decorators.idempotent_id('dbe09d4c-e615-48cb-b908-a06a0f410a8e')
+    @rbac_rule_validation.action(
+        service="glance",
+        rule="get_image")
+    def test_show_image_metadata_item(self):
+        self.compute_images_client.set_image_metadata(self.image['id'],
+                                                      meta={'foo': 'bar'})
+        self.addCleanup(self.compute_images_client.delete_image_metadata_item,
+                        self.image['id'], key='foo')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.compute_images_client.show_image_metadata_item(self.image['id'],
+                                                            key='foo')
+
+    @decorators.idempotent_id('59f66079-d564-47e8-81b0-03c2e84d339e')
+    @rbac_rule_validation.action(
+        service="glance",
+        rule="get_image")
+    def test_list_image_metadata(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.compute_images_client.list_image_metadata(self.image['id'])
+
+    @decorators.idempotent_id('5888c7aa-0803-46d4-a3fb-5d4729465cd5')
+    @rbac_rule_validation.action(
+        service="glance",
+        rule="delete_image")
+    def test_delete_image(self):
+        image = self.glance_image_client.create_image(
+            name=data_utils.rand_name(self.__class__.__name__ + '-image'))
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.glance_image_client.delete_image, image['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.compute_images_client.delete_image(image['id'])
+
+    @decorators.idempotent_id('575604aa-909f-4b1b-a5a5-cfae1f63044b')
+    @rbac_rule_validation.action(
+        service="glance",
+        rule="modify_image")
+    def test_create_image_metadata(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        # NOTE(felipemonteiro): Although the name of the client function
+        # appears wrong, it's actually correct: update_image_metadata does an
+        # http post.
+        self.compute_images_client.update_image_metadata(self.image['id'],
+                                                         meta={'foo': 'bar'})
+        self.addCleanup(self.compute_images_client.delete_image_metadata_item,
+                        self.image['id'], key='foo')
+
+    @decorators.idempotent_id('fb8c4eb6-00e5-454c-b8bc-0e801ec369f1')
+    @rbac_rule_validation.action(
+        service="glance",
+        rule="modify_image")
+    def test_update_image_metadata(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.compute_images_client.set_image_metadata(self.image['id'],
+                                                      meta={'foo': 'bar'})
+        self.addCleanup(self.compute_images_client.delete_image_metadata_item,
+                        self.image['id'], key='foo')
+
+    @decorators.idempotent_id('9c7c2036-af9b-49a8-8ba1-09b027ee5def')
+    @rbac_rule_validation.action(
+        service="glance",
+        rule="modify_image")
+    def test_update_image_metadata_item(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.compute_images_client.set_image_metadata_item(
+            self.image['id'], meta={'foo': 'bar'}, key='foo')
+        self.addCleanup(self.compute_images_client.delete_image_metadata_item,
+                        self.image['id'], key='foo')
+
+    @decorators.idempotent_id('5f0dc4e6-0761-4613-9bde-0a6acdc78f46')
+    @rbac_rule_validation.action(
+        service="glance",
+        rule="modify_image")
+    def test_delete_image_metadata_item(self):
+        self.compute_images_client.set_image_metadata(self.image['id'],
+                                                      meta={'foo': 'bar'})
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.compute_images_client.delete_image_metadata_item,
+                        self.image['id'], key='foo')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.compute_images_client.delete_image_metadata_item(self.image['id'],
+                                                              key='foo')
+
+
+class ImageSizeRbacTest(rbac_base.BaseV2ComputeRbacTest):
+    """Tests the ``image_size`` compute policies.
+
+    NOTE(felipemonteiro): If Patrole is enhanced to test multiple policies
+    simultaneously, these policy actions can be combined with the related
+    tests from ``ImagesRbacTest`` above.
+    """
+
+    # These tests will fail with a 404 starting from microversion 2.36.
+    # See the following link for details:
+    # https://developer.openstack.org/api-ref/compute/#images-deprecated
+    max_microversion = '2.35'
+
+    @decorators.idempotent_id('fe34d2a6-5743-45bf-8f92-a1d703d7c7ab')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:image-size")
+    def test_list_images(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.compute_images_client.list_images()
+
+    @decorators.idempotent_id('08342c7d-297d-42ee-b398-90fce2443792')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:image-size")
+    def test_list_images_with_details(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.compute_images_client.list_images(detail=True)
diff --git a/patrole_tempest_plugin/tests/api/compute/test_instance_actions.py b/patrole_tempest_plugin/tests/api/compute/test_instance_actions_rbac.py
similarity index 74%
rename from patrole_tempest_plugin/tests/api/compute/test_instance_actions.py
rename to patrole_tempest_plugin/tests/api/compute/test_instance_actions_rbac.py
index a1f12d6..b81d2ab 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_instance_actions.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_instance_actions_rbac.py
@@ -13,28 +13,22 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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 = config.CONF
-
 
 class InstanceActionsRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
     @classmethod
-    def setup_clients(cls):
-        super(InstanceActionsRbacTest, cls).setup_clients()
-        cls.client = cls.servers_client
-
-    @classmethod
     def skip_checks(cls):
         super(InstanceActionsRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
+        if not test.is_extension_enabled('os-instance-actions', 'compute'):
             raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
+                '%s skipped as os-instance-actions not enabled' % cls.__name__)
 
     @classmethod
     def resource_setup(cls):
@@ -42,21 +36,21 @@
         cls.server = cls.create_test_server(wait_until='ACTIVE')
         cls.request_id = cls.server.response['x-compute-request-id']
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(InstanceActionsRbacTest, self).tearDown()
-
     @decorators.idempotent_id('9d1b131d-407e-4fa3-8eef-eb2c4526f1da')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-instance-actions")
     def test_list_instance_actions(self):
-        self.client.list_instance_actions(self.server['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.list_instance_actions(self.server['id'])
 
     @decorators.idempotent_id('eb04c439-4215-4029-9ccb-5b3c041bfc25')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-instance-actions:events")
     def test_get_instance_action(self):
-        self.client.show_instance_action(
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        instance_action = self.servers_client.show_instance_action(
             self.server['id'], self.request_id)['instanceAction']
+        if 'events' not in instance_action:
+            raise rbac_exceptions.RbacActionFailed
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 aba5b7d..e55e306 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
@@ -20,30 +20,21 @@
 from patrole_tempest_plugin.tests.api.compute import rbac_base
 
 
-class InstanceUsagesAuditLogAdminRbacTest(
-        rbac_base.BaseV2ComputeAdminRbacTest):
+class InstanceUsagesAuditLogRbacTest(
+        rbac_base.BaseV2ComputeRbacTest):
 
     @classmethod
     def skip_checks(cls):
-        super(InstanceUsagesAuditLogAdminRbacTest, cls).skip_checks()
+        super(InstanceUsagesAuditLogRbacTest, cls).skip_checks()
         if not test.is_extension_enabled('os-instance-usage-audit-log',
                                          'compute'):
             msg = "os-instance-usage-audit-log extension not enabled."
             raise cls.skipException(msg)
 
-    @classmethod
-    def setup_clients(cls):
-        super(InstanceUsagesAuditLogAdminRbacTest, cls).setup_clients()
-        cls.client = cls.instance_usages_audit_log_client
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(InstanceUsagesAuditLogAdminRbacTest, self).tearDown()
-
     @decorators.idempotent_id('c80246c0-5c13-4ab0-97ba-91551cd53dc1')
     @rbac_rule_validation.action(
         service="nova", rule="os_compute_api:os-instance-usage-audit-log")
     def test_list_instance_usage_audit_logs(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_instance_usage_audit_logs()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.instance_usages_audit_log_client.list_instance_usage_audit_logs()
         ["instance_usage_audit_logs"]
diff --git a/patrole_tempest_plugin/tests/api/compute/test_ips_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_ips_rbac.py
deleted file mode 100644
index a7b2f6a..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_ips_rbac.py
+++ /dev/null
@@ -1,73 +0,0 @@
-#    Copyright 2017 AT&T Corporation.
-#    All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest import config
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.compute import rbac_base
-
-CONF = config.CONF
-
-
-class IpsRbacTest(rbac_base.BaseV2ComputeRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(IpsRbacTest, cls).setup_clients()
-        cls.client = cls.servers_client
-
-    @classmethod
-    def skip_checks(cls):
-        super(IpsRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
-        if not CONF.service_available.neutron:
-            raise cls.skipException(
-                '%s skipped as Neutron is required' % cls.__name__)
-
-    @classmethod
-    def setup_credentials(cls):
-        cls.prepare_instance_network()
-        super(IpsRbacTest, cls).setup_credentials()
-
-    @classmethod
-    def resource_setup(cls):
-        super(IpsRbacTest, cls).resource_setup()
-        cls.server = cls.create_test_server(wait_until='ACTIVE')
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(IpsRbacTest, self).tearDown()
-
-    @decorators.idempotent_id('6886d360-0d86-4760-b1a3-882d81fbebcc')
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:ips:index")
-    def test_list_addresses(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_addresses(self.server['id'])['addresses']
-
-    @decorators.idempotent_id('fa43e7e5-0db9-48eb-9c6b-c11eb766b8e4')
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:ips:show")
-    def test_list_addresses_by_network(self):
-        addresses = self.client.list_addresses(self.server['id'])['addresses']
-        address = next(iter(addresses))
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_addresses_by_network(
-            self.server['id'], address)[address]
diff --git a/patrole_tempest_plugin/tests/api/compute/test_keypairs_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_keypairs_rbac.py
index d4d9306..8e434fc 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_keypairs_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_keypairs_rbac.py
@@ -23,20 +23,11 @@
 
 class KeypairsRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
-    @classmethod
-    def setup_clients(cls):
-        super(KeypairsRbacTest, cls).setup_clients()
-        cls.client = cls.keypairs_client
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(KeypairsRbacTest, self).tearDown()
-
     def _create_keypair(self):
-        key_name = data_utils.rand_name('key')
-        keypair = self.client.create_keypair(name=key_name)
+        key_name = data_utils.rand_name(self.__class__.__name__ + '-key')
+        keypair = self.keypairs_client.create_keypair(name=key_name)
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.client.delete_keypair,
+                        self.keypairs_client.delete_keypair,
                         key_name)
         return keypair
 
@@ -45,7 +36,7 @@
         service="nova",
         rule="os_compute_api:os-keypairs:create")
     def test_create_keypair(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_keypair()
 
     @decorators.idempotent_id('85a5eb99-40ec-4e77-9358-bee2cdf9d7df')
@@ -54,8 +45,8 @@
         rule="os_compute_api:os-keypairs:show")
     def test_show_keypair(self):
         kp_name = self._create_keypair()['keypair']['name']
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_keypair(kp_name)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.keypairs_client.show_keypair(kp_name)
 
     @decorators.idempotent_id('6bff9f1c-b809-43c1-8d63-61fbd19d49d3')
     @rbac_rule_validation.action(
@@ -63,13 +54,13 @@
         rule="os_compute_api:os-keypairs:delete")
     def test_delete_keypair(self):
         kp_name = self._create_keypair()['keypair']['name']
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.delete_keypair(kp_name)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.keypairs_client.delete_keypair(kp_name)
 
     @decorators.idempotent_id('6bb31346-ff7f-4b10-978e-170ac5fcfa3e')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-keypairs:index")
     def test_index_keypair(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_keypairs()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.keypairs_client.list_keypairs()
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 5b0d9b6..2f19d13 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_limits_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_limits_rbac.py
@@ -11,36 +11,25 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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
 
-CONF = config.CONF
-
 
 class LimitsRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(LimitsRbacTest, self).tearDown()
-
-    @classmethod
-    def setup_clients(cls):
-        super(LimitsRbacTest, cls).setup_clients()
-        cls.client = cls.limits_client
-
     @classmethod
     def skip_checks(cls):
         super(LimitsRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
+        if not test.is_extension_enabled('os-limits', 'compute'):
+            msg = "%s skipped as os-limits not enabled." % cls.__name__
+            raise cls.skipException(msg)
 
     @rbac_rule_validation.action(service="nova",
                                  rule="os_compute_api:limits")
     @decorators.idempotent_id('3fb60f83-9a5f-4fdd-89d9-26c3710844a1')
     def test_show_limits(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_limits()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.limits_client.show_limits()
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 9ccd35b..dc2bdf6 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_migrations_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_migrations_rbac.py
@@ -13,37 +13,26 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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
 
-CONF = config.CONF
 
-
-class MigrationsAdminRbacTest(rbac_base.BaseV2ComputeAdminRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(MigrationsAdminRbacTest, cls).setup_clients()
-        cls.client = cls.migrations_client
+class MigrationsRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
     @classmethod
     def skip_checks(cls):
-        super(MigrationsAdminRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(MigrationsAdminRbacTest, self).tearDown()
+        super(MigrationsRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('os-migrations', 'compute'):
+            msg = "%s skipped as os-migrations not enabled." % cls.__name__
+            raise cls.skipException(msg)
 
     @decorators.idempotent_id('5795231c-3729-448c-a072-9a225db1a328')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-migrations:index")
     def test_list_services(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_migrations()['migrations']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.migrations_client.list_migrations()['migrations']
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
new file mode 100644
index 0000000..a7d8997
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_quota_class_sets_rbac.py
@@ -0,0 +1,84 @@
+#    Copyright 2017 AT&T Corporation.
+#    All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.common import tempest_fixtures as fixtures
+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
+
+
+class QuotaClassesRbacTest(rbac_base.BaseV2ComputeRbacTest):
+
+    def setUp(self):
+        # All test cases in this class need to externally lock on doing
+        # anything with default quota values.
+        self.useFixture(fixtures.LockFixture('compute_quotas'))
+        super(QuotaClassesRbacTest, self).setUp()
+
+    @classmethod
+    def skip_checks(cls):
+        super(QuotaClassesRbacTest, cls).skip_checks()
+        if not test.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)
+
+    @classmethod
+    def setup_clients(cls):
+        super(QuotaClassesRbacTest, cls).setup_clients()
+        cls.quota_classes_client = cls.os_primary.quota_classes_client
+        cls.identity_projects_client = cls.os_primary.projects_client
+
+    @classmethod
+    def resource_setup(cls):
+        super(QuotaClassesRbacTest, cls).resource_setup()
+        # Create a project with its own quota.
+        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()
+
+    @decorators.idempotent_id('c10198ed-9df2-440e-a49b-367dadc6de94')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-quota-class-sets:show")
+    def test_show_quota_class_set(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.quota_classes_client.show_quota_class_set('default')[
+            'quota_class_set']
+
+    @decorators.idempotent_id('81889e69-efd2-4e96-bb4c-ee3b646b9755')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-quota-class-sets:update")
+    def test_update_quota_class_set(self):
+        # Update the pre-existing quotas for the project_id.
+        quota_class_set = self.quota_classes_client.show_quota_class_set(
+            self.project_id)['quota_class_set']
+        quota_class_set.pop('id')
+        for quota, default in quota_class_set.items():
+            quota_class_set[quota] = default + 100
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.quota_classes_client.update_quota_class_set(
+            self.project_id, **quota_class_set)['quota_class_set']
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
new file mode 100644
index 0000000..a4527c3
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_quota_sets_rbac.py
@@ -0,0 +1,107 @@
+#    Copyright 2017 AT&T Corporation.
+#    All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.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
+
+
+class QuotaSetsRbacTest(rbac_base.BaseV2ComputeRbacTest):
+
+    @classmethod
+    def setup_clients(cls):
+        super(QuotaSetsRbacTest, cls).setup_clients()
+        cls.projects_client = cls.os_primary.projects_client
+
+    @classmethod
+    def skip_checks(cls):
+        super(QuotaSetsRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('os-quota-sets', 'compute'):
+            msg = "%s skipped as os-quota-sets extension not enabled."\
+                  % cls.__name__
+            raise cls.skipException(msg)
+
+    @classmethod
+    def resource_setup(cls):
+        super(QuotaSetsRbacTest, cls).resource_setup()
+        cls.tenant_id = cls.quotas_client.tenant_id
+        cls.user_id = cls.quotas_client.user_id
+        cls.quota_set = set(('injected_file_content_bytes',
+                             'metadata_items', 'injected_files',
+                             'ram', 'floating_ips', 'fixed_ips', 'key_pair',
+                             'injected_file_path_bytes', 'instances',
+                             'security_group_rules', 'cores',
+                             'security_groups'))
+
+    @decorators.idempotent_id('8229ceb0-db6a-4a2c-99c2-de226905d8b6')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-quota-sets:update")
+    def test_update_quota_set(self):
+        default_quota_set = self.quotas_client.show_default_quota_set(
+            self.tenant_id)['quota_set']
+        default_quota_set.pop('id')
+        new_quota_set = {'injected_file_content_bytes': 20480}
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.quotas_client.update_quota_set(self.tenant_id,
+                                            force=True,
+                                            **new_quota_set)['quota_set']
+        self.addCleanup(self.quotas_client.update_quota_set, self.tenant_id,
+                        **default_quota_set)
+
+    @decorators.idempotent_id('58df5613-8f3c-400a-8b4b-2bae624d05e9')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-quota-sets:defaults")
+    def test_show_default_quota_set(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.quotas_client.show_default_quota_set(self.tenant_id)['quota_set']
+
+    @decorators.idempotent_id('e8169ac4-c402-4864-894e-aba74e3a459c')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-quota-sets:show")
+    def test_show_quota_set(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.quotas_client.show_quota_set(self.tenant_id)['quota_set']
+
+    @decorators.idempotent_id('4e240644-bf61-4872-9c32-8289ee2fdbbd')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-quota-sets:delete")
+    def test_delete_quota_set(self):
+        project_name = data_utils.rand_name(
+            self.__class__.__name__ + '-project')
+        project = self.projects_client.create_project(name=project_name)
+        project_id = project['project']['id']
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.projects_client.delete_project, project_id)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.quotas_client.delete_quota_set(project_id)
+
+    @decorators.idempotent_id('ac9184b6-f3b3-4e17-a632-4b92c6500f86')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-quota-sets:detail")
+    def test_show_quota_set_details(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.quotas_client.show_quota_set(self.tenant_id,
+                                          detail=True)['quota_set']
diff --git a/patrole_tempest_plugin/tests/api/compute/test_rescue_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_rescue_rbac.py
deleted file mode 100644
index 09a020f..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_rescue_rbac.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#    Copyright 2017 AT&T Corporation.
-#    All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest import config
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.compute import rbac_base
-
-CONF = config.CONF
-
-
-class RescueRbacTest(rbac_base.BaseV2ComputeRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(RescueRbacTest, cls).setup_clients()
-        cls.client = cls.servers_client
-
-    @classmethod
-    def skip_checks(cls):
-        super(RescueRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
-
-    @classmethod
-    def resource_setup(cls):
-        super(RescueRbacTest, cls).resource_setup()
-        cls.server = cls.create_test_server(wait_until='ACTIVE')
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(RescueRbacTest, self).tearDown()
-
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-rescue")
-    @decorators.idempotent_id('fbbb2afc-ed0e-4552-887d-ac00fb5d436e')
-    def test_rescue_server(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.rescue_server(self.server['id'])
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 255c48b..17a6c74 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
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
@@ -21,14 +22,54 @@
 
 class SecurityGroupsRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(SecurityGroupsRbacTest, self).tearDown()
+    # Tests in this class will fail with a 404 from microversion 2.36,
+    # according to:
+    # https://developer.openstack.org/api-ref/compute/#security-groups-os-security-groups-deprecated
+    max_microversion = '2.35'
 
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-security-groups")
     @decorators.idempotent_id('4ac58e49-48c1-4fca-a6c3-3f95fb99eb77')
-    def test_server_security_groups(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+    def test_list_security_groups(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.security_groups_client.list_security_groups()
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-security-groups")
+    @decorators.idempotent_id('e8fe7f5a-69ee-412d-81d3-a8c7a488b54d')
+    def test_create_security_groups(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.create_security_group()['id']
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-security-groups")
+    @decorators.idempotent_id('59127e8e-302d-11e7-93ae-92361f002671')
+    def test_delete_security_groups(self):
+        sec_group_id = self.create_security_group()['id']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.security_groups_client.delete_security_group(sec_group_id)
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-security-groups")
+    @decorators.idempotent_id('3de5c6bc-b822-469e-a627-82427d38b067')
+    def test_update_security_groups(self):
+        sec_group_id = self.create_security_group()['id']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        new_name = data_utils.rand_name()
+        new_desc = data_utils.rand_name()
+        self.security_groups_client.update_security_group(sec_group_id,
+                                                          name=new_name,
+                                                          description=new_desc)
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-security-groups")
+    @decorators.idempotent_id('6edc0320-302d-11e7-93ae-92361f002671')
+    def test_show_security_groups(self):
+        sec_group_id = self.create_security_group()['id']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.security_groups_client.show_security_group(sec_group_id)
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 ab75709..ffbc530 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,93 +13,146 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from oslo_log import log
 import testtools
 
 from tempest.common import waiters
 from tempest import config
+from tempest.lib.common.utils import data_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):
 
     @classmethod
-    def setup_clients(cls):
-        super(ServerActionsRbacTest, cls).setup_clients()
-        cls.client = cls.servers_client
-
-    @classmethod
-    def skip_checks(cls):
-        super(ServerActionsRbacTest, cls).skip_checks()
-
-    @classmethod
     def resource_setup(cls):
-        cls.set_validation_resources()
         super(ServerActionsRbacTest, cls).resource_setup()
-        cls.server_id = cls.create_test_server(wait_until='ACTIVE',
-                                               validatable=True)['id']
+        # 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:
-            waiters.wait_for_server_status(self.client,
+            waiters.wait_for_server_status(self.servers_client,
                                            self.server_id, 'ACTIVE')
         except lib_exc.NotFound:
-            # if the server was found to be deleted by a previous test,
+            # If the server was found to be deleted by a previous test,
             # a new one is built
-            server = self.create_test_server(
-                validatable=True,
-                wait_until='ACTIVE')
+            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, validatable=True)
+            self.__class__.server_id = self.rebuild_server(self.server_id)
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ServerActionsRbacTest, self).tearDown()
+    @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.client.start_server(self.server_id)
-        waiters.wait_for_server_status(self.client, self.server_id,
-                                       'ACTIVE')
+        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):
-        self.client.stop_server(self.server_id)
-        waiters.wait_for_server_status(self.client, self.server_id,
-                                       'SHUTOFF')
+        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):
-        self.client.resize_server(self.server_id, flavor)
-        waiters.wait_for_server_status(self.client, self.server_id,
-                                       'VERIFY_RESIZE')
+        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.client.revert_resize_server(self.server_id)
-        waiters.wait_for_server_status(self.client, self.server_id,
-                                       'ACTIVE')
+        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):
-        self.client.confirm_resize_server(self.server_id)
-        waiters.wait_for_server_status(self.client, self.server_id,
-                                       'ACTIVE')
+        self.servers_client.confirm_resize_server(self.server_id)
+        waiters.wait_for_server_status(
+            self.os_admin.servers_client, self.server_id, 'ACTIVE')
 
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:servers:stop")
     @decorators.idempotent_id('ab4a17d2-166f-4a6d-9944-f17baa576cf2')
     def test_stop_server(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._test_stop_server()
 
     @test.attr(type='slow')
@@ -109,7 +162,7 @@
     @decorators.idempotent_id('8876bfa9-4d10-406e-a335-a57e451abb12')
     def test_start_server(self):
         self._test_stop_server()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._test_start_server()
 
     @test.attr(type='slow')
@@ -120,7 +173,7 @@
     @testtools.skipUnless(CONF.compute_feature_enabled.resize,
                           'Resize is not available.')
     def test_resize_server(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._test_resize_server(self.flavor_ref_alt)
 
     @test.attr(type='slow')
@@ -132,7 +185,7 @@
                           'Resize is not available.')
     def test_revert_resize_server(self):
         self._test_resize_server(self.flavor_ref_alt)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._test_revert_resize_server()
 
     @test.attr(type='slow')
@@ -144,7 +197,7 @@
                           'Resize is not available.')
     def test_confirm_resize_server(self):
         self._test_resize_server(self.flavor_ref_alt)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        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())
@@ -156,17 +209,135 @@
         rule="os_compute_api:servers:rebuild")
     @decorators.idempotent_id('54b1a30b-c96c-472c-9c83-ccaf6ec7e20b')
     def test_rebuild_server(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.rebuild_server(self.server_id, self.image_ref)
-        waiters.wait_for_server_status(self.client, self.server_id,
-                                       'ACTIVE')
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.rebuild_server(self.server_id, self.image_ref)
+        waiters.wait_for_server_status(
+            self.os_admin.servers_client, self.server_id, 'ACTIVE')
 
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:servers:reboot")
     @decorators.idempotent_id('19f27856-56e1-44f8-8615-7257f6b85cbb')
     def test_reboot_server(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.reboot_server(self.server_id, type='HARD')
-        waiters.wait_for_server_status(self.client, self.server_id,
-                                       'ACTIVE')
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.reboot_server(self.server_id, type='HARD')
+        waiters.wait_for_server_status(
+            self.os_admin.servers_client, self.server_id, 'ACTIVE')
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:index")
+    @decorators.idempotent_id('631f0d86-7607-4198-8312-9da2f05464a4')
+    def test_server_index(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.list_servers(minimal=True)
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:detail")
+    @decorators.idempotent_id('96093480-3ce5-4a8b-b569-aed870379c24')
+    def test_server_detail(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.list_servers(detail=True)
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:detail:get_all_tenants")
+    @decorators.idempotent_id('a9e5a1c0-acfe-49a2-b2b1-fd8b19d61f71')
+    def test_server_detail_all_tenants(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.list_servers(detail=True, all_tenants=1)
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:index:get_all_tenants")
+    @decorators.idempotent_id('4b93ba56-69e6-41f5-82c4-84a5c4c42091')
+    def test_server_index_all_tenants(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.list_servers(minimal=True, all_tenants=1)
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:show")
+    @decorators.idempotent_id('eaaf4f51-31b5-497f-8f0f-f527e5f70b83')
+    def test_show_server(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.show_server(self.server_id)
+
+    @test.services('image')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:create_image")
+    @decorators.idempotent_id('ba0ac859-99f4-4055-b5e0-e0905a44d331')
+    def test_create_image(self):
+        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')
+
+    @test.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)
+        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')
+
+
+class ServerActionsV214RbacTest(rbac_base.BaseV2ComputeRbacTest):
+
+    min_microversion = '2.14'
+    max_microversion = 'latest'
+
+    @classmethod
+    def resource_setup(cls):
+        super(ServerActionsV214RbacTest, cls).resource_setup()
+        cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id']
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-evacuate")
+    @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.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.assertRaisesRegex(lib_exc.NotFound,
+                               "Compute host %s not found." % fake_host_name,
+                               self.servers_client.evacuate_server,
+                               self.server_id,
+                               host=fake_host_name)
+
+
+class ServerActionsV216RbacTest(rbac_base.BaseV2ComputeRbacTest):
+
+    # This class has test case(s) that requires at least microversion 2.16.
+    # See the following link for details:
+    # http://developer.openstack.org/api-ref-compute-v2.1.html#show-server-details
+    min_microversion = '2.16'
+    max_microversion = 'latest'
+
+    @classmethod
+    def resource_setup(cls):
+        super(ServerActionsV216RbacTest, cls).resource_setup()
+        cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id']
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:show:host_status")
+    @decorators.idempotent_id('736da575-86f8-4b2a-9902-dd37dc9a409b')
+    def test_show_server_host_status(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        server = self.servers_client.show_server(self.server_id)['server']
+
+        if 'host_status' not in server:
+            LOG.info("host_status attribute not returned when role doesn't "
+                     "have permission to access it.")
+            raise rbac_exceptions.RbacActionFailed
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_consoles_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_consoles_rbac.py
new file mode 100644
index 0000000..7744263
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_consoles_rbac.py
@@ -0,0 +1,94 @@
+#    Copyright 2017 AT&T Corporation.
+#    All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest import config
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.compute import rbac_base
+
+CONF = config.CONF
+
+
+class ServerConsolesRbacTest(rbac_base.BaseV2ComputeRbacTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(ServerConsolesRbacTest, cls).skip_checks()
+        if not CONF.compute_feature_enabled.console_output:
+            raise cls.skipException('Console output not available.')
+
+    @classmethod
+    def resource_setup(cls):
+        super(ServerConsolesRbacTest, cls).resource_setup()
+        cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id']
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-console-output")
+    @decorators.idempotent_id('90fd80f6-456c-11e7-a919-92ebcb67fe33')
+    def test_get_console_output(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.get_console_output(self.server_id)
+
+
+class ServerConsolesMaxV25RbacTest(rbac_base.BaseV2ComputeRbacTest):
+
+    max_microversion = '2.5'
+
+    @classmethod
+    def skip_checks(cls):
+        super(ServerConsolesMaxV25RbacTest, cls).skip_checks()
+        if not CONF.compute_feature_enabled.console_output:
+            raise cls.skipException('Console output not available.')
+
+    @classmethod
+    def resource_setup(cls):
+        super(ServerConsolesMaxV25RbacTest, cls).resource_setup()
+        cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id']
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-remote-consoles")
+    @decorators.idempotent_id('b0a72c02-9b15-4dcb-b186-efe8753370ab')
+    def test_get_vnc_console_output(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.get_vnc_console(self.server_id, type="novnc")
+
+
+class ServerConsolesV26RbacTest(rbac_base.BaseV2ComputeRbacTest):
+
+    min_microversion = '2.6'
+    max_microversion = 'latest'
+
+    @classmethod
+    def skip_checks(cls):
+        super(ServerConsolesV26RbacTest, cls).skip_checks()
+        if not CONF.compute_feature_enabled.console_output:
+            raise cls.skipException('Console output not available.')
+
+    @classmethod
+    def resource_setup(cls):
+        super(ServerConsolesV26RbacTest, cls).resource_setup()
+        cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id']
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-remote-consoles")
+    @decorators.idempotent_id('879597de-87e0-4da9-a60a-28c8088dc508')
+    def test_get_remote_console_output(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.get_remote_console(self.server_id,
+                                               "novnc", "vnc")
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_diagnostics_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_diagnostics_rbac.py
deleted file mode 100644
index ecce552..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_server_diagnostics_rbac.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#    Copyright 2017 AT&T Corporation.
-#    All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest import config
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.compute import rbac_base
-
-CONF = config.CONF
-
-
-class ServerDiagnosticsRbacTest(rbac_base.BaseV2ComputeRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(ServerDiagnosticsRbacTest, cls).setup_clients()
-        cls.client = cls.servers_client
-
-    @classmethod
-    def skip_checks(cls):
-        super(ServerDiagnosticsRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
-
-    @classmethod
-    def resource_setup(cls):
-        super(ServerDiagnosticsRbacTest, cls).resource_setup()
-        cls.server = cls.create_test_server(wait_until='ACTIVE')
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ServerDiagnosticsRbacTest, self).tearDown()
-
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-server-diagnostics")
-    @decorators.idempotent_id('5dabfcc4-bedb-417b-8247-b3ee7c5c0f3e')
-    def test_show_server_diagnostics(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_server_diagnostics(self.server['id'])
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 2a108cd..f9b065c 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,44 +13,28 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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
 
-CONF = config.CONF
-
 
 class ServerGroupsRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
     @classmethod
-    def setup_clients(cls):
-        super(ServerGroupsRbacTest, cls).setup_clients()
-        cls.client = cls.server_groups_client
-
-    @classmethod
     def skip_checks(cls):
         super(ServerGroupsRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
-
-    @classmethod
-    def resource_setup(cls):
-        super(ServerGroupsRbacTest, cls).resource_setup()
-        cls.server = cls.create_test_server(wait_until='ACTIVE')
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ServerGroupsRbacTest, self).tearDown()
+        if not test.is_extension_enabled('os-server-groups', 'compute'):
+            msg = "%s skipped as os-server-groups not enabled." % cls.__name__
+            raise cls.skipException(msg)
 
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-server-groups:create")
     @decorators.idempotent_id('7f3eae94-6130-47e9-81ac-34009f55be2f')
     def test_create_server_group(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.create_test_server_group()
 
     @rbac_rule_validation.action(
@@ -59,16 +43,16 @@
     @decorators.idempotent_id('832d9be3-632e-47b2-93d2-5897db43e3e2')
     def test_delete_server_group(self):
         server_group = self.create_test_server_group()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.delete_server_group(server_group['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.server_groups_client.delete_server_group(server_group['id'])
 
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-server-groups:index")
     @decorators.idempotent_id('5eccd67f-5945-483b-b1c8-de851ebfc1c1')
     def test_list_server_groups(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_server_groups()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.server_groups_client.list_server_groups()
 
     @rbac_rule_validation.action(
         service="nova",
@@ -76,5 +60,5 @@
     @decorators.idempotent_id('62534e3f-7e99-4a3d-a08e-33e056460cf2')
     def test_show_server_group(self):
         server_group = self.create_test_server_group()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_server_group(server_group['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.server_groups_client.show_server_group(server_group['id'])
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_metadata_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_metadata_rbac.py
new file mode 100644
index 0000000..ac2dcb0
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_metadata_rbac.py
@@ -0,0 +1,87 @@
+#    Copyright 2017 AT&T Corporation.
+#    All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.compute import rbac_base
+
+
+class ServerMetadataRbacTest(rbac_base.BaseV2ComputeRbacTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(ServerMetadataRbacTest, cls).resource_setup()
+        cls.server = cls.create_test_server(metadata={}, wait_until='ACTIVE')
+        cls.meta = {'default_key': 'value1', 'delete_key': 'value2'}
+
+    def setUp(self):
+        super(ServerMetadataRbacTest, self).setUp()
+        self.servers_client.set_server_metadata(self.server['id'], self.meta)[
+            'metadata']
+
+    @decorators.idempotent_id('b07bbc27-58e2-4581-869d-ad228cec5d9a')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:server-metadata:index")
+    def test_list_server_metadata(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.list_server_metadata(self.server['id'])['metadata']
+
+    @decorators.idempotent_id('6e76748b-2417-4fa2-b41a-c0cc4bff356b')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:server-metadata:update_all")
+    def test_set_server_metadata(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.set_server_metadata(self.server['id'], {})[
+            'metadata']
+
+    @decorators.idempotent_id('1060bac4-fe16-4a77-be64-d8e482a06eab')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:server-metadata:create")
+    def test_update_server_metadata(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.update_server_metadata(self.server['id'], {})[
+            'metadata']
+
+    @decorators.idempotent_id('93dd8323-d3fa-48d1-8bd6-91c1b62fc341')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:server-metadata:show")
+    def test_show_server_metadata_item(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.show_server_metadata_item(
+            self.server['id'], 'default_key')['meta']
+
+    @decorators.idempotent_id('79511293-4bd7-447d-ba7e-634d0f4da70c')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:server-metadata:update")
+    def test_set_server_metadata_item(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.set_server_metadata_item(
+            self.server['id'], 'default_key', {'default_key': 'value2'})[
+            'meta']
+
+    @decorators.idempotent_id('feec5064-678d-40bc-a88f-c856e18d1e31')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:server-metadata:delete")
+    def test_delete_server_metadata_item(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.delete_server_metadata_item(
+            self.server['id'], 'delete_key')
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_migrations_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_migrations_rbac.py
new file mode 100644
index 0000000..842d8b1
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_migrations_rbac.py
@@ -0,0 +1,97 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import testtools
+
+from tempest.common import waiters
+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 as base
+
+CONF = config.CONF
+
+
+class MigrateServerV225RbacTest(base.BaseV2ComputeRbacTest):
+    min_microversion = '2.25'
+    max_microversion = 'latest'
+    block_migration = 'auto'
+
+    @classmethod
+    def skip_checks(cls):
+        super(MigrateServerV225RbacTest, cls).skip_checks()
+        if CONF.compute.min_compute_nodes < 2:
+            raise cls.skipException(
+                "Less than 2 compute nodes, skipping migration tests.")
+
+    @classmethod
+    def setup_clients(cls):
+        super(MigrateServerV225RbacTest, cls).setup_clients()
+        cls.admin_servers_client = cls.os_admin.servers_client
+
+    def _get_server_details(self, server_id):
+        body = self.servers_client.show_server(server_id)['server']
+        return body
+
+    def _get_host_for_server(self, server_id):
+        return self._get_server_details(server_id)['OS-EXT-SRV-ATTR:host']
+
+    def _get_host_other_than(self, host):
+        for target_host in self._get_compute_hostnames():
+            if host != target_host:
+                return target_host
+
+    def _get_compute_hostnames(self):
+        body = self.hosts_client.list_hosts()['hosts']
+        return [
+            host_record['host_name']
+            for host_record in body
+            if host_record['service'] == 'compute'
+        ]
+
+    @test.attr(type='slow')
+    @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration,
+                          'Cold migration not available.')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-migrate-server:migrate")
+    @decorators.idempotent_id('c6f1607c-9fed-4c00-807e-9ba675b98b1b')
+    def test_cold_migration(self):
+        server = self.create_test_server(wait_until="ACTIVE")
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.migrate_server(server['id'])
+        waiters.wait_for_server_status(self.admin_servers_client,
+                                       server['id'], 'VERIFY_RESIZE')
+
+    @test.attr(type='slow')
+    @testtools.skipUnless(CONF.compute_feature_enabled.live_migration,
+                          'Live migration feature is not enabled.')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-migrate-server:migrate_live")
+    @decorators.idempotent_id('33520834-72c8-4edb-a189-a2e0fc9eb0d3')
+    def test_migration_live(self):
+        server_id = self.create_test_server(wait_until="ACTIVE",
+                                            volume_backed=False)['id']
+        actual_host = self._get_host_for_server(server_id)
+        target_host = self._get_host_other_than(actual_host)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.live_migrate_server(
+            server_id, host=target_host, block_migration=self.block_migration)
+        waiters.wait_for_server_status(self.admin_servers_client,
+                                       server_id, "ACTIVE")
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
new file mode 100644
index 0000000..afa8c02
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py
@@ -0,0 +1,396 @@
+#    Copyright 2017 AT&T Corporation.
+#    All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import testtools
+
+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_rule_validation
+from patrole_tempest_plugin.tests.api.compute import rbac_base
+
+CONF = config.CONF
+
+
+class MiscPolicyActionsRbacTest(rbac_base.BaseV2ComputeRbacTest):
+    """Test multiple policy actions that require a server to be created.
+
+    Minimize the number of servers that need to be created across classes
+    by consolidating test cases related to different policy "families" into
+    one class. This reduces the risk of running into `BuildErrorException`
+    errors being raised due to too many servers being created simultaneously
+    especially when higher concurrency is used.
+
+    Only applies to:
+      * policy "families" that require server creation
+      * small policy "families" -- i.e. containing one to three policies
+    """
+
+    @classmethod
+    def resource_setup(cls):
+        super(MiscPolicyActionsRbacTest, cls).resource_setup()
+        cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id']
+
+    def setUp(self):
+        super(MiscPolicyActionsRbacTest, self).setUp()
+        try:
+            waiters.wait_for_server_status(self.servers_client,
+                                           self.server_id, 'ACTIVE')
+        except lib_exc.NotFound:
+            # If the server was found to be deleted by a previous test,
+            # a new one is built
+            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)
+
+    @test.requires_ext(extension='os-admin-actions', service='compute')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-admin-actions:reset_state")
+    @decorators.idempotent_id('ae84dd0b-f364-462e-b565-3457f9c019ef')
+    def test_reset_server_state(self):
+        """Test reset server state, part of os-admin-actions."""
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.reset_state(self.server_id, state='error')
+        self.addCleanup(self.servers_client.reset_state, self.server_id,
+                        state='active')
+
+    @test.requires_ext(extension='os-admin-actions', service='compute')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-admin-actions:inject_network_info")
+    @decorators.idempotent_id('ce48c340-51c1-4cff-9b6e-0cc5ef008630')
+    def test_inject_network_info(self):
+        """Test inject network info, part of os-admin-actions."""
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.inject_network_info(self.server_id)
+
+    @test.attr(type=['slow'])
+    @test.requires_ext(extension='os-admin-actions', service='compute')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-admin-actions:reset_network")
+    @decorators.idempotent_id('2911a242-15c4-4fcb-80d5-80a8930661b0')
+    def test_reset_network(self):
+        """Test reset network, part of os-admin-actions."""
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.reset_network(self.server_id)
+
+    @testtools.skipUnless(CONF.compute_feature_enabled.change_password,
+                          'Change password not available.')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-admin-password")
+    @decorators.idempotent_id('908a7d59-3a66-441c-94cf-38e57ed14956')
+    def test_change_server_password(self):
+        """Test change admin password, part of os-admin-password."""
+        original_password = self.servers_client.show_password(self.server_id)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.change_password(
+            self.server_id, adminPass=data_utils.rand_password())
+        self.addCleanup(self.servers_client.change_password, self.server_id,
+                        adminPass=original_password)
+        waiters.wait_for_server_status(
+            self.os_admin.servers_client, self.server_id, 'ACTIVE')
+
+    @test.requires_ext(extension='os-deferred-delete', service='compute')
+    @decorators.idempotent_id('189bfed4-1e6d-475c-bb8c-d57e60895391')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-deferred-delete")
+    def test_force_delete_server(self):
+        """Test force delete server, part of os-deferred-delete."""
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        # Force-deleting a server enforces os-deferred-delete.
+        self.servers_client.force_delete_server(self.server_id)
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-lock-server:lock")
+    @decorators.idempotent_id('b81e10fb-1864-498f-8c1d-5175c6fec5fb')
+    def test_lock_server(self):
+        """Test lock server, part of os-lock-server."""
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.lock_server(self.server_id)
+        self.addCleanup(self.servers_client.unlock_server, self.server_id)
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-lock-server:unlock")
+    @decorators.idempotent_id('d50ef8e8-4bce-11e7-b114-b2f933d5fe66')
+    def test_unlock_server(self):
+        """Test unlock server, part of os-lock-server."""
+        self.servers_client.lock_server(self.server_id)
+        self.addCleanup(self.servers_client.unlock_server, self.server_id)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.unlock_server(self.server_id)
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-lock-server:unlock:unlock_override")
+    @decorators.idempotent_id('40dfeef9-73ee-48a9-be19-a219875de457')
+    def test_unlock_server_override(self):
+        """Test force unlock server, part of os-lock-server.
+
+        In order to trigger the unlock:unlock_override policy instead
+        of the unlock policy, the server must be locked by a different
+        user than the one who is attempting to unlock it.
+        """
+        self.os_admin.servers_client.lock_server(self.server_id)
+        self.addCleanup(self.servers_client.unlock_server, self.server_id)
+
+        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')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-rescue")
+    @decorators.idempotent_id('fbbb2afc-ed0e-4552-887d-ac00fb5d436e')
+    def test_rescue_server(self):
+        """Test rescue server, part of os-rescue."""
+        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')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-server-diagnostics")
+    @decorators.idempotent_id('5dabfcc4-bedb-417b-8247-b3ee7c5c0f3e')
+    def test_show_server_diagnostics(self):
+        """Test show server diagnostics, part of os-server-diagnostics."""
+        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')
+    @decorators.idempotent_id('aaf43f78-c178-4581-ac18-14afd3f1f6ba')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-server-password")
+    def test_delete_server_password(self):
+        """Test delete server password, part of os-server-password."""
+        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')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-server-password")
+    @decorators.idempotent_id('f677971a-7d20-493c-977f-6ff0a74b5b2c')
+    def test_get_server_password(self):
+        """Test show server password, part of os-server-password."""
+        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')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-server-usage")
+    @decorators.idempotent_id('f0437ead-b9fb-462a-9f3d-ce53fac9d57a')
+    def test_show_server_usage(self):
+        """Test show server usage, part of os-server-usage.
+
+        TODO(felipemonteiro): Once multiple policy testing is supported, this
+        test can be combined with the generic test for showing a server.
+        """
+        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')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-simple-tenant-usage:list")
+    @decorators.idempotent_id('2aef094f-0452-4df6-a66a-0ec22a92b16e')
+    def test_list_simple_tenant_usages(self):
+        """Test list tenant usages, part of os-simple-tenant-usage."""
+        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')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-simple-tenant-usage:show")
+    @decorators.idempotent_id('fe7eacda-15c4-4bf7-93ef-1091c4546a9d')
+    def test_show_simple_tenant_usage(self):
+        """Test show tenant usage, part of os-simple-tenant-usage."""
+        tenant_id = self.auth_provider.credentials.tenant_id
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.tenant_usages_client.show_tenant_usage(tenant_id=tenant_id)
+
+    @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
+                          "Suspend compute feature is not available.")
+    @decorators.idempotent_id('b775930f-237c-431c-83ae-d33ed1b9700b')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-suspend-server:suspend")
+    def test_suspend_server(self):
+        """Test suspend server, part of os-suspend-server."""
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.suspend_server(self.server_id)
+        self.addCleanup(self.servers_client.resume_server, self.server_id)
+        waiters.wait_for_server_status(
+            self.os_admin.servers_client, self.server_id, 'SUSPENDED')
+
+    @testtools.skipUnless(CONF.compute_feature_enabled.suspend,
+                          "Suspend compute feature is not available.")
+    @decorators.idempotent_id('4d90bd02-11f8-45b1-a8a1-534665584675')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-suspend-server:resume")
+    def test_resume_server(self):
+        """Test resume server, part of os-suspend-server."""
+        self.servers_client.suspend_server(self.server_id)
+        waiters.wait_for_server_status(self.servers_client, self.server_id,
+                                       'SUSPENDED')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.resume_server(self.server_id)
+        waiters.wait_for_server_status(
+            self.os_admin.servers_client, self.server_id, 'ACTIVE')
+
+
+class MiscPolicyActionsNetworkRbacTest(rbac_base.BaseV2ComputeRbacTest):
+    """Test multiple policy actions that require a server to be created.
+
+    Only applies to:
+      * policy "families" that require server creation
+      * small policy "families" -- i.e. containing one to three policies
+      * tests that require network resources
+    """
+
+    @classmethod
+    def skip_checks(cls):
+        super(MiscPolicyActionsNetworkRbacTest, cls).skip_checks()
+        # All tests below require Neutron availability.
+        if not CONF.service_available.neutron:
+            raise cls.skipException(
+                '%s skipped as Neutron is required' % cls.__name__)
+
+    @classmethod
+    def setup_credentials(cls):
+        cls.prepare_instance_network()
+        super(MiscPolicyActionsNetworkRbacTest, cls).setup_credentials()
+
+    @classmethod
+    def resource_setup(cls):
+        super(MiscPolicyActionsNetworkRbacTest, cls).resource_setup()
+        cls.server = cls.create_test_server(wait_until='ACTIVE')
+
+    def _attach_interface_to_server(self):
+        interface = self.interfaces_client.create_interface(
+            self.server['id'])['interfaceAttachment']
+        waiters.wait_for_interface_status(
+            self.os_admin.interfaces_client, self.server['id'],
+            interface['port_id'], 'ACTIVE')
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.interfaces_client.delete_interface,
+            self.server['id'], interface['port_id'])
+        return interface
+
+    @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
+                          "Interface attachment is not available.")
+    @test.requires_ext(extension='os-attach-interfaces', service='compute')
+    @decorators.idempotent_id('ddf53cb6-4a0a-4e5a-91e3-6c32aaa3b9b6')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-attach-interfaces")
+    def test_list_interfaces(self):
+        """Test list interfaces, part of os-attach-interfaces."""
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.interfaces_client.list_interfaces(
+            self.server['id'])['interfaceAttachments']
+
+    @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
+                          "Interface attachment is not available.")
+    @test.requires_ext(extension='os-attach-interfaces', service='compute')
+    @decorators.idempotent_id('d2d3a24d-4738-4bce-a287-36d664746cde')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-attach-interfaces:create")
+    def test_create_interface(self):
+        """Test create interface, part of os-attach-interfaces."""
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._attach_interface_to_server()
+
+    @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
+                          "Interface attachment is not available.")
+    @test.requires_ext(extension='os-attach-interfaces', service='compute')
+    @decorators.idempotent_id('55b05692-ed44-4608-a84c-cd4219c82799')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-attach-interfaces:delete")
+    def test_delete_interface(self):
+        """Test delete interface, part of os-attach-interfaces."""
+        interface = self._attach_interface_to_server()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.interfaces_client.delete_interface(self.server['id'],
+                                                interface['port_id'])
+
+    @decorators.idempotent_id('6886d360-0d86-4760-b1a3-882d81fbebcc')
+    @test.requires_ext(extension='os-ips', service='compute')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:ips:index")
+    def test_list_addresses(self):
+        """Test list server addresses, part of ips policy family."""
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        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')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:ips:show")
+    def test_list_addresses_by_network(self):
+        """Test list server addresses by network, part of ips policy family."""
+        addresses = self.servers_client.list_addresses(self.server['id'])[
+            'addresses']
+        address = next(iter(addresses))
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.list_addresses_by_network(
+            self.server['id'], address)[address]
+
+    @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach,
+                          "Interface attachment is not available.")
+    @test.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')
+    def test_add_fixed_ip(self):
+        """Test add fixed ip to server network, part of os-multinic."""
+        interfaces = (self.interfaces_client.list_interfaces(self.server['id'])
+                      ['interfaceAttachments'])
+        if interfaces:
+            network_id = interfaces[0]['net_id']
+        else:
+            network_id = self.interfaces_client.create_interface(
+                self.server['id'])['interfaceAttachment']['net_id']
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.add_fixed_ip(self.server['id'],
+                                         networkId=network_id)
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_password_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_password_rbac.py
deleted file mode 100644
index 45b42bf..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_server_password_rbac.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#    Copyright 2017 AT&T Corporation.
-#    All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest.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
-
-
-class ServerPasswordRbacTest(rbac_base.BaseV2ComputeRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(ServerPasswordRbacTest, cls).setup_clients()
-        cls.client = cls.servers_client
-
-    @classmethod
-    def skip_checks(cls):
-        super(ServerPasswordRbacTest, cls).skip_checks()
-        if not test.is_extension_enabled('os-server-password', 'compute'):
-            msg = "%s skipped as os-server-password extension not enabled." \
-                  % cls.__name__
-            raise cls.skipException(msg)
-
-    @classmethod
-    def resource_setup(cls):
-        super(ServerPasswordRbacTest, cls).resource_setup()
-        cls.server = cls.create_test_server()
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ServerPasswordRbacTest, self).tearDown()
-
-    @decorators.idempotent_id('43ad7995-2f12-41cd-8ef1-bae9ffc36818')
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-server-password")
-    def test_delete_password(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.delete_password(self.server['id'])
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py
new file mode 100644
index 0000000..c6ac1c5
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py
@@ -0,0 +1,251 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from oslo_log import log
+
+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
+from patrole_tempest_plugin.tests.api.compute import rbac_base as base
+
+CONF = config.CONF
+LOG = log.getLogger(__name__)
+
+
+class ComputeServersRbacTest(base.BaseV2ComputeRbacTest):
+
+    @classmethod
+    def setup_clients(cls):
+        super(ComputeServersRbacTest, cls).setup_clients()
+        cls.networks_client = cls.os_primary.networks_client
+        cls.ports_client = cls.os_primary.ports_client
+        cls.subnets_client = cls.os_primary.subnets_client
+
+    @classmethod
+    def resource_setup(cls):
+        super(ComputeServersRbacTest, cls).resource_setup()
+        cls.server = cls.create_test_server(wait_until='ACTIVE')
+        # 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 _create_network_resources(self):
+        # Create network
+        network_name = data_utils.rand_name(
+            self.__class__.__name__ + '-network')
+
+        network = self.networks_client.create_network(
+            name=network_name, port_security_enabled=True)['network']
+        self.addCleanup(self.networks_client.delete_network, network['id'])
+
+        # Create subnet for the network
+        subnet_name = data_utils.rand_name(self.__class__.__name__ + '-subnet')
+        subnet = self.subnets_client.create_subnet(
+            name=subnet_name,
+            network_id=network['id'],
+            cidr=CONF.network.project_network_cidr,
+            ip_version=4)['subnet']
+        self.addCleanup(self.subnets_client.delete_subnet, subnet['id'])
+
+        return network
+
+    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
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:create")
+    @decorators.idempotent_id('4f34c73a-6ddc-4677-976f-71320fa855bd')
+    def test_create_server(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.create_test_server(wait_until='ACTIVE')
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:create:forced_host")
+    @decorators.idempotent_id('0ae3c401-52ab-41bc-ab96-c598a65d9ae5')
+    def test_create_server_forced_host(self):
+        # Retrieve 'nova' zone host information from availiability_zone_list
+        zones = self.availability_zone_client.list_availability_zones(
+            detail=True)['availabilityZoneInfo']
+        hosts = [zone['hosts'] for zone in zones if zone['zoneName'] == 'nova']
+
+        # We just need any host out of the hosts list to build the
+        # availability_zone attribute. So, picking the first one is fine.
+        # The first key of the dictionary specifies the host name.
+        host = list(hosts[0].keys())[0]
+        availability_zone = 'nova:' + host
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.create_test_server(wait_until='ACTIVE',
+                                availability_zone=availability_zone)
+
+    @test.services('volume')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:create:attach_volume")
+    @decorators.idempotent_id('eeddac5e-15aa-454f-838d-db608aae4dd8')
+    def test_create_server_attach_volume(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._create_test_server_with_volume(self.volume_id)
+
+    @test.services('network')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:create:attach_network")
+    @decorators.idempotent_id('b44cd4ff-50a4-42ce-ada3-724e213cd540')
+    def test_create_server_attach_network(self):
+        network = self._create_network_resources()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        network_id = {'uuid': network['id']}
+        server = self.create_test_server(wait_until='ACTIVE',
+                                         networks=[network_id])
+
+        self.addCleanup(waiters.wait_for_server_termination,
+                        self.servers_client, server['id'])
+        self.addCleanup(self.servers_client.delete_server, server['id'])
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:delete")
+    @decorators.idempotent_id('062e3440-e873-4b41-9317-bf6d8be50c12')
+    def test_delete_server(self):
+        server = self.create_test_server(wait_until='ACTIVE')
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.delete_server(server['id'])
+        waiters.wait_for_server_termination(
+            self.os_admin.servers_client, server['id'])
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:servers:update")
+    @decorators.idempotent_id('077b17cb-5621-43b9-8adf-5725f0d7a863')
+    def test_update_server(self):
+        new_name = data_utils.rand_name(self.__class__.__name__ + '-server')
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        try:
+            self.servers_client.update_server(self.server['id'], name=new_name)
+            waiters.wait_for_server_status(self.os_admin.servers_client,
+                                           self.server['id'], 'ACTIVE')
+        except exceptions.ServerFault as e:
+            # Some other policy may have blocked it.
+            LOG.info("ServerFault exception caught. Some other policy "
+                     "blocked updating of server")
+            raise rbac_exceptions.RbacActionFailed(e)
+
+
+class SecurtiyGroupsRbacTest(base.BaseV2ComputeRbacTest):
+    """Tests non-deprecated security group policies. Requires network service.
+
+    This class tests non-deprecated policies for adding and removing a security
+    group to and from a server.
+    """
+
+    @classmethod
+    def setup_credentials(cls):
+        # A network and a subnet will be created for these tests.
+        cls.set_network_resources(network=True, subnet=True)
+        super(SecurtiyGroupsRbacTest, cls).setup_credentials()
+
+    @classmethod
+    def skip_checks(cls):
+        super(SecurtiyGroupsRbacTest, cls).skip_checks()
+        # All the tests below require the network service.
+        if not test.get_service_list()['network']:
+            raise cls.skipException(
+                'Skipped because the network service is not available')
+
+    @classmethod
+    def resource_setup(cls):
+        super(SecurtiyGroupsRbacTest, cls).resource_setup()
+        cls.server = cls.create_test_server(wait_until='ACTIVE')
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-security-groups")
+    @decorators.idempotent_id('3db159c6-a467-469f-9a25-574197885520')
+    def test_list_security_groups_by_server(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.list_security_groups_by_server(self.server['id'])
+
+    @test.attr(type=["slow"])
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-security-groups")
+    @decorators.idempotent_id('ea1ca73f-2d1d-43cb-9a46-900d7927b357')
+    def test_create_security_group_for_server(self):
+        sg_name = self.create_security_group()['name']
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.add_security_group(self.server['id'], name=sg_name)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.servers_client.remove_security_group,
+                        self.server['id'], name=sg_name)
+
+    @test.attr(type=["slow"])
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-security-groups")
+    @decorators.idempotent_id('0ad2e856-e2d3-4ac5-a620-f93d0d3d2626')
+    def test_remove_security_group_from_server(self):
+        sg_name = self.create_security_group()['name']
+
+        self.servers_client.add_security_group(self.server['id'], name=sg_name)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.servers_client.remove_security_group,
+                        self.server['id'], name=sg_name)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.remove_security_group(
+            self.server['id'], name=sg_name)
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 14f0638..d3576d6 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
@@ -34,23 +34,14 @@
             raise cls.skipException(msg)
 
     @classmethod
-    def setup_clients(cls):
-        super(ServerTagsRbacTest, cls).setup_clients()
-        cls.client = cls.servers_client
-
-    @classmethod
     def resource_setup(cls):
         super(ServerTagsRbacTest, cls).resource_setup()
         cls.server = cls.create_test_server(wait_until='ACTIVE')
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ServerTagsRbacTest, self).tearDown()
-
     def _add_tag_to_server(self):
-        tag_name = data_utils.rand_name('tag')
-        self.client.update_tag(self.server['id'], tag_name)
-        self.addCleanup(self.client.delete_all_tags, self.server['id'])
+        tag_name = data_utils.rand_name(self.__class__.__name__ + '-tag')
+        self.servers_client.update_tag(self.server['id'], tag_name)
+        self.addCleanup(self.servers_client.delete_all_tags, self.server['id'])
         return tag_name
 
     @decorators.idempotent_id('99e73dd3-adec-4044-b46c-84bdded35d09')
@@ -58,8 +49,8 @@
         service="nova",
         rule="os_compute_api:os-server-tags:index")
     def test_list_tags(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_tags(self.server['id'])['tags']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.list_tags(self.server['id'])['tags']
 
     @decorators.idempotent_id('9297c99e-94eb-429f-93cf-9b1838e33622')
     @rbac_rule_validation.action(
@@ -67,15 +58,15 @@
         rule="os_compute_api:os-server-tags:show")
     def test_check_tag_existence(self):
         tag_name = self._add_tag_to_server()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.check_tag_existence(self.server['id'], tag_name)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.check_tag_existence(self.server['id'], tag_name)
 
     @decorators.idempotent_id('0d84ee94-d3ca-4635-8edf-b7f67ab8e4a3')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-server-tags:update")
     def test_update_tag(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._add_tag_to_server()
 
     @decorators.idempotent_id('115c2694-00aa-41ee-99f6-9eab4040c182')
@@ -84,22 +75,23 @@
         rule="os_compute_api:os-server-tags:delete")
     def test_delete_tag(self):
         tag_name = self._add_tag_to_server()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.delete_tag(self.server['id'], tag_name)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.delete_tag(self.server['id'], tag_name)
 
     @decorators.idempotent_id('a8e19b87-6580-4bc8-9933-e62561ff667d')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-server-tags:update_all")
     def test_update_all_tags(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        new_tag_name = data_utils.rand_name('tag')
-        self.client.update_all_tags(self.server['id'], [new_tag_name])['tags']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        new_tag_name = data_utils.rand_name(self.__class__.__name__ + '-tag')
+        self.servers_client.update_all_tags(self.server['id'],
+                                            [new_tag_name])['tags']
 
     @decorators.idempotent_id('89d51936-e333-42f9-a045-132a4865ba1a')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-server-tags:delete_all")
     def test_delete_all_tags(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.delete_all_tags(self.server['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.delete_all_tags(self.server['id'])
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_usage_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_usage_rbac.py
deleted file mode 100644
index ea1341b..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_server_usage_rbac.py
+++ /dev/null
@@ -1,54 +0,0 @@
-#    Copyright 2017 AT&T Corporation.
-#    All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest import config
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.compute import rbac_base
-
-CONF = config.CONF
-
-
-class ServerUsageRbacTest(rbac_base.BaseV2ComputeRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(ServerUsageRbacTest, cls).setup_clients()
-        cls.client = cls.servers_client
-
-    @classmethod
-    def skip_checks(cls):
-        super(ServerUsageRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
-
-    @classmethod
-    def resource_setup(cls):
-        super(ServerUsageRbacTest, cls).resource_setup()
-        cls.server = cls.create_test_server(wait_until='ACTIVE')
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ServerUsageRbacTest, self).tearDown()
-
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-server-usage")
-    @decorators.idempotent_id('f0437ead-b9fb-462a-9f3d-ce53fac9d57a')
-    def test_show_server_diagnostics(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_server(self.server['id'])
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_virtual_interfaces_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_virtual_interfaces_rbac.py
new file mode 100644
index 0000000..1480444
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_virtual_interfaces_rbac.py
@@ -0,0 +1,41 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest import config
+from tempest.lib import decorators
+from tempest.lib import exceptions
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.compute import rbac_base as base
+
+CONF = config.CONF
+
+
+class ServerVirtualInterfacesRbacTest(base.BaseV2ComputeRbacTest):
+
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-virtual-interfaces")
+    @decorators.idempotent_id('fc719ae3-0f73-4689-8378-1b841f0f2818')
+    def test_list_virtual_interfaces(self):
+        server = self.create_test_server(wait_until='ACTIVE')
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+
+        if CONF.service_available.neutron:
+            msg = "Listing virtual interfaces is not supported by this cloud."
+            with self.assertRaisesRegex(exceptions.BadRequest, msg):
+                self.servers_client.list_virtual_interfaces(server['id'])
+        else:
+            self.servers_client.list_virtual_interfaces(server['id'])
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_volume_attachments_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_volume_attachments_rbac.py
index 21137a7..98dbee5 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_server_volume_attachments_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_volume_attachments_rbac.py
@@ -30,8 +30,7 @@
     @classmethod
     def setup_clients(cls):
         super(ServerVolumeAttachmentRbacTest, cls).setup_clients()
-        cls.client = cls.servers_client
-        cls.volumes_client = cls.os.volumes_client
+        cls.volumes_client = cls.os_primary.volumes_client
 
     @classmethod
     def skip_checks(cls):
@@ -46,17 +45,13 @@
         cls.server = cls.create_test_server(wait_until='ACTIVE')
         cls.volume = cls.create_volume()
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ServerVolumeAttachmentRbacTest, self).tearDown()
-
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-volumes-attachments:index")
     @decorators.idempotent_id('529b668b-6edb-41d5-8886-d7dbd0614678')
     def test_list_volume_attachments(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_volume_attachments(self.server['id'])[
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.list_volume_attachments(self.server['id'])[
             'volumeAttachments']
 
     @rbac_rule_validation.action(
@@ -64,7 +59,7 @@
         rule="os_compute_api:os-volumes-attachments:create")
     @decorators.idempotent_id('21c2c3fd-fbe8-41b1-8ef8-115ec47d54c1')
     def test_create_volume_attachment(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.attach_volume(self.server, self.volume)
 
     @rbac_rule_validation.action(
@@ -73,8 +68,8 @@
     @decorators.idempotent_id('997df9c2-6e54-47b6-ab74-e4fdb500f385')
     def test_show_volume_attachment(self):
         attachment = self.attach_volume(self.server, self.volume)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_volume_attachment(
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.show_volume_attachment(
             self.server['id'], attachment['id'])
 
     @test.attr(type='slow')
@@ -85,8 +80,8 @@
     def test_update_volume_attachment(self):
         attachment = self.attach_volume(self.server, self.volume)
         alt_volume = self.create_volume()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.update_attached_volume(
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.update_attached_volume(
             self.server['id'], attachment['id'], volumeId=alt_volume['id'])
         waiters.wait_for_volume_resource_status(self.volumes_client,
                                                 alt_volume['id'], 'in-use')
@@ -107,7 +102,7 @@
     @decorators.idempotent_id('12b03e90-d087-46af-9c4d-507d021c4984')
     def test_delete_volume_attachment(self):
         self.attach_volume(self.server, self.volume)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.detach_volume(self.server['id'], self.volume['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.servers_client.detach_volume(self.server['id'], self.volume['id'])
         waiters.wait_for_volume_resource_status(self.volumes_client,
                                                 self.volume['id'], 'available')
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 379b177..94d094c 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_services_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_services_rbac.py
@@ -13,37 +13,26 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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
 
-CONF = config.CONF
 
-
-class ServicesAdminRbacTest(rbac_base.BaseV2ComputeAdminRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(ServicesAdminRbacTest, cls).setup_clients()
-        cls.client = cls.services_client
+class ServicesRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
     @classmethod
     def skip_checks(cls):
-        super(ServicesAdminRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
+        super(ServicesRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('os-services', 'compute'):
             raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ServicesAdminRbacTest, self).tearDown()
+                '%s skipped as os-services not enabled' % cls.__name__)
 
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-services")
     @decorators.idempotent_id('7472261b-9c6d-453a-bcb3-aecaa29ad281')
     def test_list_services(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_services()['services']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.services_client.list_services()['services']
diff --git a/patrole_tempest_plugin/tests/api/compute/test_simple_tenant_usage_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_simple_tenant_usage_rbac.py
deleted file mode 100644
index f042f00..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_simple_tenant_usage_rbac.py
+++ /dev/null
@@ -1,61 +0,0 @@
-#    Copyright 2017 AT&T Corporation.
-#    All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest import config
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.compute import rbac_base
-
-CONF = config.CONF
-
-
-class SimpleTenantUsageRbacTest(rbac_base.BaseV2ComputeRbacTest):
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(SimpleTenantUsageRbacTest, self).tearDown()
-
-    @classmethod
-    def setup_clients(cls):
-        super(SimpleTenantUsageRbacTest, cls).setup_clients()
-        cls.client = cls.os.tenant_usages_client
-
-    @classmethod
-    def skip_checks(cls):
-        super(SimpleTenantUsageRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.api_extensions:
-            raise cls.skipException(
-                '%s skipped as no compute extensions enabled' % cls.__name__)
-
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-simple-tenant-usage:list")
-    @decorators.idempotent_id('2aef094f-0452-4df6-a66a-0ec22a92b16e')
-    def test_simple_tenant_usage_list(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_tenant_usages()
-
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-simple-tenant-usage:show")
-    @decorators.idempotent_id('fe7eacda-15c4-4bf7-93ef-1091c4546a9d')
-    def test_simple_tenant_usage_show(self):
-        # A server must be created in order for usage activity to exist; else
-        # the validation method in the API call throws an error.
-        self.create_test_server(wait_until='ACTIVE')['id']
-        tenant_id = self.auth_provider.credentials.tenant_id
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_tenant_usage(tenant_id=tenant_id)
diff --git a/patrole_tempest_plugin/tests/api/compute/test_suspend_server_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_suspend_server_rbac.py
deleted file mode 100644
index 3cb5ac1..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_suspend_server_rbac.py
+++ /dev/null
@@ -1,81 +0,0 @@
-#    Copyright 2017 AT&T Corporation.
-#    All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest.common import waiters
-from tempest import config
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.compute import rbac_base
-
-CONF = config.CONF
-
-
-class SuspendServerRbacTest(rbac_base.BaseV2ComputeRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(SuspendServerRbacTest, cls).setup_clients()
-        cls.client = cls.servers_client
-
-    @classmethod
-    def skip_checks(cls):
-        super(SuspendServerRbacTest, cls).skip_checks()
-        if not CONF.compute_feature_enabled.suspend:
-            msg = "%s skipped as suspend compute feature is not available." \
-                  % cls.__name__
-            raise cls.skipException(msg)
-
-    @classmethod
-    def resource_setup(cls):
-        super(SuspendServerRbacTest, cls).resource_setup()
-        cls.server = cls.create_test_server(wait_until='ACTIVE')
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-
-        # Guarantee that the server is active during each test run.
-        vm_state = self.client.show_server(self.server['id'])['server'][
-            'OS-EXT-STS:vm_state'].upper()
-        if vm_state != 'ACTIVE':
-            self.client.resume_server(self.server['id'])
-            waiters.wait_for_server_status(self.client, self.server['id'],
-                                           'ACTIVE')
-
-        super(SuspendServerRbacTest, self).tearDown()
-
-    @decorators.idempotent_id('b775930f-237c-431c-83ae-d33ed1b9700b')
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-suspend-server:suspend")
-    def test_suspend_server(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.suspend_server(self.server['id'])
-        waiters.wait_for_server_status(self.client, self.server['id'],
-                                       'SUSPENDED')
-
-    @decorators.idempotent_id('4d90bd02-11f8-45b1-a8a1-534665584675')
-    @rbac_rule_validation.action(
-        service="nova",
-        rule="os_compute_api:os-suspend-server:resume")
-    def test_resume_server(self):
-        self.client.suspend_server(self.server['id'])
-        waiters.wait_for_server_status(self.client, self.server['id'],
-                                       'SUSPENDED')
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.resume_server(self.server['id'])
-        waiters.wait_for_server_status(self.client,
-                                       self.server['id'],
-                                       'ACTIVE')
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 b5ecd55..9313943 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
@@ -26,15 +26,16 @@
 
 class TenantNetworksRbacTest(rbac_base.BaseV2ComputeRbacTest):
 
-    # Tests will fail with a 404 starting from microversion 2.36, according to:
-    # https://developer.openstack.org/api-ref/
-    # compute/?expanded=list-project-networks-detail
+    # Tests will fail with a 404 starting from microversion 2.36.
+    # See the following link for details:
+    # https://developer.openstack.org/api-ref/compute/#project-networks-os-tenant-networks-deprecated
+    min_microversion = '2.10'
     max_microversion = '2.35'
 
     @classmethod
     def setup_clients(cls):
         super(TenantNetworksRbacTest, cls).setup_clients()
-        cls.client = cls.os.tenant_networks_client
+        cls.tenant_networks_client = cls.os_primary.tenant_networks_client
 
     @classmethod
     def skip_checks(cls):
@@ -51,14 +52,10 @@
         cls.set_network_resources(network=True)
         super(TenantNetworksRbacTest, cls).setup_credentials()
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(TenantNetworksRbacTest, self).tearDown()
-
     @decorators.idempotent_id('42b39ba1-14aa-4799-9518-34367d0da67a')
     @rbac_rule_validation.action(
         service="nova",
         rule="os_compute_api:os-tenant-networks")
     def test_list_show_tenant_networks(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_tenant_networks()['networks']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.tenant_networks_client.list_tenant_networks()['networks']
diff --git a/patrole_tempest_plugin/tests/api/compute/test_volume_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_volume_rbac.py
new file mode 100644
index 0000000..b775872
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_volume_rbac.py
@@ -0,0 +1,131 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.common import waiters
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.compute import rbac_base
+
+from tempest import config
+
+CONF = config.CONF
+
+
+class VolumeRbacTest(rbac_base.BaseV2ComputeRbacTest):
+    """RBAC tests for the Nova Volume client."""
+
+    # These tests will fail with a 404 starting from microversion 2.36.
+    # For more information, see:
+    # https://developer.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated
+    max_microversion = '2.35'
+
+    @classmethod
+    def resource_setup(cls):
+        super(VolumeRbacTest, cls).resource_setup()
+        cls.volume = cls.create_volume()
+
+    def _delete_snapshot(self, snapshot_id):
+        waiters.wait_for_volume_resource_status(
+            self.os_admin.snapshots_extensions_client, snapshot_id,
+            'available')
+        self.snapshots_extensions_client.delete_snapshot(snapshot_id)
+        self.os_admin.snapshots_extensions_client.wait_for_resource_deletion(
+            snapshot_id)
+
+    @decorators.idempotent_id('2402013e-a624-43e3-9518-44a5d1dbb32d')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-volumes")
+    def test_create_volume(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        volume = self.volumes_extensions_client.create_volume(
+            size=CONF.volume.volume_size)['volume']
+        # Use the admin volumes client to wait, because waiting involves
+        # calling show API action which enforces a different policy.
+        waiters.wait_for_volume_resource_status(self.os_admin.volumes_client,
+                                                volume['id'], 'available')
+        # Use non-deprecated volumes_client for deletion.
+        self.addCleanup(self.volumes_client.delete_volume, volume['id'])
+
+    @decorators.idempotent_id('69b3888c-dff2-47b0-9fa4-0672619c9054')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-volumes")
+    def test_list_volumes(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_extensions_client.list_volumes()
+
+    @decorators.idempotent_id('4ba0a820-040f-488b-86bb-be2e920ea12c')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-volumes")
+    def test_show_volume(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_extensions_client.show_volume(self.volume['id'])
+
+    @decorators.idempotent_id('6e7870f2-1bb2-4b58-96f8-6782071ef327')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-volumes")
+    def test_delete_volume(self):
+        volume = self.create_volume()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_extensions_client.delete_volume(volume['id'])
+
+    @decorators.idempotent_id('0c3eaa4f-69d6-4a13-9dda-19585f36b1c1')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-volumes")
+    def test_create_snapshot(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        snapshot = self.snapshots_extensions_client.create_snapshot(
+            self.volume['id'])['snapshot']
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self._delete_snapshot, snapshot['id'])
+
+    @decorators.idempotent_id('e944e816-416c-11e7-a919-92ebcb67fe33')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-volumes")
+    def test_list_snapshots(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.snapshots_extensions_client.list_snapshots()
+
+    @decorators.idempotent_id('19c2e6bd-585b-472f-a8d7-71ea9299c655')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-volumes")
+    def test_show_snapshot(self):
+        snapshot = self.snapshots_extensions_client.create_snapshot(
+            self.volume['id'])['snapshot']
+        self.addCleanup(self._delete_snapshot, snapshot['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.snapshots_extensions_client.show_snapshot(snapshot['id'])
+
+    @decorators.idempotent_id('f4f5635c-416c-11e7-a919-92ebcb67fe33')
+    @rbac_rule_validation.action(
+        service="nova",
+        rule="os_compute_api:os-volumes")
+    def test_delete_snapshot(self):
+        snapshot = self.snapshots_extensions_client.create_snapshot(
+            self.volume['id'])['snapshot']
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self._delete_snapshot, snapshot['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._delete_snapshot(snapshot['id'])
diff --git a/patrole_tempest_plugin/tests/api/identity/rbac_base.py b/patrole_tempest_plugin/tests/api/identity/rbac_base.py
new file mode 100644
index 0000000..1ed081e
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/identity/rbac_base.py
@@ -0,0 +1,377 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from oslo_log import log as logging
+
+from tempest.api.identity import base
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+
+from patrole_tempest_plugin import rbac_utils
+
+CONF = config.CONF
+LOG = logging.getLogger(__name__)
+
+
+class BaseIdentityRbacTest(base.BaseIdentityTest):
+
+    credentials = ['admin', 'primary']
+
+    @classmethod
+    def skip_checks(cls):
+        super(BaseIdentityRbacTest, cls).skip_checks()
+        if not CONF.rbac.enable_rbac:
+            raise cls.skipException(
+                "%s skipped as RBAC testing not enabled" % cls.__name__)
+
+    @classmethod
+    def setup_clients(cls):
+        super(BaseIdentityRbacTest, cls).setup_clients()
+        cls.auth_provider = cls.os_primary.auth_provider
+        cls.rbac_utils = rbac_utils.RbacUtils(cls)
+
+    @classmethod
+    def resource_setup(cls):
+        super(BaseIdentityRbacTest, 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(BaseIdentityRbacTest, cls).resource_cleanup()
+
+    @classmethod
+    def setup_test_endpoint(cls, service=None):
+        """Creates a service and an endpoint for test."""
+        interface = 'public'
+        url = data_utils.rand_url()
+        region_name = data_utils.rand_name(
+            cls.__name__ + '-region')
+        # Endpoint creation requires a service
+        if service is None:
+            service = cls.setup_test_service()
+        params = {
+            'service_id': service['id'],
+            'region': region_name,
+            'interface': interface
+        }
+        if cls.identity_version == 'v2':
+            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)
+
+        return endpoint
+
+    @classmethod
+    def setup_test_role(cls):
+        """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)
+
+        return role
+
+    @classmethod
+    def setup_test_service(cls):
+        """Setup a test service."""
+        name = data_utils.rand_name(cls.__name__ + '-service')
+        serv_type = data_utils.rand_name('type')
+        desc = data_utils.rand_name(cls.__name__ + '-description')
+
+        service = cls.services_client.create_service(
+            name=name,
+            type=serv_type,
+            description=desc)
+
+        if cls.identity_version == 'v2':
+            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)
+
+        return service
+
+    @classmethod
+    def setup_test_user(cls, password=None, **kwargs):
+        """Set up a test user."""
+        username = data_utils.rand_name(cls.__name__ + '-test_user')
+        email = username + '@testmail.tm'
+
+        user = cls.users_client.create_user(
+            name=username,
+            email=email,
+            password=password,
+            **kwargs)['user']
+        cls.users.append(user)
+
+        return user
+
+
+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
+    testing is only provided for the admin API. Instead of policy enforcement,
+    these APIs execute ``self.assert_admin(request)``, which checks that the
+    request object has ``context_is_admin``. For more details, see the
+    implementation of ``assert_admin`` in ``keystone.common.wsgi``.
+    """
+
+    identity_version = 'v2'
+
+    @classmethod
+    def skip_checks(cls):
+        super(BaseIdentityV2AdminRbacTest, cls).skip_checks()
+        if not CONF.identity_feature_enabled.api_v2_admin:
+            raise cls.skipException('Identity v2 admin not available')
+
+    @classmethod
+    def setup_clients(cls):
+        super(BaseIdentityV2AdminRbacTest, cls).setup_clients()
+        cls.client = cls.os_primary.identity_client
+        cls.endpoints_client = cls.os_primary.endpoints_client
+        cls.roles_client = cls.os_primary.roles_client
+        cls.services_client = cls.os_primary.identity_services_client
+        cls.tenants_client = cls.os_primary.tenants_client
+        cls.token_client = cls.os_primary.token_client
+        cls.users_client = cls.os_primary.users_client
+
+    @classmethod
+    def resource_setup(cls):
+        super(BaseIdentityV2AdminRbacTest, cls).resource_setup()
+        cls.tenants = []
+        cls.tokens = []
+
+    @classmethod
+    def resource_cleanup(cls):
+        for tenant in cls.tenants:
+            test_utils.call_and_ignore_notfound_exc(
+                cls.tenants_client.delete_tenant, tenant['id'])
+
+        for token in cls.tokens:
+            test_utils.call_and_ignore_notfound_exc(
+                cls.client.delete_token, token)
+
+        super(BaseIdentityV2AdminRbacTest, cls).resource_cleanup()
+
+    @classmethod
+    def setup_test_tenant(cls):
+        """Set up a test tenant."""
+        name = data_utils.rand_name(cls.__name__ + '-test_tenant')
+        tenant = cls.tenants_client.create_tenant(
+            name=name,
+            description=data_utils.rand_name(
+                cls.__name__ + '-desc'))['tenant']
+        cls.tenants.append(tenant)
+        return tenant
+
+    @classmethod
+    def setup_test_token(cls, user_name, password, tenant_name):
+        """Set up a test token."""
+        token = cls.token_client.auth(user_name, password,
+                                      tenant_name)['token']
+        token_id = token['id']
+        cls.tokens.append(token_id)
+        return token_id
+
+
+class BaseIdentityV3RbacTest(BaseIdentityRbacTest):
+
+    identity_version = 'v3'
+
+    @classmethod
+    def setup_clients(cls):
+        super(BaseIdentityV3RbacTest, cls).setup_clients()
+        cls.creds_client = cls.os_primary.credentials_client
+        cls.consumers_client = cls.os_primary.oauth_consumers_client
+        cls.domains_client = cls.os_primary.domains_client
+        cls.domain_config_client = cls.os_primary.domain_config_client
+        cls.endpoints_client = cls.os_primary.endpoints_v3_client
+        cls.endpoint_filter_client = cls.os_primary.endpoint_filter_client
+        cls.endpoint_groups_client = cls.os_primary.endpoint_groups_client
+        cls.groups_client = cls.os_primary.groups_client
+        cls.identity_client = cls.os_primary.identity_v3_client
+        cls.projects_client = cls.os_primary.projects_client
+        cls.policies_client = cls.os_primary.policies_client
+        cls.regions_client = cls.os_primary.regions_client
+        cls.role_assignments_client = cls.os_primary.role_assignments_client
+        cls.roles_client = cls.os_primary.roles_v3_client
+        cls.services_client = cls.os_primary.identity_services_v3_client
+        cls.trusts_client = cls.os_primary.trusts_client
+        cls.users_client = cls.os_primary.users_v3_client
+        cls.oauth_token_client = cls.os_primary.oauth_token_client
+
+    @classmethod
+    def resource_setup(cls):
+        super(BaseIdentityV3RbacTest, cls).resource_setup()
+        cls.credentials = []
+        cls.domains = []
+        cls.groups = []
+        cls.policies = []
+        cls.projects = []
+        cls.regions = []
+        cls.trusts = []
+
+    @classmethod
+    def resource_cleanup(cls):
+        for credential in cls.credentials:
+            test_utils.call_and_ignore_notfound_exc(
+                cls.creds_client.delete_credential, credential['id'])
+
+        # Delete each domain at the end of the test, but each domain must be
+        # disabled first.
+        for domain in cls.domains:
+            test_utils.call_and_ignore_notfound_exc(
+                cls.domains_client.update_domain, domain['id'], enabled=False)
+            test_utils.call_and_ignore_notfound_exc(
+                cls.domains_client.delete_domain, domain['id'])
+
+        for group in cls.groups:
+            test_utils.call_and_ignore_notfound_exc(
+                cls.groups_client.delete_group, group['id'])
+
+        for policy in cls.policies:
+            test_utils.call_and_ignore_notfound_exc(
+                cls.policies_client.delete_policy, policy['id'])
+
+        for project in cls.projects:
+            test_utils.call_and_ignore_notfound_exc(
+                cls.projects_client.delete_project, project['id'])
+
+        for region in cls.regions:
+            test_utils.call_and_ignore_notfound_exc(
+                cls.regions_client.delete_region, region['id'])
+
+        for trust in cls.trusts:
+            test_utils.call_and_ignore_notfound_exc(
+                cls.trusts_client.delete_trust, trust['id'])
+
+        super(BaseIdentityV3RbacTest, cls).resource_cleanup()
+
+    @classmethod
+    def setup_test_credential(cls, user=None):
+        """Creates a credential for test."""
+        keys = [data_utils.rand_uuid_hex(),
+                data_utils.rand_uuid_hex()]
+        blob = '{"access": "%s", "secret": "%s"}' % (keys[0], keys[1])
+
+        credential = cls.creds_client.create_credential(
+            user_id=user['id'],
+            project_id=user['project_id'],
+            blob=blob,
+            type='ec2')['credential']
+        cls.credentials.append(credential)
+
+        return credential
+
+    @classmethod
+    def setup_test_domain(cls):
+        """Set up a test domain."""
+        domain = cls.domains_client.create_domain(
+            name=data_utils.rand_name(cls.__name__ + '-test_domain'),
+            description=data_utils.rand_name(
+                cls.__name__ + '-desc'))['domain']
+        cls.domains.append(domain)
+
+        return domain
+
+    @classmethod
+    def setup_test_group(cls):
+        """Creates a group for test."""
+        name = data_utils.rand_name(cls.__name__ + '-test_group')
+        group = cls.groups_client.create_group(name=name)['group']
+        cls.groups.append(group)
+
+        return group
+
+    @classmethod
+    def setup_test_policy(cls):
+        """Creates a policy for test."""
+        blob = data_utils.rand_name(cls.__name__ + '-test_blob')
+        policy_type = data_utils.rand_name(
+            cls.__name__ + '-policy_type')
+
+        policy = cls.policies_client.create_policy(
+            blob=blob,
+            policy=policy_type,
+            type="application/json")['policy']
+        cls.policies.append(policy)
+
+        return policy
+
+    @classmethod
+    def setup_test_project(cls):
+        """Set up a test project."""
+        project = cls.projects_client.create_project(
+            name=data_utils.rand_name(
+                cls.__name__ + '-testproject'),
+            description=data_utils.rand_name(
+                cls.__name__ + '-desc'))['project']
+        cls.projects.append(project)
+
+        return project
+
+    @classmethod
+    def setup_test_region(cls):
+        """Creates a region for test."""
+        description = data_utils.rand_name(
+            cls.__name__ + '-test_region_desc')
+
+        region = cls.regions_client.create_region(
+            description=description)['region']
+        cls.regions.append(region)
+
+        return region
+
+    @classmethod
+    def setup_test_trust(cls, trustee_user_id, trustor_user_id, **kwargs):
+        """Setup a test trust."""
+        trust = cls.trusts_client.create_trust(
+            trustee_user_id=trustee_user_id, trustor_user_id=trustor_user_id,
+            impersonation=False, **kwargs)['trust']
+        cls.trusts.append(trust)
+
+        return trust
diff --git a/patrole_tempest_plugin/tests/api/identity/v2/rbac_base.py b/patrole_tempest_plugin/tests/api/identity/v2/rbac_base.py
deleted file mode 100644
index 77afed5..0000000
--- a/patrole_tempest_plugin/tests/api/identity/v2/rbac_base.py
+++ /dev/null
@@ -1,83 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest.api.identity import base
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib.common.utils import test_utils
-
-from patrole_tempest_plugin.rbac_utils import rbac_utils
-
-CONF = config.CONF
-
-
-class BaseIdentityV2AdminRbacTest(base.BaseIdentityV2AdminTest):
-
-    credentials = ['admin', 'primary']
-
-    @classmethod
-    def skip_checks(cls):
-        super(BaseIdentityV2AdminRbacTest, cls).skip_checks()
-        if not CONF.rbac.rbac_flag:
-            raise cls.skipException(
-                "%s skipped as RBAC Flag not enabled" % cls.__name__)
-
-    @classmethod
-    def setup_clients(cls):
-        super(BaseIdentityV2AdminRbacTest, cls).setup_clients()
-        cls.auth_provider = cls.os.auth_provider
-        cls.admin_client = cls.os_adm.identity_client
-        cls.tenants_client = cls.os.tenants_client
-        cls.users_client = cls.os.users_client
-        cls.rbac_utils = rbac_utils()
-
-    def _create_service(self):
-        name = data_utils.rand_name('service')
-        type = data_utils.rand_name('type')
-
-        self.service = self.services_client.create_service(
-            name=name, type=type,
-            description="description")
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.services_client.delete_service,
-                        self.service['OS-KSADM:service']['id'])
-        return self.service
-
-    def _create_user(self, name=None, email=None, password=None, **kwargs):
-        """Set up a test user."""
-        if name is None:
-            name = data_utils.rand_name('test_user')
-        if email is None:
-            email = name + '@testmail.tm'
-        if password is None:
-            password = data_utils.rand_password()
-        user = self.users_client.create_user(
-            name=name, email=email, password=password, **kwargs)['user']
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.users_client.delete_user,
-                        user['id'])
-        return user
-
-    def _create_tenant(self):
-        """Set up a test tenant."""
-        name = data_utils.rand_name('test_tenant')
-        tenant = self.projects_client.create_tenant(
-            name=name,
-            description=data_utils.rand_name('desc'))['tenant']
-        # Delete the tenant at the end of the test
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.tenants_client.delete_tenant,
-                        tenant['id'])
-        return tenant
diff --git a/patrole_tempest_plugin/tests/api/identity/v2/test_endpoints_rbac.py b/patrole_tempest_plugin/tests/api/identity/v2/test_endpoints_rbac.py
index 060da39..0a9feef 100644
--- a/patrole_tempest_plugin/tests/api/identity/v2/test_endpoints_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v2/test_endpoints_rbac.py
@@ -13,86 +13,50 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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 patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.identity.v2 import rbac_base
-
-CONF = config.CONF
+from patrole_tempest_plugin.tests.api.identity import rbac_base
 
 
 class IdentityEndpointsV2AdminRbacTest(rbac_base.BaseIdentityV2AdminRbacTest):
 
-    @classmethod
-    def setup_clients(cls):
-        super(IdentityEndpointsV2AdminRbacTest, cls).setup_clients()
-        cls.endpoints_client = cls.os.endpoints_client
-
-    @classmethod
-    def resource_setup(cls):
-        super(IdentityEndpointsV2AdminRbacTest, cls).resource_setup()
-        cls.region = data_utils.rand_name('region')
-        cls.public_url = data_utils.rand_url()
-        cls.admin_url = data_utils.rand_url()
-        cls.internal_url = data_utils.rand_url()
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(IdentityEndpointsV2AdminRbacTest, self).tearDown()
-
-    def _create_endpoint(self):
-        self._create_service()
-        endpoint = self.endpoints_client.create_endpoint(
-            service_id=self.service['OS-KSADM:service']['id'],
-            region=self.region,
-            publicurl=self.public_url,
-            adminurl=self.admin_url,
-            internalurl=self.internal_url
-        )
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.endpoints_client.delete_endpoint,
-                        endpoint['endpoint']['id'])
-        return endpoint
-
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:create_endpoint")
+                                 admin_only=True)
     @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd124')
     def test_create_endpoint(self):
 
         """Create Endpoint Test
 
-        RBAC test for Identity Admin 2.0 create_endpoint
+        RBAC test for Identity v2 create_endpoint
         """
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_endpoint()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_endpoint()
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:delete_endpoint")
+                                 admin_only=True)
     @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd125')
     def test_delete_endpoint(self):
 
         """Delete Endpoint Test
 
-        RBAC test for Identity Admin 2.0 delete_endpoint
+        RBAC test for Identity v2 delete_endpoint
         """
 
-        endpoint = self._create_endpoint()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.endpoints_client.delete_endpoint(endpoint['endpoint']['id'])
+        endpoint = self.setup_test_endpoint()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.endpoints_client.delete_endpoint(endpoint['id'])
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:list_endpoints")
+                                 admin_only=True)
     @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd126')
     def test_list_endpoints(self):
 
         """List Endpoints Test
 
-        RBAC test for Identity Admin 2.0 list_endpoint
+        RBAC test for Identity v2 list_endpoint
         """
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.endpoints_client.list_endpoints()
diff --git a/patrole_tempest_plugin/tests/api/identity/v2/test_projects_rbac.py b/patrole_tempest_plugin/tests/api/identity/v2/test_projects_rbac.py
index 9bfb241..784045a 100644
--- a/patrole_tempest_plugin/tests/api/identity/v2/test_projects_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v2/test_projects_rbac.py
@@ -16,20 +16,17 @@
 from tempest import config
 from tempest.lib import decorators
 
+from patrole_tempest_plugin import rbac_exceptions
 from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.identity.v2 import rbac_base
+from patrole_tempest_plugin.tests.api.identity import rbac_base
 
 CONF = config.CONF
 
 
 class IdentityProjectV2AdminRbacTest(rbac_base.BaseIdentityV2AdminRbacTest):
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(IdentityProjectV2AdminRbacTest, self).tearDown()
-
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:create_project")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-b348-080044d0d904')
     def test_create_project(self):
 
@@ -38,11 +35,11 @@
         RBAC test for Identity 2.0 create_tenant
         """
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_tenant()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_tenant()
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:update_project")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-b348-080044d0d905')
     def test_update_project(self):
 
@@ -50,14 +47,14 @@
 
         RBAC test for Identity 2.0 update_tenant
         """
-        tenant = self._create_tenant()
+        tenant = self.setup_test_tenant()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.tenants_client.update_tenant(tenant['id'],
                                           description="Changed description")
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:delete_project")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-b348-080044d0d906')
     def test_delete_project(self):
 
@@ -65,13 +62,13 @@
 
         RBAC test for Identity 2.0 delete_tenant
         """
-        tenant = self._create_tenant()
+        tenant = self.setup_test_tenant()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.tenants_client.delete_tenant(tenant['id'])
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:get_project")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-b348-080044d0d907')
     def test_get_project(self):
 
@@ -80,33 +77,54 @@
         RBAC test for Identity 2.0 show_tenant
         """
 
-        tenant = self._create_tenant()
+        tenant = self.setup_test_tenant()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.tenants_client.show_tenant(tenant['id'])
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:list_projects")
-    @decorators.idempotent_id('0f148510-63bf-11e6-b348-080044d0d908')
-    def test_get_all_projects(self):
-
-        """List All Projects Test
-
-        RBAC test for Identity 2.0 list_tenants
-        """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.tenants_client.list_tenants()
-
-    @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:list_user_projects")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-b348-080044d0d909')
-    def test_list_users_for_tenant(self):
+    def test_list_project_users(self):
 
         """Get Users of a Project Test
 
         RBAC test for Identity 2.0 list_tenant_users
         """
-        tenant = self._create_tenant()
+        tenant = self.setup_test_tenant()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.tenants_client.list_tenant_users(tenant['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 admin_only=True)
+    @decorators.idempotent_id('0f148510-63bf-11e6-b348-080044d0d908')
+    def test_list_all_projects(self):
+
+        """List All Projects Test
+
+        RBAC test for Identity 2.0 list_tenants (admin endpoint)
+
+        There are two separate APIs for listing tenants in the Keystone
+        v2 API: one for admin and one for non-admin. The ``os_admin`` client
+        calls the admin endpoint and the ``os_primary`` client calls the
+        non-admin endpoint. To ensure that the admin endpoint only returns
+        admin-scoped tenants, raise ``RbacActionFailed`` exception otherwise.
+        """
+        tenants_client = self.os_admin.tenants_client if \
+            self.rbac_utils.is_admin else self.os_primary.tenants_client
+        admin_tenant_id = self.os_admin.auth_provider.credentials.project_id
+        non_admin_tenant_id = self.auth_provider.credentials.project_id
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        tenants = tenants_client.list_tenants()['tenants']
+
+        tenant_ids = [t['id'] for t in tenants]
+        if admin_tenant_id not in tenant_ids:
+            raise rbac_exceptions.RbacActionFailed(
+                "The admin tenant id was not returned by the call to "
+                "``list_tenants``.")
+        if non_admin_tenant_id in tenant_ids:
+            raise rbac_exceptions.RbacActionFailed(
+                "The non-admin tenant id was returned by the call to "
+                "``list_tenants``.")
diff --git a/patrole_tempest_plugin/tests/api/identity/v2/test_roles_rbac.py b/patrole_tempest_plugin/tests/api/identity/v2/test_roles_rbac.py
index 4cd3d43..9d80469 100644
--- a/patrole_tempest_plugin/tests/api/identity/v2/test_roles_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v2/test_roles_rbac.py
@@ -13,39 +13,24 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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 patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.identity.v2 import rbac_base
-
-CONF = config.CONF
+from patrole_tempest_plugin.tests.api.identity import rbac_base
 
 
-class IdentityRoleV2AdminRbacTest(rbac_base.BaseIdentityV2AdminRbacTest):
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(IdentityRoleV2AdminRbacTest, self).tearDown()
+class IdentityRolesV2AdminRbacTest(rbac_base.BaseIdentityV2AdminRbacTest):
 
     @classmethod
     def setup_clients(cls):
-        super(IdentityRoleV2AdminRbacTest, cls).setup_clients()
-        cls.roles_client = cls.os.roles_client
-
-    def _create_role(self):
-        role = self.roles_client.create_role(
-            name=data_utils.rand_name('test_role'))['role']
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.roles_client.delete_role, role['id'])
-        return role
+        super(IdentityRolesV2AdminRbacTest, cls).setup_clients()
+        cls.roles_client = cls.os_primary.roles_client
 
     def _create_tenant_user_and_role(self):
-        tenant = self._create_tenant()
-        user = self._create_user(tenantid=tenant['id'])
-        role = self._create_role()
+        tenant = self.setup_test_tenant()
+        user = self.setup_test_user(tenantid=tenant['id'])
+        role = self.setup_test_role()
         return tenant, user, role
 
     def _create_role_on_project(self, tenant, user, role):
@@ -57,99 +42,99 @@
             tenant['id'], user['id'], role['id'])
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:create_role")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-8674-080044d0d904')
     def test_create_role(self):
 
         """Create Role Test
 
-        RBAC test for Identity Admin 2.0 role-create
+        RBAC test for Identity v2 role-create
         """
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_role()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_role()
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:delete_role")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-8674-080044d0d905')
     def test_delete_role(self):
 
         """Delete Role Test
 
-        RBAC test for Identity Admin 2.0 role-delete
+        RBAC test for Identity v2 delete_role
         """
-        role = self._create_role()
+        role = self.setup_test_role()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.roles_client.delete_role(role['id'])
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:get_role")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-8674-080044d0d906')
     def test_show_role(self):
 
         """Get Role Test
 
-        RBAC test for Identity Admin 2.0
+        RBAC test for Identity v2 show_role
         """
-        role = self._create_role()
+        role = self.setup_test_role()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.roles_client.show_role(role['id'])
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:list_roles")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-8674-080044d0d907')
     def test_list_roles(self):
 
         """List Roles Test
 
-        RBAC test for Identity Admin 2.0 role-list
+        RBAC test for Identity v2 list_roles
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.roles_client.list_roles()
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:add_role_to_user")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-8674-080044d0d908')
     def test_create_role_on_project(self):
 
         """Assign User Role Test
 
-        RBAC test for Identity Admin 2.0 create_user_role_on_project
+        RBAC test for Identity v2 create_user_role_on_project
         """
         tenant, user, role = self._create_tenant_user_and_role()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_role_on_project(tenant, user, role)
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:remove_role_from_user")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-8674-080044d0d909')
     def test_delete_role_from_user_on_project(self):
 
         """Remove User Roles Test
 
-        RBAC test for Identity Admin 2.0 delete_role_from_user_on_project
+        RBAC test for Identity v2 delete_role_from_user_on_project
         """
         tenant, user, role = self._create_tenant_user_and_role()
         self._create_role_on_project(tenant, user, role)
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.roles_client.delete_role_from_user_on_project(
             tenant['id'], user['id'], role['id'])
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:get_user_roles")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-8674-080044d0d90a')
     def test_list_user_roles_on_project(self):
 
         """List User Roles Test
 
-        RBAC test for Identity Admin 2.0 list_user_roles_on_project
+        RBAC test for Identity v2 list_user_roles_on_project
         """
-        tenant = self._create_tenant()
-        user = self._create_user(tenantid=tenant['id'])
+        tenant = self.setup_test_tenant()
+        user = self.setup_test_user(tenantid=tenant['id'])
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.roles_client.list_user_roles_on_project(
             tenant['id'], user['id'])
diff --git a/patrole_tempest_plugin/tests/api/identity/v2/test_services_rbac.py b/patrole_tempest_plugin/tests/api/identity/v2/test_services_rbac.py
index cb0ee90..8419ec9 100644
--- a/patrole_tempest_plugin/tests/api/identity/v2/test_services_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v2/test_services_rbac.py
@@ -13,70 +13,58 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest import config
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.identity.v2 import rbac_base
-
-CONF = config.CONF
+from patrole_tempest_plugin.tests.api.identity import rbac_base
 
 
 class IdentityServicesV2AdminRbacTest(rbac_base.BaseIdentityV2AdminRbacTest):
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(IdentityServicesV2AdminRbacTest, self).tearDown()
-
-    @classmethod
-    def setup_clients(cls):
-        super(IdentityServicesV2AdminRbacTest, cls).setup_clients()
-        cls.services_client = cls.os.identity_services_client
-
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:create_service")
+                                 admin_only=True)
     @decorators.idempotent_id('370050f6-d271-4fb4-abc5-4de1d6dfbad2')
     def test_create_service(self):
         """Create Service Test
 
-        RBAC test for Identity Admin 2.0 create_service
+        RBAC test for Identity v2 create_service
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_service()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_service()
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:delete_service")
+                                 admin_only=True)
     @decorators.idempotent_id('f6c64fc3-6a1f-423e-af91-e411add3a384')
     def test_delete_service(self):
         """Delete Service Test
 
-        RBAC test for Identity Admin 2.0 delete_service
+        RBAC test for Identity v2 delete_service
         """
-        service_id = self._create_service()['OS-KSADM:service']['id']
+        service_id = self.setup_test_service()['id']
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.services_client.delete_service(service_id)
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:get_service")
+                                 admin_only=True)
     @decorators.idempotent_id('504d62bb-97d7-445e-9d6d-b1945a7c9e08')
     def test_show_service(self):
         """Show Service Test
 
-        RBAC test for Identity Admin 2.0 show_service
+        RBAC test for Identity v2 show_service
         """
-        service_id = self._create_service()['OS-KSADM:service']['id']
+        service_id = self.setup_test_service()['id']
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.services_client.show_service(service_id)
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:list_services")
+                                 admin_only=True)
     @decorators.idempotent_id('d7dc461d-51ad-48e0-9cd2-33add1b88de9')
     def test_list_services(self):
         """List all the services
 
-        RBAC test for Identity Admin 2.0 list_service
+        RBAC test for Identity v2 list_service
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.services_client.list_services()
diff --git a/patrole_tempest_plugin/tests/api/identity/v2/test_tokens_rbac.py b/patrole_tempest_plugin/tests/api/identity/v2/test_tokens_rbac.py
new file mode 100644
index 0000000..25150dd
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/identity/v2/test_tokens_rbac.py
@@ -0,0 +1,72 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.identity import rbac_base
+
+
+class IdentityTokenV2RbacTest(rbac_base.BaseIdentityV2AdminRbacTest):
+
+    def _create_token(self):
+
+        user_name = self.client.auth_provider.credentials.username
+        tenant_name = self.client.auth_provider.credentials.tenant_name
+        password = self.client.auth_provider.credentials.password
+        token_id = self.setup_test_token(user_name, password,
+                                         tenant_name)
+        return token_id
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:validate_token")
+    @decorators.idempotent_id('71471202-4c4e-4a3d-9d41-57eb621bf3bb')
+    def test_validate_token(self):
+
+        """Validate token (get-token)
+
+        RBAC test for Identity v2 get token validation
+        """
+        token_id = self._create_token()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.client.show_token(token_id)
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:revoke_token")
+    @decorators.idempotent_id('77338f66-0713-4f20-b11c-b0d750618276')
+    def test_revoke_token(self):
+
+        """Revoke token (delete-token)
+
+        RBAC test for Identity v2 delete token
+        """
+        token_id = self._create_token()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.client.delete_token(token_id)
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:validate_token_head")
+    @decorators.idempotent_id('71471202-4c4e-4a3d-9d41-57eb621bf3ba')
+    def test_check_token_existence(self):
+
+        """Validate Token head
+
+        RBAC test for Identity v2 token head validation
+        """
+        token_id = self._create_token()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.client.check_token_existence(token_id)
diff --git a/patrole_tempest_plugin/tests/api/identity/v2/test_users_rbac.py b/patrole_tempest_plugin/tests/api/identity/v2/test_users_rbac.py
index 568733b..dfe6e71 100644
--- a/patrole_tempest_plugin/tests/api/identity/v2/test_users_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v2/test_users_rbac.py
@@ -17,71 +17,67 @@
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.identity.v2 import rbac_base
+from patrole_tempest_plugin.tests.api.identity import rbac_base
 
 
-class IdentityUserV2AdminRbacTest(rbac_base.BaseIdentityV2AdminRbacTest):
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(IdentityUserV2AdminRbacTest, self).tearDown()
+class IdentityUsersV2AdminRbacTest(rbac_base.BaseIdentityV2AdminRbacTest):
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:create_user")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-1342-080044d0d904')
     def test_create_user(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_user()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_user()
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:update_user")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-1342-080044d0d905')
     def test_update_user(self):
-        user = self._create_user()
+        user = self.setup_test_user()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.users_client.update_user(user['id'], email="changedUser@xyz.com")
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:set_user_enabled")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-1342-080044d0d9a1')
     def test_update_user_enabled(self):
-        user = self._create_user()
+        user = self.setup_test_user()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.users_client.update_user_enabled(user['id'], enabled=True)
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:delete_user")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-1342-080044d0d906')
     def test_delete_user(self):
-        user = self._create_user()
+        user = self.setup_test_user()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.users_client.delete_user(user['id'])
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:get_users")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-1342-080044d0d907')
     def test_list_users(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.users_client.list_users()
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:get_user")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-1342-080044d0d908')
     def test_show_user(self):
-        user = self._create_user()
+        user = self.setup_test_user()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.users_client.show_user(user['id'])
 
     @rbac_rule_validation.action(service="keystone",
-                                 rule="identity:change_password")
+                                 admin_only=True)
     @decorators.idempotent_id('0f148510-63bf-11e6-1342-080044d0d909')
     def test_update_user_password(self):
-        user = self._create_user()
+        user = self.setup_test_user()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.users_client.update_user_password(
             user['id'], password=data_utils.rand_password())
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/rbac_base.py b/patrole_tempest_plugin/tests/api/identity/v3/rbac_base.py
deleted file mode 100644
index bad53b3..0000000
--- a/patrole_tempest_plugin/tests/api/identity/v3/rbac_base.py
+++ /dev/null
@@ -1,80 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest.api.identity import base
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib.common.utils import test_utils
-
-from patrole_tempest_plugin.rbac_utils import rbac_utils
-
-CONF = config.CONF
-
-
-class BaseIdentityV3RbacAdminTest(base.BaseIdentityV3AdminTest):
-
-    credentials = ['admin', 'primary']
-
-    @classmethod
-    def skip_checks(cls):
-        super(BaseIdentityV3RbacAdminTest, cls).skip_checks()
-        if not CONF.rbac.rbac_flag:
-            raise cls.skipException(
-                "%s skipped as RBAC Flag not enabled" % cls.__name__)
-
-    @classmethod
-    def setup_clients(cls):
-        super(BaseIdentityV3RbacAdminTest, cls).setup_clients()
-        cls.auth_provider = cls.os.auth_provider
-        cls.admin_client = cls.os_adm.identity_v3_client
-        cls.creds_client = cls.os.credentials_client
-        cls.services_client = cls.os.identity_services_v3_client
-        cls.endpoints_client = cls.os.endpoints_v3_client
-        cls.groups_client = cls.os.groups_client
-        cls.policies_client = cls.os.policies_client
-        cls.rbac_utils = rbac_utils()
-
-    def _create_service(self):
-        """Creates a service for test."""
-        name = data_utils.rand_name('service')
-        serv_type = data_utils.rand_name('type')
-        desc = data_utils.rand_name('description')
-        service = self.services_client \
-                      .create_service(name=name,
-                                      type=serv_type,
-                                      description=desc)['service']
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.services_client.delete_service, service['id'])
-        return service
-
-    def _setup_test_project(self):
-        """Set up a test project."""
-        project = self.projects_client.create_project(
-            name=data_utils.rand_name('test_project'),
-            description=data_utils.rand_name('desc'))['project']
-        # Delete the project at the end of the test
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.projects_client.delete_project, project['id'])
-        return project
-
-    def _create_test_user(self, **kwargs):
-        if kwargs['password'] is None:
-            user_password = data_utils.rand_password()
-            kwargs['password'] = user_password
-        user = self.users_client.create_user(**kwargs)['user']
-        # Delete the user at the end of the test
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.users_client.delete_user, user['id'])
-        return user
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_auth_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_auth_rbac.py
new file mode 100644
index 0000000..bc096ce
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_auth_rbac.py
@@ -0,0 +1,38 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.identity import rbac_base
+
+
+class IdentityAuthV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
+    """Tests the APIs that enforce the auth policy actions.
+
+    For more information about the auth policy actions, see:
+    https://github.com/openstack/keystone/blob/master/keystone/common/policies/auth.py
+    """
+
+    # TODO(felipemonteiro): Add tests for identity:get_auth_catalog and
+    # identity:get_auth_domains once the endpoints are implemented in Tempest's
+    # identity v3 client.
+
+    @decorators.idempotent_id('2a9fbf7f-6feb-4161-ae4b-faf7d6421b1a')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_auth_projects")
+    def test_list_auth_projects(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.identity_client.list_auth_projects()['projects']
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_credentials_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_credentials_rbac.py
index a563784..995c3b0 100644
--- a/patrole_tempest_plugin/tests/api/identity/v3/test_credentials_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_credentials_rbac.py
@@ -14,106 +14,66 @@
 #    under the License.
 
 from tempest.lib.common.utils import data_utils
-from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.identity.v3 import rbac_base
+from patrole_tempest_plugin.tests.api.identity import rbac_base
 
 
-class IdentityCredentialsV3AdminRbacTest(
-        rbac_base.BaseIdentityV3RbacAdminTest):
+class IdentityCredentialsV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
 
-    def tearDown(self):
-        """Reverts user back to admin for cleanup."""
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(IdentityCredentialsV3AdminRbacTest, self).tearDown()
-
-    def _create_credential(self):
-        """Creates a user, project, and credential for test."""
-        user = self.setup_test_user()
-        user_id = user['id']
-        project_id = user['project_id']
-        keys = [data_utils.rand_name('Access'),
-                data_utils.rand_name('Secret')]
-        blob = "{\"access\": \"%s\", \"secret\": \"%s\"}" % (
-            keys[0], keys[1])
-        credential = self.creds_client \
-                         .create_credential(user_id=user_id,
-                                            project_id=project_id,
-                                            blob=blob,
-                                            type='ec2')['credential']
-
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.creds_client.delete_credential, credential['id'])
-
-        return (project_id, credential)
+    def _create_user_project_and_credential(self):
+        project = self.setup_test_project()
+        user = self.setup_test_user(project_id=project['id'])
+        credential = self.setup_test_credential(user=user)
+        return credential
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:create_credential")
     @decorators.idempotent_id('c1ab6d34-c59f-4ae1-bae9-bb3c1089b48e')
     def test_create_credential(self):
-        """Create a Credential.
-
-        RBAC test for Keystone: identity:create_credential
-        """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_credential()
+        project = self.setup_test_project()
+        user = self.setup_test_user(project_id=project['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_credential(user=user)
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:update_credential")
     @decorators.idempotent_id('cfb05ce3-bffb-496e-a3c2-9515d730da63')
     def test_update_credential(self):
-        """Update a Credential.
+        credential = self._create_user_project_and_credential()
+        new_keys = [data_utils.rand_uuid_hex(),
+                    data_utils.rand_uuid_hex()]
 
-        RBAC test for Keystone: identity:update_credential
-        """
-        project_id, credential = self._create_credential()
-        # Update blob keys
-        new_keys = [data_utils.rand_name('NewAccess'),
-                    data_utils.rand_name('NewSecret')]
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.creds_client \
-            .update_credential(credential['id'],
-                               credential=credential,
-                               access_key=new_keys[0],
-                               secret_key=new_keys[1],
-                               project_id=project_id)['credential']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.creds_client.update_credential(
+            credential['id'],
+            credential=credential,
+            access_key=new_keys[0],
+            secret_key=new_keys[1],
+            project_id=credential['project_id'])['credential']
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:delete_credential")
     @decorators.idempotent_id('87ab42af-8d41-401b-90df-21e72919fcde')
     def test_delete_credential(self):
-        """Delete a Credential.
+        credential = self._create_user_project_and_credential()
 
-        RBAC test for Keystone: identity:delete_credential
-        """
-        _, credential = self._create_credential()
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.creds_client.delete_credential(credential['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:get_credential")
     @decorators.idempotent_id('1b6eeae6-f1e8-4cdf-8903-1c002b1fc271')
     def test_show_credential(self):
-        """Show/Get a Credential.
+        credential = self._create_user_project_and_credential()
 
-        RBAC test for Keystone: identity:get_credential
-        """
-        _, credential = self._create_credential()
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.creds_client.show_credential(credential['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:list_credentials")
     @decorators.idempotent_id('3de303e2-12a7-4811-805a-f18906472038')
     def test_list_credentials(self):
-        """List all Credentials.
-
-        RBAC test for Keystone: identity:list_credentials
-        """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.creds_client.list_credentials()
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_domain_configuration_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_domain_configuration_rbac.py
new file mode 100644
index 0000000..31f962a
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_domain_configuration_rbac.py
@@ -0,0 +1,165 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.identity import rbac_base
+
+CONF = config.CONF
+
+
+class DomainConfigurationV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
+    """RBAC tests for domain configuration client.
+
+    Provides coverage for the following policy actions:
+    https://github.com/openstack/keystone/blob/master/keystone/common/policies/domain_config.py
+    """
+
+    identity = {"driver": "ldap"}
+    ldap = {"url": "ldap://myldap.com:389/",
+            "user_tree_dn": "ou=Users,dc=my_new_root,dc=org"}
+
+    @classmethod
+    def resource_setup(cls):
+        super(DomainConfigurationV3RbacTest, cls).resource_setup()
+        cls.domain_id = cls.setup_test_domain()['id']
+
+    def setUp(self):
+        super(DomainConfigurationV3RbacTest, self).setUp()
+        self._create_domain_config(self.domain_id)
+
+    def _create_domain_config(self, domain_id):
+        domain_config = self.domain_config_client.create_domain_config(
+            domain_id, identity=self.identity, ldap=self.ldap)['config']
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.domain_config_client.delete_domain_config,
+                        domain_id)
+        return domain_config
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:create_domain_config")
+    @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd115')
+    def test_create_domain_config(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._create_domain_config(self.domain_id)
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_domain_config")
+    @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd118')
+    def test_show_domain_config(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domain_config_client.show_domain_config(self.domain_id)['config']
+
+    @decorators.idempotent_id('1b539f95-4991-4e09-960f-fa771e1007d7')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_domain_config")
+    def test_show_domain_group_config(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domain_config_client.show_domain_group_config(
+            self.domain_id, 'identity')['config']
+
+    @decorators.idempotent_id('590c774d-a294-44f8-866e-aac9f4ab3809')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_domain_config")
+    def test_show_domain_group_option_config(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domain_config_client.show_domain_group_option_config(
+            self.domain_id, 'identity', 'driver')['config']
+
+    @decorators.idempotent_id('21053885-1ce3-4167-b5e3-e470253481da')
+    @rbac_rule_validation.action(
+        service="keystone",
+        rule="identity:get_security_compliance_domain_config")
+    def test_show_security_compliance_domain_config(self):
+        # The "security_compliance" group can only be shown for the default
+        # domain.
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domain_config_client.show_domain_group_config(
+            CONF.identity.default_domain_id, 'security_compliance')
+
+    @decorators.idempotent_id('d1addd10-9ae4-4360-9961-47324fd22f23')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_domain_config_default")
+    def test_show_default_config_settings(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domain_config_client.show_default_config_settings()['config']
+
+    @decorators.idempotent_id('63183377-251f-4622-81f0-6b58a8a285c9')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_domain_config_default")
+    def test_show_default_group_config(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domain_config_client.show_default_group_config('identity')[
+            'config']
+
+    @decorators.idempotent_id('6440e9c1-e8da-474d-9118-89996fffe5f8')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_domain_config_default")
+    def test_show_default_group_option(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domain_config_client.show_default_group_option('identity',
+                                                            'driver')['config']
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:update_domain_config")
+    @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd116')
+    def test_update_domain_config(self):
+        updated_config = {'ldap': {'url': data_utils.rand_url()}}
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domain_config_client.update_domain_config(
+            self.domain_id, **updated_config)['config']
+
+    @decorators.idempotent_id('6e32bf96-dbe9-4ac8-b814-0e79fa948285')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:update_domain_config")
+    def test_update_domain_group_config(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domain_config_client.update_domain_group_config(
+            self.domain_id, 'identity', identity=self.identity)['config']
+
+    @decorators.idempotent_id('d2c510da-a077-4c67-9522-27745ef2812b')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:update_domain_config")
+    def test_update_domain_group_option_config(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domain_config_client.update_domain_group_option_config(
+            self.domain_id, 'identity', 'driver', driver='ldap')['config']
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:delete_domain_config")
+    @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd117')
+    def test_delete_domain_config(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domain_config_client.delete_domain_config(self.domain_id)
+
+    @decorators.idempotent_id('f479694b-df02-4d5a-88b6-c8b52f9341eb')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:delete_domain_config")
+    def test_delete_domain_group_config(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domain_config_client.delete_domain_group_config(self.domain_id,
+                                                             'identity')
+
+    @decorators.idempotent_id('f594bde3-31c9-414f-922d-0ddafdc0ca40')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:delete_domain_config")
+    def test_delete_domain_group_option_config(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domain_config_client.delete_domain_group_option_config(
+            self.domain_id, 'identity', 'driver')
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_domains_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_domains_rbac.py
new file mode 100644
index 0000000..a8cd022
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_domains_rbac.py
@@ -0,0 +1,69 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.identity import rbac_base
+
+
+class IdentityDomainsV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:create_domain")
+    @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd110')
+    def test_create_domain(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_domain()
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:update_domain")
+    @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd111')
+    def test_update_domain(self):
+        domain = self.setup_test_domain()
+        new_domain_name = data_utils.rand_name(
+            self.__class__.__name__ + '-test_update_domain')
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domains_client.update_domain(domain['id'],
+                                          domain=domain,
+                                          name=new_domain_name)
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:delete_domain")
+    @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd112')
+    def test_delete_domain(self):
+        domain = self.setup_test_domain()
+        # A domain must be deactivated to be deleted
+        self.domains_client.update_domain(domain['id'],
+                                          domain=domain,
+                                          enabled=False)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domains_client.delete_domain(domain['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_domain")
+    @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd113')
+    def test_show_domain(self):
+        domain = self.setup_test_domain()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domains_client.show_domain(domain['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:list_domains")
+    @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd114')
+    def test_list_domains(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.domains_client.list_domains()
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_endpoints_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_endpoints_rbac.py
index dbdf8dc..2659bae 100644
--- a/patrole_tempest_plugin/tests/api/identity/v3/test_endpoints_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_endpoints_rbac.py
@@ -13,98 +13,56 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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 patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.identity.v3 import rbac_base
-
-CONF = config.CONF
+from patrole_tempest_plugin.tests.api.identity import rbac_base
 
 
-class IdentityEndpointsV3AdminRbacTest(
-        rbac_base.BaseIdentityV3RbacAdminTest):
-
-    def _create_endpoint(self):
-        """Creates a service and an endpoint for test."""
-        interface = 'public'
-        url = data_utils.rand_url()
-        service = self._create_service()
-        endpoint = self.endpoints_client \
-                       .create_endpoint(service_id=service['id'],
-                                        interface=interface,
-                                        url=url)['endpoint']
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.endpoints_client.delete_endpoint, endpoint['id'])
-        return (service, endpoint)
-
-    def tearDown(self):
-        """Reverts user back to admin for cleanup."""
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(IdentityEndpointsV3AdminRbacTest, self).tearDown()
+class IdentityEndpointsV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:create_endpoint")
     @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd127')
     def test_create_endpoint(self):
-        """Create an endpoint.
-
-        RBAC test for Keystone: identity:create_endpoint
-        """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_endpoint()
+        service = self.setup_test_service()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_endpoint(service=service)
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:update_endpoint")
     @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd128')
     def test_update_endpoint(self):
-        """Update an endpoint.
-
-        RBAC test for Keystone: identity:update_endpoint
-        """
-        service, endpoint = self._create_endpoint()
+        endpoint = self.setup_test_endpoint()
         new_url = data_utils.rand_url()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.endpoints_client.update_endpoint(endpoint["id"],
-                                              service_id=service['id'],
-                                              url=new_url)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.endpoints_client.update_endpoint(
+            endpoint["id"],
+            url=new_url)
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:delete_endpoint")
     @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd129')
     def test_delete_endpoint(self):
-        """Delete an endpoint.
+        endpoint = self.setup_test_endpoint()
 
-        RBAC test for Keystone: identity:delete_endpoint
-        """
-        _, endpoint = self._create_endpoint()
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.endpoints_client.delete_endpoint(endpoint['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:get_endpoint")
     @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd130')
     def test_show_endpoint(self):
-        """Show/Get an endpoint.
+        endpoint = self.setup_test_endpoint()
 
-        RBAC test for Keystone: identity:get_endpoint
-        """
-        _, endpoint = self._create_endpoint()
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.endpoints_client.show_endpoint(endpoint['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:list_endpoints")
     @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd131')
     def test_list_endpoints(self):
-        """Create a Domain.
-
-        RBAC test for Keystone: identity:create_domain
-        """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.endpoints_client.list_endpoints()
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_ep_filter_groups_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_ep_filter_groups_rbac.py
new file mode 100644
index 0000000..e7b73b6
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_ep_filter_groups_rbac.py
@@ -0,0 +1,108 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.identity import rbac_base
+
+
+class EndpointFilterGroupsV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
+
+    interface = 'public'
+
+    @classmethod
+    def resource_setup(cls):
+        super(EndpointFilterGroupsV3RbacTest, cls).resource_setup()
+        cls.service_id = cls.setup_test_service()['id']
+
+    def setUp(self):
+        super(EndpointFilterGroupsV3RbacTest, self).setUp()
+        self.endpoint_group_id = self._create_endpoint_group()
+
+    def _create_endpoint_group(self, ignore_not_found=False):
+        # Create an endpoint group
+        ep_group_name = data_utils.rand_name(
+            self.__class__.__name__ + '-EPFilterGroup')
+        filters = {
+            'filters': {
+                'interface': self.interface,
+                'service_id': self.service_id
+            }
+        }
+        endpoint_group = self.endpoint_groups_client.create_endpoint_group(
+            name=ep_group_name, **filters)['endpoint_group']
+
+        if ignore_not_found:
+            self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                            self.endpoint_groups_client.delete_endpoint_group,
+                            endpoint_group['id'])
+        else:
+            self.addCleanup(self.endpoint_groups_client.delete_endpoint_group,
+                            endpoint_group['id'])
+
+        return endpoint_group['id']
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:create_endpoint_group")
+    @decorators.idempotent_id('b4765906-52ec-477b-b441-a8508ced68e3')
+    def test_create_endpoint_group(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._create_endpoint_group(ignore_not_found=True)
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:list_endpoint_groups")
+    @decorators.idempotent_id('089aa3a7-ba1f-4f70-a1cf-f298a845058a')
+    def test_list_endpoint_groups(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.endpoint_groups_client.list_endpoint_groups()['endpoint_groups']
+
+    @decorators.idempotent_id('5c16368d-1485-4c28-9803-db3fa3510623')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:check_endpoint_group")
+    def test_check_endpoint_group(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.endpoint_groups_client.check_endpoint_group(
+            self.endpoint_group_id)
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_endpoint_group")
+    @decorators.idempotent_id('bd2b6fb8-661f-4255-84b2-50fea4a1dc61')
+    def test_show_endpoint_group(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.endpoint_groups_client.show_endpoint_group(
+            self.endpoint_group_id)['endpoint_group']
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:update_endpoint_group")
+    @decorators.idempotent_id('028b9198-ec35-4bd5-8f72-e23dfb7a0c8e')
+    def test_update_endpoint_group(self):
+        updated_name = data_utils.rand_name(
+            self.__class__.__name__ + '-EPFilterGroup')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.endpoint_groups_client.update_endpoint_group(
+            self.endpoint_group_id, name=updated_name)['endpoint_group']
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:delete_endpoint_group")
+    @decorators.idempotent_id('88cc105e-70d9-48ac-927e-200ef41e070c')
+    def test_delete_endpoint_group(self):
+        endpoint_group_id = self._create_endpoint_group(ignore_not_found=True)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.endpoint_groups_client.delete_endpoint_group(endpoint_group_id)
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_ep_filter_projects_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_ep_filter_projects_rbac.py
new file mode 100644
index 0000000..7a4f2d7
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_ep_filter_projects_rbac.py
@@ -0,0 +1,90 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.identity import rbac_base
+
+
+class EndpointFilterProjectsV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(EndpointFilterProjectsV3RbacTest, cls).resource_setup()
+        cls.project = cls.setup_test_project()
+        cls.endpoint = cls.setup_test_endpoint()
+
+    def _add_endpoint_to_project(self, ignore_not_found=False):
+        self.endpoint_filter_client.add_endpoint_to_project(
+            self.project['id'], self.endpoint['id'])
+
+        if ignore_not_found:
+            self.addCleanup(
+                test_utils.call_and_ignore_notfound_exc,
+                self.endpoint_filter_client.delete_endpoint_from_project,
+                self.project['id'], self.endpoint['id'])
+        else:
+            self.addCleanup(
+                self.endpoint_filter_client.delete_endpoint_from_project,
+                self.project['id'], self.endpoint['id'])
+
+    @rbac_rule_validation.action(
+        service="keystone",
+        rule="identity:add_endpoint_to_project")
+    @decorators.idempotent_id('9199ec13-816d-4efe-b8b1-e1cd026b9747')
+    def test_add_endpoint_to_project(self):
+        # Adding endpoints to projects
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._add_endpoint_to_project(ignore_not_found=True)
+
+    @rbac_rule_validation.action(
+        service="keystone",
+        rule="identity:list_projects_for_endpoint")
+    @decorators.idempotent_id('f53dca42-ec8a-48e9-924b-0bbe6c99727f')
+    def test_list_projects_for_endpoint(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.endpoint_filter_client.list_projects_for_endpoint(
+            self.endpoint['id'])
+
+    @rbac_rule_validation.action(
+        service="keystone",
+        rule="identity:check_endpoint_in_project")
+    @decorators.idempotent_id('0c1425eb-833c-4aa1-a21d-52ffa41fdc6a')
+    def test_check_endpoint_in_project(self):
+        self._add_endpoint_to_project()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.endpoint_filter_client.check_endpoint_in_project(
+            self.project['id'], self.endpoint['id'])
+
+    @rbac_rule_validation.action(
+        service="keystone",
+        rule="identity:list_endpoints_for_project")
+    @decorators.idempotent_id('5d86c659-c6ad-41e0-854e-3823e95c7cc2')
+    def test_list_endpoints_in_project(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.endpoint_filter_client.list_endpoints_in_project(
+            self.project['id'])
+
+    @rbac_rule_validation.action(
+        service="keystone",
+        rule="identity:remove_endpoint_from_project")
+    @decorators.idempotent_id('b4e21c10-4f47-427b-9b8a-f5b5601adfda')
+    def test_remove_endpoint_from_project(self):
+        self._add_endpoint_to_project(ignore_not_found=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.endpoint_filter_client.delete_endpoint_from_project(
+            self.project['id'], self.endpoint['id'])
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_groups_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_groups_rbac.py
index bbdf49d..0fc29b7 100644
--- a/patrole_tempest_plugin/tests/api/identity/v3/test_groups_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_groups_rbac.py
@@ -13,120 +13,99 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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 patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.identity.v3 import rbac_base
-
-CONF = config.CONF
+from patrole_tempest_plugin.tests.api.identity import rbac_base
 
 
-class IdentityGroupsV3AdminRbacTest(rbac_base.BaseIdentityV3RbacAdminTest):
+class IdentityGroupsV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
 
-    def tearDown(self):
-        """Reverts user back to admin for cleanup."""
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(IdentityGroupsV3AdminRbacTest, self).tearDown()
-
-    def _create_group(self):
-        """Creates a group for test."""
-        name = data_utils.rand_name('group')
-        group = self.groups_client.create_group(name=name)['group']
-
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.groups_client.delete_group, group['id'])
-        return group
-
-    def _add_user_to_group(self, group_id):
+    def _create_user_and_add_to_new_group(self):
         """Creates a user and adds to a group for test."""
-        user_name = data_utils.rand_name('User')
-        user = self._create_test_user(name=user_name, password=None)
-
-        self.groups_client.add_group_user(group_id, user['id'])
-
-        return user['id']
+        group = self.setup_test_group()
+        user = self.setup_test_user()
+        self.groups_client.add_group_user(group['id'], user['id'])
+        return (group['id'], user['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:create_group")
     @decorators.idempotent_id('88377f51-9074-4d64-a22f-f8931d048c9a')
     def test_create_group(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_group()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_group()
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:update_group")
     @decorators.idempotent_id('790fb7be-a657-4a64-9b83-c43425cf180b')
     def test_update_group(self):
-        group = self._create_group()
-        # Update Group
-        new_name = data_utils.rand_name('UpdateGroup')
+        group = self.setup_test_group()
+        new_group_name = data_utils.rand_name(
+            self.__class__.__name__ + '-group')
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.groups_client.update_group(group['id'],
-                                        name=new_name)
+                                        name=new_group_name)
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:delete_group")
     @decorators.idempotent_id('646b52da-2a5f-486a-afb0-51fdc86a6c12')
     def test_delete_group(self):
-        group = self._create_group()
+        group = self.setup_test_group()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.groups_client.delete_group(group['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:get_group")
     @decorators.idempotent_id('d530f0ad-42b9-429b-ad05-e53ac95a040e')
     def test_show_group(self):
-        group = self._create_group()
+        group = self.setup_test_group()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.groups_client.show_group(group['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:list_groups")
     @decorators.idempotent_id('c4d0f76b-735f-4fd0-868b-0006bc420ff4')
     def test_list_groups(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.groups_client.list_groups()
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:add_user_to_group")
     @decorators.idempotent_id('fdd49b74-3ed3-4736-9f0e-9027a32017ac')
     def test_add_user_group(self):
-        group = self._create_group()
+        group = self.setup_test_group()
+        user = self.setup_test_user()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._add_user_to_group(group['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.groups_client.add_group_user(group['id'], user['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:remove_user_from_group")
     @decorators.idempotent_id('8a60d11c-7d2b-47e5-a0f3-9ea900ca66fe')
     def test_remove_user_group(self):
-        group = self._create_group()
-        user_id = self._add_user_to_group(group['id'])
+        group_id, user_id = self._create_user_and_add_to_new_group()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.groups_client.delete_group_user(group['id'], user_id)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.groups_client.delete_group_user(group_id, user_id)
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:list_users_in_group")
     @decorators.idempotent_id('b3e394a7-079e-4a0d-a4ff-9b266293d1ee')
     def test_list_user_group(self):
-        group = self._create_group()
+        group = self.setup_test_group()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.groups_client.list_group_users(group['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:check_user_in_group")
     @decorators.idempotent_id('d3603241-fd87-4a2d-94f9-f32469d1aaba')
     def test_check_user_group(self):
-        group = self._create_group()
-        user_id = self._add_user_to_group(group['id'])
+        group_id, user_id = self._create_user_and_add_to_new_group()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.groups_client.check_group_user_existence(group['id'], user_id)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.groups_client.check_group_user_existence(group_id, user_id)
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_oauth_consumers_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_oauth_consumers_rbac.py
new file mode 100644
index 0000000..d3e17f1
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_oauth_consumers_rbac.py
@@ -0,0 +1,78 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.identity import rbac_base
+
+
+class IdentityConsumersV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
+
+    def _create_consumer(self):
+        description = data_utils.rand_name(
+            self.__class__.__name__ + '-IdentityConsumer')
+        consumer = self.consumers_client.create_consumer(
+            description)['consumer']
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.consumers_client.delete_consumer,
+                        consumer['id'])
+        return consumer
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:create_consumer")
+    @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d970')
+    def test_create_consumer(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._create_consumer()
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:delete_consumer")
+    @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d971')
+    def test_delete_consumer(self):
+        consumer = self._create_consumer()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.consumers_client.delete_consumer(consumer['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:update_consumer")
+    @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d972')
+    def test_update_consumer(self):
+        consumer = self._create_consumer()
+        updated_description = data_utils.rand_name(
+            self.__class__.__name__ + '-IdentityConsumer')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.consumers_client.update_consumer(consumer['id'],
+                                              updated_description)
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_consumer")
+    @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d973')
+    def test_show_consumer(self):
+        consumer = self._create_consumer()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.consumers_client.show_consumer(consumer['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:list_consumers")
+    @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d975')
+    def test_list_consumers(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.consumers_client.list_consumers()
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_oauth_tokens_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_oauth_tokens_rbac.py
new file mode 100644
index 0000000..78ee78a
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_oauth_tokens_rbac.py
@@ -0,0 +1,138 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+
+from tempest import config
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.identity import rbac_base
+
+CONF = config.CONF
+
+
+class IdentityOAuthTokensV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(IdentityOAuthTokensV3RbacTest, cls).resource_setup()
+        # Authorize token on admin role since primary user has admin
+        # credentials before switching roles. Populate role_ids with admin
+        # role id.
+        cls.role_ids = [cls.get_role_by_name(CONF.identity.admin_role)['id']]
+        cls.project_id = cls.auth_provider.credentials.project_id
+        cls.user_id = cls.auth_provider.credentials.user_id
+
+    def _create_consumer(self):
+        description = data_utils.rand_name(
+            self.__class__.__name__ + '-Consumer')
+        consumer = self.consumers_client.create_consumer(
+            description)['consumer']
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.consumers_client.delete_consumer,
+                        consumer['id'])
+        return consumer
+
+    def _create_consumer_and_request_token(self):
+        # Create consumer
+        consumer = self._create_consumer()
+
+        # Create request token
+        request_token = self.oauth_token_client.create_request_token(
+            consumer['id'], consumer['secret'], self.project_id)
+
+        return consumer, request_token
+
+    def _create_access_token(self):
+        consumer, request_token = self._create_consumer_and_request_token()
+
+        # Authorize request token
+        resp = self.oauth_token_client.authorize_request_token(
+            request_token['oauth_token'], self.role_ids)['token']
+        auth_verifier = resp['oauth_verifier']
+
+        # Create access token
+        body = self.oauth_token_client.create_access_token(
+            consumer['id'],
+            consumer['secret'],
+            request_token['oauth_token'],
+            request_token['oauth_token_secret'],
+            auth_verifier)
+        access_key = body['oauth_token']
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.oauth_token_client.revoke_access_token,
+                        self.user_id, access_key)
+
+        return access_key
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:authorize_request_token")
+    @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d976')
+    def test_authorize_request_token(self):
+        _, request_token = self._create_consumer_and_request_token()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.oauth_token_client.authorize_request_token(
+            request_token['oauth_token'],
+            self.role_ids)
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_access_token")
+    @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d977')
+    def test_get_access_token(self):
+        access_token = self._create_access_token()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.oauth_token_client.get_access_token(self.user_id,
+                                                 access_token)
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_access_token_role")
+    @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d980')
+    def test_get_access_token_role(self):
+        access_token = self._create_access_token()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.oauth_token_client.get_access_token_role(
+            self.user_id, access_token, self.role_ids[0])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:list_access_tokens")
+    @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d979')
+    def test_list_access_tokens(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.oauth_token_client.list_access_tokens(self.user_id)
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:list_access_token_roles")
+    @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d978')
+    def test_list_access_token_roles(self):
+        access_token = self._create_access_token()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.oauth_token_client.list_access_token_roles(
+            self.user_id, access_token)
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:delete_access_token")
+    @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d981')
+    def test_revoke_access_token(self):
+        access_token = self._create_access_token()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.oauth_token_client.revoke_access_token(
+            self.user_id, access_token)
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_policies_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_policies_rbac.py
index ade418f..3e03ac0 100644
--- a/patrole_tempest_plugin/tests/api/identity/v3/test_policies_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_policies_rbac.py
@@ -13,76 +13,55 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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 patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.identity.v3 import rbac_base
-
-CONF = config.CONF
+from patrole_tempest_plugin.tests.api.identity import rbac_base
 
 
-class IdentityPoliciesV3AdminRbacTest(rbac_base.BaseIdentityV3RbacAdminTest):
-
-    def tearDown(self):
-        """Reverts user back to admin for cleanup."""
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(IdentityPoliciesV3AdminRbacTest, self).tearDown()
-
-    def _create_policy(self):
-        """Creates a policy for test."""
-        blob = data_utils.rand_name('BlobName')
-        policy_type = data_utils.rand_name('PolicyType')
-        policy = self.policies_client.create_policy(
-            blob=blob,
-            policy=policy_type,
-            type="application/json")['policy']
-
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.policies_client.delete_policy, policy['id'])
-        return policy
+class IdentityPoliciesV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:create_policy")
     @decorators.idempotent_id('de2f7ecb-fbf0-41f3-abf4-b97b5e082fd5')
     def test_create_policy(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_policy()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_policy()
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:update_policy")
     @decorators.idempotent_id('9cfed3c6-0b27-4d15-be67-e06e0cfb01b9')
     def test_update_policy(self):
-        policy = self._create_policy()
-        update_type = data_utils.rand_name('UpdatedPolicyType')
+        policy = self.setup_test_policy()
+        updated_policy_type = data_utils.rand_name(
+            self.__class__.__name__ + '-policy_type')
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.policies_client.update_policy(policy['id'],
-                                           type=update_type)
+                                           type=updated_policy_type)
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:delete_policy")
     @decorators.idempotent_id('dcd93f75-1e1b-4fbe-bee0-9c4c7b201735')
     def test_delete_policy(self):
-        policy = self._create_policy()
+        policy = self.setup_test_policy()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.policies_client.delete_policy(policy['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:get_policy")
     @decorators.idempotent_id('d7e415c2-945a-4504-9571-0e2d0dd8594b')
     def test_show_policy(self):
-        policy = self._create_policy()
+        policy = self.setup_test_policy()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.policies_client.show_policy(policy['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:list_policies")
     @decorators.idempotent_id('35a56161-4054-4237-8a78-7ce805dce202')
     def test_list_policies(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.policies_client.list_policies()['policies']
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_projects_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_projects_rbac.py
index a00569d..51086ae 100644
--- a/patrole_tempest_plugin/tests/api/identity/v3/test_projects_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_projects_rbac.py
@@ -13,86 +13,55 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.identity.v3 import rbac_base
-
-CONF = config.CONF
+from patrole_tempest_plugin.tests.api.identity import rbac_base
 
 
-class IdentityProjectV3AdminRbacTest(
-        rbac_base.BaseIdentityV3RbacAdminTest):
-
-    def tearDown(self):
-        """Reverts user back to admin for cleanup."""
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(IdentityProjectV3AdminRbacTest, self).tearDown()
+class IdentityProjectV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:create_project")
     @decorators.idempotent_id('0f148510-63bf-11e6-1564-080044d0d904')
     def test_create_project(self):
-        """Create a Project.
-
-        RBAC test for Keystone: identity:create_project
-        """
-        name = data_utils.rand_name('project')
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        project = self.non_admin_projects_client \
-                      .create_project(name)['project']
-        self.addCleanup(self.projects_client.delete_project, project['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_project()
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:update_project")
     @decorators.idempotent_id('0f148510-63bf-11e6-1564-080044d0d905')
     def test_update_project(self):
-        """Update a Project.
+        project = self.setup_test_project()
+        new_desc = data_utils.rand_name(
+            self.__class__.__name__ + '-description')
 
-        RBAC test for Keystone: identity:update_project
-        """
-        project = self._setup_test_project()
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.non_admin_projects_client \
-            .update_project(project['id'],
-                            description="Changed description")
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.projects_client.update_project(project['id'],
+                                            description=new_desc)
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:delete_project")
     @decorators.idempotent_id('0f148510-63bf-11e6-1564-080044d0d906')
     def test_delete_project(self):
-        """Delete a Project.
+        project = self.setup_test_project()
 
-        RBAC test for Keystone: identity:delete_project
-        """
-        project = self._setup_test_project()
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.non_admin_projects_client.delete_project(project['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.projects_client.delete_project(project['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:get_project")
     @decorators.idempotent_id('0f148510-63bf-11e6-1564-080044d0d907')
     def test_show_project(self):
-        """Show a project.
+        project = self.setup_test_project()
 
-        RBAC test for Keystone: identity:get_project
-        """
-        project = self._setup_test_project()
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.non_admin_projects_client.show_project(project['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.projects_client.show_project(project['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:list_projects")
     @decorators.idempotent_id('0f148510-63bf-11e6-1564-080044d0d908')
     def test_list_projects(self):
-        """List all projects.
-
-        RBAC test for Keystone: identity:list_projects
-        """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.non_admin_projects_client.list_projects()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.projects_client.list_projects()
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_regions_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_regions_rbac.py
new file mode 100644
index 0000000..55a2f77
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_regions_rbac.py
@@ -0,0 +1,67 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.identity import rbac_base
+
+
+class IdentityRegionsV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:create_region")
+    @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd119')
+    def test_create_region(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_region()
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:update_region")
+    @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd120')
+    def test_update_region(self):
+        region = self.setup_test_region()
+        new_description = data_utils.rand_name(
+            self.__class__.__name__ + '-test_update_region')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.regions_client.update_region(region['id'],
+                                          description=new_description)
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:delete_region")
+    @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd121')
+    def test_delete_region(self):
+        region = self.setup_test_region()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.regions_client.delete_region(region['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_region")
+    @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd122')
+    def test_show_region(self):
+        region = self.setup_test_region()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.regions_client.show_region(region['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:list_regions")
+    @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd123')
+    def test_list_regions(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.regions_client.list_regions()
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_role_assignments_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_role_assignments_rbac.py
new file mode 100644
index 0000000..c1d0369
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_role_assignments_rbac.py
@@ -0,0 +1,42 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.identity import rbac_base
+
+
+class IdentityRoleAssignmentsV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
+
+    @decorators.idempotent_id('afe57adb-1b9c-43d9-84a9-f0cf4c94e416')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:list_role_assignments")
+    def test_list_role_assignments(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.role_assignments_client.\
+            list_role_assignments()['role_assignments']
+
+    @decorators.idempotent_id('36c7a990-857e-415c-8717-38d7200a9894')
+    @rbac_rule_validation.action(
+        service="keystone",
+        rule="identity:list_role_assignments_for_tree")
+    def test_list_role_assignments_for_tree(self):
+        project = self.setup_test_project()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.role_assignments_client.list_role_assignments(
+            include_subtree=True,
+            **{'scope.project.id': project['id']})['role_assignments']
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_roles_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_roles_rbac.py
new file mode 100644
index 0000000..22b03f5
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_roles_rbac.py
@@ -0,0 +1,396 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.identity import rbac_base
+
+
+class IdentityRolesV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(IdentityRolesV3RbacTest, cls).resource_setup()
+        cls.domain = cls.setup_test_domain()
+        cls.project = cls.setup_test_project()
+        cls.group = cls.setup_test_group()
+        cls.role = cls.setup_test_role()
+        cls.implies_role = cls.setup_test_role()
+        cls.user = cls.setup_test_user()
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:create_role")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d904')
+    def test_create_role(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_role()
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:update_role")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d905')
+    def test_update_role(self):
+        new_role_name = data_utils.rand_name(
+            self.__class__.__name__ + '-test_update_role')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.update_role(self.role['id'],
+                                      name=new_role_name)
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:delete_role")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d906')
+    def test_delete_role(self):
+        role = self.setup_test_role()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.delete_role(role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_role")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d907')
+    def test_show_role(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.show_role(self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:list_roles")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d908')
+    def test_list_roles(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.list_roles()
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:create_grant")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d909')
+    def test_create_user_role_on_project(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.create_user_role_on_project(
+            self.project['id'],
+            self.user['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_user_on_project,
+                        self.project['id'],
+                        self.user['id'],
+                        self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:create_grant")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90c')
+    def test_create_group_role_on_project(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.create_group_role_on_project(
+            self.project['id'],
+            self.group['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_group_on_project,
+                        self.project['id'],
+                        self.group['id'],
+                        self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:create_grant")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90f')
+    def test_create_user_role_on_domain(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.create_user_role_on_domain(
+            self.domain['id'],
+            self.user['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_user_on_domain,
+                        self.domain['id'],
+                        self.user['id'],
+                        self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:create_grant")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d912')
+    def test_create_group_role_on_domain(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.create_group_role_on_domain(
+            self.domain['id'],
+            self.group['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_group_on_domain,
+                        self.domain['id'],
+                        self.group['id'],
+                        self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:check_grant")
+    @decorators.idempotent_id('22921b1e-1a33-4026-bff9-f236d6dd149c')
+    def test_check_user_role_existence_on_project(self):
+        self.roles_client.create_user_role_on_project(
+            self.project['id'],
+            self.user['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_user_on_project,
+                        self.project['id'],
+                        self.user['id'],
+                        self.role['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.check_user_role_existence_on_project(
+            self.project['id'],
+            self.user['id'],
+            self.role['id'])
+
+    @decorators.idempotent_id('92f8e67d-85bf-407d-9814-edd5664abc47')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:check_grant")
+    def test_check_user_role_existence_on_domain(self):
+        self.roles_client.create_user_role_on_domain(
+            self.domain['id'],
+            self.user['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_user_on_domain,
+                        self.domain['id'],
+                        self.user['id'],
+                        self.role['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.check_user_role_existence_on_domain(
+            self.domain['id'],
+            self.user['id'],
+            self.role['id'])
+
+    @decorators.idempotent_id('8738d3d2-8c84-4423-b36c-7c59eaa08b73')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:check_grant")
+    def test_check_role_from_group_on_project_existence(self):
+        self.roles_client.create_group_role_on_project(
+            self.project['id'],
+            self.group['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_group_on_project,
+                        self.project['id'],
+                        self.group['id'],
+                        self.role['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.check_role_from_group_on_project_existence(
+            self.project['id'],
+            self.group['id'],
+            self.role['id'])
+
+    @decorators.idempotent_id('e7d73bd0-cf5e-4c0c-9c93-cf53e23232d6')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:check_grant")
+    def test_check_role_from_group_on_domain_existence(self):
+        self.roles_client.create_group_role_on_domain(
+            self.domain['id'],
+            self.group['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_group_on_domain,
+                        self.domain['id'],
+                        self.group['id'],
+                        self.role['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.check_role_from_group_on_domain_existence(
+            self.domain['id'],
+            self.group['id'],
+            self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:revoke_grant")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90a')
+    def test_delete_role_from_user_on_project(self):
+        self.roles_client.create_user_role_on_project(
+            self.project['id'],
+            self.user['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_user_on_project,
+                        self.project['id'],
+                        self.user['id'],
+                        self.role['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.delete_role_from_user_on_project(
+            self.project['id'],
+            self.user['id'],
+            self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:revoke_grant")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90d')
+    def test_delete_role_from_group_on_project(self):
+        self.roles_client.create_group_role_on_project(
+            self.project['id'],
+            self.group['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_group_on_project,
+                        self.project['id'],
+                        self.group['id'],
+                        self.role['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.delete_role_from_group_on_project(
+            self.project['id'],
+            self.group['id'],
+            self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:revoke_grant")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d910')
+    def test_delete_role_from_user_on_domain(self):
+        self.roles_client.create_user_role_on_domain(
+            self.domain['id'],
+            self.user['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_user_on_domain,
+                        self.domain['id'],
+                        self.user['id'],
+                        self.role['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.delete_role_from_user_on_domain(
+            self.domain['id'],
+            self.user['id'],
+            self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:revoke_grant")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d913')
+    def test_delete_role_from_group_on_domain(self):
+        self.roles_client.create_group_role_on_domain(
+            self.domain['id'],
+            self.group['id'],
+            self.role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_from_group_on_domain,
+                        self.domain['id'],
+                        self.group['id'],
+                        self.role['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.delete_role_from_group_on_domain(
+            self.domain['id'],
+            self.group['id'],
+            self.role['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:list_grants")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90b')
+    def test_list_user_roles_on_project(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.list_user_roles_on_project(
+            self.project['id'],
+            self.user['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:list_grants")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90e')
+    def test_list_group_roles_on_project(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.list_group_roles_on_project(
+            self.project['id'],
+            self.group['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:list_grants")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d911')
+    def test_list_user_roles_on_domain(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.list_user_roles_on_domain(
+            self.domain['id'],
+            self.user['id'])
+
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:list_grants")
+    @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d914')
+    def test_list_group_roles_on_domain(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.list_group_roles_on_domain(
+            self.domain['id'],
+            self.group['id'])
+
+    @decorators.idempotent_id('2aef3eaa-8156-4962-a01d-c9bb0e499e15')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:create_implied_role")
+    def test_create_role_inference_rule(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.create_role_inference_rule(
+            self.role['id'], self.implies_role['id'])['role_inference']
+        self.addCleanup(self.roles_client.delete_role_inference_rule,
+                        self.role['id'], self.implies_role['id'])
+
+    @decorators.idempotent_id('83f997b2-55c4-4894-b1f2-e175b19d1fa5')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:get_implied_role")
+    def test_show_role_inference_rule(self):
+        self.roles_client.create_role_inference_rule(
+            self.role['id'], self.implies_role['id'])
+        self.addCleanup(self.roles_client.delete_role_inference_rule,
+                        self.role['id'], self.implies_role['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.show_role_inference_rule(
+            self.role['id'], self.implies_role['id'])['role_inference']
+
+    @decorators.idempotent_id('f7bb39bf-0b06-468e-a8b0-60a4fb1f258d')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:list_implied_roles")
+    def test_list_role_inferences_rules(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.list_role_inferences_rules(self.role['id'])[
+            'role_inference']
+
+    @decorators.idempotent_id('eca2d502-09bb-45cd-9773-bce2e7bcddd1')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:check_implied_role")
+    def test_check_role_inference_rule(self):
+        self.roles_client.create_role_inference_rule(
+            self.role['id'], self.implies_role['id'])
+        self.addCleanup(self.roles_client.delete_role_inference_rule,
+                        self.role['id'], self.implies_role['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.check_role_inference_rule(
+            self.role['id'], self.implies_role['id'])
+
+    @decorators.idempotent_id('13a5db1e-dd4a-4ca1-81ec-d5452aaaf54b')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:delete_implied_role")
+    def test_delete_role_inference_rule(self):
+        self.roles_client.create_role_inference_rule(
+            self.role['id'], self.implies_role['id'])
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.roles_client.delete_role_inference_rule,
+                        self.role['id'], self.implies_role['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.delete_role_inference_rule(
+            self.role['id'], self.implies_role['id'])
+
+    @decorators.idempotent_id('05869f2b-4dd4-425a-905e-eec9a6f06374')
+    @rbac_rule_validation.action(service="keystone",
+                                 rule="identity:list_role_inference_rules")
+    def test_list_all_role_inference_rules(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.roles_client.list_all_role_inference_rules()['role_inferences']
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_services_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_services_rbac.py
index 42d0028..44ce1a1 100644
--- a/patrole_tempest_plugin/tests/api/identity/v3/test_services_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_services_rbac.py
@@ -13,46 +13,30 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.identity.v3 import rbac_base
-
-CONF = config.CONF
+from patrole_tempest_plugin.tests.api.identity import rbac_base
 
 
-class IdentitySericesV3AdminRbacTest(rbac_base.BaseIdentityV3RbacAdminTest):
-
-    def tearDown(self):
-        """Reverts user back to admin for cleanup."""
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(IdentitySericesV3AdminRbacTest, self).tearDown()
+class IdentitySericesV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:create_service")
     @decorators.idempotent_id('9a4bb317-f0bb-4005-8df0-4b672885b7c8')
     def test_create_service(self):
-        """Create a service.
-
-        RBAC test for Keystone: identity:create_service
-        """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_service()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_service()
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:update_service")
     @decorators.idempotent_id('b39447d1-2cf6-40e5-a899-46f287f2ecf0')
     def test_update_service(self):
-        """Update a service.
+        service = self.setup_test_service()
+        new_name = data_utils.rand_name(self.__class__.__name__ + '-service')
 
-        RBAC test for Keystone: identity:update_service
-        """
-        service = self._create_service()
-        new_name = data_utils.rand_name('new_test_name')
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.services_client.update_service(service['id'],
                                             service=service,
                                             name=new_name,
@@ -62,35 +46,23 @@
                                  rule="identity:delete_service")
     @decorators.idempotent_id('177b991a-438d-4bef-8e9f-9c6cc5a1c9e8')
     def test_delete_service(self):
-        """Delete a service.
+        service = self.setup_test_service()
 
-        RBAC test for Keystone: identity:delete_service
-        """
-        service = self._create_service()
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.services_client.delete_service(service['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:get_service")
     @decorators.idempotent_id('d89a9ac6-cd53-428d-84c0-5bc71f4a432d')
     def test_show_service(self):
-        """Show/Get a service.
+        service = self.setup_test_service()
 
-        RBAC test for Keystone: identity:get_service
-        """
-        service = self._create_service()
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.services_client.show_service(service['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:list_services")
     @decorators.idempotent_id('706e6bea-3385-4718-919c-0b5121395806')
     def test_list_services(self):
-        """list all services.
-
-        RBAC test for Keystone: identity:list_services
-        """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.services_client.list_services()
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_trusts_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_trusts_rbac.py
new file mode 100644
index 0000000..c25af25
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_trusts_rbac.py
@@ -0,0 +1,131 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest import config
+from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+from tempest import test
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.identity import rbac_base
+
+CONF = config.CONF
+
+
+class IdentityTrustV3RbacTest(rbac_base.BaseIdentityV3RbacTest):
+
+    credentials = ['primary', 'admin', 'alt']
+
+    @classmethod
+    def skip_checks(cls):
+        super(IdentityTrustV3RbacTest, cls).skip_checks()
+        if not CONF.identity_feature_enabled.trust:
+            raise cls.skipException(
+                "%s skipped as trust feature isn't enabled" % cls.__name__)
+
+    @classmethod
+    def resource_setup(cls):
+        super(IdentityTrustV3RbacTest, cls).resource_setup()
+        # Use the primary user's credentials for the "trustor_user_id", since
+        # user_id:%(trust.trustor_user_id)s will thereby evaluate to
+        # "primary user's user_id:primary user's user_id" which evaluates to
+        # true.
+        cls.trustor_user_id = cls.auth_provider.credentials.user_id
+        cls.trustor_project_id = cls.auth_provider.credentials.project_id
+        cls.trustee_user_id = cls.setup_test_user()['id']
+
+        # The "unauthorized_user_id" does not have permissions to create a
+        # trust because the user_id in "user_id:%(trust.trustor_user_id)s" (the
+        # policy rule for creating a trust) corresponds to the primary user_id
+        # not the alt user_id.
+        cls.unauthorized_user_id = cls.os_alt.auth_provider.credentials.user_id
+
+        # A role is guaranteed to exist (namely the admin role), because
+        # "trustor_user_id" and "trustor_project_id" are the primary tempest
+        # user and project, respectively.
+        cls.delegated_role_id = cls.roles_client.list_user_roles_on_project(
+            cls.trustor_project_id, cls.trustor_user_id)['roles'][0]['id']
+
+        cls.trust = cls.setup_test_trust(trustor_user_id=cls.trustor_user_id,
+                                         trustee_user_id=cls.trustee_user_id,
+                                         project_id=cls.trustor_project_id,
+                                         roles=[{'id': cls.delegated_role_id}])
+
+    @decorators.idempotent_id('7ab595a7-9b71-45fe-91d8-2793b0292f72')
+    @rbac_rule_validation.action(
+        service="keystone",
+        rule="identity:create_trust",
+        extra_target_data={
+            "trust.trustor_user_id":
+            "os_primary.auth_provider.credentials.user_id"
+        })
+    def test_create_trust(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_trust(trustor_user_id=self.trustor_user_id,
+                              trustee_user_id=self.trustee_user_id)
+
+    @decorators.idempotent_id('bd72d22a-6e11-4840-bd93-17b382e7f0e0')
+    @test.attr(type=['negative'])
+    @rbac_rule_validation.action(
+        service="keystone",
+        rule="identity:create_trust",
+        extra_target_data={
+            "trust.trustor_user_id": "os_alt.auth_provider.credentials.user_id"
+        })
+    def test_create_trust_negative(self):
+        # Explicit negative test for identity:create_trust policy action.
+        # Assert expected exception is Forbidden and then reraise it.
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        e = self.assertRaises(lib_exc.Forbidden, self.setup_test_trust,
+                              trustor_user_id=self.unauthorized_user_id,
+                              trustee_user_id=self.trustee_user_id)
+        raise e
+
+    @decorators.idempotent_id('d9a6fd06-08f6-462c-a86c-ce009adf1230')
+    @rbac_rule_validation.action(
+        service="keystone",
+        rule="identity:delete_trust")
+    def test_delete_trust(self):
+        trust = self.setup_test_trust(trustor_user_id=self.trustor_user_id,
+                                      trustee_user_id=self.trustee_user_id)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.trusts_client.delete_trust(trust['id'])
+
+    @decorators.idempotent_id('f2e32896-bf66-4f4e-89cf-e7fba0ef1f38')
+    @rbac_rule_validation.action(
+        service="keystone",
+        rule="identity:list_trusts")
+    def test_list_trusts(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.trusts_client.list_trusts(
+            trustor_user_id=self.trustor_user_id)['trusts']
+
+    @decorators.idempotent_id('3c9ff92f-a73e-4f9b-8865-e017f38c70f5')
+    @rbac_rule_validation.action(
+        service="keystone",
+        rule="identity:list_roles_for_trust")
+    def test_list_roles_for_trust(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.trusts_client.list_trust_roles(self.trust['id'])['roles']
+
+    @decorators.idempotent_id('3bb4f97b-cecd-4c7d-ad10-b88ee6c5d573')
+    @rbac_rule_validation.action(
+        service="keystone",
+        rule="identity:get_role_for_trust")
+    def test_show_trust_role(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.trusts_client.show_trust_role(
+            self.trust['id'], self.delegated_role_id)['role']
diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py
index 84d3be6..723455e 100644
--- a/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py
+++ b/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py
@@ -13,131 +13,86 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.identity.v3 import rbac_base
-
-CONF = config.CONF
+from patrole_tempest_plugin.tests.api.identity import rbac_base
 
 
-class IdentityUserV3AdminRbacTest(
-        rbac_base.BaseIdentityV3RbacAdminTest):
+class IdentityUserV3AdminRbacTest(rbac_base.BaseIdentityV3RbacTest):
 
-    def tearDown(self):
-        """Reverts user back to admin for cleanup."""
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(IdentityUserV3AdminRbacTest, self).tearDown()
+    @classmethod
+    def resource_setup(cls):
+        super(IdentityUserV3AdminRbacTest, cls).resource_setup()
+        cls.default_user_id = cls.auth_provider.credentials.user_id
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:create_user")
     @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d904')
     def test_create_user(self):
-        """Creates a user.
-
-        RBAC test for Keystone: identity:create_user
-        """
-        user_name = data_utils.rand_name('test_create_user')
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.non_admin_users_client.create_user(name=user_name)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.setup_test_user()
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:update_user")
     @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d905')
     def test_update_user(self):
-        """Updates a user.
+        user = self.setup_test_user()
+        new_email = data_utils.rand_name(
+            self.__class__.__name__ + '-user_email')
 
-        RBAC test for Keystone: identity:update_user
-        """
-        user_name = data_utils.rand_name('test_update_user')
-        user = self._create_test_user(name=user_name, password=None)
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.non_admin_users_client.update_user(user['id'],
-                                                name=user_name,
-                                                email="changedUser@xyz.com")
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.users_client.update_user(user['id'],
+                                      name=user['name'],
+                                      email=new_email)
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:delete_user")
     @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d906')
     def test_delete_user(self):
-        """Get the list of users.
+        user = self.setup_test_user()
 
-        RBAC test for Keystone: identity:delete_user
-        """
-        user_name = data_utils.rand_name('test_delete_user')
-        user = self._create_test_user(name=user_name, password=None)
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.non_admin_users_client.delete_user(user['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.users_client.delete_user(user['id'])
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:list_users")
     @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d907')
     def test_list_users(self):
-        """Get the list of users.
-
-        RBAC test for Keystone: identity:list_users
-        """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.non_admin_users_client.list_users()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.users_client.list_users()
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:get_user")
     @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d908')
-    def test_show_user(self):
-        """Get one user.
-
-        RBAC test for Keystone: identity:get_user
-        """
-        user_name = data_utils.rand_name('test_get_user')
-        user = self._create_test_user(name=user_name, password=None)
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.non_admin_users_client.show_user(user['id'])
+    def test_show_own_user(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.users_client.show_user(self.default_user_id)
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:change_password")
     @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d90a')
     def test_change_password(self):
-        """Update a user password
+        original_password = data_utils.rand_password()
+        user = self.setup_test_user(password=original_password)
 
-        RBAC test for Keystone: identity:change_password
-        """
-        user_name = data_utils.rand_name('test_change_password')
-        user = self._create_test_user(name=user_name, password='nova')
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.non_admin_users_client \
-            .update_user_password(user['id'],
-                                  original_password='nova',
-                                  password='neutron')
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.users_client.update_user_password(
+            user['id'],
+            original_password=original_password,
+            password=data_utils.rand_password())
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:list_groups_for_user")
     @decorators.idempotent_id('bd5946d4-46d2-423d-a800-a3e7aabc18b3')
-    def test_list_group_user(self):
-        """Lists groups which a user belongs to.
-
-        RBAC test for Keystone: identity:list_groups_for_user
-        """
-        user_name = data_utils.rand_name('User')
-        user = self._create_test_user(name=user_name, password=None)
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.non_admin_users_client.list_user_groups(user['id'])
+    def test_list_own_user_group(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.users_client.list_user_groups(self.default_user_id)
 
     @rbac_rule_validation.action(service="keystone",
                                  rule="identity:list_user_projects")
     @decorators.idempotent_id('0f148510-63bf-11e6-1564-080044d0d909')
-    def test_list_user_projects(self):
-        """List User's Projects.
-
-        RBAC test for Keystone: identity:list_user_projects
-        """
-        user = self.setup_test_user()
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.non_admin_users_client.list_user_projects(user['id'])
+    def test_list_own_user_projects(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.users_client.list_user_projects(self.default_user_id)
diff --git a/patrole_tempest_plugin/tests/api/image/rbac_base.py b/patrole_tempest_plugin/tests/api/image/rbac_base.py
index 3570b81..7270560 100644
--- a/patrole_tempest_plugin/tests/api/image/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/image/rbac_base.py
@@ -14,7 +14,7 @@
 from tempest.api.image import base as image_base
 from tempest import config
 
-from patrole_tempest_plugin.rbac_utils import rbac_utils
+from patrole_tempest_plugin import rbac_utils
 
 CONF = config.CONF
 
@@ -26,16 +26,15 @@
     @classmethod
     def skip_checks(cls):
         super(BaseV1ImageRbacTest, cls).skip_checks()
-        if not CONF.rbac.rbac_flag:
+        if not CONF.rbac.enable_rbac:
             raise cls.skipException(
-                "%s skipped as RBAC Flag not enabled" % cls.__name__)
+                "%s skipped as RBAC testing not enabled" % cls.__name__)
 
     @classmethod
     def setup_clients(cls):
         super(BaseV1ImageRbacTest, cls).setup_clients()
-        cls.auth_provider = cls.os.auth_provider
-        cls.admin_client = cls.os_adm.image_client
-        cls.rbac_utils = rbac_utils()
+        cls.auth_provider = cls.os_primary.auth_provider
+        cls.rbac_utils = rbac_utils.RbacUtils(cls)
 
 
 class BaseV2ImageRbacTest(image_base.BaseV2ImageTest):
@@ -45,13 +44,12 @@
     @classmethod
     def skip_checks(cls):
         super(BaseV2ImageRbacTest, cls).skip_checks()
-        if not CONF.rbac.rbac_flag:
+        if not CONF.rbac.enable_rbac:
             raise cls.skipException(
-                "%s skipped as RBAC Flag not enabled" % cls.__name__)
+                "%s skipped as RBAC testing not enabled" % cls.__name__)
 
     @classmethod
     def setup_clients(cls):
         super(BaseV2ImageRbacTest, cls).setup_clients()
-        cls.auth_provider = cls.os.auth_provider
-        cls.admin_client = cls.os_adm.image_client_v2
-        cls.rbac_utils = rbac_utils()
+        cls.auth_provider = cls.os_primary.auth_provider
+        cls.rbac_utils = rbac_utils.RbacUtils(cls)
diff --git a/patrole_tempest_plugin/tests/api/image/v2/test_image_namespace_objects_rbac.py b/patrole_tempest_plugin/tests/api/image/test_image_namespace_objects_rbac.py
similarity index 86%
rename from patrole_tempest_plugin/tests/api/image/v2/test_image_namespace_objects_rbac.py
rename to patrole_tempest_plugin/tests/api/image/test_image_namespace_objects_rbac.py
index f66b00c..74c64e1 100644
--- a/patrole_tempest_plugin/tests/api/image/v2/test_image_namespace_objects_rbac.py
+++ b/patrole_tempest_plugin/tests/api/image/test_image_namespace_objects_rbac.py
@@ -13,7 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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
@@ -21,15 +20,9 @@
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.image import rbac_base
 
-CONF = config.CONF
-
 
 class ImageNamespacesObjectsRbacTest(rbac_base.BaseV2ImageRbacTest):
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ImageNamespacesObjectsRbacTest, self).tearDown()
-
     @rbac_rule_validation.action(service="glance",
                                  rule="add_metadef_object")
     @decorators.idempotent_id("772156f2-e33d-432e-8521-12385746c2f0")
@@ -39,10 +32,11 @@
         RBAC test for the glance add_metadef_object policy
         """
         namespace = self.create_namespace()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         # create a md object, it will be cleaned automatically after
         # cleanup of namespace
-        object_name = data_utils.rand_name('test-object')
+        object_name = data_utils.rand_name(
+            self.__class__.__name__ + '-test-object')
         self.namespace_objects_client.create_namespace_object(
             namespace['namespace'],
             name=object_name)
@@ -59,7 +53,7 @@
         RBAC test for the glance get_metadef_objects policy
         """
         namespace = self.create_namespace()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         # list md objects
         self.namespace_objects_client.list_namespace_objects(
             namespace['namespace'])
@@ -73,7 +67,8 @@
         RBAC test for the glance modify_metadef_object policy
         """
         namespace = self.create_namespace()
-        object_name = data_utils.rand_name('test-object')
+        object_name = data_utils.rand_name(
+            self.__class__.__name__ + '-test-object')
         self.namespace_objects_client.create_namespace_object(
             namespace['namespace'],
             name=object_name)
@@ -82,7 +77,7 @@
                         namespace['namespace'], object_name)
 
         # Toggle role and modify object
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         new_name = "Object New Name"
         self.namespace_objects_client.update_namespace_object(
             namespace['namespace'], object_name, name=new_name)
@@ -96,7 +91,8 @@
         RBAC test for the glance get_metadef_object policy
         """
         namespace = self.create_namespace()
-        object_name = data_utils.rand_name('test-object')
+        object_name = data_utils.rand_name(
+            self.__class__.__name__ + '-test-object')
         self.namespace_objects_client.create_namespace_object(
             namespace['namespace'],
             name=object_name)
@@ -104,7 +100,7 @@
                         self.namespace_objects_client.delete_namespace_object,
                         namespace['namespace'], object_name)
         # Toggle role and get object
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.namespace_objects_client.show_namespace_object(
             namespace['namespace'],
             object_name)
diff --git a/patrole_tempest_plugin/tests/api/image/v2/test_image_namespace_property_rbac.py b/patrole_tempest_plugin/tests/api/image/test_image_namespace_property_rbac.py
similarity index 85%
rename from patrole_tempest_plugin/tests/api/image/v2/test_image_namespace_property_rbac.py
rename to patrole_tempest_plugin/tests/api/image/test_image_namespace_property_rbac.py
index cd7982b..93c50c4 100644
--- a/patrole_tempest_plugin/tests/api/image/v2/test_image_namespace_property_rbac.py
+++ b/patrole_tempest_plugin/tests/api/image/test_image_namespace_property_rbac.py
@@ -13,15 +13,12 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from tempest import config
 from tempest.lib.common.utils import data_utils
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.image import rbac_base
 
-CONF = config.CONF
-
 
 class NamespacesPropertyRbacTest(rbac_base.BaseV2ImageRbacTest):
 
@@ -31,10 +28,6 @@
         body = cls.resource_types_client.list_resource_types()
         cls.resource_name = body['resource_types'][0]['name']
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(NamespacesPropertyRbacTest, self).tearDown()
-
     @rbac_rule_validation.action(service="glance",
                                  rule="add_metadef_property")
     @decorators.idempotent_id('383555ca-677b-43e9-b809-acc2b5a0176c')
@@ -44,8 +37,9 @@
         RBAC test for the glance add_metadef_property policy
         """
         namespace = self.create_namespace()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        property_name = data_utils.rand_name('test-ns-property')
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        property_name = data_utils.rand_name(
+            self.__class__.__name__ + '-test-ns-property')
         self.namespace_properties_client.create_namespace_property(
             namespace=namespace['namespace'], type="string",
             title=property_name, name=self.resource_name)
@@ -59,7 +53,7 @@
         RBAC test for the glance get_metadef_properties policy
         """
         namespace = self.create_namespace()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.namespace_properties_client.list_namespace_properties(
             namespace=namespace['namespace'])
 
@@ -72,12 +66,13 @@
         RBAC test for the glance get_metadef_property policy
         """
         namespace = self.create_namespace()
-        property_name = data_utils.rand_name('test-ns-property')
+        property_name = data_utils.rand_name(
+            self.__class__.__name__ + '-test-ns-property')
         self.namespace_properties_client.create_namespace_property(
             namespace=namespace['namespace'], type="string",
             title=property_name, name=self.resource_name)
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.namespace_properties_client.show_namespace_properties(
             namespace['namespace'], self.resource_name)
 
@@ -90,12 +85,13 @@
         RBAC test for the glance modify_metadef_property policy
         """
         namespace = self.create_namespace()
-        property_name = data_utils.rand_name('test-ns-property')
+        property_name = data_utils.rand_name(
+            self.__class__.__name__ + '-test-ns-property')
         self.namespace_properties_client.create_namespace_property(
             namespace=namespace['namespace'], type="string",
             title=property_name, name=self.resource_name)
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.namespace_properties_client.update_namespace_properties(
             namespace['namespace'], self.resource_name, type="string",
             title=property_name, name=self.resource_name)
diff --git a/patrole_tempest_plugin/tests/api/image/v2/test_image_namespace_rbac.py b/patrole_tempest_plugin/tests/api/image/test_image_namespace_rbac.py
similarity index 84%
rename from patrole_tempest_plugin/tests/api/image/v2/test_image_namespace_rbac.py
rename to patrole_tempest_plugin/tests/api/image/test_image_namespace_rbac.py
index 19b815e..c6bd60e 100644
--- a/patrole_tempest_plugin/tests/api/image/v2/test_image_namespace_rbac.py
+++ b/patrole_tempest_plugin/tests/api/image/test_image_namespace_rbac.py
@@ -13,7 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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
@@ -21,15 +20,9 @@
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.image import rbac_base
 
-CONF = config.CONF
-
 
 class ImageNamespacesRbacTest(rbac_base.BaseV2ImageRbacTest):
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ImageNamespacesRbacTest, self).tearDown()
-
     @rbac_rule_validation.action(service="glance",
                                  rule="add_metadef_namespace")
     @decorators.idempotent_id('e0730ead-b824-4ffc-b774-9469df0e4da6')
@@ -38,8 +31,9 @@
 
         RBAC test for the glance add_metadef_namespace policy
         """
-        namespace_name = data_utils.rand_name('test-ns')
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        namespace_name = data_utils.rand_name(
+            self.__class__.__name__ + '-test-ns')
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.namespaces_client.create_namespace(
             namespace=namespace_name,
             protected=False)
@@ -56,7 +50,7 @@
 
         RBAC test for the glance get_metadef_namespaces policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.namespaces_client.list_namespaces()
 
     @rbac_rule_validation.action(service="glance",
@@ -67,11 +61,12 @@
 
         RBAC test for the glance modify_metadef_namespace policy
         """
-        namespace_name = data_utils.rand_name('test-ns')
+        namespace_name = data_utils.rand_name(
+            self.__class__.__name__ + '-test-ns')
         body = self.namespaces_client.create_namespace(
             namespace=namespace_name,
             protected=False)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.namespaces_client.update_namespace(body['namespace'],
                                                 description="My new "
                                                             "description")
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
new file mode 100644
index 0000000..8e2bc49
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/image/test_image_namespace_tags_rbac.py
@@ -0,0 +1,109 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.image import rbac_base as base
+
+
+class NamespaceTagsRbacTest(base.BaseV2ImageRbacTest):
+    """RBAC tests for namespace_tags_client.
+
+    Performs RBAC testing for the endpoints in namespace_tags_client, except
+    for
+
+        1) delete_namespace_tag
+        2) delete_namespace_tags
+
+    because Glance does not currently do policy enforcement for them.
+    """
+
+    @classmethod
+    def resource_setup(cls):
+        super(NamespaceTagsRbacTest, cls).resource_setup()
+        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()
+
+    def _create_namespace_tag(self, multiple=False):
+        tag_count = 2 if multiple else 1
+        namespace_tag_names = []
+
+        for i in range(tag_count):
+            tag_name = data_utils.rand_name(self.__class__.__name__ + '-tag')
+            namespace_tag_names.append({'name': tag_name})
+
+        if multiple:
+            namespace_tags = self.namespace_tags_client.create_namespace_tags(
+                self.namespace, tags=namespace_tag_names)['tags']
+        else:
+            namespace_tags = self.namespace_tags_client.create_namespace_tag(
+                self.namespace, namespace_tag_names[0]['name'])
+
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.namespace_tags_client.delete_namespace_tags,
+                        self.namespace)
+
+        return [nt['name'] for nt in namespace_tags] if multiple \
+            else namespace_tags['name']
+
+    @decorators.idempotent_id('50bedccb-9d0b-4138-8d95-31a89250edf6')
+    @rbac_rule_validation.action(service="glance",
+                                 rule="add_metadef_tag")
+    def test_create_namespace_tag(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._create_namespace_tag()
+
+    @decorators.idempotent_id('4acf70cc-05da-4b1e-87b2-d5e4475164e7')
+    @rbac_rule_validation.action(service="glance",
+                                 rule="get_metadef_tag")
+    def test_show_namespace_tag(self):
+        tag_name = self._create_namespace_tag()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.namespace_tags_client.show_namespace_tag(self.namespace, tag_name)
+
+    @decorators.idempotent_id('01593828-3edb-461e-8abc-8fdeb3927e37')
+    @rbac_rule_validation.action(service="glance",
+                                 rule="modify_metadef_tag")
+    def test_update_namespace_tag(self):
+        tag_name = self._create_namespace_tag()
+        updated_tag_name = data_utils.rand_name(
+            self.__class__.__name__ + '-tag')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.namespace_tags_client.update_namespace_tag(
+            self.namespace, tag_name, name=updated_tag_name)
+
+    @decorators.idempotent_id('20ffaf76-ebdc-4267-a1ad-194346f5cc91')
+    @rbac_rule_validation.action(service="glance",
+                                 rule="add_metadef_tags")
+    def test_create_namespace_tags(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._create_namespace_tag(multiple=True)
+
+    @decorators.idempotent_id('d37c1501-e787-449d-89b3-754a942a459a')
+    @rbac_rule_validation.action(service="glance",
+                                 rule="get_metadef_tags")
+    def test_list_namespace_tags(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.namespace_tags_client.list_namespace_tags(self.namespace)
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
new file mode 100644
index 0000000..6727cc8
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/image/test_image_resource_types_rbac.py
@@ -0,0 +1,72 @@
+#    Copyright 2017 AT&T Corporation.
+#    All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.image import rbac_base
+
+
+class ImageResourceTypesRbacTest(rbac_base.BaseV2ImageRbacTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(ImageResourceTypesRbacTest, cls).resource_setup()
+        cls.namespace_name = data_utils.rand_name(
+            cls.__name__ + '-test-ns')
+        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_setup()
+
+    @rbac_rule_validation.action(service="glance",
+                                 rule="list_metadef_resource_types")
+    @decorators.idempotent_id('0416fc4d-cfdc-447b-88b6-d9f1dd0382f7')
+    def test_list_metadef_resource_types(self):
+        """List Metadef Resource Type Image Test
+
+        RBAC test for the glance list_metadef_resource_type policy.
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.resource_types_client.list_resource_types()
+
+    @rbac_rule_validation.action(service="glance",
+                                 rule="get_metadef_resource_type")
+    @decorators.idempotent_id('3698d53c-71ae-4803-a2c3-c272c054f25c')
+    def test_get_metadef_resource_type(self):
+        """Get Metadef Resource Type Image Test
+
+        RBAC test for the glance get_metadef_resource_type policy.
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.resource_types_client.list_resource_type_association(
+            self.namespace_name)
+
+    @rbac_rule_validation.action(service="glance",
+                                 rule="add_metadef_resource_type_association")
+    @decorators.idempotent_id('ef9fbc60-3e28-4164-a25c-d30d892f7939')
+    def test_add_metadef_resource_type(self):
+        type_name = data_utils.rand_name()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.resource_types_client.create_resource_type_association(
+            self.namespace_name, name=type_name)
diff --git a/patrole_tempest_plugin/tests/api/image/v2/test_images_member_rbac.py b/patrole_tempest_plugin/tests/api/image/test_images_member_rbac.py
similarity index 66%
rename from patrole_tempest_plugin/tests/api/image/v2/test_images_member_rbac.py
rename to patrole_tempest_plugin/tests/api/image/test_images_member_rbac.py
index 81bad5f..a7c59f5 100644
--- a/patrole_tempest_plugin/tests/api/image/v2/test_images_member_rbac.py
+++ b/patrole_tempest_plugin/tests/api/image/test_images_member_rbac.py
@@ -13,44 +13,27 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from oslo_log import log as logging
-from tempest import config
 from tempest.lib import decorators
-from tempest.lib import exceptions
 
-from patrole_tempest_plugin import rbac_exceptions
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.image import rbac_base as base
 
-CONF = config.CONF
-LOG = logging.getLogger(__name__)
-
 
 class ImagesMemberRbacTest(base.BaseV2ImageRbacTest):
 
-    credentials = ['admin', 'alt']
+    credentials = ['admin', 'primary', 'alt']
 
     @classmethod
     def resource_setup(cls):
         super(ImagesMemberRbacTest, cls).resource_setup()
         cls.tenant_id = cls.image_member_client.tenant_id
-        cls.alt_tenant_id = cls.alt_image_member_client.tenant_id
+        cls.alt_tenant_id = cls.os_alt.image_member_client_v2.tenant_id
 
     @classmethod
     def setup_clients(cls):
         super(ImagesMemberRbacTest, cls).setup_clients()
-        cls.image_client = cls.os.image_client_v2
-        cls.alt_image_client = cls.os_alt.image_client_v2
-        cls.image_member_client = cls.os.image_member_client_v2
-        cls.alt_image_member_client = cls.os_alt.image_member_client_v2
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ImagesMemberRbacTest, self).tearDown()
-
-    def setUp(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ImagesMemberRbacTest, self).setUp()
+        cls.image_client = cls.os_primary.image_client_v2
+        cls.image_member_client = cls.os_primary.image_member_client_v2
 
     @rbac_rule_validation.action(service="glance",
                                  rule="add_member")
@@ -63,7 +46,7 @@
         """
         image_id = self.create_image()['id']
         # Toggle role and add image member
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.image_member_client.create_image_member(image_id,
                                                      member=self.alt_tenant_id)
 
@@ -80,12 +63,13 @@
         self.image_member_client.create_image_member(image_id,
                                                      member=self.alt_tenant_id)
         # Toggle role and delete image member
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.image_member_client.delete_image_member(image_id,
                                                      self.alt_tenant_id)
 
     @rbac_rule_validation.action(service="glance",
-                                 rule="get_member")
+                                 rule="get_member",
+                                 expected_error_code=404)
     @decorators.idempotent_id('c01fd308-6484-11e6-881e-080027d0d606')
     def test_show_image_member(self):
 
@@ -93,24 +77,16 @@
 
         RBAC test for the glance get_member policy
         """
-        try:
-            image_id = self.create_image()['id']
-            self.image_member_client.create_image_member(
-                image_id,
-                member=self.alt_tenant_id)
+        image_id = self.create_image()['id']
+        self.image_member_client.create_image_member(
+            image_id,
+            member=self.alt_tenant_id)
 
-            # Toggle role and get image member
-            self.rbac_utils.switch_role(self, switchToRbacRole=True)
-            self.image_member_client.show_image_member(
-                image_id,
-                self.alt_tenant_id)
-        except exceptions.NotFound as e:
-            '''If the role doesn't have access to an image, a 404 exception is
-            thrown when the roles tries to show an image member'''
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the image and tries to show "
-                     "image members")
-            raise rbac_exceptions.RbacActionFailed(e)
+        # Toggle role and get image member
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.image_member_client.show_image_member(
+            image_id,
+            self.alt_tenant_id)
 
     @rbac_rule_validation.action(service="glance",
                                  rule="modify_member")
@@ -129,7 +105,7 @@
             image_id, self.tenant_id,
             status='accepted')
         # Toggle role and update member
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.image_member_client.update_image_member(
             image_id, self.tenant_id,
             status='pending')
@@ -147,5 +123,5 @@
         self.image_member_client.create_image_member(image_id,
                                                      member=self.alt_tenant_id)
         # Toggle role and list image members
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.image_member_client.list_image_members(image_id)
diff --git a/patrole_tempest_plugin/tests/api/image/test_images_rbac.py b/patrole_tempest_plugin/tests/api/image/test_images_rbac.py
new file mode 100644
index 0000000..340323e
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/image/test_images_rbac.py
@@ -0,0 +1,228 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import six
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.image import rbac_base
+
+
+class BasicOperationsImagesRbacTest(rbac_base.BaseV2ImageRbacTest):
+
+    @classmethod
+    def setup_clients(cls):
+        super(BasicOperationsImagesRbacTest, cls).setup_clients()
+        cls.image_client = cls.os_primary.image_client_v2
+        cls.admin_image_client = cls.os_admin.image_client_v2
+
+    def _create_image(self, **kwargs):
+        image_name = data_utils.rand_name(self.__class__.__name__ + '-Image')
+        image = self.create_image(name=image_name,
+                                  container_format='bare',
+                                  disk_format='raw',
+                                  **kwargs)
+        return image
+
+    def _upload_image(self, image_id):
+        image_file = six.BytesIO(data_utils.random_bytes())
+        return self.image_client.store_image_file(image_id, image_file)
+
+    @rbac_rule_validation.action(service="glance",
+                                 rule="add_image")
+    @decorators.idempotent_id('0f148510-63bf-11e6-b348-080027d0d606')
+    def test_create_image(self):
+
+        """Create Image Test
+
+        RBAC test for the glance create_image endpoint
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._create_image()
+
+    @rbac_rule_validation.action(service="glance",
+                                 rule="upload_image")
+    @decorators.idempotent_id('fdc0c7e2-ad58-4c5a-ba9d-1f6046a5b656')
+    def test_upload_image(self):
+
+        """Upload Image Test
+
+        RBAC test for the glance upload_image endpoint
+        """
+        image = self._create_image()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._upload_image(image['id'])
+
+    @decorators.idempotent_id('f0c268f3-cb51-49aa-9bd5-d30cf647322f')
+    @rbac_rule_validation.action(service="glance",
+                                 rule="download_image")
+    def test_download_image(self):
+
+        """Download Image Test
+
+        RBAC test for the glance download_image endpoint
+        """
+        image = self._create_image()
+        self._upload_image(image['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.image_client.show_image_file(image['id'])
+
+    @rbac_rule_validation.action(service="glance",
+                                 rule="delete_image")
+    @decorators.idempotent_id('3b5c341e-645b-11e6-ac4f-080027d0d606')
+    def test_delete_image(self):
+
+        """Delete created image
+
+        RBAC test for the glance delete_image endpoint
+        """
+        image = self._create_image()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.image_client.delete_image(image['id'])
+        self.admin_image_client.wait_for_resource_deletion(image['id'])
+
+    @rbac_rule_validation.action(service="glance",
+                                 rule="get_image")
+    @decorators.idempotent_id('3085c7c6-645b-11e6-ac4f-080027d0d606')
+    def test_show_image(self):
+
+        """Get created image
+
+        RBAC test for the glance create_image endpoint
+        """
+        image = self._create_image()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.image_client.show_image(image['id'])
+
+    @rbac_rule_validation.action(service="glance",
+                                 rule="get_images")
+    @decorators.idempotent_id('bf1a4e94-645b-11e6-ac4f-080027d0d606')
+    def test_list_images(self):
+
+        """List all the images
+
+        RBAC test for the glance list_images endpoint
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.image_client.list_images()['images']
+
+    @rbac_rule_validation.action(service="glance",
+                                 rule="modify_image")
+    @decorators.idempotent_id('32ecf48c-645e-11e6-ac4f-080027d0d606')
+    def test_update_image(self):
+
+        """Update given images
+
+        RBAC test for the glance update_image endpoint
+        """
+        image = self._create_image()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        updated_image_name = data_utils.rand_name(
+            self.__class__.__name__ + '-image')
+        self.image_client.update_image(image['id'], [
+            dict(replace='/name', value=updated_image_name)])
+
+    @decorators.idempotent_id('244050d9-1b9a-446a-b3c5-f26f3ba8eb75')
+    @rbac_rule_validation.action(service="glance",
+                                 rule="modify_image")
+    def test_create_image_tag(self):
+
+        """Create image tag
+
+        RBAC test for the glance add_image_tag endpoint
+        """
+        image = self._create_image()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.image_client.add_image_tag(
+            image['id'],
+            data_utils.rand_name(self.__class__.__name__ + '-tag'))
+
+    @decorators.idempotent_id('c4a0bf9c-b78b-48c6-a31f-72c95f943c6e')
+    @rbac_rule_validation.action(service="glance",
+                                 rule="modify_image")
+    def test_delete_image_tag(self):
+
+        """Delete image tag
+
+        RBAC test for the glance delete_image_tag endpoint
+        """
+        image = self._create_image()
+        tag_name = data_utils.rand_name(self.__class__.__name__ + '-tag')
+        self.image_client.add_image_tag(image['id'], tag_name)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.image_client.delete_image_tag(image['id'], tag_name)
+
+    @rbac_rule_validation.action(service="glance",
+                                 rule="publicize_image")
+    @decorators.idempotent_id('0ea4809c-6461-11e6-ac4f-080027d0d606')
+    def test_publicize_image(self):
+
+        """Publicize Image Test
+
+        RBAC test for the glance publicize_image endpoint
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._create_image(visibility='public')
+
+    @decorators.idempotent_id('0f2d8427-134a-4d3c-a102-5fcdf5443d09')
+    @rbac_rule_validation.action(service="glance",
+                                 rule="communitize_image")
+    def test_communitize_image(self):
+
+        """Communitize Image Test
+
+        RBAC test for the glance communitize_image policy
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._create_image(visibility='community')
+
+    @rbac_rule_validation.action(service="glance",
+                                 rule="deactivate")
+    @decorators.idempotent_id('b488458c-65df-11e6-9947-080027824017')
+    def test_deactivate_image(self):
+
+        """Deactivate Image Test
+
+        RBAC test for the glance deactivate_image endpoint
+        """
+        image = self._create_image()
+        self._upload_image(image['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.image_client.deactivate_image(image['id'])
+
+    @rbac_rule_validation.action(service="glance",
+                                 rule="reactivate")
+    @decorators.idempotent_id('d3fa28b8-65df-11e6-9947-080027824017')
+    def test_reactivate_image(self):
+
+        """Reactivate Image Test
+
+        RBAC test for the glance reactivate_image endpoint
+        """
+        image = self._create_image()
+        self._upload_image(image['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.image_client.reactivate_image(image['id'])
diff --git a/patrole_tempest_plugin/tests/api/image/v1/test_images_member_rbac.py b/patrole_tempest_plugin/tests/api/image/v1/test_images_member_rbac.py
deleted file mode 100644
index 8ded2ec..0000000
--- a/patrole_tempest_plugin/tests/api/image/v1/test_images_member_rbac.py
+++ /dev/null
@@ -1,84 +0,0 @@
-#    Copyright 2017 AT&T Corporation.
-#    All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest import config
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.image import rbac_base as base
-
-CONF = config.CONF
-
-
-class ImagesMemberRbacTest(base.BaseV1ImageRbacTest):
-
-    credentials = ['primary', 'alt', 'admin']
-
-    @classmethod
-    def setup_clients(cls):
-        super(ImagesMemberRbacTest, cls).setup_clients()
-        cls.image_member_client = cls.os.image_member_client
-        cls.alt_image_member_client = cls.os_alt.image_member_client
-
-    @classmethod
-    def resource_setup(cls):
-        super(ImagesMemberRbacTest, cls).resource_setup()
-        cls.alt_tenant_id = cls.alt_image_member_client.tenant_id
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ImagesMemberRbacTest, self).tearDown()
-
-    @rbac_rule_validation.action(service="glance", rule="add_member")
-    @decorators.idempotent_id('bda2bb78-e6ec-4b87-ba6d-1eaf1b28fa8b')
-    def test_add_image_member(self):
-        """Add image member
-
-        RBAC test for the glance add_member policy
-        """
-        image = self.create_image()
-        # Toggle role and add image member
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.image_member_client.create_image_member(image['id'],
-                                                     self.alt_tenant_id)
-
-    @rbac_rule_validation.action(service="glance", rule="delete_member")
-    @decorators.idempotent_id('9beaf28c-62b7-4c30-bbe5-4283aed1201c')
-    def test_delete_image_member(self):
-        """Delete image member
-
-        RBAC test for the glance delete_member policy
-        """
-        image = self.create_image()
-        self.image_member_client.create_image_member(image['id'],
-                                                     self.alt_tenant_id)
-        # Toggle role and delete image member
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.image_member_client.delete_image_member(image['id'],
-                                                     self.alt_tenant_id)
-
-    @rbac_rule_validation.action(service="glance", rule="get_members")
-    @decorators.idempotent_id('a0fcd855-31ef-458c-97e0-14a448cdd6da')
-    def test_list_image_members(self):
-        """List image members
-
-        RBAC test for the glance get_members policy
-        """
-        image = self.create_image()
-        self.image_member_client.create_image_member(image['id'],
-                                                     self.alt_tenant_id)
-        # Toggle role and delete image member
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.image_member_client.list_image_members(image['id'])
diff --git a/patrole_tempest_plugin/tests/api/image/v1/test_images_rbac.py b/patrole_tempest_plugin/tests/api/image/v1/test_images_rbac.py
deleted file mode 100644
index 2bebc2c..0000000
--- a/patrole_tempest_plugin/tests/api/image/v1/test_images_rbac.py
+++ /dev/null
@@ -1,155 +0,0 @@
-#    Copyright 2017 AT&T Corporation.
-#    All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from six import moves
-
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.image import rbac_base
-
-CONF = config.CONF
-
-
-class BasicOperationsImagesRbacTest(rbac_base.BaseV1ImageRbacTest):
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(BasicOperationsImagesRbacTest, self).tearDown()
-
-    @rbac_rule_validation.action(service="glance", rule="add_image")
-    @decorators.idempotent_id('33248a04-6527-11e6-be0f-080027d0d606')
-    def test_create_image(self):
-        """Create Image Test
-
-        RBAC test for the glance add_image policy.
-        """
-        properties = {'prop1': 'val1'}
-        image_name = data_utils.rand_name('image')
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.create_image(name=image_name,
-                          container_format='bare',
-                          disk_format='raw',
-                          is_public=False,
-                          properties=properties)
-
-    @rbac_rule_validation.action(service="glance", rule="delete_image")
-    @decorators.idempotent_id('731c8c81-6c63-413b-a61a-050ce9ca16ad')
-    def test_delete_image(self):
-        """Delete Image Test
-
-        RBAC test for the glance delete_image policy.
-        """
-        image_name = data_utils.rand_name('image')
-        properties = {'prop1': 'val1'}
-        body = self.create_image(name=image_name,
-                                 container_format='bare',
-                                 disk_format='raw',
-                                 is_public=False,
-                                 properties=properties)
-        image_id = body['id']
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.delete_image(image_id)
-
-    @rbac_rule_validation.action(service="glance", rule="download_image")
-    @decorators.idempotent_id('a22bf112-5a3a-419e-9cd6-9562d1a3a458')
-    def test_download_image(self):
-        """Download Image Test
-
-        RBAC test for the glance download_image policy.
-        """
-        image_name = data_utils.rand_name('image')
-        properties = {'prop1': 'val1'}
-        body = self.create_image(name=image_name,
-                                 container_format='bare',
-                                 disk_format='raw',
-                                 is_public=False,
-                                 properties=properties)
-        image_id = body['id']
-        # Now try uploading an image file
-        image_file = moves.cStringIO(data_utils.random_bytes())
-        self.client.update_image(image_id, data=image_file)
-        # Toggle role and get created image
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_image(image_id)
-
-    @rbac_rule_validation.action(service="glance", rule="get_image")
-    @decorators.idempotent_id('110257aa-6fa3-4cc0-b8dd-d93d43acd45c')
-    def test_get_image(self):
-        """Get Image Test
-
-        RBAC test for the glance get_image policy.
-        """
-        image_name = data_utils.rand_name('image')
-        properties = {'prop1': 'val1'}
-        body = self.create_image(name=image_name,
-                                 container_format='bare',
-                                 disk_format='raw',
-                                 is_public=False,
-                                 properties=properties)
-        image_id = body['id']
-        # Now try uploading an image file
-        image_file = moves.cStringIO(data_utils.random_bytes())
-        self.client.update_image(image_id, data=image_file)
-        # Toggle role and get created image
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.check_image(image_id)
-
-    @rbac_rule_validation.action(service="glance", rule="get_images")
-    @decorators.idempotent_id('37662238-0fe9-4dff-8d90-e02f31e7e3fb')
-    def test_list_images(self):
-        """Get Image Test
-
-        RBAC test for the glance get_images policy.
-        """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_images()
-
-    @rbac_rule_validation.action(service="glance", rule="modify_image")
-    @decorators.idempotent_id('3a391a19-d756-4c96-a346-72cc02f6106e')
-    def test_update_image(self):
-        """Update Image Test
-
-        RBAC test for the glance modify_image policy.
-        """
-        image_name = data_utils.rand_name('image')
-        properties = {'prop1': 'val1'}
-        body = self.create_image(name=image_name,
-                                 container_format='bare',
-                                 disk_format='raw',
-                                 is_public=False,
-                                 properties=properties)
-        image_id = body.get('id')
-        properties = {'prop1': 'val2'}
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.update_image(image_id, headers=properties)
-
-    @rbac_rule_validation.action(service="glance", rule="publicize_image")
-    @decorators.idempotent_id('d5b1d09f-ba47-4d56-913e-4f38733a9a5c')
-    def test_publicize_image(self):
-        """Publicize Image Test
-
-        RBAC test for the glance publicize_image policy.
-        """
-        image_name = data_utils.rand_name('image')
-        properties = {'prop1': 'val1'}
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.create_image(name=image_name,
-                          container_format='bare',
-                          disk_format='raw',
-                          is_public=True,
-                          properties=properties)
diff --git a/patrole_tempest_plugin/tests/api/image/v2/__init__.py b/patrole_tempest_plugin/tests/api/image/v2/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/patrole_tempest_plugin/tests/api/image/v2/__init__.py
+++ /dev/null
diff --git a/patrole_tempest_plugin/tests/api/image/v2/test_image_namespace_resource_type.py b/patrole_tempest_plugin/tests/api/image/v2/test_image_namespace_resource_type.py
deleted file mode 100644
index 8d9bc24..0000000
--- a/patrole_tempest_plugin/tests/api/image/v2/test_image_namespace_resource_type.py
+++ /dev/null
@@ -1,63 +0,0 @@
-#    Copyright 2017 AT&T Corporation.
-#    All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib.common.utils import test_utils
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.image import rbac_base
-
-CONF = config.CONF
-
-
-class ImageNamespacesResourceTypeRbacTest(rbac_base.BaseV2ImageRbacTest):
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ImageNamespacesResourceTypeRbacTest, self).tearDown()
-
-    @rbac_rule_validation.action(service="glance",
-                                 rule="list_metadef_resource_types")
-    @decorators.idempotent_id('0416fc4d-cfdc-447b-88b6-d9f1dd0382f7')
-    def test_list_metadef_resource_types(self):
-        """List Metadef Resource Type Image Test
-
-        RBAC test for the glance list_metadef_resource_type policy.
-        """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.resource_types_client.list_resource_types()
-
-    @rbac_rule_validation.action(service="glance",
-                                 rule="get_metadef_resource_type")
-    @decorators.idempotent_id('3698d53c-71ae-4803-a2c3-c272c054f25c')
-    def test_get_metadef_resource_type(self):
-        """Get Metadef Resource Type Image Test
-
-        RBAC test for the glance get_metadef_resource_type policy.
-        """
-        namespace_name = data_utils.rand_name('test-ns')
-        self.namespaces_client.create_namespace(
-            namespace=namespace_name,
-            protected=False)
-        self.addCleanup(
-            test_utils.call_and_ignore_notfound_exc,
-            self.namespaces_client.delete_namespace,
-            namespace_name)
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.resource_types_client.list_resource_type_association(
-            namespace_name)
diff --git a/patrole_tempest_plugin/tests/api/image/v2/test_images_rbac.py b/patrole_tempest_plugin/tests/api/image/v2/test_images_rbac.py
deleted file mode 100644
index faba098..0000000
--- a/patrole_tempest_plugin/tests/api/image/v2/test_images_rbac.py
+++ /dev/null
@@ -1,224 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from six import moves
-
-from oslo_log import log as logging
-from tempest import config
-from tempest.lib.common.utils import data_utils
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.image import rbac_base
-
-CONF = config.CONF
-LOG = logging.getLogger(__name__)
-
-
-class BasicOperationsImagesRbacTest(rbac_base.BaseV2ImageRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(BasicOperationsImagesRbacTest, cls).setup_clients()
-        cls.client = cls.os.image_client_v2
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(BasicOperationsImagesRbacTest, self).tearDown()
-
-    @rbac_rule_validation.action(service="glance",
-                                 rule="add_image")
-    @decorators.idempotent_id('0f148510-63bf-11e6-b348-080027d0d606')
-    def test_create_image(self):
-
-        """Create Image Test
-
-        RBAC test for the glance create_image endpoint
-        """
-        uuid = '00000000-1111-2222-3333-444455556666'
-        image_name = data_utils.rand_name('image')
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.create_image(name=image_name,
-                          container_format='bare',
-                          disk_format='raw',
-                          visibility='private',
-                          ramdisk_id=uuid)
-
-    @rbac_rule_validation.action(service="glance",
-                                 rule="upload_image")
-    @decorators.idempotent_id('fdc0c7e2-ad58-4c5a-ba9d-1f6046a5b656')
-    def test_upload_image(self):
-
-        """Upload Image Test
-
-        RBAC test for the glance upload_image endpoint
-        """
-        uuid = '00000000-1111-2222-3333-444455556666'
-        image_name = data_utils.rand_name('image')
-        body = self.create_image(name=image_name,
-                                 container_format='bare',
-                                 disk_format='raw',
-                                 visibility='private',
-                                 ramdisk_id=uuid)
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # Try uploading an image file
-        image_file = moves.cStringIO(data_utils.random_bytes())
-        self.client.store_image_file(body['id'], image_file)
-
-    @rbac_rule_validation.action(service="glance",
-                                 rule="delete_image")
-    @decorators.idempotent_id('3b5c341e-645b-11e6-ac4f-080027d0d606')
-    def test_delete_image(self):
-
-        """Delete created image
-
-        RBAC test for the glance delete_image endpoint
-        """
-        image_name = data_utils.rand_name('image')
-        body = self.create_image(name=image_name,
-                                 container_format='bare',
-                                 disk_format='raw',
-                                 visibility='public')
-        image_id = body.get('id')
-        # Toggle role and delete created image
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.delete_image(image_id)
-        self.client.wait_for_resource_deletion(image_id)
-
-    @rbac_rule_validation.action(service="glance",
-                                 rule="get_image")
-    @decorators.idempotent_id('3085c7c6-645b-11e6-ac4f-080027d0d606')
-    def test_show_image(self):
-
-        """Get created image
-
-        RBAC test for the glance create_image endpoint
-        """
-
-        image_name = data_utils.rand_name('image')
-        body = self.create_image(name=image_name,
-                                 container_format='bare',
-                                 disk_format='raw',
-                                 visibility='private')
-        image_id = body.get('id')
-        # Toggle role and get created image
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_image(image_id)
-
-    @rbac_rule_validation.action(service="glance",
-                                 rule="get_images")
-    @decorators.idempotent_id('bf1a4e94-645b-11e6-ac4f-080027d0d606')
-    def test_list_images(self):
-
-        """List all the images
-
-        RBAC test for the glance list_images endpoint
-        """
-
-        # Toggle role and get created image
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_images()
-
-    @rbac_rule_validation.action(service="glance",
-                                 rule="modify_image")
-    @decorators.idempotent_id('32ecf48c-645e-11e6-ac4f-080027d0d606')
-    def test_update_image(self):
-
-        """Update given images
-
-        RBAC test for the glance update_image endpoint
-        """
-        image_name = data_utils.rand_name('image')
-        body = self.create_image(name=image_name,
-                                 container_format='bare',
-                                 disk_format='raw',
-                                 visibility='private')
-        image_id = body.get('id')
-
-        # Now try uploading an image file
-        image_file = moves.cStringIO(data_utils.random_bytes())
-        self.client.store_image_file(image_id, image_file)
-
-        # Toggle role and update created image
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        new_image_name = data_utils.rand_name('new-image')
-        body = self.client.update_image(image_id, [
-            dict(replace='/name', value=new_image_name)])
-
-    @rbac_rule_validation.action(service="glance",
-                                 rule="publicize_image")
-    @decorators.idempotent_id('0ea4809c-6461-11e6-ac4f-080027d0d606')
-    def test_publicize_image(self):
-
-        """Publicize Image Test
-
-        RBAC test for the glance publicize_image endpoint
-        """
-        image_name = data_utils.rand_name('image')
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.create_image(name=image_name,
-                          container_format='bare',
-                          disk_format='raw',
-                          visibility='public')
-
-    @rbac_rule_validation.action(service="glance",
-                                 rule="deactivate")
-    @decorators.idempotent_id('b488458c-65df-11e6-9947-080027824017')
-    def test_deactivate_image(self):
-
-        """Deactivate Image Test
-
-        RBAC test for the glance deactivate_image endpoint
-        """
-        uuid = '00000000-1111-2222-3333-444455556666'
-        image_name = data_utils.rand_name('image')
-        body = self.create_image(name=image_name,
-                                 container_format='bare',
-                                 disk_format='raw',
-                                 visibility='private',
-                                 ramdisk_id=uuid)
-        image_id = body.get('id')
-        # Now try uploading an image file
-        image_file = moves.cStringIO(data_utils.random_bytes())
-        self.client.store_image_file(image_id=image_id, data=image_file)
-        # Toggling role and deacivate image
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.deactivate_image(image_id)
-
-    @rbac_rule_validation.action(service="glance",
-                                 rule="reactivate")
-    @decorators.idempotent_id('d3fa28b8-65df-11e6-9947-080027824017')
-    def test_reactivate_image(self):
-
-        """Reactivate Image Test
-
-        RBAC test for the glance reactivate_image endpoint
-        """
-        uuid = '00000000-1111-2222-3333-444455556666'
-        image_name = data_utils.rand_name('image')
-        body = self.create_image(name=image_name,
-                                 container_format='bare',
-                                 disk_format='raw',
-                                 visibility='private',
-                                 ramdisk_id=uuid)
-
-        # Now try uploading an image file
-        image_id = body.get('id')
-        image_file = moves.cStringIO(data_utils.random_bytes())
-        self.client.store_image_file(image_id=image_id, data=image_file)
-        # Toggling role and reactivate image
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.reactivate_image(image_id)
diff --git a/patrole_tempest_plugin/tests/api/network/rbac_base.py b/patrole_tempest_plugin/tests/api/network/rbac_base.py
index 5beedc2..3ee31b7 100644
--- a/patrole_tempest_plugin/tests/api/network/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/network/rbac_base.py
@@ -16,7 +16,7 @@
 from tempest.api.network import base as network_base
 from tempest import config
 
-from patrole_tempest_plugin.rbac_utils import rbac_utils
+from patrole_tempest_plugin import rbac_utils
 
 CONF = config.CONF
 
@@ -28,13 +28,12 @@
     @classmethod
     def skip_checks(cls):
         super(BaseNetworkRbacTest, cls).skip_checks()
-        if not CONF.rbac.rbac_flag:
+        if not CONF.rbac.enable_rbac:
             raise cls.skipException(
-                "%s skipped as RBAC Flag not enabled" % cls.__name__)
+                "%s skipped as RBAC testing not enabled" % cls.__name__)
 
     @classmethod
     def setup_clients(cls):
         super(BaseNetworkRbacTest, cls).setup_clients()
-        cls.auth_provider = cls.os.auth_provider
-        cls.admin_client = cls.os_adm.agents_client
-        cls.rbac_utils = rbac_utils()
+        cls.auth_provider = cls.os_primary.auth_provider
+        cls.rbac_utils = rbac_utils.RbacUtils(cls)
diff --git a/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py b/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py
new file mode 100644
index 0000000..506dd5b
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py
@@ -0,0 +1,237 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.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
+
+
+class AgentsRbacTest(base.BaseNetworkRbacTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(AgentsRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('agent', 'network'):
+            msg = "agent extension not enabled."
+            raise cls.skipException(msg)
+
+    @classmethod
+    def resource_setup(cls):
+        super(AgentsRbacTest, cls).resource_setup()
+        agents = cls.agents_client.list_agents()['agents']
+        cls.agent = agents[0]
+
+    @decorators.idempotent_id('f88e38e0-ab52-4b97-8ffa-48a27f9d199b')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="get_agent",
+                                 expected_error_code=404)
+    def test_show_agent(self):
+        """Show agent test.
+
+        RBAC test for the neutron get_agent policy
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.agents_client.show_agent(self.agent['id'])
+
+    @decorators.idempotent_id('8ca68fdb-eaf6-4880-af82-ba0982949dec')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="update_agent",
+                                 expected_error_code=404)
+    def test_update_agent(self):
+        """Update agent test.
+
+        RBAC test for the neutron update_agent policy
+        """
+        original_status = self.agent['admin_state_up']
+        agent_status = {'admin_state_up': original_status}
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.agents_client.update_agent(agent_id=self.agent['id'],
+                                        agent=agent_status)
+
+
+class L3AgentSchedulerRbacTest(base.BaseNetworkRbacTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(L3AgentSchedulerRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('l3_agent_scheduler', 'network'):
+            msg = "l3_agent_scheduler extension not enabled."
+            raise cls.skipException(msg)
+
+    @classmethod
+    def resource_setup(cls):
+        super(L3AgentSchedulerRbacTest, cls).resource_setup()
+        cls.router = cls.create_router()
+        cls.agent = None
+
+    def setUp(self):
+        super(L3AgentSchedulerRbacTest, self).setUp()
+        if self.agent is not None:
+            return
+
+        # Find an agent and validate that it is correct.
+        agents = self.agents_client.list_agents()['agents']
+        agent = {'agent_type': None}
+        for a in agents:
+            if a['agent_type'] == 'L3 agent':
+                agent = a
+                break
+        self.assertEqual(agent['agent_type'], 'L3 agent', 'Could not find '
+                         'L3 agent in agent list though l3_agent_scheduler '
+                         'is enabled.')
+        self.agent = agent
+
+    @decorators.idempotent_id('5d2bbdbc-40a5-43d2-828a-84dc93fcc453')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="get_l3-routers")
+    def test_list_routers_on_l3_agent(self):
+        """List routers on L3 agent test.
+
+        RBAC test for the neutron get_l3-routers policy
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.agents_client.list_routers_on_l3_agent(self.agent['id'])
+
+    @decorators.idempotent_id('466b2a10-8747-4c09-855a-bd90a1c86ce7')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="create_l3-router")
+    def test_create_router_on_l3_agent(self):
+        """Create router on L3 agent test.
+
+        RBAC test for the neutron create_l3-router policy
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.agents_client.create_router_on_l3_agent(
+            self.agent['id'], router_id=self.router['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.agents_client.delete_router_from_l3_agent,
+            self.agent['id'], router_id=self.router['id'])
+
+    @decorators.idempotent_id('8138cfc9-3e48-4a34-adf6-894077aa1be4')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="delete_l3-router")
+    def test_delete_router_from_l3_agent(self):
+        """Delete router from L3 agent test.
+
+        RBAC test for the neutron delete_l3-router policy
+        """
+        self.agents_client.create_router_on_l3_agent(
+            self.agent['id'], router_id=self.router['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.agents_client.delete_router_from_l3_agent,
+            self.agent['id'], router_id=self.router['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.agents_client.delete_router_from_l3_agent(
+            self.agent['id'], router_id=self.router['id'])
+
+
+class DHCPAgentSchedulersRbacTest(base.BaseNetworkRbacTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(DHCPAgentSchedulersRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('dhcp_agent_scheduler', 'network'):
+            msg = "dhcp_agent_scheduler extension not enabled."
+            raise cls.skipException(msg)
+
+    @classmethod
+    def resource_setup(cls):
+        super(DHCPAgentSchedulersRbacTest, cls).resource_setup()
+        cls.agent = None
+
+    def setUp(self):
+        super(DHCPAgentSchedulersRbacTest, self).setUp()
+        if self.agent is not None:
+            return
+
+        # Find a DHCP agent and validate that it is correct.
+        agents = self.agents_client.list_agents()['agents']
+        agent = {'agent_type': None}
+        for a in agents:
+            if a['agent_type'] == 'DHCP agent':
+                agent = a
+                break
+        self.assertEqual(agent['agent_type'], 'DHCP agent', 'Could not find '
+                         'DHCP agent in agent list though dhcp_agent_scheduler'
+                         ' is enabled.')
+        self.agent = agent
+
+    def _create_and_prepare_network_for_agent(self, agent_id):
+        """Create network and ensure it is not hosted by agent_id."""
+        network_id = self.create_network()['id']
+
+        if self._check_network_in_dhcp_agent(network_id, agent_id):
+            self.agents_client.delete_network_from_dhcp_agent(
+                agent_id=agent_id, network_id=network_id)
+
+        return network_id
+
+    def _check_network_in_dhcp_agent(self, network_id, agent_id):
+        networks = self.agents_client.list_networks_hosted_by_one_dhcp_agent(
+            agent_id)['networks'] or []
+        return network_id in [network['id'] for network in networks]
+
+    @decorators.idempotent_id('dc84087b-4c2a-4878-8ed0-40370e19da17')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="get_dhcp-networks")
+    def test_list_networks_hosted_by_one_dhcp_agent(self):
+        """List networks hosted by one DHCP agent test.
+
+        RBAC test for the neutron get_dhcp-networks policy
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.agents_client.list_networks_hosted_by_one_dhcp_agent(
+            self.agent['id'])
+
+    @decorators.idempotent_id('14e014ac-f355-46d3-b6d8-98f2c9ec1610')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="create_dhcp-network")
+    def test_add_dhcp_agent_to_network(self):
+        """Add DHCP agent to network test.
+
+        RBAC test for the neutron create_dhcp-network policy
+        """
+        network_id = self._create_and_prepare_network_for_agent(
+            self.agent['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.agents_client.add_dhcp_agent_to_network(
+            self.agent['id'], network_id=network_id)
+        # Clean up is not necessary and might result in 409 being raised.
+
+    @decorators.idempotent_id('937a4302-4b49-407d-9980-5843d7badc38')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="delete_dhcp-network")
+    def test_delete_network_from_dhcp_agent(self):
+        """Delete DHCP agent from network test.
+
+        RBAC test for the neutron delete_dhcp-network policy
+        """
+        network_id = self._create_and_prepare_network_for_agent(
+            self.agent['id'])
+        self.agents_client.add_dhcp_agent_to_network(
+            self.agent['id'], network_id=network_id)
+        # Clean up is not necessary and might result in 409 being raised.
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.agents_client.delete_network_from_dhcp_agent(
+            self.agent['id'], network_id=network_id)
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 698d462..67b32a2 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
@@ -15,18 +15,14 @@
 
 import netaddr
 
-from oslo_log import log
 from tempest import config
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
-from tempest.lib import exceptions
 
-from patrole_tempest_plugin import rbac_exceptions
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.network import rbac_base as base
 
 CONF = config.CONF
-LOG = log.getLogger(__name__)
 
 
 class FloatingIpsRbacTest(base.BaseNetworkRbacTest):
@@ -69,10 +65,6 @@
 
         return floating_ip
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(FloatingIpsRbacTest, self).tearDown()
-
     @rbac_rule_validation.action(service="neutron",
                                  rule="create_floatingip")
     @decorators.idempotent_id('f8f7474c-b8a5-4174-af84-73097d6ced38')
@@ -81,7 +73,7 @@
 
         RBAC test for the neutron create_floatingip policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_floatingip()
 
     @rbac_rule_validation.action(service="neutron",
@@ -94,7 +86,7 @@
         """
         fip = str(netaddr.IPAddress(self.cidr) + 10)
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_floatingip(floating_ip_address=fip)
 
     @rbac_rule_validation.action(service="neutron",
@@ -106,13 +98,15 @@
         RBAC test for the neutron update_floatingip policy
         """
         floating_ip = self._create_floatingip()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
 
         # Associate floating IP to the other port
         self.floating_ips_client.update_floatingip(
             floating_ip['id'], port_id=None)
 
-    @rbac_rule_validation.action(service="neutron", rule="get_floatingip")
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="get_floatingip",
+                                 expected_error_code=404)
     @decorators.idempotent_id('f8846fd0-c976-48fe-a148-105303931b32')
     def test_show_floating_ip(self):
         """Show floating IP.
@@ -120,19 +114,13 @@
         RBAC test for the neutron get_floatingip policy
         """
         floating_ip = self._create_floatingip()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-
-        try:
-            # Show floating IP
-            self.floating_ips_client.show_floatingip(floating_ip['id'])
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        # Show floating IP
+        self.floating_ips_client.show_floatingip(floating_ip['id'])
 
     @rbac_rule_validation.action(service="neutron",
-                                 rule="delete_floatingip")
+                                 rule="delete_floatingip",
+                                 expected_error_code=404)
     @decorators.idempotent_id('2611b068-30d4-4241-a78f-1b801a14db7e')
     def test_delete_floating_ip(self):
         """Delete floating IP.
@@ -140,14 +128,6 @@
         RBAC test for the neutron delete_floatingip policy
         """
         floating_ip = self._create_floatingip()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-
-        try:
-            # Delete the floating IP
-            self.floating_ips_client.delete_floatingip(floating_ip['id'])
-
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        # Delete the floating IP
+        self.floating_ips_client.delete_floatingip(floating_ip['id'])
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 3f768e1..3c74c07 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,20 +13,16 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from oslo_log import log
 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
 from patrole_tempest_plugin.tests.api.network import rbac_base as base
 
 CONF = config.CONF
-LOG = log.getLogger(__name__)
 
 
 class MeteringLabelRulesRbacTest(base.BaseNetworkRbacTest):
@@ -41,12 +37,9 @@
     @classmethod
     def setup_clients(cls):
         super(MeteringLabelRulesRbacTest, cls).setup_clients()
-        cls.metering_labels_client = cls.os.metering_labels_client
-        cls.metering_label_rules_client = cls.os.metering_label_rules_client
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(MeteringLabelRulesRbacTest, self).tearDown()
+        cls.metering_labels_client = cls.os_primary.metering_labels_client
+        cls.metering_label_rules_client = \
+            cls.os_primary.metering_label_rules_client
 
     @classmethod
     def resource_setup(cls):
@@ -81,11 +74,12 @@
 
         RBAC test for the neutron create_metering_label_rule policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_metering_label_rule(self.label)
 
     @rbac_rule_validation.action(service="neutron",
-                                 rule="get_metering_label_rule")
+                                 rule="get_metering_label_rule",
+                                 expected_error_code=404)
     @decorators.idempotent_id('e21b40c3-d44d-412f-84ea-836ca8603bcb')
     def test_show_metering_label_rule(self):
         """Show metering label rule.
@@ -93,18 +87,13 @@
         RBAC test for the neutron get_metering_label_rule policy
         """
         label_rule = self._create_metering_label_rule(self.label)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.metering_label_rules_client.show_metering_label_rule(
-                label_rule['id'])
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.metering_label_rules_client.show_metering_label_rule(
+            label_rule['id'])
 
     @rbac_rule_validation.action(service="neutron",
-                                 rule="delete_metering_label_rule")
+                                 rule="delete_metering_label_rule",
+                                 expected_error_code=404)
     @decorators.idempotent_id('e3adc88c-05c0-43a7-8e32-63947ae4890e')
     def test_delete_metering_label_rule(self):
         """Delete metering label rule.
@@ -112,12 +101,6 @@
         RBAC test for the neutron delete_metering_label_rule policy
         """
         label_rule = self._create_metering_label_rule(self.label)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.metering_label_rules_client.delete_metering_label_rule(
-                label_rule['id'])
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.metering_label_rules_client.delete_metering_label_rule(
+            label_rule['id'])
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 70dab77..89c6870 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,19 +13,14 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from oslo_log import log
 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
 from patrole_tempest_plugin.tests.api.network import rbac_base as base
 
-LOG = log.getLogger(__name__)
-
 
 class MeteringLabelsRbacTest(base.BaseNetworkRbacTest):
 
@@ -39,11 +34,7 @@
     @classmethod
     def setup_clients(cls):
         super(MeteringLabelsRbacTest, cls).setup_clients()
-        cls.metering_labels_client = cls.os.metering_labels_client
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(MeteringLabelsRbacTest, self).tearDown()
+        cls.metering_labels_client = cls.os_primary.metering_labels_client
 
     def _create_metering_label(self):
         body = self.metering_labels_client.create_metering_label(
@@ -63,11 +54,12 @@
 
         RBAC test for the neutron "create_metering_label" policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_metering_label()
 
     @rbac_rule_validation.action(service="neutron",
-                                 rule="get_metering_label")
+                                 rule="get_metering_label",
+                                 expected_error_code=404)
     @decorators.idempotent_id('c57f6636-c702-4755-8eac-5e73bc1f7d14')
     def test_show_metering_label(self):
         """Show metering label.
@@ -75,17 +67,12 @@
         RBAC test for the neutron "get_metering_label" policy
         """
         label = self._create_metering_label()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.metering_labels_client.show_metering_label(label['id'])
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.metering_labels_client.show_metering_label(label['id'])
 
     @rbac_rule_validation.action(service="neutron",
-                                 rule="delete_metering_label")
+                                 rule="delete_metering_label",
+                                 expected_error_code=404)
     @decorators.idempotent_id('1621ccfe-2e3f-4d16-98aa-b620f9d00404')
     def test_delete_metering_label(self):
         """Delete metering label.
@@ -93,11 +80,5 @@
         RBAC test for the neutron "delete_metering_label" policy
         """
         label = self._create_metering_label()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.metering_labels_client.delete_metering_label(label['id'])
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.metering_labels_client.delete_metering_label(label['id'])
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 99552e0..01cf0fd 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
@@ -35,10 +35,6 @@
             msg = "multi-provider extension not enabled."
             raise cls.skipException(msg)
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(NetworksMultiProviderRbacTest, self).tearDown()
-
     def _create_network_segments(self):
         segments = [{"provider:network_type": "gre"},
                     {"provider:network_type": "gre"}]
@@ -60,7 +56,7 @@
 
         RBAC test for the neutron create_network:segments policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_network_segments()
 
     @rbac_rule_validation.action(service="neutron",
@@ -74,7 +70,7 @@
         network = self._create_network_segments()
         new_segments = [{"provider:network_type": "gre"}]
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.networks_client.update_network(network['id'],
                                             segments=new_segments)
 
@@ -88,7 +84,7 @@
         """
         network = self._create_network_segments()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         body = self.networks_client.show_network(network['id'],
                                                  fields='segments')
         response_network = body['network']
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 cb79742..b42be93 100644
--- a/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py
@@ -17,8 +17,8 @@
 
 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_exceptions
 from patrole_tempest_plugin import rbac_rule_validation
@@ -27,72 +27,37 @@
 CONF = config.CONF
 
 
-class RbacNetworksTest(base.BaseNetworkRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(RbacNetworksTest, cls).setup_clients()
-        cls.networks_client = cls.os.networks_client
-        cls.subnet_client = cls.os.subnets_client
+class NetworksRbacTest(base.BaseNetworkRbacTest):
 
     @classmethod
     def resource_setup(cls):
-        super(RbacNetworksTest, cls).resource_setup()
-
-        network_name = data_utils.rand_name('rbac-admin-network-')
-
-        post_body = {'name': network_name}
-        body = cls.networks_client.create_network(**post_body)
-        cls.admin_network = body['network']
-        cls.networks.append(cls.admin_network)
-
-        # Create a subnet by admin user
+        super(NetworksRbacTest, cls).resource_setup()
+        cls.network = cls.create_network()
         cls.cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
-
-        cls.admin_subnet = cls.create_subnet(cls.admin_network,
-                                             cidr=cls.cidr,
-                                             mask_bits=24,
-                                             enable_dhcp=False)
-
-    def _delete_network(self, network):
-        # Deleting network also deletes its subnets if exists
-        self.networks_client.delete_network(network['id'])
-        if network in self.networks:
-            self.networks.remove(network)
-        for subnet in self.subnets:
-            if subnet['network_id'] == network['id']:
-                self.subnets.remove(subnet)
+        cls.subnet = cls.create_subnet(
+            cls.network, cidr=cls.cidr, mask_bits=24, enable_dhcp=False)
 
     def _create_network(self,
-                        shared=None,
                         router_external=None,
                         router_private=None,
                         provider_network_type=None,
                         provider_physical_network=None,
-                        provider_segmentation_id=None):
-
-        network_name = data_utils.rand_name('test-network-')
-        post_body = {'name': network_name}
-
-        if shared is not None:
-            post_body['shared'] = shared
+                        provider_segmentation_id=None,
+                        **kwargs):
         if router_external is not None:
-            post_body['router:external'] = router_external
+            kwargs['router:external'] = router_external
         if router_private is not None:
-            post_body['router:private'] = router_private
+            kwargs['router:private'] = router_private
         if provider_network_type is not None:
-            post_body['provider:network_type'] = provider_network_type
+            kwargs['provider:network_type'] = provider_network_type
         if provider_physical_network is not None:
-            post_body['provider:physical_network'] = provider_physical_network
+            kwargs['provider:physical_network'] = provider_physical_network
         if provider_segmentation_id is not None:
-            post_body['provider:segmentation_id'] = provider_segmentation_id
+            kwargs['provider:segmentation_id'] = provider_segmentation_id
 
-        body = self.networks_client.create_network(**post_body)
-        network = body['network']
-
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self._delete_network, network)
-        self.assertEqual('ACTIVE', network['status'])
+        network_name = data_utils.rand_name(
+            self.__class__.__name__ + '-Network')
+        network = self.create_network(network_name=network_name, **kwargs)
         return network
 
     def _update_network(self,
@@ -101,36 +66,26 @@
                         shared_network=None,
                         router_external=None,
                         router_private=None,
-                        segments=None):
-
-        # update a network that has been created during class setup
+                        segments=None,
+                        **kwargs):
         if not net_id:
-            net_id = self.admin_network['id']
-
-        post_body = {}
-        updated_network = None
+            net_id = self.network['id']
 
         if admin is not None:
-            post_body['admin_state_up'] = admin
+            kwargs['admin_state_up'] = admin
         elif shared_network is not None:
-            post_body['shared'] = shared_network
+            kwargs['shared'] = shared_network
         elif router_external is not None:
-            post_body['router:external'] = router_external
+            kwargs['router:external'] = router_external
         elif router_private is not None:
-            post_body['router:private'] = router_private
+            kwargs['router:private'] = router_private
         elif segments is not None:
-            post_body['segments'] = segments
-        else:
-            return updated_network
+            kwargs['segments'] = segments
 
-        body = self.networks_client.update_network(net_id, **post_body)
-        updated_network = body['network']
+        updated_network = self.networks_client.update_network(
+            net_id, **kwargs)['network']
         return updated_network
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(RbacNetworksTest, self).tearDown()
-
     @rbac_rule_validation.action(service="neutron",
                                  rule="create_network")
     @decorators.idempotent_id('95b9baab-1ece-4e2b-89c8-8d671d974e54')
@@ -140,7 +95,7 @@
 
         RBAC test for the neutron create_network policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_network()
 
     @rbac_rule_validation.action(service="neutron",
@@ -152,9 +107,10 @@
 
         RBAC test for the neutron create_network:shared policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_network(shared=True)
 
+    @test.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')
@@ -164,9 +120,10 @@
 
         RBAC test for the neutron create_network:router:external policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_network(router_external=True)
 
+    @test.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')
@@ -176,9 +133,10 @@
 
         RBAC test for the neutron create_network:provider:network_type policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_network(provider_network_type='vxlan')
 
+    @test.requires_ext(extension='provider', service='network')
     @rbac_rule_validation.action(
         service="neutron",
         rule="create_network:provider:segmentation_id")
@@ -189,7 +147,7 @@
 
         RBAC test for the neutron create_network:provider:segmentation_id
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_network(provider_network_type='vxlan',
                              provider_segmentation_id=200)
 
@@ -202,13 +160,11 @@
 
         RBAC test for the neutron update_network policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        updated_network = self._update_network(admin=False)
-        self.assertEqual(updated_network['admin_state_up'], False)
+        updated_name = data_utils.rand_name(
+            self.__class__.__name__ + '-Network')
 
-        # Revert back to True
-        updated_network = self._update_network(admin=True)
-        self.assertEqual(updated_network['admin_state_up'], True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._update_network(name=updated_name)
 
     @rbac_rule_validation.action(service="neutron",
                                  rule="update_network:shared")
@@ -219,14 +175,11 @@
 
         RBAC test for the neutron update_network:shared policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        updated_network = self._update_network(shared_network=True)
-        self.assertEqual(updated_network['shared'], True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._update_network(shared_network=True)
+        self.addCleanup(self._update_network, shared_network=False)
 
-        # Revert back to False
-        updated_network = self._update_network(shared_network=False)
-        self.assertEqual(updated_network['shared'], False)
-
+    @test.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')
@@ -237,7 +190,7 @@
         RBAC test for the neutron update_network:router:external policy
         """
         network = self._create_network()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._update_network(net_id=network['id'], router_external=True)
 
     @rbac_rule_validation.action(service="neutron",
@@ -249,10 +202,10 @@
 
         RBAC test for the neutron get_network policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # show a network that has been created during class setup
-        self.networks_client.show_network(self.admin_network['id'])
+        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')
     @rbac_rule_validation.action(service="neutron",
                                  rule="get_network:router:external")
     @decorators.idempotent_id('529e4814-22e9-413f-af48-8fefcd637344')
@@ -262,12 +215,13 @@
 
         RBAC test for the neutron get_network:router:external policy
         """
-        post_body = {'fields': 'router:external'}
+        kwargs = {'fields': 'router:external'}
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.networks_client.show_network(self.admin_network['id'],
-                                          **post_body)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.networks_client.show_network(self.network['id'],
+                                          **kwargs)
 
+    @test.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')
@@ -277,16 +231,16 @@
 
         RBAC test for the neutron get_network:provider:network_type policy
         """
-        post_body = {'fields': 'provider:network_type'}
+        kwargs = {'fields': 'provider:network_type'}
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        body = self.networks_client.show_network(self.admin_network['id'],
-                                                 **post_body)
-        showed_net = body['network']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        retrieved_network = self.networks_client.show_network(
+            self.network['id'], **kwargs)['network']
 
-        if len(showed_net) == 0:
+        if len(retrieved_network) == 0:
             raise rbac_exceptions.RbacActionFailed
 
+    @test.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')
@@ -296,16 +250,16 @@
 
         RBAC test for the neutron get_network:provider:physical_network policy
         """
-        post_body = {'fields': 'provider:physical_network'}
+        kwargs = {'fields': 'provider:physical_network'}
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        body = self.networks_client.show_network(self.admin_network['id'],
-                                                 **post_body)
-        showed_net = body['network']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        retrieved_network = self.networks_client.show_network(
+            self.network['id'], **kwargs)['network']
 
-        if len(showed_net) == 0:
+        if len(retrieved_network) == 0:
             raise rbac_exceptions.RbacActionFailed
 
+    @test.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')
@@ -315,18 +269,17 @@
 
         RBAC test for the neutron get_network:provider:segmentation_id policy
         """
-        post_body = {'fields': 'provider:segmentation_id'}
+        kwargs = {'fields': 'provider:segmentation_id'}
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        body = self.networks_client.show_network(self.admin_network['id'],
-                                                 **post_body)
-        showed_net = body['network']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        retrieved_network = self.networks_client.show_network(
+            self.network['id'], **kwargs)['network']
 
-        if len(showed_net) == 0:
+        if len(retrieved_network) == 0:
             raise rbac_exceptions.RbacActionFailed
 
-        key = showed_net.get('provider:segmentation_id', "NotFound")
-        self.assertIsNot(key, "NotFound")
+        key = retrieved_network.get('provider:segmentation_id', "NotFound")
+        self.assertNotEqual(key, "NotFound")
 
     @rbac_rule_validation.action(service="neutron",
                                  rule="delete_network")
@@ -338,7 +291,7 @@
         RBAC test for the neutron delete_network policy
         """
         network = self._create_network()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.networks_client.delete_network(network['id'])
 
     @rbac_rule_validation.action(service="neutron",
@@ -351,10 +304,8 @@
         RBAC test for the neutron create_subnet policy
         """
         network = self._create_network()
-        self.assertEqual('ACTIVE', network['status'])
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # Create a subnet
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.create_subnet(network, enable_dhcp=False)
 
     @rbac_rule_validation.action(service="neutron",
@@ -366,8 +317,8 @@
 
         RBAC test for the neutron get_subnet policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.subnets_client.show_subnet(self.admin_subnet['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.subnets_client.show_subnet(self.subnet['id'])
 
     @rbac_rule_validation.action(service="neutron",
                                  rule="update_subnet")
@@ -378,9 +329,12 @@
 
         RBAC test for the neutron update_subnet policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.subnets_client.update_subnet(self.admin_subnet['id'],
-                                          name="New_subnet")
+        updated_name = data_utils.rand_name(
+            self.__class__.__name__ + '-Network')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.subnets_client.update_subnet(self.subnet['id'],
+                                          name=updated_name)
 
     @rbac_rule_validation.action(service="neutron",
                                  rule="delete_subnet")
@@ -391,13 +345,22 @@
 
         RBAC test for the neutron delete_subnet policy
         """
-        # Create a network using admin privilege
         network = self._create_network()
-        self.assertEqual('ACTIVE', network['status'])
-
-        # Create a subnet using admin privilege
         subnet = self.create_subnet(network, enable_dhcp=False)
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # Delete the subnet
+        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')
+    @decorators.idempotent_id('b524f19f-fbb4-4d11-a85d-03bfae17bf0e')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="get_dhcp-agents")
+    def test_list_dhcp_agents_on_hosting_network(self):
+
+        """List DHCP Agents on Hosting Network Test
+
+        RBAC test for the neutron "get_dhcp-agents" policy
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.networks_client.list_dhcp_agents_on_hosting_network(
+            self.network['id'])
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 65d9fee..cec860c 100644
--- a/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py
@@ -13,22 +13,20 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 #
-import netaddr
-import random
 
-from oslo_log import log
+import netaddr
+
+from tempest.common.utils import net_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.lib import exceptions
+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.network import rbac_base as base
 
 CONF = config.CONF
-LOG = log.getLogger(__name__)
 
 
 class PortsRbacTest(base.BaseNetworkRbacTest):
@@ -36,89 +34,64 @@
     @classmethod
     def resource_setup(cls):
         super(PortsRbacTest, cls).resource_setup()
-        cls.admin_network = cls.create_network()
-
-        # Create a subnet by admin user
+        # Create a network and subnet.
+        cls.network = cls.create_network()
         cls.cidr = netaddr.IPNetwork(CONF.network.project_network_cidr)
+        cls.subnet = cls.create_subnet(cls.network, cidr=cls.cidr,
+                                       mask_bits=24)
+        cls.ip_range = netaddr.IPRange(
+            cls.subnet['allocation_pools'][0]['start'],
+            cls.subnet['allocation_pools'][0]['end'])
 
-        cls.admin_subnet = cls.create_subnet(cls.admin_network,
-                                             cidr=cls.cidr,
-                                             mask_bits=24)
-        cls.admin_ip_range = netaddr.IPRange(
-            cls.admin_subnet['allocation_pools'][0]['start'],
-            cls.admin_subnet['allocation_pools'][0]['end'])
+        cls.port = cls.create_port(cls.network)
+        ipaddr = cls.port['fixed_ips'][0]['ip_address']
+        cls.port_ip_address = ipaddr
+        cls.port_mac_address = cls.port['mac_address']
 
-        # Create a port by admin user
-        body = cls.ports_client.create_port(network_id=cls.admin_network['id'])
-        cls.admin_port = body['port']
-        cls.ports.append(cls.admin_port)
-        ipaddr = cls.admin_port['fixed_ips'][0]['ip_address']
-        cls.admin_port_ip_address = ipaddr
-        cls.admin_port_mac_address = cls.admin_port['mac_address']
-
-    def _create_port(self, **post_body):
-
-        body = self.ports_client.create_port(**post_body)
-        port = body['port']
-
-        # Schedule port deletion with verification upon test completion
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.ports_client.delete_port,
-                        port['id'])
-
-        return port
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(PortsRbacTest, self).tearDown()
+    def _get_unused_ip_address(self):
+        # Pick an unused ip address.
+        ip_list = net_utils.get_unused_ip_addresses(self.ports_client,
+                                                    self.subnets_client,
+                                                    self.network['id'],
+                                                    self.subnet['id'],
+                                                    1)
+        return ip_list
 
     @rbac_rule_validation.action(service="neutron",
                                  rule="create_port")
     @decorators.idempotent_id('0ec8c551-625c-4864-8a52-85baa7c40f22')
     def test_create_port(self):
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        post_body = {'network_id': self.admin_network['id']}
-        self._create_port(**post_body)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.create_port(self.network)
 
+    @decorators.idempotent_id('045ee797-4962-4913-b96a-5d7ea04099e7')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="create_port:device_owner")
+    def test_create_port_device_owner(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.create_port(self.network, device_owner='network:router_interface')
+
+    @decorators.idempotent_id('c4fa8844-f5ef-4daa-bfa2-b89897dfaedf')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="create_port:port_security_enabled")
+    def test_create_port_security_enabled(self):
+        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')
     @rbac_rule_validation.action(service="neutron",
                                  rule="create_port:binding:host_id")
     @decorators.idempotent_id('a54bd6b8-a7eb-4101-bfe8-093930b0d660')
     def test_create_port_binding_host_id(self):
 
-        post_body = {'network_id': self.admin_network['id'],
+        post_body = {'network': self.network,
                      'binding:host_id': "rbac_test_host"}
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_port(**post_body)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.create_port(**post_body)
 
-    @rbac_rule_validation.action(service="neutron",
-                                 rule="create_port:fixed_ips")
-    @decorators.idempotent_id('2551e10d-006a-413c-925a-8c6f834c09ac')
-    def test_create_port_fixed_ips(self):
-        # Pick an ip address within the allocation_pools range
-        ip_address = random.choice(list(self.admin_ip_range))
-
-        fixed_ips = [{'ip_address': ip_address},
-                     {'subnet_id': self.admin_subnet['id']}]
-
-        post_body = {'network_id': self.admin_network['id'],
-                     'fixed_ips': fixed_ips}
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_port(**post_body)
-
-    @rbac_rule_validation.action(service="neutron",
-                                 rule="create_port:mac_address")
-    @decorators.idempotent_id('aee6d0be-a7f3-452f-aefc-796b4eb9c9a8')
-    def test_create_port_mac_address(self):
-
-        post_body = {'network_id': self.admin_network['id'],
-                     'mac_address': data_utils.rand_mac_address()}
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_port(**post_body)
-
+    @test.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')
@@ -126,11 +99,37 @@
 
         binding_profile = {"foo": "1"}
 
-        post_body = {'network_id': self.admin_network['id'],
+        post_body = {'network': self.network,
                      'binding:profile': binding_profile}
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_port(**post_body)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.create_port(**post_body)
+
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="create_port:fixed_ips")
+    @decorators.idempotent_id('2551e10d-006a-413c-925a-8c6f834c09ac')
+    def test_create_port_fixed_ips(self):
+
+        ip_list = self._get_unused_ip_address()
+        fixed_ips = [{'ip_address': ip_list[0]},
+                     {'subnet_id': self.subnet['id']}]
+
+        post_body = {'network': self.network,
+                     'fixed_ips': fixed_ips}
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.create_port(**post_body)
+
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="create_port:mac_address")
+    @decorators.idempotent_id('aee6d0be-a7f3-452f-aefc-796b4eb9c9a8')
+    def test_create_port_mac_address(self):
+
+        post_body = {'network': self.network,
+                     'mac_address': data_utils.rand_mac_address()}
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.create_port(**post_body)
 
     @rbac_rule_validation.action(service="neutron",
                                  rule="create_port:allowed_address_pairs")
@@ -138,30 +137,24 @@
     def test_create_port_allowed_address_pairs(self):
 
         # Create port with allowed address pair attribute
-        allowed_address_pairs = [{'ip_address': self.admin_port_ip_address,
-                                  'mac_address': self.admin_port_mac_address}]
+        allowed_address_pairs = [{'ip_address': self.port_ip_address,
+                                  'mac_address': self.port_mac_address}]
 
-        post_body = {'network_id': self.admin_network['id'],
+        post_body = {'network': self.network,
                      'allowed_address_pairs': allowed_address_pairs}
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._create_port(**post_body)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.create_port(**post_body)
 
-    @rbac_rule_validation.action(service="neutron", rule="get_port")
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="get_port",
+                                 expected_error_code=404)
     @decorators.idempotent_id('a9d41cb8-78a2-4b97-985c-44e4064416f4')
     def test_show_port(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.ports_client.show_port(self.port['id'])
 
-        try:
-            self.rbac_utils.switch_role(self, switchToRbacRole=True)
-
-            self.ports_client.show_port(self.admin_port['id'])
-
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
-
+    @test.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')
@@ -170,17 +163,16 @@
         # Verify specific fields of a port
         fields = ['binding:vif_type']
 
-        try:
-            self.rbac_utils.switch_role(self, switchToRbacRole=True)
-            self.ports_client.show_port(self.admin_port['id'],
-                                        fields=fields)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
 
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        retrieved_port = self.ports_client.show_port(
+            self.port['id'], fields=fields)['port']
 
+        # Rather than throwing a 403, the field is not present, so raise exc.
+        if fields[0] not in retrieved_port:
+            raise rbac_exceptions.RbacActionFailed
+
+    @test.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')
@@ -189,17 +181,16 @@
         # Verify specific fields of a port
         fields = ['binding:vif_details']
 
-        try:
-            self.rbac_utils.switch_role(self, switchToRbacRole=True)
-            self.ports_client.show_port(self.admin_port['id'],
-                                        fields=fields)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
 
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        retrieved_port = self.ports_client.show_port(
+            self.port['id'], fields=fields)['port']
 
+        # Rather than throwing a 403, the field is not present, so raise exc.
+        if fields[0] not in retrieved_port:
+            raise rbac_exceptions.RbacActionFailed
+
+    @test.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')
@@ -207,21 +198,19 @@
 
         # Verify specific fields of a port
         fields = ['binding:host_id']
-        post_body = {'network_id': self.admin_network['id'],
+        post_body = {'network': self.network,
                      'binding:host_id': data_utils.rand_name('host-id')}
-        port = self._create_port(**post_body)
+        port = self.create_port(**post_body)
 
-        try:
-            self.rbac_utils.switch_role(self, switchToRbacRole=True)
-            self.ports_client.show_port(port['id'],
-                                        fields=fields)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        retrieved_port = self.ports_client.show_port(
+            port['id'], fields=fields)['port']
 
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        # Rather than throwing a 403, the field is not present, so raise exc.
+        if fields[0] not in retrieved_port:
+            raise rbac_exceptions.RbacActionFailed
 
+    @test.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')
@@ -230,98 +219,106 @@
         # Verify specific fields of a port
         fields = ['binding:profile']
         binding_profile = {"foo": "1"}
-        post_body = {'network_id': self.admin_network['id'],
+        post_body = {'network': self.network,
                      'binding:profile': binding_profile}
-        port = self._create_port(**post_body)
+        port = self.create_port(**post_body)
 
-        try:
-            self.rbac_utils.switch_role(self, switchToRbacRole=True)
-            self.ports_client.show_port(port['id'],
-                                        fields=fields)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        retrieved_port = self.ports_client.show_port(
+            port['id'], fields=fields)['port']
 
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        # Rather than throwing a 403, the field is not present, so raise exc.
+        if fields[0] not in retrieved_port:
+            raise rbac_exceptions.RbacActionFailed
 
     @rbac_rule_validation.action(service="neutron",
                                  rule="update_port")
     @decorators.idempotent_id('afa80981-3c59-42fd-9531-3bcb2cd03711')
     def test_update_port(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.ports_client.update_port(self.port['id'], admin_state_up=False)
+        self.addCleanup(self.ports_client.update_port, self.port['id'],
+                        admin_state_up=True)
 
-        port = self.create_port(self.admin_network)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.ports_client.update_port(port['id'],
-                                      admin_state_up=False)
+    @decorators.idempotent_id('08d70f59-67cb-4fb1-bd6c-a5e59dd5db2b')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="update_port:device_owner")
+    def test_update_port_device_owner(self):
+        original_device_owner = self.port['device_owner']
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.ports_client.update_port(
+            self.port['id'], device_owner='network:router_interface')
+        self.addCleanup(self.ports_client.update_port, self.port['id'],
+                        device_owner=original_device_owner)
 
     @rbac_rule_validation.action(service="neutron",
                                  rule="update_port:mac_address")
     @decorators.idempotent_id('507140c8-7b14-4d63-b627-2103691d887e')
     def test_update_port_mac_address(self):
+        original_mac_address = self.port['mac_address']
 
-        port = self.create_port(self.admin_network)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.ports_client.update_port(
-            port['id'],
-            mac_address=data_utils.rand_mac_address())
+            self.port['id'], mac_address=data_utils.rand_mac_address())
+        self.addCleanup(self.ports_client.update_port, self.port['id'],
+                        mac_address=original_mac_address)
 
     @rbac_rule_validation.action(service="neutron",
                                  rule="update_port:fixed_ips")
     @decorators.idempotent_id('c091c825-532b-4c6f-a14f-affd3259c1c3')
     def test_update_port_fixed_ips(self):
 
-        # Pick an ip address within the allocation_pools range
-        ip_address = random.choice(list(self.admin_ip_range))
-        fixed_ips = [{'ip_address': ip_address}]
-        post_body = {'network_id': self.admin_network['id']}
-        port = self._create_port(**post_body)
+        # Pick an ip address within the allocation_pools range.
+        post_body = {'network': self.network}
+        port = self.create_port(**post_body)
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.ports_client.update_port(port['id'],
-                                      fixed_ips=fixed_ips)
+        ip_list = self._get_unused_ip_address()
+        fixed_ips = [{'ip_address': ip_list[0]}]
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.ports_client.update_port(port['id'], fixed_ips=fixed_ips)
 
     @rbac_rule_validation.action(service="neutron",
                                  rule="update_port:port_security_enabled")
     @decorators.idempotent_id('795541af-6652-4e35-9581-fd58224f7545')
     def test_update_port_security_enabled(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.ports_client.update_port(self.port['id'], security_groups=[])
 
-        port = self.create_port(self.admin_network)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.ports_client.update_port(port['id'],
-                                      security_groups=[])
-
+    @test.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')
     def test_update_port_binding_host_id(self):
 
-        post_body = {'network_id': self.admin_network['id'],
+        post_body = {'network': self.network,
                      'binding:host_id': 'rbac_test_host'}
-        port = self._create_port(**post_body)
+        port = self.create_port(**post_body)
 
         updated_body = {'port_id': port['id'],
                         'binding:host_id': 'rbac_test_host_updated'}
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.ports_client.update_port(**updated_body)
 
+    @test.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')
     def test_update_port_binding_profile(self):
 
         binding_profile = {"foo": "1"}
-        post_body = {'network_id': self.admin_network['id'],
+        post_body = {'network': self.network,
                      'binding:profile': binding_profile}
 
-        port = self._create_port(**post_body)
+        port = self.create_port(**post_body)
 
         new_binding_profile = {"foo": "2"}
         updated_body = {'port_id': port['id'],
                         'binding:profile': new_binding_profile}
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.ports_client.update_port(**updated_body)
 
     @rbac_rule_validation.action(service="neutron",
@@ -329,29 +326,23 @@
     @decorators.idempotent_id('729c2151-bb49-4f4f-9d58-3ed8819b7582')
     def test_update_port_allowed_address_pairs(self):
 
-        ip_address = random.choice(list(self.admin_ip_range))
+        ip_list = self._get_unused_ip_address()
         # Update allowed address pair attribute of port
-        address_pairs = [{'ip_address': ip_address,
+        address_pairs = [{'ip_address': ip_list[0],
                           'mac_address': data_utils.rand_mac_address()}]
-        post_body = {'network_id': self.admin_network['id']}
-        port = self._create_port(**post_body)
+        post_body = {'network': self.network}
+        port = self.create_port(**post_body)
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.ports_client.update_port(port['id'],
                                       allowed_address_pairs=address_pairs)
 
     @rbac_rule_validation.action(service="neutron",
-                                 rule="delete_port")
+                                 rule="delete_port",
+                                 expected_error_code=404)
     @decorators.idempotent_id('1cf8e582-bc09-46cb-b32a-82bf991ad56f')
     def test_delete_port(self):
 
-        try:
-            port = self._create_port(network_id=self.admin_network['id'])
-            self.rbac_utils.switch_role(self, switchToRbacRole=True)
-            self.ports_client.delete_port(port['id'])
-
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        port = self.create_port(self.network)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.ports_client.delete_port(port['id'])
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 580b064..6aec5d1 100644
--- a/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py
@@ -14,23 +14,17 @@
 #    under the License.
 
 import netaddr
-import random
 
-from oslo_log import log
-from tempest import config
+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.lib import exceptions
 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.network import rbac_base as base
 
-CONF = config.CONF
-LOG = log.getLogger(__name__)
-
 
 class RouterRbacTest(base.BaseNetworkRbacTest):
     @classmethod
@@ -43,18 +37,23 @@
     @classmethod
     def resource_setup(cls):
         super(RouterRbacTest, cls).resource_setup()
-        post_body = {}
-        post_body['router:external'] = True
-        cls.admin_network = cls.create_network(**post_body)
-        cls.admin_subnet = cls.create_subnet(cls.admin_network)
-        cls.admin_ip_range = netaddr.IPRange(
-            cls.admin_subnet['allocation_pools'][0]['start'],
-            cls.admin_subnet['allocation_pools'][0]['end'])
-        cls.admin_router = cls.create_router()
+        # Create a network with external gateway so that
+        # ``external_gateway_info`` policies can be validated.
+        post_body = {'router:external': True}
+        cls.network = cls.create_network(**post_body)
+        cls.subnet = cls.create_subnet(cls.network)
+        cls.ip_range = netaddr.IPRange(
+            cls.subnet['allocation_pools'][0]['start'],
+            cls.subnet['allocation_pools'][0]['end'])
+        cls.router = cls.create_router()
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(RouterRbacTest, self).tearDown()
+    def _get_unused_ip_address(self):
+        unused_ip = net_utils.get_unused_ip_addresses(self.ports_client,
+                                                      self.subnets_client,
+                                                      self.network['id'],
+                                                      self.subnet['id'],
+                                                      1)
+        return unused_ip[0]
 
     @rbac_rule_validation.action(service="neutron",
                                  rule="create_router")
@@ -64,11 +63,40 @@
 
         RBAC test for the neutron create_router policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         router = self.routers_client.create_router()
         self.addCleanup(self.routers_client.delete_router,
                         router['router']['id'])
 
+    @decorators.idempotent_id('6139eb97-95c0-40d8-a109-99de11ab2e5e')
+    @test.requires_ext(extension='l3-ha', service='network')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="create_router:ha")
+    def test_create_high_availability_router(self):
+        """Create high-availability router
+
+        RBAC test for the neutron create_router:ha policy
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        router = self.routers_client.create_router(ha=True)
+        self.addCleanup(self.routers_client.delete_router,
+                        router['router']['id'])
+
+    @decorators.idempotent_id('c6254ca6-2728-412d-803d-d4aa3935e56d')
+    @test.requires_ext(extension='dvr', service='network')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="create_router:distributed")
+    def test_create_distributed_router(self):
+        """Create distributed router
+
+        RBAC test for the neutron create_router:distributed policy
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        router = self.routers_client.create_router(distributed=True)
+        self.addCleanup(self.routers_client.delete_router,
+                        router['router']['id'])
+
+    @test.requires_ext(extension='ext-gw-mode', service='network')
     @rbac_rule_validation.action(
         service="neutron",
         rule="create_router:external_gateway_info:enable_snat")
@@ -79,11 +107,11 @@
         RBAC test for the neutron
         create_router:external_gateway_info:enable_snat policy
         """
-        name = data_utils.rand_name('snat-router')
-        external_gateway_info = {'network_id': self.admin_network['id'],
+        name = data_utils.rand_name(self.__class__.__name__ + '-snat-router')
+        external_gateway_info = {'network_id': self.network['id'],
                                  'enable_snat': True}
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         router = self.routers_client.create_router(
             name=name, external_gateway_info=external_gateway_info)
         self.addCleanup(self.routers_client.delete_router,
@@ -99,37 +127,54 @@
         RBAC test for the neutron
         create_router:external_gateway_info:external_fixed_ips policy
         """
-        name = data_utils.rand_name('snat-router')
-        # Pick an ip address within the allocation_pools range
-        ip_address = random.choice(list(self.admin_ip_range))
-        external_fixed_ips = {'subnet_id': self.admin_subnet['id'],
-                              'ip_address': ip_address}
+        name = data_utils.rand_name(self.__class__.__name__ + '-snat-router')
 
-        external_gateway_info = {'network_id': self.admin_network['id'],
-                                 'enable_snat': False,
+        unused_ip = self._get_unused_ip_address()
+        external_fixed_ips = {'subnet_id': self.subnet['id'],
+                              'ip_address': unused_ip}
+        external_gateway_info = {'network_id': self.network['id'],
+                                 'enable_snat': False,  # Default is True.
                                  'external_fixed_ips': [external_fixed_ips]}
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         router = self.routers_client.create_router(
             name=name, external_gateway_info=external_gateway_info)
         self.addCleanup(self.routers_client.delete_router,
                         router['router']['id'])
 
-    @rbac_rule_validation.action(service="neutron", rule="get_router")
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="get_router",
+                                 expected_error_code=404)
     @decorators.idempotent_id('bfbdbcff-f115-4d3e-8cd5-6ada33fd0e21')
     def test_show_router(self):
         """Get Router
 
         RBAC test for the neutron get_router policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.routers_client.show_router(self.admin_router['id'])
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        # Prevent other policies from being enforced by using barebones fields.
+        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')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="get_router:distributed")
+    def test_show_distributed_router(self):
+        """Get distributed router
+
+        RBAC test for the neutron get_router:distributed policy
+        """
+        router = self.routers_client.create_router(distributed=True)['router']
+        self.addCleanup(self.routers_client.delete_router, router['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        retrieved_fields = self.routers_client.show_router(
+            router['id'], fields=['distributed'])['router']
+
+        # Rather than throwing a 403, the field is not present, so raise exc.
+        if 'distributed' not in retrieved_fields:
+            raise rbac_exceptions.RbacActionFailed(
+                '"distributed" parameter not present in response body')
 
     @rbac_rule_validation.action(
         service="neutron", rule="update_router")
@@ -139,10 +184,10 @@
 
         RBAC test for the neutron update_router policy
         """
-        new_name = data_utils.rand_name('new-router-name')
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.routers_client.update_router(self.admin_router['id'],
-                                          name=new_name)
+        new_name = data_utils.rand_name(
+            self.__class__.__name__ + '-new-router-name')
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.routers_client.update_router(self.router['id'], name=new_name)
 
     @rbac_rule_validation.action(
         service="neutron", rule="update_router:external_gateway_info")
@@ -153,8 +198,8 @@
         RBAC test for the neutron
         update_router:external_gateway_info policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.routers_client.update_router(self.admin_router['id'],
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.routers_client.update_router(self.router['id'],
                                           external_gateway_info={})
 
     @rbac_rule_validation.action(
@@ -167,11 +212,16 @@
         RBAC test for the neutron
         update_router:external_gateway_info:network_id policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.routers_client.update_router(
-            self.admin_router['id'],
-            external_gateway_info={'network_id': self.admin_network['id']})
+            self.router['id'],
+            external_gateway_info={'network_id': self.network['id']})
+        self.addCleanup(
+            self.routers_client.update_router,
+            self.router['id'],
+            external_gateway_info=None)
 
+    @test.requires_ext(extension='ext-gw-mode', service='network')
     @rbac_rule_validation.action(
         service="neutron",
         rule="update_router:external_gateway_info:enable_snat")
@@ -182,11 +232,15 @@
         RBAC test for the neutron
         update_router:external_gateway_info:enable_snat policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.routers_client.update_router(
-            self.admin_router['id'],
-            external_gateway_info={'network_id': self.admin_network['id'],
+            self.router['id'],
+            external_gateway_info={'network_id': self.network['id'],
                                    'enable_snat': True})
+        self.addCleanup(
+            self.routers_client.update_router,
+            self.router['id'],
+            external_gateway_info=None)
 
     @rbac_rule_validation.action(
         service="neutron",
@@ -198,24 +252,52 @@
         RBAC test for the neutron
         update_router:external_gateway_info:external_fixed_ips policy
         """
-        # Pick an ip address within the allocation_pools range
-        ip_address = random.choice(list(self.admin_ip_range))
-        external_fixed_ips = {'subnet_id': self.admin_subnet['id'],
-                              'ip_address': ip_address}
-        external_gateway_info = {'network_id': self.admin_network['id'],
+        unused_ip = self._get_unused_ip_address()
+        external_fixed_ips = {'subnet_id': self.subnet['id'],
+                              'ip_address': unused_ip}
+        external_gateway_info = {'network_id': self.network['id'],
                                  'external_fixed_ips': [external_fixed_ips]}
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.routers_client.update_router(
-            self.admin_router['id'],
+            self.router['id'],
             external_gateway_info=external_gateway_info)
         self.addCleanup(
             self.routers_client.update_router,
-            self.admin_router['id'],
+            self.router['id'],
             external_gateway_info=None)
 
+    @decorators.idempotent_id('ddc20731-dea1-4321-9abf-8772bf0b5977')
+    @test.requires_ext(extension='l3-ha', service='network')
     @rbac_rule_validation.action(service="neutron",
-                                 rule="delete_router")
+                                 rule="update_router:ha")
+    def test_update_high_availability_router(self):
+        """Update high-availability router
+
+        RBAC test for the neutron update_router:ha policy
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.routers_client.update_router(self.router['id'], ha=True)
+        self.addCleanup(self.routers_client.update_router, self.router['id'],
+                        ha=False)
+
+    @decorators.idempotent_id('e1932c19-8f73-41cd-b5d2-84c7ae5d530c')
+    @test.requires_ext(extension='dvr', service='network')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="update_router:distributed")
+    def test_update_distributed_router(self):
+        """Update distributed router
+
+        RBAC test for the neutron update_router:distributed policy
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.routers_client.update_router(self.router['id'], distributed=True)
+        self.addCleanup(self.routers_client.update_router, self.router['id'],
+                        distributed=False)
+
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="delete_router",
+                                 expected_error_code=404)
     @decorators.idempotent_id('c0634dd5-0467-48f7-a4ae-1014d8edb2a7')
     def test_delete_router(self):
         """Delete Router
@@ -223,17 +305,12 @@
         RBAC test for the neutron delete_router policy
         """
         router = self.create_router()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.routers_client.delete_router(router['id'])
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.routers_client.delete_router(router['id'])
 
     @rbac_rule_validation.action(service="neutron",
-                                 rule="add_router_interface")
+                                 rule="add_router_interface",
+                                 expected_error_code=404)
     @decorators.idempotent_id('a0627778-d68d-4913-881b-e345360cca19')
     def test_add_router_interfaces(self):
         """Add Router Interface
@@ -244,23 +321,18 @@
         subnet = self.create_subnet(network)
         router = self.create_router()
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.routers_client.add_router_interface(
-                router['id'], subnet_id=subnet['id'])
-            self.addCleanup(
-                test_utils.call_and_ignore_notfound_exc,
-                self.routers_client.remove_router_interface,
-                router['id'],
-                subnet_id=subnet['id'])
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.routers_client.add_router_interface(
+            router['id'], subnet_id=subnet['id'])
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.routers_client.remove_router_interface,
+            router['id'],
+            subnet_id=subnet['id'])
 
     @rbac_rule_validation.action(service="neutron",
-                                 rule="remove_router_interface")
+                                 rule="remove_router_interface",
+                                 expected_error_code=404)
     @decorators.idempotent_id('ff2593a4-2bff-4c27-97d3-dd3702b27dfb')
     def test_remove_router_interfaces(self):
         """Remove Router Interface
@@ -279,13 +351,7 @@
                         router['id'],
                         subnet_id=subnet['id'])
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.routers_client.remove_router_interface(
-                router['id'],
-                subnet_id=subnet['id'])
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.routers_client.remove_router_interface(
+            router['id'],
+            subnet_id=subnet['id'])
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 25f1acf..2672b57 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,30 +13,28 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from oslo_log import log
-
 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
 from patrole_tempest_plugin.tests.api.network import rbac_base as base
 
-LOG = log.getLogger(__name__)
-
 
 class SecGroupRbacTest(base.BaseNetworkRbacTest):
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(SecGroupRbacTest, self).tearDown()
+    @classmethod
+    def skip_checks(cls):
+        super(SecGroupRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('security-group', 'network'):
+            msg = "security-group extension not enabled."
+            raise cls.skipException(msg)
 
     @classmethod
     def resource_setup(cls):
         super(SecGroupRbacTest, cls).resource_setup()
-        secgroup_name = data_utils.rand_name('secgroup')
+        secgroup_name = data_utils.rand_name(cls.__name__ + '-secgroup')
         cls.secgroup = cls.security_groups_client.create_security_group(
             name=secgroup_name)['security_group']
 
@@ -50,7 +48,7 @@
 
     def _create_security_group(self):
         # Create a security group
-        name = data_utils.rand_name('secgroup')
+        name = data_utils.rand_name(self.__class__.__name__ + '-secgroup')
         security_group =\
             self.security_groups_client.create_security_group(
                 name=name)['security_group']
@@ -80,64 +78,51 @@
     @decorators.idempotent_id('db7003ce-5717-4e5b-afc7-befa35e8c67f')
     def test_create_security_group(self):
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_security_group()
 
     @rbac_rule_validation.action(service="neutron",
-                                 rule="get_security_group")
+                                 rule="get_security_group",
+                                 expected_error_code=404)
     @decorators.idempotent_id('56335e77-aef2-4b54-86c7-7f772034b585')
     def test_show_security_groups(self):
 
-        try:
-            self.rbac_utils.switch_role(self, switchToRbacRole=True)
-            self.security_groups_client.show_security_group(
-                self.secgroup['id'])
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.security_groups_client.show_security_group(
+            self.secgroup['id'])
 
     @rbac_rule_validation.action(service="neutron",
-                                 rule="delete_security_group")
+                                 rule="delete_security_group",
+                                 expected_error_code=404)
     @decorators.idempotent_id('0b1330fd-dd28-40f3-ad73-966052e4b3de')
     def test_delete_security_group(self):
 
         # Create a security group
         secgroup_id = self._create_security_group()['id']
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.security_groups_client.delete_security_group(secgroup_id)
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.security_groups_client.delete_security_group(secgroup_id)
 
     @rbac_rule_validation.action(service="neutron",
-                                 rule="update_security_group")
+                                 rule="update_security_group",
+                                 expected_error_code=404)
     @decorators.idempotent_id('56c5e4dc-f8aa-11e6-bc64-92361f002671')
     def test_update_security_group(self):
 
         # Create a security group
         secgroup_id = self._create_security_group()['id']
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.security_groups_client.update_security_group(
-                secgroup_id,
-                description="test description")
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.security_groups_client.update_security_group(
+            secgroup_id,
+            description="test description")
 
     @rbac_rule_validation.action(service="neutron",
                                  rule="get_security_groups")
     @decorators.idempotent_id('fbaf8d96-ed3e-49af-b24c-5fb44f05bbb7')
     def test_list_security_groups(self):
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.security_groups_client.list_security_groups()
 
     @rbac_rule_validation.action(service="neutron",
@@ -145,47 +130,35 @@
     @decorators.idempotent_id('953d78df-00cd-416f-9cbd-b7cb4ea65772')
     def test_create_security_group_rule(self):
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_security_group_rule()
 
     @rbac_rule_validation.action(service="neutron",
-                                 rule="delete_security_group_rule")
+                                 rule="delete_security_group_rule",
+                                 expected_error_code=404)
     @decorators.idempotent_id('2262539e-b7d9-438c-acf9-a5ce0613be28')
     def test_delete_security_group_rule(self):
 
         sec_group_rule = self._create_security_group_rule()
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.security_group_rules_client.delete_security_group_rule(
-                sec_group_rule['id'])
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.security_group_rules_client.delete_security_group_rule(
+            sec_group_rule['id'])
 
     @rbac_rule_validation.action(service="neutron",
-                                 rule="get_security_group_rule")
+                                 rule="get_security_group_rule",
+                                 expected_error_code=404)
     @decorators.idempotent_id('84b4038c-261e-4a94-90d5-c885739ab0d5')
     def test_show_security_group_rule(self):
 
         sec_group_rule = self._create_security_group_rule()
-
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.security_group_rules_client.show_security_group_rule(
-                sec_group_rule['id'])
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.security_group_rules_client.show_security_group_rule(
+            sec_group_rule['id'])
 
     @rbac_rule_validation.action(service="neutron",
                                  rule="get_security_group_rules")
     @decorators.idempotent_id('05739ab6-fa35-11e6-bc64-92361f002671')
     def test_list_security_group_rules(self):
 
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.security_group_rules_client.list_security_group_rules()
diff --git a/patrole_tempest_plugin/tests/api/network/test_service_providers_rbac.py b/patrole_tempest_plugin/tests/api/network/test_service_providers_rbac.py
new file mode 100644
index 0000000..e111ae8
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/network/test_service_providers_rbac.py
@@ -0,0 +1,29 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.network import rbac_base as base
+
+
+class ServiceProvidersRbacTest(base.BaseNetworkRbacTest):
+
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="get_service_provider")
+    @decorators.idempotent_id('15f573b7-474a-4b37-8629-7fac86553ce5')
+    def test_list_service_providers(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.service_providers_client.list_service_providers()
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 ce38aea..8c799b6 100644
--- a/patrole_tempest_plugin/tests/api/network/test_subnetpools_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_subnetpools_rbac.py
@@ -13,20 +13,16 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from oslo_log import log
 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
 from patrole_tempest_plugin.tests.api.network import rbac_base as base
 
 CONF = config.CONF
-LOG = log.getLogger(__name__)
 
 
 class SubnetPoolsRbacTest(base.BaseNetworkRbacTest):
@@ -38,18 +34,14 @@
             msg = "subnet_allocation extension not enabled."
             raise cls.skipException(msg)
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(SubnetPoolsRbacTest, self).tearDown()
-
-    def _create_subnetpool(self, shared=None):
+    def _create_subnetpool(self, **kwargs):
         post_body = {'name': data_utils.rand_name(self.__class__.__name__),
                      'min_prefixlen': 24,
                      'max_prefixlen': 32,
                      'prefixes': [CONF.network.project_network_cidr]}
 
-        if shared is not None:
-            post_body['shared'] = shared
+        if kwargs:
+            post_body.update(kwargs)
 
         body = self.subnetpools_client.create_subnetpool(**post_body)
         subnetpool = body['subnetpool']
@@ -68,7 +60,7 @@
 
         RBAC test for the neutron create_subnetpool policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_subnetpool()
 
     @rbac_rule_validation.action(service="neutron",
@@ -79,11 +71,12 @@
 
         RBAC test for the neutron create_subnetpool:shared policy
         """
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_subnetpool(shared=True)
 
     @rbac_rule_validation.action(service="neutron",
-                                 rule="get_subnetpool")
+                                 rule="get_subnetpool",
+                                 expected_error_code=404)
     @decorators.idempotent_id('4f5aee26-0507-4b6d-b44c-3128a25094d2')
     def test_show_subnetpool(self):
         """Show subnetpool.
@@ -91,14 +84,8 @@
         RBAC test for the neutron get_subnetpool policy
         """
         subnetpool = self._create_subnetpool()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.subnetpools_client.show_subnetpool(subnetpool['id'])
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.subnetpools_client.show_subnetpool(subnetpool['id'])
 
     @rbac_rule_validation.action(service="neutron",
                                  rule="update_subnetpool")
@@ -109,12 +96,35 @@
         RBAC test for the neutron update_subnetpool policy
         """
         subnetpool = self._create_subnetpool()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.subnetpools_client.update_subnetpool(subnetpool['id'],
                                                   min_prefixlen=24)
 
+    @decorators.idempotent_id('a16f4e5c-0675-415f-b636-00af00638693')
     @rbac_rule_validation.action(service="neutron",
-                                 rule="delete_subnetpool")
+                                 rule="update_subnetpool:is_default",
+                                 expected_error_code=404)
+    def test_update_subnetpool_is_default(self):
+        """Update default subnetpool.
+
+        RBAC test for the neutron update_subnetpool:is_default policy
+        """
+        subnetpools = self.subnetpools_client.list_subnetpools()['subnetpools']
+        default_pool = list(
+            filter(lambda p: p['is_default'] is True, subnetpools))
+        if default_pool:
+            default_pool = default_pool[0]
+        else:
+            default_pool = self._create_subnetpool(is_default=True)
+        original_desc = default_pool['description']
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.subnetpools_client.update_subnetpool(
+            default_pool['id'], description=original_desc, is_default=True)
+
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="delete_subnetpool",
+                                 expected_error_code=404)
     @decorators.idempotent_id('50f5944e-43e5-457b-ab50-fb48a73f0d3e')
     def test_delete_subnetpool(self):
         """Delete subnetpool.
@@ -122,11 +132,5 @@
         RBAC test for the neutron delete_subnetpool policy
         """
         subnetpool = self._create_subnetpool()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        try:
-            self.subnetpools_client.delete_subnetpool(subnetpool['id'])
-        except exceptions.NotFound as e:
-            LOG.info("NotFound exception caught. Exception is thrown when "
-                     "role doesn't have access to the endpoint."
-                     "This is irregular and should be fixed.")
-            raise rbac_exceptions.RbacActionFailed(e)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.subnetpools_client.delete_subnetpool(subnetpool['id'])
diff --git a/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py b/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py
new file mode 100644
index 0000000..68f5156
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py
@@ -0,0 +1,96 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.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
+
+
+class SubnetsRbacTest(base.BaseNetworkRbacTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(SubnetsRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('subnet_allocation', 'network'):
+            msg = "subnet_allocation extension not enabled."
+            raise cls.skipException(msg)
+
+    @classmethod
+    def resource_setup(cls):
+        super(SubnetsRbacTest, cls).resource_setup()
+        cls.network = cls.create_network()
+        cls.subnet = cls.create_subnet(cls.network)
+
+    @decorators.idempotent_id('0481adeb-4301-44d5-851c-35910cc18a6b')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="create_subnet")
+    def test_create_subnet(self):
+        """Create subnet.
+
+        RBAC test for the neutron "create_subnet" policy
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.create_subnet(self.network)
+
+    @decorators.idempotent_id('c02618e7-bb20-4abd-83c8-6eec2af08752')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="get_subnet")
+    def test_show_subnet(self):
+        """Show subnet.
+
+        RBAC test for the neutron "get_subnet" policy
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.subnets_client.show_subnet(self.subnet['id'])
+
+    @decorators.idempotent_id('e2ddc415-5cab-43f4-9b61-166aed65d637')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="get_subnet")
+    def test_list_subnets(self):
+        """List subnets.
+
+        RBAC test for the neutron "get_subnet" policy
+        """
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.subnets_client.list_subnets()
+
+    @decorators.idempotent_id('f36cd821-dd22-4bd0-b43d-110fc4b553eb')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="update_subnet")
+    def test_update_subnet(self):
+        """Update subnet.
+
+        RBAC test for the neutron "update_subnet" policy
+        """
+        update_name = data_utils.rand_name(self.__class__.__name__ + '-Subnet')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.subnets_client.update_subnet(self.subnet['id'], name=update_name)
+
+    @decorators.idempotent_id('bcfc7153-bbd1-43a4-a908-b3e1b0cde0dc')
+    @rbac_rule_validation.action(service="neutron",
+                                 rule="delete_subnet")
+    def test_delete_subnet(self):
+        """Delete subnet.
+
+        RBAC test for the neutron "delete_subnet" policy
+        """
+        subnet = self.create_subnet(self.network)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.subnets_client.delete_subnet(subnet['id'])
diff --git a/patrole_tempest_plugin/tests/api/orchestration/__init__.py b/patrole_tempest_plugin/tests/api/orchestration/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/patrole_tempest_plugin/tests/api/orchestration/__init__.py
+++ /dev/null
diff --git a/patrole_tempest_plugin/tests/api/orchestration/rbac_base.py b/patrole_tempest_plugin/tests/api/orchestration/rbac_base.py
deleted file mode 100644
index e892a02..0000000
--- a/patrole_tempest_plugin/tests/api/orchestration/rbac_base.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest.api.orchestration import base as heat_base
-from tempest import config
-
-from patrole_tempest_plugin.rbac_utils import rbac_utils
-
-CONF = config.CONF
-
-
-class BaseOrchestrationRbacTest(heat_base.BaseOrchestrationTest):
-
-    credentials = ['admin', 'primary']
-
-    @classmethod
-    def skip_checks(cls):
-        super(BaseOrchestrationRbacTest, cls).skip_checks()
-        if not CONF.rbac.rbac_flag:
-            raise cls.skipException(
-                "%s skipped as RBAC Flag not enabled" % cls.__name__)
-
-    @classmethod
-    def setup_clients(cls):
-        super(BaseOrchestrationRbacTest, cls).setup_clients()
-        cls.auth_provider = cls.os.auth_provider
-        cls.admin_client = cls.os_adm.orchestration_client
-        cls.rbac_utils = rbac_utils()
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(BaseOrchestrationRbacTest, self).tearDown()
diff --git a/patrole_tempest_plugin/tests/api/orchestration/test_soft_config_rbac.py b/patrole_tempest_plugin/tests/api/orchestration/test_soft_config_rbac.py
deleted file mode 100644
index fa3840c..0000000
--- a/patrole_tempest_plugin/tests/api/orchestration/test_soft_config_rbac.py
+++ /dev/null
@@ -1,138 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest.lib.common.utils import data_utils
-from tempest.lib.common.utils import test_utils
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.orchestration import rbac_base
-
-
-class TestRbacSoftwareConfig(rbac_base.BaseOrchestrationRbacTest):
-
-    def setUp(self):
-        super(TestRbacSoftwareConfig, self).setUp()
-        self.config = self._config_create('a')
-        self._deployment_create(self.config['id'])
-
-    @rbac_rule_validation.action(service="heat",
-                                 rule="software_configs:show")
-    @decorators.idempotent_id('b2e7c98c-e17b-4f37-82f3-5d21eff86e79')
-    def test_get_software_config(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_software_config(self.config['id'])
-
-    @rbac_rule_validation.action(service="heat",
-                                 rule="software_deployments:metadata")
-    @decorators.idempotent_id('defa34ab-9d1f-4b14-8613-34e964c0c478')
-    def test_get_deployment_metadata(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_software_deployment_metadata(self.server_id)
-
-    @rbac_rule_validation.action(service="heat",
-                                 rule="software_deployments:index")
-    @decorators.idempotent_id('2a4dcb91-1803-4749-9cb7-5b69ba668b18')
-    def test_get_deployment_list(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_software_deployments()
-
-    @rbac_rule_validation.action(service="heat",
-                                 rule="software_deployments:show")
-    @decorators.idempotent_id('d4e627bc-88a3-4189-8092-151f22ed989d')
-    def test_software_show_deployment(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_software_deployment(self.deployment_id)
-
-    @rbac_rule_validation.action(service="heat",
-                                 rule="software_deployments:update")
-    @decorators.idempotent_id('90e8958c-6fa7-4515-b6d7-6d6952979f8c')
-    def test_software_deployment_update(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        new_action = data_utils.rand_name('ACTION')
-        new_status = data_utils.rand_name('STATUS')
-        new_reason = data_utils.rand_name('REASON')
-        self.client.update_software_deploy(self.deployment_id,
-                                           self.server_id,
-                                           self.config['id'],
-                                           new_action, new_status,
-                                           self.input_values,
-                                           self.output_values,
-                                           new_reason,
-                                           self.signal_transport)
-
-    @rbac_rule_validation.action(service="heat",
-                                 rule="software_deployments:create")
-    @decorators.idempotent_id('9175fe7b-4210-4c1d-acbb-954998a9fd77')
-    def test_software_deployment_create(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._deployment_create(self.config['id'])
-
-    @rbac_rule_validation.action(service="heat",
-                                 rule="software_deployments:delete")
-    @decorators.idempotent_id('20f4683d-7316-4d88-a6ea-1ee6013da908')
-    def test_software_deployment_delete(self):
-        deploy_id = self._deployment_create(self.config['id'])
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.delete_software_deploy(deploy_id)
-
-    @rbac_rule_validation.action(service="heat",
-                                 rule="software_configs:create")
-    @decorators.idempotent_id('c8fb1c73-fcb6-46c2-9510-8ef0083c9620')
-    def test_config_create(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._config_create('e')
-
-    @rbac_rule_validation.action(service="heat",
-                                 rule="software_configs:delete")
-    @decorators.idempotent_id('f4f784ea-9878-4306-bc5f-041ba5307ce5')
-    def test_config_delete(self):
-        configuration = self._config_create('d')
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.delete_software_config(configuration['id'])
-
-    def _config_create(self, suffix):
-        configuration = {'group': 'script',
-                         'inputs': [],
-                         'outputs': [],
-                         'options': {}}
-        configuration['name'] = 'heat_soft_config_%s' % suffix
-        configuration['config'] = '#!/bin/bash echo init-%s' % suffix
-        api_config = self.client.create_software_config(**configuration)
-        self.addCleanup(
-            test_utils.call_and_ignore_notfound_exc,
-            self.client.delete_software_config,
-            api_config['software_config']['id'])
-        configuration['id'] = api_config['software_config']['id']
-        return configuration
-
-    def _deployment_create(self, config_id):
-        self.server_id = data_utils.rand_name('dummy-server')
-        self.action = 'ACTION_0'
-        self.status = 'STATUS_0'
-        self.input_values = {}
-        self.output_values = []
-        self.status_reason = 'REASON_0'
-        self.signal_transport = 'NO_SIGNAL'
-        self.deployment = self.client.create_software_deploy(
-            self.server_id, config_id, self.action, self.status,
-            self.input_values, self.output_values, self.status_reason,
-            self.signal_transport)
-        self.addCleanup(
-            test_utils.call_and_ignore_notfound_exc,
-            self.client.delete_software_deploy,
-            self.deployment['software_deployment']['id'])
-        self.deployment_id = self.deployment['software_deployment']['id']
-        return self.deployment_id
diff --git a/patrole_tempest_plugin/tests/api/volume/admin/__init__.py b/patrole_tempest_plugin/tests/api/volume/admin/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/patrole_tempest_plugin/tests/api/volume/admin/__init__.py
+++ /dev/null
diff --git a/patrole_tempest_plugin/tests/api/volume/admin/test_qos_rbac.py b/patrole_tempest_plugin/tests/api/volume/admin/test_qos_rbac.py
deleted file mode 100644
index 0d59f77..0000000
--- a/patrole_tempest_plugin/tests/api/volume/admin/test_qos_rbac.py
+++ /dev/null
@@ -1,162 +0,0 @@
-# Copyright 2017 AT&T Corp
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest.common import waiters
-from tempest import config
-from tempest.lib.common.utils import test_utils
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.volume import rbac_base
-
-CONF = config.CONF
-
-
-class VolumeQOSRbacTest(rbac_base.BaseVolumeAdminRbacTest):
-    @classmethod
-    def setup_clients(cls):
-        super(VolumeQOSRbacTest, cls).setup_clients()
-        cls.admin_client = cls.os_adm.volume_qos_client
-        cls.auth_provider = cls.os.auth_provider
-        cls.client = cls.admin_volume_qos_client
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(VolumeQOSRbacTest, self).tearDown()
-
-    @rbac_rule_validation.action(
-        service="cinder", rule="volume_extension:qos_specs_manage:create")
-    @decorators.idempotent_id('4f9f45f0-b379-4577-a279-cec3e917cbec')
-    def test_create_qos_with_consumer(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # Create a qos
-        self.create_test_qos_specs()
-
-    @rbac_rule_validation.action(
-        service="cinder", rule="volume_extension:qos_specs_manage:delete")
-    @decorators.idempotent_id('fbc8a77e-6b6d-45ae-bebe-c496eb8f06f7')
-    def test_delete_qos_with_consumer(self):
-        # Create a qos
-        qos = self.create_test_qos_specs()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # Delete a qos
-        self.client.delete_qos(qos['id'])
-
-    @rbac_rule_validation.action(service="cinder",
-                                 rule="volume_extension:qos_specs_manage:read")
-    @decorators.idempotent_id('22aff0dd-0343-408d-ae80-e77551956e14')
-    def test_get_qos(self):
-        # Create a qos
-        qos = self.create_test_qos_specs()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # Get a qos
-        self.client.show_qos(qos['id'])['qos_specs']
-
-    @rbac_rule_validation.action(service="cinder",
-                                 rule="volume_extension:qos_specs_manage:read")
-    @decorators.idempotent_id('546b8bb1-04a4-4387-9506-a538a7f3cd6a')
-    def test_list_qos(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # list all qos
-        self.client.list_qos()['qos_specs']
-
-    @rbac_rule_validation.action(
-        service="cinder", rule="volume_extension:qos_specs_manage:update")
-    @decorators.idempotent_id('89b630b7-c170-47c3-ac80-50ed425c2d98')
-    def test_set_qos_key(self):
-        # Create a qos
-        qos = self.create_test_qos_specs()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # set key
-        self.client.set_qos_key(qos['id'], iops_bytes='500')['qos_specs']
-
-    @rbac_rule_validation.action(
-        service="cinder", rule="volume_extension:qos_specs_manage:update")
-    @decorators.idempotent_id('6c50c837-de77-4dae-a2ec-30e05c62969c')
-    def test_unset_qos_key(self):
-        # Create a qos
-        qos = self.create_test_qos_specs()
-        # Set key
-        self.client.set_qos_key(qos['id'], iops_bytes='500')['qos_specs']
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # Unset key
-        keys = ['iops_bytes']
-        self.client.unset_qos_key(qos['id'], keys)
-        operation = 'qos-key-unset'
-        waiters.wait_for_qos_operations(self.client, qos['id'],
-                                        operation, args=keys)
-
-    @rbac_rule_validation.action(
-        service="cinder", rule="volume_extension:qos_specs_manage:update")
-    @decorators.idempotent_id('2047b347-8bbe-405e-bf5a-c75a0d7e3930')
-    def test_associate_qos(self):
-        # Create a qos
-        qos = self.create_test_qos_specs()
-        # create a test volume-type
-        vol_type = self.create_volume_type()['id']
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # associate the qos-specs with volume-types
-        self.client.associate_qos(qos['id'], vol_type)
-        self.addCleanup(self.client.disassociate_qos, qos['id'], vol_type)
-
-    @rbac_rule_validation.action(service="cinder",
-                                 rule="volume_extension:qos_specs_manage:read")
-    @decorators.idempotent_id('ff1e98f3-d456-40a9-96d4-c7e4a55dcffa')
-    def test_get_association_qos(self):
-        # create a test volume-type
-        qos = self.create_test_qos_specs()
-        vol_type = self.create_volume_type()['id']
-        # associate the qos-specs with volume-types
-        self.client.associate_qos(qos['id'], vol_type)
-        self.addCleanup(self.client.disassociate_qos, qos['id'], vol_type)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # get the association of the qos-specs
-        self.client.show_association_qos(qos['id'])
-
-    @rbac_rule_validation.action(
-        service="cinder", rule="volume_extension:qos_specs_manage:update")
-    @decorators.idempotent_id('f12aeca1-0c02-4f33-b805-014171e5b2d4')
-    def test_disassociate_qos(self):
-        # create a test volume-type
-        qos = self.create_test_qos_specs()
-        vol_type = self.create_volume_type()['id']
-        # associate the qos-specs with volume-types
-        self.client.associate_qos(qos['id'], vol_type)
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.client.disassociate_qos, qos['id'], vol_type)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # disassociate a volume-type with qos-specs
-        self.client.disassociate_qos(qos['id'], vol_type)
-        operation = 'disassociate'
-        waiters.wait_for_qos_operations(self.client, qos['id'],
-                                        operation, args=vol_type)
-
-    @rbac_rule_validation.action(
-        service="cinder", rule="volume_extension:qos_specs_manage:update")
-    @decorators.idempotent_id('9f6e664d-a5d9-4e71-b122-73a3086be1b9')
-    def test_disassociate_all_qos(self):
-        qos = self.create_test_qos_specs()
-        # create a test volume-type
-        vol_type = self.create_volume_type()['id']
-        # associate the qos-specs with volume-types
-        self.client.associate_qos(qos['id'], vol_type)
-        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.client.disassociate_qos, qos['id'], vol_type)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # disassociate all volume-types from qos-specs
-        self.client.disassociate_all_qos(qos['id'])
-        operation = 'disassociate-all'
-        waiters.wait_for_qos_operations(self.client, qos['id'],
-                                        operation)
diff --git a/patrole_tempest_plugin/tests/api/volume/admin/test_volumes_backup_admin_rbac.py b/patrole_tempest_plugin/tests/api/volume/admin/test_volumes_backup_admin_rbac.py
deleted file mode 100644
index b801b67..0000000
--- a/patrole_tempest_plugin/tests/api/volume/admin/test_volumes_backup_admin_rbac.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest 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.volume import rbac_base
-
-CONF = config.CONF
-
-
-class VolumesBackupsAdminRbacTest(rbac_base.BaseVolumeAdminRbacTest):
-
-    @classmethod
-    def skip_checks(cls):
-        super(VolumesBackupsAdminRbacTest, cls).skip_checks()
-        if not CONF.volume_feature_enabled.backup:
-            raise cls.skipException("Cinder backup feature disabled")
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(VolumesBackupsAdminRbacTest, self).tearDown()
-
-    @classmethod
-    def resource_setup(cls):
-        super(VolumesBackupsAdminRbacTest, cls).resource_setup()
-        cls.volume = cls.create_volume()
-
-    @test.attr(type='slow')
-    @rbac_rule_validation.action(service="cinder",
-                                 rule="backup:backup-export")
-    @decorators.idempotent_id('e984ec8d-e8eb-485c-98bc-f1856020303c')
-    def test_volume_backup_export(self):
-        # Create a temp backup
-        backup = self.create_backup(volume_id=self.volume['id'])
-        # Export Backup
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.backups_client.export_backup(
-            backup['id'])['backup-record']
-
-    @test.attr(type='slow')
-    @rbac_rule_validation.action(service="cinder",
-                                 rule="backup:backup-import")
-    @decorators.idempotent_id('1e70f039-4556-44cc-9cc1-edf2b7ed648b')
-    def test_volume_backup_import(self):
-        # Create a temp backup
-        backup = self.create_backup(volume_id=self.volume['id'])
-        # Export a temp backup
-        export_backup = self.backups_client.export_backup(
-            backup['id'])['backup-record']
-        # Import the temp backup
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        import_backup = self.backups_client.import_backup(
-            backup_service=export_backup['backup_service'],
-            backup_url=export_backup['backup_url'])['backup']
-        self.addCleanup(self.backups_client.delete_backup, import_backup['id'])
-
-
-class VolumesBackupsAdminV3RbacTest(VolumesBackupsAdminRbacTest):
-    _api_version = 3
diff --git a/patrole_tempest_plugin/tests/api/volume/rbac_base.py b/patrole_tempest_plugin/tests/api/volume/rbac_base.py
index 6d1ad16..953a834 100644
--- a/patrole_tempest_plugin/tests/api/volume/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/volume/rbac_base.py
@@ -13,8 +13,10 @@
 
 from tempest.api.volume import base as vol_base
 from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
 
-from patrole_tempest_plugin.rbac_utils import rbac_utils
+from patrole_tempest_plugin import rbac_utils
 
 CONF = config.CONF
 
@@ -26,38 +28,73 @@
     @classmethod
     def skip_checks(cls):
         super(BaseVolumeRbacTest, cls).skip_checks()
-        if not CONF.rbac.rbac_flag:
+        if not CONF.rbac.enable_rbac:
             raise cls.skipException(
-                "%s skipped as RBAC Flag not enabled" % cls.__name__)
+                "%s skipped as RBAC testing not enabled" % cls.__name__)
 
     @classmethod
     def setup_clients(cls):
         super(BaseVolumeRbacTest, cls).setup_clients()
-        cls.auth_provider = cls.os.auth_provider
-        cls.admin_client = cls.os_adm.volumes_client
-        cls.rbac_utils = rbac_utils()
+        cls.auth_provider = cls.os_primary.auth_provider
 
+        cls.rbac_utils = rbac_utils.RbacUtils(cls)
 
-class BaseVolumeAdminRbacTest(vol_base.BaseVolumeAdminTest):
-
-    credentials = ['admin', 'primary']
-
-    @classmethod
-    def skip_checks(cls):
-        super(BaseVolumeAdminRbacTest, cls).skip_checks()
-        if not CONF.rbac.rbac_flag:
-            raise cls.skipException(
-                "%s skipped as RBAC Flag not enabled" % cls.__name__)
-
-    @classmethod
-    def setup_clients(cls):
-        super(BaseVolumeAdminRbacTest, cls).setup_clients()
-        cls.auth_provider = cls.os.auth_provider
-        cls.admin_client = cls.os_adm.volumes_client
-        cls.rbac_utils = rbac_utils()
         version_checker = {
-            1: [cls.os.volume_hosts_client, cls.os.volume_types_client],
-            2: [cls.os.volume_hosts_v2_client, cls.os.volume_types_v2_client]
+            2: [cls.os_primary.volume_hosts_v2_client,
+                cls.os_primary.volume_types_v2_client],
+            3: [cls.os_primary.volume_hosts_v2_client,
+                cls.os_primary.volume_types_v2_client]
         }
         cls.volume_hosts_client, cls.volume_types_client = \
             version_checker[cls._api_version]
+        cls.groups_client = cls.os_primary.groups_v3_client
+        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)
+        return volume_type
+
+    def create_group_type(self, name=None, ignore_notfound=False, **kwargs):
+        """Create a test group-type"""
+        name = name or data_utils.rand_name(
+            self.__class__.__name__ + '-group-type')
+        group_type = self.group_types_client.create_group_type(
+            name=name, **kwargs)['group_type']
+
+        if ignore_notfound:
+            self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                            self.group_types_client.delete_group_type,
+                            group_type['id'])
+        else:
+            self.addCleanup(self.group_types_client.delete_group_type,
+                            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_availability_zone_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_availability_zone_rbac.py
deleted file mode 100644
index f20d767..0000000
--- a/patrole_tempest_plugin/tests/api/volume/test_availability_zone_rbac.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest import config
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.volume import rbac_base
-
-CONF = config.CONF
-
-
-class AvailabilityZoneRbacTest(rbac_base.BaseVolumeRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(AvailabilityZoneRbacTest, cls).setup_clients()
-        cls.client = cls.availability_zone_client
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(AvailabilityZoneRbacTest, self).tearDown()
-
-    @rbac_rule_validation.action(service="cinder",
-                                 rule="volume:availability_zone_list")
-    @decorators.idempotent_id('8cfd920c-4b6c-402d-b6e2-ede86bedc702')
-    def test_get_availability_zone_list(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_availability_zones()
diff --git a/patrole_tempest_plugin/tests/api/volume/test_capabilities_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_capabilities_rbac.py
new file mode 100644
index 0000000..45b1660
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/volume/test_capabilities_rbac.py
@@ -0,0 +1,48 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.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
+
+
+class CapabilitiesRbacTest(rbac_base.BaseVolumeRbacTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(CapabilitiesRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('capabilities', 'volume'):
+            msg = "%s skipped as capabilities not enabled." % cls.__name__
+            raise cls.skipException(msg)
+
+    @classmethod
+    def setup_clients(cls):
+        super(CapabilitiesRbacTest, cls).setup_clients()
+        cls.capabilities_client = cls.os_primary.volume_capabilities_v2_client
+        cls.hosts_client = cls.os_primary.volume_hosts_v2_client
+
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume_extension:capabilities")
+    @decorators.idempotent_id('40928b74-2141-11e7-93ae-92361f002671')
+    def test_show_back_end_capabilities(self):
+        host = self.hosts_client.list_hosts()['hosts'][0]['host_name']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.capabilities_client.show_backend_capabilities(host)
+
+
+class CapabilitiesV3RbacTest(CapabilitiesRbacTest):
+    _api_version = 3
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
new file mode 100644
index 0000000..f11ef03
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/volume/test_encryption_types_rbac.py
@@ -0,0 +1,87 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+from tempest.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
+
+
+class EncryptionTypesRbacTest(rbac_base.BaseVolumeRbacTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(EncryptionTypesRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('encryption', 'volume'):
+            msg = "%s skipped as encryption not enabled." % cls.__name__
+            raise cls.skipException(msg)
+
+    @classmethod
+    def setup_clients(cls):
+        super(EncryptionTypesRbacTest, cls).setup_clients()
+        cls.encryption_types_client = cls.os_primary.encryption_types_v2_client
+
+    def _create_volume_type_encryption(self):
+        vol_type_id = self.create_volume_type()['id']
+        self.encryption_types_client.create_encryption_type(
+            vol_type_id,
+            provider="nova.volume.encryptors.luks.LuksEncryptor",
+            control_location="front-end")['encryption']
+        return vol_type_id
+
+    @decorators.idempotent_id('ffd94ce5-c24b-4b6c-84c9-c5aad8c3010c')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_type_encryption")
+    def test_create_volume_type_encryption(self):
+        vol_type_id = self.create_volume_type()['id']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.encryption_types_client.create_encryption_type(
+            vol_type_id,
+            provider="nova.volume.encryptors.luks.LuksEncryptor",
+            control_location="front-end")['encryption']
+
+    @decorators.idempotent_id('6599e72e-acef-4c0d-a9b2-463fca30d1da')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_type_encryption")
+    def test_delete_volume_type_encryption(self):
+        vol_type_id = self._create_volume_type_encryption()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.encryption_types_client.delete_encryption_type(vol_type_id)
+
+    @decorators.idempotent_id('42da9fec-32fd-4dca-9242-8a53b2fed25a')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_type_encryption")
+    def test_update_volume_type_encryption(self):
+        vol_type_id = self._create_volume_type_encryption()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.encryption_types_client.update_encryption_type(
+            vol_type_id,
+            control_location="front-end")
+
+    @decorators.idempotent_id('1381a3dc-248f-4282-b231-c9399018c804')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_type_encryption")
+    def test_show_volume_type_encryption(self):
+        vol_type_id = self._create_volume_type_encryption()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.encryption_types_client.show_encryption_type(vol_type_id)
+
+
+class EncryptionTypesV3RbacTest(EncryptionTypesRbacTest):
+    _api_version = 3
diff --git a/patrole_tempest_plugin/tests/api/volume/test_extensions_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_extensions_rbac.py
deleted file mode 100644
index f952ee5..0000000
--- a/patrole_tempest_plugin/tests/api/volume/test_extensions_rbac.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest import config
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.volume import rbac_base
-
-CONF = config.CONF
-
-
-class ExtensionsRbacTest(rbac_base.BaseVolumeRbacTest):
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(ExtensionsRbacTest, self).tearDown()
-
-    @rbac_rule_validation.action(service="cinder",
-                                 rule="volume:list_extensions")
-    @decorators.idempotent_id('7f2dcc41-e850-493f-a400-82db4e2b50c0')
-    def test_list_extensions(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.volumes_extension_client.list_extensions()
-
-
-class ExtensionsV3RbacTest(ExtensionsRbacTest):
-    _api_version = 3
diff --git a/patrole_tempest_plugin/tests/api/volume/test_groups_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_groups_rbac.py
new file mode 100644
index 0000000..6b07aaa
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/volume/test_groups_rbac.py
@@ -0,0 +1,143 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.common import waiters
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_exceptions
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.volume import rbac_base
+
+
+class GroupsV3RbacTest(rbac_base.BaseVolumeRbacTest):
+    _api_version = 3
+    min_microversion = '3.14'
+    max_microversion = 'latest'
+
+    def setUp(self):
+        super(GroupsV3RbacTest, self).setUp()
+        self.volume_type_id = self.create_volume_type()['id']
+        self.group_type_id = self.create_group_type()['id']
+
+    def _create_group(self, name=None, ignore_notfound=False, **kwargs):
+        group_name = name or data_utils.rand_name(
+            self.__class__.__name__ + '-Group')
+        group = self.groups_client.create_group(name=group_name, **kwargs)[
+            'group']
+        waiters.wait_for_volume_resource_status(
+            self.groups_client, group['id'], 'available')
+
+        if ignore_notfound:
+            self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                            self._delete_group, group['id'])
+        else:
+            self.addCleanup(self._delete_group, group['id'])
+
+        return group
+
+    def _delete_group(self, group_id, delete_volumes=True):
+        self.groups_client.delete_group(group_id, delete_volumes)
+        self.groups_client.wait_for_resource_deletion(group_id)
+
+    @decorators.idempotent_id('43235328-66ae-424f-bc7f-f709c0ca268c')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="group:create")
+    def test_create_group(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._create_group(ignore_notfound=True,
+                           group_type=self.group_type_id,
+                           volume_types=[self.volume_type_id])
+
+    @decorators.idempotent_id('9dc34a62-ae3e-439e-92b6-9389ea4c2863')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="group:get")
+    def test_show_group(self):
+        group = self._create_group(group_type=self.group_type_id,
+                                   volume_types=[self.volume_type_id])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.groups_client.show_group(group['id'])
+
+    @decorators.idempotent_id('db43841b-a173-4317-acfc-f83e4e48e4ee')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="group:get_all")
+    def test_list_groups(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.groups_client.list_groups()['groups']
+
+    @decorators.idempotent_id('5378da93-9c26-4ad4-b039-0555e2b8f668')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="group:get_all")
+    def test_list_groups_with_details(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.groups_client.list_groups(detail=True)['groups']
+
+    @decorators.idempotent_id('66fda391-5774-42a9-a018-80b34e57ab76')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="group:delete")
+    def test_delete_group(self):
+        group = self._create_group(ignore_notfound=True,
+                                   group_type=self.group_type_id,
+                                   volume_types=[self.volume_type_id])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.groups_client.delete_group(group['id'])
+
+
+class GroupTypesV3RbacTest(rbac_base.BaseVolumeRbacTest):
+    _api_version = 3
+    min_microversion = '3.11'
+    max_microversion = 'latest'
+
+    @decorators.idempotent_id('2820f12c-4681-4c7f-b28d-e6925637dff6')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="group:group_types_manage")
+    def test_create_group_type(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.create_group_type(ignore_notfound=True)
+
+    @decorators.idempotent_id('a5f88c26-df7c-4f21-a3ae-7a4c2d6212b4')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="group:access_group_types_specs")
+    def test_create_group_type_group_specs(self):
+        # TODO(felipemonteiro): Combine with ``test_create_group_type``
+        # once multiple policy testing is supported. This policy is
+        # only enforced after "group:group_types_manage".
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        group_type = self.create_group_type(ignore_notfound=True)
+
+        if 'group_specs' not in group_type:
+            raise rbac_exceptions.RbacActionFailed(
+                'Policy %s does not return %s in response body.' %
+                ('group:access_group_types_specs', 'group_specs'))
+
+    @decorators.idempotent_id('f77f8156-4fc9-4f02-be15-8930f748e10c')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="group:group_types_manage")
+    def test_delete_group_type(self):
+        goup_type = self.create_group_type(ignore_notfound=True)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.group_types_client.delete_group_type(goup_type['id'])
diff --git a/patrole_tempest_plugin/tests/api/volume/test_qos_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_qos_rbac.py
new file mode 100644
index 0000000..c6703b0
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/volume/test_qos_rbac.py
@@ -0,0 +1,146 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.common import waiters
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.volume import rbac_base
+
+
+class VolumeQOSRbacTest(rbac_base.BaseVolumeRbacTest):
+    @classmethod
+    def setup_clients(cls):
+        super(VolumeQOSRbacTest, cls).setup_clients()
+        cls.auth_provider = cls.os_primary.auth_provider
+        cls.qos_client = cls.os_primary.volume_qos_v2_client
+        cls.admin_qos_client = cls.os_admin.volume_qos_v2_client
+
+    def _create_test_qos_specs(self, name=None, consumer=None, **kwargs):
+        name = name or data_utils.rand_name(self.__class__.__name__ + '-QoS')
+        consumer = consumer or 'front-end'
+        qos_specs = self.qos_client.create_qos(
+            name=name, consumer=consumer, **kwargs)['qos_specs']
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.qos_client.delete_qos, qos_specs['id'])
+        return qos_specs
+
+    @rbac_rule_validation.action(
+        service="cinder", rule="volume_extension:qos_specs_manage:create")
+    @decorators.idempotent_id('4f9f45f0-b379-4577-a279-cec3e917cbec')
+    def test_create_qos_with_consumer(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._create_test_qos_specs()
+
+    @rbac_rule_validation.action(
+        service="cinder", rule="volume_extension:qos_specs_manage:delete")
+    @decorators.idempotent_id('fbc8a77e-6b6d-45ae-bebe-c496eb8f06f7')
+    def test_delete_qos_with_consumer(self):
+        qos = self._create_test_qos_specs()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.qos_client.delete_qos(qos['id'])
+
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume_extension:qos_specs_manage:get")
+    @decorators.idempotent_id('22aff0dd-0343-408d-ae80-e77551956e14')
+    def test_show_qos(self):
+        qos = self._create_test_qos_specs()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.qos_client.show_qos(qos['id'])['qos_specs']
+
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume_extension:qos_specs_manage:get")
+    @decorators.idempotent_id('ff1e98f3-d456-40a9-96d4-c7e4a55dcffa')
+    def test_get_association_qos(self):
+        qos = self._create_test_qos_specs()
+        vol_type = self.create_volume_type()['id']
+        self.qos_client.associate_qos(qos['id'], vol_type)
+        self.addCleanup(self.qos_client.disassociate_qos, qos['id'], vol_type)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.qos_client.show_association_qos(qos['id'])
+
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:qos_specs_manage:get_all")
+    @decorators.idempotent_id('546b8bb1-04a4-4387-9506-a538a7f3cd6a')
+    def test_list_qos(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.qos_client.list_qos()['qos_specs']
+
+    @rbac_rule_validation.action(
+        service="cinder", rule="volume_extension:qos_specs_manage:update")
+    @decorators.idempotent_id('89b630b7-c170-47c3-ac80-50ed425c2d98')
+    def test_set_qos_key(self):
+        qos = self._create_test_qos_specs()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.qos_client.set_qos_key(qos['id'], iops_bytes='500')['qos_specs']
+
+    @rbac_rule_validation.action(
+        service="cinder", rule="volume_extension:qos_specs_manage:update")
+    @decorators.idempotent_id('6c50c837-de77-4dae-a2ec-30e05c62969c')
+    def test_unset_qos_key(self):
+        qos = self._create_test_qos_specs()
+        self.qos_client.set_qos_key(qos['id'], iops_bytes='500')['qos_specs']
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.qos_client.unset_qos_key(qos['id'], ['iops_bytes'])
+        waiters.wait_for_qos_operations(self.admin_qos_client, qos['id'],
+                                        'qos-key-unset', args=['iops_bytes'])
+
+    @rbac_rule_validation.action(
+        service="cinder", rule="volume_extension:qos_specs_manage:update")
+    @decorators.idempotent_id('2047b347-8bbe-405e-bf5a-c75a0d7e3930')
+    def test_associate_qos(self):
+        qos = self._create_test_qos_specs()
+        vol_type = self.create_volume_type()['id']
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.qos_client.associate_qos(qos['id'], vol_type)
+        self.addCleanup(
+            test_utils.call_and_ignore_notfound_exc,
+            self.qos_client.disassociate_qos, qos['id'], vol_type)
+
+    @rbac_rule_validation.action(
+        service="cinder", rule="volume_extension:qos_specs_manage:update")
+    @decorators.idempotent_id('f12aeca1-0c02-4f33-b805-014171e5b2d4')
+    def test_disassociate_qos(self):
+        qos = self._create_test_qos_specs()
+        vol_type = self.create_volume_type()['id']
+        self.qos_client.associate_qos(qos['id'], vol_type)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.qos_client.disassociate_qos, qos['id'], vol_type)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.qos_client.disassociate_qos(qos['id'], vol_type)
+        waiters.wait_for_qos_operations(self.admin_qos_client, qos['id'],
+                                        'disassociate', args=vol_type)
+
+    @rbac_rule_validation.action(
+        service="cinder", rule="volume_extension:qos_specs_manage:update")
+    @decorators.idempotent_id('9f6e664d-a5d9-4e71-b122-73a3086be1b9')
+    def test_disassociate_all_qos(self):
+        qos = self._create_test_qos_specs()
+        vol_type = self.create_volume_type()['id']
+        self.qos_client.associate_qos(qos['id'], vol_type)
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.qos_client.disassociate_qos, qos['id'], vol_type)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.qos_client.disassociate_all_qos(qos['id'])
+        waiters.wait_for_qos_operations(self.admin_qos_client, qos['id'],
+                                        'disassociate-all')
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
new file mode 100644
index 0000000..1518ef4
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/volume/test_quota_classes_rbac.py
@@ -0,0 +1,62 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.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
+
+
+class QuotaClassesRbacTest(rbac_base.BaseVolumeRbacTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(QuotaClassesRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('os-quota-class-sets', 'volume'):
+            msg = ("%s skipped as os-quota-class-sets not enabled."
+                   % cls.__name__)
+            raise cls.skipException(msg)
+
+    @classmethod
+    def setup_clients(cls):
+        super(QuotaClassesRbacTest, cls).setup_clients()
+        cls.quota_classes_client = cls.os_primary.quota_classes_client
+        cls.quota_name = data_utils.rand_name(cls.__name__ + '-QuotaClass')
+
+    @decorators.idempotent_id('1a060def-2b43-4534-97f5-5eadbbe8c726')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume_extension:quota_classes")
+    def test_show_quota_class_set(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.quota_classes_client.show_quota_class_set(
+            self.quota_name)['quota_class_set']
+
+    @decorators.idempotent_id('72159478-23a7-4c75-989f-6bac609eca62')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume_extension:quota_classes")
+    def test_update_quota_class_set(self):
+        quota_class_set = self.quota_classes_client.show_quota_class_set(
+            self.quota_name)['quota_class_set']
+        quota_class_set.pop('id')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.quota_classes_client.update_quota_class_set(self.quota_name,
+                                                         **quota_class_set)
+
+
+class QuotaClassesV3RbacTest(QuotaClassesRbacTest):
+    _api_version = 3
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
new file mode 100644
index 0000000..dd423d1
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/volume/test_scheduler_stats_rbac.py
@@ -0,0 +1,48 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.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
+
+
+class SchedulerStatsRbacTest(rbac_base.BaseVolumeRbacTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(SchedulerStatsRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('scheduler-stats', 'volume'):
+            msg = "%s skipped as scheduler-stats not enabled." % cls.__name__
+            raise cls.skipException(msg)
+
+    @classmethod
+    def setup_clients(cls):
+        super(SchedulerStatsRbacTest, cls).setup_clients()
+        cls.scheduler_stats_client =\
+            cls.os_primary.volume_scheduler_stats_v2_client
+
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="scheduler_extension:scheduler_stats:get_pools")
+    @decorators.idempotent_id('5f800441-4d30-48ec-9e5b-0d55bc86acbb')
+    def test_list_back_end_storage_pools(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.scheduler_stats_client.list_pools()
+
+
+class SchedulerStatsV3RbacTest(SchedulerStatsRbacTest):
+    _api_version = 3
diff --git a/patrole_tempest_plugin/tests/api/volume/test_snapshots_actions_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_snapshots_actions_rbac.py
index 5b1b560..fc39f4a 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_snapshots_actions_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_snapshots_actions_rbac.py
@@ -13,8 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from oslo_log import log as logging
-
 from tempest import config
 from tempest.lib import decorators
 
@@ -22,7 +20,6 @@
 from patrole_tempest_plugin.tests.api.volume import rbac_base
 
 CONF = config.CONF
-LOG = logging.getLogger(__name__)
 
 
 class SnapshotsActionsRbacTest(rbac_base.BaseVolumeRbacTest):
@@ -34,20 +31,9 @@
             raise cls.skipException("Cinder snapshot feature disabled")
 
     @classmethod
-    def setup_clients(cls):
-        super(SnapshotsActionsRbacTest, cls).setup_clients()
-        cls.client = cls.os.snapshots_client
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(SnapshotsActionsRbacTest, self).tearDown()
-
-    @classmethod
     def resource_setup(cls):
         super(SnapshotsActionsRbacTest, cls).resource_setup()
-        # Create a volume
         cls.volume = cls.create_volume()
-        # Create a snapshot
         cls.snapshot = cls.create_snapshot(volume_id=cls.volume['id'])
         cls.snapshot_id = cls.snapshot['id']
 
@@ -56,25 +42,21 @@
         rule="volume_extension:snapshot_admin_actions:reset_status")
     @decorators.idempotent_id('ea430145-34ef-408d-b678-95d5ae5f46eb')
     def test_reset_snapshot_status(self):
-        # Reset snapshot status to error
         status = 'error'
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.\
-            reset_snapshot_status(self.snapshot['id'], status)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.snapshots_client.reset_snapshot_status(self.snapshot['id'],
+                                                    status)
 
     @rbac_rule_validation.action(
         service="cinder",
-        rule="volume_extension:volume_admin_actions:force_delete")
+        rule="volume_extension:snapshot_admin_actions:force_delete")
     @decorators.idempotent_id('a8b0f7d8-4c00-4645-b8d5-33ab4eecc6cb')
     def test_snapshot_force_delete(self):
-        # Test force delete of snapshot
-        # Create snapshot,
-        # and force delete temp snapshot
         temp_snapshot = self.create_snapshot(self.volume['id'])
-        # Force delete the snapshot
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.force_delete_snapshot(temp_snapshot['id'])
-        self.client.wait_for_resource_deletion(temp_snapshot['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.snapshots_client.force_delete_snapshot(temp_snapshot['id'])
+        self.snapshots_client.wait_for_resource_deletion(temp_snapshot['id'])
 
 
 class SnapshotsActionsV3RbacTest(SnapshotsActionsRbacTest):
diff --git a/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py
index e445214..81cd854 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py
@@ -30,10 +30,6 @@
         if not CONF.volume_feature_enabled.snapshot:
             raise cls.skipException("Cinder snapshot feature disabled")
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(SnapshotMetadataRbacTest, self).tearDown()
-
     @classmethod
     def resource_setup(cls):
         super(SnapshotMetadataRbacTest, cls).resource_setup()
@@ -57,17 +53,17 @@
     @decorators.idempotent_id('c9cbec1c-edfe-46b8-825b-7b6ac0a58c25')
     def test_create_snapshot_metadata(self):
         # Create metadata for the snapshot
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_test_snapshot_metadata()
 
     @rbac_rule_validation.action(service="cinder",
-                                 rule="volume:get_volume_image_metadata")
+                                 rule="volume:get_snapshot_metadata")
     @decorators.idempotent_id('f6912bb1-62e6-483d-bcd0-e98c1641f4c3')
     def test_get_snapshot_metadata(self):
         # Create volume and snapshot metadata
         self._create_test_snapshot_metadata()
         # Get metadata for the snapshot
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.snapshots_client.show_snapshot_metadata(
             self.snapshot_id)
 
@@ -79,7 +75,7 @@
         # Create volume and snapshot metadata
         self._create_test_snapshot_metadata()
         # Get metadata for the snapshot
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         # Get the metadata of the snapshot
         self.snapshots_client.show_snapshot_metadata(
             self.snapshot_id)['metadata']
diff --git a/patrole_tempest_plugin/tests/api/volume/test_user_messages_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_user_messages_rbac.py
new file mode 100644
index 0000000..d2a5452
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/volume/test_user_messages_rbac.py
@@ -0,0 +1,94 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib.common.utils import test_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.volume import rbac_base
+
+CONF = config.CONF
+
+
+class MessagesV3RbacTest(rbac_base.BaseVolumeRbacTest):
+    _api_version = 3
+    min_microversion = '3.3'
+    max_microversion = 'latest'
+
+    @classmethod
+    def setup_clients(cls):
+        super(MessagesV3RbacTest, cls).setup_clients()
+        cls.messages_client = cls.os_primary.volume_v3_messages_client
+        cls.admin_messages_client = cls.os_admin.volume_v3_messages_client
+
+    def _create_user_message(self):
+        """Trigger a 'no valid host' situation to generate a message."""
+        bad_protocol = data_utils.rand_name(
+            self.__class__.__name__ + '-storage_protocol')
+        bad_vendor = data_utils.rand_name(
+            self.__class__.__name__ + '-vendor_name')
+        extra_specs = {'storage_protocol': bad_protocol,
+                       'vendor_name': bad_vendor}
+        vol_type_name = data_utils.rand_name(
+            self.__class__.__name__ + '-volume-type')
+        bogus_type = self.create_volume_type(
+            name=vol_type_name, extra_specs=extra_specs)
+        params = {'volume_type': bogus_type['id'],
+                  'size': CONF.volume.volume_size}
+        volume = self.create_volume(wait_until="error", **params)
+        messages = self.messages_client.list_messages()['messages']
+        message_id = None
+        for message in messages:
+            if message['resource_uuid'] == volume['id']:
+                message_id = message['id']
+                break
+        self.assertIsNotNone(message_id, 'No user message generated for '
+                                         'volume %s' % volume['id'])
+
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.messages_client.delete_message, message_id)
+
+        return message_id
+
+    @decorators.idempotent_id('bf7f31a1-509b-4a7d-a8a8-ad6ce68229c7')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="message:get_all")
+    def test_list_messages(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.messages_client.list_messages()['messages']
+
+    @decorators.idempotent_id('9cc1ad1e-68a2-4407-8b60-ea77909bce08')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="message:get")
+    def test_show_message(self):
+        message_id = self._create_user_message()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.messages_client.show_message(message_id)['message']
+
+    @decorators.idempotent_id('65ca7fb7-7f2c-443e-b144-ac86973a97be')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="message:delete")
+    def test_delete_message(self):
+        message_id = self._create_user_message()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.messages_client.delete_message(message_id)
+        self.admin_messages_client.wait_for_resource_deletion(message_id)
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 d8861b1..b666a2d 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
@@ -13,11 +13,13 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import compute
 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
@@ -28,93 +30,230 @@
 class VolumesActionsRbacTest(rbac_base.BaseVolumeRbacTest):
 
     @classmethod
-    def skip_checks(cls):
-        super(VolumesActionsRbacTest, cls).skip_checks()
-        # Nova is needed to create a server
-        if not CONF.service_available.nova:
-            skip_msg = ("%s skipped as nova is not available" % cls.__name__)
-            raise cls.skipException(skip_msg)
-        # Glance is needed to create an image
-        if not CONF.service_available.glance:
-            skip_msg = ("%s skipped as glance is not available" % cls.__name__)
-            raise cls.skipException(skip_msg)
-
-    @classmethod
     def setup_clients(cls):
         super(VolumesActionsRbacTest, cls).setup_clients()
-        cls.client = cls.os.volumes_client
-        cls.image_client = cls.os.image_client
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(VolumesActionsRbacTest, self).tearDown()
+        cls.admin_image_client = cls.os_admin.image_client_v2
 
     @classmethod
     def resource_setup(cls):
         super(VolumesActionsRbacTest, cls).resource_setup()
         cls.volume = cls.create_volume()
 
-    def _attach_volume(self):
-        server = self.create_server(wait_until='ACTIVE')
+    def _create_server(self):
+        server, _ = compute.create_test_server(
+            self.os_primary, wait_until='ACTIVE')
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.servers_client.delete_server, server['id'])
+        return server
+
+    def _attach_volume(self, server, volume_id=None):
+        if volume_id is None:
+            volume_id = self.volume['id']
+
         self.servers_client.attach_volume(
-            server['id'], volumeId=self.volume['id'],
+            server['id'], volumeId=volume_id,
             device='/dev/%s' % CONF.compute.volume_device_name)
-        waiters.wait_for_volume_status(self.client,
-                                       self.volume['id'], 'in-use')
-        self.addCleanup(self._detach_volume)
+        waiters.wait_for_volume_resource_status(
+            self.os_admin.volumes_client, volume_id, 'in-use')
+        self.addCleanup(self._detach_volume, volume_id)
 
-    def _detach_volume(self):
-        self.client.detach_volume(self.volume['id'])
-        waiters.wait_for_volume_status(self.client, self.volume['id'],
-                                       'available')
+    def _detach_volume(self, volume_id=None):
+        if volume_id is None:
+            volume_id = self.volume['id']
 
+        self.volumes_client.detach_volume(volume_id)
+        waiters.wait_for_volume_resource_status(
+            self.os_admin.volumes_client, volume_id, 'available')
+
+    @test.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):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # Attach the volume
-        self._attach_volume()
+        server = self._create_server()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._attach_volume(server)
 
+    @test.attr(type=["slow"])
+    @test.services('compute')
     @rbac_rule_validation.action(service="cinder", rule="volume:detach")
     @decorators.idempotent_id('5a042f6a-688b-42e6-a02e-fe5c47b89b07')
-    def test_detach_volume_to_instance(self):
-        # Attach the volume
-        self._attach_volume()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # Detach the volume
+    def test_detach_volume_from_instance(self):
+        server = self._create_server()
+        self._attach_volume(server)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._detach_volume()
 
-    @rbac_rule_validation.action(service="cinder", rule="volume:get")
-    @decorators.idempotent_id('c4c3fdd5-b1b1-49c3-b977-a9f40ee9257a')
-    def test_get_volume_attachment(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # Get attachment
-        self.client.show_volume(self.volume['id'])
-
-    @rbac_rule_validation.action(service="cinder",
-                                 rule="volume:copy_volume_to_image")
+    @test.attr(type=["slow"])
+    @test.services('image')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_actions:upload_image")
     @decorators.idempotent_id('b0d0da46-903c-4445-893e-20e680d68b50')
     def test_volume_upload(self):
-        image_name = data_utils.rand_name('image')
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        body = self.client.upload_volume(
-            self.volume['id'], image_name=image_name,
+        # TODO(felipemonteiro): The ``upload_volume`` endpoint also enforces
+        # "volume:copy_volume_to_image" but is not currently contained in
+        # Cinder's policy.json.
+        image_name = data_utils.rand_name(self.__class__.__name__ + '-Image')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        body = self.volumes_client.upload_volume(
+            self.volume['id'], image_name=image_name, visibility="private",
             disk_format=CONF.volume.disk_format)['os-volume_upload_image']
-        image_id = body['image_id']
+        image_id = body["image_id"]
         self.addCleanup(test_utils.call_and_ignore_notfound_exc,
-                        self.image_client.delete_image,
+                        self.admin_image_client.delete_image,
                         image_id)
-        waiters.wait_for_image_status(self.image_client, image_id, 'active')
+        waiters.wait_for_image_status(self.admin_image_client, image_id,
+                                      'active')
+        waiters.wait_for_volume_resource_status(self.os_admin.volumes_client,
+                                                self.volume['id'], 'available')
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:update_readonly_flag")
     @decorators.idempotent_id('2750717a-f250-4e41-9e09-02624aad6ff8')
     def test_volume_readonly_update(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.update_volume_readonly(self.volume['id'],
+                                                   readonly=True)
+        self.addCleanup(self.volumes_client.update_volume_readonly,
+                        self.volume['id'], readonly=False)
+
+    @decorators.idempotent_id('72bab13c-dfaf-4b6d-a132-c83a85fb1776')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_unmanage")
+    def test_unmanage_volume(self):
         volume = self.create_volume()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # Update volume readonly
-        self.client.update_volume_readonly(volume['id'], readonly=True)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.unmanage_volume(volume['id'])
+
+    @decorators.idempotent_id('59b783c0-f4ef-430c-8a90-1bad97d4ec5c')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume:update")
+    def test_volume_set_bootable(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.set_bootable_volume(self.volume['id'],
+                                                bootable=True)
+
+    @decorators.idempotent_id('41566922-75a1-4484-99c7-9c8782ee99ac')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume:reserve_volume")
+    def test_volume_reserve(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.reserve_volume(self.volume['id'])
+
+    @decorators.idempotent_id('e5fa9564-77d9-4e57-b0c0-3e0ae4d08535')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume:unreserve_volume")
+    def test_volume_unreserve(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.unreserve_volume(self.volume['id'])
+
+    @decorators.idempotent_id('c015c82f-7010-48cc-bd71-4ef542046f20')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume:retype")
+    def test_volume_retype(self):
+        vol_type = self.create_volume_type()['name']
+        volume = self.create_volume()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.retype_volume(volume['id'], new_type=vol_type)
+        waiters.wait_for_volume_retype(
+            self.os_admin.volumes_client, volume['id'], vol_type)
+
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_admin_actions:reset_status")
+    @decorators.idempotent_id('4b3dad7d-0e73-4839-8781-796dd3d7af1d')
+    def test_volume_reset_status(self):
+        volume = self.create_volume()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.reset_volume_status(volume['id'], status='error')
+
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_admin_actions:force_delete")
+    @decorators.idempotent_id('a312a937-6abf-4b91-a950-747086cbce48')
+    def test_volume_force_delete(self):
+        volume = self.create_volume()
+        self.volumes_client.reset_volume_status(volume['id'], status='error')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.force_delete_volume(volume['id'])
+        self.volumes_client.wait_for_resource_deletion(volume['id'])
+
+    @decorators.idempotent_id('48bd302b-950a-4830-840c-3158246ecdcc')
+    @test.services('compute')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_admin_actions:force_detach")
+    def test_force_detach_volume_from_instance(self):
+        volume = self.create_volume()
+        server = self._create_server()
+        self._attach_volume(server, volume['id'])
+        attachment = self.volumes_client.show_volume(
+            volume['id'])['volume']['attachments'][0]
+
+        # Reset volume's status to error.
+        self.volumes_client.reset_volume_status(volume['id'], status='error')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.force_detach_volume(
+            volume['id'], connector=None,
+            attachment_id=attachment['attachment_id'])
+        waiters.wait_for_volume_resource_status(self.os_admin.volumes_client,
+                                                volume['id'], 'available')
 
 
 class VolumesActionsV3RbacTest(VolumesActionsRbacTest):
     _api_version = 3
+
+
+class VolumesActionsV310RbacTest(rbac_base.BaseVolumeRbacTest):
+    _api_version = 3
+    min_microversion = '3.10'
+    max_microversion = 'latest'
+
+    @classmethod
+    def setup_clients(cls):
+        super(VolumesActionsV310RbacTest, cls).setup_clients()
+        cls.admin_image_client = cls.os_admin.image_client_v2
+
+    @test.attr(type=["slow"])
+    @test.services('image')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_actions:upload_public")
+    @decorators.idempotent_id('578a84dd-a6bd-4f97-a418-4a0c3c272c08')
+    def test_volume_upload_public(self):
+        # This also enforces "volume_extension:volume_actions:upload_image".
+        volume = self.create_volume()
+        image_name = data_utils.rand_name(self.__class__.__name__ + '-Image')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        body = self.volumes_client.upload_volume(
+            volume['id'], image_name=image_name, visibility="public",
+            disk_format=CONF.volume.disk_format)['os-volume_upload_image']
+        image_id = body["image_id"]
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.admin_image_client.delete_image,
+                        image_id)
+        waiters.wait_for_image_status(self.admin_image_client, image_id,
+                                      'active')
+        waiters.wait_for_volume_resource_status(self.os_admin.volumes_client,
+                                                volume['id'], 'available')
+
+
+class VolumesActionsV312RbacTest(rbac_base.BaseVolumeRbacTest):
+    _api_version = 3
+    min_microversion = '3.12'
+    max_microversion = 'latest'
+
+    @decorators.idempotent_id('a654833d-4811-4acd-93ef-5ac4a34c75bc')
+    @rbac_rule_validation.action(service="cinder", rule="volume:get_all")
+    def test_show_volume_summary(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.show_volume_summary()['volume-summary']
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_basic_crud_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_basic_crud_rbac.py
new file mode 100644
index 0000000..d780de7
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_basic_crud_rbac.py
@@ -0,0 +1,76 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.volume import rbac_base
+
+
+class VolumesV2BasicCrudRbacTest(rbac_base.BaseVolumeRbacTest):
+
+    @classmethod
+    def resource_setup(cls):
+        super(VolumesV2BasicCrudRbacTest, cls).resource_setup()
+        cls.volume = cls.create_volume()
+
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume:create")
+    @decorators.idempotent_id('426b08ef-6394-4d06-9128-965d5a6c38ef')
+    def test_create_volume(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.create_volume()
+
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume:delete")
+    @decorators.idempotent_id('6de9f9c2-509f-4558-867b-af21c7163be4')
+    def test_delete_volume(self):
+        volume = self.create_volume()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.delete_volume(volume['id'])
+
+    @rbac_rule_validation.action(service="cinder", rule="volume:get")
+    @decorators.idempotent_id('c4c3fdd5-b1b1-49c3-b977-a9f40ee9257a')
+    def test_get_volume(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.show_volume(self.volume['id'])
+
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume:get_all")
+    @decorators.idempotent_id('e3ab7906-b04b-4c45-aa11-1104d302f940')
+    def test_volume_list(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.list_volumes()
+
+    @rbac_rule_validation.action(service="cinder", rule="volume:update")
+    @decorators.idempotent_id('b751b889-9a9b-40d8-ae7d-4b0f65e71ac7')
+    def test_update_volume(self):
+        update_name = data_utils.rand_name(self.__class__.__name__ + 'volume')
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.update_volume(self.volume['id'],
+                                          name=update_name)
+
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_image_metadata")
+    @decorators.idempotent_id('3d48ca91-f02b-4616-a69d-4a8b296c8529')
+    def test_volume_list_image_metadata(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.list_volumes(detail=True)
+
+
+class VolumesV3BasicCrudRbacTest(VolumesV2BasicCrudRbacTest):
+    _api_version = 3
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_create_delete_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_create_delete_rbac.py
deleted file mode 100644
index 2f65f9a..0000000
--- a/patrole_tempest_plugin/tests/api/volume/test_volume_create_delete_rbac.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from oslo_log import log as logging
-
-from tempest import config
-from tempest.lib import decorators
-from tempest.lib import exceptions
-
-from patrole_tempest_plugin import rbac_exceptions
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.volume import rbac_base
-
-CONF = config.CONF
-LOG = logging.getLogger(__name__)
-
-
-class CreateDeleteVolumeRbacTest(rbac_base.BaseVolumeRbacTest):
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(CreateDeleteVolumeRbacTest, self).tearDown()
-
-    def _create_volume(self):
-        # create_volume waits for volume status to be
-        # "available" before returning and automatically
-        # cleans up at the end of testing
-        volume = self.create_volume()
-        return volume
-
-    @rbac_rule_validation.action(service="cinder",
-                                 rule="volume:create")
-    @decorators.idempotent_id('426b08ef-6394-4d06-9128-965d5a6c38ef')
-    def test_create_volume(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # Create a volume
-        self._create_volume()
-
-    @rbac_rule_validation.action(service="cinder",
-                                 rule="volume:delete")
-    @decorators.idempotent_id('6de9f9c2-509f-4558-867b-af21c7163be4')
-    def test_delete_volume(self):
-        try:
-            # Create a volume
-            volume = self._create_volume()
-            self.rbac_utils.switch_role(self, switchToRbacRole=True)
-            # Delete a volume
-            self.volumes_client.delete_volume(volume['id'])
-        except exceptions.NotFound as e:
-            raise rbac_exceptions.RbacActionFailed(e)
-
-
-class CreateDeleteVolumeV3RbacTest(CreateDeleteVolumeRbacTest):
-    _api_version = 3
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_hosts_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_hosts_rbac.py
index 45720e6..18a2768 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volume_hosts_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_hosts_rbac.py
@@ -19,15 +19,11 @@
 from patrole_tempest_plugin.tests.api.volume import rbac_base
 
 
-class VolumeHostsAdminRbacTest(rbac_base.BaseVolumeAdminRbacTest):
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(VolumeHostsAdminRbacTest, self).tearDown()
+class VolumeHostsRbacTest(rbac_base.BaseVolumeRbacTest):
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume_extension:hosts")
     @decorators.idempotent_id('64e837f5-5452-4e26-b934-c721ea7a8644')
     def test_list_hosts(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.volume_hosts_client.list_hosts()
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_metadata_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_metadata_rbac.py
index a90fadc..8c4185b 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volume_metadata_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_metadata_rbac.py
@@ -13,8 +13,6 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-from oslo_log import log as logging
-
 from tempest import config
 from tempest.lib import decorators
 
@@ -22,67 +20,86 @@
 from patrole_tempest_plugin.tests.api.volume import rbac_base
 
 CONF = config.CONF
-LOG = logging.getLogger(__name__)
 
 
 class VolumeMetadataRbacTest(rbac_base.BaseVolumeRbacTest):
+
     @classmethod
-    def setup_clients(cls):
-        super(VolumeMetadataRbacTest, cls).setup_clients()
-        cls.client = cls.os.volumes_client
+    def resource_setup(cls):
+        super(VolumeMetadataRbacTest, cls).resource_setup()
+        cls.volume = cls.create_volume()
+        cls.image_id = CONF.compute.image_ref
+
+    def setUp(self):
+        super(VolumeMetadataRbacTest, self).setUp()
+        self._add_metadata(self.volume)
 
     def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
+        self.volumes_client.update_volume_metadata(self.volume['id'], {})
         super(VolumeMetadataRbacTest, self).tearDown()
 
     def _add_metadata(self, volume):
         # Create metadata for the volume
-        metadata = {"key1": "value1",
-                    "key2": "value2",
-                    "key3": "value3",
-                    "key4": "<value&special_chars>"}
-        self.volumes_client.create_volume_metadata(volume['id'],
-                                                   metadata)['metadata']
+        metadata = {"key1": "value1"}
+        self.volumes_client.create_volume_metadata(
+            self.volume['id'], metadata)['metadata']
 
     @rbac_rule_validation.action(service="cinder",
-                                 rule="volume:update_volume_metadata")
+                                 rule="volume:create_volume_metadata")
     @decorators.idempotent_id('232bbb8b-4c29-44dc-9077-b1398c20b738')
     def test_create_volume_metadata(self):
-        volume = self.create_volume()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self._add_metadata(volume)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._add_metadata(self.volume)
 
     @rbac_rule_validation.action(service="cinder",
-                                 rule="volume:get")
+                                 rule="volume:get_volume_metadata")
     @decorators.idempotent_id('87ea37d9-23ab-47b2-a59c-16fc4d2c6dfa')
-    def test_get_volume_metadata(self):
-        volume = self.create_volume()
-        self._add_metadata(volume)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.volumes_client.show_volume_metadata(volume['id'])['metadata']
+    def test_show_volume_metadata(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.show_volume_metadata(self.volume['id'])['metadata']
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:delete_volume_metadata")
     @decorators.idempotent_id('7498dfc1-9db2-4423-ad20-e6dcb25d1beb')
-    def test_delete_volume_metadata(self):
-        volume = self.create_volume()
-        self._add_metadata(volume)
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.volumes_client.delete_volume_metadata_item(volume['id'],
+    def test_delete_volume_metadata_item(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.delete_volume_metadata_item(self.volume['id'],
                                                         "key1")
 
+    @decorators.idempotent_id('a41c8eed-2051-4a25-b401-df036faacbdc')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume:delete_volume_metadata")
+    def test_delete_volume_image_metadata(self):
+        self.volumes_client.update_volume_image_metadata(
+            self.volume['id'], image_id=self.image_id)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.delete_volume_image_metadata(self.volume['id'],
+                                                         'image_id')
+
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:update_volume_metadata")
     @decorators.idempotent_id('8ce2ff80-99ba-49ae-9bb1-7e96729ee5af')
-    def test_update_volume_metadata(self):
-        volume = self.create_volume()
-        self._add_metadata(volume)
-        # Metadata to update
-        update_item = {"key3": "value3_update"}
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+    def test_update_volume_metadata_item(self):
+        updated_metadata_item = {"key1": "value1_update"}
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.volumes_client.update_volume_metadata_item(
-            volume['id'], "key3", update_item)['meta']
+            self.volume['id'], "key1", updated_metadata_item)['meta']
 
+    @decorators.idempotent_id('a231b445-97a5-4657-b05f-245895e88da9')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume:update_volume_metadata")
+    def test_update_volume_metadata(self):
+        updated_metadata = {"key1": "value1"}
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.update_volume_metadata(self.volume['id'],
+                                                   updated_metadata)
 
-class VolumeMetadataV3RbacTest(VolumeMetadataRbacTest):
-    _api_version = 3
+    @decorators.idempotent_id('a9d9e825-5ea3-42e6-96f3-7ac4e97b2ed0')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume:update_volume_metadata")
+    def test_update_volume_image_metadata(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volumes_client.update_volume_image_metadata(
+            self.volume['id'], image_id=self.image_id)
diff --git a/patrole_tempest_plugin/tests/api/volume/admin/test_volume_quotas_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_quotas_rbac.py
similarity index 64%
rename from patrole_tempest_plugin/tests/api/volume/admin/test_volume_quotas_rbac.py
rename to patrole_tempest_plugin/tests/api/volume/test_volume_quotas_rbac.py
index 4fd8cd6..6e9812b 100644
--- a/patrole_tempest_plugin/tests/api/volume/admin/test_volume_quotas_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_quotas_rbac.py
@@ -13,42 +13,30 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import logging
-
-from tempest import config
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.volume import rbac_base
 
-QUOTA_KEYS = ['gigabytes', 'snapshots', 'volumes']
-QUOTA_USAGE_KEYS = ['reserved', 'limit', 'in_use']
-CONF = config.CONF
-LOG = logging.getLogger(__name__)
 
-
-class VolumeQuotasAdminRbacTest(rbac_base.BaseVolumeAdminRbacTest):
+class VolumeQuotasRbacTest(rbac_base.BaseVolumeRbacTest):
 
     @classmethod
     def setup_credentials(cls):
-        super(VolumeQuotasAdminRbacTest, cls).setup_credentials()
-        cls.demo_tenant_id = cls.os.credentials.tenant_id
+        super(VolumeQuotasRbacTest, cls).setup_credentials()
+        cls.demo_tenant_id = cls.os_primary.credentials.tenant_id
 
     @classmethod
     def setup_clients(cls):
-        super(VolumeQuotasAdminRbacTest, cls).setup_clients()
-        cls.client = cls.os.volume_quotas_client
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(VolumeQuotasAdminRbacTest, self).tearDown()
+        super(VolumeQuotasRbacTest, cls).setup_clients()
+        cls.quotas_client = cls.os_primary.volume_quotas_client
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume_extension:quotas:show")
     @decorators.idempotent_id('b3c7177e-b6b1-4d0f-810a-fc95606964dd')
     def test_list_default_quotas(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_default_quota_set(
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.quotas_client.show_default_quota_set(
             self.demo_tenant_id)['quota_set']
 
     @rbac_rule_validation.action(service="cinder",
@@ -59,11 +47,11 @@
                          'volumes': 11,
                          'snapshots': 11}
         # Update limits for all quota resources
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.update_quota_set(
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.quotas_client.update_quota_set(
             self.demo_tenant_id,
             **new_quota_set)['quota_set']
 
 
-class VolumeQuotasAdminV3RbacTest(VolumeQuotasAdminRbacTest):
+class VolumeQuotasV3RbacTest(VolumeQuotasRbacTest):
     _api_version = 3
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
new file mode 100644
index 0000000..ac6d2ce
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_services_rbac.py
@@ -0,0 +1,51 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.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
+
+
+class VolumeServicesRbacTest(rbac_base.BaseVolumeRbacTest):
+
+    # TODO(felipemonteiro): Implement a test to cover the policy action,
+    # "volume_extension:services:update", once the Tempest client endpoint
+    # is implemented.
+
+    @classmethod
+    def skip_checks(cls):
+        super(VolumeServicesRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('os-services', 'volume'):
+            msg = "%s skipped as os-services not enabled." % cls.__name__
+            raise cls.skipException(msg)
+
+    @classmethod
+    def setup_clients(cls):
+        super(VolumeServicesRbacTest, cls).setup_clients()
+        cls.services_client = cls.os_primary.volume_services_v2_client
+
+    @decorators.idempotent_id('b9134f01-97c0-4abd-9455-fe2f03e3f966')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:services:index")
+    def test_list_services(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.services_client.list_services()['services']
+
+
+class VolumeServicesV3RbacTest(VolumeServicesRbacTest):
+    _api_version = 3
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_transfers_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_transfers_rbac.py
index 885ab8b..212482c 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volume_transfers_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_transfers_rbac.py
@@ -14,30 +14,22 @@
 #    under the License.
 
 from tempest.common import waiters
-from tempest import config
 from tempest.lib.common.utils import test_utils
 from tempest.lib import decorators
 
 from patrole_tempest_plugin import rbac_rule_validation
 from patrole_tempest_plugin.tests.api.volume import rbac_base
 
-CONF = config.CONF
-
 
 class VolumesTransfersRbacTest(rbac_base.BaseVolumeRbacTest):
 
-    credentials = ['alt', 'admin']
+    credentials = ['primary', 'admin']
 
     @classmethod
     def setup_clients(cls):
         super(VolumesTransfersRbacTest, cls).setup_clients()
-        cls.client = cls.volumes_client
-        cls.alt_client = cls.os_alt.volumes_client
-        cls.alt_tenant_id = cls.alt_client.tenant_id
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(VolumesTransfersRbacTest, self).tearDown()
+        cls.transfers_client = cls.os_primary.volume_transfers_v2_client
+        cls.adm_volumes_client = cls.os_admin.volumes_v2_client
 
     @classmethod
     def resource_setup(cls):
@@ -47,14 +39,14 @@
     def _delete_transfer(self, transfer):
         # Volume from create_volume_transfer test may get stuck in
         # 'awaiting-transfer' state, preventing cleanup and causing
-        # the test to fail
+        # the test to fail.
         test_utils.call_and_ignore_notfound_exc(
-            self.client.delete_volume_transfer, transfer['id'])
-        waiters.wait_for_volume_status(self.client, self.volume['id'],
-                                       'available')
+            self.transfers_client.delete_volume_transfer, transfer['id'])
+        waiters.wait_for_volume_resource_status(
+            self.adm_volumes_client, self.volume['id'], 'available')
 
     def _create_transfer(self):
-        transfer = self.client.create_volume_transfer(
+        transfer = self.transfers_client.create_volume_transfer(
             volume_id=self.volume['id'])['transfer']
         self.addCleanup(self._delete_transfer, transfer)
         return transfer
@@ -63,7 +55,7 @@
                                  rule="volume:create_transfer")
     @decorators.idempotent_id('25413af4-468d-48ff-94ca-4436f8526b3e')
     def test_create_volume_transfer(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._create_transfer()
 
     @rbac_rule_validation.action(service="cinder",
@@ -71,32 +63,32 @@
     @decorators.idempotent_id('7a0925d3-ed97-4c25-8299-e5cdabe2eb55')
     def test_get_volume_transfer(self):
         transfer = self._create_transfer()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_volume_transfer(transfer['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.transfers_client.show_volume_transfer(transfer['id'])
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:get_all_transfers")
     @decorators.idempotent_id('02a06f2b-5040-49e2-b2b7-619a7db59603')
     def test_list_volume_transfers(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_volume_transfers()
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.transfers_client.list_volume_transfers()
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:accept_transfer")
     @decorators.idempotent_id('987f2a11-d657-4984-a6c9-28f06c1cd014')
     def test_accept_volume_transfer(self):
         transfer = self._create_transfer()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.accept_volume_transfer(transfer['id'],
-                                           auth_key=transfer['auth_key'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.transfers_client.accept_volume_transfer(
+            transfer['id'], auth_key=transfer['auth_key'])
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:delete_transfer")
     @decorators.idempotent_id('4672187e-7fff-454b-832a-5c8865dda868')
     def test_delete_volume_transfer(self):
         transfer = self._create_transfer()
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.delete_volume_transfer(transfer['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.transfers_client.delete_volume_transfer(transfer['id'])
 
 
 class VolumesTransfersV3RbacTest(VolumesTransfersRbacTest):
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
new file mode 100644
index 0000000..8fd68a3
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/volume/test_volume_types_access_rbac.py
@@ -0,0 +1,81 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.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
+
+
+class VolumeTypesAccessRbacTest(rbac_base.BaseVolumeRbacTest):
+    _api_version = 3
+
+    @classmethod
+    def skip_checks(cls):
+        super(VolumeTypesAccessRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('os-volume-type-access', 'volume'):
+            msg = "os-volume-type-access extension not enabled."
+            raise cls.skipException(msg)
+
+    @classmethod
+    def resource_setup(cls):
+        super(VolumeTypesAccessRbacTest, cls).resource_setup()
+        cls.vol_type = cls.create_volume_type(
+            **{'os-volume-type-access:is_public': False})
+        cls.project_id = cls.auth_provider.credentials.project_id
+
+    def _add_type_access(self, ignore_not_found=False):
+        self.volume_types_client.add_type_access(
+            self.vol_type['id'], project=self.project_id)
+
+        if ignore_not_found:
+            self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                            self.volume_types_client.remove_type_access,
+                            self.vol_type['id'], project=self.project_id)
+        else:
+            self.addCleanup(self.volume_types_client.remove_type_access,
+                            self.vol_type['id'], project=self.project_id)
+
+    @decorators.idempotent_id('af70e6ad-e931-419f-9200-8bcc284e4e47')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_type_access")
+    def test_list_type_access(self):
+        self._add_type_access()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volume_types_client.list_type_access(self.vol_type['id'])[
+            'volume_type_access']
+
+    @decorators.idempotent_id('b462eeba-45d0-4d6e-945a-a1d27708d367')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_type_access:addProjectAccess")
+    def test_add_type_access(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._add_type_access(ignore_not_found=True)
+
+    @decorators.idempotent_id('8f848aeb-636a-46f1-aeeb-e2a60e9d2bfe')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_type_access:removeProjectAccess")
+    def test_remove_type_access(self):
+        self._add_type_access(ignore_not_found=True)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volume_types_client.remove_type_access(
+            self.vol_type['id'], project=self.project_id)
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 0e9d2c3..97eaab7 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,28 +13,88 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-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
 
-CONF = config.CONF
 
+class VolumeTypesExtraSpecsRbacTest(rbac_base.BaseVolumeRbacTest):
+    _api_version = 3
 
-class VolumeTypesExtraSpecsAdminRbacTest(rbac_base.BaseVolumeAdminRbacTest):
+    @classmethod
+    def skip_checks(cls):
+        super(VolumeTypesExtraSpecsRbacTest, cls).skip_checks()
+        if not test.is_extension_enabled('os-types-extra-specs', 'volume'):
+            msg = "os-types-extra-specs extension not enabled."
+            raise cls.skipException(msg)
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(VolumeTypesExtraSpecsAdminRbacTest, self).tearDown()
+    @classmethod
+    def resource_setup(cls):
+        super(VolumeTypesExtraSpecsRbacTest, cls).resource_setup()
+        cls.vol_type = cls.create_volume_type()
+        cls.spec_key = data_utils.rand_name(cls.__name__ + '-Spec')
+
+    def _create_volume_type_extra_specs(self, ignore_not_found=False):
+        extra_specs = {self.spec_key: "val1"}
+        self.volume_types_client.create_volume_type_extra_specs(
+            self.vol_type['id'], extra_specs)
+
+        if ignore_not_found:
+            self.addCleanup(
+                test_utils.call_and_ignore_notfound_exc,
+                self.volume_types_client.delete_volume_type_extra_specs,
+                self.vol_type['id'], self.spec_key)
+        else:
+            self.addCleanup(
+                self.volume_types_client.delete_volume_type_extra_specs,
+                self.vol_type['id'], self.spec_key)
+
+    @decorators.idempotent_id('76c36be2-2b6c-4acf-9aac-c9dc5c17cdbe')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume_extension:types_extra_specs")
+    def test_list_volume_types_extra_specs(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volume_types_client.list_volume_types_extra_specs(
+            self.vol_type['id'])['extra_specs']
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume_extension:types_extra_specs")
     @decorators.idempotent_id('eea40251-990b-49b0-99ae-10e4585b479b')
-    def test_volume_type_extra_specs_list(self):
-        vol_type = self.create_volume_type()
-        # List Volume types extra specs.
-        extra_specs = {"spec1": "val1"}
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.volume_types_client.create_volume_type_extra_specs(
-            vol_type['id'], extra_specs)
+    def test_create_volume_type_extra_specs(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._create_volume_type_extra_specs(ignore_not_found=True)
+
+    @decorators.idempotent_id('e2dcc9c6-2fef-431d-afaf-92b45bc76d1a')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume_extension:types_extra_specs")
+    def test_show_volume_type_extra_specs(self):
+        self._create_volume_type_extra_specs()
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volume_types_client.show_volume_type_extra_specs(
+            self.vol_type['id'], self.spec_key)
+
+    @decorators.idempotent_id('93001912-f938-41c7-8787-62dc7010fd52')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume_extension:types_extra_specs")
+    def test_delete_volume_type_extra_specs(self):
+        self._create_volume_type_extra_specs(ignore_not_found=True)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volume_types_client.delete_volume_type_extra_specs(
+            self.vol_type['id'], self.spec_key)
+
+    @decorators.idempotent_id('0a444437-7402-4fbe-a18a-93af2ee00618')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="volume_extension:types_extra_specs")
+    def test_update_volume_type_extra_specs(self):
+        self._create_volume_type_extra_specs()
+        update_extra_specs = {self.spec_key: "val2"}
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.volume_types_client.update_volume_type_extra_specs(
+            self.vol_type['id'], self.spec_key, update_extra_specs)
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volumes_backup_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volumes_backup_rbac.py
index 8fb1c67..e6944cc 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volumes_backup_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volumes_backup_rbac.py
@@ -13,10 +13,15 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from oslo_serialization import base64
+from oslo_serialization import jsonutils as json
+
 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
@@ -26,74 +31,130 @@
 
 class VolumesBackupsRbacTest(rbac_base.BaseVolumeRbacTest):
 
+    def setUp(self):
+        super(VolumesBackupsRbacTest, self).setUp()
+        self.volume = self.create_volume()
+
     @classmethod
     def skip_checks(cls):
         super(VolumesBackupsRbacTest, cls).skip_checks()
         if not CONF.volume_feature_enabled.backup:
             raise cls.skipException("Cinder backup feature disabled")
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(VolumesBackupsRbacTest, self).tearDown()
+    def _decode_url(self, backup_url):
+        return json.loads(base64.decode_as_text(backup_url))
 
-    def create_backup(self, volume_id):
-        backup_name = data_utils.rand_name(
-            self.__class__.__name__ + '-Backup')
-        backup = self.backups_client.create_backup(
-            volume_id=volume_id, name=backup_name)['backup']
-        self.addCleanup(self.backups_client.delete_backup, backup['id'])
-        waiters.wait_for_backup_status(self.backups_client, backup['id'],
-                                       'available')
-        return backup
+    def _encode_backup(self, backup):
+        retval = json.dumps(backup)
+        return base64.encode_as_text(retval)
 
-    @classmethod
-    def resource_setup(cls):
-        super(VolumesBackupsRbacTest, cls).resource_setup()
-        cls.volume = cls.create_volume()
+    def _modify_backup_url(self, backup_url, changes):
+        backup = self._decode_url(backup_url)
+        backup.update(changes)
+        return self._encode_backup(backup)
 
+    @test.attr(type=["slow"])
     @rbac_rule_validation.action(service="cinder",
                                  rule="backup:create")
     @decorators.idempotent_id('6887ec94-0bcf-4ab7-b30f-3808a4b5a2a5')
-    def test_volume_backup_create(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+    def test_create_backup(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.create_backup(volume_id=self.volume['id'])
 
+    @test.attr(type=["slow"])
     @rbac_rule_validation.action(service="cinder",
                                  rule="backup:get")
     @decorators.idempotent_id('abd92bdd-b0fb-4dc4-9cfc-de9e968f8c8a')
-    def test_volume_backup_get(self):
-        # Create a temp backup
+    def test_show_backup(self):
         backup = self.create_backup(volume_id=self.volume['id'])
-        # Get a given backup
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.backups_client.show_backup(backup['id'])
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="backup:get_all")
     @decorators.idempotent_id('4d18f0f0-7e01-4007-b622-dedc859b22f6')
-    def test_volume_backup_list(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+    def test_list_backups(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.backups_client.list_backups()
 
+    @decorators.idempotent_id('dbd69865-876f-4835-b70e-7341153fb162')
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="backup:get_all")
+    def test_list_backups_with_details(self):
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.backups_client.list_backups(detail=True)
+
+    @decorators.idempotent_id('50f43bde-205e-438e-9a05-5eac07fc3d63')
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:backup_admin_actions:reset_status")
+    def test_reset_backup_status(self):
+        volume = self.create_volume()
+        backup = self.create_backup(volume_id=volume['id'])
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.backups_client.reset_backup_status(backup_id=backup['id'],
+                                                status='error')
+        waiters.wait_for_volume_resource_status(self.os_admin.backups_client,
+                                                backup['id'], 'error')
+
+    @test.attr(type=["slow"])
     @rbac_rule_validation.action(service="cinder",
                                  rule="backup:restore")
     @decorators.idempotent_id('9c794bf9-2446-4f41-8fe0-80b71e757f9d')
-    def test_volume_backup_restore(self):
-        # Create a temp backup
+    def test_restore_backup(self):
         backup = self.create_backup(volume_id=self.volume['id'])
-        # Restore backup
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.backups_client.restore_backup(backup['id'])['restore']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        restore = self.backups_client.restore_backup(backup['id'])['restore']
+        waiters.wait_for_volume_resource_status(
+            self.os_admin.backups_client, restore['backup_id'], 'available')
 
+    @test.attr(type=["slow"])
     @rbac_rule_validation.action(service="cinder",
                                  rule="backup:delete")
     @decorators.idempotent_id('d5d0c6a2-413d-437e-a73f-4bf2b41a20ed')
-    def test_volume_backup_delete(self):
-        # Create a temp backup
-        backup = self.create_backup(volume_id=self.volume['id'])
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        # Delete backup
+    def test_delete_backup(self):
+        # Do not call the create_backup in Tempest's base volume class, because
+        # it doesn't use ``test_utils.call_and_ignore_notfound_exc`` for clean
+        # up.
+        backup = self.backups_client.create_backup(
+            volume_id=self.volume['id'])['backup']
+        self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+                        self.backups_client.delete_backup, backup['id'])
+        waiters.wait_for_volume_resource_status(self.os_admin.backups_client,
+                                                backup['id'], 'available')
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.backups_client.delete_backup(backup['id'])
+        # Wait for deletion so error isn't thrown during clean up.
+        self.backups_client.wait_for_resource_deletion(backup['id'])
+
+    @test.attr(type=["slow"])
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="backup:backup-export")
+    @decorators.idempotent_id('e984ec8d-e8eb-485c-98bc-f1856020303c')
+    def test_export_backup(self):
+        backup = self.create_backup(volume_id=self.volume['id'])
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.backups_client.export_backup(backup['id'])['backup-record']
+
+    @test.attr(type=["slow"])
+    @rbac_rule_validation.action(service="cinder",
+                                 rule="backup:backup-import")
+    @decorators.idempotent_id('1e70f039-4556-44cc-9cc1-edf2b7ed648b')
+    def test_import_backup(self):
+        backup = self.create_backup(volume_id=self.volume['id'])
+        export_backup = self.backups_client.export_backup(
+            backup['id'])['backup-record']
+        new_id = data_utils.rand_uuid()
+        new_url = self._modify_backup_url(
+            export_backup['backup_url'], {'id': new_id})
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        import_backup = self.backups_client.import_backup(
+            backup_service=export_backup['backup_service'],
+            backup_url=new_url)['backup']
+        self.addCleanup(self.backups_client.delete_backup, import_backup['id'])
 
 
 class VolumesBackupsV3RbacTest(VolumesBackupsRbacTest):
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volumes_extend_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volumes_extend_rbac.py
index 8fccb47..5709669 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volumes_extend_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volumes_extend_rbac.py
@@ -25,10 +25,6 @@
 
 class VolumesExtendRbacTest(rbac_base.BaseVolumeRbacTest):
 
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(VolumesExtendRbacTest, self).tearDown()
-
     @classmethod
     def resource_setup(cls):
         super(VolumesExtendRbacTest, cls).resource_setup()
@@ -40,11 +36,11 @@
     def test_volume_extend(self):
         # Extend volume test
         extend_size = int(self.volume['size']) + 1
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.volumes_client.extend_volume(self.volume['id'],
                                           new_size=extend_size)
-        waiters.wait_for_volume_status(self.volumes_client, self.volume['id'],
-                                       'available')
+        waiters.wait_for_volume_resource_status(
+            self.os_admin.volumes_client, self.volume['id'], 'available')
 
 
 class VolumesExtendV3RbacTest(VolumesExtendRbacTest):
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volumes_list_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volumes_list_rbac.py
deleted file mode 100644
index cd37d1c..0000000
--- a/patrole_tempest_plugin/tests/api/volume/test_volumes_list_rbac.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright 2017 AT&T Corp
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from tempest import config
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.volume import rbac_base
-
-CONF = config.CONF
-
-
-class VolumesListRbacTest(rbac_base.BaseVolumeRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(VolumesListRbacTest, cls).setup_clients()
-        cls.client = cls.os.volumes_client
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(VolumesListRbacTest, self).tearDown()
-
-    @rbac_rule_validation.action(service="cinder",
-                                 rule="volume:get_all")
-    @decorators.idempotent_id('e3ab7906-b04b-4c45-aa11-1104d302f940')
-    def test_volume_list(self):
-        # Get a list of Volumes
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_volumes()
-
-    @rbac_rule_validation.action(
-        service="cinder",
-        rule="volume_extension:get_volumes_image_metadata")
-    @decorators.idempotent_id('3d48ca91-f02b-4616-a69d-4a8b296c8529')
-    def test_volume_list_image_metadata(self):
-        # Get a list of Volumes
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.list_volumes(detail=True)
-
-
-class VolumeListV3RbacTest(VolumesListRbacTest):
-    _api_version = 3
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volumes_manage_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volumes_manage_rbac.py
new file mode 100644
index 0000000..8e71ee8
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/volume/test_volumes_manage_rbac.py
@@ -0,0 +1,113 @@
+# Copyright 2017 AT&T Corporation.
+# All Rights Reserved.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+from tempest.common import waiters
+from tempest import config
+from tempest.lib.common.utils import data_utils
+from tempest.lib import decorators
+from tempest.lib import exceptions
+
+from patrole_tempest_plugin import rbac_rule_validation
+from patrole_tempest_plugin.tests.api.volume import rbac_base
+
+CONF = config.CONF
+
+
+class VolumesManageRbacTest(rbac_base.BaseVolumeRbacTest):
+
+    @classmethod
+    def skip_checks(cls):
+        super(VolumesManageRbacTest, cls).skip_checks()
+
+        if not CONF.volume_feature_enabled.manage_volume:
+            raise cls.skipException("Manage volume tests are disabled")
+
+        if len(CONF.volume.manage_volume_ref) != 2:
+            raise cls.skipException("Manage volume ref is not correctly "
+                                    "configured")
+
+    @classmethod
+    def setup_clients(cls):
+        super(VolumesManageRbacTest, cls).setup_clients()
+        cls.volume_manage_client = cls.os_primary.volume_manage_v2_client
+
+    def _manage_volume(self, org_volume):
+        # Manage volume
+        new_volume_name = data_utils.rand_name(
+            self.__class__.__name__ + '-volume')
+
+        new_volume_ref = {
+            'name': new_volume_name,
+            'host': org_volume['os-vol-host-attr:host'],
+            'ref': {CONF.volume.manage_volume_ref[0]:
+                    CONF.volume.manage_volume_ref[1] % org_volume['id']},
+            'volume_type': org_volume['volume_type'],
+            'availability_zone': org_volume['availability_zone']}
+
+        new_volume_id = self.volume_manage_client.manage_volume(
+            **new_volume_ref)['volume']['id']
+
+        waiters.wait_for_volume_resource_status(self.os_admin.volumes_client,
+                                                new_volume_id, 'available')
+        self.addCleanup(self.delete_volume,
+                        self.volumes_client, new_volume_id)
+
+    def _unmanage_volume(self, volume):
+        self.volumes_client.unmanage_volume(volume['id'])
+        self.volumes_client.wait_for_resource_deletion(volume['id'])
+
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_manage")
+    @decorators.idempotent_id('114f9708-939b-407e-aeac-d21ebfabaad3')
+    def test_volume_manage(self):
+        volume_id = self.create_volume()['id']
+        volume = self.volumes_client.show_volume(volume_id)['volume']
+
+        # By default, the volume is managed after creation.  We need to
+        # unmanage the volume first before testing manage volume.
+        self._unmanage_volume(volume)
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        try:
+            self._manage_volume(volume)
+        except exceptions.Forbidden as e:
+            # Since the test role under test does not have permission to
+            # manage the volume, Forbidden exception is thrown and the
+            # manageable list will not be cleaned up. Therefore, we need to
+            # re-manage the volume at the end of the test case for proper
+            # resource clean up.
+            self.addCleanup(self._manage_volume, volume)
+            raise exceptions.Forbidden(e)
+
+    @rbac_rule_validation.action(
+        service="cinder",
+        rule="volume_extension:volume_unmanage")
+    @decorators.idempotent_id('d5d72abe-60bc-45ac-a8f2-c21b24f0b5d6')
+    def test_volume_unmanage(self):
+        volume_id = self.create_volume()['id']
+        volume = self.volumes_client.show_volume(volume_id)['volume']
+
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self._unmanage_volume(volume)
+
+        # In order to clean up the manageable list, we need to re-manage the
+        # volume after the test.  The _manage_volume method will set up the
+        # proper resource cleanup
+        self.addCleanup(self._manage_volume, volume)
+
+
+class VolumesManageV3RbacTest(VolumesManageRbacTest):
+    _api_version = 3
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volumes_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volumes_rbac.py
deleted file mode 100644
index 71401f3..0000000
--- a/patrole_tempest_plugin/tests/api/volume/test_volumes_rbac.py
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright 2017 AT&T Corporation.
-# All Rights Reserved.
-#
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
-#    not use this file except in compliance with the License. You may obtain
-#    a copy of the License at
-#
-#         http://www.apache.org/licenses/LICENSE-2.0
-#
-#    Unless required by applicable law or agreed to in writing, software
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-#    License for the specific language governing permissions and limitations
-#    under the License.
-
-from oslo_log import log as logging
-
-from tempest import config
-from tempest.lib import decorators
-
-from patrole_tempest_plugin import rbac_rule_validation
-from patrole_tempest_plugin.tests.api.volume import rbac_base
-
-CONF = config.CONF
-LOG = logging.getLogger(__name__)
-
-
-class VolumesRbacTest(rbac_base.BaseVolumeRbacTest):
-
-    @classmethod
-    def setup_clients(cls):
-        super(VolumesRbacTest, cls).setup_clients()
-        cls.client = cls.volumes_client
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(VolumesRbacTest, self).tearDown()
-
-    @rbac_rule_validation.action(
-        service="cinder",
-        rule="volume_extension:volume_admin_actions:reset_status")
-    @decorators.idempotent_id('4b3dad7d-0e73-4839-8781-796dd3d7af1d')
-    def test_volume_reset_status(self):
-        volume = self.create_volume()
-        # Test volume reset status : available->error->available
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.reset_volume_status(volume['id'], status='error')
-        self.client.reset_volume_status(volume['id'], status='available')
-
-    @rbac_rule_validation.action(
-        service="cinder",
-        rule="volume_extension:volume_admin_actions:force_delete")
-    @decorators.idempotent_id('a312a937-6abf-4b91-a950-747086cbce48')
-    def test_volume_force_delete_when_volume_is_error(self):
-        volume = self.create_volume()
-        self.client.reset_volume_status(volume['id'], status='error')
-        # Test force delete when status of volume is error
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.force_delete_volume(volume['id'])
-        self.client.wait_for_resource_deletion(volume['id'])
-
-
-class VolumesV3RbacTest(VolumesRbacTest):
-    _api_version = 3
diff --git a/patrole_tempest_plugin/tests/api/volume/test_volumes_snapshots_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volumes_snapshots_rbac.py
index c6e7417..422a3db 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_volumes_snapshots_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_volumes_snapshots_rbac.py
@@ -13,6 +13,7 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+from tempest.common import waiters
 from tempest import config
 from tempest.lib import decorators
 
@@ -25,15 +26,6 @@
 class VolumesSnapshotRbacTest(rbac_base.BaseVolumeRbacTest):
 
     @classmethod
-    def setup_clients(cls):
-        super(VolumesSnapshotRbacTest, cls).setup_clients()
-        cls.client = cls.snapshots_client
-
-    def tearDown(self):
-        self.rbac_utils.switch_role(self, switchToRbacRole=False)
-        super(VolumesSnapshotRbacTest, self).tearDown()
-
-    @classmethod
     def skip_checks(cls):
         super(VolumesSnapshotRbacTest, cls).skip_checks()
         if not CONF.volume_feature_enabled.snapshot:
@@ -43,8 +35,6 @@
     def resource_setup(cls):
         super(VolumesSnapshotRbacTest, cls).resource_setup()
         # Create a test shared volume for tests
-        cls.name_field = cls.special_fields['name_field']
-        cls.descrip_field = cls.special_fields['descrip_field']
         cls.volume = cls.create_volume()
         # Create a test shared snapshot for tests
         cls.snapshot = cls.create_snapshot(cls.volume['id'])
@@ -52,7 +42,6 @@
     def _list_by_param_values(self, params, with_detail=False):
         # Perform list or list_details action with given params
         # and validates result.
-
         if with_detail:
             self.snapshots_client.list_snapshots(
                 detail=True, params=params)['snapshots']
@@ -65,7 +54,7 @@
     @decorators.idempotent_id('ac7b2ee5-fbc0-4360-afc2-de8fa4881ede')
     def test_snapshot_create(self):
         # Create a temp snapshot
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self.create_snapshot(self.volume['id'])
 
     @rbac_rule_validation.action(service="cinder",
@@ -73,20 +62,23 @@
     @decorators.idempotent_id('93a11b40-1ba8-44d6-a196-f8d97220f796')
     def test_snapshot_get(self):
         # Get the snapshot
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.show_snapshot(self.snapshot
-                                  ['id'])['snapshot']
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.snapshots_client.show_snapshot(self.snapshot
+                                            ['id'])['snapshot']
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:update_snapshot")
     @decorators.idempotent_id('53fe8ee3-3bea-4ae8-a979-3c98ea72f620')
     def test_snapshot_update(self):
         new_desc = 'This is the new description of snapshot.'
-        params = {self.descrip_field: new_desc}
+        params = {'description': new_desc}
         # Updates snapshot with new values
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
-        self.client.update_snapshot(
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+        self.snapshots_client.update_snapshot(
             self.snapshot['id'], **params)['snapshot']
+        waiters.wait_for_volume_resource_status(
+            self.os_admin.snapshots_client,
+            self.snapshot['id'], 'available')
 
     @rbac_rule_validation.action(service="cinder",
                                  rule="volume:get_all_snapshots")
@@ -94,8 +86,8 @@
     def test_snapshots_get_all(self):
         """list snapshots with params."""
         # Verify list snapshots by display_name filter
-        params = {self.name_field: self.snapshot[self.name_field]}
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        params = {'name': self.snapshot['name']}
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         self._list_by_param_values(params)
 
     @rbac_rule_validation.action(service="cinder",
@@ -104,9 +96,11 @@
     def test_snapshot_delete(self):
         # Create a temp snapshot
         temp_snapshot = self.create_snapshot(self.volume['id'])
-        self.rbac_utils.switch_role(self, switchToRbacRole=True)
+        self.rbac_utils.switch_role(self, toggle_rbac_role=True)
         # Delete the snapshot
-        self.client.delete_snapshot(temp_snapshot['id'])
+        self.snapshots_client.delete_snapshot(temp_snapshot['id'])
+        self.os_admin.snapshots_client.wait_for_resource_deletion(
+            temp_snapshot['id'])
 
 
 class VolumesSnapshotV3RbacTest(VolumesSnapshotRbacTest):
diff --git a/patrole_tempest_plugin/tests/unit/resources/custom_rbac_policy.json b/patrole_tempest_plugin/tests/unit/resources/custom_rbac_policy.json
index 0e7466a..d959168 100644
--- a/patrole_tempest_plugin/tests/unit/resources/custom_rbac_policy.json
+++ b/patrole_tempest_plugin/tests/unit/resources/custom_rbac_policy.json
@@ -10,5 +10,5 @@
     "policy_action_3": "rule:zero_rule",
     "policy_action_4": "rule:prime_rule",
     "policy_action_5": "rule:all_rule",
-    "policy_action_6": "role:eight",
+    "policy_action_6": "role:eight"
 }
diff --git a/patrole_tempest_plugin/tests/unit/resources/rbac_roles.yaml b/patrole_tempest_plugin/tests/unit/resources/rbac_roles.yaml
new file mode 100644
index 0000000..c5436d0
--- /dev/null
+++ b/patrole_tempest_plugin/tests/unit/resources/rbac_roles.yaml
@@ -0,0 +1,6 @@
+Test:
+  test:create:
+    - test_member
+    - _member_
+  test:create2:
+    - test_member
diff --git a/patrole_tempest_plugin/tests/unit/test_rbac_policy_parser.py b/patrole_tempest_plugin/tests/unit/test_rbac_policy_parser.py
index 35aaa82..e3a4429 100644
--- a/patrole_tempest_plugin/tests/unit/test_rbac_policy_parser.py
+++ b/patrole_tempest_plugin/tests/unit/test_rbac_policy_parser.py
@@ -13,12 +13,14 @@
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
+import json
 import mock
 import os
 
 from tempest import config
 from tempest.tests import base
 
+from patrole_tempest_plugin import rbac_exceptions
 from patrole_tempest_plugin import rbac_policy_parser
 
 CONF = config.CONF
@@ -26,8 +28,21 @@
 
 class RbacPolicyTest(base.TestCase):
 
+    services = {
+        'services': [
+            {'name': 'custom_rbac_policy'},
+            {'name': 'admin_rbac_policy'},
+            {'name': 'alt_admin_rbac_policy'},
+            {'name': 'tenant_rbac_policy'},
+            {'name': 'test_service'}
+        ]
+    }
+
     def setUp(self):
         super(RbacPolicyTest, self).setUp()
+        mock_admin_mgr = self.patchobject(rbac_policy_parser, 'credentials')
+        mock_admin_mgr.AdminManager().identity_services_v3_client.\
+            list_services.return_value = self.services
 
         current_directory = os.path.dirname(os.path.realpath(__file__))
         self.custom_policy_file = os.path.join(current_directory,
@@ -43,6 +58,18 @@
                                                'resources',
                                                'tenant_rbac_policy.json')
 
+        CONF.set_override(
+            'custom_policy_files',
+            [os.path.join(current_directory, 'resources', '%s.json')],
+            group='rbac')
+        self.addCleanup(CONF.clear_override, 'custom_policy_files',
+                        group='rbac')
+
+    def _get_fake_policy_rule(self, name, rule):
+        fake_rule = mock.Mock(check=rule)
+        fake_rule.name = name
+        return fake_rule
+
     @mock.patch.object(rbac_policy_parser, 'LOG', autospec=True)
     def test_custom_policy(self, m_log):
         default_roles = ['zero', 'one', 'two', 'three', 'four',
@@ -50,8 +77,8 @@
 
         test_tenant_id = mock.sentinel.tenant_id
         test_user_id = mock.sentinel.user_id
-        converter = rbac_policy_parser.RbacPolicyParser(
-            test_tenant_id, test_user_id, "test", self.custom_policy_file)
+        parser = rbac_policy_parser.RbacPolicyParser(
+            test_tenant_id, test_user_id, "custom_rbac_policy")
 
         expected = {
             'policy_action_1': ['two', 'four', 'six', 'eight'],
@@ -63,25 +90,17 @@
             'policy_action_6': ['eight'],
         }
 
-        fake_rule = 'fake_rule'
-
-        for role in default_roles:
-            self.assertFalse(converter.allowed(fake_rule, role))
-            m_log.debug.assert_called_once_with(
-                "{0} not found in policy file.".format('fake_rule'))
-            m_log.debug.reset_mock()
-
         for rule, role_list in expected.items():
             for role in role_list:
-                self.assertTrue(converter.allowed(rule, role))
+                self.assertTrue(parser.allowed(rule, role))
             for role in set(default_roles) - set(role_list):
-                self.assertFalse(converter.allowed(rule, role))
+                self.assertFalse(parser.allowed(rule, role))
 
     def test_admin_policy_file_with_admin_role(self):
         test_tenant_id = mock.sentinel.tenant_id
         test_user_id = mock.sentinel.user_id
-        converter = rbac_policy_parser.RbacPolicyParser(
-            test_tenant_id, test_user_id, "test", self.admin_policy_file)
+        parser = rbac_policy_parser.RbacPolicyParser(
+            test_tenant_id, test_user_id, "admin_rbac_policy")
 
         role = 'admin'
         allowed_rules = [
@@ -90,18 +109,18 @@
         disallowed_rules = ['non_admin_rule']
 
         for rule in allowed_rules:
-            allowed = converter.allowed(rule, role)
+            allowed = parser.allowed(rule, role)
             self.assertTrue(allowed)
 
         for rule in disallowed_rules:
-            allowed = converter.allowed(rule, role)
+            allowed = parser.allowed(rule, role)
             self.assertFalse(allowed)
 
     def test_admin_policy_file_with_member_role(self):
         test_tenant_id = mock.sentinel.tenant_id
         test_user_id = mock.sentinel.user_id
-        converter = rbac_policy_parser.RbacPolicyParser(
-            test_tenant_id, test_user_id, "test", self.admin_policy_file)
+        parser = rbac_policy_parser.RbacPolicyParser(
+            test_tenant_id, test_user_id, "admin_rbac_policy")
 
         role = 'Member'
         allowed_rules = [
@@ -111,29 +130,29 @@
             'admin_rule', 'is_admin_rule', 'alt_admin_rule']
 
         for rule in allowed_rules:
-            allowed = converter.allowed(rule, role)
+            allowed = parser.allowed(rule, role)
             self.assertTrue(allowed)
 
         for rule in disallowed_rules:
-            allowed = converter.allowed(rule, role)
+            allowed = parser.allowed(rule, role)
             self.assertFalse(allowed)
 
-    def test_admin_policy_file_with_context_is_admin(self):
+    def test_alt_admin_policy_file_with_context_is_admin(self):
         test_tenant_id = mock.sentinel.tenant_id
         test_user_id = mock.sentinel.user_id
-        converter = rbac_policy_parser.RbacPolicyParser(
-            test_tenant_id, test_user_id, "test", self.alt_admin_policy_file)
+        parser = rbac_policy_parser.RbacPolicyParser(
+            test_tenant_id, test_user_id, "alt_admin_rbac_policy")
 
         role = 'fake_admin'
         allowed_rules = ['non_admin_rule']
         disallowed_rules = ['admin_rule']
 
         for rule in allowed_rules:
-            allowed = converter.allowed(rule, role)
+            allowed = parser.allowed(rule, role)
             self.assertTrue(allowed)
 
         for rule in disallowed_rules:
-            allowed = converter.allowed(rule, role)
+            allowed = parser.allowed(rule, role)
             self.assertFalse(allowed)
 
         role = 'super_admin'
@@ -141,11 +160,11 @@
         disallowed_rules = ['non_admin_rule']
 
         for rule in allowed_rules:
-            allowed = converter.allowed(rule, role)
+            allowed = parser.allowed(rule, role)
             self.assertTrue(allowed)
 
         for rule in disallowed_rules:
-            allowed = converter.allowed(rule, role)
+            allowed = parser.allowed(rule, role)
             self.assertFalse(allowed)
 
     def test_tenant_user_policy(self):
@@ -157,28 +176,28 @@
         """
         test_tenant_id = mock.sentinel.tenant_id
         test_user_id = mock.sentinel.user_id
-        converter = rbac_policy_parser.RbacPolicyParser(
-            test_tenant_id, test_user_id, "test", self.tenant_policy_file)
+        parser = rbac_policy_parser.RbacPolicyParser(
+            test_tenant_id, test_user_id, "tenant_rbac_policy")
 
         # Check whether Member role can perform expected actions.
         allowed_rules = ['rule1', 'rule2', 'rule3', 'rule4']
         for rule in allowed_rules:
-            allowed = converter.allowed(rule, 'Member')
+            allowed = parser.allowed(rule, 'Member')
             self.assertTrue(allowed)
 
         disallowed_rules = ['admin_tenant_rule', 'admin_user_rule']
         for disallowed_rule in disallowed_rules:
-            self.assertFalse(converter.allowed(disallowed_rule, 'Member'))
+            self.assertFalse(parser.allowed(disallowed_rule, 'Member'))
 
         # Check whether admin role can perform expected actions.
         allowed_rules.extend(disallowed_rules)
         for rule in allowed_rules:
-            allowed = converter.allowed(rule, 'admin')
+            allowed = parser.allowed(rule, 'admin')
             self.assertTrue(allowed)
 
         # Check whether _try_rule is called with the correct target dictionary.
         with mock.patch.object(
-            converter, '_try_rule', return_value=True, autospec=True) \
+            parser, '_try_rule', return_value=True, autospec=True) \
             as mock_try_rule:
 
             expected_target = {
@@ -198,8 +217,213 @@
             }
 
             for rule in allowed_rules:
-                allowed = converter.allowed(rule, 'Member')
+                allowed = parser.allowed(rule, 'Member')
                 self.assertTrue(allowed)
                 mock_try_rule.assert_called_once_with(
                     rule, expected_target, expected_access_data, mock.ANY)
                 mock_try_rule.reset_mock()
+
+    @mock.patch.object(rbac_policy_parser, 'LOG', autospec=True)
+    def test_invalid_service_raises_exception(self, m_log):
+        test_tenant_id = mock.sentinel.tenant_id
+        test_user_id = mock.sentinel.user_id
+        service = 'invalid_service'
+
+        self.assertRaises(rbac_exceptions.RbacInvalidService,
+                          rbac_policy_parser.RbacPolicyParser,
+                          test_tenant_id,
+                          test_user_id,
+                          service)
+
+        m_log.debug.assert_called_once_with(
+            '%s is NOT a valid service.', service)
+
+    @mock.patch.object(rbac_policy_parser, 'LOG', autospec=True)
+    def test_service_is_none_raises_exception(self, m_log):
+        test_tenant_id = mock.sentinel.tenant_id
+        test_user_id = mock.sentinel.user_id
+        service = None
+
+        self.assertRaises(rbac_exceptions.RbacInvalidService,
+                          rbac_policy_parser.RbacPolicyParser,
+                          test_tenant_id,
+                          test_user_id,
+                          service)
+
+        m_log.debug.assert_called_once_with('%s is NOT a valid service.', None)
+
+    @mock.patch.object(rbac_policy_parser, 'LOG', autospec=True)
+    def test_invalid_policy_rule_throws_rbac_parsing_exception(self, m_log):
+        test_tenant_id = mock.sentinel.tenant_id
+        test_user_id = mock.sentinel.user_id
+        parser = rbac_policy_parser.RbacPolicyParser(
+            test_tenant_id, test_user_id, "custom_rbac_policy")
+
+        fake_rule = 'fake_rule'
+        expected_message = "Policy action: {0} not found in policy file: {1}."\
+                           .format(fake_rule, self.custom_policy_file)
+
+        e = self.assertRaises(rbac_exceptions.RbacParsingException,
+                              parser.allowed, fake_rule, None)
+        self.assertIn(expected_message, str(e))
+        m_log.debug.assert_called_once_with(expected_message)
+
+    @mock.patch.object(rbac_policy_parser, 'LOG', autospec=True)
+    def test_unknown_exception_throws_rbac_parsing_exception(self, m_log):
+        test_tenant_id = mock.sentinel.tenant_id
+        test_user_id = mock.sentinel.user_id
+
+        parser = rbac_policy_parser.RbacPolicyParser(
+            test_tenant_id, test_user_id, "custom_rbac_policy")
+        parser.rules = mock.MagicMock(
+            **{'__getitem__.return_value.side_effect': Exception(
+               mock.sentinel.error)})
+
+        expected_message = "Policy action: {0} not found in "\
+                           "policy file: {1}.".format(mock.sentinel.rule,
+                                                      self.custom_policy_file)
+
+        e = self.assertRaises(rbac_exceptions.RbacParsingException,
+                              parser.allowed, mock.sentinel.rule, None)
+        self.assertIn(expected_message, str(e))
+        m_log.debug.assert_called_once_with(expected_message)
+
+    @mock.patch.object(rbac_policy_parser, 'stevedore', autospec=True)
+    def test_get_policy_data_from_file_and_from_code(self, mock_stevedore):
+        fake_policy_rules = [
+            self._get_fake_policy_rule('code_policy_action_1',
+                                       'rule:code_rule_1'),
+            self._get_fake_policy_rule('code_policy_action_2',
+                                       'rule:code_rule_2'),
+            self._get_fake_policy_rule('code_policy_action_3',
+                                       'rule:code_rule_3'),
+        ]
+
+        mock_manager = mock.Mock(obj=fake_policy_rules)
+        mock_manager.configure_mock(name='fake_service')
+        mock_stevedore.named.NamedExtensionManager.return_value = [
+            mock_manager
+        ]
+
+        test_tenant_id = mock.sentinel.tenant_id
+        test_user_id = mock.sentinel.user_id
+        parser = rbac_policy_parser.RbacPolicyParser(
+            test_tenant_id, test_user_id, "tenant_rbac_policy")
+
+        policy_data = parser._get_policy_data('fake_service')
+        self.assertIsInstance(policy_data, str)
+
+        actual_policy_data = json.loads(policy_data)
+        expected_policy_data = {
+            "code_policy_action_1": "rule:code_rule_1",
+            "code_policy_action_2": "rule:code_rule_2",
+            "code_policy_action_3": "rule:code_rule_3",
+            "rule1": "tenant_id:%(network:tenant_id)s",
+            "rule2": "tenant_id:%(tenant_id)s",
+            "rule3": "project_id:%(project_id)s",
+            "rule4": "user_id:%(user_id)s",
+            "admin_tenant_rule": "role:admin and tenant_id:%(tenant_id)s",
+            "admin_user_rule": "role:admin and user_id:%(user_id)s"
+        }
+
+        self.assertEqual(expected_policy_data, actual_policy_data)
+
+    @mock.patch.object(rbac_policy_parser, 'stevedore', autospec=True)
+    def test_get_policy_data_from_file_and_from_code_with_overwrite(
+            self, mock_stevedore):
+        # The custom policy file should overwrite default rules rule1 and rule2
+        # that are defined in code.
+        fake_policy_rules = [
+            self._get_fake_policy_rule('rule1', 'rule:code_rule_1'),
+            self._get_fake_policy_rule('rule2', 'rule:code_rule_2'),
+            self._get_fake_policy_rule('code_policy_action_3',
+                                       'rule:code_rule_3'),
+        ]
+
+        mock_manager = mock.Mock(obj=fake_policy_rules)
+        mock_manager.configure_mock(name='fake_service')
+        mock_stevedore.named.NamedExtensionManager.return_value = [
+            mock_manager
+        ]
+
+        test_tenant_id = mock.sentinel.tenant_id
+        test_user_id = mock.sentinel.user_id
+
+        parser = rbac_policy_parser.RbacPolicyParser(
+            test_tenant_id, test_user_id, 'tenant_rbac_policy')
+        policy_data = parser._get_policy_data('fake_service')
+        self.assertIsInstance(policy_data, str)
+
+        actual_policy_data = json.loads(policy_data)
+        expected_policy_data = {
+            "code_policy_action_3": "rule:code_rule_3",
+            "rule1": "tenant_id:%(network:tenant_id)s",
+            "rule2": "tenant_id:%(tenant_id)s",
+            "rule3": "project_id:%(project_id)s",
+            "rule4": "user_id:%(user_id)s",
+            "admin_tenant_rule": "role:admin and tenant_id:%(tenant_id)s",
+            "admin_user_rule": "role:admin and user_id:%(user_id)s"
+        }
+
+        self.assertEqual(expected_policy_data, actual_policy_data)
+
+    @mock.patch.object(rbac_policy_parser, 'stevedore', autospec=True)
+    def test_get_policy_data_cannot_find_policy(self, mock_stevedore):
+        mock_stevedore.named.NamedExtensionManager.return_value = None
+        e = self.assertRaises(rbac_exceptions.RbacParsingException,
+                              rbac_policy_parser.RbacPolicyParser,
+                              None, None, 'test_service')
+
+        expected_error = \
+            'Policy file for {0} service neither found in code '\
+            'nor at {1}.'.format(
+                'test_service',
+                [CONF.rbac.custom_policy_files[0] % 'test_service'])
+
+        self.assertIn(expected_error, str(e))
+
+    @mock.patch.object(rbac_policy_parser, 'json', autospec=True)
+    @mock.patch.object(rbac_policy_parser, 'stevedore', autospec=True)
+    def test_get_policy_data_without_valid_policy(self, mock_stevedore,
+                                                  mock_json):
+        test_policy_action = mock.Mock(check='rule:bar')
+        test_policy_action.configure_mock(name='foo')
+
+        test_policy = mock.Mock(obj=[test_policy_action])
+        test_policy.configure_mock(name='test_service')
+
+        mock_stevedore.named.NamedExtensionManager\
+            .return_value = [test_policy]
+
+        mock_json.dumps.side_effect = ValueError
+
+        e = self.assertRaises(rbac_exceptions.RbacParsingException,
+                              rbac_policy_parser.RbacPolicyParser,
+                              None, None, 'test_service')
+
+        expected_error = "Policy file for {0} service is invalid."\
+                         .format("test_service")
+        self.assertIn(expected_error, str(e))
+
+        mock_stevedore.named.NamedExtensionManager.assert_called_once_with(
+            'oslo.policy.policies',
+            names=['test_service'],
+            on_load_failure_callback=None,
+            invoke_on_load=True,
+            warn_on_missing_entrypoint=False)
+
+    @mock.patch.object(rbac_policy_parser, 'json', autospec=True)
+    @mock.patch.object(rbac_policy_parser, 'stevedore', autospec=True)
+    def test_get_policy_data_from_file_not_json(self, mock_stevedore,
+                                                mock_json):
+        mock_stevedore.named.NamedExtensionManager.return_value = None
+        mock_json.loads.side_effect = ValueError
+        e = self.assertRaises(rbac_exceptions.RbacParsingException,
+                              rbac_policy_parser.RbacPolicyParser,
+                              None, None, 'tenant_rbac_policy')
+
+        expected_error = (
+            'Policy file for {0} service neither found in code nor at {1}.'
+            .format('tenant_rbac_policy', [CONF.rbac.custom_policy_files[0]
+                                           % 'tenant_rbac_policy']))
+        self.assertIn(expected_error, str(e))
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 edc442e..a90ec2a 100644
--- a/patrole_tempest_plugin/tests/unit/test_rbac_rule_validation.py
+++ b/patrole_tempest_plugin/tests/unit/test_rbac_rule_validation.py
@@ -14,99 +14,321 @@
 
 import mock
 
+from tempest import config
+from tempest.lib import exceptions
+from tempest import test
+from tempest.tests import base
+
 from patrole_tempest_plugin import rbac_exceptions
 from patrole_tempest_plugin import rbac_rule_validation as rbac_rv
 
-from tempest.lib import exceptions
-
-from tempest.tests import base
+CONF = config.CONF
 
 
 class RBACRuleValidationTest(base.TestCase):
-    @mock.patch('patrole_tempest_plugin.rbac_auth.RbacAuthority')
-    def test_RBAC_rv_happy_path(self, mock_auth):
-        decorator = rbac_rv.action("", "")
-        mock_function = mock.Mock()
-        mock_args = mock.MagicMock(**{
-            'auth_provider.credentials.tenant_id': 'tenant_id'
-        })
-        wrapper = decorator(mock_function)
-        wrapper((mock_args))
-        self.assertTrue(mock_function.called)
 
-    @mock.patch('patrole_tempest_plugin.rbac_auth.RbacAuthority')
-    def test_RBAC_rv_forbidden(self, mock_auth):
-        decorator = rbac_rv.action("", "")
+    def setUp(self):
+        super(RBACRuleValidationTest, self).setUp()
+        self.mock_args = mock.Mock(spec=test.BaseTestCase)
+        self.mock_args.auth_provider = mock.Mock()
+        self.mock_args.rbac_utils = mock.Mock()
+        self.mock_args.auth_provider.credentials.project_id = \
+            mock.sentinel.project_id
+        self.mock_args.auth_provider.credentials.user_id = \
+            mock.sentinel.user_id
+
+        CONF.set_override('rbac_test_role', 'Member', group='rbac')
+        self.addCleanup(CONF.clear_override, 'rbac_test_role', group='rbac')
+
+    @mock.patch.object(rbac_rv, 'LOG', autospec=True)
+    @mock.patch.object(rbac_rv, 'rbac_policy_parser', autospec=True)
+    def test_rule_validation_have_permission_no_exc(self, mock_policy,
+                                                    mock_log):
+        """Test that having permission and no exception thrown is success.
+
+        Positive test case success scenario.
+        """
+        decorator = rbac_rv.action(mock.sentinel.service, mock.sentinel.action)
+
+        mock_function = mock.Mock()
+        wrapper = decorator(mock_function)
+
+        mock_policy.RbacPolicyParser.return_value.allowed.return_value = True
+
+        result = wrapper(self.mock_args)
+
+        self.assertIsNone(result)
+        mock_log.warning.assert_not_called()
+        mock_log.error.assert_not_called()
+
+    @mock.patch.object(rbac_rv, 'LOG', autospec=True)
+    @mock.patch.object(rbac_rv, 'rbac_policy_parser', autospec=True)
+    def test_rule_validation_lack_permission_throw_exc(self, mock_policy,
+                                                       mock_log):
+        """Test that having no permission and exception thrown is success.
+
+        Negative test case success scenario.
+        """
+        decorator = rbac_rv.action(mock.sentinel.service, mock.sentinel.action)
+
         mock_function = mock.Mock()
         mock_function.side_effect = exceptions.Forbidden
         wrapper = decorator(mock_function)
-        mock_args = mock.MagicMock(**{
-            'auth_provider.credentials.tenant_id': 'tenant_id'
-        })
 
-        self.assertRaises(exceptions.Forbidden, wrapper, mock_args)
+        mock_policy.RbacPolicyParser.return_value.allowed.return_value = False
 
-    @mock.patch('patrole_tempest_plugin.rbac_auth.RbacAuthority')
-    def test_RBAC_rv_rbac_action_failed(self, mock_auth):
-        decorator = rbac_rv.action("", "")
-        mock_function = mock.Mock()
-        mock_function.side_effect = rbac_exceptions.RbacActionFailed
-        mock_args = mock.MagicMock(**{
-            'auth_provider.credentials.tenant_id': 'tenant_id'
-        })
+        result = wrapper(self.mock_args)
 
-        wrapper = decorator(mock_function)
-        self.assertRaises(exceptions.Forbidden, wrapper, mock_args)
+        self.assertIsNone(result)
+        mock_log.warning.assert_not_called()
+        mock_log.error.assert_not_called()
 
-    @mock.patch('patrole_tempest_plugin.rbac_auth.RbacAuthority')
-    def test_RBAC_rv_not_allowed(self, mock_auth):
-        decorator = rbac_rv.action("", "")
+    @mock.patch.object(rbac_rv, 'LOG', autospec=True)
+    @mock.patch.object(rbac_rv, 'rbac_policy_parser', autospec=True)
+    def test_rule_validation_forbidden_negative(self, mock_policy, mock_log):
+        """Test Forbidden error is thrown and have permission fails.
 
-        mock_function = mock.Mock()
-        wrapper = decorator(mock_function)
-
-        mock_permission = mock.Mock()
-        mock_permission.get_permission.return_value = False
-        mock_auth.return_value = mock_permission
-
-        mock_args = mock.MagicMock(**{
-            'auth_provider.credentials.tenant_id': 'tenant_id'
-        })
-
-        self.assertRaises(rbac_exceptions.RbacOverPermission, wrapper,
-                          mock_args)
-
-    @mock.patch('patrole_tempest_plugin.rbac_auth.RbacAuthority')
-    def test_RBAC_rv_forbidden_not_allowed(self, mock_auth):
-        decorator = rbac_rv.action("", "")
-
+        Negative test case: if Forbidden is thrown and the user should be
+        allowed to perform the action, then the Forbidden exception should be
+        raised.
+        """
+        decorator = rbac_rv.action(mock.sentinel.service, mock.sentinel.action)
         mock_function = mock.Mock()
         mock_function.side_effect = exceptions.Forbidden
-        mock_args = mock.MagicMock(**{
-            'auth_provider.credentials.tenant_id': 'tenant_id'
-        })
         wrapper = decorator(mock_function)
 
-        mock_permission = mock.Mock()
-        mock_permission.get_permission.return_value = False
-        mock_auth.return_value = mock_permission
+        mock_policy.RbacPolicyParser.return_value.allowed.return_value = True
 
-        self.assertIsNone(wrapper(mock_args))
+        e = self.assertRaises(exceptions.Forbidden, wrapper, self.mock_args)
+        self.assertIn(
+            "Role Member was not allowed to perform sentinel.action.",
+            e.__str__())
+        mock_log.error.assert_called_once_with("Role Member was not allowed to"
+                                               " perform sentinel.action.")
 
-    @mock.patch('patrole_tempest_plugin.rbac_auth.RbacAuthority')
-    def test_RBAC_rv_rbac_action_failed_not_allowed(self, mock_auth):
-        decorator = rbac_rv.action("", "")
+    @mock.patch.object(rbac_rv, 'LOG', autospec=True)
+    @mock.patch.object(rbac_rv, 'rbac_policy_parser', autospec=True)
+    def test_rule_validation_rbac_action_failed_positive(self, mock_policy,
+                                                         mock_log):
+        """Test RbacActionFailed error is thrown without permission passes.
 
+        Positive test case: if RbacActionFailed is thrown and the user is not
+        allowed to perform the action, then this is a success.
+        """
+        decorator = rbac_rv.action(mock.sentinel.service, mock.sentinel.action)
         mock_function = mock.Mock()
         mock_function.side_effect = rbac_exceptions.RbacActionFailed
         wrapper = decorator(mock_function)
 
-        mock_permission = mock.Mock()
-        mock_permission.get_permission.return_value = False
-        mock_auth.return_value = mock_permission
+        mock_policy.RbacPolicyParser.return_value.allowed.return_value = False
 
-        mock_args = mock.MagicMock(**{
-            'auth_provider.credentials.tenant_id': 'tenant_id'
-        })
+        result = wrapper(self.mock_args)
 
-        self.assertIsNone(wrapper(mock_args))
+        self.assertIsNone(result)
+        mock_log.error.assert_not_called()
+        mock_log.warning.assert_not_called()
+
+    @mock.patch.object(rbac_rv, 'LOG', autospec=True)
+    @mock.patch.object(rbac_rv, 'rbac_policy_parser', autospec=True)
+    def test_rule_validation_rbac_action_failed_negative(self, mock_policy,
+                                                         mock_log):
+        """Test RbacActionFailed error is thrown with permission fails.
+
+        Negative test case: if RbacActionFailed is thrown and the user is
+        allowed to perform the action, then this is an expected failure.
+        """
+        decorator = rbac_rv.action(mock.sentinel.service, mock.sentinel.action)
+        mock_function = mock.Mock()
+        mock_function.side_effect = rbac_exceptions.RbacActionFailed
+        wrapper = decorator(mock_function)
+
+        mock_policy.RbacPolicyParser.return_value.allowed.return_value = True
+
+        e = self.assertRaises(exceptions.Forbidden, wrapper, self.mock_args)
+        self.assertIn(
+            "Role Member was not allowed to perform sentinel.action.",
+            e.__str__())
+
+        mock_log.error.assert_called_once_with("Role Member was not allowed to"
+                                               " perform sentinel.action.")
+
+    @mock.patch.object(rbac_rv, 'LOG', autospec=True)
+    @mock.patch.object(rbac_rv, 'rbac_policy_parser', autospec=True)
+    def test_expect_not_found_but_raises_forbidden(self, mock_policy,
+                                                   mock_log):
+        """Test that expecting 404 but getting 403 works for all scenarios.
+
+        Tests the following scenarios:
+        1) Test no permission and 404 is expected but 403 is thrown throws
+           exception.
+        2) Test have permission and 404 is expected but 403 is thrown throws
+           exception.
+        """
+        decorator = rbac_rv.action(mock.sentinel.service,
+                                   mock.sentinel.action,
+                                   expected_error_code=404)
+        mock_function = mock.Mock()
+        mock_function.side_effect = exceptions.Forbidden('Random message.')
+        wrapper = decorator(mock_function)
+
+        expected_error = "Forbidden\nDetails: Random message. An unexpected "\
+                         "exception has occurred: Expected exception was "\
+                         "NotFound, which was not thrown."
+
+        for permission in [True, False]:
+            mock_policy.RbacPolicyParser.return_value.allowed.return_value =\
+                permission
+
+            e = self.assertRaises(exceptions.Forbidden, wrapper,
+                                  self.mock_args)
+            self.assertIn(expected_error, e.__str__())
+            mock_log.error.assert_called_once_with(expected_error)
+            mock_log.error.reset_mock()
+
+    @mock.patch.object(rbac_rv, 'LOG', autospec=True)
+    @mock.patch.object(rbac_rv, 'rbac_policy_parser', autospec=True)
+    def test_expect_not_found_and_raise_not_found(self, mock_policy, mock_log):
+        """Test that expecting 404 and getting 404 works for all scenarios.
+
+        Tests the following scenarios:
+        1) Test no permission and 404 is expected and 404 is thrown succeeds.
+        2) Test have permission and 404 is expected and 404 is thrown fails.
+
+        In both cases, a LOG.warning is called with the "irregular message"
+        that signals to user that a 404 was expected and caught.
+        """
+        decorator = rbac_rv.action(mock.sentinel.service,
+                                   mock.sentinel.action,
+                                   expected_error_code=404)
+        mock_function = mock.Mock()
+        mock_function.side_effect = exceptions.NotFound
+        wrapper = decorator(mock_function)
+
+        expected_errors = [
+            "Role Member was not allowed to perform sentinel.action.", None
+        ]
+
+        for pos, permission in enumerate([True, False]):
+            mock_policy.RbacPolicyParser.return_value.allowed.return_value =\
+                permission
+
+            expected_error = expected_errors[pos]
+
+            if expected_error:
+                e = self.assertRaises(exceptions.Forbidden, wrapper,
+                                      self.mock_args)
+                self.assertIn(expected_error, e.__str__())
+                mock_log.error.assert_called_once_with(expected_error)
+            else:
+                wrapper(self.mock_args)
+                mock_log.error.assert_not_called()
+
+            mock_log.warning.assert_called_once_with(
+                "NotFound exception was caught for policy action {0}. The "
+                "service {1} throws a 404 instead of a 403, which is "
+                "irregular.".format(mock.sentinel.action,
+                                    mock.sentinel.service))
+
+            mock_log.warning.reset_mock()
+            mock_log.error.reset_mock()
+
+    @mock.patch.object(rbac_rv, 'LOG', autospec=True)
+    @mock.patch.object(rbac_rv, 'rbac_policy_parser', autospec=True)
+    def test_rule_validation_overpermission_negative(self, mock_policy,
+                                                     mock_log):
+        """Test that OverPermission is correctly handled.
+
+        Tests that case where no exception is thrown but the Patrole framework
+        says that the role should not be allowed to perform the policy action.
+        """
+        decorator = rbac_rv.action(mock.sentinel.service, mock.sentinel.action)
+
+        mock_function = mock.Mock()
+        wrapper = decorator(mock_function)
+
+        mock_policy.RbacPolicyParser.return_value.allowed.return_value = False
+
+        e = self.assertRaises(rbac_exceptions.RbacOverPermission, wrapper,
+                              self.mock_args)
+        self.assertIn(("OverPermission: Role Member was allowed to perform "
+                      "sentinel.action"), e.__str__())
+        mock_log.error.assert_called_once_with(
+            'Role %s was allowed to perform %s', 'Member',
+            mock.sentinel.action)
+
+    @mock.patch.object(rbac_rv, 'rbac_policy_parser', autospec=True)
+    def test_invalid_policy_rule_throws_parsing_exception(
+            self, mock_rbac_policy_parser):
+        """Test that invalid policy action causes test to be skipped."""
+        CONF.set_override('strict_policy_check', True, group='rbac')
+        self.addCleanup(CONF.clear_override, 'strict_policy_check',
+                        group='rbac')
+
+        mock_rbac_policy_parser.RbacPolicyParser.return_value.allowed.\
+            side_effect = rbac_exceptions.RbacParsingException
+
+        decorator = rbac_rv.action(mock.sentinel.service,
+                                   mock.sentinel.policy_rule)
+        wrapper = decorator(mock.Mock())
+
+        e = self.assertRaises(rbac_exceptions.RbacParsingException, wrapper,
+                              self.mock_args)
+        self.assertEqual('Attempted to test an invalid policy file or action',
+                         str(e))
+
+        mock_rbac_policy_parser.RbacPolicyParser.assert_called_once_with(
+            mock.sentinel.project_id, mock.sentinel.user_id,
+            mock.sentinel.service, extra_target_data={})
+
+    @mock.patch.object(rbac_rv, 'rbac_policy_parser', autospec=True)
+    def test_get_exception_type_404(self, mock_policy):
+        """Test that getting a 404 exception type returns NotFound."""
+        expected_exception = exceptions.NotFound
+        expected_irregular_msg = ("NotFound exception was caught for policy "
+                                  "action {0}. The service {1} throws a 404 "
+                                  "instead of a 403, which is irregular.")
+
+        actual_exception, actual_irregular_msg = \
+            rbac_rv._get_exception_type(404)
+
+        self.assertEqual(expected_exception, actual_exception)
+        self.assertEqual(expected_irregular_msg, actual_irregular_msg)
+
+    @mock.patch.object(rbac_rv, 'rbac_policy_parser', autospec=True)
+    def test_get_exception_type_403(self, mock_policy):
+        """Test that getting a 404 exception type returns Forbidden."""
+        expected_exception = exceptions.Forbidden
+        expected_irregular_msg = None
+
+        actual_exception, actual_irregular_msg = \
+            rbac_rv._get_exception_type(403)
+
+        self.assertEqual(expected_exception, actual_exception)
+        self.assertEqual(expected_irregular_msg, actual_irregular_msg)
+
+    @mock.patch.object(rbac_rv, 'LOG', autospec=True)
+    @mock.patch.object(rbac_rv, 'rbac_policy_parser', autospec=True)
+    def test_exception_thrown_when_type_is_not_int(self, mock_policy,
+                                                   mock_log):
+        """Test that non-integer exception type raises error."""
+        self.assertRaises(rbac_exceptions.RbacInvalidErrorCode,
+                          rbac_rv._get_exception_type, "403")
+
+        mock_log.error.assert_called_once_with("Please pass an expected error "
+                                               "code. Currently supported "
+                                               "codes: [403, 404]")
+
+    @mock.patch.object(rbac_rv, 'LOG', autospec=True)
+    @mock.patch.object(rbac_rv, 'rbac_policy_parser', autospec=True)
+    def test_exception_thrown_when_type_is_403_or_404(self, mock_policy,
+                                                      mock_log):
+        """Test that unsupported exceptions throw error."""
+        invalid_exceptions = [200, 400, 500]
+        for exc in invalid_exceptions:
+            self.assertRaises(rbac_exceptions.RbacInvalidErrorCode,
+                              rbac_rv._get_exception_type, exc)
+            mock_log.error.assert_called_once_with(
+                "Please pass an expected error code. Currently supported "
+                "codes: [403, 404]")
+
+            mock_log.error.reset_mock()
diff --git a/patrole_tempest_plugin/tests/unit/test_rbac_utils.py b/patrole_tempest_plugin/tests/unit/test_rbac_utils.py
index add1770..85b1c39 100644
--- a/patrole_tempest_plugin/tests/unit/test_rbac_utils.py
+++ b/patrole_tempest_plugin/tests/unit/test_rbac_utils.py
@@ -14,8 +14,10 @@
 #    under the License.
 
 import mock
+import testtools
 
 from tempest import config
+from tempest.lib import base as lib_base
 from tempest.lib import exceptions as lib_exc
 from tempest.tests import base
 
@@ -27,62 +29,97 @@
 
 class RBACUtilsTest(base.TestCase):
 
-    @mock.patch.object(rbac_utils, 'time', autospec=True)
-    def setUp(self, _):
+    available_roles = {
+        'roles': [
+            {'name': 'admin', 'id': 'admin_id'},
+            {'name': 'Member', 'id': 'member_id'}
+        ]
+    }
+
+    @mock.patch.object(rbac_utils, 'credentials', autospec=True,
+                       **{'is_admin_available.return_value': True})
+    @mock.patch.object(rbac_utils.RbacUtils, '_clear_user_roles',
+                       autospec=True, return_value=False)
+    def setUp(self, *args):
         super(RBACUtilsTest, self).setUp()
-        self.mock_creds_provider = mock.patch.object(
-            rbac_utils, 'credentials_factory', autospec=True).start()
 
-        available_roles = {
-            'roles': [
-                {'name': 'admin', 'id': 'admin_id'},
-                {'name': 'Member', 'id': 'member_id'}
-            ]
-        }
-        self.mock_creds_provider.get_credentials_provider.return_value.\
-            creds_client.roles_client.list_roles.return_value = \
-            available_roles
-        self.addCleanup(mock.patch.stopall)
+        self.mock_test_obj = mock.Mock(spec=lib_base.BaseTestCase)
+        self.mock_test_obj.auth_provider = mock.Mock(
+            **{'credentials.user_id': mock.sentinel.user_id,
+               'credentials.tenant_id': mock.sentinel.project_id})
+        self.mock_test_obj.os_admin = mock.Mock(
+            **{'roles_v3_client.list_roles.return_value': self.available_roles}
+        )
+        self.mock_test_obj.get_identity_version = mock.Mock(return_value=3)
 
-        CONF.set_override('rbac_test_role', 'Member', group='rbac',
-                          enforce_type=True)
-        self.addCleanup(CONF.clear_override, 'rbac_test_role', group='rbac')
-
-        # Because rbac_utils is a singleton, reset all of its role-related
-        # parameters to the correct values for each test run.
-        self.rbac_utils = rbac_utils.rbac_utils()
-        self.rbac_utils.available_roles = available_roles
+        with mock.patch.object(rbac_utils.RbacUtils, '_validate_switch_role'):
+            self.rbac_utils = rbac_utils.RbacUtils(self.mock_test_obj)
+        self.rbac_utils.switch_role_history = {}
         self.rbac_utils.admin_role_id = 'admin_id'
         self.rbac_utils.rbac_role_id = 'member_id'
 
-    def test_initialization_with_missing_admin_role(self):
-        self.rbac_utils.admin_role_id = None
-        e = self.assertRaises(rbac_exceptions.RbacResourceSetupFailed,
-                              self.rbac_utils.switch_role, None)
-        self.assertIn("Defined 'rbac_role' or 'admin' role does not exist"
-                      " in the system.", e.__str__())
+        CONF.set_override('admin_role', 'admin', group='identity')
+        CONF.set_override('auth_version', 'v3', group='identity')
+        CONF.set_override('rbac_test_role', 'Member', group='rbac')
 
-    def test_initialization_with_missing_rbac_role(self):
+        roles_client = self.mock_test_obj.os_admin.roles_v3_client
+        roles_client.create_user_role_on_project.reset_mock()
+        self.mock_test_obj.auth_provider.reset_mock()
+
+        self.addCleanup(CONF.clear_override, 'rbac_test_role', group='rbac')
+        self.addCleanup(CONF.clear_override, 'admin_role', group='identity')
+        self.addCleanup(CONF.clear_override, 'auth_version', group='identity')
+        self.addCleanup(mock.patch.stopall)
+
+    def _mock_list_user_roles_on_project(self, return_value):
+        self.mock_test_obj.os_admin = mock.Mock(
+            **{'roles_client.list_user_roles_on_project.'
+               'return_value': {'roles': [{'id': return_value}]}})
+
+    @mock.patch.object(rbac_utils.RbacUtils, '_clear_user_roles',
+                       autospec=True, return_value=False)
+    def test_initialization_with_missing_admin_role(self, _):
+        self.mock_test_obj.os_admin = mock.Mock(
+            **{'roles_v3_client.list_roles.return_value':
+               {'roles': [{'name': 'Member', 'id': 'member_id'}]}})
+        self.rbac_utils.admin_role_id = None
         self.rbac_utils.rbac_role_id = None
         e = self.assertRaises(rbac_exceptions.RbacResourceSetupFailed,
-                              self.rbac_utils.switch_role, None)
-        self.assertIn("Defined 'rbac_role' or 'admin' role does not exist"
-                      " in the system.", e.__str__())
+                              self.rbac_utils.switch_role, self.mock_test_obj,
+                              True)
+        self.assertIn("Role with name 'admin' does not exist in the system.",
+                      e.__str__())
+
+    @mock.patch.object(rbac_utils.RbacUtils, '_clear_user_roles',
+                       autospec=True, return_value=False)
+    def test_initialization_with_missing_rbac_role(self, _):
+        self.mock_test_obj.os_admin = mock.Mock(
+            **{'roles_v3_client.list_roles.return_value':
+               {'roles': [{'name': 'admin', 'id': 'admin_id'}]}})
+        self.rbac_utils.admin_role_id = None
+        self.rbac_utils.rbac_role_id = None
+        e = self.assertRaises(rbac_exceptions.RbacResourceSetupFailed,
+                              self.rbac_utils.switch_role, self.mock_test_obj,
+                              True)
+        self.assertIn("Role defined by rbac_test_role does not exist in the "
+                      "system.", e.__str__())
 
     def test_clear_user_roles(self):
-        self.rbac_utils.creds_client = mock.Mock()
-        creds_client = self.rbac_utils.creds_client
-        creds_client.roles_client.list_user_roles_on_project.return_value = {
+        roles_client = self.mock_test_obj.os_admin.roles_v3_client
+        roles_client.list_user_roles_on_project.return_value = {
             'roles': [{'id': 'admin_id'}, {'id': 'member_id'}]
         }
 
-        self.rbac_utils._clear_user_roles(mock.sentinel.user_id,
-                                          mock.sentinel.project_id)
+        self.rbac_utils.roles_client = roles_client
+        self.rbac_utils.project_id = mock.sentinel.project_id
+        self.rbac_utils.user_id = mock.sentinel.user_id
 
-        creds_client.roles_client.list_user_roles_on_project.\
+        self.rbac_utils._clear_user_roles(None)
+
+        roles_client.list_user_roles_on_project.\
             assert_called_once_with(mock.sentinel.project_id,
                                     mock.sentinel.user_id)
-        creds_client.roles_client.delete_role_from_user_on_project.\
+        roles_client.delete_role_from_user_on_project.\
             assert_has_calls([
                 mock.call(mock.sentinel.project_id, mock.sentinel.user_id,
                           'admin_id'),
@@ -90,66 +127,115 @@
                           'member_id'),
             ])
 
-    @mock.patch.object(rbac_utils.rbac_utils, '_clear_user_roles',
-                       autospec=True)
-    def test_rbac_utils_switch_role_to_admin(self, mock_clear_user_roles):
-        mock_test_object = mock.Mock()
-        mock_test_object.auth_provider.credentials.user_id = \
-            mock.sentinel.user_id
-        mock_test_object.auth_provider.credentials.tenant_id = \
-            mock.sentinel.project_id
+    @mock.patch.object(rbac_utils.RbacUtils, '_clear_user_roles',
+                       autospec=True, return_value=False)
+    @mock.patch.object(rbac_utils, 'time', autospec=True)
+    def test_rbac_utils_switch_role_to_admin_role(self, mock_time, _):
+        self.rbac_utils.prev_switch_role = True
+        self._mock_list_user_roles_on_project('admin_id')
+        roles_client = self.mock_test_obj.os_admin.roles_v3_client
 
-        self.rbac_utils.creds_client = mock.Mock()
-        creds_client = self.rbac_utils.creds_client
+        self.rbac_utils.switch_role(self.mock_test_obj, False)
 
-        self.rbac_utils.switch_role(mock_test_object, False)
+        roles_client.create_user_role_on_project.assert_called_once_with(
+            mock.sentinel.project_id, mock.sentinel.user_id, 'admin_id')
+        self.mock_test_obj.auth_provider.clear_auth.assert_called_once_with()
+        self.mock_test_obj.auth_provider.set_auth.assert_called_once_with()
+        mock_time.sleep.assert_called_once_with(1)
 
-        creds_client.roles_client.create_user_role_on_project.\
-            assert_called_once_with(mock.sentinel.project_id,
-                                    mock.sentinel.user_id,
-                                    'admin_id')
-        mock_clear_user_roles.assert_called_once_with(
-            self.rbac_utils, mock.sentinel.user_id, mock.sentinel.project_id)
-        mock_test_object.auth_provider.clear_auth.assert_called_once_with()
-        mock_test_object.auth_provider.set_auth.assert_called_once_with()
+    @mock.patch.object(rbac_utils.RbacUtils, '_clear_user_roles',
+                       autospec=True, return_value=False)
+    @mock.patch.object(rbac_utils, 'time', autospec=True)
+    def test_rbac_utils_switch_role_to_rbac_role(self, mock_time, _):
+        self._mock_list_user_roles_on_project('member_id')
+        roles_client = self.mock_test_obj.os_admin.roles_v3_client
 
-    @mock.patch.object(rbac_utils.rbac_utils, '_clear_user_roles',
-                       autospec=True)
-    def test_rbac_utils_switch_role_to_rbac_role(self, mock_clear_user_roles):
-        mock_test_object = mock.Mock()
-        mock_test_object.auth_provider.credentials.user_id = \
-            mock.sentinel.user_id
-        mock_test_object.auth_provider.credentials.tenant_id = \
-            mock.sentinel.project_id
+        self.rbac_utils.switch_role(self.mock_test_obj, True)
 
-        self.rbac_utils.creds_client = mock.Mock()
-        creds_client = self.rbac_utils.creds_client
+        roles_client.create_user_role_on_project.assert_called_once_with(
+            mock.sentinel.project_id, mock.sentinel.user_id, 'member_id')
+        self.mock_test_obj.auth_provider.clear_auth.assert_called_once_with()
+        self.mock_test_obj.auth_provider.set_auth.assert_called_once_with()
+        mock_time.sleep.assert_called_once_with(1)
 
-        self.rbac_utils.switch_role(mock_test_object, True)
+    def test_RBAC_utils_switch_roles_without_boolean_value(self):
+        self.assertRaises(rbac_exceptions.RbacResourceSetupFailed,
+                          self.rbac_utils.switch_role, self.mock_test_obj,
+                          "admin")
+        self.assertRaises(rbac_exceptions.RbacResourceSetupFailed,
+                          self.rbac_utils.switch_role, self.mock_test_obj,
+                          None)
 
-        creds_client.roles_client.create_user_role_on_project.\
-            assert_called_once_with(mock.sentinel.project_id,
-                                    mock.sentinel.user_id,
-                                    'member_id')
-        mock_clear_user_roles.assert_called_once_with(
-            self.rbac_utils, mock.sentinel.user_id, mock.sentinel.project_id)
-        mock_test_object.auth_provider.clear_auth.assert_called_once_with()
-        mock_test_object.auth_provider.set_auth.assert_called_once_with()
-
-    def test_rbac_utils_switch_roles_with_invalid_value(self):
+    @mock.patch.object(rbac_utils.RbacUtils, '_clear_user_roles',
+                       autospec=True, return_value=False)
+    def test_rbac_utils_switch_roles_with_false_value_twice(self, _):
+        self._mock_list_user_roles_on_project('admin_id')
+        self.rbac_utils.switch_role(self.mock_test_obj, False)
         e = self.assertRaises(rbac_exceptions.RbacResourceSetupFailed,
-                              self.rbac_utils.switch_role, None)
-        self.assertIn("Wrong value for parameter 'switchToRbacRole' is passed."
-                      " It should be either 'True' or 'False'.", e.__str__())
+                              self.rbac_utils.switch_role, self.mock_test_obj,
+                              False)
+        self.assertIn(
+            '`toggle_rbac_role` must not be called with the same bool value '
+            'twice. Make sure that you included a rbac_utils.switch_role '
+            'method call inside the test.', str(e))
 
-    @mock.patch.object(rbac_utils.rbac_utils, '_clear_user_roles',
-                       autospec=True)
+    @mock.patch.object(rbac_utils.RbacUtils, '_clear_user_roles',
+                       autospec=True, return_value=False)
+    def test_rbac_utils_switch_roles_with_true_value_twice(self, _):
+        self._mock_list_user_roles_on_project('admin_id')
+        self.rbac_utils.switch_role(self.mock_test_obj, True)
+        e = self.assertRaises(rbac_exceptions.RbacResourceSetupFailed,
+                              self.rbac_utils.switch_role, self.mock_test_obj,
+                              True)
+        self.assertIn(
+            '`toggle_rbac_role` must not be called with the same bool value '
+            'twice. Make sure that you included a rbac_utils.switch_role '
+            'method call inside the test.', str(e))
+
+    @mock.patch.object(rbac_utils.RbacUtils, '_clear_user_roles',
+                       autospec=True, return_value=False)
+    @mock.patch.object(rbac_utils, 'LOG', autospec=True)
+    @mock.patch.object(rbac_utils, 'sys', autospec=True)
+    def test_rbac_utils_switch_roles_with_unhandled_exception(self, mock_sys,
+                                                              mock_log, _):
+        """Test whether throwing an unhandled exception doesn't throw error.
+
+        If a skip exception, say, is thrown then this means that switch_role is
+        never called within the test function. But if an unhandled exception
+        or skip exception is thrown, then this should not result in an error
+        being raised.
+        """
+        self._mock_list_user_roles_on_project('member_id')
+
+        # Skip exception is an example of a legitimate case where `switch_role`
+        # is thrown. AttributeError, on the other hand, is an example of an
+        # unexpected exception being thrown that should be allowed to bubble
+        # up, rather than being obfuscated by `switch_role` error being thrown
+        # instead.
+        unhandled_exceptions = [testtools.TestCase.skipException,
+                                AttributeError]
+
+        for unhandled_exception in unhandled_exceptions:
+            mock_sys.exc_info.return_value = [unhandled_exception]
+
+            # Ordinarily switching to the same role would result in an error,
+            # but because the skipException is thrown before the test finishes,
+            # this is not treated as a failure.
+            self.rbac_utils.switch_role(self.mock_test_obj, False)
+            self.rbac_utils.switch_role(self.mock_test_obj, False)
+            mock_log.error.assert_not_called()
+
+            self.rbac_utils.switch_role(self.mock_test_obj, True)
+            self.rbac_utils.switch_role(self.mock_test_obj, True)
+            mock_log.error.assert_not_called()
+
+    @mock.patch.object(rbac_utils.RbacUtils, '_clear_user_roles',
+                       autospec=True, return_value=False)
     def test_rbac_utils_switch_role_except_exception(self,
                                                      mock_clear_user_roles):
-        self.rbac_utils.creds_client = mock.Mock()
-        creds_client = self.rbac_utils.creds_client
-        creds_client.roles_client.create_user_role_on_project.side_effect =\
+        roles_client = self.mock_test_obj.os_admin.roles_v3_client
+        roles_client.create_user_role_on_project.side_effect =\
             lib_exc.NotFound
 
         self.assertRaises(lib_exc.NotFound, self.rbac_utils.switch_role,
-                          mock.Mock(), True)
+                          self.mock_test_obj, True)
diff --git a/patrole_tempest_plugin/tests/unit/test_requirements_authority.py b/patrole_tempest_plugin/tests/unit/test_requirements_authority.py
new file mode 100644
index 0000000..1fb9636
--- /dev/null
+++ b/patrole_tempest_plugin/tests/unit/test_requirements_authority.py
@@ -0,0 +1,85 @@
+# Copyright 2017 AT&T Corporation.
+#
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
+#    not use this file except in compliance with the License. You may obtain
+#    a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+#    Unless required by applicable law or agreed to in writing, software
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+#    License for the specific language governing permissions and limitations
+#    under the License.
+
+import os
+
+from tempest.lib import exceptions
+from tempest.tests import base
+
+from patrole_tempest_plugin import requirements_authority as req_auth
+
+
+class RequirementsAuthorityTest(base.TestCase):
+    def setUp(self):
+        super(RequirementsAuthorityTest, self).setUp()
+        self.rbac_auth = req_auth.RequirementsAuthority()
+        self.current_directory = os.path.dirname(os.path.realpath(__file__))
+        self.yaml_test_file = os.path.join(self.current_directory,
+                                           'resources',
+                                           'rbac_roles.yaml')
+        self.expected_result = {'test:create': ['test_member', '_member_'],
+                                'test:create2': ['test_member']}
+
+    def test_requirements_auth_init(self):
+        rbac_auth = req_auth.RequirementsAuthority(self.yaml_test_file, 'Test')
+        self.assertEqual(self.expected_result, rbac_auth.roles_dict)
+
+    def test_auth_allowed_empty_roles(self):
+        self.rbac_auth.roles_dict = None
+        self.assertRaises(exceptions.InvalidConfiguration,
+                          self.rbac_auth.allowed, "", "")
+
+    def test_auth_allowed_role_in_api(self):
+        self.rbac_auth.roles_dict = {'api': ['_member_']}
+        self.assertTrue(self.rbac_auth.allowed("api", "_member_"))
+
+    def test_auth_allowed_role_not_in_api(self):
+        self.rbac_auth.roles_dict = {'api': ['_member_']}
+        self.assertFalse(self.rbac_auth.allowed("api", "support_member"))
+
+    def test_parser_get_allowed_except_keyerror(self):
+        self.rbac_auth.roles_dict = {}
+        self.assertRaises(KeyError, self.rbac_auth.allowed,
+                          "api", "support_member")
+
+    def test_parser_init(self):
+        req_auth.RequirementsParser(self.yaml_test_file)
+        self.assertEqual([{'Test': self.expected_result}],
+                         req_auth.RequirementsParser.Inner._rbac_map)
+
+    def test_parser_role_in_api(self):
+        req_auth.RequirementsParser.Inner._rbac_map = \
+            [{'Test': self.expected_result}]
+        self.rbac_auth.roles_dict = req_auth.RequirementsParser.parse("Test")
+
+        self.assertEqual(self.expected_result, self.rbac_auth.roles_dict)
+        self.assertTrue(self.rbac_auth.allowed("test:create2", "test_member"))
+
+    def test_parser_role_not_in_api(self):
+        req_auth.RequirementsParser.Inner._rbac_map = \
+            [{'Test': self.expected_result}]
+        self.rbac_auth.roles_dict = req_auth.RequirementsParser.parse("Test")
+
+        self.assertEqual(self.expected_result, self.rbac_auth.roles_dict)
+        self.assertFalse(self.rbac_auth.allowed("test:create2", "_member_"))
+
+    def test_parser_except_invalid_configuration(self):
+        req_auth.RequirementsParser.Inner._rbac_map = \
+            [{'Test': self.expected_result}]
+        self.rbac_auth.roles_dict = \
+            req_auth.RequirementsParser.parse("Failure")
+
+        self.assertIsNone(self.rbac_auth.roles_dict)
+        self.assertRaises(exceptions.InvalidConfiguration,
+                          self.rbac_auth.allowed, "", "")
diff --git a/patrole_tempest_plugin/version.py b/patrole_tempest_plugin/version.py
new file mode 100644
index 0000000..5f8aaf6
--- /dev/null
+++ b/patrole_tempest_plugin/version.py
@@ -0,0 +1,18 @@
+# Copyright (c) 2017 AT&T Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may not
+# use this file except in compliance with the License. You may obtain a copy of
+# the License at
+#
+#    http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations under
+# the License.
+
+
+import pbr.version
+
+version_info = pbr.version.VersionInfo('patrole')
diff --git a/releasenotes/notes/0.1.0-pike-6590a2996b7c06d6.yaml b/releasenotes/notes/0.1.0-pike-6590a2996b7c06d6.yaml
new file mode 100644
index 0000000..ab159cd
--- /dev/null
+++ b/releasenotes/notes/0.1.0-pike-6590a2996b7c06d6.yaml
@@ -0,0 +1,14 @@
+---
+prelude: >
+    This release marks the first release for Patrole, tagged as 0.1.0.
+other:
+  - |
+    Patrole currently supports RBAC testing for Cinder, Glance, Nova, Neutron
+    and Keystone.
+
+    The release under current development as of this tag is Pike,
+    meaning that every Patrole commit is also tested against master branch
+    during the Pike cycle. However, this does not necessarily mean that
+    using Patrole as of this tag will work against Pike (or future
+    releases) cloud. In addition, backward compatibility with previous
+    releases is not guaranteed.
diff --git a/releasenotes/notes/add-extra-hypervisor-tests-9374e5fcdb0266e2.yaml b/releasenotes/notes/add-extra-hypervisor-tests-9374e5fcdb0266e2.yaml
new file mode 100644
index 0000000..4cb7b4a
--- /dev/null
+++ b/releasenotes/notes/add-extra-hypervisor-tests-9374e5fcdb0266e2.yaml
@@ -0,0 +1,12 @@
+---
+features:
+  - |
+    Add additional compute hypervisor RBAC tests, so that the previously
+    missing hypervisor endpoints are covered. Tests for the following
+    endpoints were written:
+
+      * show_hypervisor
+      * list_servers_on_hypervisor
+      * show_hypervisor_statistics
+      * show_hypervisor_uptime
+      * search_hypervisor
diff --git a/releasenotes/notes/add-force-delete-backup-test-7e896affd1471328.yaml b/releasenotes/notes/add-force-delete-backup-test-7e896affd1471328.yaml
new file mode 100644
index 0000000..3d81baa
--- /dev/null
+++ b/releasenotes/notes/add-force-delete-backup-test-7e896affd1471328.yaml
@@ -0,0 +1,11 @@
+---
+features:
+  - |
+    Added an RBAC test for force-deleting a backup which enforces the cinder
+    policy action: "volume_extension:backup_admin_actions:force_delete".
+fixes:
+  - |
+    Corrected the policy action in the ``rbac_rule_validation`` decorator
+    for the test ``test_snapshot_force_delete`` from
+    "volume_extension:volume_admin_actions:force_delete" to
+    "volume_extension:snapshot_admin_actions:force_delete".
diff --git a/releasenotes/notes/add-metadef-resource-type-7973621c5e8fff7f.yaml b/releasenotes/notes/add-metadef-resource-type-7973621c5e8fff7f.yaml
new file mode 100644
index 0000000..61bec83
--- /dev/null
+++ b/releasenotes/notes/add-metadef-resource-type-7973621c5e8fff7f.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Adds test for glance's
+    add_metadef_resource_type_association policy.
diff --git a/releasenotes/notes/add-quota-classes-tests-3e61e671f6e131df.yaml b/releasenotes/notes/add-quota-classes-tests-3e61e671f6e131df.yaml
new file mode 100644
index 0000000..656f6a1
--- /dev/null
+++ b/releasenotes/notes/add-quota-classes-tests-3e61e671f6e131df.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Add RBAC tests for cinder os-quota-class-sets API, which cover the
+    policy action "volume_extension:quota_classes".
diff --git a/releasenotes/notes/add-security-group-tests-ae5c07074e0ac849.yaml b/releasenotes/notes/add-security-group-tests-ae5c07074e0ac849.yaml
new file mode 100644
index 0000000..8d250cd
--- /dev/null
+++ b/releasenotes/notes/add-security-group-tests-ae5c07074e0ac849.yaml
@@ -0,0 +1,13 @@
+---
+features:
+  - |
+    Add security groups and server security groups
+    tests to Nova RBAC tests.
+fixes:
+  - |
+    Add microversion check to test_security_groups_rbac
+    as tests in this file will fail with a 404 after
+    2.36.
+  - Rename test_server_security_groups to
+    test_list_security_groups to properly reflect the
+    test actually being run.
diff --git a/releasenotes/notes/additional-network-ports-rbac-tests-3f48ce1b6bda7694.yaml b/releasenotes/notes/additional-network-ports-rbac-tests-3f48ce1b6bda7694.yaml
new file mode 100644
index 0000000..a75db95
--- /dev/null
+++ b/releasenotes/notes/additional-network-ports-rbac-tests-3f48ce1b6bda7694.yaml
@@ -0,0 +1,13 @@
+---
+features:
+  - |
+    Add additional port-related RBAC tests to ``test_ports_rbac`` in the
+    network module, providing coverage for the following policy actions:
+    * create_port:device_owner
+    * create_port:port_security_enabled
+    * create_port:binding:profile
+    * update_port:device_owner
+fixes:
+  - |
+    Add ``test.requires_ext`` above tests that require the ``binding``
+    extension.
diff --git a/releasenotes/notes/additional-router-rbac-tests-66ef013c54016326.yaml b/releasenotes/notes/additional-router-rbac-tests-66ef013c54016326.yaml
new file mode 100644
index 0000000..4f91a12
--- /dev/null
+++ b/releasenotes/notes/additional-router-rbac-tests-66ef013c54016326.yaml
@@ -0,0 +1,11 @@
+---
+features:
+  - |
+    Add additional RBAC tests for network routers API, providing coverage for
+    the following policy actions:
+
+      * create_router:ha
+      * create_router:distributed
+      * get_router:distributed
+      * update_router:ha
+      * update_router:distributed
\ No newline at end of file
diff --git a/releasenotes/notes/admin-only-identity-v2-admin-6f382e38d7a690a4.yaml b/releasenotes/notes/admin-only-identity-v2-admin-6f382e38d7a690a4.yaml
new file mode 100644
index 0000000..750a9f1
--- /dev/null
+++ b/releasenotes/notes/admin-only-identity-v2-admin-6f382e38d7a690a4.yaml
@@ -0,0 +1,12 @@
+---
+fixes:
+  - |
+    Removed ``rule`` kwarg from ``rbac_rule_validation`` decorator for identity
+    v2 admin tests, because the identity v2 admin API does not do policy
+    enforcement, and instead checks whether the request object has
+    ``context_is_admin``.
+other:
+  - |
+    Updated the class names for identity v2 tests to include the "Admin"
+    substring, to convey the fact that these tests are only intended
+    to test the v2 admin API, not the v2 API.
diff --git a/releasenotes/notes/communitize-image-rbac-test-bdf1109e58a6c2e0.yaml b/releasenotes/notes/communitize-image-rbac-test-bdf1109e58a6c2e0.yaml
new file mode 100644
index 0000000..200cc58
--- /dev/null
+++ b/releasenotes/notes/communitize-image-rbac-test-bdf1109e58a6c2e0.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Add RBAC test for communitizing image, providing coverage for the policy
+    action "communitize_image".
diff --git a/releasenotes/notes/compute-snapshots-tests-86c137eb545707ee.yaml b/releasenotes/notes/compute-snapshots-tests-86c137eb545707ee.yaml
new file mode 100644
index 0000000..b15d0a1
--- /dev/null
+++ b/releasenotes/notes/compute-snapshots-tests-86c137eb545707ee.yaml
@@ -0,0 +1,4 @@
+---
+features:
+  - |
+    Adds tests for compute snapshot APIs.
diff --git a/releasenotes/notes/config-opts-paths-01e2a5096a1579b8.yaml b/releasenotes/notes/config-opts-paths-01e2a5096a1579b8.yaml
new file mode 100644
index 0000000..3e63c9d
--- /dev/null
+++ b/releasenotes/notes/config-opts-paths-01e2a5096a1579b8.yaml
@@ -0,0 +1,8 @@
+---
+features:
+  - |
+    Refactored framework to remove unused "path"
+    argument. Added config options to allow the path
+    to the policy.json files for Nova, Keystone, Cinder,
+    Neutron, and Glance to be configured without needing
+    to manually change code.
diff --git a/releasenotes/notes/console-6db96c4e329c0ab2.yaml b/releasenotes/notes/console-6db96c4e329c0ab2.yaml
new file mode 100644
index 0000000..43ad236
--- /dev/null
+++ b/releasenotes/notes/console-6db96c4e329c0ab2.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Adds tests for os-console-output and os-remote-console
+    to compute module.
diff --git a/releasenotes/notes/dhcp-agent-scheduler-test-842fc1df45799def.yaml b/releasenotes/notes/dhcp-agent-scheduler-test-842fc1df45799def.yaml
new file mode 100644
index 0000000..0a422e6
--- /dev/null
+++ b/releasenotes/notes/dhcp-agent-scheduler-test-842fc1df45799def.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Added RBAC network test for listing dhcp agents on a hosting
+    network, providing coverage for the "get_dhcp-agents" policy.
diff --git a/releasenotes/notes/domain-config-rbac-tests-8806ca7c159ddf94.yaml b/releasenotes/notes/domain-config-rbac-tests-8806ca7c159ddf94.yaml
new file mode 100644
index 0000000..8108cf4
--- /dev/null
+++ b/releasenotes/notes/domain-config-rbac-tests-8806ca7c159ddf94.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Adds RBAC tests for the domain configuration Keystone v3 extension
+    API.
diff --git a/releasenotes/notes/dynamic-policy-file-discovery-104cbfc64b55d605.yaml b/releasenotes/notes/dynamic-policy-file-discovery-104cbfc64b55d605.yaml
new file mode 100644
index 0000000..59019cf
--- /dev/null
+++ b/releasenotes/notes/dynamic-policy-file-discovery-104cbfc64b55d605.yaml
@@ -0,0 +1,22 @@
+---
+features:
+  - |
+    Add new configuration option ``[rbac] custom_policy_files``,
+    allowing users to specify list of the paths to search for custom
+    policy files. Each policy path assumes that the service name is
+    included in the path once. Also assumes Patrole is on the same host
+    as the policy files. The paths should be ordered by precedence, with
+    high-priority paths before low-priority paths. The first path that
+    is found to contain the service's policy file will be used.
+deprecations:
+  - |
+    Deprecate the following configuration options from ``[rbac]`` group:
+
+    * cinder_policy_file
+    * glance_policy_file
+    * keystone_policy_file
+    * neutron_policy_file
+    * nova_policy_file
+
+    It is better to use ``[rbac] custom_policy_files`` which supports
+    any OpenStack service.
diff --git a/releasenotes/notes/encryption-types-c9a2d9a3c1996da4.yaml b/releasenotes/notes/encryption-types-c9a2d9a3c1996da4.yaml
new file mode 100644
index 0000000..7b6ae0c
--- /dev/null
+++ b/releasenotes/notes/encryption-types-c9a2d9a3c1996da4.yaml
@@ -0,0 +1,4 @@
+---
+features:
+  - |
+    Adds RBAC tests for the encryption types client.
diff --git a/releasenotes/notes/endpoint-filter-projects-7f64c88659ef0c30.yaml b/releasenotes/notes/endpoint-filter-projects-7f64c88659ef0c30.yaml
new file mode 100644
index 0000000..1537618
--- /dev/null
+++ b/releasenotes/notes/endpoint-filter-projects-7f64c88659ef0c30.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Adds RBAC tests for the project-related endpoints belonging to the
+    OS-EP-FILTER Keystone v3 extension API.
diff --git a/releasenotes/notes/ep-filter-groups-rbac-tests-bca28e9a055bbb8d.yaml b/releasenotes/notes/ep-filter-groups-rbac-tests-bca28e9a055bbb8d.yaml
new file mode 100644
index 0000000..6014061
--- /dev/null
+++ b/releasenotes/notes/ep-filter-groups-rbac-tests-bca28e9a055bbb8d.yaml
@@ -0,0 +1,13 @@
+---
+features:
+  - |
+    Add group-specific RBAC tests for the identity v3 extension API,
+    OS-EP-FILTER, providing coverage for the following policy actions:
+
+      * identity:create_endpoint_group
+      * identity:list_endpoint_groups
+      * identity:show_endpoint_group (get endpoint group)
+      * identity:check_endpoint_group
+      * identity:list_endpoint_group (get endpoint groups)
+      * identity:update_endpoint_group
+      * identity:delete_endpoint_group
diff --git a/releasenotes/notes/extra-volume-types-tests-2e4538bed7348be4.yaml b/releasenotes/notes/extra-volume-types-tests-2e4538bed7348be4.yaml
new file mode 100644
index 0000000..9be15fc
--- /dev/null
+++ b/releasenotes/notes/extra-volume-types-tests-2e4538bed7348be4.yaml
@@ -0,0 +1,10 @@
+---
+features:
+  - |
+    Added RBAC tests for volume type access and volume type extra specs
+    APIs, providing coverage for the following policy actions:
+
+      * "volume_extension:types_extra_specs"
+      * "volume_extension:volume_type_access"
+      * "volume_extension:volume_type_access:addProjectAccess"
+      * "volume_extension:volume_type_access:removeProjectAccess"
diff --git a/releasenotes/notes/glance-v1-api-deprecated-1aba7b6ae0b6e063.yaml b/releasenotes/notes/glance-v1-api-deprecated-1aba7b6ae0b6e063.yaml
new file mode 100644
index 0000000..dffd064
--- /dev/null
+++ b/releasenotes/notes/glance-v1-api-deprecated-1aba7b6ae0b6e063.yaml
@@ -0,0 +1,4 @@
+---
+deprecations:
+  - Glance v1 APIs are deprecated and v2 APIs are current. Glance v1 APIs are
+    removed from volume tests and Glance v1 RBAC tests are removed.
diff --git a/releasenotes/notes/hypervisor-list-with-details-test-655e873cd881c2bb.yaml b/releasenotes/notes/hypervisor-list-with-details-test-655e873cd881c2bb.yaml
new file mode 100644
index 0000000..30ccb45
--- /dev/null
+++ b/releasenotes/notes/hypervisor-list-with-details-test-655e873cd881c2bb.yaml
@@ -0,0 +1,4 @@
+---
+features:
+  - |
+    Add RBAC test for listing hypervisors with details.
diff --git a/releasenotes/notes/image-size-rbac-tests-545e5ace0d88ab34.yaml b/releasenotes/notes/image-size-rbac-tests-545e5ace0d88ab34.yaml
new file mode 100644
index 0000000..c0340cf
--- /dev/null
+++ b/releasenotes/notes/image-size-rbac-tests-545e5ace0d88ab34.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Add RBAC tests related to the ``image_size`` compute policy action:
+    "os_compute_api:image-size".
diff --git a/releasenotes/notes/lock-server-460767a02d15bb29.yaml b/releasenotes/notes/lock-server-460767a02d15bb29.yaml
new file mode 100644
index 0000000..7af7ff3
--- /dev/null
+++ b/releasenotes/notes/lock-server-460767a02d15bb29.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Adds tests for Nova's lock_server policies: lock,
+    unlock, and unlock_override.
diff --git a/releasenotes/notes/merge-rbac-auth-with-rbac-rule-validation-5d7c286788a95ee9.yaml b/releasenotes/notes/merge-rbac-auth-with-rbac-rule-validation-5d7c286788a95ee9.yaml
new file mode 100644
index 0000000..b96c73a
--- /dev/null
+++ b/releasenotes/notes/merge-rbac-auth-with-rbac-rule-validation-5d7c286788a95ee9.yaml
@@ -0,0 +1,7 @@
+---
+features:
+  - |
+    Merges `rbac_auth` with `rbac_rule_validation`, because `rbac_auth`
+    decentralized logic from `rbac_rule_validation` without providing any
+    authentication-related utility. This change facilitates code maintenance
+    and code readability.
diff --git a/releasenotes/notes/more-volume-backup-tests-c3f10aa245df2a4b.yaml b/releasenotes/notes/more-volume-backup-tests-c3f10aa245df2a4b.yaml
new file mode 100644
index 0000000..8d71130
--- /dev/null
+++ b/releasenotes/notes/more-volume-backup-tests-c3f10aa245df2a4b.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Add additional RBAC tests to ``VolumesBackupsRbacTest``, providing coverage
+    for "volume_extension:backup_admin_actions:reset_status".
diff --git a/releasenotes/notes/nova_volume_client-75e153a1c84e4ff8.yaml b/releasenotes/notes/nova_volume_client-75e153a1c84e4ff8.yaml
new file mode 100644
index 0000000..0562137
--- /dev/null
+++ b/releasenotes/notes/nova_volume_client-75e153a1c84e4ff8.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Adds RBAC tests for the Nova os-volumes API which is deprecated
+    from microversion 2.36 onward.
diff --git a/releasenotes/notes/patrole-devstack-plugin-551c9af3325723c9.yaml b/releasenotes/notes/patrole-devstack-plugin-551c9af3325723c9.yaml
new file mode 100644
index 0000000..a0950bd
--- /dev/null
+++ b/releasenotes/notes/patrole-devstack-plugin-551c9af3325723c9.yaml
@@ -0,0 +1,6 @@
+---
+features:
+  - |
+    Add Patrole DevStack plugin, allowing Patrole to be installed using
+    DevStack by adding "enable_plugin patrole" to "local" section of
+    local.conf.
diff --git a/releasenotes/notes/rbac-tests-for-network-agents-fbc899925b5948b1.yaml b/releasenotes/notes/rbac-tests-for-network-agents-fbc899925b5948b1.yaml
new file mode 100644
index 0000000..64deadc
--- /dev/null
+++ b/releasenotes/notes/rbac-tests-for-network-agents-fbc899925b5948b1.yaml
@@ -0,0 +1,14 @@
+---
+features:
+  - |
+    Implements RBAC tests for Tempest network agents_client, providing
+    coverage for the following policies:
+
+      * update_agent
+      * get_agent
+      * create_dhcp-network
+      * delete_dhcp-network
+      * get_dhcp-networks
+      * create_l3-router
+      * delete_l3-router
+      * get_l3-routers
diff --git a/releasenotes/notes/rbac-tests-for-quota-class-sets-20d874b185902308.yaml b/releasenotes/notes/rbac-tests-for-quota-class-sets-20d874b185902308.yaml
new file mode 100644
index 0000000..96e280a
--- /dev/null
+++ b/releasenotes/notes/rbac-tests-for-quota-class-sets-20d874b185902308.yaml
@@ -0,0 +1,8 @@
+---
+features:
+  - |
+    Add RBAC tests for compute quota class sets API, providing coverage for
+    the following policy actions:
+
+      * os_compute_api:os-quota-class-sets:show
+      * os_compute_api:os-quota-class-sets:update
diff --git a/releasenotes/notes/remove-assisted-volume-snapshot-tests-c204bc72779cb53a.yaml b/releasenotes/notes/remove-assisted-volume-snapshot-tests-c204bc72779cb53a.yaml
new file mode 100644
index 0000000..1988f74
--- /dev/null
+++ b/releasenotes/notes/remove-assisted-volume-snapshot-tests-c204bc72779cb53a.yaml
@@ -0,0 +1,5 @@
+---
+deprecations:
+  - |
+    Remove assisted volume snapshot RBAC tests, because the Tempest client
+    does not yet exist.
diff --git a/releasenotes/notes/server-metadata-rbac-tests-2404b5d13c492b62.yaml b/releasenotes/notes/server-metadata-rbac-tests-2404b5d13c492b62.yaml
new file mode 100644
index 0000000..1bb63c9
--- /dev/null
+++ b/releasenotes/notes/server-metadata-rbac-tests-2404b5d13c492b62.yaml
@@ -0,0 +1,12 @@
+---
+features:
+  - |
+    Add RBAC tests for the compute server metadata API, providing
+    coverage for the following policy actions:
+
+      * os_compute_api:server-metadata:index
+      * os_compute_api:server-metadata:update_all
+      * os_compute_api:server-metadata:create
+      * os_compute_api:server-metadata:show
+      * os_compute_api:server-metadata:update
+      * os_compute_api:server-metadata:delete
diff --git a/releasenotes/notes/service-provider-bc71da578e717c3a.yaml b/releasenotes/notes/service-provider-bc71da578e717c3a.yaml
new file mode 100644
index 0000000..855f398
--- /dev/null
+++ b/releasenotes/notes/service-provider-bc71da578e717c3a.yaml
@@ -0,0 +1,4 @@
+---
+features:
+  - |
+    Adds test for Neutron's get_service_provider policy.
diff --git a/releasenotes/notes/subnet-rbac-tests-6d3cf54e39a7b486.yaml b/releasenotes/notes/subnet-rbac-tests-6d3cf54e39a7b486.yaml
new file mode 100644
index 0000000..8d3d22a
--- /dev/null
+++ b/releasenotes/notes/subnet-rbac-tests-6d3cf54e39a7b486.yaml
@@ -0,0 +1,10 @@
+---
+features:
+  - |
+    Add RBAC tests for network subnet endpoints, providing coverage for the
+    following policy actions:
+
+      * create_subnet
+      * get_subnet
+      * update_subnet
+      * delete_subnet
diff --git a/releasenotes/notes/subnetpools_update_is_default_test-d3540a87469b6dc8.yaml b/releasenotes/notes/subnetpools_update_is_default_test-d3540a87469b6dc8.yaml
new file mode 100644
index 0000000..25aa2d1
--- /dev/null
+++ b/releasenotes/notes/subnetpools_update_is_default_test-d3540a87469b6dc8.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Add RBAC test for updating the default subnetpool, providing coverage
+    for the policy action: "update_subnetpool:is_default".
\ No newline at end of file
diff --git a/releasenotes/notes/support_requirements_yaml-a90e0188a19421ba.yaml b/releasenotes/notes/support_requirements_yaml-a90e0188a19421ba.yaml
new file mode 100644
index 0000000..d2f5519
--- /dev/null
+++ b/releasenotes/notes/support_requirements_yaml-a90e0188a19421ba.yaml
@@ -0,0 +1,12 @@
+---
+features:
+  - |
+    Add support of running Patrole against a custom requirements YAML that
+    defines RBAC requirements. The YAML file lists all the APIs and the roles
+    that should have access to the APIs. The purpose of running Patrole against
+    a requirements YAML is to verify that the RBAC policy is in accordance to
+    deployment specific requirements. Running Patrole against a requirements
+    YAML is completely optional and can be enabled by setting the
+    ``[rbac] test_custom_requirements`` option to True in Tempest's
+    configuration file. The requirements YAML must be located on the same host
+    that Patrole runs on.
diff --git a/releasenotes/notes/test_oauth_tokens_rbac-13e1d3b5decbaf79.yaml b/releasenotes/notes/test_oauth_tokens_rbac-13e1d3b5decbaf79.yaml
new file mode 100644
index 0000000..d7c5d5b
--- /dev/null
+++ b/releasenotes/notes/test_oauth_tokens_rbac-13e1d3b5decbaf79.yaml
@@ -0,0 +1,4 @@
+---
+features:
+  - Add test_oauth_tokens_rbac.py with RBAC test cases related to
+    the OS-OAUTH1 Keystone v3 extension API.
diff --git a/releasenotes/notes/test_tokens_rbac-7f36919b786e9ffc.yaml b/releasenotes/notes/test_tokens_rbac-7f36919b786e9ffc.yaml
new file mode 100644
index 0000000..5ff448b
--- /dev/null
+++ b/releasenotes/notes/test_tokens_rbac-7f36919b786e9ffc.yaml
@@ -0,0 +1,3 @@
+---
+features:
+  - Added RBAC test scenarios for the token-related admin v2 identity API.
diff --git a/releasenotes/notes/volume-services-rbac-test-57e69f9952c8746e.yaml b/releasenotes/notes/volume-services-rbac-test-57e69f9952c8746e.yaml
new file mode 100644
index 0000000..5b6f0cd
--- /dev/null
+++ b/releasenotes/notes/volume-services-rbac-test-57e69f9952c8746e.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Added RBAC test for the volume services API, which covers the following
+    policy action: "volume_extension:services:index".
diff --git a/releasenotes/notes/volume-summary-a3c3b010c1880bcb.yaml b/releasenotes/notes/volume-summary-a3c3b010c1880bcb.yaml
new file mode 100644
index 0000000..5074840
--- /dev/null
+++ b/releasenotes/notes/volume-summary-a3c3b010c1880bcb.yaml
@@ -0,0 +1,4 @@
+---
+features:
+  - |
+    Added test for volume summary API.
diff --git a/releasenotes/notes/volume-upload-public-test-f8e741a838ae7607.yaml b/releasenotes/notes/volume-upload-public-test-f8e741a838ae7607.yaml
new file mode 100644
index 0000000..c8c0ecd
--- /dev/null
+++ b/releasenotes/notes/volume-upload-public-test-f8e741a838ae7607.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Add RBAC test to provide coverage for the following cinder policy:
+    "volume_extension:volume_actions:upload_public".
diff --git a/releasenotes/notes/volume-v3-groups-rbac-tests-60bddf6fa509545d.yaml b/releasenotes/notes/volume-v3-groups-rbac-tests-60bddf6fa509545d.yaml
new file mode 100644
index 0000000..92b1123
--- /dev/null
+++ b/releasenotes/notes/volume-v3-groups-rbac-tests-60bddf6fa509545d.yaml
@@ -0,0 +1,12 @@
+---
+features:
+  - |
+    Add RBAC tests for the volume v3 groups and group types APIs, providing
+    coverage for the following policy actions:
+
+    * group:create
+    * group:get
+    * group:get_all
+    * group:delete
+    * group:group_types_manage
+    * group:access_group_types_specs
diff --git a/releasenotes/notes/volumes-client-tests-d697a4a75d3e1405.yaml b/releasenotes/notes/volumes-client-tests-d697a4a75d3e1405.yaml
new file mode 100644
index 0000000..5dc9ff3
--- /dev/null
+++ b/releasenotes/notes/volumes-client-tests-d697a4a75d3e1405.yaml
@@ -0,0 +1,8 @@
+---
+features:
+  - Added tests for volumes client functions set
+    bootable, reserve, unreserve, and update metadata.
+other:
+  - Renamed update metadata item and delete metadata
+    item tests to accurately reflect what actions are
+    being performed.
diff --git a/releasenotes/source/conf.py b/releasenotes/source/conf.py
index d86d91c..7444c35 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -38,7 +38,7 @@
 # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
 # ones.
 extensions = [
-    'oslosphinx',
+    'openstackdocstheme',
     'reno.sphinxext',
 ]
 
@@ -55,18 +55,18 @@
 master_doc = 'index'
 
 # General information about the project.
-project = u'patrole Release Notes'
+project = u'Patrole Release Notes'
 copyright = u'2017, Patrole Developers'
 
 # The version info for the project you're documenting, acts as replacement for
 # |version| and |release|, also used in various other places throughout the
 # built documents.
 #
-# The short X.Y version.
+from patrole_tempest_plugin.version import version_info as patrole_version
 # The full version, including alpha/beta/rc tags.
-release = ''
+release = patrole_version.version_string_with_vcs()
 # The short X.Y version.
-version = ''
+version = patrole_version.canonical_version_string()
 
 # The language for content autogenerated by Sphinx. Refer to documentation
 # for a list of supported languages.
@@ -111,7 +111,7 @@
 
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
-html_theme = 'default'
+html_theme = 'openstackdocs'
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the
@@ -149,7 +149,7 @@
 
 # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
 # using the given strftime format.
-# html_last_updated_fmt = '%b %d, %Y'
+html_last_updated_fmt = '%Y-%m-%d %H:%M'
 
 # If true, SmartyPants will be used to convert quotes and dashes to
 # typographically correct entities.
@@ -191,6 +191,11 @@
 # Output file base name for HTML help builder.
 htmlhelp_basename = 'PatroleReleaseNotesdoc'
 
+# openstackdocstheme options
+repository_name = 'openstack/patrole'
+bug_project = 'patrole'
+bug_tag = ''
+
 
 # -- Options for LaTeX output ---------------------------------------------
 
@@ -256,7 +261,7 @@
 texinfo_documents = [
     ('index', 'PatroleReleaseNotes', u'Patrole Release Notes Documentation',
      u'Patrole Developers', 'PatroleReleaseNotes',
-     'One line description of project.',
+     'A Tempest plugin for performing RBAC testing.',
      'Miscellaneous'),
 ]
 
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index b2e9377..11e1ac4 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -1,8 +1,9 @@
-============================================
- patrole Release Notes
-============================================
+======================
+ Patrole Release Notes
+======================
 
 .. toctree::
    :maxdepth: 1
 
    unreleased
+   v0.1.0
diff --git a/releasenotes/source/v0.1.0.rst b/releasenotes/source/v0.1.0.rst
new file mode 100644
index 0000000..5db583f
--- /dev/null
+++ b/releasenotes/source/v0.1.0.rst
@@ -0,0 +1,6 @@
+=====================
+ v0.1.0 Release Notes
+=====================
+
+.. release-notes:: 0.1.0 Release Notes
+   :version: 0.1.0
diff --git a/requirements.txt b/requirements.txt
index b22bec8..126a3dc 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,7 +1,11 @@
 # 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.
-
-pbr>=1.8 # Apache-2.0
-urllib3>=1.15.1 # MIT
-oslo.log>=3.11.0 # Apache-2.0
+hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
+pbr!=2.1.0,>=2.0.0 # Apache-2.0
+urllib3>=1.21.1 # MIT
+oslo.log>=3.22.0 # Apache-2.0
+oslo.config!=4.3.0,!=4.4.0,>=4.0.0 # Apache-2.0
+oslo.policy>=1.23.0 # Apache-2.0
+tempest>=14.0.0 # Apache-2.0
+stevedore>=1.20.0 # Apache-2.0
diff --git a/setup.cfg b/setup.cfg
index eae0d8b..212db9e 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -5,7 +5,7 @@
     README.rst
 author = OpenStack
 author-email = openstack-dev@lists.openstack.org
-home-page = http://docs.openstack.org/developer/patrole/
+home-page = https://docs.openstack.org/developer/patrole/
 classifier =
     Environment :: OpenStack
     Intended Audience :: Information Technology
@@ -17,11 +17,11 @@
     Programming Language :: Python :: 2.7
     Programming Language :: Python :: 3
     Programming Language :: Python :: 3.3
-    Programming Language :: Python :: 3.4
+    Programming Language :: Python :: 3.5
 
 [files]
 packages =
-    patrole
+    patrole_tempest_plugin
 
 [build_sphinx]
 source-dir = doc/source
@@ -53,4 +53,4 @@
 
 [entry_points]
 tempest.test_plugins =
-    patrole-tempest-plugin = patrole_tempest_plugin.plugin:PatroleTempestPlugin
+    patrole_tempest_plugin = patrole_tempest_plugin.plugin:PatroleTempestPlugin
diff --git a/setup.py b/setup.py
index f730546..566d844 100644
--- a/setup.py
+++ b/setup.py
@@ -1,5 +1,4 @@
-# Copyright 2017 ATT Corporation.
-# All Rights Reserved.
+# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
@@ -26,5 +25,5 @@
     pass
 
 setuptools.setup(
-    setup_requires=['pbr>=1.8'],
+    setup_requires=['pbr>=2.0.0'],
     pbr=True)
diff --git a/test-requirements.txt b/test-requirements.txt
index 7c97fa7..3e03437 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -1,16 +1,16 @@
 # 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.12.0,!=0.13.0,<0.14  # Apache-2.0
+hacking!=0.13.0,<0.14,>=0.12.0 # Apache-2.0
 
-sphinx>=1.2.1,!=1.3b1,<1.4  # BSD
-oslosphinx>=4.7.0 # Apache-2.0
-reno>=1.8.0 # Apache-2.0
+sphinx>=1.6.2 # BSD
+openstackdocstheme>=1.11.0 # Apache-2.0
+reno!=2.3.1,>=1.8.0 # Apache-2.0
 mock>=2.0 # BSD
-coverage>=4.0 # Apache-2.0
+coverage!=4.4,>=4.0 # Apache-2.0
 nose # LGPL
 nosexcover # BSD
 oslotest>=1.10.0 # Apache-2.0
-oslo.policy>=1.17.0  # Apache-2.0
-oslo.log>=3.11.0 # Apache-2.0
-tempest>=12.1.0  # Apache-2.0
+oslo.policy>=1.23.0 # Apache-2.0
+oslo.log>=3.22.0 # Apache-2.0
+tempest>=14.0.0 # Apache-2.0
diff --git a/tox.ini b/tox.ini
index b4953e7..d2e83e9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -13,21 +13,25 @@
 whitelist_externals = find
 deps = -r{toxinidir}/requirements.txt
        -r{toxinidir}/test-requirements.txt
-commands = 
+commands =
     find . -type f -name "*.pyc" -delete
     ostestr {posargs} --whitelist-file test-whitelist.txt
 
 [testenv:pep8]
 commands = flake8 {posargs}
-		   check-uuid
+           check-uuid --package patrole_tempest_plugin.tests.api
 
 [testenv:uuidgen]
-commands = check-uuid --fix
+commands = check-uuid --package patrole_tempest_plugin.tests.api --fix
 
 [testenv:venv]
 commands = {posargs}
 
 [testenv:cover]
+commands = rm -rf *.pyc
+           rm -rf cover
+           rm -f .coverage
+           nosetests {posargs}
 setenv = VIRTUAL_ENV={envdir}
          NOSE_WITH_COVERAGE=1
          NOSE_COVER_BRANCHES=1
@@ -36,7 +40,7 @@
          NOSE_COVER_HTML_DIR={toxinidir}/cover
          NOSE_WHERE=patrole_tempest_plugin/tests/unit
 whitelist_externals = nosetests
-commands = nosetests {posargs}
+                      rm
 
 [testenv:docs]
 commands = python setup.py build_sphinx
@@ -46,12 +50,15 @@
   sphinx-build -a -E -W -d releasenotes/build/doctrees -b html releasenotes/source releasenotes/build/html
 
 [testenv:debug]
-commands = oslo_debug_helper {posargs}
+commands = oslo_debug_helper -t patrole_tempest_plugin/tests {posargs}
 
 [flake8]
-# E123, E125 skipped as they are invalid PEP-8.
-
+enable-extensions = H106,H203,H904
 show-source = True
+# E123, E125 skipped as they are invalid PEP-8.
 ignore = E123,E125
 builtins = _
 exclude=.venv,.git,.tox,dist,doc,*lib/python*,*egg,build
+
+[hacking]
+local-check-factory = patrole_tempest_plugin.hacking.checks.factory