blob: 486b7fd19fd8329632e17edfab5e4228f2a19b35 [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
14import os
15
16from oslo_log import log as logging
17from tempest_lib import auth
18
19from tempest import clients
20from tempest.common import cred_provider
21from tempest.common import dynamic_creds
22from tempest.common import preprov_creds
23from tempest import config
24from tempest import exceptions
25
26CONF = config.CONF
27LOG = logging.getLogger(__name__)
28
29
30"""This module provides factories of credential and credential providers
31
32Credentials providers and clients are (going to be) part of tempest-lib,
33and so they may not hold any dependency to tempest configuration.
34
35Methods in this module collect the relevant configuration details and pass
36them to credentials providers and clients, so that test can have easy
37access to these features.
38
39Client managers with hard-coded configured credentials are also moved here,
40to avoid circular dependencies."""
41
42# === Credential Providers
43
44
45class LegacyCredentialProvider(cred_provider.CredentialProvider):
46
47 def __init__(self, identity_version):
48 """Credentials provider which returns credentials from tempest.conf
49
50 Credentials provider which always returns the first and second
51 configured accounts as primary and alt users.
52 Credentials from tempest.conf are deprecated, and this credential
53 provider is also accordingly.
54
55 This credential provider can be used in case of serial test execution
56 to preserve the current behaviour of the serial tempest run.
57
58 :param identity_version: Version of the identity API
59 :return: CredentialProvider
60 """
61 super(LegacyCredentialProvider, self).__init__(
62 identity_version=identity_version)
63 self._creds = {}
64
65 def _unique_creds(self, cred_arg=None):
66 """Verify that the configured credentials are valid and distinct """
67 try:
68 user = self.get_primary_creds()
69 alt_user = self.get_alt_creds()
70 return getattr(user, cred_arg) != getattr(alt_user, cred_arg)
71 except exceptions.InvalidCredentials as ic:
72 msg = "At least one of the configured credentials is " \
73 "not valid: %s" % ic.message
74 raise exceptions.InvalidConfiguration(msg)
75
76 def is_multi_user(self):
77 return self._unique_creds('username')
78
79 def is_multi_tenant(self):
80 return self._unique_creds('tenant_id')
81
82 def get_primary_creds(self):
83 if self._creds.get('primary'):
84 return self._creds.get('primary')
85 primary_credential = get_configured_credentials(
86 credential_type='user', fill_in=False,
87 identity_version=self.identity_version)
88 self._creds['primary'] = cred_provider.TestResources(
89 primary_credential)
90 return self._creds['primary']
91
92 def get_alt_creds(self):
93 if self._creds.get('alt'):
94 return self._creds.get('alt')
95 alt_credential = get_configured_credentials(
96 credential_type='alt_user', fill_in=False,
97 identity_version=self.identity_version)
98 self._creds['alt'] = cred_provider.TestResources(
99 alt_credential)
100 return self._creds['alt']
101
102 def clear_creds(self):
103 self._creds = {}
104
105 def get_admin_creds(self):
106 if self._creds.get('admin'):
107 return self._creds.get('admin')
108 creds = get_configured_credentials(
109 "identity_admin", fill_in=False)
110 self._creds['admin'] = cred_provider.TestResources(creds)
111 return self._creds['admin']
112
113 def get_creds_by_roles(self, roles, force_new=False):
114 msg = "Credentials being specified through the config file can not be"\
115 " used with tests that specify using credentials by roles. "\
116 "Either exclude/skip the tests doing this or use either an "\
117 "test_accounts_file or dynamic credentials."
118 raise exceptions.InvalidConfiguration(msg)
119
120 def is_role_available(self, role):
121 msg = "Credentials being specified through the config file can not be"\
122 " used with tests that specify using credentials by roles. "\
123 "Either exclude/skip the tests doing this or use either an "\
124 "test_accounts_file or dynamic credentials."
125 raise exceptions.InvalidConfiguration(msg)
126
127
128# Return the right implementation of CredentialProvider based on config
129# Dropping interface and password, as they are never used anyways
130# TODO(andreaf) Drop them from the CredentialsProvider interface completely
131def get_credentials_provider(name, network_resources=None,
132 force_tenant_isolation=False,
133 identity_version=None):
134 # If a test requires a new account to work, it can have it via forcing
135 # dynamic credentials. A new account will be produced only for that test.
136 # In case admin credentials are not available for the account creation,
137 # the test should be skipped else it would fail.
138 identity_version = identity_version or CONF.identity.auth_version
139 if CONF.auth.use_dynamic_credentials or force_tenant_isolation:
140 admin_creds = get_configured_credentials(
141 'identity_admin', fill_in=True, identity_version=identity_version)
142 return dynamic_creds.DynamicCredentialProvider(
143 name=name,
144 network_resources=network_resources,
145 identity_version=identity_version,
146 credentials_domain=CONF.auth.default_credentials_domain_name,
147 admin_role=CONF.identity.admin_role,
148 admin_creds=admin_creds)
149 else:
150 if (CONF.auth.test_accounts_file and
151 os.path.isfile(CONF.auth.test_accounts_file)):
152 # Most params are not relevant for pre-created accounts
153 return preprov_creds.PreProvisionedCredentialProvider(
154 name=name, identity_version=identity_version,
155 credentials_domain=CONF.auth.default_credentials_domain_name,
156 admin_role=CONF.identity.admin_role)
157 else:
158 # Dynamic credentials are disabled, and the account file is not
159 # defined - we fall back on credentials configured in tempest.conf
160 return LegacyCredentialProvider(identity_version=identity_version)
161
162
163# We want a helper function here to check and see if admin credentials
164# are available so we can do a single call from skip_checks if admin
165# creds area available.
166# This depends on identity_version as there may be admin credentials
167# available for v2 but not for v3.
168def is_admin_available(identity_version):
169 is_admin = True
170 # If dynamic credentials is enabled admin will be available
171 if CONF.auth.use_dynamic_credentials:
172 return is_admin
173 # Check whether test accounts file has the admin specified or not
174 elif (CONF.auth.test_accounts_file and
175 os.path.isfile(CONF.auth.test_accounts_file)):
176 check_accounts = preprov_creds.PreProvisionedCredentialProvider(
177 identity_version=identity_version, name='check_admin',
178 admin_role=CONF.identity.admin_role)
179 if not check_accounts.admin_available():
180 is_admin = False
181 else:
182 try:
183 get_configured_credentials('identity_admin', fill_in=False,
184 identity_version=identity_version)
185 except exceptions.InvalidConfiguration:
186 is_admin = False
187 return is_admin
188
189
190# We want a helper function here to check and see if alt credentials
191# are available so we can do a single call from skip_checks if alt
192# creds area available.
193# This depends on identity_version as there may be alt credentials
194# available for v2 but not for v3.
195def is_alt_available(identity_version):
196 # If dynamic credentials is enabled alt will be available
197 if CONF.auth.use_dynamic_credentials:
198 return True
199 # Check whether test accounts file has the admin specified or not
200 if (CONF.auth.test_accounts_file and
201 os.path.isfile(CONF.auth.test_accounts_file)):
202 check_accounts = preprov_creds.PreProvisionedCredentialProvider(
203 identity_version=identity_version, name='check_alt',
204 admin_role=CONF.identity.admin_role)
205 else:
206 check_accounts = LegacyCredentialProvider(identity_version)
207 try:
208 if not check_accounts.is_multi_user():
209 return False
210 else:
211 return True
212 except exceptions.InvalidConfiguration:
213 return False
214
215# === Credentials
216
217# Type of credentials available from configuration
218CREDENTIAL_TYPES = {
219 'identity_admin': ('auth', 'admin'),
220 'user': ('identity', None),
221 'alt_user': ('identity', 'alt')
222}
223
224DEFAULT_PARAMS = {
225 'disable_ssl_certificate_validation':
226 CONF.identity.disable_ssl_certificate_validation,
227 'ca_certs': CONF.identity.ca_certificates_file,
228 'trace_requests': CONF.debug.trace_requests
229}
230
231
232# Read credentials from configuration, builds a Credentials object
233# based on the specified or configured version
234def get_configured_credentials(credential_type, fill_in=True,
235 identity_version=None):
236 identity_version = identity_version or CONF.identity.auth_version
237
238 if identity_version not in ('v2', 'v3'):
239 raise exceptions.InvalidConfiguration(
240 'Unsupported auth version: %s' % identity_version)
241
242 if credential_type not in CREDENTIAL_TYPES:
243 raise exceptions.InvalidCredentials()
244 conf_attributes = ['username', 'password', 'tenant_name']
245
246 if identity_version == 'v3':
247 conf_attributes.append('domain_name')
248 # Read the parts of credentials from config
249 params = DEFAULT_PARAMS.copy()
250 section, prefix = CREDENTIAL_TYPES[credential_type]
251 for attr in conf_attributes:
252 _section = getattr(CONF, section)
253 if prefix is None:
254 params[attr] = getattr(_section, attr)
255 else:
256 params[attr] = getattr(_section, prefix + "_" + attr)
257 # Build and validate credentials. We are reading configured credentials,
258 # so validate them even if fill_in is False
259 credentials = get_credentials(fill_in=fill_in,
260 identity_version=identity_version, **params)
261 if not fill_in:
262 if not credentials.is_valid():
263 msg = ("The %s credentials are incorrectly set in the config file."
264 " Double check that all required values are assigned" %
265 credential_type)
266 raise exceptions.InvalidConfiguration(msg)
267 return credentials
268
269
270# Wrapper around auth.get_credentials to use the configured identity version
271# is none is specified
272def get_credentials(fill_in=True, identity_version=None, **kwargs):
273 params = dict(DEFAULT_PARAMS, **kwargs)
274 identity_version = identity_version or CONF.identity.auth_version
275 # In case of "v3" add the domain from config if not specified
276 if identity_version == 'v3':
277 domain_fields = set(x for x in auth.KeystoneV3Credentials.ATTRIBUTES
278 if 'domain' in x)
279 if not domain_fields.intersection(kwargs.keys()):
280 domain_name = CONF.auth.default_credentials_domain_name
281 params['user_domain_name'] = domain_name
282
283 auth_url = CONF.identity.uri_v3
284 else:
285 auth_url = CONF.identity.uri
286 return auth.get_credentials(auth_url,
287 fill_in=fill_in,
288 identity_version=identity_version,
289 **params)
290
291# === Credential / client managers
292
293
294class ConfiguredUserManager(clients.Manager):
295 """
296 Manager object that uses the `user` credentials for its
297 managed client objects
298 """
299
300 def __init__(self, service=None):
301 super(ConfiguredUserManager, self).__init__(
302 credentials=get_configured_credentials('user'),
303 service=service)
304
305
306class AdminManager(clients.Manager):
307
308 """
309 Manager object that uses the admin credentials for its
310 managed client objects
311 """
312
313 def __init__(self, service=None):
314 super(AdminManager, self).__init__(
315 credentials=get_configured_credentials('identity_admin'),
316 service=service)