blob: 8b015cd731411bfa5780a9f7778d585533c1bbec [file] [log] [blame]
ZhiQiang Fan39f97222013-09-20 04:49:44 +08001# Copyright 2012 OpenStack Foundation
Jay Pipes051075a2012-04-28 17:39:37 -04002# 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
Attila Fazekasf86fa312013-07-30 19:56:39 +020016import atexit
Masayuki Igawa80c1b9f2013-10-07 17:19:11 +090017import functools
Ian Wienand98c35f32013-07-23 20:34:23 +100018import os
Attila Fazekas53943322014-02-10 16:07:34 +010019import sys
Jay Pipes051075a2012-04-28 17:39:37 -040020
Jordan Pittier35a63752016-08-30 13:09:12 +020021import debtcollector.moves
Matthew Treinish78561ad2013-07-26 11:41:56 -040022import fixtures
Doug Hellmann583ce2c2015-03-11 14:55:46 +000023from oslo_log import log as logging
Chris Hoge296558c2015-02-19 00:29:49 -060024import six
ivan-zhu1feeb382013-01-24 10:14:39 +080025import testtools
Jay Pipes051075a2012-04-28 17:39:37 -040026
Matthew Treinish3e046852013-07-23 16:00:24 -040027from tempest import clients
Andrea Frittoli (andreaf)290b3e12015-10-08 10:25:02 +010028from tempest.common import credentials_factory as credentials
Rohan Kanade9ce97df2013-12-10 18:59:35 +053029from tempest.common import fixed_network
nithya-ganesan222efd72015-01-22 12:20:27 +000030import tempest.common.validation_resources as vresources
Attila Fazekasdc216422013-01-29 15:12:14 +010031from tempest import config
Matthew Treinish16c43792013-09-09 19:55:23 +000032from tempest import exceptions
Matthew Treinish3787e4c2016-10-07 21:25:33 -040033from tempest.lib.common import cred_client
Andrea Frittoli (andreaf)db9672e2016-02-23 14:07:24 -050034from tempest.lib import decorators
Andrea Frittoli (andreaf)af4f7cf2016-06-13 15:12:26 +010035from tempest.lib import exceptions as lib_exc
Jay Pipes051075a2012-04-28 17:39:37 -040036
37LOG = logging.getLogger(__name__)
38
Sean Dague86bd8422013-12-20 09:56:44 -050039CONF = config.CONF
40
Ken'ichi Ohmichi44f01272017-01-27 18:44:14 -080041# TODO(oomichi): This test.idempotent_id should be removed after all projects
42# switch to use decorators.idempotent_id.
43idempotent_id = debtcollector.moves.moved_function(
44 decorators.idempotent_id, 'idempotent_id', __name__,
45 version='Mitaka', removal_version='?')
Matthew Treinishc1802bc2015-12-03 18:48:11 -050046
Jay Pipes051075a2012-04-28 17:39:37 -040047
Jordan Pittierc5665a62017-04-12 16:42:53 +020048related_bug = debtcollector.moves.moved_function(
49 decorators.related_bug, 'related_bug', __name__,
50 version='Pike', removal_version='?')
51
52
Jordan Pittier3b46d272017-04-12 16:17:28 +020053attr = debtcollector.moves.moved_function(
54 decorators.attr, 'attr', __name__,
55 version='Pike', removal_version='?')
Chris Yeoh55530bb2013-02-08 16:04:27 +103056
57
Matthew Treinish3d8c7322014-08-03 23:53:28 -040058def get_service_list():
Matthew Treinish8afbffd2014-01-21 23:56:13 +000059 service_list = {
60 'compute': CONF.service_available.nova,
61 'image': CONF.service_available.glance,
62 'volume': CONF.service_available.cinder,
Matthew Treinish8afbffd2014-01-21 23:56:13 +000063 'network': True,
64 'identity': True,
65 'object_storage': CONF.service_available.swift,
Matthew Treinish8afbffd2014-01-21 23:56:13 +000066 }
Matthew Treinish3d8c7322014-08-03 23:53:28 -040067 return service_list
Matthew Treinish16c43792013-09-09 19:55:23 +000068
Matthew Treinish3d8c7322014-08-03 23:53:28 -040069
Yaroslav Lobankovda999f72015-06-30 20:32:55 +030070def services(*args):
Matthew Treinish3d8c7322014-08-03 23:53:28 -040071 """A decorator used to set an attr for each service used in a test case
72
73 This decorator applies a testtools attr for each service that gets
74 exercised by a test case.
75 """
Matthew Treinish16c43792013-09-09 19:55:23 +000076 def decorator(f):
Andrea Frittoli6f053072017-04-09 19:22:47 +020077 known_services = get_service_list()
78
Matthew Treinish16c43792013-09-09 19:55:23 +000079 for service in args:
Andrea Frittoli6f053072017-04-09 19:22:47 +020080 if service not in known_services:
Matthew Treinish3d8c7322014-08-03 23:53:28 -040081 raise exceptions.InvalidServiceTag('%s is not a valid '
82 'service' % service)
Jordan Pittier3b46d272017-04-12 16:17:28 +020083 decorators.attr(type=list(args))(f)
Matthew Treinish8afbffd2014-01-21 23:56:13 +000084
85 @functools.wraps(f)
86 def wrapper(self, *func_args, **func_kwargs):
Matthew Treinish3d8c7322014-08-03 23:53:28 -040087 service_list = get_service_list()
88
Matthew Treinish8afbffd2014-01-21 23:56:13 +000089 for service in args:
90 if not service_list[service]:
91 msg = 'Skipped because the %s service is not available' % (
92 service)
93 raise testtools.TestCase.skipException(msg)
94 return f(self, *func_args, **func_kwargs)
95 return wrapper
Matthew Treinish16c43792013-09-09 19:55:23 +000096 return decorator
97
98
Yaroslav Lobankovda999f72015-06-30 20:32:55 +030099def requires_ext(**kwargs):
Matthew Treinishe3d26142013-11-26 19:14:58 +0000100 """A decorator to skip tests if an extension is not enabled
101
102 @param extension
103 @param service
104 """
105 def decorator(func):
106 @functools.wraps(func)
107 def wrapper(*func_args, **func_kwargs):
108 if not is_extension_enabled(kwargs['extension'],
109 kwargs['service']):
110 msg = "Skipped because %s extension: %s is not enabled" % (
111 kwargs['service'], kwargs['extension'])
112 raise testtools.TestCase.skipException(msg)
113 return func(*func_args, **func_kwargs)
114 return wrapper
115 return decorator
116
117
118def is_extension_enabled(extension_name, service):
119 """A function that will check the list of enabled extensions from config
120
121 """
Matthew Treinishe3d26142013-11-26 19:14:58 +0000122 config_dict = {
Matthew Treinishbc0e03e2014-01-30 16:51:06 +0000123 'compute': CONF.compute_feature_enabled.api_extensions,
Matthew Treinishbc0e03e2014-01-30 16:51:06 +0000124 'volume': CONF.volume_feature_enabled.api_extensions,
125 'network': CONF.network_feature_enabled.api_extensions,
126 'object': CONF.object_storage_feature_enabled.discoverable_apis,
Jane Zadorozhna121576d2015-06-23 12:57:13 +0300127 'identity': CONF.identity_feature_enabled.api_extensions
Matthew Treinishe3d26142013-11-26 19:14:58 +0000128 }
Simeon Monov5d7effe2014-07-16 07:32:38 +0300129 if len(config_dict[service]) == 0:
130 return False
Matthew Treinishe3d26142013-11-26 19:14:58 +0000131 if config_dict[service][0] == 'all':
132 return True
133 if extension_name in config_dict[service]:
134 return True
135 return False
136
Ian Wienand98c35f32013-07-23 20:34:23 +1000137
Yair Fried95914122016-03-03 09:14:40 +0200138def is_scheduler_filter_enabled(filter_name):
ghanshyam5817e142016-12-01 11:38:46 +0900139 """Check the list of enabled compute scheduler filters from config.
140
141 This function checks whether the given compute scheduler filter is
142 available and configured in the config file. If the
143 scheduler_available_filters option is set to 'all' (Default value. which
144 means default filters are configured in nova) in tempest.conf then, this
145 function returns True with assumption that requested filter 'filter_name'
146 is one of available filter in nova ("nova.scheduler.filters.all_filters").
147 """
Yair Friedca5cfb52016-01-04 15:41:55 +0200148
149 filters = CONF.compute_feature_enabled.scheduler_available_filters
150 if len(filters) == 0:
151 return False
152 if 'all' in filters:
153 return True
154 if filter_name in filters:
155 return True
156 return False
157
158
Attila Fazekasf86fa312013-07-30 19:56:39 +0200159at_exit_set = set()
160
161
162def validate_tearDownClass():
163 if at_exit_set:
Sean Dagueeb1523b2014-03-10 10:17:44 -0400164 LOG.error(
165 "tearDownClass does not call the super's "
166 "tearDownClass in these classes: \n"
167 + str(at_exit_set))
168
Attila Fazekasf86fa312013-07-30 19:56:39 +0200169
170atexit.register(validate_tearDownClass)
171
Attila Fazekas53943322014-02-10 16:07:34 +0100172
Matthew Treinish2474f412014-11-17 18:11:56 -0500173class BaseTestCase(testtools.testcase.WithAttributes,
174 testtools.TestCase):
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100175 """The test base class defines Tempest framework for class level fixtures.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000176
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100177 `setUpClass` and `tearDownClass` are defined here and cannot be overwritten
178 by subclasses (enforced via hacking rule T105).
179
180 Set-up is split in a series of steps (setup stages), which can be
181 overwritten by test classes. Set-up stages are:
182 - skip_checks
183 - setup_credentials
184 - setup_clients
185 - resource_setup
186
187 Tear-down is also split in a series of steps (teardown stages), which are
188 stacked for execution only if the corresponding setup stage had been
189 reached during the setup phase. Tear-down stages are:
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700190 - clear_credentials (defined in the base test class)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100191 - resource_cleanup
192 """
Attila Fazekasc43fec82013-04-09 23:17:52 +0200193
Attila Fazekasf86fa312013-07-30 19:56:39 +0200194 setUpClassCalled = False
195
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000196 # NOTE(andreaf) credentials holds a list of the credentials to be allocated
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100197 # at class setup time. Credential types can be 'primary', 'alt', 'admin' or
198 # a list of roles - the first element of the list being a label, and the
199 # rest the actual roles
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000200 credentials = []
nithya-ganesan222efd72015-01-22 12:20:27 +0000201 # Resources required to validate a server using ssh
202 validation_resources = {}
Matthew Treinish9f756a02014-01-15 10:26:07 -0500203 network_resources = {}
204
Sean Dague2ef32ac2014-06-09 11:32:23 -0400205 # NOTE(sdague): log_format is defined inline here instead of using the oslo
206 # default because going through the config path recouples config to the
207 # stress tests too early, and depending on testr order will fail unit tests
208 log_format = ('%(asctime)s %(process)d %(levelname)-8s '
209 '[%(name)s] %(message)s')
210
Ryota MIBU60687e52015-12-09 18:37:39 +0900211 # Client manager class to use in this test case.
212 client_manager = clients.Manager
213
Sean Dague02620fd2016-03-02 15:52:51 -0500214 # A way to adjust slow test classes
215 TIMEOUT_SCALING_FACTOR = 1
216
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200217 @classmethod
218 def setUpClass(cls):
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100219 # It should never be overridden by descendants
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200220 if hasattr(super(BaseTestCase, cls), 'setUpClass'):
221 super(BaseTestCase, cls).setUpClass()
Attila Fazekasf86fa312013-07-30 19:56:39 +0200222 cls.setUpClassCalled = True
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100223 # Stack of (name, callable) to be invoked in reverse order at teardown
224 cls.teardowns = []
225 # All the configuration checks that may generate a skip
226 cls.skip_checks()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100227 try:
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100228 # Allocation of all required credentials and client managers
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700229 cls.teardowns.append(('credentials', cls.clear_credentials))
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100230 cls.setup_credentials()
231 # Shortcuts to clients
232 cls.setup_clients()
233 # Additional class-wide test resources
234 cls.teardowns.append(('resources', cls.resource_cleanup))
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100235 cls.resource_setup()
236 except Exception:
237 etype, value, trace = sys.exc_info()
Jordan Pittier525ec712016-12-07 17:51:26 +0100238 LOG.info("%s raised in %s.setUpClass. Invoking tearDownClass.",
239 etype, cls.__name__)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100240 cls.tearDownClass()
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100241 try:
Matthew Treinish843227d2015-04-23 10:17:17 -0400242 six.reraise(etype, value, trace)
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100243 finally:
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100244 del trace # to avoid circular refs
Pavel Sedlák1053bd32013-04-16 16:47:40 +0200245
Attila Fazekasf86fa312013-07-30 19:56:39 +0200246 @classmethod
247 def tearDownClass(cls):
Attila Fazekas5d275302013-08-29 12:35:12 +0200248 at_exit_set.discard(cls)
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100249 # It should never be overridden by descendants
Attila Fazekasf86fa312013-07-30 19:56:39 +0200250 if hasattr(super(BaseTestCase, cls), 'tearDownClass'):
251 super(BaseTestCase, cls).tearDownClass()
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100252 # Save any existing exception, we always want to re-raise the original
253 # exception only
254 etype, value, trace = sys.exc_info()
255 # If there was no exception during setup we shall re-raise the first
256 # exception in teardown
257 re_raise = (etype is None)
258 while cls.teardowns:
259 name, teardown = cls.teardowns.pop()
260 # Catch any exception in tearDown so we can re-raise the original
261 # exception at the end
262 try:
263 teardown()
264 except Exception as te:
265 sys_exec_info = sys.exc_info()
266 tetype = sys_exec_info[0]
267 # TODO(andreaf): Till we have the ability to cleanup only
268 # resources that were successfully setup in resource_cleanup,
269 # log AttributeError as info instead of exception.
270 if tetype is AttributeError and name == 'resources':
Jordan Pittier525ec712016-12-07 17:51:26 +0100271 LOG.info("tearDownClass of %s failed: %s", name, te)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100272 else:
Jordan Pittier525ec712016-12-07 17:51:26 +0100273 LOG.exception("teardown of %s failed: %s", name, te)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100274 if not etype:
275 etype, value, trace = sys_exec_info
Joshua Whitebd769602016-02-02 09:30:11 -0800276 # If exceptions were raised during teardown, and not before, re-raise
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100277 # the first one
278 if re_raise and etype is not None:
279 try:
Matthew Treinish843227d2015-04-23 10:17:17 -0400280 six.reraise(etype, value, trace)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100281 finally:
282 del trace # to avoid circular refs
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100283
284 @classmethod
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100285 def skip_checks(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000286 """Class level skip checks.
287
288 Subclasses verify in here all conditions that might prevent the
289 execution of the entire test class.
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100290 Checks implemented here may not make use API calls, and should rely on
291 configuration alone.
292 In general skip checks that require an API call are discouraged.
293 If one is really needed it may be implemented either in the
294 resource_setup or at test level.
295 """
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100296 identity_version = cls.get_identity_version()
297 if 'admin' in cls.credentials and not credentials.is_admin_available(
298 identity_version=identity_version):
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000299 msg = "Missing Identity Admin API credentials in configuration."
300 raise cls.skipException(msg)
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100301 if 'alt' in cls.credentials and not credentials.is_alt_available(
302 identity_version=identity_version):
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000303 msg = "Missing a 2nd set of API credentials in configuration."
304 raise cls.skipException(msg)
Andrea Frittoli (andreaf)41601412015-05-12 16:39:03 +0100305 if hasattr(cls, 'identity_version'):
306 if cls.identity_version == 'v2':
307 if not CONF.identity_feature_enabled.api_v2:
308 raise cls.skipException("Identity api v2 is not enabled")
309 elif cls.identity_version == 'v3':
310 if not CONF.identity_feature_enabled.api_v3:
311 raise cls.skipException("Identity api v3 is not enabled")
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100312
313 @classmethod
314 def setup_credentials(cls):
edannon6cc6fbc2016-05-03 11:56:12 +0300315 """Allocate credentials and create the client managers from them.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000316
edannon6cc6fbc2016-05-03 11:56:12 +0300317 For every element of credentials param function creates tenant/user,
318 Then it creates client manager for that credential.
319
320 Network related tests must override this function with
321 set_network_resources() method, otherwise it will create
322 network resources(network resources are created in a later step).
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000323 """
324 for credentials_type in cls.credentials:
325 # This may raise an exception in case credentials are not available
326 # In that case we want to let the exception through and the test
327 # fail accordingly
Andrea Frittoli (andreaf)825b2d32015-04-08 20:58:01 +0100328 if isinstance(credentials_type, six.string_types):
329 manager = cls.get_client_manager(
330 credential_type=credentials_type)
331 setattr(cls, 'os_%s' % credentials_type, manager)
332 # Setup some common aliases
333 # TODO(andreaf) The aliases below are a temporary hack
334 # to avoid changing too much code in one patch. They should
335 # be removed eventually
336 if credentials_type == 'primary':
337 cls.os = cls.manager = cls.os_primary
338 if credentials_type == 'admin':
339 cls.os_adm = cls.admin_manager = cls.os_admin
340 if credentials_type == 'alt':
341 cls.alt_manager = cls.os_alt
342 elif isinstance(credentials_type, list):
343 manager = cls.get_client_manager(roles=credentials_type[1:],
344 force_new=True)
345 setattr(cls, 'os_roles_%s' % credentials_type[0], manager)
Andrea Frittolia5ddd552014-08-19 18:30:00 +0100346
347 @classmethod
348 def setup_clients(cls):
349 """Create links to the clients into the test object."""
350 # TODO(andreaf) There is a fair amount of code that could me moved from
351 # base / test classes in here. Ideally tests should be able to only
352 # specify which client is `client` and nothing else.
Andrea Frittoli73ee2472014-09-15 12:31:53 +0100353 pass
Attila Fazekasf86fa312013-07-30 19:56:39 +0200354
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000355 @classmethod
356 def resource_setup(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000357 """Class level resource setup for test cases."""
nithya-ganesan222efd72015-01-22 12:20:27 +0000358 if hasattr(cls, "os"):
359 cls.validation_resources = vresources.create_validation_resources(
360 cls.os, cls.validation_resources)
361 else:
zhangguoqing6c096642016-01-04 06:17:21 +0000362 LOG.warning("Client manager not found, validation resources not"
363 " created")
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000364
365 @classmethod
366 def resource_cleanup(cls):
367 """Class level resource cleanup for test cases.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000368
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000369 Resource cleanup must be able to handle the case of partially setup
370 resources, in case a failure during `resource_setup` should happen.
371 """
nithya-ganesan222efd72015-01-22 12:20:27 +0000372 if cls.validation_resources:
373 if hasattr(cls, "os"):
374 vresources.clear_validation_resources(cls.os,
375 cls.validation_resources)
376 cls.validation_resources = {}
377 else:
zhangguoqing6c096642016-01-04 06:17:21 +0000378 LOG.warning("Client manager not found, validation resources "
379 "not deleted")
Emily Hugenbruch5bd4cbf2014-12-17 21:38:38 +0000380
Attila Fazekasf86fa312013-07-30 19:56:39 +0200381 def setUp(self):
382 super(BaseTestCase, self).setUp()
383 if not self.setUpClassCalled:
384 raise RuntimeError("setUpClass does not calls the super's"
385 "setUpClass in the "
386 + self.__class__.__name__)
387 at_exit_set.add(self.__class__)
Matthew Treinish78561ad2013-07-26 11:41:56 -0400388 test_timeout = os.environ.get('OS_TEST_TIMEOUT', 0)
389 try:
Sean Dague02620fd2016-03-02 15:52:51 -0500390 test_timeout = int(test_timeout) * self.TIMEOUT_SCALING_FACTOR
Matthew Treinish78561ad2013-07-26 11:41:56 -0400391 except ValueError:
392 test_timeout = 0
393 if test_timeout > 0:
Attila Fazekasf86fa312013-07-30 19:56:39 +0200394 self.useFixture(fixtures.Timeout(test_timeout, gentle=True))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400395
396 if (os.environ.get('OS_STDOUT_CAPTURE') == 'True' or
397 os.environ.get('OS_STDOUT_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200398 stdout = self.useFixture(fixtures.StringStream('stdout')).stream
399 self.useFixture(fixtures.MonkeyPatch('sys.stdout', stdout))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400400 if (os.environ.get('OS_STDERR_CAPTURE') == 'True' or
401 os.environ.get('OS_STDERR_CAPTURE') == '1'):
Attila Fazekasf86fa312013-07-30 19:56:39 +0200402 stderr = self.useFixture(fixtures.StringStream('stderr')).stream
403 self.useFixture(fixtures.MonkeyPatch('sys.stderr', stderr))
Attila Fazekas31388072013-08-15 08:58:07 +0200404 if (os.environ.get('OS_LOG_CAPTURE') != 'False' and
405 os.environ.get('OS_LOG_CAPTURE') != '0'):
Attila Fazekas31388072013-08-15 08:58:07 +0200406 self.useFixture(fixtures.LoggerFixture(nuke_handlers=False,
Sean Dague2ef32ac2014-06-09 11:32:23 -0400407 format=self.log_format,
Attila Fazekas90445be2013-10-24 16:46:03 +0200408 level=None))
Matthew Treinish78561ad2013-07-26 11:41:56 -0400409
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100410 @property
411 def credentials_provider(self):
412 return self._get_credentials_provider()
413
Jamie Lennox15350172015-08-17 10:54:25 +1000414 @property
415 def identity_utils(self):
416 """A client that abstracts v2 and v3 identity operations.
417
418 This can be used for creating and tearing down projects in tests. It
419 should not be used for testing identity features.
420 """
421 if CONF.identity.auth_version == 'v2':
422 client = self.os_admin.identity_client
Daniel Mellado7aea5342016-02-09 09:10:12 +0000423 users_client = self.os_admin.users_client
Daniel Melladob04da902015-11-20 17:43:12 +0100424 project_client = self.os_admin.tenants_client
Daniel Mellado6b16b922015-12-07 12:43:08 +0000425 roles_client = self.os_admin.roles_client
Daniel Mellado91a26b62016-02-11 11:13:04 +0000426 domains_client = None
Jamie Lennox15350172015-08-17 10:54:25 +1000427 else:
428 client = self.os_admin.identity_v3_client
Daniel Mellado7aea5342016-02-09 09:10:12 +0000429 users_client = self.os_admin.users_v3_client
Arx Cruz24bcb882016-02-10 15:20:16 +0100430 project_client = self.os_admin.projects_client
431 roles_client = self.os_admin.roles_v3_client
Daniel Mellado91a26b62016-02-11 11:13:04 +0000432 domains_client = self.os_admin.domains_client
Jamie Lennox15350172015-08-17 10:54:25 +1000433
434 try:
435 domain = client.auth_provider.credentials.project_domain_name
436 except AttributeError:
437 domain = 'Default'
438
Daniel Melladob04da902015-11-20 17:43:12 +0100439 return cred_client.get_creds_client(client, project_client,
Daniel Mellado82c83a52015-12-09 15:16:49 +0000440 users_client,
Daniel Mellado7aea5342016-02-09 09:10:12 +0000441 roles_client,
Daniel Mellado91a26b62016-02-11 11:13:04 +0000442 domains_client,
Daniel Melladob04da902015-11-20 17:43:12 +0100443 project_domain_name=domain)
Jamie Lennox15350172015-08-17 10:54:25 +1000444
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100445 @classmethod
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100446 def get_identity_version(cls):
447 """Returns the identity version used by the test class"""
448 identity_version = getattr(cls, 'identity_version', None)
449 return identity_version or CONF.identity.auth_version
450
451 @classmethod
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100452 def _get_credentials_provider(cls):
453 """Returns a credentials provider
454
455 If no credential provider exists yet creates one.
456 It uses self.identity_version if defined, or the configuration value
457 """
458 if (not hasattr(cls, '_creds_provider') or not cls._creds_provider or
459 not cls._creds_provider.name == cls.__name__):
460 force_tenant_isolation = getattr(cls, 'force_tenant_isolation',
461 False)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100462
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700463 cls._creds_provider = credentials.get_credentials_provider(
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100464 name=cls.__name__, network_resources=cls.network_resources,
465 force_tenant_isolation=force_tenant_isolation,
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100466 identity_version=cls.get_identity_version())
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100467 return cls._creds_provider
468
Matthew Treinish3e046852013-07-23 16:00:24 -0400469 @classmethod
Andrea Frittoli (andreaf)41601412015-05-12 16:39:03 +0100470 def get_client_manager(cls, credential_type=None, roles=None,
471 force_new=None):
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100472 """Returns an OpenStack client manager
473
474 Returns an OpenStack client manager based on either credential_type
475 or a list of roles. If neither is specified, it defaults to
476 credential_type 'primary'
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100477 :param credential_type: string - primary, alt or admin
478 :param roles: list of roles
479
lei zhangdd552b22015-11-25 20:41:48 +0800480 :returns: the created client manager
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100481 :raises skipException: if the requested credentials are not available
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700482 """
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100483 if all([roles, credential_type]):
484 msg = "Cannot get credentials by type and roles at the same time"
485 raise ValueError(msg)
486 if not any([roles, credential_type]):
487 credential_type = 'primary'
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100488 cred_provider = cls._get_credentials_provider()
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100489 if roles:
490 for role in roles:
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100491 if not cred_provider.is_role_available(role):
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100492 skip_msg = (
493 "%s skipped because the configured credential provider"
494 " is not able to provide credentials with the %s role "
495 "assigned." % (cls.__name__, role))
496 raise cls.skipException(skip_msg)
497 params = dict(roles=roles)
498 if force_new is not None:
499 params.update(force_new=force_new)
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100500 creds = cred_provider.get_creds_by_roles(**params)
Andrea Frittolib21de6c2015-02-06 20:12:38 +0000501 else:
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100502 credentials_method = 'get_%s_creds' % credential_type
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100503 if hasattr(cred_provider, credentials_method):
504 creds = getattr(cred_provider, credentials_method)()
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100505 else:
Andrea Frittoli (andreaf)af4f7cf2016-06-13 15:12:26 +0100506 raise lib_exc.InvalidCredentials(
Andrea Frittoli (andreaf)737fac92015-05-12 16:14:35 +0100507 "Invalid credentials type %s" % credential_type)
Jordan Pittiere4be9072017-01-04 19:17:35 +0100508 manager = cls.client_manager(credentials=creds.credentials)
Andrea Frittoli73224672016-12-09 21:08:19 +0000509 # NOTE(andreaf) Ensure credentials have user and project id fields.
510 # It may not be the case when using pre-provisioned credentials.
511 manager.auth_provider.set_auth()
512 return manager
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700513
514 @classmethod
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700515 def clear_credentials(cls):
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000516 """Clears creds if set"""
Attila Fazekas5b0d9262015-05-20 10:17:39 +0200517 if hasattr(cls, '_creds_provider'):
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700518 cls._creds_provider.clear_creds()
Ryan Hsu6c4bb3d2013-10-21 21:22:50 -0700519
520 @classmethod
nithya-ganesan222efd72015-01-22 12:20:27 +0000521 def set_validation_resources(cls, keypair=None, floating_ip=None,
522 security_group=None,
523 security_group_rules=None):
524 """Specify which ssh server validation resources should be created.
Ken'ichi Ohmichi2e2ee192015-11-19 09:48:27 +0000525
nithya-ganesan222efd72015-01-22 12:20:27 +0000526 Each of the argument must be set to either None, True or False, with
527 None - use default from config (security groups and security group
528 rules get created when set to None)
529 False - Do not create the validation resource
530 True - create the validation resource
531
532 @param keypair
533 @param security_group
534 @param security_group_rules
535 @param floating_ip
536 """
Matthew Treinishe5cca002015-05-11 15:36:50 -0400537 if not CONF.validation.run_validation:
538 return
Jordan Pittier79cd1822016-12-08 17:20:35 +0100539
nithya-ganesan222efd72015-01-22 12:20:27 +0000540 if keypair is None:
Jordan Pittier79cd1822016-12-08 17:20:35 +0100541 keypair = (CONF.validation.auth_method.lower() == "keypair")
542
nithya-ganesan222efd72015-01-22 12:20:27 +0000543 if floating_ip is None:
Jordan Pittier79cd1822016-12-08 17:20:35 +0100544 floating_ip = (CONF.validation.connect_method.lower() ==
545 "floating")
546
nithya-ganesan222efd72015-01-22 12:20:27 +0000547 if security_group is None:
Brandon Palmc6cc91d2015-08-19 13:20:21 -0500548 security_group = CONF.validation.security_group
Jordan Pittier79cd1822016-12-08 17:20:35 +0100549
nithya-ganesan222efd72015-01-22 12:20:27 +0000550 if security_group_rules is None:
Brandon Palmc6cc91d2015-08-19 13:20:21 -0500551 security_group_rules = CONF.validation.security_group_rules
552
nithya-ganesan222efd72015-01-22 12:20:27 +0000553 if not cls.validation_resources:
554 cls.validation_resources = {
555 'keypair': keypair,
556 'security_group': security_group,
557 'security_group_rules': security_group_rules,
558 'floating_ip': floating_ip}
559
560 @classmethod
Andrea Frittoli7d5ed592015-02-10 01:10:23 +0000561 def set_network_resources(cls, network=False, router=False, subnet=False,
Matthew Treinish9f756a02014-01-15 10:26:07 -0500562 dhcp=False):
563 """Specify which network resources should be created
564
565 @param network
566 @param router
567 @param subnet
568 @param dhcp
569 """
Salvatore Orlando5a337242014-01-15 22:49:22 +0000570 # network resources should be set only once from callers
571 # in order to ensure that even if it's called multiple times in
572 # a chain of overloaded methods, the attribute is set only
573 # in the leaf class
Andrea Frittoli7d5ed592015-02-10 01:10:23 +0000574 if not cls.network_resources:
575 cls.network_resources = {
Salvatore Orlando5a337242014-01-15 22:49:22 +0000576 'network': network,
577 'router': router,
578 'subnet': subnet,
579 'dhcp': dhcp}
Matthew Treinish9f756a02014-01-15 10:26:07 -0500580
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530581 @classmethod
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000582 def get_tenant_network(cls, credentials_type='primary'):
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530583 """Get the network to be used in testing
584
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000585 :param credentials_type: The type of credentials for which to get the
586 tenant network
587
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530588 :return: network dict including 'id' and 'name'
589 """
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000590 # Get a manager for the given credentials_type, but at least
591 # always fall back on getting the manager for primary credentials
592 if isinstance(credentials_type, six.string_types):
593 manager = cls.get_client_manager(credential_type=credentials_type)
594 elif isinstance(credentials_type, list):
595 manager = cls.get_client_manager(roles=credentials_type[1:])
596 else:
597 manager = cls.get_client_manager()
598
Andrea Frittoli (andreaf)17209bb2015-05-22 10:16:57 -0700599 # Make sure cred_provider exists and get a network client
Ryan Rossiter9228bf72016-02-25 03:06:12 +0000600 networks_client = manager.compute_networks_client
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100601 cred_provider = cls._get_credentials_provider()
Andrea Frittoli700711e2015-04-02 11:39:38 +0100602 # In case of nova network, isolated tenants are not able to list the
Joshua Whitebd769602016-02-02 09:30:11 -0800603 # network configured in fixed_network_name, even if they can use it
Andrea Frittoli700711e2015-04-02 11:39:38 +0100604 # for their servers, so using an admin network client to validate
605 # the network name
606 if (not CONF.service_available.neutron and
Andrea Frittoli (andreaf)32d0de12015-10-09 14:43:53 +0100607 credentials.is_admin_available(
608 identity_version=cls.get_identity_version())):
Andrea Frittoli (andreaf)1f342412015-05-12 16:37:19 +0100609 admin_creds = cred_provider.get_admin_creds()
Andrea Frittoli (andreaf)848c4a12016-06-09 11:09:02 +0100610 admin_manager = clients.Manager(admin_creds.credentials)
John Warren9487a182015-09-14 18:12:56 -0400611 networks_client = admin_manager.compute_networks_client
Andrea Frittoli (andreaf)940f8c62015-10-30 16:39:24 +0900612 return fixed_network.get_tenant_network(
613 cred_provider, networks_client, CONF.compute.fixed_network_name)
Rohan Kanade9ce97df2013-12-10 18:59:35 +0530614
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100615 def assertEmpty(self, items, msg=None):
616 """Asserts whether a sequence or collection is empty
Mark Maglana5885eb32014-02-28 10:57:34 -0800617
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100618 :param items: sequence or collection to be tested
619 :param msg: message to be passed to the AssertionError
620 :raises AssertionError: when items is not empty
621 """
zhufl92ade4b2017-03-03 15:20:10 +0800622 if msg is None:
Andrea Frittoli71c71e92017-04-07 17:45:21 +0100623 msg = "sequence or collection is not empty: %s" % items
624 self.assertEqual(0, len(items), msg)
625
626 def assertNotEmpty(self, items, msg=None):
627 """Asserts whether a sequence or collection is not empty
628
629 :param items: sequence or collection to be tested
630 :param msg: message to be passed to the AssertionError
631 :raises AssertionError: when items is empty
632 """
633 if msg is None:
634 msg = "sequence or collection is empty."
635 self.assertGreater(len(items), 0, msg)