[docs] Update rbac_utils.rst documentation
This PS updates the rbac_utils.rst documentation to replace
occurrences of switch_role (which has been deprecated) with
override_role. The documentation has also been updated to
include correct and incorrect examples for how to use
the override_role contextmanager.
Change-Id: Ia68a58267cda2c31af0e296aba32b2f949788fd7
diff --git a/doc/source/framework/rbac_utils.rst b/doc/source/framework/rbac_utils.rst
index 0f000ff..69ba045 100644
--- a/doc/source/framework/rbac_utils.rst
+++ b/doc/source/framework/rbac_utils.rst
@@ -1,7 +1,7 @@
.. _rbac-utils:
-The RBAC Utils Module
-=====================
+RBAC Utils Module
+=================
Overview
--------
@@ -30,10 +30,10 @@
#. Setup: Admin role is used automatically. The primary credentials are
overridden with the admin role.
-#. Test execution: ``[patrole] rbac_test_role`` is used manually via a call
- to ``rbac_utils.switch_role(self, toggle_rbac_role=True)``. Everything that
- is executed after this call, until the end of the test, uses the primary
- credentials overridden with the ``rbac_test_role``.
+#. Test execution: ``[patrole] rbac_test_role`` is used manually via the
+ call to ``with rbac_utils.override_role(self)``. Everything that
+ is executed within this contextmanager uses the primary
+ credentials overridden with the ``[patrole] rbac_test_role``.
#. Teardown: Admin role is used automatically. The primary credentials have
been overridden with the admin role.
@@ -64,26 +64,90 @@
"Test execution" here means calling the API endpoint that enforces the policy
action expected by the ``rbac_rule_validation`` decorator. Test execution
should be performed *only after* calling
-``rbac_utils.switch_role(self, toggle_rbac_role=True)``.
+``with rbac_utils.override_role(self)``.
Immediately after that call, the API endpoint that enforces the policy should
be called.
+Examples
+^^^^^^^^
+
+Always use the contextmanager before calling the API that enforces the
+expected policy action.
+
Example::
- # Always apply the RBAC decorator to the test.
@rbac_rule_validation.action(
service="nova",
rule="os_compute_api:os-aggregates:show")
def test_show_aggregate_rbac(self):
- # Do test setup before the switch_role call.
+ # Do test setup before the ``override_role`` call.
aggregate_id = self._create_aggregate()
- # Call the switch_role method so that the primary credentials have
- # the test role needed for test execution.
- self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- # Call the endpoint that enforces the expected policy action, described
- # by the "rule" kwarg in the decorator above.
- self.aggregates_client.show_aggregate(aggregate_id)
+ # Call the ``override_role`` method so that the primary credentials
+ # have the test role needed for test execution.
+ with self.rbac_utils.override_role(self):
+ self.aggregates_client.show_aggregate(aggregate_id)
+
+When using a waiter, do the wait outside the contextmanager. "Waiting" always
+entails executing a ``GET`` request to the server, until the state of the
+returned resource matches a desired state. These ``GET`` requests enforce
+a different policy than the one expected. This is undesirable because
+Patrole should only test policies in isolation from one another.
+
+Otherwise, the test result will be tainted, because instead of only the
+expected policy getting enforced with the ``os_primary`` role, at least
+two policies get enforced.
+
+Example using waiter::
+
+ @rbac_rule_validation.action(
+ service="nova",
+ rule="os_compute_api:os-admin-password")
+ def test_change_server_password(self):
+ original_password = self.servers_client.show_password(
+ self.server['id'])
+ self.addCleanup(self.servers_client.change_password, self.server['id'],
+ adminPass=original_password)
+
+ with self.rbac_utils.override_role(self):
+ self.servers_client.change_password(
+ self.server['id'], adminPass=data_utils.rand_password())
+ # Call the waiter outside the ``override_role`` contextmanager, so that
+ # it is executed with admin role.
+ waiters.wait_for_server_status(
+ self.servers_client, self.server['id'], 'ACTIVE')
+
+Below is an example of a method that enforces multiple policies getting
+called inside the contextmanager. The ``_complex_setup_method`` below
+performs the correct API that enforces the expected policy -- in this
+case ``self.resources_client.create_resource`` -- but then proceeds to
+use a waiter.
+
+Incorrect::
+
+ def _complex_setup_method(self):
+ resource = self.resources_client.create_resource(
+ **kwargs)['resource']
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self._delete_resource, resource)
+ waiters.wait_for_resource_status(
+ self.resources_client, resource['id'], 'available')
+ return resource
+
+ @rbac_rule_validation.action(
+ service="example-service",
+ rule="example-rule")
+ def test_change_server_password(self):
+ # Never call a helper function inside the contextmanager that calls a
+ # bunch of APIs. Only call the API that enforces the policy action
+ # contained in the decorator above.
+ with self.rbac_utils.override_role(self):
+ self._complex_setup_method()
+
+To fix this test, see the "Example using waiter" section above. It is
+recommended to re-implement the logic in a helper method inside a test such
+that only the relevant API is called inside the contextmanager, with
+everything extraneous outside.
Test Cleanup
------------