diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index 4b521c72..00000000 --- a/.coveragerc +++ /dev/null @@ -1,6 +0,0 @@ -[run] -branch = True -source = patrole - -[report] -ignore_errors = True diff --git a/.gitignore b/.gitignore deleted file mode 100644 index cda7cbe8..00000000 --- a/.gitignore +++ /dev/null @@ -1,65 +0,0 @@ -*.py[cod] - -# C extensions -*.so - -# Packages -*.egg* -*.egg-info -dist -build -eggs -parts -bin -var -sdist -develop-eggs -.installed.cfg -lib -lib64 - -# Installer logs -pip-log.txt - -# Unit test / coverage reports -cover/ -.coverage* -!.coveragerc -.tox -nosetests.xml -.testrepository -.venv - -# Translations -*.mo - -# Mr Developer -.mr.developer.cfg -.project -.pydevproject - -# Complexity -output/*.html -output/*/index.html - -# Sphinx -doc/build -doc/source/_static/patrole.conf.sample -doc/source/framework/code/ - -# pbr generates these -AUTHORS -ChangeLog - -# Editors -*~ -.*.swp -.*sw? -*.idea - -# Files created by releasenotes build -releasenotes/build - -# Misc -.stestr -*.log diff --git a/.mailmap b/.mailmap deleted file mode 100644 index 47612b35..00000000 --- a/.mailmap +++ /dev/null @@ -1,5 +0,0 @@ -# Format is: -# -# -Felipe Monteiro -Felipe Monteiro diff --git a/.stestr.conf b/.stestr.conf deleted file mode 100644 index 76a6ac56..00000000 --- a/.stestr.conf +++ /dev/null @@ -1,3 +0,0 @@ -[DEFAULT] -test_path=./patrole_tempest_plugin/tests/unit -group_regex=([^\.]*\.)* diff --git a/.zuul.yaml b/.zuul.yaml deleted file mode 100644 index 01f3f60d..00000000 --- a/.zuul.yaml +++ /dev/null @@ -1,246 +0,0 @@ -- job: - name: patrole-base - parent: devstack-tempest - description: | - Patrole base job for admin,member and reader roles. This job executes RBAC tests - for all the "core" services that Tempest covers, excluding Swift. - required-projects: - - name: opendev.org/openstack/tempest - - name: opendev.org/openstack/patrole - timeout: 7800 - roles: - - zuul: opendev.org/openstack/devstack - # Define common irrelevant files to use everywhere else - irrelevant-files: &patrole-irrelevant-files - - ^(test-|)requirements.txt$ - - ^.*\.rst$ - - ^doc/.* - - ^etc/.*$ - - ^patrole_tempest_plugin/tests/unit/.*$ - - ^patrole_tempest_plugin/hacking/.*$ - - ^releasenotes/.* - - ^setup.cfg$ - vars: - tempest_plugins: - - patrole - devstack_plugins: - patrole: https://opendev.org/openstack/patrole.git - devstack_services: - tempest: true - neutron: true - neutron-trunk: true - tempest_test_regex: (?!.*\[.*\bslow\b.*\])(^patrole_tempest_plugin\.tests\.api) - # run the tempest all tox environment target with patrole regex - tox_envlist: all - # allows job to use the tempest version installed with devstack instead of pypi - # according to the requirements.txt - tox_extra_args: --sitepackages - -- job: - name: patrole-base-multinode - parent: tempest-multinode-full-py3 - description: |- - Patrole base job for multinode and "slow" tests where "slow" tests include: - - * Tests that take more than ~30 seconds to run. - * Tests that experience spurious failures related to servers, volumes, - backups and similar resources failing to build. - timeout: 7800 - branches: - - master - required-projects: - - opendev.org/openstack/devstack-gate - - opendev.org/openstack/tempest - - opendev.org/openstack/patrole - irrelevant-files: *patrole-irrelevant-files - vars: - tempest_plugins: - - patrole - devstack_plugins: - patrole: https://opendev.org/openstack/patrole.git - devstack_services: - tempest: true - neutron: true - tempest_concurrency: 1 - tempest_test_regex: (?=.*\[.*\bslow\b.*\])(^patrole_tempest_plugin\.tests\.api) - tox_envlist: all - tox_extra_args: --sitepackages - -- job: - name: patrole-admin - parent: patrole-base - description: Patrole job for admin role. - vars: - devstack_localrc: - RBAC_TEST_ROLES: admin - # https://storyboard.openstack.org/#!/story/2009048 - tempest_exclude_regex: patrole_tempest_plugin.tests.api.volume.test_volume_actions_rbac.VolumesActionsV3RbacTest.test_force_detach_volume_from_instance - -- job: - name: patrole-member - parent: patrole-base - description: Patrole job for member role. - # This currently works from stable/pike onward. - branches: ^(?!stable/ocata).*$ - vars: - devstack_localrc: - RBAC_TEST_ROLES: member - # https://storyboard.openstack.org/#!/story/2009216 - tempest_exclude_regex: patrole_tempest_plugin.tests.api.volume.test_volume_types_extra_specs_rbac.VolumeTypesExtraSpecsRbacTest.test_show_volume_type_extra_specs - -- job: - name: patrole-reader - parent: patrole-base - description: Patrole job for reader role. - # This currently works from stable/stein onward. - branches: ^(?!stable/(ocata|pike|queens|rocky)).*$ - vars: - devstack_localrc: - RBAC_TEST_ROLES: reader - # https://storyboard.openstack.org/#!/story/2009216 - tempest_exclude_regex: patrole_tempest_plugin.tests.api.volume.test_volume_types_extra_specs_rbac.VolumeTypesExtraSpecsRbacTest.test_show_volume_type_extra_specs - -- job: - name: patrole-member-wallaby - parent: patrole-member - override-checkout: stable/wallaby - -- job: - name: patrole-member-victoria - parent: patrole-member - override-checkout: stable/victoria - -- job: - name: patrole-member-ussuri - parent: patrole-member - nodeset: openstack-single-node-bionic - override-checkout: stable/ussuri - vars: - # https://storyboard.openstack.org/#!/story/2009048 - tempest_exclude_regex: patrole_tempest_plugin.tests.api.volume.test_volume_actions_rbac.VolumesActionsV3RbacTest.test_force_detach_volume_from_instance - -- job: - name: patrole-multinode-admin - parent: patrole-base-multinode - voting: false - vars: - devstack_localrc: - RBAC_TEST_ROLES: admin - -- job: - name: patrole-multinode-member - parent: patrole-base-multinode - voting: false - vars: - devstack_localrc: - RBAC_TEST_ROLES: member - -- job: - name: patrole-multinode-reader - parent: patrole-base-multinode - voting: false - vars: - devstack_localrc: - RBAC_TEST_ROLES: reader - -- job: - name: patrole-py35-member - parent: patrole-base - description: Patrole py35 job for member role. - vars: - devstack_localrc: - # Use member for py35 because arguably negative testing is more - # important than admin, which is already covered by patrole-admin job. - RBAC_TEST_ROLES: member - USE_PYTHON3: true - devstack_services: - s-account: false - s-container: false - s-object: false - s-proxy: false - # Without Swift, c-bak cannot run (in the gate at least). - c-bak: false - -- job: - name: patrole-extension-base - parent: patrole-base - description: | - Patrole plugin job for admin and member roles which runs RBAC tests for - neutron-tempest-plugin APIs (if the plugin is installed). - - Covers Neutron extension functionality only. Should not be used for - supporting Neutron plugins like fwaas. - required-projects: - - name: opendev.org/openstack/tempest - - name: opendev.org/openstack/patrole - - name: opendev.org/openstack/neutron-tempest-plugin - vars: - tempest_plugins: - - patrole - - neutron-tempest-plugin - devstack_plugins: - neutron: https://opendev.org/openstack/neutron.git - patrole: https://opendev.org/openstack/patrole.git - neutron-tempest-plugin: https://opendev.org/openstack/neutron-tempest-plugin.git - devstack_services: - tempest: true - neutron: true - neutron-segments: true - neutron-qos: true - tempest_test_regex: (?=.*ExtRbacTest)(^patrole_tempest_plugin\.tests\.api) - -- job: - name: patrole-extension-admin - parent: patrole-extension-base - voting: false - vars: - devstack_localrc: - RBAC_TEST_ROLES: admin - -- job: - name: patrole-extension-member - parent: patrole-extension-base - voting: false - vars: - devstack_localrc: - RBAC_TEST_ROLES: member - -- job: - name: patrole-extension-reader - parent: patrole-extension-base - voting: false - vars: - devstack_localrc: - RBAC_TEST_ROLES: reader - -- project: - templates: - - openstack-cover-jobs - - openstack-python3-yoga-jobs - - check-requirements - - publish-openstack-docs-pti - - release-notes-jobs-python3 - check: - jobs: - - patrole-admin - - patrole-member - - patrole-reader - - patrole-member-wallaby - - patrole-member-victoria - - patrole-member-ussuri - - patrole-multinode-admin - - patrole-multinode-member - - patrole-multinode-reader - - patrole-extension-admin - - patrole-extension-member - - patrole-extension-reader - gate: - jobs: - - patrole-admin - - patrole-member - - patrole-reader - periodic-stable: - jobs: - - patrole-member-wallaby - - patrole-member-victoria - - patrole-member-ussuri diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst deleted file mode 100644 index a138d666..00000000 --- a/CONTRIBUTING.rst +++ /dev/null @@ -1,19 +0,0 @@ -The source repository for this project can be found at: - - https://opendev.org/openstack/patrole - -Pull requests submitted through GitHub are not monitored. - -To start contributing to OpenStack, follow the steps in the contribution guide -to set up and use Gerrit: - - https://docs.openstack.org/contributors/code-and-documentation/quick-start.html - -Bugs should be filed on Storyboard: - - https://storyboard.openstack.org/#!/project/1040 - -For more specific information about contributing to this repository, see the -Patrole contributor guide: - - https://docs.openstack.org/patrole/latest/contributor/contributing.html diff --git a/HACKING.rst b/HACKING.rst deleted file mode 100644 index 5fb3faad..00000000 --- a/HACKING.rst +++ /dev/null @@ -1,170 +0,0 @@ -Patrole Coding Guide -==================== - -- Step 1: Read the OpenStack Style Commandments: ``__ -- Step 2: Review Tempest's Style Commandments: ``__ -- Step 3: Read on - -Patrole Specific Commandments ------------------------------- - -Patrole borrows the following commandments from Tempest; refer to -`Tempest's Commandments `__ -for more information: - -.. note:: - - The original Tempest Commandments do not include Patrole-specific paths. - Patrole-specific paths replace the Tempest-specific paths within Patrole's - hacking checks. - -- [T102] Cannot import OpenStack python clients in - ``patrole_tempest_plugin/tests/api`` -- [T105] Tests cannot use setUpClass/tearDownClass -- [T107] Check that a service tag isn't in the module path -- [T108] Check no hyphen at the end of rand_name() argument -- [T109] Cannot use testtools.skip decorator; instead use - ``decorators.skip_because`` from ``tempest.lib`` -- [T113] Check that tests use ``data_utils.rand_uuid()`` instead of - ``uuid.uuid4()`` -- [N322] Method's default argument shouldn't be mutable - -The following are Patrole's specific Commandments: - -- [P100] The ``rbac_rule_validation.action`` decorator must be applied to - all RBAC tests -- [P101] RBAC test filenames must end with "_rbac.py"; for example, - test_servers_rbac.py, not test_servers.py -- [P102] RBAC test class names must end in 'RbacTest' -- [P103] ``self.client`` must not be used as a client alias; this allows for - code that is more maintainable and easier to read -- [P104] RBAC `extension test class`_ names must end in 'ExtRbacTest' - -.. _extension test class: https://git.openstack.org/cgit/openstack/patrole/plain/patrole_tempest_plugin/tests/api/network/README.rst - -Supported OpenStack Components ------------------------------- - -Patrole only offers **in-tree** integration testing coverage for the following -components: - -* Cinder -* Glance -* Keystone -* Neutron -* Nova - -Patrole currently has no stable library, so reliance upon Patrole's framework -for external RBAC testing should be done with caution. Nonetheless, even when -Patrole has a stable library, it will only offer in-tree RBAC testing for -the components listed above. - -Role Overriding ---------------- - -Correct role overriding is vital to correct RBAC testing within Patrole. If a -test does not call ``self.override_role()`` within the RBAC test, followed -by the API endpoint that enforces the expected policy action, then the test is -**not** a valid Patrole test: The API endpoint under test will be performed -with admin role, which is always wrong unless ``CONF.patrole.rbac_test_role`` -is also admin. - -.. todo:: - - Patrole does not have a hacking check for role overriding, but one may be - added in the future. - -Branchless Patrole Considerations ---------------------------------- - -Like Tempest, Patrole is branchless. This is to better ensure API and RBAC -consistency between releases because API and RBAC behavior should not change -between releases. This means that the stable branches are also gated by the -Patrole master branch, which also means that proposed commits to Patrole must -work against both the master and all the currently supported stable branches -of the projects. As such there are a few special considerations that have to -be accounted for when pushing new changes to Patrole. - -1. New Tests for new features -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Patrole, like Tempest, *implicitly* tests new features because new policies -oftentimes accompany new features. The same `Tempest philosophy`_ regarding -feature flags and new features also applies to Patrole. - -.. _Tempest philosophy: https://docs.openstack.org/tempest/latest/HACKING.html#new-tests-for-new-features - -2. New Tests for new policies -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When adding tests for new policies that were not in previous releases of the -projects, the new test must be properly skipped with a feature flag. This -involves using the ``testtools.skip(Unless|If)`` decorator above the test -to check if the required policy is enabled. Similarly, a feature flag must -be used whenever an OpenStack service covered by Patrole changes one of its -policies in a backwards-incompatible way. If there isn't a method of selecting -the new policy from the config file then there won't be a mechanism to disable -the test with older stable releases and the new test won't be able to merge. - -Introduction of a new feature flag requires specifying a default value for the -corresponding config option that is appropriate in the latest OpenStack -release. Because Patrole is branchless, the feature flag's default value will -need to be overridden to a value that is appropriate in earlier releases in -which the feature isn't available. In DevStack, this can be accomplished by -modifying Patrole's lib installation script for previous branches (because -DevStack is branched). - -3. Bug fix on core project needing Patrole changes -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -When trying to land a bug fix which changes a tested API you'll have to use the -following procedure: - - #. Propose change to the project, get a +2 on the change even with the - test failing Patrole side. - #. Propose skip to the relevant Patrole test which will only be approved - after the corresponding change in the project has a +2. - #. Land project change in master and all open stable branches - (if required). - #. Land changed test in Patrole. - -Otherwise the bug fix won't be able to land in the project. - -4. New Tests for existing features or policies -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The same `Tempest logic`_ regarding new tests for existing features or -policies also applies to Patrole. - -.. _Tempest logic: https://docs.openstack.org/tempest/latest/HACKING.html#new-tests-for-existing-features - - -Black Box vs. White Box Testing -------------------------------- - -Tempest is a `black box testing framework`_, meaning that it is concerned with -testing public API endpoints and doesn't concern itself with testing internal -implementation details. Patrole, as a Tempest plugin, also falls underneath -the category of black box testing. However, even with policy in code -documentation, some degree of white box testing is required in order to -correctly write RBAC tests. - -This is because :ref:`policy-in-code` documentation, while useful in many -respects, is usually quite brief and its main purpose is to help operators -understand how to customize policy configuration rather than to help -developers understand complex policy authorization work flows. For example, -policy in code documentation doesn't make deriving -:ref:`multiple policies ` easy. Such documentation also -doesn't usually mention that a specific parameter needs to be set, or that a -particular microversion must be enabled, or that a particular set of -prerequisite API or policy actions must be executed, in order for the policy -under test to be enforced by the server. This means that test writers must -account for the internal RBAC implementation in API code in order to correctly -understand the complete RBAC work flow within an API. - -Besides, as mentioned :ref:`elsewhere ` in this -documentation, not all services currently implement policy in code, making -some degree of white box testing a "necessary evil" for writing robust RBAC -tests. - -.. _black box testing framework: https://docs.openstack.org/tempest/latest/HACKING.html#negative-tests diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 68c771a0..00000000 --- a/LICENSE +++ /dev/null @@ -1,176 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - diff --git a/README.rst b/README.rst index ef0ff001..e85d62c0 100644 --- a/README.rst +++ b/README.rst @@ -1,251 +1,10 @@ -Patrole - RBAC Integration Tempest Plugin -========================================= - -Patrole is a set of integration tests to be run against a live OpenStack -cluster. It has a battery of tests dedicated to validating the correctness and -integrity of the cloud's RBAC implementation. - -More importantly, Patrole is a security validation tool for verifying that -Role-Based Access Control is correctly configured and enforced in an OpenStack -cloud. It runs `Tempest`_-based API tests using specified RBAC roles, thus -allowing deployments to verify that only intended roles have access to those -APIs. - -Patrole is currently undergoing heavy development. As more projects move -toward policy in code, Patrole will align its testing with the appropriate -documentation. - -* Free software: Apache license -* Documentation: https://docs.openstack.org/patrole/latest -* Source: https://opendev.org/openstack/patrole -* Bugs: https://storyboard.openstack.org/#!/project/openstack/patrole -* Release notes: https://docs.openstack.org/releasenotes/patrole/ - -Team and repository tags ------------------------- - -.. image:: https://governance.openstack.org/tc/badges/patrole.svg - :target: https://governance.openstack.org/tc/reference/tags/index.html - -.. _design-principles: - -Design Principles ------------------ - -As a `Tempest plugin`_, Patrole borrows some design principles from `Tempest design principles`_, -but not all, as its testing scope is confined to policies. - -* *Stability*. Patrole uses OpenStack public interfaces. Tests in Patrole - should only touch public OpenStack APIs. -* *Atomicity*. Patrole tests should be atomic: they should test policies in - isolation. Unlike Tempest, a Patrole test strives to only call a single - endpoint at a time. This is because it is important to validate each policy - is authorized correctly and the best way to do that is to validate each - policy alone, to avoid test contamination. -* *Complete coverage*. Patrole should validate all policy in code defaults. For - testing, Patrole uses the API-to-policy mapping contained in each project's - `policy in code`_ documentation where applicable. - - For example, Nova's policy in code documentation is located in the - `Nova repository`_ under ``nova/policies``. Likewise, Keystone's policy in - code documentation is located in the `Keystone repository`_ under - ``keystone/common/policies``. The other OpenStack services follow the same - directory layout pattern with respect to policy in code. - - .. note:: - - Realistically this is not always possible because some services have - not yet moved to policy in code. - -* *Customizable*. Patrole should be able to validate custom policy overrides to - ensure that those overrides enhance rather than undermine the cloud's RBAC - configuration. In addition, Patrole should be able to validate any role. -* *Self-cleaning*. Patrole should attempt to clean up after itself; whenever - possible we should tear down resources when done. - - .. note:: - - Patrole modifies roles dynamically in the background, which affects - pre-provisioned credentials. Work is currently underway to clean up - modifications made to pre-provisioned credentials. - -* *Self-testing*. Patrole should be self-testing. - -.. _Tempest plugin: https://docs.openstack.org/tempest/latest/plugin.html -.. _Tempest design principles: https://docs.openstack.org/tempest/latest/overview.html#design-principles -.. _policy in code: https://specs.openstack.org/openstack/oslo-specs/specs/newton/policy-in-code.html -.. _Nova repository: https://opendev.org/openstack/nova/src/branch/master/nova/policies -.. _Keystone repository: https://opendev.org/openstack/keystone/src/branch/master/keystone/common/policies - -Features --------- -* Validation of default policy definitions located in policy.json files. -* Validation of in-code policy definitions. -* Validation of custom policy file definitions that override default policy - definitions. -* Built-in positive and negative testing. Positive and negative testing - are performed using the same tests and role-switching. -* Valdation of custom roles as well as default OpenStack roles. - -.. note:: - - Patrole does not yet support policy.yaml files, the new file format for - policy files in OpenStack. - -How It Works ------------- -Patrole leverages ``oslo.policy`` (OpenStack's policy enforcement engine) to -determine whether a given role is allowed to perform a policy action, given a -specific role and OpenStack service. The output from ``oslo.policy`` (the -expected result) and the actual result from test execution are compared to -each other: if both results match, then the test passes; else it fails. - -Terminology -^^^^^^^^^^^ -* Expected Result - The expected result of a given test. -* Actual Result - The actual result of a given test. -* Final Result - A match between both expected and actual results. A mismatch - in the expected result and the actual result will result in a test failure. - - * Expected: Pass | Actual: Pass - Test Case Success - * Expected: Pass | Actual: Fail - Test Case Under-Permission Failure - * Expected: Fail | Actual: Pass - Test Case Over-Permission Failure - * Expected: Fail | Actual: Fail (Expected exception) - Test Case Success - * Expected: Fail | Actual: Fail (Unexpected exception) - Test Case Failure - -Quickstart ----------- -To run Patrole, you must first have `Tempest`_ installed and configured -properly. Please reference `Tempest_quickstart`_ guide to do so. Follow all -the steps outlined therein. Afterward, proceed with the steps below. - -#. You first need to install Patrole. This is done with pip after you check out - the Patrole repo:: - - $ git clone https://opendev.org/openstack/patrole - $ pip install patrole/ - - This can be done within a venv. - - .. note:: - - You may also install Patrole from source code by running:: - - pip install -e patrole/ - -#. Next you must properly configure Patrole, which is relatively - straightforward. For details on configuring Patrole refer to the - `Patrole Configuration `_. - -#. Once the configuration is done you're now ready to run Patrole. This can - be done using the `tempest_run`_ command. This can be done by running:: - - $ tempest run --regex '^patrole_tempest_plugin\.tests\.api' - - There is also the option to use testr directly, or any `testr`_ based test - runner, like `ostestr`_. For example, from the workspace dir run:: - - $ stestr --regex '(?!.*\[.*\bslow\b.*\])(^patrole_tempest_plugin\.tests\.api))' - - will run the same set of tests as the default gate jobs. - - You can also run Patrole tests using `tox`_, but as Patrole needs access to - global packages use ``--sitepackages`` argument. To do so, ``cd`` into the - **Tempest** directory and run:: - - $ tox -eall --sitepackages -- patrole_tempest_plugin.tests.api - - .. 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 - -#. Log information from tests is captured in ``tempest.log`` under the Tempest - repository. Some Patrole debugging information is captured in that log - related to expected test results and `Role Overriding `_. - - More detailed RBAC testing log output is emitted to ``patrole.log`` under - the Patrole repository. To configure Patrole's logging, see the - `Patrole Configuration Guide `_. - -.. _Tempest: https://opendev.org/openstack/tempest/ -.. _Tempest_quickstart: https://docs.openstack.org/tempest/latest/overview.html#quickstart -.. _tempest_run: https://docs.openstack.org/tempest/latest/run.html -.. _testr: https://testrepository.readthedocs.org/en/latest/MANUAL.html -.. _ostestr: https://docs.openstack.org/os-testr/latest/ -.. _tox: https://tox.readthedocs.io/en/latest/ - -RBAC Tests ----------- - -To change the roles that the patrole tests are being run as, edit -``rbac_test_roles`` in the ``patrole`` section of tempest.conf: :: - - [patrole] - rbac_test_roles = member,reader - ... - -.. note:: - - The ``rbac_test_roles`` is service-specific. member, for example, - is an arbitrary role, but by convention is used to designate the default - non-admin role in the system. Most Patrole tests should be run with - **admin** and **member** roles. However, other services may use entirely - different roles or role combinations. - -For more information about RBAC, reference the `rbac-overview`_ -documentation page. - -For information regarding which projects Patrole offers RBAC testing for, -reference the `HACKING`_ documentation page. - -.. _rbac-overview: https://docs.openstack.org/patrole/latest/rbac-overview.html -.. _HACKING: https://docs.openstack.org/patrole/latest/HACKING.html#supported-openstack-components - -Unit Tests ----------- - -Patrole also has a set of unit tests which test the Patrole code itself. These -tests can be run by specifying the test discovery path:: - - $ stestr --test-path ./patrole_tempest_plugin/tests/unit run - -By setting ``--test-path`` option to ``./patrole_tempest_plugin/tests/unit`` -it specifies that test discovery should only be run on the unit test directory. - -Alternatively, there are the py27 and py35 tox jobs which will run the unit -tests with the corresponding version of Python. - -One common activity is to just run a single test; you can do this with tox -simply by specifying to just run py27 or py35 tests against a single test:: - - $ tox -e py27 -- -n patrole_tempest_plugin.tests.unit.test_rbac_utils.RBACUtilsTest.test_override_role_with_missing_admin_role - -Or all tests in the test_rbac_utils.py file:: - - $ tox -e py27 -- -n patrole_tempest_plugin.tests.unit.test_rbac_utils - -You may also use regular expressions to run any matching tests:: - - $ tox -e py27 -- test_rbac_utils - -For more information on these options and details about stestr, please see the -`stestr documentation `_. - -Release Versioning ------------------- -`Patrole Release Notes `_ -shows which changes have been released for each version. - -Patrole's release versioning follows Tempest's conventions. Like Tempest, -Patrole is branchless and uses versioning instead. - -Storyboard ----------- -Bugs and enhancements are tracked via Patrole's -`Storyboard Page `_. +This project is no longer maintained. + +The contents of this repository are still available in the Git +source code management system. To see the contents of this +repository before it reached its end of life, please check out the +previous commit with "git checkout HEAD^1". + +For any further questions, please email +openstack-discuss@lists.openstack.org or join #openstack-dev on +OFTC. diff --git a/REVIEWING.rst b/REVIEWING.rst deleted file mode 100644 index f8ea144c..00000000 --- a/REVIEWING.rst +++ /dev/null @@ -1,189 +0,0 @@ -Reviewing Patrole Code -====================== -To start read the `OpenStack Common Review Checklist -`_ - - -Ensuring code is executed -------------------------- -Any new test or change to an existing test has to be verified in the gate. This -means that the first thing to check with any change is that a gate job actually -runs it. Tests which aren't executed either because of configuration or skips -should not be accepted. - - -Execution time --------------- -Along with checking that the jobs log that a new test is actually executed, -also pay attention to the execution time of that test. Patrole already runs -hundreds of tests per job in its check and gate pipelines and it is important -that the overall runtime of the jobs be constrained as much as possible. -Consider applying the ``@decorators.attr(type='slow')`` -`test attribute decorator`_ to a test if its runtime is longer than 30 seconds. - -.. _test attribute decorator: https://docs.openstack.org/tempest/latest/HACKING.html#test-attributes - - -Unit Tests ----------- -For any change that adds new functionality to common functionality unit tests -are required. This is to ensure we don't introduce future regressions and to -test conditions which we may not hit in the gate runs. - - -API Stability -------------- -Tests should only be added for published stable APIs. If a patch contains -tests for an API which hasn't been marked as stable or for an API which -doesn't conform to the `API stability guidelines -`_ then it -should not be approved. - -Similarly, tests should only be added for policies that are covered by -`policy in code documentation -`_. -Any existing tests that test policies not covered by such documentation -are either: - -* part of a service that has not yet migrated to policy in code; or -* legacy in the sense that they were created prior to policy in code - -For the first bullet, the tests should not be considered stable, but should be -kept around to maintain coverage. These tests are a best-effort attempt at -offering RBAC test coverage for the service that has not yet migrated to -policy in code. - -For the second bullet, the tests should be updated to conform to policy in -code documentation, if applicable. - - -Reject Copy and Paste Test Code -------------------------------- -When creating new tests that are similar to existing tests it is tempting to -simply copy the code and make a few modifications. This increases code size and -the maintenance burden. Such changes should not be approved if it is easy to -abstract the duplicated code into a function or method. - - -Tests overlap -------------- -When a new test is being proposed, question whether this feature is not already -tested with Patrole. Patrole has more than 600 tests, spread amongst many -directories, so it's easy to introduce test duplication. - -Test Duplication -^^^^^^^^^^^^^^^^ - -Test duplication means: - -* testing an API endpoint in more than one test -* testing the same policy in more than one test - -For the first bullet, try to avoid calling the same API inside the -``self.override_role()`` call. - -.. note:: - - If the same API is tested against different policies, consider combining - the different tests into only 1 test, that tests the API against all - the policies it enforces. - -For the second bullet, try to avoid testing the same policies across multiple -tests. - -.. note:: - - This is not always possible since policy granularity doesn't exist for all - APIs. In cases where policy granularity doesn't exist, make sure that the - policy overlap only exists for the non-granular APIs that enforce the same - policy. - - -Being explicit --------------- -When tests are being added that depend on a configurable feature or extension, -polling the API to discover that it is enabled should not be done. This will -just result in bugs being masked because the test can be skipped automatically. -Instead the config file should be used to determine whether a test should be -skipped or not. Do not approve changes that depend on an API call to determine -whether to skip or not. - - -Multi-Policy Guidelines ------------------------ - -Care should be taken when using multiple policies in an RBAC test. The -following guidelines should be followed before deciding to add multiple -policies to a Patrole test. - -.. _general-multi-policy-guidelines: - -General Multi-policy API Code Guidelines -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The list below enumerates guidelines beginning with those with the highest -priority and ending with those with the lowest priority. A higher priority -item takes precedence over lower priority items. - -#. Order the policies in the ``rules`` parameter chronologically with respect - to the order they're called by the API endpoint under test. -#. Only use policies that map to the API by referencing the appropriate policy - in code documentation. -#. Only include the minimum number of policies needed to test the API - correctly: don't add extraneous policies. -#. If possible, only use policies that directly relate to the API. If the - policies are used across multiple APIs, try to omit it. If a "generic" - policy needs to be added to get the test to pass, then this is fair game. -#. Limit the number of policies to a reasonable number, such as 3. - -Neutron Multi-policy API Code Guidelines -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Because Neutron can raise a 403 or 404 following failed authorization, Patrole -uses the ``expected_error_codes`` parameter to accommodate this behavior. -Each policy action enumerated in ``rules`` must have a corresponding entry -in ``expected_error_codes``. Each expected error code must be either a 403 or a -404, which indicates that, when policy enforcement fails for the corresponding -policy action, that error code is expected by Patrole. For more information -about these parameters, see :ref:`rbac-validation`. - -The list below enumerates additional multi-policy guidelines that apply in -particular to Neutron. A higher priority item takes precedence over lower -priority items. - -#. Order the expected error codes in the ``expected_error_codes`` parameter - chronologically with respect to the order each corresponding policy in - ``rules`` is authorized by the API under test. -#. Ensure the :ref:`neutron-multi-policy-validation` is followed when - determining the expected error code for each corresponding policy. - -The same guidelines under :ref:`general-multi-policy-guidelines` should be -applied afterward. - - -Release Notes -------------- -Release notes are how we indicate to users and other consumers of Patrole what -has changed in a given release. There are certain types of changes that -require release notes and we should not approve them without including a release -note. These include but aren't limited to, any addition, deprecation or removal -from the framework code, any change to configuration options (including -deprecation), major feature additions, and anything backwards incompatible or -would require a user to take note or do something extra. - - -Deprecated Code ---------------- -Sometimes we have some bugs in deprecated code. Basically, we leave it. Because -we don't need to maintain it. However, if the bug is critical, we might need to -fix it. When it will happen, we will deal with it on a case-by-case basis. - - -When to approve ---------------- -* Every patch can be approved with single +2 which means single reviewer can approve. -* It's OK to hold off on an approval until a subject matter expert reviews it. -* If a patch has already been approved but requires a trivial rebase to merge, - you do not have to wait for a +2, since the patch has already had +2's. With - single +2 rule, this means that author can also approve this case if he/she has - approve rights. diff --git a/babel.cfg b/babel.cfg deleted file mode 100644 index 15cd6cb7..00000000 --- a/babel.cfg +++ /dev/null @@ -1,2 +0,0 @@ -[python: **.py] - diff --git a/devstack/README.rst b/devstack/README.rst deleted file mode 100644 index 490f8333..00000000 --- a/devstack/README.rst +++ /dev/null @@ -1,25 +0,0 @@ -==================== -Enabling in Devstack -==================== - -.. warning:: - - The ``stack.sh`` script must be run in a disposable VM that is not - being created automatically. See the `README file`_ in the DevStack - repository for more information. - -1. Download DevStack:: - - git clone https://git.openstack.org/openstack-dev/devstack.git - cd devstack - -2. Patrole can be installed like any other DevStack plugin by including the - ``enable_plugin`` directive inside local.conf:: - - > cat local.conf - [[local|localrc]] - enable_plugin patrole https://git.openstack.org/openstack/patrole - -3. Run ``stack.sh`` found in the DevStack repo. - -.. _README file: https://git.openstack.org/cgit/openstack-dev/devstack/plain/README.rst diff --git a/devstack/plugin.sh b/devstack/plugin.sh deleted file mode 100644 index 9ccc4d73..00000000 --- a/devstack/plugin.sh +++ /dev/null @@ -1,179 +0,0 @@ -#!/usr/bin/env bash -# Plugin file for Patrole Tempest plugin -# -------------------------------------- - -# Dependencies: -# ``functions`` file -# ``DEST`` must be defined - -# Save trace setting -XTRACE=$(set +o | grep xtrace) -set -o xtrace - -function install_patrole_tempest_plugin { - setup_package $PATROLE_DIR -e - - if [[ ${DEVSTACK_SERIES} == 'pike' ]]; then - IFS=',' read -ra roles_array <<< "$RBAC_TEST_ROLES" - RBAC_TEST_ROLES="" - for i in "${roles_array[@]}"; do - if [[ $i == "member" ]]; then - i="Member" - fi - RBAC_TEST_ROLES="$i,$RBAC_TEST_ROLES" - done - - # Policies used by Patrole testing that were changed in a backwards-incompatible way. - # TODO(felipemonteiro): Remove these once stable/pike becomes EOL. - iniset $TEMPEST_CONFIG policy-feature-enabled create_port_fixed_ips_ip_address_policy False - iniset $TEMPEST_CONFIG policy-feature-enabled update_port_fixed_ips_ip_address_policy False - iniset $TEMPEST_CONFIG policy-feature-enabled limits_extension_used_limits_policy False - iniset $TEMPEST_CONFIG policy-feature-enabled volume_extension_volume_actions_attach_policy False - iniset $TEMPEST_CONFIG policy-feature-enabled volume_extension_volume_actions_reserve_policy False - iniset $TEMPEST_CONFIG policy-feature-enabled volume_extension_volume_actions_unreserve_policy False - - # TODO(cl566n): Remove these once stable/pike becomes EOL. - # These policies were removed in Stein but are available in Pike. - iniset $TEMPEST_CONFIG policy-feature-enabled removed_nova_policies_stein False - iniset $TEMPEST_CONFIG policy-feature-enabled removed_keystone_policies_stein False - iniset $TEMPEST_CONFIG policy-feature-enabled added_cinder_policies_stein False - - # TODO(rb560u): Remove this once stable/pike becomes EOL. - # Make the 'test_list_trusts' test backwards compatible. - # The Keystone Trust API is enforced differently depending on passed - # arguments - iniset $TEMPEST_CONFIG policy-feature-enabled keystone_policy_enforcement_train False - - # TODO(rb560u): Remove this once stable/pike becomes EOL. - # These policies were removed in Ussuri but are available in Pike. - iniset $TEMPEST_CONFIG policy-feature-enabled changed_nova_policies_ussuri False - iniset $TEMPEST_CONFIG policy-feature-enabled changed_nova_policies_victoria False - - # TODO(gmann): Remove these once stable/victoria becomes EOL. - # These policies were removed in Wallaby. - iniset $TEMPEST_CONFIG policy-feature-enabled removed_nova_policies_wallaby False - fi - - if [[ ${DEVSTACK_SERIES} == 'queens' ]]; then - IFS=',' read -ra roles_array <<< "$RBAC_TEST_ROLES" - RBAC_TEST_ROLES="" - for i in "${roles_array[@]}"; do - if [[ $i == "member" ]]; then - i="Member" - fi - RBAC_TEST_ROLES="$i,$RBAC_TEST_ROLES" - done - - # TODO(cl566n): Remove these once stable/queens becomes EOL. - # These policies were removed in Stein but are available in Queens. - iniset $TEMPEST_CONFIG policy-feature-enabled removed_nova_policies_stein False - iniset $TEMPEST_CONFIG policy-feature-enabled removed_keystone_policies_stein False - iniset $TEMPEST_CONFIG policy-feature-enabled added_cinder_policies_stein False - - # TODO(rb560u): Remove this once stable/queens becomes EOL. - # Make the 'test_list_trusts' test backwards compatible. - # The Keystone Trust API is enforced differently depending on passed - # arguments - iniset $TEMPEST_CONFIG policy-feature-enabled keystone_policy_enforcement_train False - - # TODO(rb560u): Remove this once stable/queens becomes EOL. - # These policies were removed in Ussuri but are available in Queens. - iniset $TEMPEST_CONFIG policy-feature-enabled changed_nova_policies_ussuri False - iniset $TEMPEST_CONFIG policy-feature-enabled changed_nova_policies_victoria False - - # TODO(gmann): Remove these once stable/victoria becomes EOL. - # These policies were removed in Wallaby. - iniset $TEMPEST_CONFIG policy-feature-enabled removed_nova_policies_wallaby False - - # TODO(gmann): Remove these once stable/xena becomes EOL. - iniset $TEMPEST_CONFIG policy-feature-enabled changed_cinder_policies_xena False - fi - - if [[ ${DEVSTACK_SERIES} == 'rocky' ]]; then - # TODO(cl566n): Policies used by Patrole testing. Remove these once stable/rocky becomes EOL. - iniset $TEMPEST_CONFIG policy-feature-enabled removed_nova_policies_stein False - iniset $TEMPEST_CONFIG policy-feature-enabled added_cinder_policies_stein False - iniset $TEMPEST_CONFIG policy-feature-enabled removed_keystone_policies_stein False - - # TODO(rb560u): Remove this once stable/rocky becomes EOL. - # Make the 'test_list_trusts' test backwards compatible. - # The Keystone Trust API is enforced differently depending on passed - # arguments - iniset $TEMPEST_CONFIG policy-feature-enabled keystone_policy_enforcement_train False - - # TODO(rb560u): Remove this once stable/rocky becomes EOL. - # These policies were removed in Ussuri but are available in Rocky. - iniset $TEMPEST_CONFIG policy-feature-enabled changed_nova_policies_ussuri False - iniset $TEMPEST_CONFIG policy-feature-enabled changed_nova_policies_victoria False - - # TODO(gmann): Remove these once stable/victoria becomes EOL. - # These policies were removed in Wallaby. - iniset $TEMPEST_CONFIG policy-feature-enabled removed_nova_policies_wallaby False - - # TODO(gmann): Remove these once stable/xena becomes EOL. - iniset $TEMPEST_CONFIG policy-feature-enabled changed_cinder_policies_xena False - fi - - if [[ ${DEVSTACK_SERIES} == 'stein' ]]; then - # TODO(rb560u): Remove this once stable/stein becomes EOL. - # Make the 'test_list_trusts' test backwards compatible. - # The Keystone Trust API is enforced differently depending on passed - # arguments - iniset $TEMPEST_CONFIG policy-feature-enabled keystone_policy_enforcement_train False - - # TODO(rb560u): Remove this once stable/stein becomes EOL. - # These policies were removed in Ussuri but are available in Stein. - iniset $TEMPEST_CONFIG policy-feature-enabled changed_nova_policies_ussuri False - iniset $TEMPEST_CONFIG policy-feature-enabled changed_nova_policies_victoria False - - # TODO(gmann): Remove these once stable/victoria becomes EOL. - # These policies were removed in Wallaby. - iniset $TEMPEST_CONFIG policy-feature-enabled removed_nova_policies_wallaby False - # TODO(gmann): Remove these once stable/xena becomes EOL. - iniset $TEMPEST_CONFIG policy-feature-enabled changed_cinder_policies_xena False - fi - - if [[ ${DEVSTACK_SERIES} == 'train' ]]; then - # Remove this once stable/train becomes EOL. - iniset $TEMPEST_CONFIG policy-feature-enabled changed_nova_policies_ussuri False - iniset $TEMPEST_CONFIG policy-feature-enabled changed_nova_policies_victoria False - # TODO(gmann): Remove these once stable/victoria becomes EOL. - # These policies were removed in Wallaby. - iniset $TEMPEST_CONFIG policy-feature-enabled removed_nova_policies_wallaby False - # TODO(gmann): Remove these once stable/xena becomes EOL. - iniset $TEMPEST_CONFIG policy-feature-enabled changed_cinder_policies_xena False - fi - - if [[ ${DEVSTACK_SERIES} == 'ussuri' ]]; then - # Remove this once stable/ussuri becomes EOL. - iniset $TEMPEST_CONFIG policy-feature-enabled changed_nova_policies_victoria False - # TODO(gmann): Remove these once stable/victoria becomes EOL. - # These policies were removed in Wallaby. - iniset $TEMPEST_CONFIG policy-feature-enabled removed_nova_policies_wallaby False - # TODO(gmann): Remove these once stable/xena becomes EOL. - iniset $TEMPEST_CONFIG policy-feature-enabled changed_cinder_policies_xena False - fi - - if [[ ${DEVSTACK_SERIES} == 'victoria' ]]; then - # TODO(gmann): Remove these once stable/victoria becomes EOL. - # These policies were removed in Wallaby. - iniset $TEMPEST_CONFIG policy-feature-enabled removed_nova_policies_wallaby False - # TODO(gmann): Remove these once stable/xena becomes EOL. - iniset $TEMPEST_CONFIG policy-feature-enabled changed_cinder_policies_xena False - fi - if [[ ${DEVSTACK_SERIES} == 'wallaby' ]]; then - # TODO(gmann): Remove these once stable/xena becomes EOL. - iniset $TEMPEST_CONFIG policy-feature-enabled changed_cinder_policies_xena False - fi - iniset $TEMPEST_CONFIG patrole rbac_test_roles $RBAC_TEST_ROLES -} - -if is_service_enabled tempest; then - if [[ "$1" == "stack" && "$2" == "test-config" ]]; then - echo_summary "Installing Patrole Tempest plugin" - install_patrole_tempest_plugin - fi -fi - -# Restore xtrace -$XTRACE diff --git a/devstack/settings b/devstack/settings deleted file mode 100644 index 670e878f..00000000 --- a/devstack/settings +++ /dev/null @@ -1,8 +0,0 @@ -# Settings needed for the Patrole Tempest plugin -# ---------------------------------------------- - -PATROLE_DIR=$DEST/patrole -TEMPEST_DIR=$DEST/tempest -TEMPEST_CONFIG_DIR=${TEMPEST_CONFIG_DIR:-$TEMPEST_DIR/etc} -TEMPEST_CONFIG=$TEMPEST_CONFIG_DIR/tempest.conf -RBAC_TEST_ROLE=${RBAC_TEST_ROLE:-admin} diff --git a/doc/requirements.txt b/doc/requirements.txt deleted file mode 100644 index ae5457e7..00000000 --- a/doc/requirements.txt +++ /dev/null @@ -1,8 +0,0 @@ -# The order of packages is significant, because pip processes them in the order -# of appearance. Changing the order has an impact on the overall integration -# process, which may cause wedges in the gate later. -sphinx>=2.0.0,!=2.1.0 # BSD -openstackdocstheme>=2.2.0 # Apache-2.0 -reno>=3.1.0 # Apache-2.0 -sphinxcontrib-apidoc>=0.2.0 # BSD -sphinxcontrib-svg2pdfconverter>=0.1.0 # BSD diff --git a/doc/source/HACKING.rst b/doc/source/HACKING.rst deleted file mode 100644 index 8777875b..00000000 --- a/doc/source/HACKING.rst +++ /dev/null @@ -1,5 +0,0 @@ -==================== -Patrole Coding Guide -==================== - -.. include:: ../../HACKING.rst diff --git a/doc/source/REVIEWING.rst b/doc/source/REVIEWING.rst deleted file mode 100644 index e8e3c1a7..00000000 --- a/doc/source/REVIEWING.rst +++ /dev/null @@ -1,5 +0,0 @@ -====================== -Reviewing Patrole Code -====================== - -.. include:: ../../REVIEWING.rst diff --git a/doc/source/_static/.keep b/doc/source/_static/.keep deleted file mode 100644 index e69de29b..00000000 diff --git a/doc/source/conf.py b/doc/source/conf.py deleted file mode 100755 index ff8c0252..00000000 --- a/doc/source/conf.py +++ /dev/null @@ -1,110 +0,0 @@ -# -*- coding: utf-8 -*- -# 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 os -import sys - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -sys.path.insert(0, os.path.abspath('../../')) -sys.path.insert(0, os.path.abspath('../')) -sys.path.insert(0, os.path.abspath('./')) - -# -- General configuration ---------------------------------------------------- - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. -extensions = [ - 'sphinx.ext.autodoc', - 'sphinx.ext.todo', - 'sphinx.ext.viewcode', - 'sphinxcontrib.rsvgconverter', - 'openstackdocstheme', - 'oslo_config.sphinxconfiggen', - 'sphinxcontrib.apidoc', -] - -# sphinxcontrib.apidoc options -apidoc_module_dir = '../../patrole_tempest_plugin' -apidoc_output_dir = 'framework/code' -apidoc_excluded_paths = [ - 'hacking', - 'hacking/*', - 'tests', - 'tests/*', - 'config.py', - 'plugin.py', - 'version.py' -] -apidoc_separate_modules = True - -config_generator_config_file = '../../etc/config-generator.patrole.conf' -sample_config_basename = '_static/patrole' - -# autodoc generation is a bit aggressive and a nuisance when doing heavy -# text edit cycles. -# execute "export SPHINX_DEBUG=1" in your terminal to disable - -# The suffix of source filenames. -source_suffix = '.rst' - -# The master toctree document. -master_doc = 'index' - -# General information about the project. - -copyright = u'2017, Patrole Developers' - -# If true, '()' will be appended to :func: etc. cross-reference text. -add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -add_module_names = True - -# The name of the Pygments (syntax highlighting) style to use. -pygments_style = 'sphinx' - -# -- Options for HTML output -------------------------------------------------- - -# The theme to use for HTML and HTML Help pages. Major themes that come with -# Sphinx are currently 'default' and 'sphinxdoc'. -# html_theme_path = ["."] -html_theme = 'openstackdocs' - -# openstackdocstheme options -openstackdocs_repo_name = 'openstack/patrole' -openstackdocs_pdf_link = True -openstackdocs_bug_project = 'patrole' -openstackdocs_bug_tag = '' - -# Output file base name for HTML help builder. -htmlhelp_basename = 'patroledoc' - -# Example configuration for intersphinx: refer to the Python standard library. -#intersphinx_mapping = {'http://docs.python.org/': None} - -# -- Options for LaTeX output ------------------------------------------------- - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, author, documentclass -# [howto/manual]). -latex_documents = [ - ('index', 'doc-patrole.tex', u'Patrole: Tempest Plugin for RBAC Testing', - u'OpenStack Foundation', 'manual'), -] - -# Disable usage of xindy https://bugzilla.redhat.com/show_bug.cgi?id=1643664 -latex_use_xindy = False diff --git a/doc/source/configuration.rst b/doc/source/configuration.rst deleted file mode 100644 index 1e7fe8fb..00000000 --- a/doc/source/configuration.rst +++ /dev/null @@ -1,94 +0,0 @@ -.. _patrole-configuration: - -Patrole Configuration Guide -=========================== - -Patrole can be customized by updating Tempest's ``tempest.conf`` configuration -file. All Patrole-specific configuration options should be included under -the ``patrole`` group. - -RBAC Test Roles ---------------- - -The RBAC test roles govern the list of roles to be used when running Patrole -tests. For example, setting ``rbac_test_roles`` to "admin" will execute all -RBAC tests using admin credentials. Changing the ``rbac_test_roles`` value -will `override` Tempest's primary credentials to use that role. - -This implies that, if ``rbac_test_roles`` is "admin", regardless of the Tempest -credentials used by a client, the client will be calling APIs using the admin -role. That is, ``self.os_primary.servers_client`` will run as though it were -``self.os_admin.servers_client``. - -Similarly, setting ``rbac_test_roles`` with various roles, results in -Tempest's primary credentials being overridden by the roles specified by -``rbac_test_roles``. - -.. note:: - - Only the roles of the primary Tempest credentials ("os_primary") are - modified. The ``user_id`` and ``project_id`` remain unchanged. - -Custom Policy Files -------------------- - -Patrole supports testing custom policy file definitions, along with default -policy definitions. Default policy definitions are used if custom file -definitions are not specified. If both are specified, the custom policy -definition takes precedence (that is, replaces the default definition, -as this is the default behavior in OpenStack). - -The ``custom_policy_files`` option allows a user to specify a comma-separated -list of custom policy file locations that are on the same host as Patrole. -Each policy file must include the name of the service that is being tested: -for example, if "compute" tests are executed, then Patrole will use the first -policy file contained in ``custom_policy_files`` that contains the "nova" -keyword. - -.. note:: - - Patrole currently does not support policy files located on a host different - than the one on which it is running. - -Policy Feature Flags --------------------- - -Patrole's ``[policy-feature-enabled]`` configuration group includes one option -per supported policy feature flag. These feature flags are introduced when an -OpenStack service introduces a new policy or changes a policy in a -backwards-incompatible way. Since Patrole is branchless, it copes with the -unexpected policy change by making the relevant policy change as well, but -also introduces a new policy feature flag so that the test won't break N-1/N-2 -releases where N is the currently supported release. - -The default value for the feature flag is enabled for N and disabled for any -releases prior to N in which the feature is not available. This is done by -overriding the default value of the feature flag in DevStack's ``lib/patrole`` -installation script. The change is made in Tempest's DevStack script because -Patrole's DevStack plugin is hosted in-repo, which is branch-less (whereas -the former is branched). - -After the backwards-incompatible change no longer affects any supported -release, then the corresponding policy feature flag is removed. - -For more information on feature flags, reference the relevant -`Tempest documentation`_. - -.. _Tempest documentation: https://docs.openstack.org/tempest/latest/HACKING.html#new-tests-for-new-features - -Sample Configuration File -------------------------- - -The following is a sample Patrole configuration for adaptation and use. It is -auto-generated from Patrole when this documentation is built, so -if you are having issues with an option, please compare your version of -Patrole with the version of this documentation. - -Note that the Patrole configuration options actually live inside the Tempest -configuration file; at runtime, Tempest populates its own configuration -file with Patrole groups and options, assuming that Patrole is correctly -installed and recognized as a plugin. - -The sample configuration can also be viewed in `file form <_static/patrole.conf.sample>`_. - -.. literalinclude:: _static/patrole.conf.sample diff --git a/doc/source/contributor/contributing.rst b/doc/source/contributor/contributing.rst deleted file mode 100644 index 6d9bb86a..00000000 --- a/doc/source/contributor/contributing.rst +++ /dev/null @@ -1,57 +0,0 @@ -============================ -So You Want to Contribute... -============================ - -For general information on contributing to OpenStack, please check out the -`contributor guide `_ to get started. -It covers all the basics that are common to all OpenStack projects: the accounts -you need, the basics of interacting with our Gerrit review system, how we -communicate as a community, etc. - -Below will cover the more project specific information you need to get started -with Tempest. - -Communication -~~~~~~~~~~~~~ -* IRC channel ``#openstack-qa`` at OFTC -* Mailing list (prefix subjects with ``[qa]`` for faster responses) - http://lists.openstack.org/cgi-bin/mailman/listinfo/openstack-discuss - -Contacting the Core Team -~~~~~~~~~~~~~~~~~~~~~~~~ -Please refer to the `Patrole Core Team -`_ contacts. - -New Feature Planning -~~~~~~~~~~~~~~~~~~~~ -If you want to propose a new feature please read `Feature Proposal Process`_ -Patrole features are tracked on `Storyboard `_. - -Task Tracking -~~~~~~~~~~~~~ -We track our tasks in `Storyboard `_. - -If you're looking for some smaller, easier work item to pick up and get started -on, search for the 'low-hanging-fruit' tag. - -Reporting a Bug -~~~~~~~~~~~~~~~ -You found an issue and want to make sure we are aware of it? You can do so on -`StoryBoard `_. - -Getting Your Patch Merged -~~~~~~~~~~~~~~~~~~~~~~~~~ -All changes proposed to the Patrole requires one ``Code-Review +2`` votes from -Patrole core reviewers before one of the core reviewers can approve patch by -giving ``Workflow +1`` vote. More detailed guidelines for reviewers are available -at :doc:`../REVIEWING`. - -Project Team Lead Duties -~~~~~~~~~~~~~~~~~~~~~~~~ -All common PTL duties are enumerated in the `PTL guide -`_. - -The Release Process for QA is documented in `QA Release Process -`_. - -.. _Feature Proposal Process: https://wiki.openstack.org/wiki/QA#Feature_Proposal_.26_Design_discussions diff --git a/doc/source/field_guide/index.rst b/doc/source/field_guide/index.rst deleted file mode 100644 index ba06c423..00000000 --- a/doc/source/field_guide/index.rst +++ /dev/null @@ -1,60 +0,0 @@ -.. _patrole-field-guide: - -============================ -Patrole Field Guide Overview -============================ - -Testing Scope -============= - -Patrole testing scope is strictly confined to Role-Based Access Control -(RBAC). In OpenStack, ``oslo.policy`` is the RBAC library used by all -major services. Thus, Patrole is concerned with validating that public API -endpoints are correctly using ``oslo.policy`` for authorization. - -In other words, all tests in Patrole are RBAC tests. - -:ref:`rbac_field_guide` -======================= - -RBAC tests are `Tempest`_-like API tests plus Patrole's -:ref:`rbac-validation`. All Patrole tests are RBAC validation tests for the -OpenStack API. - -.. _Tempest: https://docs.openstack.org/tempest/latest/ - -Stable Tests -============ - -In the discussion below, "correct" means that a test is consistent with -a service's API-to-policy mapping and "stable" means that a test should -require minimal maintenance for the supported releases. - -Present -------- - -During the Queens release, a `governance spec`_ was pushed to support policy -in code, which documents the mapping between APIs and each of their policies. - -This documentation is an important prerequisite for ensuring that Patrole -tests for a given service are correct. This mapping can be referenced to -confirm that Patrole's assumed mapping for a test is correct. For -example, Nova has implemented policy in code which can be used to verify -that Patrole's Nova RBAC tests use the same mapping. - -If a given service does not have policy in code, this implies that it is -*more likely* that the RBAC tests for that service are inconsistent with the -*intended* policy mapping. Until that service implements policy in code, it -is difficult for Patrole maintainers to verify that tests for that service -are correct. - -Future ------- - -Once all services that Patrole tests have implemented policy in code -- -and once Patrole has updated all its tests in accordance with the policy in -code documentation -- then Patrole tests can guaranteed to be stable. - -This stability will be denoted with a 1.0 version release. - -.. _governance spec: https://governance.openstack.org/tc/goals/queens/policy-in-code.html diff --git a/doc/source/field_guide/rbac.rst b/doc/source/field_guide/rbac.rst deleted file mode 100644 index a3830990..00000000 --- a/doc/source/field_guide/rbac.rst +++ /dev/null @@ -1,118 +0,0 @@ -.. _rbac_field_guide: - -Patrole Field Guide to RBAC Tests -================================= - - -What are these tests? ---------------------- - -Patrole's primary responsibility is to ensure that your OpenStack cloud -has properly configured Role-Based Access Control (RBAC). All Patrole -tests cases are devoted to this responsibility. Tempest API clients -and utility functions are leveraged to accomplish this goal, but such -functionality is secondary to RBAC validation. - -Like Tempest, Patrole not only tests expected positive paths for RBAC -validation, but also -- and more importantly -- negative paths. While -Patrole could be thought of as validating RBAC, it more importantly -verifies that your OpenStack cloud is secure from the perspective of -RBAC (there are many gotchas when it comes to security, not just RBAC). - -Negative paths are arguably more important than positive paths when it -comes to RBAC and by extension security, because it is essential that -your cloud be secure from unauthorized access. For example, while it is -important to verify that the admin role has access to admin-level -functionality, it is of critical importance to verify that non-admin roles -*do not* have access to such functionality. - -Unlike Tempest, Patrole accomplishes negative testing implicitly -- by -abstracting it away in the background. Patrole dynamically determines -whether a role should have access to an API depending on your cloud's -policy configuration and then confirms whether that is true or false. - - -Why are these tests in Patrole? -------------------------------- - -These tests constitute the core mission in Patrole: to verify RBAC. These -tests are mainly intended to validate RBAC, but can also *unofficially* -be used to discover the policy-to-API mapping for an OpenStack component. - -It could be argued that some of these tests could be implemented in -the projects themselves, but that approach has the following shortcomings: - -* The projects do not validate RBAC from an integration testing perspective. -* By extension, RBAC across cross-service communication is not usually - validated. -* The projects' tests do not pass all the metadata to ``oslo.policy`` that is - in reality passed by the deployed server to that library to determine - whether a given user is authorized to perform an API action. -* The projects do not exhaustively do RBAC testing for all positive and - negative paths. -* Patrole is designed to work with any role via configuration settings, but - on the other hand the projects handpick which roles to test. - -Why not use Patrole framework on Tempest tests? -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -The Patrole framework can't be applied to existing Tempest tests via -:ref:`rbac-validation`, because: - -* Tempest tests aren't factored the right way: They're not granular enough. - They call too many APIs and too many policies are enforced by each test. -* Tempest tests assume default policy rules: Tempest uses ``os_admin`` - `credentials`_ for admin APIs and ``os_primary`` for non-admin APIs. - This breaks for custom policy overrides. -* Tempest doesn't have tests that enforce all the policy actions, regardless. - Some RBAC tests require that tests be written a very precise way for the - server to authorize the expected policy actions. - -Why are these tests not in Tempest? -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -Patrole should be a separate project that specializes in RBAC tests. This -was agreed upon during `discussion`_ that led to the approval of the RBAC -testing framework `spec`_, which was the genesis for Patrole. - -Philosophically speaking: - -* Tempest supports `API and scenario testing`_. RBAC testing is out of scope. -* The `OpenStack project structure reform`_ evolved OpenStack "to a more - decentralized model where [projects like QA] provide processes and tools to - empower projects to do the work themselves". This model resulted in the - creation of the `Tempest external plugin interface`_. -* Tempest supports `plugins`_. Why not use one for RBAC testing? - -Practically speaking: - -* The Tempest team should not be burdened with having to support Patrole, too. - Tempest is a big project and having to absorb RBAC testing is difficult. -* Tempest already has many in-tree Zuul checks/gates. If Patrole tests lived - in Tempest, then adding more Zuul checks/gates for Patrole would only make it - harder to get changes merged in Tempest. - -.. _credentials: https://docs.openstack.org/tempest/latest/write_tests.html#allocating-credentials -.. _discussion: https://review.openstack.org/#/c/382672/ -.. _spec: https://specs.openstack.org/openstack/qa-specs/specs/tempest/rbac-policy-testing.html -.. _API and scenario testing: https://docs.openstack.org/tempest/latest/overview.html#tempest-the-openstack-integration-test-suite -.. _OpenStack project structure reform: https://governance.openstack.org/tc/resolutions/20141202-project-structure-reform-spec.html#impact-for-horizontal-teams -.. _Tempest external plugin interface: https://specs.openstack.org/openstack/qa-specs/specs/tempest/implemented/tempest-external-plugin-interface.html -.. _plugins: https://docs.openstack.org/tempest/latest/plugin.html - - -Scope of these tests --------------------- - -RBAC tests should always use the Tempest implementation of the -OpenStack API, to take advantage of Tempest's stable library. - -Each test should test a specific API endpoint and the related policy. - -Each policy should be tested in isolation of one another -- or at least -as close to this rule as possible -- to ensure proper validation of RBAC. - -Each test should be able to work for positive and negative paths. - -All tests should be able to be run on their own, not depending on the -state created by a previous test. diff --git a/doc/source/framework/overview.rst b/doc/source/framework/overview.rst deleted file mode 100644 index 6f72eec7..00000000 --- a/doc/source/framework/overview.rst +++ /dev/null @@ -1,81 +0,0 @@ -RBAC Testing Validation -======================= - -.. _validation-workflow-overview: - ----------------------------- -Validation Workflow Overview ----------------------------- - -RBAC testing validation is broken up into 3 stages: - -#. "Expected" stage. Determine whether the test should be able to succeed - or fail based on the test roles defined by ``[patrole] rbac_test_roles``) - and the policy action that the test enforces. -#. "Actual" stage. Run the test by calling the API endpoint that enforces - the expected policy action using the test roles. -#. Comparing the outputs from both stages for consistency. A "consistent" - result is treated as a pass and an "inconsistent" result is treated - as a failure. "Consistent" (or successful) cases include: - - * Expected result is ``True`` and the test passes. - * Expected result is ``False`` and the test fails. - - For example, a 200 from the API call and a ``True`` result from - ``oslo.policy`` or a 403 from the API call and a ``False`` result from - ``oslo.policy`` are successful results. - - "Inconsistent" (or failing) cases include: - - * Expected result is ``False`` and the test passes. This results in an - :class:`~rbac_exceptions.RbacOverPermissionException` exception - getting thrown. - * Expected result is ``True`` and the test fails. This results in a - :class:`~rbac_exceptions.RbacOverPermissionException` exception - getting thrown. - - For example, a 200 from the API call and a ``False`` result from - ``oslo.policy`` or a 403 from the API call and a ``True`` result from - ``oslo.policy`` are failing results. - -.. warning:: - - Note that Patrole cannot currently derive the expected policy result for - service-specific ``oslo.policy`` `checks`_, like Neutron's `FieldCheck`_, - because such checks are contained within the service's code base itself, - which Patrole cannot import. - -.. _checks: https://docs.openstack.org/oslo.policy/latest/reference/api/oslo_policy.policy.html#generic-checks -.. _FieldCheck: https://docs.openstack.org/neutron/pike/contributor/internals/policy.html#fieldcheck-verify-resource-attributes - -------------------------------- -The RBAC Rule Validation Module -------------------------------- - -High-level module that provides the decorator that wraps around Tempest tests -and serves as the entry point for RBAC testing validation. The workflow -described above is ultimately carried out by the decorator. - -For more information about this module, please see :ref:`rbac-validation`. - ---------------------------- -The Policy Authority Module ---------------------------- - -Module called by :ref:`rbac-validation` to verify whether the test -roles are allowed to execute a policy action by querying ``oslo.policy`` with -required test data. The result is used by :ref:`rbac-validation` as the -"Expected" result. - -For more information about this module, please see :ref:`policy-authority`. - ---------------------- -The RBAC Utils Module ---------------------- - -This module is responsible for handling role switching, the mechanism by which -Patrole is able to set up, tear down and execute APIs using the same set -of credentials. Every RBAC test must perform a role switch even if the role -that is being switched to is admin. - -For more information about this module, please see :ref:`rbac-utils`. diff --git a/doc/source/framework/policy_authority.rst b/doc/source/framework/policy_authority.rst deleted file mode 100644 index f0396926..00000000 --- a/doc/source/framework/policy_authority.rst +++ /dev/null @@ -1,60 +0,0 @@ -.. _policy-authority: - -Policy Authority Module -======================= - -Overview --------- - -This module is only called for calculating the "Expected" result if -``[patrole] test_custom_requirements`` is ``False``. - -Using the :class:`~patrole_tempest_plugin.policy_authority.PolicyAuthority` -class, policy verification is performed by: - -#. Pooling together the default `in-code` policy rules. -#. Overriding the defaults with custom policy rules located in a policy.json, - if the policy file exists and the custom policy definition is explicitly - defined therein. -#. Confirming that the policy action -- for example, "list_users" -- exists. - (``oslo.policy`` otherwise claims that role "foo" is allowed to - perform policy action "bar", for example, because it defers to the - "default" policy rule and oftentimes the default can be "anyone allowed"). -#. Performing a call with all necessary data to ``oslo.policy`` and returning - the expected result back to ``rbac_rule_validation`` decorator. - -When to use ------------ - -This :class:`~patrole_tempest_plugin.rbac_authority.RbacAuthority` class -can be used to validate the default OpenStack policy configuration. It -is recommended that this approach be used for RBAC validation for clouds that -use little to no policy customizations or overrides. - -This validation approach should be used when: - -* Validating the out-of-the-box policy-in-code OpenStack policy configuration. - - It is important that the default OpenStack policy configuration be validated - before deploying OpenStack into production. Bugs exist in software and the - earlier they can be caught and prevented (via CI/CD, for example), the - better. Patrole continues to be used to identify default policy bugs - across OpenStack services. - -* Validating policy reliably and accurately. - - Relying on ``oslo.policy`` to compute the expected test results provides - accurate tests, without the hassle of having to reinvent the wheel. Since - OpenStack APIs use ``oslo.policy`` for policy enforcement, it makes sense - to compute expected results by using the same library, ensuring test - reliability. - -* Continuously validating policy changes to OpenStack projects under - development by gating them against Patrole CI/CD jobs run by `Zuul`_. - -.. _Zuul: https://docs.openstack.org/infra/zuul/ - -Implementation --------------- - -:py:mod:`Policy Authority Module ` diff --git a/doc/source/framework/rbac_authority.rst b/doc/source/framework/rbac_authority.rst deleted file mode 100644 index 7ffe24f8..00000000 --- a/doc/source/framework/rbac_authority.rst +++ /dev/null @@ -1,35 +0,0 @@ -.. rbac-authority: - -RBAC Authority Module -===================== - -Overview --------- - -This module implements an abstract class that is implemented by the classes -below. Each implementation is used by the :ref:`rbac-validation` framework -to determine each expected test result. - -:ref:`policy-authority` ------------------------ - -The *default* :class:`~patrole_tempest_plugin.rbac_authority.RbacAuthority` -implementation class which is used for policy validation. Uses ``oslo.policy`` -to determine the expected test result. - -All Patrole `Zuul`_ gates use this -:class:`~patrole_tempest_plugin.rbac_authority.RbacAuthority` class by default. - -.. _Zuul: https://docs.openstack.org/infra/zuul/ - -:ref:`requirements-authority` ------------------------------ - -Optional :class:`~patrole_tempest_plugin.rbac_authority.RbacAuthority` -implementation class which is used for policy validation. It uses a high-level -requirements-driven approach to validating RBAC in Patrole. - -Implementation --------------- - -:py:mod:`RBAC Authority Module ` diff --git a/doc/source/framework/rbac_utils.rst b/doc/source/framework/rbac_utils.rst deleted file mode 100644 index f7cb182f..00000000 --- a/doc/source/framework/rbac_utils.rst +++ /dev/null @@ -1,33 +0,0 @@ -.. _rbac-utils: - -RBAC Utils Module -================= - -Overview --------- - -Patrole manipulates the ``os_primary`` `Tempest credentials`_, which are the -primary set of Tempest credentials. It is necessary to use the same credentials -across the entire test setup/test execution/test teardown workflow -because otherwise 400-level errors will be thrown by OpenStack services. - -This is because many services check the request context's project scope -- and -in very rare cases, user scope. However, each set of Tempest credentials (via -`dynamic credentials`_) is allocated its own distinct project. For example, the -``os_admin`` and ``os_primary`` credentials each have a distinct project, -meaning that it is not always possible for the ``os_primary`` credentials to -access resources created by the ``os_admin`` credentials. - -The only foolproof solution is to manipulate the role for the same set of -credentials, rather than using distinct credentials for setup/teardown -and test execution, respectively. This is especially true when considering -custom policy rule definitions, which can be arbitrarily complex. - -Implementation --------------- - -:py:mod:`RBAC Utils Module ` - -.. _Tempest credentials: https://docs.openstack.org/tempest/latest/library/credential_providers.html -.. _dynamic credentials: https://docs.openstack.org/tempest/latest/configuration.html#dynamic-credentials - diff --git a/doc/source/framework/rbac_validation.rst b/doc/source/framework/rbac_validation.rst deleted file mode 100644 index 460c08c8..00000000 --- a/doc/source/framework/rbac_validation.rst +++ /dev/null @@ -1,17 +0,0 @@ -.. _rbac-validation: - -RBAC Rule Validation Module -=========================== - -Overview --------- - -Module that implements the decorator which serves as the entry point for -RBAC validation testing. The decorator should be applied to every RBAC test -with the appropriate ``service`` (OpenStack service) and ``rule`` (OpenStack -policy name defined by the ``service``). - -Implementation --------------- - -:py:mod:`RBAC Rule Validation Module ` diff --git a/doc/source/framework/requirements_authority.rst b/doc/source/framework/requirements_authority.rst deleted file mode 100644 index daed3196..00000000 --- a/doc/source/framework/requirements_authority.rst +++ /dev/null @@ -1,156 +0,0 @@ -.. _requirements-authority: - -Requirements Authority Module -============================= - -Overview --------- - -Requirements-driven approach to declaring the expected RBAC test results -referenced by Patrole. These requirements express the *intention* behind the -policy. A high-level YAML syntax is used to concisely and clearly map each -policy action to the list of associated roles. - -.. note:: - - The :ref:`custom-requirements-file` is required to use this validation - approach and, currently, must be manually generated. - -This validation approach can be toggled on by setting the -``[patrole].test_custom_requirements`` configuration option to ``True``; -see :ref:`patrole-configuration` for more information. - -When to use ------------ - -This :class:`~patrole_tempest_plugin.rbac_authority.RbacAuthority` class -can be used to achieve a requirements-driven approach to validating an -OpenStack cloud's RBAC implementation. Using this approach, Patrole computes -expected test results by performing lookups against a -:ref:`custom-requirements-file` which precisely defines the cloud's RBAC -requirements. - -This validation approach should be used when: - -* The cloud has heavily customized policy files that require careful validation - against one's requirements. - - Heavily customized policy files can contain relatively nuanced/technical - syntax that impinges upon the goal of using a clear and concise syntax - present in the :ref:`custom-requirements-file` to drive RBAC validation. - -* The cloud has non-OpenStack services that require RBAC validation but which - don't leverage the ``oslo.policy`` framework. - - Services like `Contrail`_ that are present in an OpenStack-based cloud that - interface with OpenStack services like Neutron also require RBAC validation. - The requirements-driven approach to RBAC validation is framework-agnostic - and so can work with any policy engine. - -* Expected results are captured as clear-cut, unambiguous requirements. - - Validating a cloud's RBAC against high-level, clear-cut requirements is - a valid use case. Relying on ``oslo.policy`` validating customized policy - files is not sufficient to satisfy this use case. - -As mentioned above, the trade-off with this approach is having to manually -generate the :ref:`custom-requirements-file`. There is currently no -tooling to automatically do this. - -.. _Contrail: https://github.com/Juniper/contrail-controller/wiki/RBAC - -.. _custom-requirements-file: - -Custom Requirements File -^^^^^^^^^^^^^^^^^^^^^^^^ - -File path of the YAML file that defines your RBAC requirements. This -file must be located on the same host that Patrole runs on. The YAML -file should be written as follows: - - .. code-block:: yaml - - : - : - - - - - : - - , - : - : - - - -Where: - -* ``service`` - the service that is being tested (Cinder, Nova, etc.). -* ``api_action`` - the policy action that is being tested. Examples: - - * volume:create - * os_compute_api:servers:start - * add_image - -* ``allowed_role`` - the ``oslo.policy`` role that is allowed to perform the - API. - -Each item under ``logical_or_example`` is "logical OR"-ed together. Each role -in the comma-separated string under ``logical_and_example`` is "logical AND"-ed -together. And each item prefixed with "!" under ``logical_not_example`` is -"logical negated". - -.. note:: - - The custom requirements file only allows policy actions to be mapped to - the associated roles that define it. Complex ``oslo.policy`` constructs - like ``literals`` or ``GenericChecks`` are not supported. For more - information, reference the `oslo.policy documentation`_. - -.. _oslo.policy documentation: https://docs.openstack.org/oslo.policy/latest/reference/api/oslo_policy.policy.html#policy-rule-expressions - -Examples -~~~~~~~~ - -Items within ``api_action`` are considered as logical or, so you may read: - -.. code-block:: yaml - - : - # "api_action_a: allowed_role_1 or allowed_role_2 or allowed_role_3" - : - - - - - - - -as `` or or ``. - -Roles within comma-separated items are considered as logic and, so you may -read: - -.. code-block:: yaml - - : - # "api_action_a: (allowed_role_1 and allowed_role_2) or allowed_role_3" - : - - , - - - -as `` and or ``. - -Also negative roles may be defined with an exclamation mark ahead of role: - -.. code-block:: yaml - - : - # "api_action_a: (allowed_role_1 and allowed_role_2 and not - # disallowed_role_4) or allowed_role_3" - : - - , , ! - - - -This example must be read as `` and and not - or ``. - - -Implementation --------------- - -:py:mod:`Requirements Authority Module ` diff --git a/doc/source/index.rst b/doc/source/index.rst deleted file mode 100644 index d24f517f..00000000 --- a/doc/source/index.rst +++ /dev/null @@ -1,92 +0,0 @@ -======================================== -Patrole: Tempest Plugin for RBAC Testing -======================================== - -Overview -======== - -.. toctree:: - :maxdepth: 2 - - overview - -RBAC Overview -------------- - -.. toctree:: - :maxdepth: 2 - - rbac-overview - multi-policy-validation - -User's Guide -============ - -Patrole Configuration Guide ---------------------------- - -.. toctree:: - :maxdepth: 2 - - configuration - -Patrole Installation Guide --------------------------- - -.. toctree:: - :maxdepth: 2 - - installation - -Field Guides -============ - -.. toctree:: - :maxdepth: 1 - - field_guide/index - field_guide/rbac - -For Contributors -================ - -* If you are a new contributor to Patrole please refer: :doc:`contributor/contributing` - -.. toctree:: - :hidden: - - contributor/contributing - -Developer's Guide -================= - -.. toctree:: - :maxdepth: 1 - - HACKING - REVIEWING - test_writing_guide - -Framework ---------- - -.. toctree:: - :maxdepth: 3 - - framework/overview - framework/rbac_validation - framework/rbac_authority - framework/policy_authority - framework/requirements_authority - framework/rbac_utils - framework/code/modules - -Search -====== - -.. only:: html - - * :ref:`Patrole document search `: Search the contents of this document. - -* `OpenStack wide search `_: Search the wider - set of OpenStack documentation, including forums. diff --git a/doc/source/installation.rst b/doc/source/installation.rst deleted file mode 100644 index 827239ff..00000000 --- a/doc/source/installation.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. _patrole-installation: - -========================== -Patrole Installation Guide -========================== - -Manual Installation Information -=============================== - -At the command line:: - - $ git clone http://git.openstack.org/openstack/patrole - $ sudo pip install ./patrole - -Or, if you have virtualenvwrapper installed:: - - $ mkvirtualenv patrole_env - $ workon patrole_env - $ pip install ./patrole - -Or to install from the source:: - - $ navigate to patrole directory - $ sudo pip install -e . - -DevStack Installation -===================== - -.. include:: ../../devstack/README.rst diff --git a/doc/source/multi-policy-validation.rst b/doc/source/multi-policy-validation.rst deleted file mode 100644 index 441bd35e..00000000 --- a/doc/source/multi-policy-validation.rst +++ /dev/null @@ -1,187 +0,0 @@ -.. _multi-policy-validation: - -======================= -Multi-policy Validation -======================= - -Introduction ------------- - -Multi-policy validation exists in Patrole because if one policy were assumed, -then tests could fail because they would not consider all the policies actually -being enforced. The reasoning can be found in `this spec`_. Basically, -since Patrole derives the expected test result dynamically in order to test any -role, each policy enforced by the API under test must be considered to derive -an accurate expected test result, or else the expected and actual test -results will not always match, resulting in overall test failure. For more -information about Patrole's RBAC validation work flow, reference -:ref:`rbac-validation`. - -Multi-policy support allows Patrole to more accurately offer RBAC tests for API -endpoints that enforce multiple policy actions. - -.. _this spec: http://specs.openstack.org/openstack/qa-specs/specs/patrole/rbac-testing-multiple-policies.html - -Scope ------ - -Multiple policies should be applied only to tests that require them. Not all -API endpoints enforce multiple policies. Some services consistently enforce -1 policy per API, while on the other side of the spectrum, services like -Neutron have much more involved policy enforcement work flows. See -:ref:`neutron-multi-policy-validation` for more information. - -.. _neutron-multi-policy-validation: - -Neutron Multi-policy Validation -------------------------------- - -Neutron can raise different :ref:`policy-error-codes` following failed policy -authorization. Many endpoints in Neutron enforce multiple policies, which -complicates matters when trying to determine whether the endpoint raises a -403 or a 404 following unauthorized access. - -Multi-policy Examples ---------------------- - -General Examples -^^^^^^^^^^^^^^^^ - -Below is an example of multi-policy validation for a carefully chosen Nova API: - -.. code-block:: python - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-lock-server:unlock", - "os_compute_api:os-lock-server:unlock:unlock_override"]) - @decorators.idempotent_id('40dfeef9-73ee-48a9-be19-a219875de457') - def test_unlock_server_override(self): - """Test force unlock server, part of os-lock-server. - - 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(self.server['id']) - self.addCleanup(self.servers_client.unlock_server, self.server['id']) - - with self.override_role(): - self.servers_client.unlock_server(self.server['id']) - -While the ``expected_error_codes`` parameter is omitted in the example above, -Patrole automatically populates it with a 403 for each policy in ``rules``. -Therefore, in the example above, the following expected error codes/rules -relationship is observed: - -* "os_compute_api:os-lock-server:unlock" => 403 -* "os_compute_api:os-lock-server:unlock:unlock_override" => 403 - -Below is an example that uses ``expected_error_codes`` to account for the -fact that Neutron is expected to raise a ``404`` on the first policy that -is enforced server-side ("get_port"). Also, in this example, soft authorization -is performed, meaning that it is necessary to check the response body for an -attribute that is added only following successful policy authorization. - -.. code-block:: python - - @utils.requires_ext(extension='binding', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["get_port", - "get_port:binding:vif_type"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('125aff0b-8fed-4f8e-8410-338616594b06') - def test_show_port_binding_vif_type(self): - - # Verify specific fields of a port - fields = ['binding:vif_type'] - - with self.override_role(): - retrieved_port = self.ports_client.show_port( - self.port['id'], fields=fields)['port'] - - # Rather than throwing a 403, the field is not present, so raise exc. - if fields[0] not in retrieved_port: - raise rbac_exceptions.RbacMalformedResponse( - attribute='binding:vif_type') - -Note that in the example above, failure to authorize -"get_port:binding:vif_type" results in the response body getting successfully -returned by the server, but without additional dictionary keys. If Patrole -fails to find those expected keys, it *acts as though* a 403 was thrown (by -raising an exception itself, the ``rbac_rule_validation`` decorator handles -the rest). - -Neutron Examples -^^^^^^^^^^^^^^^^ - -A basic Neutron example that only expects 403's to be raised: - -.. code-block:: python - - @utils.requires_ext(extension='external-net', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["create_network", - "create_network:router:external"], - expected_error_codes=[403, 403]) - @decorators.idempotent_id('51adf2a7-739c-41e0-8857-3b4c460cbd24') - def test_create_network_router_external(self): - - """Create External Router Network Test - - RBAC test for the neutron create_network:router:external policy - """ - with self.override_role(): - self._create_network(router_external=True) - -Note that above the following expected error codes/rules relationship is -observed: - -* "create_network" => 403 -* "create_network:router:external" => 403 - -A more involved example that expects a 404 to be raised, should the first -policy under ``rules`` fail authorization, and a 403 to be raised for any -subsequent policy authorization failure: - -.. code-block:: python - - @rbac_rule_validation.action(service="neutron", - rules=["get_network", - "update_network", - "update_network:shared"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('37ea3e33-47d9-49fc-9bba-1af98fbd46d6') - def test_update_network_shared(self): - - """Update Shared Network Test - - RBAC test for the neutron update_network:shared policy - """ - with self.override_role(): - self._update_network(shared_network=True) - self.addCleanup(self._update_network, shared_network=False) - -Note that above the following expected error codes/rules relationship is -observed: - -* "get_network" => 404 -* "update_network" => 403 -* "update_network:shared" => 403 - -Limitations ------------ - -Multi-policy validation in RBAC tests comes with limitations, due to technical -and practical challenges. - -Technically, there are challenges associated with multiple policies across -cross-service API communication in OpenStack, such as between Nova and Cinder -or Nova and Neutron. The current framework does not account for these -cross-service policy enforcement workflows, and it is still up for debate -whether it should. - -Practically, it is not possible to enumerate every policy enforced by every API -in Patrole, as the maintenance overhead would be huge. - -.. _Neutron policy documentation: https://docs.openstack.org/neutron/pike/contributor/internals/policy.html diff --git a/doc/source/overview.rst b/doc/source/overview.rst deleted file mode 120000 index c768ff7d..00000000 --- a/doc/source/overview.rst +++ /dev/null @@ -1 +0,0 @@ -../../README.rst \ No newline at end of file diff --git a/doc/source/rbac-overview.rst b/doc/source/rbac-overview.rst deleted file mode 100644 index cf130b06..00000000 --- a/doc/source/rbac-overview.rst +++ /dev/null @@ -1,285 +0,0 @@ -.. _rbac-overview: - -================================== -Role-Based Access Control Overview -================================== - -Introduction ------------- - -Role-Based Access Control (RBAC) is used by most OpenStack services to control -user access to resources. Authorization is granted if a user has the necessary -role to perform an action. Patrole is concerned with validating that each of -these resources *can* be accessed by authorized users and *cannot* be accessed -by unauthorized users. - -OpenStack services use `oslo.policy`_ as the library for RBAC authorization. -Patrole relies on the same library for deriving expected test results. - -.. _policy-in-code: - -Policy in Code --------------- - -Services publish their policy-to-API mapping via policy in code documentation. -This mapping includes the list of APIs that authorize a policy, for each -policy declared within a service. - -For example, Nova's policy in code documentation is located in the -`Nova repository`_ under ``nova/policies``. Likewise, Keystone's policy in -code documentation is located in the `Keystone repository`_ under -``keystone/common/policies``. The other OpenStack services follow the same -directory layout pattern with respect to policy in code. - -The policy in code `governance goal`_ enumerates many advantages with following -this RBAC design approach. A so-called library of in-code policies offers the -following advantages, with respect to facilitating validation: - -* includes every policy enforced by an OpenStack service, enabling the - possibility of complete Patrole test coverage for that service (otherwise - one has to read the source code to discover all the policies) -* provides the policy-to-API mapping for each policy which can be used - to write correct Patrole tests (otherwise reading source code and - experimentation are required to derive this mapping) -* by extension, the policy-to-API mapping facilitates writing multi-policy - Patrole tests (otherwise even more experimentation and code reading is - required to arrive at all the policies enforced by an API) -* policy in code documentation includes additional information, like - descriptions and (in the case of some services, like Keystone) - `scope types`_, which help with understanding how to correctly write - Patrole tests -* by extension, such information helps to determine whether a Patrole test - should assume :term:`hard authorization` or :term:`soft authorization` - -Policy in Code (Default) Validation -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -By default, Patrole validates default OpenStack policies. This is so that -the out-of-the-box defaults are sanity-checked, to ensure that OpenStack -services are secure, from an RBAC perspective, for each release. - -Patrole strives to validate RBAC by using the policy in code documentation, -wherever possible. See :ref:`validation-workflow-overview` for more details. - -.. _custom-policies: - -Custom Policies ---------------- - -Operators can override policy in code defaults using `policy.yaml`_. While -this allows operators to offer more fine-grained RBAC control to their tenants, -it opens the door to misconfiguration and bugs. Patrole can be used to validate -that custom policy overrides don't break anything and work as expected. - -Custom Policy Validation -^^^^^^^^^^^^^^^^^^^^^^^^ - -While testing default policy behavior is a valid use case, oftentimes default -policies are modified with custom overrides in production. OpenStack's -`policy.yaml`_ documentation claims that "modifying policy can have unexpected -side effects", which is why Patrole was created: to ensure that custom -overrides allow the principle of least privilege to be tailor-made to exact -specifications via policy overrides, without: - -* causing unintended side effects (breaking API endpoints, breaking - cross-service workflows, breaking the policy file itself); or -* resulting in poor RBAC configuration, promoting security vulnerabilities - -This has implications on Patrole's :ref:`design-principles`: validating custom -overrides requires the ability to handle arbitrary roles, which requires logic -capable of dynamically determining expected test behavior. - -Note that support for custom policies is limited. This is because custom -policies can be arbitrarily complex, requiring that tests be very robust -in order to handle all edge cases. - -.. _multiple-policies: - -Multiple Policies ------------------ - -Behind the scenes, many APIs enforce multiple policies, for many reasons, -including: - -* to control complex cross-service workflows; -* to control whether a server is booted from an image or booted from a volume - (for example); -* to control whether a response body should contain additional information - conditioned upon successful policy authorization. - -This makes `policy in code`_ especially important for policy validation: it -is difficult to keep track of all the policies being enforced across all the -individual APIs, without policy in code documentation. - -Multi-Policy Validation -^^^^^^^^^^^^^^^^^^^^^^^ - -Patrole offers support for validating APIs that enforce multiple policies. -Perhaps in an ideal world each API endpoint would enforce only one policy, -but in reality some API endpoints enforce multiple policies. Thus, to offer -accurate validation, Patrole handles multiple policies: - -* for services *with* policy in code documentation: this documentation - indicates that a single API endpoint enforces multiple policy actions. -* for services *without* policy in code documentation: the API code clearly - shows multiple policy actions being validated. Note that in this case some - degree of log tracing is required by developers to confirm that the expected - policies are getting enforced, prior to the tests getting merged. - -For more information, see :ref:`multi-policy-validation`. - -.. _policy-error-codes: - -Error Codes ------------ - -Most OpenStack services raise a ``403 Forbidden`` following failed -:term:`hard authorization`. Neutron, however, can raise a ``404 NotFound`` -as well. See Neutron's `authorization policy enforcement`_ documentation -for more details. - -Admin Context Policy --------------------- - -The so-called "admin context" policy refers to the following policy definition -(using the legacy policy file syntax): - -.. code-block:: javascript - - { - "context_is_admin": "role:admin" - ... - } - -Which is unfortunately used to bypass ``oslo.policy`` authorization checks, -for example: - -.. code-block:: python - - # This function is responsible for calling oslo.policy to check whether - # requests are authorized to perform an API action. - def enforce(context, action, target, [...]): - # Here this condition, if True, skips over the enforce call below which - # is what calls oslo.policy. - if context.is_admin: - return True - _ENFORCER.enforce([...]) # This is what can be skipped over. - [...] - -This type of behavior is currently present in many services. Unless such -logic is removed in the future for services that implement it, Patrole -won't really be able to validate that admin role works from an ``oslo.policy`` -perspective. - -Glossary --------- - -The following nomenclature is used throughout Patrole documentation so it is -important to understand what each term means in order to understand concepts -related to RBAC in Patrole. - -.. glossary:: - - authorize - - The act of ``oslo.policy`` determining whether a user can perform a - :term:`policy` given his or her :term:`role`. - - enforce - - See :term:`authorize`. - - hard authorization - - The `do_raise`_ flag controls whether policy authorization should result - in an exception getting raised or a boolean value getting returned. - Hard authorization results in an exception getting raised. Usually, this - results in a ``403 Forbidden`` getting returned for unauthorized requests. - (See :ref:`policy-error-codes` for further details.) - - Related term: :term:`soft authorization`. - - oslo.policy - - The OpenStack library providing support for RBAC policy enforcement across - all OpenStack services. See the `official documentation`_ for more - information. - - policy - - Defines an RBAC rule. Each policy is defined by a one-line statement in - the form "" : "". For more information, reference OpenStack's - `policy documentation`_. - - policy action - - See :term:`policy target`. - - policy file - - Prior to `governance goal`_ used by all OpenStack services to define - policy defaults. Still used by some services, which is why Patrole - needs to read the policy files to derive policy information for testing. - - policy in code - - Registers default OpenStack policies for a service in the service's code - base. - - Beginning with the Queens release, policy in code became a - `governance goal`_. - - policy rule - - The policy rule determines under which circumstances the API call is - permitted. - - policy target - - The name of a policy. - - requirements file - - Requirements-driven approach to declaring the expected RBAC test results - referenced by Patrole. Uses a high-level YAML syntax to crystallize policy - requirements concisely and unambiguously. See :ref:`requirements-authority` - for more information. - - role - - A designation for the set of actions that describe what a user can do in - the system. Roles are managed through the `Keystone Roles API`_. - - Role-Based Access Control (RBAC) - - May be formally defined as "an approach to restricting system access to - authorized users." - - rule - - See :term:`policy rule`. Note that currently the Patrole code base - conflates "rule" with :term:`policy target` in some places. - - soft authorization - - The `do_raise`_ flag controls whether policy authorization should result - in an exception getting raised or a boolean value getting returned. - Soft authorization results in a boolean value getting returned. When policy - authorization evaluates to true, additional operations are performed as a - part of the API request or additional information is included in the - response body (see `response filtering`_ for an example). - - Related term: :term:`hard authorization`. - -.. _Nova repository: https://git.openstack.org/cgit/openstack/nova/tree/nova/policies -.. _Keystone repository: https://git.openstack.org/cgit/openstack/keystone/tree/keystone/common/policies -.. _governance goal: https://governance.openstack.org/tc/goals/queens/policy-in-code.html -.. _scope types: https://docs.openstack.org/keystone/latest/admin/tokens-overview.html#authorization-scopes -.. _policy.yaml: https://docs.openstack.org/ocata/config-reference/policy-yaml-file.html -.. _oslo.policy: https://docs.openstack.org/oslo.policy/latest/ -.. _policy documentation: https://docs.openstack.org/kilo/config-reference/content/policy-json-file.html -.. _do_raise: https://docs.openstack.org/oslo.policy/latest/reference/api/oslo_policy.policy.html#oslo_policy.policy.Enforcer.enforce -.. _authorization policy enforcement: https://docs.openstack.org/neutron/latest/contributor/internals/policy.html -.. _official documentation: https://docs.openstack.org/oslo.policy/latest/ -.. _Keystone Roles API: https://docs.openstack.org/api-ref/identity/v3/#roles -.. _response filtering: https://docs.openstack.org/neutron/latest/contributor/internals/policy.html#response-filtering diff --git a/doc/source/test_writing_guide.rst b/doc/source/test_writing_guide.rst deleted file mode 100644 index ac502103..00000000 --- a/doc/source/test_writing_guide.rst +++ /dev/null @@ -1,166 +0,0 @@ -Patrole Test Writing Overview -============================= - -Introduction ------------- - -Patrole tests are broken up into 3 stages: - -#. :ref:`rbac-test-setup` -#. :ref:`rbac-test-execution` -#. :ref:`rbac-test-cleanup` - -See the :ref:`framework overview documentation ` -for a high-level explanation of the entire testing work flow and framework -implementation. The guide that follows is concerned with helping developers -know how to write Patrole tests. - -.. _role-overriding: - -Role Overriding ---------------- - -Role overriding is the way Patrole is able to create resources and delete -resources -- including those that require admin credentials -- while still -being able to exercise the same set of Tempest credentials to perform the API -action that authorizes the policy under test, by manipulating roles of the -Tempest credentials. - -Patrole implicitly splits up each test into 3 stages: set up, test execution, -and teardown. - -The role workflow is as follows: - -#. Setup: Admin role is used automatically. The primary credentials are - overridden with the admin role. -#. Test execution: ``[patrole] rbac_test_roles`` is used manually via the - call to ``with self.override_role()``. Everything that - is executed within this contextmanager uses the primary - credentials overridden with the ``[patrole] rbac_test_roles``. -#. Teardown: Admin role is used automatically. The primary credentials have - been overridden with the admin role. - -.. _rbac-test-setup: - -Test Setup ----------- - -Automatic role override in background. - -Resources can be set up inside the ``resource_setup`` class method that Tempest -provides. These resources are typically reserved for "expensive" resources -in terms of memory or storage requirements, like volumes and VMs. These -resources are **always** created via the admin role; Patrole automatically -handles this. - -Like Tempest, however, Patrole must also create resources inside tests -themselves. At the beginning of each test, the primary credentials have already -been overridden with the admin role. One can create whatever test-level -resources one needs, without having to worry about permissions. - -.. _rbac-test-execution: - -Test Execution --------------- - -Manual role override required. - -"Test execution" here means calling the API endpoint that enforces the policy -action expected by the ``rbac_rule_validation`` decorator. Test execution -should be performed *only after* calling -``with self.override_role()``. - -Immediately after that call, the API endpoint that enforces the policy should -be called. - -Examples -^^^^^^^^ - -Always use the contextmanager before calling the API that enforces the -expected policy action. - -Example:: - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-aggregates:show"]) - def test_show_aggregate_rbac(self): - # Do test setup before the ``override_role`` call. - aggregate_id = self._create_aggregate() - # Call the ``override_role`` method so that the primary credentials - # have the test role needed for test execution. - with self.override_role(): - self.aggregates_client.show_aggregate(aggregate_id) - -When using a waiter, do the wait outside the contextmanager. "Waiting" always -entails executing a ``GET`` request to the server, until the state of the -returned resource matches a desired state. These ``GET`` requests enforce -a different policy than the one expected. This is undesirable because -Patrole should only test policies in isolation from one another. - -Otherwise, the test result will be tainted, because instead of only the -expected policy getting enforced with the ``os_primary`` role, at least -two policies get enforced. - -Example using waiter:: - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-admin-password"]) - def test_change_server_password(self): - original_password = self.servers_client.show_password( - self.server['id']) - self.addCleanup(self.servers_client.change_password, self.server['id'], - adminPass=original_password) - - with self.override_role(): - self.servers_client.change_password( - self.server['id'], adminPass=data_utils.rand_password()) - # Call the waiter outside the ``override_role`` contextmanager, so that - # it is executed with admin role. - waiters.wait_for_server_status( - self.servers_client, self.server['id'], 'ACTIVE') - -Below is an example of a method that enforces multiple policies getting -called inside the contextmanager. The ``_complex_setup_method`` below -performs the correct API that enforces the expected policy -- in this -case ``self.resources_client.create_resource`` -- but then proceeds to -use a waiter. - -Incorrect:: - - def _complex_setup_method(self): - resource = self.resources_client.create_resource( - **kwargs)['resource'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self._delete_resource, resource) - waiters.wait_for_resource_status( - self.resources_client, resource['id'], 'available') - return resource - - @rbac_rule_validation.action( - service="example-service", - rules=["example-rule"]) - def test_change_server_password(self): - # Never call a helper function inside the contextmanager that calls a - # bunch of APIs. Only call the API that enforces the policy action - # contained in the decorator above. - with self.override_role(): - self._complex_setup_method() - -To fix this test, see the "Example using waiter" section above. It is -recommended to re-implement the logic in a helper method inside a test such -that only the relevant API is called inside the contextmanager, with -everything extraneous outside. - -.. _rbac-test-cleanup: - -Test Cleanup ------------- - -Automatic role override in background. - -After the test -- no matter whether it ended successfully or in failure -- -the credentials are overridden with the admin role by the Patrole framework, -*before* ``tearDown`` or ``tearDownClass`` are called. This means that -resources are always cleaned up using the admin role. diff --git a/etc/config-generator.patrole.conf b/etc/config-generator.patrole.conf deleted file mode 100644 index 8988ae00..00000000 --- a/etc/config-generator.patrole.conf +++ /dev/null @@ -1,3 +0,0 @@ -[DEFAULT] -output_file = etc/patrole.conf.sample -namespace = patrole.config diff --git a/etc/patrole.conf.sample b/etc/patrole.conf.sample deleted file mode 100644 index 42f10421..00000000 --- a/etc/patrole.conf.sample +++ /dev/null @@ -1,172 +0,0 @@ -[DEFAULT] - - -[patrole] - -# -# From patrole.config -# - -# DEPRECATED: The current RBAC role against which to run -# Patrole tests. (string value) -# This option is deprecated for removal. -# Its value may be silently ignored in the future. -# Reason: This option is deprecated and being -# replaced with ``rbac_test_roles``. -#rbac_test_role = - -# The current RBAC roles to be assigned to Keystone -# Group against which to run Patrole tests. (list value) -#rbac_test_roles = admin - -# List of the paths to search for policy files. Each -# policy path assumes that the service name is included in the path -# once. Also -# assumes Patrole is on the same host as the policy files. The paths -# should be -# ordered by precedence, with high-priority paths before low-priority -# paths. All -# the paths that are found to contain the service's policy file will -# be used and -# all policy files will be merged. Allowed ``json`` or ``yaml`` -# formats. -# (list value) -#custom_policy_files = /etc/%s/policy.json - -# -# This option determines whether Patrole should run against a -# ``custom_requirements_file`` which defines RBAC requirements. The -# purpose of setting this flag to ``True`` is to verify that RBAC -# policy -# is in accordance to requirements. The idea is that the -# ``custom_requirements_file`` precisely defines what the RBAC -# requirements are. -# -# Here are the possible outcomes when running the Patrole tests -# against -# a ``custom_requirements_file``: -# -# YAML definition: allowed -# test run: allowed -# test result: pass -# -# YAML definition: allowed -# test run: not allowed -# test result: fail (under-permission) -# -# YAML definition: not allowed -# test run: allowed -# test result: fail (over-permission) -# (boolean value) -#test_custom_requirements = false - -# -# File path of the YAML file that defines your RBAC requirements. This -# file must be located on the same host that Patrole runs on. The YAML -# file should be written as follows: -# -# .. code-block:: yaml -# -# : -# : -# - -# - -# - -# : -# - -# - -# : -# : -# - -# -# Where: -# -# service = the service that is being tested (cinder, nova, etc.). -# -# api_action = the policy action that is being tested. Examples: -# -# * volume:create -# * os_compute_api:servers:start -# * add_image -# -# allowed_role = the ``oslo.policy`` role that is allowed to perform -# the API. -# (string value) -#custom_requirements_file = - - -[patrole_log] - -# -# From patrole.config -# - -# Enables reporting on RBAC expected and actual test results for each -# Patrole test (boolean value) -#enable_reporting = false - -# Name of file where output from 'enable_reporting' is logged. Note -# that this file is recreated on each invocation of patrole (string -# value) -#report_log_name = patrole.log - -# Path (relative or absolute) where the output from 'enable_reporting' -# is logged. This is combined withreport_log_name to generate the full -# path. (string value) -#report_log_path = . - - -[policy-feature-enabled] - -# -# From patrole.config -# - -# Is the Neutron policy -# "create_port:fixed_ips:ip_address" available in the cloud? This -# policy was -# changed in a backwards-incompatible way. (boolean value) -#create_port_fixed_ips_ip_address_policy = true - -# Is the Neutron policy -# "update_port:fixed_ips:ip_address" available in the cloud? This -# policy was -# changed in a backwards-incompatible way. (boolean value) -#update_port_fixed_ips_ip_address_policy = true - -# Is the Cinder policy -# "limits_extension:used_limits" available in the cloud? This policy -# was -# changed in a backwards-incompatible way. (boolean value) -#limits_extension_used_limits_policy = true - -# Is the Cinder policy -# "volume_extension:volume_actions:attach" available in the cloud? -# This policy -# was changed in a backwards-incompatible way. (boolean value) -#volume_extension_volume_actions_attach_policy = true - -# Is the Cinder policy -# "volume_extension:volume_actions:reserve" available in the cloud? -# This policy -# was changed in a backwards-incompatible way. (boolean value) -#volume_extension_volume_actions_reserve_policy = true - -# Is the Cinder policy -# "volume_extension:volume_actions:unreserve" available in the cloud? -# This policy -# was changed in a backwards-incompatible way. (boolean value) -#volume_extension_volume_actions_unreserve_policy = true - -# Are the Nova API extension policies available in the -# cloud (e.g. os_compute_api:os-extended-availability-zone)? These -# policies were -# removed in Stein because Nova API extension concept was removed in -# Pike. (boolean value) -#removed_nova_policies_stein = true - -# Are the Cinder API extension policies available in the -# cloud (e.g. [create|update|get|delete]_encryption_policy)? These -# policies are -# added in Stein. (boolean value) -#added_cinder_policies_stein = true diff --git a/lower-constraints.txt b/lower-constraints.txt deleted file mode 100644 index a9fa87ac..00000000 --- a/lower-constraints.txt +++ /dev/null @@ -1,76 +0,0 @@ -alabaster==0.7.10 -appdirs==1.4.3 -asn1crypto==0.24.0 -Babel==2.5.3 -bcrypt==3.1.4 -certifi==2018.1.18 -cffi==1.14.0 -chardet==3.0.4 -cliff==2.11.0 -cmd2==0.8.1 -coverage==4.0 -cryptography==2.1.4 -debtcollector==1.19.0 -docutils==0.14 -dulwich==0.19.0 -extras==1.0.0 -fasteners==0.14.1 -fixtures==3.0.0 -future==0.16.0 -idna==2.6 -imagesize==1.0.0 -iso8601==0.1.12 -Jinja2==2.10 -jsonschema==2.6.0 -keystoneauth1==3.4.0 -linecache2==1.0.0 -MarkupSafe==1.0 -mccabe==0.2.1 -mock==2.0.0 -monotonic==1.4 -mox3==0.25.0 -msgpack==0.5.6 -netaddr==0.7.19 -netifaces==0.10.6 -nose==1.3.7 -nosexcover==1.0.10 -os-client-config==1.29.0 -oslo.concurrency==3.26.0 -oslo.config==5.2.0 -oslo.context==2.20.0 -oslo.i18n==3.20.0 -oslo.log==3.36.0 -oslo.policy==1.30.0 -oslo.serialization==2.25.0 -oslo.utils==3.36.0 -oslotest==3.2.0 -paramiko==2.4.1 -pbr==2.0.0 -prettytable==0.7.2 -pyasn1==0.4.2 -pycparser==2.18 -Pygments==2.2.0 -pyinotify==0.9.6 -PyNaCl==1.2.1 -pyparsing==2.2.0 -pyperclip==1.6.0 -python-dateutil==2.7.0 -python-mimeparse==1.6.0 -python-subunit==1.2.0 -pytz==2018.3 -PyYAML==3.13 -requests==2.18.4 -requestsexceptions==1.4.0 -rfc3986==1.1.0 -six==1.11.0 -snowballstemmer==1.2.1 -stestr==2.0.0 -stevedore==1.20.0 -tempest==30.0.0 -testrepository==0.0.20 -testtools==2.3.0 -traceback2==1.4.0 -unittest2==1.1.0 -urllib3==1.22 -voluptuous==0.11.1 -wrapt==1.10.11 diff --git a/patrole_tempest_plugin/__init__.py b/patrole_tempest_plugin/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/patrole_tempest_plugin/config.py b/patrole_tempest_plugin/config.py deleted file mode 100644 index e6d25159..00000000 --- a/patrole_tempest_plugin/config.py +++ /dev/null @@ -1,229 +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 oslo_config import cfg - - -patrole_group = cfg.OptGroup(name='patrole', title='Patrole Testing Options') - - -PatroleGroup = [ - cfg.StrOpt('rbac_test_role', - default='admin', - deprecated_for_removal=True, - deprecated_reason="""This option is deprecated and being -replaced with ``rbac_test_roles``. -""", - help="""The current RBAC role against which to run -Patrole tests."""), - cfg.ListOpt('rbac_test_roles', - help="""List of the RBAC roles against which to run -Patrole tests.""", - default=['admin']), - cfg.ListOpt('custom_policy_files', - default=['/etc/%s/policy.json'], - help="""List of the paths to search for policy files. Each -policy path assumes that the service name is included in the path once. Also -assumes Patrole is on the same host as the policy files. The paths should be -ordered by precedence, with high-priority paths before low-priority paths. All -the paths that are found to contain the service's policy file will be used and -all policy files will be merged. Allowed ``json`` or ``yaml`` formats. -"""), - cfg.BoolOpt('test_custom_requirements', - default=False, - help=""" -This option determines whether Patrole should run against a -``custom_requirements_file`` which defines RBAC requirements. The -purpose of setting this flag to ``True`` is to verify that RBAC policy -is in accordance to requirements. The idea is that the -``custom_requirements_file`` precisely defines what the RBAC requirements are. - -Here are the possible outcomes when running the Patrole tests against -a ``custom_requirements_file``: - -YAML definition: allowed -test run: allowed -test result: pass - -YAML definition: allowed -test run: not allowed -test result: fail (under-permission) - -YAML definition: not allowed -test run: allowed -test result: fail (over-permission) -"""), - cfg.StrOpt('custom_requirements_file', - help=""" -File path of the YAML file that defines your RBAC requirements. This -file must be located on the same host that Patrole runs on. The YAML -file should be written as follows: - -.. code-block:: yaml - - : - : - - - - - - - : - - - - - : - : - - - -Where: - -service = the service that is being tested (Cinder, Nova, etc.). - -api_action = the policy action that is being tested. Examples: - -* volume:create -* os_compute_api:servers:start -* add_image - -allowed_role = the ``oslo.policy`` role that is allowed to perform the API. -"""), - cfg.BoolOpt('validate_deprecated_rules', default=True, - help="""Some of the policy rules have deprecated version, -Patrole should be able to run check against default and deprecated rules, -otherwise the result of the tests may not be correct. -""") -] - - -patrole_log_group = cfg.OptGroup( - name='patrole_log', title='Patrole Logging Options') - - -PatroleLogGroup = [ - cfg.BoolOpt('enable_reporting', - default=False, - help="Enables reporting on RBAC expected and actual test " - "results for each Patrole test"), - cfg.StrOpt('report_log_name', - default='patrole.log', - help="Name of file where output from 'enable_reporting' is " - "logged. Note that this file is recreated on each " - "invocation of patrole"), - cfg.StrOpt('report_log_path', - default='.', - help="Path (relative or absolute) where the output from " - "'enable_reporting' is logged. This is combined with " - "report_log_name to generate the full path."), -] - - -policy_feature_enabled = cfg.OptGroup( - name='policy-feature-enabled', - title='Feature Flags for New or Changed Policies') - - -PolicyFeatureEnabledGroup = [ - # TODO(felipemonteiro): The 6 feature flags below should be removed after - # Pike is EOL. - cfg.BoolOpt('create_port_fixed_ips_ip_address_policy', - default=True, - help="""Is the Neutron policy -"create_port:fixed_ips:ip_address" available in the cloud? This policy was -changed in a backwards-incompatible way."""), - cfg.BoolOpt('update_port_fixed_ips_ip_address_policy', - default=True, - help="""Is the Neutron policy -"update_port:fixed_ips:ip_address" available in the cloud? This policy was -changed in a backwards-incompatible way."""), - cfg.BoolOpt('limits_extension_used_limits_policy', - default=True, - help="""Is the Cinder policy -"limits_extension:used_limits" available in the cloud? This policy was -changed in a backwards-incompatible way."""), - cfg.BoolOpt('volume_extension_volume_actions_attach_policy', - default=True, - help="""Is the Cinder policy -"volume_extension:volume_actions:attach" available in the cloud? This policy -was changed in a backwards-incompatible way."""), - cfg.BoolOpt('volume_extension_volume_actions_reserve_policy', - default=True, - help="""Is the Cinder policy -"volume_extension:volume_actions:reserve" available in the cloud? This policy -was changed in a backwards-incompatible way."""), - cfg.BoolOpt('volume_extension_volume_actions_unreserve_policy', - default=True, - help="""Is the Cinder policy -"volume_extension:volume_actions:unreserve" available in the cloud? This policy -was changed in a backwards-incompatible way."""), - # *** Include feature flags for groups of policies below. *** - # Best practice is to capture new policies, removed policies, renamed - # policies in a group, per release. - # - # TODO(felipemonteiro): Remove these feature flags once Stein is EOL. - cfg.BoolOpt('removed_nova_policies_stein', - default=True, - help="""Are the Nova API extension policies available in the -cloud (e.g. os_compute_api:os-extended-availability-zone)? These policies were -removed in Stein because Nova API extension concept was removed in Pike."""), - # TODO(gmann): Remove these feature flags once Victoria is EOL. - cfg.BoolOpt('removed_nova_policies_wallaby', - default=True, - help="""Are the Nova API policies being removed in wallaby -cycle (e.g. os_compute_api:os-agents)?"""), - cfg.BoolOpt('removed_keystone_policies_stein', - default=True, - help="""Are the obsolete Keystone policies available in the -cloud (e.g. identity:[create|update|get|delete]_credential)? These policies -were removed in Stein."""), - cfg.BoolOpt('added_cinder_policies_stein', - default=True, - help="""Are the Cinder Stein policies available in the cloud -(e.g. [create|update|get|delete]_encryption_policy)? These policies are added -in Stein."""), - cfg.BoolOpt('keystone_policy_enforcement_train', - default=True, - help="""Is the cloud running the Train release or newer? If -so, the Keystone Trust API is enforced differently depending on passed -arguments"""), - cfg.BoolOpt('changed_nova_policies_ussuri', - default=True, - help="""Are the Nova API policies available in the -cloud (e.g. os_compute_api:os-services)? These policies were -changed in Ussuri."""), - cfg.BoolOpt('changed_nova_policies_victoria', - default=True, - help="""Are the Nova deprecated API policies available in the -cloud (e.g. os_compute_api:os-networks)? These policies were -changed in Victoria."""), - cfg.BoolOpt('changed_cinder_policies_xena', - default=True, - help="""Are the Cinder API policies changed in the -cloud (e.g. 'group:group_types_specs')? These policies were -changed in Xena.""") -] - - -def list_opts(): - """Return a list of oslo.config options available. - - The purpose of this is to allow tools like the Oslo sample config file - generator to discover the options exposed to users. - """ - opt_list = [ - (patrole_group, PatroleGroup), - (patrole_log_group, PatroleLogGroup), - (policy_feature_enabled, PolicyFeatureEnabledGroup) - - ] - - return opt_list diff --git a/patrole_tempest_plugin/hacking/__init__.py b/patrole_tempest_plugin/hacking/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/patrole_tempest_plugin/hacking/checks.py b/patrole_tempest_plugin/hacking/checks.py deleted file mode 100644 index 48ef2695..00000000 --- a/patrole_tempest_plugin/hacking/checks.py +++ /dev/null @@ -1,249 +0,0 @@ -# Copyright 2013 IBM Corp. -# 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. - -import os -import re - -from hacking import core -import pycodestyle - - -PYTHON_CLIENTS = ['cinder', 'glance', 'keystone', 'nova', 'swift', 'neutron', - 'ironic', 'heat', 'sahara'] - -PYTHON_CLIENT_RE = re.compile('import (%s)client' % '|'.join(PYTHON_CLIENTS)) -TEST_DEFINITION = re.compile(r'^\s*def test.*') -SETUP_TEARDOWN_CLASS_DEFINITION = re.compile(r'^\s+def (setUp|tearDown)Class') -SCENARIO_DECORATOR = re.compile(r'\s*@.*services\((.*)\)') -RAND_NAME_HYPHEN_RE = re.compile(r".*rand_name\(.+[\-\_][\"\']\)") -MUTABLE_DEFAULT_ARGS = re.compile(r"^\s*def .+\((.+=\{\}|.+=\[\])") -TESTTOOLS_SKIP_DECORATOR = re.compile(r'\s*@testtools\.skip\((.*)\)') -CLASS = re.compile(r"^class .+") -RBAC_CLASS_NAME_RE = re.compile(r'class .+RbacTest') -RULE_VALIDATION_DECORATOR = re.compile( - r'\s*@rbac_rule_validation.action\(.*') -IDEMPOTENT_ID_DECORATOR = re.compile(r'\s*@decorators\.idempotent_id\((.*)\)') -EXT_RBAC_TEST = re.compile( - r"class .+\(.+ExtRbacTest\)|class .+ExtRbacTest\(.+\)") - -have_rbac_decorator = False - - -@core.flake8ext -def import_no_clients_in_api_tests(physical_line, filename): - """Check for client imports from patrole_tempest_plugin/tests/api - - T102: Cannot import OpenStack python clients - """ - if "patrole_tempest_plugin/tests/api" in filename: - res = PYTHON_CLIENT_RE.match(physical_line) - if res: - return (physical_line.find(res.group(1)), - ("T102: python clients import not allowed " - "in patrole_tempest_plugin/tests/api/* or " - "patrole_tempest_plugin/tests/scenario/* tests")) - - -@core.flake8ext -def no_setup_teardown_class_for_tests(physical_line, filename): - """Check that tests do not use setUpClass/tearDownClass - - T105: Tests cannot use setUpClass/tearDownClass - """ - if pycodestyle.noqa(physical_line): - return - - if SETUP_TEARDOWN_CLASS_DEFINITION.match(physical_line): - return (physical_line.find('def'), - "T105: (setUp|tearDown)Class can not be used in tests") - - -@core.flake8ext -def service_tags_not_in_module_path(physical_line, filename): - """Check that a service tag isn't in the module path - - A service tag should only be added if the service name isn't already in - the module path. - - T107 - """ - matches = SCENARIO_DECORATOR.match(physical_line) - if matches: - services = matches.group(1).split(',') - for service in services: - service_name = service.strip().strip("'") - modulepath = os.path.split(filename)[0] - if service_name in modulepath: - return (physical_line.find(service_name), - "T107: service tag should not be in path") - - -@core.flake8ext -def no_hyphen_at_end_of_rand_name(logical_line, filename): - """Check no hyphen at the end of rand_name() argument - - T108 - """ - msg = "T108: hyphen should not be specified at the end of rand_name()" - if RAND_NAME_HYPHEN_RE.match(logical_line): - return 0, msg - - -@core.flake8ext -def no_mutable_default_args(logical_line): - """Check that mutable object isn't used as default argument - - N322: Method's default argument shouldn't be mutable - """ - msg = "N322: Method's default argument shouldn't be mutable!" - if MUTABLE_DEFAULT_ARGS.match(logical_line): - yield (0, msg) - - -@core.flake8ext -def no_testtools_skip_decorator(logical_line): - """Check that methods do not have the testtools.skip decorator - - T109 - """ - if TESTTOOLS_SKIP_DECORATOR.match(logical_line): - yield (0, "T109: Cannot use testtools.skip decorator; instead use " - "decorators.skip_because from tempest.lib") - - -@core.flake8ext -def use_rand_uuid_instead_of_uuid4(logical_line, filename): - """Check that tests use data_utils.rand_uuid() instead of uuid.uuid4() - - T113 - """ - if 'uuid.uuid4()' not in logical_line: - return - - msg = ("T113: Tests should use data_utils.rand_uuid()/rand_uuid_hex() " - "instead of uuid.uuid4()/uuid.uuid4().hex") - yield (0, msg) - - -@core.flake8ext -def no_rbac_rule_validation_decorator(physical_line, filename): - """Check that each test has the ``rbac_rule_validation.action`` decorator. - - Checks whether the test function has "@rbac_rule_validation.action" - above it; otherwise checks that it has "@decorators.idempotent_id" above - it and "@rbac_rule_validation.action" above that. - - Assumes that ``rbac_rule_validation.action`` decorator is either the first - or second decorator above the test function; otherwise this check fails. - - P100 - """ - global have_rbac_decorator - - if ("patrole_tempest_plugin/tests/api" in filename or - "patrole_tempest_plugin/tests/scenario" in filename): - - if RULE_VALIDATION_DECORATOR.match(physical_line): - have_rbac_decorator = True - return - - if TEST_DEFINITION.match(physical_line): - if not have_rbac_decorator: - return (0, "Must use rbac_rule_validation.action " - "decorator for API and scenario tests") - - have_rbac_decorator = False - - -@core.flake8ext -def no_rbac_suffix_in_test_filename(filename): - """Check that RBAC filenames end with "_rbac" suffix. - - P101 - """ - if "patrole_tempest_plugin/tests/api" in filename: - - if filename.endswith('rbac_base.py'): - return - - if not filename.endswith('_rbac.py'): - return 0, "RBAC test filenames must end in _rbac suffix" - - -@core.flake8ext -def no_rbac_test_suffix_in_test_class_name(physical_line, filename): - """Check that RBAC class names end with "RbacTest" - - P102 - """ - if "patrole_tempest_plugin/tests/api" in filename: - - if filename.endswith('rbac_base.py'): - return - - if CLASS.match(physical_line): - if not RBAC_CLASS_NAME_RE.match(physical_line): - return 0, "RBAC test class names must end in 'RbacTest'" - - -@core.flake8ext -def no_client_alias_in_test_cases(logical_line, filename): - """Check that test cases don't use "self.client" to define a client. - - P103 - """ - if "patrole_tempest_plugin/tests/api" in filename: - if "self.client" in logical_line or "cls.client" in logical_line: - return 0, "Do not use 'self.client' as a service client alias" - - -@core.flake8ext -def no_extension_rbac_test_suffix_in_plugin_test_class_name(physical_line, - filename): - """Check that Extension RBAC class names end with "ExtRbacTest" - - P104 - """ - suffix = "ExtRbacTest" - if "patrole_tempest_plugin/tests/api" in filename: - if EXT_RBAC_TEST.match(physical_line): - subclass, superclass = physical_line.split('(') - subclass = subclass.split('class')[1].strip() - superclass = superclass.split(')')[0].strip() - if "." in superclass: - superclass = superclass.split(".")[1] - - both_have = all( - clazz.endswith(suffix) for clazz in [subclass, superclass]) - none_have = not any( - clazz.endswith(suffix) for clazz in [subclass, superclass]) - - if not (both_have or none_have): - if (subclass.startswith("Base") and - superclass.startswith("Base")): - return - - # Case 1: Subclass of "BaseExtRbacTest" must end in `suffix` - # Case 2: Subclass that ends in `suffix` must inherit from base - # class ending in `suffix`. - if not subclass.endswith(suffix): - error = ("Plugin RBAC test subclasses must end in " - "'ExtRbacTest'") - return len(subclass) - 1, error - elif not superclass.endswith(suffix): - error = ("Plugin RBAC test subclasses must inherit from a " - "'ExtRbacTest' base class") - return len(superclass) - 1, error diff --git a/patrole_tempest_plugin/plugin.py b/patrole_tempest_plugin/plugin.py deleted file mode 100644 index 8af6a69d..00000000 --- a/patrole_tempest_plugin/plugin.py +++ /dev/null @@ -1,86 +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. - -import logging -import os - -from oslo_concurrency import lockutils - -from tempest import config -from tempest.test_discover import plugins - -from patrole_tempest_plugin import config as pconfig - -RBACLOG = logging.getLogger('rbac_reporting') - - -class PatroleTempestPlugin(plugins.TempestPlugin): - - def load_tests(self): - base_path = os.path.split(os.path.dirname( - os.path.abspath(__file__)))[0] - test_dir = "patrole_tempest_plugin/tests/api" - full_test_dir = os.path.join(base_path, test_dir) - return full_test_dir, base_path - - @lockutils.synchronized('_reset_log_file') - def _reset_log_file(self, logfile): - try: - os.remove(logfile) - except OSError: - pass - - def _configure_per_test_logging(self, conf): - # Separate log handler for rbac reporting - RBACLOG.setLevel(level=logging.INFO) - # Set up proper directory handling - report_abs_path = os.path.abspath(conf.patrole_log.report_log_path) - report_path = os.path.join( - report_abs_path, conf.patrole_log.report_log_name) - - # Remove the log file if it exists - self._reset_log_file(report_path) - - # Delay=True so that we don't end up creating an empty file if we - # never log to it. - rbac_report_handler = logging.FileHandler( - filename=report_path, delay=True, mode='a') - rbac_report_handler.setFormatter( - fmt=logging.Formatter(fmt='%(message)s')) - RBACLOG.addHandler(rbac_report_handler) - - def register_opts(self, conf): - config.register_opt_group( - conf, - pconfig.patrole_group, - pconfig.PatroleGroup) - config.register_opt_group( - conf, - pconfig.patrole_log_group, - pconfig.PatroleLogGroup) - config.register_opt_group( - conf, - pconfig.policy_feature_enabled, - pconfig.PolicyFeatureEnabledGroup) - - if conf.patrole_log.enable_reporting: - self._configure_per_test_logging(conf) - - def get_opt_lists(self): - return [ - (pconfig.patrole_group.name, pconfig.PatroleGroup), - (pconfig.policy_feature_enabled.name, - pconfig.PolicyFeatureEnabledGroup) - ] diff --git a/patrole_tempest_plugin/policy_authority.py b/patrole_tempest_plugin/policy_authority.py deleted file mode 100644 index 914f2f9a..00000000 --- a/patrole_tempest_plugin/policy_authority.py +++ /dev/null @@ -1,330 +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. - -import collections -import copy -import glob -import os - -from oslo_log import log as logging -from oslo_policy import policy -import pkg_resources -import stevedore -from tempest import config - -from patrole_tempest_plugin.rbac_authority import RbacAuthority -from patrole_tempest_plugin import rbac_exceptions - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class PolicyAuthority(RbacAuthority): - """A class that uses ``oslo.policy`` for validating RBAC.""" - os_admin = None - - def __init__(self, project_id, user_id, service, extra_target_data=None): - """Initialization of Policy Authority class. - - Validates whether a test role can perform a policy action by querying - ``oslo.policy`` with necessary test data. - - If a policy file does not exist, checks whether the policy file is - registered as a namespace under "oslo.policy.policies". Nova, for - example, doesn't use a policy file by default; its policies are - implemented in code and registered as "nova" under - "oslo.policy.policies". - - If the policy file is not found in either code or in a policy file, - then an exception is raised. - - Additionally, if a custom policy file exists along with the default - policy in code implementation, the custom policy is prioritized. - - :param uuid project_id: project_id of object performing API call - :param uuid user_id: user_id of object performing API call - :param string service: service of the policy file - :param dict extra_target_data: dictionary containing additional object - data needed by oslo.policy to validate generic checks - - Example: - - .. code-block:: python - - # Below is the default policy implementation in code, defined in - # a service like Nova. - test_policies = [ - policy.DocumentedRuleDefault( - 'service:test_rule', - base.RULE_ADMIN_OR_OWNER, - "This is a description for a test policy", - [ - { - 'method': 'POST', - 'path': '/path/to/test/resource' - } - ]), - 'service:another_test_rule', - base.RULE_ADMIN_OR_OWNER, - "This is a description for another test policy", - [ - { - 'method': 'GET', - 'path': '/path/to/test/resource' - } - ]), - ] - - .. code-block:: yaml - - # Below is the custom override of the default policy in a YAML - # policy file. Note that the default rule is "rule:admin_or_owner" - # and the custom rule is "rule:admin_api". The `PolicyAuthority` - # class will use the "rule:admin_api" definition for this policy - # action. - "service:test_rule" : "rule:admin_api" - - # Note below that no override is provided for - # "service:another_test_rule", which means that the default policy - # rule is used: "rule:admin_or_owner". - """ - - if extra_target_data is None: - extra_target_data = {} - - self.service = self.validate_service(service) - - # Prioritize dynamically searching for policy files over relying on - # deprecated service-specific policy file locations. - if CONF.patrole.custom_policy_files: - self.discover_policy_files() - - self.rules = self.get_rules() - self.project_id = project_id - self.user_id = user_id - self.extra_target_data = extra_target_data - - @classmethod - def validate_service(cls, service): - """Validate whether the service passed to ``__init__`` exists.""" - service = service.lower().strip() if service else None - - # Cache the list of available services in memory to avoid needlessly - # doing an API call every time. - if not hasattr(cls, 'available_services') and cls.os_admin: - services_client = (cls.os_admin.identity_services_v3_client - if CONF.identity_feature_enabled.api_v3 - else cls.os_admin.identity_services_client) - services = services_client.list_services()['services'] - cls.available_services = [s['name'] for s in services] - - if not service or service not in cls.available_services: - LOG.debug("%s is NOT a valid service.", service) - raise rbac_exceptions.RbacInvalidServiceException( - "%s is NOT a valid service." % service) - - return service - - @classmethod - def discover_policy_files(cls): - """Dynamically discover the policy file for each service in - ``cls.available_services``. Pick all candidate paths found - out of the potential paths in ``[patrole] custom_policy_files``. - """ - if not hasattr(cls, 'policy_files'): - cls.policy_files = collections.defaultdict(list) - for service in cls.available_services: - for candidate_path in CONF.patrole.custom_policy_files: - path = candidate_path % service - for filename in glob.iglob(path): - if os.path.isfile(filename): - cls.policy_files[service].append(filename) - - def allowed(self, rule_name, roles): - """Checks if a given rule in a policy is allowed with given role. - - :param string rule_name: Policy name to pass to``oslo.policy``. - :param List[string] roles: List of roles to validate for authorization. - :raises RbacParsingException: If ``rule_name`` does not exist in the - cloud (in policy file or among registered in-code policy defaults). - """ - is_admin_context = self._is_admin_context(roles) - is_allowed = self._allowed( - access=self._get_access_token(roles), - apply_rule=rule_name, - is_admin=is_admin_context) - return is_allowed - - def _handle_deprecated_rule(self, default): - deprecated_rule = default.deprecated_rule - deprecated_msg = ( - 'Policy "%(old_name)s":"%(old_check_str)s" was deprecated in ' - '%(release)s in favor of "%(name)s":"%(check_str)s". Reason: ' - '%(reason)s. Either ensure your deployment is ready for the new ' - 'default or copy/paste the deprecated policy into your policy ' - 'file and maintain it manually.' % { - 'old_name': deprecated_rule.name, - 'old_check_str': deprecated_rule.check_str, - 'release': default.deprecated_since, - 'name': default.name, - 'check_str': default.check_str, - 'reason': default.deprecated_reason - } - ) - LOG.warn(deprecated_msg) - oslo_policy_version = pkg_resources.parse_version( - pkg_resources.get_distribution("oslo.policy").version) - # NOTE(gmann): oslo policy 3.7.0 onwards does not allow to modify - # the Rule object check attribute. - required_version = pkg_resources.parse_version('3.7.0') - if oslo_policy_version >= required_version: - return policy.OrCheck([default.check, deprecated_rule.check]) - else: - default.check = policy.OrCheck( - [policy._parser.parse_rule(cs) for cs in - [default.check_str, - deprecated_rule.check_str]]) - return default.check - - def get_rules(self): - rules = policy.Rules() - # Check whether policy file exists and attempt to read it. - for path in self.policy_files[self.service]: - try: - with open(path, 'r') as fp: - for k, v in policy.Rules.load(fp.read()).items(): - if k not in rules: - rules[k] = v - # If the policy name and rule are the same, no - # ambiguity, so no reason to warn. - elif str(v) != str(rules[k]): - msg = ("The same policy name: %s was found in " - "multiple policies files for service %s. " - "This can lead to policy rule ambiguity. " - "Using rule: %s; Rule from file: %s") - LOG.warning(msg, k, self.service, rules[k], v) - except (ValueError, IOError): - LOG.warning("Failed to read policy file '%s' for service %s.", - path, self.service) - - # Check whether policy actions are defined in code. Nova and Keystone, - # for example, define their default policy actions in code. - mgr = stevedore.named.NamedExtensionManager( - 'oslo.policy.policies', - names=[self.service], - invoke_on_load=True, - warn_on_missing_entrypoint=False) - - if mgr: - policy_generator = {plc.name: plc.obj for plc in mgr} - if self.service in policy_generator: - for rule in policy_generator[self.service]: - if rule.name not in rules: - if CONF.patrole.validate_deprecated_rules: - # NOTE (sergey.vilgelm): - # The `DocumentedRuleDefault` object has no - # `deprecated_rule` attribute in Pike - check = rule.check - if getattr(rule, 'deprecated_rule', False): - check = self._handle_deprecated_rule(rule) - rules[rule.name] = check - elif str(rule.check) != str(rules[rule.name]): - msg = ("The same policy name: %s was found in the " - "policies files and in the code for service " - "%s. This can lead to policy rule ambiguity. " - "Using rule: %s; Rule from code: %s") - LOG.warning(msg, rule.name, self.service, - rules[rule.name], rule.check) - - if not rules: - msg = ( - 'Policy files for {0} service were not found among the ' - 'registered in-code policies or in any of the possible policy ' - 'files: {1}.'.format( - self.service, - [loc % self.service - for loc in CONF.patrole.custom_policy_files])) - raise rbac_exceptions.RbacParsingException(msg) - - return rules - - def _is_admin_context(self, roles): - """Checks whether a role has admin context. - - If context_is_admin is contained in the policy file, then checks - whether the given role is contained in context_is_admin. If it is not - in the policy file, then default to context_is_admin: admin. - """ - if 'context_is_admin' in self.rules: - return self._allowed( - access=self._get_access_token(roles), - apply_rule='context_is_admin') - return CONF.identity.admin_role in roles - - def _get_access_token(self, roles): - access_token = { - "token": { - "roles": [{'name': r} for r in roles], - "project_id": self.project_id, - "tenant_id": self.project_id, - "user_id": self.user_id - } - } - return access_token - - def _allowed(self, access, apply_rule, is_admin=False): - """Checks if a given rule in a policy is allowed with given ``access``. - - :param dict access: Dictionary from ``_get_access_token``. - :param string apply_rule: Rule to be checked using ``oslo.policy``. - :param bool is_admin: Whether admin context is used. - """ - access_data = copy.copy(access['token']) - access_data['roles'] = [role['name'] for role in access_data['roles']] - access_data['is_admin'] = is_admin - # TODO(felipemonteiro): Dynamically calculate is_admin_project rather - # than hard-coding it to True. is_admin_project cannot be determined - # from the role, but rather from project and domain names. For more - # information, see: - # https://git.openstack.org/cgit/openstack/keystone/tree/keystone/token/providers/common.py?id=37ce5417418f8acbd27f3dacb70c605b0fe48301#n150 - access_data['is_admin_project'] = True - - class Object(object): - pass - o = Object() - o.rules = self.rules - - target = {"project_id": access_data['project_id'], - "tenant_id": access_data['project_id'], - "network:tenant_id": access_data['project_id'], - "user_id": access_data['user_id']} - if self.extra_target_data: - target.update(self.extra_target_data) - - result = self._try_rule(apply_rule, target, access_data, o) - return result - - def _try_rule(self, apply_rule, target, access_data, o): - if apply_rule not in self.rules: - message = ('Policy action "{0}" not found in policy files: ' - '{1} or among registered policy in code defaults for ' - '{2} service.').format(apply_rule, - self.policy_files[self.service], - self.service) - LOG.debug(message) - raise rbac_exceptions.RbacParsingException(message) - else: - rule = self.rules[apply_rule] - return rule(target, access_data, o) diff --git a/patrole_tempest_plugin/rbac_authority.py b/patrole_tempest_plugin/rbac_authority.py deleted file mode 100644 index 294ecc51..00000000 --- a/patrole_tempest_plugin/rbac_authority.py +++ /dev/null @@ -1,38 +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. - -import abc - -import six - - -@six.add_metaclass(abc.ABCMeta) -class RbacAuthority(object): - """Class for validating whether a given role can perform a policy action. - - Any class that extends ``RbacAuthority`` provides the logic for determining - whether a role has permissions to execute a policy action. - """ - - @abc.abstractmethod - def allowed(self, rule, role): - """Determine whether the role should be able to perform the API. - - :param rule: The name of the policy enforced by the API. - :param role: The role used to determine whether ``rule`` can be - executed. - :returns: True if the ``role`` has permissions to execute - ``rule``, else False. - """ diff --git a/patrole_tempest_plugin/rbac_exceptions.py b/patrole_tempest_plugin/rbac_exceptions.py deleted file mode 100644 index c30961ba..00000000 --- a/patrole_tempest_plugin/rbac_exceptions.py +++ /dev/null @@ -1,119 +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 exceptions - - -class BasePatroleException(exceptions.TempestException): - message = "An unknown RBAC exception occurred" - - -class BasePatroleResponseBodyException(BasePatroleException): - message = "Response body incomplete due to RBAC authorization failure" - - -class RbacMissingAttributeResponseBody(BasePatroleResponseBodyException): - """Raised when a list or show action is missing an attribute following - RBAC authorization failure. - """ - message = ("The response body is missing the expected %(attribute)s due " - "to policy enforcement failure") - - -class RbacPartialResponseBody(BasePatroleResponseBodyException): - """Raised when a list action only returns a subset of the available - resources. - - For example, admin can return more resources than member for a list action. - """ - message = ("The response body only lists a subset of the available " - "resources due to partial policy enforcement failure. Response " - "body: %(body)s") - - -class RbacEmptyResponseBody(BasePatroleResponseBodyException): - """Raised when a list or show action is empty following RBAC authorization - failure. - """ - message = "The response body is empty due to policy enforcement failure." - - -class RbacResourceSetupFailed(BasePatroleException): - message = "RBAC resource setup failed" - - -class RbacOverPermissionException(BasePatroleException): - """Raised when the expected result is failure but the actual result is - pass. - """ - message = "Unauthorized action was allowed to be performed" - - -class RbacUnderPermissionException(BasePatroleException): - """Raised when the expected result is pass but the actual result is - failure. - """ - message = "Authorized action was not allowed to be performed" - - -class RbacExpectedWrongException(BasePatroleException): - """Raised when the expected exception does not match the actual exception - raised, when both are instances of Forbidden or NotFound, indicating - the test provides a wrong argument to `expected_error_codes`. - """ - message = ("Expected %(expected)s to be raised but %(actual)s was raised " - "instead. Actual exception: %(exception)s") - - -class RbacInvalidServiceException(BasePatroleException): - """Raised when an invalid service is passed to ``rbac_rule_validation`` - decorator. - """ - message = "Attempted to test an invalid service" - - -class RbacParsingException(BasePatroleException): - message = "Attempted to test an invalid policy file or action" - - -class RbacInvalidErrorCode(BasePatroleException): - message = "Unsupported error code passed in test" - - -class RbacOverrideRoleException(BasePatroleException): - """Raised when override_role is used incorrectly or fails somehow. - - Used for safeguarding against false positives that might occur when the - expected exception isn't raised inside the ``override_role`` context. - Specifically, when: - - * ``override_role`` isn't called - * an exception is raised before ``override_role`` context - * an exception is raised after ``override_role`` context - """ - message = "Override role failure or incorrect usage" - - -class RbacValidateListException(BasePatroleException): - """Raised when override_role_and_validate_list is used incorrectly. - - Specifically, when: - - * Neither ``resource_id`` nor ``resources`` is initialized - * Both ``resource_id`` and ``resources`` are initialized - * The ``ctx.resources`` variable wasn't set in - override_role_and_validate_list context. - """ - message = "Incorrect usage of override_role_and_validate_list: %(reason)s" diff --git a/patrole_tempest_plugin/rbac_rule_validation.py b/patrole_tempest_plugin/rbac_rule_validation.py deleted file mode 100644 index 9334702d..00000000 --- a/patrole_tempest_plugin/rbac_rule_validation.py +++ /dev/null @@ -1,516 +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. - -import functools -import logging -import sys - -from oslo_log import versionutils -from oslo_utils import excutils -import six - -from tempest import config -from tempest.lib import exceptions as lib_exc -from tempest import test - -from patrole_tempest_plugin import policy_authority -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import requirements_authority -import testtools - - -CONF = config.CONF -LOG = logging.getLogger(__name__) - -_SUPPORTED_ERROR_CODES = [403, 404] -_DEFAULT_ERROR_CODE = 403 - -RBACLOG = logging.getLogger('rbac_reporting') - - -def action(service, - rules=None, - expected_error_codes=None, - extra_target_data=None): - """A decorator for verifying OpenStack policy enforcement. - - A decorator which allows for positive and negative RBAC testing. Given: - - * an OpenStack service, - * a policy action (``rule``) enforced by that service, and - * the test roles defined by ``[patrole] rbac_test_roles`` - - determines whether the test role has sufficient permissions to perform an - API call that enforces the ``rule``. - - This decorator should only be applied to an instance or subclass of - ``tempest.test.BaseTestCase``. - - The result from ``_is_authorized`` is used to determine the *expected* - test result. The *actual* test result is determined by running the - Tempest test this decorator applies to. - - Below are the following possibilities from comparing the *expected* and - *actual* results: - - 1) If *expected* is True and the test passes (*actual*), this is a success. - 2) If *expected* is True and the test fails (*actual*), this results in a - ``RbacUnderPermissionException`` exception failure. - 3) If *expected* is False and the test passes (*actual*), this results in - an ``RbacOverPermissionException`` exception failure. - 4) If *expected* is False and the test fails (*actual*), this is a success. - - As such, negative and positive testing can be applied using this decorator. - - :param str service: An OpenStack service. Examples: "nova" or "neutron". - :param list rules: A list of policy actions defined in a policy file or in - code. The rules are logical-ANDed together to derive the expected - result. Also accepts list of callables that return a policy action. - - .. note:: - - Patrole currently only supports custom JSON policy files. - - :type rules: list[str] or list[callable] - :param list expected_error_codes: When the ``rules`` list parameter is - used, then this list indicates the expected error code to use if one - of the rules does not allow the role being tested. This list must - coincide with and its elements remain in the same order as the rules - in the rules list. - - Example:: - - rules=["api_action1", "api_action2"] - expected_error_codes=[404, 403] - - a) If api_action1 fails and api_action2 passes, then the expected - error code is 404. - b) if api_action2 fails and api_action1 passes, then the expected - error code is 403. - c) if both api_action1 and api_action2 fail, then the expected error - code is the first error seen (404). - - If it is not passed, then it is defaulted to 403. - - .. warning:: - - A 404 should not be provided *unless* the endpoint masks a - ``Forbidden`` exception as a ``NotFound`` exception. - - :type expected_error_codes: list[int] - :param dict extra_target_data: Dictionary, keyed with ``oslo.policy`` - generic check names, whose values are string literals that reference - nested ``tempest.test.BaseTestCase`` attributes. Used by - ``oslo.policy`` for performing matching against attributes that are - sent along with the API calls. Example:: - - extra_target_data={ - "target.token.user_id": - "os_alt.auth_provider.credentials.user_id" - }) - - :raises RbacInvalidServiceException: If ``service`` is invalid. - :raises RbacUnderPermissionException: For item (2) above. - :raises RbacOverPermissionException: For item (3) above. - :raises RbacExpectedWrongException: When a 403 is expected but a 404 - is raised instead or vice versa. - - Examples:: - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-agents"]) - def test_list_agents_rbac(self): - # The call to `override_role` is mandatory. - with self.override_role(): - self.agents_client.list_agents() - """ - - if extra_target_data is None: - extra_target_data = {} - - rules, expected_error_codes = _prepare_multi_policy(rules, - expected_error_codes) - - def decorator(test_func): - roles = CONF.patrole.rbac_test_roles - # TODO(vegasq) drop once CONF.patrole.rbac_test_role is removed - if CONF.patrole.rbac_test_role: - msg = ('CONF.patrole.rbac_test_role is deprecated in favor of ' - 'CONF.patrole.rbac_test_roles and will be removed in ' - 'future.') - versionutils.report_deprecated_feature(LOG, msg) - if not roles: - roles.append(CONF.patrole.rbac_test_role) - - @functools.wraps(test_func) - def wrapper(*args, **kwargs): - if args and isinstance(args[0], test.BaseTestCase): - test_obj = args[0] - else: - raise rbac_exceptions.RbacResourceSetupFailed( - '`rbac_rule_validation` decorator can only be applied to ' - 'an instance of `tempest.test.BaseTestCase`.') - - allowed = True - disallowed_rules = [] - for rule in rules: - _allowed = _is_authorized( - test_obj, service, rule, extra_target_data) - if not _allowed: - disallowed_rules.append(rule) - allowed = allowed and _allowed - - if disallowed_rules: - # Choose the first disallowed rule and expect the error - # code corresponding to it. - first_error_index = rules.index(disallowed_rules[0]) - exp_error_code = expected_error_codes[first_error_index] - LOG.debug("%s: Expecting %d to be raised for policy name: %s", - test_func.__name__, exp_error_code, - disallowed_rules[0]) - else: - exp_error_code = expected_error_codes[0] - - expected_exception, irregular_msg = _get_exception_type( - exp_error_code) - - caught_exception = None - test_status = 'Allowed' - - try: - test_func(*args, **kwargs) - except rbac_exceptions.RbacInvalidServiceException: - with excutils.save_and_reraise_exception(): - msg = ("%s is not a valid service." % service) - # FIXME(felipemonteiro): This test_status is logged too - # late. Need a function to log it before re-raising. - test_status = ('Error, %s' % (msg)) - LOG.error(msg) - except (expected_exception, - rbac_exceptions.BasePatroleResponseBodyException) \ - as actual_exception: - caught_exception = actual_exception - test_status = 'Denied' - - if irregular_msg: - LOG.warning(irregular_msg, - test_func.__name__, - ', '.join(rules), - service) - - if allowed: - msg = ("User with roles %s was not allowed to perform the " - "following actions: %s. Expected allowed actions: " - "%s. Expected disallowed actions: %s." % ( - roles, sorted(rules), - sorted(set(rules) - set(disallowed_rules)), - sorted(disallowed_rules))) - LOG.error(msg) - raise rbac_exceptions.RbacUnderPermissionException( - "%s Exception was: %s" % (msg, actual_exception)) - except Exception as actual_exception: - caught_exception = actual_exception - - if _check_for_expected_mismatch_exception(expected_exception, - actual_exception): - LOG.error('Expected and actual exceptions do not match. ' - 'Expected: %s. Actual: %s.', - expected_exception, - actual_exception.__class__) - raise rbac_exceptions.RbacExpectedWrongException( - expected=expected_exception, - actual=actual_exception.__class__, - exception=actual_exception) - else: - with excutils.save_and_reraise_exception(): - exc_info = sys.exc_info() - error_details = six.text_type(exc_info[1]) - msg = ("An unexpected exception has occurred during " - "test: %s. Exception was: %s" % ( - test_func.__name__, error_details)) - test_status = 'Error, %s' % (error_details) - LOG.error(msg) - else: - if not allowed: - msg = ( - "OverPermission: Role %s was allowed to perform the " - "following disallowed actions: %s" % ( - roles, sorted(disallowed_rules) - ) - ) - LOG.error(msg) - raise rbac_exceptions.RbacOverPermissionException(msg) - finally: - if CONF.patrole_log.enable_reporting: - RBACLOG.info( - "[Service]: %s, [Test]: %s, [Rules]: %s, " - "[Expected]: %s, [Actual]: %s", - service, test_func.__name__, ', '.join(rules), - "Allowed" if allowed else "Denied", - test_status) - - # Sanity-check that ``override_role`` was called to eliminate - # false-positives and bad test flows resulting from exceptions - # getting raised too early, too late or not at all, within - # the scope of an RBAC test. - _validate_override_role_called( - test_obj, - actual_exception=caught_exception) - - return wrapper - return decorator - - -def _prepare_multi_policy(rules, exp_error_codes): - if exp_error_codes: - if not rules: - msg = ("The `rules` list must be provided if using the " - "`expected_error_codes` list.") - raise ValueError(msg) - if len(rules) != len(exp_error_codes): - msg = ("The `expected_error_codes` list is not the same length " - "as the `rules` list.") - raise ValueError(msg) - if not isinstance(exp_error_codes, (tuple, list)): - exp_error_codes = [exp_error_codes] - else: - exp_error_codes = [] - - if rules is None: - rules = [] - elif not isinstance(rules, (tuple, list)): - rules = [rules] - - # Fill in the exp_error_codes if needed. This is needed for the scenarios - # where no exp_error_codes array is provided, so the error codes must be - # set to the default error code value and there must be the same number - # of error codes as rules. - num_ecs = len(exp_error_codes) - num_rules = len(rules) - if (num_ecs < num_rules): - for i in range(num_rules - num_ecs): - exp_error_codes.append(_DEFAULT_ERROR_CODE) - - evaluated_rules = [ - r() if callable(r) else r for r in rules - ] - - return evaluated_rules, exp_error_codes - - -def _is_authorized(test_obj, service, rule, extra_target_data): - """Validates whether current RBAC role has permission to do policy action. - - :param test_obj: An instance or subclass of ``tempest.test.BaseTestCase``. - :param service: The OpenStack service that enforces ``rule``. - :param rule: The name of the policy action. Examples include - "identity:create_user" or "os_compute_api:os-agents". - :param extra_target_data: Dictionary, keyed with ``oslo.policy`` generic - check names, whose values are string literals that reference nested - ``tempest.test.BaseTestCase`` attributes. Used by ``oslo.policy`` for - performing matching against attributes that are sent along with the API - calls. - - :returns: True if the current RBAC role can perform the policy action, - else False. - - :raises RbacResourceSetupFailed: If `project_id` or `user_id` are missing - from the `auth_provider` attribute in `test_obj`. - """ - - try: - project_id = test_obj.os_primary.credentials.project_id - user_id = test_obj.os_primary.credentials.user_id - except AttributeError as e: - msg = ("{0}: project_id or user_id not found in os_primary.credentials" - .format(e)) - LOG.error(msg) - raise rbac_exceptions.RbacResourceSetupFailed(msg) - - roles = CONF.patrole.rbac_test_roles - # TODO(vegasq) drop once CONF.patrole.rbac_test_role is removed - if CONF.patrole.rbac_test_role: - if not roles: - roles.append(CONF.patrole.rbac_test_role) - - # Adding implied roles - roles = test_obj.get_all_needed_roles(roles) - - # Test RBAC against custom requirements. Otherwise use oslo.policy. - if CONF.patrole.test_custom_requirements: - authority = requirements_authority.RequirementsAuthority( - CONF.patrole.custom_requirements_file, service) - else: - formatted_target_data = _format_extra_target_data( - test_obj, extra_target_data) - policy_authority.PolicyAuthority.os_admin = test_obj.os_admin - authority = policy_authority.PolicyAuthority( - project_id, user_id, service, - extra_target_data=formatted_target_data) - - is_allowed = authority.allowed(rule, roles) - - if is_allowed: - LOG.debug("[Policy action]: %s, [Role]: %s is allowed!", rule, - roles) - else: - LOG.debug("[Policy action]: %s, [Role]: %s is NOT allowed!", - rule, roles) - - return is_allowed - - -def _get_exception_type(expected_error_code=_DEFAULT_ERROR_CODE): - """Dynamically calculate the expected exception to be caught. - - Dynamically calculate the expected exception to be caught by the test case. - Only ``Forbidden`` and ``NotFound`` exceptions are permitted. ``NotFound`` - is supported because Neutron, for security reasons, masks ``Forbidden`` - exceptions as ``NotFound`` exceptions. - - :param expected_error_code: the integer representation of the expected - exception to be caught. Must be contained in - ``_SUPPORTED_ERROR_CODES``. - :returns: tuple of the exception type corresponding to - ``expected_error_code`` and a message explaining that a non-Forbidden - exception was expected, if applicable. - """ - expected_exception = None - irregular_msg = None - - if not isinstance(expected_error_code, six.integer_types) \ - or expected_error_code not in _SUPPORTED_ERROR_CODES: - msg = ("Please pass an expected error code. Currently " - "supported codes: {0}".format(_SUPPORTED_ERROR_CODES)) - LOG.error(msg) - raise rbac_exceptions.RbacInvalidErrorCode(msg) - - if expected_error_code == 403: - expected_exception = lib_exc.Forbidden - elif expected_error_code == 404: - expected_exception = lib_exc.NotFound - irregular_msg = ("NotFound exception was caught for test %s. Expected " - "policies which may have caused the error: %s. The " - "service %s throws a 404 instead of a 403, which is " - "irregular") - return expected_exception, irregular_msg - - -def _format_extra_target_data(test_obj, extra_target_data): - """Formats the "extra_target_data" dictionary with correct test data. - - Before being formatted, "extra_target_data" is a dictionary that maps a - policy string like "trust.trustor_user_id" to a nested list of - ``tempest.test.BaseTestCase`` attributes. For example, the attribute list - in:: - - "trust.trustor_user_id": "os.auth_provider.credentials.user_id" - - is parsed by iteratively calling ``getattr`` until the value of "user_id" - is resolved. The resulting dictionary returns:: - - "trust.trustor_user_id": "the user_id of the `os_primary` credential" - - :param test_obj: An instance or subclass of ``tempest.test.BaseTestCase``. - :param extra_target_data: Dictionary, keyed with ``oslo.policy`` generic - check names, whose values are string literals that reference nested - ``tempest.test.BaseTestCase`` attributes. Used by ``oslo.policy`` for - performing matching against attributes that are sent along with the API - calls. - :returns: Dictionary containing additional object data needed by - ``oslo.policy`` to validate generic checks. - """ - attr_value = test_obj - formatted_target_data = {} - - for user_attribute, attr_string in extra_target_data.items(): - attrs = attr_string.split('.') - for attr in attrs: - attr_value = getattr(attr_value, attr) - formatted_target_data[user_attribute] = attr_value - - return formatted_target_data - - -def _check_for_expected_mismatch_exception(expected_exception, - actual_exception): - """Checks that ``expected_exception`` matches ``actual_exception``. - - Since Patrole must handle 403/404 it is important that the expected and - actual error codes match. - - :param excepted_exception: Expected exception for test. - :param actual_exception: Actual exception raised by test. - :returns: True if match, else False. - :rtype: boolean - """ - permission_exceptions = (lib_exc.Forbidden, lib_exc.NotFound) - if isinstance(actual_exception, permission_exceptions): - if not isinstance(actual_exception, expected_exception.__class__): - return True - return False - - -def _validate_override_role_called(test_obj, actual_exception): - """Validates that :func:`rbac_utils.RbacUtilsMixin.override_role` is called - during each Patrole test. - - Useful for validating that the expected exception isn't raised too early - (before ``override_role`` call) or too late (after ``override_call``) or - at all (which is a bad test). - - :param test_obj: An instance or subclass of ``tempest.test.BaseTestCase``. - :param actual_exception: Actual exception raised by test. - :raises RbacOverrideRoleException: If ``override_role`` isn't called, is - called too early, or is called too late. - """ - called = test_obj._validate_override_role_called() - base_msg = ('This error is unrelated to RBAC and is due to either ' - 'an API or override role failure. Exception: %s' % - actual_exception) - - if not called: - if actual_exception is not None: - # Use testtools skipException in base TestCase - # to support different skip exceptions used. - # Just return so the skip exception will go up - # the stack and be handled by the unit testing framework - if isinstance(actual_exception, - testtools.testcase.TestCase.skipException): - return - msg = ('Caught exception (%s) but it was raised before the ' - '`override_role` context. ' % actual_exception.__class__) - else: - msg = 'Test missing required `override_role` call. ' - msg += base_msg - LOG.error(msg) - raise rbac_exceptions.RbacOverrideRoleException(msg) - else: - exc_caught_in_ctx = test_obj._validate_override_role_caught_exc() - # This block is only executed if ``override_role`` is called. If - # an exception is raised and the exception wasn't raised in the - # ``override_role`` context and if the exception isn't a valid - # exception type (instance of ``BasePatroleException``), then this is - # a legitimate error. - if (not exc_caught_in_ctx and - actual_exception is not None and - not isinstance(actual_exception, - rbac_exceptions.BasePatroleException)): - msg = ('Caught exception (%s) but it was raised after the ' - '`override_role` context. ' % actual_exception.__class__) - msg += base_msg - LOG.error(msg) - raise rbac_exceptions.RbacOverrideRoleException(msg) diff --git a/patrole_tempest_plugin/rbac_utils.py b/patrole_tempest_plugin/rbac_utils.py deleted file mode 100644 index ed65a740..00000000 --- a/patrole_tempest_plugin/rbac_utils.py +++ /dev/null @@ -1,501 +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. - -import contextlib -import sys -import time - -from oslo_log import log as logging -from oslo_utils import excutils - -from tempest import config -from tempest.lib import exceptions as lib_exc - -from patrole_tempest_plugin import rbac_exceptions - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class _ValidateListContext(object): - """Context class responsible for validation of the list functions. - - This class is used in ``override_role_and_validate_list`` function and - the result of a list function must be assigned to the ``ctx.resources`` - variable. - - Example:: - - with self.override_role_and_validate_list(...) as ctx: - ctx.resources = list_function() - - """ - def __init__(self, admin_resources=None, admin_resource_id=None): - """Constructor for ``ValidateListContext``. - - Either ``admin_resources`` or ``admin_resource_id`` should be used, - not both. - - :param list admin_resources: The list of resources received before - calling the ``override_role_and_validate_list`` function. To - validate will be used the ``_validate_len`` function. - :param UUID admin_resource_id: An ID of a resource created before - calling the ``override_role_and_validate_list`` function. To - validate will be used the ``_validate_resource`` function. - :raises RbacValidateListException: if both ``admin_resources`` and - ``admin_resource_id`` are set or unset. - """ - self.resources = None - if admin_resources is not None and not admin_resource_id: - self._admin_len = len(admin_resources) - if not self._admin_len: - raise rbac_exceptions.RbacValidateListException( - reason="the list of admin resources cannot be empty") - self._validate_func = self._validate_len - elif admin_resource_id and admin_resources is None: - self._admin_resource_id = admin_resource_id - self._validate_func = self._validate_resource - else: - raise rbac_exceptions.RbacValidateListException( - reason="admin_resources and admin_resource_id are mutually " - "exclusive") - - def _validate_len(self): - """Validates that the number of resources is less than admin resources. - """ - if not len(self.resources): - raise rbac_exceptions.RbacEmptyResponseBody() - elif self._admin_len > len(self.resources): - raise rbac_exceptions.RbacPartialResponseBody(body=self.resources) - - def _validate_resource(self): - """Validates that the admin resource is present in the resources. - """ - for resource in self.resources: - if resource['id'] == self._admin_resource_id: - return - raise rbac_exceptions.RbacPartialResponseBody(body=self.resources) - - def _validate(self): - """Calls the proper validation function. - - :raises RbacValidateListException: if the ``ctx.resources`` variable is - not assigned. - """ - if self.resources is None: - raise rbac_exceptions.RbacValidateListException( - reason="ctx.resources is not assigned") - self._validate_func() - - -class RbacUtilsMixin(object): - """Utility mixin responsible for switching ``os_primary`` role. - - Should be used as a mixin class alongside an instance of - :py:class:`tempest.test.BaseTestCase` to perform Patrole class setup for a - base RBAC class. Child classes should not use this mixin. - - Example:: - - class BaseRbacTest(rbac_utils.RbacUtilsMixin, base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(BaseRbacTest, cls).setup_clients() - - cls.hosts_client = cls.os_primary.hosts_client - ... - - This class is responsible for overriding the value of the primary Tempest - credential's role (i.e. ``os_primary`` role). By doing so, it is possible - to seamlessly swap between admin credentials, needed for setup and clean - up, and primary credentials, needed to perform the API call which does - policy enforcement. The primary credentials always cycle between roles - defined by ``CONF.identity.admin_role`` and - ``CONF.patrole.rbac_test_roles``. - """ - credentials = ['primary', 'admin'] - - def __init__(self, *args, **kwargs): - super(RbacUtilsMixin, self).__init__(*args, **kwargs) - - # Shows if override_role was called. - self.__override_role_called = False - # Shows if exception raised during override_role. - self.__override_role_caught_exc = False - - _admin_role_id = None - _rbac_role_ids = None - _project_id = None - _user_id = None - _role_map = None - _role_inferences_mapping = None - _orig_roles = [] - - admin_roles_client = None - - @classmethod - def restore_roles(cls): - if cls._orig_roles: - LOG.info("Restoring original roles %s", cls._orig_roles) - roles_already_present = cls._list_and_clear_user_roles_on_project( - cls._orig_roles) - - if not roles_already_present: - cls._create_user_role_on_project(cls._orig_roles) - - @classmethod - def setup_clients(cls): - if CONF.identity_feature_enabled.api_v3: - admin_roles_client = cls.os_admin.roles_v3_client - else: - raise lib_exc.InvalidConfiguration( - "Patrole role overriding only supports v3 identity API.") - - cls.admin_roles_client = admin_roles_client - - cls._project_id = cls.os_primary.credentials.tenant_id - cls._user_id = cls.os_primary.credentials.user_id - cls._role_inferences_mapping = cls._prepare_role_inferences_mapping() - - cls._init_roles() - - # Store the user's original roles and rollback after testing. - roles = cls.admin_roles_client.list_user_roles_on_project( - cls._project_id, cls._user_id)['roles'] - cls._orig_roles = [role['id'] for role in roles] - cls.addClassResourceCleanup(cls.restore_roles) - - # Change default role to admin - cls._override_role(False) - - super(RbacUtilsMixin, cls).setup_clients() - - @classmethod - def _prepare_role_inferences_mapping(cls): - """Preparing roles mapping to support role inferences - - Making query to `list-all-role-inference-rules`_ keystone API - returns all inference rules, which makes it possible to prepare - roles mapping. - - It walks recursively through the raw data:: - - {"role_inferences": [ - { - "implies": [{"id": "3", "name": "reader"}], - "prior_role": {"id": "2", "name": "member"} - }, - { - "implies": [{"id": "2", "name": "member"}], - "prior_role": {"id": "1", "name": "admin"} - } - ] - } - - and converts it to the mapping:: - - { - "2": ["3"], # "member": ["reader"], - "1": ["2", "3"] # "admin": ["member", "reader"] - } - - .. _list-all-role-inference-rules: https://docs.openstack.org/api-ref/identity/v3/#list-all-role-inference-rules - """ # noqa: E501 - def process_roles(role_id, data): - roles = data.get(role_id, set()) - for rid in roles.copy(): - roles.update(process_roles(rid, data)) - - return roles - - def convert_data(data): - res = {} - for rule in data: - prior_role = rule['prior_role']['id'] - implies = {r['id'] for r in rule['implies']} - res[prior_role] = implies - return res - - raw_data = cls.admin_roles_client.list_all_role_inference_rules() - data = convert_data(raw_data['role_inferences']) - res = {} - for role_id in data: - res[role_id] = process_roles(role_id, data) - return res - - def get_all_needed_roles(self, roles): - """Extending given roles with roles from mapping - - Examples:: - ["admin"] >> ["admin", "member", "reader"] - ["member"] >> ["member", "reader"] - ["reader"] >> ["reader"] - ["custom_role"] >> ["custom_role"] - - :param roles: list of roles - :return: extended list of roles - """ - res = set(r for r in roles) - for role in res.copy(): - role_id = self.__class__._role_map.get(role) - implied_roles = self.__class__._role_inferences_mapping.get( - role_id, set()) - role_names = {self.__class__._role_map[rid] - for rid in implied_roles} - res.update(role_names) - LOG.debug('All needed roles: %s; Base roles: %s', res, roles) - return list(res) - - @contextlib.contextmanager - def override_role(self): - """Override the role used by ``os_primary`` Tempest credentials. - - Temporarily change the role used by ``os_primary`` credentials to: - - * ``[patrole] rbac_test_roles`` before test execution - * ``[identity] admin_role`` after test execution - - Automatically switches to admin role after test execution. - - :returns: None - - .. warning:: - - This function can alter user roles for pre-provisioned credentials. - Work is underway to safely clean up after this function. - - Example:: - - @rbac_rule_validation.action(service='test', - rules=['a:test:rule']) - def test_foo(self): - # Allocate test-level resources here. - with self.override_role(): - # The role for `os_primary` has now been overridden. Within - # this block, call the API endpoint that enforces the - # expected policy specified by "rule" in the decorator. - self.foo_service.bar_api_call() - # The role is switched back to admin automatically. Note that - # if the API call above threw an exception, any code below this - # point in the test is not executed. - """ - self._set_override_role_called() - self._override_role(True) - try: - # Execute the test. - yield - finally: - # Check whether an exception was raised. If so, remember that - # for future validation. - exc = sys.exc_info()[0] - if exc is not None: - self._set_override_role_caught_exc() - # This code block is always executed, no matter the result of the - # test. Automatically switch back to the admin role for test clean - # up. - self._override_role(False) - - @classmethod - def _override_role(cls, toggle_rbac_role=False): - """Private helper for overriding ``os_primary`` Tempest credentials. - - :param toggle_rbac_role: Boolean value that controls the role that - overrides default role of ``os_primary`` credentials. - * If True: role is set to ``[patrole] rbac_test_role`` - * If False: role is set to ``[identity] admin_role`` - """ - LOG.debug('Overriding role to: %s.', toggle_rbac_role) - roles_already_present = False - - try: - target_roles = (cls._rbac_role_ids - if toggle_rbac_role else [cls._admin_role_id]) - roles_already_present = cls._list_and_clear_user_roles_on_project( - target_roles) - - # Do not override roles if `target_role` already exists. - if not roles_already_present: - cls._create_user_role_on_project(target_roles) - except Exception as exp: - with excutils.save_and_reraise_exception(): - LOG.exception(exp) - finally: - auth_providers = cls.get_auth_providers() - for provider in auth_providers: - provider.clear_auth() - # Fernet tokens are not subsecond aware so sleep to ensure we are - # passing the second boundary before attempting to authenticate. - # Only sleep if a token revocation occurred as a result of role - # overriding. This will optimize test runtime in the case where - # ``[identity] admin_role`` == ``[patrole] rbac_test_roles``. - if not roles_already_present: - time.sleep(1) - - for provider in auth_providers: - provider.set_auth() - - @classmethod - def _init_roles(cls): - available_roles = cls.admin_roles_client.list_roles()['roles'] - cls._role_map = {r['name']: r['id'] for r in available_roles} - LOG.debug('Available roles: %s', cls._role_map.keys()) - - rbac_role_ids = [] - roles = CONF.patrole.rbac_test_roles - # TODO(vegasq) drop once CONF.patrole.rbac_test_role is removed - if CONF.patrole.rbac_test_role: - if not roles: - roles.append(CONF.patrole.rbac_test_role) - - for role_name in roles: - rbac_role_ids.append(cls._role_map.get(role_name)) - - admin_role_id = cls._role_map.get(CONF.identity.admin_role) - - if not all([admin_role_id, all(rbac_role_ids)]): - missing_roles = [] - msg = ("Could not find `[patrole] rbac_test_roles` or " - "`[identity] admin_role`, both of which are required for " - "RBAC testing.") - if not admin_role_id: - missing_roles.append(CONF.identity.admin_role) - if not all(rbac_role_ids): - missing_roles += [role_name for role_name in roles - if role_name not in cls._role_map] - - msg += " Following roles were not found: %s." % ( - ", ".join(missing_roles)) - msg += " Available roles: %s." % ", ".join(cls._role_map) - raise rbac_exceptions.RbacResourceSetupFailed(msg) - - cls._admin_role_id = admin_role_id - cls._rbac_role_ids = rbac_role_ids - # Adding backward mapping - cls._role_map.update({v: k for k, v in cls._role_map.items()}) - - @classmethod - def _create_user_role_on_project(cls, role_ids): - for role_id in role_ids: - cls.admin_roles_client.create_user_role_on_project( - cls._project_id, cls._user_id, role_id) - - @classmethod - def _list_and_clear_user_roles_on_project(cls, role_ids): - roles = cls.admin_roles_client.list_user_roles_on_project( - cls._project_id, cls._user_id)['roles'] - all_role_ids = [role['id'] for role in roles] - - # NOTE(felipemonteiro): We do not use ``role_id in all_role_ids`` here - # to avoid over-permission errors: if the current list of roles on the - # project includes "admin" and "Member", and we are switching to the - # "Member" role, then we must delete the "admin" role. Thus, we only - # return early if the user's roles on the project are an exact match. - if set(role_ids) == set(all_role_ids): - return True - - for role in roles: - cls.admin_roles_client.delete_role_from_user_on_project( - cls._project_id, cls._user_id, role['id']) - - return False - - @contextlib.contextmanager - def override_role_and_validate_list(self, - admin_resources=None, - admin_resource_id=None): - """Call ``override_role`` and validate RBAC for a list API action. - - List actions usually do soft authorization: partial or empty response - bodies are returned instead of exceptions. This helper validates - that unauthorized roles only return a subset of the available - resources. - Should only be used for validating list API actions. - - :param test_obj: Instance of ``tempest.test.BaseTestCase``. - :param list admin_resources: The list of resources received before - calling the ``override_role_and_validate_list`` function. - :param UUID admin_resource_id: An ID of a resource created before - calling the ``override_role_and_validate_list`` function. - :return: py:class:`_ValidateListContext` object. - - Example:: - - # the resource created by admin - admin_resource_id = ( - self.ntp_client.create_dscp_marking_rule() - ["dscp_marking_rule"]["id']) - with self.override_role_and_validate_list( - admin_resource_id=admin_resource_id) as ctx: - # the list of resources available for member role - ctx.resources = self.ntp_client.list_dscp_marking_rules( - policy_id=self.policy_id)["dscp_marking_rules"] - """ - ctx = _ValidateListContext(admin_resources, admin_resource_id) - with self.override_role(): - yield ctx - ctx._validate() - - @classmethod - def get_auth_providers(cls): - """Returns list of auth_providers used within test. - - Tests may redefine this method to include their own or third party - client auth_providers. - """ - return [cls.os_primary.auth_provider] - - def _set_override_role_called(self): - """Helper for tracking whether ``override_role`` was called.""" - self.__override_role_called = True - - def _set_override_role_caught_exc(self): - """Helper for tracking whether exception was thrown inside - ``override_role``. - """ - self.__override_role_caught_exc = True - - def _validate_override_role_called(self): - """Idempotently validate that ``override_role`` is called and reset - its value to False for sequential tests. - """ - was_called = self.__override_role_called - self.__override_role_called = False - return was_called - - def _validate_override_role_caught_exc(self): - """Idempotently validate that exception was caught inside - ``override_role``, so that, by process of elimination, it can be - determined whether one was thrown outside (which is invalid). - """ - caught_exception = self.__override_role_caught_exc - self.__override_role_caught_exc = False - return caught_exception - - -def is_admin(): - """Verifies whether the current test role equals the admin role. - - :returns: True if ``rbac_test_roles`` contain the admin role. - """ - roles = CONF.patrole.rbac_test_roles - # TODO(vegasq) drop once CONF.patrole.rbac_test_role is removed - if CONF.patrole.rbac_test_role: - roles.append(CONF.patrole.rbac_test_role) - roles = list(set(roles)) - - # TODO(felipemonteiro): Make this more robust via a context is admin - # lookup. - return CONF.identity.admin_role in roles diff --git a/patrole_tempest_plugin/requirements_authority.py b/patrole_tempest_plugin/requirements_authority.py deleted file mode 100644 index 4d6f25be..00000000 --- a/patrole_tempest_plugin/requirements_authority.py +++ /dev/null @@ -1,150 +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. -import copy -import yaml - -from oslo_log import log as logging - -from tempest import config -from tempest.lib import exceptions as lib_exc - -from patrole_tempest_plugin.rbac_authority import RbacAuthority -from patrole_tempest_plugin import rbac_exceptions - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -class RequirementsParser(object): - """A class that parses a custom requirements file.""" - _inner = None - - class Inner(object): - _rbac_map = None - - def __init__(self, filepath): - with open(filepath) as f: - RequirementsParser.Inner._rbac_map = \ - list(yaml.safe_load_all(f)) - - def __init__(self, filepath): - if RequirementsParser._inner is None: - RequirementsParser._inner = RequirementsParser.Inner(filepath) - - @staticmethod - def parse(component): - """Parses a requirements file with the following format: - - .. code-block:: yaml - - : - : - - - - , - - - : - - - - - : - : - - - - :param str component: Name of the OpenStack service to be validated. - :returns: The dictionary that maps each policy action to the list - of allowed roles, for the given ``component``. - :rtype: dict - """ - try: - for section in RequirementsParser.Inner._rbac_map: - if component in section: - rules = copy.copy(section[component]) - - for rule in rules: - rules[rule] = [ - roles.split(',') for roles in rules[rule]] - - for i, role_pack in enumerate(rules[rule]): - rules[rule][i] = [r.strip() for r in role_pack] - - return rules - except yaml.parser.ParserError: - LOG.error("Error while parsing the requirements YAML file. Did " - "you pass a valid component name from the test case?") - return {} - - -class RequirementsAuthority(RbacAuthority): - """A class that uses a custom requirements file to validate RBAC.""" - - def __init__(self, filepath=None, component=None): - """This class can be used to achieve a requirements-driven approach to - validating an OpenStack cloud's RBAC implementation. Using this - approach, Patrole computes expected test results by performing lookups - against a custom requirements file which precisely defines the cloud's - RBAC requirements. - - :param str filepath: Path where the custom requirements file lives. - Defaults to ``[patrole].custom_requirements_file``. - :param str component: Name of the OpenStack service to be validated. - """ - self.filepath = filepath or CONF.patrole.custom_requirements_file - if component is not None: - self.roles_dict = RequirementsParser(self.filepath).parse( - component) - else: - self.roles_dict = None - - def allowed(self, rule_name, roles): - """Checks if a given rule in a policy is allowed with given role. - - :param string rule_name: Rule to be checked using provided requirements - file specified by ``[patrole].custom_requirements_file``. Must be - a key present in this file, under the appropriate component. - :param List[string] roles: Roles to validate against custom - requirements file. - :returns: True if ``role`` is allowed to perform ``rule_name``, else - False. - :rtype: bool - :raises RbacParsingException: If ``rule_name`` does not exist among the - keyed policy names in the custom requirements file. - """ - if not self.roles_dict: - raise lib_exc.InvalidConfiguration( - "Roles dictionary parsed from requirements YAML file is " - "empty. Ensure the requirements YAML file is correctly " - "formatted.") - try: - requirement_roles = self.roles_dict[rule_name] - except KeyError: - raise rbac_exceptions.RbacParsingException( - "'%s' rule name is not defined in the requirements YAML file: " - "%s" % (rule_name, self.filepath)) - - for role_reqs in requirement_roles: - required_roles = [ - role for role in role_reqs if not role.startswith("!")] - forbidden_roles = [ - role[1:] for role in role_reqs if role.startswith("!")] - - # User must have all required roles - required_passed = all([r in roles for r in required_roles]) - # User must not have any forbidden roles - forbidden_passed = all([r not in forbidden_roles - for r in roles]) - - if required_passed and forbidden_passed: - return True - - return False diff --git a/patrole_tempest_plugin/tests/__init__.py b/patrole_tempest_plugin/tests/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/patrole_tempest_plugin/tests/api/README.rst b/patrole_tempest_plugin/tests/api/README.rst deleted file mode 120000 index e2853ecd..00000000 --- a/patrole_tempest_plugin/tests/api/README.rst +++ /dev/null @@ -1 +0,0 @@ -../../../doc/source/field_guide/rbac.rst \ No newline at end of file diff --git a/patrole_tempest_plugin/tests/api/__init__.py b/patrole_tempest_plugin/tests/api/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/patrole_tempest_plugin/tests/api/compute/__init__.py b/patrole_tempest_plugin/tests/api/compute/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/patrole_tempest_plugin/tests/api/compute/rbac_base.py b/patrole_tempest_plugin/tests/api/compute/rbac_base.py deleted file mode 100644 index b798b166..00000000 --- a/patrole_tempest_plugin/tests/api/compute/rbac_base.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright 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. - -from tempest.api.compute import base as compute_base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils - -from patrole_tempest_plugin import rbac_utils - - -class BaseV2ComputeRbacTest(rbac_utils.RbacUtilsMixin, - compute_base.BaseV2ComputeTest): - - @classmethod - def setup_clients(cls): - super(BaseV2ComputeRbacTest, cls).setup_clients() - cls.hosts_client = cls.os_primary.hosts_client - cls.tenant_usages_client = cls.os_primary.tenant_usages_client - cls.networks_client = cls.os_primary.networks_client - cls.subnets_client = cls.os_primary.subnets_client - cls.ports_client = cls.os_primary.ports_client - - @classmethod - def create_flavor(cls, **kwargs): - flavor_kwargs = { - "name": data_utils.rand_name(cls.__name__ + '-flavor'), - "ram": data_utils.rand_int_id(1, 10), - "vcpus": data_utils.rand_int_id(1, 10), - "disk": data_utils.rand_int_id(1, 10), - "id": data_utils.rand_uuid(), - } - if kwargs: - flavor_kwargs.update(kwargs) - flavor = cls.flavors_client.create_flavor(**flavor_kwargs)['flavor'] - cls.addClassResourceCleanup( - cls.flavors_client.wait_for_resource_deletion, flavor['id']) - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.flavors_client.delete_flavor, flavor['id']) - return flavor diff --git a/patrole_tempest_plugin/tests/api/compute/test_agents_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_agents_rbac.py deleted file mode 100644 index de9a1730..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_agents_rbac.py +++ /dev/null @@ -1,118 +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.common import 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 patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - -CONF = config.CONF - -if CONF.policy_feature_enabled.changed_nova_policies_ussuri: - _AGENTS_LIST = "os_compute_api:os-agents:list" - _AGENTS_CREATE = "os_compute_api:os-agents:create" - _AGENTS_UPDATE = "os_compute_api:os-agents:update" - _AGENTS_DELETE = "os_compute_api:os-agents:delete" -else: - _AGENTS_LIST = "os_compute_api:os-agents" - _AGENTS_CREATE = "os_compute_api:os-agents" - _AGENTS_UPDATE = "os_compute_api:os-agents" - _AGENTS_DELETE = "os_compute_api:os-agents" - - -class AgentsRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def skip_checks(cls): - super(AgentsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-agents', 'compute'): - raise cls.skipException( - '%s skipped as os-agents not enabled' % cls.__name__) - if CONF.policy_feature_enabled.removed_nova_policies_wallaby: - raise cls.skipException( - '%s skipped as os-agents APIs/policies are not avaialble ' - 'any more.' % cls.__name__) - - def _param_helper(self, **kwargs): - rand_key = 'architecture' - if rand_key in kwargs: - # NOTE: The rand_name is for avoiding agent conflicts. - # If you try to create an agent with the same hypervisor, - # os and architecture as an existing agent, Nova will return - # an HTTPConflict or HTTPServerError. - kwargs[rand_key] = data_utils.rand_name(kwargs[rand_key]) - return kwargs - - @rbac_rule_validation.action( - service="nova", rules=[_AGENTS_LIST]) - @decorators.idempotent_id('d1bc6d97-07f5-4f45-ac29-1c619a6a7e27') - def test_list_agents_rbac(self): - with self.override_role(): - self.agents_client.list_agents() - - @rbac_rule_validation.action( - service="nova", - rules=[_AGENTS_CREATE]) - @decorators.idempotent_id('77d6cae4-1ced-47f7-af2e-3d6a45958fd6') - def test_create_agent(self): - params = {'hypervisor': 'kvm', 'os': 'win', 'architecture': 'x86', - 'version': '7.0', 'url': 'xxx://xxxx/xxx/xxx', - 'md5hash': 'add6bb58e139be103324d04d82d8f545'} - with self.override_role(): - body = self.agents_client.create_agent(**params)['agent'] - self.addCleanup(self.agents_client.delete_agent, - body['agent_id']) - - @rbac_rule_validation.action( - service="nova", - rules=[_AGENTS_UPDATE]) - @decorators.idempotent_id('b22f2681-9ffb-439b-b240-dae503e41020') - def test_update_agent(self): - params = self._param_helper( - hypervisor='common', os='linux', - architecture='x86_64', version='7.0', - url='xxx://xxxx/xxx/xxx', - md5hash='add6bb58e139be103324d04d82d8f545') - body = self.agents_client.create_agent(**params)['agent'] - self.addCleanup(self.agents_client.delete_agent, - body['agent_id']) - update_params = self._param_helper( - version='8.0', - url='xxx://xxxx/xxx/xxx2', - md5hash='add6bb58e139be103324d04d82d8f547') - - with self.override_role(): - self.agents_client.update_agent(body['agent_id'], **update_params) - - @rbac_rule_validation.action( - service="nova", - rules=[_AGENTS_DELETE]) - @decorators.idempotent_id('c5042af8-0682-43b0-abc4-bf33349e23dd') - def test_delete_agent(self): - params = self._param_helper( - hypervisor='common', os='linux', - architecture='x86_64', version='7.0', - url='xxx://xxxx/xxx/xxx', - md5hash='add6bb58e139be103324d04d82d8f545') - body = self.agents_client.create_agent(**params)['agent'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.agents_client.delete_agent, - body['agent_id']) - with self.override_role(): - self.agents_client.delete_agent(body['agent_id']) diff --git a/patrole_tempest_plugin/tests/api/compute/test_aggregates_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_aggregates_rbac.py deleted file mode 100644 index 687512b2..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_aggregates_rbac.py +++ /dev/null @@ -1,150 +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. - -import testtools - -from tempest.common import 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 patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - -CONF = config.CONF - - -class AggregatesRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def skip_checks(cls): - super(AggregatesRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-aggregates', 'compute'): - msg = "%s skipped as os-aggregates not enabled." % cls.__name__ - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(AggregatesRbacTest, cls).setup_clients() - cls.hosts_client = cls.os_primary.hosts_client - - @classmethod - def resource_setup(cls): - super(AggregatesRbacTest, cls).resource_setup() - cls.host = None - hypers = cls.hypervisor_client.list_hypervisors( - detail=True)['hypervisors'] - - if CONF.compute.hypervisor_type: - hypers = [hyper for hyper in hypers - if (hyper['hypervisor_type'] == - CONF.compute.hypervisor_type)] - - hosts_available = [hyper['service']['host'] for hyper in hypers - if (hyper['state'] == 'up' and - hyper['status'] == 'enabled')] - if hosts_available: - cls.host = hosts_available[0] - else: - msg = "no available compute node found" - if CONF.compute.hypervisor_type: - msg += " for hypervisor_type %s" % CONF.compute.hypervisor_type - raise testtools.TestCase.failureException(msg) - - def _create_aggregate(self): - agg_name = data_utils.rand_name(self.__class__.__name__ + '-aggregate') - aggregate = self.aggregates_client.create_aggregate(name=agg_name) - aggregate_id = aggregate['aggregate']['id'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.aggregates_client.delete_aggregate, - aggregate_id) - return aggregate_id - - def _add_host_to_aggregate(self, aggregate_id): - self.aggregates_client.add_host(aggregate_id, host=self.host) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.aggregates_client.remove_host, - aggregate_id, - host=self.host) - - @rbac_rule_validation.action( - service="nova", rules=["os_compute_api:os-aggregates:create"]) - @decorators.idempotent_id('ba754393-896e-434a-9704-452ff4a84f3f') - def test_create_aggregate_rbac(self): - with self.override_role(): - self._create_aggregate() - - @rbac_rule_validation.action( - service="nova", rules=["os_compute_api:os-aggregates:show"]) - @decorators.idempotent_id('8fb0b749-b120-4727-b3fb-bcfa3fa6f55b') - def test_show_aggregate_rbac(self): - aggregate_id = self._create_aggregate() - with self.override_role(): - self.aggregates_client.show_aggregate(aggregate_id) - - @rbac_rule_validation.action( - service="nova", rules=["os_compute_api:os-aggregates:index"]) - @decorators.idempotent_id('146284da-5dd6-4c97-b598-42b480f014c6') - def test_list_aggregate_rbac(self): - with self.override_role(): - self.aggregates_client.list_aggregates() - - @rbac_rule_validation.action( - service="nova", rules=["os_compute_api:os-aggregates:update"]) - @decorators.idempotent_id('c94e0d69-99b6-477e-b301-2cd0e9d0ad81') - def test_update_aggregate_rbac(self): - aggregate_id = self._create_aggregate() - new_name = data_utils.rand_name(self.__class__.__name__ + '-aggregate') - with self.override_role(): - self.aggregates_client.update_aggregate(aggregate_id, - name=new_name) - - @rbac_rule_validation.action( - service="nova", rules=["os_compute_api:os-aggregates:delete"]) - @decorators.idempotent_id('5a50c5a6-0f12-4405-a1ce-2288ae895ea6') - def test_delete_aggregate_rbac(self): - aggregate_id = self._create_aggregate() - with self.override_role(): - self.aggregates_client.delete_aggregate(aggregate_id) - - @rbac_rule_validation.action( - service="nova", rules=["os_compute_api:os-aggregates:add_host"]) - @decorators.idempotent_id('97e6e9df-5291-4faa-8147-755b2d1f1ce2') - def test_add_host_to_aggregate_rbac(self): - aggregate_id = self._create_aggregate() - with self.override_role(): - self._add_host_to_aggregate(aggregate_id) - - @rbac_rule_validation.action( - service="nova", rules=["os_compute_api:os-aggregates:remove_host"]) - @decorators.idempotent_id('5b035a25-75d2-4d72-b4d6-0f0337335628') - def test_remove_host_from_aggregate_rbac(self): - aggregate_id = self._create_aggregate() - self._add_host_to_aggregate(aggregate_id) - with self.override_role(): - self.aggregates_client.remove_host(aggregate_id, host=self.host) - - @rbac_rule_validation.action( - service="nova", rules=["os_compute_api:os-aggregates:set_metadata"]) - @decorators.idempotent_id('ed6f3849-065c-4ae9-a81e-6ad7ed0d3d9d') - def test_set_metadata_on_aggregate_rbac(self): - aggregate_id = self._create_aggregate() - rand_key = data_utils.rand_name(self.__class__.__name__ + '-key') - rand_val = data_utils.rand_name(self.__class__.__name__ + '-val') - with self.override_role(): - self.aggregates_client.set_metadata( - aggregate_id, - metadata={rand_key: rand_val}) diff --git a/patrole_tempest_plugin/tests/api/compute/test_availability_zone_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_availability_zone_rbac.py deleted file mode 100644 index c7fe6426..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_availability_zone_rbac.py +++ /dev/null @@ -1,45 +0,0 @@ -# Copyright 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. - -from tempest.common import utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - - -class NovaAvailabilityZoneRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def skip_checks(cls): - super(NovaAvailabilityZoneRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-availability-zone', 'compute'): - msg = ("%s skipped as os-availability-zone not " - "enabled." % cls.__name__) - raise cls.skipException(msg) - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-availability-zone:list"]) - @decorators.idempotent_id('cd34e7ea-d26e-4fa3-a8d0-f8883726ce3d') - def test_get_availability_zone_list_rbac(self): - with self.override_role(): - self.availability_zone_client.list_availability_zones() - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-availability-zone:detail"]) - @decorators.idempotent_id('2f61c191-6ece-4f21-b487-39d749e3d38e') - def test_get_availability_zone_list_detail_rbac(self): - with self.override_role(): - self.availability_zone_client.list_availability_zones(detail=True) diff --git a/patrole_tempest_plugin/tests/api/compute/test_flavor_access_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_flavor_access_rbac.py deleted file mode 100644 index 9f976bdc..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_flavor_access_rbac.py +++ /dev/null @@ -1,116 +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. - -import testtools - -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - -CONF = config.CONF - - -class FlavorAccessRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def resource_setup(cls): - super(FlavorAccessRbacTest, cls).resource_setup() - cls.flavor_id = cls.create_flavor(is_public=False)['id'] - cls.public_flavor_id = CONF.compute.flavor_ref - cls.tenant_id = cls.os_primary.credentials.tenant_id - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @decorators.idempotent_id('a2bd3740-765d-4c95-ac98-9e027378c75e') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-flavor-access"]) - def test_show_flavor_contains_is_public_key(self): - public_flavor_id = CONF.compute.flavor_ref - - with self.override_role(): - body = self.flavors_client.show_flavor(public_flavor_id)[ - 'flavor'] - - expected_attr = 'os-flavor-access:is_public' - if expected_attr not in body: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @decorators.idempotent_id('dd388146-9750-4124-82ba-62deff1052bb') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-flavor-access"]) - def test_list_flavors_details_contains_is_public_key(self): - expected_attr = 'os-flavor-access:is_public' - - with self.override_role(): - flavors = self.flavors_client.list_flavors(detail=True)['flavors'] - # There should already be a public flavor available, namely - # `CONF.compute.flavor_ref`. - public_flavors = [f for f in flavors if expected_attr in f] - - # If the `expected_attr` was not found in any flavor, then policy - # enforcement failed. - if not public_flavors: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) - - @decorators.idempotent_id('39cb5c8f-9990-436f-9282-fc76a41d9bac') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-flavor-access:add_tenant_access"]) - def test_add_flavor_access(self): - with self.override_role(): - self.flavors_client.add_flavor_access( - flavor_id=self.flavor_id, tenant_id=self.tenant_id) - self.addCleanup(self.flavors_client.remove_flavor_access, - flavor_id=self.flavor_id, tenant_id=self.tenant_id) - - @decorators.idempotent_id('61b8621f-52e4-473a-8d07-e228af8853d1') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-flavor-access:remove_tenant_access"]) - def test_remove_flavor_access(self): - self.flavors_client.add_flavor_access( - flavor_id=self.flavor_id, tenant_id=self.tenant_id) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.flavors_client.remove_flavor_access, - flavor_id=self.flavor_id, tenant_id=self.tenant_id) - - with self.override_role(): - self.flavors_client.remove_flavor_access( - flavor_id=self.flavor_id, tenant_id=self.tenant_id) - - @decorators.idempotent_id('e1cf59fb-7f32-40a1-96b9-248ab23dd581') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-flavor-access"]) - def test_list_flavor_access(self): - # Add flavor access for os_primary so that it can access the flavor or - # else a NotFound is raised. - self.flavors_client.add_flavor_access( - flavor_id=self.flavor_id, tenant_id=self.tenant_id) - self.addCleanup(self.flavors_client.remove_flavor_access, - flavor_id=self.flavor_id, tenant_id=self.tenant_id) - - with self.override_role(): - self.flavors_client.list_flavor_access(self.flavor_id) diff --git a/patrole_tempest_plugin/tests/api/compute/test_flavor_extra_specs_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_flavor_extra_specs_rbac.py deleted file mode 100644 index c2f9f402..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_flavor_extra_specs_rbac.py +++ /dev/null @@ -1,94 +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.common import utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - - -class FlavorExtraSpecsRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def skip_checks(cls): - super(FlavorExtraSpecsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-flavor-extra-specs', 'compute'): - msg = "os-flavor-extra-specs extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(FlavorExtraSpecsRbacTest, cls).resource_setup() - cls.flavor = cls.create_flavor() - - def _set_flavor_extra_spec(self): - rand_key = data_utils.rand_name(self.__class__.__name__ + '-key') - rand_val = data_utils.rand_name(self.__class__.__name__ + '-val') - specs = {rand_key: rand_val} - self.flavors_client.set_flavor_extra_spec(self.flavor['id'], - **specs)['extra_specs'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.flavors_client.unset_flavor_extra_spec, - self.flavor['id'], rand_key) - return rand_key - - @decorators.idempotent_id('daee891d-dfe9-4501-a39c-29f2371bec3c') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-flavor-extra-specs:show"]) - def test_show_flavor_extra_spec(self): - key = self._set_flavor_extra_spec() - with self.override_role(): - self.flavors_client.show_flavor_extra_spec(self.flavor['id'], key) - - @decorators.idempotent_id('fcffeca2-ed04-4e85-bf93-02fb5643f22b') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-flavor-extra-specs:create"]) - def test_set_flavor_extra_spec(self): - with self.override_role(): - self._set_flavor_extra_spec() - - @decorators.idempotent_id('42b85279-6bfa-4f58-b7a2-258c284f03c5') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-flavor-extra-specs:update"]) - def test_update_flavor_extra_spec(self): - key = self._set_flavor_extra_spec() - update_val = data_utils.rand_name(self.__class__.__name__ + '-val') - with self.override_role(): - self.flavors_client.update_flavor_extra_spec( - self.flavor['id'], key, **{key: update_val}) - - @decorators.idempotent_id('4b0e5471-e010-4c09-8965-80898e6760a3') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-flavor-extra-specs:delete"]) - def test_unset_flavor_extra_spec(self): - key = self._set_flavor_extra_spec() - with self.override_role(): - self.flavors_client.unset_flavor_extra_spec(self.flavor['id'], key) - - @decorators.idempotent_id('02c3831a-3ce9-476e-a722-d805ac2da621') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-flavor-extra-specs:index"]) - def test_list_flavor_extra_specs(self): - self._set_flavor_extra_spec() - with self.override_role(): - self.flavors_client.list_flavor_extra_specs(self.flavor['id']) diff --git a/patrole_tempest_plugin/tests/api/compute/test_flavor_manage_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_flavor_manage_rbac.py deleted file mode 100644 index 2aa69321..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_flavor_manage_rbac.py +++ /dev/null @@ -1,49 +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.common import utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - - -class FlavorManageRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def skip_checks(cls): - super(FlavorManageRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('OS-FLV-EXT-DATA', 'compute'): - msg = "OS-FLV-EXT-DATA extension not enabled." - raise cls.skipException(msg) - - @decorators.idempotent_id('a4e7faec-7a4b-4809-9856-90d5b747ca35') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-flavor-manage:create"]) - def test_create_flavor_manage(self): - with self.override_role(): - self.create_flavor() - - @decorators.idempotent_id('782e988e-061b-4c40-896f-a77c70c2b057') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-flavor-manage:delete"]) - def test_delete_flavor_manage(self): - flavor_id = self.create_flavor()['id'] - - with self.override_role(): - self.flavors_client.delete_flavor(flavor_id) - self.flavors_client.wait_for_resource_deletion(flavor_id) diff --git a/patrole_tempest_plugin/tests/api/compute/test_flavor_rxtx_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_flavor_rxtx_rbac.py deleted file mode 100644 index 50ab048d..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_flavor_rxtx_rbac.py +++ /dev/null @@ -1,63 +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. - -import testtools - -from tempest.common import utils -from tempest import config -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - -CONF = config.CONF - - -class FlavorRxtxRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def skip_checks(cls): - super(FlavorRxtxRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-flavor-rxtx', 'compute'): - msg = "os-flavor-rxtx extension not enabled." - raise cls.skipException(msg) - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @decorators.idempotent_id('5e1fd9f0-9a08-485a-ad9c-0fc66e4d64b7') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-flavor-rxtx"]) - def test_list_flavors_details_rxtx(self): - with self.override_role(): - result = self.flavors_client.list_flavors(detail=True)['flavors'] - if 'rxtx_factor' not in result[0]: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='rxtx_factor') - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @decorators.idempotent_id('70c55a07-c843-4627-a29d-ba78673c1e63') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-flavor-rxtx"]) - def test_get_flavor_rxtx(self): - with self.override_role(): - result = self.flavors_client.show_flavor( - CONF.compute.flavor_ref)['flavor'] - if 'rxtx_factor' not in result: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='rxtx_factor') diff --git a/patrole_tempest_plugin/tests/api/compute/test_floating_ip_pools_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_floating_ip_pools_rbac.py deleted file mode 100644 index 3736f8db..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_floating_ip_pools_rbac.py +++ /dev/null @@ -1,54 +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.common import utils -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 FloatingIpPoolsRbacTest(rbac_base.BaseV2ComputeRbacTest): - - # Tests will fail with a 404 starting from microversion 2.36: - # See the following link for details: - # https://docs.openstack.org/api-ref/compute/#floating-ip-pools-os-floating-ip-pools-deprecated - max_microversion = '2.35' - - @classmethod - def setup_clients(cls): - super(FloatingIpPoolsRbacTest, cls).setup_clients() - cls.fip_pools_client = cls.os_primary.floating_ip_pools_client - - @classmethod - def skip_checks(cls): - super(FloatingIpPoolsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-floating-ip-pools', 'compute'): - msg = "%s skipped as os-floating-ip-pools extension not enabled." \ - % cls.__name__ - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @decorators.idempotent_id('c1a17153-b25d-4444-a721-5897d7737482') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-floating-ip-pools"]) - def test_list_floating_ip_pools(self): - with self.override_role(): - self.fip_pools_client.list_floating_ip_pools() diff --git a/patrole_tempest_plugin/tests/api/compute/test_floating_ips_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_floating_ips_rbac.py deleted file mode 100644 index ed3691ef..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_floating_ips_rbac.py +++ /dev/null @@ -1,101 +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.common import utils -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - -CONF = config.CONF - -# RBAC category or action was changed in Victoria release per -# https://docs.openstack.org/api-ref/compute/#floating-ips-os-floating-ips-deprecated -# and -# https://github.com/openstack/nova/blob/master/nova/policies/floating_ips.py#L21 -if CONF.policy_feature_enabled.changed_nova_policies_victoria: - _FIP_GET = "os_compute_api:os-floating-ips:list" - _FIP_SHOW = "os_compute_api:os-floating-ips:show" - _FIP_CREATE = "os_compute_api:os-floating-ips:create" - _FIP_DELETE = "os_compute_api:os-floating-ips:delete" -else: - _FIP_GET = "os_compute_api:os-floating-ips" - _FIP_SHOW = "os_compute_api:os-floating-ips" - _FIP_CREATE = "os_compute_api:os-floating-ips" - _FIP_DELETE = "os_compute_api:os-floating-ips" - - -class FloatingIpsRbacTest(rbac_base.BaseV2ComputeRbacTest): - - # Tests will fail with a 404 starting from microversion 2.36: - # See the following link for details: - # https://docs.openstack.org/api-ref/compute/#floating-ips-os-floating-ips-deprecated - max_microversion = '2.35' - - @classmethod - def skip_checks(cls): - super(FloatingIpsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-floating-ips', 'compute'): - msg = "%s skipped as os-floating-ips extension not enabled." \ - % cls.__name__ - raise cls.skipException(msg) - if not CONF.network_feature_enabled.floating_ips: - raise cls.skipException("Floating ips are not available") - - @decorators.idempotent_id('ac1b3053-f755-4cda-85a0-30e88b88d7ba') - @rbac_rule_validation.action( - service="nova", - rules=[_FIP_GET]) - def test_list_floating_ips(self): - with self.override_role(): - self.floating_ips_client.list_floating_ips() - - @decorators.idempotent_id('bebe52b3-5269-4e72-80c8-5a4a39c3bfa6') - @rbac_rule_validation.action( - service="nova", - rules=[_FIP_SHOW]) - def test_show_floating_ip(self): - body = self.floating_ips_client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - self.addCleanup( - self.floating_ips_client.delete_floating_ip, body['id']) - with self.override_role(): - self.floating_ips_client.show_floating_ip(body['id']) - - @decorators.idempotent_id('2bfb8745-c329-4ee9-95f6-c165a1989dbf') - @rbac_rule_validation.action( - service="nova", - rules=[_FIP_CREATE]) - def test_create_floating_ips(self): - with self.override_role(): - body = self.floating_ips_client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - self.addCleanup( - self.floating_ips_client.delete_floating_ip, body['id']) - - @decorators.idempotent_id('d3028373-5027-4e7a-b761-01c515403ecb') - @rbac_rule_validation.action( - service="nova", - rules=[_FIP_DELETE]) - def test_delete_floating_ip(self): - body = self.floating_ips_client.create_floating_ip( - pool=CONF.network.floating_network_name)['floating_ip'] - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.floating_ips_client.delete_floating_ip, body['id']) - with self.override_role(): - self.floating_ips_client.delete_floating_ip(body['id']) diff --git a/patrole_tempest_plugin/tests/api/compute/test_hosts_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_hosts_rbac.py deleted file mode 100644 index 5a598e0c..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_hosts_rbac.py +++ /dev/null @@ -1,64 +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.common import utils -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 - -if CONF.policy_feature_enabled.changed_nova_policies_victoria: - _HOSTS_LIST = "os_compute_api:os-hosts:list" - _HOSTS_SHOW = "os_compute_api:os-hosts:show" -else: - _HOSTS_LIST = "os_compute_api:os-hosts" - _HOSTS_SHOW = "os_compute_api:os-hosts" - - -class HostsRbacTest(rbac_base.BaseV2ComputeRbacTest): - # These tests will fail with a 404 starting from microversion 2.43: - # See the following links for details: - # https://docs.openstack.org/api-ref/compute/#hosts-os-hosts-deprecated - max_microversion = '2.42' - - @classmethod - def skip_checks(cls): - super(HostsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-hosts', 'compute'): - msg = "%s skipped as os-hosts not enabled." % cls.__name__ - raise cls.skipException(msg) - - @decorators.idempotent_id('035b7935-2fae-4218-8d37-27fa83097494') - @rbac_rule_validation.action( - service="nova", - rules=[_HOSTS_LIST]) - def test_list_hosts(self): - with self.override_role(): - self.hosts_client.list_hosts() - - @decorators.idempotent_id('bc10d8b4-d2c3-4d4e-9d2b-31d1bd3e1b51') - @rbac_rule_validation.action( - service="nova", - rules=[_HOSTS_SHOW]) - def test_show_host_details(self): - hosts = self.hosts_client.list_hosts()['hosts'] - hosts = [host for host in hosts if host['service'] == 'compute'] - self.assertNotEmpty(hosts) - - with self.override_role(): - self.hosts_client.show_host(hosts[0]['host_name']) diff --git a/patrole_tempest_plugin/tests/api/compute/test_hypervisor_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_hypervisor_rbac.py deleted file mode 100644 index 8ad253a9..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_hypervisor_rbac.py +++ /dev/null @@ -1,138 +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.common import utils -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 - -if CONF.policy_feature_enabled.changed_nova_policies_ussuri: - _HYPERVISOR_LIST = "os_compute_api:os-hypervisors:list" - _HYPERVISOR_SHOW = "os_compute_api:os-hypervisors:show" - _HYPERVISOR_LIST_DETAIL = "os_compute_api:os-hypervisors:list-detail" - _HYPERVISOR_STATISTICS = "os_compute_api:os-hypervisors:statistics" - _HYPERVISOR_UPTIME = "os_compute_api:os-hypervisors:uptime" - _HYPERVISOR_SEARCH = "os_compute_api:os-hypervisors:search" - _HYPERVISOR_SERVER = "os_compute_api:os-hypervisors:servers" -else: - _HYPERVISOR_LIST = "os_compute_api:os-hypervisors" - _HYPERVISOR_SHOW = "os_compute_api:os-hypervisors" - _HYPERVISOR_LIST_DETAIL = "os_compute_api:os-hypervisors" - _HYPERVISOR_STATISTICS = "os_compute_api:os-hypervisors" - _HYPERVISOR_UPTIME = "os_compute_api:os-hypervisors" - _HYPERVISOR_SEARCH = "os_compute_api:os-hypervisors" - _HYPERVISOR_SERVER = "os_compute_api:os-hypervisors" - - -class HypervisorRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def skip_checks(cls): - super(HypervisorRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-hypervisors', 'compute'): - msg = "%s skipped as os-hypervisors extension not enabled." \ - % cls.__name__ - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(HypervisorRbacTest, cls).resource_setup() - cls.hypervisor =\ - cls.hypervisor_client.list_hypervisors()['hypervisors'][0] - - @decorators.idempotent_id('17bbeb9a-e73e-445f-a771-c794448ef562') - @rbac_rule_validation.action( - service="nova", - rules=[_HYPERVISOR_LIST]) - def test_list_hypervisors(self): - with self.override_role(): - self.hypervisor_client.list_hypervisors() - - @decorators.idempotent_id('36b95c7d-1085-487a-a674-b7c1ca35f520') - @rbac_rule_validation.action( - service="nova", - rules=[_HYPERVISOR_LIST_DETAIL]) - def test_list_hypervisors_with_details(self): - with self.override_role(): - self.hypervisor_client.list_hypervisors(detail=True) - - @decorators.idempotent_id('8a7f6f9e-34a6-4480-8875-bba566c3a581') - @rbac_rule_validation.action( - service="nova", - rules=[_HYPERVISOR_SHOW]) - def test_show_hypervisor(self): - with self.override_role(): - self.hypervisor_client.show_hypervisor(self.hypervisor['id']) - - @decorators.idempotent_id('ca0e465c-6365-4a7f-ae58-6f8ddbca06c2') - @rbac_rule_validation.action( - service="nova", - rules=[_HYPERVISOR_STATISTICS]) - def test_show_hypervisor_statistics(self): - with self.override_role(): - self.hypervisor_client.show_hypervisor_statistics() - - @decorators.idempotent_id('109b37c5-91ba-4da5-b2a2-d7618d84406d') - @rbac_rule_validation.action( - service="nova", - rules=[_HYPERVISOR_UPTIME]) - def test_show_hypervisor_uptime(self): - with self.override_role(): - self.hypervisor_client.show_hypervisor_uptime( - self.hypervisor['id']) - - -class HypervisorMaxv252RbacTest(rbac_base.BaseV2ComputeRbacTest): - # These tests will fail with a 404 starting from microversion 2.53: - # See the following links for details: - # https://docs.openstack.org/api-ref/compute/#list-hypervisor-servers - # https://docs.openstack.org/api-ref/compute/#search-hypervisor - max_microversion = '2.52' - - @classmethod - def skip_checks(cls): - super(HypervisorMaxv252RbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-hypervisors', 'compute'): - msg = "%s skipped as os-hypervisors extension not enabled." \ - % cls.__name__ - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(HypervisorMaxv252RbacTest, cls).resource_setup() - cls.hypervisor =\ - cls.hypervisor_client.list_hypervisors()['hypervisors'][0] - - @decorators.idempotent_id('b86f03cf-2e79-4d88-9eea-62f761591413') - @rbac_rule_validation.action( - service="nova", - rules=[_HYPERVISOR_SERVER]) - def test_list_servers_on_hypervisor(self): - with self.override_role(): - self.hypervisor_client.list_servers_on_hypervisor( - self.hypervisor['hypervisor_hostname']) - - @decorators.idempotent_id('3dbc71c1-8f04-4674-a67c-dcb2fd99b1b4') - @rbac_rule_validation.action( - service="nova", - rules=[_HYPERVISOR_SEARCH]) - def test_search_hypervisor(self): - with self.override_role(): - self.hypervisor_client.search_hypervisor( - self.hypervisor['hypervisor_hostname']) diff --git a/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py deleted file mode 100644 index 66590e9d..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_images_rbac.py +++ /dev/null @@ -1,314 +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. - -import testtools - -from tempest.common import image as common_image -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 as lib_exc - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - -CONF = config.CONF - - -class ImagesRbacTest(rbac_base.BaseV2ComputeRbacTest): - """RBAC tests for the Nova images API. - - These APIs are proxy calls to the Image service. Consequently, no Nova - policy actions are enforced; instead, only Glance policy actions are - enforced. As such, these tests check that only Glance policy actions are - executed. - """ - - # These tests will fail with a 404 starting from microversion 2.36. - # See the following link for details: - # https://docs.openstack.org/api-ref/compute/#images-deprecated - max_microversion = '2.35' - - @classmethod - def skip_checks(cls): - super(ImagesRbacTest, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ImagesRbacTest, cls).setup_clients() - if CONF.image_feature_enabled.api_v2: - cls.glance_image_client = cls.os_primary.image_client_v2 - elif CONF.image_feature_enabled.api_v1: - cls.glance_image_client = cls.os_primary.image_client - else: - raise lib_exc.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - - @classmethod - def resource_setup(cls): - super(ImagesRbacTest, cls).resource_setup() - params = {'name': data_utils.rand_name(cls.__name__ + '-image')} - if CONF.image_feature_enabled.api_v1: - params = {'headers': common_image.image_meta_to_headers(**params)} - - cls.image = cls.glance_image_client.create_image(**params) - cls.addClassResourceCleanup( - cls.glance_image_client.wait_for_resource_deletion, - cls.image['id']) - cls.addClassResourceCleanup( - cls.glance_image_client.delete_image, cls.image['id']) - - @decorators.idempotent_id('b861f302-b72b-4055-81db-c62ff30b136d') - @rbac_rule_validation.action( - service="glance", - rules=["get_images"]) - def test_list_images(self): - with self.override_role(): - self.compute_images_client.list_images() - - @decorators.idempotent_id('4365ae0f-15ee-4b54-a527-1679faaed140') - @rbac_rule_validation.action( - service="glance", - rules=["get_images"]) - def test_list_images_with_details(self): - with self.override_role(): - self.compute_images_client.list_images(detail=True) - - @decorators.idempotent_id('886dfcae-51bf-4610-9e52-82d7189524c2') - @rbac_rule_validation.action( - service="glance", - rules=["get_image"]) - def test_show_image_details(self): - with self.override_role(): - self.compute_images_client.show_image(self.image['id']) - - @decorators.idempotent_id('5888c7aa-0803-46d4-a3fb-5d4729465cd5') - @rbac_rule_validation.action( - service="glance", - rules=["delete_image"]) - def test_delete_image(self): - image = self.glance_image_client.create_image( - name=data_utils.rand_name(self.__class__.__name__ + '-image')) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.glance_image_client.delete_image, image['id']) - - with self.override_role(): - self.compute_images_client.delete_image(image['id']) - - -class ImagesMetadataRbacTest(rbac_base.BaseV2ComputeRbacTest): - """RBAC tests for the Nova metadata images API. - - These APIs are proxy calls to the Image service. Consequently, no Nova - policy actions are enforced; instead, only Glance policy actions are - enforced. As such, these tests check that only Glance policy actions are - executed. - """ - - # These tests will fail with a 404 starting from microversion 2.39. - # See the following link for details: - # https://docs.openstack.org/api-ref/compute/#images-deprecated - max_microversion = '2.38' - - @classmethod - def skip_checks(cls): - super(ImagesMetadataRbacTest, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ImagesMetadataRbacTest, cls).setup_clients() - if CONF.image_feature_enabled.api_v2: - cls.glance_image_client = cls.os_primary.image_client_v2 - elif CONF.image_feature_enabled.api_v1: - cls.glance_image_client = cls.os_primary.image_client - else: - raise lib_exc.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - - @classmethod - def resource_setup(cls): - super(ImagesMetadataRbacTest, cls).resource_setup() - params = {'name': data_utils.rand_name(cls.__name__ + '-image')} - if CONF.image_feature_enabled.api_v1: - params = {'headers': common_image.image_meta_to_headers(**params)} - - cls.image = cls.glance_image_client.create_image(**params) - cls.addClassResourceCleanup( - cls.glance_image_client.wait_for_resource_deletion, - cls.image['id']) - cls.addClassResourceCleanup( - cls.glance_image_client.delete_image, cls.image['id']) - - @decorators.idempotent_id('dbe09d4c-e615-48cb-b908-a06a0f410a8e') - @rbac_rule_validation.action( - service="glance", - rules=["get_image"]) - def test_show_image_metadata_item(self): - self.compute_images_client.set_image_metadata(self.image['id'], - meta={'foo': 'bar'}) - self.addCleanup(self.compute_images_client.delete_image_metadata_item, - self.image['id'], key='foo') - - with self.override_role(): - self.compute_images_client.show_image_metadata_item( - self.image['id'], key='foo') - - @decorators.idempotent_id('59f66079-d564-47e8-81b0-03c2e84d339e') - @rbac_rule_validation.action( - service="glance", - rules=["get_image"]) - def test_list_image_metadata(self): - with self.override_role(): - self.compute_images_client.list_image_metadata(self.image['id']) - - @decorators.idempotent_id('575604aa-909f-4b1b-a5a5-cfae1f63044b') - @rbac_rule_validation.action( - service="glance", - rules=["modify_image"]) - def test_create_image_metadata(self): - with self.override_role(): - # NOTE(felipemonteiro): Although the name of the client function - # appears wrong, it's actually correct: update_image_metadata does - # an http post. - self.compute_images_client.update_image_metadata( - self.image['id'], meta={'foo': 'bar'}) - self.addCleanup(self.compute_images_client.delete_image_metadata_item, - self.image['id'], key='foo') - - @decorators.idempotent_id('fb8c4eb6-00e5-454c-b8bc-0e801ec369f1') - @rbac_rule_validation.action( - service="glance", - rules=["modify_image"]) - def test_update_image_metadata(self): - with self.override_role(): - self.compute_images_client.set_image_metadata(self.image['id'], - meta={'foo': 'bar'}) - self.addCleanup(self.compute_images_client.delete_image_metadata_item, - self.image['id'], key='foo') - - @decorators.idempotent_id('9c7c2036-af9b-49a8-8ba1-09b027ee5def') - @rbac_rule_validation.action( - service="glance", - rules=["modify_image"]) - def test_update_image_metadata_item(self): - with self.override_role(): - self.compute_images_client.set_image_metadata_item( - self.image['id'], meta={'foo': 'bar'}, key='foo') - self.addCleanup(self.compute_images_client.delete_image_metadata_item, - self.image['id'], key='foo') - - @decorators.idempotent_id('5f0dc4e6-0761-4613-9bde-0a6acdc78f46') - @rbac_rule_validation.action( - service="glance", - rules=["modify_image"]) - def test_delete_image_metadata_item(self): - self.compute_images_client.set_image_metadata(self.image['id'], - meta={'foo': 'bar'}) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.compute_images_client.delete_image_metadata_item, - self.image['id'], key='foo') - - with self.override_role(): - 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://docs.openstack.org/api-ref/compute/#images-deprecated - max_microversion = '2.35' - - @classmethod - def skip_checks(cls): - super(ImageSizeRbacTest, cls).skip_checks() - if not CONF.service_available.glance: - skip_msg = ("%s skipped as glance is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def setup_clients(cls): - super(ImageSizeRbacTest, cls).setup_clients() - if CONF.image_feature_enabled.api_v2: - cls.glance_image_client = cls.os_primary.image_client_v2 - elif CONF.image_feature_enabled.api_v1: - cls.glance_image_client = cls.os_primary.image_client - else: - raise lib_exc.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - - @classmethod - def resource_setup(cls): - super(ImageSizeRbacTest, cls).resource_setup() - params = {'name': data_utils.rand_name(cls.__name__ + '-image')} - if CONF.image_feature_enabled.api_v1: - params = {'headers': common_image.image_meta_to_headers(**params)} - - cls.image = cls.glance_image_client.create_image(**params) - cls.addClassResourceCleanup( - cls.glance_image_client.wait_for_resource_deletion, - cls.image['id']) - cls.addClassResourceCleanup( - cls.glance_image_client.delete_image, cls.image['id']) - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @decorators.idempotent_id('fe34d2a6-5743-45bf-8f92-a1d703d7c7ab') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:image-size"]) - def test_show_image_includes_image_size(self): - with self.override_role(): - body = self.compute_images_client.show_image(self.image['id'])[ - 'image'] - - expected_attr = 'OS-EXT-IMG-SIZE:size' - if expected_attr not in body: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @decorators.idempotent_id('08342c7d-297d-42ee-b398-90fce2443792') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:image-size"]) - def test_list_images_with_details_includes_image_size(self): - with self.override_role(): - body = self.compute_images_client.list_images(detail=True)[ - 'images'] - - expected_attr = 'OS-EXT-IMG-SIZE:size' - if expected_attr not in body[0]: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) diff --git a/patrole_tempest_plugin/tests/api/compute/test_instance_usages_audit_log_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_instance_usages_audit_log_rbac.py deleted file mode 100644 index 72c4b022..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_instance_usages_audit_log_rbac.py +++ /dev/null @@ -1,64 +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. - -import datetime - -from six.moves.urllib import parse as urllib - -from tempest.common import utils -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 - -if CONF.policy_feature_enabled.changed_nova_policies_ussuri: - _INSTANCE_USAGE_LIST = "os_compute_api:os-instance-usage-audit-log:list" - _INSTANCE_USAGE_SHOW = "os_compute_api:os-instance-usage-audit-log:show" -else: - _INSTANCE_USAGE_LIST = "os_compute_api:os-instance-usage-audit-log" - _INSTANCE_USAGE_SHOW = "os_compute_api:os-instance-usage-audit-log" - - -class InstanceUsagesAuditLogRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def skip_checks(cls): - super(InstanceUsagesAuditLogRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-instance-usage-audit-log', - 'compute'): - msg = "os-instance-usage-audit-log extension not enabled." - raise cls.skipException(msg) - - @decorators.idempotent_id('c80246c0-5c13-4ab0-97ba-91551cd53dc1') - @rbac_rule_validation.action( - service="nova", rules=[_INSTANCE_USAGE_LIST]) - def test_list_instance_usage_audit_logs(self): - with self.override_role(): - (self.instance_usages_audit_log_client - .list_instance_usage_audit_logs()) - - @decorators.idempotent_id('ded8bfbd-5d90-4a58-aee0-d31231bf3c9b') - @rbac_rule_validation.action( - service="nova", rules=[_INSTANCE_USAGE_SHOW]) - def test_show_instance_usage_audit_log(self): - now = datetime.datetime.now() - - with self.override_role(): - (self.instance_usages_audit_log_client. - show_instance_usage_audit_log( - urllib.quote(now.strftime("%Y-%m-%d %H:%M:%S")))) diff --git a/patrole_tempest_plugin/tests/api/compute/test_keypairs_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_keypairs_rbac.py deleted file mode 100644 index 15d71436..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_keypairs_rbac.py +++ /dev/null @@ -1,66 +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.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - - -class KeypairsRbacTest(rbac_base.BaseV2ComputeRbacTest): - - def _create_keypair(self): - key_name = data_utils.rand_name(self.__class__.__name__ + '-key') - keypair = self.keypairs_client.create_keypair(name=key_name) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.keypairs_client.delete_keypair, - key_name) - return keypair - - @decorators.idempotent_id('16e0ae81-e05f-48cd-b253-cf31ab0732f0') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-keypairs:create"]) - def test_create_keypair(self): - with self.override_role(): - self._create_keypair() - - @decorators.idempotent_id('85a5eb99-40ec-4e77-9358-bee2cdf9d7df') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-keypairs:show"]) - def test_show_keypair(self): - kp_name = self._create_keypair()['keypair']['name'] - with self.override_role(): - self.keypairs_client.show_keypair(kp_name) - - @decorators.idempotent_id('6bff9f1c-b809-43c1-8d63-61fbd19d49d3') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-keypairs:delete"]) - def test_delete_keypair(self): - kp_name = self._create_keypair()['keypair']['name'] - with self.override_role(): - self.keypairs_client.delete_keypair(kp_name) - - @decorators.idempotent_id('6bb31346-ff7f-4b10-978e-170ac5fcfa3e') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-keypairs:index"]) - def test_index_keypair(self): - with self.override_role(): - self.keypairs_client.list_keypairs() diff --git a/patrole_tempest_plugin/tests/api/compute/test_limits_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_limits_rbac.py deleted file mode 100644 index 564a36d5..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_limits_rbac.py +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright 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. - -from tempest.common import utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - - -class LimitsRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def skip_checks(cls): - super(LimitsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-limits', 'compute'): - msg = "%s skipped as os-limits not enabled." % cls.__name__ - raise cls.skipException(msg) - - @rbac_rule_validation.action(service="nova", - rules=["os_compute_api:limits"]) - @decorators.idempotent_id('3fb60f83-9a5f-4fdd-89d9-26c3710844a1') - def test_show_limits(self): - with self.override_role(): - self.limits_client.show_limits() diff --git a/patrole_tempest_plugin/tests/api/compute/test_migrations_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_migrations_rbac.py deleted file mode 100644 index cd3047da..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_migrations_rbac.py +++ /dev/null @@ -1,38 +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.common import utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - - -class MigrationsRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def skip_checks(cls): - super(MigrationsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-migrations', 'compute'): - msg = "%s skipped as os-migrations not enabled." % cls.__name__ - raise cls.skipException(msg) - - @decorators.idempotent_id('5795231c-3729-448c-a072-9a225db1a328') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-migrations:index"]) - def test_list_services(self): - with self.override_role(): - self.migrations_client.list_migrations() diff --git a/patrole_tempest_plugin/tests/api/compute/test_quota_class_sets_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_quota_class_sets_rbac.py deleted file mode 100644 index b26ddc3b..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_quota_class_sets_rbac.py +++ /dev/null @@ -1,85 +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.common import identity -from tempest.common import tempest_fixtures as fixtures -from tempest.common import utils -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.compute import rbac_base - - -class QuotaClassesRbacTest(rbac_base.BaseV2ComputeRbacTest): - - credentials = ['primary', 'admin'] - - def setUp(self): - # All test cases in this class need to externally lock on doing - # anything with default quota values. - self.useFixture(fixtures.LockFixture('compute_quotas')) - super(QuotaClassesRbacTest, self).setUp() - - @classmethod - def skip_checks(cls): - super(QuotaClassesRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-quota-class-sets', 'compute'): - msg = "%s skipped as os-quota-class-sets extension not enabled."\ - % cls.__name__ - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(QuotaClassesRbacTest, cls).setup_clients() - cls.quota_classes_client = cls.os_primary.quota_classes_client - cls.identity_projects_client = cls.os_primary.projects_client - - @classmethod - def resource_setup(cls): - super(QuotaClassesRbacTest, cls).resource_setup() - # Create a project with its own quota. - project_name = data_utils.rand_name(cls.__name__) - project_desc = project_name + '-desc' - project = identity.identity_utils(cls.os_admin).create_project( - name=project_name, description=project_desc) - cls.project_id = project['id'] - cls.addClassResourceCleanup( - identity.identity_utils(cls.os_admin).delete_project, - cls.project_id) - - @decorators.idempotent_id('c10198ed-9df2-440e-a49b-367dadc6de94') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-quota-class-sets:show"]) - def test_show_quota_class_set(self): - with self.override_role(): - self.quota_classes_client.show_quota_class_set('default') - - @decorators.idempotent_id('81889e69-efd2-4e96-bb4c-ee3b646b9755') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-quota-class-sets:update"]) - def test_update_quota_class_set(self): - # Update the pre-existing quotas for the project_id. - quota_class_set = self.quota_classes_client.show_quota_class_set( - self.project_id)['quota_class_set'] - quota_class_set.pop('id') - for quota, default in quota_class_set.items(): - quota_class_set[quota] = default + 100 - - with self.override_role(): - self.quota_classes_client.update_quota_class_set( - self.project_id, **quota_class_set) diff --git a/patrole_tempest_plugin/tests/api/compute/test_quota_sets_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_quota_sets_rbac.py deleted file mode 100644 index a41d0e0c..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_quota_sets_rbac.py +++ /dev/null @@ -1,112 +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.common import identity -from tempest.common import utils -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.compute import rbac_base - - -class QuotaSetsRbacTest(rbac_base.BaseV2ComputeRbacTest): - - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(QuotaSetsRbacTest, cls).setup_clients() - cls.projects_client = cls.os_primary.projects_client - - @classmethod - def skip_checks(cls): - super(QuotaSetsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-quota-sets', 'compute'): - msg = "%s skipped as os-quota-sets extension not enabled."\ - % cls.__name__ - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(QuotaSetsRbacTest, cls).resource_setup() - cls.tenant_id = cls.quotas_client.tenant_id - cls.user_id = cls.quotas_client.user_id - cls.quota_set = set(('injected_file_content_bytes', - 'metadata_items', 'injected_files', - 'ram', 'floating_ips', 'fixed_ips', 'key_pair', - 'injected_file_path_bytes', 'instances', - 'security_group_rules', 'cores', - 'security_groups')) - - @decorators.idempotent_id('8229ceb0-db6a-4a2c-99c2-de226905d8b6') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-quota-sets:update"]) - def test_update_quota_set(self): - default_quota_set = self.quotas_client.show_default_quota_set( - self.tenant_id)['quota_set'] - default_quota_set.pop('id') - new_quota_set = {'injected_file_content_bytes': 20480} - - with self.override_role(): - self.quotas_client.update_quota_set(self.tenant_id, - force=True, - **new_quota_set) - self.addCleanup(self.quotas_client.update_quota_set, self.tenant_id, - **default_quota_set) - - @decorators.idempotent_id('58df5613-8f3c-400a-8b4b-2bae624d05e9') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-quota-sets:defaults"]) - def test_show_default_quota_set(self): - with self.override_role(): - self.quotas_client.show_default_quota_set(self.tenant_id) - - @decorators.idempotent_id('e8169ac4-c402-4864-894e-aba74e3a459c') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-quota-sets:show"]) - def test_show_quota_set(self): - with self.override_role(): - self.quotas_client.show_quota_set(self.tenant_id) - - @decorators.idempotent_id('4e240644-bf61-4872-9c32-8289ee2fdbbd') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-quota-sets:delete"]) - def test_delete_quota_set(self): - project_name = data_utils.rand_name( - self.__class__.__name__) - project_desc = project_name + '-desc' - project = identity.identity_utils(self.os_admin).create_project( - name=project_name, description=project_desc) - project_id = project['id'] - self.addCleanup( - identity.identity_utils(self.os_admin).delete_project, - project_id) - - with self.override_role(): - self.quotas_client.delete_quota_set(project_id) - - @decorators.idempotent_id('ac9184b6-f3b3-4e17-a632-4b92c6500f86') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-quota-sets:detail"]) - def test_show_quota_set_details(self): - with self.override_role(): - self.quotas_client.show_quota_set(self.tenant_id, - detail=True) 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 deleted file mode 100644 index cf19befb..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_security_groups_rbac.py +++ /dev/null @@ -1,187 +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.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - -CONF = config.CONF - -if CONF.policy_feature_enabled.changed_nova_policies_ussuri: - _SG_LIST = "os_compute_api:os-security-groups:list" - _SG_ADD = "os_compute_api:os-security-groups:add" - _SG_REMOVE = "os_compute_api:os-security-groups:remove" -else: - _SG_LIST = "os_compute_api:os-security-groups" - _SG_ADD = "os_compute_api:os-security-groups" - _SG_REMOVE = "os_compute_api:os-security-groups" - -if CONF.policy_feature_enabled.changed_nova_policies_victoria: - _SG_GET = "os_compute_api:os-security-groups:get" - _SG_SHOW = "os_compute_api:os-security-groups:show" - _SG_CREATE = "os_compute_api:os-security-groups:create" - _SG_UPDATE = "os_compute_api:os-security-groups:update" - _SG_DELETE = "os_compute_api:os-security-groups:delete" -else: - _SG_GET = "os_compute_api:os-security-groups" - _SG_SHOW = "os_compute_api:os-security-groups" - _SG_CREATE = "os_compute_api:os-security-groups" - _SG_UPDATE = "os_compute_api:os-security-groups" - _SG_DELETE = "os_compute_api:os-security-groups" - - -class SecurtiyGroupsRbacTest(rbac_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 skip_checks(cls): - super(SecurtiyGroupsRbacTest, cls).skip_checks() - # All the tests below require the network service. - # NOTE(gmann) Currently 'network' service is always True in - # utils.get_service_list() So below check is not much of use. - # Commenting the below check as Tempest is moving the get_service_list - # from test.py to utils. - # If we want to check 'network' service availability, then - # get_service_list can be used from new location. - # if not utils.get_service_list()['network']: - # raise cls.skipException( - # 'Skipped because the network service is not available') - - @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 resource_setup(cls): - super(SecurtiyGroupsRbacTest, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - - @rbac_rule_validation.action( - service="nova", - rules=[_SG_LIST]) - @decorators.idempotent_id('3db159c6-a467-469f-9a25-574197885520') - def test_list_security_groups_by_server(self): - with self.override_role(): - self.servers_client.list_security_groups_by_server( - self.server['id']) - - @rbac_rule_validation.action( - service="nova", - rules=[_SG_ADD]) - @decorators.idempotent_id('ea1ca73f-2d1d-43cb-9a46-900d7927b357') - def test_create_security_group_for_server(self): - sg_name = self.create_security_group()['name'] - - with self.override_role(): - 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) - - @rbac_rule_validation.action( - service="nova", - rules=[_SG_REMOVE]) - @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) - - with self.override_role(): - self.servers_client.remove_security_group( - self.server['id'], name=sg_name) - - -class SecurityGroupsRbacMaxV235Test(rbac_base.BaseV2ComputeRbacTest): - - # Tests in this class will fail with a 404 from microversion 2.36, - # according to: - # https://docs.openstack.org/api-ref/compute/#security-groups-os-security-groups-deprecated - max_microversion = '2.35' - - @classmethod - def skip_checks(cls): - super(SecurityGroupsRbacMaxV235Test, cls).skip_checks() - # All the tests below require the network service. - # NOTE(gmann) Currently 'network' service is always True in - # utils.get_service_list() So below check is not much of use. - # Commenting the below check as Tempest is moving the get_service_list - # from test.py to utils. - # If we want to check 'network' service availability, then - # get_service_list can be used from new location. - # if not utils.get_service_list()['network']: - # raise cls.skipException( - # 'Skipped because the network service is not available') - - @rbac_rule_validation.action( - service="nova", - rules=[_SG_GET]) - @decorators.idempotent_id('4ac58e49-48c1-4fca-a6c3-3f95fb99eb77') - def test_list_security_groups(self): - with self.override_role(): - self.security_groups_client.list_security_groups() - - @rbac_rule_validation.action( - service="nova", - rules=[_SG_CREATE]) - @decorators.idempotent_id('e8fe7f5a-69ee-412d-81d3-a8c7a488b54d') - def test_create_security_groups(self): - with self.override_role(): - self.create_security_group()['id'] - - @rbac_rule_validation.action( - service="nova", - rules=[_SG_DELETE]) - @decorators.idempotent_id('59127e8e-302d-11e7-93ae-92361f002671') - def test_delete_security_groups(self): - sec_group_id = self.create_security_group()['id'] - with self.override_role(): - self.security_groups_client.delete_security_group(sec_group_id) - - @rbac_rule_validation.action( - service="nova", - rules=[_SG_UPDATE]) - @decorators.idempotent_id('3de5c6bc-b822-469e-a627-82427d38b067') - def test_update_security_groups(self): - sec_group_id = self.create_security_group()['id'] - new_name = data_utils.rand_name() - new_desc = data_utils.rand_name() - - with self.override_role(): - self.security_groups_client.update_security_group( - sec_group_id, name=new_name, description=new_desc) - - @rbac_rule_validation.action( - service="nova", - rules=[_SG_SHOW]) - @decorators.idempotent_id('6edc0320-302d-11e7-93ae-92361f002671') - def test_show_security_groups(self): - sec_group_id = self.create_security_group()['id'] - with self.override_role(): - self.security_groups_client.show_security_group(sec_group_id) diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py deleted file mode 100644 index 1410caa1..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_server_actions_rbac.py +++ /dev/null @@ -1,422 +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. - -import testtools - -from tempest.common import utils -from tempest.common import waiters -from tempest import config -from tempest.lib.common import api_version_utils -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 as lib_exc - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - -CONF = config.CONF - - -class ServerActionsRbacTest(rbac_base.BaseV2ComputeRbacTest): - - # admin credentials used for waiters which invokes a show API call - credentials = ['primary', 'admin'] - - @classmethod - def setup_clients(cls): - super(ServerActionsRbacTest, cls).setup_clients() - cls.admin_servers_client = cls.os_admin.servers_client - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(ServerActionsRbacTest, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(ServerActionsRbacTest, cls).resource_setup() - cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id'] - cls.flavor_ref = CONF.compute.flavor_ref - cls.flavor_ref_alt = CONF.compute.flavor_ref_alt - cls.image_ref = CONF.compute.image_ref - - def setUp(self): - super(ServerActionsRbacTest, 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: - # Recreating the server in case something happened during a test - self.__class__.server_id = self.recreate_server(self.server_id) - - def _stop_server(self): - self.servers_client.stop_server(self.server_id) - waiters.wait_for_server_status( - self.admin_servers_client, self.server_id, 'SHUTOFF') - - def _resize_server(self, flavor): - status = self.admin_servers_client. \ - show_server(self.server_id)['server']['status'] - if status == 'RESIZED': - return - self.servers_client.resize_server(self.server_id, flavor) - waiters.wait_for_server_status( - self.admin_servers_client, self.server_id, 'VERIFY_RESIZE') - - def _confirm_resize_server(self): - status = self.admin_servers_client. \ - show_server(self.server_id)['server']['status'] - if status == 'VERIFY_RESIZE': - self.servers_client.confirm_resize_server(self.server_id) - waiters.wait_for_server_status( - self.admin_servers_client, self.server_id, 'ACTIVE') - - def _shelve_server(self): - self.servers_client.shelve_server(self.server_id) - self.addCleanup(self._cleanup_server_actions, - self.servers_client.unshelve_server, - self.server_id) - offload_time = CONF.compute.shelved_offload_time - if offload_time >= 0: - waiters.wait_for_server_status(self.admin_servers_client, - self.server_id, - 'SHELVED_OFFLOADED', - extra_timeout=offload_time) - else: - waiters.wait_for_server_status(self.admin_servers_client, - self.server_id, - 'SHELVED') - - def _pause_server(self): - self.servers_client.pause_server(self.server_id) - self.addCleanup(self._cleanup_server_actions, - self.servers_client.unpause_server, - self.server_id) - waiters.wait_for_server_status( - self.admin_servers_client, self.server_id, 'PAUSED') - - def _cleanup_server_actions(self, function, server_id, **kwargs): - server = self.servers_client.show_server(server_id)['server'] - if server['status'] != 'ACTIVE': - function(server_id, **kwargs) - - @decorators.idempotent_id('117f4ff2-8544-437b-824f-5e41cb6640ee') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-pause-server:pause"]) - def test_pause_server(self): - with self.override_role(): - self._pause_server() - - @decorators.idempotent_id('087008cf-82fa-4eeb-ae8b-32c4126456ad') - @testtools.skipUnless(CONF.compute_feature_enabled.pause, - 'Pause is not available.') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-pause-server:unpause"]) - def test_unpause_server(self): - self._pause_server() - with self.override_role(): - self.servers_client.unpause_server(self.server_id) - waiters.wait_for_server_status( - self.servers_client, self.server_id, 'ACTIVE') - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:stop"]) - @decorators.idempotent_id('ab4a17d2-166f-4a6d-9944-f17baa576cf2') - def test_stop_server(self): - with self.override_role(): - self._stop_server() - - @decorators.attr(type='slow') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:start"]) - @decorators.idempotent_id('8876bfa9-4d10-406e-a335-a57e451abb12') - def test_start_server(self): - self._stop_server() - - with self.override_role(): - self.servers_client.start_server(self.server_id) - waiters.wait_for_server_status( - self.servers_client, self.server_id, 'ACTIVE') - - @decorators.attr(type='slow') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:resize"]) - @decorators.idempotent_id('0546fbdd-2d8f-4ce8-ac00-f1e2129d0765') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize is not available.') - def test_resize_server(self): - with self.override_role(): - self._resize_server(self.flavor_ref_alt) - - @decorators.attr(type='slow') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:revert_resize"]) - @decorators.idempotent_id('d41b64b8-a72d-414a-a4c5-94e1eb5e5a96') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize is not available.') - def test_revert_resize_server(self): - self._resize_server(self.flavor_ref_alt) - - with self.override_role(): - self.servers_client.revert_resize_server(self.server_id) - waiters.wait_for_server_status( - self.servers_client, self.server_id, 'ACTIVE') - - @decorators.attr(type='slow') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:confirm_resize"]) - @decorators.idempotent_id('f51620cb-dfcb-4e5d-b421-2e0edaa1316e') - @testtools.skipUnless(CONF.compute_feature_enabled.resize, - 'Resize is not available.') - def test_confirm_resize_server(self): - self._resize_server(self.flavor_ref_alt) - self.addCleanup(self._confirm_resize_server) - self.addCleanup(self._resize_server, self.flavor_ref) - self.addCleanup(self._confirm_resize_server) - - with self.override_role(): - self._confirm_resize_server() - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:rebuild"]) - @decorators.idempotent_id('54b1a30b-c96c-472c-9c83-ccaf6ec7e20b') - def test_rebuild_server(self): - with self.override_role(): - self.servers_client.rebuild_server(self.server_id, self.image_ref) - waiters.wait_for_server_status( - self.servers_client, self.server_id, 'ACTIVE') - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:reboot"]) - @decorators.idempotent_id('19f27856-56e1-44f8-8615-7257f6b85cbb') - def test_reboot_server(self): - with self.override_role(): - self.servers_client.reboot_server(self.server_id, type='HARD') - waiters.wait_for_server_status( - self.servers_client, self.server_id, 'ACTIVE') - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:index"]) - @decorators.idempotent_id('631f0d86-7607-4198-8312-9da2f05464a4') - def test_server_index(self): - with self.override_role(): - self.servers_client.list_servers(minimal=True) - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:detail"]) - @decorators.idempotent_id('96093480-3ce5-4a8b-b569-aed870379c24') - def test_server_detail(self): - with self.override_role(): - self.servers_client.list_servers(detail=True) - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:detail:get_all_tenants"]) - @decorators.idempotent_id('a9e5a1c0-acfe-49a2-b2b1-fd8b19d61f71') - def test_server_detail_all_tenants(self): - with self.override_role(): - self.servers_client.list_servers(detail=True, all_tenants=1) - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:index:get_all_tenants"]) - @decorators.idempotent_id('4b93ba56-69e6-41f5-82c4-84a5c4c42091') - def test_server_index_all_tenants(self): - with self.override_role(): - self.servers_client.list_servers(minimal=True, all_tenants=1) - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:show"]) - @decorators.idempotent_id('eaaf4f51-31b5-497f-8f0f-f527e5f70b83') - def test_show_server(self): - with self.override_role(): - self.servers_client.show_server(self.server_id) - - @utils.services('image') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:create_image"]) - @decorators.idempotent_id('ba0ac859-99f4-4055-b5e0-e0905a44d331') - def test_create_image(self): - with self.override_role(): - # This function will also call show image - self.create_image_from_server(self.server_id, wait_until='ACTIVE') - - @utils.services('image', 'volume') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:create_image:allow_volume_backed"]) - @decorators.idempotent_id('8b869f73-49b3-4cc4-a0ce-ef64f8e1d6f9') - def test_create_image_from_volume_backed_server(self): - # volume_backed=True creates a volume and create server will be - # requested with 'block_device_mapping_v2' with necessary values for - # this test. - server = self.create_test_server(volume_backed=True, - wait_until='ACTIVE') - with self.override_role(): - # This function will also call show image. - image = self.create_image_from_server(server['id'], - wait_until='ACTIVE', - wait_for_server=False) - self.addCleanup(self.compute_images_client.wait_for_resource_deletion, - image['id']) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.compute_images_client.delete_image, image['id']) - - @decorators.idempotent_id('9fdd4630-731c-4f7c-bce5-69fa3792c52a') - @decorators.attr(type='slow') - @testtools.skipUnless(CONF.compute_feature_enabled.snapshot, - 'Snapshotting not available, backup not possible.') - @utils.services('image') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-create-backup"]) - def test_create_backup(self): - # Prioritize glance v2 over v1 for deleting/waiting for image status. - if CONF.image_feature_enabled.api_v2: - glance_client = self.os_primary.image_client_v2 - elif CONF.image_feature_enabled.api_v1: - glance_client = self.os_primary.image_client - else: - raise lib_exc.InvalidConfiguration( - 'Either api_v1 or api_v2 must be True in ' - '[image-feature-enabled].') - - backup_name = data_utils.rand_name(self.__class__.__name__ + '-Backup') - - with self.override_role(): - resp = self.servers_client.create_backup( - self.server_id, backup_type='daily', rotation=1, - name=backup_name).response - - # Prior to microversion 2.45, image ID must be parsed from location - # header. With microversion 2.45+, image_id is returned. - if api_version_utils.compare_version_header_to_response( - "OpenStack-API-Version", "2.45", resp, "lt"): - image_id = resp['image_id'] - else: - image_id = data_utils.parse_image_id(resp['location']) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - glance_client.delete_image, image_id) - waiters.wait_for_image_status(glance_client, image_id, 'active') - - @decorators.attr(type='slow') - @decorators.idempotent_id('0b70c527-af75-4bed-9ccf-4f1310a8b60f') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-shelve:shelve"]) - def test_shelve_server(self): - with self.override_role(): - self._shelve_server() - - @decorators.attr(type='slow') - @decorators.idempotent_id('4b6e849a-9182-49ff-9257-e97e751b475e') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-shelve:unshelve"]) - def test_unshelve_server(self): - self._shelve_server() - with self.override_role(): - self.servers_client.unshelve_server(self.server_id) - waiters.wait_for_server_status( - self.servers_client, self.server_id, 'ACTIVE') - - -class ServerActionsV214RbacTest(rbac_base.BaseV2ComputeRbacTest): - - min_microversion = '2.14' - max_microversion = 'latest' - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(ServerActionsV214RbacTest, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(ServerActionsV214RbacTest, cls).resource_setup() - cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id'] - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-evacuate"]) - @decorators.idempotent_id('78ecef3c-faff-412a-83be-47651963eb21') - def test_evacuate_server(self): - fake_host_name = data_utils.rand_name( - self.__class__.__name__ + '-fake-host') - - # NOTE(felipemonteiro): Because evacuating a server is a risky action - # to test in the gates, a 404 is coerced using a fake host. However, - # the policy check is done before the 404 is thrown. - with self.override_role(): - self.assertRaisesRegex( - lib_exc.NotFound, - "Compute host %s not found." % fake_host_name, - self.servers_client.evacuate_server, self.server_id, - host=fake_host_name) - - -class ServerActionsV216RbacTest(rbac_base.BaseV2ComputeRbacTest): - - # This class has test case(s) that requires at least microversion 2.16. - # See the following link for details: - # https://docs.openstack.org/api-ref/compute/#show-server-details - min_microversion = '2.16' - max_microversion = 'latest' - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(ServerActionsV216RbacTest, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(ServerActionsV216RbacTest, cls).resource_setup() - cls.server_id = cls.create_test_server(wait_until='ACTIVE')['id'] - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:show:host_status"]) - @decorators.idempotent_id('736da575-86f8-4b2a-9902-dd37dc9a409b') - def test_show_server_host_status(self): - with self.override_role(): - server = self.servers_client.show_server(self.server_id)['server'] - - if 'host_status' not in server: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='host_status') 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 deleted file mode 100644 index 076ad058..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_server_consoles_rbac.py +++ /dev/null @@ -1,109 +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.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 setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(ServerConsolesRbacTest, cls).setup_credentials() - - @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", - rules=["os_compute_api:os-console-output"]) - @decorators.idempotent_id('90fd80f6-456c-11e7-a919-92ebcb67fe33') - def test_get_console_output(self): - with self.override_role(): - 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 setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(ServerConsolesMaxV25RbacTest, cls).setup_credentials() - - @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", - rules=["os_compute_api:os-remote-consoles"]) - @decorators.idempotent_id('b0a72c02-9b15-4dcb-b186-efe8753370ab') - def test_get_vnc_console_output(self): - with self.override_role(): - 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 setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(ServerConsolesV26RbacTest, cls).setup_credentials() - - @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", - rules=["os_compute_api:os-remote-consoles"]) - @decorators.idempotent_id('879597de-87e0-4da9-a60a-28c8088dc508') - def test_get_remote_console_output(self): - with self.override_role(): - self.servers_client.get_remote_console(self.server_id, - "novnc", "vnc") diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_groups_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_groups_rbac.py deleted file mode 100644 index 7c5002be..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_server_groups_rbac.py +++ /dev/null @@ -1,64 +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.common import utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - - -class ServerGroupsRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def skip_checks(cls): - super(ServerGroupsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-server-groups', 'compute'): - msg = "%s skipped as os-server-groups not enabled." % cls.__name__ - raise cls.skipException(msg) - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-server-groups:create"]) - @decorators.idempotent_id('7f3eae94-6130-47e9-81ac-34009f55be2f') - def test_create_server_group(self): - with self.override_role(): - self.create_test_server_group() - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-server-groups:delete"]) - @decorators.idempotent_id('832d9be3-632e-47b2-93d2-5897db43e3e2') - def test_delete_server_group(self): - server_group = self.create_test_server_group() - with self.override_role(): - self.server_groups_client.delete_server_group(server_group['id']) - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-server-groups:index"]) - @decorators.idempotent_id('5eccd67f-5945-483b-b1c8-de851ebfc1c1') - def test_list_server_groups(self): - with self.override_role(): - self.server_groups_client.list_server_groups() - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-server-groups:show"]) - @decorators.idempotent_id('62534e3f-7e99-4a3d-a08e-33e056460cf2') - def test_show_server_group(self): - server_group = self.create_test_server_group() - with self.override_role(): - self.server_groups_client.show_server_group(server_group['id']) diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_metadata_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_metadata_rbac.py deleted file mode 100644 index 55536ad6..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_server_metadata_rbac.py +++ /dev/null @@ -1,89 +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 patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - - -class ServerMetadataRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(ServerMetadataRbacTest, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(ServerMetadataRbacTest, cls).resource_setup() - cls.server = cls.create_test_server(metadata={}, wait_until='ACTIVE') - cls.meta = {'default_key': 'value1', 'delete_key': 'value2'} - - def setUp(self): - super(ServerMetadataRbacTest, self).setUp() - self.servers_client.set_server_metadata(self.server['id'], self.meta)[ - 'metadata'] - - @decorators.idempotent_id('b07bbc27-58e2-4581-869d-ad228cec5d9a') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:server-metadata:index"]) - def test_list_server_metadata(self): - with self.override_role(): - self.servers_client.list_server_metadata(self.server['id']) - - @decorators.idempotent_id('6e76748b-2417-4fa2-b41a-c0cc4bff356b') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:server-metadata:update_all"]) - def test_set_server_metadata(self): - with self.override_role(): - self.servers_client.set_server_metadata(self.server['id'], {}) - - @decorators.idempotent_id('1060bac4-fe16-4a77-be64-d8e482a06eab') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:server-metadata:create"]) - def test_update_server_metadata(self): - with self.override_role(): - self.servers_client.update_server_metadata(self.server['id'], {}) - - @decorators.idempotent_id('93dd8323-d3fa-48d1-8bd6-91c1b62fc341') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:server-metadata:show"]) - def test_show_server_metadata_item(self): - with self.override_role(): - self.servers_client.show_server_metadata_item( - self.server['id'], 'default_key') - - @decorators.idempotent_id('79511293-4bd7-447d-ba7e-634d0f4da70c') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:server-metadata:update"]) - def test_set_server_metadata_item(self): - with self.override_role(): - self.servers_client.set_server_metadata_item( - self.server['id'], 'default_key', {'default_key': 'value2'}) - - @decorators.idempotent_id('feec5064-678d-40bc-a88f-c856e18d1e31') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:server-metadata:delete"]) - def test_delete_server_metadata_item(self): - with self.override_role(): - self.servers_client.delete_server_metadata_item( - self.server['id'], 'delete_key') diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_migrations_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_migrations_rbac.py deleted file mode 100644 index 6ad8f400..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_server_migrations_rbac.py +++ /dev/null @@ -1,92 +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. - -import testtools - -from tempest.common import waiters -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 as base - -CONF = config.CONF - - -class MigrateServerV225RbacTest(base.BaseV2ComputeRbacTest): - min_microversion = '2.25' - max_microversion = 'latest' - block_migration = 'auto' - - @classmethod - def skip_checks(cls): - super(MigrateServerV225RbacTest, cls).skip_checks() - if CONF.compute.min_compute_nodes < 2: - raise cls.skipException( - "Less than 2 compute nodes, skipping migration tests.") - - def _get_server_details(self, server_id): - body = self.servers_client.show_server(server_id)['server'] - return body - - def _get_host_for_server(self, server_id): - return self._get_server_details(server_id)['OS-EXT-SRV-ATTR:host'] - - def _get_host_other_than(self, host): - for target_host in self._get_compute_hostnames(): - if host != target_host: - return target_host - - def _get_compute_hostnames(self): - body = self.hosts_client.list_hosts()['hosts'] - return [ - host_record['host_name'] - for host_record in body - if host_record['service'] == 'compute' - ] - - @decorators.attr(type='slow') - @testtools.skipUnless(CONF.compute_feature_enabled.cold_migration, - 'Cold migration not available.') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-migrate-server:migrate"]) - @decorators.idempotent_id('c6f1607c-9fed-4c00-807e-9ba675b98b1b') - def test_cold_migration(self): - server = self.create_test_server(wait_until="ACTIVE") - with self.override_role(): - self.servers_client.migrate_server(server['id']) - waiters.wait_for_server_status(self.servers_client, - server['id'], 'VERIFY_RESIZE') - - @decorators.attr(type='slow') - @testtools.skipUnless(CONF.compute_feature_enabled.live_migration, - 'Live migration feature is not enabled.') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-migrate-server:migrate_live"]) - @decorators.idempotent_id('33520834-72c8-4edb-a189-a2e0fc9eb0d3') - def test_migration_live(self): - server_id = self.create_test_server(wait_until="ACTIVE", - volume_backed=False)['id'] - actual_host = self._get_host_for_server(server_id) - target_host = self._get_host_other_than(actual_host) - - with self.override_role(): - self.servers_client.live_migrate_server( - server_id, host=target_host, - block_migration=self.block_migration) - waiters.wait_for_server_status(self.servers_client, - server_id, "ACTIVE") 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 deleted file mode 100644 index 9abd00e5..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_server_misc_policy_actions_rbac.py +++ /dev/null @@ -1,828 +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. - -import netaddr - -import testtools - -from tempest.common import utils -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 as lib_exc - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - -CONF = config.CONF - -if CONF.policy_feature_enabled.changed_nova_policies_ussuri: - _DEFERRED_FORCE = "os_compute_api:os-deferred-delete:force" - _ATTACH_INTERFACES_LIST = "os_compute_api:os-attach-interfaces:list" - _ATTACH_INTERFACES_SHOW = "os_compute_api:os-attach-interfaces:show" - _INSTANCE_ACTIONS_LIST = "os_compute_api:os-instance-actions:list" - _SERVER_PASSWORD_SHOW = "os_compute_api:os-server-password:show" - _SERVER_PASSWORD_CLEAR = "os_compute_api:os-server-password:clear" -else: - _DEFERRED_FORCE = "os_compute_api:os-deferred-delete" - _ATTACH_INTERFACES_LIST = "os_compute_api:os-attach-interfaces" - _ATTACH_INTERFACES_SHOW = "os_compute_api:os-attach-interfaces" - _INSTANCE_ACTIONS_LIST = "os_compute_api:os-instance-actions" - _SERVER_PASSWORD_SHOW = "os_compute_api:os-server-password" - _SERVER_PASSWORD_CLEAR = "os_compute_api:os-server-password" - -if CONF.policy_feature_enabled.changed_nova_policies_victoria: - _MULTINIC_ADD = "os_compute_api:os-multinic:add" -else: - _MULTINIC_ADD = "os_compute_api:os-multinic" - - -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 - - Tests are ordered by policy name. - """ - - credentials = ['primary', 'admin'] - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(MiscPolicyActionsRbacTest, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(MiscPolicyActionsRbacTest, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - - 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 - self.__class__.server = self.create_test_server( - wait_until='ACTIVE') - except Exception: - # Rebuilding the server in case something happened during a test - self.__class__.server = self._rebuild_server(self.server['id']) - - def _rebuild_server(self, server_id): - # Destroy an existing server and creates a new one. - if server_id: - self.delete_server(server_id) - - self.password = data_utils.rand_password() - return self.create_test_server( - wait_until='ACTIVE', adminPass=self.password) - - @utils.requires_ext(extension='os-admin-actions', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["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.""" - with self.override_role(): - self.servers_client.reset_state(self.server['id'], state='error') - self.addCleanup(self.servers_client.reset_state, self.server['id'], - state='active') - - @utils.requires_ext(extension='os-admin-actions', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["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.""" - with self.override_role(): - self.servers_client.inject_network_info(self.server['id']) - - @testtools.skipIf( - CONF.policy_feature_enabled.removed_nova_policies_wallaby, - "This API extension policy was removed in Wallaby") - @utils.requires_ext(extension='os-admin-actions', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["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.""" - with self.override_role(): - self.servers_client.reset_network(self.server['id']) - - @testtools.skipUnless(CONF.compute_feature_enabled.change_password, - 'Change password not available.') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-admin-password"]) - @decorators.idempotent_id('908a7d59-3a66-441c-94cf-38e57ed14956') - def test_change_server_password(self): - """Test change admin password, part of os-admin-password.""" - original_password = self.servers_client.show_password( - self.server['id']) - - with self.override_role(): - self.servers_client.change_password( - self.server['id'], adminPass=data_utils.rand_password()) - self.addCleanup(self.servers_client.change_password, self.server['id'], - adminPass=original_password) - waiters.wait_for_server_status( - self.servers_client, self.server['id'], 'ACTIVE') - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @utils.requires_ext(extension='os-config-drive', service='compute') - @decorators.idempotent_id('2c82e819-382d-4d6f-87f0-a45954cbbc64') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-config-drive"]) - def test_list_servers_with_details_config_drive(self): - """Test list servers with config_drive property in response body.""" - with self.override_role(): - body = self.servers_client.list_servers(detail=True)['servers'] - expected_attr = 'config_drive' - # If the first server contains "config_drive", then all the others do. - if expected_attr not in body[0]: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @utils.requires_ext(extension='os-config-drive', service='compute') - @decorators.idempotent_id('55c62ef7-b72b-4970-acc6-05b0a4316e5d') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-config-drive"]) - def test_show_server_config_drive(self): - """Test show server with config_drive property in response body.""" - with self.override_role(): - body = self.servers_client.show_server(self.server['id'])['server'] - expected_attr = 'config_drive' - if expected_attr not in body: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) - - @utils.requires_ext(extension='os-deferred-delete', service='compute') - @decorators.idempotent_id('189bfed4-1e6d-475c-bb8c-d57e60895391') - @rbac_rule_validation.action( - service="nova", - rules=[_DEFERRED_FORCE]) - def test_force_delete_server(self): - """Test force delete server, part of os-deferred-delete.""" - with self.override_role(): - # Force-deleting a server enforces os-deferred-delete. - self.servers_client.force_delete_server(self.server['id']) - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @decorators.idempotent_id('d873740a-7b10-40a9-943d-7cc18115370e') - @utils.requires_ext(extension='OS-EXT-AZ', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-extended-availability-zone"]) - def test_list_servers_with_details_extended_availability_zone(self): - """Test list servers OS-EXT-AZ:availability_zone attr in resp body.""" - expected_attr = 'OS-EXT-AZ:availability_zone' - - with self.override_role(): - body = self.servers_client.list_servers(detail=True)['servers'] - # If the first server contains `expected_attr`, then all the others do. - if expected_attr not in body[0]: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @decorators.idempotent_id('727e5360-770a-4b9c-8015-513a40216635') - @utils.requires_ext(extension='OS-EXT-AZ', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-extended-availability-zone"]) - def test_show_server_extended_availability_zone(self): - """Test show server OS-EXT-AZ:availability_zone attr in resp body.""" - expected_attr = 'OS-EXT-AZ:availability_zone' - - with self.override_role(): - body = self.servers_client.show_server(self.server['id'])['server'] - if expected_attr not in body: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @decorators.idempotent_id('4aa5d93e-4887-468a-8eb4-b6eca0ca6437') - @utils.requires_ext(extension='OS-EXT-SRV-ATTR', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-extended-server-attributes"]) - def test_list_servers_extended_server_attributes(self): - """Test list servers with details, with extended server attributes in - response body. - """ - with self.override_role(): - body = self.servers_client.list_servers(detail=True)['servers'] - - # NOTE(felipemonteiro): The attributes included below should be - # returned by all microversions. We don't include tests for other - # microversions since Tempest schema validation takes care of that in - # `show_server` call above. (Attributes there are *optional*.) - for attr in ('host', 'instance_name'): - whole_attr = 'OS-EXT-SRV-ATTR:%s' % attr - if whole_attr not in body[0]: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=whole_attr) - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @decorators.idempotent_id('2ed7aee2-94b2-4a9f-ae63-a51b7f94fe30') - @utils.requires_ext(extension='OS-EXT-SRV-ATTR', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-extended-server-attributes"]) - def test_show_server_extended_server_attributes(self): - """Test show server with extended server attributes in response - body. - """ - with self.override_role(): - body = self.servers_client.show_server(self.server['id'])['server'] - - # NOTE(felipemonteiro): The attributes included below should be - # returned by all microversions. We don't include tests for other - # microversions since Tempest schema validation takes care of that in - # `show_server` call above. (Attributes there are *optional*.) - for attr in ('host', 'instance_name'): - whole_attr = 'OS-EXT-SRV-ATTR:%s' % attr - if whole_attr not in body: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=whole_attr) - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @decorators.idempotent_id('82053c27-3134-4003-9b55-bc9fafdb0e3b') - @utils.requires_ext(extension='OS-EXT-STS', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-extended-status"]) - def test_list_servers_extended_status(self): - """Test list servers with extended properties in response body.""" - with self.override_role(): - body = self.servers_client.list_servers(detail=True)['servers'] - - expected_attrs = ('OS-EXT-STS:task_state', 'OS-EXT-STS:vm_state', - 'OS-EXT-STS:power_state') - for attr in expected_attrs: - if attr not in body[0]: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=attr) - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @decorators.idempotent_id('7d2620a5-eea1-4a8b-96ea-86ad77a73fc8') - @utils.requires_ext(extension='OS-EXT-STS', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-extended-status"]) - def test_show_server_extended_status(self): - """Test show server with extended properties in response body.""" - with self.override_role(): - body = self.servers_client.show_server(self.server['id'])['server'] - - expected_attrs = ('OS-EXT-STS:task_state', 'OS-EXT-STS:vm_state', - 'OS-EXT-STS:power_state') - for attr in expected_attrs: - if attr not in body: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=attr) - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @decorators.idempotent_id('21e39cbe-6c32-48fc-80dd-3e1fece6053f') - @utils.requires_ext(extension='os-extended-volumes', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-extended-volumes"]) - def test_list_servers_with_details_extended_volumes(self): - """Test list servers os-extended-volumes:volumes_attached attr in resp - body. - """ - expected_attr = 'os-extended-volumes:volumes_attached' - - with self.override_role(): - body = self.servers_client.list_servers(detail=True)['servers'] - if expected_attr not in body[0]: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @decorators.idempotent_id('7f163708-0d25-4138-8512-dfdd72a92989') - @utils.requires_ext(extension='os-extended-volumes', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-extended-volumes"]) - def test_show_server_extended_volumes(self): - """Test show server os-extended-volumes:volumes_attached attr in resp - body. - """ - expected_attr = 'os-extended-volumes:volumes_attached' - - with self.override_role(): - body = self.servers_client.show_server(self.server['id'])['server'] - if expected_attr not in body: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) - - @utils.requires_ext(extension='os-instance-actions', service='compute') - @decorators.idempotent_id('9d1b131d-407e-4fa3-8eef-eb2c4526f1da') - @rbac_rule_validation.action( - service="nova", - rules=[_INSTANCE_ACTIONS_LIST]) - def test_list_instance_actions(self): - """Test list instance actions, part of os-instance-actions.""" - with self.override_role(): - self.servers_client.list_instance_actions(self.server['id']) - - @utils.requires_ext(extension='os-instance-actions', service='compute') - @decorators.idempotent_id('eb04c439-4215-4029-9ccb-5b3c041bfc25') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-instance-actions:events"]) - def test_show_instance_action(self): - """Test show instance action, part of os-instance-actions. - - Expect "events" details to be included in the response body. - """ - # NOTE: "os_compute_api:os-instance-actions" is also enforced. - request_id = self.server.response['x-compute-request-id'] - - with self.override_role(): - instance_action = self.servers_client.show_instance_action( - self.server['id'], request_id)['instanceAction'] - - if 'events' not in instance_action: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='events') - # Microversion 2.51+ returns 'events' always, but not 'traceback'. If - # 'traceback' is also present then policy enforcement passed. - if 'traceback' not in instance_action['events'][0]: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='events.traceback') - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-keypairs"]) - @decorators.idempotent_id('81e6fa34-c06b-42ca-b195-82bf8699b940') - def test_show_server_keypair(self): - with self.override_role(): - result = self.servers_client.show_server(self.server['id'])[ - 'server'] - if 'key_name' not in result: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='key_name') - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-keypairs"]) - @decorators.idempotent_id('41ca4280-ec59-4b80-a9b1-6bc6366faf39') - def test_list_servers_keypairs(self): - with self.override_role(): - result = self.servers_client.list_servers(detail=True)['servers'] - if 'key_name' not in result[0]: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='key_name') - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-lock-server:lock"]) - @decorators.idempotent_id('b81e10fb-1864-498f-8c1d-5175c6fec5fb') - def test_lock_server(self): - """Test lock server, part of os-lock-server.""" - with self.override_role(): - self.servers_client.lock_server(self.server['id']) - self.addCleanup(self.servers_client.unlock_server, self.server['id']) - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-lock-server:unlock"]) - @decorators.idempotent_id('d50ef8e8-4bce-11e7-b114-b2f933d5fe66') - def test_unlock_server(self): - """Test unlock server, part of os-lock-server.""" - self.servers_client.lock_server(self.server['id']) - self.addCleanup(self.servers_client.unlock_server, self.server['id']) - - with self.override_role(): - self.servers_client.unlock_server(self.server['id']) - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-lock-server:unlock", - "os_compute_api:os-lock-server:unlock:unlock_override"]) - @decorators.idempotent_id('40dfeef9-73ee-48a9-be19-a219875de457') - def test_unlock_server_override(self): - """Test force unlock server, part of os-lock-server. - - 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(self.server['id']) - self.addCleanup(self.servers_client.unlock_server, self.server['id']) - - with self.override_role(): - self.servers_client.unlock_server(self.server['id']) - - @utils.requires_ext(extension='os-rescue', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["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.""" - with self.override_role(): - self.servers_client.rescue_server(self.server['id']) - waiters.wait_for_server_status( - self.servers_client, self.server['id'], 'RESCUE') - - @decorators.idempotent_id('ac2d956f-d6a3-4184-b814-b44d05c9574c') - @utils.requires_ext(extension='os-rescue', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-rescue"]) - def test_unrescue_server(self): - """Test unrescue server, part of os-rescue.""" - self.servers_client.rescue_server(self.server['id']) - waiters.wait_for_server_status( - self.servers_client, self.server['id'], 'RESCUE') - - with self.override_role(): - self.servers_client.unrescue_server(self.server['id']) - waiters.wait_for_server_status( - self.servers_client, self.server['id'], 'ACTIVE') - - @utils.requires_ext(extension='os-server-diagnostics', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["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.""" - with self.override_role(): - self.servers_client.show_server_diagnostics(self.server['id']) - - @utils.requires_ext(extension='os-server-password', service='compute') - @decorators.idempotent_id('aaf43f78-c178-4581-ac18-14afd3f1f6ba') - @rbac_rule_validation.action( - service="nova", - rules=[_SERVER_PASSWORD_CLEAR]) - def test_delete_server_password(self): - """Test delete server password, part of os-server-password.""" - with self.override_role(): - self.servers_client.delete_password(self.server['id']) - - @utils.requires_ext(extension='os-server-password', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=[_SERVER_PASSWORD_SHOW]) - @decorators.idempotent_id('f677971a-7d20-493c-977f-6ff0a74b5b2c') - def test_get_server_password(self): - """Test show server password, part of os-server-password.""" - with self.override_role(): - self.servers_client.show_password(self.server['id']) - - @testtools.skipIf(CONF.policy_feature_enabled.removed_nova_policies_stein, - "This API extension policy was removed in Stein") - @utils.requires_ext(extension='OS-SRV-USG', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["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 testing is supported, this - test should also check for additional policies mentioned here: - https://git.openstack.org/cgit/openstack/nova/tree/nova/policies/server_usage.py?h=17.0.0 - """ - expected_attrs = ('OS-SRV-USG:launched_at', - 'OS-SRV-USG:terminated_at') - - with self.override_role(): - body = self.servers_client.show_server(self.server['id'])['server'] - for expected_attr in expected_attrs: - if expected_attr not in body: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) - - @utils.requires_ext(extension='os-simple-tenant-usage', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-simple-tenant-usage:list"]) - @decorators.idempotent_id('2aef094f-0452-4df6-a66a-0ec22a92b16e') - def test_list_simple_tenant_usages(self): - """Test list tenant usages, part of os-simple-tenant-usage.""" - with self.override_role(): - self.tenant_usages_client.list_tenant_usages() - - @utils.requires_ext(extension='os-simple-tenant-usage', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-simple-tenant-usage:show"]) - @decorators.idempotent_id('fe7eacda-15c4-4bf7-93ef-1091c4546a9d') - def test_show_simple_tenant_usage(self): - """Test show tenant usage, part of os-simple-tenant-usage.""" - tenant_id = self.os_primary.credentials.tenant_id - - with self.override_role(): - self.tenant_usages_client.show_tenant_usage(tenant_id=tenant_id) - - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - "Suspend compute feature is not available.") - @decorators.idempotent_id('b775930f-237c-431c-83ae-d33ed1b9700b') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-suspend-server:suspend"]) - def test_suspend_server(self): - """Test suspend server, part of os-suspend-server.""" - with self.override_role(): - self.servers_client.suspend_server(self.server['id']) - self.addCleanup(self.servers_client.resume_server, self.server['id']) - waiters.wait_for_server_status( - self.servers_client, self.server['id'], 'SUSPENDED') - - @testtools.skipUnless(CONF.compute_feature_enabled.suspend, - "Suspend compute feature is not available.") - @decorators.idempotent_id('4d90bd02-11f8-45b1-a8a1-534665584675') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-suspend-server:resume"]) - def test_resume_server(self): - """Test resume server, part of os-suspend-server.""" - self.servers_client.suspend_server(self.server['id']) - waiters.wait_for_server_status( - self.servers_client, self.server['id'], 'SUSPENDED') - - with self.override_role(): - self.servers_client.resume_server(self.server['id']) - waiters.wait_for_server_status( - self.servers_client, self.server['id'], 'ACTIVE') - - -class MiscPolicyActionsNetworkRbacTest(rbac_base.BaseV2ComputeRbacTest): - """Test multiple policy actions that require a server to be created. - - Only applies to: - * policy "families" that require server creation - * small policy "families" -- i.e. containing one to three policies - * tests that require network resources - """ - - @classmethod - def skip_checks(cls): - super(MiscPolicyActionsNetworkRbacTest, cls).skip_checks() - # All tests below require Neutron availability. - if not CONF.service_available.neutron: - raise cls.skipException( - '%s skipped as Neutron is required' % cls.__name__) - - @classmethod - def setup_clients(cls): - super(MiscPolicyActionsNetworkRbacTest, cls).setup_clients() - cls.servers_admin_client = cls.os_admin.servers_client - - @classmethod - def setup_credentials(cls): - cls.prepare_instance_network() - super(MiscPolicyActionsNetworkRbacTest, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - def _cleanup_ports(network_id): - ports = cls.ports_client.list_ports(network_id=network_id)['ports'] - for port in ports: - test_utils.call_and_ignore_notfound_exc( - cls.ports_client.delete_port, - port['id']) - - super(MiscPolicyActionsNetworkRbacTest, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - - # Create network the interface will be attached to - network_name = data_utils.rand_name(cls.__name__ + '-network') - post_body = {'name': network_name} - post_body['router:external'] = False - post_body['shared'] = True - post_body['port_security_enabled'] = True - cls.network = \ - cls.networks_client.create_network(**post_body)['network'] - cls.addClassResourceCleanup( - cls.networks_client.delete_network, - cls.network['id']) - - # Create subnet for network - cls.cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) - cls.subnet = cls.subnets_client.create_subnet( - network_id=cls.network['id'], - cidr=cls.cidr, - ip_version=4)['subnet'] - cls.addClassResourceCleanup( - cls.subnets_client.delete_subnet, - cls.subnet['id']) - - # ports on the network need to be deleted before the network can - # be deleted - cls.addClassResourceCleanup(_cleanup_ports, cls.network['id']) - - def _delete_and_wait_for_interface_detach( - self, server_id, port_id): - req_id = self.interfaces_client.delete_interface( - server_id, port_id - ).response['x-openstack-request-id'] - waiters.wait_for_interface_detach( - self.servers_admin_client, server_id, port_id, req_id) - - def _delete_and_wait_for_interface_detach_ignore_timeout( - self, server_id, port_id): - try: - self._delete_and_wait_for_interface_detach( - server_id, port_id) - except lib_exc.TimeoutException: - pass - - def _attach_interface_to_server(self): - network_id = self.network['id'] - interface = self.interfaces_client.create_interface( - self.server['id'], net_id=network_id)['interfaceAttachment'] - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self._delete_and_wait_for_interface_detach_ignore_timeout, - self.server['id'], interface['port_id']) - waiters.wait_for_interface_status( - self.interfaces_client, self.server['id'], - interface['port_id'], 'ACTIVE') - return interface - - @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach, - "Interface attachment is not available.") - @utils.requires_ext(extension='os-attach-interfaces', service='compute') - @decorators.idempotent_id('ddf53cb6-4a0a-4e5a-91e3-6c32aaa3b9b6') - @rbac_rule_validation.action( - service="nova", - rules=[_ATTACH_INTERFACES_LIST]) - def test_list_interfaces(self): - """Test list interfaces, part of os-attach-interfaces.""" - with self.override_role(): - self.interfaces_client.list_interfaces(self.server['id']) - - @decorators.idempotent_id('1b9cf7db-dc50-48a2-8eb9-8c25af5e934a') - @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach, - "Interface attachment is not available.") - @utils.requires_ext(extension='os-attach-interfaces', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=[_ATTACH_INTERFACES_SHOW]) - def test_show_interface(self): - """Test show interfaces, part of os-attach-interfaces.""" - interface = self._attach_interface_to_server() - with self.override_role(): - self.interfaces_client.show_interface( - self.server['id'], interface['port_id']) - - @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach, - "Interface attachment is not available.") - @utils.requires_ext(extension='os-attach-interfaces', service='compute') - @decorators.idempotent_id('d2d3a24d-4738-4bce-a287-36d664746cde') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-attach-interfaces:create"]) - def test_create_interface(self): - """Test create interface, part of os-attach-interfaces.""" - network_id = self.network['id'] - with self.override_role(): - interface = self.interfaces_client.create_interface( - self.server['id'], net_id=network_id)['interfaceAttachment'] - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self._delete_and_wait_for_interface_detach_ignore_timeout, - self.server['id'], interface['port_id']) - waiters.wait_for_interface_status( - self.interfaces_client, self.server['id'], - interface['port_id'], 'ACTIVE') - - @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach, - "Interface attachment is not available.") - @utils.requires_ext(extension='os-attach-interfaces', service='compute') - @decorators.idempotent_id('55b05692-ed44-4608-a84c-cd4219c82799') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-attach-interfaces:delete"]) - def test_delete_interface(self): - """Test delete interface, part of os-attach-interfaces.""" - interface = self._attach_interface_to_server() - - with self.override_role(): - req_id = self.interfaces_client.delete_interface( - self.server['id'], interface['port_id']) - try: - # interface may be not found - we need to ignore that - waiters.wait_for_interface_detach( - self.servers_admin_client, self.server['id'], - interface['port_id'], req_id) - except lib_exc.NotFound: - pass - - @decorators.idempotent_id('6886d360-0d86-4760-b1a3-882d81fbebcc') - @utils.requires_ext(extension='os-ips', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:ips:index"]) - def test_list_addresses(self): - """Test list server addresses, part of ips policy family.""" - with self.override_role(): - self.servers_client.list_addresses(self.server['id']) - - @decorators.idempotent_id('fa43e7e5-0db9-48eb-9c6b-c11eb766b8e4') - @utils.requires_ext(extension='os-ips', service='compute') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:ips:show"]) - def test_list_addresses_by_network(self): - """Test list server addresses by network, part of ips policy family.""" - addresses = self.servers_client.list_addresses(self.server['id'])[ - 'addresses'] - address = next(iter(addresses)) - - with self.override_role(): - self.servers_client.list_addresses_by_network( - self.server['id'], address) - - @testtools.skipUnless(CONF.compute_feature_enabled.interface_attach, - "Interface attachment is not available.") - @utils.requires_ext(extension='os-multinic', service='compute') - @rbac_rule_validation.action( - service="nova", rules=[_MULTINIC_ADD]) - @decorators.idempotent_id('bd3e2c74-130a-40f0-8085-124d93fe67da') - def test_add_fixed_ip(self): - """Test add fixed ip to server network, part of os-multinic.""" - interfaces = (self.interfaces_client.list_interfaces(self.server['id']) - ['interfaceAttachments']) - if interfaces: - network_id = interfaces[0]['net_id'] - else: - interface = self.interfaces_client.create_interface( - self.server['id'])['interfaceAttachment'] - network_id = interface['net_id'] - self.addCleanup( - self._delete_and_wait_for_interface_detach, - self.server['id'], interface['port_id']) - - with self.override_role(): - self.servers_client.add_fixed_ip(self.server['id'], - networkId=network_id) - # Get the Fixed IP from server. - server_detail = self.servers_client.show_server( - self.server['id'])['server'] - fixed_ip = None - for ip_set in server_detail['addresses']: - for ip in server_detail['addresses'][ip_set]: - if ip['OS-EXT-IPS:type'] == 'fixed': - fixed_ip = ip['addr'] - break - if fixed_ip is not None: - break - # Remove the fixed IP from server. - # TODO(gmann): separate the remve fixded ip test as it has - # separate policy now. - # self.servers_client.remove_fixed_ip(self.server['id'], - # address=fixed_ip) diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py deleted file mode 100644 index 8592e127..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_server_rbac.py +++ /dev/null @@ -1,204 +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 oslo_log import log - -from tempest.common import utils -from tempest.common import waiters -from tempest import config -from tempest.lib.common import fixed_network -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base as base - -CONF = config.CONF -LOG = log.getLogger(__name__) - - -class ComputeServersRbacTest(base.BaseV2ComputeRbacTest): - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(ComputeServersRbacTest, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ComputeServersRbacTest, cls).setup_clients() - 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') - cls.tenant_network = fixed_network.set_networks_kwarg( - cls.get_tenant_network() - ) - - def _get_instance_config(self): - instance_params = { - 'name': data_utils.rand_name(self.__class__.__name__ + '-Server'), - 'flavorRef': CONF.compute.flavor_ref, - 'imageRef': CONF.compute.image_ref - } - if 'networks' in self.tenant_network: - instance_params['networks'] = self.tenant_network['networks'] - - return instance_params - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:create"]) - @decorators.idempotent_id('4f34c73a-6ddc-4677-976f-71320fa855bd') - def test_create_server(self): - with self.override_role(): - instance_params = self._get_instance_config() - server = self.servers_client.create_server( - **instance_params - )['server'] - self.addCleanup(waiters.wait_for_server_termination, - self.servers_client, server['id']) - self.addCleanup(self.servers_client.delete_server, server['id']) - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:create:forced_host"]) - @decorators.idempotent_id('0ae3c401-52ab-41bc-ab96-c598a65d9ae5') - def test_create_server_forced_host(self): - # Retrieve 'nova' zone host information from availiability_zone_list - zones = self.availability_zone_client.list_availability_zones( - detail=True)['availabilityZoneInfo'] - hosts = [zone['hosts'] for zone in zones if zone['zoneName'] == 'nova'] - - # 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 = list(hosts[0].keys())[0] - availability_zone = 'nova:' + host - with self.override_role(): - instance_params = self._get_instance_config() - instance_params['availability_zone'] = availability_zone - server = self.servers_client.create_server( - **instance_params - )['server'] - self.addCleanup(waiters.wait_for_server_termination, - self.servers_client, server['id']) - self.addCleanup(self.servers_client.delete_server, server['id']) - - @utils.services('volume') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:create:attach_volume"]) - @decorators.idempotent_id('eeddac5e-15aa-454f-838d-db608aae4dd8') - def test_create_server_attach_volume(self): - # To create a bootable volume, the UUID of the image from which - # to create the volume must be included as the imageRef attribute in - # the request body. - volume_id = self.create_volume( - imageRef=CONF.compute.image_ref, - size=CONF.volume.volume_size)['id'] - - bd_map_v2 = [{'uuid': volume_id, - 'source_type': 'volume', - 'destination_type': 'volume', - 'boot_index': 0, - 'delete_on_termination': False}] - with self.override_role(): - instance_params = self._get_instance_config() - # Use imageRef='' to avoid using the default image in tempest.conf. - instance_params['imageRef'] = '' - instance_params['block_device_mapping_v2'] = bd_map_v2 - server = self.servers_client.create_server( - **instance_params - )['server'] - waiters.wait_for_server_status( - self.servers_client, server['id'], 'ACTIVE') - # Delete the server and wait for the volume to become available to - # avoid clean up errors. - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - waiters.wait_for_volume_resource_status, - self.volumes_client, volume_id, 'available') - self.addCleanup(waiters.wait_for_server_termination, - self.servers_client, server['id']) - self.addCleanup(self.delete_server, server['id']) - - @utils.services('network') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:create:attach_network"]) - @decorators.idempotent_id('b44cd4ff-50a4-42ce-ada3-724e213cd540') - def test_create_server_attach_network(self): - def _create_network_resources(): - # Create network - network_name = data_utils.rand_name( - self.__class__.__name__ + '-network') - - network = self.networks_client.create_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') - subnet = self.subnets_client.create_subnet( - name=subnet_name, - network_id=network['id'], - cidr=CONF.network.project_network_cidr, - ip_version=4)['subnet'] - self.addCleanup(self.subnets_client.delete_subnet, subnet['id']) - - return network - - network = _create_network_resources() - network_id = {'uuid': network['id']} - - with self.override_role(): - instance_params = self._get_instance_config() - instance_params['networks'] = [network_id] - server = self.servers_client.create_server( - **instance_params - )['server'] - self.addCleanup(waiters.wait_for_server_termination, - self.servers_client, server['id']) - self.addCleanup(self.servers_client.delete_server, server['id']) - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:delete"]) - @decorators.idempotent_id('062e3440-e873-4b41-9317-bf6d8be50c12') - def test_delete_server(self): - server = self.create_test_server(wait_until='ACTIVE') - - with self.override_role(): - self.servers_client.delete_server(server['id']) - waiters.wait_for_server_termination( - self.servers_client, server['id']) - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:servers:update"]) - @decorators.idempotent_id('077b17cb-5621-43b9-8adf-5725f0d7a863') - def test_update_server(self): - new_name = data_utils.rand_name(self.__class__.__name__ + '-server') - with self.override_role(): - self.servers_client.update_server(self.server['id'], - name=new_name) - waiters.wait_for_server_status(self.servers_client, - self.server['id'], 'ACTIVE') diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_tags_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_tags_rbac.py deleted file mode 100644 index 8a386f66..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_server_tags_rbac.py +++ /dev/null @@ -1,103 +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.common import utils -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.compute import rbac_base - - -class ServerTagsRbacTest(rbac_base.BaseV2ComputeRbacTest): - - min_microversion = '2.26' - max_microversion = 'latest' - - @classmethod - def skip_checks(cls): - super(ServerTagsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-server-tags', 'compute'): - msg = "os-server-tags extension is not enabled." - raise cls.skipException(msg) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(ServerTagsRbacTest, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(ServerTagsRbacTest, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - - def _add_tag_to_server(self): - tag_name = data_utils.rand_name(self.__class__.__name__ + '-tag') - self.servers_client.update_tag(self.server['id'], tag_name) - self.addCleanup(self.servers_client.delete_all_tags, self.server['id']) - return tag_name - - @decorators.idempotent_id('99e73dd3-adec-4044-b46c-84bdded35d09') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-server-tags:index"]) - def test_list_tags(self): - with self.override_role(): - self.servers_client.list_tags(self.server['id']) - - @decorators.idempotent_id('9297c99e-94eb-429f-93cf-9b1838e33622') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-server-tags:show"]) - def test_check_tag_existence(self): - tag_name = self._add_tag_to_server() - with self.override_role(): - self.servers_client.check_tag_existence(self.server['id'], - tag_name) - - @decorators.idempotent_id('0d84ee94-d3ca-4635-8edf-b7f67ab8e4a3') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-server-tags:update"]) - def test_update_tag(self): - with self.override_role(): - self._add_tag_to_server() - - @decorators.idempotent_id('115c2694-00aa-41ee-99f6-9eab4040c182') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-server-tags:delete"]) - def test_delete_tag(self): - tag_name = self._add_tag_to_server() - with self.override_role(): - self.servers_client.delete_tag(self.server['id'], tag_name) - - @decorators.idempotent_id('a8e19b87-6580-4bc8-9933-e62561ff667d') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-server-tags:update_all"]) - def test_update_all_tags(self): - new_tag_name = data_utils.rand_name(self.__class__.__name__ + '-tag') - with self.override_role(): - self.servers_client.update_all_tags(self.server['id'], - [new_tag_name]) - - @decorators.idempotent_id('89d51936-e333-42f9-a045-132a4865ba1a') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-server-tags:delete_all"]) - def test_delete_all_tags(self): - with self.override_role(): - self.servers_client.delete_all_tags(self.server['id']) diff --git a/patrole_tempest_plugin/tests/api/compute/test_server_volume_attachments_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_server_volume_attachments_rbac.py deleted file mode 100644 index 946bf3f3..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_server_volume_attachments_rbac.py +++ /dev/null @@ -1,221 +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. - -import time - -from oslo_log import log as logging -import testtools - -from tempest.common import waiters -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - -CONF = config.CONF -LOG = logging.getLogger(__name__) - - -# FIXME(felipemonteiro): `@decorators.attr(type='slow')` are added to tests -# below to in effect cause the tests to be non-voting in Zuul due to a high -# rate of spurious failures related to volume attachments. This will be -# revisited at a later date. -class ServerVolumeAttachmentRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(ServerVolumeAttachmentRbacTest, cls).setup_credentials() - - @classmethod - def setup_clients(cls): - super(ServerVolumeAttachmentRbacTest, cls).setup_clients() - cls.volumes_client = cls.os_primary.volumes_client_latest - - @classmethod - def skip_checks(cls): - super(ServerVolumeAttachmentRbacTest, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - - @classmethod - def resource_setup(cls): - super(ServerVolumeAttachmentRbacTest, cls).resource_setup() - cls.server = cls.create_test_server(wait_until='ACTIVE') - cls.volume = cls.create_volume() - - def _detach_volume_and_wait_until_available(self, server, volume): - self.servers_client.detach_volume(server['id'], - volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - - def _recreate_volume(self): - try: - # In case detachment failed, update the DB status of the volume - # to avoid error getting thrown when deleting the volume. - self.volumes_client.reset_volume_status( - self.volume['id'], status='available', - attach_status='detached') - waiters.wait_for_volume_resource_status( - self.volumes_client, self.volume['id'], 'available') - # Next, forcibly delete the volume. - self.volumes_client.force_delete_volume(self.volume['id']) - self.volumes_client.wait_for_resource_deletion(self.volume['id']) - except lib_exc.TimeoutException: - LOG.exception('Failed to delete volume %s', self.volume['id']) - # Finally, re-create the volume. - self.__class__.volume = self.create_volume() - - def _restore_volume_status(self): - # Forcibly detach any attachments still attached to the volume. - try: - attachments = self.volumes_client.show_volume( - self.volume['id'])['volume']['attachments'] - if attachments: - # Tests below only ever create one attachment for the volume. - attachment = attachments[0] - self.volumes_client.force_detach_volume( - self.volume['id'], connector=None, - attachment_id=attachment['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], - 'available') - except lib_exc.TimeoutException: - # If all else fails, rebuild the volume. - self._recreate_volume() - - def setUp(self): - super(ServerVolumeAttachmentRbacTest, self).setUp() - self._restore_volume_status() - - def wait_for_server_volume_swap(self, server_id, old_volume_id, - new_volume_id): - """Waits for a server to swap the old volume to a new one.""" - volume_attachments = self.servers_client.list_volume_attachments( - server_id)['volumeAttachments'] - attached_volume_ids = [attachment['volumeId'] - for attachment in volume_attachments] - start = int(time.time()) - - while (old_volume_id in attached_volume_ids) \ - or (new_volume_id not in attached_volume_ids): - time.sleep(self.servers_client.build_interval) - volume_attachments = self.servers_client.list_volume_attachments( - server_id)['volumeAttachments'] - attached_volume_ids = [attachment['volumeId'] - for attachment in volume_attachments] - - if int(time.time()) - start >= self.servers_client.build_timeout: - old_vol_bdm_status = 'in BDM' \ - if old_volume_id in attached_volume_ids else 'not in BDM' - new_vol_bdm_status = 'in BDM' \ - if new_volume_id in attached_volume_ids else 'not in BDM' - message = ('Failed to swap old volume %(old_volume_id)s ' - '(current %(old_vol_bdm_status)s) to new volume ' - '%(new_volume_id)s (current %(new_vol_bdm_status)s)' - ' on server %(server_id)s within the required time ' - '(%(timeout)s s)' % - {'old_volume_id': old_volume_id, - 'old_vol_bdm_status': old_vol_bdm_status, - 'new_volume_id': new_volume_id, - 'new_vol_bdm_status': new_vol_bdm_status, - 'server_id': server_id, - 'timeout': self.servers_client.build_timeout}) - raise lib_exc.TimeoutException(message) - - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-volumes-attachments:index"]) - @decorators.idempotent_id('529b668b-6edb-41d5-8886-d7dbd0614678') - def test_list_volume_attachments(self): - with self.override_role(): - self.servers_client.list_volume_attachments(self.server['id']) - - @decorators.attr(type='slow') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-volumes-attachments:create"]) - @decorators.idempotent_id('21c2c3fd-fbe8-41b1-8ef8-115ec47d54c1') - def test_create_volume_attachment(self): - with self.override_role(): - self.servers_client.attach_volume(self.server['id'], - volumeId=self.volume['id']) - # On teardown detach the volume and wait for it to be available. This - # is so we don't error out when trying to delete the volume during - # teardown. - self.addCleanup(waiters.wait_for_volume_resource_status, - self.volumes_client, self.volume['id'], 'available') - # Ignore 404s on detach in case the server is deleted or the volume - # is already detached. - self.addCleanup(self._detach_volume, self.server, self.volume) - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], 'in-use') - - @decorators.attr(type='slow') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-volumes-attachments:show"]) - @decorators.idempotent_id('997df9c2-6e54-47b6-ab74-e4fdb500f385') - def test_show_volume_attachment(self): - attachment = self.attach_volume(self.server, self.volume) - - with self.override_role(): - self.servers_client.show_volume_attachment( - self.server['id'], attachment['id']) - - @decorators.skip_because(bug='2008051', bug_type='storyboard') - @decorators.attr(type='slow') - @testtools.skipUnless(CONF.compute_feature_enabled.swap_volume, - 'In-place swapping of volumes not supported.') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-volumes-attachments:update"]) - @decorators.idempotent_id('bd667186-eca6-4b78-ab6a-3e2fabcb971f') - def test_update_volume_attachment(self): - volume1 = self.volume - volume2 = self.create_volume() - # Attach "volume1" to server - self.attach_volume(self.server, volume1) - - with self.override_role(): - # Swap volume from "volume1" to "volume2" - self.servers_client.update_attached_volume( - self.server['id'], volume1['id'], volumeId=volume2['id']) - self.addCleanup(self._detach_volume_and_wait_until_available, - self.server, volume2) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume1['id'], 'available') - waiters.wait_for_volume_resource_status(self.volumes_client, - volume2['id'], 'in-use') - self.wait_for_server_volume_swap(self.server['id'], volume1['id'], - volume2['id']) - - @decorators.attr(type='slow') - @rbac_rule_validation.action( - service="nova", - rules=["os_compute_api:os-volumes-attachments:delete"]) - @decorators.idempotent_id('12b03e90-d087-46af-9c4d-507d021c4984') - def test_delete_volume_attachment(self): - self.attach_volume(self.server, self.volume) - - with self.override_role(): - self.servers_client.detach_volume(self.server['id'], - self.volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], 'available') diff --git a/patrole_tempest_plugin/tests/api/compute/test_services_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_services_rbac.py deleted file mode 100644 index da4923d6..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_services_rbac.py +++ /dev/null @@ -1,46 +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.common import utils -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 - -if CONF.policy_feature_enabled.changed_nova_policies_ussuri: - _OS_COMPUTE_API_OS_SERVICES = "os_compute_api:os-services:list" -else: - _OS_COMPUTE_API_OS_SERVICES = "os_compute_api:os-services" - - -class ServicesRbacTest(rbac_base.BaseV2ComputeRbacTest): - - @classmethod - def skip_checks(cls): - super(ServicesRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-services', 'compute'): - raise cls.skipException( - '%s skipped as os-services not enabled' % cls.__name__) - - @rbac_rule_validation.action( - service="nova", - rules=[_OS_COMPUTE_API_OS_SERVICES]) - @decorators.idempotent_id('7472261b-9c6d-453a-bcb3-aecaa29ad281') - def test_list_services(self): - with self.override_role(): - self.services_client.list_services()['services'] diff --git a/patrole_tempest_plugin/tests/api/compute/test_tenant_networks_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_tenant_networks_rbac.py deleted file mode 100644 index a71901c1..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_tenant_networks_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.common import utils -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 - -if CONF.policy_feature_enabled.changed_nova_policies_victoria: - _TENANT_NET_LIST = "os_compute_api:os-tenant-networks:list" -else: - _TENANT_NET_LIST = "os_compute_api:os-tenant-networks" - - -class TenantNetworksRbacTest(rbac_base.BaseV2ComputeRbacTest): - - # Tests will fail with a 404 starting from microversion 2.36. - # See the following link for details: - # https://docs.openstack.org/api-ref/compute/#project-networks-os-tenant-networks-deprecated - max_microversion = '2.35' - - @classmethod - def setup_clients(cls): - super(TenantNetworksRbacTest, cls).setup_clients() - cls.tenant_networks_client = cls.os_primary.tenant_networks_client - - @classmethod - def skip_checks(cls): - super(TenantNetworksRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-tenant-networks', 'compute'): - msg = "os-tenant-networks extension not enabled." - raise cls.skipException(msg) - if not CONF.service_available.neutron: - raise cls.skipException( - '%s skipped as Neutron is required' % cls.__name__) - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True) - super(TenantNetworksRbacTest, cls).setup_credentials() - - @decorators.idempotent_id('42b39ba1-14aa-4799-9518-34367d0da67a') - @rbac_rule_validation.action( - service="nova", - rules=[_TENANT_NET_LIST]) - def test_list_show_tenant_networks(self): - with self.override_role(): - self.tenant_networks_client.list_tenant_networks() diff --git a/patrole_tempest_plugin/tests/api/compute/test_volume_rbac.py b/patrole_tempest_plugin/tests/api/compute/test_volume_rbac.py deleted file mode 100644 index 1d1b06a9..00000000 --- a/patrole_tempest_plugin/tests/api/compute/test_volume_rbac.py +++ /dev/null @@ -1,167 +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.common import waiters -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.compute import rbac_base - -from tempest import config - -CONF = config.CONF - -if CONF.policy_feature_enabled.changed_nova_policies_victoria: - _VOLUME_LIST = "os_compute_api:os-volumes:list" - _VOLUME_CREATE = "os_compute_api:os-volumes:create" - _VOLUME_SHOW = "os_compute_api:os-volumes:show" - _VOLUME_DELETE = "os_compute_api:os-volumes:delete" - _SNAPSHOT_LIST = "os_compute_api:os-volumes:snapshots:list" - _SNAPSHOT_CREATE = "os_compute_api:os-volumes:snapshots:create" - _SNAPSHOT_SHOW = "os_compute_api:os-volumes:snapshots:show" - _SNAPSHOT_DELETE = "os_compute_api:os-volumes:snapshots:delete" -else: - _VOLUME_LIST = "os_compute_api:os-volumes" - _VOLUME_CREATE = "os_compute_api:os-volumes" - _VOLUME_SHOW = "os_compute_api:os-volumes" - _VOLUME_DELETE = "os_compute_api:os-volumes" - _SNAPSHOT_LIST = "os_compute_api:os-volumes" - _SNAPSHOT_CREATE = "os_compute_api:os-volumes" - _SNAPSHOT_SHOW = "os_compute_api:os-volumes" - _SNAPSHOT_DELETE = "os_compute_api:os-volumes" - - -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://docs.openstack.org/api-ref/compute/#volume-extension-os-volumes-os-snapshots-deprecated - max_microversion = '2.35' - - @classmethod - def skip_checks(cls): - super(VolumeRbacTest, cls).skip_checks() - if not CONF.service_available.cinder: - skip_msg = ("%s skipped as Cinder is not available" % cls.__name__) - raise cls.skipException(skip_msg) - if not CONF.volume_feature_enabled.snapshot: - skip_msg = ("Cinder volume snapshots are disabled") - raise cls.skipException(skip_msg) - - @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.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", - rules=[_VOLUME_CREATE]) - def test_create_volume(self): - with self.override_role(): - volume = self.volumes_extensions_client.create_volume( - size=CONF.volume.volume_size)['volume'] - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - # Use non-deprecated volumes_client for deletion. - self.addCleanup(self.volumes_client.delete_volume, volume['id']) - - @decorators.idempotent_id('69b3888c-dff2-47b0-9fa4-0672619c9054') - @rbac_rule_validation.action( - service="nova", - rules=[_VOLUME_LIST]) - def test_list_volumes(self): - with self.override_role(): - self.volumes_extensions_client.list_volumes() - - @decorators.idempotent_id('4ba0a820-040f-488b-86bb-be2e920ea12c') - @rbac_rule_validation.action( - service="nova", - rules=[_VOLUME_SHOW]) - def test_show_volume(self): - with self.override_role(): - self.volumes_extensions_client.show_volume(self.volume['id']) - - @decorators.idempotent_id('6e7870f2-1bb2-4b58-96f8-6782071ef327') - @rbac_rule_validation.action( - service="nova", - rules=[_VOLUME_DELETE]) - def test_delete_volume(self): - volume = self.create_volume() - with self.override_role(): - self.volumes_extensions_client.delete_volume(volume['id']) - - @decorators.idempotent_id('0c3eaa4f-69d6-4a13-9dda-19585f36b1c1') - @rbac_rule_validation.action( - service="nova", - rules=[_SNAPSHOT_CREATE]) - def test_create_snapshot(self): - s_name = data_utils.rand_name(self.__class__.__name__ + '-Snapshot') - with self.override_role(): - snapshot = self.snapshots_extensions_client.create_snapshot( - volume_id=self.volume['id'], display_name=s_name)['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", - rules=[_SNAPSHOT_LIST]) - def test_list_snapshots(self): - with self.override_role(): - self.snapshots_extensions_client.list_snapshots() - - @decorators.idempotent_id('19c2e6bd-585b-472f-a8d7-71ea9299c655') - @rbac_rule_validation.action( - service="nova", - rules=[_SNAPSHOT_SHOW]) - def test_show_snapshot(self): - s_name = data_utils.rand_name(self.__class__.__name__ + '-Snapshot') - snapshot = self.snapshots_extensions_client.create_snapshot( - volume_id=self.volume['id'], display_name=s_name)['snapshot'] - self.addCleanup(self._delete_snapshot, snapshot['id']) - - with self.override_role(): - self.snapshots_extensions_client.show_snapshot(snapshot['id']) - - @decorators.idempotent_id('f4f5635c-416c-11e7-a919-92ebcb67fe33') - @rbac_rule_validation.action( - service="nova", - rules=[_SNAPSHOT_DELETE]) - def test_delete_snapshot(self): - s_name = data_utils.rand_name(self.__class__.__name__ + '-Snapshot') - snapshot = self.snapshots_extensions_client.create_snapshot( - volume_id=self.volume['id'], display_name=s_name)['snapshot'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self._delete_snapshot, snapshot['id']) - waiters.wait_for_volume_resource_status( - self.snapshots_extensions_client, snapshot['id'], - 'available') - - with self.override_role(): - self.snapshots_extensions_client.delete_snapshot(snapshot['id']) - self.snapshots_extensions_client.wait_for_resource_deletion( - snapshot['id']) diff --git a/patrole_tempest_plugin/tests/api/identity/__init__.py b/patrole_tempest_plugin/tests/api/identity/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/patrole_tempest_plugin/tests/api/identity/rbac_base.py b/patrole_tempest_plugin/tests/api/identity/rbac_base.py deleted file mode 100644 index aa5cd4bd..00000000 --- a/patrole_tempest_plugin/tests/api/identity/rbac_base.py +++ /dev/null @@ -1,280 +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 oslo_log import log as logging - -from tempest.api.identity import base -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils - -from patrole_tempest_plugin import rbac_utils - -LOG = logging.getLogger(__name__) - - -class BaseIdentityRbacTest(rbac_utils.RbacUtilsMixin, - base.BaseIdentityTest): - - @classmethod - def setup_test_role(cls): - """Set up a test role.""" - name = data_utils.rand_name(cls.__name__ + '-test_role') - role = cls.roles_client.create_role(name=name)['role'] - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.roles_client.delete_role, role['id']) - - return role - - @classmethod - def setup_test_service(cls): - """Setup a test service.""" - name = data_utils.rand_name(cls.__name__ + '-service') - serv_type = data_utils.rand_name('type') - desc = data_utils.rand_name(cls.__name__ + '-description') - - service = cls.services_client.create_service( - name=name, - type=serv_type, - description=desc)['service'] - - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.services_client.delete_service, service['id']) - - return service - - @classmethod - def setup_test_user(cls, password=None, **kwargs): - """Set up a test user.""" - username = data_utils.rand_name(cls.__name__ + '-test_user') - email = username + '@testmail.tm' - - user = cls.users_client.create_user( - name=username, - email=email, - password=password, - **kwargs)['user'] - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.users_client.delete_user, user['id']) - - return user - - -class BaseIdentityV3RbacTest(BaseIdentityRbacTest): - - identity_version = 'v3' - - @classmethod - def setup_clients(cls): - super(BaseIdentityV3RbacTest, cls).setup_clients() - cls.application_credentials_client = \ - cls.os_primary.application_credentials_client - cls.creds_client = cls.os_primary.credentials_client - cls.consumers_client = cls.os_primary.oauth_consumers_client - cls.domains_client = cls.os_primary.domains_client - cls.domain_config_client = cls.os_primary.domain_config_client - cls.endpoints_client = cls.os_primary.endpoints_v3_client - cls.endpoint_filter_client = cls.os_primary.endpoint_filter_client - cls.endpoint_groups_client = cls.os_primary.endpoint_groups_client - cls.groups_client = cls.os_primary.groups_client - cls.identity_client = cls.os_primary.identity_v3_client - cls.oauth_token_client = cls.os_primary.oauth_token_client - cls.projects_client = cls.os_primary.projects_client - cls.project_tags_client = cls.os_primary.project_tags_client - cls.policies_client = cls.os_primary.policies_client - cls.regions_client = cls.os_primary.regions_client - cls.role_assignments_client = cls.os_primary.role_assignments_client - cls.roles_client = cls.os_primary.roles_v3_client - cls.services_client = cls.os_primary.identity_services_v3_client - cls.token_client = cls.os_primary.token_v3_client - cls.trusts_client = cls.os_primary.trusts_client - cls.users_client = cls.os_primary.users_v3_client - - @classmethod - def resource_setup(cls): - super(BaseIdentityV3RbacTest, cls).resource_setup() - cls.credentials = [] - cls.domains = [] - cls.groups = [] - cls.policies = [] - cls.projects = [] - cls.regions = [] - cls.trusts = [] - cls.tokens = [] - - @classmethod - def resource_cleanup(cls): - for credential in cls.credentials: - test_utils.call_and_ignore_notfound_exc( - cls.creds_client.delete_credential, credential['id']) - - # Delete each domain at the end of the test, but each domain must be - # disabled first. - for domain in cls.domains: - test_utils.call_and_ignore_notfound_exc( - cls.domains_client.update_domain, domain['id'], enabled=False) - test_utils.call_and_ignore_notfound_exc( - cls.domains_client.delete_domain, domain['id']) - - for group in cls.groups: - test_utils.call_and_ignore_notfound_exc( - cls.groups_client.delete_group, group['id']) - - for policy in cls.policies: - test_utils.call_and_ignore_notfound_exc( - cls.policies_client.delete_policy, policy['id']) - - for project in cls.projects: - test_utils.call_and_ignore_notfound_exc( - cls.projects_client.delete_project, project['id']) - - for region in cls.regions: - test_utils.call_and_ignore_notfound_exc( - cls.regions_client.delete_region, region['id']) - - for trust in cls.trusts: - test_utils.call_and_ignore_notfound_exc( - cls.trusts_client.delete_trust, trust['id']) - - for token in cls.tokens: - test_utils.call_and_ignore_notfound_exc( - cls.identity_client.delete_token, token) - - super(BaseIdentityV3RbacTest, cls).resource_cleanup() - - @classmethod - def setup_test_endpoint(cls, service=None): - """Creates a service and an endpoint for test.""" - interface = 'public' - url = data_utils.rand_url() - region_name = data_utils.rand_name( - cls.__name__ + '-region') - # Endpoint creation requires a service - if service is None: - service = cls.setup_test_service() - params = { - 'service_id': service['id'], - 'region': region_name, - 'interface': interface, - 'url': url - } - - endpoint = cls.endpoints_client.create_endpoint(**params)['endpoint'] - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.regions_client.delete_region, endpoint['region']) - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.endpoints_client.delete_endpoint, endpoint['id']) - - return endpoint - - @classmethod - def setup_test_credential(cls, user=None): - """Creates a credential for test.""" - keys = [data_utils.rand_uuid_hex(), - data_utils.rand_uuid_hex()] - blob = '{"access": "%s", "secret": "%s"}' % (keys[0], keys[1]) - - credential = cls.creds_client.create_credential( - user_id=user['id'], - project_id=user['project_id'], - blob=blob, - type='ec2')['credential'] - cls.credentials.append(credential) - - return credential - - @classmethod - def setup_test_domain(cls): - """Set up a test domain.""" - domain = cls.domains_client.create_domain( - name=data_utils.rand_name(cls.__name__), - description=data_utils.rand_name( - cls.__name__ + '-desc'))['domain'] - cls.domains.append(domain) - - return domain - - @classmethod - def setup_test_group(cls): - """Creates a group for test.""" - name = data_utils.rand_name(cls.__name__ + '-test_group') - group = cls.groups_client.create_group(name=name)['group'] - cls.groups.append(group) - - return group - - @classmethod - def setup_test_policy(cls): - """Creates a policy for test.""" - blob = data_utils.rand_name(cls.__name__ + '-test_blob') - policy_type = data_utils.rand_name( - cls.__name__ + '-policy_type') - - policy = cls.policies_client.create_policy( - blob=blob, - policy=policy_type, - type="application/json")['policy'] - cls.policies.append(policy) - - return policy - - @classmethod - def setup_test_project(cls): - """Set up a test project.""" - project = cls.projects_client.create_project( - name=data_utils.rand_name( - cls.__name__), - description=data_utils.rand_name( - cls.__name__ + '-desc'))['project'] - cls.projects.append(project) - - return project - - @classmethod - def setup_test_region(cls): - """Creates a region for test.""" - description = data_utils.rand_name( - cls.__name__ + '-test_region_desc') - id = data_utils.rand_name(cls.__name__) - - region = cls.regions_client.create_region( - id=id, - description=description)['region'] - cls.regions.append(region) - - return region - - @classmethod - def setup_test_trust(cls, trustee_user_id, trustor_user_id, **kwargs): - """Setup a test trust.""" - trust = cls.trusts_client.create_trust( - trustee_user_id=trustee_user_id, trustor_user_id=trustor_user_id, - impersonation=False, **kwargs)['trust'] - cls.trusts.append(trust) - - return trust - - @classmethod - def setup_test_token(cls, user_id, password): - """Set up a test token.""" - token = cls.token_client.auth(user_id=user_id, - password=password).response - token_id = token['x-subject-token'] - cls.tokens.append(token_id) - return token_id diff --git a/patrole_tempest_plugin/tests/api/identity/v3/__init__.py b/patrole_tempest_plugin/tests/api/identity/v3/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_application_credentials_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_application_credentials_rbac.py deleted file mode 100644 index 2d9e3116..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_application_credentials_rbac.py +++ /dev/null @@ -1,89 +0,0 @@ -# Copyright 2018 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -CONF = config.CONF - - -class ApplicationCredentialsV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - @classmethod - def skip_checks(cls): - super(ApplicationCredentialsV3RbacTest, cls).skip_checks() - if not CONF.identity_feature_enabled.application_credentials: - raise cls.skipException("Application credentials are not available" - " in this environment") - - @classmethod - def resource_setup(cls): - super(ApplicationCredentialsV3RbacTest, cls).resource_setup() - cls.user_id = cls.os_primary.credentials.user_id - - def _create_application_credential(self, name=None, **kwargs): - name = name or data_utils.rand_name('application_credential') - application_credential = ( - self.application_credentials_client.create_application_credential( - self.user_id, name=name, **kwargs))['application_credential'] - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.application_credentials_client.delete_application_credential, - self.user_id, - application_credential['id']) - return application_credential - - @decorators.idempotent_id('b53bee14-e9df-4929-b257-6def76c12e4d') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:create_application_credential"]) - def test_create_application_credential(self): - with self.override_role(): - self._create_application_credential() - - @decorators.idempotent_id('58b3c3a0-5ad0-44f7-8da7-0736f71f7168') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:list_application_credentials"]) - def test_list_application_credentials(self): - with self.override_role(): - self.application_credentials_client.list_application_credentials( - user_id=self.user_id) - - @decorators.idempotent_id('d7b13968-a8a6-47fd-8e1d-7cc7f565c7f8') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:get_application_credential"]) - def test_show_application_credential(self): - app_cred = self._create_application_credential() - with self.override_role(): - self.application_credentials_client.show_application_credential( - user_id=self.user_id, application_credential_id=app_cred['id']) - - @decorators.idempotent_id('521b7c0f-1dd5-47a6-ae95-95c0323d7735') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:delete_application_credential"]) - def test_delete_application_credential(self): - app_cred = self._create_application_credential() - with self.override_role(): - self.application_credentials_client.delete_application_credential( - user_id=self.user_id, application_credential_id=app_cred['id']) diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_auth_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_auth_rbac.py deleted file mode 100644 index 3cfc6709..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_auth_rbac.py +++ /dev/null @@ -1,45 +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 patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -class IdentityAuthV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - """Tests the APIs that enforce the auth policy actions. - - For more information about the auth policy actions, see: - https://git.openstack.org/cgit/openstack/keystone/tree/keystone/common/policies/auth.py - """ - - # TODO(felipemonteiro): Add tests for identity:get_auth_catalog - # once the endpoints are implemented in Tempest's - # identity v3 client. - - @decorators.idempotent_id('2a9fbf7f-6feb-4161-ae4b-faf7d6421b1a') - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_auth_projects"]) - def test_list_auth_projects(self): - with self.override_role(): - self.identity_client.list_auth_projects() - - @decorators.idempotent_id('6a40af0d-7265-4657-b6b2-87a2828e263e') - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_auth_domains"]) - def test_list_auth_domain(self): - with self.override_role(): - self.identity_client.list_auth_domains() diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_credentials_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_credentials_rbac.py deleted file mode 100644 index aa77aa3c..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_credentials_rbac.py +++ /dev/null @@ -1,96 +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. - -import testtools - -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.identity import rbac_base - -CONF = config.CONF - - -@testtools.skipIf( - CONF.policy_feature_enabled.removed_keystone_policies_stein, - "This policy is unavailable in Stein so cannot be tested.") -class IdentityCredentialsV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - def _create_user_project_and_credential(self): - project = self.setup_test_project() - user = self.setup_test_user(project_id=project['id']) - credential = self.setup_test_credential(user=user) - return credential - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_credential"]) - @decorators.idempotent_id('c1ab6d34-c59f-4ae1-bae9-bb3c1089b48e') - def test_create_credential(self): - project = self.setup_test_project() - user = self.setup_test_user(project_id=project['id']) - with self.override_role(): - self.setup_test_credential(user=user) - - @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source, - 'Skipped because environment has an immutable user ' - 'source and solely provides read-only access to users.') - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_credential"]) - @decorators.idempotent_id('cfb05ce3-bffb-496e-a3c2-9515d730da63') - def test_update_credential(self): - credential = self._create_user_project_and_credential() - new_keys = [data_utils.rand_uuid_hex(), - data_utils.rand_uuid_hex()] - - with self.override_role(): - self.creds_client.update_credential( - credential['id'], - credential=credential, - access_key=new_keys[0], - secret_key=new_keys[1], - project_id=credential['project_id']) - - @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source, - 'Skipped because environment has an immutable user ' - 'source and solely provides read-only access to users.') - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_credential"]) - @decorators.idempotent_id('87ab42af-8d41-401b-90df-21e72919fcde') - def test_delete_credential(self): - credential = self._create_user_project_and_credential() - - with self.override_role(): - self.creds_client.delete_credential(credential['id']) - - @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source, - 'Skipped because environment has an immutable user ' - 'source and solely provides read-only access to users.') - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_credential"]) - @decorators.idempotent_id('1b6eeae6-f1e8-4cdf-8903-1c002b1fc271') - def test_show_credential(self): - credential = self._create_user_project_and_credential() - - with self.override_role(): - self.creds_client.show_credential(credential['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_credentials"]) - @decorators.idempotent_id('3de303e2-12a7-4811-805a-f18906472038') - def test_list_credentials(self): - with self.override_role(): - self.creds_client.list_credentials() diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_domain_configuration_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_domain_configuration_rbac.py deleted file mode 100644 index 821b942d..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_domain_configuration_rbac.py +++ /dev/null @@ -1,164 +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.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - -CONF = config.CONF - - -class DomainConfigurationV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - """RBAC tests for domain configuration client. - - Provides coverage for the following policy actions: - https://git.openstack.org/cgit/openstack/keystone/tree/keystone/common/policies/domain_config.py - """ - - identity = {"driver": "ldap"} - ldap = {"url": "ldap://myldap.com:389/", - "user_tree_dn": "ou=Users,dc=my_new_root,dc=org"} - - @classmethod - def resource_setup(cls): - super(DomainConfigurationV3RbacTest, cls).resource_setup() - cls.domain_id = cls.setup_test_domain()['id'] - - def setUp(self): - super(DomainConfigurationV3RbacTest, self).setUp() - self._create_domain_config(self.domain_id) - - def _create_domain_config(self, domain_id): - domain_config = self.domain_config_client.create_domain_config( - domain_id, identity=self.identity, ldap=self.ldap)['config'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.domain_config_client.delete_domain_config, - domain_id) - return domain_config - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_domain_config"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd115') - def test_create_domain_config(self): - with self.override_role(): - self._create_domain_config(self.domain_id) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_domain_config"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd118') - def test_show_domain_config(self): - with self.override_role(): - self.domain_config_client.show_domain_config(self.domain_id) - - @decorators.idempotent_id('1b539f95-4991-4e09-960f-fa771e1007d7') - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_domain_config"]) - def test_show_domain_group_config(self): - with self.override_role(): - self.domain_config_client.show_domain_group_config( - self.domain_id, 'identity') - - @decorators.idempotent_id('590c774d-a294-44f8-866e-aac9f4ab3809') - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_domain_config"]) - def test_show_domain_group_option_config(self): - with self.override_role(): - self.domain_config_client.show_domain_group_option_config( - self.domain_id, 'identity', 'driver') - - @decorators.idempotent_id('21053885-1ce3-4167-b5e3-e470253481da') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:get_security_compliance_domain_config"]) - def test_show_security_compliance_domain_config(self): - # The "security_compliance" group can only be shown for the default - # domain. - with self.override_role(): - self.domain_config_client.show_domain_group_config( - CONF.identity.default_domain_id, 'security_compliance') - - @decorators.idempotent_id('d1addd10-9ae4-4360-9961-47324fd22f23') - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_domain_config_default"]) - def test_show_default_config_settings(self): - with self.override_role(): - self.domain_config_client.show_default_config_settings() - - @decorators.idempotent_id('63183377-251f-4622-81f0-6b58a8a285c9') - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_domain_config_default"]) - def test_show_default_group_config(self): - with self.override_role(): - self.domain_config_client.show_default_group_config('identity') - - @decorators.idempotent_id('6440e9c1-e8da-474d-9118-89996fffe5f8') - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_domain_config_default"]) - def test_show_default_group_option(self): - with self.override_role(): - self.domain_config_client.show_default_group_option('identity', - 'driver') - - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_domain_config"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd116') - def test_update_domain_config(self): - updated_config = {'ldap': {'url': data_utils.rand_url()}} - with self.override_role(): - self.domain_config_client.update_domain_config( - self.domain_id, **updated_config) - - @decorators.idempotent_id('6e32bf96-dbe9-4ac8-b814-0e79fa948285') - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_domain_config"]) - def test_update_domain_group_config(self): - with self.override_role(): - self.domain_config_client.update_domain_group_config( - self.domain_id, 'identity', identity=self.identity) - - @decorators.idempotent_id('d2c510da-a077-4c67-9522-27745ef2812b') - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_domain_config"]) - def test_update_domain_group_option_config(self): - with self.override_role(): - self.domain_config_client.update_domain_group_option_config( - self.domain_id, 'identity', 'driver', driver='ldap') - - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_domain_config"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd117') - def test_delete_domain_config(self): - with self.override_role(): - self.domain_config_client.delete_domain_config(self.domain_id) - - @decorators.idempotent_id('f479694b-df02-4d5a-88b6-c8b52f9341eb') - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_domain_config"]) - def test_delete_domain_group_config(self): - with self.override_role(): - self.domain_config_client.delete_domain_group_config( - self.domain_id, 'identity') - - @decorators.idempotent_id('f594bde3-31c9-414f-922d-0ddafdc0ca40') - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_domain_config"]) - def test_delete_domain_group_option_config(self): - with self.override_role(): - self.domain_config_client.delete_domain_group_option_config( - self.domain_id, 'identity', 'driver') diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_domains_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_domains_rbac.py deleted file mode 100644 index 2ad50cf9..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_domains_rbac.py +++ /dev/null @@ -1,69 +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.common.utils import data_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -class IdentityDomainsV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_domain"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd110') - def test_create_domain(self): - with self.override_role(): - self.setup_test_domain() - - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_domain"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd111') - def test_update_domain(self): - domain = self.setup_test_domain() - new_domain_name = data_utils.rand_name( - self.__class__.__name__) - with self.override_role(): - self.domains_client.update_domain(domain['id'], - domain=domain, - name=new_domain_name) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_domain"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd112') - def test_delete_domain(self): - domain = self.setup_test_domain() - # A domain must be deactivated to be deleted - self.domains_client.update_domain(domain['id'], - domain=domain, - enabled=False) - with self.override_role(): - self.domains_client.delete_domain(domain['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_domain"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd113') - def test_show_domain(self): - domain = self.setup_test_domain() - with self.override_role(): - self.domains_client.show_domain(domain['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_domains"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd114') - def test_list_domains(self): - with self.override_role(): - self.domains_client.list_domains() diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_endpoints_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_endpoints_rbac.py deleted file mode 100644 index 5554b737..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_endpoints_rbac.py +++ /dev/null @@ -1,68 +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.common.utils import data_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -class IdentityEndpointsV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_endpoint"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd127') - def test_create_endpoint(self): - service = self.setup_test_service() - with self.override_role(): - self.setup_test_endpoint(service=service) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_endpoint"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd128') - def test_update_endpoint(self): - endpoint = self.setup_test_endpoint() - new_url = data_utils.rand_url() - - with self.override_role(): - self.endpoints_client.update_endpoint( - endpoint["id"], - url=new_url) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_endpoint"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd129') - def test_delete_endpoint(self): - endpoint = self.setup_test_endpoint() - - with self.override_role(): - self.endpoints_client.delete_endpoint(endpoint['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_endpoint"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd130') - def test_show_endpoint(self): - endpoint = self.setup_test_endpoint() - - with self.override_role(): - self.endpoints_client.show_endpoint(endpoint['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_endpoints"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd131') - def test_list_endpoints(self): - with self.override_role(): - self.endpoints_client.list_endpoints() diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_ep_filter_groups_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_ep_filter_groups_rbac.py deleted file mode 100644 index 48a4e584..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_ep_filter_groups_rbac.py +++ /dev/null @@ -1,109 +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.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -class EndpointFilterGroupsV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - interface = 'public' - - @classmethod - def resource_setup(cls): - super(EndpointFilterGroupsV3RbacTest, cls).resource_setup() - cls.service_id = cls.setup_test_service()['id'] - - def setUp(self): - super(EndpointFilterGroupsV3RbacTest, self).setUp() - self.endpoint_group_id = self._create_endpoint_group() - - def _create_endpoint_group(self, ignore_not_found=False): - # Create an endpoint group - ep_group_name = data_utils.rand_name( - self.__class__.__name__ + '-EPFilterGroup') - filters = { - 'filters': { - 'interface': self.interface, - 'service_id': self.service_id - } - } - endpoint_group = self.endpoint_groups_client.create_endpoint_group( - name=ep_group_name, **filters)['endpoint_group'] - - if ignore_not_found: - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.endpoint_groups_client.delete_endpoint_group, - endpoint_group['id']) - else: - self.addCleanup(self.endpoint_groups_client.delete_endpoint_group, - endpoint_group['id']) - - return endpoint_group['id'] - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_endpoint_group"]) - @decorators.idempotent_id('b4765906-52ec-477b-b441-a8508ced68e3') - def test_create_endpoint_group(self): - with self.override_role(): - self._create_endpoint_group(ignore_not_found=True) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_endpoint_groups"]) - @decorators.idempotent_id('089aa3a7-ba1f-4f70-a1cf-f298a845058a') - def test_list_endpoint_groups(self): - with self.override_role(): - self.endpoint_groups_client.list_endpoint_groups() - - @decorators.idempotent_id('5c16368d-1485-4c28-9803-db3fa3510623') - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_endpoint_group"]) - def test_check_endpoint_group(self): - with self.override_role(): - self.endpoint_groups_client.check_endpoint_group( - self.endpoint_group_id) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_endpoint_group"]) - @decorators.idempotent_id('bd2b6fb8-661f-4255-84b2-50fea4a1dc61') - def test_show_endpoint_group(self): - with self.override_role(): - self.endpoint_groups_client.show_endpoint_group( - self.endpoint_group_id) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_endpoint_group"]) - @decorators.idempotent_id('028b9198-ec35-4bd5-8f72-e23dfb7a0c8e') - def test_update_endpoint_group(self): - updated_name = data_utils.rand_name( - self.__class__.__name__ + '-EPFilterGroup') - - with self.override_role(): - self.endpoint_groups_client.update_endpoint_group( - self.endpoint_group_id, name=updated_name) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_endpoint_group"]) - @decorators.idempotent_id('88cc105e-70d9-48ac-927e-200ef41e070c') - def test_delete_endpoint_group(self): - endpoint_group_id = self._create_endpoint_group(ignore_not_found=True) - - with self.override_role(): - self.endpoint_groups_client.delete_endpoint_group( - endpoint_group_id) diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_ep_filter_projects_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_ep_filter_projects_rbac.py deleted file mode 100644 index 8385d6d7..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_ep_filter_projects_rbac.py +++ /dev/null @@ -1,90 +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.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -class EndpointFilterProjectsV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - @classmethod - def resource_setup(cls): - super(EndpointFilterProjectsV3RbacTest, cls).resource_setup() - cls.project = cls.setup_test_project() - cls.endpoint = cls.setup_test_endpoint() - - def _add_endpoint_to_project(self, ignore_not_found=False): - self.endpoint_filter_client.add_endpoint_to_project( - self.project['id'], self.endpoint['id']) - - if ignore_not_found: - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.endpoint_filter_client.delete_endpoint_from_project, - self.project['id'], self.endpoint['id']) - else: - self.addCleanup( - self.endpoint_filter_client.delete_endpoint_from_project, - self.project['id'], self.endpoint['id']) - - @rbac_rule_validation.action( - service="keystone", - rules=["identity:add_endpoint_to_project"]) - @decorators.idempotent_id('9199ec13-816d-4efe-b8b1-e1cd026b9747') - def test_add_endpoint_to_project(self): - # Adding endpoints to projects - with self.override_role(): - self._add_endpoint_to_project(ignore_not_found=True) - - @rbac_rule_validation.action( - service="keystone", - rules=["identity:list_projects_for_endpoint"]) - @decorators.idempotent_id('f53dca42-ec8a-48e9-924b-0bbe6c99727f') - def test_list_projects_for_endpoint(self): - with self.override_role(): - self.endpoint_filter_client.list_projects_for_endpoint( - self.endpoint['id']) - - @rbac_rule_validation.action( - service="keystone", - rules=["identity:check_endpoint_in_project"]) - @decorators.idempotent_id('0c1425eb-833c-4aa1-a21d-52ffa41fdc6a') - def test_check_endpoint_in_project(self): - self._add_endpoint_to_project() - with self.override_role(): - self.endpoint_filter_client.check_endpoint_in_project( - self.project['id'], self.endpoint['id']) - - @rbac_rule_validation.action( - service="keystone", - rules=["identity:list_endpoints_for_project"]) - @decorators.idempotent_id('5d86c659-c6ad-41e0-854e-3823e95c7cc2') - def test_list_endpoints_in_project(self): - with self.override_role(): - self.endpoint_filter_client.list_endpoints_in_project( - self.project['id']) - - @rbac_rule_validation.action( - service="keystone", - rules=["identity:remove_endpoint_from_project"]) - @decorators.idempotent_id('b4e21c10-4f47-427b-9b8a-f5b5601adfda') - def test_remove_endpoint_from_project(self): - self._add_endpoint_to_project(ignore_not_found=True) - with self.override_role(): - self.endpoint_filter_client.delete_endpoint_from_project( - self.project['id'], self.endpoint['id']) diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_groups_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_groups_rbac.py deleted file mode 100644 index 1e79501f..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_groups_rbac.py +++ /dev/null @@ -1,121 +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. - -import testtools - -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.identity import rbac_base - -CONF = config.CONF - - -class IdentityGroupsV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - def _create_user_and_add_to_new_group(self): - """Creates a user and adds to a group for test.""" - group = self.setup_test_group() - user = self.setup_test_user() - self.groups_client.add_group_user(group['id'], user['id']) - return (group['id'], user['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_group"]) - @decorators.idempotent_id('88377f51-9074-4d64-a22f-f8931d048c9a') - def test_create_group(self): - with self.override_role(): - self.setup_test_group() - - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_group"]) - @decorators.idempotent_id('790fb7be-a657-4a64-9b83-c43425cf180b') - def test_update_group(self): - group = self.setup_test_group() - new_group_name = data_utils.rand_name( - self.__class__.__name__ + '-group') - - with self.override_role(): - self.groups_client.update_group(group['id'], name=new_group_name) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_group"]) - @decorators.idempotent_id('646b52da-2a5f-486a-afb0-51fdc86a6c12') - def test_delete_group(self): - group = self.setup_test_group() - - with self.override_role(): - self.groups_client.delete_group(group['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_group"]) - @decorators.idempotent_id('d530f0ad-42b9-429b-ad05-e53ac95a040e') - def test_show_group(self): - group = self.setup_test_group() - - with self.override_role(): - self.groups_client.show_group(group['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_groups"]) - @decorators.idempotent_id('c4d0f76b-735f-4fd0-868b-0006bc420ff4') - def test_list_groups(self): - with self.override_role(): - self.groups_client.list_groups() - - @rbac_rule_validation.action(service="keystone", - rules=["identity:add_user_to_group"]) - @decorators.idempotent_id('fdd49b74-3ed3-4736-9f0e-9027a32017ac') - def test_add_user_group(self): - group = self.setup_test_group() - user = self.setup_test_user() - - with self.override_role(): - self.groups_client.add_group_user(group['id'], user['id']) - - @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source, - 'Skipped because environment has an immutable user ' - 'source and solely provides read-only access to users.') - @rbac_rule_validation.action(service="keystone", - rules=["identity:remove_user_from_group"]) - @decorators.idempotent_id('8a60d11c-7d2b-47e5-a0f3-9ea900ca66fe') - def test_remove_user_group(self): - group_id, user_id = self._create_user_and_add_to_new_group() - - with self.override_role(): - self.groups_client.delete_group_user(group_id, user_id) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_users_in_group"]) - @decorators.idempotent_id('b3e394a7-079e-4a0d-a4ff-9b266293d1ee') - def test_list_user_group(self): - group = self.setup_test_group() - - with self.override_role(): - self.groups_client.list_group_users(group['id']) - - @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source, - 'Skipped because environment has an immutable user ' - 'source and solely provides read-only access to users.') - @rbac_rule_validation.action(service="keystone", - rules=["identity:check_user_in_group"]) - @decorators.idempotent_id('d3603241-fd87-4a2d-94f9-f32469d1aaba') - def test_check_user_group(self): - group_id, user_id = self._create_user_and_add_to_new_group() - - with self.override_role(): - self.groups_client.check_group_user_existence(group_id, user_id) diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_oauth_consumers_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_oauth_consumers_rbac.py deleted file mode 100644 index 4198a467..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_oauth_consumers_rbac.py +++ /dev/null @@ -1,78 +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.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -class IdentityConsumersV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - def _create_consumer(self): - description = data_utils.rand_name( - self.__class__.__name__) - consumer = self.consumers_client.create_consumer( - description)['consumer'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.consumers_client.delete_consumer, - consumer['id']) - return consumer - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_consumer"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d970') - def test_create_consumer(self): - with self.override_role(): - self._create_consumer() - - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_consumer"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d971') - def test_delete_consumer(self): - consumer = self._create_consumer() - - with self.override_role(): - self.consumers_client.delete_consumer(consumer['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_consumer"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d972') - def test_update_consumer(self): - consumer = self._create_consumer() - updated_description = data_utils.rand_name( - self.__class__.__name__) - - with self.override_role(): - self.consumers_client.update_consumer(consumer['id'], - updated_description) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_consumer"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d973') - def test_show_consumer(self): - consumer = self._create_consumer() - - with self.override_role(): - self.consumers_client.show_consumer(consumer['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_consumers"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d975') - def test_list_consumers(self): - with self.override_role(): - self.consumers_client.list_consumers() diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_oauth_tokens_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_oauth_tokens_rbac.py deleted file mode 100644 index 86cb4a83..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_oauth_tokens_rbac.py +++ /dev/null @@ -1,138 +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.common.utils import data_utils -from tempest.lib.common.utils import test_utils - -from tempest import config -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - -CONF = config.CONF - - -class IdentityOAuthTokensV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - @classmethod - def resource_setup(cls): - super(IdentityOAuthTokensV3RbacTest, cls).resource_setup() - # Authorize token on admin role since primary user has admin - # credentials before switching roles. Populate role_ids with admin - # role id. - cls.role_ids = [cls.get_role_by_name(CONF.identity.admin_role)['id']] - cls.project_id = cls.os_primary.credentials.project_id - cls.user_id = cls.os_primary.credentials.user_id - - def _create_consumer(self): - description = data_utils.rand_name( - self.__class__.__name__ + '-Consumer') - consumer = self.consumers_client.create_consumer( - description)['consumer'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.consumers_client.delete_consumer, - consumer['id']) - return consumer - - def _create_consumer_and_request_token(self): - # Create consumer - consumer = self._create_consumer() - - # Create request token - request_token = self.oauth_token_client.create_request_token( - consumer['id'], consumer['secret'], self.project_id) - - return consumer, request_token - - def _create_access_token(self): - consumer, request_token = self._create_consumer_and_request_token() - - # Authorize request token - resp = self.oauth_token_client.authorize_request_token( - request_token['oauth_token'], self.role_ids)['token'] - auth_verifier = resp['oauth_verifier'] - - # Create access token - body = self.oauth_token_client.create_access_token( - consumer['id'], - consumer['secret'], - request_token['oauth_token'], - request_token['oauth_token_secret'], - auth_verifier) - access_key = body['oauth_token'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.oauth_token_client.revoke_access_token, - self.user_id, access_key) - - return access_key - - @rbac_rule_validation.action(service="keystone", - rules=["identity:authorize_request_token"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d976') - def test_authorize_request_token(self): - _, request_token = self._create_consumer_and_request_token() - - with self.override_role(): - self.oauth_token_client.authorize_request_token( - request_token['oauth_token'], - self.role_ids) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_access_token"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d977') - def test_get_access_token(self): - access_token = self._create_access_token() - - with self.override_role(): - self.oauth_token_client.get_access_token(self.user_id, - access_token) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_access_token_role"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d980') - def test_get_access_token_role(self): - access_token = self._create_access_token() - - with self.override_role(): - self.oauth_token_client.get_access_token_role( - self.user_id, access_token, self.role_ids[0]) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_access_tokens"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d979') - def test_list_access_tokens(self): - with self.override_role(): - self.oauth_token_client.list_access_tokens(self.user_id) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_access_token_roles"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d978') - def test_list_access_token_roles(self): - access_token = self._create_access_token() - - with self.override_role(): - self.oauth_token_client.list_access_token_roles( - self.user_id, access_token) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_access_token"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d981') - def test_revoke_access_token(self): - access_token = self._create_access_token() - - with self.override_role(): - self.oauth_token_client.revoke_access_token( - self.user_id, access_token) diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_policies_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_policies_rbac.py deleted file mode 100644 index 8bb405be..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_policies_rbac.py +++ /dev/null @@ -1,67 +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.common.utils import data_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -class IdentityPoliciesV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_policy"]) - @decorators.idempotent_id('de2f7ecb-fbf0-41f3-abf4-b97b5e082fd5') - def test_create_policy(self): - with self.override_role(): - self.setup_test_policy() - - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_policy"]) - @decorators.idempotent_id('9cfed3c6-0b27-4d15-be67-e06e0cfb01b9') - def test_update_policy(self): - policy = self.setup_test_policy() - updated_policy_type = data_utils.rand_name( - self.__class__.__name__ + '-policy_type') - - with self.override_role(): - self.policies_client.update_policy(policy['id'], - type=updated_policy_type) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_policy"]) - @decorators.idempotent_id('dcd93f75-1e1b-4fbe-bee0-9c4c7b201735') - def test_delete_policy(self): - policy = self.setup_test_policy() - - with self.override_role(): - self.policies_client.delete_policy(policy['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_policy"]) - @decorators.idempotent_id('d7e415c2-945a-4504-9571-0e2d0dd8594b') - def test_show_policy(self): - policy = self.setup_test_policy() - - with self.override_role(): - self.policies_client.show_policy(policy['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_policies"]) - @decorators.idempotent_id('35a56161-4054-4237-8a78-7ce805dce202') - def test_list_policies(self): - with self.override_role(): - self.policies_client.list_policies() diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_policy_association_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_policy_association_rbac.py deleted file mode 100644 index c35ae815..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_policy_association_rbac.py +++ /dev/null @@ -1,152 +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.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -class IdentityPolicyAssociationRbacTest( - rbac_base.BaseIdentityV3RbacTest): - - def setUp(self): - super(IdentityPolicyAssociationRbacTest, self).setUp() - self.policy_id = self.setup_test_policy()['id'] - self.service_id = self.setup_test_service()['id'] - self.endpoint_id = self.setup_test_endpoint()['id'] - self.region_id = self.setup_test_region()['id'] - - def _update_policy_association_for_endpoint(self, policy_id, endpoint_id): - self.policies_client.update_policy_association_for_endpoint( - policy_id, endpoint_id) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.policies_client.delete_policy_association_for_endpoint, - policy_id, endpoint_id) - - def _update_policy_association_for_service(self, policy_id, service_id): - self.policies_client.update_policy_association_for_service( - policy_id, service_id) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.policies_client.delete_policy_association_for_service, - policy_id, service_id) - - def _update_policy_association_for_region_and_service( - self, policy_id, service_id, region_id): - self.policies_client.update_policy_association_for_region_and_service( - policy_id, service_id, region_id) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.policies_client. - delete_policy_association_for_region_and_service, - policy_id, service_id, region_id) - - @rbac_rule_validation.action( - service="keystone", - rules=["identity:create_policy_association_for_endpoint"]) - @decorators.idempotent_id('1b3f4f62-4f4a-4d27-be27-9a113058597f') - def test_update_policy_association_for_endpoint(self): - with self.override_role(): - self._update_policy_association_for_endpoint( - self.policy_id, self.endpoint_id) - - @rbac_rule_validation.action( - service="keystone", - rules=["identity:check_policy_association_for_endpoint"]) - @decorators.idempotent_id('25ce8c89-e751-465c-8d35-52bacd774beb') - def test_show_policy_association_for_endpoint(self): - self._update_policy_association_for_endpoint( - self.policy_id, self.endpoint_id) - with self.override_role(): - self.policies_client.show_policy_association_for_endpoint( - self.policy_id, self.endpoint_id) - - @rbac_rule_validation.action( - service="keystone", - rules=["identity:delete_policy_association_for_endpoint"]) - @decorators.idempotent_id('95cad2d8-bcd0-4c4e-a8f7-cc80601e43a1') - def test_delete_policy_association_for_endpoint(self): - self._update_policy_association_for_endpoint( - self.policy_id, self.endpoint_id) - with self.override_role(): - self.policies_client.delete_policy_association_for_endpoint( - self.policy_id, self.endpoint_id) - - @rbac_rule_validation.action( - service="keystone", - rules=["identity:create_policy_association_for_service"]) - @decorators.idempotent_id('57fb80fe-6ce2-4995-b710-4692b3fc3cdc') - def test_update_policy_association_for_service(self): - with self.override_role(): - self._update_policy_association_for_service( - self.policy_id, self.service_id) - - @rbac_rule_validation.action( - service="keystone", - rules=["identity:check_policy_association_for_service"]) - @decorators.idempotent_id('5cbe285f-4888-4f98-978f-30210ff28b74') - def test_show_policy_association_for_service(self): - self._update_policy_association_for_service( - self.policy_id, self.service_id) - with self.override_role(): - self.policies_client.show_policy_association_for_service( - self.policy_id, self.service_id) - - @rbac_rule_validation.action( - service="keystone", - rules=["identity:delete_policy_association_for_service"]) - @decorators.idempotent_id('f754455c-02a4-4fb6-8c73-64ef453f955f') - def test_delete_policy_association_for_service(self): - self._update_policy_association_for_service( - self.policy_id, self.service_id) - with self.override_role(): - self.policies_client.delete_policy_association_for_service( - self.policy_id, self.service_id) - - @rbac_rule_validation.action( - service="keystone", - rules=["identity:create_policy_association_for_region_and_service"]) - @decorators.idempotent_id('54d2a93e-c84d-4079-8ea9-2fb227c262a1') - def test_update_policy_association_for_region_and_service(self): - with self.override_role(): - self._update_policy_association_for_region_and_service( - self.policy_id, self.service_id, self.region_id) - - @rbac_rule_validation.action( - service="keystone", - rules=["identity:check_policy_association_for_region_and_service"]) - @decorators.idempotent_id('0763b780-52c1-47bc-9316-1fe12a2ab0bc') - def test_show_policy_association_for_region_and_service(self): - self._update_policy_association_for_region_and_service( - self.policy_id, self.service_id, self.region_id) - with self.override_role(): - self.policies_client\ - .show_policy_association_for_region_and_service( - self.policy_id, self.service_id, self.region_id) - - @rbac_rule_validation.action( - service="keystone", - rules=["identity:delete_policy_association_for_region_and_service"]) - @decorators.idempotent_id('9c956888-81d4-4a24-8203-bff7b8a7834c') - def test_delete_policy_association_for_region_and_service(self): - self._update_policy_association_for_region_and_service( - self.policy_id, self.service_id, self.region_id) - with self.override_role(): - self.policies_client.\ - delete_policy_association_for_region_and_service( - self.policy_id, self.service_id, self.region_id) diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_project_tags_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_project_tags_rbac.py deleted file mode 100644 index ae43b38b..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_project_tags_rbac.py +++ /dev/null @@ -1,96 +0,0 @@ -# Copyright 2018 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest 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.identity import rbac_base - -CONF = config.CONF - - -class ProjectTagsV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - @classmethod - def skip_checks(cls): - super(ProjectTagsV3RbacTest, cls).skip_checks() - if not CONF.identity_feature_enabled.project_tags: - raise cls.skipException("Project tags feature disabled") - - @classmethod - def resource_setup(cls): - super(ProjectTagsV3RbacTest, cls).resource_setup() - cls.project_id = cls.setup_test_project()['id'] - - def tearDown(self): - self.project_tags_client.delete_all_project_tags(self.project_id) - super(ProjectTagsV3RbacTest, self).tearDown() - - @decorators.idempotent_id('acbd7b2d-0a4d-4990-9fab-eccad69d4238') - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_project_tag"]) - def test_update_project_tag(self): - tag = data_utils.rand_name(self.__class__.__name__ + '-Tag') - with self.override_role(): - self.project_tags_client.update_project_tag(self.project_id, tag) - - @decorators.idempotent_id('e122d7d1-bb6d-43af-b489-afa8c609b9ae') - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_project_tags"]) - def test_list_project_tags(self): - with self.override_role(): - self.project_tags_client.list_project_tags(self.project_id) - - @decorators.idempotent_id('716f9081-4626-4594-a82c-e7dc037464ac') - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_project_tags"]) - def test_update_all_project_tags(self): - tags = [ - data_utils.rand_name(self.__class__.__name__ + '-Tag') - for _ in range(2) - ] - with self.override_role(): - self.project_tags_client.update_all_project_tags( - self.project_id, tags) - - @decorators.idempotent_id('974cb1da-d7d4-4863-99da-4a3f0c801729') - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_project_tag"]) - def test_check_project_tag_existence(self): - tag = data_utils.rand_name(self.__class__.__name__ + '-Tag') - self.project_tags_client.update_project_tag(self.project_id, tag) - - with self.override_role(): - self.project_tags_client.check_project_tag_existence( - self.project_id, tag) - - @decorators.idempotent_id('ffe0c8e1-f9eb-43c5-8097-1e938fc08e07') - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_project_tag"]) - def test_delete_project_tag(self): - tag = data_utils.rand_name(self.__class__.__name__ + '-Tag') - self.project_tags_client.update_project_tag(self.project_id, tag) - - with self.override_role(): - self.project_tags_client.delete_project_tag(self.project_id, tag) - - @decorators.idempotent_id('94d0ef63-e9e3-4287-9c5e-bd5464467d77') - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_project_tags"]) - def test_delete_all_project_tags(self): - with self.override_role(): - self.project_tags_client.delete_all_project_tags(self.project_id) diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_projects_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_projects_rbac.py deleted file mode 100644 index af587994..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_projects_rbac.py +++ /dev/null @@ -1,67 +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.common.utils import data_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -class IdentityProjectV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_project"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1564-080044d0d904') - def test_create_project(self): - with self.override_role(): - self.setup_test_project() - - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_project"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1564-080044d0d905') - def test_update_project(self): - project = self.setup_test_project() - new_desc = data_utils.rand_name( - self.__class__.__name__ + '-description') - - with self.override_role(): - self.projects_client.update_project(project['id'], - description=new_desc) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_project"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1564-080044d0d906') - def test_delete_project(self): - project = self.setup_test_project() - - with self.override_role(): - self.projects_client.delete_project(project['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_project"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1564-080044d0d907') - def test_show_project(self): - project = self.setup_test_project() - - with self.override_role(): - self.projects_client.show_project(project['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_projects"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1564-080044d0d908') - def test_list_projects(self): - with self.override_role(): - self.projects_client.list_projects() diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_regions_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_regions_rbac.py deleted file mode 100644 index 5a4de23e..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_regions_rbac.py +++ /dev/null @@ -1,67 +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.common.utils import data_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -class IdentityRegionsV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_region"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd119') - def test_create_region(self): - with self.override_role(): - self.setup_test_region() - - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_region"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd120') - def test_update_region(self): - region = self.setup_test_region() - new_description = data_utils.rand_name( - self.__class__.__name__ + '-test_update_region') - - with self.override_role(): - self.regions_client.update_region(region['id'], - description=new_description) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_region"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd121') - def test_delete_region(self): - region = self.setup_test_region() - - with self.override_role(): - self.regions_client.delete_region(region['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_region"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd122') - def test_show_region(self): - region = self.setup_test_region() - - with self.override_role(): - self.regions_client.show_region(region['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_regions"]) - @decorators.idempotent_id('6bdaecd4-0843-4ed6-ab64-3a57ab0cd123') - def test_list_regions(self): - with self.override_role(): - self.regions_client.list_regions() diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_role_assignments_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_role_assignments_rbac.py deleted file mode 100644 index b0d3dfea..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_role_assignments_rbac.py +++ /dev/null @@ -1,41 +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 patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -class IdentityRoleAssignmentsV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - @decorators.idempotent_id('afe57adb-1b9c-43d9-84a9-f0cf4c94e416') - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_role_assignments"]) - def test_list_role_assignments(self): - with self.override_role(): - self.role_assignments_client.list_role_assignments() - - @decorators.idempotent_id('36c7a990-857e-415c-8717-38d7200a9894') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:list_role_assignments_for_tree"]) - def test_list_role_assignments_for_tree(self): - project = self.setup_test_project() - - with self.override_role(): - self.role_assignments_client.list_role_assignments( - include_subtree=True, - **{'scope.project.id': project['id']}) diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_roles_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_roles_rbac.py deleted file mode 100644 index c93afa1f..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_roles_rbac.py +++ /dev/null @@ -1,422 +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.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - -CONF = config.CONF - - -class IdentityRolesV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - @classmethod - def resource_setup(cls): - super(IdentityRolesV3RbacTest, cls).resource_setup() - cls.domain = cls.setup_test_domain() - cls.project = cls.setup_test_project() - cls.group = cls.setup_test_group() - cls.role = cls.setup_test_role() - cls.implies_role = cls.setup_test_role() - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_role"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d904') - def test_create_role(self): - with self.override_role(): - self.setup_test_role() - - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_role"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d905') - def test_update_role(self): - new_role_name = data_utils.rand_name( - self.__class__.__name__ + '-test_update_role') - - with self.override_role(): - self.roles_client.update_role(self.role['id'], - name=new_role_name) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_role"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d906') - def test_delete_role(self): - role = self.setup_test_role() - - with self.override_role(): - self.roles_client.delete_role(role['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_role"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d907') - def test_show_role(self): - with self.override_role(): - self.roles_client.show_role(self.role['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_roles"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d908') - def test_list_roles(self): - with self.override_role(): - self.roles_client.list_roles() - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_grant"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90c') - def test_create_group_role_on_project(self): - with self.override_role(): - self.roles_client.create_group_role_on_project( - self.project['id'], - self.group['id'], - self.role['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_from_group_on_project, - self.project['id'], - self.group['id'], - self.role['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_grant"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d912') - def test_create_group_role_on_domain(self): - with self.override_role(): - self.roles_client.create_group_role_on_domain( - self.domain['id'], - self.group['id'], - self.role['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_from_group_on_domain, - self.domain['id'], - self.group['id'], - self.role['id']) - - @decorators.idempotent_id('8738d3d2-8c84-4423-b36c-7c59eaa08b73') - @rbac_rule_validation.action(service="keystone", - rules=["identity:check_grant"]) - def test_check_role_from_group_on_project_existence(self): - self.roles_client.create_group_role_on_project( - self.project['id'], - self.group['id'], - self.role['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_from_group_on_project, - self.project['id'], - self.group['id'], - self.role['id']) - - with self.override_role(): - self.roles_client.check_role_from_group_on_project_existence( - self.project['id'], - self.group['id'], - self.role['id']) - - @decorators.idempotent_id('e7d73bd0-cf5e-4c0c-9c93-cf53e23232d6') - @rbac_rule_validation.action(service="keystone", - rules=["identity:check_grant"]) - def test_check_role_from_group_on_domain_existence(self): - self.roles_client.create_group_role_on_domain( - self.domain['id'], - self.group['id'], - self.role['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_from_group_on_domain, - self.domain['id'], - self.group['id'], - self.role['id']) - - with self.override_role(): - self.roles_client.check_role_from_group_on_domain_existence( - self.domain['id'], - self.group['id'], - self.role['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:revoke_grant"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90d') - def test_delete_role_from_group_on_project(self): - self.roles_client.create_group_role_on_project( - self.project['id'], - self.group['id'], - self.role['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_from_group_on_project, - self.project['id'], - self.group['id'], - self.role['id']) - - with self.override_role(): - self.roles_client.delete_role_from_group_on_project( - self.project['id'], - self.group['id'], - self.role['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:revoke_grant"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d913') - def test_delete_role_from_group_on_domain(self): - self.roles_client.create_group_role_on_domain( - self.domain['id'], - self.group['id'], - self.role['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_from_group_on_domain, - self.domain['id'], - self.group['id'], - self.role['id']) - - with self.override_role(): - self.roles_client.delete_role_from_group_on_domain( - self.domain['id'], - self.group['id'], - self.role['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_grants"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90e') - def test_list_group_roles_on_project(self): - with self.override_role(): - self.roles_client.list_group_roles_on_project( - self.project['id'], - self.group['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_grants"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d914') - def test_list_group_roles_on_domain(self): - with self.override_role(): - self.roles_client.list_group_roles_on_domain( - self.domain['id'], - self.group['id']) - - @decorators.idempotent_id('2aef3eaa-8156-4962-a01d-c9bb0e499e15') - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_implied_role"]) - def test_create_role_inference_rule(self): - with self.override_role(): - self.roles_client.create_role_inference_rule( - self.role['id'], self.implies_role['id']) - self.addCleanup(self.roles_client.delete_role_inference_rule, - self.role['id'], self.implies_role['id']) - - @decorators.idempotent_id('83f997b2-55c4-4894-b1f2-e175b19d1fa5') - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_implied_role"]) - def test_show_role_inference_rule(self): - self.roles_client.create_role_inference_rule( - self.role['id'], self.implies_role['id']) - self.addCleanup(self.roles_client.delete_role_inference_rule, - self.role['id'], self.implies_role['id']) - - with self.override_role(): - self.roles_client.show_role_inference_rule( - self.role['id'], self.implies_role['id']) - - @decorators.idempotent_id('f7bb39bf-0b06-468e-a8b0-60a4fb1f258d') - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_implied_roles"]) - def test_list_role_inferences_rules(self): - with self.override_role(): - self.roles_client.list_role_inferences_rules(self.role['id']) - - @decorators.idempotent_id('eca2d502-09bb-45cd-9773-bce2e7bcddd1') - @rbac_rule_validation.action(service="keystone", - rules=["identity:check_implied_role"]) - def test_check_role_inference_rule(self): - self.roles_client.create_role_inference_rule( - self.role['id'], self.implies_role['id']) - self.addCleanup(self.roles_client.delete_role_inference_rule, - self.role['id'], self.implies_role['id']) - - with self.override_role(): - self.roles_client.check_role_inference_rule( - self.role['id'], self.implies_role['id']) - - @decorators.idempotent_id('13a5db1e-dd4a-4ca1-81ec-d5452aaaf54b') - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_implied_role"]) - def test_delete_role_inference_rule(self): - self.roles_client.create_role_inference_rule( - self.role['id'], self.implies_role['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_inference_rule, - self.role['id'], self.implies_role['id']) - - with self.override_role(): - self.roles_client.delete_role_inference_rule( - self.role['id'], self.implies_role['id']) - - @decorators.idempotent_id('05869f2b-4dd4-425a-905e-eec9a6f06374') - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_role_inference_rules"]) - def test_list_all_role_inference_rules(self): - with self.override_role(): - self.roles_client.list_all_role_inference_rules() - - -class IdentityRolesUserCreateV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - """Tests identity roles v3 API endpoints that require user creation. - This is in a separate class to better manage immutable user source feature - flag. - """ - - @classmethod - def skip_checks(cls): - super(IdentityRolesUserCreateV3RbacTest, cls).skip_checks() - if CONF.identity_feature_enabled.immutable_user_source: - raise cls.skipException('Skipped because environment has an ' - 'immutable user source and solely ' - 'provides read-only access to users.') - - @classmethod - def resource_setup(cls): - super(IdentityRolesUserCreateV3RbacTest, cls).resource_setup() - cls.domain = cls.setup_test_domain() - cls.project = cls.setup_test_project() - cls.group = cls.setup_test_group() - cls.role = cls.setup_test_role() - cls.implies_role = cls.setup_test_role() - cls.user = cls.setup_test_user() - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_grant"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d909') - def test_create_user_role_on_project(self): - with self.override_role(): - self.roles_client.create_user_role_on_project( - self.project['id'], - self.user['id'], - self.role['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_from_user_on_project, - self.project['id'], - self.user['id'], - self.role['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_grant"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90f') - def test_create_user_role_on_domain(self): - with self.override_role(): - self.roles_client.create_user_role_on_domain( - self.domain['id'], - self.user['id'], - self.role['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_from_user_on_domain, - self.domain['id'], - self.user['id'], - self.role['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:check_grant"]) - @decorators.idempotent_id('22921b1e-1a33-4026-bff9-f236d6dd149c') - def test_check_user_role_existence_on_project(self): - self.roles_client.create_user_role_on_project( - self.project['id'], - self.user['id'], - self.role['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_from_user_on_project, - self.project['id'], - self.user['id'], - self.role['id']) - - with self.override_role(): - self.roles_client.check_user_role_existence_on_project( - self.project['id'], - self.user['id'], - self.role['id']) - - @decorators.idempotent_id('92f8e67d-85bf-407d-9814-edd5664abc47') - @rbac_rule_validation.action(service="keystone", - rules=["identity:check_grant"]) - def test_check_user_role_existence_on_domain(self): - self.roles_client.create_user_role_on_domain( - self.domain['id'], - self.user['id'], - self.role['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_from_user_on_domain, - self.domain['id'], - self.user['id'], - self.role['id']) - - with self.override_role(): - self.roles_client.check_user_role_existence_on_domain( - self.domain['id'], - self.user['id'], - self.role['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:revoke_grant"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90a') - def test_delete_role_from_user_on_project(self): - self.roles_client.create_user_role_on_project( - self.project['id'], - self.user['id'], - self.role['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_from_user_on_project, - self.project['id'], - self.user['id'], - self.role['id']) - - with self.override_role(): - self.roles_client.delete_role_from_user_on_project( - self.project['id'], - self.user['id'], - self.role['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:revoke_grant"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d910') - def test_delete_role_from_user_on_domain(self): - self.roles_client.create_user_role_on_domain( - self.domain['id'], - self.user['id'], - self.role['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.roles_client.delete_role_from_user_on_domain, - self.domain['id'], - self.user['id'], - self.role['id']) - - with self.override_role(): - self.roles_client.delete_role_from_user_on_domain( - self.domain['id'], - self.user['id'], - self.role['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_grants"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d90b') - def test_list_user_roles_on_project(self): - with self.override_role(): - self.roles_client.list_user_roles_on_project( - self.project['id'], - self.user['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_grants"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1395-080044d0d911') - def test_list_user_roles_on_domain(self): - with self.override_role(): - self.roles_client.list_user_roles_on_domain( - self.domain['id'], - self.user['id']) diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_services_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_services_rbac.py deleted file mode 100644 index 5427f5f6..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_services_rbac.py +++ /dev/null @@ -1,68 +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.common.utils import data_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -class IdentitySericesV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_service"]) - @decorators.idempotent_id('9a4bb317-f0bb-4005-8df0-4b672885b7c8') - def test_create_service(self): - with self.override_role(): - self.setup_test_service() - - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_service"]) - @decorators.idempotent_id('b39447d1-2cf6-40e5-a899-46f287f2ecf0') - def test_update_service(self): - service = self.setup_test_service() - new_name = data_utils.rand_name(self.__class__.__name__ + '-service') - - with self.override_role(): - self.services_client.update_service(service['id'], - service=service, - name=new_name, - type=service['type']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_service"]) - @decorators.idempotent_id('177b991a-438d-4bef-8e9f-9c6cc5a1c9e8') - def test_delete_service(self): - service = self.setup_test_service() - - with self.override_role(): - self.services_client.delete_service(service['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_service"]) - @decorators.idempotent_id('d89a9ac6-cd53-428d-84c0-5bc71f4a432d') - def test_show_service(self): - service = self.setup_test_service() - - with self.override_role(): - self.services_client.show_service(service['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_services"]) - @decorators.idempotent_id('706e6bea-3385-4718-919c-0b5121395806') - def test_list_services(self): - with self.override_role(): - self.services_client.list_services() diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_tokens_negative_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_tokens_negative_rbac.py deleted file mode 100644 index 45eb601e..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_tokens_negative_rbac.py +++ /dev/null @@ -1,97 +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.lib import exceptions as lib_exc - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin import rbac_utils -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -class IdentityTokenV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - credentials = ['primary', 'alt', 'admin'] - - @classmethod - def skip_checks(cls): - super(IdentityTokenV3RbacTest, cls).skip_checks() - # In case of admin, the positive testcase would be used, hence - # skipping negative testcase. - if rbac_utils.is_admin(): - raise cls.skipException( - "Skipped as admin role doesn't require negative testing") - - def _setup_alt_token(self): - return self.setup_test_token( - self.os_alt.auth_provider.credentials.user_id, - self.os_alt.auth_provider.credentials.password) - - @decorators.idempotent_id('c83c8f1a-79cb-4dc4-b55f-c7d2bfd98b1e') - @decorators.attr(type=['negative']) - @rbac_rule_validation.action( - service="keystone", - rules=["identity:validate_token"], - extra_target_data={ - "target.token.user_id": - "os_alt.auth_provider.credentials.user_id" - }) - def test_show_token_negative(self): - # Explicit negative test for identity:validate_token policy action. - # Assert expected exception is Forbidden and then reraise it. - alt_token_id = self._setup_alt_token() - with self.override_role(): - e = self.assertRaises(lib_exc.Forbidden, - self.identity_client.show_token, - alt_token_id) - raise e - - @decorators.idempotent_id('2786a55d-a818-433a-af7a-41ebf72ab4da') - @decorators.attr(type=['negative']) - @rbac_rule_validation.action( - service="keystone", - rules=["identity:revoke_token"], - extra_target_data={ - "target.token.user_id": - "os_alt.auth_provider.credentials.user_id" - }) - def test_delete_token_negative(self): - # Explicit negative test for identity:revoke_token policy action. - # Assert expected exception is Forbidden and then reraise it. - alt_token_id = self._setup_alt_token() - with self.override_role(): - e = self.assertRaises(lib_exc.Forbidden, - self.identity_client.delete_token, - alt_token_id) - raise e - - @decorators.idempotent_id('1ea02ac0-9a96-44bd-bdc3-4dae3c10cc2e') - @decorators.attr(type=['negative']) - @rbac_rule_validation.action( - service="keystone", - rules=["identity:check_token"], - extra_target_data={ - "target.token.user_id": - "os_alt.auth_provider.credentials.user_id" - }) - def test_check_token_existence_negative(self): - # Explicit negative test for identity:check_token policy action. - # Assert expected exception is Forbidden and then reraise it. - alt_token_id = self._setup_alt_token() - with self.override_role(): - e = self.assertRaises(lib_exc.Forbidden, - self.identity_client.check_token_existence, - alt_token_id) - raise e diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_tokens_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_tokens_rbac.py deleted file mode 100644 index 0028a974..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_tokens_rbac.py +++ /dev/null @@ -1,67 +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 patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - - -class IdentityTokenV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - @classmethod - def resource_setup(cls): - super(IdentityTokenV3RbacTest, cls).resource_setup() - cls.user_id = cls.os_primary.auth_provider.credentials.user_id - cls.password = cls.os_primary.auth_provider.credentials.password - - @decorators.idempotent_id('201e2fe5-2023-4bce-9189-78b51520a91e') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:validate_token"], - extra_target_data={ - "target.token.user_id": - "os_primary.auth_provider.credentials.user_id" - }) - def test_show_token(self): - token_id = self.setup_test_token(self.user_id, self.password) - with self.override_role(): - self.identity_client.show_token(token_id) - - @decorators.idempotent_id('42a299db-fe0a-4ea0-9824-0bfd13155886') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:revoke_token"], - extra_target_data={ - "target.token.user_id": - "os_primary.auth_provider.credentials.user_id" - }) - def test_delete_token(self): - token_id = self.setup_test_token(self.user_id, self.password) - with self.override_role(): - self.identity_client.delete_token(token_id) - - @decorators.idempotent_id('3554d218-8cd6-4730-a1b2-0e22f9b78f45') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:check_token"], - extra_target_data={ - "target.token.user_id": - "os_primary.auth_provider.credentials.user_id" - }) - def test_check_token_exsitence(self): - token_id = self.setup_test_token(self.user_id, self.password) - with self.override_role(): - self.identity_client.check_token_existence(token_id) diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_trusts_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_trusts_rbac.py deleted file mode 100644 index da29433c..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_trusts_rbac.py +++ /dev/null @@ -1,192 +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. - -import testtools - -from tempest import config -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.identity import rbac_base - -CONF = config.CONF - - -class IdentityTrustV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - credentials = ['primary', 'alt', 'admin'] - - @classmethod - def skip_checks(cls): - super(IdentityTrustV3RbacTest, cls).skip_checks() - if not CONF.identity_feature_enabled.trust: - raise cls.skipException( - "%s skipped as trust feature isn't enabled" % cls.__name__) - if CONF.identity_feature_enabled.immutable_user_source: - raise cls.skipException('Skipped because environment has an ' - 'immutable user source and solely ' - 'provides read-only access to users.') - - @classmethod - def resource_setup(cls): - super(IdentityTrustV3RbacTest, cls).resource_setup() - # Use the primary user's credentials for the "trustor_user_id", since - # user_id:%(trust.trustor_user_id)s will thereby evaluate to - # "primary user's user_id:primary user's user_id" which evaluates to - # true. - cls.trustor_user_id = cls.os_primary.credentials.user_id - cls.trustor_project_id = cls.os_primary.credentials.project_id - cls.trustee_user_id = cls.setup_test_user()['id'] - - # The "unauthorized_user_id" does not have permissions to create a - # trust because the user_id in "user_id:%(trust.trustor_user_id)s" (the - # policy rule for creating a trust) corresponds to the primary user_id - # not the alt user_id. - cls.unauthorized_user_id = cls.os_alt.credentials.user_id - - # A role is guaranteed to exist (namely the admin role), because - # "trustor_user_id" and "trustor_project_id" are the primary tempest - # user and project, respectively. - cls.delegated_role_id = cls.roles_client.list_user_roles_on_project( - cls.trustor_project_id, cls.trustor_user_id)['roles'][0]['id'] - - cls.trust = cls.setup_test_trust(trustor_user_id=cls.trustor_user_id, - trustee_user_id=cls.trustee_user_id, - project_id=cls.trustor_project_id, - roles=[{'id': cls.delegated_role_id}]) - - @decorators.idempotent_id('7ab595a7-9b71-45fe-91d8-2793b0292f72') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:create_trust"], - extra_target_data={ - "trust.trustor_user_id": "os_primary.credentials.user_id" - }) - def test_create_trust(self): - with self.override_role(): - self.setup_test_trust(trustor_user_id=self.trustor_user_id, - trustee_user_id=self.trustee_user_id) - - @decorators.idempotent_id('bd72d22a-6e11-4840-bd93-17b382e7f0e0') - @decorators.attr(type=['negative']) - @rbac_rule_validation.action( - service="keystone", - rules=["identity:create_trust"], - extra_target_data={ - "trust.trustor_user_id": "os_alt.credentials.user_id" - }) - def test_create_trust_negative(self): - # Explicit negative test for identity:create_trust policy action. - # Assert expected exception is Forbidden and then reraise it. - with self.override_role(): - e = self.assertRaises(lib_exc.Forbidden, self.setup_test_trust, - trustor_user_id=self.unauthorized_user_id, - trustee_user_id=self.trustee_user_id) - raise e - - @decorators.idempotent_id('d9a6fd06-08f6-462c-a86c-ce009adf1230') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:delete_trust"], - extra_target_data={ - "target.trust.trustor_user_id": "os_primary.credentials.user_id" - }) - def test_delete_trust(self): - trust = self.setup_test_trust(trustor_user_id=self.trustor_user_id, - trustee_user_id=self.trustee_user_id) - - with self.override_role(): - self.trusts_client.delete_trust(trust['id']) - - @decorators.idempotent_id('f2e32896-bf66-4f4e-89cf-e7fba0ef1f38') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:list_trusts"]) - def test_list_trusts(self): - # Depending on the passed arguments to the list trusts API, different - # policy actions are enforced. - feature_flag = \ - CONF.policy_feature_enabled.keystone_policy_enforcement_train - with self.override_role(): - if feature_flag: - self.trusts_client.list_trusts() - else: - self.trusts_client.list_trusts( - trustor_user_id=self.trustor_user_id) - - @testtools.skipUnless( - CONF.policy_feature_enabled.keystone_policy_enforcement_train, - 'This test tests Keystone policy actions introduced in Train') - @decorators.idempotent_id('6273ab11-32ad-450e-be4e-deaa856d7051') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:list_trusts_for_trustor"], - extra_target_data={ - "target.trust.trustor_user_id": "os_primary.credentials.user_id" - }) - def test_list_trusts_for_trustor(self): - with self.override_role(): - self.trusts_client.list_trusts( - trustor_user_id=self.trustor_user_id) - - @testtools.skipUnless( - CONF.policy_feature_enabled.keystone_policy_enforcement_train, - 'This test tests Keystone policy actions introduced in Train') - @decorators.idempotent_id('90bbbd77-c1df-43f9-99dc-088d52b95eff') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:list_trusts_for_trustee"], - extra_target_data={ - "target.trust.trustee_user_id": "trustee_user_id" - }) - def test_list_trusts_for_trustee(self): - with self.override_role(): - self.trusts_client.list_trusts( - trustee_user_id=self.trustee_user_id) - - @decorators.idempotent_id('3c9ff92f-a73e-4f9b-8865-e017f38c70f5') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:list_roles_for_trust"], - extra_target_data={ - "target.trust.trustor_user_id": "os_primary.credentials.user_id" - }) - def test_list_roles_for_trust(self): - with self.override_role(): - self.trusts_client.list_trust_roles(self.trust['id']) - - @decorators.idempotent_id('3bb4f97b-cecd-4c7d-ad10-b88ee6c5d573') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:get_role_for_trust"], - extra_target_data={ - "target.trust.trustor_user_id": "os_primary.credentials.user_id" - }) - def test_show_trust_role(self): - with self.override_role(): - self.trusts_client.show_trust_role( - self.trust['id'], self.delegated_role_id) - - @decorators.idempotent_id('0184e0fb-641e-4b52-ab73-81c1ce6ca5c1') - @rbac_rule_validation.action( - service="keystone", - rules=["identity:get_trust"], - extra_target_data={ - "target.trust.trustor_user_id": "os_primary.credentials.user_id" - }) - def test_show_trust(self): - with self.override_role(): - self.trusts_client.show_trust(self.trust['id']) diff --git a/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py b/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py deleted file mode 100644 index 0d2a04d0..00000000 --- a/patrole_tempest_plugin/tests/api/identity/v3/test_users_rbac.py +++ /dev/null @@ -1,96 +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. - -import testtools - -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.identity import rbac_base - -CONF = config.CONF - - -class IdentityUserV3RbacTest(rbac_base.BaseIdentityV3RbacTest): - - @classmethod - def resource_setup(cls): - super(IdentityUserV3RbacTest, cls).resource_setup() - cls.default_user_id = cls.os_primary.credentials.user_id - - @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source, - "Configured to use an immutable user source") - @rbac_rule_validation.action(service="keystone", - rules=["identity:create_user"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d904') - def test_create_user(self): - with self.override_role(): - self.setup_test_user() - - @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source, - "Configured to use an immutable user source") - @rbac_rule_validation.action(service="keystone", - rules=["identity:update_user"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d905') - def test_update_user(self): - user = self.setup_test_user() - new_email = data_utils.rand_name( - self.__class__.__name__ + '-user_email') - - with self.override_role(): - self.users_client.update_user(user['id'], - name=user['name'], - email=new_email) - - @testtools.skipIf(CONF.identity_feature_enabled.immutable_user_source, - "Configured to use an immutable user source") - @rbac_rule_validation.action(service="keystone", - rules=["identity:delete_user"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d906') - def test_delete_user(self): - user = self.setup_test_user() - - with self.override_role(): - self.users_client.delete_user(user['id']) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_users"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d907') - def test_list_users(self): - with self.override_role(): - self.users_client.list_users() - - @rbac_rule_validation.action(service="keystone", - rules=["identity:get_user"]) - @decorators.idempotent_id('0f148510-63bf-11e6-4522-080044d0d908') - def test_show_own_user(self): - with self.override_role(): - self.users_client.show_user(self.default_user_id) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_groups_for_user"]) - @decorators.idempotent_id('bd5946d4-46d2-423d-a800-a3e7aabc18b3') - def test_list_own_user_group(self): - with self.override_role(): - self.users_client.list_user_groups(self.default_user_id) - - @rbac_rule_validation.action(service="keystone", - rules=["identity:list_user_projects"]) - @decorators.idempotent_id('0f148510-63bf-11e6-1564-080044d0d909') - def test_list_own_user_projects(self): - with self.override_role(): - self.users_client.list_user_projects(self.default_user_id) diff --git a/patrole_tempest_plugin/tests/api/image/__init__.py b/patrole_tempest_plugin/tests/api/image/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/patrole_tempest_plugin/tests/api/image/rbac_base.py b/patrole_tempest_plugin/tests/api/image/rbac_base.py deleted file mode 100644 index 9019bc45..00000000 --- a/patrole_tempest_plugin/tests/api/image/rbac_base.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 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. - -from tempest.api.image import base as image_base - -from patrole_tempest_plugin import rbac_utils - - -class BaseV2ImageRbacTest(rbac_utils.RbacUtilsMixin, - image_base.BaseV2ImageTest): - - @classmethod - def setup_clients(cls): - super(BaseV2ImageRbacTest, cls).setup_clients() - cls.namespaces_client = cls.os_primary.namespaces_client - cls.resource_types_client = cls.os_primary.resource_types_client - cls.namespace_properties_client =\ - cls.os_primary.namespace_properties_client - cls.namespace_objects_client = cls.os_primary.namespace_objects_client - cls.namespace_tags_client = cls.os_primary.namespace_tags_client diff --git a/patrole_tempest_plugin/tests/api/image/test_image_namespace_objects_rbac.py b/patrole_tempest_plugin/tests/api/image/test_image_namespace_objects_rbac.py deleted file mode 100644 index ebb848f3..00000000 --- a/patrole_tempest_plugin/tests/api/image/test_image_namespace_objects_rbac.py +++ /dev/null @@ -1,106 +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.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.image import rbac_base - - -class ImageNamespacesObjectsRbacTest(rbac_base.BaseV2ImageRbacTest): - - @rbac_rule_validation.action(service="glance", - rules=["add_metadef_object"]) - @decorators.idempotent_id("772156f2-e33d-432e-8521-12385746c2f0") - def test_create_metadef_object_in_namespace(self): - """Create Metadef Object Namespace Test - - RBAC test for the glance add_metadef_object policy - """ - namespace = self.create_namespace() - # create a md object, it will be cleaned automatically after - # cleanup of namespace - object_name = data_utils.rand_name( - self.__class__.__name__ + '-test-object') - with self.override_role(): - self.namespace_objects_client.create_namespace_object( - namespace['namespace'], - name=object_name) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.namespace_objects_client.delete_namespace_object, - namespace['namespace'], object_name) - - @rbac_rule_validation.action(service="glance", - rules=["get_metadef_objects"]) - @decorators.idempotent_id("48b50ecb-237d-4909-be62-b6a05c47b64d") - def test_list_metadef_objects_in_namespace(self): - """List Metadef Object Namespace Test - - RBAC test for the glance get_metadef_objects policy - """ - namespace = self.create_namespace() - with self.override_role(): - # list md objects - self.namespace_objects_client.list_namespace_objects( - namespace['namespace']) - - @rbac_rule_validation.action(service="glance", - rules=["modify_metadef_object"]) - @decorators.idempotent_id("cd130b1d-89fa-479c-a90e-498d895fb455") - def test_update_metadef_object_in_namespace(self): - """Update Metadef Object Namespace Test - - RBAC test for the glance modify_metadef_object policy - """ - namespace = self.create_namespace() - object_name = data_utils.rand_name( - self.__class__.__name__ + '-test-object') - self.namespace_objects_client.create_namespace_object( - namespace['namespace'], - name=object_name) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.namespace_objects_client.delete_namespace_object, - namespace['namespace'], object_name) - - # Toggle role and modify object - new_name = "Object New Name" - with self.override_role(): - self.namespace_objects_client.update_namespace_object( - namespace['namespace'], object_name, name=new_name) - - @rbac_rule_validation.action(service="glance", - rules=["get_metadef_object"]) - @decorators.idempotent_id("93c61420-5b80-4a0e-b6f3-4ccc6e90b865") - def test_show_metadef_object_in_namespace(self): - """Show Metadef Object Namespace Test - - RBAC test for the glance get_metadef_object policy - """ - namespace = self.create_namespace() - object_name = data_utils.rand_name( - self.__class__.__name__ + '-test-object') - self.namespace_objects_client.create_namespace_object( - namespace['namespace'], - name=object_name) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.namespace_objects_client.delete_namespace_object, - namespace['namespace'], object_name) - # Toggle role and get object - with self.override_role(): - self.namespace_objects_client.show_namespace_object( - namespace['namespace'], - object_name) diff --git a/patrole_tempest_plugin/tests/api/image/test_image_namespace_property_rbac.py b/patrole_tempest_plugin/tests/api/image/test_image_namespace_property_rbac.py deleted file mode 100644 index cc3ba3bd..00000000 --- a/patrole_tempest_plugin/tests/api/image/test_image_namespace_property_rbac.py +++ /dev/null @@ -1,97 +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.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 - - -class NamespacesPropertyRbacTest(rbac_base.BaseV2ImageRbacTest): - - @classmethod - def resource_setup(cls): - super(NamespacesPropertyRbacTest, cls).resource_setup() - body = cls.resource_types_client.list_resource_types() - cls.resource_name = body['resource_types'][0]['name'] - - @rbac_rule_validation.action(service="glance", - rules=["add_metadef_property"]) - @decorators.idempotent_id('383555ca-677b-43e9-b809-acc2b5a0176c') - def test_add_md_properties(self): - """Create Image Metadef Namespace Property Test - - RBAC test for the glance add_metadef_property policy - """ - namespace = self.create_namespace() - property_name = data_utils.rand_name( - self.__class__.__name__ + '-test-ns-property') - with self.override_role(): - self.namespace_properties_client.create_namespace_property( - namespace=namespace['namespace'], type="string", - title=property_name, name=self.resource_name) - - @rbac_rule_validation.action(service="glance", - rules=["get_metadef_properties"]) - @decorators.idempotent_id('d5177611-c2b5-4000-bd9c-1987af9222ea') - def test_get_md_properties(self): - """List Image Metadef Namespace Properties Test - - RBAC test for the glance get_metadef_properties policy - """ - namespace = self.create_namespace() - with self.override_role(): - self.namespace_properties_client.list_namespace_properties( - namespace=namespace['namespace']) - - @rbac_rule_validation.action(service="glance", - rules=["get_metadef_property"]) - @decorators.idempotent_id('cfeda2af-bcab-433e-80c7-4b40c774aed5') - def test_get_md_property(self): - """Get Image Metadef Namespace Property Test - - RBAC test for the glance get_metadef_property policy - """ - namespace = self.create_namespace() - property_name = data_utils.rand_name( - self.__class__.__name__ + '-test-ns-property') - self.namespace_properties_client.create_namespace_property( - namespace=namespace['namespace'], type="string", - title=property_name, name=self.resource_name) - - with self.override_role(): - self.namespace_properties_client.show_namespace_properties( - namespace['namespace'], self.resource_name) - - @rbac_rule_validation.action(service="glance", - rules=["modify_metadef_property"]) - @decorators.idempotent_id('fdaf9363-4010-4f2f-8192-1b28f6b22e69') - def test_modify_md_properties(self): - """Modify Image Metadef Namespace Policy Test - - RBAC test for the glance modify_metadef_property policy - """ - namespace = self.create_namespace() - property_name = data_utils.rand_name( - self.__class__.__name__ + '-test-ns-property') - self.namespace_properties_client.create_namespace_property( - namespace=namespace['namespace'], type="string", - title=property_name, name=self.resource_name) - - with self.override_role(): - self.namespace_properties_client.update_namespace_properties( - namespace['namespace'], self.resource_name, type="string", - title=property_name, name=self.resource_name) diff --git a/patrole_tempest_plugin/tests/api/image/test_image_namespace_rbac.py b/patrole_tempest_plugin/tests/api/image/test_image_namespace_rbac.py deleted file mode 100644 index 1883d7ce..00000000 --- a/patrole_tempest_plugin/tests/api/image/test_image_namespace_rbac.py +++ /dev/null @@ -1,75 +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.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.image import rbac_base - - -class ImageNamespacesRbacTest(rbac_base.BaseV2ImageRbacTest): - - @rbac_rule_validation.action(service="glance", - rules=["add_metadef_namespace"]) - @decorators.idempotent_id('e0730ead-b824-4ffc-b774-9469df0e4da6') - def test_create_metadef_namespace(self): - """Create Image Metadef Namespace Test - - RBAC test for the glance add_metadef_namespace policy - """ - namespace_name = data_utils.rand_name( - self.__class__.__name__ + '-test-ns') - with self.override_role(): - self.namespaces_client.create_namespace( - namespace=namespace_name, - protected=False) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.namespaces_client.delete_namespace, - namespace_name) - - @rbac_rule_validation.action(service="glance", - rules=["get_metadef_namespaces"]) - @decorators.idempotent_id('f0b12538-9047-489e-98a5-2d78f48ce789') - def test_list_metadef_namespaces(self): - """List Image Metadef Namespace Test - - RBAC test for the glance get_metadef_namespaces policy - """ - with self.override_role(): - self.namespaces_client.list_namespaces() - - @rbac_rule_validation.action(service="glance", - rules=["modify_metadef_namespace"]) - @decorators.idempotent_id('72c14a7e-927d-4f1a-9e1f-25475552922b') - def test_modify_metadef_namespace(self): - """Modify Image Metadef Namespace Test - - RBAC test for the glance modify_metadef_namespace policy - """ - namespace_name = data_utils.rand_name( - self.__class__.__name__ + '-test-ns') - body = self.namespaces_client.create_namespace( - namespace=namespace_name, - protected=False) - with self.override_role(): - self.namespaces_client.update_namespace( - body['namespace'], description="My new description") - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.namespaces_client.delete_namespace, - namespace_name) diff --git a/patrole_tempest_plugin/tests/api/image/test_image_namespace_tags_rbac.py b/patrole_tempest_plugin/tests/api/image/test_image_namespace_tags_rbac.py deleted file mode 100644 index cc367ee2..00000000 --- a/patrole_tempest_plugin/tests/api/image/test_image_namespace_tags_rbac.py +++ /dev/null @@ -1,108 +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.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.image import rbac_base as base - - -class NamespaceTagsRbacTest(base.BaseV2ImageRbacTest): - """RBAC tests for namespace_tags_client. - - Performs RBAC testing for the endpoints in namespace_tags_client, except - for - - 1) delete_namespace_tag - 2) delete_namespace_tags - - because Glance does not currently do policy enforcement for them. - """ - - @classmethod - def resource_setup(cls): - super(NamespaceTagsRbacTest, cls).resource_setup() - cls.namespace = cls.namespaces_client.create_namespace( - namespace=data_utils.rand_name( - cls.__name__ + '-namespace'))['namespace'] - cls.addClassResourceCleanup( - cls.namespaces_client.delete_namespace, - cls.namespace) - - def _create_namespace_tag(self, multiple=False): - tag_count = 2 if multiple else 1 - namespace_tag_names = [] - - for i in range(tag_count): - tag_name = data_utils.rand_name(self.__class__.__name__ + '-tag') - namespace_tag_names.append({'name': tag_name}) - - if multiple: - namespace_tags = self.namespace_tags_client.create_namespace_tags( - self.namespace, tags=namespace_tag_names)['tags'] - else: - namespace_tags = self.namespace_tags_client.create_namespace_tag( - self.namespace, namespace_tag_names[0]['name']) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.namespace_tags_client.delete_namespace_tags, - self.namespace) - - return [nt['name'] for nt in namespace_tags] if multiple \ - else namespace_tags['name'] - - @decorators.idempotent_id('50bedccb-9d0b-4138-8d95-31a89250edf6') - @rbac_rule_validation.action(service="glance", - rules=["add_metadef_tag"]) - def test_create_namespace_tag(self): - with self.override_role(): - self._create_namespace_tag() - - @decorators.idempotent_id('4acf70cc-05da-4b1e-87b2-d5e4475164e7') - @rbac_rule_validation.action(service="glance", - rules=["get_metadef_tag"]) - def test_show_namespace_tag(self): - tag_name = self._create_namespace_tag() - with self.override_role(): - self.namespace_tags_client.show_namespace_tag(self.namespace, - tag_name) - - @decorators.idempotent_id('01593828-3edb-461e-8abc-8fdeb3927e37') - @rbac_rule_validation.action(service="glance", - rules=["modify_metadef_tag"]) - def test_update_namespace_tag(self): - tag_name = self._create_namespace_tag() - updated_tag_name = data_utils.rand_name( - self.__class__.__name__ + '-tag') - - with self.override_role(): - self.namespace_tags_client.update_namespace_tag( - self.namespace, tag_name, name=updated_tag_name) - - @decorators.idempotent_id('20ffaf76-ebdc-4267-a1ad-194346f5cc91') - @rbac_rule_validation.action(service="glance", - rules=["add_metadef_tags"]) - def test_create_namespace_tags(self): - with self.override_role(): - self._create_namespace_tag(multiple=True) - - @decorators.idempotent_id('d37c1501-e787-449d-89b3-754a942a459a') - @rbac_rule_validation.action(service="glance", - rules=["get_metadef_tags"]) - def test_list_namespace_tags(self): - with self.override_role(): - self.namespace_tags_client.list_namespace_tags(self.namespace) diff --git a/patrole_tempest_plugin/tests/api/image/test_image_resource_types_rbac.py b/patrole_tempest_plugin/tests/api/image/test_image_resource_types_rbac.py deleted file mode 100644 index b2780c99..00000000 --- a/patrole_tempest_plugin/tests/api/image/test_image_resource_types_rbac.py +++ /dev/null @@ -1,69 +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.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.image import rbac_base - - -class ImageResourceTypesRbacTest(rbac_base.BaseV2ImageRbacTest): - - @classmethod - def resource_setup(cls): - super(ImageResourceTypesRbacTest, cls).resource_setup() - cls.namespace_name = data_utils.rand_name( - cls.__name__ + '-test-ns') - cls.namespaces_client.create_namespace( - namespace=cls.namespace_name, - protected=False) - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.namespaces_client.delete_namespace, cls.namespace_name) - - @rbac_rule_validation.action(service="glance", - rules=["list_metadef_resource_types"]) - @decorators.idempotent_id('0416fc4d-cfdc-447b-88b6-d9f1dd0382f7') - def test_list_metadef_resource_types(self): - """List Metadef Resource Type Image Test - - RBAC test for the glance list_metadef_resource_type policy. - """ - with self.override_role(): - self.resource_types_client.list_resource_types() - - @rbac_rule_validation.action(service="glance", - rules=["get_metadef_resource_type"]) - @decorators.idempotent_id('3698d53c-71ae-4803-a2c3-c272c054f25c') - def test_get_metadef_resource_type(self): - """Get Metadef Resource Type Image Test - - RBAC test for the glance get_metadef_resource_type policy. - """ - with self.override_role(): - self.resource_types_client.list_resource_type_association( - self.namespace_name) - - @rbac_rule_validation.action( - service="glance", - rules=["add_metadef_resource_type_association"]) - @decorators.idempotent_id('ef9fbc60-3e28-4164-a25c-d30d892f7939') - def test_add_metadef_resource_type(self): - type_name = data_utils.rand_name() - with self.override_role(): - self.resource_types_client.create_resource_type_association( - self.namespace_name, name=type_name) diff --git a/patrole_tempest_plugin/tests/api/image/test_images_member_rbac.py b/patrole_tempest_plugin/tests/api/image/test_images_member_rbac.py deleted file mode 100644 index 18515e23..00000000 --- a/patrole_tempest_plugin/tests/api/image/test_images_member_rbac.py +++ /dev/null @@ -1,124 +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 patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.image import rbac_base as base - - -class ImagesMemberRbacTest(base.BaseV2ImageRbacTest): - - credentials = ['primary', 'alt', 'admin'] - - @classmethod - def resource_setup(cls): - super(ImagesMemberRbacTest, cls).resource_setup() - cls.tenant_id = cls.image_member_client.tenant_id - cls.alt_tenant_id = cls.os_alt.image_member_client_v2.tenant_id - - @classmethod - def setup_clients(cls): - super(ImagesMemberRbacTest, cls).setup_clients() - cls.image_client = cls.os_primary.image_client_v2 - cls.image_member_client = cls.os_primary.image_member_client_v2 - cls.alt_image_member_client = cls.os_alt.image_member_client_v2 - - @rbac_rule_validation.action(service="glance", - rules=["add_member"]) - @decorators.idempotent_id('b1b85ace-6484-11e6-881e-080027d0d606') - def test_add_image_member(self): - - """Add image member - - RBAC test for the glance add_member policy - """ - image_id = self.create_image()['id'] - # Toggle role and add image member - with self.override_role(): - self.image_member_client.create_image_member( - image_id, member=self.alt_tenant_id) - - @rbac_rule_validation.action(service="glance", - rules=["delete_member"]) - @decorators.idempotent_id('ba075234-6484-11e6-881e-080027d0d606') - def test_delete_image_member(self): - - """Delete image member - - RBAC test for the glance delete_member policy - """ - image_id = self.create_image()['id'] - self.image_member_client.create_image_member(image_id, - member=self.alt_tenant_id) - # Toggle role and delete image member - with self.override_role(): - self.image_member_client.delete_image_member(image_id, - self.alt_tenant_id) - - @rbac_rule_validation.action(service="glance", - rules=["get_member"], - expected_error_codes=[404]) - @decorators.idempotent_id('c01fd308-6484-11e6-881e-080027d0d606') - def test_show_image_member(self): - - """Show image member - - RBAC test for the glance get_member policy - """ - image_id = self.create_image()['id'] - self.image_member_client.create_image_member( - image_id, - member=self.alt_tenant_id) - - # Toggle role and get image member - with self.override_role(): - self.image_member_client.show_image_member(image_id, - self.alt_tenant_id) - - @rbac_rule_validation.action(service="glance", - rules=["modify_member"]) - @decorators.idempotent_id('ca448bb2-6484-11e6-881e-080027d0d606') - def test_update_image_member(self): - - """Update image member - - RBAC test for the glance modify_member policy - """ - image_id = self.create_image(visibility='shared')['id'] - self.image_member_client.create_image_member( - image_id, - member=self.alt_tenant_id) - # Toggle role and update member - with self.override_role(): - self.alt_image_member_client.update_image_member( - image_id, self.alt_tenant_id, - status='accepted') - - @rbac_rule_validation.action(service="glance", - rules=["get_members"]) - @decorators.idempotent_id('d0a2dc20-6484-11e6-881e-080027d0d606') - def test_list_image_members(self): - - """List image member - - RBAC test for the glance get_members policy - """ - image_id = self.create_image()['id'] - self.image_member_client.create_image_member(image_id, - member=self.alt_tenant_id) - # Toggle role and list image members - with self.override_role(): - self.image_member_client.list_image_members(image_id) diff --git a/patrole_tempest_plugin/tests/api/image/test_images_rbac.py b/patrole_tempest_plugin/tests/api/image/test_images_rbac.py deleted file mode 100644 index 00292b9e..00000000 --- a/patrole_tempest_plugin/tests/api/image/test_images_rbac.py +++ /dev/null @@ -1,233 +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. - -import six - -from oslo_log import log as logging -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 - -LOG = logging.getLogger(__name__) - - -class BasicOperationsImagesRbacTest(rbac_base.BaseV2ImageRbacTest): - - @classmethod - def setup_clients(cls): - super(BasicOperationsImagesRbacTest, cls).setup_clients() - cls.image_client = cls.os_primary.image_client_v2 - - def _create_image(self, **kwargs): - image_name = data_utils.rand_name(self.__class__.__name__ + '-Image') - image = self.create_image(name=image_name, - container_format='bare', - disk_format='raw', - **kwargs) - return image - - def _upload_image(self, image_id): - file_content = data_utils.random_bytes() - LOG.debug("Image file content type %s", - type(file_content)) - image_file = six.BytesIO(file_content) - return self.image_client.store_image_file(image_id, image_file) - - @rbac_rule_validation.action(service="glance", - rules=["add_image"]) - @decorators.idempotent_id('0f148510-63bf-11e6-b348-080027d0d606') - def test_create_image(self): - - """Create Image Test - - RBAC test for the glance create_image endpoint - """ - with self.override_role(): - self._create_image() - - @rbac_rule_validation.action(service="glance", - rules=["upload_image"]) - @decorators.idempotent_id('fdc0c7e2-ad58-4c5a-ba9d-1f6046a5b656') - def test_upload_image(self): - - """Upload Image Test - - RBAC test for the glance upload_image endpoint - """ - image = self._create_image() - - with self.override_role(): - self._upload_image(image['id']) - - @decorators.idempotent_id('f0c268f3-cb51-49aa-9bd5-d30cf647322f') - @rbac_rule_validation.action(service="glance", - rules=["download_image"]) - def test_download_image(self): - - """Download Image Test - - RBAC test for the glance download_image endpoint - """ - image = self._create_image() - self._upload_image(image['id']) - - with self.override_role(): - self.image_client.show_image_file(image['id']) - - @rbac_rule_validation.action(service="glance", - rules=["delete_image"]) - @decorators.idempotent_id('3b5c341e-645b-11e6-ac4f-080027d0d606') - def test_delete_image(self): - - """Delete created image - - RBAC test for the glance delete_image endpoint - """ - image = self._create_image() - - with self.override_role(): - self.image_client.delete_image(image['id']) - self.image_client.wait_for_resource_deletion(image['id']) - - @rbac_rule_validation.action(service="glance", - rules=["get_image"]) - @decorators.idempotent_id('3085c7c6-645b-11e6-ac4f-080027d0d606') - def test_show_image(self): - - """Get created image - - RBAC test for the glance create_image endpoint - """ - image = self._create_image() - - with self.override_role(): - self.image_client.show_image(image['id']) - - @rbac_rule_validation.action(service="glance", - rules=["get_images"]) - @decorators.idempotent_id('bf1a4e94-645b-11e6-ac4f-080027d0d606') - def test_list_images(self): - - """List all the images - - RBAC test for the glance list_images endpoint - """ - with self.override_role(): - self.image_client.list_images()['images'] - - @rbac_rule_validation.action(service="glance", - rules=["modify_image"]) - @decorators.idempotent_id('32ecf48c-645e-11e6-ac4f-080027d0d606') - def test_update_image(self): - - """Update given images - - RBAC test for the glance update_image endpoint - """ - image = self._create_image() - - updated_image_name = data_utils.rand_name( - self.__class__.__name__ + '-image') - with self.override_role(): - self.image_client.update_image(image['id'], [ - dict(replace='/name', value=updated_image_name)]) - - @decorators.idempotent_id('244050d9-1b9a-446a-b3c5-f26f3ba8eb75') - @rbac_rule_validation.action(service="glance", - rules=["modify_image"]) - def test_create_image_tag(self): - - """Create image tag - - RBAC test for the glance add_image_tag endpoint - """ - image = self._create_image() - - with self.override_role(): - self.image_client.add_image_tag( - image['id'], - data_utils.rand_name(self.__class__.__name__ + '-tag')) - - @decorators.idempotent_id('c4a0bf9c-b78b-48c6-a31f-72c95f943c6e') - @rbac_rule_validation.action(service="glance", - rules=["modify_image"]) - def test_delete_image_tag(self): - - """Delete image tag - - RBAC test for the glance delete_image_tag endpoint - """ - image = self._create_image() - tag_name = data_utils.rand_name(self.__class__.__name__ + '-tag') - self.image_client.add_image_tag(image['id'], tag_name) - - with self.override_role(): - self.image_client.delete_image_tag(image['id'], tag_name) - - @rbac_rule_validation.action(service="glance", - rules=["publicize_image"]) - @decorators.idempotent_id('0ea4809c-6461-11e6-ac4f-080027d0d606') - def test_publicize_image(self): - - """Publicize Image Test - - RBAC test for the glance publicize_image endpoint - """ - with self.override_role(): - self._create_image(visibility='public') - - @decorators.idempotent_id('0f2d8427-134a-4d3c-a102-5fcdf5443d09') - @rbac_rule_validation.action(service="glance", - rules=["communitize_image"]) - def test_communitize_image(self): - - """Communitize Image Test - - RBAC test for the glance communitize_image policy - """ - with self.override_role(): - self._create_image(visibility='community') - - @rbac_rule_validation.action(service="glance", - rules=["deactivate"]) - @decorators.idempotent_id('b488458c-65df-11e6-9947-080027824017') - def test_deactivate_image(self): - - """Deactivate Image Test - - RBAC test for the glance deactivate_image endpoint - """ - image = self._create_image() - self._upload_image(image['id']) - - with self.override_role(): - self.image_client.deactivate_image(image['id']) - - @rbac_rule_validation.action(service="glance", - rules=["reactivate"]) - @decorators.idempotent_id('d3fa28b8-65df-11e6-9947-080027824017') - def test_reactivate_image(self): - - """Reactivate Image Test - - RBAC test for the glance reactivate_image endpoint - """ - image = self._create_image() - self._upload_image(image['id']) - - with self.override_role(): - self.image_client.reactivate_image(image['id']) diff --git a/patrole_tempest_plugin/tests/api/network/README.rst b/patrole_tempest_plugin/tests/api/network/README.rst deleted file mode 100644 index 6eaae080..00000000 --- a/patrole_tempest_plugin/tests/api/network/README.rst +++ /dev/null @@ -1,47 +0,0 @@ -.. _network-rbac-tests: - -Network RBAC Tests -================== - -What are these tests? ---------------------- - -These tests are RBAC tests for Neutron and its associated plugins. They are -broken up into the following categories: - -* :ref:`neutron-rbac-tests` -* :ref:`neutron-extension-rbac-tests` - -.. _neutron-rbac-tests: - -Neutron tests -^^^^^^^^^^^^^ - -Neutron RBAC tests inherit from the base class ``BaseNetworkRbacTest``. They -test many of the Neutron policies found in the service's `policy.json file`_. -These tests are gated in many `Zuul jobs`_ (master, n-1, n-2) against many -roles (member, admin). - -.. _neutron-extension-rbac-tests: - -Neutron extension tests -^^^^^^^^^^^^^^^^^^^^^^^ - -The Neutron RBAC plugin tests focus on testing RBAC for various Neutron -extensions, or, stated differently: tests that rely on -`neutron-tempest-plugin`_. - -These tests inherit from the base class ``BaseNetworkExtRbacTest``. If an -extension or plugin is not enabled in the cloud, the corresponding tests are -gracefully skipped. - -.. note:: - - Patrole should import as few dependencies from ``neutron_tempest_plugin`` as - possible (such as ``neutron_tempest_plugin.api.clients`` for the service - clients) because the module is not a `stable interface`_. - -.. _policy.json file: https://git.openstack.org/cgit/openstack/neutron/tree/etc/policy.json?h=12.0.0 -.. _Zuul jobs: https://git.openstack.org/cgit/openstack/patrole/tree/.zuul.yaml -.. _neutron-tempest-plugin: https://git.openstack.org/cgit/openstack/neutron-tempest-plugin -.. _stable interface: https://git.openstack.org/cgit/openstack/neutron-tempest-plugin/plain/neutron_tempest_plugin/README.rst diff --git a/patrole_tempest_plugin/tests/api/network/__init__.py b/patrole_tempest_plugin/tests/api/network/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/patrole_tempest_plugin/tests/api/network/rbac_base.py b/patrole_tempest_plugin/tests/api/network/rbac_base.py deleted file mode 100644 index ca94e5f4..00000000 --- a/patrole_tempest_plugin/tests/api/network/rbac_base.py +++ /dev/null @@ -1,84 +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 oslo_serialization import jsonutils as json - -from tempest.api.network import base as network_base -from tempest.lib.common.utils import test_utils - -from patrole_tempest_plugin import rbac_utils - - -class BaseNetworkRbacTest(rbac_utils.RbacUtilsMixin, - network_base.BaseNetworkTest): - pass - - -class BaseNetworkExtRbacTest(BaseNetworkRbacTest): - """Base class to be used with tests that require neutron-tempest-plugin. - """ - - @classmethod - def get_auth_providers(cls): - """Register auth_provider from neutron-tempest-plugin. - """ - providers = super(BaseNetworkExtRbacTest, cls).get_auth_providers() - if cls.is_neutron_tempest_plugin_available(): - providers.append(cls.ntp_client.auth_provider) - return providers - - @classmethod - def skip_checks(cls): - super(BaseNetworkExtRbacTest, cls).skip_checks() - - if not cls.is_neutron_tempest_plugin_available(): - msg = ("neutron-tempest-plugin not installed.") - raise cls.skipException(msg) - - @classmethod - def is_neutron_tempest_plugin_available(cls): - try: - import neutron_tempest_plugin # noqa - return True - except ImportError: - return False - - @classmethod - def get_client_manager(cls, credential_type=None, roles=None, - force_new=None): - manager = super(BaseNetworkExtRbacTest, cls).get_client_manager( - credential_type=credential_type, - roles=roles, - force_new=force_new - ) - - # Import neutron-tempest-plugin clients - if cls.is_neutron_tempest_plugin_available(): - from neutron_tempest_plugin.api import clients - neutron_tempest_manager = clients.Manager(manager.credentials) - neutron_tempest_manager.auth_provider.set_auth() - cls.ntp_client = neutron_tempest_manager.network_client - - return manager - - @classmethod - def create_service_profile(cls): - service_profile = cls.ntp_client.create_service_profile( - metainfo=json.dumps({'foo': 'bar'})) - service_profile_id = service_profile["service_profile"]["id"] - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.ntp_client.delete_service_profile, service_profile_id) - return service_profile_id diff --git a/patrole_tempest_plugin/tests/api/network/test_address_scope_rbac.py b/patrole_tempest_plugin/tests/api/network/test_address_scope_rbac.py deleted file mode 100644 index 9ca52b4f..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_address_scope_rbac.py +++ /dev/null @@ -1,154 +0,0 @@ -# Copyright 2018 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - - -from tempest.common import utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class AddressScopeExtRbacTest(base.BaseNetworkExtRbacTest): - - @classmethod - def skip_checks(cls): - super(AddressScopeExtRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('address-scope', 'network'): - msg = "address-scope extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(AddressScopeExtRbacTest, cls).resource_setup() - cls.network = cls.create_network() - - def _create_address_scope(self, name=None, **kwargs): - name = name or data_utils.rand_name(self.__class__.__name__) - address_scope = self.ntp_client.create_address_scope(name=name, - ip_version=6, - **kwargs) - address_scope = address_scope['address_scope'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.ntp_client.delete_address_scope, - address_scope['id']) - return address_scope - - @rbac_rule_validation.action(service="neutron", - rules=["create_address_scope"], - expected_error_codes=[403]) - @decorators.idempotent_id('8cb2d6b5-23c2-4648-997b-7a6ae55be3ad') - def test_create_address_scope(self): - - """Create Address Scope - - RBAC test for the neutron create_address_scope policy - """ - with self.override_role(): - self._create_address_scope() - - @rbac_rule_validation.action(service="neutron", - rules=["create_address_scope", - "create_address_scope:shared"], - expected_error_codes=[403, 403]) - @decorators.idempotent_id('0c3f55c0-6ebe-4251-afca-62c5cb4632ca') - def test_create_address_scope_shared(self): - - """Create Shared Address Scope - - RBAC test for the neutron create_address_scope:shared policy - """ - with self.override_role(): - self._create_address_scope(shared=True) - - @rbac_rule_validation.action(service="neutron", - rules=["get_address_scope"], - expected_error_codes=[404]) - @decorators.idempotent_id('a53f741b-46f6-412f-936f-ac920d449da8') - def test_get_address_scope(self): - - """Get Address Scope - - RBAC test for the neutron get_address_scope policy - """ - address_scope = self._create_address_scope() - with self.override_role(): - self.ntp_client.show_address_scope(address_scope['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_address_scope", - "update_address_scope"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('3ce4d606-e067-4ef5-840f-96c680226e73') - def test_update_address_scope(self): - - """Update Address Scope - - RBAC test for neutron update_address_scope policy - """ - address_scope = self._create_address_scope() - name = data_utils.rand_name(self.__class__.__name__) - with self.override_role(): - self.ntp_client.update_address_scope(address_scope['id'], - name=name) - - @rbac_rule_validation.action(service="neutron", - rules=["get_address_scope", - "update_address_scope", - "update_address_scope:shared"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('77d3a9d2-721a-4d9f-9654-6b52f113df85') - def test_update_address_scope_shared(self): - - """Update Shared Address Scope - - RBAC test for neutron update_address_scope:shared policy - """ - address_scope = self._create_address_scope(shared=True) - with self.override_role(): - self.ntp_client.update_address_scope(address_scope['id'], - shared=True) - - @rbac_rule_validation.action(service="neutron", - rules=["get_address_scope", - "delete_address_scope"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('277d8e47-e498-4452-b969-a91f747296ba') - def test_delete_address_scope(self): - - """Delete Address Scope - - RBAC test for neutron delete_address_scope policy - """ - address_scope = self._create_address_scope() - with self.override_role(): - self.ntp_client.delete_address_scope(address_scope['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_address_scope"]) - @decorators.idempotent_id('c093fd34-96ee-4abe-8fa5-916dc29653e3') - def test_list_address_scopes(self): - """List Address Scopes - - RBAC test for the neutron ``list_address_scopes`` function and - the ``get_address_scope`` policy - """ - admin_resource_id = self._create_address_scope()['id'] - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = self.ntp_client.list_address_scopes( - id=admin_resource_id)["address_scopes"] diff --git a/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py b/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py deleted file mode 100644 index 3a341289..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_agents_rbac.py +++ /dev/null @@ -1,285 +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.common import utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class AgentsRbacTest(base.BaseNetworkRbacTest): - - @classmethod - def skip_checks(cls): - super(AgentsRbacTest, cls).skip_checks() - if not utils.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", - rules=["get_agent"], - expected_error_codes=[404]) - def test_show_agent(self): - """Show agent test. - - RBAC test for the neutron get_agent policy - """ - with self.override_role(): - self.agents_client.show_agent(self.agent['id']) - - @decorators.idempotent_id('8ca68fdb-eaf6-4880-af82-ba0982949dec') - @rbac_rule_validation.action(service="neutron", - rules=["get_agent", "update_agent"], - expected_error_codes=[404, 403]) - 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} - - with self.override_role(): - self.agents_client.update_agent(agent_id=self.agent['id'], - agent=agent_status) - - @decorators.idempotent_id('f7a085e2-71b1-4d39-be3e-fea4bc10ccb8') - @rbac_rule_validation.action(service="neutron", rules=["get_agent"]) - def test_list_agents(self): - """List agents test. - - RBAC test for the neutron ``list_agents`` function and - the ``get_agent`` policy - """ - admin_resource_id = self.agent['id'] - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = self.agents_client.list_agents( - id=admin_resource_id)["agents"] - - -class L3AgentSchedulerRbacTest(base.BaseNetworkRbacTest): - - @classmethod - def skip_checks(cls): - super(L3AgentSchedulerRbacTest, cls).skip_checks() - if not utils.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", - rules=["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 - """ - with self.override_role(): - 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", - rules=["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 - """ - with self.override_role(): - 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", - rules=["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']) - - with self.override_role(): - 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 utils.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", - rules=["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 - """ - with self.override_role(): - 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", - rules=["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']) - - with self.override_role(): - 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", - rules=["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. - - with self.override_role(): - self.agents_client.delete_network_from_dhcp_agent( - self.agent['id'], network_id=network_id) - - -class L3AgentsExtRbacTest(base.BaseNetworkExtRbacTest): - - @classmethod - def skip_checks(cls): - super(L3AgentsExtRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('l3_agent_scheduler', 'network'): - msg = "l3_agent_scheduler extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(L3AgentsExtRbacTest, cls).resource_setup() - name = data_utils.rand_name(cls.__name__ + '-Router') - cls.router = cls.ntp_client.create_router(name)['router'] - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.ntp_client.delete_router, - cls.router['id']) - - @decorators.idempotent_id('5d2bbdbc-40a5-43d2-828a-84dc93bcd321') - @rbac_rule_validation.action(service="neutron", - rules=["get_l3-agents"]) - def test_list_l3_agents_on_router(self): - """List L3 agents on router test. - - RBAC test for the neutron get_l3-agents policy - """ - with self.override_role(): - # NOTE: It is not empty list since it's a special case where - # policy.enforce is called from the controller. - self.ntp_client.list_l3_agents_hosting_router(self.router['id']) diff --git a/patrole_tempest_plugin/tests/api/network/test_auto_allocated_topology_rbac.py b/patrole_tempest_plugin/tests/api/network/test_auto_allocated_topology_rbac.py deleted file mode 100644 index aee5e99f..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_auto_allocated_topology_rbac.py +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright 2018 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.common import utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class AutoAllocationTopologyExtRbacTest(base.BaseNetworkExtRbacTest): - - @classmethod - def skip_checks(cls): - super(AutoAllocationTopologyExtRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('auto-allocated-topology', - 'network'): - msg = "auto-allocated-topology extension not enabled." - raise cls.skipException(msg) - - @decorators.idempotent_id('299CB831-F6B2-49CA-882B-E9A8E36945A2') - @rbac_rule_validation.action(service="neutron", - rules=["get_auto_allocated_topology"], - expected_error_codes=[404]) - def test_show_auto_allocated_topology(self): - """Test show auto_allocated_topology. - - RBAC test for the neutron "get_auto_allocated_topology" policy - """ - with self.override_role(): - self.ntp_client.get_auto_allocated_topology( - tenant_id=self.os_primary.credentials.tenant_id) - - # Auto allocated topology has to be deleted here because - # Neutron provisions new auto allocated topology for a project - # when: - # - receives GET request for auto allocated topology and - # - there is no auto allocated topology already associated - # with the project. - self.ntp_client.delete_auto_allocated_topology( - tenant_id=self.os_primary.credentials.tenant_id) - - def _ensure_network_not_in_use(cls, network_id): - ports = cls.ntp_client.list_ports(network_id=network_id)["ports"] - - # Every subnet within network should have a router interface - expected_ports_count = len( - cls.ntp_client.show_network(network_id)["network"]["subnets"]) - # Every network should have a single dhcp interface - expected_ports_count += 1 - - if len(ports) != expected_ports_count: - msg = "Auto Allocated Topology in use." - raise cls.skipException(msg) - - @decorators.idempotent_id('A0606AFE-065E-4C09-8E51-58EE7FBA30A2') - @decorators.attr(type='slow') - @rbac_rule_validation.action(service="neutron", - rules=["get_auto_allocated_topology", - "delete_auto_allocated_topology"], - expected_error_codes=[404, 403]) - def test_delete_auto_allocated_topology(self): - """Test delete auto_allocated_topology. - - RBAC test for the neutron "delete_auto_allocated_topology" policy - """ - tenant_id = self.os_primary.credentials.tenant_id - net_id = self.ntp_client.get_auto_allocated_topology( - tenant_id=tenant_id)["auto_allocated_topology"]["id"] - - self._ensure_network_not_in_use(net_id) - - with self.override_role(): - self.ntp_client.delete_auto_allocated_topology( - tenant_id=self.os_primary.credentials.tenant_id) diff --git a/patrole_tempest_plugin/tests/api/network/test_availability_zones_rbac.py b/patrole_tempest_plugin/tests/api/network/test_availability_zones_rbac.py deleted file mode 100644 index b5331e3b..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_availability_zones_rbac.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright 2018 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.common import utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class AvailabilityZoneExtRbacTest(base.BaseNetworkExtRbacTest): - - @classmethod - def skip_checks(cls): - super(AvailabilityZoneExtRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('availability_zone', - 'network'): - msg = "network_availability_zone extension not enabled." - raise cls.skipException(msg) - - @rbac_rule_validation.action(service="neutron", - rules=["get_availability_zone"]) - @decorators.idempotent_id('3c521be8-c32e-11e8-a611-080027758b73') - def test_list_availability_zone_rbac(self): - - """List all available zones. - - RBAC test for the neutron ``list_availability_zones`` - function and the ``get_availability_zone`` policy - """ - admin_resources = (self.ntp_client.list_availability_zones() - ["availability_zones"]) - with self.override_role_and_validate_list( - admin_resources=admin_resources) as ctx: - ctx.resources = (self.ntp_client.list_availability_zones() - ['availability_zones']) diff --git a/patrole_tempest_plugin/tests/api/network/test_dscp_marking_rule_rbac.py b/patrole_tempest_plugin/tests/api/network/test_dscp_marking_rule_rbac.py deleted file mode 100644 index 444dcd29..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_dscp_marking_rule_rbac.py +++ /dev/null @@ -1,121 +0,0 @@ -# Copyright 2018 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.common import utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class DscpMarkingRuleExtRbacTest(base.BaseNetworkExtRbacTest): - - @classmethod - def skip_checks(cls): - super(DscpMarkingRuleExtRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('qos', 'network'): - msg = "qos extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(DscpMarkingRuleExtRbacTest, cls).resource_setup() - name = data_utils.rand_name(cls.__name__ + '-qos') - cls.policy_id = cls.ntp_client.create_qos_policy( - name=name)["policy"]["id"] - cls.addClassResourceCleanup( - cls.ntp_client.delete_qos_policy, cls.policy_id) - - def create_policy_dscp_marking_rule(cls): - rule = cls.ntp_client.create_dscp_marking_rule(cls.policy_id, 10) - rule_id = rule['dscp_marking_rule']['id'] - cls.addCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.ntp_client.delete_dscp_marking_rule, cls.policy_id, rule_id) - return rule_id - - @decorators.idempotent_id('2717AB75-E4CF-4CA4-AF04-5BEC0C808AA5') - @rbac_rule_validation.action(service="neutron", - rules=["create_policy_dscp_marking_rule"]) - def test_create_policy_dscp_marking_rule(self): - """Create policy_dscp_marking_rule. - - RBAC test for the neutron "create_policy_dscp_marking_rule" policy - """ - - with self.override_role(): - self.create_policy_dscp_marking_rule() - - @decorators.idempotent_id('3D68F50E-B948-4B25-8A72-F6F4890BBC6F') - @rbac_rule_validation.action(service="neutron", - rules=["get_policy_dscp_marking_rule"], - expected_error_codes=[404]) - def test_show_policy_dscp_marking_rule(self): - """Show policy_dscp_marking_rule. - - RBAC test for the neutron "get_policy_dscp_marking_rule" policy - """ - rule_id = self.create_policy_dscp_marking_rule() - - with self.override_role(): - self.ntp_client.show_dscp_marking_rule(self.policy_id, rule_id) - - @decorators.idempotent_id('33830794-8731-45C3-BC97-17718555DD7C') - @rbac_rule_validation.action(service="neutron", - rules=["get_policy_dscp_marking_rule", - "update_policy_dscp_marking_rule"], - expected_error_codes=[404, 403]) - def test_update_policy_dscp_marking_rule(self): - """Update policy_dscp_marking_rule. - - RBAC test for the neutron "update_policy_dscp_marking_rule" policy - """ - rule_id = self.create_policy_dscp_marking_rule() - - with self.override_role(): - self.ntp_client.update_dscp_marking_rule( - self.policy_id, rule_id, dscp_mark=16) - - @decorators.idempotent_id('7BF564DD-3648-4D12-8A8B-6D5E576D1843') - @rbac_rule_validation.action(service="neutron", - rules=["get_policy_dscp_marking_rule", - "delete_policy_dscp_marking_rule"], - expected_error_codes=[404, 403]) - def test_delete_policy_dscp_marking_rule(self): - """Delete policy_dscp_marking_rule. - - RBAC test for the neutron "delete_policy_dscp_marking_rule" policy - """ - rule_id = self.create_policy_dscp_marking_rule() - - with self.override_role(): - self.ntp_client.delete_dscp_marking_rule(self.policy_id, rule_id) - - @decorators.idempotent_id('c012fd4f-3a3e-4af4-9075-dd3e170daecd') - @rbac_rule_validation.action(service="neutron", - rules=["get_policy_dscp_marking_rule"]) - def test_list_policy_dscp_marking_rules(self): - """List policy_dscp_marking_rules. - - RBAC test for the neutron ``list_dscp_marking_rules`` function and - the ``get_policy_dscp_marking_rule`` policy - """ - admin_resource_id = self.create_policy_dscp_marking_rule() - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = self.ntp_client.list_dscp_marking_rules( - policy_id=self.policy_id)["dscp_marking_rules"] diff --git a/patrole_tempest_plugin/tests/api/network/test_flavor_service_profile_rbac.py b/patrole_tempest_plugin/tests/api/network/test_flavor_service_profile_rbac.py deleted file mode 100644 index 0ada6ace..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_flavor_service_profile_rbac.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2018 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class FlavorsServiceProfileExtRbacTest(base.BaseNetworkExtRbacTest): - @classmethod - def resource_setup(cls): - super(FlavorsServiceProfileExtRbacTest, cls).resource_setup() - providers = cls.ntp_client.list_service_providers() - if not providers["service_providers"]: - raise cls.skipException("No service_providers available.") - cls.service_type = providers["service_providers"][0]["service_type"] - - cls.flavor_id = cls.create_flavor() - cls.service_profile_id = cls.create_service_profile() - - @classmethod - def create_flavor(cls): - flavor = cls.ntp_client.create_flavor(service_type=cls.service_type) - flavor_id = flavor["flavor"]["id"] - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.ntp_client.delete_flavor, flavor_id) - return flavor_id - - def create_flavor_service_profile(self, flavor_id, service_profile_id): - self.ntp_client.create_flavor_service_profile( - flavor_id, service_profile_id) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.ntp_client.delete_flavor_service_profile, - flavor_id, service_profile_id) - - @decorators.idempotent_id('aa84b4c5-0dd6-4c34-aa81-3a76507f9b81') - @rbac_rule_validation.action(service="neutron", - rules=["create_flavor_service_profile"]) - def test_create_flavor_service_profile(self): - """Create flavor_service_profile. - - RBAC test for the neutron "create_flavor_service_profile" policy - """ - with self.override_role(): - self.create_flavor_service_profile(self.flavor_id, - self.service_profile_id) - - @decorators.idempotent_id('3b680d9e-946a-4670-ab7f-0e4576675833') - @rbac_rule_validation.action(service="neutron", - rules=["delete_flavor_service_profile"]) - def test_delete_flavor_service_profile(self): - """Delete flavor_service_profile. - - RBAC test for the neutron "delete_flavor_service_profile" policy - """ - self.create_flavor_service_profile(self.flavor_id, - self.service_profile_id) - - with self.override_role(): - self.ntp_client.delete_flavor_service_profile( - self.flavor_id, self.service_profile_id) diff --git a/patrole_tempest_plugin/tests/api/network/test_flavors_rbac.py b/patrole_tempest_plugin/tests/api/network/test_flavors_rbac.py deleted file mode 100644 index 67e0d1e6..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_flavors_rbac.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright 2018 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class FlavorsExtRbacTest(base.BaseNetworkExtRbacTest): - - @classmethod - def resource_setup(cls): - super(FlavorsExtRbacTest, cls).resource_setup() - providers = cls.ntp_client.list_service_providers() - if not providers["service_providers"]: - raise cls.skipException("No service_providers available.") - cls.service_type = providers["service_providers"][0]["service_type"] - - @decorators.idempotent_id('2632a61b-831e-4da5-82c8-a5f7d448589b') - @rbac_rule_validation.action(service="neutron", - rules=["create_flavor"]) - def test_create_flavor(self): - """Create flavor. - - RBAC test for the neutron "create_flavor" policy - """ - with self.override_role(): - flavor = self.ntp_client.create_flavor( - service_type=self.service_type) - - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.ntp_client.delete_flavor, flavor["flavor"]["id"]) - - @decorators.idempotent_id('9c53164c-117d-4b44-a5cb-96f08386513f') - @rbac_rule_validation.action(service="neutron", - rules=["get_flavor", - "update_flavor"], - expected_error_codes=[404, 403]) - def test_update_flavor(self): - """Update flavor. - - RBAC test for the neutron "update_flavor" policy - """ - flavor = self.ntp_client.create_flavor(service_type=self.service_type) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.ntp_client.delete_flavor, flavor["flavor"]["id"]) - - name = data_utils.rand_name(self.__class__.__name__ + '-Flavor') - with self.override_role(): - self.ntp_client.update_flavor(flavor["flavor"]["id"], name=name) - - @decorators.idempotent_id('1de15f9e-5080-4259-ab41-e230bb312de8') - @rbac_rule_validation.action(service="neutron", - rules=["get_flavor", - "delete_flavor"], - expected_error_codes=[404, 403]) - def test_delete_flavor(self): - """Delete flavor. - - RBAC test for the neutron "delete_flavor" policy - """ - flavor = self.ntp_client.create_flavor(service_type=self.service_type) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.ntp_client.delete_flavor, flavor["flavor"]["id"]) - - with self.override_role(): - self.ntp_client.delete_flavor(flavor["flavor"]["id"]) - - @decorators.idempotent_id('c2baf35f-e6c1-4833-9114-aadd9b1f6aaa') - @rbac_rule_validation.action(service="neutron", - rules=["get_flavor"], - expected_error_codes=[404]) - def test_show_flavor(self): - """Show flavor. - - RBAC test for the neutron "get_flavor" policy - """ - flavor = self.ntp_client.create_flavor(service_type=self.service_type) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.ntp_client.delete_flavor, flavor["flavor"]["id"]) - - with self.override_role(): - self.ntp_client.show_flavor(flavor["flavor"]["id"]) - - @decorators.idempotent_id('ab10bd5d-987e-4255-966f-947670ffd0fa') - @rbac_rule_validation.action(service="neutron", - rules=["get_flavor"]) - def test_list_flavors(self): - """List flavors. - - RBAC test for the neutron "get_flavor" policy for "list_flavors" action - """ - flavor = self.ntp_client.create_flavor(service_type=self.service_type) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.ntp_client.delete_flavor, flavor["flavor"]["id"]) - - with self.override_role_and_validate_list( - admin_resource_id=flavor["flavor"]["id"] - ) as ctx: - ctx.resources = self.ntp_client.list_flavors()['flavors'] diff --git a/patrole_tempest_plugin/tests/api/network/test_floating_ips_rbac.py b/patrole_tempest_plugin/tests/api/network/test_floating_ips_rbac.py deleted file mode 100644 index b580cb05..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_floating_ips_rbac.py +++ /dev/null @@ -1,146 +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. - -import netaddr - -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - -CONF = config.CONF - - -class FloatingIpsRbacTest(base.BaseNetworkRbacTest): - - @classmethod - def resource_setup(cls): - super(FloatingIpsRbacTest, cls).resource_setup() - # Create an external network for floating ip creation. - cls.fip_extnet = cls.create_network(**{'router:external': True}) - # Update router:external attribute to False for proper subnet resource - # cleanup by base class. - cls.fip_extnet_id = cls.fip_extnet['id'] - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.networks_client.update_network, cls.fip_extnet_id, - **{'router:external': False}) - - # Create a subnet for the external network - cls.cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) - cls.create_subnet(cls.fip_extnet, - cidr=cls.cidr, - mask_bits=24) - - def _create_floatingip(self, floating_ip_address=None): - if floating_ip_address is not None: - body = self.floating_ips_client.create_floatingip( - floating_network_id=self.fip_extnet_id, - floating_ip_address=floating_ip_address) - else: - body = self.floating_ips_client.create_floatingip( - floating_network_id=self.fip_extnet_id) - - floating_ip = body['floatingip'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.floating_ips_client.delete_floatingip, - floating_ip['id']) - - return floating_ip - - @rbac_rule_validation.action(service="neutron", - rules=["create_floatingip"]) - @decorators.idempotent_id('f8f7474c-b8a5-4174-af84-73097d6ced38') - def test_create_floating_ip(self): - """Create floating IP. - - RBAC test for the neutron create_floatingip policy - """ - with self.override_role(): - self._create_floatingip() - - @rbac_rule_validation.action( - service="neutron", - rules=["create_floatingip", - "create_floatingip:floating_ip_address"]) - @decorators.idempotent_id('a8bb826a-403d-4130-a55d-120a0a660806') - def test_create_floating_ip_floatingip_address(self): - """Create floating IP with address. - - RBAC test for the neutron create_floatingip:floating_ip_address policy - """ - fip = str(netaddr.IPAddress(self.cidr) + 10) - - with self.override_role(): - self._create_floatingip(floating_ip_address=fip) - - @rbac_rule_validation.action(service="neutron", - rules=["get_floatingip", "update_floatingip"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('2ab1b060-19f8-4ef6-a838-e2ab7b377c63') - def test_update_floating_ip(self): - """Update floating IP. - - RBAC test for the neutron update_floatingip policy - """ - floating_ip = self._create_floatingip() - with self.override_role(): - # Associate floating IP to the other port - self.floating_ips_client.update_floatingip( - floating_ip['id'], port_id=None) - - @rbac_rule_validation.action(service="neutron", - rules=["get_floatingip"], - expected_error_codes=[404]) - @decorators.idempotent_id('f8846fd0-c976-48fe-a148-105303931b32') - def test_show_floating_ip(self): - """Show floating IP. - - RBAC test for the neutron get_floatingip policy - """ - floating_ip = self._create_floatingip() - with self.override_role(): - # Show floating IP - self.floating_ips_client.show_floatingip(floating_ip['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_floatingip", "delete_floatingip"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('2611b068-30d4-4241-a78f-1b801a14db7e') - def test_delete_floating_ip(self): - """Delete floating IP. - - RBAC test for the neutron delete_floatingip policy - """ - floating_ip = self._create_floatingip() - with self.override_role(): - # Delete the floating IP - self.floating_ips_client.delete_floatingip(floating_ip['id']) - - @rbac_rule_validation.action(service="neutron", rules=["get_floatingip"]) - @decorators.idempotent_id('824965e3-8be8-46e2-be64-0d793533ad20') - def test_list_floating_ips(self): - """List Floating IPs. - - RBAC test for the neutron ``list_floatingips`` function and - the ``get_floatingip`` policy - """ - admin_resource_id = self._create_floatingip()['id'] - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = self.floating_ips_client.list_floatingips( - id=admin_resource_id)["floatingips"] diff --git a/patrole_tempest_plugin/tests/api/network/test_metering_label_rules_rbac.py b/patrole_tempest_plugin/tests/api/network/test_metering_label_rules_rbac.py deleted file mode 100644 index c0d226d9..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_metering_label_rules_rbac.py +++ /dev/null @@ -1,120 +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.common import 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 patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - -CONF = config.CONF - - -class MeteringLabelRulesRbacTest(base.BaseNetworkRbacTest): - - @classmethod - def skip_checks(cls): - super(MeteringLabelRulesRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('metering', 'network'): - msg = "metering extension not enabled." - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(MeteringLabelRulesRbacTest, cls).setup_clients() - cls.metering_labels_client = cls.os_primary.metering_labels_client - cls.metering_label_rules_client = \ - cls.os_primary.metering_label_rules_client - - @classmethod - def resource_setup(cls): - super(MeteringLabelRulesRbacTest, cls).resource_setup() - body = cls.metering_labels_client.create_metering_label( - name=data_utils.rand_name(cls.__name__)) - cls.label = body['metering_label'] - cls.addClassResourceCleanup( - cls.metering_labels_client.delete_metering_label, cls.label['id']) - - def _create_metering_label_rule(self, label): - body = self.metering_label_rules_client.create_metering_label_rule( - metering_label_id=label['id'], - remote_ip_prefix=CONF.network.project_network_cidr, - direction="ingress") - label_rule = body['metering_label_rule'] - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.metering_label_rules_client.delete_metering_label_rule, - label_rule['id']) - return label_rule - - @rbac_rule_validation.action(service="neutron", - rules=["create_metering_label_rule"]) - @decorators.idempotent_id('81e81776-9d41-4d5e-b5c4-59d5c54a31ad') - def test_create_metering_label_rule(self): - """Create metering label rule. - - RBAC test for the neutron create_metering_label_rule policy - """ - with self.override_role(): - self._create_metering_label_rule(self.label) - - @rbac_rule_validation.action(service="neutron", - rules=["get_metering_label_rule"], - expected_error_codes=[404]) - @decorators.idempotent_id('e21b40c3-d44d-412f-84ea-836ca8603bcb') - def test_show_metering_label_rule(self): - """Show metering label rule. - - RBAC test for the neutron get_metering_label_rule policy - """ - label_rule = self._create_metering_label_rule(self.label) - with self.override_role(): - self.metering_label_rules_client.show_metering_label_rule( - label_rule['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_metering_label_rule", - "delete_metering_label_rule"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('e3adc88c-05c0-43a7-8e32-63947ae4890e') - def test_delete_metering_label_rule(self): - """Delete metering label rule. - - RBAC test for the neutron delete_metering_label_rule policy - """ - label_rule = self._create_metering_label_rule(self.label) - with self.override_role(): - self.metering_label_rules_client.delete_metering_label_rule( - label_rule['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_metering_label_rule"]) - @decorators.idempotent_id('eaaf9eb5-ee53-4b6b-a4d3-a721dd39bc40') - def test_list_metering_label_rules(self): - """List metering label rules. - - RBAC test for the neutron ``list_metering_label_rules`` function and - the ``get_metering_label_rule`` policy - """ - admin_resource_id = self._create_metering_label_rule(self.label)['id'] - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = ( - self.metering_label_rules_client. - list_metering_label_rules(id=admin_resource_id) - ["metering_label_rules"]) diff --git a/patrole_tempest_plugin/tests/api/network/test_metering_labels_rbac.py b/patrole_tempest_plugin/tests/api/network/test_metering_labels_rbac.py deleted file mode 100644 index 63c47444..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_metering_labels_rbac.py +++ /dev/null @@ -1,102 +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.common import utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class MeteringLabelsRbacTest(base.BaseNetworkRbacTest): - - @classmethod - def skip_checks(cls): - super(MeteringLabelsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('metering', 'network'): - msg = "metering extension not enabled." - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(MeteringLabelsRbacTest, cls).setup_clients() - cls.metering_labels_client = cls.os_primary.metering_labels_client - - def _create_metering_label(self): - body = self.metering_labels_client.create_metering_label( - name=data_utils.rand_name(self.__class__.__name__)) - - label = body['metering_label'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.metering_labels_client.delete_metering_label, - label['id']) - return label - - @rbac_rule_validation.action(service="neutron", - rules=["create_metering_label"]) - @decorators.idempotent_id('e8cfc8b8-c159-48f0-93b3-591625a02f8b') - def test_create_metering_label(self): - """Create metering label. - - RBAC test for the neutron "create_metering_label" policy - """ - with self.override_role(): - self._create_metering_label() - - @rbac_rule_validation.action(service="neutron", - rules=["get_metering_label"], - expected_error_codes=[404]) - @decorators.idempotent_id('c57f6636-c702-4755-8eac-5e73bc1f7d14') - def test_show_metering_label(self): - """Show metering label. - - RBAC test for the neutron "get_metering_label" policy - """ - label = self._create_metering_label() - with self.override_role(): - self.metering_labels_client.show_metering_label(label['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_metering_label", - "delete_metering_label"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('1621ccfe-2e3f-4d16-98aa-b620f9d00404') - def test_delete_metering_label(self): - """Delete metering label. - - RBAC test for the neutron "delete_metering_label" policy - """ - label = self._create_metering_label() - with self.override_role(): - self.metering_labels_client.delete_metering_label(label['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_metering_label"]) - @decorators.idempotent_id('d60d72b0-cb8f-44db-b10b-5092fa01cb0e') - def test_list_metering_labels(self): - """List metering label. - - RBAC test for the neutron ``list_metering_labels`` function and - the ``get_metering_label`` policy - """ - admin_resource_id = self._create_metering_label()['id'] - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = ( - self.metering_labels_client. - list_metering_labels(id=admin_resource_id) - ["metering_labels"]) diff --git a/patrole_tempest_plugin/tests/api/network/test_network_ip_availability_rbac.py b/patrole_tempest_plugin/tests/api/network/test_network_ip_availability_rbac.py deleted file mode 100644 index 3e33df63..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_network_ip_availability_rbac.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2018 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.common import utils -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class NetworkIpAvailabilityExtRbacTest(base.BaseNetworkExtRbacTest): - @classmethod - def skip_checks(cls): - super(NetworkIpAvailabilityExtRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('network-ip-availability', - 'network'): - msg = "network-ip-availability extension not enabled." - raise cls.skipException(msg) - - @rbac_rule_validation.action(service="neutron", - rules=["get_network_ip_availability"], - expected_error_codes=[404]) - @decorators.idempotent_id('93edc5ed-385f-4a8e-9b15-4370ec608253') - def test_get_network_ip_availability(self): - """Get network availability - - RBAC test for the neutron get_network_ip_availability policy - """ - - network_name = data_utils.rand_name( - self.__class__.__name__ + '-Network') - network = self.create_network(network_name=network_name) - - with self.override_role(): - self.ntp_client.show_network_ip_availability(network['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_network_ip_availability"]) - @decorators.idempotent_id('d4ceb5f0-2342-4412-a617-4e1aaf7fcaf0') - def test_get_network_ip_availabilities(self): - """List network ip availabilities - - RBAC test for the neutron "get_network_ip_availability" policy - for the "list_network_ip_availabilities" action. - """ - admin_resources = (self.ntp_client.list_network_ip_availabilities() - ["network_ip_availabilities"]) - with self.override_role_and_validate_list( - admin_resources=admin_resources) as ctx: - ctx.resources = (self.ntp_client.list_network_ip_availabilities() - ["network_ip_availabilities"]) diff --git a/patrole_tempest_plugin/tests/api/network/test_network_segments_rbac.py b/patrole_tempest_plugin/tests/api/network/test_network_segments_rbac.py deleted file mode 100644 index aa752ea7..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_network_segments_rbac.py +++ /dev/null @@ -1,121 +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 oslo_log import log - -from tempest.common import utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - -LOG = log.getLogger(__name__) - - -class NetworkSegmentsRbacTest(base.BaseNetworkRbacTest): - - @classmethod - def skip_checks(cls): - super(NetworkSegmentsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('multi-provider', 'network'): - msg = "multi-provider extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(NetworkSegmentsRbacTest, cls).resource_setup() - # Find the network type that is supported by the current cloud by - # checking which network type other networks currently have. This is - # done because there is no tempest.conf option enumerating supported - # network types. - networks = cls.networks_client.list_networks()['networks'] - network_types = [n['provider:network_type'] for n in networks - if n['provider:network_type'] != 'flat'] - if not network_types: - raise cls.skipException( - 'Could not find network with provider:network_type that is ' - 'not "flat".') - cls.network_type = network_types[0] - - def _create_network_segments(self): - segments = [{'provider:network_type': self.network_type}, - {'provider:network_type': self.network_type}] - - body = self.networks_client.create_network( - name=data_utils.rand_name(self.__class__.__name__), - segments=segments) - network = body['network'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.networks_client.delete_network, - network['id']) - return network - - @rbac_rule_validation.action(service="neutron", - rules=["create_network", - "create_network:segments"]) - @decorators.idempotent_id('9e1d0c3d-92e3-40e3-855e-bfbb72ea6e0b') - def test_create_network_segments(self): - """Create network with segments. - - RBAC test for the neutron create_network:segments policy - """ - with self.override_role(): - self._create_network_segments() - - @rbac_rule_validation.action(service="neutron", - rules=["get_network", "update_network", - "update_network:segments"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('0f45232a-7b59-4bb1-9a91-db77d0a8cc9b') - def test_update_network_segments(self): - """Update network segments. - - RBAC test for the neutron update_network:segments policy - """ - network = self._create_network_segments() - new_segments = [{'provider:network_type': self.network_type}] - - with self.override_role(): - self.networks_client.update_network(network['id'], - segments=new_segments) - - @rbac_rule_validation.action(service="neutron", - rules=["get_network", - "get_network:segments"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('094ff9b7-0c3b-4515-b19b-b9d2031337bd') - def test_show_network_segments(self): - """Show network segments. - - RBAC test for the neutron get_network:segments policy - """ - network = self._create_network_segments() - - with self.override_role(): - body = self.networks_client.show_network(network['id'], - fields='segments') - response_network = body['network'] - - # If user does not have access to the network segments attribute, - # no NotFound or Forbidden exception are thrown. Instead, - # the response will have an empty network body only. - if not response_network: - LOG.info("NotFound or Forbidden exception are not thrown when " - "role doesn't have access to the endpoint. Instead, " - "the response will have an empty network body.") - raise rbac_exceptions.RbacEmptyResponseBody() diff --git a/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py b/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py deleted file mode 100644 index a024b2c2..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_networks_rbac.py +++ /dev/null @@ -1,479 +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. - -import netaddr - -from tempest.common import utils -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - -CONF = config.CONF - - -class NetworksRbacTest(base.BaseNetworkRbacTest): - - @classmethod - def resource_setup(cls): - super(NetworksRbacTest, cls).resource_setup() - cls.network = cls.create_network() - cls.cidr = netaddr.IPNetwork(CONF.network.project_network_cidr) - cls.subnet = cls.create_subnet( - cls.network, cidr=cls.cidr, mask_bits=24, enable_dhcp=False) - - def _create_network(self, - router_external=None, - router_private=None, - provider_network_type=None, - provider_physical_network=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__ + '-Network') - network = self.create_network(network_name=network_name, **kwargs) - return network - - def _update_network(self, - net_id=None, - admin=None, - shared_network=None, - router_external=None, - router_private=None, - provider_network_type=None, - provider_physical_network=None, - provider_segmentation_id=None, - segments=None, - **kwargs): - if not net_id: - net_id = self.network['id'] - - if admin is not None: - kwargs['admin_state_up'] = admin - if shared_network is not None: - kwargs['shared'] = shared_network - 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 - if segments is not None: - kwargs['segments'] = segments - - updated_network = self.networks_client.update_network( - net_id, **kwargs)['network'] - return updated_network - - @rbac_rule_validation.action(service="neutron", - rules=["create_network"]) - @decorators.idempotent_id('95b9baab-1ece-4e2b-89c8-8d671d974e54') - def test_create_network(self): - - """Create Network Test - - RBAC test for the neutron create_network policy - """ - with self.override_role(): - self._create_network() - - @rbac_rule_validation.action(service="neutron", - rules=["create_network", - "create_network:is_default"]) - @decorators.idempotent_id('28602661-5ac7-407e-b739-e393f619f5e3') - def test_create_network_is_default(self): - - """Create Is Default Network Test - - RBAC test for the neutron create_network:is_default policy - """ - try: - with self.override_role(): - self._create_network(is_default=True) - except lib_exc.Conflict as exc: - # A default network might already exist - self.assertIn('A default external network already exists', - str(exc)) - - @rbac_rule_validation.action(service="neutron", - rules=["create_network", - "create_network:shared"]) - @decorators.idempotent_id('ccabf2a9-28c8-44b2-80e6-ffd65d43eef2') - def test_create_network_shared(self): - - """Create Shared Network Test - - RBAC test for the neutron create_network:shared policy - """ - with self.override_role(): - self._create_network(shared=True) - - @utils.requires_ext(extension='external-net', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["create_network", - "create_network:router:external"]) - @decorators.idempotent_id('51adf2a7-739c-41e0-8857-3b4c460cbd24') - def test_create_network_router_external(self): - - """Create External Router Network Test - - RBAC test for the neutron create_network:router:external policy - """ - with self.override_role(): - self._create_network(router_external=True) - - @utils.requires_ext(extension='provider', service='network') - @rbac_rule_validation.action( - service="neutron", - rules=["create_network", - "create_network:provider:physical_network"]) - @decorators.idempotent_id('76783fed-9ff3-4499-a0d1-82d99eec364e') - def test_create_network_provider_physical_network(self): - - """Create Network Physical Network Provider Test - - RBAC test for neutron create_network:provider:physical_network policy - """ - try: - with self.override_role(): - self._create_network(provider_physical_network='provider', - provider_network_type='flat') - except lib_exc.BadRequest as exc: - # There probably won't be a physical network called 'provider', but - # we aren't testing state of the network - self.assertIn("Invalid input for operation: physical_network " + - "'provider' unknown for flat provider network.", - str(exc)) - - @utils.requires_ext(extension='provider', service='network') - @rbac_rule_validation.action( - service="neutron", - rules=["create_network", - "create_network:provider:network_type"]) - @decorators.idempotent_id('3c42f7b8-b80c-44ef-8fa4-69ec4b1836bc') - def test_create_network_provider_network_type(self): - - """Create Provider Network Test - - RBAC test for the neutron create_network:provider:network_type policy - """ - with self.override_role(): - self._create_network(provider_physical_network='public', - provider_network_type='vlan') - - @utils.requires_ext(extension='provider', service='network') - @rbac_rule_validation.action( - service="neutron", - rules=["create_network", - "create_network:provider:segmentation_id"]) - @decorators.idempotent_id('b9decb7b-68ef-4504-b99b-41edbf7d2af5') - def test_create_network_provider_segmentation_id(self): - - """Create Provider Network Segmentation Id Test - - RBAC test for the neutron create_network:provider:segmentation_id - """ - with self.override_role(): - self._create_network(provider_physical_network='public', - provider_network_type='vlan', - provider_segmentation_id=200) - - @rbac_rule_validation.action(service="neutron", - rules=["get_network", "update_network"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('6485bb4e-e110-48ae-83e1-3ec8b40c3107') - def test_update_network(self): - - """Update Network Test - - RBAC test for the neutron update_network policy - """ - updated_name = data_utils.rand_name( - self.__class__.__name__ + '-Network') - - with self.override_role(): - self._update_network(name=updated_name) - - @rbac_rule_validation.action(service="neutron", - rules=["get_network", - "update_network", - "update_network:shared"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('37ea3e33-47d9-49fc-9bba-1af98fbd46d6') - def test_update_network_shared(self): - - """Update Shared Network Test - - RBAC test for the neutron update_network:shared policy - """ - with self.override_role(): - self._update_network(shared_network=True) - self.addCleanup(self._update_network, shared_network=False) - - @utils.requires_ext(extension='external-net', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["get_network", - "update_network", - "update_network:router:external"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('34884c22-499b-4960-97f1-e2ed8522a9c9') - def test_update_network_router_external(self): - - """Update Network Router External Test - - RBAC test for the neutron update_network:router:external policy - """ - network = self._create_network() - with self.override_role(): - self._update_network(net_id=network['id'], router_external=True) - - @decorators.skip_because(bug='2005489', bug_type='storyboard') - @utils.requires_ext(extension='provider', service='network') - @rbac_rule_validation.action( - service="neutron", - rules=["get_network", - "update_network", - "update_network:provider:network_type"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('d064ef96-662b-47b6-94b7-9106dcd7ba8c') - def test_update_network_provider_network_type(self): - - """Update Network Provider Network Type Test - - RBAC test for neutron update_network:provider:network_type policy - """ - try: - with self.override_role(): - self._update_network(self.network['id'], - provider_network_type='vlan') - except lib_exc.BadRequest as exc: - # Per the api documentation, most plugins don't support updating - # provider attributes - self.assertIn( - "Plugin does not support updating provider attributes", - str(exc)) - - @decorators.skip_because(bug='2005489', bug_type='storyboard') - @utils.requires_ext(extension='provider', service='network') - @rbac_rule_validation.action( - service="neutron", - rules=["get_network", - "update_network", - "update_network:provider:physical_network"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('e3a55660-f75c-494e-a1b1-a8b36cc789ef') - def test_update_network_provider_physical_network(self): - - """Update Network Provider Physical Network Test - - RBAC test for neutron update_network:provider:physical_network policy - """ - try: - with self.override_role(): - self._update_network(self.network['id'], - provider_physical_network='provider') - except lib_exc.BadRequest as exc: - # Per the api documenation, most plugins don't support updating - # provider attributes - self.assertIn( - "Plugin does not support updating provider attributes", - str(exc)) - - @decorators.skip_because(bug='2005489', bug_type='storyboard') - @utils.requires_ext(extension='provider', service='network') - @rbac_rule_validation.action( - service="neutron", - rules=["get_network", - "update_network", - "update_network:provider:segmentation_id"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('f6164228-b670-45fd-9ff9-b101930318c7') - def test_update_network_provider_segmentation_id(self): - - """Update Network Provider Segmentation Id Test - - RBAC test for neutron update_network:provider:segmentation_id policy - """ - try: - with self.override_role(): - self._update_network(self.network['id'], - provider_segmentation_id=400) - except lib_exc.BadRequest as exc: - # Per the api documenation, most plugins don't support updating - # provider attributes - self.assertIn( - "Plugin does not support updating provider attributes", - str(exc)) - - @rbac_rule_validation.action(service="neutron", - rules=["get_network"], - expected_error_codes=[404]) - @decorators.idempotent_id('0eb62d04-338a-4ff4-a8fa-534e52110534') - def test_show_network(self): - - """Show Network Test - - RBAC test for the neutron get_network policy - """ - with self.override_role(): - self.networks_client.show_network(self.network['id']) - - @utils.requires_ext(extension='external-net', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["get_network", - "get_network:router:external"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('529e4814-22e9-413f-af48-8fefcd637344') - def test_show_network_router_external(self): - - """Show Network Router External Test - - RBAC test for the neutron get_network:router:external policy - """ - kwargs = {'fields': 'router:external'} - - with self.override_role(): - retrieved_network = self.networks_client.show_network( - self.network['id'], **kwargs)['network'] - - if len(retrieved_network) == 0: - raise rbac_exceptions.RbacEmptyResponseBody() - - @utils.requires_ext(extension='provider', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["get_network", - "get_network:provider:network_type"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('6521dd60-0950-458b-8491-09d3c84ac0f4') - def test_show_network_provider_network_type(self): - - """Show Network Prodiver Network Type Test - - RBAC test for the neutron get_network:provider:network_type policy - """ - kwargs = {'fields': 'provider:network_type'} - - with self.override_role(): - retrieved_network = self.networks_client.show_network( - self.network['id'], **kwargs)['network'] - - if len(retrieved_network) == 0: - raise rbac_exceptions.RbacEmptyResponseBody() - - @utils.requires_ext(extension='provider', service='network') - @rbac_rule_validation.action( - service="neutron", - rules=["get_network", - "get_network:provider:physical_network"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('c049f11a-240c-4a85-ad43-a4d3fd0a5e39') - def test_show_network_provider_physical_network(self): - - """Show Network Provider Physical Network Test - - RBAC test for the neutron get_network:provider:physical_network policy - """ - kwargs = {'fields': 'provider:physical_network'} - - with self.override_role(): - retrieved_network = self.networks_client.show_network( - self.network['id'], **kwargs)['network'] - - if len(retrieved_network) == 0: - raise rbac_exceptions.RbacEmptyResponseBody() - - @utils.requires_ext(extension='provider', service='network') - @rbac_rule_validation.action( - service="neutron", - rules=["get_network", - "get_network:provider:segmentation_id"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('38d9f085-6365-4f81-bac9-c53c294d727e') - def test_show_network_provider_segmentation_id(self): - - """Show Network Provider Segmentation Id Test - - RBAC test for the neutron get_network:provider:segmentation_id policy - """ - kwargs = {'fields': 'provider:segmentation_id'} - - with self.override_role(): - retrieved_network = self.networks_client.show_network( - self.network['id'], **kwargs)['network'] - - if len(retrieved_network) == 0: - raise rbac_exceptions.RbacEmptyResponseBody() - - @rbac_rule_validation.action(service="neutron", - rules=["get_network", "delete_network"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('56ca50ed-ac58-49d6-b239-ed39e7124d5c') - def test_delete_network(self): - - """Delete Network Test - - RBAC test for the neutron delete_network policy - """ - network = self._create_network() - with self.override_role(): - self.networks_client.delete_network(network['id']) - - @utils.requires_ext(extension='dhcp_agent_scheduler', service='network') - @decorators.idempotent_id('b524f19f-fbb4-4d11-a85d-03bfae17bf0e') - @rbac_rule_validation.action(service="neutron", - rules=["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 - """ - with self.override_role(): - self.networks_client.list_dhcp_agents_on_hosting_network( - self.network['id']) - - @rbac_rule_validation.action(service="neutron", rules=["get_network"]) - @decorators.idempotent_id('53d6d826-ec9a-4407-9362-b474187fae6d') - def test_list_networks(self): - """List Networks - - RBAC test for the neutron ``list_networks`` function and - the ``get_network`` policy - """ - - admin_resource_id = self.network['id'] - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = self.networks_client.list_networks( - id=admin_resource_id)["networks"] diff --git a/patrole_tempest_plugin/tests/api/network/test_policy_bandwidth_limit_rule_rbac.py b/patrole_tempest_plugin/tests/api/network/test_policy_bandwidth_limit_rule_rbac.py deleted file mode 100644 index cd750a07..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_policy_bandwidth_limit_rule_rbac.py +++ /dev/null @@ -1,109 +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.common import utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class PolicyBandwidthLimitRuleExtRbacTest(base.BaseNetworkExtRbacTest): - - @classmethod - def skip_checks(cls): - super(PolicyBandwidthLimitRuleExtRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('qos', 'network'): - msg = "qos extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(PolicyBandwidthLimitRuleExtRbacTest, cls).resource_setup() - name = data_utils.rand_name(cls.__name__ + '-qos-policy') - cls.policy_id = cls.ntp_client.create_qos_policy( - name=name)["policy"]["id"] - cls.addClassResourceCleanup(cls.ntp_client.delete_qos_policy, - cls.policy_id) - - def _create_bandwidth_limit_rule(self): - rule = self.ntp_client.create_bandwidth_limit_rule( - self.policy_id, max_kbps=1000, max_burst_kbps=1000, - direction="egress") - rule_id = rule['bandwidth_limit_rule']['id'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.ntp_client.delete_bandwidth_limit_rule, - self.policy_id, rule_id) - return rule_id - - @decorators.idempotent_id('E0FDCB39-E16D-4AF5-9165-3FEFD116E69D') - @rbac_rule_validation.action( - service="neutron", rules=["create_policy_bandwidth_limit_rule"]) - def test_create_policy_bandwidth_limit_rule(self): - """Create bandwidth_limit_rule. - - RBAC test for the neutron "create_policy_bandwidth_limit_rule" policy - """ - - with self.override_role(): - self._create_bandwidth_limit_rule() - - @decorators.idempotent_id('A092BD50-364F-4F55-B81A-37DAD6E77B95') - @rbac_rule_validation.action(service="neutron", - rules=["get_policy_bandwidth_limit_rule"], - expected_error_codes=[404]) - def test_show_policy_bandwidth_limit_rule(self): - """Show bandwidth_limit_rule. - - RBAC test for the neutron "get_policy_bandwidth_limit_rule" policy - """ - rule_id = self._create_bandwidth_limit_rule() - - with self.override_role(): - self.ntp_client.show_bandwidth_limit_rule(self.policy_id, rule_id) - - @decorators.idempotent_id('CAA27599-082B-44B9-AF09-8C9B8E777ED7') - @rbac_rule_validation.action(service="neutron", - rules=["get_policy_bandwidth_limit_rule", - "update_policy_bandwidth_limit_rule"], - expected_error_codes=[404, 403]) - def test_update_policy_bandwidth_limit_rule(self): - """Update bandwidth_limit_rule. - - RBAC test for the neutron "update_policy_bandwidth_limit_rule" policy - """ - rule_id = self._create_bandwidth_limit_rule() - - with self.override_role(): - self.ntp_client.update_bandwidth_limit_rule( - self.policy_id, rule_id, max_kbps=2000) - - @decorators.idempotent_id('BF6D9ED7-4B04-423D-857D-455DB0705852') - @rbac_rule_validation.action(service="neutron", - rules=["get_policy_bandwidth_limit_rule", - "delete_policy_bandwidth_limit_rule"], - expected_error_codes=[404, 403]) - def test_delete_policy_bandwidth_limit_rule(self): - """Delete bandwidth_limit_rule. - - RBAC test for the neutron "delete_policy_bandwidth_limit_rule" policy - """ - rule_id = self._create_bandwidth_limit_rule() - - with self.override_role(): - self.ntp_client.delete_bandwidth_limit_rule(self.policy_id, - rule_id) diff --git a/patrole_tempest_plugin/tests/api/network/test_policy_minimum_bandwidth_rule_rbac.py b/patrole_tempest_plugin/tests/api/network/test_policy_minimum_bandwidth_rule_rbac.py deleted file mode 100644 index 990a3576..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_policy_minimum_bandwidth_rule_rbac.py +++ /dev/null @@ -1,112 +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.common import utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class PolicyMinimumBandwidthRuleExtRbacTest(base.BaseNetworkExtRbacTest): - - @classmethod - def skip_checks(cls): - super(PolicyMinimumBandwidthRuleExtRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('qos', 'network'): - msg = "qos extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(PolicyMinimumBandwidthRuleExtRbacTest, cls).resource_setup() - name = data_utils.rand_name(cls.__name__ + '-qos') - cls.policy_id = cls.ntp_client.create_qos_policy( - name=name)["policy"]["id"] - cls.addClassResourceCleanup(test_utils.call_and_ignore_notfound_exc, - cls.ntp_client.delete_qos_policy, - cls.policy_id) - - def create_minimum_bandwidth_rule(self): - rule = self.ntp_client.create_minimum_bandwidth_rule( - self.policy_id, direction="egress", min_kbps=1000) - rule_id = rule['minimum_bandwidth_rule']['id'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.ntp_client.delete_minimum_bandwidth_rule, - self.policy_id, rule_id) - return rule_id - - @decorators.idempotent_id('25B5EF3A-DF2A-4C80-A498-3BE14A321D97') - @rbac_rule_validation.action( - service="neutron", rules=["create_policy_minimum_bandwidth_rule"]) - def test_create_policy_minimum_bandwidth_rule(self): - """Create policy_minimum_bandwidth_rule. - - RBAC test for the neutron "create_policy_minimum_bandwidth_rule" policy - """ - - with self.override_role(): - self.create_minimum_bandwidth_rule() - - @decorators.idempotent_id('01DD902C-47C5-45D2-9A0E-7AF05981DF21') - @rbac_rule_validation.action(service="neutron", - rules=["get_policy_minimum_bandwidth_rule"], - expected_error_codes=[404]) - def test_show_policy_minimum_bandwidth_rule(self): - """Show policy_minimum_bandwidth_rule. - - RBAC test for the neutron "get_policy_minimum_bandwidth_rule" policy - """ - rule_id = self.create_minimum_bandwidth_rule() - - with self.override_role(): - self.ntp_client.show_minimum_bandwidth_rule( - self.policy_id, rule_id) - - @decorators.idempotent_id('50AFE69B-455C-413A-BDC6-26B42DC8D55D') - @rbac_rule_validation.action( - service="neutron", - rules=["get_policy_minimum_bandwidth_rule", - "update_policy_minimum_bandwidth_rule"], - expected_error_codes=[404, 403]) - def test_update_policy_minimum_bandwidth_rule(self): - """Update policy_minimum_bandwidth_rule. - - RBAC test for the neutron "update_policy_minimum_bandwidth_rule" policy - """ - rule_id = self.create_minimum_bandwidth_rule() - - with self.override_role(): - self.ntp_client.update_minimum_bandwidth_rule( - self.policy_id, rule_id, min_kbps=2000) - - @decorators.idempotent_id('2112E325-C3B2-4071-8A93-B218F275A83B') - @rbac_rule_validation.action( - service="neutron", - rules=["get_policy_minimum_bandwidth_rule", - "delete_policy_minimum_bandwidth_rule"], - expected_error_codes=[404, 403]) - def test_delete_policy_minimum_bandwidth_rule(self): - """Delete policy_minimum_bandwidth_rule. - - RBAC test for the neutron "delete_policy_minimum_bandwidth_rule" policy - """ - rule_id = self.create_minimum_bandwidth_rule() - - with self.override_role(): - self.ntp_client.delete_minimum_bandwidth_rule( - self.policy_id, rule_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 deleted file mode 100644 index d699e12f..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_ports_rbac.py +++ /dev/null @@ -1,404 +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. -# - -import netaddr -import testtools - -from tempest.common import utils -from tempest.common.utils import net_utils -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - -CONF = config.CONF - - -class PortsRbacTest(base.BaseNetworkRbacTest): - - @classmethod - def resource_setup(cls): - super(PortsRbacTest, cls).resource_setup() - # Create a network and subnet. - cls.network = cls.create_network() - 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']) - - 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 _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", - rules=["create_port"]) - @decorators.idempotent_id('0ec8c551-625c-4864-8a52-85baa7c40f22') - def test_create_port(self): - - with self.override_role(): - self.create_port(self.network) - - @decorators.idempotent_id('045ee797-4962-4913-b96a-5d7ea04099e7') - @rbac_rule_validation.action(service="neutron", - rules=["create_port", - "create_port:device_owner"]) - def test_create_port_device_owner(self): - with self.override_role(): - self.create_port(self.network, - device_owner='network:router_interface') - - @decorators.idempotent_id('c4fa8844-f5ef-4daa-bfa2-b89897dfaedf') - @rbac_rule_validation.action(service="neutron", - rules=["create_port", - "create_port:port_security_enabled"]) - def test_create_port_security_enabled(self): - with self.override_role(): - self.create_port(self.network, port_security_enabled=True) - - @utils.requires_ext(extension='binding', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["create_port", - "create_port:binding:host_id"]) - @decorators.idempotent_id('a54bd6b8-a7eb-4101-bfe8-093930b0d660') - def test_create_port_binding_host_id(self): - - post_body = {'network': self.network, - 'binding:host_id': "rbac_test_host"} - - with self.override_role(): - self.create_port(**post_body) - - @utils.requires_ext(extension='binding', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["create_port", - "create_port:binding:profile"]) - @decorators.idempotent_id('98fa38ab-c2ed-46a0-99f0-59f18cbd257a') - def test_create_port_binding_profile(self): - - binding_profile = {"foo": "1"} - - post_body = {'network': self.network, - 'binding:profile': binding_profile} - - with self.override_role(): - self.create_port(**post_body) - - @testtools.skipUnless( - CONF.policy_feature_enabled.create_port_fixed_ips_ip_address_policy, - '"create_port:fixed_ips:ip_address" must be available in the cloud.') - @rbac_rule_validation.action(service="neutron", - rules=["create_port", - "create_port:fixed_ips:ip_address"]) - @decorators.idempotent_id('2551e10d-006a-413c-925a-8c6f834c09ac') - def test_create_port_fixed_ips_ip_address(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} - - with self.override_role(): - self.create_port(**post_body) - - @rbac_rule_validation.action(service="neutron", - rules=["create_port", - "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()} - - with self.override_role(): - self.create_port(**post_body) - - @rbac_rule_validation.action(service="neutron", - rules=["create_port", - "create_port:allowed_address_pairs"]) - @decorators.idempotent_id('b638d1f4-d903-4ca8-aa2a-6fd603c5ec3a') - def test_create_port_allowed_address_pairs(self): - - # Create port with allowed address pair attribute - allowed_address_pairs = [{'ip_address': self.port_ip_address, - 'mac_address': self.port_mac_address}] - - post_body = {'network': self.network, - 'allowed_address_pairs': allowed_address_pairs} - - with self.override_role(): - self.create_port(**post_body) - - @rbac_rule_validation.action(service="neutron", - rules=["get_port"], - expected_error_codes=[404]) - @decorators.idempotent_id('a9d41cb8-78a2-4b97-985c-44e4064416f4') - def test_show_port(self): - with self.override_role(): - self.ports_client.show_port(self.port['id']) - - @utils.requires_ext(extension='binding', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["get_port", - "get_port:binding:vif_type"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('125aff0b-8fed-4f8e-8410-338616594b06') - def test_show_port_binding_vif_type(self): - - # Verify specific fields of a port - fields = ['binding:vif_type'] - - with self.override_role(): - retrieved_port = self.ports_client.show_port( - self.port['id'], fields=fields)['port'] - - # Rather than throwing a 403, the field is not present, so raise exc. - if fields[0] not in retrieved_port: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='binding:vif_type') - - @utils.requires_ext(extension='binding', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["get_port", - "get_port:binding:vif_details"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('e42bfd77-fcce-45ee-9728-3424300f0d6f') - def test_show_port_binding_vif_details(self): - - # Verify specific fields of a port - fields = ['binding:vif_details'] - - with self.override_role(): - retrieved_port = self.ports_client.show_port( - self.port['id'], fields=fields)['port'] - - # Rather than throwing a 403, the field is not present, so raise exc. - if fields[0] not in retrieved_port: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='binding:vif_details') - - @utils.requires_ext(extension='binding', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["get_port", - "get_port:binding:host_id"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('8e61bcdc-6f81-443c-833e-44410266551e') - def test_show_port_binding_host_id(self): - - # Verify specific fields of a port - fields = ['binding:host_id'] - post_body = {'network': self.network, - 'binding:host_id': data_utils.rand_name('host-id')} - port = self.create_port(**post_body) - - with self.override_role(): - retrieved_port = self.ports_client.show_port( - port['id'], fields=fields)['port'] - - # Rather than throwing a 403, the field is not present, so raise exc. - if fields[0] not in retrieved_port: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='binding:host_id') - - @utils.requires_ext(extension='binding', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["get_port", - "get_port:binding:profile"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('d497cea9-c4ad-42e0-acc9-8d257d6b01fc') - def test_show_port_binding_profile(self): - - # Verify specific fields of a port - fields = ['binding:profile'] - binding_profile = {"foo": "1"} - post_body = {'network': self.network, - 'binding:profile': binding_profile} - port = self.create_port(**post_body) - - with self.override_role(): - retrieved_port = self.ports_client.show_port( - port['id'], fields=fields)['port'] - - # Rather than throwing a 403, the field is not present, so raise exc. - if fields[0] not in retrieved_port: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='binding:profile') - - @rbac_rule_validation.action(service="neutron", - rules=["get_port", "update_port"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('afa80981-3c59-42fd-9531-3bcb2cd03711') - def test_update_port(self): - with self.override_role(): - 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", - rules=["get_port", "update_port", - "update_port:device_owner"], - expected_error_codes=[404, 403, 403]) - def test_update_port_device_owner(self): - original_device_owner = self.port['device_owner'] - - with self.override_role(): - 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", - rules=["get_port", "update_port", - "update_port:mac_address"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('507140c8-7b14-4d63-b627-2103691d887e') - def test_update_port_mac_address(self): - original_mac_address = self.port['mac_address'] - - with self.override_role(): - self.ports_client.update_port( - 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) - - @testtools.skipUnless( - CONF.policy_feature_enabled.update_port_fixed_ips_ip_address_policy, - '"update_port:fixed_ips:ip_address" must be available in the cloud.') - @rbac_rule_validation.action(service="neutron", - rules=["get_port", "update_port", - "update_port:fixed_ips:ip_address"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('c091c825-532b-4c6f-a14f-affd3259c1c3') - def test_update_port_fixed_ips_ip_address(self): - - # Pick an ip address within the allocation_pools range. - post_body = {'network': self.network} - port = self.create_port(**post_body) - - ip_list = self._get_unused_ip_address() - fixed_ips = [{'ip_address': ip_list[0]}] - - with self.override_role(): - self.ports_client.update_port(port['id'], fixed_ips=fixed_ips) - - @rbac_rule_validation.action(service="neutron", - rules=["get_port", "update_port", - "update_port:port_security_enabled"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('795541af-6652-4e35-9581-fd58224f7545') - def test_update_port_security_enabled(self): - with self.override_role(): - self.ports_client.update_port(self.port['id'], - port_security_enabled=True) - - @utils.requires_ext(extension='binding', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["get_port", "update_port", - "update_port:binding:host_id"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('24206a72-0d90-4712-918c-5c9a1ebef64d') - def test_update_port_binding_host_id(self): - - post_body = {'network': self.network, - 'binding:host_id': 'rbac_test_host'} - port = self.create_port(**post_body) - - updated_body = {'port_id': port['id'], - 'binding:host_id': 'rbac_test_host_updated'} - - with self.override_role(): - self.ports_client.update_port(**updated_body) - - @utils.requires_ext(extension='binding', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["get_port", "update_port", - "update_port:binding:profile"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('990ea8d1-9257-4f71-a3bf-d6d0914625c5') - def test_update_port_binding_profile(self): - - binding_profile = {"foo": "1"} - post_body = {'network': self.network, - 'binding:profile': binding_profile} - - port = self.create_port(**post_body) - - new_binding_profile = {"foo": "2"} - updated_body = {'port_id': port['id'], - 'binding:profile': new_binding_profile} - - with self.override_role(): - self.ports_client.update_port(**updated_body) - - @rbac_rule_validation.action(service="neutron", - rules=["get_port", "update_port", - "update_port:allowed_address_pairs"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('729c2151-bb49-4f4f-9d58-3ed8819b7582') - def test_update_port_allowed_address_pairs(self): - - 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': self.network} - port = self.create_port(**post_body) - - with self.override_role(): - self.ports_client.update_port(port['id'], - allowed_address_pairs=address_pairs) - - @rbac_rule_validation.action(service="neutron", - rules=["get_port", "delete_port"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('1cf8e582-bc09-46cb-b32a-82bf991ad56f') - def test_delete_port(self): - - port = self.create_port(self.network) - with self.override_role(): - self.ports_client.delete_port(port['id']) - - @rbac_rule_validation.action(service="neutron", rules=["get_port"]) - @decorators.idempotent_id('877ea70d-b000-4af4-9322-0a76b47b7890') - def test_list_ports(self): - """List Ports - - RBAC test for the neutron ``list_ports`` function and - the ``get_port`` policy - """ - admin_resource_id = self.port['id'] - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = self.ports_client.list_ports( - id=admin_resource_id)["ports"] diff --git a/patrole_tempest_plugin/tests/api/network/test_qos_rbac.py b/patrole_tempest_plugin/tests/api/network/test_qos_rbac.py deleted file mode 100644 index 2951e53f..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_qos_rbac.py +++ /dev/null @@ -1,114 +0,0 @@ -# Copyright 2018 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.common import utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class QosExtRbacTest(base.BaseNetworkExtRbacTest): - - @classmethod - def skip_checks(cls): - super(QosExtRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('qos', 'network'): - msg = "qos extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(QosExtRbacTest, cls).resource_setup() - cls.network = cls.create_network() - - def create_policy(self, name=None): - name = name or data_utils.rand_name(self.__class__.__name__) - policy = self.ntp_client.create_qos_policy(name)['policy'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.ntp_client.delete_qos_policy, policy['id']) - return policy - - @rbac_rule_validation.action(service="neutron", - rules=["create_policy"], - expected_error_codes=[403]) - @decorators.idempotent_id('2ade2e48-7f82-4650-a69c-933d8d594636') - def test_create_policy(self): - - """Create Policy Test - - RBAC test for the neutron create_policy policy - """ - with self.override_role(): - self.create_policy() - - @rbac_rule_validation.action(service="neutron", - rules=["get_policy"], - expected_error_codes=[404]) - @decorators.idempotent_id('d004a8de-b226-4eb4-9fdc-8202a7f64c56') - def test_get_policy(self): - - """Show Policy Test - - RBAC test for the neutron get_policy policy - """ - policy = self.create_policy() - with self.override_role(): - self.ntp_client.show_qos_policy(policy['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_policy", "update_policy"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('fb74d56f-1dfc-490b-a9e1-454af583eefb') - def test_update_policy(self): - - """Update Policy Test - - RBAC test for the neutron update_policy policy - """ - policy = self.create_policy() - with self.override_role(): - self.ntp_client.update_qos_policy(policy['id'], - description='updated') - - @rbac_rule_validation.action(service="neutron", - rules=["get_policy", "delete_policy"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('ef4c23a6-4095-47a6-958e-1df585f7d8db') - def test_delete_policy(self): - - """Delete Policy Test - - RBAC test for the neutron delete_policy policy - """ - policy = self.create_policy() - with self.override_role(): - self.ntp_client.delete_qos_policy(policy['id']) - - @rbac_rule_validation.action(service="neutron", rules=["get_policy"]) - @decorators.idempotent_id('e84cec88-8478-4787-b603-5fcdd8ed7bd5') - def test_list_policies(self): - """List Policies Test - - RBAC test for the neutron ``list_qos_policies`` function and - the ``get_policy`` - """ - admin_resource_id = self.create_policy()['id'] - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = self.ntp_client.list_qos_policies( - id=admin_resource_id)["policies"] diff --git a/patrole_tempest_plugin/tests/api/network/test_rbac_policies_rbac.py b/patrole_tempest_plugin/tests/api/network/test_rbac_policies_rbac.py deleted file mode 100644 index c2bc9700..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_rbac_policies_rbac.py +++ /dev/null @@ -1,126 +0,0 @@ -# Copyright 2018 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class RbacPoliciesExtRbacTest(base.BaseNetworkExtRbacTest): - - @classmethod - def resource_setup(cls): - super(RbacPoliciesExtRbacTest, cls).resource_setup() - cls.tenant_id = cls.os_primary.credentials.tenant_id - cls.network_id = cls.create_network()['id'] - - def create_rbac_policy(self, tenant_id, network_id): - policy = self.ntp_client.create_rbac_policy( - target_tenant=tenant_id, - object_type="network", - object_id=network_id, - action="access_as_shared" - ) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.ntp_client.delete_rbac_policy, policy["rbac_policy"]["id"]) - - return policy["rbac_policy"]["id"] - - @decorators.idempotent_id('effd9545-99ad-4c3c-92dd-ea422602c868') - @rbac_rule_validation.action(service="neutron", - rules=["create_rbac_policy", - "create_rbac_policy:target_tenant"]) - def test_create_rbac_policy(self): - """Create RBAC policy. - - RBAC test for the neutron "create_rbac_policy" policy - - We can't validate "create_rbac_policy:target_tenant" for all cases - since if "restrict_wildcard" rule is modified then Patrole won't be - able to determine the correct result since that requires relying on - Neutron's custom FieldCheck oslo.policy rule. - """ - - with self.override_role(): - self.create_rbac_policy(self.tenant_id, self.network_id) - - @decorators.idempotent_id('f5d836d8-3b64-412d-a283-ee29761017f3') - @rbac_rule_validation.action(service="neutron", - rules=["get_rbac_policy", - "update_rbac_policy", - "update_rbac_policy:target_tenant"], - expected_error_codes=[404, 403, 403]) - def test_update_rbac_policy(self): - """Update RBAC policy. - - RBAC test for the neutron "update_rbac_policy" policy - - We can't validate "create_rbac_policy:target_tenant" for all cases - since if "restrict_wildcard" rule is modified then Patrole won't be - able to determine the correct result since that requires relying on - Neutron's custom FieldCheck oslo.policy rule. - """ - policy_id = self.create_rbac_policy(self.tenant_id, self.network_id) - - with self.override_role(): - self.ntp_client.update_rbac_policy( - policy_id, target_tenant=self.tenant_id) - - @decorators.idempotent_id('9308ab18-426c-41b7-bce5-11081f7dd259') - @rbac_rule_validation.action(service="neutron", - rules=["get_rbac_policy"], - expected_error_codes=[404]) - def test_show_rbac_policy(self): - """Show RBAC policy. - - RBAC test for the neutron "get_rbac_policy" policy - """ - policy_id = self.create_rbac_policy(self.tenant_id, self.network_id) - - with self.override_role(): - self.ntp_client.show_rbac_policy(policy_id) - - @decorators.idempotent_id('54aa9bce-efea-47fb-b0e4-12012f82f285') - @rbac_rule_validation.action(service="neutron", - rules=["get_rbac_policy", - "delete_rbac_policy"], - expected_error_codes=[404, 403]) - def test_delete_rbac_policy(self): - """Delete RBAC policy. - - RBAC test for the neutron "delete_rbac_policy" policy - """ - policy_id = self.create_rbac_policy(self.tenant_id, self.network_id) - - with self.override_role(): - self.ntp_client.delete_rbac_policy(policy_id) - - @decorators.idempotent_id('5337d95a-2e75-47bb-a0ea-0a082be930bf') - @rbac_rule_validation.action(service="neutron", rules=["get_rbac_policy"]) - def test_list_rbac_policies(self): - """List RBAC policies. - - RBAC test for the neutron ``list_rbac_policies`` function and - the ``get_rbac_policy`` policy - """ - admin_resource_id = self.create_rbac_policy(self.tenant_id, - self.network_id) - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = self.ntp_client.list_rbac_policies( - id=admin_resource_id)["rbac_policies"] diff --git a/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py b/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py deleted file mode 100644 index 42318e9e..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_routers_rbac.py +++ /dev/null @@ -1,418 +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. - -import netaddr - -from tempest.common import utils -from tempest.common.utils import net_utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class RouterRbacTest(base.BaseNetworkRbacTest): - @classmethod - def skip_checks(cls): - super(RouterRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('router', 'network'): - msg = "router extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(RouterRbacTest, cls).resource_setup() - # Create a network with external gateway so that - # ``external_gateway_info`` policies can be validated. - post_body = {'router:external': True} - cls.network = cls.create_network(**post_body) - cls.subnet = cls.create_subnet(cls.network) - cls.ip_range = netaddr.IPRange( - cls.subnet['allocation_pools'][0]['start'], - cls.subnet['allocation_pools'][0]['end']) - cls.router = cls.create_router() - - def _get_unused_ip_address(self): - unused_ip = net_utils.get_unused_ip_addresses(self.ports_client, - self.subnets_client, - self.network['id'], - self.subnet['id'], - 1) - return unused_ip[0] - - @rbac_rule_validation.action(service="neutron", - rules=["create_router"]) - @decorators.idempotent_id('acc5005c-bdb6-4192-bc9f-ece9035bb488') - def test_create_router(self): - """Create Router - - RBAC test for the neutron create_router policy - """ - with self.override_role(): - router = self.routers_client.create_router() - self.addCleanup(self.routers_client.delete_router, - router['router']['id']) - - @decorators.idempotent_id('6139eb97-95c0-40d8-a109-99de11ab2e5e') - @utils.requires_ext(extension='l3-ha', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["create_router", - "create_router:ha"]) - def test_create_high_availability_router(self): - """Create high-availability router - - RBAC test for the neutron create_router:ha policy - """ - with self.override_role(): - router = self.routers_client.create_router(ha=True) - self.addCleanup(self.routers_client.delete_router, - router['router']['id']) - - @decorators.idempotent_id('c6254ca6-2728-412d-803d-d4aa3935e56d') - @utils.requires_ext(extension='dvr', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["create_router", - "create_router:distributed"]) - def test_create_distributed_router(self): - """Create distributed router - - RBAC test for the neutron create_router:distributed policy - """ - with self.override_role(): - router = self.routers_client.create_router(distributed=True) - self.addCleanup(self.routers_client.delete_router, - router['router']['id']) - - @utils.requires_ext(extension='ext-gw-mode', service='network') - @rbac_rule_validation.action( - service="neutron", - rules=["create_router", - "create_router:external_gateway_info:enable_snat"]) - @decorators.idempotent_id('3c5acd49-0ec7-4109-ab51-640557b48ebc') - def test_create_router_enable_snat(self): - """Create Router Snat - - RBAC test for the neutron - create_router:external_gateway_info:enable_snat policy - """ - name = data_utils.rand_name(self.__class__.__name__ + '-snat-router') - external_gateway_info = {'network_id': self.network['id'], - 'enable_snat': True} - - with self.override_role(): - router = self.routers_client.create_router( - name=name, external_gateway_info=external_gateway_info) - self.addCleanup(self.routers_client.delete_router, - router['router']['id']) - - @rbac_rule_validation.action( - service="neutron", - rules=["create_router", - "create_router:external_gateway_info:external_fixed_ips"]) - @decorators.idempotent_id('d0354369-a040-4349-b869-645c8aed13cd') - def test_create_router_external_fixed_ips(self): - """Create Router Fixed IPs - - RBAC test for the neutron - create_router:external_gateway_info:external_fixed_ips policy - """ - name = data_utils.rand_name(self.__class__.__name__ + '-snat-router') - - unused_ip = self._get_unused_ip_address() - external_fixed_ips = {'subnet_id': self.subnet['id'], - 'ip_address': unused_ip} - external_gateway_info = {'network_id': self.network['id'], - 'enable_snat': False, # Default is True. - 'external_fixed_ips': [external_fixed_ips]} - - with self.override_role(): - router = self.routers_client.create_router( - name=name, external_gateway_info=external_gateway_info) - self.addCleanup(self.routers_client.delete_router, - router['router']['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_router"], - expected_error_codes=[404]) - @decorators.idempotent_id('bfbdbcff-f115-4d3e-8cd5-6ada33fd0e21') - def test_show_router(self): - """Get Router - - RBAC test for the neutron get_router policy - """ - # Prevent other policies from being enforced by using barebones fields. - with self.override_role(): - self.routers_client.show_router(self.router['id'], fields=['id']) - - @decorators.idempotent_id('3ed26ea2-b419-410c-b4b5-576c1edafa06') - @utils.requires_ext(extension='dvr', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["get_router", - "get_router:distributed"], - expected_error_codes=[404, 403]) - def test_show_distributed_router(self): - """Get distributed router - - RBAC test for the neutron get_router:distributed policy - """ - router = self.routers_client.create_router(distributed=True)['router'] - self.addCleanup(self.routers_client.delete_router, router['id']) - - with self.override_role(): - retrieved_fields = self.routers_client.show_router( - router['id'], fields=['distributed'])['router'] - - # Rather than throwing a 403, the field is not present, so raise exc. - if 'distributed' not in retrieved_fields: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='distributed') - - @decorators.idempotent_id('defc502c-4159-4824-b4d9-3cdcc39015b2') - @utils.requires_ext(extension='l3-ha', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["get_router", "get_router:ha"], - expected_error_codes=[404, 403]) - def test_show_high_availability_router(self): - """GET high-availability router - - RBAC test for the neutron get_router:ha policy - """ - router = self.routers_client.create_router(ha=True)['router'] - self.addCleanup(self.routers_client.delete_router, router['id']) - - with self.override_role(): - retrieved_fields = self.routers_client.show_router( - router['id'], fields=['ha'])['router'] - - # Rather than throwing a 403, the field is not present, so raise exc. - if 'ha' not in retrieved_fields: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='ha') - - @rbac_rule_validation.action(service="neutron", - rules=["get_router", "update_router"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('3d182f4e-0023-4218-9aa0-ea2b0ae0bd7a') - def test_update_router(self): - """Update Router - - RBAC test for the neutron update_router policy - """ - new_name = data_utils.rand_name( - self.__class__.__name__ + '-new-router-name') - with self.override_role(): - self.routers_client.update_router(self.router['id'], name=new_name) - - @rbac_rule_validation.action(service="neutron", - rules=["get_router", "update_router", - "update_router:external_gateway_info"], - expected_error_codes=[404, 403, 403]) - @decorators.idempotent_id('5a6ae104-a9c3-4b56-8622-e1a0a0194474') - def test_update_router_external_gateway_info(self): - """Update Router External Gateway Info - - RBAC test for the neutron - update_router:external_gateway_info policy - """ - with self.override_role(): - self.routers_client.update_router(self.router['id'], - external_gateway_info={}) - - @rbac_rule_validation.action( - service="neutron", - rules=["get_router", "update_router", - "update_router:external_gateway_info", - "update_router:external_gateway_info:network_id"], - expected_error_codes=[404, 403, 403, 403]) - @decorators.idempotent_id('f1fc5a23-e3d8-44f0-b7bc-47006ad9d3d4') - def test_update_router_external_gateway_info_network_id(self): - """Update Router External Gateway Info Network Id - - RBAC test for the neutron - update_router:external_gateway_info:network_id policy - """ - with self.override_role(): - self.routers_client.update_router( - self.router['id'], - external_gateway_info={'network_id': self.network['id']}) - self.addCleanup( - self.routers_client.update_router, - self.router['id'], - external_gateway_info=None) - - @utils.requires_ext(extension='ext-gw-mode', service='network') - @rbac_rule_validation.action( - service="neutron", - rules=["get_router", "update_router", - "update_router:external_gateway_info", - "update_router:external_gateway_info:enable_snat"], - expected_error_codes=[404, 403, 403, 403]) - @decorators.idempotent_id('515a2954-3d79-4695-aeb9-d1c222765840') - def test_update_router_enable_snat(self): - """Update Router External Gateway Info Enable Snat - - RBAC test for the neutron - update_router:external_gateway_info:enable_snat policy - """ - with self.override_role(): - self.routers_client.update_router( - self.router['id'], - external_gateway_info={'network_id': self.network['id'], - 'enable_snat': True}) - self.addCleanup( - self.routers_client.update_router, - self.router['id'], - external_gateway_info=None) - - @rbac_rule_validation.action( - service="neutron", - rules=["get_router", "update_router", - "update_router:external_gateway_info", - "update_router:external_gateway_info:external_fixed_ips"], - expected_error_codes=[404, 403, 403, 403]) - @decorators.idempotent_id('f429e5ee-8f0a-4667-963e-72dd95d5adee') - def test_update_router_external_fixed_ips(self): - """Update Router External Gateway Info External Fixed Ips - - RBAC test for the neutron - update_router:external_gateway_info:external_fixed_ips policy - """ - unused_ip = self._get_unused_ip_address() - external_fixed_ips = {'subnet_id': self.subnet['id'], - 'ip_address': unused_ip} - external_gateway_info = {'network_id': self.network['id'], - 'external_fixed_ips': [external_fixed_ips]} - - with self.override_role(): - self.routers_client.update_router( - self.router['id'], - external_gateway_info=external_gateway_info) - self.addCleanup( - self.routers_client.update_router, - self.router['id'], - external_gateway_info=None) - - @decorators.idempotent_id('ddc20731-dea1-4321-9abf-8772bf0b5977') - @utils.requires_ext(extension='l3-ha', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["get_router", "update_router", - "update_router:ha"], - expected_error_codes=[404, 403, 403]) - def test_update_high_availability_router(self): - """Update high-availability router - - RBAC test for the neutron update_router:ha policy - """ - with self.override_role(): - self.routers_client.update_router(self.router['id'], ha=True) - self.addCleanup(self.routers_client.update_router, self.router['id'], - ha=False) - - @decorators.idempotent_id('e1932c19-8f73-41cd-b5d2-84c7ae5d530c') - @utils.requires_ext(extension='dvr', service='network') - @rbac_rule_validation.action(service="neutron", - rules=["get_router", "update_router", - "update_router:distributed"], - expected_error_codes=[404, 403, 403]) - def test_update_distributed_router(self): - """Update distributed router - - RBAC test for the neutron update_router:distributed policy - """ - with self.override_role(): - self.routers_client.update_router(self.router['id'], - distributed=True) - self.addCleanup(self.routers_client.update_router, self.router['id'], - distributed=False) - - @rbac_rule_validation.action(service="neutron", - rules=["get_router", "delete_router"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('c0634dd5-0467-48f7-a4ae-1014d8edb2a7') - def test_delete_router(self): - """Delete Router - - RBAC test for the neutron delete_router policy - """ - router = self.create_router() - with self.override_role(): - self.routers_client.delete_router(router['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_router", "add_router_interface"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('a0627778-d68d-4913-881b-e345360cca19') - def test_add_router_interface(self): - """Add Router Interface - - RBAC test for the neutron add_router_interface policy - """ - network = self.create_network() - subnet = self.create_subnet(network) - router = self.create_router() - - with self.override_role(): - self.routers_client.add_router_interface( - router['id'], subnet_id=subnet['id']) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.routers_client.remove_router_interface, - router['id'], - subnet_id=subnet['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_router", - "remove_router_interface"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('ff2593a4-2bff-4c27-97d3-dd3702b27dfb') - def test_remove_router_interface(self): - """Remove Router Interface - - RBAC test for the neutron remove_router_interface policy - """ - network = self.create_network() - subnet = self.create_subnet(network) - router = self.create_router() - - self.routers_client.add_router_interface( - router['id'], subnet_id=subnet['id']) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.routers_client.remove_router_interface, - router['id'], - subnet_id=subnet['id']) - - with self.override_role(): - self.routers_client.remove_router_interface( - router['id'], - subnet_id=subnet['id']) - - @rbac_rule_validation.action(service="neutron", rules=["get_router"]) - @decorators.idempotent_id('86816700-12d1-4173-a50f-34bd137f47e6') - def test_list_routers(self): - """List Routers - - RBAC test for the neutron ``get_router policy`` and - the ``get_router`` policy - """ - - admin_resource_id = self.router['id'] - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = self.routers_client.list_routers( - id=admin_resource_id)["routers"] 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 deleted file mode 100644 index 3460880b..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_security_groups_rbac.py +++ /dev/null @@ -1,175 +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.common import utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class SecGroupRbacTest(base.BaseNetworkRbacTest): - - @classmethod - def skip_checks(cls): - super(SecGroupRbacTest, cls).skip_checks() - if not utils.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') - cls.secgroup = cls.security_groups_client.create_security_group( - name=secgroup_name)['security_group'] - cls.addClassResourceCleanup( - cls.security_groups_client.delete_security_group, - cls.secgroup['id']) - - def _create_security_group(self): - # Create a security group - name = data_utils.rand_name(self.__class__.__name__ + '-secgroup') - security_group =\ - self.security_groups_client.create_security_group( - name=name)['security_group'] - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.security_groups_client.delete_security_group, - security_group['id']) - return security_group - - def _create_security_group_rule(self): - # Create a security group rule - sec_group_rule = \ - self.security_group_rules_client.create_security_group_rule( - security_group_id=self.secgroup['id'], - direction='ingress', - protocol='tcp', - port_range_min=99, - port_range_max=99)['security_group_rule'] - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.security_group_rules_client.delete_security_group_rule, - sec_group_rule['id']) - return sec_group_rule - - @rbac_rule_validation.action(service="neutron", - rules=["create_security_group"]) - @decorators.idempotent_id('db7003ce-5717-4e5b-afc7-befa35e8c67f') - def test_create_security_group(self): - - with self.override_role(): - self._create_security_group() - - @rbac_rule_validation.action(service="neutron", - rules=["get_security_group"], - expected_error_codes=[404]) - @decorators.idempotent_id('56335e77-aef2-4b54-86c7-7f772034b585') - def test_show_security_group(self): - - with self.override_role(): - self.security_groups_client.show_security_group( - self.secgroup['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_security_group", - "delete_security_group"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('0b1330fd-dd28-40f3-ad73-966052e4b3de') - def test_delete_security_group(self): - - # Create a security group - secgroup_id = self._create_security_group()['id'] - - with self.override_role(): - self.security_groups_client.delete_security_group(secgroup_id) - - @rbac_rule_validation.action(service="neutron", - rules=["get_security_group", - "update_security_group"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('56c5e4dc-f8aa-11e6-bc64-92361f002671') - def test_update_security_group(self): - - # Create a security group - secgroup_id = self._create_security_group()['id'] - - with self.override_role(): - self.security_groups_client.update_security_group( - secgroup_id, - description="test description") - - @rbac_rule_validation.action(service="neutron", - rules=["get_security_group"]) - @decorators.idempotent_id('fbaf8d96-ed3e-49af-b24c-5fb44f05bbb7') - def test_list_security_groups(self): - """List Security Groups - - RBAC test for the neutron ``list_security_groups`` function and - the ``get_security_group`` policy - """ - admin_resource_id = self.secgroup['id'] - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = self.security_groups_client.list_security_groups( - id=admin_resource_id)["security_groups"] - - @rbac_rule_validation.action(service="neutron", - rules=["create_security_group_rule"]) - @decorators.idempotent_id('953d78df-00cd-416f-9cbd-b7cb4ea65772') - def test_create_security_group_rule(self): - - with self.override_role(): - self._create_security_group_rule() - - @rbac_rule_validation.action(service="neutron", - rules=["get_security_group_rule", - "delete_security_group_rule"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('2262539e-b7d9-438c-acf9-a5ce0613be28') - def test_delete_security_group_rule(self): - - sec_group_rule = self._create_security_group_rule() - with self.override_role(): - self.security_group_rules_client.delete_security_group_rule( - sec_group_rule['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_security_group_rule"], - expected_error_codes=[404]) - @decorators.idempotent_id('84b4038c-261e-4a94-90d5-c885739ab0d5') - def test_show_security_group_rule(self): - - sec_group_rule = self._create_security_group_rule() - with self.override_role(): - self.security_group_rules_client.show_security_group_rule( - sec_group_rule['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_security_group_rule"]) - @decorators.idempotent_id('05739ab6-fa35-11e6-bc64-92361f002671') - def test_list_security_group_rules(self): - - with self.override_role(): - security_rules = self.security_group_rules_client.\ - list_security_group_rules() - - # Neutron may return an empty list if access is denied. - if not security_rules['security_group_rules']: - raise rbac_exceptions.RbacEmptyResponseBody() diff --git a/patrole_tempest_plugin/tests/api/network/test_segments_rbac.py b/patrole_tempest_plugin/tests/api/network/test_segments_rbac.py deleted file mode 100644 index 1e6d7f11..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_segments_rbac.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright 2018 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -import random - -from tempest.common import utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class SegmentsExtRbacTest(base.BaseNetworkExtRbacTest): - - @classmethod - def skip_checks(cls): - super(SegmentsExtRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('segment', 'network'): - msg = "segment extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(SegmentsExtRbacTest, cls).resource_setup() - cls.network = cls.create_network() - - @classmethod - def get_free_segmentation_id(cls): - # Select unused segmentation_id to prevent usage conflict - segments = cls.ntp_client.list_segments()["segments"] - segmentation_ids = [s["segmentation_id"] for s in segments] - - # With 2+ concurrency, tests that ran in the same moment may fail due - # to usage conflict. To prevent it we select segmentation to start - # randomly. - segmentation_id = random.randint(1000, 5000) # nosec - while segmentation_id in segmentation_ids: - segmentation_id += 1 - - return segmentation_id - - @classmethod - def create_segment(cls, network): - segmentation_id = cls.get_free_segmentation_id() - - seg = cls.ntp_client.create_segment( - network_id=network['id'], network_type="gre", - segmentation_id=segmentation_id) - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.ntp_client.delete_segment, seg['segment']['id']) - - return seg - - @decorators.idempotent_id('c02618e7-bb20-1a3a-83c8-6eec2af08126') - @rbac_rule_validation.action(service="neutron", - rules=["create_segment"]) - def test_create_segment(self): - """Create segment. - - RBAC test for the neutron "create_segment" policy - """ - with self.override_role(): - self.create_segment(self.network) - - @decorators.idempotent_id('c02618e7-bb20-1a3a-83c8-6eec2af08127') - @rbac_rule_validation.action(service="neutron", - rules=["get_segment"], - expected_error_codes=[404]) - def test_show_segment(self): - """Show segment. - - RBAC test for the neutron "get_segment" policy - """ - segment = self.create_segment(self.network) - - with self.override_role(): - self.ntp_client.show_segment(segment['segment']['id']) - - @decorators.idempotent_id('c02618e7-bb20-1a3a-83c8-6eec2af08128') - @rbac_rule_validation.action(service="neutron", - rules=["get_segment", - "update_segment"], - expected_error_codes=[404, 403]) - def test_update_segment(self): - """Update segment. - - RBAC test for the neutron "update_segment" policy - """ - segment = self.create_segment(self.network) - - with self.override_role(): - self.ntp_client.update_segment(segment['segment']['id'], - name="NewName") - - @decorators.idempotent_id('c02618e7-bb20-1a3a-83c8-6eec2af08129') - @rbac_rule_validation.action(service="neutron", - rules=["get_segment", - "delete_segment"], - expected_error_codes=[404, 403]) - def test_delete_segment(self): - """Delete segment. - - RBAC test for the neutron "delete_segment" policy - """ - segment = self.create_segment(self.network) - - with self.override_role(): - self.ntp_client.delete_segment(segment['segment']['id']) - - @decorators.idempotent_id('d68a0578-36ae-435e-8aaa-508ee96bdfae') - @rbac_rule_validation.action(service="neutron", rules=["get_segment"]) - def test_list_segments(self): - """List segments. - - RBAC test for the neutron ``list_segments`` function and - the``get_segment`` policy - """ - admin_resource_id = self.create_segment(self.network)['segment']['id'] - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = self.ntp_client.list_segments( - id=admin_resource_id)["segments"] diff --git a/patrole_tempest_plugin/tests/api/network/test_service_profile_rbac.py b/patrole_tempest_plugin/tests/api/network/test_service_profile_rbac.py deleted file mode 100644 index fbb42304..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_service_profile_rbac.py +++ /dev/null @@ -1,73 +0,0 @@ -# Copyright 2018 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class ServiceProfileExtRbacTest(base.BaseNetworkExtRbacTest): - @decorators.idempotent_id('6ce76efa-7400-44c1-80ec-58f79b1d89ca') - @rbac_rule_validation.action(service="neutron", - rules=["create_service_profile"]) - def test_create_service_profile(self): - """Create service profile - - RBAC test for the neutron "create_service_profile" policy - """ - with self.override_role(): - self.create_service_profile() - - @decorators.idempotent_id('e4c473b7-3ae9-4a2e-8cac-848f7b01187d') - @rbac_rule_validation.action(service="neutron", - rules=["get_service_profile"], - expected_error_codes=[404]) - def test_show_service_profile(self): - """Show service profile - - RBAC test for the neutron "get_service_profile" policy - """ - profile_id = self.create_service_profile() - with self.override_role(): - self.ntp_client.show_service_profile(profile_id) - - @decorators.idempotent_id('a3dd719d-4cd3-40cc-b4f1-5642e2717adf') - @rbac_rule_validation.action(service="neutron", - rules=["get_service_profile", - "update_service_profile"], - expected_error_codes=[404, 403]) - def test_update_service_profile(self): - """Update service profile - - RBAC test for the neutron "update_service_profile" policy - """ - profile_id = self.create_service_profile() - with self.override_role(): - self.ntp_client.update_service_profile(profile_id, enabled=False) - - @decorators.idempotent_id('926b60c2-04fe-4339-aa44-bf27121392e8') - @rbac_rule_validation.action(service="neutron", - rules=["get_service_profile", - "delete_service_profile"], - expected_error_codes=[404, 403]) - def test_delete_service_profile(self): - """Delete service profile - - RBAC test for the neutron "delete_service_profile" policy - """ - profile_id = self.create_service_profile() - with self.override_role(): - self.ntp_client.delete_service_profile(profile_id) 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 deleted file mode 100644 index 41725d57..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_service_providers_rbac.py +++ /dev/null @@ -1,29 +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 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", - rules=["get_service_provider"]) - @decorators.idempotent_id('15f573b7-474a-4b37-8629-7fac86553ce5') - def test_list_service_providers(self): - with self.override_role(): - 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 deleted file mode 100644 index af65f2fd..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_subnetpools_rbac.py +++ /dev/null @@ -1,180 +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.common import 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 patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - -CONF = config.CONF - - -class SubnetPoolsRbacTest(base.BaseNetworkRbacTest): - - @classmethod - def skip_checks(cls): - super(SubnetPoolsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('subnet_allocation', 'network'): - msg = "subnet_allocation extension not enabled." - raise cls.skipException(msg) - - 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 kwargs: - post_body.update(kwargs) - - body = self.subnetpools_client.create_subnetpool(**post_body) - subnetpool = body['subnetpool'] - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.subnetpools_client.delete_subnetpool, - subnetpool['id']) - - return subnetpool - - @rbac_rule_validation.action(service="neutron", - rules=["create_subnetpool"]) - @decorators.idempotent_id('1b5509fd-2c32-44a8-a786-1b6ca162dbd1') - def test_create_subnetpool(self): - """Create subnetpool. - - RBAC test for the neutron create_subnetpool policy - """ - with self.override_role(): - self._create_subnetpool() - - @rbac_rule_validation.action(service="neutron", - rules=["create_subnetpool", - "create_subnetpool:is_default"], - expected_error_codes=[403, 403]) - @decorators.idempotent_id('1b5509fd-2c32-44a8-a786-1b6ca162dbd2') - def test_create_subnetpool_default(self): - """Create default subnetpool. - - RBAC test for the neutron create_subnetpool:is_default policy - """ - # Most likely we already have default subnetpools for ipv4 and ipv6, - # so we temporary mark them as is_default=False, to let this test pass. - def_pools = self.subnetpools_client.list_subnetpools(is_default=True) - for default_pool in def_pools["subnetpools"]: - self.subnetpools_client.update_subnetpool(default_pool["id"], - is_default=False) - - self.addCleanup(self.subnetpools_client.update_subnetpool, - default_pool["id"], is_default=True) - - with self.override_role(): - # It apparently only enforces the policy for is_default=True. - # It does nothing for is_default=False - self._create_subnetpool(is_default=True) - - @rbac_rule_validation.action(service="neutron", - rules=["create_subnetpool", - "create_subnetpool:shared"], - expected_error_codes=[403, 403]) - @decorators.idempotent_id('cf730989-0d47-40bc-b39a-99e7de484723') - def test_create_subnetpool_shared(self): - """Create subnetpool shared. - - RBAC test for the neutron create_subnetpool:shared policy - """ - with self.override_role(): - self._create_subnetpool(shared=True) - - @rbac_rule_validation.action(service="neutron", - rules=["get_subnetpool"], - expected_error_codes=[404]) - @decorators.idempotent_id('4f5aee26-0507-4b6d-b44c-3128a25094d2') - def test_show_subnetpool(self): - """Show subnetpool. - - RBAC test for the neutron get_subnetpool policy - """ - subnetpool = self._create_subnetpool() - with self.override_role(): - self.subnetpools_client.show_subnetpool(subnetpool['id']) - - @rbac_rule_validation.action(service="neutron", - rules=["get_subnetpool", - "update_subnetpool"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('1e79cead-5081-4be2-a4f7-484c0f443b9b') - def test_update_subnetpool(self): - """Update subnetpool. - - RBAC test for the neutron update_subnetpool policy - """ - subnetpool = self._create_subnetpool() - with self.override_role(): - self.subnetpools_client.update_subnetpool(subnetpool['id'], - min_prefixlen=24) - - @decorators.idempotent_id('a16f4e5c-0675-415f-b636-00af00638693') - @rbac_rule_validation.action(service="neutron", - rules=["update_subnetpool", - "update_subnetpool:is_default"]) - 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'] - - with self.override_role(): - self.subnetpools_client.update_subnetpool( - default_pool['id'], description=original_desc, is_default=True) - - @rbac_rule_validation.action(service="neutron", - rules=["get_subnetpool", - "delete_subnetpool"], - expected_error_codes=[404, 403]) - @decorators.idempotent_id('50f5944e-43e5-457b-ab50-fb48a73f0d3e') - def test_delete_subnetpool(self): - """Delete subnetpool. - - RBAC test for the neutron delete_subnetpool policy - """ - subnetpool = self._create_subnetpool() - with self.override_role(): - self.subnetpools_client.delete_subnetpool(subnetpool['id']) - - @rbac_rule_validation.action(service="neutron", rules=["get_subnetpool"]) - @decorators.idempotent_id('f1caf0f6-bde5-11e8-a355-529269fb1459') - def test_list_subnetpools(self): - """List subnetpools. - - RBAC test for the neutron ``list_subnetpools`` function and - the ``get_subnetpool`` policy - """ - admin_resource_id = self._create_subnetpool()['id'] - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = self.subnetpools_client.list_subnetpools( - id=admin_resource_id)["subnetpools"] diff --git a/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py b/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py deleted file mode 100644 index 2b03ece7..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_subnets_rbac.py +++ /dev/null @@ -1,103 +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.common import utils -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.network import rbac_base as base - - -class SubnetsRbacTest(base.BaseNetworkRbacTest): - - @classmethod - def skip_checks(cls): - super(SubnetsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('subnet_allocation', 'network'): - msg = "subnet_allocation extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(SubnetsRbacTest, cls).resource_setup() - cls.network = cls.create_network() - cls.subnet = cls.create_subnet(cls.network) - - @decorators.idempotent_id('0481adeb-4301-44d5-851c-35910cc18a6b') - @rbac_rule_validation.action(service="neutron", - rules=["create_subnet"]) - def test_create_subnet(self): - """Create subnet. - - RBAC test for the neutron "create_subnet" policy - """ - with self.override_role(): - self.create_subnet(self.network) - - @decorators.idempotent_id('c02618e7-bb20-4abd-83c8-6eec2af08752') - @rbac_rule_validation.action(service="neutron", - rules=["get_subnet"], - expected_error_codes=[404]) - def test_show_subnet(self): - """Show subnet. - - RBAC test for the neutron "get_subnet" policy - """ - with self.override_role(): - self.subnets_client.show_subnet(self.subnet['id']) - - @decorators.idempotent_id('e2ddc415-5cab-43f4-9b61-166aed65d637') - @rbac_rule_validation.action(service="neutron", rules=["get_subnet"]) - def test_list_subnets(self): - """List subnets. - - RBAC test for the neutron ``list_subnets`` function and - the ``get_subnet`` policy - """ - admin_resource_id = self.subnet['id'] - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = self.subnets_client.list_subnets( - id=admin_resource_id)["subnets"] - - @decorators.idempotent_id('f36cd821-dd22-4bd0-b43d-110fc4b553eb') - @rbac_rule_validation.action(service="neutron", - rules=["get_subnet", "update_subnet"], - expected_error_codes=[404, 403]) - def test_update_subnet(self): - """Update subnet. - - RBAC test for the neutron "update_subnet" policy - """ - update_name = data_utils.rand_name(self.__class__.__name__ + '-Subnet') - - with self.override_role(): - self.subnets_client.update_subnet(self.subnet['id'], - name=update_name) - - @decorators.idempotent_id('bcfc7153-bbd1-43a4-a908-b3e1b0cde0dc') - @rbac_rule_validation.action(service="neutron", - rules=["get_subnet", "delete_subnet"], - expected_error_codes=[404, 403]) - def test_delete_subnet(self): - """Delete subnet. - - RBAC test for the neutron "delete_subnet" policy - """ - subnet = self.create_subnet(self.network) - - with self.override_role(): - self.subnets_client.delete_subnet(subnet['id']) diff --git a/patrole_tempest_plugin/tests/api/network/test_trunks_rbac.py b/patrole_tempest_plugin/tests/api/network/test_trunks_rbac.py deleted file mode 100644 index 0e8719ee..00000000 --- a/patrole_tempest_plugin/tests/api/network/test_trunks_rbac.py +++ /dev/null @@ -1,201 +0,0 @@ -# Copyright 2018 AT&T Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.common import utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.network import rbac_base as base - - -class TrunksExtRbacTest(base.BaseNetworkExtRbacTest): - - @classmethod - def skip_checks(cls): - super(TrunksExtRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('trunk', 'network'): - msg = "trunk extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(TrunksExtRbacTest, cls).resource_setup() - cls.network = cls.create_network() - cls.port_id = cls.create_port(cls.network)["id"] - - def create_trunk(self, port_id): - trunk = self.ntp_client.create_trunk(port_id, []) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.ntp_client.delete_trunk, trunk["trunk"]['id']) - - return trunk - - @decorators.idempotent_id('c02618e7-bb20-1a3a-83c8-6eec2af08130') - @rbac_rule_validation.action(service="neutron", - rules=["create_trunk"]) - def test_create_trunk(self): - """Create trunk. - - RBAC test for the neutron "create_trunk" policy - """ - with self.override_role(): - self.create_trunk(self.port_id) - - @decorators.idempotent_id('c02618e7-bb20-1a3a-83c8-6eec2af08131') - @rbac_rule_validation.action(service="neutron", - rules=["get_trunk"], - expected_error_codes=[404]) - def test_show_trunk(self): - """Show trunk. - - RBAC test for the neutron "get_trunk" policy - """ - trunk = self.create_trunk(self.port_id) - - with self.override_role(): - self.ntp_client.show_trunk(trunk['trunk']['id']) - - @decorators.idempotent_id('c02618e7-bb20-1a3a-83c8-6eec2af08132') - @rbac_rule_validation.action(service="neutron", - rules=["get_trunk", - "delete_trunk"], - expected_error_codes=[404, 403]) - def test_delete_trunk(self): - """Delete trunk. - - RBAC test for the neutron "delete_trunk" policy - """ - trunk = self.create_trunk(self.port_id) - - with self.override_role(): - self.ntp_client.delete_trunk(trunk['trunk']['id']) - - @decorators.idempotent_id('047badd1-e4ff-40c5-9929-99ffcb8750a7') - @rbac_rule_validation.action(service="neutron", rules=["get_trunk"]) - def test_list_trunks(self): - """Show trunk. - - RBAC test for the neutron ``list_trunks``` function and - the ``get_trunk`` policy - """ - admin_resource_id = self.create_trunk(self.port_id)["trunk"]['id'] - with (self.override_role_and_validate_list( - admin_resource_id=admin_resource_id)) as ctx: - ctx.resources = self.ntp_client.list_trunks( - id=admin_resource_id)["trunks"] - - -class TrunksSubportsExtRbacTest(base.BaseNetworkExtRbacTest): - - @classmethod - def skip_checks(cls): - super(TrunksSubportsExtRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('trunk', 'network'): - msg = "trunk extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(TrunksSubportsExtRbacTest, cls).resource_setup() - cls.network = cls.create_network() - cls.port_id = cls.create_port(cls.network)["id"] - cls.trunk_id = cls.ntp_client.create_trunk( - cls.port_id, [])['trunk']['id'] - - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.ntp_client.delete_trunk, cls.trunk_id) - - def create_subports(self, trunk_id, port_id): - subports = [{'port_id': port_id, - 'segmentation_type': 'vlan', - 'segmentation_id': 4000}] - sub = self.ntp_client.add_subports(trunk_id, subports) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.ntp_client.remove_subports, - trunk_id, subports) - return sub["sub_ports"] - - @decorators.idempotent_id('c02618e7-bb20-1a3a-83c8-6eec2af08133') - @rbac_rule_validation.action(service="neutron", - rules=["get_trunk", - "get_subports"], - expected_error_codes=[404, 403]) - def test_get_subports(self): - """Get subports. - - RBAC test for the neutron "get_subports" policy. - - Error 403 expected due to implementation of subports as a part of - trunk object. - """ - network = self.create_network() - port = self.create_port(network) - - self.create_subports(self.trunk_id, port["id"]) - - with self.override_role(): - self.ntp_client.get_subports(self.trunk_id) - - @decorators.idempotent_id('c02618e7-bb20-1a3a-83c8-6eec2af08134') - @rbac_rule_validation.action(service="neutron", - rules=["get_trunk", - "add_subports"], - expected_error_codes=[404, 403]) - def test_add_subports(self): - """Add subports. - - RBAC test for the neutron "add_subports" policy - - Error 403 expected due to implementation of subports as a part of - trunk object. - """ - network = self.create_network() - port = self.create_port(network) - - subports = [{'port_id': port["id"], - 'segmentation_type': 'vlan', - 'segmentation_id': 4000}] - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.ntp_client.remove_subports, - self.trunk_id, subports) - - with self.override_role(): - self.ntp_client.add_subports(self.trunk_id, subports) - - @decorators.idempotent_id('c02618e7-bb20-1a3a-83c8-6eec2af08135') - @rbac_rule_validation.action(service="neutron", - rules=["get_trunk", - "remove_subports"], - expected_error_codes=[404, 403]) - def test_remove_subports(self): - """Remove subports. - - RBAC test for the neutron "remove_subports" policy - - Error 403 expected due to implementation of subports as a part of - trunk object. - """ - network = self.create_network() - port = self.create_port(network) - - subports = self.create_subports(self.trunk_id, port["id"]) - - with self.override_role(): - self.ntp_client.remove_subports(self.trunk_id, subports) diff --git a/patrole_tempest_plugin/tests/api/volume/__init__.py b/patrole_tempest_plugin/tests/api/volume/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/patrole_tempest_plugin/tests/api/volume/rbac_base.py b/patrole_tempest_plugin/tests/api/volume/rbac_base.py deleted file mode 100644 index e517b67c..00000000 --- a/patrole_tempest_plugin/tests/api/volume/rbac_base.py +++ /dev/null @@ -1,94 +0,0 @@ -# Copyright 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. - -from tempest.api.volume import base as vol_base -from tempest.common import waiters -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils - -from patrole_tempest_plugin import rbac_utils - - -class BaseVolumeRbacTest(rbac_utils.RbacUtilsMixin, - vol_base.BaseVolumeTest): - # NOTE(felipemonteiro): Patrole currently only tests the v3 Cinder API - # because it is the current API and because policy enforcement does not - # change between API major versions. So, it is not necessary to specify - # the `_api_version` in any test class. However, specify microversions in - # subclasses if necessary. - _api_version = 3 - - @classmethod - def setup_clients(cls): - super(BaseVolumeRbacTest, cls).setup_clients() - cls.volume_hosts_client = cls.os_primary.volume_hosts_client_latest - cls.volume_types_client = cls.os_primary.volume_types_client_latest - cls.groups_client = cls.os_primary.groups_client_latest - cls.group_types_client = cls.os_primary.group_types_client_latest - - @classmethod - def create_volume_type(cls, name=None, **kwargs): - """Create a test volume-type""" - name = name or data_utils.rand_name(cls.__name__ + '-volume-type') - volume_type = cls.volume_types_client.create_volume_type( - name=name, **kwargs)['volume_type'] - cls.addClassResourceCleanup( - cls.volume_types_client.wait_for_resource_deletion, - volume_type['id']) - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - cls.volume_types_client.delete_volume_type, volume_type['id']) - return volume_type - - @classmethod - def _create_backup(cls, volume_id, backup_client=None, **kwargs): - """Wrapper utility that returns a test backup. - - Tempest has an instance-level version. This is a class-level version. - """ - if backup_client is None: - backup_client = cls.backups_client - if 'name' not in kwargs: - name = data_utils.rand_name(cls.__name__ + '-Backup') - kwargs['name'] = name - - backup = backup_client.create_backup( - volume_id=volume_id, **kwargs)['backup'] - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - backup_client.wait_for_resource_deletion, backup['id']) - cls.addClassResourceCleanup( - test_utils.call_and_ignore_notfound_exc, - backup_client.delete_backup, backup['id']) - waiters.wait_for_volume_resource_status(backup_client, backup['id'], - 'available') - waiters.wait_for_volume_resource_status(cls.volumes_client, volume_id, - 'available') - return backup - - def create_group_type(self, name=None, ignore_notfound=False, **kwargs): - """Create a test group-type""" - name = name or data_utils.rand_name( - self.__class__.__name__ + '-group-type') - group_type = self.group_types_client.create_group_type( - name=name, **kwargs)['group_type'] - - if ignore_notfound: - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.group_types_client.delete_group_type, - group_type['id']) - else: - self.addCleanup(self.group_types_client.delete_group_type, - group_type['id']) - - return group_type diff --git a/patrole_tempest_plugin/tests/api/volume/test_capabilities_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_capabilities_rbac.py deleted file mode 100644 index 2860c2f0..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_capabilities_rbac.py +++ /dev/null @@ -1,45 +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.common import utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - - -class CapabilitiesV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def skip_checks(cls): - super(CapabilitiesV3RbacTest, cls).skip_checks() - if not utils.is_extension_enabled('capabilities', 'volume'): - msg = "%s skipped as capabilities not enabled." % cls.__name__ - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(CapabilitiesV3RbacTest, cls).setup_clients() - cls.capabilities_client = \ - cls.os_primary.volume_capabilities_client_latest - cls.hosts_client = cls.os_primary.volume_hosts_client_latest - - @rbac_rule_validation.action(service="cinder", - rules=["volume_extension:capabilities"]) - @decorators.idempotent_id('40928b74-2141-11e7-93ae-92361f002671') - def test_show_back_end_capabilities(self): - host = self.hosts_client.list_hosts()['hosts'][0]['host_name'] - with self.override_role(): - self.capabilities_client.show_backend_capabilities(host) diff --git a/patrole_tempest_plugin/tests/api/volume/test_encryption_types_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_encryption_types_rbac.py deleted file mode 100644 index 07bbd6b4..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_encryption_types_rbac.py +++ /dev/null @@ -1,119 +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. - -import functools - -from tempest.common import utils -from tempest import config -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - -CONF = config.CONF - - -def _get_volume_type_encryption_policy(action): - feature_flag = CONF.policy_feature_enabled.added_cinder_policies_stein - - if feature_flag: - return "volume_extension:volume_type_encryption:%s" % action - - return "volume_extension:volume_type_encryption" - - -_CREATE_VOLUME_TYPE_ENCRYPTION = functools.partial( - _get_volume_type_encryption_policy, "create") -_SHOW_VOLUME_TYPE_ENCRYPTION = functools.partial( - _get_volume_type_encryption_policy, "get") -_UPDATE_VOLUME_TYPE_ENCRYPTION = functools.partial( - _get_volume_type_encryption_policy, "update") -_DELETE_VOLUME_TYPE_ENCRYPTION = functools.partial( - _get_volume_type_encryption_policy, "delete") - - -class EncryptionTypesV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def skip_checks(cls): - super(EncryptionTypesV3RbacTest, cls).skip_checks() - if not utils.is_extension_enabled('encryption', 'volume'): - msg = "%s skipped as encryption not enabled." % cls.__name__ - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(EncryptionTypesV3RbacTest, cls).setup_clients() - cls.encryption_types_client = \ - cls.os_primary.encryption_types_client_latest - - def _create_volume_type_encryption(self): - vol_type_id = self.create_volume_type()['id'] - self.encryption_types_client.create_encryption_type( - vol_type_id, - provider="nova.volume.encryptors.luks.LuksEncryptor", - control_location="front-end")['encryption'] - return vol_type_id - - @decorators.idempotent_id('ffd94ce5-c24b-4b6c-84c9-c5aad8c3010c') - @rbac_rule_validation.action( - service="cinder", - rules=[_CREATE_VOLUME_TYPE_ENCRYPTION]) - def test_create_volume_type_encryption(self): - vol_type_id = self.create_volume_type()['id'] - with self.override_role(): - self.encryption_types_client.create_encryption_type( - vol_type_id, - provider="nova.volume.encryptors.luks.LuksEncryptor", - control_location="front-end")['encryption'] - - @decorators.idempotent_id('6599e72e-acef-4c0d-a9b2-463fca30d1da') - @rbac_rule_validation.action( - service="cinder", - rules=[_DELETE_VOLUME_TYPE_ENCRYPTION]) - def test_delete_volume_type_encryption(self): - vol_type_id = self._create_volume_type_encryption() - with self.override_role(): - self.encryption_types_client.delete_encryption_type(vol_type_id) - - @decorators.idempotent_id('42da9fec-32fd-4dca-9242-8a53b2fed25a') - @rbac_rule_validation.action( - service="cinder", - rules=[_UPDATE_VOLUME_TYPE_ENCRYPTION]) - def test_update_volume_type_encryption(self): - vol_type_id = self._create_volume_type_encryption() - with self.override_role(): - self.encryption_types_client.update_encryption_type( - vol_type_id, - control_location="front-end") - - @decorators.idempotent_id('1381a3dc-248f-4282-b231-c9399018c804') - @rbac_rule_validation.action( - service="cinder", - rules=[_SHOW_VOLUME_TYPE_ENCRYPTION]) - def test_show_volume_type_encryption(self): - vol_type_id = self._create_volume_type_encryption() - with self.override_role(): - self.encryption_types_client.show_encryption_type(vol_type_id) - - @decorators.idempotent_id('d4ed3cf8-52b2-4fa2-910d-e405361f0881') - @rbac_rule_validation.action( - service="cinder", - rules=[_SHOW_VOLUME_TYPE_ENCRYPTION]) - def test_show_encryption_specs_item(self): - vol_type_id = self._create_volume_type_encryption() - with self.override_role(): - self.encryption_types_client.show_encryption_specs_item( - vol_type_id, 'provider') diff --git a/patrole_tempest_plugin/tests/api/volume/test_group_snapshots_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_group_snapshots_rbac.py deleted file mode 100644 index 0b265e8a..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_group_snapshots_rbac.py +++ /dev/null @@ -1,200 +0,0 @@ -# Copyright 2017 NEC Corporation. -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest.common import utils -from tempest.common import waiters -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - - -class BaseGroupSnapshotsRbacTest(rbac_base.BaseVolumeRbacTest): - - def _create_group_snapshot(self, **kwargs): - if 'name' not in kwargs: - kwargs['name'] = data_utils.rand_name( - self.__class__.__name__ + '-Group_Snapshot') - group_snapshot = self.group_snapshots_client.create_group_snapshot( - **kwargs)['group_snapshot'] - group_snapshot['group_id'] = kwargs['group_id'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self._delete_group_snapshot, group_snapshot) - waiters.wait_for_volume_resource_status( - self.group_snapshots_client, group_snapshot['id'], 'available') - snapshots = self.snapshots_client.list_snapshots( - detail=True)['snapshots'] - for snap in snapshots: - if self.vol['id'] == snap['volume_id']: - waiters.wait_for_volume_resource_status( - self.snapshots_client, snap['id'], 'available') - return group_snapshot - - def _delete_group_snapshot(self, group_snapshot): - self.group_snapshots_client.delete_group_snapshot(group_snapshot['id']) - vols = self.volumes_client.list_volumes(detail=True)['volumes'] - snapshots = self.snapshots_client.list_snapshots( - detail=True)['snapshots'] - for vol in vols: - for snap in snapshots: - if (vol['group_id'] == group_snapshot['group_id'] and - vol['id'] == snap['volume_id']): - self.snapshots_client.wait_for_resource_deletion( - snap['id']) - self.group_snapshots_client.wait_for_resource_deletion( - group_snapshot['id']) - - -class GroupSnaphotsV314RbacTest(BaseGroupSnapshotsRbacTest): - _api_version = 3 - volume_min_microversion = '3.14' - volume_max_microversion = 'latest' - - @classmethod - def skip_checks(cls): - super(GroupSnaphotsV314RbacTest, cls).skip_checks() - if not utils.is_extension_enabled('groupsnapshot', 'volume'): - msg = "%s skipped as group snapshots not enabled." % cls.__name__ - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(GroupSnaphotsV314RbacTest, cls).setup_clients() - cls.group_snapshot_client = \ - cls.os_primary.group_snapshots_client_latest - - def setUp(self): - super(GroupSnaphotsV314RbacTest, self).setUp() - self.volume_type = self.create_volume_type() - self.group_type = self.create_group_type() - self.grp = self.create_group(group_type=self.group_type['id'], - volume_types=[self.volume_type['id']]) - self.vol = self.create_volume(volume_type=self.volume_type['id'], - group_id=self.grp['id']) - - @decorators.idempotent_id('653df0e8-d90a-474a-a5ce-3c2339aff7ba') - @rbac_rule_validation.action( - service="cinder", - rules=["group:create_group_snapshot"] - ) - def test_create_group_snapshot(self): - with self.override_role(): - name = data_utils.rand_name( - self.__class__.__name__ + '-Group_Snapshot') - group_snapshot = self.group_snapshots_client.create_group_snapshot( - name=name, group_id=self.grp['id'])['group_snapshot'] - group_snapshot['group_id'] = self.grp['id'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self._delete_group_snapshot, group_snapshot) - waiters.wait_for_volume_resource_status( - self.group_snapshots_client, group_snapshot['id'], 'available') - snapshots = self.snapshots_client.list_snapshots( - detail=True)['snapshots'] - for snap in snapshots: - if self.vol['id'] == snap['volume_id']: - waiters.wait_for_volume_resource_status( - self.snapshots_client, snap['id'], 'available') - - @decorators.idempotent_id('8b966844-4421-4f73-940b-9157cb878331') - @rbac_rule_validation.action( - service="cinder", - rules=["group:get_group_snapshot"] - ) - def test_show_group_snapshot_rbac(self): - group_snapshot_name = data_utils.rand_name('group_snapshot') - group_snapshot = self._create_group_snapshot(group_id=self.grp['id'], - name=group_snapshot_name) - with self.override_role(): - self.group_snapshots_client.show_group_snapshot( - group_snapshot['id']) - - @decorators.idempotent_id('e9de6dae-1efb-47cd-a3a8-d1f4b8f9f3ff') - @rbac_rule_validation.action( - service="cinder", - rules=["group:get_all_group_snapshots"] - ) - def test_list_group_snapshot_rbac(self): - with self.override_role(): - self.group_snapshots_client.list_group_snapshots() - - @decorators.idempotent_id('cf2e25ee-ca58-4ad6-b98d-33235c77db7b') - @rbac_rule_validation.action( - service="cinder", - rules=["group:delete_group_snapshot"] - ) - def test_delete_group_snapshot_rbac(self): - group_snapshot_name = data_utils.rand_name('group_snapshot') - group_snapshot = self._create_group_snapshot(group_id=self.grp['id'], - name=group_snapshot_name) - with self.override_role(): - self.group_snapshots_client.delete_group_snapshot( - group_snapshot['id']) - vols = self.volumes_client.list_volumes(detail=True)['volumes'] - snapshots = self.snapshots_client.list_snapshots( - detail=True)['snapshots'] - for vol in vols: - for snap in snapshots: - if (vol['group_id'] == group_snapshot['group_id'] and - vol['id'] == snap['volume_id']): - self.snapshots_client.wait_for_resource_deletion( - snap['id']) - self.group_snapshots_client.wait_for_resource_deletion( - group_snapshot['id']) - - -class GroupSnaphotsV319RbacTest(BaseGroupSnapshotsRbacTest): - _api_version = 3 - volume_min_microversion = '3.19' - volume_max_microversion = 'latest' - - @classmethod - def skip_checks(cls): - super(GroupSnaphotsV319RbacTest, cls).skip_checks() - if not utils.is_extension_enabled('groupsnapshot', 'volume'): - msg = "%s skipped as group snapshots not enabled." % cls.__name__ - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(GroupSnaphotsV319RbacTest, cls).setup_clients() - cls.group_snapshot_client = \ - cls.os_primary.group_snapshots_client_latest - - def setUp(self): - super(GroupSnaphotsV319RbacTest, self).setUp() - self.volume_type = self.create_volume_type() - self.group_type = self.create_group_type() - self.grp = self.create_group(group_type=self.group_type['id'], - volume_types=[self.volume_type['id']]) - self.vol = self.create_volume(volume_type=self.volume_type['id'], - group_id=self.grp['id']) - - @decorators.idempotent_id('3f0c842e-0c72-4f5e-a9c2-281070be3e2c') - @rbac_rule_validation.action( - service="cinder", - rules=["group:reset_group_snapshot_status"] - ) - def test_reset_group_snapshot_rbac(self): - group_snapshot_name = data_utils.rand_name('group_snapshot') - group_snapshot = self._create_group_snapshot(group_id=self.grp['id'], - name=group_snapshot_name) - with self.override_role(): - self.group_snapshots_client.reset_group_snapshot_status( - group_snapshot['id'], 'error') - - waiters.wait_for_volume_resource_status( - self.group_snapshots_client, group_snapshot['id'], 'error') diff --git a/patrole_tempest_plugin/tests/api/volume/test_group_type_specs.py b/patrole_tempest_plugin/tests/api/volume/test_group_type_specs.py deleted file mode 100644 index 3b93d093..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_group_type_specs.py +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright 2018 AT&T Corporation -# All Rights Reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); you may -# not use this file except in compliance with the License. You may obtain -# a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT -# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the -# License for the specific language governing permissions and limitations -# under the License. - -from tempest import config -from tempest.lib import decorators - -from patrole_tempest_plugin.tests.api.volume import rbac_base - -from patrole_tempest_plugin import rbac_rule_validation - -CONF = config.CONF - -if CONF.policy_feature_enabled.changed_cinder_policies_xena: - _GROUP_SPEC_SHOW = "group:group_types_specs:get" - _GROUP_SPEC_LIST = "group:group_types_specs:get_all" - _GROUP_SPEC_CREATE = "group:group_types_specs:create" - _GROUP_SPEC_UPDATE = "group:group_types_specs:update" - _GROUP_SPEC_DELETE = "group:group_types_specs:delete" -else: - _GROUP_SPEC_SHOW = "group:group_types_specs" - _GROUP_SPEC_LIST = "group:group_types_specs" - _GROUP_SPEC_CREATE = "group:group_types_specs" - _GROUP_SPEC_UPDATE = "group:group_types_specs" - _GROUP_SPEC_DELETE = "group:group_types_specs" - - -class GroupTypeSpecsRbacTest(rbac_base.BaseVolumeRbacTest): - _api_version = 3 - volume_min_microversion = '3.11' - volume_max_microversion = 'latest' - - @decorators.idempotent_id('b2859734-00ad-4a22-88ee-541698e90d12') - @rbac_rule_validation.action( - service="cinder", - rules=[_GROUP_SPEC_CREATE] - ) - def test_group_type_specs_create(self): - # Create new group type - group_type = self.create_group_type() - - # Create new group type specs - create_specs = { - "key1": "value1", - "key2": "value2" - } - - with self.override_role(): - self.group_types_client. \ - create_or_update_group_type_specs( - group_type['id'], create_specs)['group_specs'] - - @decorators.idempotent_id('469d0253-aa13-423f-8264-231ac17effbf') - @rbac_rule_validation.action( - service="cinder", - rules=[_GROUP_SPEC_SHOW] - ) - def test_group_type_specs_show(self): - group_type = self.create_group_type() - specs = { - "key1": "value1", - "key2": "value2" - } - self.group_types_client.create_or_update_group_type_specs( - group_type['id'], specs)['group_specs'] - # Show specified item of group type specs - with self.override_role(): - self.group_types_client.show_group_type_specs_item( - group_type['id'], 'key2') - - @decorators.idempotent_id('2e706a4e-dec9-46bf-9426-1c5b6f3ce102') - @rbac_rule_validation.action( - service="cinder", - rules=[_GROUP_SPEC_UPDATE] - ) - def test_group_type_specs_update(self): - group_type = self.create_group_type() - # Update specified item of group type specs - update_key = 'key3' - update_spec = {update_key: "value3-updated"} - self.group_types_client.create_or_update_group_type_specs( - group_type['id'], update_spec)['group_specs'] - with self.override_role(): - self.group_types_client.update_group_type_specs_item( - group_type['id'], update_key, update_spec) - - @decorators.idempotent_id('fd5e332b-fb2c-4957-ace9-11d60ddd5472') - @rbac_rule_validation.action( - service="cinder", - rules=[_GROUP_SPEC_LIST] - ) - def test_group_type_specs_list(self): - group_type = self.create_group_type() - with self.override_role(): - self.group_types_client.list_group_type_specs( - group_type['id'])['group_specs'] - - @decorators.idempotent_id('d9639a07-e441-4576-baf6-7ec732b16572') - @rbac_rule_validation.action( - service="cinder", - rules=[_GROUP_SPEC_DELETE] - ) - def test_group_type_specs_delete(self): - group_type = self.create_group_type() - # Delete specified item of group type specs - delete_key = 'key1' - specs = {'key1': 'value1'} - self.group_types_client.create_or_update_group_type_specs( - group_type['id'], specs)['group_specs'] - with self.override_role(): - self.group_types_client.delete_group_type_specs_item( - group_type['id'], delete_key) diff --git a/patrole_tempest_plugin/tests/api/volume/test_groups_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_groups_rbac.py deleted file mode 100644 index f0123844..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_groups_rbac.py +++ /dev/null @@ -1,237 +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.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 patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - -CONF = config.CONF - -if CONF.policy_feature_enabled.changed_cinder_policies_xena: - _GROUP_CREATE = "group:group_types:create" - _GROUP_UPDATE = "group:group_types:update" - _GROUP_DELETE = "group:group_types:delete" -else: - _GROUP_CREATE = "group:group_types_manage" - _GROUP_UPDATE = "group:group_types_manage" - _GROUP_DELETE = "group:group_types_manage" - - -class BaseGroupRbacTest(rbac_base.BaseVolumeRbacTest): - - def setUp(self): - super(BaseGroupRbacTest, self).setUp() - self.volume_type_id = self.create_volume_type()['id'] - self.group_type_id = self.create_group_type()['id'] - - def _create_group(self, name=None, ignore_notfound=False, **kwargs): - group_name = name or data_utils.rand_name( - self.__class__.__name__ + '-Group') - group = self.groups_client.create_group(name=group_name, **kwargs)[ - 'group'] - if ignore_notfound: - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self._delete_group, group['id']) - else: - self.addCleanup(self._delete_group, group['id']) - waiters.wait_for_volume_resource_status( - self.groups_client, group['id'], 'available') - return group - - def _delete_group(self, group_id): - self.groups_client.delete_group(group_id, delete_volumes=True) - self.groups_client.wait_for_resource_deletion(group_id) - - vols = self.volumes_client.list_volumes( - detail=True, params={'all_tenants': True})['volumes'] - for vol in vols: - if vol['group_id'] == group_id: - self.volumes_client.wait_for_resource_deletion( - vol['id']) - - -class GroupsV3RbacTest(BaseGroupRbacTest): - volume_min_microversion = '3.13' - volume_max_microversion = 'latest' - - @decorators.idempotent_id('43235328-66ae-424f-bc7f-f709c0ca268c') - @rbac_rule_validation.action( - service="cinder", - rules=["group:create"]) - def test_create_group(self, name=None): - - group_name = name or data_utils.rand_name( - self.__class__.__name__ + '-Group') - with self.override_role(): - group = self.groups_client.create_group( - name=group_name, group_type=self.group_type_id, - volume_types=[self.volume_type_id])['group'] - self.addCleanup(self._delete_group, group['id']) - - waiters.wait_for_volume_resource_status( - self.groups_client, group['id'], 'available') - - @decorators.idempotent_id('9dc34a62-ae3e-439e-92b6-9389ea4c2863') - @rbac_rule_validation.action( - service="cinder", - rules=["group:get"]) - def test_show_group(self): - group = self._create_group(group_type=self.group_type_id, - volume_types=[self.volume_type_id]) - - with self.override_role(): - self.groups_client.show_group(group['id']) - - @decorators.idempotent_id('db43841b-a173-4317-acfc-f83e4e48e4ee') - @rbac_rule_validation.action( - service="cinder", - rules=["group:get_all"]) - def test_list_groups(self): - with self.override_role(): - self.groups_client.list_groups()['groups'] - - @decorators.idempotent_id('5378da93-9c26-4ad4-b039-0555e2b8f668') - @rbac_rule_validation.action( - service="cinder", - rules=["group:get_all"]) - def test_list_groups_with_details(self): - with self.override_role(): - self.groups_client.list_groups(detail=True)['groups'] - - @decorators.idempotent_id('f499fc48-df83-4917-bf8d-783ebf6f080b') - @rbac_rule_validation.action( - service="cinder", - rules=["group:update"]) - def test_update_group(self): - group = self._create_group(group_type=self.group_type_id, - volume_types=[self.volume_type_id]) - updated_name = data_utils.rand_name(self.__class__.__name__ + '-Group') - - with self.override_role(): - self.groups_client.update_group(group['id'], name=updated_name) - - @decorators.idempotent_id('66fda391-5774-42a9-a018-80b34e57ab76') - @rbac_rule_validation.action( - service="cinder", - rules=["group:delete"]) - def test_delete_group(self): - - group = self._create_group(ignore_notfound=True, - group_type=self.group_type_id, - volume_types=[self.volume_type_id]) - group_id = group['id'] - with self.override_role(): - self.groups_client.delete_group(group_id, delete_volumes=True) - - self.groups_client.wait_for_resource_deletion(group_id) - vols = self.volumes_client.list_volumes( - detail=True, params={'all_tenants': True})['volumes'] - for vol in vols: - if vol['group_id'] == group_id: - self.volumes_client.wait_for_resource_deletion( - vol['id']) - - -class GroupV320RbacTest(BaseGroupRbacTest): - _api_version = 3 - volume_min_microversion = '3.20' - volume_max_microversion = 'latest' - - @decorators.idempotent_id('b849c1d4-3215-4f9d-b1e6-0aeb4b2b65ac') - @rbac_rule_validation.action( - service="cinder", - rules=["group:reset_status"]) - def test_reset_group_status(self): - group = self._create_group(ignore_notfound=False, - group_type=self.group_type_id, - volume_types=[self.volume_type_id]) - status = 'available' - with self.override_role(): - self.groups_client.reset_group_status(group['id'], - status) - waiters.wait_for_volume_resource_status( - self.groups_client, group['id'], status) - - -class GroupTypesV3RbacTest(rbac_base.BaseVolumeRbacTest): - volume_min_microversion = '3.11' - volume_max_microversion = 'latest' - - @decorators.idempotent_id('2820f12c-4681-4c7f-b28d-e6925637dff6') - @rbac_rule_validation.action( - service="cinder", - rules=[_GROUP_CREATE]) - def test_create_group_type(self): - with self.override_role(): - self.create_group_type(ignore_notfound=True) - - @decorators.idempotent_id('f77f8156-4fc9-4f02-be15-8930f748e10c') - @rbac_rule_validation.action( - service="cinder", - rules=[_GROUP_DELETE]) - def test_delete_group_type(self): - group_type = self.create_group_type(ignore_notfound=True) - - with self.override_role(): - self.group_types_client.delete_group_type(group_type['id']) - - @decorators.idempotent_id('67929954-4551-4d22-b15a-27fb6e56b711') - @rbac_rule_validation.action( - service="cinder", - rules=[_GROUP_DELETE]) - def test_update_group_type(self): - group_type = self.create_group_type() - update_params = { - 'name': data_utils.rand_name( - self.__class__.__name__ + '-updated-group-type'), - 'description': 'updated-group-type-desc' - } - with self.override_role(): - self.group_types_client.update_group_type( - group_type['id'], **update_params) - - @decorators.idempotent_id('a5f88c26-df7c-4f21-a3ae-7a4c2d6212b4') - @rbac_rule_validation.action( - service="cinder", - rules=["group:access_group_types_specs"]) - def test_create_group_type_group_specs(self): - # TODO(felipemonteiro): Combine with ``test_create_group_type`` - # once multiple policy testing is supported. This policy is - # only enforced after "group:group_types_manage". - with self.override_role(): - group_type = self.create_group_type(ignore_notfound=True) - - if 'group_specs' not in group_type: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='group_specs') - - @decorators.idempotent_id('8d9e2831-24c3-47b7-a76a-2e563287f12f') - @rbac_rule_validation.action( - service="cinder", - rules=["group:access_group_types_specs"]) - def test_show_group_type(self): - group_type = self.create_group_type() - with self.override_role(): - resp_body = self.group_types_client.show_group_type( - group_type['id'])['group_type'] - if 'group_specs' not in resp_body: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute='group_specs') diff --git a/patrole_tempest_plugin/tests/api/volume/test_limits_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_limits_rbac.py deleted file mode 100644 index 32baf561..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_limits_rbac.py +++ /dev/null @@ -1,55 +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. - -import testtools - -from tempest import config -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - -CONF = config.CONF - - -class LimitsV3RbacTest(rbac_base.BaseVolumeRbacTest): - _api_version = 3 - - @testtools.skipUnless( - CONF.policy_feature_enabled.limits_extension_used_limits_policy, - '"limits_extension:used_limits" must be available in the cloud.') - @decorators.idempotent_id('dab04510-5b86-4479-a633-6e496ff405af') - @rbac_rule_validation.action(service="cinder", - rules=["limits_extension:used_limits"]) - def test_show_limits(self): - # It is enough to check whether any of the following keys below - # are in the response body under ['limits']['absolute'], but no harm - # in checking for them all. - expected_keys = { - 'totalVolumesUsed', - 'totalGigabytesUsed', - 'totalSnapshotsUsed', - 'totalBackupsUsed', - 'totalBackupGigabytesUsed' - } - - with self.override_role(): - absolute_limits = self.volume_limits_client.show_limits()[ - 'limits']['absolute'] - for key in expected_keys: - if key not in absolute_limits: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=key) diff --git a/patrole_tempest_plugin/tests/api/volume/test_qos_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_qos_rbac.py deleted file mode 100644 index be8424e6..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_qos_rbac.py +++ /dev/null @@ -1,148 +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.common import waiters -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - - -class VolumeQOSV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def setup_clients(cls): - super(VolumeQOSV3RbacTest, cls).setup_clients() - cls.qos_client = cls.os_primary.volume_qos_client_latest - - def _create_test_qos_specs(self, name=None, consumer=None, **kwargs): - name = name or data_utils.rand_name(self.__class__.__name__ + '-QoS') - consumer = consumer or 'front-end' - qos_specs = self.qos_client.create_qos( - name=name, consumer=consumer, **kwargs)['qos_specs'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.qos_client.delete_qos, qos_specs['id']) - return qos_specs - - @rbac_rule_validation.action( - service="cinder", rules=["volume_extension:qos_specs_manage:create"]) - @decorators.idempotent_id('4f9f45f0-b379-4577-a279-cec3e917cbec') - def test_create_qos_with_consumer(self): - with self.override_role(): - self._create_test_qos_specs() - - @rbac_rule_validation.action( - service="cinder", rules=["volume_extension:qos_specs_manage:delete"]) - @decorators.idempotent_id('fbc8a77e-6b6d-45ae-bebe-c496eb8f06f7') - def test_delete_qos_with_consumer(self): - qos = self._create_test_qos_specs() - with self.override_role(): - self.qos_client.delete_qos(qos['id']) - - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:qos_specs_manage:get"]) - @decorators.idempotent_id('22aff0dd-0343-408d-ae80-e77551956e14') - def test_show_qos(self): - qos = self._create_test_qos_specs() - with self.override_role(): - self.qos_client.show_qos(qos['id'])['qos_specs'] - - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:qos_specs_manage:get_all"]) - @decorators.idempotent_id('ff1e98f3-d456-40a9-96d4-c7e4a55dcffa') - def test_get_association_qos(self): - qos = self._create_test_qos_specs() - vol_type = self.create_volume_type()['id'] - self.qos_client.associate_qos(qos['id'], vol_type) - self.addCleanup(self.qos_client.disassociate_qos, qos['id'], vol_type) - - with self.override_role(): - self.qos_client.show_association_qos(qos['id']) - - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:qos_specs_manage:get_all"]) - @decorators.idempotent_id('546b8bb1-04a4-4387-9506-a538a7f3cd6a') - def test_list_qos(self): - with self.override_role(): - self.qos_client.list_qos()['qos_specs'] - - @rbac_rule_validation.action( - service="cinder", rules=["volume_extension:qos_specs_manage:update"]) - @decorators.idempotent_id('89b630b7-c170-47c3-ac80-50ed425c2d98') - def test_set_qos_key(self): - qos = self._create_test_qos_specs() - with self.override_role(): - self.qos_client.set_qos_key( - qos['id'], iops_bytes='500')['qos_specs'] - - @rbac_rule_validation.action( - service="cinder", rules=["volume_extension:qos_specs_manage:update"]) - @decorators.idempotent_id('6c50c837-de77-4dae-a2ec-30e05c62969c') - def test_unset_qos_key(self): - qos = self._create_test_qos_specs() - self.qos_client.set_qos_key(qos['id'], iops_bytes='500')['qos_specs'] - - with self.override_role(): - self.qos_client.unset_qos_key(qos['id'], ['iops_bytes']) - waiters.wait_for_qos_operations(self.qos_client, qos['id'], - 'qos-key-unset', args=['iops_bytes']) - - @rbac_rule_validation.action( - service="cinder", rules=["volume_extension:qos_specs_manage:update"]) - @decorators.idempotent_id('2047b347-8bbe-405e-bf5a-c75a0d7e3930') - def test_associate_qos(self): - qos = self._create_test_qos_specs() - vol_type = self.create_volume_type()['id'] - - with self.override_role(): - self.qos_client.associate_qos(qos['id'], vol_type) - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.qos_client.disassociate_qos, qos['id'], vol_type) - - @rbac_rule_validation.action( - service="cinder", rules=["volume_extension:qos_specs_manage:update"]) - @decorators.idempotent_id('f12aeca1-0c02-4f33-b805-014171e5b2d4') - def test_disassociate_qos(self): - qos = self._create_test_qos_specs() - vol_type = self.create_volume_type()['id'] - self.qos_client.associate_qos(qos['id'], vol_type) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.qos_client.disassociate_qos, qos['id'], vol_type) - - with self.override_role(): - self.qos_client.disassociate_qos(qos['id'], vol_type) - waiters.wait_for_qos_operations(self.qos_client, qos['id'], - 'disassociate', args=vol_type) - - @rbac_rule_validation.action( - service="cinder", rules=["volume_extension:qos_specs_manage:update"]) - @decorators.idempotent_id('9f6e664d-a5d9-4e71-b122-73a3086be1b9') - def test_disassociate_all_qos(self): - qos = self._create_test_qos_specs() - vol_type = self.create_volume_type()['id'] - self.qos_client.associate_qos(qos['id'], vol_type) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.qos_client.disassociate_qos, qos['id'], vol_type) - - with self.override_role(): - self.qos_client.disassociate_all_qos(qos['id']) - waiters.wait_for_qos_operations(self.qos_client, qos['id'], - 'disassociate-all') diff --git a/patrole_tempest_plugin/tests/api/volume/test_quota_classes_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_quota_classes_rbac.py deleted file mode 100644 index f29fff1f..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_quota_classes_rbac.py +++ /dev/null @@ -1,68 +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.common import utils -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.volume import rbac_base - -CONF = config.CONF - -if CONF.policy_feature_enabled.changed_cinder_policies_xena: - _QUOTA_SET_SHOW = "volume_extension:quota_classes:get" - _QUOTA_SET_UPDATE = "volume_extension:quota_classes:update" -else: - _QUOTA_SET_SHOW = "volume_extension:quota_classes" - _QUOTA_SET_UPDATE = "volume_extension:quota_classes" - - -class QuotaClassesV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def skip_checks(cls): - super(QuotaClassesV3RbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-quota-class-sets', 'volume'): - msg = ("%s skipped as os-quota-class-sets not enabled." - % cls.__name__) - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(QuotaClassesV3RbacTest, cls).setup_clients() - cls.quota_classes_client = cls.os_primary.quota_classes_client - cls.quota_name = data_utils.rand_name(cls.__name__ + '-QuotaClass') - - @decorators.idempotent_id('1a060def-2b43-4534-97f5-5eadbbe8c726') - @rbac_rule_validation.action(service="cinder", - rules=[_QUOTA_SET_SHOW]) - def test_show_quota_class_set(self): - with self.override_role(): - self.quota_classes_client.show_quota_class_set( - self.quota_name)['quota_class_set'] - - @decorators.idempotent_id('72159478-23a7-4c75-989f-6bac609eca62') - @rbac_rule_validation.action(service="cinder", - rules=[_QUOTA_SET_UPDATE]) - def test_update_quota_class_set(self): - quota_class_set = self.quota_classes_client.show_quota_class_set( - self.quota_name)['quota_class_set'] - quota_class_set.pop('id') - - with self.override_role(): - self.quota_classes_client.update_quota_class_set(self.quota_name, - **quota_class_set) diff --git a/patrole_tempest_plugin/tests/api/volume/test_scheduler_stats_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_scheduler_stats_rbac.py deleted file mode 100644 index 5bb57e77..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_scheduler_stats_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.common import utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - - -class SchedulerStatsV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def skip_checks(cls): - super(SchedulerStatsV3RbacTest, cls).skip_checks() - if not utils.is_extension_enabled('scheduler-stats', 'volume'): - msg = "%s skipped as scheduler-stats not enabled." % cls.__name__ - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(SchedulerStatsV3RbacTest, cls).setup_clients() - cls.scheduler_stats_client =\ - cls.os_primary.volume_scheduler_stats_client_latest - - @rbac_rule_validation.action( - service="cinder", - rules=["scheduler_extension:scheduler_stats:get_pools"]) - @decorators.idempotent_id('5f800441-4d30-48ec-9e5b-0d55bc86acbb') - def test_list_back_end_storage_pools(self): - with self.override_role(): - self.scheduler_stats_client.list_pools() diff --git a/patrole_tempest_plugin/tests/api/volume/test_snapshot_manage_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_snapshot_manage_rbac.py deleted file mode 100644 index f083924a..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_snapshot_manage_rbac.py +++ /dev/null @@ -1,82 +0,0 @@ -# Copyright 2017 NEC 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 import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions as lib_exc - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - -CONF = config.CONF - - -class SnapshotManageRbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def skip_checks(cls): - super(SnapshotManageRbacTest, cls).skip_checks() - if not CONF.volume_feature_enabled.manage_snapshot: - raise cls.skipException("Manage snapshot tests are disabled") - if len(CONF.volume.manage_snapshot_ref) != 2: - msg = ("Manage snapshot ref is not correctly configured, " - "it should be a list of two elements") - raise lib_exc.InvalidConfiguration(msg) - - @classmethod - def setup_clients(cls): - super(SnapshotManageRbacTest, cls).setup_clients() - cls.snapshot_manage_client = \ - cls.os_primary.snapshot_manage_client_latest - - @classmethod - def resource_setup(cls): - super(SnapshotManageRbacTest, cls).resource_setup() - cls.volume = cls.create_volume() - cls.snapshot = cls.create_snapshot(volume_id=cls.volume['id']) - - @decorators.idempotent_id('bd7d62f2-e485-4626-87ef-03b7f19ee1d0') - @rbac_rule_validation.action( - service="cinder", - rules=["snapshot_extension:snapshot_manage"]) - def test_manage_snapshot_rbac(self): - name = data_utils.rand_name(self.__class__.__name__ + - '-Managed-Snapshot') - snapshot_ref = { - 'volume_id': self.volume['id'], - 'ref': {CONF.volume.manage_snapshot_ref[0]: - CONF.volume.manage_snapshot_ref[1] % self.snapshot['id']}, - 'name': name - } - with self.override_role(): - snapshot = self.snapshot_manage_client.manage_snapshot( - **snapshot_ref)['snapshot'] - self.addCleanup(self.delete_snapshot, snapshot['id'], - self.snapshots_client) - waiters.wait_for_volume_resource_status(self.snapshots_client, - snapshot['id'], - 'available') - - @decorators.idempotent_id('4a2e8934-9c0b-434e-8f0b-e18b9aff126f') - @rbac_rule_validation.action( - service="cinder", - rules=["snapshot_extension:snapshot_unmanage"]) - def test_unmanage_snapshot_rbac(self): - with self.override_role(): - self.snapshots_client.unmanage_snapshot(self.snapshot['id']) - self.snapshots_client.wait_for_resource_deletion( - self.snapshot['id']) diff --git a/patrole_tempest_plugin/tests/api/volume/test_snapshots_actions_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_snapshots_actions_rbac.py deleted file mode 100644 index b3714ba5..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_snapshots_actions_rbac.py +++ /dev/null @@ -1,87 +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.common import waiters -from tempest import config -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - -CONF = config.CONF - - -class SnapshotsActionsV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def skip_checks(cls): - super(SnapshotsActionsV3RbacTest, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder snapshot feature disabled") - - @classmethod - def resource_setup(cls): - super(SnapshotsActionsV3RbacTest, cls).resource_setup() - cls.volume = cls.create_volume() - cls.snapshot = cls.create_snapshot(volume_id=cls.volume['id']) - cls.snapshot_id = cls.snapshot['id'] - - def tearDown(self): - # Set snapshot's status to available after test - status = 'available' - self.snapshots_client.reset_snapshot_status(self.snapshot_id, - status) - waiters.wait_for_volume_resource_status(self.snapshots_client, - self.snapshot_id, status) - super(SnapshotsActionsV3RbacTest, self).tearDown() - - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:snapshot_admin_actions:reset_status"]) - @decorators.idempotent_id('ea430145-34ef-408d-b678-95d5ae5f46eb') - def test_reset_snapshot_status(self): - status = 'error' - with self.override_role(): - self.snapshots_client.reset_snapshot_status( - self.snapshot['id'], status) - waiters.wait_for_volume_resource_status( - self.snapshots_client, self.snapshot['id'], status) - - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:snapshot_admin_actions:force_delete"]) - @decorators.idempotent_id('a8b0f7d8-4c00-4645-b8d5-33ab4eecc6cb') - def test_snapshot_force_delete(self): - temp_snapshot = self.create_snapshot(self.volume['id']) - - with self.override_role(): - self.snapshots_client.force_delete_snapshot(temp_snapshot['id']) - self.snapshots_client.wait_for_resource_deletion(temp_snapshot['id']) - - @decorators.idempotent_id('a95eab2a-c441-4609-9235-f7478627da88') - @rbac_rule_validation.action( - service="cinder", - rules=["snapshot_extension:snapshot_actions:update_snapshot_status"]) - def test_update_snapshot_status(self): - status = 'creating' - self.snapshots_client.reset_snapshot_status( - self.snapshot['id'], status) - waiters.wait_for_volume_resource_status(self.snapshots_client, - self.snapshot['id'], status) - with self.override_role(): - self.snapshots_client.update_snapshot_status(self.snapshot['id'], - status="creating") - waiters.wait_for_volume_resource_status( - self.snapshots_client, self.snapshot['id'], status) diff --git a/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py deleted file mode 100644 index bf452ce7..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_snapshots_metadata_rbac.py +++ /dev/null @@ -1,110 +0,0 @@ -# Copyright 2016 AT&T Corp -# 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.volume import rbac_base - -CONF = config.CONF - - -class SnapshotMetadataV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def skip_checks(cls): - super(SnapshotMetadataV3RbacTest, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder snapshot feature disabled") - - @classmethod - def resource_setup(cls): - super(SnapshotMetadataV3RbacTest, cls).resource_setup() - cls.volume = cls.create_volume() - # Create a snapshot - cls.snapshot = cls.create_snapshot(volume_id=cls.volume['id']) - cls.snapshot_id = cls.snapshot['id'] - - @classmethod - def _create_test_snapshot_metadata(cls): - # Create test snapshot metadata - metadata = {"key1": "value1", - "key2": "value2", - "key3": "value3"} - cls.snapshots_client.create_snapshot_metadata( - cls.snapshot_id, metadata)['metadata'] - - @rbac_rule_validation.action(service="cinder", - rules=["volume:get_snapshot_metadata"]) - @decorators.idempotent_id('f6912bb1-62e6-483d-bcd0-e98c1641f4c3') - def test_get_snapshot_metadata(self): - # Create volume and snapshot metadata - self._create_test_snapshot_metadata() - # Get metadata for the snapshot - with self.override_role(): - self.snapshots_client.show_snapshot_metadata( - self.snapshot_id) - - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:volume_tenant_attribute"]) - @decorators.idempotent_id('e2c73b00-0c19-4bb7-8c61-d84b1a223ed1') - def test_get_snapshot_metadata_for_volume_tenant(self): - # Create volume and snapshot metadata - self._create_test_snapshot_metadata() - # Get the metadata of the snapshot - with self.override_role(): - self.snapshots_client.show_snapshot_metadata( - self.snapshot_id)['metadata'] - - @decorators.idempotent_id('7ea597f6-c544-4b10-aab0-ff68f595fb06') - @rbac_rule_validation.action(service="cinder", - rules=["volume:update_snapshot_metadata"]) - def test_update_snapshot_metadata(self): - self._create_test_snapshot_metadata() - with self.override_role(): - update = {"key3": "value3_update", - "key4": "value4"} - self.snapshots_client.update_snapshot_metadata( - self.snapshot['id'], metadata=update) - - @decorators.idempotent_id('93068d02-0131-4dd3-af16-fc40d7128d93') - @rbac_rule_validation.action(service="cinder", - rules=["volume:get_snapshot_metadata"]) - def test_show_snapshot_metadata_item(self): - self._create_test_snapshot_metadata() - with self.override_role(): - self.snapshots_client.show_snapshot_metadata_item( - self.snapshot['id'], "key3")['meta'] - - @decorators.idempotent_id('1f8f43e7-da31-4128-bb3c-73fc548650e3') - @rbac_rule_validation.action(service="cinder", - rules=["volume:update_snapshot_metadata"]) - def test_update_snapshot_metadata_item(self): - update_item = {"key3": "value3_update"} - self._create_test_snapshot_metadata() - with self.override_role(): - self.snapshots_client.update_snapshot_metadata_item( - self.snapshot['id'], "key3", meta=update_item)['meta'] - - @decorators.idempotent_id('3ec32516-f7cd-4f88-b78a-ddee67492071') - @rbac_rule_validation.action(service="cinder", - rules=["volume:delete_snapshot_metadata"]) - def test_delete_snapshot_metadata_item(self): - self._create_test_snapshot_metadata() - with self.override_role(): - self.snapshots_client.delete_snapshot_metadata_item( - self.snapshot['id'], "key1") diff --git a/patrole_tempest_plugin/tests/api/volume/test_user_messages_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_user_messages_rbac.py deleted file mode 100644 index 3feb2dfc..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_user_messages_rbac.py +++ /dev/null @@ -1,92 +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.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - -CONF = config.CONF - - -class MessagesV3RbacTest(rbac_base.BaseVolumeRbacTest): - volume_min_microversion = '3.3' - volume_max_microversion = 'latest' - - @classmethod - def setup_clients(cls): - super(MessagesV3RbacTest, cls).setup_clients() - cls.messages_client = cls.os_primary.volume_messages_client_latest - - def _create_user_message(self): - """Trigger a 'no valid host' situation to generate a message.""" - bad_protocol = data_utils.rand_name( - self.__class__.__name__ + '-storage_protocol') - bad_vendor = data_utils.rand_name( - self.__class__.__name__ + '-vendor_name') - extra_specs = {'storage_protocol': bad_protocol, - 'vendor_name': bad_vendor} - vol_type_name = data_utils.rand_name( - self.__class__.__name__ + '-volume-type') - bogus_type = self.create_volume_type( - name=vol_type_name, extra_specs=extra_specs) - params = {'volume_type': bogus_type['id'], - 'size': CONF.volume.volume_size} - volume = self.create_volume(wait_until="error", **params) - messages = self.messages_client.list_messages()['messages'] - message_id = None - for message in messages: - if message['resource_uuid'] == volume['id']: - message_id = message['id'] - break - self.assertIsNotNone(message_id, 'No user message generated for ' - 'volume %s' % volume['id']) - - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.messages_client.delete_message, message_id) - - return message_id - - @decorators.idempotent_id('bf7f31a1-509b-4a7d-a8a8-ad6ce68229c7') - @rbac_rule_validation.action( - service="cinder", - rules=["message:get_all"]) - def test_list_messages(self): - with self.override_role(): - self.messages_client.list_messages()['messages'] - - @decorators.idempotent_id('9cc1ad1e-68a2-4407-8b60-ea77909bce08') - @rbac_rule_validation.action( - service="cinder", - rules=["message:get"]) - def test_show_message(self): - message_id = self._create_user_message() - - with self.override_role(): - self.messages_client.show_message(message_id)['message'] - - @decorators.idempotent_id('65ca7fb7-7f2c-443e-b144-ac86973a97be') - @rbac_rule_validation.action( - service="cinder", - rules=["message:delete"]) - def test_delete_message(self): - message_id = self._create_user_message() - - with self.override_role(): - self.messages_client.delete_message(message_id) - self.messages_client.wait_for_resource_deletion(message_id) 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 deleted file mode 100644 index e3311eae..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_volume_actions_rbac.py +++ /dev/null @@ -1,293 +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. - -import testtools - -from tempest.common import compute -from tempest.common import utils -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 patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - -CONF = config.CONF - - -class VolumesActionsV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def setup_clients(cls): - super(VolumesActionsV3RbacTest, cls).setup_clients() - cls.image_client = cls.os_primary.image_client_v2 - - @classmethod - def setup_credentials(cls): - cls.set_network_resources(network=True, subnet=True, router=True) - super(VolumesActionsV3RbacTest, cls).setup_credentials() - - @classmethod - def resource_setup(cls): - super(VolumesActionsV3RbacTest, cls).resource_setup() - cls.volume = cls.create_volume() - - def _create_server(self): - tenant_network = self.get_tenant_network() - server, _ = compute.create_test_server( - self.os_primary, tenant_network=tenant_network, - wait_until='ACTIVE') - self.addCleanup(waiters.wait_for_server_termination, - self.servers_client, server['id']) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.servers_client.delete_server, server['id']) - return 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=volume_id, - device='/dev/%s' % CONF.compute.volume_device_name) - waiters.wait_for_volume_resource_status( - self.volumes_client, volume_id, 'in-use') - self.addCleanup(self._detach_volume, 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, volume_id, 'available') - - @testtools.skipUnless( - CONF.policy_feature_enabled - .volume_extension_volume_actions_attach_policy, - '"volume_extension:volume_actions:attach" must be available in the ' - 'cloud.') - @utils.services('compute') - @decorators.attr(type='slow') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:volume_actions:attach"]) - @decorators.idempotent_id('f97b10e4-2eed-4f8b-8632-71c02cb9fe42') - def test_attach_volume_to_instance(self): - server = self._create_server() - volume_id = self.volume['id'] - - with self.override_role(): - self.servers_client.attach_volume( - server['id'], volumeId=volume_id, - device='/dev/%s' % CONF.compute.volume_device_name) - waiters.wait_for_volume_resource_status( - self.volumes_client, volume_id, 'in-use') - self.addCleanup(self._detach_volume, volume_id) - - @utils.services('compute') - @decorators.attr(type='slow') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:volume_actions:detach"]) - @decorators.idempotent_id('5a042f6a-688b-42e6-a02e-fe5c47b89b07') - def test_detach_volume_from_instance(self): - server = self._create_server() - self._attach_volume(server) - volume_id = self.volume['id'] - - with self.override_role(): - self.volumes_client.detach_volume(volume_id) - waiters.wait_for_volume_resource_status( - self.volumes_client, volume_id, 'available') - - @rbac_rule_validation.action(service="cinder", - rules=["volume:update_readonly_flag"]) - @decorators.idempotent_id('2750717a-f250-4e41-9e09-02624aad6ff8') - def test_volume_readonly_update(self): - with self.override_role(): - self.volumes_client.update_volume_readonly(self.volume['id'], - readonly=True) - self.addCleanup(self.volumes_client.update_volume_readonly, - self.volume['id'], readonly=False) - - @decorators.idempotent_id('59b783c0-f4ef-430c-8a90-1bad97d4ec5c') - @rbac_rule_validation.action(service="cinder", - rules=["volume:update"]) - def test_volume_set_bootable(self): - with self.override_role(): - self.volumes_client.set_bootable_volume(self.volume['id'], - bootable=True) - - @testtools.skipUnless( - CONF.policy_feature_enabled - .volume_extension_volume_actions_reserve_policy, - '"volume_extension:volume_actions:reserve" must be available in the ' - 'cloud.') - @decorators.idempotent_id('41566922-75a1-4484-99c7-9c8782ee99ac') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:volume_actions:reserve"]) - def test_volume_reserve(self): - with self.override_role(): - self.volumes_client.reserve_volume(self.volume['id']) - - @testtools.skipUnless( - CONF.policy_feature_enabled - .volume_extension_volume_actions_unreserve_policy, - '"volume_extension:volume_actions:unreserve" must be available in the ' - 'cloud.') - @decorators.idempotent_id('e5fa9564-77d9-4e57-b0c0-3e0ae4d08535') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:volume_actions:unreserve"]) - def test_volume_unreserve(self): - with self.override_role(): - self.volumes_client.unreserve_volume(self.volume['id']) - - @decorators.idempotent_id('c015c82f-7010-48cc-bd71-4ef542046f20') - @rbac_rule_validation.action(service="cinder", - rules=["volume:retype"]) - def test_volume_retype(self): - vol_type = self.create_volume_type()['name'] - volume = self.create_volume() - - with self.override_role(): - self.volumes_client.retype_volume(volume['id'], new_type=vol_type) - waiters.wait_for_volume_retype( - self.volumes_client, volume['id'], vol_type) - - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:volume_admin_actions:reset_status"]) - @decorators.idempotent_id('4b3dad7d-0e73-4839-8781-796dd3d7af1d') - def test_volume_reset_status(self): - volume = self.create_volume() - - with self.override_role(): - self.volumes_client.reset_volume_status( - volume['id'], status='error') - - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:volume_admin_actions:force_delete"]) - @decorators.idempotent_id('a312a937-6abf-4b91-a950-747086cbce48') - def test_volume_force_delete(self): - volume = self.create_volume() - self.volumes_client.reset_volume_status(volume['id'], status='error') - - with self.override_role(): - self.volumes_client.force_delete_volume(volume['id']) - self.volumes_client.wait_for_resource_deletion(volume['id']) - - @decorators.idempotent_id('48bd302b-950a-4830-840c-3158246ecdcc') - @utils.services('compute') - @rbac_rule_validation.action( - service="cinder", - rules=["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, volume['id']) - attachment = self.volumes_client.show_volume( - volume['id'])['volume']['attachments'][0] - - # Reset volume's status to error. - self.volumes_client.reset_volume_status(volume['id'], status='error') - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'error') - with self.override_role(): - self.volumes_client.force_detach_volume( - volume['id'], connector=None, - attachment_id=attachment['attachment_id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - - -class VolumesActionsV310RbacTest(rbac_base.BaseVolumeRbacTest): - _api_version = 3 - volume_min_microversion = '3.10' - volume_max_microversion = 'latest' - - @classmethod - def setup_clients(cls): - super(VolumesActionsV310RbacTest, cls).setup_clients() - cls.image_client = cls.os_primary.image_client_v2 - - @classmethod - def resource_setup(cls): - super(VolumesActionsV310RbacTest, cls).resource_setup() - cls.volume = cls.create_volume() - - @decorators.attr(type=["slow"]) - @utils.services('image') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:volume_actions:upload_image"]) - @decorators.idempotent_id('b0d0da46-903c-4445-893e-20e680d68b50') - def test_volume_upload_image(self): - # TODO(felipemonteiro): The ``upload_volume`` endpoint also enforces - # "volume:copy_volume_to_image". - image_name = data_utils.rand_name(self.__class__.__name__ + '-Image') - - with self.override_role(): - body = self.volumes_client.upload_volume( - self.volume['id'], image_name=image_name, visibility="private", - disk_format=CONF.volume.disk_format)['os-volume_upload_image'] - image_id = body["image_id"] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.image_client.delete_image, - image_id) - waiters.wait_for_image_status(self.image_client, image_id, - 'active') - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], 'available') - - @decorators.attr(type=["slow"]) - @utils.services('image') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:volume_actions:upload_public"]) - @decorators.idempotent_id('578a84dd-a6bd-4f97-a418-4a0c3c272c08') - def test_volume_upload_public(self): - # This also enforces "volume_extension:volume_actions:upload_image". - image_name = data_utils.rand_name(self.__class__.__name__ + '-Image') - - with self.override_role(): - body = self.volumes_client.upload_volume( - self.volume['id'], image_name=image_name, visibility="public", - disk_format=CONF.volume.disk_format)['os-volume_upload_image'] - image_id = body["image_id"] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.image_client.delete_image, - image_id) - waiters.wait_for_image_status(self.image_client, image_id, - 'active') - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], 'available') - - -class VolumesActionsV312RbacTest(rbac_base.BaseVolumeRbacTest): - _api_version = 3 - volume_min_microversion = '3.12' - volume_max_microversion = 'latest' - - @decorators.idempotent_id('a654833d-4811-4acd-93ef-5ac4a34c75bc') - @rbac_rule_validation.action(service="cinder", rules=["volume:get_all"]) - def test_show_volume_summary(self): - with self.override_role(): - self.volumes_client.show_volume_summary() diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_basic_crud_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_basic_crud_rbac.py deleted file mode 100644 index e4958f5a..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_volume_basic_crud_rbac.py +++ /dev/null @@ -1,100 +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.common import waiters -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.volume import rbac_base - -CONF = config.CONF - - -class VolumesBasicCrudV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def resource_setup(cls): - super(VolumesBasicCrudV3RbacTest, cls).resource_setup() - cls.volume = cls.create_volume() - - @rbac_rule_validation.action(service="cinder", - rules=["volume:create"]) - @decorators.idempotent_id('426b08ef-6394-4d06-9128-965d5a6c38ef') - def test_create_volume(self): - name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - size = CONF.volume.volume_size - - with self.override_role(): - volume = self.volumes_client.create_volume(name=name, size=size)[ - 'volume'] - # Use helper in base Tempest volume class which waits for deletion. - self.addCleanup(self.delete_volume, self.volumes_client, volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - - @decorators.idempotent_id('a009e6dc-e8bf-4412-99f5-8e45cffcffec') - @rbac_rule_validation.action(service="cinder", - rules=["volume:create_from_image"]) - def test_create_volume_from_image(self): - name = data_utils.rand_name(self.__class__.__name__ + '-Volume') - size = CONF.volume.volume_size - img_uuid = CONF.compute.image_ref - - with self.override_role(): - volume = self.volumes_client.create_volume( - name=name, size=size, imageRef=img_uuid)['volume'] - # Use helper in base Tempest volume class which waits for deletion. - self.addCleanup(self.delete_volume, self.volumes_client, volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - volume['id'], 'available') - - @rbac_rule_validation.action(service="cinder", - rules=["volume:delete"]) - @decorators.idempotent_id('6de9f9c2-509f-4558-867b-af21c7163be4') - def test_delete_volume(self): - volume = self.create_volume() - with self.override_role(): - self.volumes_client.delete_volume(volume['id']) - self.volumes_client.wait_for_resource_deletion(volume['id']) - - @rbac_rule_validation.action(service="cinder", rules=["volume:get"]) - @decorators.idempotent_id('c4c3fdd5-b1b1-49c3-b977-a9f40ee9257a') - def test_show_volume(self): - with self.override_role(): - self.volumes_client.show_volume(self.volume['id']) - - @rbac_rule_validation.action(service="cinder", - rules=["volume:get_all"]) - @decorators.idempotent_id('e3ab7906-b04b-4c45-aa11-1104d302f940') - def test_list_volumes(self): - with self.override_role(): - self.volumes_client.list_volumes() - - @decorators.idempotent_id('9b6d5beb-254f-4f1b-9906-0bdce4042f53') - @rbac_rule_validation.action(service="cinder", - rules=["volume:get_all"]) - def test_list_volumes_with_details(self): - with self.override_role(): - self.volumes_client.list_volumes(detail=True) - - @rbac_rule_validation.action(service="cinder", rules=["volume:update"]) - @decorators.idempotent_id('b751b889-9a9b-40d8-ae7d-4b0f65e71ac7') - def test_update_volume(self): - update_name = data_utils.rand_name(self.__class__.__name__ + 'volume') - with self.override_role(): - self.volumes_client.update_volume(self.volume['id'], - name=update_name) diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_hosts_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_hosts_rbac.py deleted file mode 100644 index b3fb0b6c..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_volume_hosts_rbac.py +++ /dev/null @@ -1,41 +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 patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - - -class VolumeHostsV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @rbac_rule_validation.action(service="cinder", - rules=["volume_extension:hosts"]) - @decorators.idempotent_id('64e837f5-5452-4e26-b934-c721ea7a8644') - def test_list_hosts(self): - with self.override_role(): - self.volume_hosts_client.list_hosts() - - @decorators.idempotent_id('9ddf321e-788f-4787-b8cc-dfa59e264143') - @rbac_rule_validation.action(service="cinder", - rules=["volume_extension:hosts"]) - def test_show_host(self): - hosts = self.volume_hosts_client.list_hosts()['hosts'] - host_names = [host['host_name'] for host in hosts] - self.assertNotEmpty(host_names, "No available volume host was found, " - "all hosts found were: %s" % hosts) - - with self.override_role(): - self.volume_hosts_client.show_host(host_names[0]) 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 deleted file mode 100644 index d7ae6ee8..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_volume_metadata_rbac.py +++ /dev/null @@ -1,168 +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.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - -CONF = config.CONF - -if CONF.policy_feature_enabled.changed_cinder_policies_xena: - _METADATA_SHOW = "volume_extension:volume_image_metadata:show" - _METADATA_SET = "volume_extension:volume_image_metadata:set" - _METADATA_REMOVE = "volume_extension:volume_image_metadata:remove" -else: - _METADATA_SHOW = "volume_extension:volume_image_metadata" - _METADATA_SET = "volume_extension:volume_image_metadata" - _METADATA_REMOVE = "volume_extension:volume_image_metadata" - - -class VolumeMetadataV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def resource_setup(cls): - super(VolumeMetadataV3RbacTest, cls).resource_setup() - cls.volume = cls.create_volume() - cls.image_id = CONF.compute.image_ref - - def _add_metadata(self, volume): - # Create metadata for the volume. - metadata = {"key1": "value1"} - self.volumes_client.create_volume_metadata( - self.volume['id'], metadata)['metadata'] - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.volumes_client.delete_volume_metadata_item, - self.volume['id'], "key1") - - @rbac_rule_validation.action(service="cinder", - rules=["volume:create_volume_metadata"]) - @decorators.idempotent_id('232bbb8b-4c29-44dc-9077-b1398c20b738') - def test_create_volume_metadata(self): - with self.override_role(): - self._add_metadata(self.volume) - - @rbac_rule_validation.action(service="cinder", - rules=["volume:get_volume_metadata"]) - @decorators.idempotent_id('87ea37d9-23ab-47b2-a59c-16fc4d2c6dfa') - def test_show_volume_metadata(self): - with self.override_role(): - self.volumes_client.show_volume_metadata( - self.volume['id'])['metadata'] - - @decorators.idempotent_id('5c0f4c19-b448-4f51-9224-dad5faddc3bb') - @rbac_rule_validation.action(service="cinder", - rules=["volume:get_volume_metadata"]) - def test_show_volume_metadata_item(self): - self._add_metadata(self.volume) - - with self.override_role(): - self.volumes_client.show_volume_metadata_item( - self.volume['id'], "key1") - - @rbac_rule_validation.action(service="cinder", - rules=["volume:delete_volume_metadata"]) - @decorators.idempotent_id('7498dfc1-9db2-4423-ad20-e6dcb25d1beb') - def test_delete_volume_metadata_item(self): - self._add_metadata(self.volume) - - with self.override_role(): - self.volumes_client.delete_volume_metadata_item(self.volume['id'], - "key1") - - @rbac_rule_validation.action(service="cinder", - rules=["volume:update_volume_metadata"]) - @decorators.idempotent_id('8ce2ff80-99ba-49ae-9bb1-7e96729ee5af') - def test_update_volume_metadata_item(self): - self._add_metadata(self.volume) - updated_metadata_item = {"key1": "value1_update"} - with self.override_role(): - self.volumes_client.update_volume_metadata_item( - self.volume['id'], "key1", updated_metadata_item)['meta'] - - @decorators.idempotent_id('a231b445-97a5-4657-b05f-245895e88da9') - @rbac_rule_validation.action(service="cinder", - rules=["volume:update_volume_metadata"]) - def test_update_volume_metadata(self): - self._add_metadata(self.volume) - updated_metadata = {"key1": "value1"} - with self.override_role(): - self.volumes_client.update_volume_metadata(self.volume['id'], - updated_metadata) - - @decorators.idempotent_id('39e8f82c-f1fc-4905-bf47-177ce2f71bb9') - @rbac_rule_validation.action( - service="cinder", - rules=[_METADATA_SET]) - def test_list_volumes_details_image_metadata(self): - self.volumes_client.update_volume_image_metadata( - self.volume['id'], image_id=self.image_id) - self.addCleanup(self.volumes_client.delete_volume_image_metadata, - self.volume['id'], 'image_id') - - with self.override_role(): - resp_body = self.volumes_client.list_volumes(detail=True)[ - 'volumes'] - expected_attr = 'volume_image_metadata' - if expected_attr not in resp_body[0]: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) - - @decorators.idempotent_id('53f94d52-0dd5-42cf-a3a4-59b35150b3d5') - @rbac_rule_validation.action( - service="cinder", - rules=[_METADATA_SHOW]) - def test_show_volume_details_image_metadata(self): - self.volumes_client.update_volume_image_metadata( - self.volume['id'], image_id=self.image_id) - self.addCleanup(self.volumes_client.delete_volume_image_metadata, - self.volume['id'], 'image_id') - - with self.override_role(): - resp_body = self.volumes_client.show_volume(self.volume['id'])[ - 'volume'] - expected_attr = 'volume_image_metadata' - if expected_attr not in resp_body: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) - - @decorators.idempotent_id('a9d9e825-5ea3-42e6-96f3-7ac4e97b2ed0') - @rbac_rule_validation.action( - service="cinder", - rules=[_METADATA_SET]) - def test_update_volume_image_metadata(self): - with self.override_role(): - self.volumes_client.update_volume_image_metadata( - self.volume['id'], image_id=self.image_id) - self.addCleanup(self.volumes_client.delete_volume_image_metadata, - self.volume['id'], 'image_id') - - @decorators.idempotent_id('a41c8eed-2051-4a25-b401-df036faacbdc') - @rbac_rule_validation.action( - service="cinder", - rules=[_METADATA_REMOVE]) - def test_delete_volume_image_metadata(self): - self.volumes_client.update_volume_image_metadata( - self.volume['id'], image_id=self.image_id) - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.volumes_client.delete_volume_image_metadata, - self.volume['id'], 'image_id') - - with self.override_role(): - self.volumes_client.delete_volume_image_metadata(self.volume['id'], - 'image_id') diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_quotas_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_quotas_rbac.py deleted file mode 100644 index 6d27d2c6..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_volume_quotas_rbac.py +++ /dev/null @@ -1,89 +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 patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - -QUOTA_KEYS = ['gigabytes', 'snapshots', 'volumes', 'backups', - 'backup_gigabytes', 'per_volume_gigabytes'] - - -class VolumeQuotasV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def setup_credentials(cls): - super(VolumeQuotasV3RbacTest, cls).setup_credentials() - cls.demo_tenant_id = cls.os_primary.credentials.tenant_id - - @classmethod - def setup_clients(cls): - super(VolumeQuotasV3RbacTest, cls).setup_clients() - cls.quotas_client = cls.os_primary.volume_quotas_client_latest - - def _restore_default_quota_set(self): - default_quota_set = self.quotas_client.show_default_quota_set( - self.demo_tenant_id)['quota_set'] - cleanup_quota_set = dict( - (k, v) for k, v in default_quota_set.items() - if k in QUOTA_KEYS) - self.addCleanup(self.quotas_client.update_quota_set, - self.demo_tenant_id, **cleanup_quota_set) - - @decorators.idempotent_id('427c9f0c-982e-403d-ae45-c05f4d6322ff') - @rbac_rule_validation.action(service="cinder", - rules=["volume_extension:quotas:show"]) - def test_list_quotas(self): - with self.override_role(): - self.quotas_client.show_quota_set(self.demo_tenant_id) - - @decorators.idempotent_id('e47cf444-2753-4983-be6d-fc0d6523720f') - @rbac_rule_validation.action(service="cinder", - rules=["volume_extension:quotas:show"]) - def test_list_quotas_usage_true(self): - with self.override_role(): - self.quotas_client.show_quota_set(self.demo_tenant_id, - params={'usage': True}) - - @rbac_rule_validation.action(service="cinder", - rules=["volume_extension:quotas:show"]) - @decorators.idempotent_id('b3c7177e-b6b1-4d0f-810a-fc95606964dd') - def test_list_default_quotas(self): - with self.override_role(): - self.quotas_client.show_default_quota_set( - self.demo_tenant_id) - - @rbac_rule_validation.action(service="cinder", - rules=["volume_extension:quotas:update"]) - @decorators.idempotent_id('60f8f421-1630-4953-b449-b22af32265c7') - def test_update_quota_set(self): - self._restore_default_quota_set() - new_quota_set = {'gigabytes': 1009, - 'volumes': 11, - 'snapshots': 11} - # Update limits for all quota resources. - with self.override_role(): - self.quotas_client.update_quota_set( - self.demo_tenant_id, **new_quota_set) - - @decorators.idempotent_id('329bdb88-5132-4810-b1fc-350d181577e3') - @rbac_rule_validation.action(service="cinder", - rules=["volume_extension:quotas:delete"]) - def test_delete_quota_set(self): - self._restore_default_quota_set() - - with self.override_role(): - self.quotas_client.delete_quota_set(self.demo_tenant_id) diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_services_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_services_rbac.py deleted file mode 100644 index 945d0162..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_volume_services_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.common import utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - - -class VolumeServicesV3RbacTest(rbac_base.BaseVolumeRbacTest): - - # TODO(felipemonteiro): Implement a test to cover the policy action, - # "volume_extension:services:update", once the Tempest client endpoint - # is implemented. - - @classmethod - def skip_checks(cls): - super(VolumeServicesV3RbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-services', 'volume'): - msg = "%s skipped as os-services not enabled." % cls.__name__ - raise cls.skipException(msg) - - @classmethod - def setup_clients(cls): - super(VolumeServicesV3RbacTest, cls).setup_clients() - cls.services_client = cls.os_primary.volume_services_client_latest - - @decorators.idempotent_id('b9134f01-97c0-4abd-9455-fe2f03e3f966') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:services:index"]) - def test_list_services(self): - with self.override_role(): - self.services_client.list_services()['services'] diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_transfers_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_transfers_rbac.py deleted file mode 100644 index e52e0741..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_volume_transfers_rbac.py +++ /dev/null @@ -1,110 +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.common import waiters -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - - -class VolumesTransfersV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def setup_clients(cls): - super(VolumesTransfersV3RbacTest, cls).setup_clients() - cls.transfers_client = cls.os_primary.volume_transfers_client_latest - - @classmethod - def resource_setup(cls): - super(VolumesTransfersV3RbacTest, cls).resource_setup() - cls.volume = cls.create_volume() - - def _delete_transfer(self, transfer): - # Volume from create_volume_transfer test may get stuck in - # 'awaiting-transfer' state, preventing cleanup and causing - # the test to fail. - test_utils.call_and_ignore_notfound_exc( - self.transfers_client.delete_volume_transfer, transfer['id']) - waiters.wait_for_volume_resource_status( - self.volumes_client, self.volume['id'], 'available') - - def _create_transfer(self): - transfer = self.transfers_client.create_volume_transfer( - volume_id=self.volume['id'])['transfer'] - self.addCleanup(self._delete_transfer, transfer) - return transfer - - @rbac_rule_validation.action(service="cinder", - rules=["volume:create_transfer"]) - @decorators.idempotent_id('25413af4-468d-48ff-94ca-4436f8526b3e') - def test_create_volume_transfer(self): - with self.override_role(): - self._create_transfer() - waiters.wait_for_volume_resource_status( - self.volumes_client, self.volume['id'], 'awaiting-transfer') - - @rbac_rule_validation.action(service="cinder", - rules=["volume:get_transfer"]) - @decorators.idempotent_id('7a0925d3-ed97-4c25-8299-e5cdabe2eb55') - def test_get_volume_transfer(self): - transfer = self._create_transfer() - waiters.wait_for_volume_resource_status( - self.volumes_client, self.volume['id'], 'awaiting-transfer') - - with self.override_role(): - self.transfers_client.show_volume_transfer(transfer['id']) - - @rbac_rule_validation.action(service="cinder", - rules=["volume:get_all_transfers"]) - @decorators.idempotent_id('02a06f2b-5040-49e2-b2b7-619a7db59603') - def test_list_volume_transfers(self): - with self.override_role(): - self.transfers_client.list_volume_transfers() - - @decorators.idempotent_id('e84e45b0-9872-40bf-bf44-971266161a86') - @rbac_rule_validation.action(service="cinder", - rules=["volume:get_all_transfers"]) - def test_list_volume_transfers_details(self): - with self.override_role(): - self.transfers_client.list_volume_transfers(detail=True) - - @rbac_rule_validation.action(service="cinder", - rules=["volume:accept_transfer"]) - @decorators.idempotent_id('987f2a11-d657-4984-a6c9-28f06c1cd014') - def test_accept_volume_transfer(self): - transfer = self._create_transfer() - waiters.wait_for_volume_resource_status( - self.volumes_client, self.volume['id'], 'awaiting-transfer') - - with self.override_role(): - self.transfers_client.accept_volume_transfer( - transfer['id'], auth_key=transfer['auth_key']) - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], 'available') - - @rbac_rule_validation.action(service="cinder", - rules=["volume:delete_transfer"]) - @decorators.idempotent_id('4672187e-7fff-454b-832a-5c8865dda868') - def test_delete_volume_transfer(self): - transfer = self._create_transfer() - waiters.wait_for_volume_resource_status( - self.volumes_client, self.volume['id'], 'awaiting-transfer') - - with self.override_role(): - self.transfers_client.delete_volume_transfer(transfer['id']) - waiters.wait_for_volume_resource_status( - self.volumes_client, self.volume['id'], 'available') diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_types_access_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_types_access_rbac.py deleted file mode 100644 index d07a4013..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_volume_types_access_rbac.py +++ /dev/null @@ -1,88 +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.common import utils -from tempest import config -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - -CONF = config.CONF - -if CONF.policy_feature_enabled.changed_cinder_policies_xena: - _TYPE_ACCESS_LIST = "volume_extension:volume_type_access:get_all_for_type" -else: - _TYPE_ACCESS_LIST = "volume_extension:volume_type_access" - - -class VolumeTypesAccessRbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def skip_checks(cls): - super(VolumeTypesAccessRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-volume-type-access', 'volume'): - msg = "os-volume-type-access extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(VolumeTypesAccessRbacTest, cls).resource_setup() - cls.vol_type = cls.create_volume_type( - **{'os-volume-type-access:is_public': False}) - cls.project_id = cls.os_primary.credentials.project_id - - def _add_type_access(self, ignore_not_found=False): - self.volume_types_client.add_type_access( - self.vol_type['id'], project=self.project_id) - - if ignore_not_found: - self.addCleanup(test_utils.call_and_ignore_notfound_exc, - self.volume_types_client.remove_type_access, - self.vol_type['id'], project=self.project_id) - else: - self.addCleanup(self.volume_types_client.remove_type_access, - self.vol_type['id'], project=self.project_id) - - @decorators.idempotent_id('af70e6ad-e931-419f-9200-8bcc284e4e47') - @rbac_rule_validation.action( - service="cinder", - rules=[_TYPE_ACCESS_LIST]) - def test_list_type_access(self): - self._add_type_access() - - with self.override_role(): - self.volume_types_client.list_type_access(self.vol_type['id'])[ - 'volume_type_access'] - - @decorators.idempotent_id('b462eeba-45d0-4d6e-945a-a1d27708d367') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:volume_type_access:addProjectAccess"]) - def test_add_type_access(self): - with self.override_role(): - self._add_type_access(ignore_not_found=True) - - @decorators.idempotent_id('8f848aeb-636a-46f1-aeeb-e2a60e9d2bfe') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:volume_type_access:removeProjectAccess"]) - def test_remove_type_access(self): - self._add_type_access(ignore_not_found=True) - - with self.override_role(): - self.volume_types_client.remove_type_access( - self.vol_type['id'], project=self.project_id) diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_types_extra_specs_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_types_extra_specs_rbac.py deleted file mode 100644 index f4e625f5..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_volume_types_extra_specs_rbac.py +++ /dev/null @@ -1,107 +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.common import utils -from tempest.lib.common.utils import data_utils -from tempest.lib.common.utils import test_utils -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - - -class VolumeTypesExtraSpecsRbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def skip_checks(cls): - super(VolumeTypesExtraSpecsRbacTest, cls).skip_checks() - if not utils.is_extension_enabled('os-types-extra-specs', 'volume'): - msg = "os-types-extra-specs extension not enabled." - raise cls.skipException(msg) - - @classmethod - def resource_setup(cls): - super(VolumeTypesExtraSpecsRbacTest, cls).resource_setup() - cls.vol_type = cls.create_volume_type() - - def setUp(self): - super(VolumeTypesExtraSpecsRbacTest, self).setUp() - self.spec_key = data_utils.rand_name('-VolumeTypesExtraSpec') - - def _create_volume_type_extra_specs(self, ignore_not_found=False): - extra_specs = {self.spec_key: "val1"} - self.volume_types_client.create_volume_type_extra_specs( - self.vol_type['id'], extra_specs) - - if ignore_not_found: - self.addCleanup( - test_utils.call_and_ignore_notfound_exc, - self.volume_types_client.delete_volume_type_extra_specs, - self.vol_type['id'], self.spec_key) - else: - self.addCleanup( - self.volume_types_client.delete_volume_type_extra_specs, - self.vol_type['id'], self.spec_key) - - @decorators.idempotent_id('76c36be2-2b6c-4acf-9aac-c9dc5c17cdbe') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:types_extra_specs:index"]) - def test_list_volume_types_extra_specs(self): - with self.override_role(): - self.volume_types_client.list_volume_types_extra_specs( - self.vol_type['id'])['extra_specs'] - - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:types_extra_specs:create"]) - @decorators.idempotent_id('eea40251-990b-49b0-99ae-10e4585b479b') - def test_create_volume_type_extra_specs(self): - with self.override_role(): - self._create_volume_type_extra_specs(ignore_not_found=True) - - @decorators.idempotent_id('e2dcc9c6-2fef-431d-afaf-92b45bc76d1a') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:types_extra_specs:show"]) - def test_show_volume_type_extra_specs(self): - self._create_volume_type_extra_specs() - - with self.override_role(): - self.volume_types_client.show_volume_type_extra_specs( - self.vol_type['id'], self.spec_key) - - @decorators.idempotent_id('93001912-f938-41c7-8787-62dc7010fd52') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:types_extra_specs:delete"]) - def test_delete_volume_type_extra_specs(self): - self._create_volume_type_extra_specs(ignore_not_found=True) - - with self.override_role(): - self.volume_types_client.delete_volume_type_extra_specs( - self.vol_type['id'], self.spec_key) - - @decorators.idempotent_id('0a444437-7402-4fbe-a18a-93af2ee00618') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:types_extra_specs:update"]) - def test_update_volume_type_extra_specs(self): - self._create_volume_type_extra_specs() - update_extra_specs = {self.spec_key: "val2"} - - with self.override_role(): - self.volume_types_client.update_volume_type_extra_specs( - self.vol_type['id'], self.spec_key, update_extra_specs) diff --git a/patrole_tempest_plugin/tests/api/volume/test_volume_types_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volume_types_rbac.py deleted file mode 100644 index 46d2d558..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_volume_types_rbac.py +++ /dev/null @@ -1,62 +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.volume import rbac_base - -CONF = config.CONF - -if CONF.policy_feature_enabled.changed_cinder_policies_xena: - _TYPE_MANAGE_CREATE = "volume_extension:type_create" - _TYPE_MANAGE_UPDATE = "volume_extension:type_update" - _TYPE_MANAGE_DELETE = "volume_extension:type_delete" -else: - _TYPE_MANAGE_CREATE = "volume_extension:types_manage" - _TYPE_MANAGE_UPDATE = "volume_extension:types_manage" - _TYPE_MANAGE_DELETE = "volume_extension:types_manage" - - -class VolumeTypesRbacTest(rbac_base.BaseVolumeRbacTest): - - @decorators.idempotent_id('e2bbf968-d947-4a15-a4da-a98c3069731e') - @rbac_rule_validation.action( - service="cinder", - rules=[_TYPE_MANAGE_CREATE]) - def test_create_volume_type(self): - with self.override_role(): - self.create_volume_type() - - @decorators.idempotent_id('2b74ac82-e03e-4801-86f3-d05c9acfd66b') - @rbac_rule_validation.action( - service="cinder", - rules=[_TYPE_MANAGE_UPDATE]) - def test_update_volume_type(self): - volume_type = self.create_volume_type() - with self.override_role(): - self.volume_types_client.update_volume_type( - volume_type['id'], description='updated-description') - - @decorators.idempotent_id('90aec0ef-4f9b-4170-be6b-a392c12540be') - @rbac_rule_validation.action( - service="cinder", - rules=[_TYPE_MANAGE_DELETE]) - def test_delete_volume_type(self): - volume_type = self.create_volume_type() - with self.override_role(): - self.volume_types_client.delete_volume_type(volume_type['id']) - self.volume_types_client.wait_for_resource_deletion(volume_type['id']) 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 deleted file mode 100644 index 073b26ce..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_volumes_backup_rbac.py +++ /dev/null @@ -1,256 +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 oslo_serialization import base64 -from oslo_serialization import jsonutils as json - -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 patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - -CONF = config.CONF - - -class VolumesBackupsV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def skip_checks(cls): - super(VolumesBackupsV3RbacTest, cls).skip_checks() - if not CONF.volume_feature_enabled.backup: - raise cls.skipException("Cinder backup feature disabled") - - @classmethod - def resource_setup(cls): - super(VolumesBackupsV3RbacTest, cls).resource_setup() - cls.volume = cls.create_volume() - cls.backup = cls._create_backup(volume_id=cls.volume['id']) - - def _decode_url(self, backup_url): - return json.loads(base64.decode_as_text(backup_url)) - - def _encode_backup(self, backup): - retval = json.dumps(backup) - return base64.encode_as_text(retval) - - def _modify_backup_url(self, backup_url, changes): - backup = self._decode_url(backup_url) - backup.update(changes) - return self._encode_backup(backup) - - @decorators.attr(type='slow') - @rbac_rule_validation.action(service="cinder", - rules=["backup:create"]) - @decorators.idempotent_id('6887ec94-0bcf-4ab7-b30f-3808a4b5a2a5') - def test_create_backup(self): - backup_name = data_utils.rand_name(self.__class__.__name__ + '-Backup') - - with self.override_role(): - backup = self.backups_client.create_backup( - volume_id=self.volume['id'], name=backup_name)['backup'] - self.addCleanup(self.backups_client.delete_backup, backup['id']) - waiters.wait_for_volume_resource_status( - self.backups_client, backup['id'], 'available') - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], 'available') - - @decorators.attr(type='slow') - @rbac_rule_validation.action(service="cinder", - rules=["backup:get"]) - @decorators.idempotent_id('abd92bdd-b0fb-4dc4-9cfc-de9e968f8c8a') - def test_show_backup(self): - with self.override_role(): - self.backups_client.show_backup(self.backup['id']) - - @rbac_rule_validation.action(service="cinder", - rules=["backup:get_all"]) - @decorators.idempotent_id('4d18f0f0-7e01-4007-b622-dedc859b22f6') - def test_list_backups(self): - with self.override_role(): - self.backups_client.list_backups() - - @decorators.idempotent_id('dbd69865-876f-4835-b70e-7341153fb162') - @rbac_rule_validation.action(service="cinder", - rules=["backup:get_all"]) - def test_list_backups_with_details(self): - with self.override_role(): - self.backups_client.list_backups(detail=True) - - @decorators.attr(type='slow') - @decorators.idempotent_id('50f43bde-205e-438e-9a05-5eac07fc3d63') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:backup_admin_actions:reset_status"]) - def test_reset_backup_status(self): - # Use instance-level create_backup for easier debugging. - backup = self.create_backup(volume_id=self.volume['id']) - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], 'available') - with self.override_role(): - self.backups_client.reset_backup_status(backup_id=backup['id'], - status='error') - waiters.wait_for_volume_resource_status(self.backups_client, - backup['id'], 'error') - - @decorators.attr(type='slow') - @rbac_rule_validation.action(service="cinder", - rules=["backup:restore"]) - @decorators.idempotent_id('9c794bf9-2446-4f41-8fe0-80b71e757f9d') - def test_restore_backup(self): - with self.override_role(): - restore = self.backups_client.restore_backup( - self.backup['id'])['restore'] - self.addCleanup(self.volumes_client.delete_volume, - restore['volume_id']) - waiters.wait_for_volume_resource_status( - self.backups_client, restore['backup_id'], 'available') - - @decorators.attr(type='slow') - @rbac_rule_validation.action(service="cinder", - rules=["backup:delete"]) - @decorators.idempotent_id('d5d0c6a2-413d-437e-a73f-4bf2b41a20ed') - def test_delete_backup(self): - # 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.backups_client, - backup['id'], 'available') - waiters.wait_for_volume_resource_status(self.volumes_client, - self.volume['id'], 'available') - - with self.override_role(): - 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']) - - @decorators.attr(type='slow') - @rbac_rule_validation.action(service="cinder", - rules=["backup:export-import"]) - @decorators.idempotent_id('e984ec8d-e8eb-485c-98bc-f1856020303c') - def test_export_backup(self): - with self.override_role(): - self.backups_client.export_backup(self.backup['id'])[ - 'backup-record'] - - @decorators.attr(type='slow') - @rbac_rule_validation.action(service="cinder", - rules=["backup:backup-import"]) - @decorators.idempotent_id('1e70f039-4556-44cc-9cc1-edf2b7ed648b') - def test_import_backup(self): - export_backup = self.backups_client.export_backup( - self.backup['id'])['backup-record'] - new_id = data_utils.rand_uuid() - new_url = self._modify_backup_url( - export_backup['backup_url'], {'id': new_id}) - - with self.override_role(): - import_backup = self.backups_client.import_backup( - backup_service=export_backup['backup_service'], - backup_url=new_url)['backup'] - self.addCleanup(self.backups_client.delete_backup, import_backup['id']) - waiters.wait_for_volume_resource_status(self.backups_client, - import_backup['id'], - 'available') - - -class VolumesBackupsV318RbacTest(rbac_base.BaseVolumeRbacTest): - """Validates that the ``GET /backups/{backup_id}`` and - ``GET /backups/details`` APIs inject the expected attribute - 'os-backup-project-attr:project_id' into the response body following - successful authorization. - """ - _api_version = 3 - # The minimum microversion for showing 'os-backup-project-attr:project_id' - # is 3.18. - volume_min_microversion = '3.18' - volume_max_microversion = 'latest' - - @classmethod - def skip_checks(cls): - super(VolumesBackupsV318RbacTest, cls).skip_checks() - if not CONF.volume_feature_enabled.backup: - raise cls.skipException("Cinder backup feature disabled") - - @classmethod - def resource_setup(cls): - super(VolumesBackupsV318RbacTest, cls).resource_setup() - cls.volume = cls.create_volume() - cls.backup = cls._create_backup(volume_id=cls.volume['id']) - cls.expected_attr = 'os-backup-project-attr:project_id' - - @decorators.idempotent_id('69801485-d5be-4e75-bbb4-168d50b5a8c2') - @rbac_rule_validation.action(service="cinder", - rules=["backup:backup_project_attribute"]) - def test_show_backup_project_attribute(self): - with self.override_role(): - body = self.backups_client.show_backup(self.backup['id'])['backup'] - - # Show backup API attempts to inject the attribute below into the - # response body but only if policy enforcement succeeds. - if self.expected_attr not in body: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=self.expected_attr) - - @decorators.idempotent_id('aa40b7c0-5974-48be-8cbc-e23cc61c4c68') - @rbac_rule_validation.action(service="cinder", - rules=["backup:backup_project_attribute"]) - def test_list_backup_details_project_attribute(self): - with self.override_role(): - body = self.backups_client.list_backups(detail=True)['backups'] - - if self.expected_attr not in body[0]: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=self.expected_attr) - - -class VolumesBackupsV39RbacTest(rbac_base.BaseVolumeRbacTest): - _api_version = 3 - volume_min_microversion = '3.9' - volume_max_microversion = 'latest' - - @classmethod - def skip_checks(cls): - super(VolumesBackupsV39RbacTest, cls).skip_checks() - if not CONF.volume_feature_enabled.backup: - raise cls.skipException("Cinder backup feature disabled") - - @classmethod - def resource_setup(cls): - super(VolumesBackupsV39RbacTest, cls).resource_setup() - cls.volume = cls.create_volume() - cls.backup = cls._create_backup(volume_id=cls.volume['id']) - - @decorators.attr(type='slow') - @decorators.idempotent_id('b45b0e98-6eb8-4c62-aa53-0f8c7c09faa6') - @rbac_rule_validation.action( - service="cinder", - rules=["backup:update"]) - def test_backup_update(self): - update_kwargs = { - 'name': data_utils.rand_name(self.__class__.__name__ + '-Backup'), - 'description': data_utils.rand_name("volume-backup-description") - } - with self.override_role(): - self.backups_client.update_backup(self.backup['id'], - **update_kwargs) diff --git a/patrole_tempest_plugin/tests/api/volume/test_volumes_extend_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volumes_extend_rbac.py deleted file mode 100644 index c7c52d23..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_volumes_extend_rbac.py +++ /dev/null @@ -1,40 +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.common import waiters -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - - -class VolumesExtendV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def resource_setup(cls): - super(VolumesExtendV3RbacTest, cls).resource_setup() - # Create a test shared volume for tests - cls.volume = cls.create_volume() - - @rbac_rule_validation.action(service="cinder", rules=["volume:extend"]) - @decorators.idempotent_id('1627b065-4081-4e14-8340-8e4fb02ceaf2') - def test_volume_extend(self): - # Extend volume test - extend_size = int(self.volume['size']) + 1 - with self.override_role(): - self.volumes_client.extend_volume(self.volume['id'], - new_size=extend_size) - waiters.wait_for_volume_resource_status( - self.volumes_client, self.volume['id'], 'available') diff --git a/patrole_tempest_plugin/tests/api/volume/test_volumes_manage_rbac.py b/patrole_tempest_plugin/tests/api/volume/test_volumes_manage_rbac.py deleted file mode 100644 index 480ebeb3..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_volumes_manage_rbac.py +++ /dev/null @@ -1,124 +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.common import waiters -from tempest import config -from tempest.lib.common.utils import data_utils -from tempest.lib import decorators -from tempest.lib import exceptions - -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - -CONF = config.CONF - - -class VolumesManageV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def skip_checks(cls): - super(VolumesManageV3RbacTest, cls).skip_checks() - - if not CONF.volume_feature_enabled.manage_volume: - raise cls.skipException("Manage volume tests are disabled") - - if len(CONF.volume.manage_volume_ref) != 2: - raise cls.skipException("Manage volume ref is not correctly " - "configured") - - @classmethod - def setup_clients(cls): - super(VolumesManageV3RbacTest, cls).setup_clients() - cls.volume_manage_client = cls.os_primary.volume_manage_client_latest - - def _manage_volume(self, org_volume): - # Manage volume - new_volume_name = data_utils.rand_name( - self.__class__.__name__ + '-volume') - - new_volume_ref = { - 'name': new_volume_name, - 'host': org_volume['os-vol-host-attr:host'], - 'ref': {CONF.volume.manage_volume_ref[0]: - CONF.volume.manage_volume_ref[1] % org_volume['id']}, - 'volume_type': org_volume['volume_type'], - 'availability_zone': org_volume['availability_zone']} - - new_volume_id = self.volume_manage_client.manage_volume( - **new_volume_ref)['volume']['id'] - - waiters.wait_for_volume_resource_status(self.volumes_client, - new_volume_id, 'available') - self.addCleanup(self.delete_volume, - self.volumes_client, new_volume_id) - - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:volume_manage"]) - @decorators.idempotent_id('114f9708-939b-407e-aeac-d21ebfabaad3') - def test_volume_manage(self): - volume_id = self.create_volume()['id'] - volume = self.volumes_client.show_volume(volume_id)['volume'] - - # By default, the volume is managed after creation. We need to - # unmanage the volume first before testing manage volume. - self.volumes_client.unmanage_volume(volume['id']) - self.volumes_client.wait_for_resource_deletion(volume['id']) - - new_volume_name = data_utils.rand_name( - self.__class__.__name__ + '-volume') - - new_volume_ref = { - 'name': new_volume_name, - 'host': volume['os-vol-host-attr:host'], - 'ref': {CONF.volume.manage_volume_ref[0]: - CONF.volume.manage_volume_ref[1] % volume['id']}, - 'volume_type': volume['volume_type'], - 'availability_zone': volume['availability_zone']} - - with self.override_role(): - try: - new_volume_id = self.volume_manage_client.manage_volume( - **new_volume_ref)['volume']['id'] - except exceptions.Forbidden as e: - # Since the test role under test does not have permission to - # manage the volume, Forbidden exception is thrown and the - # manageable list will not be cleaned up. Therefore, we need to - # re-manage the volume at the end of the test case for proper - # resource clean up. - self.addCleanup(self._manage_volume, volume) - raise exceptions.Forbidden(e) - - waiters.wait_for_volume_resource_status(self.volumes_client, - new_volume_id, 'available') - self.addCleanup( - self.delete_volume, self.volumes_client, new_volume_id) - - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:volume_unmanage"]) - @decorators.idempotent_id('d5d72abe-60bc-45ac-a8f2-c21b24f0b5d6') - def test_volume_unmanage(self): - volume_id = self.create_volume()['id'] - volume = self.volumes_client.show_volume(volume_id)['volume'] - - with self.override_role(): - self.volumes_client.unmanage_volume(volume['id']) - self.volumes_client.wait_for_resource_deletion(volume['id']) - - # In order to clean up the manageable list, we need to re-manage the - # volume after the test. The _manage_volume method will set up the - # proper resource cleanup - self.addCleanup(self._manage_volume, volume) 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 deleted file mode 100644 index f56a4e1f..00000000 --- a/patrole_tempest_plugin/tests/api/volume/test_volumes_snapshots_rbac.py +++ /dev/null @@ -1,140 +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.common import waiters -from tempest import config -from tempest.lib import decorators - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation -from patrole_tempest_plugin.tests.api.volume import rbac_base - -CONF = config.CONF - - -class VolumesSnapshotV3RbacTest(rbac_base.BaseVolumeRbacTest): - - @classmethod - def skip_checks(cls): - super(VolumesSnapshotV3RbacTest, cls).skip_checks() - if not CONF.volume_feature_enabled.snapshot: - raise cls.skipException("Cinder volume snapshots are disabled") - - @classmethod - def resource_setup(cls): - super(VolumesSnapshotV3RbacTest, cls).resource_setup() - # Create a test shared volume for tests - cls.volume = cls.create_volume() - # Create a test shared snapshot for tests - cls.snapshot = cls.create_snapshot(cls.volume['id']) - - def _list_by_param_values(self, with_detail=False, **params): - # Perform list or list_details action with given params. - return self.snapshots_client.list_snapshots( - detail=with_detail, **params)['snapshots'] - - @rbac_rule_validation.action(service="cinder", - rules=["volume:create_snapshot"]) - @decorators.idempotent_id('ac7b2ee5-fbc0-4360-afc2-de8fa4881ede') - def test_create_snapshot(self): - # Create a temp snapshot - with self.override_role(): - self.create_snapshot(self.volume['id']) - - @rbac_rule_validation.action(service="cinder", - rules=["volume:get_snapshot"]) - @decorators.idempotent_id('93a11b40-1ba8-44d6-a196-f8d97220f796') - def test_show_snapshot(self): - # Get the snapshot - with self.override_role(): - self.snapshots_client.show_snapshot( - self.snapshot['id'])['snapshot'] - - @decorators.idempotent_id('5d6f5f21-9293-4f2a-8f44-cabdc24d92cb') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:extended_snapshot_attributes"]) - def test_show_snapshot_with_extended_attributes(self): - """List snapshots with extended attributes.""" - expected_attrs = ('os-extended-snapshot-attributes:project_id', - 'os-extended-snapshot-attributes:progress') - - with self.override_role(): - resp = self.snapshots_client.show_snapshot( - self.snapshot['id'])['snapshot'] - for expected_attr in expected_attrs: - if expected_attr not in resp: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) - - @rbac_rule_validation.action(service="cinder", - rules=["volume:update_snapshot"]) - @decorators.idempotent_id('53fe8ee3-3bea-4ae8-a979-3c98ea72f620') - def test_update_snapshot(self): - new_desc = 'This is the new description of snapshot.' - params = {'description': new_desc} - # Updates snapshot with new values - with self.override_role(): - self.snapshots_client.update_snapshot( - self.snapshot['id'], **params)['snapshot'] - waiters.wait_for_volume_resource_status( - self.snapshots_client, self.snapshot['id'], 'available') - - @rbac_rule_validation.action(service="cinder", - rules=["volume:delete_snapshot"]) - @decorators.idempotent_id('c7fe54ec-3b70-4772-ba11-f166d95888a3') - def test_delete_snapshot(self): - # Create a temp snapshot - temp_snapshot = self.create_snapshot(self.volume['id']) - with self.override_role(): - # Delete the snapshot - self.snapshots_client.delete_snapshot(temp_snapshot['id']) - self.snapshots_client.wait_for_resource_deletion( - temp_snapshot['id']) - - @rbac_rule_validation.action(service="cinder", - rules=["volume:get_all_snapshots"]) - @decorators.idempotent_id('e4edf0c0-2cd3-420f-b8ab-4d98a0718608') - def test_list_snapshots(self): - """List snapshots with params.""" - params = {'name': self.snapshot['name']} - with self.override_role(): - self._list_by_param_values(**params) - - @decorators.idempotent_id('f3155d8e-45ee-45c9-910d-18c0242229e1') - @rbac_rule_validation.action(service="cinder", - rules=["volume:get_all_snapshots"]) - def test_list_snapshots_details(self): - """List snapshots details with params.""" - params = {'name': self.snapshot['name']} - with self.override_role(): - self._list_by_param_values(with_detail=True, **params) - - @decorators.idempotent_id('dd37f388-2731-446d-a78f-676997ebb04a') - @rbac_rule_validation.action( - service="cinder", - rules=["volume_extension:extended_snapshot_attributes"]) - def test_list_snapshots_details_with_extended_attributes(self): - """List snapshots details with extended attributes.""" - expected_attrs = ('os-extended-snapshot-attributes:project_id', - 'os-extended-snapshot-attributes:progress') - params = {'name': self.snapshot['name']} - - with self.override_role(): - resp = self._list_by_param_values(with_detail=True, **params) - for expected_attr in expected_attrs: - if expected_attr not in resp[0]: - raise rbac_exceptions.RbacMissingAttributeResponseBody( - attribute=expected_attr) diff --git a/patrole_tempest_plugin/tests/scenario/__init__.py b/patrole_tempest_plugin/tests/scenario/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/patrole_tempest_plugin/tests/unit/__init__.py b/patrole_tempest_plugin/tests/unit/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/patrole_tempest_plugin/tests/unit/base.py b/patrole_tempest_plugin/tests/unit/base.py deleted file mode 100644 index c08da430..00000000 --- a/patrole_tempest_plugin/tests/unit/base.py +++ /dev/null @@ -1,30 +0,0 @@ -# Copyright 2010-2011 OpenStack Foundation -# Copyright (c) 2013 Hewlett-Packard Development Company, L.P. -# Copyright 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. - -from tempest.tests import base - -from patrole_tempest_plugin.tests.unit import fixtures as patrole_fixtures - - -class TestCase(base.TestCase): - """Test case base class for all unit tests.""" - - def setUp(self): - super(TestCase, self).setUp() - # Disable patrole log for unit tests. - self.useFixture( - patrole_fixtures.ConfPatcher(enable_reporting=False, - group='patrole_log')) diff --git a/patrole_tempest_plugin/tests/unit/fixtures.py b/patrole_tempest_plugin/tests/unit/fixtures.py deleted file mode 100644 index 01b99db3..00000000 --- a/patrole_tempest_plugin/tests/unit/fixtures.py +++ /dev/null @@ -1,158 +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. - -"""Fixtures for Patrole tests.""" -from unittest import mock - -import fixtures -import time - -from tempest import config -from tempest import test - -from patrole_tempest_plugin import rbac_utils - - -CONF = config.CONF - - -class ConfPatcher(fixtures.Fixture): - """Fixture to patch and restore global CONF. Adopted from Nova. - - This also resets overrides for everything that is patched during - its teardown. - """ - - def __init__(self, **kwargs): - """Constructor - - :params group: if specified all config options apply to that group. - :params **kwargs: the rest of the kwargs are processed as a - set of key/value pairs to be set as configuration override. - """ - super(ConfPatcher, self).__init__() - self.group = kwargs.pop('group', None) - self.args = kwargs - - def setUp(self): - super(ConfPatcher, self).setUp() - for k, v in self.args.items(): - self.addCleanup(CONF.clear_override, k, self.group) - CONF.set_override(k, v, self.group) - - -class FakeBaseRbacTest(rbac_utils.RbacUtilsMixin, test.BaseTestCase): - credentials = [] - os_primary = None - - def runTest(self): - pass - - -class RbacUtilsMixinFixture(fixtures.Fixture): - """Fixture for `RbacUtils` class.""" - - USER_ID = mock.sentinel.user_id - PROJECT_ID = mock.sentinel.project_id - - def __init__(self, do_reset_mocks=True, rbac_test_roles=None): - self._do_reset_mocks = do_reset_mocks - self._rbac_test_roles = rbac_test_roles or ['member'] - - def patchobject(self, target, attribute, *args, **kwargs): - p = mock.patch.object(target, attribute, *args, **kwargs) - m = p.start() - self.addCleanup(p.stop) - return m - - def setUp(self): - super(RbacUtilsMixinFixture, self).setUp() - - self.useFixture(ConfPatcher(rbac_test_roles=self._rbac_test_roles, - group='patrole')) - self.useFixture(ConfPatcher( - admin_role='admin', auth_version='v3', group='identity')) - self.useFixture(ConfPatcher( - api_v3=True, group='identity-feature-enabled')) - - # Mock out functionality that can't be used by unit tests. Mocking out - # time.sleep is a test optimization. - self.mock_time = self.patchobject(rbac_utils, 'time', - __name__='mock_time', spec=time) - - test_obj_kwargs = { - 'credentials.user_id': self.USER_ID, - 'credentials.tenant_id': self.PROJECT_ID, - 'credentials.project_id': self.PROJECT_ID, - } - - class FakeRbacTest(FakeBaseRbacTest): - os_primary = mock.Mock() - os_admin = mock.Mock() - - FakeRbacTest.os_primary.configure_mock(**test_obj_kwargs) - - self.admin_roles_client = FakeRbacTest.os_admin.roles_v3_client - self.admin_roles_client.list_all_role_inference_rules.return_value = { - "role_inferences": [ - { - "implies": [{"id": "reader_id", "name": "reader"}], - "prior_role": {"id": "member_id", "name": "member"} - }, - { - "implies": [{"id": "member_id", "name": "member"}], - "prior_role": {"id": "admin_id", "name": "admin"} - } - ] - } - - default_roles = {'admin', 'member', 'reader'}.union( - set(self._rbac_test_roles)) - self.set_roles(list(default_roles), []) - - FakeRbacTest.setUpClass() - self.test_obj = FakeRbacTest() - if self._do_reset_mocks: - self.admin_roles_client.reset_mock() - self.test_obj.os_primary.reset_mock() - self.test_obj.os_admin.reset_mock() - self.mock_time.reset_mock() - - def set_roles(self, roles, roles_on_project=None): - """Set the list of available roles in the system. - - :param roles: List of roles returned by ``list_roles``. - :param roles_on_project: List of roles returned by - ``list_user_roles_on_project``. - :returns: None. - """ - if not roles_on_project: - roles_on_project = [] - if not isinstance(roles, list): - roles = [roles] - if not isinstance(roles_on_project, list): - roles_on_project = [roles_on_project] - - available_roles = { - 'roles': [{'name': role, 'id': '%s_id' % role} for role in roles] - } - available_project_roles = { - 'roles': [{'name': role, 'id': '%s_id' % role} - for role in roles_on_project] - } - - self.admin_roles_client.list_roles.return_value = available_roles - self.admin_roles_client.list_user_roles_on_project.return_value = ( - available_project_roles) diff --git a/patrole_tempest_plugin/tests/unit/resources/admin_rbac_policy.json b/patrole_tempest_plugin/tests/unit/resources/admin_rbac_policy.json deleted file mode 100644 index d6d9605c..00000000 --- a/patrole_tempest_plugin/tests/unit/resources/admin_rbac_policy.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "admin_rule": "role:admin", - "is_admin_rule": "is_admin:True", - "alt_admin_rule": "is_admin:True or (role:admin and is_project_admin:True)", - "member_rule": "role:member", - "reader_rule": "role:reader" -} diff --git a/patrole_tempest_plugin/tests/unit/resources/alt_admin_rbac_policy.json b/patrole_tempest_plugin/tests/unit/resources/alt_admin_rbac_policy.json deleted file mode 100644 index bf07182c..00000000 --- a/patrole_tempest_plugin/tests/unit/resources/alt_admin_rbac_policy.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "context_is_admin": "role:super_admin", - "admin_rule": "role:super_admin", - "non_admin_rule": "role:fake_admin" -} diff --git a/patrole_tempest_plugin/tests/unit/resources/custom_rbac_policy.json b/patrole_tempest_plugin/tests/unit/resources/custom_rbac_policy.json deleted file mode 100644 index d9591680..00000000 --- a/patrole_tempest_plugin/tests/unit/resources/custom_rbac_policy.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "even_rule": "role:two or role:four or role:six or role:eight", - "odd_rule": "role:one or role:three or role:five or role:seven or role:nine", - "zero_rule": "role:zero", - "prime_rule": "role:one or role:two or role:three or role:five or role:seven", - "all_rule": "", - - "policy_action_1": "rule:even_rule", - "policy_action_2": "rule:odd_rule", - "policy_action_3": "rule:zero_rule", - "policy_action_4": "rule:prime_rule", - "policy_action_5": "rule:all_rule", - "policy_action_6": "role:eight" -} diff --git a/patrole_tempest_plugin/tests/unit/resources/custom_rbac_policy.yaml b/patrole_tempest_plugin/tests/unit/resources/custom_rbac_policy.yaml deleted file mode 100644 index 444bd2e1..00000000 --- a/patrole_tempest_plugin/tests/unit/resources/custom_rbac_policy.yaml +++ /dev/null @@ -1,13 +0,0 @@ ---- -even_rule: role:two or role:four or role:six or role:eight -odd_rule: role:one or role:three or role:five or role:seven or role:nine -zero_rule: role:zero -prime_rule: role:one or role:two or role:three or role:five or role:seven -all_rule: '' - -policy_action_1: rule:even_rule -policy_action_2: rule:odd_rule -policy_action_3: rule:zero_rule -policy_action_4: rule:prime_rule -policy_action_5: rule:all_rule -policy_action_6: role:eight diff --git a/patrole_tempest_plugin/tests/unit/resources/rbac_roles.yaml b/patrole_tempest_plugin/tests/unit/resources/rbac_roles.yaml deleted file mode 100644 index 357e0e6b..00000000 --- a/patrole_tempest_plugin/tests/unit/resources/rbac_roles.yaml +++ /dev/null @@ -1,10 +0,0 @@ -Test: - test:create: - - test_member - - _member_ - test:create2: - - test_member - test:create3: - - test_member, _member_ - test:create4: - - test_member, !_member_ \ No newline at end of file diff --git a/patrole_tempest_plugin/tests/unit/resources/tenant_rbac_policy.json b/patrole_tempest_plugin/tests/unit/resources/tenant_rbac_policy.json deleted file mode 100644 index ea65c880..00000000 --- a/patrole_tempest_plugin/tests/unit/resources/tenant_rbac_policy.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "rule1": "tenant_id:%(network:tenant_id)s", - "rule2": "tenant_id:%(tenant_id)s", - "rule3": "project_id:%(project_id)s", - "rule4": "user_id:%(user_id)s", - "admin_tenant_rule": "role:admin and tenant_id:%(tenant_id)s", - "admin_user_rule": "role:admin and user_id:%(user_id)s" -} \ No newline at end of file diff --git a/patrole_tempest_plugin/tests/unit/test_hacking.py b/patrole_tempest_plugin/tests/unit/test_hacking.py deleted file mode 100644 index edfaa7eb..00000000 --- a/patrole_tempest_plugin/tests/unit/test_hacking.py +++ /dev/null @@ -1,302 +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.tests import base - -from patrole_tempest_plugin.hacking import checks - - -class RBACHackingTestCase(base.TestCase): - - def test_import_no_clients_in_api_tests(self): - for client in checks.PYTHON_CLIENTS: - import_string = "import " + client + "client" - self.assertTrue(checks.import_no_clients_in_api_tests( - import_string, - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - self.assertFalse(checks.import_no_clients_in_api_tests( - import_string, - "./patrole_tempest_plugin/tests/scenario/fake_test.py")) - self.assertFalse(checks.import_no_clients_in_api_tests( - import_string, - "./patrole_tempest_plugin/tests/unit/fake_test.py")) - self.assertFalse(checks.import_no_clients_in_api_tests( - import_string, - "./patrole_tempest_plugin/fake_test.py")) - - def test_no_setup_teardown_class_for_tests(self): - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def setUpClass(cls):", - "./patrole_tempest_plugin/tests/fake_test.py")) - self.assertIsNone(checks.no_setup_teardown_class_for_tests( - " def setUpClass(cls): # noqa", - "./patrole_tempest_plugin/tests/fake_test.py")) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def setUpClass(cls):", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def setUpClass(cls):", - "./patrole_tempest_plugin/tests/scenario/fake_test.py")) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def tearDownClass(cls):", - "./patrole_tempest_plugin/tests/fake_test.py")) - self.assertIsNone(checks.no_setup_teardown_class_for_tests( - " def tearDownClass(cls): # noqa", - "./patrole_tempest_plugin/tests/fake_test.py")) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def tearDownClass(cls):", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - self.assertTrue(checks.no_setup_teardown_class_for_tests( - " def tearDownClass(cls):", - "./patrole_tempest_plugin/tests/scenario/fake_test.py")) - - def test_service_tags_not_in_module_path(self): - self.assertTrue(checks.service_tags_not_in_module_path( - "@utils.services('volume')", - "./patrole_tempest_plugin/tests/api/volume/fake_test_rbac.py")) - self.assertFalse(checks.service_tags_not_in_module_path( - "@utils.services('image')", - "./patrole_tempest_plugin/tests/api/volume/fake_test_rbac.py")) - - def test_no_hyphen_at_end_of_rand_name(self): - self.assertIsNone(checks.no_hyphen_at_end_of_rand_name( - "data_utils.rand_name('test')", - "./patrole_tempest_plugin/tests/fake_test.py")) - self.assertIsNone(checks.no_hyphen_at_end_of_rand_name( - "data_utils.rand_name('test')", - "./patrole_tempest_plugin/tests/api/compute/fake_test_rbac.py")) - self.assertIsNone(checks.no_hyphen_at_end_of_rand_name( - "data_utils.rand_name('test')", - "./patrole_tempest_plugin/tests/scenario/fake_test.py")) - self.assertIsNone(checks.no_hyphen_at_end_of_rand_name( - "data_utils.rand_name('test')", - "./patrole_tempest_plugin/tests/unit/fake_test.py")) - self.assertTrue(checks.no_hyphen_at_end_of_rand_name( - "data_utils.rand_name('test-')", - "./patrole_tempest_plugin/tests/fake_test.py")) - self.assertTrue(checks.no_hyphen_at_end_of_rand_name( - "data_utils.rand_name('test-')", - "./patrole_tempest_plugin/tests/api/compute/fake_test_rbac.py")) - self.assertTrue(checks.no_hyphen_at_end_of_rand_name( - "data_utils.rand_name('test-')", - "./patrole_tempest_plugin/tests/scenario/fake_test.py")) - self.assertTrue(checks.no_hyphen_at_end_of_rand_name( - "data_utils.rand_name('test-')", - "./patrole_tempest_plugin/tests/unit/fake_test.py")) - - def test_no_mutable_default_args(self): - self.assertEqual(0, len(list(checks.no_mutable_default_args( - " def test_function(test_param_1, test_param_2")))) - self.assertEqual(1, len(list(checks.no_mutable_default_args( - " def test_function(test_param_1, test_param_2={}")))) - - def test_no_testtools_skip_decorator(self): - self.assertEqual(1, len(list(checks.no_testtools_skip_decorator( - " @testtools.skip('Bug')")))) - self.assertEqual(0, len(list(checks.no_testtools_skip_decorator( - " @testtools.skipTest('reason')")))) - self.assertEqual(0, len(list(checks.no_testtools_skip_decorator( - " @testtools.skipUnless(reason, 'message')")))) - self.assertEqual(0, len(list(checks.no_testtools_skip_decorator( - " @testtools.skipIf(reason, 'message')")))) - - def test_use_rand_uuid_instead_of_uuid4(self): - self.assertTrue(checks.use_rand_uuid_instead_of_uuid4( - "new_uuid = uuid.uuid4()", - "./patrole_tempest_plugin/tests/fake_test.py")) - self.assertTrue(checks.use_rand_uuid_instead_of_uuid4( - "new_hex_uuid = uuid.uuid4().hex", - "./patrole_tempest_plugin/tests/fake_test.py")) - self.assertIsNotNone(checks.use_rand_uuid_instead_of_uuid4( - "new_uuid = data_utils.rand_uuid()", - "./patrole_tempest_plugin/tests/fake_test.py")) - self.assertIsNotNone(checks.use_rand_uuid_instead_of_uuid4( - "new_hex_uuid = data_utils.rand_uuid_hex()", - "./patrole_tempest_plugin/tests/fake_test.py")) - - def _test_no_rbac_rule_validation_decorator( - self, filename, with_other_decorators=True, - with_rbac_decorator=True, expected_success=True): - other_decorators = [ - "@decorators.idempotent_id(123)", - "@decorators.attr(type=['slow'])", - "@utils.requires_ext(extension='ext', service='svc')" - ] - - if with_other_decorators: - # Include multiple decorators to verify that this check works with - # arbitrarily many decorators. These insert decorators above the - # rbac_rule_validation decorator. - for decorator in other_decorators: - self.assertIsNone(checks.no_rbac_rule_validation_decorator( - " %s" % decorator, filename)) - if with_rbac_decorator: - self.assertIsNone(checks.no_rbac_rule_validation_decorator( - " @rbac_rule_validation.action('rule')", - filename)) - if with_other_decorators: - # Include multiple decorators to verify that this check works with - # arbitrarily many decorators. These insert decorators between - # the test and the @rbac_rule_validation decorator. - for decorator in other_decorators: - self.assertIsNone(checks.no_rbac_rule_validation_decorator( - " %s" % decorator, filename)) - final_result = checks.no_rbac_rule_validation_decorator( - " def test_rbac_test", - filename) - if expected_success: - self.assertIsNone(final_result) - else: - self.assertIsInstance(final_result, tuple) - self.assertFalse(final_result[0]) - - def test_no_rbac_rule_validation_decorator(self): - self._test_no_rbac_rule_validation_decorator( - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py") - self._test_no_rbac_rule_validation_decorator( - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py", - False) - self._test_no_rbac_rule_validation_decorator( - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py", - with_other_decorators=True, with_rbac_decorator=False, - expected_success=False) - self._test_no_rbac_rule_validation_decorator( - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py", - with_other_decorators=False, with_rbac_decorator=False, - expected_success=False) - - self._test_no_rbac_rule_validation_decorator( - "./patrole_tempest_plugin/tests/scenario/fake_test.py") - self._test_no_rbac_rule_validation_decorator( - "./patrole_tempest_plugin/tests/scenario/fake_test.py", - False) - self._test_no_rbac_rule_validation_decorator( - "./patrole_tempest_plugin/tests/scenario/fake_test.py", - with_other_decorators=True, with_rbac_decorator=False, - expected_success=False) - self._test_no_rbac_rule_validation_decorator( - "./patrole_tempest_plugin/tests/scenario/fake_test.py", - with_other_decorators=False, with_rbac_decorator=False, - expected_success=False) - - def test_no_rbac_suffix_in_test_filename(self): - self.assertFalse(checks.no_rbac_suffix_in_test_filename( - "./patrole_tempest_plugin/tests/fake_test.py")) - self.assertFalse(checks.no_rbac_suffix_in_test_filename( - "./patrole_tempest_plugin/tests/scenario/fake_test.py")) - self.assertFalse(checks.no_rbac_suffix_in_test_filename( - "./patrole_tempest_plugin/tests/unit/fake_test.py")) - self.assertFalse(checks.no_rbac_suffix_in_test_filename( - "./patrole_tempest_plugin/tests/api/fake_rbac_base.py")) - self.assertFalse(checks.no_rbac_suffix_in_test_filename( - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - self.assertTrue(checks.no_rbac_suffix_in_test_filename( - "./patrole_tempest_plugin/tests/api/fake_test.py")) - - def test_no_rbac_test_suffix_in_test_class_name(self): - self.assertFalse(checks.no_rbac_test_suffix_in_test_class_name( - "class FakeTest", - "./patrole_tempest_plugin/tests/fake_test.py")) - self.assertFalse(checks.no_rbac_test_suffix_in_test_class_name( - "class FakeTest", - "./patrole_tempest_plugin/tests/scenario/fake_test.py")) - self.assertFalse(checks.no_rbac_test_suffix_in_test_class_name( - "class FakeTest", - "./patrole_tempest_plugin/tests/unit/fake_test.py")) - self.assertFalse(checks.no_rbac_test_suffix_in_test_class_name( - "class FakeTest", - "./patrole_tempest_plugin/tests/api/fake_rbac_base.py")) - self.assertFalse(checks.no_rbac_test_suffix_in_test_class_name( - "class FakeRbacTest", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - self.assertTrue(checks.no_rbac_test_suffix_in_test_class_name( - "class FakeTest", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - - def test_no_client_alias_in_test_cases(self): - self.assertFalse(checks.no_client_alias_in_test_cases( - " self.client", - "./patrole_tempest_plugin/tests/fake_test.py")) - self.assertFalse(checks.no_client_alias_in_test_cases( - " cls.client", - "./patrole_tempest_plugin/tests/fake_test.py")) - self.assertFalse(checks.no_client_alias_in_test_cases( - " self.client", - "./patrole_tempest_plugin/tests/unit/fake_test.py")) - self.assertFalse(checks.no_client_alias_in_test_cases( - " cls.client", - "./patrole_tempest_plugin/tests/unit/fake_test.py")) - self.assertFalse(checks.no_client_alias_in_test_cases( - " self.client", - "./patrole_tempest_plugin/tests/scenario/fake_test.py")) - self.assertFalse(checks.no_client_alias_in_test_cases( - " cls.client", - "./patrole_tempest_plugin/tests/scenario/fake_test.py")) - self.assertTrue(checks.no_client_alias_in_test_cases( - " self.client", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - self.assertTrue(checks.no_client_alias_in_test_cases( - " cls.client", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - - def no_extension_rbac_test_suffix_in_plugin_test_class_name(self): - check = checks.no_extension_rbac_test_suffix_in_plugin_test_class_name - - # Passing cases: these do not inherit from "ExtRbacTest" base class. - self.assertFalse(check( - "class FakeRbacTest(BaseFakeRbacTest)", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - self.assertFalse(check( - "class FakeRbacTest(base.BaseFakeRbacTest)", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - - # Passing cases: these **do** end in correct test class suffix. - self.assertFalse(check( - "class FakeExtRbacTest(BaseFakeExtRbacTest)", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - self.assertFalse(check( - "class FakeExtRbacTest(base.BaseFakeExtRbacTest)", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - - # Passing cases: plugin base class inherits from another base class. - self.assertFalse(check( - "class BaseFakeExtRbacTest(base.BaseFakeRbacTest)", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - self.assertFalse(check( - "class BaseFakeExtRbacTest(BaseFakeRbacTest)", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - - # Failing cases: these **do not** end in correct test class suffix. - # Case 1: RbacTest subclass doesn't end in ExtRbacTest. - self.assertTrue(check( - "class FakeRbacTest(base.BaseFakeExtRbacTest)", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - self.assertTrue(check( - "class FakeRbacTest(BaseFakeExtRbacTest)", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - self.assertTrue(check( - "class FakeRbacTest(BaseFakeNetworkExtRbacTest)", - "./patrole_tempest_plugin/tests/api/network/fake_test_rbac.py")) - # Case 2: ExtRbacTest subclass doesn't inherit from - # BaseExtRbacTest. - self.assertTrue(check( - "class FakeExtRbacTest(base.BaseFakeRbacTest)", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - self.assertTrue(check( - "class FakeExtRbacTest(BaseFakeRbacTest)", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) - self.assertTrue(check( - "class FakeNeutronExtRbacTest(BaseFakeNeutronRbacTest)", - "./patrole_tempest_plugin/tests/api/fake_test_rbac.py")) diff --git a/patrole_tempest_plugin/tests/unit/test_policy_authority.py b/patrole_tempest_plugin/tests/unit/test_policy_authority.py deleted file mode 100644 index fc7cafb7..00000000 --- a/patrole_tempest_plugin/tests/unit/test_policy_authority.py +++ /dev/null @@ -1,639 +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. - -import os -from unittest import mock - -from tempest import config - -from patrole_tempest_plugin import policy_authority -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin.tests.unit import base -from patrole_tempest_plugin.tests.unit import fixtures - -CONF = config.CONF - - -class PolicyAuthorityTest(base.TestCase): - - services = { - 'services': [ - {'name': 'custom_rbac_policy'}, - {'name': 'admin_rbac_policy'}, - {'name': 'alt_admin_rbac_policy'}, - {'name': 'tenant_rbac_policy'}, - {'name': 'test_service'} - ] - } - - def setUp(self): - super(PolicyAuthorityTest, self).setUp() - - mock_admin = self.patchobject(policy_authority.PolicyAuthority, - 'os_admin') - mock_admin.identity_services_client.list_services.\ - return_value = self.services - mock_admin.identity_services_v3_client.list_services.\ - return_value = self.services - - current_directory = os.path.dirname(os.path.realpath(__file__)) - self.custom_policy_file = os.path.join(current_directory, - 'resources', - 'custom_rbac_policy.json') - self.admin_policy_file = os.path.join(current_directory, - 'resources', - 'admin_rbac_policy.json') - self.alt_admin_policy_file = os.path.join(current_directory, - 'resources', - 'alt_admin_rbac_policy.json') - self.tenant_policy_file = os.path.join(current_directory, - 'resources', - 'tenant_rbac_policy.json') - self.conf_policy_path_json = os.path.join( - current_directory, 'resources', '%s.json') - - self.conf_policy_path_yaml = os.path.join( - current_directory, 'resources', '%s.yaml') - - self.useFixture(fixtures.ConfPatcher( - custom_policy_files=[self.conf_policy_path_json], group='patrole')) - self.useFixture(fixtures.ConfPatcher( - api_v3=True, api_v2=False, group='identity-feature-enabled')) - - # Guarantee a blank slate for each test. - for attr in ('available_services', 'policy_files'): - if attr in dir(policy_authority.PolicyAuthority): - delattr(policy_authority.PolicyAuthority, attr) - - self.test_obj = self.useFixture(fixtures.RbacUtilsMixinFixture()).\ - test_obj - - @staticmethod - def _get_fake_policies(rules): - fake_rules = [] - rules = policy_authority.policy.Rules.from_dict(rules) - for name, check in rules.items(): - fake_rule = mock.Mock(check=check, __name__='foo') - fake_rule.name = name - fake_rule.deprecated_rule = False - fake_rules.append(fake_rule) - return fake_rules - - def _test_policy_file(self, roles, allowed_rules, - disallowed_rules, authority=None, service=None): - if authority is None: - self.assertIsNotNone(service) - test_tenant_id = mock.sentinel.tenant_id - test_user_id = mock.sentinel.user_id - authority = policy_authority.PolicyAuthority( - test_tenant_id, test_user_id, service) - - roles = self.test_obj.get_all_needed_roles(roles) - - for rule in allowed_rules: - allowed = authority.allowed(rule, roles) - self.assertTrue(allowed) - - for rule in disallowed_rules: - allowed = authority.allowed(rule, roles) - self.assertFalse(allowed) - - return authority - - @mock.patch.object(policy_authority, 'LOG', autospec=True) - def _test_custom_policy(self, *args): - default_roles = ['zero', 'one', 'two', 'three', 'four', - 'five', 'six', 'seven', 'eight', 'nine'] - - test_tenant_id = mock.sentinel.tenant_id - test_user_id = mock.sentinel.user_id - authority = policy_authority.PolicyAuthority( - test_tenant_id, test_user_id, "custom_rbac_policy") - - expected = { - 'policy_action_1': ['two', 'four', 'six', 'eight'], - 'policy_action_2': ['one', 'three', 'five', 'seven', 'nine'], - 'policy_action_3': ['zero'], - 'policy_action_4': ['one', 'two', 'three', 'five', 'seven'], - 'policy_action_5': ['zero', 'one', 'two', 'three', 'four', 'five', - 'six', 'seven', 'eight', 'nine'], - 'policy_action_6': ['eight'], - } - - for rule, role_list in expected.items(): - for role in role_list: - self.assertTrue(authority.allowed(rule, [role])) - for role in set(default_roles) - set(role_list): - self.assertFalse(authority.allowed(rule, [role])) - - @mock.patch.object(policy_authority, 'LOG', autospec=True) - def _test_custom_multi_roles_policy(self, *args): - default_roles = ['zero', 'one', 'two', 'three', 'four', - 'five', 'six', 'seven', 'eight', 'nine'] - - test_tenant_id = mock.sentinel.tenant_id - test_user_id = mock.sentinel.user_id - authority = policy_authority.PolicyAuthority( - test_tenant_id, test_user_id, "custom_rbac_policy") - - expected = { - 'policy_action_1': ['two', 'four', 'six', 'eight'], - 'policy_action_2': ['one', 'three', 'five', 'seven', 'nine'], - 'policy_action_4': ['one', 'two', 'three', 'five', 'seven'], - 'policy_action_5': ['zero', 'one', 'two', 'three', 'four', 'five', - 'six', 'seven', 'eight', 'nine'], - } - - for rule, role_list in expected.items(): - allowed_roles_lists = [roles for roles in [ - role_list[len(role_list) // 2:], - role_list[:len(role_list) // 2]] if roles] - for test_roles in allowed_roles_lists: - self.assertTrue(authority.allowed(rule, test_roles)) - - disallowed_roles = list(set(default_roles) - set(role_list)) - disallowed_roles_lists = [roles for roles in [ - disallowed_roles[len(disallowed_roles) // 2:], - disallowed_roles[:len(disallowed_roles) // 2]] if roles] - for test_roles in disallowed_roles_lists: - self.assertFalse(authority.allowed(rule, test_roles)) - - def test_empty_rbac_test_roles(self): - self._test_policy_file( - roles=[], - allowed_rules=['policy_action_5'], - disallowed_rules=['policy_action_1', 'policy_action_2', - 'policy_action_3', 'policy_action_4', - 'policy_action_6'], - service="custom_rbac_policy" - ) - - def test_custom_policy_json(self): - # The CONF.patrole.custom_policy_files has a path to JSON file by - # default, so we don't need to use ConfPatcher here. - self._test_custom_policy() - - def test_custom_policy_yaml(self): - self.useFixture(fixtures.ConfPatcher( - custom_policy_files=[self.conf_policy_path_yaml], group='patrole')) - self._test_custom_policy() - - def test_custom_multi_roles_policy_json(self): - # The CONF.patrole.custom_policy_files has a path to JSON file by - # default, so we don't need to use ConfPatcher here. - self._test_custom_multi_roles_policy() - - def test_custom_multi_roles_policy_yaml(self): - self.useFixture(fixtures.ConfPatcher( - custom_policy_files=[self.conf_policy_path_yaml], group='patrole')) - self._test_custom_multi_roles_policy() - - def test_admin_policy_file_with_admin_role(self): - # admin role implies member and reader roles - self._test_policy_file( - roles=['admin'], - allowed_rules=['admin_rule', 'is_admin_rule', 'alt_admin_rule', - 'member_rule', 'reader_rule'], - disallowed_rules=[], - service="admin_rbac_policy" - ) - - def test_admin_policy_file_with_member_role(self): - # member role implies reader role - self._test_policy_file( - roles=['member'], - allowed_rules=['member_rule', 'reader_rule'], - disallowed_rules=['admin_rule', 'is_admin_rule', 'alt_admin_rule'], - service="admin_rbac_policy" - ) - - def test_admin_policy_file_with_reader_role(self): - self._test_policy_file( - roles=['reader'], - allowed_rules=['reader_rule'], - disallowed_rules=['admin_rule', 'is_admin_rule', 'alt_admin_rule', - 'member_rule'], - service="admin_rbac_policy" - ) - - def test_alt_admin_policy_file_with_context_is_admin(self): - authority = self._test_policy_file( - roles=['fake_admin'], - allowed_rules=['non_admin_rule'], - disallowed_rules=['admin_rule'], - service="alt_admin_rbac_policy" - ) - - self._test_policy_file( - roles=['super_admin'], - allowed_rules=['admin_rule'], - disallowed_rules=['non_admin_rule'], - authority=authority - ) - - def test_tenant_user_policy(self): - """Test whether rules with format tenant_id/user_id formatting work. - - Test whether Neutron rules that contain project_id, tenant_id, and - network:tenant_id pass. And test whether Nova rules that contain - user_id pass. - """ - allowed_rules = ['rule1', 'rule2', 'rule3', 'rule4'] - disallowed_rules = ['admin_tenant_rule', 'admin_user_rule'] - - # Check whether Member role can perform expected actions. - authority = self._test_policy_file( - roles=['member'], - allowed_rules=allowed_rules, - disallowed_rules=disallowed_rules, - service="tenant_rbac_policy", - ) - - # Check whether admin role can perform expected actions. - allowed_rules.extend(disallowed_rules) - self._test_policy_file( - roles=['admin'], - allowed_rules=allowed_rules, - disallowed_rules=[], - authority=authority - ) - - # Check whether _try_rule is called with the correct target dictionary. - with mock.patch.object( - authority, '_try_rule', return_value=True, autospec=True) \ - as mock_try_rule: - - expected_target = { - "project_id": mock.sentinel.tenant_id, - "tenant_id": mock.sentinel.tenant_id, - "network:tenant_id": mock.sentinel.tenant_id, - "user_id": mock.sentinel.user_id - } - - expected_access_data = { - "roles": sorted(['member', 'reader']), - "is_admin": False, - "is_admin_project": True, - "user_id": mock.sentinel.user_id, - "tenant_id": mock.sentinel.tenant_id, - "project_id": mock.sentinel.tenant_id - } - - for rule in allowed_rules: - allowed = authority.allowed( - rule, self.test_obj.get_all_needed_roles(['member'])) - self.assertTrue(allowed) - # for sure that roles are in same order - mock_try_rule.call_args[0][2]["roles"] = sorted( - mock_try_rule.call_args[0][2]["roles"]) - mock_try_rule.assert_called_once_with( - rule, expected_target, expected_access_data, mock.ANY) - mock_try_rule.reset_mock() - - @mock.patch.object(policy_authority, 'LOG', autospec=True) - def test_invalid_service_raises_exception(self, m_log): - test_tenant_id = mock.sentinel.tenant_id - test_user_id = mock.sentinel.user_id - service = 'invalid_service' - - self.assertRaises(rbac_exceptions.RbacInvalidServiceException, - policy_authority.PolicyAuthority, - test_tenant_id, - test_user_id, - service) - - m_log.debug.assert_called_once_with( - '%s is NOT a valid service.', service) - - @mock.patch.object(policy_authority, 'LOG', autospec=True) - def test_service_is_none_raises_exception(self, m_log): - test_tenant_id = mock.sentinel.tenant_id - test_user_id = mock.sentinel.user_id - service = None - - self.assertRaises(rbac_exceptions.RbacInvalidServiceException, - policy_authority.PolicyAuthority, - test_tenant_id, - test_user_id, - service) - - m_log.debug.assert_called_once_with('%s is NOT a valid service.', None) - - @mock.patch.object(policy_authority, 'LOG', autospec=True) - def test_invalid_policy_rule_throws_rbac_parsing_exception(self, m_log): - test_tenant_id = mock.sentinel.tenant_id - test_user_id = mock.sentinel.user_id - authority = policy_authority.PolicyAuthority( - test_tenant_id, test_user_id, "custom_rbac_policy") - - fake_rule = 'fake_rule' - expected_message = ( - 'Policy action "{0}" not found in policy files: {1} or among ' - 'registered policy in code defaults for {2} service.').format( - fake_rule, [self.custom_policy_file], "custom_rbac_policy") - - e = self.assertRaises(rbac_exceptions.RbacParsingException, - authority.allowed, fake_rule, [None]) - self.assertIn(expected_message, str(e)) - m_log.debug.assert_called_once_with(expected_message) - - @mock.patch.object(policy_authority, 'LOG', autospec=True) - def test_unknown_exception_throws_rbac_parsing_exception(self, m_log): - test_tenant_id = mock.sentinel.tenant_id - test_user_id = mock.sentinel.user_id - - authority = policy_authority.PolicyAuthority( - test_tenant_id, test_user_id, "custom_rbac_policy") - authority.rules = mock.MagicMock( - __name__='foo', - **{'__getitem__.return_value.side_effect': Exception( - mock.sentinel.error)}) - - expected_message = ( - 'Policy action "[{0}]" not found in policy files: {1} or among ' - 'registered policy in code defaults for {2} service.').format( - mock.sentinel.rule, [self.custom_policy_file], - "custom_rbac_policy") - - e = self.assertRaises(rbac_exceptions.RbacParsingException, - authority.allowed, [mock.sentinel.rule], [None]) - self.assertIn(expected_message, str(e)) - m_log.debug.assert_called_once_with(expected_message) - - @mock.patch.object(policy_authority, 'stevedore', autospec=True) - def test_get_rules_from_file_and_from_code(self, mock_stevedore): - fake_policy_rules = self._get_fake_policies({ - 'code_policy_action_1': 'rule:code_rule_1', - 'code_policy_action_2': 'rule:code_rule_2', - 'code_policy_action_3': 'rule:code_rule_3', - }) - - mock_manager = mock.Mock(obj=fake_policy_rules, __name__='foo') - mock_manager.configure_mock(name='tenant_rbac_policy') - mock_stevedore.named.NamedExtensionManager.return_value = [ - mock_manager - ] - - test_tenant_id = mock.sentinel.tenant_id - test_user_id = mock.sentinel.user_id - authority = policy_authority.PolicyAuthority( - test_tenant_id, test_user_id, "tenant_rbac_policy") - - rules = authority.get_rules() - self.assertIsInstance(rules, policy_authority.policy.Rules) - - actual_policy_data = {k: str(v) for k, v in rules.items()} - expected_policy_data = { - "code_policy_action_1": "rule:code_rule_1", - "code_policy_action_2": "rule:code_rule_2", - "code_policy_action_3": "rule:code_rule_3", - "rule1": "tenant_id:%(network:tenant_id)s", - "rule2": "tenant_id:%(tenant_id)s", - "rule3": "project_id:%(project_id)s", - "rule4": "user_id:%(user_id)s", - "admin_tenant_rule": "(role:admin and tenant_id:%(tenant_id)s)", - "admin_user_rule": "(role:admin and user_id:%(user_id)s)" - } - - self.assertEqual(expected_policy_data, actual_policy_data) - - @mock.patch.object(policy_authority, 'stevedore', autospec=True) - def test_get_rules_from_file_and_from_code_with_overwrite( - self, mock_stevedore): - # The custom policy file should overwrite default rules rule1 and rule2 - # that are defined in code. - fake_policy_rules = self._get_fake_policies({ - 'rule1': 'rule:code_rule_1', - 'rule2': 'rule:code_rule_2', - 'code_policy_action_3': 'rule:code_rule_3', - }) - - mock_manager = mock.Mock(obj=fake_policy_rules, __name__='foo') - mock_manager.configure_mock(name='tenant_rbac_policy') - mock_stevedore.named.NamedExtensionManager.return_value = [ - mock_manager - ] - - test_tenant_id = mock.sentinel.tenant_id - test_user_id = mock.sentinel.user_id - - authority = policy_authority.PolicyAuthority( - test_tenant_id, test_user_id, 'tenant_rbac_policy') - rules = authority.get_rules() - self.assertIsInstance(rules, policy_authority.policy.Rules) - - actual_policy_data = {k: str(v) for k, v in rules.items()} - expected_policy_data = { - "code_policy_action_3": "rule:code_rule_3", - "rule1": "tenant_id:%(network:tenant_id)s", - "rule2": "tenant_id:%(tenant_id)s", - "rule3": "project_id:%(project_id)s", - "rule4": "user_id:%(user_id)s", - "admin_tenant_rule": "(role:admin and tenant_id:%(tenant_id)s)", - "admin_user_rule": "(role:admin and user_id:%(user_id)s)" - } - - self.assertEqual(expected_policy_data, actual_policy_data) - - @mock.patch.object(policy_authority, 'stevedore', autospec=True) - def test_get_rules_cannot_find_policy(self, mock_stevedore): - mock_stevedore.named.NamedExtensionManager.return_value = None - e = self.assertRaises(rbac_exceptions.RbacParsingException, - policy_authority.PolicyAuthority, - None, None, 'test_service') - - expected_error = ( - 'Policy files for {0} service were not found among the registered ' - 'in-code policies or in any of the possible policy files: {1}.' - .format('test_service', - [CONF.patrole.custom_policy_files[0] % 'test_service'])) - self.assertIn(expected_error, str(e)) - - @mock.patch.object(policy_authority.policy, 'parse_file_contents', - autospec=True) - @mock.patch.object(policy_authority, 'stevedore', autospec=True) - def test_get_rules_without_valid_policy(self, mock_stevedore, - mock_parse_file_contents): - mock_stevedore.named.NamedExtensionManager.return_value = None - mock_parse_file_contents.side_effect = ValueError - e = self.assertRaises(rbac_exceptions.RbacParsingException, - policy_authority.PolicyAuthority, - None, None, 'tenant_rbac_policy') - - expected_error = ( - 'Policy files for {0} service were not found among the registered ' - 'in-code policies or in any of the possible policy files:' - .format('tenant_rbac_policy')) - self.assertIn(expected_error, str(e)) - - def test_discover_policy_files(self): - policy_parser = policy_authority.PolicyAuthority( - None, None, 'tenant_rbac_policy') - - # Ensure that "policy_files" is set at class and instance levels. - self.assertIn('policy_files', - dir(policy_authority.PolicyAuthority)) - self.assertIn('policy_files', dir(policy_parser)) - self.assertIn('tenant_rbac_policy', policy_parser.policy_files) - self.assertEqual([self.conf_policy_path_json % 'tenant_rbac_policy'], - policy_parser.policy_files['tenant_rbac_policy']) - - @mock.patch.object(policy_authority, 'policy', autospec=True) - @mock.patch.object(policy_authority.PolicyAuthority, 'get_rules', - autospec=True) - @mock.patch.object(policy_authority.PolicyAuthority, 'os_admin', - autospec=True) - @mock.patch.object(policy_authority, 'os', autospec=True) - @mock.patch.object(policy_authority, 'glob', autospec=True) - def test_discover_policy_files_with_many_invalid_one_valid(self, m_glob, - m_os, m_admin, - *args): - service = 'test_service' - custom_policy_files = ['foo/%s', 'bar/%s', 'baz/%s'] - m_glob.iglob.side_effect = [iter([path % service]) - for path in custom_policy_files] - # Only the 3rd path is valid. - m_os.path.isfile.side_effect = [False, False, True] - - # Ensure the outer for loop runs only once in `discover_policy_files`. - m_admin.identity_services_v3_client.\ - list_services.return_value = { - 'services': [{'name': service}]} - - # The expected policy will be 'baz/test_service'. - self.useFixture(fixtures.ConfPatcher( - custom_policy_files=custom_policy_files, - group='patrole')) - - policy_parser = policy_authority.PolicyAuthority( - None, None, service) - - # Ensure that "policy_files" is set at class and instance levels. - self.assertTrue(hasattr(policy_authority.PolicyAuthority, - 'policy_files')) - self.assertTrue(hasattr(policy_parser, 'policy_files')) - self.assertEqual(['baz/%s' % service], - policy_parser.policy_files[service]) - - def test_discover_policy_files_with_no_valid_files(self): - expected_error = ( - 'Policy files for {0} service were not found among the registered ' - 'in-code policies or in any of the possible policy files: {1}.' - .format('test_service', - [self.conf_policy_path_json % 'test_service'])) - - e = self.assertRaises(rbac_exceptions.RbacParsingException, - policy_authority.PolicyAuthority, - None, None, 'test_service') - self.assertIn(expected_error, str(e)) - - self.assertTrue(hasattr(policy_authority.PolicyAuthority, - 'policy_files')) - self.assertEqual( - [], - policy_authority.PolicyAuthority.policy_files['test_service']) - - def _test_validate_service(self, v2_services, v3_services, - expected_failure=False, expected_services=None): - with mock.patch.object(policy_authority.PolicyAuthority, 'os_admin', - autospec=True) as m_admin: - m_admin.identity_services_client.list_services.\ - return_value = v2_services - m_admin.identity_services_v3_client.list_services.\ - return_value = v3_services - - test_tenant_id = mock.sentinel.tenant_id - test_user_id = mock.sentinel.user_id - - mock_os = self.patchobject(policy_authority, 'os') - mock_os.path.join.return_value = self.admin_policy_file - - if not expected_services: - expected_services = [s['name'] for s in self.services['services']] - - # Guarantee a blank slate for this test. - if hasattr(policy_authority.PolicyAuthority, 'available_services'): - delattr(policy_authority.PolicyAuthority, - 'available_services') - - if expected_failure: - policy_parser = None - - expected_exception = 'invalid_service is NOT a valid service' - with self.assertRaisesRegex( - rbac_exceptions.RbacInvalidServiceException, - expected_exception): - policy_authority.PolicyAuthority( - test_tenant_id, test_user_id, "INVALID_SERVICE") - else: - policy_parser = policy_authority.PolicyAuthority( - test_tenant_id, test_user_id, "tenant_rbac_policy") - - # Check that the attribute is available at object and class levels. - # If initialization failed, only check at class level. - if policy_parser: - self.assertTrue(hasattr(policy_parser, 'available_services')) - self.assertEqual(expected_services, - policy_parser.available_services) - self.assertTrue(hasattr(policy_authority.PolicyAuthority, - 'available_services')) - self.assertEqual( - expected_services, - policy_authority.PolicyAuthority.available_services) - - def test_validate_service(self): - """Positive test case to ensure ``validate_service`` works. - - There are 3 possibilities: - 1) Identity v3 API enabled. - 2) Identity v2 API enabled. - 3) Both are enabled. - """ - self.useFixture(fixtures.ConfPatcher( - api_v2=True, api_v3=False, group='identity-feature-enabled')) - self._test_validate_service(self.services, [], False) - - self.useFixture(fixtures.ConfPatcher( - api_v2=False, api_v3=True, group='identity-feature-enabled')) - self._test_validate_service([], self.services, False) - - self.useFixture(fixtures.ConfPatcher( - api_v2=True, api_v3=True, group='identity-feature-enabled')) - self._test_validate_service(self.services, self.services, False) - - def test_validate_service_except_invalid_service(self): - """Negative test case to ensure ``validate_service`` works. - - There are 4 possibilities: - 1) Identity v3 API enabled. - 2) Identity v2 API enabled. - 3) Both are enabled. - 4) Neither are enabled. - """ - self.useFixture(fixtures.ConfPatcher( - api_v2=True, api_v3=False, group='identity-feature-enabled')) - self._test_validate_service(self.services, [], True) - - self.useFixture(fixtures.ConfPatcher( - api_v2=False, api_v3=True, group='identity-feature-enabled')) - self._test_validate_service([], self.services, True) - - self.useFixture(fixtures.ConfPatcher( - api_v2=True, api_v3=True, group='identity-feature-enabled')) - self._test_validate_service(self.services, self.services, True) - - self.useFixture(fixtures.ConfPatcher( - api_v2=False, api_v3=False, group='identity-feature-enabled')) - self._test_validate_service([], [], True, []) diff --git a/patrole_tempest_plugin/tests/unit/test_rbac_rule_validation.py b/patrole_tempest_plugin/tests/unit/test_rbac_rule_validation.py deleted file mode 100644 index 471bcdc4..00000000 --- a/patrole_tempest_plugin/tests/unit/test_rbac_rule_validation.py +++ /dev/null @@ -1,1089 +0,0 @@ -# Copyright 2017 AT&T Inc. -# -# 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 unittest import mock - -import fixtures -import functools -from oslo_config import cfg -from tempest.lib import exceptions - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_rule_validation as rbac_rv -from patrole_tempest_plugin.tests.unit import base -from patrole_tempest_plugin.tests.unit import fixtures as patrole_fixtures - -CONF = cfg.CONF - - -class BaseRBACRuleValidationTest(base.TestCase): - - test_roles = ['member'] - - def setUp(self): - super(BaseRBACRuleValidationTest, self).setUp() - self.rbac_utils_fixture = self.useFixture( - patrole_fixtures.RbacUtilsMixinFixture( - rbac_test_roles=self.test_roles)) - self.test_obj = self.rbac_utils_fixture.test_obj - - -class BaseRBACMultiRoleRuleValidationTest(BaseRBACRuleValidationTest): - - test_roles = ['member', 'anotherrole'] - - -class RBACRuleValidationTest(BaseRBACRuleValidationTest): - """Test suite for validating fundamental functionality for the - ``rbac_rule_validation`` decorator. - """ - - def setUp(self): - super(RBACRuleValidationTest, self).setUp() - # This behavior is tested in separate test class below. - self.useFixture(fixtures.MockPatchObject( - rbac_rv, '_validate_override_role_called')) - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_have_permission_no_exc(self, mock_authority, - mock_log): - """Test that having permission and no exception thrown is success. - - Positive test case success scenario. - """ - mock_authority.PolicyAuthority.return_value.allowed.return_value = True - - @rbac_rv.action(mock.sentinel.service, rules=[mock.sentinel.action]) - def test_policy(*args): - pass - - test_policy(self.test_obj) - mock_log.error.assert_not_called() - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_lack_permission_throw_exc(self, mock_authority, - mock_log): - """Test that having no permission and exception thrown is success. - - Negative test case success scenario. - """ - mock_authority.PolicyAuthority.return_value.allowed.return_value =\ - False - - @rbac_rv.action(mock.sentinel.service, rules=[mock.sentinel.action]) - def test_policy(*args): - raise exceptions.Forbidden() - - test_policy(self.test_obj) - mock_log.error.assert_not_called() - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_forbidden_negative(self, mock_authority, - mock_log): - """Test RbacUnderPermissionException error is thrown and have - permission fails. - - Negative test case: if Forbidden is thrown and the user should be - allowed to perform the action, then the RbacUnderPermissionException - exception should be raised. - """ - mock_authority.PolicyAuthority.return_value.allowed.return_value = True - - @rbac_rv.action(mock.sentinel.service, rules=[mock.sentinel.action]) - def test_policy(*args): - raise exceptions.Forbidden() - - test_re = (r"User with roles \['member'\] was not allowed to perform " - r"the following actions: \[%s\].*" % (mock.sentinel.action)) - self.assertRaisesRegex( - rbac_exceptions.RbacUnderPermissionException, test_re, test_policy, - self.test_obj) - self.assertRegex(mock_log.error.mock_calls[0][1][0], test_re) - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_rbac_failed_response_body_positive( - self, mock_authority, mock_log): - """Test BasePatroleResponseBodyException error is thrown without - permission passes. - - Positive test case: if subclass of BasePatroleResponseBodyException is - thrown and the user is not allowed to perform the action, then this is - a success. - """ - mock_authority.PolicyAuthority.return_value.allowed.return_value =\ - False - - def _do_test(exception_cls, **kwargs): - @rbac_rv.action(mock.sentinel.service, - rules=[mock.sentinel.action]) - def test_policy(*args): - raise exception_cls(**kwargs) - - mock_log.error.assert_not_called() - mock_log.warning.assert_not_called() - - _do_test(rbac_exceptions.RbacMissingAttributeResponseBody, - attribute=mock.sentinel.attr) - _do_test(rbac_exceptions.RbacPartialResponseBody, - body=mock.sentinel.body) - _do_test(rbac_exceptions.RbacEmptyResponseBody) - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_soft_authorization_exceptions( - self, mock_authority, mock_log): - """Test RbacUnderPermissionException error is thrown when any of the - soft authorization-related exceptions are raised by a test. - - Negative test case: if subclass of BasePatroleResponseBodyException is - thrown and the user is allowed to perform the action, then this is an - expected failure. - """ - mock_authority.PolicyAuthority.return_value.allowed.return_value = True - - def _do_test(exception_cls, **kwargs): - @rbac_rv.action(mock.sentinel.service, - rules=[mock.sentinel.action]) - def test_policy(*args): - raise exception_cls(**kwargs) - - test_re = (r".*User with roles \[%s\] was not allowed to " - r"perform the following actions: \[%s\].*" % ( - ', '.join("'%s'" % r for r in self.test_roles), - mock.sentinel.action)) - self.assertRaisesRegex( - rbac_exceptions.RbacUnderPermissionException, test_re, - test_policy, self.test_obj) - self.assertRegex(mock_log.error.mock_calls[0][1][0], test_re) - - _do_test(rbac_exceptions.RbacMissingAttributeResponseBody, - attribute=mock.sentinel.attr) - _do_test(rbac_exceptions.RbacPartialResponseBody, - body=mock.sentinel.body) - _do_test(rbac_exceptions.RbacEmptyResponseBody) - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_expect_not_found_but_raises_forbidden(self, mock_authority, - mock_log): - """Test that expecting 404 but getting 403 works for all scenarios. - - Tests the following scenarios: - 1) Test no permission and 404 is expected but 403 is thrown throws - exception. - 2) Test have permission and 404 is expected but 403 is thrown throws - exception. - """ - @rbac_rv.action(mock.sentinel.service, rules=[mock.sentinel.action], - expected_error_codes=[404]) - def test_policy(*args): - raise exceptions.Forbidden('Test message') - - error_re = r'Expected .* to be raised but .* was raised instead' - - for allowed in [True, False]: - mock_authority.PolicyAuthority.return_value.allowed.\ - return_value = allowed - self.assertRaisesRegex( - rbac_exceptions.RbacExpectedWrongException, error_re, - test_policy, self.test_obj) - self.assertTrue(mock_log.error.called) - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_expect_not_found_and_raise_not_found(self, mock_authority, - mock_log): - """Test that expecting 404 and getting 404 works for all scenarios. - - Tests the following scenarios: - 1) Test no permission and 404 is expected and 404 is thrown succeeds. - 2) Test have permission and 404 is expected and 404 is thrown fails. - - In both cases, a LOG.warning is called with the "irregular message" - that signals to user that a 404 was expected and caught. - """ - policy_names = ['foo:bar'] - - @rbac_rv.action(mock.sentinel.service, rules=policy_names, - expected_error_codes=[404]) - def test_policy(*args): - raise exceptions.NotFound() - - expected_errors = [ - (r"User with roles \['member'\] was not allowed to perform the " - r"following actions: \['%s'\].*" % policy_names[0]), - None - ] - - for pos, allowed in enumerate([True, False]): - mock_authority.PolicyAuthority.return_value.allowed\ - .return_value = allowed - - error_re = expected_errors[pos] - - if error_re: - self.assertRaisesRegex( - rbac_exceptions.RbacUnderPermissionException, error_re, - test_policy, self.test_obj) - self.assertRegex(mock_log.error.mock_calls[0][1][0], error_re) - else: - test_policy(self.test_obj) - mock_log.error.assert_not_called() - - mock_log.warning.assert_called_with( - "NotFound exception was caught for test %s. Expected policies " - "which may have caused the error: %s. The service %s throws a " - "404 instead of a 403, which is irregular", - test_policy.__name__, - ', '.join(policy_names), - mock.sentinel.service) - - mock_log.warning.reset_mock() - mock_log.error.reset_mock() - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_overpermission_negative(self, mock_authority, - mock_log): - """Test that RbacOverPermissionException is correctly handled. - - Tests that case where no exception is thrown but the Patrole framework - says that the role should not be allowed to perform the policy action. - """ - mock_authority.PolicyAuthority.return_value.allowed.return_value =\ - False - - @rbac_rv.action(mock.sentinel.service, rules=[mock.sentinel.action]) - def test_policy_expect_forbidden(*args): - pass - - @rbac_rv.action(mock.sentinel.service, rules=[mock.sentinel.action], - expected_error_codes=[404]) - def test_policy_expect_not_found(*args): - pass - - for test_policy in ( - test_policy_expect_forbidden, test_policy_expect_not_found): - - error_re = r".*OverPermission: .* \[%s\]$" % mock.sentinel.action - self.assertRaisesRegex(rbac_exceptions.RbacOverPermissionException, - error_re, test_policy, self.test_obj) - self.assertRegex(mock_log.error.mock_calls[0][1][0], error_re) - mock_log.error.reset_mock() - - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_invalid_policy_rule_raises_parsing_exception( - self, mock_authority): - """Test that invalid policy action causes test to raise an exception. - """ - mock_authority.PolicyAuthority.return_value.allowed.\ - side_effect = rbac_exceptions.RbacParsingException - - @rbac_rv.action(mock.sentinel.service, mock.sentinel.action) - def test_policy(*args): - pass - - error_re = 'Attempted to test an invalid policy file or action' - self.assertRaisesRegex(rbac_exceptions.RbacParsingException, error_re, - test_policy, self.test_obj) - - mock_authority.PolicyAuthority.assert_called_once_with( - mock.sentinel.project_id, mock.sentinel.user_id, - mock.sentinel.service, extra_target_data={}) - - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_get_exception_type_404(self, _): - """Test that getting a 404 exception type returns NotFound.""" - expected_exception = exceptions.NotFound - expected_irregular_msg = ( - "NotFound exception was caught for test %s. Expected policies " - "which may have caused the error: %s. The service %s throws a " - "404 instead of a 403, which is irregular") - - actual_exception, actual_irregular_msg = \ - rbac_rv._get_exception_type(404) - - self.assertEqual(expected_exception, actual_exception) - self.assertEqual(expected_irregular_msg, actual_irregular_msg) - - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_get_exception_type_403(self, _): - """Test that getting a 403 exception type returns Forbidden.""" - expected_exception = exceptions.Forbidden - expected_irregular_msg = None - - actual_exception, actual_irregular_msg = \ - rbac_rv._get_exception_type(403) - - self.assertEqual(expected_exception, actual_exception) - self.assertEqual(expected_irregular_msg, actual_irregular_msg) - - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - def test_exception_thrown_when_type_is_not_int(self, mock_log, _): - """Test that non-integer exception type raises error.""" - self.assertRaises(rbac_exceptions.RbacInvalidErrorCode, - rbac_rv._get_exception_type, "403") - - mock_log.error.assert_called_once_with("Please pass an expected error " - "code. Currently supported " - "codes: [403, 404]") - - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - def test_exception_thrown_when_type_is_403_or_404(self, mock_log, _): - """Test that unsupported exceptions throw error.""" - invalid_exceptions = [200, 400, 500] - for exc in invalid_exceptions: - self.assertRaises(rbac_exceptions.RbacInvalidErrorCode, - rbac_rv._get_exception_type, exc) - mock_log.error.assert_called_once_with( - "Please pass an expected error code. Currently supported " - "codes: [403, 404]") - - mock_log.error.reset_mock() - - -class RBACMultiRoleRuleValidationTest(BaseRBACMultiRoleRuleValidationTest, - RBACRuleValidationTest): - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_forbidden_negative(self, mock_authority, - mock_log): - """Test RbacUnderPermissionException error is thrown and have - permission fails. - - Negative test case: if Forbidden is thrown and the user should be - allowed to perform the action, then the RbacUnderPermissionException - exception should be raised. - """ - mock_authority.PolicyAuthority.return_value.allowed.return_value = True - - @rbac_rv.action(mock.sentinel.service, rules=[mock.sentinel.action]) - def test_policy(*args): - raise exceptions.Forbidden() - - test_re = (r"User with roles \['member', 'anotherrole'\] was not " - r"allowed to perform the following actions: \[%s\].*" % - (mock.sentinel.action)) - self.assertRaisesRegex( - rbac_exceptions.RbacUnderPermissionException, test_re, test_policy, - self.test_obj) - self.assertRegex(mock_log.error.mock_calls[0][1][0], test_re) - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_expect_not_found_and_raise_not_found(self, mock_authority, - mock_log): - """Test that expecting 404 and getting 404 works for all scenarios. - - Tests the following scenarios: - 1) Test no permission and 404 is expected and 404 is thrown succeeds. - 2) Test have permission and 404 is expected and 404 is thrown fails. - - In both cases, a LOG.warning is called with the "irregular message" - that signals to user that a 404 was expected and caught. - """ - policy_names = ['foo:bar'] - - @rbac_rv.action(mock.sentinel.service, rules=policy_names, - expected_error_codes=[404]) - def test_policy(*args): - raise exceptions.NotFound() - - expected_errors = [ - (r"User with roles \['member', 'anotherrole'\] was not allowed to " - r"perform the following actions: \['%s'\].*" % policy_names[0]), - None - ] - - for pos, allowed in enumerate([True, False]): - mock_authority.PolicyAuthority.return_value.allowed\ - .return_value = allowed - - error_re = expected_errors[pos] - - if error_re: - self.assertRaisesRegex( - rbac_exceptions.RbacUnderPermissionException, error_re, - test_policy, self.test_obj) - self.assertRegex(mock_log.error.mock_calls[0][1][0], error_re) - else: - test_policy(self.test_obj) - mock_log.error.assert_not_called() - - mock_log.warning.assert_called_with( - "NotFound exception was caught for test %s. Expected policies " - "which may have caused the error: %s. The service %s throws a " - "404 instead of a 403, which is irregular", - test_policy.__name__, - ', '.join(policy_names), - mock.sentinel.service) - - mock_log.warning.reset_mock() - mock_log.error.reset_mock() - - -class RBACRuleValidationLoggingTest(BaseRBACRuleValidationTest): - """Test class for validating the RBAC log, dedicated to just logging - Patrole RBAC validation work flows. - """ - - def setUp(self): - super(RBACRuleValidationLoggingTest, self).setUp() - # This behavior is tested in separate test class below. - self.useFixture(fixtures.MockPatchObject( - rbac_rv, '_validate_override_role_called')) - - @mock.patch.object(rbac_rv, 'RBACLOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rbac_report_logging_disabled(self, mock_authority, mock_rbaclog): - """Test case to ensure that we DON'T write logs when enable_reporting - is False - """ - self.useFixture( - patrole_fixtures.ConfPatcher(enable_reporting=False, - group='patrole_log')) - - mock_authority.PolicyAuthority.return_value.allowed.return_value = True - - @rbac_rv.action(mock.sentinel.service, rules=[mock.sentinel.action]) - def test_policy(*args): - pass - - test_policy(self.test_obj) - self.assertFalse(mock_rbaclog.info.called) - - @mock.patch.object(rbac_rv, 'RBACLOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rbac_report_logging_enabled(self, mock_authority, mock_rbaclog): - """Test case to ensure that we DO write logs when enable_reporting is - True - """ - self.useFixture( - patrole_fixtures.ConfPatcher(enable_reporting=True, - group='patrole_log')) - - mock_authority.PolicyAuthority.return_value.allowed.return_value = True - policy_names = ['foo:bar', 'baz:qux'] - - @rbac_rv.action(mock.sentinel.service, rules=policy_names) - def test_policy(*args): - pass - - test_policy(self.test_obj) - mock_rbaclog.info.assert_called_once_with( - "[Service]: %s, [Test]: %s, [Rules]: %s, " - "[Expected]: %s, [Actual]: %s", - mock.sentinel.service, - 'test_policy', - ', '.join(policy_names), - "Allowed", - "Allowed") - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_with_callable_rule(self, mock_authority, - mock_log): - """Test that a callable as the rule is evaluated correctly.""" - mock_authority.PolicyAuthority.return_value.allowed.return_value = True - - @rbac_rv.action(mock.sentinel.service, - rules=[lambda: mock.sentinel.action]) - def test_policy(*args): - pass - - test_policy(self.test_obj) - - policy_authority = mock_authority.PolicyAuthority.return_value - policy_authority.allowed.assert_called_with( - mock.sentinel.action, - self.test_obj.get_all_needed_roles(CONF.patrole.rbac_test_roles)) - - mock_log.error.assert_not_called() - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_with_conditional_callable_rule( - self, mock_authority, mock_log): - """Test that a complex callable with conditional logic as the rule is - evaluated correctly. - """ - mock_authority.PolicyAuthority.return_value.allowed.return_value = True - expected_roles = self.test_obj.get_all_needed_roles( - CONF.patrole.rbac_test_roles) - - def partial_func(x): - return "foo" if x == "bar" else "qux" - foo_callable = functools.partial(partial_func, "bar") - bar_callable = functools.partial(partial_func, "baz") - - @rbac_rv.action(mock.sentinel.service, - rules=[foo_callable]) - def test_foo_policy(*args): - pass - - @rbac_rv.action(mock.sentinel.service, - rules=[bar_callable]) - def test_bar_policy(*args): - pass - - test_foo_policy(self.test_obj) - policy_authority = mock_authority.PolicyAuthority.return_value - policy_authority.allowed.assert_called_with( - "foo", - expected_roles) - policy_authority.allowed.reset_mock() - - test_bar_policy(self.test_obj) - policy_authority = mock_authority.PolicyAuthority.return_value - policy_authority.allowed.assert_called_with( - "qux", - expected_roles) - - mock_log.error.assert_not_called() - - -class RBACMultiRoleRuleValidationLoggingTest( - BaseRBACMultiRoleRuleValidationTest, RBACRuleValidationLoggingTest): - pass - - -class RBACRuleValidationNegativeTest(BaseRBACRuleValidationTest): - - def setUp(self): - super(RBACRuleValidationNegativeTest, self).setUp() - # This behavior is tested in separate test class below. - self.useFixture(fixtures.MockPatchObject( - rbac_rv, '_validate_override_role_called')) - - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_invalid_service_raises_exc(self, mock_authority): - """Test that invalid service raises the appropriate exception.""" - mock_authority.PolicyAuthority.return_value.allowed.side_effect = ( - rbac_exceptions.RbacInvalidServiceException) - - @rbac_rv.action(mock.sentinel.service, mock.sentinel.action) - def test_policy(*args): - pass - - self.assertRaises(rbac_exceptions.RbacInvalidServiceException, - test_policy, self.test_obj) - - -class RBACMultiRoleRuleValidationNegativeTest( - BaseRBACMultiRoleRuleValidationTest, RBACRuleValidationNegativeTest): - pass - - -class RBACRuleValidationTestMultiPolicy(BaseRBACRuleValidationTest): - """Test suite for validating multi-policy support for the - ``rbac_rule_validation`` decorator. - """ - - def setUp(self): - super(RBACRuleValidationTestMultiPolicy, self).setUp() - # This behavior is tested in separate test class below. - self.useFixture(fixtures.MockPatchObject( - rbac_rv, '_validate_override_role_called')) - - def _assert_policy_authority_called_with(self, rules, mock_authority): - m_authority = mock_authority.PolicyAuthority.return_value - m_authority.allowed.assert_has_calls([ - mock.call( - rule, - self.test_obj.get_all_needed_roles( - CONF.patrole.rbac_test_roles) - ) for rule in rules - ]) - m_authority.allowed.reset_mock() - - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_multi_policy_have_permission_success( - self, mock_authority): - """Test that when expected result is authorized and test passes that - the overall evaluation succeeds. - """ - mock_authority.PolicyAuthority.return_value.allowed.\ - return_value = True - - rules = [mock.sentinel.action1, mock.sentinel.action2] - - @rbac_rv.action(mock.sentinel.service, rules=rules, - expected_error_codes=[403, 403]) - def test_policy(*args): - pass - - test_policy(self.test_obj) - self._assert_policy_authority_called_with(rules, mock_authority) - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_multi_policy_overpermission_failure( - self, mock_authority, mock_log): - """Test that when expected result is unauthorized and test passes that - the overall evaluation results in an RbacOverPermissionException - getting raised. - """ - - rules = [ - mock.sentinel.action1, mock.sentinel.action2, mock.sentinel.action3 - ] - exp_ecodes = [403, 403, 403] - - @rbac_rv.action(mock.sentinel.service, rules=rules, - expected_error_codes=exp_ecodes) - def test_policy(*args): - pass - - def _do_test(allowed_list, fail_on_action): - mock_authority.PolicyAuthority.return_value.allowed.side_effect = ( - allowed_list) - - error_re = r".*OverPermission: .* \[%s\]$" % fail_on_action - self.assertRaisesRegex( - rbac_exceptions.RbacOverPermissionException, error_re, - test_policy, self.test_obj) - mock_log.debug.assert_any_call( - "%s: Expecting %d to be raised for policy name: %s", - 'test_policy', 403, fail_on_action) - self.assertRegex(mock_log.error.mock_calls[0][1][0], error_re) - mock_log.error.reset_mock() - self._assert_policy_authority_called_with(rules, mock_authority) - - _do_test([True, True, False], mock.sentinel.action3) - _do_test([False, True, True], mock.sentinel.action1) - _do_test([True, False, True], mock.sentinel.action2) - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_multi_policy_forbidden_success( - self, mock_authority, mock_log): - """Test that when the expected result is unauthorized and the test - fails that the overall evaluation results in success. - """ - - rules = [ - mock.sentinel.action1, mock.sentinel.action2, mock.sentinel.action3 - ] - exp_ecodes = [403, 403, 403] - - @rbac_rv.action(mock.sentinel.service, rules=rules, - expected_error_codes=exp_ecodes) - def test_policy(*args): - raise exceptions.Forbidden() - - def _do_test(allowed_list, fail_on_action): - mock_authority.PolicyAuthority.return_value.allowed.\ - side_effect = allowed_list - test_policy(self.test_obj) - mock_log.debug.assert_called_with( - "%s: Expecting %d to be raised for policy name: %s", - 'test_policy', 403, fail_on_action) - mock_log.error.assert_not_called() - self._assert_policy_authority_called_with(rules, mock_authority) - - _do_test([True, True, False], mock.sentinel.action3) - _do_test([False, True, True], mock.sentinel.action1) - _do_test([True, False, True], mock.sentinel.action2) - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_multi_policy_forbidden_failure( - self, mock_authority, mock_log): - """Test that when the expected result is authorized and the test - fails (with a Forbidden error code) that the overall evaluation - results in a RbacUnderPermissionException getting raised. - """ - - # NOTE: Avoid mock.sentinel here due to weird sorting with them. - rules = ['action1', 'action2', 'action3'] - - @rbac_rv.action(mock.sentinel.service, rules=rules, - expected_error_codes=[403, 403, 403]) - def test_policy(*args): - raise exceptions.Forbidden() - - mock_authority.PolicyAuthority.return_value.allowed\ - .return_value = True - - error_re = ("User with roles ['member'] was not allowed to perform " - "the following actions: %s. Expected allowed actions: %s. " - "Expected disallowed actions: []." % - (rules, rules)).replace('[', r'\[').replace(']', r'\]') - self.assertRaisesRegex( - rbac_exceptions.RbacUnderPermissionException, error_re, - test_policy, self.test_obj) - self.assertRegex(mock_log.error.mock_calls[0][1][0], error_re) - self._assert_policy_authority_called_with(rules, mock_authority) - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_multi_actions_forbidden( - self, mock_authority, mock_log): - """Test that when the expected result is Forbidden because - two of the actions fail and the first action specifies 403, - verify that the overall evaluation results in success. - """ - - rules = [ - mock.sentinel.action1, mock.sentinel.action2, mock.sentinel.action3 - ] - exp_ecodes = [403, 403, 404] - - @rbac_rv.action(mock.sentinel.service, rules=rules, - expected_error_codes=exp_ecodes) - def test_policy(*args): - raise exceptions.Forbidden() - - def _do_test(allowed_list, fail_on_action): - mock_authority.PolicyAuthority.return_value.allowed.\ - side_effect = allowed_list - test_policy(self.test_obj) - mock_log.debug.assert_called_with( - "%s: Expecting %d to be raised for policy name: %s", - 'test_policy', 403, fail_on_action) - mock_log.error.assert_not_called() - self._assert_policy_authority_called_with(rules, mock_authority) - - _do_test([False, True, False], mock.sentinel.action1) - _do_test([False, False, True], mock.sentinel.action1) - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_multi_actions_notfound( - self, mock_authority, mock_log): - """Test that when the expected result is not found because - two of the actions fail and the first action specifies 404, - verify that the overall evaluation results in success. - """ - - rules = [ - 'mock.sentinel.action1', 'mock.sentinel.action2', - 'mock.sentinel.action3', 'mock.sentinel.action4' - ] - exp_ecodes = [403, 404, 403, 403] - - @rbac_rv.action(mock.sentinel.service, rules=rules, - expected_error_codes=exp_ecodes) - def test_policy(*args): - raise exceptions.NotFound() - - def _do_test(allowed_list, fail_on_action): - mock_authority.PolicyAuthority.return_value.allowed.\ - side_effect = allowed_list - test_policy(self.test_obj) - mock_log.debug.assert_called_with( - "%s: Expecting %d to be raised for policy name: %s", - 'test_policy', 404, fail_on_action) - mock_log.error.assert_not_called() - self._assert_policy_authority_called_with(rules, mock_authority) - - _do_test([True, False, False, True], 'mock.sentinel.action2') - _do_test([True, False, True, False], 'mock.sentinel.action2') - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_multi_policy_defaults_to_correct_error_codes( - self, mock_authority, mock_log): - """Test omission of expected_error_codes defaults to [403] * len(rules) - """ - mock_authority.PolicyAuthority.return_value.allowed.\ - return_value = False - expected_log = "%s: Expecting %d to be raised for policy name: %s" - - # Validate with single rule => expected_error_codes == [403]. - rules = [mock.sentinel.action1] - - @rbac_rv.action(mock.sentinel.service, rules=rules) - def test_policy(*args): - raise exceptions.Forbidden() - - test_policy(self.test_obj) - self._assert_policy_authority_called_with(rules, mock_authority) - # Assert that 403 is expected. - mock_calls = [x[1] for x in mock_log.debug.mock_calls] - self.assertTrue( - any([(expected_log, 'test_policy', 403, rules[0]) in mock_calls])) - - # Validate with multiple rules => expected_error_codes == [403, 403]. - rules = [mock.sentinel.action1, mock.sentinel.action2] - - @rbac_rv.action(mock.sentinel.service, rules=rules) - def test_policy(*args): - raise exceptions.Forbidden() - - test_policy(self.test_obj) - self._assert_policy_authority_called_with(rules, mock_authority) - # Assert that 403 is expected. - mock_calls = [x[1] for x in mock_log.debug.mock_calls] - self.assertTrue( - any([(expected_log, 'test_policy', 403, rules[0]) in mock_calls])) - - def test_prepare_multi_policy_allowed_usages(self): - - def _do_test(rules, ecodes, exp_rules, exp_ecodes): - rule_list, ec_list = rbac_rv._prepare_multi_policy(rules, ecodes) - self.assertEqual(rule_list, exp_rules) - self.assertEqual(ec_list, exp_ecodes) - - # Validate that expected_error_codes defaults to 403 when no values - # are provided. - _do_test(["rule1"], None, ["rule1"], [403]) - - # Validate that `len(rules) == len(expected_error_codes)` works when - # both == 1. - _do_test(["rule1"], [403], ["rule1"], [403]) - - # Validate that `len(rules) == len(expected_error_codes)` works when - # both are > 1. - _do_test(["rule1", "rule2"], [403, 404], - ["rule1", "rule2"], [403, 404]) - - # Validate that when only a default expected_error_code argument is - # provided, that default value and other default values (403) are - # filled into the expected_error_codes list. - # Example: - # @rbac_rv.action(service, rules=[, ]) - # def test_policy(*args): - # ... - _do_test(["rule1", "rule2"], None, - ["rule1", "rule2"], [403, 403]) - - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - def test_prepare_multi_policy_disallowed_usages(self, mock_log): - - def _do_test(rules, ecodes): - rule_list, ec_list = rbac_rv._prepare_multi_policy(rules, ecodes) - - error_re = ("The `expected_error_codes` list is not the same length" - " as the `rules` list.") - # When len(rules) > 1 then len(expected_error_codes) must be same len. - self.assertRaisesRegex(ValueError, error_re, _do_test, - ["rule1", "rule2"], [403]) - # When len(expected_error_codes) > 1 len(rules) must be same len. - self.assertRaisesRegex(ValueError, error_re, _do_test, ["rule1"], - [403, 404]) - error_re = ("The `rules` list must be provided if using the " - "`expected_error_codes` list.") - # When expected_error_codes is provided rules must be as well. - self.assertRaisesRegex(ValueError, error_re, _do_test, None, [404]) - - -class RBACMultiRoleRuleValidationTestMultiPolicy( - BaseRBACMultiRoleRuleValidationTest, RBACRuleValidationTestMultiPolicy): - @mock.patch.object(rbac_rv, 'LOG', autospec=True) - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_multi_policy_forbidden_failure( - self, mock_authority, mock_log): - """Test that when the expected result is authorized and the test - fails (with a Forbidden error code) that the overall evaluation - results in a RbacUnderPermissionException getting raised. - """ - - # NOTE: Avoid mock.sentinel here due to weird sorting with them. - rules = ['action1', 'action2', 'action3'] - - @rbac_rv.action(mock.sentinel.service, rules=rules, - expected_error_codes=[403, 403, 403]) - def test_policy(*args): - raise exceptions.Forbidden() - - mock_authority.PolicyAuthority.return_value.allowed\ - .return_value = True - - error_re = ("User with roles ['member', 'anotherrole'] was not " - "allowed to perform the following actions: %s. Expected " - "allowed actions: %s. Expected disallowed actions: []." % - (rules, rules)).replace('[', r'\[').replace(']', r'\]') - self.assertRaisesRegex( - rbac_exceptions.RbacUnderPermissionException, error_re, - test_policy, self.test_obj) - self.assertRegex(mock_log.error.mock_calls[0][1][0], error_re) - self._assert_policy_authority_called_with(rules, mock_authority) - - -class RBACOverrideRoleValidationTest(BaseRBACRuleValidationTest): - """Class for validating that untimely exceptions (outside - ``override_role`` is called) result in test failures. - - This regression tests false positives caused by test exceptions matching - the expected exception before or after the ``override_role`` context is - called. Also tests case where ``override_role`` is never called which is - an invalid Patrole test. - - """ - - def setUp(self): - super(RBACOverrideRoleValidationTest, self).setUp() - - self.parent_class = self.test_obj.__class__ - - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_override_role_called_inside_ctx(self, - mock_authority): - """Test success case when the expected exception is raised within the - override_role context. - """ - mock_authority.PolicyAuthority.return_value.allowed.return_value =\ - False - - class ChildRbacTest(self.parent_class): - - @rbac_rv.action(mock.sentinel.service, rules=["fake:rule"], - expected_error_codes=[404]) - def test_called(self_): - with self_.override_role(): - raise exceptions.NotFound() - - child_test = ChildRbacTest() - child_test.test_called() - - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_override_role_patrole_exception_ignored( - self, mock_authority): - """Test success case where Patrole exception is raised (which is - valid in case of e.g. BasePatroleResponseBodyException) after - override_role passes. - """ - mock_authority.PolicyAuthority.return_value.allowed.return_value =\ - True - - class ChildRbacTest(self.parent_class): - - @rbac_rv.action(mock.sentinel.service, rules=["fake:rule"], - expected_error_codes=[404]) - def test_called(self_): - with self_.override_role(): - pass - # Instances of BasePatroleResponseBodyException don't count as - # they are part of the validation work flow. - raise rbac_exceptions.BasePatroleResponseBodyException() - - child_test = ChildRbacTest() - self.assertRaises(rbac_exceptions.RbacUnderPermissionException, - child_test.test_called) - - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_override_role_called_before_ctx(self, - mock_authority): - """Test failure case when an exception that happens before - ``override_role`` context, even if it is the expected exception, - raises ``RbacOverrideRoleException``. - """ - mock_authority.PolicyAuthority.return_value.allowed.return_value =\ - False - - # This behavior should work for supported (NotFound/Forbidden) and - # miscellaneous exceptions alike. - for exception_type in (exceptions.NotFound, - Exception): - class ChildRbacTest(self.parent_class): - - @rbac_rv.action(mock.sentinel.service, rules=["fake:rule"], - expected_error_codes=[404]) - def test_called_before(self_): - raise exception_type() - - child_test = ChildRbacTest() - test_re = ".*before.*" - self.assertRaisesRegex(rbac_exceptions.RbacOverrideRoleException, - test_re, child_test.test_called_before) - - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_override_role_called_after_ctx(self, - mock_authority): - """Test failure case when an exception that happens before - ``override_role`` context, even if it is the expected exception, - raises ``RbacOverrideRoleException``. - """ - mock_authority.PolicyAuthority.return_value.allowed.return_value =\ - False - - # This behavior should work for supported (NotFound/Forbidden) and - # miscellaneous exceptions alike. - for exception_type in (exceptions.NotFound, - Exception): - class ChildRbacTest(self.parent_class): - - @rbac_rv.action(mock.sentinel.service, rules=["fake:rule"], - expected_error_codes=[404]) - def test_called_after(self_): - with self_.override_role(): - pass - # Simulates a test tearDown failure or some such. - raise exception_type() - - child_test = ChildRbacTest() - test_re = ".*after.*" - self.assertRaisesRegex(rbac_exceptions.RbacOverrideRoleException, - test_re, child_test.test_called_after) - - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_override_role_never_called(self, mock_authority): - """Test failure case where override_role is **never** called.""" - mock_authority.PolicyAuthority.return_value.allowed.return_value =\ - False - - class ChildRbacTest(self.parent_class): - - @rbac_rv.action(mock.sentinel.service, rules=["fake:rule"], - expected_error_codes=[404]) - def test_never_called(self_): - pass - - child_test = ChildRbacTest() - test_re = ".*missing required `override_role` call.*" - self.assertRaisesRegex(rbac_exceptions.RbacOverrideRoleException, - test_re, child_test.test_never_called) - - @mock.patch.object(rbac_rv, 'policy_authority', autospec=True) - def test_rule_validation_override_role_sequential_test_calls( - self, mock_authority): - """Test success/failure scenarios above across sequential test calls. - """ - mock_authority.PolicyAuthority.return_value.allowed.return_value =\ - False - - class ChildRbacTest(self.parent_class): - - @rbac_rv.action(mock.sentinel.service, rules=["fake:rule1"], - expected_error_codes=[404]) - def test_called(self_): - with self_.override_role(): - raise exceptions.NotFound() - - @rbac_rv.action(mock.sentinel.service, rules=["fake:rule2"], - expected_error_codes=[404]) - def test_called_before(self_): - raise exceptions.NotFound() - - test_re = ".*before.*" - - # Test case where override role is called in first test but *not* in - # second test. - child_test1 = ChildRbacTest() - child_test1.test_called() - self.assertRaisesRegex(rbac_exceptions.RbacOverrideRoleException, - test_re, child_test1.test_called_before) - - # Test case where override role is *not* called in first test but is - # in second test. - child_test2 = ChildRbacTest() - self.assertRaisesRegex(rbac_exceptions.RbacOverrideRoleException, - test_re, child_test2.test_called_before) - child_test2.test_called() diff --git a/patrole_tempest_plugin/tests/unit/test_rbac_utils.py b/patrole_tempest_plugin/tests/unit/test_rbac_utils.py deleted file mode 100644 index f72a4f4a..00000000 --- a/patrole_tempest_plugin/tests/unit/test_rbac_utils.py +++ /dev/null @@ -1,347 +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. - -import testtools -from unittest import mock - -from tempest.lib import exceptions as lib_exc - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import rbac_utils -from patrole_tempest_plugin.tests.unit import base -from patrole_tempest_plugin.tests.unit import fixtures as patrole_fixtures - - -class RBACUtilsMixinTest(base.TestCase): - - def setUp(self): - super(RBACUtilsMixinTest, self).setUp() - self.rbac_utils_fixture = self.useFixture( - patrole_fixtures.RbacUtilsMixinFixture()) - self.test_obj = self.rbac_utils_fixture.test_obj - - def test_init_roles_with_missing_admin_role(self): - self.rbac_utils_fixture.set_roles('member') - error_re = (".*Following roles were not found: admin. Available " - "roles: member.") - self.assertRaisesRegex(rbac_exceptions.RbacResourceSetupFailed, - error_re, self.test_obj._init_roles) - - def test_init_roles_with_missing_rbac_role(self): - self.rbac_utils_fixture.set_roles('admin') - error_re = (".*Following roles were not found: member. Available " - "roles: admin.") - self.assertRaisesRegex(rbac_exceptions.RbacResourceSetupFailed, - error_re, self.test_obj._init_roles) - - def test_override_role_to_admin_role_at_creating(self): - rbac_utils_fixture = self.useFixture( - patrole_fixtures.RbacUtilsMixinFixture(do_reset_mocks=False)) - test_obj = rbac_utils_fixture.test_obj - roles_client = rbac_utils_fixture.admin_roles_client - mock_time = rbac_utils_fixture.mock_time - - roles_client.create_user_role_on_project.assert_called_once_with( - rbac_utils_fixture.PROJECT_ID, - rbac_utils_fixture.USER_ID, - 'admin_id') - test_obj.get_auth_providers()[0].clear_auth.assert_called_once_with() - test_obj.get_auth_providers()[0].set_auth.assert_called_once_with() - mock_time.sleep.assert_called_once_with(1) - - def test_override_role_to_admin_role(self): - self.test_obj._override_role() - - roles_client = self.rbac_utils_fixture.admin_roles_client - mock_time = self.rbac_utils_fixture.mock_time - - roles_client.create_user_role_on_project.assert_called_once_with( - self.rbac_utils_fixture.PROJECT_ID, - self.rbac_utils_fixture.USER_ID, - 'admin_id') - self.test_obj.get_auth_providers()[0].clear_auth\ - .assert_called_once_with() - self.test_obj.get_auth_providers()[0].set_auth\ - .assert_called_once_with() - mock_time.sleep.assert_called_once_with(1) - - def test_override_role_to_admin_role_avoids_role_switch(self): - self.rbac_utils_fixture.set_roles(['admin', 'member'], 'admin') - self.test_obj._override_role() - - roles_client = self.rbac_utils_fixture.admin_roles_client - mock_time = self.rbac_utils_fixture.mock_time - - roles_client.create_user_role_on_project.assert_not_called() - mock_time.sleep.assert_not_called() - - def test_override_role_to_member_role(self): - self.test_obj._override_role(True) - - roles_client = self.rbac_utils_fixture.admin_roles_client - mock_time = self.rbac_utils_fixture.mock_time - - roles_client.create_user_role_on_project.assert_has_calls([ - mock.call(self.rbac_utils_fixture.PROJECT_ID, - self.rbac_utils_fixture.USER_ID, - 'member_id') - ]) - self.test_obj.get_auth_providers()[0].clear_auth.assert_has_calls( - [mock.call()]) - self.test_obj.get_auth_providers()[0].set_auth.assert_has_calls( - [mock.call()]) - mock_time.sleep.assert_has_calls([mock.call(1)]) - - def test_override_role_to_member_role_avoids_role_switch(self): - self.rbac_utils_fixture.set_roles(['admin', 'member'], 'member') - self.test_obj._override_role(True) - - roles_client = self.rbac_utils_fixture.admin_roles_client - mock_time = self.rbac_utils_fixture.mock_time - - self.assertEqual(0, - roles_client.create_user_role_on_project.call_count) - self.assertEqual(0, - mock_time.sleep.call_count) - - def test_override_role_to_member_role_then_admin_role(self): - self.test_obj._override_role(True) - self.test_obj._override_role(False) - - roles_client = self.rbac_utils_fixture.admin_roles_client - mock_time = self.rbac_utils_fixture.mock_time - - roles_client.create_user_role_on_project.assert_has_calls([ - mock.call(self.rbac_utils_fixture.PROJECT_ID, - self.rbac_utils_fixture.USER_ID, - 'member_id'), - mock.call(self.rbac_utils_fixture.PROJECT_ID, - self.rbac_utils_fixture.USER_ID, - 'admin_id') - ]) - self.test_obj.get_auth_providers()[0].clear_auth.assert_has_calls( - [mock.call()] * 2) - self.test_obj.get_auth_providers()[0].set_auth.assert_has_calls( - [mock.call()] * 2) - mock_time.sleep.assert_has_calls([mock.call(1)] * 2) - - def test_clear_user_roles(self): - # NOTE(felipemonteiro): Set the user's roles on the project to - # include 'random' to coerce a role switch, or else it will be - # skipped. - self.rbac_utils_fixture.set_roles(['admin', 'member'], - ['member', 'random']) - self.test_obj._override_role() - - roles_client = self.rbac_utils_fixture.admin_roles_client - - roles_client.list_user_roles_on_project.assert_called_once_with( - self.rbac_utils_fixture.PROJECT_ID, - self.rbac_utils_fixture.USER_ID) - roles_client.delete_role_from_user_on_project.\ - assert_has_calls([ - mock.call(mock.sentinel.project_id, mock.sentinel.user_id, - 'member_id'), - mock.call(mock.sentinel.project_id, mock.sentinel.user_id, - 'random_id')]) - - def test_override_role_context_manager_simulate_pass(self): - """Validate that expected override_role calls are made when switching - to admin role for success path. - """ - - mock_override_role = self.patchobject(self.test_obj, '_override_role') - with self.test_obj.override_role(): - # Validate `override_role` public method called private method - # `_override_role` with True. - mock_override_role.assert_called_once_with(True) - mock_override_role.reset_mock() - # Validate that `override_role` switched back to admin role after - # contextmanager. - mock_override_role.assert_called_once_with(False) - - def test_override_role_context_manager_simulate_fail(self): - """Validate that expected override_role calls are made when switching - to admin role for failure path (i.e. when test raises exception). - """ - mock_override_role = self.patchobject(self.test_obj, '_override_role') - - def _do_test(): - with self.test_obj.override_role(): - # Validate `override_role` public method called private method - # `_override_role` with True. - mock_override_role.assert_called_once_with(True) - mock_override_role.reset_mock() - # Raise exc to verify role switch works for negative case. - raise lib_exc.Forbidden() - - # Validate that role is switched back to admin, despite test failure. - with testtools.ExpectedException(lib_exc.Forbidden): - _do_test() - mock_override_role.assert_called_once_with(False) - - def test_override_role_and_validate_list(self): - m_override_role = self.patchobject(self.test_obj, 'override_role') - - with (self.test_obj.override_role_and_validate_list( - admin_resource_id='foo')) as ctx: - self.assertIsInstance(ctx, rbac_utils._ValidateListContext) - m_validate = self.patchobject(ctx, '_validate') - m_override_role.assert_called_once_with() - m_validate.assert_called_once() - - def test_prepare_role_inferences_mapping(self): - self.test_obj.admin_roles_client.list_all_role_inference_rules.\ - return_value = { - "role_inferences": [ - { - "implies": [{"id": "reader_id", "name": "reader"}], - "prior_role": {"id": "member_id", "name": "member"} - }, - { - "implies": [{"id": "member_id", "name": "member"}], - "prior_role": {"id": "admin_id", "name": "admin"} - } - ] - } - - expected_role_inferences_mapping = { - "member_id": {"reader_id"}, - "admin_id": {"member_id", "reader_id"} - } - actual_role_inferences_mapping = self.test_obj.\ - _prepare_role_inferences_mapping() - self.assertEqual(expected_role_inferences_mapping, - actual_role_inferences_mapping) - - def test_get_all_needed_roles(self): - self.test_obj.__class__._role_inferences_mapping = { - "member_id": {"reader_id"}, - "admin_id": {"member_id", "reader_id"} - } - self.test_obj.__class__._role_map = { - "admin_id": "admin", "admin": "admin_id", - "member_id": "member", "member": "member_id", - "reader_id": "reader", "reader": "reader_id" - } - for roles, expected_roles in ( - (['admin'], ['admin', 'member', 'reader']), - (['member'], ['member', 'reader']), - (['reader'], ['reader']), - (['custom_role'], ['custom_role']), - (['custom_role', 'member'], ['custom_role', 'member', 'reader']), - (['admin', 'member'], ['admin', 'member', 'reader']), - ): - expected_roles = sorted(expected_roles) - actual_roles = sorted(self.test_obj.get_all_needed_roles(roles)) - self.assertEqual(expected_roles, actual_roles) - - def test_restore_roles(self): - self.rbac_utils_fixture.set_roles(['admin', 'member'], 'member') - roles_client = self.rbac_utils_fixture.admin_roles_client - - # Explicitly call setup_clients() to make sure cls._orig_roles is set - # properly. Explicitly call resource_cleanup to invoke restore_roles(). - self.test_obj.setup_clients() - self.test_obj.resource_cleanup() - - # list_user_roles_on_project is called twice in setup_clients(), - # restore_roles() is called twice during resource cleanup. - self.assertEqual(4, roles_client.list_user_roles_on_project.call_count) - self.assertEqual(['member_id'], self.test_obj._orig_roles) - - -class ValidateListContextTest(base.TestCase): - @staticmethod - def _get_context(admin_resources=None, admin_resource_id=None): - return rbac_utils._ValidateListContext( - admin_resources=admin_resources, - admin_resource_id=admin_resource_id) - - def test_incorrect_usage(self): - # admin_resources and admin_resource_is are not assigned - self.assertRaises(rbac_exceptions.RbacValidateListException, - self._get_context) - - # both admin_resources and admin_resource_is are assigned - self.assertRaises(rbac_exceptions.RbacValidateListException, - self._get_context, - admin_resources='foo', admin_resource_id='bar') - # empty list assigned to admin_resources - self.assertRaises(rbac_exceptions.RbacValidateListException, - self._get_context, admin_resources=[]) - - # ctx.resources is not assigned - ctx = self._get_context(admin_resources='foo') - self.assertRaises(rbac_exceptions.RbacValidateListException, - ctx._validate) - - def test_validate_len_negative(self): - ctx = self._get_context(admin_resources=[1, 2, 3, 4]) - self.assertEqual(ctx._validate_len, ctx._validate_func) - self.assertEqual(4, ctx._admin_len) - self.assertFalse(hasattr(ctx, '_admin_resource_id')) - - # the number of resources is less than admin resources - ctx.resources = [1, 2, 3] - self.assertRaises(rbac_exceptions.RbacPartialResponseBody, - ctx._validate_len) - - # the resources is empty - ctx.resources = [] - self.assertRaises(rbac_exceptions.RbacEmptyResponseBody, - ctx._validate_len) - - def test_validate_len(self): - ctx = self._get_context(admin_resources=[1, 2, 3, 4]) - - # the number of resources and admin resources are same - ctx.resources = [1, 2, 3, 4] - self.assertIsNone(ctx._validate_len()) - - def test_validate_resource_negative(self): - ctx = self._get_context(admin_resource_id=1) - self.assertEqual(ctx._validate_resource, ctx._validate_func) - self.assertEqual(1, ctx._admin_resource_id) - self.assertFalse(hasattr(ctx, '_admin_len')) - - # there is no admin resource in the resources - ctx.resources = [{'id': 2}, {'id': 3}] - self.assertRaises(rbac_exceptions.RbacPartialResponseBody, - ctx._validate_resource) - - def test_validate_resource(self): - ctx = self._get_context(admin_resource_id=1) - - # there is admin resource in the resources - ctx.resources = [{'id': 1}, {'id': 2}] - self.assertIsNone(ctx._validate_resource()) - - def test_validate(self): - ctx = self._get_context(admin_resources='foo') - ctx.resources = 'bar' - with mock.patch.object(ctx, '_validate_func', - autospec=False) as m_validate_func: - m_validate_func.side_effect = ( - rbac_exceptions.RbacPartialResponseBody, - None - ) - self.assertRaises(rbac_exceptions.RbacPartialResponseBody, - ctx._validate) - m_validate_func.assert_called_once() - - m_validate_func.reset_mock() - ctx._validate() - m_validate_func.assert_called_once() diff --git a/patrole_tempest_plugin/tests/unit/test_requirements_authority.py b/patrole_tempest_plugin/tests/unit/test_requirements_authority.py deleted file mode 100644 index d069dcb3..00000000 --- a/patrole_tempest_plugin/tests/unit/test_requirements_authority.py +++ /dev/null @@ -1,188 +0,0 @@ -# Copyright 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 os - -from tempest.lib import exceptions - -from patrole_tempest_plugin import rbac_exceptions -from patrole_tempest_plugin import requirements_authority as req_auth -from patrole_tempest_plugin.tests.unit import base - - -class BaseRequirementsAuthorityTest(base.TestCase): - def setUp(self): - super(BaseRequirementsAuthorityTest, self).setUp() - self.rbac_auth = req_auth.RequirementsAuthority() - self.current_directory = os.path.dirname(os.path.realpath(__file__)) - self.yaml_test_file = os.path.join(self.current_directory, - 'resources', - 'rbac_roles.yaml') - self.expected_result = {'test:create': [['test_member'], ['_member_']], - 'test:create2': [['test_member']], - 'test:create3': [['test_member', '_member_']], - 'test:create4': [['test_member', '!_member_']]} - self.expected_rbac_map = {'test:create': ['test_member', '_member_'], - 'test:create2': ['test_member'], - 'test:create3': ['test_member, _member_'], - 'test:create4': ['test_member, !_member_']} - - -class RequirementsAuthorityTest(BaseRequirementsAuthorityTest): - - def test_requirements_auth_init(self): - rbac_auth = req_auth.RequirementsAuthority(self.yaml_test_file, 'Test') - self.assertEqual(self.expected_result, rbac_auth.roles_dict) - - def test_auth_allowed_empty_roles(self): - self.rbac_auth.roles_dict = None - self.assertRaises(exceptions.InvalidConfiguration, - self.rbac_auth.allowed, "", [""]) - - def test_auth_allowed_role_in_api(self): - self.rbac_auth.roles_dict = {'rule': [['_member_']]} - self.assertTrue(self.rbac_auth.allowed("rule", ["_member_"])) - - def test_auth_allowed_role_not_in_api(self): - self.rbac_auth.roles_dict = {'rule': [['_member_']]} - self.assertFalse(self.rbac_auth.allowed("rule", "support_member")) - - def test_parser_get_allowed_invalid_rule_raises_parsing_exception(self): - self.rbac_auth.roles_dict = {"foo": "bar"} - self.assertRaises(rbac_exceptions.RbacParsingException, - self.rbac_auth.allowed, "baz", "support_member") - - def test_parser_init(self): - req_auth.RequirementsParser(self.yaml_test_file) - self.assertEqual([{'Test': self.expected_rbac_map}], - req_auth.RequirementsParser.Inner._rbac_map) - - def test_parser_role_in_api(self): - req_auth.RequirementsParser.Inner._rbac_map = \ - [{'Test': self.expected_rbac_map}] - self.rbac_auth.roles_dict = req_auth.RequirementsParser.parse("Test") - - self.assertEqual(self.expected_result, self.rbac_auth.roles_dict) - self.assertTrue( - self.rbac_auth.allowed("test:create2", ["test_member"])) - - def test_parser_role_not_in_api(self): - req_auth.RequirementsParser.Inner._rbac_map = \ - [{'Test': self.expected_rbac_map}] - self.rbac_auth.roles_dict = req_auth.RequirementsParser.parse("Test") - - self.assertEqual(self.expected_result, self.rbac_auth.roles_dict) - self.assertFalse(self.rbac_auth.allowed("test:create2", "_member_")) - - def test_parser_except_invalid_configuration(self): - req_auth.RequirementsParser.Inner._rbac_map = \ - [{'Test': self.expected_rbac_map}] - self.rbac_auth.roles_dict = \ - req_auth.RequirementsParser.parse("Failure") - - self.assertFalse(self.rbac_auth.roles_dict) - self.assertRaises(exceptions.InvalidConfiguration, - self.rbac_auth.allowed, "", [""]) - - def test_auth_allowed_exclamation_mark_syntax_single_role(self): - """Ensure that exclamation mark in front of role is dropped, and not - considered as part of role itself. - """ - - self.rbac_auth.roles_dict = {'rule': [['!admin']]} - self.assertTrue(self.rbac_auth.allowed("rule", ["member"])) - self.assertTrue(self.rbac_auth.allowed("rule", ["!admin"])) - self.assertFalse(self.rbac_auth.allowed("rule", ["admin"])) - - -class RequirementsAuthorityMultiRoleTest(BaseRequirementsAuthorityTest): - - def test_auth_allowed_exclamation_mark_syntax_multi_role(self): - """Ensure that exclamation mark in front of role is dropped, and not - considered as part of role itself. - """ - - self.rbac_auth.roles_dict = {'rule': [['member', '!admin']]} - self.assertFalse(self.rbac_auth.allowed("rule", ["member", "admin"])) - self.assertTrue(self.rbac_auth.allowed("rule", ["member", "!admin"])) - - def test_auth_allowed_single_rule_scenario(self): - # member and support and not admin and not manager - self.rbac_auth.roles_dict = {'rule': [['member', 'support', - '!admin', '!manager']]} - - # User is member and support and not manager or admin - self.assertTrue(self.rbac_auth.allowed("rule", ["member", - "support"])) - - # User is member and not manager or admin, but not support - self.assertFalse(self.rbac_auth.allowed("rule", ["member"])) - - # User is support and not manager or admin, but not member - self.assertFalse(self.rbac_auth.allowed("rule", ["support"])) - - # User is member and support and not manager, but have admin role - self.assertFalse(self.rbac_auth.allowed("rule", ["member", - "support", - "admin"])) - - # User is member and not manager, but have admin role and not support - self.assertFalse(self.rbac_auth.allowed("rule", ["member", - "admin"])) - - # User is member and support, but have manager and admin roles - self.assertFalse(self.rbac_auth.allowed("rule", ["member", - "support", - "admin", - "manager"])) - - def test_auth_allowed_multi_rule_scenario(self): - rules = [ - ['member', 'support', '!admin', '!manager'], - ['member', 'admin'], - ["manager"] - ] - self.rbac_auth.roles_dict = {'rule': rules} - - # Not a single role allows viewer - self.assertFalse(self.rbac_auth.allowed("rule", ["viewer"])) - # We have no rule that allows support and admin - self.assertFalse(self.rbac_auth.allowed("rule", ["support", - "admin"])) - # There is no rule that requires member without additional