Merge "Subnet rbac tests"
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 178e538..5281b53 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -1,7 +1,7 @@
Patrole Style Commandments
==========================
-- Step 1: 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
diff --git a/README.rst b/README.rst
index ad8add0..f5b4c00 100644
--- a/README.rst
+++ b/README.rst
@@ -1,6 +1,15 @@
-========
-Overview
-========
+========================
+Team and repository tags
+========================
+
+.. image:: http://governance.openstack.org/badges/patrole.svg
+ :target: http://governance.openstack.org/reference/tags/index.html
+
+..
+
+=========================================
+Patrole - RBAC Integration Tempest Plugin
+=========================================
Patrole is a tool for verifying that Role-Based Access Control is being
correctly enforced.
@@ -11,9 +20,9 @@
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
========
@@ -69,7 +78,7 @@
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: :ref:`test-flows`.
+as outlined above: `Test Flows`_.
.. note::
@@ -110,14 +119,15 @@
#. 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)``: ::
+ ``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.auth_provider
- cls.rbac_utils = rbac_utils()
- cls.rbac_utils.switch_role(cls, toggle_rbac_role=False)
+ 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``
@@ -137,7 +147,7 @@
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"
+#. The API endpoint in which policy enforcement of "os_compute_api:servers:stop"
is performed can now be called.
.. note:
diff --git a/doc/source/installation.rst b/doc/source/installation.rst
index e342dd8..31f94f4 100644
--- a/doc/source/installation.rst
+++ b/doc/source/installation.rst
@@ -7,6 +7,7 @@
At the command line::
+ $ git clone http://git.openstack.org/openstack/patrole
$ sudo pip install patrole
Or, if you have virtualenvwrapper installed::
@@ -19,6 +20,17 @@
$ navigate to patrole directory
$ 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
=========================
diff --git a/doc/source/usage.rst b/doc/source/usage.rst
index c2fc6d3..d2570bc 100644
--- a/doc/source/usage.rst
+++ b/doc/source/usage.rst
@@ -4,17 +4,28 @@
Usage
========
-Running Patrole Tests in Tempest
-================================
+RBAC (API) Tests
+================
-If Patrole is installed correctly, then the API tests can be executed
-from inside the tempest root directory as follows: ::
+If Patrole is installed correctly, then the RBAC tests can be executed
+from inside the tempest root directory as follows::
- tox -eall-plugin -- patrole_tempest_plugin.tests.api
+ $ tox -eall-plugin -- patrole_tempest_plugin.tests.api
-To execute patrole tests for a specific module, run: ::
+To execute patrole tests for a specific module, run::
- tox -eall-plugin -- patrole_tempest_plugin.tests.api.compute
+ $ 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: ::
@@ -34,3 +45,17 @@
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/plugin.py b/patrole_tempest_plugin/plugin.py
index cfe5c0a..28ce12c 100644
--- a/patrole_tempest_plugin/plugin.py
+++ b/patrole_tempest_plugin/plugin.py
@@ -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_rule_validation.py b/patrole_tempest_plugin/rbac_rule_validation.py
index c63ef90..ba04a30 100644
--- a/patrole_tempest_plugin/rbac_rule_validation.py
+++ b/patrole_tempest_plugin/rbac_rule_validation.py
@@ -81,7 +81,7 @@
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 = CONF.rbac.rbac_test_role == CONF.identity.admin_role
+ allowed = test_obj.rbac_utils.is_admin
else:
allowed = _is_authorized(test_obj, service, rule,
extra_target_data)
diff --git a/patrole_tempest_plugin/rbac_utils.py b/patrole_tempest_plugin/rbac_utils.py
index fe2d99f..3bb2cbd 100644
--- a/patrole_tempest_plugin/rbac_utils.py
+++ b/patrole_tempest_plugin/rbac_utils.py
@@ -162,3 +162,11 @@
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
diff --git a/patrole_tempest_plugin/tests/api/compute/test_admin_password_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_admin_password_rbac.py
index a0e46a6..38b5f1a 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_admin_password_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_admin_password_rbac.py
@@ -13,6 +13,9 @@
# 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 import decorators
@@ -20,28 +23,22 @@
from patrole_tempest_plugin import rbac_rule_validation
from patrole_tempest_plugin.tests.api.compute import rbac_base
-
CONF = config.CONF
class AdminPasswordRbacTest(rbac_base.BaseV2ComputeRbacTest):
- @classmethod
- def skip_checks(cls):
- super(AdminPasswordRbacTest, cls).skip_checks()
- if not CONF.compute_feature_enabled.change_password:
- raise cls.skipException('Change password not available.')
-
- @classmethod
- def resource_setup(cls):
- super(AdminPasswordRbacTest, 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")
+ service="nova",
+ rule="os_compute_api:os-admin-password")
@decorators.idempotent_id('908a7d59-3a66-441c-94cf-38e57ed14956')
def test_change_server_password(self):
+ server_id = self.create_test_server(wait_until='ACTIVE')['id']
+
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
self.servers_client.change_password(
- self.server_id,
- adminPass=data_utils.rand_password())
+ server_id, adminPass=data_utils.rand_password())
+ waiters.wait_for_server_status(
+ self.os_admin.servers_client, server_id, 'ACTIVE')
diff --git a/patrole_tempest_plugin/tests/api/compute/test_admin_server_actions_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_admin_server_actions_rbac.py
deleted file mode 100644
index 37fad18..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_admin_server_actions_rbac.py
+++ /dev/null
@@ -1,65 +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.compute import rbac_base
-
-CONF = config.CONF
-
-
-class AdminServerActionsRbacTest(rbac_base.BaseV2ComputeRbacTest):
-
- @classmethod
- def skip_checks(cls):
- super(AdminServerActionsRbacTest, cls).skip_checks()
- if not test.is_extension_enabled('os-admin-actions', 'compute'):
- msg = "%s skipped as os-admin-actions not enabled." % cls.__name__
- raise cls.skipException(msg)
-
- @classmethod
- def resource_setup(cls):
- super(AdminServerActionsRbacTest, 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, 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')
-
- @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, toggle_rbac_role=True)
- self.servers_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, toggle_rbac_role=True)
- self.servers_client.reset_network(self.server_id)
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 ebeab76..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_deferred_delete_rbac.py
+++ /dev/null
@@ -1,47 +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 DeferredDeleteRbacTest(rbac_base.BaseV2ComputeRbacTest):
-
- @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')
-
- @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):
- self.rbac_utils.switch_role(self, toggle_rbac_role=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.servers_client.force_delete_server(self.server['id'])
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 3d66f2e..cdabf6f 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py
@@ -178,3 +178,33 @@
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_lock_server_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_lock_server_rbac.py
new file mode 100644
index 0000000..1daf305
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_lock_server_rbac.py
@@ -0,0 +1,58 @@
+# 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 as base
+
+
+class ComputeLockServersRbacTest(base.BaseV2ComputeRbacTest):
+
+ @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):
+ server = self.create_test_server(wait_until='ACTIVE')
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.servers_client.lock_server(server['id'])
+ self.addCleanup(self.servers_client.unlock_server, 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):
+ server = self.create_test_server(wait_until='ACTIVE')
+ self.servers_client.lock_server(server['id'])
+ self.addCleanup(self.servers_client.unlock_server, server['id'])
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.servers_client.unlock_server(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):
+ server = self.create_test_server(wait_until='ACTIVE')
+ # 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(server['id'])
+ self.addCleanup(self.servers_client.unlock_server, server['id'])
+
+ self.rbac_utils.switch_role(self, toggle_rbac_role=True)
+ self.servers_client.unlock_server(server['id'])
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 a0a021f..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_rescue_rbac.py
+++ /dev/null
@@ -1,43 +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 RescueRbacTest(rbac_base.BaseV2ComputeRbacTest):
-
- @classmethod
- def skip_checks(cls):
- super(RescueRbacTest, cls).skip_checks()
- if not test.is_extension_enabled('os-rescue', 'compute'):
- msg = "%s skipped as os-rescue not enabled." % cls.__name__
- raise cls.skipException(msg)
-
- @classmethod
- def resource_setup(cls):
- super(RescueRbacTest, cls).resource_setup()
- cls.server = cls.create_test_server(wait_until='ACTIVE')
-
- @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, toggle_rbac_role=True)
- self.servers_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 f45632e..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,10 +22,54 @@
class SecurityGroupsRbacTest(rbac_base.BaseV2ComputeRbacTest):
+ # 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):
+ 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_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 f6359b4..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_server_diagnostics_rbac.py
+++ /dev/null
@@ -1,44 +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 ServerDiagnosticsRbacTest(rbac_base.BaseV2ComputeRbacTest):
-
- @classmethod
- def skip_checks(cls):
- super(ServerDiagnosticsRbacTest, cls).skip_checks()
- if not test.is_extension_enabled('os-server-diagnostics', 'compute'):
- msg = ("%s skipped as os-server-diagnostics not "
- "enabled." % cls.__name__)
- raise cls.skipException(msg)
-
- @classmethod
- def resource_setup(cls):
- super(ServerDiagnosticsRbacTest, cls).resource_setup()
- cls.server = cls.create_test_server(wait_until='ACTIVE')
-
- @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, toggle_rbac_role=True)
- self.servers_client.show_server_diagnostics(self.server['id'])
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..cb826e3
--- /dev/null
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py
@@ -0,0 +1,154 @@
+# 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 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
+
+
+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)
+
+ @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)
+
+ @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 test 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)
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 7826268..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_server_password_rbac.py
+++ /dev/null
@@ -1,52 +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 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(wait_until="ACTIVE")
-
- @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):
- self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- self.servers_client.delete_password(self.server['id'])
-
- @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):
- self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- self.servers_client.show_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
index 3613a25..3a2b5ec 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py
@@ -17,11 +17,11 @@
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
@@ -36,14 +36,14 @@
@classmethod
def setup_clients(cls):
super(ComputeServersRbacTest, cls).setup_clients()
- cls.client = cls.servers_client
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'
@@ -66,7 +66,8 @@
self.__class__.__name__ + '-network')
network = self.networks_client.create_network(
- **{'name': network_name})['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')
@@ -75,11 +76,7 @@
network_id=network['id'],
cidr=CONF.network.project_network_cidr,
ip_version=4)['subnet']
-
- self.addCleanup(test_utils.call_and_ignore_notfound_exc,
- self.networks_client.delete_network, network['id'])
- self.addCleanup(test_utils.call_and_ignore_notfound_exc,
- self.subnets_client.delete_subnet, subnet['id'])
+ self.addCleanup(self.subnets_client.delete_subnet, subnet['id'])
return network
@@ -127,12 +124,14 @@
# 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 = hosts[0].keys()[0]
+ 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")
@@ -141,20 +140,18 @@
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()
- network_id = {'uuid': network['id']}
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])
- # The network resources created is for this test case only. We will
- # clean them up after this test case. In order to do that,
- # we need to clean up the server first.
self.addCleanup(waiters.wait_for_server_termination,
self.servers_client, server['id'])
self.addCleanup(self.servers_client.delete_server, server['id'])
@@ -174,13 +171,80 @@
rule="os_compute_api:servers:update")
@decorators.idempotent_id('077b17cb-5621-43b9-8adf-5725f0d7a863')
def test_update_server(self):
- server = self.create_test_server(wait_until='ACTIVE')
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(server['id'], name=new_name)
+ 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_usage_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_usage_rbac.py
deleted file mode 100644
index 777af29..0000000
--- a/patrole_tempest_plugin/tests/api/compute/test_server_usage_rbac.py
+++ /dev/null
@@ -1,43 +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 ServerUsageRbacTest(rbac_base.BaseV2ComputeRbacTest):
-
- @classmethod
- def skip_checks(cls):
- super(ServerUsageRbacTest, cls).skip_checks()
- if not test.is_extension_enabled('OS-SRV-USG', 'compute'):
- msg = "%s skipped as OS-SRV-USG not enabled." % cls.__name__
- raise cls.skipException(msg)
-
- @classmethod
- def resource_setup(cls):
- super(ServerUsageRbacTest, cls).resource_setup()
- cls.server = cls.create_test_server(wait_until='ACTIVE')
-
- @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, toggle_rbac_role=True)
- self.servers_client.show_server(self.server['id'])
diff --git a/patrole_tempest_plugin/tests/api/compute/test_volume_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_volume_rbac.py
index a2ae8e5..23dbf1b 100644
--- a/patrole_tempest_plugin/tests/api/compute/test_volume_rbac.py
+++ b/patrole_tempest_plugin/tests/api/compute/test_volume_rbac.py
@@ -14,6 +14,7 @@
# 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
@@ -24,15 +25,27 @@
CONF = config.CONF
-class VolumeV235RbacTest(rbac_base.BaseV2ComputeRbacTest):
+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
- min_microversion = '2.10'
+ # 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.snapshots_extensions_client.wait_for_resource_deletion(
+ snapshot_id)
+
@decorators.idempotent_id('2402013e-a624-43e3-9518-44a5d1dbb32d')
@rbac_rule_validation.action(
service="nova",
@@ -61,9 +74,8 @@
service="nova",
rule="os_compute_api:os-volumes")
def test_show_volume(self):
- volume = self.create_volume()
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- self.volumes_extensions_client.show_volume(volume['id'])
+ self.volumes_extensions_client.show_volume(self.volume['id'])
@decorators.idempotent_id('6e7870f2-1bb2-4b58-96f8-6782071ef327')
@rbac_rule_validation.action(
@@ -73,3 +85,47 @@
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
index 6cb3d2f..a053614 100644
--- a/patrole_tempest_plugin/tests/api/identity/rbac_base.py
+++ b/patrole_tempest_plugin/tests/api/identity/rbac_base.py
@@ -183,6 +183,7 @@
def resource_setup(cls):
super(BaseIdentityV2AdminRbacTest, cls).resource_setup()
cls.tenants = []
+ cls.tokens = []
@classmethod
def resource_cleanup(cls):
@@ -190,6 +191,10 @@
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
@@ -203,6 +208,15 @@
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):
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 9a4363d..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
@@ -112,8 +112,7 @@
admin-scoped tenants, raise ``RbacActionFailed`` exception otherwise.
"""
tenants_client = self.os_admin.tenants_client if \
- CONF.identity.admin_role == CONF.rbac.rbac_test_role else \
- self.os_primary.tenants_client
+ 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
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/image/v2/test_image_namespace_objects_rbac.py b/patrole_tempest_plugin/tests/api/image/test_image_namespace_objects_rbac.py
similarity index 100%
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
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 100%
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
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 100%
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
diff --git a/patrole_tempest_plugin/tests/api/image/v2/test_image_namespace_tags_rbac.py b/patrole_tempest_plugin/tests/api/image/test_image_namespace_tags_rbac.py
similarity index 100%
rename from patrole_tempest_plugin/tests/api/image/v2/test_image_namespace_tags_rbac.py
rename to patrole_tempest_plugin/tests/api/image/test_image_namespace_tags_rbac.py
diff --git a/patrole_tempest_plugin/tests/api/image/v2/test_image_resource_types_rbac.py b/patrole_tempest_plugin/tests/api/image/test_image_resource_types_rbac.py
similarity index 100%
rename from patrole_tempest_plugin/tests/api/image/v2/test_image_resource_types_rbac.py
rename to patrole_tempest_plugin/tests/api/image/test_image_resource_types_rbac.py
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 100%
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
diff --git a/patrole_tempest_plugin/tests/api/image/v2/test_images_rbac.py b/patrole_tempest_plugin/tests/api/image/test_images_rbac.py
similarity index 93%
rename from patrole_tempest_plugin/tests/api/image/v2/test_images_rbac.py
rename to patrole_tempest_plugin/tests/api/image/test_images_rbac.py
index 5b7c823..78ba9e5 100644
--- a/patrole_tempest_plugin/tests/api/image/v2/test_images_rbac.py
+++ b/patrole_tempest_plugin/tests/api/image/test_images_rbac.py
@@ -13,7 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
-from six import moves
+import six
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
@@ -38,7 +38,7 @@
return image
def _upload_image(self, image_id):
- image_file = moves.cStringIO(data_utils.random_bytes())
+ image_file = six.BytesIO(data_utils.random_bytes())
return self.client.store_image_file(image_id, image_file)
@rbac_rule_validation.action(service="glance",
@@ -184,6 +184,18 @@
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')
diff --git a/patrole_tempest_plugin/tests/api/image/v1/__init__.py b/patrole_tempest_plugin/tests/api/image/v1/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/patrole_tempest_plugin/tests/api/image/v1/__init__.py
+++ /dev/null
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 8015277..0000000
--- a/patrole_tempest_plugin/tests/api/image/v1/test_images_member_rbac.py
+++ /dev/null
@@ -1,79 +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_primary.image_member_client
-
- @classmethod
- def resource_setup(cls):
- super(ImagesMemberRbacTest, cls).resource_setup()
- cls.alt_tenant_id = cls.os_alt.image_member_client.tenant_id
-
- @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, toggle_rbac_role=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, 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_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, toggle_rbac_role=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 7010baa..0000000
--- a/patrole_tempest_plugin/tests/api/image/v1/test_images_rbac.py
+++ /dev/null
@@ -1,151 +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):
-
- @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(self.__class__.__name__ + '-Image')
- self.rbac_utils.switch_role(self, toggle_rbac_role=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(self.__class__.__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, toggle_rbac_role=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(self.__class__.__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, toggle_rbac_role=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(self.__class__.__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, toggle_rbac_role=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, toggle_rbac_role=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(self.__class__.__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, toggle_rbac_role=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(self.__class__.__name__ + '-Image')
- properties = {'prop1': 'val1'}
- self.rbac_utils.switch_role(self, toggle_rbac_role=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/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_networks_rbac.py b/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py
index 8208fde..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,68 +27,37 @@
CONF = config.CONF
-class RbacNetworksTest(base.BaseNetworkRbacTest):
+class NetworksRbacTest(base.BaseNetworkRbacTest):
@classmethod
def resource_setup(cls):
- super(RbacNetworksTest, cls).resource_setup()
-
- network_name = data_utils.rand_name(
- cls.__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):
+ provider_segmentation_id=None,
+ **kwargs):
+ if router_external is not None:
+ kwargs['router:external'] = router_external
+ if router_private is not None:
+ kwargs['router:private'] = router_private
+ if provider_network_type is not None:
+ kwargs['provider:network_type'] = provider_network_type
+ if provider_physical_network is not None:
+ kwargs['provider:physical_network'] = provider_physical_network
+ if provider_segmentation_id is not None:
+ kwargs['provider:segmentation_id'] = provider_segmentation_id
network_name = data_utils.rand_name(
- self.__class__.__name__ + '-test-network-')
- post_body = {'name': network_name}
-
- if shared is not None:
- post_body['shared'] = shared
- if router_external is not None:
- post_body['router:external'] = router_external
- if router_private is not None:
- post_body['router:private'] = router_private
- if provider_network_type is not None:
- post_body['provider:network_type'] = provider_network_type
- if provider_physical_network is not None:
- post_body['provider:physical_network'] = provider_physical_network
- if provider_segmentation_id is not None:
- post_body['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'])
+ self.__class__.__name__ + '-Network')
+ network = self.create_network(network_name=network_name, **kwargs)
return network
def _update_network(self,
@@ -97,30 +66,24 @@
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
@rbac_rule_validation.action(service="neutron",
@@ -147,6 +110,7 @@
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')
@@ -159,6 +123,7 @@
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')
@@ -171,6 +136,7 @@
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")
@@ -194,13 +160,11 @@
RBAC test for the neutron update_network policy
"""
- self.rbac_utils.switch_role(self, toggle_rbac_role=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")
@@ -212,13 +176,10 @@
RBAC test for the neutron update_network:shared policy
"""
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- updated_network = self._update_network(shared_network=True)
- self.assertEqual(updated_network['shared'], 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')
@@ -242,9 +203,9 @@
RBAC test for the neutron get_network policy
"""
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- # show a network that has been created during class setup
- self.networks_client.show_network(self.admin_network['id'])
+ 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')
@@ -254,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, toggle_rbac_role=True)
- self.networks_client.show_network(self.admin_network['id'],
- **post_body)
+ 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')
@@ -269,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, toggle_rbac_role=True)
- body = self.networks_client.show_network(self.admin_network['id'],
- **post_body)
- showed_net = body['network']
+ 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')
@@ -288,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, toggle_rbac_role=True)
- body = self.networks_client.show_network(self.admin_network['id'],
- **post_body)
- showed_net = body['network']
+ 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')
@@ -307,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, toggle_rbac_role=True)
- body = self.networks_client.show_network(self.admin_network['id'],
- **post_body)
- showed_net = body['network']
+ 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")
@@ -343,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, toggle_rbac_role=True)
- # Create a subnet
self.create_subnet(network, enable_dhcp=False)
@rbac_rule_validation.action(service="neutron",
@@ -359,7 +318,7 @@
RBAC test for the neutron get_subnet policy
"""
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- self.subnets_client.show_subnet(self.admin_subnet['id'])
+ self.subnets_client.show_subnet(self.subnet['id'])
@rbac_rule_validation.action(service="neutron",
rule="update_subnet")
@@ -370,9 +329,12 @@
RBAC test for the neutron update_subnet policy
"""
+ 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.admin_subnet['id'],
- name="New_subnet")
+ self.subnets_client.update_subnet(self.subnet['id'],
+ name=updated_name)
@rbac_rule_validation.action(service="neutron",
rule="delete_subnet")
@@ -383,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, toggle_rbac_role=True)
- # Delete the subnet
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 33e0d2e..cec860c 100644
--- a/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py
+++ b/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py
@@ -16,20 +16,17 @@
import netaddr
-from oslo_log import log
-
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 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):
@@ -37,36 +34,28 @@
@classmethod
def resource_setup(cls):
super(PortsRbacTest, cls).resource_setup()
+ # Create a network and subnet.
cls.network = cls.create_network()
-
- # Create a subnet by admin user
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'])
- # Create a port by admin user
- body = cls.ports_client.create_port(network_id=cls.network['id'])
- cls.port = body['port']
- cls.ports.append(cls.port)
+ 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']
- 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 _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")
@@ -74,51 +63,35 @@
def test_create_port(self):
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- post_body = {'network_id': self.network['id']}
- self._create_port(**post_body)
+ 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.network['id'],
+ post_body = {'network': self.network,
'binding:host_id': "rbac_test_host"}
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- self._create_port(**post_body)
+ 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 unused ip address.
- ip_list = net_utils.get_unused_ip_addresses(self.ports_client,
- self.subnets_client,
- self.network['id'],
- self.subnet['id'],
- 1)
- fixed_ips = [{'ip_address': ip_list[0]},
- {'subnet_id': self.subnet['id']}]
-
- post_body = {'network_id': self.network['id'],
- '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_id': self.network['id'],
- 'mac_address': data_utils.rand_mac_address()}
-
- self.rbac_utils.switch_role(self, toggle_rbac_role=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.network['id'],
+ post_body = {'network': self.network,
'binding:profile': binding_profile}
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- self._create_port(**post_body)
+ 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")
@@ -141,11 +140,11 @@
allowed_address_pairs = [{'ip_address': self.port_ip_address,
'mac_address': self.port_mac_address}]
- post_body = {'network_id': self.network['id'],
+ post_body = {'network': self.network,
'allowed_address_pairs': allowed_address_pairs}
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- self._create_port(**post_body)
+ self.create_port(**post_body)
@rbac_rule_validation.action(service="neutron",
rule="get_port",
@@ -155,6 +154,7 @@
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
self.ports_client.show_port(self.port['id'])
+ @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')
@@ -172,6 +172,7 @@
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,6 +190,7 @@
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')
@@ -196,12 +198,11 @@
# Verify specific fields of a port
fields = ['binding:host_id']
- post_body = {'network_id': self.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)
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
-
retrieved_port = self.ports_client.show_port(
port['id'], fields=fields)['port']
@@ -209,6 +210,7 @@
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')
@@ -217,12 +219,11 @@
# Verify specific fields of a port
fields = ['binding:profile']
binding_profile = {"foo": "1"}
- post_body = {'network_id': self.network['id'],
+ post_body = {'network': self.network,
'binding:profile': binding_profile}
- port = self._create_port(**post_body)
+ port = self.create_port(**post_body)
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
-
retrieved_port = self.ports_client.show_port(
port['id'], fields=fields)['port']
@@ -234,21 +235,34 @@
rule="update_port")
@decorators.idempotent_id('afa80981-3c59-42fd-9531-3bcb2cd03711')
def test_update_port(self):
-
- port = self.create_port(self.network)
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- self.ports_client.update_port(port['id'], admin_state_up=False)
+ 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)
+
+ @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.network)
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")
@@ -256,39 +270,31 @@
def test_update_port_fixed_ips(self):
# Pick an ip address within the allocation_pools range.
- post_body = {'network_id': self.network['id']}
- port = self._create_port(**post_body)
+ post_body = {'network': self.network}
+ port = self.create_port(**post_body)
- # 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)
+ 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)
+ 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):
-
- port = self.create_port(self.network)
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- self.ports_client.update_port(port['id'],
- security_groups=[])
+ self.ports_client.update_port(self.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.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'}
@@ -296,16 +302,17 @@
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.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'],
@@ -319,17 +326,12 @@
@decorators.idempotent_id('729c2151-bb49-4f4f-9d58-3ed8819b7582')
def test_update_port_allowed_address_pairs(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)
+ ip_list = self._get_unused_ip_address()
# Update allowed address pair attribute of port
address_pairs = [{'ip_address': ip_list[0],
'mac_address': data_utils.rand_mac_address()}]
- post_body = {'network_id': self.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, toggle_rbac_role=True)
self.ports_client.update_port(port['id'],
@@ -341,6 +343,6 @@
@decorators.idempotent_id('1cf8e582-bc09-46cb-b32a-82bf991ad56f')
def test_delete_port(self):
- port = self._create_port(network_id=self.network['id'])
+ 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_security_groups_rbac.py b/patrole_tempest_plugin/tests/api/network/test_security_groups_rbac.py
index 20f4bea..2ccc688 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
@@ -18,6 +18,7 @@
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.network import rbac_base as base
@@ -28,6 +29,13 @@
class SecGroupRbacTest(base.BaseNetworkRbacTest):
@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(cls.__name__ + '-secgroup')
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 e7682df..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,7 +13,6 @@
# 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
@@ -24,7 +23,6 @@
from patrole_tempest_plugin.tests.api.network import rbac_base as base
CONF = config.CONF
-LOG = log.getLogger(__name__)
class SubnetPoolsRbacTest(base.BaseNetworkRbacTest):
@@ -36,14 +34,14 @@
msg = "subnet_allocation extension not enabled."
raise cls.skipException(msg)
- 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']
@@ -102,6 +100,28 @@
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="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)
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 b490ebe..f27b8a8 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
@@ -35,10 +35,7 @@
@classmethod
def setup_clients(cls):
super(VolumesActionsRbacTest, cls).setup_clients()
- if CONF.image_feature_enabled.api_v1:
- cls.image_client = cls.os_primary.image_client
- elif CONF.image_feature_enabled.api_v2:
- cls.image_client = cls.os_primary.image_client_v2
+ cls.image_client = cls.os_primary.image_client_v2
@classmethod
def resource_setup(cls):
@@ -52,18 +49,24 @@
self.servers_client.delete_server, server['id'])
return server
- def _attach_volume(self, 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_resource_status(
- self.volumes_client, self.volume['id'], 'in-use')
- self.addCleanup(self._detach_volume)
+ self.volumes_client, volume_id, 'in-use')
+ self.addCleanup(self._detach_volume, volume_id)
- def _detach_volume(self):
- self.volumes_client.detach_volume(self.volume['id'])
+ 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.volumes_client, self.volume['id'], 'available')
+ self.volumes_client, volume_id, 'available')
@test.services('compute')
@rbac_rule_validation.action(service="cinder", rule="volume:attach")
@@ -186,19 +189,21 @@
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)
+ self._attach_volume(server, volume['id'])
attachment = self.volumes_client.show_volume(
- self.volume['id'])['volume']['attachments'][0]
+ volume['id'])['volume']['attachments'][0]
# Reset volume's status to error.
- self.volumes_client.reset_volume_status(self.volume['id'],
- status='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(
- self.volume['id'], connector=None,
+ 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):
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 9e93658..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
@@ -25,14 +25,6 @@
class VolumeMetadataRbacTest(rbac_base.BaseVolumeRbacTest):
@classmethod
- def setup_clients(cls):
- super(VolumeMetadataRbacTest, cls).setup_clients()
- if CONF.image_feature_enabled.api_v1:
- cls.image_client = cls.os_primary.image_client
- elif CONF.image_feature_enabled.api_v2:
- cls.image_client = cls.os_primary.image_client_v2
-
- @classmethod
def resource_setup(cls):
super(VolumeMetadataRbacTest, cls).resource_setup()
cls.volume = cls.create_volume()
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 c39a376..2861531 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
@@ -31,28 +31,16 @@
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")
- @classmethod
- def resource_setup(cls):
- super(VolumesBackupsRbacTest, cls).resource_setup()
- cls.volume = cls.create_volume()
-
- 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(
- test_utils.call_and_ignore_notfound_exc,
- self.backups_client.delete_backup, backup['id'])
- waiters.wait_for_volume_resource_status(
- self.backups_client, backup['id'], 'available')
- return backup
-
def _decode_url(self, backup_url):
return json.loads(base64.decode_as_text(backup_url))
@@ -71,16 +59,14 @@
@decorators.idempotent_id('6887ec94-0bcf-4ab7-b30f-3808a4b5a2a5')
def test_volume_backup_create(self):
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
- self._create_backup(volume_id=self.volume['id'])
+ 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
- backup = self._create_backup(volume_id=self.volume['id'])
- # Get a given backup
+ backup = self.create_backup(volume_id=self.volume['id'])
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
self.backups_client.show_backup(backup['id'])
@@ -96,9 +82,7 @@
rule="backup:restore")
@decorators.idempotent_id('9c794bf9-2446-4f41-8fe0-80b71e757f9d')
def test_volume_backup_restore(self):
- # Create a temp backup
- backup = self._create_backup(volume_id=self.volume['id'])
- # Restore backup
+ backup = self.create_backup(volume_id=self.volume['id'])
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(
@@ -109,11 +93,19 @@
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'])
+ # 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)
- # Delete backup
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"])
@@ -121,10 +113,7 @@
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
+ 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']
@@ -133,16 +122,13 @@
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
+ 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})
- # Import the temp backup
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
import_backup = self.backups_client.import_backup(
backup_service=export_backup['backup_service'],
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 34889cd..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
@@ -75,6 +76,9 @@
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")
@@ -95,6 +99,8 @@
self.rbac_utils.switch_role(self, toggle_rbac_role=True)
# Delete the snapshot
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/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/add-extra-hypervisor-tests-9374e5fcdb0266e2.yaml b/releasenotes/notes/add-extra-hypervisor-tests-9374e5fcdb0266e2.yaml
index 0c46435..4cb7b4a 100644
--- a/releasenotes/notes/add-extra-hypervisor-tests-9374e5fcdb0266e2.yaml
+++ b/releasenotes/notes/add-extra-hypervisor-tests-9374e5fcdb0266e2.yaml
@@ -4,8 +4,9 @@
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
+
+ * show_hypervisor
+ * list_servers_on_hypervisor
+ * show_hypervisor_statistics
+ * show_hypervisor_uptime
+ * search_hypervisor
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/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/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/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/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/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/server-metadata-rbac-tests-2404b5d13c492b62.yaml b/releasenotes/notes/server-metadata-rbac-tests-2404b5d13c492b62.yaml
index b8eb281..1bb63c9 100644
--- a/releasenotes/notes/server-metadata-rbac-tests-2404b5d13c492b62.yaml
+++ b/releasenotes/notes/server-metadata-rbac-tests-2404b5d13c492b62.yaml
@@ -3,9 +3,10 @@
- |
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
+
+ * 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/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/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/source/conf.py b/releasenotes/source/conf.py
index d86d91c..c8439f6 100644
--- a/releasenotes/source/conf.py
+++ b/releasenotes/source/conf.py
@@ -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.
@@ -256,7 +256,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/setup.cfg b/setup.cfg
index d8c9505..6fd4b8a 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,7 +17,6 @@
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]