blob: d3c63deaaf21e7583befca61d8892773c405fc67 [file] [log] [blame]
lkuchlan7b2566a2021-04-14 10:31:31 +03001# Copyright 2022 Red Hat, Inc.
2# All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License"); you may
5# not use this file except in compliance with the License. You may obtain
6# a copy of the License at
7#
8# http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13# License for the specific language governing permissions and limitations
14# under the License.
15
16
17from tempest import clients
18from tempest import config
19from tempest.lib import auth
20from tempest.lib.common.utils import data_utils
21from tempest.lib.common.utils import test_utils
22
23from manila_tempest_tests.common import waiters
24
25CONF = config.CONF
26
27
28class ShareRbacBaseTests(object):
29
30 identity_version = 'v3'
31 protocols = ['nfs', 'cifs', 'glusterfs', 'hdfs', 'cephfs', 'maprfs']
32
33 @classmethod
34 def skip_checks(cls):
35 super(ShareRbacBaseTests, cls).skip_checks()
36 if not CONF.enforce_scope.manila:
37 raise cls.skipException(
38 "Tempest is not configured to enforce_scope for manila, "
39 "skipping RBAC tests. To enable these tests set "
40 "`tempest.conf [enforce_scope] manila=True`."
41 )
42 if not CONF.share.default_share_type_name:
43 raise cls.skipException("Secure rbac tests require a default "
44 "share type")
45 if not any(p in CONF.share.enable_protocols for p in cls.protocols):
46 message = "%s tests are disabled" % cls.protocol
47 raise cls.skipException(message)
48
49 @classmethod
50 def delete_resource(cls, client, **kwargs):
51 key_names = {
52 'st': 'share_type',
53 'sn': 'share_network',
54 }
55 key, resource_id = list(kwargs.items())[0]
lkuchlan796f3eb2022-11-24 14:05:01 +020056 key = key.rsplit('_', 1)[0]
lkuchlan7b2566a2021-04-14 10:31:31 +030057 resource_name = key_names[key] if key in key_names else key
58
59 del_action = getattr(client, 'delete_{}'.format(resource_name))
60 test_utils.call_and_ignore_notfound_exc(
61 del_action, resource_id)
62 test_utils.call_and_ignore_notfound_exc(
63 client.wait_for_resource_deletion, **kwargs)
64
65 @classmethod
66 def create_share(cls, client, share_type_id, size=None, name=None,
67 metadata=None):
68 kwargs = {}
69 name = name or data_utils.rand_name('share')
70 metadata = metadata or {}
71 kwargs.update({
72 'share_protocol': cls.protocol,
73 'size': size or CONF.share.share_size,
74 'name': name or data_utils.rand_name('share'),
75 'share_type_id': share_type_id,
76 'metadata': metadata,
77 })
78 share = client.create_share(**kwargs)['share']
79 waiters.wait_for_resource_status(client, share['id'], 'available')
80 cls.addClassResourceCleanup(
81 cls.delete_resource, client,
82 share_id=share['id'])
83 return share
84
85 @classmethod
lkuchlan5bd5f542022-11-02 12:22:56 +020086 def create_snapshot(cls, client, share_id, name=None, metadata=None):
lkuchlan7b2566a2021-04-14 10:31:31 +030087 name = name or data_utils.rand_name('snapshot')
lkuchlan5bd5f542022-11-02 12:22:56 +020088 snapshot = client.create_snapshot(
89 share_id, name=name, metadata=metadata)['snapshot']
lkuchlan7b2566a2021-04-14 10:31:31 +030090 waiters.wait_for_resource_status(
91 client, snapshot['id'], 'available', resource_name='snapshot')
92 cls.addClassResourceCleanup(
93 cls.delete_resource, client, snapshot_id=snapshot['id'])
94 return snapshot
95
96 @classmethod
97 def create_share_network(cls, client, name=None):
98 name = name or data_utils.rand_name('share_network')
99 share_network = client.create_share_network(name=name)['share_network']
100
101 cls.addClassResourceCleanup(
102 cls.delete_resource, client, sn_id=share_network['id'])
103 return share_network
104
105 @classmethod
lkuchlan4db10d42022-11-22 12:05:47 +0200106 def create_share_type(cls):
107 name = data_utils.rand_name('share-type')
108 extra_specs = {
109 'driver_handles_share_servers': CONF.share.multitenancy_enabled,
110 }
111 share_type = cls.admin_shares_v2_client.create_share_type(
112 name=name, extra_specs=extra_specs)['share_type']
113 cls.addClassResourceCleanup(
114 cls.delete_resource, cls.admin_shares_v2_client,
115 st_id=share_type['id'])
116 return share_type
117
118 @classmethod
lkuchlan796f3eb2022-11-24 14:05:01 +0200119 def create_share_group_type(cls, share_types, is_public=True,
120 group_specs=None):
121 name = data_utils.rand_name('share-group-type')
122 share_group_type = (
123 cls.admin_shares_v2_client.create_share_group_type(
124 name=name, share_types=share_types, is_public=is_public,
125 group_specs=group_specs))['share_group_type']
126 cls.addClassResourceCleanup(
127 cls.delete_resource, cls.admin_shares_v2_client,
128 share_group_type_id=share_group_type['id'])
129 return share_group_type
130
131 @classmethod
lkuchlan0f7345a2022-12-12 14:11:07 +0200132 def create_share_group(cls, client, share_group_type_id, share_type_ids):
133 name = data_utils.rand_name('share-group')
134 share_group = client.create_share_group(
135 name=name, share_group_type_id=share_group_type_id,
136 share_type_ids=share_type_ids)['share_group']
137 waiters.wait_for_resource_status(
138 client, share_group['id'], 'available',
139 resource_name='share_group')
140 cls.addClassResourceCleanup(
141 cls.delete_resource, client,
142 share_group_id=share_group['id'])
143 return share_group
144
145 @classmethod
lkuchlan7b2566a2021-04-14 10:31:31 +0300146 def get_share_type(cls):
147 return cls.shares_v2_client.get_default_share_type()['share_type']
148
149 def do_request(self, method, expected_status=200, client=None, **payload):
150 if not client:
151 client = self.client
152 if isinstance(expected_status, type(Exception)):
153 self.assertRaises(expected_status,
154 getattr(client, method),
155 **payload)
156 else:
157 response = getattr(client, method)(**payload)
158 self.assertEqual(response.response.status, expected_status)
159 return response
160
161 @classmethod
162 def setup_user_client(cls, client, project_id=None):
163 """Set up project user with its own client.
164
165 This is useful for testing protection of resources in separate
166 projects.
167 NOTE(lkuchlan): Tempest creates 'project_member' and 'project_reader'
168 dynamic credentials in different projects. So this method is also
169 necessary for testing protection of resources in a specific project.
170
171 Returns a client object and the user's ID.
172 """
173
174 projects_client = client.identity_v3.ProjectsClient()
175 users_client = client.identity_v3.UsersClient()
176 roles_client = client.identity_v3.RolesClient()
177
178 user_dict = {
179 'name': data_utils.rand_name('user'),
180 'password': data_utils.rand_password(),
181 }
182 user_id = users_client.create_user(
183 **user_dict)['user']['id']
184 cls.addClassResourceCleanup(users_client.delete_user, user_id)
185
186 if not project_id:
187 project_id = projects_client.create_project(
188 data_utils.rand_name())['project']['id']
189 cls.addClassResourceCleanup(
190 projects_client.delete_project,
191 project_id)
192
193 member_role_id = roles_client.list_roles(
194 name='member')['roles'][0]['id']
195 roles_client.create_user_role_on_project(
196 project_id, user_id, member_role_id)
197 creds = auth.KeystoneV3Credentials(
198 user_id=user_id,
199 password=user_dict['password'],
200 project_id=project_id)
201 auth_provider = clients.get_auth_provider(creds)
202 creds = auth_provider.fill_credentials()
203 client = clients.Manager(credentials=creds)
204 return client