Merge "[docs] Add information about supported & stable tests"
diff --git a/patrole_tempest_plugin/rbac_rule_validation.py b/patrole_tempest_plugin/rbac_rule_validation.py
index daf03e4..97d246f 100644
--- a/patrole_tempest_plugin/rbac_rule_validation.py
+++ b/patrole_tempest_plugin/rbac_rule_validation.py
@@ -26,7 +26,6 @@
from patrole_tempest_plugin import policy_authority
from patrole_tempest_plugin import rbac_exceptions
-from patrole_tempest_plugin import rbac_utils
from patrole_tempest_plugin import requirements_authority
CONF = config.CONF
@@ -37,8 +36,7 @@
RBACLOG = logging.getLogger('rbac_reporting')
-def action(service, rule='', admin_only=False, expected_error_code=403,
- extra_target_data=None):
+def action(service, rule='', expected_error_code=403, extra_target_data=None):
"""A decorator for verifying OpenStack policy enforcement.
A decorator which allows for positive and negative RBAC testing. Given:
@@ -77,10 +75,6 @@
Patrole currently only supports custom JSON policy files.
- :param admin_only: Skips over ``oslo.policy`` check because the policy
- action defined by ``rule`` is not enforced by the service's policy
- enforcement engine. 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,
@@ -131,7 +125,7 @@
'an instance of `tempest.test.BaseTestCase`.')
allowed = _is_authorized(test_obj, service, rule,
- extra_target_data, admin_only)
+ extra_target_data)
expected_exception, irregular_msg = _get_exception_type(
expected_error_code)
@@ -188,7 +182,7 @@
return decorator
-def _is_authorized(test_obj, service, rule, extra_target_data, admin_only):
+def _is_authorized(test_obj, service, rule, extra_target_data):
"""Validates whether current RBAC role has permission to do policy action.
:param test_obj: An instance or subclass of ``tempest.test.BaseTestCase``.
@@ -200,10 +194,6 @@
``tempest.test.BaseTestCase`` attributes. Used by ``oslo.policy`` for
performing matching against attributes that are sent along with the API
calls.
- :param admin_only: Skips over ``oslo.policy`` check because the policy
- action defined by ``rule`` is not enforced by the service's policy
- enforcement engine. For example, Keystone v2 performs an admin check
- for most of its endpoints. If True, ``rule`` is effectively ignored.
:returns: True if the current RBAC role can perform the policy action,
else False.
@@ -216,12 +206,6 @@
the ``rule`` does not exist in the system.
"""
- 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))
- return rbac_utils.is_admin()
-
try:
project_id = test_obj.os_primary.credentials.project_id
user_id = test_obj.os_primary.credentials.user_id
diff --git a/patrole_tempest_plugin/tests/api/network/test_networks_multiprovider_rbac.py b/patrole_tempest_plugin/tests/api/network/test_network_segments_rbac.py
similarity index 76%
rename from patrole_tempest_plugin/tests/api/network/test_networks_multiprovider_rbac.py
rename to patrole_tempest_plugin/tests/api/network/test_network_segments_rbac.py
index 9c65c14..1dee46b 100644
--- a/patrole_tempest_plugin/tests/api/network/test_networks_multiprovider_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_network_segments_rbac.py
@@ -14,6 +14,7 @@
# under the License.
from oslo_log import log
+
from tempest.common import utils
from tempest.lib.common.utils import data_utils
from tempest.lib.common.utils import test_utils
@@ -26,18 +27,34 @@
LOG = log.getLogger(__name__)
-class NetworksMultiProviderRbacTest(base.BaseNetworkRbacTest):
+class NetworkSegmentsRbacTest(base.BaseNetworkRbacTest):
@classmethod
def skip_checks(cls):
- super(NetworksMultiProviderRbacTest, cls).skip_checks()
+ super(NetworkSegmentsRbacTest, cls).skip_checks()
if not utils.is_extension_enabled('multi-provider', 'network'):
msg = "multi-provider extension not enabled."
raise cls.skipException(msg)
+ @classmethod
+ def resource_setup(cls):
+ super(NetworkSegmentsRbacTest, cls).resource_setup()
+ # Find the network type that is supported by the current cloud by
+ # checking which network type other networks currently have. This is
+ # done because there is no tempest.conf option enumerating supported
+ # network types.
+ networks = cls.networks_client.list_networks()['networks']
+ network_types = [n['provider:network_type'] for n in networks
+ if n['provider:network_type'] != 'flat']
+ if not network_types:
+ raise cls.skipException(
+ 'Could not find network with provider:network_type that is '
+ 'not "flat".')
+ cls.network_type = network_types[0]
+
def _create_network_segments(self):
- segments = [{"provider:network_type": "gre"},
- {"provider:network_type": "gre"}]
+ segments = [{'provider:network_type': self.network_type},
+ {'provider:network_type': self.network_type}]
body = self.networks_client.create_network(
name=data_utils.rand_name(self.__class__.__name__),
@@ -68,7 +85,7 @@
RBAC test for the neutron update_network:segments policy
"""
network = self._create_network_segments()
- new_segments = [{"provider:network_type": "gre"}]
+ new_segments = [{'provider:network_type': self.network_type}]
with self.rbac_utils.override_role(self):
self.networks_client.update_network(network['id'],
@@ -92,7 +109,7 @@
# If user does not have access to the network segments attribute,
# no NotFound or Forbidden exception are thrown. Instead,
# the response will have an empty network body only.
- if len(response_network) == 0:
+ if not response_network:
LOG.info("NotFound or Forbidden exception are not thrown when "
"role doesn't have access to the endpoint. Instead, "
"the response will have an empty network body.")
diff --git a/patrole_tempest_plugin/tests/api/volume/test_encryption_types_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_encryption_types_rbac.py
index 62ccc9e..f10e41b 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_encryption_types_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_encryption_types_rbac.py
@@ -82,3 +82,13 @@
vol_type_id = self._create_volume_type_encryption()
with self.rbac_utils.override_role(self):
self.encryption_types_client.show_encryption_type(vol_type_id)
+
+ @decorators.idempotent_id('d4ed3cf8-52b2-4fa2-910d-e405361f0881')
+ @rbac_rule_validation.action(
+ service="cinder",
+ rule="volume_extension:volume_type_encryption")
+ def test_show_encryption_specs_item(self):
+ vol_type_id = self._create_volume_type_encryption()
+ with self.rbac_utils.override_role(self):
+ self.encryption_types_client.show_encryption_specs_item(
+ vol_type_id, 'provider')
diff --git a/patrole_tempest_plugin/tests/api/volume/test_limits_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_limits_rbac.py
index 976d756..78cfd9a 100644
--- a/patrole_tempest_plugin/tests/api/volume/test_limits_rbac.py
+++ b/patrole_tempest_plugin/tests/api/volume/test_limits_rbac.py
@@ -15,6 +15,7 @@
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
@@ -26,5 +27,20 @@
@rbac_rule_validation.action(service="cinder",
rule="limits_extension:used_limits")
def test_show_limits(self):
+ # It is enough to check whether any of the following keys below
+ # are in the response body under ['limits']['absolute'], but no harm
+ # in checking for them all.
+ expected_keys = {
+ 'totalVolumesUsed',
+ 'totalGigabytesUsed',
+ 'totalSnapshotsUsed',
+ 'totalBackupsUsed',
+ 'totalBackupGigabytesUsed'
+ }
+
with self.rbac_utils.override_role(self):
- self.volume_limits_client.show_limits()
+ absolute_limits = self.volume_limits_client.show_limits()[
+ 'limits']['absolute']
+ for key in expected_keys:
+ if key not in absolute_limits:
+ raise rbac_exceptions.RbacMalformedResponse(attribute=key)
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 768372f..8a50141 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
@@ -17,6 +17,7 @@
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
@@ -31,19 +32,14 @@
cls.volume = cls.create_volume()
cls.image_id = CONF.compute.image_ref
- def setUp(self):
- super(VolumeMetadataV3RbacTest, self).setUp()
- self._add_metadata(self.volume)
-
- def tearDown(self):
- self.volumes_client.update_volume_metadata(self.volume['id'], {})
- super(VolumeMetadataV3RbacTest, self).tearDown()
-
def _add_metadata(self, volume):
- # Create metadata for the volume
+ # Create metadata for the volume.
metadata = {"key1": "value1"}
self.volumes_client.create_volume_metadata(
self.volume['id'], metadata)['metadata']
+ self.addCleanup(test_utils.call_and_ignore_notfound_exc,
+ self.volumes_client.delete_volume_metadata_item,
+ self.volume['id'], "key1")
@rbac_rule_validation.action(service="cinder",
rule="volume:create_volume_metadata")
@@ -60,10 +56,22 @@
self.volumes_client.show_volume_metadata(
self.volume['id'])['metadata']
+ @decorators.idempotent_id('5c0f4c19-b448-4f51-9224-dad5faddc3bb')
+ @rbac_rule_validation.action(service="cinder",
+ rule="volume:get_volume_metadata")
+ def test_show_volume_metadata_item(self):
+ self._add_metadata(self.volume)
+
+ with self.rbac_utils.override_role(self):
+ self.volumes_client.show_volume_metadata_item(
+ self.volume['id'], "key1")
+
@rbac_rule_validation.action(service="cinder",
rule="volume:delete_volume_metadata")
@decorators.idempotent_id('7498dfc1-9db2-4423-ad20-e6dcb25d1beb')
def test_delete_volume_metadata_item(self):
+ self._add_metadata(self.volume)
+
with self.rbac_utils.override_role(self):
self.volumes_client.delete_volume_metadata_item(self.volume['id'],
"key1")
@@ -72,6 +80,7 @@
rule="volume:update_volume_metadata")
@decorators.idempotent_id('8ce2ff80-99ba-49ae-9bb1-7e96729ee5af')
def test_update_volume_metadata_item(self):
+ self._add_metadata(self.volume)
updated_metadata_item = {"key1": "value1_update"}
with self.rbac_utils.override_role(self):
self.volumes_client.update_volume_metadata_item(
@@ -81,11 +90,48 @@
@rbac_rule_validation.action(service="cinder",
rule="volume:update_volume_metadata")
def test_update_volume_metadata(self):
+ self._add_metadata(self.volume)
updated_metadata = {"key1": "value1"}
with self.rbac_utils.override_role(self):
self.volumes_client.update_volume_metadata(self.volume['id'],
updated_metadata)
+ @decorators.idempotent_id('39e8f82c-f1fc-4905-bf47-177ce2f71bb9')
+ @rbac_rule_validation.action(
+ service="cinder",
+ rule="volume_extension:volume_image_metadata")
+ def test_list_volumes_details_image_metadata(self):
+ self.volumes_client.update_volume_image_metadata(
+ self.volume['id'], image_id=self.image_id)
+ self.addCleanup(self.volumes_client.delete_volume_image_metadata,
+ self.volume['id'], 'image_id')
+
+ with self.rbac_utils.override_role(self):
+ resp_body = self.volumes_client.list_volumes(detail=True)[
+ 'volumes']
+ expected_attr = 'volume_image_metadata'
+ if expected_attr not in resp_body[0]:
+ raise rbac_exceptions.RbacMalformedResponse(
+ attribute=expected_attr)
+
+ @decorators.idempotent_id('53f94d52-0dd5-42cf-a3a4-59b35150b3d5')
+ @rbac_rule_validation.action(
+ service="cinder",
+ rule="volume_extension:volume_image_metadata")
+ def test_show_volume_details_image_metadata(self):
+ self.volumes_client.update_volume_image_metadata(
+ self.volume['id'], image_id=self.image_id)
+ self.addCleanup(self.volumes_client.delete_volume_image_metadata,
+ self.volume['id'], 'image_id')
+
+ with self.rbac_utils.override_role(self):
+ resp_body = self.volumes_client.show_volume(self.volume['id'])[
+ 'volume']
+ expected_attr = 'volume_image_metadata'
+ if expected_attr not in resp_body:
+ raise rbac_exceptions.RbacMalformedResponse(
+ attribute=expected_attr)
+
@decorators.idempotent_id('a9d9e825-5ea3-42e6-96f3-7ac4e97b2ed0')
@rbac_rule_validation.action(
service="cinder",
diff --git a/releasenotes/notes/remove-admin-only-kwarg-919f1a4797318a33.yaml b/releasenotes/notes/remove-admin-only-kwarg-919f1a4797318a33.yaml
new file mode 100644
index 0000000..21b8eb0
--- /dev/null
+++ b/releasenotes/notes/remove-admin-only-kwarg-919f1a4797318a33.yaml
@@ -0,0 +1,8 @@
+---
+upgrade:
+ - |
+ The ``admin_only`` kwarg has been removed from ``rbac_rule_validation``
+ decorator because it is no longer used by any tests. Besides that,
+ it should not be used because Patrole is dedicated to RBAC testing and
+ an admin-only check is not RBAC because it does not use ``oslo.policy``
+ library.
diff --git a/releasenotes/notes/start-of-queens-support-6c379f2b9cafbf31.yaml b/releasenotes/notes/start-of-queens-support-6c379f2b9cafbf31.yaml
new file mode 100644
index 0000000..588266b
--- /dev/null
+++ b/releasenotes/notes/start-of-queens-support-6c379f2b9cafbf31.yaml
@@ -0,0 +1,11 @@
+---
+prelude: >
+ This release marks the start of Queens release support in Patrole.
+other:
+ - OpenStack Releases supported after this release are **Queens**
+ and **Pike**.
+
+ The release under current development of this tag is Rocky, meaning
+ that every Patrole commit is also tested against master during the Rocky
+ cycle. However, this does not necessarily mean that using Patrole as of
+ this tag will work against a Rocky (or future release) cloud.
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index 11e1ac4..ce29994 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -1,9 +1,11 @@
-======================
- Patrole Release Notes
-======================
+=====================
+Patrole Release Notes
+=====================
.. toctree::
:maxdepth: 1
unreleased
+ v0.3.0
+ v0.2.0
v0.1.0
diff --git a/releasenotes/source/v0.2.0.rst b/releasenotes/source/v0.2.0.rst
new file mode 100644
index 0000000..415988e
--- /dev/null
+++ b/releasenotes/source/v0.2.0.rst
@@ -0,0 +1,6 @@
+====================
+v0.2.0 Release Notes
+====================
+
+.. release-notes:: 0.2.0 Release Notes
+ :version: 0.2.0
diff --git a/releasenotes/source/v0.3.0.rst b/releasenotes/source/v0.3.0.rst
new file mode 100644
index 0000000..5b6f04a
--- /dev/null
+++ b/releasenotes/source/v0.3.0.rst
@@ -0,0 +1,6 @@
+====================
+v0.3.0 Release Notes
+====================
+
+.. release-notes:: 0.3.0 Release Notes
+ :version: 0.3.0
diff --git a/requirements.txt b/requirements.txt
index 35c6038..cc13aa9 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -3,7 +3,7 @@
# process, which may cause wedges in the gate later.
pbr!=2.1.0,>=2.0.0 # Apache-2.0
oslo.log>=3.36.0 # Apache-2.0
-oslo.config>=5.1.0 # Apache-2.0
+oslo.config>=5.2.0 # Apache-2.0
oslo.policy>=1.30.0 # Apache-2.0
tempest>=17.1.0 # Apache-2.0
stevedore>=1.20.0 # Apache-2.0
diff --git a/test-requirements.txt b/test-requirements.txt
index add2388..475d1e5 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -3,7 +3,7 @@
# process, which may cause wedges in the gate later.
hacking>=1.0.0 # Apache-2.0
-sphinx!=1.6.6,>=1.6.2 # BSD
+sphinx!=1.6.6,!=1.6.7,>=1.6.2 # BSD
openstackdocstheme>=1.18.1 # Apache-2.0
reno>=2.5.0 # Apache-2.0
fixtures>=3.0.0 # Apache-2.0/BSD