Merge "Add tests to cover flavor_service_profile"
diff --git a/.zuul.yaml b/.zuul.yaml
index 5701eb4..5e6deeb 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -25,6 +25,7 @@
devstack_services:
tempest: true
neutron: true
+ neutron-trunk: true
tempest_concurrency: 2
tempest_test_regex: (?!.*\[.*\bslow\b.*\])(^patrole_tempest_plugin\.tests\.api)
tox_envlist: all-plugin
@@ -171,6 +172,8 @@
tempest_test_regex: (?=.*PluginRbacTest)(^patrole_tempest_plugin\.tests\.api)
- project:
+ templates:
+ - openstack-python36-jobs
check:
jobs:
- patrole-admin
diff --git a/README.rst b/README.rst
index 2028536..fdcbc6b 100644
--- a/README.rst
+++ b/README.rst
@@ -36,7 +36,7 @@
Design Principles
-----------------
-As a `Tempest plugin`_, Patrole borrows some `design principles`_ from Tempest,
+As a `Tempest plugin`_, Patrole borrows some design principles from `Tempest design principles`_,
but not all, as its testing scope is confined to policies.
* *Stability*. Patrole uses OpenStack public interfaces. Tests in Patrole
@@ -76,7 +76,7 @@
* *Self-testing*. Patrole should be self-testing.
.. _Tempest plugin: https://docs.openstack.org/tempest/latest/plugin.html
-.. _design principles: https://docs.openstack.org/tempest/latest/overview.html#design-principles
+.. _Tempest design principles: https://docs.openstack.org/tempest/latest/overview.html#design-principles
.. _policy in code: https://specs.openstack.org/openstack/oslo-specs/specs/newton/policy-in-code.html
.. _Nova repository: https://github.com/openstack/nova/tree/master/nova/policies
.. _Keystone repository: https://github.com/openstack/keystone/tree/master/keystone/common/policies
@@ -120,7 +120,7 @@
Quickstart
----------
To run Patrole, you must first have `Tempest`_ installed and configured
-properly. Please reference Tempest's `Quickstart`_ guide to do so. Follow all
+properly. Please reference `Tempest_quickstart`_ guide to do so. Follow all
the steps outlined therein. Afterward, proceed with the steps below.
#. You first need to install Patrole. This is done with pip after you check out
@@ -139,7 +139,7 @@
#. Next you must properly configure Patrole, which is relatively
straightforward. For details on configuring Patrole refer to the
- :ref:`patrole-configuration`.
+ `Patrole Configuration <https://docs.openstack.org/patrole/latest/configuration.html#patrole-configuration>`_.
#. Once the configuration is done you're now ready to run Patrole. This can
be done using the `tempest_run`_ command. This can be done by running::
@@ -170,14 +170,14 @@
#. Log information from tests is captured in ``tempest.log`` under the Tempest
repository. Some Patrole debugging information is captured in that log
- related to expected test results and :ref:`role-overriding`.
+ related to expected test results and `Role Overriding <https://docs.openstack.org/patrole/latest/framework/rbac_utils.html#role-overriding>`_.
More detailed RBAC testing log output is emitted to ``patrole.log`` under
the Patrole repository. To configure Patrole's logging, see the
- :ref:`patrole-configuration` guide.
+ `Patrole Configuration Guide <https://docs.openstack.org/patrole/latest/configuration.html#patrole-configuration>`_.
.. _Tempest: https://github.com/openstack/tempest
-.. _Quickstart: https://docs.openstack.org/tempest/latest/overview.html#quickstart
+.. _Tempest_quickstart: https://docs.openstack.org/tempest/latest/overview.html#quickstart
.. _tempest_run: https://docs.openstack.org/tempest/latest/run.html
.. _testr: https://testrepository.readthedocs.org/en/latest/MANUAL.html
.. _ostestr: https://docs.openstack.org/os-testr/latest/
diff --git a/devstack/plugin.sh b/devstack/plugin.sh
index bd0068b..4826d21 100644
--- a/devstack/plugin.sh
+++ b/devstack/plugin.sh
@@ -26,12 +26,18 @@
iniset $TEMPEST_CONFIG policy-feature-enabled volume_extension_volume_actions_attach_policy False
iniset $TEMPEST_CONFIG policy-feature-enabled volume_extension_volume_actions_reserve_policy False
iniset $TEMPEST_CONFIG policy-feature-enabled volume_extension_volume_actions_unreserve_policy False
+
+ # These policies were removed in Stein but are available in Pike.
+ iniset $TEMPEST_CONFIG policy-feature-enabled removed_nova_policies_stein False
fi
if [[ ${DEVSTACK_SERIES} == 'queens' ]]; then
if [[ "$RBAC_TEST_ROLE" == "member" ]]; then
RBAC_TEST_ROLE="Member"
fi
+
+ # These policies were removed in Stein but are available in Queens.
+ iniset $TEMPEST_CONFIG policy-feature-enabled removed_nova_policies_stein False
fi
iniset $TEMPEST_CONFIG patrole enable_rbac True
diff --git a/patrole_tempest_plugin/config.py b/patrole_tempest_plugin/config.py
index ebc8a1d..47b76d4 100644
--- a/patrole_tempest_plugin/config.py
+++ b/patrole_tempest_plugin/config.py
@@ -160,7 +160,17 @@
default=True,
help="""Is the Cinder policy
"volume_extension:volume_actions:unreserve" available in the cloud? This policy
-was changed in a backwards-incompatible way.""")
+was changed in a backwards-incompatible way."""),
+ # *** Include feature flags for groups of policies below. ***
+ # Best practice is to capture new policies, removed policies, renamed
+ # policies in a group, per release.
+ #
+ # TODO(felipemonteiro): Remove these feature flags once Stein is EOL.
+ cfg.BoolOpt('removed_nova_policies_stein',
+ default=True,
+ help="""Are the Nova API extension policies available in the
+cloud (e.g. os_compute_api:os-extended-availability-zone)? These policies were
+removed in Stein because Nova API extension concept was removed in Pike."""),
]
diff --git a/patrole_tempest_plugin/rbac_rule_validation.py b/patrole_tempest_plugin/rbac_rule_validation.py
index e6d1e80..32deb9f 100644
--- a/patrole_tempest_plugin/rbac_rule_validation.py
+++ b/patrole_tempest_plugin/rbac_rule_validation.py
@@ -110,7 +110,7 @@
c) if both api_action1 and api_action2 fail, then the expected error
code is the first error seen (404).
- If an error code is missing from the list, it is defaulted to 403.
+ If it is not passed, then it is defaulted to 403.
:param dict extra_target_data: Dictionary, keyed with ``oslo.policy``
generic check names, whose values are string literals that reference
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 d6364c9..a99ddbd 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,8 +13,9 @@
# License for the specific language governing permissions and limitations
# under the License.
-from tempest import config
+import testtools
+from tempest import config
from tempest.lib.common.utils import test_utils
from tempest.lib import decorators
@@ -34,6 +35,8 @@
cls.public_flavor_id = CONF.compute.flavor_ref
cls.tenant_id = cls.os_primary.credentials.tenant_id
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@decorators.idempotent_id('a2bd3740-765d-4c95-ac98-9e027378c75e')
@rbac_rule_validation.action(
service="nova",
@@ -50,6 +53,8 @@
raise rbac_exceptions.RbacMalformedResponse(
attribute=expected_attr)
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@decorators.idempotent_id('dd388146-9750-4124-82ba-62deff1052bb')
@rbac_rule_validation.action(
service="nova",
diff --git a/patrole_tempest_plugin/tests/api/compute/test_flavor_rxtx_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_flavor_rxtx_rbac.py
index fbc03cf..b4531af 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_flavor_rxtx_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_flavor_rxtx_rbac.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import testtools
+
from tempest.common import utils
from tempest import config
from tempest.lib import decorators
@@ -33,6 +35,8 @@
msg = "os-flavor-rxtx extension not enabled."
raise cls.skipException(msg)
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@decorators.idempotent_id('5e1fd9f0-9a08-485a-ad9c-0fc66e4d64b7')
@rbac_rule_validation.action(
service="nova",
@@ -44,6 +48,8 @@
raise rbac_exceptions.RbacMalformedResponse(
attribute='rxtx_factor')
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@decorators.idempotent_id('70c55a07-c843-4627-a29d-ba78673c1e63')
@rbac_rule_validation.action(
service="nova",
diff --git a/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py
index f36b8ec..c988128 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py
@@ -13,6 +13,8 @@
# License for the specific language governing permissions and limitations
# under the License.
+import testtools
+
from tempest.common import image as common_image
from tempest import config
from tempest.lib.common.utils import data_utils
@@ -20,6 +22,7 @@
from tempest.lib import decorators
from tempest.lib import exceptions as lib_exc
+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
@@ -245,18 +248,67 @@
# https://developer.openstack.org/api-ref/compute/#images-deprecated
max_microversion = '2.35'
+ @classmethod
+ def skip_checks(cls):
+ super(ImageSizeRbacTest, 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(ImageSizeRbacTest, cls).setup_clients()
+ if CONF.image_feature_enabled.api_v2:
+ cls.glance_image_client = cls.os_primary.image_client_v2
+ elif CONF.image_feature_enabled.api_v1:
+ cls.glance_image_client = cls.os_primary.image_client
+ else:
+ raise lib_exc.InvalidConfiguration(
+ 'Either api_v1 or api_v2 must be True in '
+ '[image-feature-enabled].')
+
+ @classmethod
+ def resource_setup(cls):
+ super(ImageSizeRbacTest, cls).resource_setup()
+ params = {'name': data_utils.rand_name(cls.__name__ + '-image')}
+ if CONF.image_feature_enabled.api_v1:
+ params = {'headers': common_image.image_meta_to_headers(**params)}
+
+ cls.image = cls.glance_image_client.create_image(**params)
+ cls.addClassResourceCleanup(
+ cls.glance_image_client.wait_for_resource_deletion,
+ cls.image['id'])
+ cls.addClassResourceCleanup(
+ cls.glance_image_client.delete_image, cls.image['id'])
+
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@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):
+ def test_show_image_includes_image_size(self):
with self.rbac_utils.override_role(self):
- self.compute_images_client.list_images()
+ body = self.compute_images_client.show_image(self.image['id'])[
+ 'image']
+ expected_attr = 'OS-EXT-IMG-SIZE:size'
+ if expected_attr not in body:
+ raise rbac_exceptions.RbacMalformedResponse(
+ attribute=expected_attr)
+
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@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):
+ def test_list_images_with_details_includes_image_size(self):
with self.rbac_utils.override_role(self):
- self.compute_images_client.list_images(detail=True)
+ body = self.compute_images_client.list_images(detail=True)[
+ 'images']
+
+ expected_attr = 'OS-EXT-IMG-SIZE:size'
+ if expected_attr not in body[0]:
+ raise rbac_exceptions.RbacMalformedResponse(
+ attribute=expected_attr)
diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py
index d97f382..5681799 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py
@@ -129,6 +129,8 @@
waiters.wait_for_server_status(
self.servers_client, self.server['id'], 'ACTIVE')
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@utils.requires_ext(extension='os-config-drive', service='compute')
@decorators.idempotent_id('2c82e819-382d-4d6f-87f0-a45954cbbc64')
@rbac_rule_validation.action(
@@ -144,6 +146,8 @@
raise rbac_exceptions.RbacMalformedResponse(
attribute=expected_attr)
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@utils.requires_ext(extension='os-config-drive', service='compute')
@decorators.idempotent_id('55c62ef7-b72b-4970-acc6-05b0a4316e5d')
@rbac_rule_validation.action(
@@ -169,6 +173,8 @@
# Force-deleting a server enforces os-deferred-delete.
self.servers_client.force_delete_server(self.server['id'])
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@decorators.idempotent_id('d873740a-7b10-40a9-943d-7cc18115370e')
@utils.requires_ext(extension='OS-EXT-AZ', service='compute')
@rbac_rule_validation.action(
@@ -185,6 +191,8 @@
raise rbac_exceptions.RbacMalformedResponse(
attribute=expected_attr)
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@decorators.idempotent_id('727e5360-770a-4b9c-8015-513a40216635')
@utils.requires_ext(extension='OS-EXT-AZ', service='compute')
@rbac_rule_validation.action(
@@ -200,6 +208,8 @@
raise rbac_exceptions.RbacMalformedResponse(
attribute=expected_attr)
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@decorators.idempotent_id('4aa5d93e-4887-468a-8eb4-b6eca0ca6437')
@utils.requires_ext(extension='OS-EXT-SRV-ATTR', service='compute')
@rbac_rule_validation.action(
@@ -222,6 +232,8 @@
raise rbac_exceptions.RbacMalformedResponse(
attribute=whole_attr)
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@decorators.idempotent_id('2ed7aee2-94b2-4a9f-ae63-a51b7f94fe30')
@utils.requires_ext(extension='OS-EXT-SRV-ATTR', service='compute')
@rbac_rule_validation.action(
@@ -244,6 +256,8 @@
raise rbac_exceptions.RbacMalformedResponse(
attribute=whole_attr)
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@decorators.idempotent_id('82053c27-3134-4003-9b55-bc9fafdb0e3b')
@utils.requires_ext(extension='OS-EXT-STS', service='compute')
@rbac_rule_validation.action(
@@ -261,6 +275,8 @@
raise rbac_exceptions.RbacMalformedResponse(
attribute=attr)
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@decorators.idempotent_id('7d2620a5-eea1-4a8b-96ea-86ad77a73fc8')
@utils.requires_ext(extension='OS-EXT-STS', service='compute')
@rbac_rule_validation.action(
@@ -278,6 +294,8 @@
raise rbac_exceptions.RbacMalformedResponse(
attribute=attr)
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@decorators.idempotent_id('21e39cbe-6c32-48fc-80dd-3e1fece6053f')
@utils.requires_ext(extension='os-extended-volumes', service='compute')
@rbac_rule_validation.action(
@@ -295,6 +313,8 @@
raise rbac_exceptions.RbacMalformedResponse(
attribute=expected_attr)
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@decorators.idempotent_id('7f163708-0d25-4138-8512-dfdd72a92989')
@utils.requires_ext(extension='os-extended-volumes', service='compute')
@rbac_rule_validation.action(
@@ -348,6 +368,8 @@
raise rbac_exceptions.RbacMalformedResponse(
attribute='events.traceback')
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@rbac_rule_validation.action(
service="nova",
rule="os_compute_api:os-keypairs")
@@ -360,6 +382,8 @@
raise rbac_exceptions.RbacMalformedResponse(
attribute='key_name')
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@rbac_rule_validation.action(
service="nova",
rule="os_compute_api:os-keypairs")
@@ -469,6 +493,8 @@
with self.rbac_utils.override_role(self):
self.servers_client.show_password(self.server['id'])
+ @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein,
+ "This API extension policy was removed in Stein")
@utils.requires_ext(extension='OS-SRV-USG', service='compute')
@rbac_rule_validation.action(
service="nova",
diff --git a/patrole_tempest_plugin/tests/api/image/test_images_member_rbac.py b/patrole_tempest_plugin/tests/api/image/test_images_member_rbac.py
index 952c41f..4b5fd08 100644
--- a/patrole_tempest_plugin/tests/api/image/test_images_member_rbac.py
+++ b/patrole_tempest_plugin/tests/api/image/test_images_member_rbac.py
@@ -68,8 +68,8 @@
self.alt_tenant_id)
@rbac_rule_validation.action(service="glance",
- rule="get_member",
- expected_error_code=404)
+ rules=["get_member"],
+ expected_error_codes=[404])
@decorators.idempotent_id('c01fd308-6484-11e6-881e-080027d0d606')
def test_show_image_member(self):
diff --git a/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py b/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py
index 2756a10..7567275 100644
--- a/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py
@@ -38,8 +38,8 @@
@decorators.idempotent_id('f88e38e0-ab52-4b97-8ffa-48a27f9d199b')
@rbac_rule_validation.action(service="neutron",
- rule="get_agent",
- expected_error_code=404)
+ rules=["get_agent"],
+ expected_error_codes=[404])
def test_show_agent(self):
"""Show agent test.
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 ed52c34..8a02149 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
@@ -76,8 +76,7 @@
@rbac_rule_validation.action(
service="neutron",
rules=["create_floatingip",
- "create_floatingip:floating_ip_address"],
- expected_error_codes=[403, 403])
+ "create_floatingip:floating_ip_address"])
@decorators.idempotent_id('a8bb826a-403d-4130-a55d-120a0a660806')
def test_create_floating_ip_floatingip_address(self):
"""Create floating IP with address.
@@ -105,8 +104,8 @@
floating_ip['id'], port_id=None)
@rbac_rule_validation.action(service="neutron",
- rule="get_floatingip",
- expected_error_code=404)
+ rules=["get_floatingip"],
+ expected_error_codes=[404])
@decorators.idempotent_id('f8846fd0-c976-48fe-a148-105303931b32')
def test_show_floating_ip(self):
"""Show floating IP.
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 adab1e6..db099a1 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
@@ -74,8 +74,8 @@
self._create_metering_label_rule(self.label)
@rbac_rule_validation.action(service="neutron",
- rule="get_metering_label_rule",
- expected_error_code=404)
+ rules=["get_metering_label_rule"],
+ expected_error_codes=[404])
@decorators.idempotent_id('e21b40c3-d44d-412f-84ea-836ca8603bcb')
def test_show_metering_label_rule(self):
"""Show metering label rule.
diff --git a/patrole_tempest_plugin/tests/api/network/test_metering_labels_rbac.py b/patrole_tempest_plugin/tests/api/network/test_metering_labels_rbac.py
index 0231868..0e10f5b 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
@@ -58,8 +58,8 @@
self._create_metering_label()
@rbac_rule_validation.action(service="neutron",
- rule="get_metering_label",
- expected_error_code=404)
+ rules=["get_metering_label"],
+ expected_error_codes=[404])
@decorators.idempotent_id('c57f6636-c702-4755-8eac-5e73bc1f7d14')
def test_show_metering_label(self):
"""Show metering label.
diff --git a/patrole_tempest_plugin/tests/api/network/test_network_segments_rbac.py b/patrole_tempest_plugin/tests/api/network/test_network_segments_rbac.py
index 0097c7b..c985111 100644
--- a/patrole_tempest_plugin/tests/api/network/test_network_segments_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_network_segments_rbac.py
@@ -67,8 +67,7 @@
@rbac_rule_validation.action(service="neutron",
rules=["create_network",
- "create_network:segments"],
- expected_error_codes=[403, 403])
+ "create_network:segments"])
@decorators.idempotent_id('9e1d0c3d-92e3-40e3-855e-bfbb72ea6e0b')
def test_create_network_segments(self):
"""Create network with segments.
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 72674f6..2e69f89 100644
--- a/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py
@@ -110,8 +110,7 @@
@rbac_rule_validation.action(service="neutron",
rules=["create_network",
- "create_network:is_default"],
- expected_error_codes=[403, 403])
+ "create_network:is_default"])
@decorators.idempotent_id('28602661-5ac7-407e-b739-e393f619f5e3')
def test_create_network_is_default(self):
@@ -129,8 +128,7 @@
@rbac_rule_validation.action(service="neutron",
rules=["create_network",
- "create_network:shared"],
- expected_error_codes=[403, 403])
+ "create_network:shared"])
@decorators.idempotent_id('ccabf2a9-28c8-44b2-80e6-ffd65d43eef2')
def test_create_network_shared(self):
@@ -144,8 +142,7 @@
@utils.requires_ext(extension='external-net', service='network')
@rbac_rule_validation.action(service="neutron",
rules=["create_network",
- "create_network:router:external"],
- expected_error_codes=[403, 403])
+ "create_network:router:external"])
@decorators.idempotent_id('51adf2a7-739c-41e0-8857-3b4c460cbd24')
def test_create_network_router_external(self):
@@ -160,8 +157,7 @@
@rbac_rule_validation.action(
service="neutron",
rules=["create_network",
- "create_network:provider:physical_network"],
- expected_error_codes=[403, 403])
+ "create_network:provider:physical_network"])
@decorators.idempotent_id('76783fed-9ff3-4499-a0d1-82d99eec364e')
def test_create_network_provider_physical_network(self):
@@ -184,8 +180,7 @@
@rbac_rule_validation.action(
service="neutron",
rules=["create_network",
- "create_network:provider:network_type"],
- expected_error_codes=[403, 403])
+ "create_network:provider:network_type"])
@decorators.idempotent_id('3c42f7b8-b80c-44ef-8fa4-69ec4b1836bc')
def test_create_network_provider_network_type(self):
@@ -200,8 +195,7 @@
@rbac_rule_validation.action(
service="neutron",
rules=["create_network",
- "create_network:provider:segmentation_id"],
- expected_error_codes=[403, 403])
+ "create_network:provider:segmentation_id"])
@decorators.idempotent_id('b9decb7b-68ef-4504-b99b-41edbf7d2af5')
def test_create_network_provider_segmentation_id(self):
@@ -338,8 +332,8 @@
str(exc))
@rbac_rule_validation.action(service="neutron",
- rule="get_network",
- expected_error_code=404)
+ rules=["get_network"],
+ expected_error_codes=[404])
@decorators.idempotent_id('0eb62d04-338a-4ff4-a8fa-534e52110534')
def test_show_network(self):
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 2cf3cd6..175d051 100644
--- a/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py
@@ -69,8 +69,7 @@
@decorators.idempotent_id('045ee797-4962-4913-b96a-5d7ea04099e7')
@rbac_rule_validation.action(service="neutron",
rules=["create_port",
- "create_port:device_owner"],
- expected_error_codes=[403, 403])
+ "create_port:device_owner"])
def test_create_port_device_owner(self):
with self.rbac_utils.override_role(self):
self.create_port(self.network,
@@ -79,8 +78,7 @@
@decorators.idempotent_id('c4fa8844-f5ef-4daa-bfa2-b89897dfaedf')
@rbac_rule_validation.action(service="neutron",
rules=["create_port",
- "create_port:port_security_enabled"],
- expected_error_codes=[403, 403])
+ "create_port:port_security_enabled"])
def test_create_port_security_enabled(self):
with self.rbac_utils.override_role(self):
self.create_port(self.network, port_security_enabled=True)
@@ -88,8 +86,7 @@
@utils.requires_ext(extension='binding', service='network')
@rbac_rule_validation.action(service="neutron",
rules=["create_port",
- "create_port:binding:host_id"],
- expected_error_codes=[403, 403])
+ "create_port:binding:host_id"])
@decorators.idempotent_id('a54bd6b8-a7eb-4101-bfe8-093930b0d660')
def test_create_port_binding_host_id(self):
@@ -102,8 +99,7 @@
@utils.requires_ext(extension='binding', service='network')
@rbac_rule_validation.action(service="neutron",
rules=["create_port",
- "create_port:binding:profile"],
- expected_error_codes=[403, 403])
+ "create_port:binding:profile"])
@decorators.idempotent_id('98fa38ab-c2ed-46a0-99f0-59f18cbd257a')
def test_create_port_binding_profile(self):
@@ -120,8 +116,7 @@
'"create_port:fixed_ips:ip_address" must be available in the cloud.')
@rbac_rule_validation.action(service="neutron",
rules=["create_port",
- "create_port:fixed_ips:ip_address"],
- expected_error_codes=[403, 403])
+ "create_port:fixed_ips:ip_address"])
@decorators.idempotent_id('2551e10d-006a-413c-925a-8c6f834c09ac')
def test_create_port_fixed_ips_ip_address(self):
@@ -137,8 +132,7 @@
@rbac_rule_validation.action(service="neutron",
rules=["create_port",
- "create_port:mac_address"],
- expected_error_codes=[403, 403])
+ "create_port:mac_address"])
@decorators.idempotent_id('aee6d0be-a7f3-452f-aefc-796b4eb9c9a8')
def test_create_port_mac_address(self):
@@ -150,8 +144,7 @@
@rbac_rule_validation.action(service="neutron",
rules=["create_port",
- "create_port:allowed_address_pairs"],
- expected_error_codes=[403, 403])
+ "create_port:allowed_address_pairs"])
@decorators.idempotent_id('b638d1f4-d903-4ca8-aa2a-6fd603c5ec3a')
def test_create_port_allowed_address_pairs(self):
@@ -166,8 +159,8 @@
self.create_port(**post_body)
@rbac_rule_validation.action(service="neutron",
- rule="get_port",
- expected_error_code=404)
+ rules=["get_port"],
+ expected_error_codes=[404])
@decorators.idempotent_id('a9d41cb8-78a2-4b97-985c-44e4064416f4')
def test_show_port(self):
with self.rbac_utils.override_role(self):
diff --git a/patrole_tempest_plugin/tests/api/network/test_rbac_policies_rbac.py b/patrole_tempest_plugin/tests/api/network/test_rbac_policies_rbac.py
new file mode 100644
index 0000000..a8813e7
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/network/test_rbac_policies_rbac.py
@@ -0,0 +1,111 @@
+# Copyright 2018 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.network import rbac_base as base
+
+
+class RbacPoliciesPluginRbacTest(base.BaseNetworkPluginRbacTest):
+
+ @classmethod
+ def resource_setup(cls):
+ super(RbacPoliciesPluginRbacTest, cls).resource_setup()
+ cls.tenant_id = cls.os_primary.credentials.tenant_id
+ cls.network_id = cls.create_network()['id']
+
+ def create_rbac_policy(self, tenant_id, network_id):
+ policy = self.ntp_client.create_rbac_policy(
+ target_tenant=self.tenant_id,
+ object_type="network",
+ object_id=self.network_id,
+ action="access_as_shared"
+ )
+ self.addCleanup(
+ test_utils.call_and_ignore_notfound_exc,
+ self.ntp_client.delete_rbac_policy, policy["rbac_policy"]["id"])
+
+ return policy["rbac_policy"]["id"]
+
+ @decorators.idempotent_id('effd9545-99ad-4c3c-92dd-ea422602c868')
+ @rbac_rule_validation.action(service="neutron",
+ rules=["create_rbac_policy",
+ "create_rbac_policy:target_tenant"])
+ def test_create_rbac_policy(self):
+ """Create RBAC policy.
+
+ RBAC test for the neutron "create_rbac_policy" policy
+
+ We can't validate "create_rbac_policy:target_tenant" for all cases
+ since if "restrict_wildcard" rule is modified then Patrole won't be
+ able to determine the correct result since that requires relying on
+ Neutron's custom FieldCheck oslo.policy rule.
+ """
+
+ with self.rbac_utils.override_role(self):
+ self.create_rbac_policy(self.tenant_id, self.network_id)
+
+ @decorators.idempotent_id('f5d836d8-3b64-412d-a283-ee29761017f3')
+ @rbac_rule_validation.action(service="neutron",
+ rules=["get_rbac_policy",
+ "update_rbac_policy",
+ "update_rbac_policy:target_tenant"],
+ expected_error_codes=[404, 403, 403])
+ def test_update_rbac_policy(self):
+ """Update RBAC policy.
+
+ RBAC test for the neutron "update_rbac_policy" policy
+
+ We can't validate "create_rbac_policy:target_tenant" for all cases
+ since if "restrict_wildcard" rule is modified then Patrole won't be
+ able to determine the correct result since that requires relying on
+ Neutron's custom FieldCheck oslo.policy rule.
+ """
+ policy_id = self.create_rbac_policy(self.tenant_id, self.network_id)
+
+ with self.rbac_utils.override_role(self):
+ self.ntp_client.update_rbac_policy(
+ policy_id, target_tenant=self.tenant_id)
+
+ @decorators.idempotent_id('9308ab18-426c-41b7-bce5-11081f7dd259')
+ @rbac_rule_validation.action(service="neutron",
+ rules=["get_rbac_policy"],
+ expected_error_codes=[404])
+ def test_show_rbac_policy(self):
+ """Show RBAC policy.
+
+ RBAC test for the neutron "get_rbac_policy" policy
+ """
+ policy_id = self.create_rbac_policy(self.tenant_id, self.network_id)
+
+ with self.rbac_utils.override_role(self):
+ self.ntp_client.show_rbac_policy(policy_id)
+
+ @decorators.idempotent_id('54aa9bce-efea-47fb-b0e4-12012f82f285')
+ @rbac_rule_validation.action(service="neutron",
+ rules=["get_rbac_policy",
+ "delete_rbac_policy"],
+ expected_error_codes=[404, 403])
+ def test_delete_rbac_policy(self):
+ """Delete RBAC policy.
+
+ RBAC test for the neutron "delete_rbac_policy" policy
+ """
+ policy_id = self.create_rbac_policy(self.tenant_id, self.network_id)
+
+ with self.rbac_utils.override_role(self):
+ self.ntp_client.delete_rbac_policy(policy_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 a3d973d..3d7631a 100644
--- a/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py
@@ -72,8 +72,7 @@
@utils.requires_ext(extension='l3-ha', service='network')
@rbac_rule_validation.action(service="neutron",
rules=["create_router",
- "create_router:ha"],
- expected_error_codes=[403, 403])
+ "create_router:ha"])
def test_create_high_availability_router(self):
"""Create high-availability router
@@ -88,8 +87,7 @@
@utils.requires_ext(extension='dvr', service='network')
@rbac_rule_validation.action(service="neutron",
rules=["create_router",
- "create_router:distributed"],
- expected_error_codes=[403, 403])
+ "create_router:distributed"])
def test_create_distributed_router(self):
"""Create distributed router
@@ -104,8 +102,7 @@
@rbac_rule_validation.action(
service="neutron",
rules=["create_router",
- "create_router:external_gateway_info:enable_snat"],
- expected_error_codes=[403, 403])
+ "create_router:external_gateway_info:enable_snat"])
@decorators.idempotent_id('3c5acd49-0ec7-4109-ab51-640557b48ebc')
def test_create_router_enable_snat(self):
"""Create Router Snat
@@ -126,8 +123,7 @@
@rbac_rule_validation.action(
service="neutron",
rules=["create_router",
- "create_router:external_gateway_info:external_fixed_ips"],
- expected_error_codes=[403, 403])
+ "create_router:external_gateway_info:external_fixed_ips"])
@decorators.idempotent_id('d0354369-a040-4349-b869-645c8aed13cd')
def test_create_router_external_fixed_ips(self):
"""Create Router Fixed IPs
@@ -151,8 +147,8 @@
router['router']['id'])
@rbac_rule_validation.action(service="neutron",
- rule="get_router",
- expected_error_code=404)
+ rules=["get_router"],
+ expected_error_codes=[404])
@decorators.idempotent_id('bfbdbcff-f115-4d3e-8cd5-6ada33fd0e21')
def test_show_router(self):
"""Get Router
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 1cf841d..4536fdb 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
@@ -78,8 +78,8 @@
self._create_security_group()
@rbac_rule_validation.action(service="neutron",
- rule="get_security_group",
- expected_error_code=404)
+ rules=["get_security_group"],
+ expected_error_codes=[404])
@decorators.idempotent_id('56335e77-aef2-4b54-86c7-7f772034b585')
def test_show_security_group(self):
@@ -149,8 +149,8 @@
sec_group_rule['id'])
@rbac_rule_validation.action(service="neutron",
- rule="get_security_group_rule",
- expected_error_code=404)
+ rules=["get_security_group_rule"],
+ expected_error_codes=[404])
@decorators.idempotent_id('84b4038c-261e-4a94-90d5-c885739ab0d5')
def test_show_security_group_rule(self):
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 124b59a..7d02271 100644
--- a/patrole_tempest_plugin/tests/api/network/test_subnetpools_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_subnetpools_rbac.py
@@ -65,8 +65,7 @@
@rbac_rule_validation.action(service="neutron",
rules=["create_subnetpool",
- "create_subnetpool:shared"],
- expected_error_codes=[403, 403])
+ "create_subnetpool:shared"])
@decorators.idempotent_id('cf730989-0d47-40bc-b39a-99e7de484723')
def test_create_subnetpool_shared(self):
"""Create subnetpool shared.
@@ -77,8 +76,8 @@
self._create_subnetpool(shared=True)
@rbac_rule_validation.action(service="neutron",
- rule="get_subnetpool",
- expected_error_code=404)
+ rules=["get_subnetpool"],
+ expected_error_codes=[404])
@decorators.idempotent_id('4f5aee26-0507-4b6d-b44c-3128a25094d2')
def test_show_subnetpool(self):
"""Show subnetpool.
@@ -107,8 +106,7 @@
@decorators.idempotent_id('a16f4e5c-0675-415f-b636-00af00638693')
@rbac_rule_validation.action(service="neutron",
rules=["update_subnetpool",
- "update_subnetpool:is_default"],
- expected_error_codes=[403, 403])
+ "update_subnetpool:is_default"])
def test_update_subnetpool_is_default(self):
"""Update default subnetpool.
diff --git a/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py b/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py
index 77d4b42..93d79a9 100644
--- a/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py
@@ -50,8 +50,8 @@
@decorators.idempotent_id('c02618e7-bb20-4abd-83c8-6eec2af08752')
@rbac_rule_validation.action(service="neutron",
- rule="get_subnet",
- expected_error_code=404)
+ rules=["get_subnet"],
+ expected_error_codes=[404])
def test_show_subnet(self):
"""Show subnet.
diff --git a/patrole_tempest_plugin/tests/api/network/test_trunks_rbac.py b/patrole_tempest_plugin/tests/api/network/test_trunks_rbac.py
new file mode 100644
index 0000000..063fd55
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/network/test_trunks_rbac.py
@@ -0,0 +1,85 @@
+# Copyright 2018 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 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.network import rbac_base as base
+
+
+class TrunksPluginRbacTest(base.BaseNetworkPluginRbacTest):
+
+ @classmethod
+ def skip_checks(cls):
+ super(TrunksPluginRbacTest, cls).skip_checks()
+ if not utils.is_extension_enabled('trunk', 'network'):
+ msg = "trunk extension not enabled."
+ raise cls.skipException(msg)
+
+ @classmethod
+ def resource_setup(cls):
+ super(TrunksPluginRbacTest, cls).resource_setup()
+ cls.network = cls.create_network()
+ cls.port_id = cls.create_port(cls.network)["id"]
+
+ def create_trunk(self, port_id):
+ trunk = self.ntp_client.create_trunk(port_id, [])
+ self.addCleanup(
+ test_utils.call_and_ignore_notfound_exc,
+ self.ntp_client.delete_trunk, trunk["trunk"]['id'])
+
+ return trunk
+
+ @decorators.idempotent_id('c02618e7-bb20-1a3a-83c8-6eec2af08130')
+ @rbac_rule_validation.action(service="neutron",
+ rules=["create_trunk"])
+ def test_create_trunk(self):
+ """Create trunk.
+
+ RBAC test for the neutron "create_trunk" policy
+ """
+ with self.rbac_utils.override_role(self):
+ self.create_trunk(self.port_id)
+
+ @decorators.idempotent_id('c02618e7-bb20-1a3a-83c8-6eec2af08131')
+ @rbac_rule_validation.action(service="neutron",
+ rules=["get_trunk"],
+ expected_error_codes=[404])
+ def test_show_trunk(self):
+ """Show trunk.
+
+ RBAC test for the neutron "get_trunk" policy
+ """
+ trunk = self.create_trunk(self.port_id)
+
+ with self.rbac_utils.override_role(self):
+ self.ntp_client.show_trunk(trunk['trunk']['id'])
+
+ @decorators.idempotent_id('c02618e7-bb20-1a3a-83c8-6eec2af08132')
+ @rbac_rule_validation.action(service="neutron",
+ rules=["get_trunk",
+ "delete_trunk"],
+ expected_error_codes=[404, 403])
+ def test_delete_trunk(self):
+ """Delete trunk.
+
+ RBAC test for the neutron "delete_trunk" policy
+ """
+ trunk = self.create_trunk(self.port_id)
+
+ with self.rbac_utils.override_role(self):
+ self.ntp_client.delete_trunk(trunk['trunk']['id'])
diff --git a/releasenotes/notes/patrole-rocky-release-e6f36691306bec7e.yaml b/releasenotes/notes/patrole-rocky-release-e6f36691306bec7e.yaml
new file mode 100644
index 0000000..22c4958
--- /dev/null
+++ b/releasenotes/notes/patrole-rocky-release-e6f36691306bec7e.yaml
@@ -0,0 +1,14 @@
+---
+prelude: >
+ This release is to tag the Patrole for OpenStack Rocky release.
+ After this release, Patrole will support below OpenStack Releases:
+
+ * Rocky
+ * Queens
+ * Pike
+
+ Current development of Patrole is for OpenStack Stein development
+ cycle. Every Patrole commit is also tested against master during
+ the Stein cycle. However, this does not necessarily mean that using
+ Patrole as of this tag will work against a Stein (or future release)
+ cloud.
diff --git a/releasenotes/notes/remove-deprecated-api-extensions-policies-fca3d31c7f5f1f6c.yaml b/releasenotes/notes/remove-deprecated-api-extensions-policies-fca3d31c7f5f1f6c.yaml
new file mode 100644
index 0000000..925791f
--- /dev/null
+++ b/releasenotes/notes/remove-deprecated-api-extensions-policies-fca3d31c7f5f1f6c.yaml
@@ -0,0 +1,23 @@
+---
+features:
+ - |
+ A new policy feature flag called
+ ``[policy_feature_flag].removed_nova_policies_stein`` has been added to
+ Patrole's config to handle Nova API extension policies removed in Stein.
+
+ The policy feature flag is applied to tests that validate response bodies
+ for expected attributes previously returned for the following policies
+ that passed authorization:
+
+ - os_compute_api:os-config-drive
+ - os_compute_api:os-extended-availability-zone
+ - os_compute_api:os-extended-status
+ - os_compute_api:os-extended-volumes
+ - os_compute_api:os-keypairs
+ - os_compute_api:os-server-usage
+ - os_compute_api:os-flavor-rxtx
+ - os_compute_api:os-flavor-access (only from /flavors APIs)
+ - os_compute_api:image-size
+
+ Note that not all removed policies are included above because test coverage
+ is missing for them (like os_compute_api:os-security-groups).
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index ce29994..eb061a4 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -6,6 +6,7 @@
:maxdepth: 1
unreleased
+ v0.4.0
v0.3.0
v0.2.0
v0.1.0
diff --git a/releasenotes/source/v0.4.0.rst b/releasenotes/source/v0.4.0.rst
new file mode 100644
index 0000000..2ed32ff
--- /dev/null
+++ b/releasenotes/source/v0.4.0.rst
@@ -0,0 +1,6 @@
+====================
+v0.4.0 Release Notes
+====================
+
+.. release-notes:: 0.4.0 Release Notes
+ :version: 0.4.0
diff --git a/test-requirements.txt b/test-requirements.txt
index 9085c07..a08c27a 100644
--- a/test-requirements.txt
+++ b/test-requirements.txt
@@ -8,3 +8,4 @@
nose>=1.3.7 # LGPL
nosexcover>=1.0.10 # BSD
oslotest>=3.2.0 # Apache-2.0
+bandit>=1.5 # Apache-2.0
diff --git a/tox.ini b/tox.ini
index a09822f..ea9abf1 100644
--- a/tox.ini
+++ b/tox.ini
@@ -22,8 +22,12 @@
[testenv:pep8]
basepython = python3
-commands = flake8 {posargs}
- check-uuid --package patrole_tempest_plugin.tests.api
+deps =
+ -r{toxinidir}/test-requirements.txt
+commands =
+ flake8 {posargs}
+ bandit -r patrole_tempest_plugin -x patrole_tempest_plugin/tests -n 5
+ check-uuid --package patrole_tempest_plugin.tests.api
[testenv:uuidgen]
basepython = python3