blob: 2d486a7ac9ffabfa9f644dadf40cfee78c21a366 [file] [log] [blame]
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +01001# Copyright (c) 2014 Hewlett-Packard Development Company, L.P.
2# Licensed under the Apache License, Version 2.0 (the "License");
3# you may not use this file except in compliance with the License.
4# You may obtain a copy of the License at
5#
6# http://www.apache.org/licenses/LICENSE-2.0
7#
8# Unless required by applicable law or agreed to in writing, software
9# distributed under the License is distributed on an "AS IS" BASIS,
10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11# See the License for the specific language governing permissions and
12# limitations under the License.
13
Andrea Frittoli (andreaf)848e3482015-10-12 14:17:21 +010014from oslo_concurrency import lockutils
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +010015
16from tempest import clients
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +010017from tempest import config
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050018from tempest.lib import auth
Matthew Treinishc51b7122017-07-17 12:28:07 -040019from tempest.lib.common import dynamic_creds
Matthew Treinishb19c55d2017-07-17 12:38:35 -040020from tempest.lib.common import preprov_creds
Matthew Treinish4217a702016-10-07 17:27:11 -040021from tempest.lib import exceptions
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +010022
23CONF = config.CONF
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +010024
25
26"""This module provides factories of credential and credential providers
27
Andrea Frittoli (andreaf)1370baf2016-04-29 14:26:22 -050028Credentials providers and clients are (going to be) part of tempest.lib,
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +010029and so they may not hold any dependency to tempest configuration.
30
31Methods in this module collect the relevant configuration details and pass
32them to credentials providers and clients, so that test can have easy
33access to these features.
34
35Client managers with hard-coded configured credentials are also moved here,
36to avoid circular dependencies."""
37
38# === Credential Providers
39
40
Andrea Frittoli (andreaf)848e3482015-10-12 14:17:21 +010041# Subset of the parameters of credential providers that depend on configuration
Andrea Frittolid199caf2017-07-18 17:12:38 +010042def _get_common_provider_params(identity_version):
Andrea Frittolidcd91002017-07-18 11:34:13 +010043 if identity_version == 'v3':
44 identity_uri = CONF.identity.uri_v3
45 elif identity_version == 'v2':
46 identity_uri = CONF.identity.uri
Andrea Frittoli17347f02017-07-26 16:18:30 +010047 else:
48 raise exceptions.InvalidIdentityVersion(
49 identity_version=identity_version)
Andrea Frittoli (andreaf)848e3482015-10-12 14:17:21 +010050 return {
Andrea Frittolid199caf2017-07-18 17:12:38 +010051 'identity_version': identity_version,
Andrea Frittolidcd91002017-07-18 11:34:13 +010052 'identity_uri': identity_uri,
Andrea Frittoli (andreaf)848e3482015-10-12 14:17:21 +010053 'credentials_domain': CONF.auth.default_credentials_domain_name,
54 'admin_role': CONF.identity.admin_role
55 }
56
57
Andrea Frittolid199caf2017-07-18 17:12:38 +010058def get_dynamic_provider_params(identity_version, admin_creds=None):
59 """Dynamic provider parameters setup from config
60
61 This helper returns a dict of parameter that can be used to initialise
62 a `DynamicCredentialProvider` according to tempest configuration.
63 Parameters that are not configuration specific (name, network_resources)
64 are not returned.
65
66 :param identity_version: 'v2' or 'v3'
67 :param admin_creds: An object of type `auth.Credentials`. If None, it
68 is built from the configuration file as well.
junboli4ddc5ee2017-07-28 09:23:05 +080069 :return: A dict with the parameters
Andrea Frittolid199caf2017-07-18 17:12:38 +010070 """
71 _common_params = _get_common_provider_params(identity_version)
72 admin_creds = admin_creds or get_configured_admin_credentials(
73 fill_in=True, identity_version=identity_version)
Andrea Frittolidcd91002017-07-18 11:34:13 +010074 if identity_version == 'v3':
75 endpoint_type = CONF.identity.v3_endpoint_type
76 elif identity_version == 'v2':
77 endpoint_type = CONF.identity.v2_admin_endpoint_type
Andrea Frittolid199caf2017-07-18 17:12:38 +010078 return dict(_common_params, **dict([
79 ('admin_creds', admin_creds),
80 ('identity_admin_domain_scope', CONF.identity.admin_domain_scope),
81 ('identity_admin_role', CONF.identity.admin_role),
82 ('extra_roles', CONF.auth.tempest_roles),
83 ('neutron_available', CONF.service_available.neutron),
84 ('project_network_cidr', CONF.network.project_network_cidr),
85 ('project_network_mask_bits', CONF.network.project_network_mask_bits),
86 ('public_network_id', CONF.network.public_network_id),
87 ('create_networks', (CONF.auth.create_isolated_networks and not
88 CONF.network.shared_physical_network)),
ghanshyamb20f7e62017-12-10 07:10:22 +030089 ('resource_prefix', 'tempest'),
Andrea Frittolidcd91002017-07-18 11:34:13 +010090 ('identity_admin_endpoint_type', endpoint_type)
Andrea Frittolid199caf2017-07-18 17:12:38 +010091 ]))
Andrea Frittoli (andreaf)848e3482015-10-12 14:17:21 +010092
93
Andrea Frittolid199caf2017-07-18 17:12:38 +010094def get_preprov_provider_params(identity_version):
95 """Pre-provisioned provider parameters setup from config
96
97 This helper returns a dict of parameter that can be used to initialise
98 a `PreProvisionedCredentialProvider` according to tempest configuration.
99 Parameters that are not configuration specific (name) are not returned.
100
101 :param identity_version: 'v2' or 'v3'
junboli4ddc5ee2017-07-28 09:23:05 +0800102 :return: A dict with the parameters
Andrea Frittolid199caf2017-07-18 17:12:38 +0100103 """
104 _common_params = _get_common_provider_params(identity_version)
Andrea Frittoli (andreaf)848e3482015-10-12 14:17:21 +0100105 reseller_admin_role = CONF.object_storage.reseller_admin_role
106 return dict(_common_params, **dict([
107 ('accounts_lock_dir', lockutils.get_lock_path(CONF)),
108 ('test_accounts_file', CONF.auth.test_accounts_file),
109 ('object_storage_operator_role', CONF.object_storage.operator_role),
110 ('object_storage_reseller_admin_role', reseller_admin_role)
111 ]))
112
113
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100114def get_credentials_provider(name, network_resources=None,
115 force_tenant_isolation=False,
116 identity_version=None):
Andrea Frittolid199caf2017-07-18 17:12:38 +0100117 """Return the right implementation of CredentialProvider based on config
118
119 This helper returns the right implementation of CredentialProvider based on
120 config and on the value of force_tenant_isolation.
121
122 :param name: When provided, it makes it possible to associate credential
123 artifacts back to the owner (test class).
124 :param network_resources: Dictionary of network resources to be allocated
125 for each test account. Only valid for the dynamic
126 credentials provider.
127 :param force_tenant_isolation: Always return a `DynamicCredentialProvider`,
128 regardless of the configuration.
129 :param identity_version: Use the specified identity API version, regardless
130 of the configuration. Valid values are 'v2', 'v3'.
131 """
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100132 # If a test requires a new account to work, it can have it via forcing
133 # dynamic credentials. A new account will be produced only for that test.
134 # In case admin credentials are not available for the account creation,
135 # the test should be skipped else it would fail.
136 identity_version = identity_version or CONF.identity.auth_version
137 if CONF.auth.use_dynamic_credentials or force_tenant_isolation:
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100138 return dynamic_creds.DynamicCredentialProvider(
139 name=name,
140 network_resources=network_resources,
Andrea Frittolid199caf2017-07-18 17:12:38 +0100141 **get_dynamic_provider_params(identity_version))
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100142 else:
Matthew Treinishd89db1b2015-12-16 17:29:14 -0500143 if CONF.auth.test_accounts_file:
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100144 # Most params are not relevant for pre-created accounts
145 return preprov_creds.PreProvisionedCredentialProvider(
Andrea Frittolid199caf2017-07-18 17:12:38 +0100146 name=name,
147 **get_preprov_provider_params(identity_version))
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100148 else:
Matthew Treinish40847ac2016-01-04 13:16:03 -0500149 raise exceptions.InvalidConfiguration(
150 'A valid credential provider is needed')
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100151
152
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100153def is_admin_available(identity_version):
Andrea Frittoli00c35882017-07-19 13:35:27 +0100154 """Helper to check for admin credentials
155
156 Helper function to check if a set of admin credentials is available so we
157 can do a single call from skip_checks.
158 This helper depends on identity_version as there may be admin credentials
159 available for v2 but not for v3.
160
161 :param identity_version: 'v2' or 'v3'
162 """
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100163 is_admin = True
164 # If dynamic credentials is enabled admin will be available
165 if CONF.auth.use_dynamic_credentials:
166 return is_admin
167 # Check whether test accounts file has the admin specified or not
Matthew Treinishd89db1b2015-12-16 17:29:14 -0500168 elif CONF.auth.test_accounts_file:
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100169 check_accounts = preprov_creds.PreProvisionedCredentialProvider(
Andrea Frittolid199caf2017-07-18 17:12:38 +0100170 name='check_admin',
171 **get_preprov_provider_params(identity_version))
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100172 if not check_accounts.admin_available():
173 is_admin = False
174 else:
175 try:
Andrea Frittoli (andreaf)bc0a7a62016-05-26 19:31:49 +0100176 get_configured_admin_credentials(fill_in=False,
177 identity_version=identity_version)
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100178 except exceptions.InvalidConfiguration:
179 is_admin = False
180 return is_admin
181
182
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100183def is_alt_available(identity_version):
Andrea Frittoli00c35882017-07-19 13:35:27 +0100184 """Helper to check for alt credentials
185
186 Helper function to check if a second set of credentials is available (aka
187 alt credentials) so we can do a single call from skip_checks.
188 This helper depends on identity_version as there may be alt credentials
189 available for v2 but not for v3.
190
191 :param identity_version: 'v2' or 'v3'
192 """
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100193 # If dynamic credentials is enabled alt will be available
194 if CONF.auth.use_dynamic_credentials:
195 return True
196 # Check whether test accounts file has the admin specified or not
Matthew Treinishd89db1b2015-12-16 17:29:14 -0500197 if CONF.auth.test_accounts_file:
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100198 check_accounts = preprov_creds.PreProvisionedCredentialProvider(
Andrea Frittolid199caf2017-07-18 17:12:38 +0100199 name='check_alt',
200 **get_preprov_provider_params(identity_version))
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100201 else:
Matthew Treinish40847ac2016-01-04 13:16:03 -0500202 raise exceptions.InvalidConfiguration(
203 'A valid credential provider is needed')
204
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100205 try:
206 if not check_accounts.is_multi_user():
207 return False
208 else:
209 return True
210 except exceptions.InvalidConfiguration:
211 return False
212
Stephen Finucane7f4a6212018-07-06 13:58:21 +0100213
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100214# === Credentials
215
216# Type of credentials available from configuration
217CREDENTIAL_TYPES = {
218 'identity_admin': ('auth', 'admin'),
219 'user': ('identity', None),
220 'alt_user': ('identity', 'alt')
221}
222
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100223
Andrea Frittoli (andreaf)bc0a7a62016-05-26 19:31:49 +0100224def get_configured_admin_credentials(fill_in=True, identity_version=None):
Andrea Frittoli00c35882017-07-19 13:35:27 +0100225 """Get admin credentials from the config file
226
227 Read credentials from configuration, builds a Credentials object based on
228 the specified or configured version
229
230 :param fill_in: If True, a request to the Token API is submitted, and the
231 credential object is filled in with all names and IDs from
232 the token API response.
233 :param identity_version: The identity version to talk to and the type of
234 credentials object to be created. 'v2' or 'v3'.
235 :returns: An object of a sub-type of `auth.Credentials`
236 """
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100237 identity_version = identity_version or CONF.identity.auth_version
238
239 if identity_version not in ('v2', 'v3'):
240 raise exceptions.InvalidConfiguration(
241 'Unsupported auth version: %s' % identity_version)
242
Andrea Frittoli (andreaf)bc0a7a62016-05-26 19:31:49 +0100243 conf_attributes = ['username', 'password',
244 'project_name']
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100245
246 if identity_version == 'v3':
247 conf_attributes.append('domain_name')
Colleen Murphycd0bbbd2019-10-01 16:18:36 -0700248 conf_attributes.append('user_domain_name')
249 conf_attributes.append('project_domain_name')
250 conf_attributes.append('system')
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100251 # Read the parts of credentials from config
Andrea Frittolicad70e22017-08-16 13:19:04 +0100252 params = config.service_client_config()
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100253 for attr in conf_attributes:
Andrea Frittoli (andreaf)bc0a7a62016-05-26 19:31:49 +0100254 params[attr] = getattr(CONF.auth, 'admin_' + attr)
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100255 # Build and validate credentials. We are reading configured credentials,
256 # so validate them even if fill_in is False
257 credentials = get_credentials(fill_in=fill_in,
258 identity_version=identity_version, **params)
259 if not fill_in:
260 if not credentials.is_valid():
Andrea Frittoli (andreaf)bc0a7a62016-05-26 19:31:49 +0100261 msg = ("The admin credentials are incorrectly set in the config "
262 "file for identity version %s. Double check that all "
263 "required values are assigned.")
264 raise exceptions.InvalidConfiguration(msg % identity_version)
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100265 return credentials
266
267
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100268def get_credentials(fill_in=True, identity_version=None, **kwargs):
Andrea Frittoli00c35882017-07-19 13:35:27 +0100269 """Get credentials from dict based on config
270
271 Wrapper around auth.get_credentials to use the configured identity version
272 if none is specified.
273
274 :param fill_in: If True, a request to the Token API is submitted, and the
275 credential object is filled in with all names and IDs from
276 the token API response.
277 :param identity_version: The identity version to talk to and the type of
278 credentials object to be created. 'v2' or 'v3'.
279 :param kwargs: Attributes to be used to build the Credentials object.
280 :returns: An object of a sub-type of `auth.Credentials`
281 """
Andrea Frittolicad70e22017-08-16 13:19:04 +0100282 params = dict(config.service_client_config(), **kwargs)
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100283 identity_version = identity_version or CONF.identity.auth_version
284 # In case of "v3" add the domain from config if not specified
Andrea Frittoli (andreaf)100d18d2016-05-05 23:34:52 +0100285 # To honour the "default_credentials_domain_name", if not domain
286 # field is specified at all, add it the credential dict.
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100287 if identity_version == 'v3':
288 domain_fields = set(x for x in auth.KeystoneV3Credentials.ATTRIBUTES
289 if 'domain' in x)
Colleen Murphycd0bbbd2019-10-01 16:18:36 -0700290 if (not params.get('system') and
291 not domain_fields.intersection(kwargs.keys())):
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100292 domain_name = CONF.auth.default_credentials_domain_name
Andrea Frittoli (andreaf)100d18d2016-05-05 23:34:52 +0100293 # NOTE(andreaf) Setting domain_name implicitly sets user and
294 # project domain names, if they are None
295 params['domain_name'] = domain_name
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100296
297 auth_url = CONF.identity.uri_v3
298 else:
299 auth_url = CONF.identity.uri
300 return auth.get_credentials(auth_url,
301 fill_in=fill_in,
302 identity_version=identity_version,
303 **params)
304
305# === Credential / client managers
306
307
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100308class AdminManager(clients.Manager):
Ken'ichi Ohmichicb67d2d2015-11-19 08:23:22 +0000309 """Manager that uses admin credentials for its managed client objects"""
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100310
Jordan Pittiere4be9072017-01-04 19:17:35 +0100311 def __init__(self):
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +0100312 super(AdminManager, self).__init__(
Jordan Pittiere4be9072017-01-04 19:17:35 +0100313 credentials=get_configured_admin_credentials())