From 606549c1c95b3f2c611b8bd5771e19dadeed3995 Mon Sep 17 00:00:00 2001 From: Steve Baker Date: Tue, 22 Dec 2020 14:40:05 +1300 Subject: [PATCH] Populate existing policy tests Testing every combination of role, endpoint and policy rule would result in a huge test count, so to make testing the existing policy rules complete and practical, the following guidelines are suggested: - Only the default policy is tested, so inactive rules such as is_node_owner, is_node_lessee are ignored. - Each rule is tested completely on one endpoint which uses it. - A rule (such as baremetal:node:list) which inherits a parent rule (baremetal:node:get) is considered covered by the parent test. - All endpoints need at least one test, but other endpoints which share a fully tested rule only need one denied test which shows that they are covered by some policy. Also adds the initial pass of contributor documentation on how the rbac testing works to try and express the mechanics and what to expect to aid in reviewing/updating/editing the rules. Co-Authored-By: Julia Kreger Change-Id: I1cd88210e40e42f86464e6a817354620f5ab1d9c --- doc/source/contributor/index.rst | 1 + doc/source/contributor/rbac-testing.rst | 119 ++ ironic/tests/unit/api/base.py | 15 +- ironic/tests/unit/api/test_acl.py | 150 +- ironic/tests/unit/api/test_acl_basic.yaml | 1 + ironic/tests/unit/api/test_rbac_legacy.yaml | 2026 ++++++++++++++++--- 6 files changed, 1968 insertions(+), 344 deletions(-) create mode 100644 doc/source/contributor/rbac-testing.rst diff --git a/doc/source/contributor/index.rst b/doc/source/contributor/index.rst index 0377bdb34b..072490554b 100644 --- a/doc/source/contributor/index.rst +++ b/doc/source/contributor/index.rst @@ -32,6 +32,7 @@ primarily for developers. Developing New Notifications OSProfiler Tracing Rolling Upgrades + Role Based Access Control Testing These pages contain information for PTLs, cross-project liaisons, and core reviewers. diff --git a/doc/source/contributor/rbac-testing.rst b/doc/source/contributor/rbac-testing.rst new file mode 100644 index 0000000000..dca06b36d0 --- /dev/null +++ b/doc/source/contributor/rbac-testing.rst @@ -0,0 +1,119 @@ +================================== +Role Based Acces Control - Testing +================================== + +.. todo: This entire file is being added in to provide context for + reviewers so we can keep in-line comments to the necessary points + in the yaml files. It *IS* written with a forward awareness of the + later patches, but it is also broad in nature attempting to provide + context to aid in review. + +The Role Based Access control testing is a minor departure from the ironic +standard pattern of entirely python based unit testing. In part this was done +for purposes of speed and to keep the declaration of the test context. + +This also lended itself to be very useful due to the nature of A/B testing +which is requried to properly migrate the Ironic project from a project +scoped universe where an ``admin project`` is utilized as the authenticating +factor coupled with two custom roles, ``baremetal_admin``, and +``baremetal_observer``. + +As a contributor looking back after getting a over a thousand additional tests +in place using this method, it definitely helped the speed at which these +were created, and then ported to support additional. + +How these tests work +==================== + +These tests execute API calls through the API layer, using the appropriate +verb and header, which settings to prevent the ``keystonemiddleware`` from +intercepting and replacing the headers we're passing. Ultimately this is a +feature, and it helps quite a bit. + +The second aspect of how this works is we're mocking the conductor RPC +``get_topic_for`` and ``get_random_topic_for`` methods. These calls raise +Temporary Unavailable, since trying to execute the entire interaction into +the conductor is moderately pointless because all policy enforement is +located with-in the API layer. + +At the same time wiring everything up to go from API to conductor code and +back would have been a heavier lift. As such, the tests largely look for +one of the following error codes. + +* 200 - Got the item from the API - This is an database driven interaction. +* 201 - Created - This is databaes driven interaction. These are rare. +* 204 - Accepted - This is a database driven interaction. These are rare. +* 403 - Forbidden - This tells us the policy worked as expected where + access was denied. +* 404 - NotFound - This is typically when objects were not found. Before + ironic becomes scope aware, these are generally only in the drivers + API endpoint's behavior. In System scope aware Project scoped + configuration, i.e. later RBAC tests, this will become the dominant + response for project scoped users as responding with a 403 if they + could be an owner or lessee would provide insight into the existence + of a node. +* 503 - Service Unavailable - In the context of our tests, we expect this + when a request *has* been successfully authenticated and would have + been sent along to the conductor. + +How to make changes or review these tests? +========================================== + +The tests cycle through the various endpoints, and repeating patterns +are clearly visible. Typically this means a given endpoint is cycled +through with the same basic test using slightly different parameters +such as different authentication parameters. When it comes to system +scope aware tests supporting node ``owners`` and ``lessee``, these +tests will cycle a little more with slightly different attributes +as the operation is not general against a shared common node, but +different nodes. + +Some tests will test body contents, or attributes. some will validate +the number of records returned. This is important later with ``owner`` +and ``lessee`` having slightly different views of the universe. + +Some general rules apply + +* Admins can do things +* Members can do some things, but not everything +* Readers can always read, but as we get into sensitive data later on + such as fields containing infrastucture internal addresses, these values + will become hidden and additional tests will examine this. +* Third party, or external/other Admins will find nothing but sadness + in empty lists, 403, 404, or even 500 errors. + +What is/will be tested? +======================= + +The idea is to in essence test as much as possible, however as these +tests Role Based Access Control related capabilities will come in a +series of phases, styles vary a little. + +The first phase is ``"legacy"``. In essence these are partially +programatically generated and then human reviewed and values populated +with expected values. + +The second phase is remarkably similar to ``legacy``. It is the safety net +where we execute the ``legacy`` tests with the updated ``oslo.policy`` +configuration to help enforce scopes. These tests will intentionally begin to +fail in phase three. + +The third phase is the implementation of System scope awareness for the +API. In this process, as various portions of the API are made system scope +aware. The ``legacy`` tests are marked as ``deprecated`` which signals to +the second phase test sequences that they are **expected** to fail. New +``system scoped`` tests are also implemented which are matched up by name +to the ``legacy`` tests. The major difference being some header values, +and a user with a ``member`` role in the ``system`` scope now has some +rights. + +The forth phase, is implementaiton of ``owner`` and ``lessee`` aware +project scoping. The testing approach is similar, however it is much more of +a "shotgun" approach. We test what we know should work, and what know should +not work, but we do not have redundant testing for each role as ``admin`` +users are also ``members``, and since the policy rules are designed around +thresholds of access, it just made no sense to run the same test for admin +and members, where member was the threshold. These thresholds will vary with +the proposed default policy. The forth scope also tests a third party external +admin as a negative test to ensure that we are also denying access to +resources appropriately. diff --git a/ironic/tests/unit/api/base.py b/ironic/tests/unit/api/base.py index 3d80ee42fb..ebf89df32a 100644 --- a/ironic/tests/unit/api/base.py +++ b/ironic/tests/unit/api/base.py @@ -112,7 +112,7 @@ class BaseApiTest(db_base.DbTestCase): return response def put_json(self, path, params, expect_errors=False, headers=None, - extra_environ=None, status=None): + extra_environ=None, status=None, path_prefix=PATH_PREFIX): """Sends simulated HTTP PUT request to Pecan test app. :param path: url path of target service @@ -127,10 +127,11 @@ class BaseApiTest(db_base.DbTestCase): return self._request_json(path=path, params=params, expect_errors=expect_errors, headers=headers, extra_environ=extra_environ, - status=status, method="put") + status=status, method="put", + path_prefix=path_prefix) def post_json(self, path, params, expect_errors=False, headers=None, - extra_environ=None, status=None): + extra_environ=None, status=None, path_prefix=PATH_PREFIX): """Sends simulated HTTP POST request to Pecan test app. :param path: url path of target service @@ -145,10 +146,11 @@ class BaseApiTest(db_base.DbTestCase): return self._request_json(path=path, params=params, expect_errors=expect_errors, headers=headers, extra_environ=extra_environ, - status=status, method="post") + status=status, method="post", + path_prefix=path_prefix) def patch_json(self, path, params, expect_errors=False, headers=None, - extra_environ=None, status=None): + extra_environ=None, status=None, path_prefix=PATH_PREFIX): """Sends simulated HTTP PATCH request to Pecan test app. :param path: url path of target service @@ -163,7 +165,8 @@ class BaseApiTest(db_base.DbTestCase): return self._request_json(path=path, params=params, expect_errors=expect_errors, headers=headers, extra_environ=extra_environ, - status=status, method="patch") + status=status, method="patch", + path_prefix=path_prefix) def delete(self, path, expect_errors=False, headers=None, extra_environ=None, status=None, path_prefix=PATH_PREFIX): diff --git a/ironic/tests/unit/api/test_acl.py b/ironic/tests/unit/api/test_acl.py index aa9a74019c..adea1fe4e0 100644 --- a/ironic/tests/unit/api/test_acl.py +++ b/ironic/tests/unit/api/test_acl.py @@ -23,6 +23,9 @@ import ddt from keystonemiddleware import auth_token from oslo_config import cfg +from ironic.api.controllers.v1 import versions as api_versions +from ironic.common import exception +from ironic.conductor import rpcapi from ironic.tests.unit.api import base from ironic.tests.unit.db import utils as db_utils @@ -42,6 +45,17 @@ class TestACLBase(base.BaseApiTest): self.mock_auth = mock_auth.start() self.addCleanup(mock_auth.stop) + topic = mock.patch.object( + rpcapi.ConductorAPI, 'get_topic_for', autospec=True) + self.mock_topic = topic.start() + self.mock_topic.side_effect = exception.TemporaryFailure + self.addCleanup(topic.stop) + rtopic = mock.patch.object(rpcapi.ConductorAPI, 'get_random_topic', + autospec=True) + self.mock_random_topic = rtopic.start() + self.mock_random_topic.side_effect = exception.TemporaryFailure + self.addCleanup(rtopic.stop) + def _make_app(self): cfg.CONF.set_override('auth_strategy', 'keystone') return super(TestACLBase, self)._make_app() @@ -53,23 +67,70 @@ class TestACLBase(base.BaseApiTest): def _check_skip(self, **kwargs): if kwargs.get('skip_reason'): self.skipTest(kwargs.get('skip_reason')) - # Remove ASAP, but as a few hundred tests use this, we can - # rip it out later. - if kwargs.get('skip'): - self.skipTest(kwargs.get('skip_reason', 'Not implemented')) def _fake_process_request(self, request, auth_token_request): pass def _test_request(self, path, params=None, headers=None, method='get', - assert_status=None, assert_dict_contains=None): + body=None, assert_status=None, + assert_dict_contains=None, + assert_list_length=None): path = path.format(**self.format_data) self.mock_auth.side_effect = self._fake_process_request + # always request the latest api version + version = api_versions.max_version_string() + rheaders = { + 'X-OpenStack-Ironic-API-Version': version + } + # NOTE(TheJulia): Logging the test request to aid + # in troubleshooting ACL testing. This is a pattern + # followed in API unit testing in ironic, and + # really does help. + print('API ACL Testing Path %s %s' % (method, path)) + if headers: + for k, v in headers.items(): + rheaders[k] = v.format(**self.format_data) + if method == 'get': response = self.get_json( path, - headers=headers, + headers=rheaders, + expect_errors=True, + extra_environ=self.environ, + path_prefix='' + ) + elif method == 'put': + response = self.put_json( + path, + headers=rheaders, + expect_errors=True, + extra_environ=self.environ, + path_prefix='', + params=body + ) + elif method == 'post': + response = self.post_json( + path, + headers=rheaders, + expect_errors=True, + extra_environ=self.environ, + path_prefix='', + params=body + ) + elif method == 'patch': + response = self.patch_json( + path, + params=body, + headers=rheaders, + expect_errors=True, + extra_environ=self.environ, + path_prefix='' + ) + elif method == 'delete': + response = self.delete( + path, + headers=rheaders, expect_errors=True, extra_environ=self.environ, path_prefix='' @@ -77,12 +138,10 @@ class TestACLBase(base.BaseApiTest): else: assert False, 'Unimplemented test method: %s' % method - other_asserts = bool(assert_dict_contains) - if assert_status: self.assertEqual(assert_status, response.status_int) else: - self.assertIsNotNone(other_asserts, + self.assertIsNotNone(assert_status, 'Tests must include an assert_status') if assert_dict_contains: @@ -91,6 +150,22 @@ class TestACLBase(base.BaseApiTest): self.assertEqual(v.format(**self.format_data), response.json[k]) + if assert_list_length: + for root, length in assert_list_length.items(): + # root - object to look inside + # length - number of expected elements which will be + # important for owner/lessee testing. + items = response.json[root] + self.assertIsInstance(items, list) + self.assertEqual(length, len(items)) + + # NOTE(TheJulia): API tests in Ironic tend to have a pattern + # to print request and response data to aid in development + # and troubleshooting. As such the prints should remain, + # at least until we are through primary development of the + # this test suite. + print('ACL Test GOT %s' % response) + @ddt.ddt class TestRBACBasic(TestACLBase): @@ -110,8 +185,61 @@ class TestRBACBasic(TestACLBase): class TestRBACModelBeforeScopes(TestACLBase): def _create_test_data(self): - fake_db_node = db_utils.create_test_node(chassis_id=None) - self.format_data['node_ident'] = fake_db_node['uuid'] + allocated_node_id = 31 + fake_db_allocation = db_utils.create_test_allocation( + node_id=allocated_node_id, + resource_class="CUSTOM_TEST") + fake_db_node = db_utils.create_test_node( + chassis_id=None, + driver='fake-driverz') + fake_db_node_alloced = db_utils.create_test_node( + id=allocated_node_id, + chassis_id=None, + allocation_id=fake_db_allocation['id'], + uuid='22e26c0b-03f2-4d2e-ae87-c02d7f33c000', + driver='fake-driverz') + fake_vif_port_id = "ee21d58f-5de2-4956-85ff-33935ea1ca00" + fake_db_port = db_utils.create_test_port( + node_id=fake_db_node['id'], + internal_info={'tenant_vif_port_id': fake_vif_port_id}) + fake_db_portgroup = db_utils.create_test_portgroup( + node_id=fake_db_node['id']) + fake_db_chassis = db_utils.create_test_chassis() + fake_db_deploy_template = db_utils.create_test_deploy_template() + fake_db_conductor = db_utils.create_test_conductor() + fake_db_volume_target = db_utils.create_test_volume_target( + node_id=fake_db_allocation['id']) + fake_db_volume_connector = db_utils.create_test_volume_connector( + node_id=fake_db_allocation['id']) + # Trait name aligns with create_test_node_trait. + fake_trait = 'trait' + fake_setting = 'FAKE_SETTING' + db_utils.create_test_bios_setting( + node_id=fake_db_node['id'], + name=fake_setting, + value=fake_setting) + db_utils.create_test_node_trait( + node_id=fake_db_node['id']) + + self.format_data.update({ + 'node_ident': fake_db_node['uuid'], + 'allocated_node_ident': fake_db_node_alloced['uuid'], + 'port_ident': fake_db_port['uuid'], + 'portgroup_ident': fake_db_portgroup['uuid'], + 'chassis_ident': fake_db_chassis['uuid'], + 'deploy_template_ident': fake_db_deploy_template['uuid'], + 'allocation_ident': fake_db_allocation['uuid'], + 'conductor_ident': fake_db_conductor['hostname'], + 'vif_ident': fake_vif_port_id, + # Can't use the same fake-driver as other tests can + # pollute a global method cache in the API that is in the + # test runner, resulting in false positives. + 'driver_name': 'fake-driverz', + 'bios_setting': fake_setting, + 'trait': fake_trait, + 'volume_target_ident': fake_db_volume_target['uuid'], + 'volume_connector_ident': fake_db_volume_connector['uuid'], + }) @ddt.file_data('test_rbac_legacy.yaml') @ddt.unpack diff --git a/ironic/tests/unit/api/test_acl_basic.yaml b/ironic/tests/unit/api/test_acl_basic.yaml index 52be09d8e2..78e860180d 100644 --- a/ironic/tests/unit/api/test_acl_basic.yaml +++ b/ironic/tests/unit/api/test_acl_basic.yaml @@ -19,6 +19,7 @@ project_admin_can_get_node: assert_dict_contains: uuid: '{node_uuid}' driver: 'fake-hardware' + assert_status: 200 project_member_cannot_get_node: path: *node_path diff --git a/ironic/tests/unit/api/test_rbac_legacy.yaml b/ironic/tests/unit/api/test_rbac_legacy.yaml index 2e9b6b48a8..cccb0b0db3 100644 --- a/ironic/tests/unit/api/test_rbac_legacy.yaml +++ b/ironic/tests/unit/api/test_rbac_legacy.yaml @@ -1,643 +1,2015 @@ +# NOTE(TheJulia): This file is intended for legacy project RBAC testing +# and is entirely project scoped in nature. This file will not be used +# for system scoped testing, which will be kept to separate files to +# enable the legacy tests to eventually be removed once support +# for the legacy rules has been removed from Ironic. +# +# For more information on the how these tests work, see: +# doc/source/contributor/rbac-testing.rst + +values: + skip_reason: "These are fake reference values for YAML templating" + # Project scoped admin token + admin_headers: &admin_headers + X-Auth-Token: 'baremetal-admin-token' + X-Project-ID: 66140b35c7524c6da836ca834e3fd3f9 + X-Roles: baremetal_admin + X-Project-Name: baremetal + # Project scoped other member token. + member_headers: &member_headers + X-Auth-Token: 'baremetal-member-token' + X-Project-ID: 66140b35c7524c6da836ca834e3fd3f9 + X-Roles: member + X-Project-Name: baremetal + # Project scoped Observer Token + observer_headers: &observer_headers + X-Auth-Token: 'baremetal-observer-token' + X-Project-ID: 66140b35c7524c6da836ca834e3fd3f9 + X-Project-Name: baremetal + X-Roles: baremetal_observer + other_admin_headers: &other_admin_headers + X-Auth-Token: 'other-admin-token' + X-Project-ID: a1111111111111111111111111111111 + X-Roles: admin,member,reader + X-Project-Name: 'other-project' + owner_project_id: &owner_project_id '{owner_project_id}' + other_project_id: &other_project_id '{other_project_id}' + node_ident: &node_ident '{node_ident}' + # Nodes - https://docs.openstack.org/api-ref/baremetal/?expanded=#nodes-nodes -nodes_post_allow: +nodes_post_admin: path: '/v1/nodes' method: post - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + body: &node_post_body + name: node + driver: fake-driverz + assert_status: 503 -nodes_get_allow: +nodes_post_member: + path: '/v1/nodes' + method: post + headers: *member_headers + body: *node_post_body + assert_status: 403 + +nodes_post_observer: + path: '/v1/nodes' + method: post + headers: *observer_headers + body: *node_post_body + assert_status: 403 + +nodes_get_node_admin: + path: '/v1/nodes/{node_ident}' + method: get + headers: *admin_headers + assert_dict_contains: + uuid: '{node_ident}' + driver: 'fake-driverz' + assert_status: 200 + +nodes_get_node_member: + path: '/v1/nodes/{node_ident}' + method: get + headers: *member_headers + assert_status: 403 + +nodes_get_node_observer: + path: '/v1/nodes/{node_ident}' + method: get + headers: *observer_headers + assert_dict_contains: + uuid: '{node_ident}' + driver: 'fake-driverz' + assert_status: 200 + +nodes_get_node_other_admin: + path: '/v1/nodes/{node_ident}' + method: get + headers: *other_admin_headers + # FIXME(TheJulia): So this is not great, but it is default for now + # And MUST be changed moving forward, just not in this patch. + # This just represents the *current* state, not what the world should be + # in the end. + assert_status: 200 + +nodes_get_admin: path: '/v1/nodes' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_list_length: + nodes: 2 + assert_status: 200 -nodes_detail_get_allow: +nodes_get_other_admin: + path: '/v1/nodes' + method: get + headers: *other_admin_headers + assert_list_length: + nodes: 2 + assert_status: 200 + +nodes_detail_get_admin: path: '/v1/nodes/detail' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -nodes_node_ident_get_allow: +nodes_detail_get_member: + path: '/v1/nodes/detail' + method: get + headers: *member_headers + assert_status: 403 + +nodes_detail_get_observer: + path: '/v1/nodes/detail' + method: get + headers: *observer_headers + assert_status: 200 + +nodes_node_ident_get_admin: path: '/v1/nodes/{node_ident}' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -nodes_node_ident_patch_allow: +nodes_node_ident_get_member: + path: '/v1/nodes/{node_ident}' + method: get + headers: *member_headers + assert_status: 403 + +nodes_node_ident_get_observer: + path: '/v1/nodes/{node_ident}' + method: get + headers: *observer_headers + assert_status: 200 + +nodes_node_ident_patch_admin: path: '/v1/nodes/{node_ident}' method: patch - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + body: &extra_patch + - op: replace + path: /extra + value: {'test': 'testing'} + assert_status: 503 -nodes_node_ident_delete_allow: +nodes_node_ident_patch_member: + path: '/v1/nodes/{node_ident}' + method: patch + headers: *member_headers + body: *extra_patch + assert_status: 403 + +nodes_node_ident_patch_observer: + path: '/v1/nodes/{node_ident}' + method: patch + headers: *observer_headers + body: *extra_patch + assert_status: 403 + +nodes_node_ident_delete_admin: path: '/v1/nodes/{node_ident}' method: delete - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 + +nodes_node_ident_delete_member: + path: '/v1/nodes/{node_ident}' + method: delete + headers: *member_headers + assert_status: 403 + +nodes_node_ident_delete_observer: + path: '/v1/nodes/{node_ident}' + method: delete + headers: *observer_headers + assert_status: 403 # Node Management - https://docs.openstack.org/api-ref/baremetal/?expanded=#node-management-nodes -nodes_validate_get_allow: +nodes_validate_get_admin: path: '/v1/nodes/{node_ident}/validate' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 -nodes_maintenance_put_allow: +nodes_validate_get_member: + path: '/v1/nodes/{node_ident}/validate' + method: get + headers: *member_headers + assert_status: 403 + +nodes_validate_get_observer: + path: '/v1/nodes/{node_ident}/validate' + method: get + headers: *observer_headers + assert_status: 403 + +nodes_maintenance_put_admin: path: '/v1/nodes/{node_ident}/maintenance' method: put - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 -nodes_maintenance_delete_allow: +nodes_maintenance_put_member: + path: '/v1/nodes/{node_ident}/maintenance' + method: put + headers: *member_headers + assert_status: 403 + +nodes_maintenance_put_observer: + path: '/v1/nodes/{node_ident}/maintenance' + method: put + headers: *observer_headers + assert_status: 403 + +nodes_maintenance_delete_admin: path: '/v1/nodes/{node_ident}/maintenance' method: delete - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 -nodes_management_boot_device_put_allow: +nodes_maintenance_delete_member: + path: '/v1/nodes/{node_ident}/maintenance' + method: delete + headers: *member_headers + assert_status: 403 + +nodes_maintenance_delete_observer: + path: '/v1/nodes/{node_ident}/maintenance' + method: delete + headers: *observer_headers + assert_status: 403 + +nodes_management_boot_device_put_admin: path: '/v1/nodes/{node_ident}/management/boot_device' method: put - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + body: &boot_device_body + boot_device: pxe + assert_status: 503 -nodes_management_boot_device_get_allow: +nodes_management_boot_device_put_member: + path: '/v1/nodes/{node_ident}/management/boot_device' + method: put + headers: *member_headers + body: *boot_device_body + assert_status: 403 + +nodes_management_boot_device_put_observer: + path: '/v1/nodes/{node_ident}/management/boot_device' + method: put + headers: *observer_headers + body: *boot_device_body + assert_status: 403 + +nodes_management_boot_device_get_admin: path: '/v1/nodes/{node_ident}/management/boot_device' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 -nodes_management_boot_device_supported_get_allow: +nodes_management_boot_device_get_member: + path: '/v1/nodes/{node_ident}/management/boot_device' + method: get + headers: *member_headers + assert_status: 403 + +nodes_management_boot_device_get_observer: + path: '/v1/nodes/{node_ident}/management/boot_device' + method: get + headers: *observer_headers + assert_status: 503 + +nodes_management_boot_device_supported_get_admin: path: '/v1/nodes/{node_ident}/management/boot_device/supported' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 -nodes_management_inject_nmi_put_allow: +nodes_management_boot_device_supported_get_member: + path: '/v1/nodes/{node_ident}/management/boot_device/supported' + method: get + headers: *member_headers + assert_status: 403 + +nodes_management_boot_device_supported_get_observer: + path: '/v1/nodes/{node_ident}/management/boot_device/supported' + method: get + headers: *observer_headers + assert_status: 503 + +nodes_management_inject_nmi_put_admin: path: '/v1/nodes/{node_ident}/management/inject_nmi' method: put - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + body: {} + assert_status: 503 -nodes_states_get_allow: +nodes_management_inject_nmi_put_member: + path: '/v1/nodes/{node_ident}/management/inject_nmi' + method: put + headers: *member_headers + body: {} + assert_status: 403 + +nodes_management_inject_nmi_put_observer: + path: '/v1/nodes/{node_ident}/management/inject_nmi' + method: put + headers: *observer_headers + body: {} + assert_status: 403 + + +nodes_states_get_admin: path: '/v1/nodes/{node_ident}/states' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -nodes_states_power_put_allow: +nodes_states_get_member: + path: '/v1/nodes/{node_ident}/states' + method: get + headers: *member_headers + assert_status: 403 + +nodes_states_get_observer: + path: '/v1/nodes/{node_ident}/states' + method: get + headers: *observer_headers + assert_status: 200 + +nodes_states_power_put_admin: path: '/v1/nodes/{node_ident}/states/power' method: put - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + body: &power_body + target: "power on" + assert_status: 503 -nodes_states_provision_put_allow: +nodes_states_power_put_member: + path: '/v1/nodes/{node_ident}/states/power' + method: put + headers: *member_headers + body: *power_body + assert_status: 403 + +nodes_states_power_put_observer: + path: '/v1/nodes/{node_ident}/states/power' + method: put + headers: *observer_headers + body: *power_body + assert_status: 403 + +nodes_states_provision_put_admin: path: '/v1/nodes/{node_ident}/states/provision' method: put - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + body: &provision_body + target: deploy + assert_status: 503 -nodes_states_raid_put_allow: +nodes_states_provision_put_member: + path: '/v1/nodes/{node_ident}/states/provision' + method: put + headers: *member_headers + body: *provision_body + assert_status: 403 + +nodes_states_provision_put_observer: + path: '/v1/nodes/{node_ident}/states/provision' + method: put + headers: *observer_headers + body: *provision_body + assert_status: 403 + +nodes_states_raid_put_admin: path: '/v1/nodes/{node_ident}/states/raid' method: put - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + body: &raid_body + target_raid_config: + logical_disks: + - size_gb: 500 + is_root_volume: true + raid_level: 1 + assert_status: 503 -nodes_states_console_get_allow: +nodes_states_raid_put_member: + path: '/v1/nodes/{node_ident}/states/raid' + method: put + headers: *member_headers + body: *raid_body + assert_status: 403 + +nodes_states_raid_put_observer: + path: '/v1/nodes/{node_ident}/states/raid' + method: put + headers: *observer_headers + body: *raid_body + assert_status: 403 + +nodes_states_console_get_admin: path: '/v1/nodes/{node_ident}/states/console' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 -nodes_states_console_put_allow: +nodes_states_console_get_member: + path: '/v1/nodes/{node_ident}/states/console' + method: get + headers: *member_headers + assert_status: 403 + +nodes_states_console_get_admin: + path: '/v1/nodes/{node_ident}/states/console' + method: get + headers: *observer_headers + assert_status: 403 + +nodes_states_console_put_admin: path: '/v1/nodes/{node_ident}/states/console' method: put - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + body: &console_body_put + enabled: true + assert_status: 503 + +nodes_states_console_put_member: + path: '/v1/nodes/{node_ident}/states/console' + method: put + headers: *member_headers + body: *console_body_put + assert_status: 403 + +nodes_states_console_put_observer: + path: '/v1/nodes/{node_ident}/states/console' + method: put + headers: *observer_headers + body: *console_body_put + assert_status: 403 # Node Traits - https://docs.openstack.org/api-ref/baremetal/?expanded=#node-vendor-passthru-nodes -nodes_vendor_passthru_methods_get_allow: +# Calls conductor upon the get as a task is required. +nodes_vendor_passthru_methods_get_admin: path: '/v1/nodes/{node_ident}/vendor_passthru/methods' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 -nodes_vendor_passthru_get_allow: - path: '/v1/nodes/{node_ident}/vendor_passthru' +nodes_vendor_passthru_methods_get_member: + path: '/v1/nodes/{node_ident}/vendor_passthru/methods' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *member_headers + assert_status: 403 -nodes_vendor_passthru_post_allow: - path: '/v1/nodes/{node_ident}/vendor_passthru' +nodes_vendor_passthru_methods_get_observer: + path: '/v1/nodes/{node_ident}/vendor_passthru/methods' + method: get + headers: *observer_headers + assert_status: 403 + +nodes_vendor_passthru_get_admin: + path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' + method: get + headers: *admin_headers + assert_status: 503 + +nodes_vendor_passthru_get_member: + path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' + method: get + headers: *member_headers + assert_status: 403 + +nodes_vendor_passthru_get_observer: + path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' + method: get + headers: *observer_headers + assert_status: 403 + +nodes_vendor_passthru_post_admin: + path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: post - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 -nodes_vendor_passthru_put_allow: - path: '/v1/nodes/{node_ident}/vendor_passthru' +nodes_vendor_passthru_post_member: + path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' + method: post + headers: *member_headers + assert_status: 403 + +nodes_vendor_passthru_post_observer: + path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' + method: post + headers: *observer_headers + assert_status: 403 + +nodes_vendor_passthru_put_admin: + path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: put - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 -nodes_vendor_passthru_delete_allow: - path: '/v1/nodes/{node_ident}/vendor_passthru' +nodes_vendor_passthru_put_member: + path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' + method: put + headers: *member_headers + assert_status: 403 + +nodes_vendor_passthru_put_observer: + path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' + method: put + headers: *observer_headers + assert_status: 403 + +nodes_vendor_passthru_delete_admin: + path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' method: delete - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 + +nodes_vendor_passthru_delete_member: + path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' + method: delete + headers: *member_headers + assert_status: 403 + +nodes_vendor_passthru_delete_observer: + path: '/v1/nodes/{node_ident}/vendor_passthru?method=test' + method: delete + headers: *observer_headers + assert_status: 403 # Node Traits - https://docs.openstack.org/api-ref/baremetal/#node-traits-nodes -nodes_traits_get_allow: +nodes_traits_get_admin: path: '/v1/nodes/{node_ident}/traits' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -nodes_traits_put_allow: +nodes_traits_get_member: + path: '/v1/nodes/{node_ident}/traits' + method: get + headers: *member_headers + assert_status: 403 + +nodes_traits_get_observer: + path: '/v1/nodes/{node_ident}/traits' + method: get + headers: *observer_headers + assert_status: 200 + +nodes_traits_put_admin: path: '/v1/nodes/{node_ident}/traits' method: put - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 + body: &traits_body + traits: + - CUSTOM_TRAIT1 + - HW_CPU_X86_VMX -nodes_traits_delete_allow: +nodes_traits_put_member: path: '/v1/nodes/{node_ident}/traits' - method: delete - skip: true - skip_reason: 'Not implemented yet' - -nodes_traits_trait_put_allow: - path: '/v1/nodes/{node_ident}/traits/{trait}' method: put - skip: true - skip_reason: 'Not implemented yet' + headers: *member_headers + assert_status: 403 + body: *traits_body -nodes_traits_trait_delete_allow: +nodes_traits_put_observer: + path: '/v1/nodes/{node_ident}/traits' + method: put + headers: *observer_headers + assert_status: 403 + body: *traits_body + +nodes_traits_delete_admin: path: '/v1/nodes/{node_ident}/traits/{trait}' method: delete - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 + +nodes_traits_delete_member: + path: '/v1/nodes/{node_ident}/traits/{trait}' + method: delete + headers: *member_headers + assert_status: 403 + +nodes_traits_delete_observer: + path: '/v1/nodes/{node_ident}/traits/{trait}' + method: delete + headers: *observer_headers + assert_status: 403 + +nodes_traits_trait_put_admin: + path: '/v1/nodes/{node_ident}/traits/CUSTOM_TRAIT2' + method: put + headers: *admin_headers + assert_status: 503 + +nodes_traits_trait_put_member: + path: '/v1/nodes/{node_ident}/traits/CUSTOM_TRAIT2' + method: put + headers: *member_headers + assert_status: 403 + +nodes_traits_trait_put_observer: + path: '/v1/nodes/{node_ident}/traits/CUSTOM_TRAIT2' + method: put + headers: *observer_headers + assert_status: 403 + +nodes_traits_trait_delete_admin: + path: '/v1/nodes/{node_ident}/traits/{trait}' + method: delete + headers: *admin_headers + assert_status: 503 + +nodes_traits_trait_delete_member: + path: '/v1/nodes/{node_ident}/traits/{trait}' + method: delete + headers: *member_headers + assert_status: 403 + +nodes_traits_trait_delete_observer: + path: '/v1/nodes/{node_ident}/traits/{trait}' + method: delete + headers: *observer_headers + assert_status: 403 # VIFS - https://docs.openstack.org/api-ref/baremetal/#vifs-virtual-interfaces-of-nodes # TODO(TheJulia): VIFS will need fairly exhaustive testing given the use path. # i.e. ensure user has rights to a vif and all. -nodes_vifs_get_allow: +# Apparently the get operation hits the conductor?!? +# With mocked conductor 503 is returned. +nodes_vifs_get_admin: path: '/v1/nodes/{node_ident}/vifs' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 -nodes_vifs_post_allow: +nodes_vifs_get_member: + path: '/v1/nodes/{node_ident}/vifs' + method: get + headers: *member_headers + assert_status: 403 + +nodes_vifs_get_observer: + path: '/v1/nodes/{node_ident}/vifs' + method: get + headers: *observer_headers + assert_status: 403 + +nodes_vifs_post_admin: path: '/v1/nodes/{node_ident}/vifs' method: post - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 + body: &vif_body + id: ee21d58f-5de2-4956-85ff-33935ea1ca00 -nodes_vifs_node_vif_ident_delete_allow: - path: '/v1/nodes/{node_ident}/vifs/{node_vif_ident}' +nodes_vifs_post_member: + path: '/v1/nodes/{node_ident}/vifs' + method: post + headers: *member_headers + assert_status: 403 + body: *vif_body + +nodes_vifs_post_observer: + path: '/v1/nodes/{node_ident}/vifs' + method: post + headers: *observer_headers + assert_status: 403 + body: *vif_body + +# This calls the conductor, hence not status 403. +nodes_vifs_node_vif_ident_delete_admin: + path: '/v1/nodes/{node_ident}/vifs/{vif_ident}' method: delete - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 + +nodes_vifs_node_vif_ident_delete_member: + path: '/v1/nodes/{node_ident}/vifs/{vif_ident}' + method: delete + headers: *member_headers + assert_status: 403 + +nodes_vifs_node_vif_ident_delete_observer: + path: '/v1/nodes/{node_ident}/vifs/{vif_ident}' + method: delete + headers: *observer_headers + assert_status: 403 # Indicators - https://docs.openstack.org/api-ref/baremetal/#indicators-management -nodes_management_indicators_get_allow: +nodes_management_indicators_get_admin: path: '/v1/nodes/{node_ident}/management/indicators' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 + +nodes_management_indicators_get_member: + path: '/v1/nodes/{node_ident}/management/indicators' + method: get + headers: *member_headers + assert_status: 403 + +nodes_management_indicators_get_observer: + path: '/v1/nodes/{node_ident}/management/indicators' + method: get + headers: *observer_headers + assert_status: 503 nodes_management_indicators_component_get_allow: path: '/v1/nodes/{node_ident}/management/indicators/{component}' method: get - skip: true - skip_reason: 'Not implemented yet' + skip_reason: API appears to be broken and should be patched outside of this work. nodes_management_indicators_component_ind_ident_get_allow: path: '/v1/nodes/{node_ident}/management/indicators/{component}/{ind_ident}' method: get - skip: true - skip_reason: 'Not implemented yet' + skip_reason: API appears to be broken and should be patched outside of this work. nodes_management_indicators_component_ind_ident_put_allow: path: '/v1/nodes/{node_ident}/management/indicators/{component}/{ind_ident}' method: put - skip: true - skip_reason: 'Not implemented yet' + skip_reason: API appears to be broken and should be patched outside of this work. # Portgroups - https://docs.openstack.org/api-ref/baremetal/#portgroups-portgroups -portgroups_get_allow: +portgroups_get_admin: path: '/v1/portgroups' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -portgroups_post_allow: +portgroups_get_member: + path: '/v1/portgroups' + method: get + headers: *member_headers + assert_status: 403 + +portgroups_get_observer: + path: '/v1/portgroups' + method: get + headers: *observer_headers + assert_status: 200 + +# Returns 400 as the node uuid cannot be found, but +# it is past the access controls. +portgroups_post_admin: path: '/v1/portgroups' method: post - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + body: &portgroup_body + node_uuid: 68a552fb-dcd2-43bf-9302-e4c93287be16 + assert_status: 400 -portgroups_detail_get_allow: +portgroups_post_member: + path: '/v1/portgroups' + method: post + headers: *member_headers + body: *portgroup_body + assert_status: 403 + +portgroups_post_observer: + path: '/v1/portgroups' + method: post + headers: *observer_headers + body: *portgroup_body + assert_status: 403 + +portgroups_detail_get_admin: path: '/v1/portgroups/detail' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -portgroups_portgroup_ident_get_allow: +portgroups_detail_get_member: + path: '/v1/portgroups/detail' + method: get + headers: *member_headers + assert_status: 403 + +portgroups_detail_get_observer: + path: '/v1/portgroups/detail' + method: get + headers: *observer_headers + assert_status: 200 + +portgroups_portgroup_ident_get_admin: path: '/v1/portgroups/{portgroup_ident}' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -portgroups_portgroup_ident_patch_allow: +portgroups_portgroup_ident_get_member: + path: '/v1/portgroups/{portgroup_ident}' + method: get + headers: *member_headers + assert_status: 403 + +portgroups_portgroup_ident_get_observer: + path: '/v1/portgroups/{portgroup_ident}' + method: get + headers: *observer_headers + assert_status: 200 + +portgroups_portgroup_ident_patch_admin: path: '/v1/portgroups/{portgroup_ident}' method: patch - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + body: &portgroup_patch_body + - op: replace + path: /extra + value: {'test': 'testing'} + assert_status: 503 -portgroups_portgroup_ident_delete_allow: +portgroups_portgroup_ident_patch_member: + path: '/v1/portgroups/{portgroup_ident}' + method: patch + headers: *member_headers + body: *portgroup_patch_body + assert_status: 403 + +portgroups_portgroup_ident_patch_observer: + path: '/v1/portgroups/{portgroup_ident}' + method: patch + headers: *observer_headers + body: *portgroup_patch_body + assert_status: 403 + +portgroups_portgroup_ident_delete_admin: path: '/v1/portgroups/{portgroup_ident}' method: delete - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 + +portgroups_portgroup_ident_delete_member: + path: '/v1/portgroups/{portgroup_ident}' + method: delete + headers: *member_headers + assert_status: 403 + +portgroups_portgroup_ident_delete_observer: + path: '/v1/portgroups/{portgroup_ident}' + method: delete + headers: *observer_headers + assert_status: 403 # Portgroups by node - https://docs.openstack.org/api-ref/baremetal/#listing-portgroups-by-node-nodes-portgroups -nodes_portgroups_get_allow: +nodes_portgroups_get_admin: path: '/v1/nodes/{node_ident}/portgroups' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -nodes_portgroups_detail_get_allow: +nodes_portgroups_get_member: + path: '/v1/nodes/{node_ident}/portgroups' + method: get + headers: *member_headers + assert_status: 403 + +nodes_portgroups_get_observer: + path: '/v1/nodes/{node_ident}/portgroups' + method: get + headers: *observer_headers + assert_status: 200 + +nodes_portgroups_detail_get_admin: path: '/v1/nodes/{node_ident}/portgroups/detail' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 + +nodes_portgroups_detail_get_member: + path: '/v1/nodes/{node_ident}/portgroups/detail' + method: get + headers: *member_headers + assert_status: 403 + +nodes_portgroups_detail_get_observer: + path: '/v1/nodes/{node_ident}/portgroups/detail' + method: get + headers: *observer_headers + assert_status: 200 # Ports - https://docs.openstack.org/api-ref/baremetal/#ports-ports -ports_get_allow: +ports_get_admin: path: '/v1/ports' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -ports_post_allow: +ports_get_member: + path: '/v1/ports' + method: get + headers: *member_headers + assert_status: 403 + +ports_get_observer: + path: '/v1/ports' + method: get + headers: *observer_headers + assert_status: 200 + +# NOTE(TheJulia): Returns 400 when the conductor calls are +# mocked indicating node lookup failed, which means the access +# check was successful. +ports_post_admin: path: '/v1/ports' method: post - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 400 + body: &port_body + node_uuid: 68a552fb-dcd2-43bf-9302-e4c93287be16 + address: 00:01:02:03:04:05 -ports_detail_get_allow: +ports_post_member: + path: '/v1/ports' + method: post + headers: *member_headers + assert_status: 403 + body: *port_body + +ports_post_observer: + path: '/v1/ports' + method: post + headers: *observer_headers + assert_status: 403 + body: *port_body + +ports_detail_get_admin: path: '/v1/ports/detail' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -ports_port_id_get_allow: - path: '/v1/ports/{port_id}' +ports_detail_get_member: + path: '/v1/ports/detail' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *member_headers + assert_status: 403 -ports_port_id_patch_allow: - path: '/v1/ports/{port_id}' +ports_detail_get_observer: + path: '/v1/ports/detail' + method: get + headers: *observer_headers + assert_status: 200 + +ports_port_id_get_admin: + path: '/v1/ports/{port_ident}' + method: get + headers: *admin_headers + assert_status: 200 + +ports_port_id_get_member: + path: '/v1/ports/{port_ident}' + method: get + headers: *member_headers + assert_status: 403 + +ports_port_id_get_observer: + path: '/v1/ports/{port_ident}' + method: get + headers: *observer_headers + assert_status: 200 + +ports_port_id_patch_admin: + path: '/v1/ports/{port_ident}' method: patch - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 + body: &port_patch_body + - op: replace + path: /extra + value: {'test': 'testing'} -ports_port_id_delete_allow: - path: '/v1/ports/{port_id}' +ports_port_id_patch_member: + path: '/v1/ports/{port_ident}' + method: patch + headers: *member_headers + assert_status: 403 + body: *port_patch_body + +ports_port_id_patch_observer: + path: '/v1/ports/{port_ident}' + method: patch + headers: *observer_headers + assert_status: 403 + body: *port_patch_body + +ports_port_id_delete_admin: + path: '/v1/ports/{port_ident}' method: delete - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 + +ports_port_id_delete_member: + path: '/v1/ports/{port_ident}' + method: delete + headers: *member_headers + assert_status: 403 + +ports_port_id_delete_observer: + path: '/v1/ports/{port_ident}' + method: delete + headers: *observer_headers + assert_status: 403 # Ports by node - https://docs.openstack.org/api-ref/baremetal/#listing-ports-by-node-nodes-ports -nodes_ports_get_allow: +nodes_ports_get_admin: path: '/v1/nodes/{node_ident}/ports' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -nodes_ports_detail_get_allow: +nodes_ports_get_member: + path: '/v1/nodes/{node_ident}/ports' + method: get + headers: *member_headers + assert_status: 403 + +nodes_ports_get_observer: + path: '/v1/nodes/{node_ident}/ports' + method: get + headers: *observer_headers + assert_status: 200 + +nodes_ports_detail_get_admin: path: '/v1/nodes/{node_ident}/ports/detail' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 + +nodes_ports_detail_get_member: + path: '/v1/nodes/{node_ident}/ports/detail' + method: get + headers: *member_headers + assert_status: 403 + +nodes_ports_detail_get_observer: + path: '/v1/nodes/{node_ident}/ports/detail' + method: get + headers: *observer_headers + assert_status: 200 # Ports by portgroup - https://docs.openstack.org/api-ref/baremetal/#listing-ports-by-portgroup-portgroup-ports -portgroups_ports_get_allow: +portgroups_ports_get_admin: path: '/v1/portgroups/{portgroup_ident}/ports' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -portgroups_ports_detail_get_allow: +portgroups_ports_get_member: + path: '/v1/portgroups/{portgroup_ident}/ports' + method: get + headers: *member_headers + assert_status: 403 + +portgroups_ports_get_observer: + path: '/v1/portgroups/{portgroup_ident}/ports' + method: get + headers: *observer_headers + assert_status: 200 + +portgroups_ports_detail_get_admin: path: '/v1/portgroups/{portgroup_ident}/ports/detail' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 + +portgroups_ports_detail_get_member: + path: '/v1/portgroups/{portgroup_ident}/ports/detail' + method: get + headers: *member_headers + assert_status: 403 + +portgroups_ports_detail_get_observer: + path: '/v1/portgroups/{portgroup_ident}/ports/detail' + method: get + headers: *observer_headers + assert_status: 200 + # Volume(s) - https://docs.openstack.org/api-ref/baremetal/#volume-volume # TODO(TheJulia): volumes will likely need some level of exhaustive testing. # i.e. ensure that the volume is permissible. However this may not be possible # here. -volume_get_allow: +volume_get_admin: path: '/v1/volume' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 + +volume_get_member: + path: '/v1/volume' + method: get + headers: *member_headers + assert_status: 403 + +volume_get_observer: + path: '/v1/volume' + method: get + headers: *observer_headers + assert_status: 200 # Volume connectors -volume_connectors_get_allow: +volume_connectors_get_admin: path: '/v1/volume/connectors' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -volume_connectors_post_allow: +volume_connectors_get_member: + path: '/v1/volume/connectors' + method: get + headers: *member_headers + assert_status: 403 + +volume_connectors_get_observer: + path: '/v1/volume/connectors' + method: get + headers: *observer_headers + assert_status: 200 + +# NOTE(TheJulia): This ends up returning a 400 due to the +# UUID not already being in ironic. +volume_connectors_post_admin: path: '/v1/volume/connectors' method: post - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 400 + body: &volume_connector_body + node_uuid: 68a552fb-dcd2-43bf-9302-e4c93287be16 + type: ip + connector_id: 192.168.1.100 -volume_volume_connector_id_get_allow: - path: '/v1/volume/connectors/{volume_connector_id}' +volume_connectors_post_member: + path: '/v1/volume/connectors' + method: post + headers: *member_headers + assert_status: 403 + body: *volume_connector_body + +volume_connectors_post_observer: + path: '/v1/volume/connectors' + method: post + headers: *observer_headers + assert_status: 403 + body: *volume_connector_body + +volume_volume_connector_id_get_admin: + path: '/v1/volume/connectors/{volume_connector_ident}' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -volume_volume_connector_id_patch_allow: - path: '/v1/volume/connectors/{volume_connector_id}' +volume_volume_connector_id_get_member: + path: '/v1/volume/connectors/{volume_connector_ident}' + method: get + headers: *member_headers + assert_status: 403 + +volume_volume_connector_id_get_observer: + path: '/v1/volume/connectors/{volume_connector_ident}' + method: get + headers: *observer_headers + assert_status: 200 + +volume_volume_connector_id_patch_admin: + path: '/v1/volume/connectors/{volume_connector_ident}' method: patch - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + body: &connector_patch_body + - op: replace + path: /extra + value: {'test': 'testing'} + assert_status: 503 -volume_volume_connector_id_delete_allow: - path: '/v1/volume/connectors/{volume_connector_id}' +volume_volume_connector_id_patch_member: + path: '/v1/volume/connectors/{volume_connector_ident}' + method: patch + headers: *member_headers + body: *connector_patch_body + assert_status: 403 + +volume_volume_connector_id_patch_observer: + path: '/v1/volume/connectors/{volume_connector_ident}' + method: patch + headers: *observer_headers + body: *connector_patch_body + assert_status: 403 + +volume_volume_connector_id_delete_admin: + path: '/v1/volume/connectors/{volume_connector_ident}' method: delete - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 + +volume_volume_connector_id_delete_member: + path: '/v1/volume/connectors/{volume_connector_ident}' + method: delete + headers: *member_headers + assert_status: 403 + +volume_volume_connector_id_delete_observer: + path: '/v1/volume/connectors/{volume_connector_ident}' + method: delete + headers: *observer_headers + assert_status: 403 # Volume targets -volume_targets_get_allow: +volume_targets_get_admin: path: '/v1/volume/targets' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -volume_targets_post_allow: +volume_targets_get_member: + path: '/v1/volume/targets' + method: get + headers: *member_headers + assert_status: 403 + +volume_targets_get_observer: + path: '/v1/volume/targets' + method: get + headers: *observer_headers + assert_status: 200 + +# NOTE(TheJulia): Because we can't seem to get the uuid +# to load from an existing uuid, since we're not subsituting +# it, this will return with 400 due to the ID not matching. +volume_targets_post_admin: path: '/v1/volume/targets' method: post - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 400 + body: &volume_target_body + node_uuid: 68a552fb-dcd2-43bf-9302-e4c93287be16 + volume_type: iscsi + boot_index: 0 + volume_id: 'test-id' -volume_volume_target_id_get_allow: - path: '/v1/volume/targets/{volume_target_id}' +volume_targets_post_member: + path: '/v1/volume/targets' + method: post + headers: *member_headers + assert_status: 403 + body: *volume_target_body + +volume_targets_post_observer: + path: '/v1/volume/targets' + method: post + headers: *observer_headers + assert_status: 403 + body: *volume_target_body + +volume_volume_target_id_get_admin: + path: '/v1/volume/targets/{volume_target_ident}' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -volume_volume_target_id_patch_allow: - path: '/v1/volume/targets/{volume_target_id}' +volume_volume_target_id_get_member: + path: '/v1/volume/targets/{volume_target_ident}' + method: get + headers: *member_headers + assert_status: 403 + +volume_volume_target_id_get_observer: + path: '/v1/volume/targets/{volume_target_ident}' + method: get + headers: *observer_headers + assert_status: 200 + +volume_volume_target_id_patch_admin: + path: '/v1/volume/targets/{volume_target_ident}' method: patch - skip: true - skip_reason: 'Not implemented yet' + body: &volume_target_patch + - op: replace + path: /extra + value: {'test': 'testing'} + headers: *admin_headers + assert_status: 503 -volume_volume_target_id_delete_allow: - path: '/v1/volume/targets/{volume_target_id}' +volume_volume_target_id_patch_admin: + path: '/v1/volume/targets/{volume_target_ident}' + method: patch + body: *volume_target_patch + headers: *member_headers + assert_status: 403 + +volume_volume_target_id_patch_observer: + path: '/v1/volume/targets/{volume_target_ident}' + method: patch + body: *volume_target_patch + headers: *observer_headers + assert_status: 403 + +volume_volume_target_id_delete_admin: + path: '/v1/volume/targets/{volume_target_ident}' method: delete - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 + +volume_volume_target_id_delete_member: + path: '/v1/volume/targets/{volume_target_ident}' + method: delete + headers: *member_headers + assert_status: 403 + +volume_volume_target_id_delete_observer: + path: '/v1/volume/targets/{volume_target_ident}' + method: delete + headers: *observer_headers + assert_status: 403 # Get Volumes by Node - https://docs.openstack.org/api-ref/baremetal/#listing-volume-resources-by-node-nodes-volume -nodes_volume_get_allow: +nodes_volume_get_admin: path: '/v1/nodes/{node_ident}/volume' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -nodes_volume_connectors_get_allow: +nodes_volume_get_member: + path: '/v1/nodes/{node_ident}/volume' + method: get + headers: *member_headers + assert_status: 403 + +nodes_volume_get_observer: + path: '/v1/nodes/{node_ident}/volume' + method: get + headers: *observer_headers + assert_status: 200 + +nodes_volume_connectors_get_admin: path: '/v1/nodes/{node_ident}/volume/connectors' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -nodes_volume_targets_get_allow: +nodes_volume_connectors_get_member: + path: '/v1/nodes/{node_ident}/volume/connectors' + method: get + headers: *member_headers + assert_status: 403 + +nodes_volume_connectors_get_observer: + path: '/v1/nodes/{node_ident}/volume/connectors' + method: get + headers: *observer_headers + assert_status: 200 + +nodes_volume_targets_get_admin: path: '/v1/nodes/{node_ident}/volume/targets' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 + +nodes_volume_targets_get_member: + path: '/v1/nodes/{node_ident}/volume/targets' + method: get + headers: *member_headers + assert_status: 403 + +nodes_volume_targets_get_observer: + path: '/v1/nodes/{node_ident}/volume/targets' + method: get + headers: *observer_headers + assert_status: 200 # Drivers - https://docs.openstack.org/api-ref/baremetal/#drivers-drivers -drivers_get_allow: +drivers_get_admin: path: '/v1/drivers' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -drivers_driver_name_get_allow: +drivers_get_member: + path: '/v1/drivers' + method: get + headers: *member_headers + assert_status: 403 + +drivers_get_observer: + path: '/v1/drivers' + method: get + headers: *observer_headers + assert_status: 200 + +# TODO(TheJulia): This is presently returning a 404, +# except it should not be. :\ +drivers_driver_name_get_admin: path: '/v1/drivers/{driver_name}' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 404 -drivers_properties_get_allow: +drivers_driver_name_get_member: + path: '/v1/drivers/{driver_name}' + method: get + headers: *member_headers + assert_status: 403 + +# TODO(TheJulia): This is presently returning a 404, +# except it should not be. :\ +drivers_driver_name_get_observer: + path: '/v1/drivers/{driver_name}' + method: get + headers: *observer_headers + assert_status: 404 + +drivers_properties_get_admin: path: '/v1/drivers/{driver_name}/properties' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 404 -drivers_raid_logical_disk_properties_get_allow: +drivers_properties_get_member: + path: '/v1/drivers/{driver_name}/properties' + method: get + headers: *member_headers + assert_status: 403 + +drivers_properties_get_observer: + path: '/v1/drivers/{driver_name}/properties' + method: get + headers: *observer_headers + assert_status: 404 + +drivers_raid_logical_disk_properties_get_admin: path: '/v1/drivers/{driver_name}/raid/logical_disk_properties' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 404 + +drivers_raid_logical_disk_properties_get_member: + path: '/v1/drivers/{driver_name}/raid/logical_disk_properties' + method: get + headers: *member_headers + assert_status: 403 + +drivers_raid_logical_disk_properties_get_observer: + path: '/v1/drivers/{driver_name}/raid/logical_disk_properties' + method: get + headers: *observer_headers + assert_status: 404 # Driver vendor passthru - https://docs.openstack.org/api-ref/baremetal/#driver-vendor-passthru-drivers -drivers_vendor_passthru_methods_get_allow: +drivers_vendor_passthru_methods_get_admin: path: '/v1/drivers/{driver_name}/vendor_passthru/methods' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 404 -drivers_vendor_passthru_get_allow: - path: '/v1/drivers/{driver_name}/vendor_passthru' +drivers_vendor_passthru_methods_get_member: + path: '/v1/drivers/{driver_name}/vendor_passthru/methods' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *member_headers + assert_status: 403 -drivers_vendor_passthru_post_allow: - path: '/v1/drivers/{driver_name}/vendor_passthru' +drivers_vendor_passthru_methods_get_observer: + path: '/v1/drivers/{driver_name}/vendor_passthru/methods' + method: get + headers: *observer_headers + assert_status: 403 + +drivers_vendor_passthru_get_admin: + path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' + method: get + headers: *admin_headers + assert_status: 404 + +drivers_vendor_passthru_get_member: + path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' + method: get + headers: *member_headers + assert_status: 403 + +drivers_vendor_passthru_get_observer: + path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' + method: get + headers: *observer_headers + assert_status: 403 + +drivers_vendor_passthru_post_admin: + path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: post - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 404 -drivers_vendor_passthru_put_allow: - path: '/v1/drivers/{driver_name}/vendor_passthru' +drivers_vendor_passthru_post_member: + path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' + method: post + headers: *member_headers + assert_status: 403 + +drivers_vendor_passthru_post_observer: + path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' + method: post + headers: *observer_headers + assert_status: 403 + +drivers_vendor_passthru_put_admin: + path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: put - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 404 -drivers_vendor_passthru_delete_allow: - path: '/v1/drivers/{driver_name}/vendor_passthru' +drivers_vendor_passthru_put_member: + path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' + method: put + headers: *member_headers + assert_status: 403 + +drivers_vendor_passthru_put_observer: + path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' + method: put + headers: *observer_headers + assert_status: 403 + +# NOTE(TheJulia): Returns an error due to the driver name +# not matching, but this should be pass policy checking. +# "No conductors registered." +drivers_vendor_passthru_delete_admin: + path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' method: delete - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 404 + +drivers_vendor_passthru_delete_observer: + path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' + method: delete + headers: *member_headers + assert_status: 403 + +drivers_vendor_passthru_delete_observer: + path: '/v1/drivers/{driver_name}/vendor_passthru?method=test' + method: delete + headers: *observer_headers + assert_status: 403 # Node Bios - https://docs.openstack.org/api-ref/baremetal/#node-bios-nodes -nodes_bios_get_allow: +nodes_bios_get_admin: path: '/v1/nodes/{node_ident}/bios' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -nodes_bios_bios_setting_get_allow: +nodes_bios_get_member: + path: '/v1/nodes/{node_ident}/bios' + method: get + headers: *member_headers + assert_status: 403 + +nodes_bios_get_observer: + path: '/v1/nodes/{node_ident}/bios' + method: get + headers: *observer_headers + assert_status: 200 + +nodes_bios_bios_setting_get_admin: path: '/v1/nodes/{node_ident}/bios/{bios_setting}' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 + +nodes_bios_bios_setting_get_member: + path: '/v1/nodes/{node_ident}/bios/{bios_setting}' + method: get + headers: *member_headers + assert_status: 403 + +nodes_bios_bios_setting_get_observer: + path: '/v1/nodes/{node_ident}/bios/{bios_setting}' + method: get + headers: *observer_headers + assert_status: 200 # Conductors - https://docs.openstack.org/api-ref/baremetal/#allocations-allocations -conductors_get_allow: +conductors_get_admin: path: '/v1/conductors' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -conductors_hostname_get_allow: - path: '/v1/conductors/{hostname}' +conductors_get_member: + path: '/v1/conductors' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *member_headers + assert_status: 403 + +conductors_get_observer: + path: '/v1/conductors' + method: get + headers: *observer_headers + assert_status: 200 + + +conductors_hostname_get_admin: + path: '/v1/conductors/{conductor_ident}' + method: get + headers: *admin_headers + assert_status: 200 + +conductors_hostname_get_member: + path: '/v1/conductors/{conductor_ident}' + method: get + headers: *member_headers + assert_status: 403 + +conductors_hostname_get_observer: + path: '/v1/conductors/{conductor_ident}' + method: get + headers: *observer_headers + assert_status: 200 # Allocations - https://docs.openstack.org/api-ref/baremetal/#allocations-allocations -allocations_post_allow: +allocations_post_admin: path: '/v1/allocations' method: post - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + body: &allocation_body + resource_class: CUSTOM_TEST + assert_status: 503 -allocations_get_allow: +allocations_post_member: + path: '/v1/allocations' + method: post + headers: *member_headers + body: *allocation_body + assert_status: 403 + +allocations_post_observer: + path: '/v1/allocations' + method: post + headers: *observer_headers + body: *allocation_body + assert_status: 403 + +allocations_get_admin: path: '/v1/allocations' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -allocations_allocation_id_get_allow: - path: '/v1/allocations/{allocation_id}' +allocations_get_member: + path: '/v1/allocations' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *member_headers + assert_status: 403 -allocations_allocation_id_patch_allow: - path: '/v1/allocations/{allocation_id}' +allocations_get_observer: + path: '/v1/allocations' + method: get + headers: *observer_headers + assert_status: 200 + +allocations_allocation_id_get_admin: + path: '/v1/allocations/{allocation_ident}' + method: get + headers: *admin_headers + assert_status: 200 + +allocations_allocation_id_get_member: + path: '/v1/allocations/{allocation_ident}' + method: get + headers: *member_headers + assert_status: 403 + +allocations_allocation_id_get_observer: + path: '/v1/allocations/{allocation_ident}' + method: get + headers: *observer_headers + assert_status: 200 + +allocations_allocation_id_patch_admin: + path: '/v1/allocations/{allocation_ident}' method: patch - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + body: &allocation_patch + - op: replace + path: /extra + value: {'test': 'testing'} + assert_status: 200 -allocations_allocation_id_delete_allow: - path: '/v1/allocations/{allocation_id}' +allocations_allocation_id_patch_member: + path: '/v1/allocations/{allocation_ident}' + method: patch + headers: *member_headers + body: *allocation_patch + assert_status: 403 + +allocations_allocation_id_patch_observer: + path: '/v1/allocations/{allocation_ident}' + method: patch + headers: *observer_headers + body: *allocation_patch + assert_status: 403 + +allocations_allocation_id_delete_admin: + path: '/v1/allocations/{allocation_ident}' method: delete - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 + +allocations_allocation_id_delete_member: + path: '/v1/allocations/{allocation_ident}' + method: delete + headers: *member_headers + assert_status: 403 + +allocations_allocation_id_delete_observer: + path: '/v1/allocations/{allocation_ident}' + method: delete + headers: *observer_headers + assert_status: 403 # Allocations ( Node level) - https://docs.openstack.org/api-ref/baremetal/#node-allocation-allocations-nodes -nodes_allocation_get_allow: - path: '/v1/nodes/{node_ident}/allocation' +nodes_allocation_get_admin: + path: '/v1/nodes/{allocated_node_ident}/allocation' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -nodes_allocation_delete_allow: - path: '/v1/nodes/{node_ident}/allocation' +nodes_allocation_get_member: + path: '/v1/nodes/{allocated_node_ident}/allocation' + method: get + headers: *member_headers + assert_status: 403 + +nodes_allocation_get_observer: + path: '/v1/nodes/{allocated_node_ident}/allocation' + method: get + headers: *observer_headers + assert_status: 200 + +nodes_allocation_delete_admin: + path: '/v1/nodes/{allocated_node_ident}/allocation' method: delete - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 503 + +nodes_allocation_delete_member: + path: '/v1/nodes/{allocated_node_ident}/allocation' + method: delete + headers: *member_headers + assert_status: 403 + +nodes_allocation_delete_observer: + path: '/v1/nodes/{allocated_node_ident}/allocation' + method: delete + headers: *observer_headers + assert_status: 403 # Deploy Templates - https://docs.openstack.org/api-ref/baremetal/#deploy-templates-deploy-templates -deploy_templates_post_allow: +deploy_templates_post_admin: path: '/v1/deploy_templates' method: post - skip: true - skip_reason: 'Not implemented yet' + body: &deploy_template_body + name: 'CUSTOM_TEST_TEMPLATE' + steps: + - interface: 'deploy' + step: 'noop' + args: {} + priority: 0 + headers: *admin_headers + assert_status: 201 -deploy_templates_get_allow: +deploy_templates_post_member: + path: '/v1/deploy_templates' + method: post + body: *deploy_template_body + headers: *member_headers + assert_status: 403 + +deploy_templates_post_observer: + path: '/v1/deploy_templates' + method: post + body: *deploy_template_body + headers: *observer_headers + assert_status: 403 + +deploy_templates_get_admin: path: '/v1/deploy_templates' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -deploy_templates_deploy_template_id_get_allow: - path: '/v1/deploy_templates/{deploy_template_id}' +deploy_templates_get_member: + path: '/v1/deploy_templates' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *member_headers + assert_status: 403 -deploy_templates_deploy_template_id_patch_allow: - path: '/v1/deploy_templates/{deploy_template_id}' +deploy_templates_get_observer: + path: '/v1/deploy_templates' + method: get + headers: *observer_headers + assert_status: 200 + +deploy_templates_deploy_template_id_get_admin: + path: '/v1/deploy_templates/{deploy_template_ident}' + method: get + headers: *admin_headers + assert_status: 200 + +deploy_templates_deploy_template_id_get_member: + path: '/v1/deploy_templates/{deploy_template_ident}' + method: get + headers: *member_headers + assert_status: 403 + +deploy_templates_deploy_template_id_get_observer: + path: '/v1/deploy_templates/{deploy_template_ident}' + method: get + headers: *observer_headers + assert_status: 200 + +deploy_templates_deploy_template_id_patch_admin: + path: '/v1/deploy_templates/{deploy_template_ident}' method: patch - skip: true - skip_reason: 'Not implemented yet' + body: &template_patch + - op: replace + path: /name + value: 'CUSTOM_MAGIC' + headers: *admin_headers + assert_status: 200 -deploy_templates_deploy_template_id_delete_allow: - path: '/v1/deploy_templates/{deploy_template_id}' +deploy_templates_deploy_template_id_patch_member: + path: '/v1/deploy_templates/{deploy_template_ident}' + method: patch + body: *template_patch + headers: *member_headers + assert_status: 403 + +deploy_templates_deploy_template_id_patch_observer: + path: '/v1/deploy_templates/{deploy_template_ident}' + method: patch + body: *template_patch + headers: *observer_headers + assert_status: 403 + +deploy_templates_deploy_template_id_delete_admin: + path: '/v1/deploy_templates/{deploy_template_ident}' method: delete - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 204 + +deploy_templates_deploy_template_id_delete_member: + path: '/v1/deploy_templates/{deploy_template_ident}' + method: delete + headers: *member_headers + assert_status: 403 + +deploy_templates_deploy_template_id_delete_observer: + path: '/v1/deploy_templates/{deploy_template_ident}' + method: delete + headers: *observer_headers + assert_status: 403 # Chassis endpoints - https://docs.openstack.org/api-ref/baremetal/#chassis-chassis -chassis_post_allow: +chassis_post_admin: path: '/v1/chassis' method: post - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + body: &chassis_body + description: 'test-chassis' + assert_status: 201 -chassis_get_allow: +chassis_post_member: + path: '/v1/chassis' + method: post + headers: *member_headers + body: *chassis_body + assert_status: 403 + +chassis_post_observer: + path: '/v1/chassis' + method: post + headers: *observer_headers + body: *chassis_body + assert_status: 403 + +chassis_get_admin: path: '/v1/chassis' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -chassis_detail_get_allow: +chassis_get_member: + path: '/v1/chassis' + method: get + headers: *member_headers + assert_status: 403 + +chassis_get_observer: + path: '/v1/chassis' + method: get + headers: *observer_headers + assert_status: 200 + +chassis_detail_get_admin: path: '/v1/chassis/detail' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 200 -chassis_chassis_id_get_allow: - path: '/v1/chassis/{chassis_id}' +chassis_detail_get_member: + path: '/v1/chassis/detail' method: get - skip: true - skip_reason: 'Not implemented yet' + headers: *member_headers + assert_status: 403 -chassis_chassis_id_patch_allow: - path: '/v1/chassis/{chassis_id}' +chassis_detail_get_observer: + path: '/v1/chassis/detail' + method: get + headers: *observer_headers + assert_status: 200 + +chassis_chassis_id_get_admin: + path: '/v1/chassis/{chassis_ident}' + method: get + headers: *admin_headers + assert_status: 200 + +chassis_chassis_id_get_member: + path: '/v1/chassis/{chassis_ident}' + method: get + headers: *member_headers + assert_status: 403 + +chassis_chassis_id_get_observer: + path: '/v1/chassis/{chassis_ident}' + method: get + headers: *observer_headers + assert_status: 200 + +chassis_chassis_id_patch_admin: + path: '/v1/chassis/{chassis_ident}' method: patch - skip: true - skip_reason: 'Not implemented yet' + body: &chassis_patch + - op: replace + path: /description + value: meow + headers: *admin_headers + assert_status: 200 -chassis_chassis_id_delete_allow: - path: '/v1/chassis/{chassis_id}' +chassis_chassis_id_patch_member: + path: '/v1/chassis/{chassis_ident}' + method: patch + body: *chassis_patch + headers: *member_headers + assert_status: 403 + +chassis_chassis_id_patch_observer: + path: '/v1/chassis/{chassis_ident}' + method: patch + body: *chassis_patch + headers: *observer_headers + assert_status: 403 + +chassis_chassis_id_delete_admin: + path: '/v1/chassis/{chassis_ident}' method: delete - skip: true - skip_reason: 'Not implemented yet' + headers: *admin_headers + assert_status: 204 + +chassis_chassis_id_delete_member: + path: '/v1/chassis/{chassis_ident}' + method: delete + headers: *member_headers + assert_status: 403 + +chassis_chassis_id_delete_observer: + path: '/v1/chassis/{chassis_ident}' + method: delete + headers: *observer_headers + assert_status: 403