Improve test coverage for flavor_access nova policies
This commit improves test coverage for flavor_access policies, achieving
the the most amount of coverage in Patrole for these policies that is
currently possible.
The base policy "os_compute_api:os-flavor-access" is covered by
4 separate APIs, but currently Patrole only tests 1 one of those
APIs. This commit extends the existing tests to achieve almost
full test coverage, with the exception of this endpoint:
POST /flavors
At present, it is impossible to test os-flavor-access for that
endpoint since it also enforces os-flavor-manage:create
(or os-flavor-manage) both of which require admin.
In addition, this commit fixes test_show_flavor always passing.
While policy enforcement happens in Nova when calling
`self.flavors_client.show_flavor`, no Forbidden exception
is raised following failure. Instead, the attribute
"os-flavor-access:is_public" is injected into the response
body following successful policy enforcement. So Patrole
checks for the attribute and, if not found, raises an
appropriate RbacMalformedResponse exception.
Reference: https://github.com/openstack/nova/blob/master/nova/policies/flavor_access.py
Change-Id: Icaf516f996ec088ce48bbfc768116b2d6994c336
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 26c9957..7503962 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
@@ -17,8 +17,8 @@
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
from patrole_tempest_plugin.tests.api.compute import rbac_base
@@ -28,14 +28,6 @@
class FlavorAccessRbacTest(rbac_base.BaseV2ComputeRbacTest):
@classmethod
- def skip_checks(cls):
- 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(FlavorAccessRbacTest, cls).resource_setup()
cls.flavor_id = cls.create_flavor(is_public=False)['id']
@@ -46,11 +38,36 @@
@rbac_rule_validation.action(
service="nova",
rule="os_compute_api:os-flavor-access")
- def test_show_flavor(self):
- # NOTE(felipemonteiro): show_flavor enforces the specified policy
- # action, but only works if a public flavor is passed.
+ def test_show_flavor_contains_is_public_key(self):
+ public_flavor_id = CONF.compute.flavor_ref
+
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- self.flavors_client.show_flavor(self.public_flavor_id)['flavor']
+ body = self.flavors_client.show_flavor(public_flavor_id)[
+ 'flavor']
+
+ expected_attr = 'os-flavor-access:is_public'
+ if expected_attr not in body:
+ raise rbac_exceptions.RbacMalformedResponse(
+ attribute=expected_attr)
+
+ @decorators.idempotent_id('dd388146-9750-4124-82ba-62deff1052bb')
+ @rbac_rule_validation.action(
+ service="nova",
+ rule="os_compute_api:os-flavor-access")
+ def test_list_flavors_details_contains_is_public_key(self):
+ expected_attr = 'os-flavor-access:is_public'
+
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ flavors = self.flavors_client.list_flavors(detail=True)['flavors']
+ # There should already be a public flavor available, namely
+ # `CONF.compute.flavor_ref`.
+ public_flavors = [f for f in flavors if expected_attr in f]
+
+ # If the `expected_attr` was not found in any flavor, then policy
+ # enforcement failed.
+ if not public_flavors:
+ raise rbac_exceptions.RbacMalformedResponse(
+ attribute=expected_attr)
@decorators.idempotent_id('39cb5c8f-9990-436f-9282-fc76a41d9bac')
@rbac_rule_validation.action(
@@ -74,6 +91,23 @@
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
self.flavors_client.remove_flavor_access,
flavor_id=self.flavor_id, tenant_id=self.tenant_id)
+
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)
+
+ @decorators.idempotent_id('e1cf59fb-7f32-40a1-96b9-248ab23dd581')
+ @rbac_rule_validation.action(
+ service="nova",
+ rule="os_compute_api:os-flavor-access")
+ def test_list_flavor_access(self):
+ # Add flavor access for os_primary so that it can access the flavor or
+ # else a NotFound is raised.
+ 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)
+
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.flavors_client.list_flavor_access(self.flavor_id)